Skip to content

Commit

Permalink
Group Concat adds language if all operands have the same language.
Browse files Browse the repository at this point in the history
  • Loading branch information
gkellogg committed Oct 30, 2024
1 parent b65a633 commit 796d3be
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 31 deletions.
6 changes: 5 additions & 1 deletion lib/sparql/algebra/operator/group_concat.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ class Operator
#
# GroupConcat is a set function which performs a string concatenation across the values of an expression with a group. The order of the strings is not specified. The separator character used in the concatenation may be given with the scalar argument SEPARATOR.
#
# If all operands are language-tagged strings with the same language (and direction), the result shares the language (and direction).
#
# [127] Aggregate::= ... | 'GROUP_CONCAT' '(' 'DISTINCT'? Expression ( ';' 'SEPARATOR' '=' String )? ')'
#
# @example SPARQL Grammar
Expand Down Expand Up @@ -72,7 +74,9 @@ def aggregate(solutions = [], **options)
# @return [RDF::Term] An arbitrary term
# @raise [TypeError] If enum is empty
def apply(enum, separator, **options)
RDF::Literal(enum.flatten.map(&:to_s).join(separator.to_s))
op1_lang = enum.first.language
lang = op1_lang if op1_lang && enum.all? {|v| v.language == op1_lang}
RDF::Literal(enum.flatten.map(&:to_s).join(separator.to_s), language: lang)
end

##
Expand Down
14 changes: 9 additions & 5 deletions script/tc
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,9 @@ def run_tc(tc, **options)
tc.expected.dump(:trig, standard_prefixes: true) :
(tc.solutions.is_a?(RDF::Enumerable) ?
tc.solutions.dump(:trig, standard_prefixes: true) :
(tc.solutions ? "Vars: #{tc.solutions.variable_names}\n" + tc.solutions.to_sse : '')))
(tc.solutions.respond_to?(:variable_names) ?
("Vars: #{tc.solutions.variable_names}\n" + tc.solutions.to_sse) :
(tc.solutions ? tc.solutions.to_sse : ''))))
end

case tc.name
Expand Down Expand Up @@ -131,7 +133,9 @@ def run_tc(tc, **options)
STDERR.puts "\nActual:\n" + (
actual.is_a?(RDF::Enumerable) ?
actual.dump(:trig, standard_prefixes: true) :
"Vars: #{actual.variable_names}\n" + actual.to_sse)
(actual.respond_to?(:variable_names) ?
("Vars: #{actual.variable_names}\n" + actual.to_sse) :
(actual ? actual.to_sse : '')))
end

case tc.form
Expand Down Expand Up @@ -368,12 +372,12 @@ opts.each do |opt, arg|
when '--optimize' then options[:optimize] = true
when '--output' then options[:output] = File.open(arg, "w")
when '--quiet'
options[:quiet] = true
logger.level = Logger::FATAL
options[:quiet] = true
logger.level = Logger::FATAL
when '--sparql10' then options[:sparql10] = true
when '--sparql11' then options[:sparql11] = true
when '--sparql12' then options[:sparql12] = true
when '--sparqldev' then options[:sparqldev] = true
when '--sparqldev' then options[:sparqldev] = true
when '--use11' then options[:use11] = true
when '--validate' then options[:validate] = true
when '--verbose' then options[:verbose] = true
Expand Down
50 changes: 25 additions & 25 deletions spec/grammar/misc_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -140,31 +140,31 @@
(triple ?ev <http://example.org/b> ?b)))))
}
},
"dawg-optional-filter-005-not-simplified" => {
query: %(
# Double curly braces do NOT get simplified to single curly braces early on, before filters are scoped
PREFIX dc: <http://purl.org/dc/elements/1.1/>
PREFIX x: <http://example.org/ns#>
SELECT ?title ?price
WHERE
{ ?book dc:title ?title .
OPTIONAL
{
{
?book x:price ?price .
FILTER (?title = "TITLE 2") .
}
} .
}
),
sse: %{(prefix ((dc: <http://purl.org/dc/elements/1.1/>) (x: <http://example.org/ns#>))
(project (?title ?price)
(leftjoin
(bgp (triple ?book dc:title ?title))
(filter (= ?title "TITLE 2")
(bgp (triple ?book x:price ?price))))))
}
}
#"dawg-optional-filter-005-not-simplified" => {
# query: %(
# # Double curly braces do NOT get simplified to single curly braces early on, before filters are scoped
# PREFIX dc: <http://purl.org/dc/elements/1.1/>
# PREFIX x: <http://example.org/ns#>
# SELECT ?title ?price
# WHERE
# { ?book dc:title ?title .
# OPTIONAL
# {
# {
# ?book x:price ?price .
# FILTER (?title = "TITLE 2") .
# }
# } .
# }
# ),
# sse: %{(prefix ((dc: <http://purl.org/dc/elements/1.1/>) (x: <http://example.org/ns#>))
# (project (?title ?price)
# (leftjoin
# (bgp (triple ?book dc:title ?title))
# (filter (= ?title "TITLE 2")
# (bgp (triple ?book x:price ?price))))))
# }
#},
}.each do |test, options|
it "parses #{test}" do
expect(options[:query]).to generate(options[:sse], logger: logger)
Expand Down

0 comments on commit 796d3be

Please sign in to comment.