sparql 1.0.6 → 1.0.7
Sign up to get free protection for your applications and to get access to all the features.
- 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
|