Attean

 view release on metacpan or  search on metacpan

lib/Attean/Algebra.pm  view on Meta::CPAN

use v5.14;
use warnings;
use utf8;

=head1 NAME

Attean::Algebra - Representation of SPARQL algebra operators

=head1 VERSION

This document describes Attean::Algebra version 0.038

=head1 SYNOPSIS

  use v5.14;
  use Attean;

=head1 DESCRIPTION

This is a utility package that defines all the Attean query algebra classes
in the Attean::Algebra namespace:

=over 4

=cut

use Attean::API::Query;

package Attean::Algebra::Query 0.038 {
	use AtteanX::SPARQL::Constants;
	use AtteanX::SPARQL::Token;
	use Types::Standard qw(Bool ArrayRef HashRef ConsumerOf);
	use Moo;
	use namespace::clean;

	has 'dataset' => (is => 'ro', isa => HashRef[ArrayRef[ConsumerOf['Attean::API::Term']]], default => sub { +{} });
	has 'subquery' => (is => 'ro', isa => Bool, default => 0);

	with 'Attean::API::UnionScopeVariables', 'Attean::API::Algebra', 'Attean::API::UnaryQueryTree';

	sub algebra_as_string {
		my $self	= shift;
		my $name	= $self->subquery ? 'SubQuery' : 'Query';
		
		my %dataset	= %{ $self->dataset };
		my @default	= @{ $dataset{ default } || [] };
		my @named	= @{ $dataset{ named } || [] };
		my $has_dataset	= (scalar(@default) + scalar(@named));
		
		my $s	= $name;
		if ($has_dataset) {
			my @parts;
			if (scalar(@default)) {
				push(@parts, 'Default graph(s): ' . join(', ', map { chomp; $_ } map { $_->as_sparql } @default));
			}
			if (scalar(@named)) {
				push(@parts, 'Named graph(s): ' . join(', ', map { chomp; $_ } map { $_->as_sparql } @named));
			}
			$s	.= ' { ' . join('; ', @parts) . ' }';
		}
		return $s;
	}

	sub sparql_tokens {
		my $self	= shift;
		my $child	= $self->child;
		my $l		= AtteanX::SPARQL::Token->lbrace;
		my $r		= AtteanX::SPARQL::Token->rbrace;
		my $from		= AtteanX::SPARQL::Token->keyword('FROM');
		my $named		= AtteanX::SPARQL::Token->keyword('NAMED');

		my %dataset	= %{ $self->dataset };
		my @default	= @{ $dataset{ default } || [] };
		my @named	= @{ $dataset{ named } || [] };
		my $has_dataset	= (scalar(@default) + scalar(@named));
		if ($child->does('Attean::API::SPARQLQuerySerializable')) {
			if ($self->subquery) {
				my @tokens;
				push(@tokens, $l);
				push(@tokens, $child->sparql_tokens->elements);
				push(@tokens, $r);
				return Attean::ListIterator->new( values => \@tokens, item_type => 'AtteanX::SPARQL::Token' );
			} else {
				my %args;
				if ($has_dataset) {
					$args{dataset}	= $self->dataset;
				}
				return $child->query_tokens(%args);
			}
		} else {
			my $sel		= AtteanX::SPARQL::Token->keyword('SELECT');
			my $star	= AtteanX::SPARQL::Token->star;
			my $where	= AtteanX::SPARQL::Token->keyword('WHERE');
			
			my @tokens;
			if ($self->subquery) {

lib/Attean/Algebra.pm  view on Meta::CPAN

	use Types::Standard qw(ConsumerOf);
	use namespace::clean;
	
	sub in_scope_variables {
		my $self	= shift;
		my ($child)	= @{ $self->children };
		my @vars	= $child->in_scope_variables;
		return Set::Scalar->new(@vars, $self->variable->value)->elements;
	}
	with 'Attean::API::Algebra', 'Attean::API::UnaryQueryTree';

	has 'variable' => (is => 'ro', isa => ConsumerOf['Attean::API::Variable'], required => 1);
	has 'expression' => (is => 'ro', isa => ConsumerOf['Attean::API::Expression'], required => 1);

	sub algebra_as_string {
		my $self	= shift;
		return sprintf('Extend { %s ← %s }', $self->variable->as_string, $self->expression->as_string);
	}
	sub tree_attributes { return qw(variable expression) };
	sub sparql_tokens {
		my $self	= shift;
		my $bind	= AtteanX::SPARQL::Token->keyword('BIND');
		my $as		= AtteanX::SPARQL::Token->keyword('AS');
		my $l		= AtteanX::SPARQL::Token->lparen;
		my $r		= AtteanX::SPARQL::Token->rparen;
		my ($child)	= @{ $self->children };
		my $var		= $self->variable;
		my $expr	= $self->expression;
		
		my @tokens;
		push(@tokens, $child->sparql_tokens->elements);
		push(@tokens, $bind);
		push(@tokens, $l);
		push(@tokens, $expr->sparql_tokens->elements);
		push(@tokens, $as);
		push(@tokens, $var->sparql_tokens->elements);
		push(@tokens, $r);
		return Attean::ListIterator->new( values => \@tokens, item_type => 'AtteanX::SPARQL::Token' );
	}
}

=item * L<Attean::Algebra::Unfold>

=cut

package Attean::Algebra::Unfold 0.031 {
	use AtteanX::SPARQL::Constants;
	use AtteanX::SPARQL::Token;
	use Moo;
	use Types::Standard qw(ArrayRef ConsumerOf);
	use namespace::clean;
	
	sub in_scope_variables {
		my $self	= shift;
		my ($child)	= @{ $self->children };
		my @vars	= $child->in_scope_variables;
		return Set::Scalar->new(@vars, map { $_->value } @{ $self->variables })->elements;
	}
	with 'Attean::API::Algebra', 'Attean::API::UnaryQueryTree';

	has 'variables' => (is => 'ro', isa => ArrayRef[ConsumerOf['Attean::API::Variable']], required => 1);
	has 'expression' => (is => 'ro', isa => ConsumerOf['Attean::API::Expression'], required => 1);

	sub algebra_as_string {
		my $self	= shift;
		my @vars	= map { $_->as_string } @{ $self->variables };
		my $vars	= '(' . join(', ', @vars) . ')';
		return sprintf('Unfold { %s ← %s }', $vars, $self->expression->as_string);
	}
	sub tree_attributes { return qw(variables expression) };
	sub sparql_tokens {
		my $self	= shift;
		my $explode	= AtteanX::SPARQL::Token->keyword('UNFOLD');
		my $as		= AtteanX::SPARQL::Token->keyword('AS');
		my $l		= AtteanX::SPARQL::Token->lparen;
		my $r		= AtteanX::SPARQL::Token->rparen;
		my ($child)	= @{ $self->children };
		my @vars	= @{ $self->variables };
		my $expr	= $self->expression;
		
		my @tokens;
		push(@tokens, $child->sparql_tokens->elements);
		push(@tokens, $explode);
		push(@tokens, $l);
		push(@tokens, $expr->sparql_tokens->elements);
		push(@tokens, $as);
		foreach my $i (0 .. $#vars) {
			my $var	= $vars[$i];
			if ($i > 0) {
				push(@tokens, AtteanX::SPARQL::Token->comma);
			}
			push(@tokens, $var->sparql_tokens->elements);
		}
		push(@tokens, $r);
		return Attean::ListIterator->new( values => \@tokens, item_type => 'AtteanX::SPARQL::Token' );
	}
}

=item * L<Attean::Algebra::Minus>

=cut

package Attean::Algebra::Minus 0.038 {
	use AtteanX::SPARQL::Constants;
	use AtteanX::SPARQL::Token;
	use Moo;
	use Types::Standard qw(ConsumerOf);
	use namespace::clean;

	with 'Attean::API::Algebra', 'Attean::API::BinaryQueryTree';

	sub in_scope_variables {
		my $self	= shift;
		my ($child)	= @{ $self->children };
		return $child->in_scope_variables;
	}

	sub algebra_as_string { return 'Minus' }
	sub sparql_tokens {
		my $self	= shift;
		my $minus	= AtteanX::SPARQL::Token->keyword('MINUS');

lib/Attean/Algebra.pm  view on Meta::CPAN


package Attean::Algebra::Distinct 0.038 {
	use Moo;
	use namespace::clean;

	with 'Attean::API::SPARQLQuerySerializable';
	with 'Attean::API::UnionScopeVariables', 'Attean::API::Algebra', 'Attean::API::UnaryQueryTree';

	sub algebra_as_string { return 'Distinct' }
}

=item * L<Attean::Algebra::Reduced>

=cut

package Attean::Algebra::Reduced 0.038 {
	use Moo;
	use namespace::clean;

	with 'Attean::API::SPARQLQuerySerializable';
	with 'Attean::API::UnionScopeVariables', 'Attean::API::Algebra', 'Attean::API::UnaryQueryTree';

	sub algebra_as_string { return 'Reduced' }
}

=item * L<Attean::Algebra::Slice>

=cut

package Attean::Algebra::Slice 0.038 {
	use Moo;
	use Types::Standard qw(Int);
	use namespace::clean;

	with 'Attean::API::SPARQLQuerySerializable';
	with 'Attean::API::UnionScopeVariables', 'Attean::API::Algebra', 'Attean::API::UnaryQueryTree';

	has 'limit' => (is => 'ro', isa => Int, default => -1);
	has 'offset' => (is => 'ro', isa => Int, default => 0);
	sub algebra_as_string {
		my $self	= shift;
		my @str	= ('Slice');
		push(@str, "Limit=" . $self->limit) if ($self->limit >= 0);
		push(@str, "Offset=" . $self->offset) if ($self->offset > 0);
		return join(' ', @str);
	}
}

=item * L<Attean::Algebra::Project>

=cut

package Attean::Algebra::Project 0.038 {
	use Types::Standard qw(ArrayRef ConsumerOf);
	use Moo;
	use namespace::clean;

	with 'Attean::API::SPARQLQuerySerializable';
	with 'Attean::API::Algebra', 'Attean::API::UnaryQueryTree';

	has 'variables' => (is => 'ro', isa => ArrayRef[ConsumerOf['Attean::API::Variable']], required => 1);

	sub in_scope_variables {
		my $self	= shift;
		my ($child)	= @{ $self->children };
		my $set		= Set::Scalar->new( $child->in_scope_variables );
		my $proj	= Set::Scalar->new( map { $_->value } @{ $self->variables } );
		return $set->intersection($proj)->elements;
	}
	sub algebra_as_string {
		my $self	= shift;
		return sprintf('Project { %s }', join(' ', map { '?' . $_->value } @{ $self->variables }));
	}
	sub tree_attributes { return qw(variables) };
}

=item * L<Attean::Algebra::Comparator>

=cut

package Attean::Algebra::Comparator 0.038 {
	use Moo;
	use AtteanX::SPARQL::Constants;
	use AtteanX::SPARQL::Token;
	use Types::Standard qw(Bool ConsumerOf);
	use namespace::clean;


	has 'ascending' => (is => 'ro', isa => Bool, default => 1);
	has 'expression' => (is => 'ro', isa => ConsumerOf['Attean::API::Expression'], required => 1);

	sub tree_attributes { return qw(expression) };
	sub as_string {
		my $self	= shift;
		if ($self->ascending) {
			return 'ASC(' . $self->expression->as_string . ')';
		} else {
			return 'DESC(' . $self->expression->as_string . ')';
		}
	}

	sub sparql_tokens {
		my $self	= shift;
		my $asc		= AtteanX::SPARQL::Token->keyword('ASC');
		my $desc	= AtteanX::SPARQL::Token->keyword('DESC');
		my $l		= AtteanX::SPARQL::Token->lparen;
		my $r		= AtteanX::SPARQL::Token->rparen;
		
		my @tokens;
		if ($self->ascending) {
			push(@tokens, $self->expression->sparql_tokens->elements);
		} else {
			push(@tokens, $desc, $l);
			push(@tokens, $self->expression->sparql_tokens->elements);
			push(@tokens, $r);
		}
		return Attean::ListIterator->new( values => \@tokens, item_type => 'AtteanX::SPARQL::Token' );
	}
}

=item * L<Attean::Algebra::OrderBy>

=cut

package Attean::Algebra::OrderBy 0.038 {
	use Moo;
	use AtteanX::SPARQL::Constants;
	use AtteanX::SPARQL::Token;
	use Types::Standard qw(ArrayRef InstanceOf);
	use namespace::clean;
	
	with 'Attean::API::SPARQLQuerySerializable';
	with 'Attean::API::UnionScopeVariables', 'Attean::API::Algebra', 'Attean::API::UnaryQueryTree';
	
	has 'comparators' => (is => 'ro', isa => ArrayRef[InstanceOf['Attean::Algebra::Comparator']], required => 1);
	
	sub tree_attributes { return qw(comparators) };
	sub algebra_as_string {
		my $self	= shift;
		return sprintf('Order { %s }', join(', ', map { $_->as_string } @{ $self->comparators }));
	}
}

=item * L<Attean::Algebra::BGP>

=cut

package Attean::Algebra::BGP 0.038 {
	use Moo;
	use Attean::RDF;
	use Set::Scalar;
	use AtteanX::SPARQL::Constants;
	use AtteanX::SPARQL::Token;
	use Types::Standard qw(ArrayRef ConsumerOf);
	use namespace::clean;

	with 'Attean::API::Algebra', 'Attean::API::NullaryQueryTree', 'Attean::API::CanonicalizingBindingSet';
	
	has 'triples' => (is => 'ro', isa => ArrayRef[ConsumerOf['Attean::API::TriplePattern']], default => sub { [] });
	
	sub in_scope_variables {
		my $self	= shift;
		my $set		= Set::Scalar->new();
		foreach my $t (@{ $self->triples }) {
			my @vars	= $t->referenced_variables();
			$set->insert(@vars);
		}
		return $set->elements;
	}
	
	sub sparql_tokens {
		my $self	= shift;
		my @tokens;
		my $dot	= AtteanX::SPARQL::Token->dot;
		foreach my $t (@{ $self->triples }) {
			push(@tokens, $t->sparql_tokens->elements);
			push(@tokens, $dot);
		}
		return Attean::ListIterator->new( values => \@tokens, item_type => 'AtteanX::SPARQL::Token' );
	}
	
	sub algebra_as_string {
		my $self	= shift;
		return 'BGP { ' . join(', ', map { $_->as_string } @{ $self->triples }) . ' }';
	}
	
	sub elements {
		my $self	= shift;
		return @{ $self->triples };
	}
	
	sub canonicalize {
		my $self	= shift;
		my ($algebra, $mapping)	= $self->canonical_bgp_with_mapping();
		my @proj	= sort map { sprintf("(?v%03d AS $_)", $mapping->{$_}{id}) } grep { $mapping->{$_}{type} eq 'variable' } (keys %$mapping);
		foreach my $var (keys %$mapping) {
			$algebra	= Attean::Algebra::Extend->new(
				children	=> [$algebra],
				variable	=> variable($var),
				expression	=> Attean::ValueExpression->new( value => variable($mapping->{$var}{id}) ),
			);
		}
	}
	
	sub canonical_bgp_with_mapping {
		my $self	= shift;
		my ($triples, $mapping)	= $self->canonical_set_with_mapping();
		my $algebra	= Attean::Algebra::BGP->new( triples => $triples );
		return ($algebra, $mapping);
	}
	sub tree_attributes { return qw(triples) };
}

=item * L<Attean::Algebra::Service>

=cut

package Attean::Algebra::Service 0.038 {
	use AtteanX::SPARQL::Constants;

lib/Attean/Algebra.pm  view on Meta::CPAN

		return Attean::ListIterator->new( values => \@tokens, item_type => 'AtteanX::SPARQL::Token' );
	}
}

=item * L<Attean::Algebra::Path>

=cut

package Attean::Algebra::Path 0.038 {
	use Moo;
	use AtteanX::SPARQL::Constants;
	use AtteanX::SPARQL::Token;
	use Types::Standard qw(ArrayRef ConsumerOf);
	use namespace::clean;

	with 'Attean::API::Algebra', 'Attean::API::NullaryQueryTree';

	has 'subject' => (is => 'ro', isa => ConsumerOf['Attean::API::TermOrVariableOrTriplePattern'], required => 1);
	has 'path' => (is => 'ro', isa => ConsumerOf['Attean::API::PropertyPath'], required => 1);
	has 'object' => (is => 'ro', isa => ConsumerOf['Attean::API::TermOrVariableOrTriplePattern'], required => 1);

	sub in_scope_variables {
		my $self	= shift;
		my @vars	= map { $_->value } grep { $_->does('Attean::API::Variable') } ($self->subject, $self->object);
		return Set::Scalar->new(@vars)->elements;
	}

	sub tree_attributes { return qw(subject path object) };

	sub algebra_as_string {
		my $self	= shift;
		return 'Path { ' . join(', ', map { $_->as_string } map { $self->$_() } qw(subject path object)) . ' }';
	}

	sub sparql_tokens {
		my $self	= shift;
		my @tokens;
		foreach my $t ($self->subject, $self->path, $self->object) {
			push(@tokens, $t->sparql_tokens->elements);
		}
		return Attean::ListIterator->new( values => \@tokens, item_type => 'AtteanX::SPARQL::Token' );
	}
}

=item * L<Attean::Algebra::Group>

=cut

package Attean::Algebra::Group 0.038 {
	use utf8;
	use Moo;
	use Attean::API::Query;
	use AtteanX::SPARQL::Constants;
	use AtteanX::SPARQL::Token;
	use Types::Standard qw(ArrayRef ConsumerOf);
	use namespace::clean;
	
	with 'Attean::API::SPARQLQuerySerializable';
	with 'Attean::API::Algebra', 'Attean::API::UnaryQueryTree';

	has 'groupby' => (is => 'ro', isa => ArrayRef[ConsumerOf['Attean::API::Expression']]);
	has 'aggregates' => (is => 'ro', isa => ArrayRef[ConsumerOf['Attean::API::AggregateExpression']]);
	
	sub BUILD {
		my $self	= shift;
		foreach my $a (@{ $self->aggregates }) {
			my $op	= $a->operator;
			if ($op eq 'RANK') {
				if (scalar(@{ $self->aggregates }) > 1) {
					die "Cannot use both aggregates and RANKing in grouping operator";
				}
			}
		}
	}
	
	sub in_scope_variables {
		my $self	= shift;
		my $aggs	= $self->aggregates // [];
		my $groups	= $self->groupby // [];
		my %vars;
		foreach my $a (@$aggs) {
			$vars{ $a->variable->value }++;
		}
		foreach my $e (@$groups) {
			if ($e->isa('Attean::ValueExpression')) {
				my $value	= $e->value;
				if ($value->does('Attean::API::Variable')) {
					$vars{ $value->value }++;
				}
			}
		}
		
		return keys %vars;
	}
	
	sub algebra_as_string {
		my $self	= shift;
		my @aggs;
		my $aggs	= $self->aggregates // [];
		my $groups	= $self->groupby // [];
		foreach my $a (@$aggs) {
			my $v	= $a->variable->as_string;
			my $op	= $a->operator;
			my $d	= $a->distinct ? "DISTINCT " : '';
			my ($e)	= ((map { $_->as_string } @{ $a->children }), '');
			my $s	= "$v ← ${op}($d$e)";
			push(@aggs, $s);
		}
		return sprintf('Group { %s } aggregate { %s }', join(', ', map { $_->as_string() } @$groups), join(', ', @aggs));
	}

	sub tree_attributes { return qw(groupby aggregates) };
}

=item * L<Attean::Algebra::NegatedPropertySet>

=cut

package Attean::Algebra::NegatedPropertySet 0.038 {
	use Moo;
	use AtteanX::SPARQL::Constants;
	use AtteanX::SPARQL::Token;
	use Types::Standard qw(ArrayRef ConsumerOf);
	use namespace::clean;

	with 'Attean::API::PropertyPath';

	has 'predicates' => (is => 'ro', isa => ArrayRef[ConsumerOf['Attean::API::IRI']], required => 0, default => sub { [] });
	has 'reversed' => (is => 'ro', isa => ArrayRef[ConsumerOf['Attean::API::IRI']], required => 0, default => sub { [] });
	
	sub as_string {
		my $self	= shift;
		my @forward	= map { $_->ntriples_string } @{ $self->predicates };
		my @rev		= map { '^' . $_->ntriples_string } @{ $self->reversed };
		return sprintf("!(%s)", join('|', @forward, @rev));
	}
	sub algebra_as_string { return 'NPS' }
	sub tree_attributes { return qw(predicates reversed) };
	sub as_sparql {
		my $self	= shift;
		my @forward	= map { $_->as_sparql } @{ $self->predicates };
		my @rev		= map { '^' . $_->as_sparql } @{ $self->reversed };
		return sprintf("!(%s)", join('|', @forward, @rev));
	}

	sub sparql_tokens {
		my $self	= shift;
		my $bang	= AtteanX::SPARQL::Token->op_bang;
		my $or		= AtteanX::SPARQL::Token->path_or;
		my $hat		= AtteanX::SPARQL::Token->path_hat;
		my $l		= AtteanX::SPARQL::Token->lparen;
		my $r		= AtteanX::SPARQL::Token->rparen;

		my @tokens;
		push(@tokens, $bang, $l);
		foreach my $t (@{ $self->predicates }) {
			push(@tokens, $t->sparql_tokens->elements);
			push(@tokens, $or);
		}
		foreach my $t (@{ $self->reversed }) {
			push(@tokens, $hat);
			push(@tokens, $t->sparql_tokens->elements);
			push(@tokens, $or);
		}
		pop(@tokens); # remove last OR token
		push(@tokens, $r);
		return Attean::ListIterator->new( values => \@tokens, item_type => 'AtteanX::SPARQL::Token' );
	}
}

=item * L<Attean::Algebra::PredicatePath>

=cut

package Attean::Algebra::PredicatePath 0.038 {
	use Moo;
	use Types::Standard qw(ConsumerOf);
	use namespace::clean;

	with 'Attean::API::PropertyPath';

	has 'predicate' => (is => 'ro', isa => ConsumerOf['Attean::API::IRI'], required => 1);
	sub as_string {
		my $self	= shift;
		return $self->predicate->ntriples_string;
	}
	sub algebra_as_string {
		my $self	= shift;
		return 'Property Path ' . $self->as_string;

lib/Attean/Algebra.pm  view on Meta::CPAN

		push(@tokens, $plus);
		
		return Attean::ListIterator->new( values => \@tokens, item_type => 'AtteanX::SPARQL::Token' );
	}
}

=item * L<Attean::Algebra::ZeroOrOnePath>

=cut

package Attean::Algebra::ZeroOrOnePath 0.038 {
	use Moo;
	use AtteanX::SPARQL::Constants;
	use AtteanX::SPARQL::Token;
	use Types::Standard qw(ConsumerOf);
	use namespace::clean;

	with 'Attean::API::UnaryPropertyPath';

	sub postfix_name { return "?" }
	sub as_sparql {
		my $self	= shift;
		my ($path)	= @{ $self->children };
		return $self->path->as_sparql . '?';
	}

	sub sparql_tokens {
		my $self	= shift;
		my $q		= AtteanX::SPARQL::Token->question;
		my $l		= AtteanX::SPARQL::Token->lparen;
		my $r		= AtteanX::SPARQL::Token->rparen;

		my @tokens;
		foreach my $t (@{ $self->children }) {
			push(@tokens, $t->sparql_tokens->elements);
		}
		
		if (scalar(@tokens) > 1) {
			unshift(@tokens, $l);
			push(@tokens, $r);
		}
		push(@tokens, $q);
		
		return Attean::ListIterator->new( values => \@tokens, item_type => 'AtteanX::SPARQL::Token' );
	}
}

=item * L<Attean::Algebra::Table>

=cut

package Attean::Algebra::Table 0.038 {
	use Moo;
	use AtteanX::SPARQL::Constants;
	use AtteanX::SPARQL::Token;
	use Types::Standard qw(ArrayRef ConsumerOf);
	use namespace::clean;

	with 'Attean::API::Algebra', 'Attean::API::NullaryQueryTree';

	has variables => (is => 'ro', isa => ArrayRef[ConsumerOf['Attean::API::Variable']]);
	has rows => (is => 'ro', isa => ArrayRef[ConsumerOf['Attean::API::Result']]);

	sub in_scope_variables {
		my $self	= shift;
		return map { $_->value } @{ $self->variables };
	}
	sub tree_attributes { return qw(variables rows) };
	sub algebra_as_string { return 'Table' }

	sub sparql_tokens {
		my $self	= shift;
		my $values	= AtteanX::SPARQL::Token->keyword('VALUES');
		my $lparen	= AtteanX::SPARQL::Token->lparen;
		my $rparen	= AtteanX::SPARQL::Token->rparen;
		my $lbrace	= AtteanX::SPARQL::Token->lbrace;
		my $rbrace	= AtteanX::SPARQL::Token->rbrace;

		my @tokens;
		push(@tokens, $values);
		push(@tokens, $lparen);
		foreach my $var (@{ $self->variables }) {
			push(@tokens, $var->sparql_tokens->elements);
		}
		push(@tokens, $rparen);
		
		push(@tokens, $lbrace);
		foreach my $row (@{ $self->rows }) {
			push(@tokens, $lparen);
			foreach my $val ($row->values) {
				# TODO: verify correct serialization of UNDEF
				push(@tokens, $val->sparql_tokens->elements);
			}
			push(@tokens, $rparen);
		}
		push(@tokens, $rbrace);
		
		return Attean::ListIterator->new( values => \@tokens, item_type => 'AtteanX::SPARQL::Token' );
	}
}

=item * L<Attean::Algebra::Ask>

=cut

package Attean::Algebra::Ask 0.038 {
	use Moo;
	use AtteanX::SPARQL::Constants;
	use AtteanX::SPARQL::Token;
	use namespace::clean;
	
	with 'Attean::API::SPARQLQuerySerializable';
	with 'Attean::API::Algebra', 'Attean::API::UnaryQueryTree';
	
	sub in_scope_variables { return; }

	sub algebra_as_string { return 'Ask' }
}

=item * L<Attean::Algebra::Construct>

=cut

package Attean::Algebra::Construct 0.038 {
	use Moo;
	use AtteanX::SPARQL::Constants;
	use AtteanX::SPARQL::Token;
	use Types::Standard qw(ArrayRef ConsumerOf);
	use namespace::clean;
	
	with 'Attean::API::SPARQLQuerySerializable';
	with 'Attean::API::Algebra', 'Attean::API::UnaryQueryTree';

	has 'triples' => (is => 'ro', isa => ArrayRef[ConsumerOf['Attean::API::TriplePattern']]);

	sub in_scope_variables { return qw(subject predicate object); }
	sub tree_attributes { return; }
	sub algebra_as_string {
		my $self	= shift;
		my $triples	= $self->triples;
		return sprintf('Construct { %s }', join(' . ', map { $_->as_string } @$triples));
	}
}

=item * L<Attean::Algebra::Describe>

=cut

package Attean::Algebra::Describe 0.038 {
	use Moo;
	use AtteanX::SPARQL::Constants;
	use AtteanX::SPARQL::Token;
	use Types::Standard qw(ArrayRef ConsumerOf);
	use namespace::clean;
	
	with 'Attean::API::SPARQLQuerySerializable';
	with 'Attean::API::Algebra', 'Attean::API::UnaryQueryTree';

	has 'terms' => (is => 'ro', isa => ArrayRef[ConsumerOf['Attean::API::TermOrVariable']]);

	sub in_scope_variables { return qw(subject predicate object); }
	sub tree_attributes { return; }
	sub algebra_as_string { return 'Describe' }
}

=item * L<Attean::Algebra::Load>

=cut

package Attean::Algebra::Load 0.038 {
	use Moo;
	use AtteanX::SPARQL::Constants;
	use AtteanX::SPARQL::Token;
	use Types::Standard qw(Bool ConsumerOf);
	use namespace::clean;
	
	with 'Attean::API::Algebra', 'Attean::API::NullaryQueryTree';

	has 'silent' => (is => 'ro', isa => Bool, default => 0);
	has 'url' => (is => 'ro', isa => ConsumerOf['Attean::API::IRI'], required => 1);
	has 'graph' => (is => 'ro', isa => ConsumerOf['Attean::API::Term'], predicate => 'has_graph');

	sub in_scope_variables { return; }
	sub tree_attributes { return; }
	sub algebra_as_string {
		my $self	= shift;
		return 'Load ' . $self->url->as_string;
	}

	sub sparql_tokens {
		my $self	= shift;

		my @tokens;
		push(@tokens, AtteanX::SPARQL::Token->keyword('LOAD'));
		if ($self->silent) {
			push(@tokens, AtteanX::SPARQL::Token->keyword('SILENT'));
		}
		push(@tokens, $self->url->sparql_tokens->elements);
		
		if ($self->has_graph) {
			push(@tokens, AtteanX::SPARQL::Token->keyword('INTO'));
			push(@tokens, AtteanX::SPARQL::Token->keyword('GRAPH'));
			push(@tokens, $self->graph->sparql_tokens->elements);
		}
		return Attean::ListIterator->new( values => \@tokens, item_type => 'AtteanX::SPARQL::Token' );
	}
}

=item * L<Attean::Algebra::Clear>

=cut

package Attean::Algebra::Clear 0.038 {
	use Moo;
	use Scalar::Util qw(blessed);
	use AtteanX::SPARQL::Constants;
	use AtteanX::SPARQL::Token;
	use Types::Standard qw(Enum Bool ConsumerOf);
	use namespace::clean;

lib/Attean/Algebra.pm  view on Meta::CPAN


	has 'silent' => (is => 'ro', isa => Bool, default => 0);
	has 'drop_source' => (is => 'ro', isa => Bool, default => 0);
	has 'drop_destination' => (is => 'ro', isa => Bool, default => 0);
	
	has 'source' => (is => 'ro', isa => ConsumerOf['Attean::API::Term'], predicate => 'has_source');
	has 'destination' => (is => 'ro', isa => ConsumerOf['Attean::API::Term'], predicate => 'has_destination');

	sub in_scope_variables { return; }
	sub tree_attributes { return; }
	sub algebra_as_string {
		my $self	= shift;
		return ($self->drop_source and $self->drop_destination) ? 'Move' : ($self->drop_destination) ? 'Copy' : 'Add';
	}

	sub sparql_tokens {
		my $self	= shift;

		my @tokens;
		my $op	= ($self->drop_source and $self->drop_destination) ? 'MOVE' : ($self->drop_destination) ? 'COPY' : 'ADD';
		push(@tokens, AtteanX::SPARQL::Token->keyword($op));
		if ($self->silent) {
			push(@tokens, AtteanX::SPARQL::Token->keyword('SILENT'));
		}
		
		if ($self->has_source) {
			push(@tokens, AtteanX::SPARQL::Token->keyword('GRAPH'));
			push(@tokens, $self->source->sparql_tokens->elements);
		} else {
			push(@tokens, AtteanX::SPARQL::Token->keyword('DEFAULT'));
		}

		push(@tokens, AtteanX::SPARQL::Token->keyword('TO'));
		
		if ($self->has_destination) {
			push(@tokens, AtteanX::SPARQL::Token->keyword('GRAPH'));
			push(@tokens, $self->destination->sparql_tokens->elements);
		} else {
			push(@tokens, AtteanX::SPARQL::Token->keyword('DEFAULT'));
		}
		
		return Attean::ListIterator->new( values => \@tokens, item_type => 'AtteanX::SPARQL::Token' );
	}
}

=item * L<Attean::Algebra::Modify>

=cut

package Attean::Algebra::Modify 0.038 {
	use Moo;
	use Scalar::Util qw(blessed);
	use AtteanX::SPARQL::Constants;
	use AtteanX::SPARQL::Token;
	use List::Util qw(all any);
	use Types::Standard qw(HashRef ArrayRef ConsumerOf);
	use namespace::clean;
	
	with 'Attean::API::Algebra', 'Attean::API::QueryTree';

	has 'dataset' => (is => 'ro', isa => HashRef, default => sub { +{} });
	has 'insert' => (is => 'ro', isa => ArrayRef[ConsumerOf['Attean::API::TripleOrQuadPattern']], default => sub { [] });
	has 'delete' => (is => 'ro', isa => ArrayRef[ConsumerOf['Attean::API::TripleOrQuadPattern']], default => sub { [] });

	sub in_scope_variables { return; }
	sub tree_attributes { return; }

	sub _op_type {
		my $self	= shift;
		my $i		= scalar(@{ $self->insert });
		my $d		= scalar(@{ $self->delete });
		my $w		= scalar(@{ $self->children });
		my $ig		= all { $_->is_ground } @{ $self->insert };
		my $dg		= all { $_->is_ground } @{ $self->delete };
		if ($i and not $d) {
			# INSERT
			return ($ig and not $w) ? 'ID' : 'I';
		} elsif ($d and not $i) {
			# DELETE
			return ($dg and not $w) ? 'DD' : 'D';
		} else {
			# INSERT + DELETE
			return 'U'
		}
	}
	
	around 'blank_nodes' => sub {
		my $orig	= shift;
		my $self	= shift;
		my @blanks	= $orig->($self, @_);
		my %seen	= map { $_->value => 1 } @blanks;
		foreach my $data ($self->insert, $self->delete) {
			my @triples	= @{ $data };
			my @b	= grep { $_->does('Attean::API::Blank') } map { $_->values } @triples;
			push(@blanks, grep { not $seen{$_->value}++ } @b);
		}
		return @blanks;
	};
	
	sub algebra_as_string {
		my $self	= shift;
		my $level	= shift;
		my $indent	= '  ' x ($level + 1);
		state $S	= {
			'ID'	=> 'Insert Data',
			'I'		=> 'Insert',
			'DD'	=> 'Delete Data',
			'D'		=> 'Delete',
			'U'		=> 'Update',
		};
		my $op	= $self->_op_type();
		my $s	= $S->{ $op };
		my @data;
		my $ic	= scalar(@{ $self->insert });
		my $dc	= scalar(@{ $self->delete });
		if ($ic) {
			my $name	= $dc ? 'Insert Data' : 'Data';
			push(@data, [$name, $self->insert]);
		}
		if ($dc) {
			my $name	= $ic ? 'Delete Data' : 'Data';
			push(@data, [$name, $self->delete]);
		}



( run in 0.712 second using v1.01-cache-2.11-cpan-8f98c5d2c55 )