Skip to content

Commit

Permalink
add support for VALUES patterns and VALUES clauses
Browse files Browse the repository at this point in the history
FQL now supports :values patterns so we can use that directly instead of translating to
a :values clause.
  • Loading branch information
dpetran committed May 17, 2024
1 parent 9f6a050 commit 64942a8
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 32 deletions.
4 changes: 3 additions & 1 deletion resources/sparql.bnf
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,9 @@ Bind ::= <'BIND' WS '(' WS> Expression <WS 'AS' WS> Var <WS ')' WS>
InlineData ::= <'VALUES'> WS DataBlock
<DataBlock> ::= InlineDataOneVar | InlineDataFull
InlineDataOneVar ::= Var <'{'> WS DataBlockValue* <'}'>
InlineDataFull ::= ( NIL | '(' Var* ')' ) '{' ( '(' DataBlockValue* ')' | NIL )* '}'
InlineDataFull ::= ( NIL | VarList ) WS <'{'> WS ( ValueList WS | NIL )* <'}'>
VarList ::= ( <'('> Var* <')'> )
ValueList ::= ( <'('> WS DataBlockValue* <')'> )
DataBlockValue ::= iri | RDFLiteral | NumericLiteral | BooleanLiteral | 'UNDEF' WS
MinusGraphPattern ::= 'MINUS' GroupGraphPattern
GroupOrUnionGraphPattern ::= GroupGraphPattern ( <'UNION'> GroupGraphPattern )*
Expand Down
46 changes: 26 additions & 20 deletions src/clj/fluree/db/query/sparql/translator.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -274,16 +274,27 @@

(defmethod parse-term :DataBlockValue
;; DataBlockValue ::= iri | RDFLiteral | NumericLiteral | BooleanLiteral | 'UNDEF' WS
[[_ value]]
(if (= value "UNDEF")
nil
(parse-term value)))
[[_ [tag :as value]]]
(cond
;; iri values need to be wrapped in a value-map
(= tag :iri) {const/iri-type const/iri-anyURI const/iri-value (parse-term value)}
(= value "UNDEF") nil
:else (parse-term value)))

(defmethod parse-term :VarList
;; VarList ::= ( <'('> Var* <')'> )
[[_ & vars]]
(mapv parse-term vars))

(defmethod parse-term :ValueList
;; ValueList ::= ( <'('> WS DataBlockValue* <')'> )
[[_ & values]]
(mapv parse-term values))

(defmethod parse-term :InlineDataFull
;; InlineDataFull ::= ( NIL | '(' Var* ')' ) '{' ( '(' DataBlockValue* ')' | NIL )* '}'
[_ data]
(throw (ex-info "Multiple inline data values not supported"
{:status 400 :error :db/invalid-query})))
;; InlineDataFull ::= ( NIL | VarList ) WS <'{'> WS ( ValueList WS | NIL )* <'}'>
[[_ vars & data]]
[:values [(parse-term vars)] (mapv parse-term data)])

(defmethod parse-term :InlineDataOneVar
;; InlineDataOneVar ::= Var <'{'> WS DataBlockValue* <'}'>
Expand All @@ -299,7 +310,7 @@
(defmethod parse-term :GraphPatternNotTriples
;; GraphPatternNotTriples ::= GroupOrUnionGraphPattern | OptionalGraphPattern | MinusGraphPattern | GraphGraphPattern | ServiceGraphPattern | Filter | Bind | InlineData
[[_ & non-triples]]
(into [] (mapv parse-term non-triples)))
(mapv parse-term non-triples))

(defmethod parse-term :PrefixedName
[[_ & name]]
Expand Down Expand Up @@ -410,6 +421,11 @@
[[_ & patterns]]
[[:where (into [] (mapcat parse-term patterns))]])

(defmethod parse-rule :ValuesClause
;; ValuesClause ::= ( <'VALUES'> WS DataBlock )? WS
[[_ datablock]]
[(parse-term datablock)])

