sparql 1.0.6 → 1.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +11 -4
- data/VERSION +1 -1
- data/lib/sparql/algebra/extensions.rb +36 -0
- data/lib/sparql/algebra/operator.rb +197 -87
- data/lib/sparql/algebra/operator/abs.rb +31 -0
- data/lib/sparql/algebra/operator/base.rb +1 -0
- data/lib/sparql/algebra/operator/bnode.rb +88 -0
- data/lib/sparql/algebra/operator/bound.rb +2 -1
- data/lib/sparql/algebra/operator/ceil.rb +31 -0
- data/lib/sparql/algebra/operator/coalesce.rb +65 -0
- data/lib/sparql/algebra/operator/concat.rb +49 -0
- data/lib/sparql/algebra/operator/contains.rb +44 -0
- data/lib/sparql/algebra/operator/dataset.rb +11 -48
- data/lib/sparql/algebra/operator/datatype.rb +4 -2
- data/lib/sparql/algebra/operator/day.rb +31 -0
- data/lib/sparql/algebra/operator/encode_for_uri.rb +38 -0
- data/lib/sparql/algebra/operator/extend.rb +31 -2
- data/lib/sparql/algebra/operator/floor.rb +33 -0
- data/lib/sparql/algebra/operator/hours.rb +31 -0
- data/lib/sparql/algebra/operator/if.rb +55 -0
- data/lib/sparql/algebra/operator/in.rb +68 -0
- data/lib/sparql/algebra/operator/iri.rb +40 -0
- data/lib/sparql/algebra/operator/is_numeric.rb +41 -0
- data/lib/sparql/algebra/operator/lang_matches.rb +2 -2
- data/lib/sparql/algebra/operator/lcase.rb +31 -0
- data/lib/sparql/algebra/operator/md5.rb +34 -0
- data/lib/sparql/algebra/operator/minutes.rb +31 -0
- data/lib/sparql/algebra/operator/month.rb +31 -0
- data/lib/sparql/algebra/operator/not.rb +2 -2
- data/lib/sparql/algebra/operator/notin.rb +70 -0
- data/lib/sparql/algebra/operator/now.rb +29 -0
- data/lib/sparql/algebra/operator/order.rb +9 -13
- data/lib/sparql/algebra/operator/rand.rb +24 -0
- data/lib/sparql/algebra/operator/replace.rb +81 -0
- data/lib/sparql/algebra/operator/round.rb +31 -0
- data/lib/sparql/algebra/operator/seconds.rb +31 -0
- data/lib/sparql/algebra/operator/sha1.rb +34 -0
- data/lib/sparql/algebra/operator/sha256.rb +34 -0
- data/lib/sparql/algebra/operator/sha384.rb +34 -0
- data/lib/sparql/algebra/operator/sha512.rb +34 -0
- data/lib/sparql/algebra/operator/strafter.rb +57 -0
- data/lib/sparql/algebra/operator/strbefore.rb +59 -0
- data/lib/sparql/algebra/operator/strdt.rb +33 -0
- data/lib/sparql/algebra/operator/strends.rb +46 -0
- data/lib/sparql/algebra/operator/strlang.rb +34 -0
- data/lib/sparql/algebra/operator/strlen.rb +34 -0
- data/lib/sparql/algebra/operator/strstarts.rb +46 -0
- data/lib/sparql/algebra/operator/struuid.rb +32 -0
- data/lib/sparql/algebra/operator/substr.rb +80 -0
- data/lib/sparql/algebra/operator/timezone.rb +34 -0
- data/lib/sparql/algebra/operator/tz.rb +31 -0
- data/lib/sparql/algebra/operator/ucase.rb +31 -0
- data/lib/sparql/algebra/operator/uuid.rb +32 -0
- data/lib/sparql/algebra/operator/year.rb +31 -0
- data/lib/sparql/grammar/parser11.rb +128 -70
- data/lib/sparql/grammar/terminals11.rb +4 -5
- metadata +62 -7
@@ -0,0 +1,34 @@
|
|
1
|
+
module SPARQL; module Algebra
|
2
|
+
class Operator
|
3
|
+
##
|
4
|
+
# The SPARQL logical `timezone` operator.
|
5
|
+
#
|
6
|
+
# @example
|
7
|
+
# (prefix ((: <http://example.org/>))
|
8
|
+
# (project (?s ?x)
|
9
|
+
# (extend ((?x (timezone ?date)))
|
10
|
+
# (bgp (triple ?s :date ?date)))))
|
11
|
+
#
|
12
|
+
# @see http://www.w3.org/TR/sparql11-query/#func-timezone
|
13
|
+
class Timezone < Operator::Unary
|
14
|
+
include Evaluatable
|
15
|
+
|
16
|
+
NAME = :timezone
|
17
|
+
|
18
|
+
##
|
19
|
+
# Returns the timezone part of arg as an xsd:dayTimeDuration. Raises an error if there is no timezone.
|
20
|
+
#
|
21
|
+
# This function corresponds to fn:timezone-from-dateTime except for the treatment of literals with no timezone.
|
22
|
+
#
|
23
|
+
# @param [RDF::Literal] operand
|
24
|
+
# the operand
|
25
|
+
# @return [RDF::Literal]
|
26
|
+
# @raise [TypeError] if the operand is not a simple literal
|
27
|
+
def apply(operand)
|
28
|
+
raise TypeError, "expected an RDF::Literal::DateTime, but got #{operand.inspect}" unless operand.is_a?(RDF::Literal::DateTime)
|
29
|
+
raise TypeError, "literal has no timezone" unless res = operand.timezone
|
30
|
+
res
|
31
|
+
end
|
32
|
+
end # Timezone
|
33
|
+
end # Operator
|
34
|
+
end; end # SPARQL::Algebra
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module SPARQL; module Algebra
|
2
|
+
class Operator
|
3
|
+
##
|
4
|
+
# The SPARQL logical `tz` operator.
|
5
|
+
#
|
6
|
+
# @example
|
7
|
+
# (prefix ((: <http://example.org/>))
|
8
|
+
# (project (?s ?x)
|
9
|
+
# (extend ((?x (tz ?date)))
|
10
|
+
# (bgp (triple ?s :date ?date)))))
|
11
|
+
#
|
12
|
+
# @see http://www.w3.org/TR/sparql11-query/#func-tz
|
13
|
+
class TZ < Operator::Unary
|
14
|
+
include Evaluatable
|
15
|
+
|
16
|
+
NAME = :tz
|
17
|
+
|
18
|
+
##
|
19
|
+
# Returns the timezone part of arg as a simple literal. Returns the empty string if there is no timezone.
|
20
|
+
#
|
21
|
+
# @param [RDF::Literal] operand
|
22
|
+
# the operand
|
23
|
+
# @return [RDF::Literal]
|
24
|
+
# @raise [TypeError] if the operand is not a simple literal
|
25
|
+
def apply(operand)
|
26
|
+
raise TypeError, "expected an RDF::Literal::DateTime, but got #{operand.inspect}" unless operand.is_a?(RDF::Literal::DateTime)
|
27
|
+
operand.tz
|
28
|
+
end
|
29
|
+
end # TZ
|
30
|
+
end # Operator
|
31
|
+
end; end # SPARQL::Algebra
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module SPARQL; module Algebra
|
2
|
+
class Operator
|
3
|
+
##
|
4
|
+
# The SPARQL logical `ucase` operator.
|
5
|
+
#
|
6
|
+
# @example
|
7
|
+
# (ucase ?x)
|
8
|
+
#
|
9
|
+
# @see http://www.w3.org/TR/sparql11-query/#func-ucase
|
10
|
+
# @see http://www.w3.org/TR/xpath-functions/#func-ucase
|
11
|
+
class UCase < Operator::Unary
|
12
|
+
include Evaluatable
|
13
|
+
|
14
|
+
NAME = :ucase
|
15
|
+
|
16
|
+
##
|
17
|
+
# The LCASE function corresponds to the XPath fn:lower-case function. It returns a string literal whose lexical form is the lower case of the lexcial form of the argument.
|
18
|
+
#
|
19
|
+
# @param [RDF::Literal] operand
|
20
|
+
# the operand
|
21
|
+
# @return [RDF::Literal] literal of same type
|
22
|
+
# @raise [TypeError] if the operand is not a literal value
|
23
|
+
def apply(operand)
|
24
|
+
case operand
|
25
|
+
when RDF::Literal then RDF::Literal(operand.to_s.upcase, :datatype => operand.datatype, :language => operand.language)
|
26
|
+
else raise TypeError, "expected an RDF::Literal::Numeric, but got #{operand.inspect}"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end # UCase
|
30
|
+
end # Operator
|
31
|
+
end; end # SPARQL::Algebra
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
|
3
|
+
module SPARQL; module Algebra
|
4
|
+
class Operator
|
5
|
+
##
|
6
|
+
# The SPARQL `uuid` function.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# (prefix ((: <http://example.org/>)
|
10
|
+
# (xsd: <http://www.w3.org/2001/XMLSchema#>))
|
11
|
+
# (project (?length)
|
12
|
+
# (extend ((?length (strlen (str ?uuid))))
|
13
|
+
# (filter (&& (isIRI ?uuid) (regex (str ?uuid) "^urn:uuid:[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}$" "i"))
|
14
|
+
# (extend ((?uuid (uuid)))
|
15
|
+
# (bgp))))))
|
16
|
+
#
|
17
|
+
# @see http://www.w3.org/TR/sparql11-query/#func-uuid
|
18
|
+
class UUID < Operator::Nullary
|
19
|
+
include Evaluatable
|
20
|
+
|
21
|
+
NAME = :uuid
|
22
|
+
|
23
|
+
##
|
24
|
+
# Return a fresh IRI from the UUID URN scheme. Each call of UUID() returns a different UUID. It must not be the "nil" UUID (all zeroes). The variant and version of the UUID is implementation dependent.
|
25
|
+
#
|
26
|
+
# @return [RDF::URI]
|
27
|
+
def apply
|
28
|
+
RDF::URI("urn:uuid:#{SecureRandom.uuid}")
|
29
|
+
end
|
30
|
+
end # UUID
|
31
|
+
end # Operator
|
32
|
+
end; end # SPARQL::Algebra
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module SPARQL; module Algebra
|
2
|
+
class Operator
|
3
|
+
##
|
4
|
+
# The SPARQL logical `year` operator.
|
5
|
+
#
|
6
|
+
# @example
|
7
|
+
# (prefix ((: <http://example.org/>))
|
8
|
+
# (project (?s ?x)
|
9
|
+
# (extend ((?x (year ?date)))
|
10
|
+
# (bgp (triple ?s :date ?date)))))
|
11
|
+
#
|
12
|
+
# @see http://www.w3.org/TR/sparql11-query/#func-year
|
13
|
+
class Year < Operator::Unary
|
14
|
+
include Evaluatable
|
15
|
+
|
16
|
+
NAME = :year
|
17
|
+
|
18
|
+
##
|
19
|
+
# Returns the year part of arg as an integer.
|
20
|
+
#
|
21
|
+
# @param [RDF::Literal] operand
|
22
|
+
# the operand
|
23
|
+
# @return [RDF::Literal]
|
24
|
+
# @raise [TypeError] if the operand is not a simple literal
|
25
|
+
def apply(operand)
|
26
|
+
raise TypeError, "expected an RDF::Literal::DateTime, but got #{operand.inspect}" unless operand.is_a?(RDF::Literal::DateTime)
|
27
|
+
RDF::Literal(operand.object.year)
|
28
|
+
end
|
29
|
+
end # Year
|
30
|
+
end # Operator
|
31
|
+
end; end # SPARQL::Algebra
|
@@ -16,7 +16,7 @@ module SPARQL::Grammar
|
|
16
16
|
# Builtin functions
|
17
17
|
BUILTINS = %w{
|
18
18
|
ABS BNODE CEIL COALESCE CONCAT
|
19
|
-
CONTAINS DATATYPE DAY ENCODE_FOR_URI
|
19
|
+
CONTAINS DATATYPE DAY ENCODE_FOR_URI
|
20
20
|
FLOOR HOURS IF IRI LANGMATCHES LANG LCASE
|
21
21
|
MD5 MINUTES MONTH NOW RAND ROUND SECONDS
|
22
22
|
SHA1 SHA224 SHA256 SHA384 SHA512
|
@@ -25,8 +25,9 @@ module SPARQL::Grammar
|
|
25
25
|
isBLANK isIRI isURI isLITERAL isNUMERIC sameTerm
|
26
26
|
}.map {|s| s.downcase.to_sym}.freeze
|
27
27
|
|
28
|
-
BUILTIN_RULES = [:regex, :substr, :replace, :exists, :
|
28
|
+
BUILTIN_RULES = [:aggregate, :regex, :substr, :replace, :exists, :notexists].freeze
|
29
29
|
|
30
|
+
AGGREGATE_RULES = [:count, :sum, :min, :max, :avg, :sample, :group_concat]
|
30
31
|
##
|
31
32
|
# Any additional options for the parser.
|
32
33
|
#
|
@@ -173,12 +174,12 @@ module SPARQL::Grammar
|
|
173
174
|
when /ASC|DESC/ then add_prod_datum(:OrderDirection, token.value.downcase.to_sym)
|
174
175
|
when /DISTINCT|REDUCED/ then add_prod_datum(:DISTINCT_REDUCED, token.value.downcase.to_sym)
|
175
176
|
when %r{
|
176
|
-
ABS|BNODE|BOUND|CEIL|COALESCE|CONCAT
|
177
|
-
|CONTAINS|DATATYPE|DAY|ENCODE_FOR_URI|EXISTS
|
178
|
-
|FLOOR|HOURS|IF|IRI|LANGMATCHES|LANG|LCASE
|
179
|
-
|MD5|MINUTES|MONTH|NOW|RAND|REPLACE|ROUND|SECONDS
|
177
|
+
ABS|AVG|BNODE|BOUND|CEIL|COALESCE|CONCAT
|
178
|
+
|CONTAINS|COUNT|DATATYPE|DAY|ENCODE_FOR_URI|EXISTS
|
179
|
+
|FLOOR|HOURS|IF|GROUP_CONCAT|IRI|LANGMATCHES|LANG|LCASE
|
180
|
+
|MAX|MD5|MINUTES|MIN|MONTH|NOW|RAND|REPLACE|ROUND|SAMPLE|SECONDS|SEPARATOR
|
180
181
|
|SHA1|SHA224|SHA256|SHA384|SHA512
|
181
|
-
|STRAFTER|STRBEFORE|STRDT|STRENDS|STRLANG|STRLEN|STRSTARTS|STRUUID|SUBSTR|STR
|
182
|
+
|STRAFTER|STRBEFORE|STRDT|STRENDS|STRLANG|STRLEN|STRSTARTS|STRUUID|SUBSTR|STR|SUM
|
182
183
|
|TIMEZONE|TZ|UCASE|URI|UUID|YEAR
|
183
184
|
|isBLANK|isIRI|isURI|isLITERAL|isNUMERIC|sameTerm
|
184
185
|
}x
|
@@ -245,7 +246,6 @@ module SPARQL::Grammar
|
|
245
246
|
# [9.8] _SelectClause_8 ::= ( '(' Expression 'AS' Var ')' )
|
246
247
|
production(:_SelectClause_8) do |input, data, callback|
|
247
248
|
add_prod_datum :extend, [data[:Expression].unshift(data[:Var].first)]
|
248
|
-
add_prod_datum :Var, data[:Var]
|
249
249
|
end
|
250
250
|
|
251
251
|
# [10] ConstructQuery ::= 'CONSTRUCT'
|
@@ -290,13 +290,25 @@ module SPARQL::Grammar
|
|
290
290
|
# [18] SolutionModifier ::= GroupClause? HavingClause? OrderClause? LimitOffsetClauses?
|
291
291
|
|
292
292
|
# [19] GroupClause ::= 'GROUP' 'BY' GroupCondition+
|
293
|
-
|
294
|
-
|
293
|
+
production(:GroupClause) do |input, data, callback|
|
294
|
+
add_prod_data :group, data[:GroupCondition]
|
295
|
+
end
|
295
296
|
|
296
297
|
# [20] GroupCondition ::= BuiltInCall | FunctionCall
|
297
298
|
# | '(' Expression ( 'AS' Var )? ')' | Var
|
298
|
-
|
299
|
-
|
299
|
+
production(:GroupCondition) do |input, data, callback|
|
300
|
+
add_prod_datum :GroupCondition, data.values.first
|
301
|
+
end
|
302
|
+
|
303
|
+
# _GroupCondition_1 ::= '(' Expression ( 'AS' Var )? ')'
|
304
|
+
production(:_GroupCondition_1) do |input, data, callback|
|
305
|
+
cond = if data[:Var]
|
306
|
+
[data[:Expression].unshift(data[:Var].first)]
|
307
|
+
else
|
308
|
+
data[:Expression]
|
309
|
+
end
|
310
|
+
add_prod_datum(:GroupCondition, cond)
|
311
|
+
end
|
300
312
|
|
301
313
|
# [21] HavingClause ::= 'HAVING' HavingCondition+
|
302
314
|
#production(:GroupClause) do |input, data, callback|
|
@@ -797,7 +809,7 @@ module SPARQL::Grammar
|
|
797
809
|
# [119] PrimaryExpression ::= BrackettedExpression | BuiltInCall
|
798
810
|
# | iriOrFunction | RDFLiteral
|
799
811
|
# | NumericLiteral | BooleanLiteral
|
800
|
-
# | Var
|
812
|
+
# | Var
|
801
813
|
production(:PrimaryExpression) do |input, data, callback|
|
802
814
|
if data[:Expression]
|
803
815
|
add_prod_datum(:Expression, data[:Expression])
|
@@ -817,56 +829,62 @@ module SPARQL::Grammar
|
|
817
829
|
add_prod_datum(:UnaryExpression, data[:UnaryExpression])
|
818
830
|
end
|
819
831
|
|
820
|
-
# [
|
821
|
-
#
|
822
|
-
#
|
823
|
-
#
|
824
|
-
#
|
825
|
-
#
|
826
|
-
#
|
827
|
-
#
|
828
|
-
#
|
829
|
-
#
|
830
|
-
#
|
831
|
-
#
|
832
|
-
#
|
833
|
-
#
|
834
|
-
#
|
835
|
-
#
|
836
|
-
#
|
837
|
-
#
|
838
|
-
#
|
839
|
-
#
|
840
|
-
#
|
841
|
-
#
|
842
|
-
#
|
843
|
-
#
|
844
|
-
#
|
845
|
-
#
|
846
|
-
#
|
847
|
-
#
|
848
|
-
#
|
849
|
-
#
|
850
|
-
#
|
851
|
-
#
|
852
|
-
#
|
853
|
-
#
|
854
|
-
#
|
855
|
-
#
|
856
|
-
#
|
857
|
-
#
|
858
|
-
#
|
859
|
-
#
|
860
|
-
#
|
861
|
-
#
|
862
|
-
#
|
863
|
-
#
|
864
|
-
#
|
865
|
-
#
|
866
|
-
#
|
867
|
-
#
|
868
|
-
#
|
869
|
-
#
|
832
|
+
# [121] BuiltInCall ::= Aggregate
|
833
|
+
# | 'STR' '(' Expression ')'
|
834
|
+
# | 'LANG' '(' Expression ')'
|
835
|
+
# | 'LANGMATCHES' '(' Expression ',' Expression ')'
|
836
|
+
# | 'DATATYPE' '(' Expression ')'
|
837
|
+
# | 'BOUND' '(' Var ')'
|
838
|
+
# | 'IRI' '(' Expression ')'
|
839
|
+
# | 'URI' '(' Expression ')'
|
840
|
+
# | 'BNODE' ( '(' Expression ')' | NIL )
|
841
|
+
# | 'RAND' NIL
|
842
|
+
# | 'ABS' '(' Expression ')'
|
843
|
+
# | 'CEIL' '(' Expression ')'
|
844
|
+
# | 'FLOOR' '(' Expression ')'
|
845
|
+
# | 'ROUND' '(' Expression ')'
|
846
|
+
# | 'CONCAT' ExpressionList
|
847
|
+
# | SubstringExpression
|
848
|
+
# | 'STRLEN' '(' Expression ')'
|
849
|
+
# | StrReplaceExpression
|
850
|
+
# | 'UCASE' '(' Expression ')'
|
851
|
+
# | 'LCASE' '(' Expression ')'
|
852
|
+
# | 'ENCODE_FOR_URI' '(' Expression ')'
|
853
|
+
# | 'CONTAINS' '(' Expression ',' Expression ')'
|
854
|
+
# | 'STRSTARTS' '(' Expression ',' Expression ')'
|
855
|
+
# | 'STRENDS' '(' Expression ',' Expression ')'
|
856
|
+
# | 'STRBEFORE' '(' Expression ',' Expression ')'
|
857
|
+
# | 'STRAFTER' '(' Expression ',' Expression ')'
|
858
|
+
# | 'YEAR' '(' Expression ')'
|
859
|
+
# | 'MONTH' '(' Expression ')'
|
860
|
+
# | 'DAY' '(' Expression ')'
|
861
|
+
# | 'HOURS' '(' Expression ')'
|
862
|
+
# | 'MINUTES' '(' Expression ')'
|
863
|
+
# | 'SECONDS' '(' Expression ')'
|
864
|
+
# | 'TIMEZONE' '(' Expression ')'
|
865
|
+
# | 'TZ' '(' Expression ')'
|
866
|
+
# | 'NOW' NIL
|
867
|
+
# | 'UUID' NIL
|
868
|
+
# | 'STRUUID' NIL
|
869
|
+
# | 'MD5' '(' Expression ')'
|
870
|
+
# | 'SHA1' '(' Expression ')'
|
871
|
+
# | 'SHA224' '(' Expression ')'
|
872
|
+
# | 'SHA256' '(' Expression ')'
|
873
|
+
# | 'SHA384' '(' Expression ')'
|
874
|
+
# | 'SHA512' '(' Expression ')'
|
875
|
+
# | 'COALESCE' ExpressionList
|
876
|
+
# | 'IF' '(' Expression ',' Expression ',' Expression ')'
|
877
|
+
# | 'STRLANG' '(' Expression ',' Expression ')'
|
878
|
+
# | 'STRDT' '(' Expression ',' Expression ')'
|
879
|
+
# | 'sameTerm' '(' Expression ',' Expression ')'
|
880
|
+
# | 'isIRI' '(' Expression ')'
|
881
|
+
# | 'isURI' '(' Expression ')'
|
882
|
+
# | 'isBLANK' '(' Expression ')'
|
883
|
+
# | 'isLITERAL' '(' Expression ')'
|
884
|
+
# | 'isNUMERIC' '(' Expression ')'
|
885
|
+
# | RegexExpression
|
886
|
+
# | ExistsFunc
|
887
|
+
# | NotExistsFunc
|
870
888
|
production(:BuiltInCall) do |input, data, callback|
|
871
889
|
if builtin = data.keys.detect {|k| BUILTINS.include?(k)}
|
872
890
|
add_prod_datum(:BuiltInCall,
|
@@ -875,6 +893,8 @@ module SPARQL::Grammar
|
|
875
893
|
unshift(builtin)))
|
876
894
|
elsif builtin_rule = data.keys.detect {|k| BUILTIN_RULES.include?(k)}
|
877
895
|
add_prod_datum(:BuiltInCall, SPARQL::Algebra::Expression.for(data[builtin_rule].unshift(builtin_rule)))
|
896
|
+
elsif aggregate_rule = data.keys.detect {|k| AGGREGATE_RULES.include?(k)}
|
897
|
+
add_prod_datum(:BuiltInCall, data[aggregate_rule].first)
|
878
898
|
elsif data[:bound]
|
879
899
|
add_prod_datum(:BuiltInCall, SPARQL::Algebra::Expression.for(data[:Var].unshift(:bound)))
|
880
900
|
elsif data[:BuiltInCall]
|
@@ -910,7 +930,25 @@ module SPARQL::Grammar
|
|
910
930
|
|
911
931
|
# [126] NotExistsFunc ::= 'NOT' 'EXISTS' GroupGraphPattern
|
912
932
|
production(:NotExistsFunc) do |input, data, callback|
|
913
|
-
add_prod_datum(:
|
933
|
+
add_prod_datum(:notexists, data[:query])
|
934
|
+
end
|
935
|
+
|
936
|
+
# [127] Aggregate ::= 'COUNT' '(' 'DISTINCT'? ( '*' | Expression ) ')'
|
937
|
+
# | 'SUM' '(' 'DISTINCT'? Expression ')'
|
938
|
+
# | 'MIN' '(' 'DISTINCT'? Expression ')'
|
939
|
+
# | 'MAX' '(' 'DISTINCT'? Expression ')'
|
940
|
+
# | 'AVG' '(' 'DISTINCT'? Expression ')'
|
941
|
+
# | 'SAMPLE' '(' 'DISTINCT'? Expression ')'
|
942
|
+
# | 'GROUP_CONCAT' '(' 'DISTINCT'? Expression
|
943
|
+
# ( ';' 'SEPARATOR' '=' String )? ')'
|
944
|
+
production(:Aggregate) do |input, data, callback|
|
945
|
+
if aggregate_rule = data.keys.detect {|k| AGGREGATE_RULES.include?(k)}
|
946
|
+
parts = [aggregate_rule]
|
947
|
+
parts << [:separator, data[:string].first] if data[:separator] && data[:string]
|
948
|
+
parts << :distinct if data[:DISTINCT_REDUCED]
|
949
|
+
parts << data[:Expression].first if data[:Expression]
|
950
|
+
add_prod_data(aggregate_rule, SPARQL::Algebra::Expression.for(parts))
|
951
|
+
end
|
914
952
|
end
|
915
953
|
|
916
954
|
# [128] iriOrFunction ::= iri ArgList?
|
@@ -988,8 +1026,8 @@ module SPARQL::Grammar
|
|
988
1026
|
@input.force_encoding(Encoding::UTF_8)
|
989
1027
|
@options = {:anon_base => "b0", :validate => false}.merge(options)
|
990
1028
|
@options[:debug] ||= case
|
991
|
-
when
|
992
|
-
when
|
1029
|
+
when options[:progress] then 2
|
1030
|
+
when options[:validate] then 1
|
993
1031
|
end
|
994
1032
|
|
995
1033
|
debug("base IRI") {base_uri.inspect}
|
@@ -1311,15 +1349,35 @@ module SPARQL::Grammar
|
|
1311
1349
|
end
|
1312
1350
|
|
1313
1351
|
# Merge query modifiers, datasets, and projections
|
1352
|
+
#
|
1353
|
+
# This includes tranforming aggregates if also used with a GROUP BY
|
1354
|
+
#
|
1355
|
+
# @see http://www.w3.org/TR/sparql11-query/#convertGroupAggSelectExpressions
|
1314
1356
|
def merge_modifiers(data)
|
1315
1357
|
query = data[:query] ? data[:query].first : SPARQL::Algebra::Operator::BGP.new
|
1316
|
-
|
1358
|
+
|
1359
|
+
vars = data[:Var] || []
|
1360
|
+
order = data[:order] ? data[:order].first : []
|
1361
|
+
|
1317
1362
|
# Add datasets and modifiers in order
|
1318
|
-
|
1363
|
+
if data[:group]
|
1364
|
+
query = SPARQL::Algebra::Expression[:group, data[:group].first, query]
|
1365
|
+
end
|
1366
|
+
|
1367
|
+
if data[:extend]
|
1368
|
+
# extension variables must not appear in projected variables.
|
1369
|
+
# Add them to the projection otherwise
|
1370
|
+
data[:extend].each do |(var, expr)|
|
1371
|
+
raise Error, "Extension variable #{var} also in SELECT" if vars.map(&:to_s).include?(var.to_s)
|
1372
|
+
vars << var
|
1373
|
+
end
|
1374
|
+
|
1375
|
+
query = SPARQL::Algebra::Expression[:extend, data[:extend], query]
|
1376
|
+
end
|
1319
1377
|
|
1320
|
-
query = SPARQL::Algebra::Expression[:order, data[:order].first, query]
|
1378
|
+
query = SPARQL::Algebra::Expression[:order, data[:order].first, query] unless order.empty?
|
1321
1379
|
|
1322
|
-
query = SPARQL::Algebra::Expression[:project,
|
1380
|
+
query = SPARQL::Algebra::Expression[:project, vars, query] unless vars.empty?
|
1323
1381
|
|
1324
1382
|
query = SPARQL::Algebra::Expression[data[:DISTINCT_REDUCED].first, query] if data[:DISTINCT_REDUCED]
|
1325
1383
|
|
@@ -91,7 +91,7 @@ module SPARQL::Grammar
|
|
91
91
|
ANON = /\[#{WS}*\]/m
|
92
92
|
|
93
93
|
# String terminals, case insensitive
|
94
|
-
STR_EXPR = %r(ABS|ADD|ALL|ASC|ASK|AS|BASE|BINDINGS|BIND
|
94
|
+
STR_EXPR = %r(ABS|ADD|ALL|ASC|ASK|AS|AVG|BASE|BINDINGS|BIND
|
95
95
|
|BNODE|BOUND|BY|CEIL|CLEAR|COALESCE|CONCAT
|
96
96
|
|CONSTRUCT|CONTAINS|COPY|COUNT|CREATE|DATATYPE|DAY
|
97
97
|
|DEFAULT|DELETE\sDATA|DELETE\sWHERE|DELETE
|
@@ -114,7 +114,7 @@ module SPARQL::Grammar
|
|
114
114
|
)xi
|
115
115
|
|
116
116
|
# Map terminals to canonical form
|
117
|
-
STR_MAP = (%w{ABS ADD ALL ASC ASK AS BASE BINDINGS BIND
|
117
|
+
STR_MAP = (%w{ABS ADD ALL ASC ASK AS AVG BASE BINDINGS BIND
|
118
118
|
BNODE BOUND BY CEIL CLEAR COALESCE CONCAT
|
119
119
|
CONSTRUCT CONTAINS COPY COUNT CREATE DATATYPE DAY
|
120
120
|
DEFAULT DELETE
|
@@ -131,12 +131,11 @@ module SPARQL::Grammar
|
|
131
131
|
TIMEZONE TO TZ UCASE UNDEF UNION URI USING UUID
|
132
132
|
WHERE WITH YEAR
|
133
133
|
isBLANK isIRI isURI isLITERAL isNUMERIC sameTerm
|
134
|
-
true
|
135
|
-
false
|
134
|
+
true false
|
136
135
|
} + [
|
137
136
|
"DELETE DATA",
|
138
137
|
"DELETE WHERE",
|
139
138
|
"INSERT DATA",
|
140
|
-
]).inject({}) {|memo, t| memo[t.downcase] = t; memo}.freeze
|
139
|
+
]).inject({}) {|memo, t| memo[t.sub(' ', '_').downcase] = t; memo}.freeze
|
141
140
|
end
|
142
141
|
end
|