(defmethod parse-rule :OffsetClause
;; OffsetClause ::= <'OFFSET'> WS INTEGER
[[_ offset]]
Expand Down Expand Up @@ -479,17 +495,7 @@
[[_ & modifiers]]
(mapcat parse-rule modifiers))

(defn format-values
[{:keys [where] :as fql}]
(let [{values true
patterns false}
(group-by (fn [pattern] (= (first pattern) :values)) where)]
(cond-> (assoc fql :where patterns)
(seq values) (assoc :values (->> (mapv second values)
(apply mapv (fn [& values] (vec values))))))))

(defn translate
[parsed]
(->> parsed
(reduce (fn [fql rule] (into fql (parse-rule rule))) {})
(format-values)))
(reduce (fn [fql rule] (into fql (parse-rule rule))) {})))
56 changes: 45 additions & 11 deletions test/fluree/db/query/sparql_test.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -186,20 +186,54 @@
[:filter ["(> ?num 10)"]]]]]
where)))))
(testing "VALUES"
(let [query "SELECT ?handle
(testing "pattern"
(let [query "SELECT ?handle
WHERE {VALUES ?handle { \"dsanchez\" }
?person person:handle ?handle.}"]
(is (= {:where [{"@id" "?person", "person:handle" "?handle"}],
:values [["?handle"] [["dsanchez"]]]}
(select-keys (sparql/->fql query) [:where :values]))
"single var, single val"))
(let [query "SELECT ?handle
WHERE {VALUES ?handle { \"dsanchez\" \"coolguy\"}
(is (= [[:values ["?handle" ["dsanchez"]]]
{"@id" "?person", "person:handle" "?handle"}]
(:where (sparql/->fql query)))
"where pattern: single var, single val"))
(let [query "SELECT ?handle
WHERE {VALUES ?person { :personA :personB }
?person person:handle ?handle.}"]
(is (= {:where [{"@id" "?person", "person:handle" "?handle"}],
:values [["?handle"] [["dsanchez" "coolguy"]]]}
(select-keys (sparql/->fql query) [:where :values]))
"single var, multiple values")))
(is (= [[:values
["?person"
[{"@type" "http://www.w3.org/2001/XMLSchema#anyURI",
"@value" ":personA"}
{"@type" "http://www.w3.org/2001/XMLSchema#anyURI",
"@value" ":personB"}]]]
{"@id" "?person", "person:handle" "?handle"}]
(:where (sparql/->fql query)))
"where pattern: single var, multiple values"))
(let [query "SELECT * WHERE {
VALUES (?color ?direction) {
( dm:red \"north\" )
( dm:blue \"west\" )
}}"]
(is (= [[:values
[["?color" "?direction"]]
[[{"@type" "http://www.w3.org/2001/XMLSchema#anyURI",
"@value" "dm:red"}
"north"]
[{"@type" "http://www.w3.org/2001/XMLSchema#anyURI",
"@value" "dm:blue"}
"west"]]]]
(:where (sparql/->fql query)))
"multiple vars, multiple values")))
(testing "clause"
(let [query "SELECT ?handle
WHERE { ?person person:handle ?handle.}
VALUES ?person { :personA :personB }"]
(is (= {:where [{"@id" "?person", "person:handle" "?handle"}],
:values
["?person"
[{"@type" "http://www.w3.org/2001/XMLSchema#anyURI",
"@value" ":personA"}
{"@type" "http://www.w3.org/2001/XMLSchema#anyURI",
"@value" ":personB"}]]}
(select-keys (sparql/->fql query) [:where :values]))
"where pattern: single var, multiple values"))))
(testing "BIND"
(let [query "SELECT ?person ?handle
WHERE {BIND (\"dsanchez\" AS ?handle)
Expand Down

0 comments on commit 64942a8

Please sign in to comment.