Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SPARQL VALUES patterns #769

Merged
merged 87 commits into from
Jun 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
87 commits
Select commit Hold shift + click to select a range
e43302f
support VALUES patterns in where clause
dpetran May 15, 2024
91ae277
support VALUES patterns in an order-agnostic way
dpetran May 16, 2024
3336a27
add values test for nested patterns
dpetran May 16, 2024
703f3ff
correctly filter solutions across ledgers and with meta
dpetran May 31, 2024
0dd8a2e
use public match api instead of removing unwanted match elements
dpetran Jun 3, 2024
2a6b1fb
correctly assign langString datatype to language tagged strings
dpetran Jun 12, 2024
4790fc5
add support for multiple values per var in VALUES pattern
dpetran May 10, 2024
e5e3e86
add support for VALUES patterns and VALUES clauses
dpetran May 17, 2024
6e33a13
SUBSTR and REPLACE expresssion translations
dpetran May 20, 2024
b116e6a
Throw errors for unsupported EXISTS and NOT EXISTS filters
dpetran May 20, 2024
41fb5e9
add support for complex multiplicative expressions
dpetran May 20, 2024
95914df
remove useless thread macro
dpetran Jun 12, 2024
6147559
handle Func translation on a case-by-case basis
dpetran May 20, 2024
37fd89f
add support for BOUND
dpetran May 20, 2024
7e27b8f
Add separate test for funcs
JaceRockman May 20, 2024
13fe3b7
Alphabetize the lists of funcs
JaceRockman May 20, 2024
74900be
add support for BNODE
JaceRockman May 21, 2024
acec6f6
add support for COALESCE
JaceRockman May 21, 2024
4801e21
fix implementation of BNODE
JaceRockman May 21, 2024
9286d4c
add support for CONTAINS
JaceRockman May 21, 2024
e28e4a6
add support for DATATYPE
JaceRockman May 21, 2024
ecada24
add support for DAY
JaceRockman May 21, 2024
3219cbb
add support for ENCODE_FOR_URI
JaceRockman May 21, 2024
276245e
add support for FLOOR
JaceRockman May 21, 2024
c4cb06f
add support for HOURS
JaceRockman May 21, 2024
1c3bc19
add support for IF
JaceRockman May 21, 2024
a9db1e0
add support for IRI
JaceRockman May 21, 2024
27d92e6
add support for LANG
JaceRockman May 21, 2024
0d33ea4
add support for LANGMATCHES
JaceRockman May 21, 2024
96f02e7
add support for LCASE
JaceRockman May 21, 2024
3cee558
add support for MD5
JaceRockman May 21, 2024
3035d03
add support for MINUTES
JaceRockman May 21, 2024
b35b1c2
add support for MONTH
JaceRockman May 21, 2024
c70a168
add support for NOW
JaceRockman May 21, 2024
22ce5a1
add support for RAND
JaceRockman May 21, 2024
f44006c
add support for ROUND
JaceRockman May 21, 2024
819545c
add support for SECONDS
JaceRockman May 21, 2024
55820d0
add support for SHA1
JaceRockman May 21, 2024
fe09d62
add support for SHA256
JaceRockman May 21, 2024
e7d9cb9
add tests for SHA512
JaceRockman May 21, 2024
3e55016
add support for STR
JaceRockman May 21, 2024
e38a748
add support for STRAFTER and STRBEFORE
JaceRockman May 21, 2024
1a0e2f7
add support for STRDT
JaceRockman May 21, 2024
9fdaeb0
add support for STRENDS
JaceRockman May 21, 2024
f594eff
add support for STRLANG
JaceRockman May 21, 2024
9851f94
add support for STRLEN and STRENDS
JaceRockman May 21, 2024
b901f9e
add support for STRUUID
JaceRockman May 21, 2024
62b0825
add support for TIMEZONE
JaceRockman May 21, 2024
05f97a0
add support for TZ
JaceRockman May 21, 2024
d0a2298
add support for UCASE
JaceRockman May 21, 2024
0dac86c
add support for URI
JaceRockman May 21, 2024
e167b66
add support for UUID
JaceRockman May 21, 2024
9d219e5
add support for YEAR
JaceRockman May 21, 2024
3b54bd6
add support for isBLANK
JaceRockman May 21, 2024
99f7880
add support for isIRI
JaceRockman May 21, 2024
5a64bd7
add support for isLITERAL
JaceRockman May 21, 2024
6a084ba
add support for isNUMERIC
JaceRockman May 21, 2024
15ce3e7
add support for isURI
JaceRockman May 21, 2024
e45471a
add support for sameTerm
JaceRockman May 21, 2024
595bcdf
support SPARQL literal datatype and language tags
dpetran May 21, 2024
e6e1481
confirm SPARQL comments are ignored
dpetran May 21, 2024
c842db3
correctly handle multiple expressions joined logically
dpetran May 21, 2024
f617b71
add error for SERVICE patterns
dpetran May 21, 2024
26c7ac6
fix typo
dpetran Jun 3, 2024
968aedd
add description of sparql function translation
dpetran Jun 3, 2024
c47cd57
add support for FROM NAMED
JaceRockman May 23, 2024
a521573
Correct grammar comment in DatasetClause parse-rule
JaceRockman May 24, 2024
25c82b9
add support for GRAPH
JaceRockman May 28, 2024
e38600a
add support for EXISTS and NOT EXISTS patterns
dpetran May 28, 2024
2a93cb7
use existing helper function instead of destructuring
dpetran May 28, 2024
fe03c44
add explanations to test cases
dpetran May 29, 2024
8890937
use parse-where-clause function
dpetran May 29, 2024
521d4c3
allow SPARQL to use `a` as an alias for @type
dpetran May 29, 2024
a00ebba
add support for `in` expression
dpetran Jun 4, 2024
3311ab7
rename sparql-in to in
dpetran Jun 12, 2024
7844077
translate SPARQL EXISTS/NOT EXISTS filters into FQL
dpetran Jun 4, 2024
662ff42
SPARQL IN support
dpetran Jun 4, 2024
ec0915d
fix expression quoting
dpetran Jun 4, 2024
d671a27
SPARQL NOT IN support
dpetran Jun 4, 2024
0b715bf
fix abs expression parsing
dpetran Jun 12, 2024
1a13d9c
no need to literal-quote numeric functions
dpetran Jun 12, 2024
faf021f
Merge pull request #797 from fluree/feature/sparql-in-not-in
dpetran Jun 17, 2024
79565b8
Merge pull request #796 from fluree/feature/sparql-exists-not-exists
dpetran Jun 17, 2024
4c13b1b
Merge pull request #795 from fluree/feature/fql-in-not-in
dpetran Jun 17, 2024
1f62042
Merge pull request #784 from fluree/feature/fql-exists-not-exists
dpetran Jun 17, 2024
2973fc1
Merge pull request #780 from fluree/feature/sparql-from-named
dpetran Jun 17, 2024
dee6c88
Merge pull request #778 from fluree/feature/sparql-func
dpetran Jun 17, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 23 additions & 19 deletions resources/sparql.bnf
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,17 @@ UpdateUnit ::= Update
Prologue ::= ( BaseDecl | PrefixDecl )*
BaseDecl ::= <'BASE'> WS IRIREF
PrefixDecl ::= <'PREFIX'> WS PNAME_NS WS IRIREF
SelectQuery ::= WS SelectClause WS DatasetClause* WS WhereClause WS SolutionModifier WS
SelectQuery ::= WS SelectClause WS DatasetClause WS WhereClause WS SolutionModifier WS
SubSelect ::= SelectClause WhereClause SolutionModifier ValuesClause
SelectClause ::= WS <'SELECT'> WS ( 'DISTINCT' | 'REDUCED')? ( ( WS ( Var | ( <'('> Expression WS 'AS' WS Var <')'> ) ) )+ | ( WS '*' ) )
ConstructQuery ::= 'CONSTRUCT' ( ConstructTemplate DatasetClause* WhereClause SolutionModifier | DatasetClause* 'WHERE' '{' TriplesTemplate? '}' SolutionModifier )
DescribeQuery ::= 'DESCRIBE' ( VarOrIri+ | '*' ) DatasetClause* WhereClause? SolutionModifier
AskQuery ::= 'ASK' DatasetClause* WhereClause SolutionModifier
Modifiers ::= (ValuesClause? | PrettyPrint? ) (PrettyPrint? | ValuesClause? )
DatasetClause ::= <'FROM'> WS ( DefaultGraphClause | NamedGraphClause )
ConstructQuery ::= 'CONSTRUCT' ( ConstructTemplate DatasetClause WhereClause SolutionModifier | DatasetClause 'WHERE' '{' TriplesTemplate? '}' SolutionModifier )
DescribeQuery ::= 'DESCRIBE' ( VarOrIri+ | '*' ) DatasetClause WhereClause? SolutionModifier
AskQuery ::= 'ASK' DatasetClause WhereClause SolutionModifier
Modifiers ::= (ValuesClause? | PrettyPrint? ) (PrettyPrint? | ValuesClause? )
DatasetClause ::= FromClause*
<FromClause> ::= <'FROM'> WS ( DefaultGraphClause | NamedGraphClause )
DefaultGraphClause ::= SourceSelector
NamedGraphClause ::= <'NAMED'> SourceSelector
NamedGraphClause ::= <'NAMED'> WS SourceSelector
<SourceSelector> ::= iri
WhereClause ::= <'WHERE'?> WS GroupGraphPattern WS
SolutionModifier ::= GroupClause? HavingClause? OrderClause? LimitOffsetClauses?
Expand Down Expand Up @@ -56,13 +57,15 @@ GroupGraphPatternSub ::= WS TriplesBlock? ( GraphPatternNotTriples WS <'.'?>
TriplesBlock ::= WS TriplesSameSubjectPath WS ( <'.'> TriplesBlock? WS )?
GraphPatternNotTriples ::= GroupOrUnionGraphPattern | OptionalGraphPattern | MinusGraphPattern | GraphGraphPattern | ServiceGraphPattern | Filter | Bind | InlineData
OptionalGraphPattern ::= <'OPTIONAL'> GroupGraphPattern
GraphGraphPattern ::= 'GRAPH' VarOrIri GroupGraphPattern
ServiceGraphPattern ::= 'SERVICE' 'SILENT'? VarOrIri GroupGraphPattern
GraphGraphPattern ::= <'GRAPH'> WS VarOrIri WS GroupGraphPattern
ServiceGraphPattern ::= <'SERVICE'> WS 'SILENT'? WS VarOrIri GroupGraphPattern
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 All @@ -76,7 +79,7 @@ ConstructTriples ::= TriplesSameSubject ( '.' ConstructTriples? )?
TriplesSameSubject ::= VarOrTerm PropertyListNotEmpty | TriplesNode PropertyList
PropertyList ::= PropertyListNotEmpty?
PropertyListNotEmpty ::= Verb ObjectList ( <';'> WS ( Verb ObjectList )? )*
Verb ::= VarOrIri | 'a'
Verb ::= VarOrIri | Type
ObjectList ::= Object ( <','> WS Object )*
Object ::= GraphNode
TriplesSameSubjectPath ::= VarOrTerm PropertyListPathNotEmpty | TriplesNodePath PropertyListPath WS
Expand All @@ -92,9 +95,9 @@ PathSequence ::= PathEltOrInverse ( <'/'> PathEltOrInverse )*
<PathElt> ::= PathPrimary PathMod?
<PathEltOrInverse> ::= PathElt | <'^'> PathElt
PathMod ::= '?' | '*' | ('+' INTEGER?) WS
PathPrimary ::= iri | 'a' | '!' PathNegatedPropertySet | '(' Path ')'
PathPrimary ::= iri | Type | '!' PathNegatedPropertySet | '(' Path ')'
PathNegatedPropertySet ::= PathOneInPropertySet | '(' ( PathOneInPropertySet ( '|' PathOneInPropertySet )* )? ')'
PathOneInPropertySet ::= iri | 'a' | '^' ( iri | 'a' )
PathOneInPropertySet ::= iri | Type | '^' ( iri | Type )
Integer ::= INTEGER
TriplesNode ::= Collection | BlankNodePropertyList
BlankNodePropertyList ::= '[' PropertyListNotEmpty ']'
Expand All @@ -105,14 +108,15 @@ CollectionPath ::= '(' GraphNodePath+ ')'
<GraphNode> ::= VarOrTerm | TriplesNode
<GraphNodePath> ::= VarOrTerm | TriplesNodePath
<VarOrTerm> ::= Var | GraphTerm WS
VarOrIri ::= Var | iri WS
<VarOrIri> ::= Var | iri WS
Var ::= VAR1 WS | VAR2 WS
<Type> ::= (WS 'a' WS)
<GraphTerm> ::= iri | RDFLiteral | NumericLiteral | BooleanLiteral | BlankNode | NIL
Expression ::= WS ConditionalOrExpression WS
<ConditionalOrExpression> ::= ConditionalAndExpression ( <'||'> ConditionalAndExpression )*
<ConditionalAndExpression> ::= ValueLogical ( <'&&'> ValueLogical )*
ConditionalOrExpression ::= ConditionalAndExpression ( <'||'> ConditionalAndExpression )*
ConditionalAndExpression ::= ValueLogical ( <'&&'> ValueLogical )*
<ValueLogical> ::= RelationalExpression
RelationalExpression ::= NumericExpression WS ( '=' NumericExpression | '!=' NumericExpression | '<' NumericExpression | '>' NumericExpression | '<=' NumericExpression | '>=' NumericExpression | 'IN' ExpressionList | 'NOT' 'IN' ExpressionList )?
RelationalExpression ::= NumericExpression WS ( '=' NumericExpression | '!=' NumericExpression | '<' NumericExpression | '>' NumericExpression | '<=' NumericExpression | '>=' NumericExpression | 'IN' WS ExpressionList | 'NOT' WS 'IN' WS ExpressionList )?
NumericExpression ::= WS AdditiveExpression WS

<AdditiveExpression> ::= MultiplicativeExpression ( '+' MultiplicativeExpression | '-' MultiplicativeExpression | ( NumericLiteralPositive | NumericLiteralNegative ) ( ( '*' UnaryExpression ) | ( '/' UnaryExpression ) )* )*
Expand Down Expand Up @@ -188,7 +192,7 @@ RegexExpression ::= <'REGEX'> <'('> Expression <','> Expression ( <','> Expr
SubstringExpression ::= <'SUBSTR'> <'('> Expression <','> Expression ( <','> Expression )? <')'>
StrReplaceExpression ::= <'REPLACE'> <'('> Expression <','> Expression <','> Expression ( <','> Expression )? <')'>
ExistsFunc ::= <'EXISTS'> GroupGraphPattern
NotExistsFunc ::= <'NOT'> <'EXISTS'> GroupGraphPattern
NotExistsFunc ::= <'NOT'> WS <'EXISTS'> GroupGraphPattern
Aggregate ::= 'COUNT' WS <'('> WS 'DISTINCT'? WS ( '*' | Expression ) WS <')'> WS
| 'SUM' WS <'('> WS 'DISTINCT'? Expression <')'>
| 'MIN' <'('> WS 'DISTINCT'? Expression <')'>
Expand All @@ -214,7 +218,7 @@ IRIREF ::= #"<[^<>\"{}|^`\x00-\x20]*>" WS
BLANK_NODE_LABEL ::= '_:' ( PN_CHARS_U | #"[0-9]" ) ((PN_CHARS|'.')* PN_CHARS)?
<VAR1> ::= <'?'> VARNAME
<VAR2> ::= <'$'> VARNAME
LANGTAG ::= #"@[a-zA-Z]+-[a-zA-Z0-9]*" WS
LANGTAG ::= #"@[a-zA-Z]+(-[a-zA-Z0-9]+)*" WS
<INTEGER> ::= #"[0-9]+"
<DECIMAL> ::= #"[0-9]*\.[0-9]*"
<DOUBLE> ::= #"[0-9]+\.[0-9]*|(\.[0-9]+)|([0-9]+)" EXPONENT
Expand Down
1 change: 1 addition & 0 deletions src/clj/fluree/db/constants.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
(def ^:const iri-rdf-type "http://www.w3.org/1999/02/22-rdf-syntax-ns#type")
(def ^:const iri-class "http://www.w3.org/2000/01/rdf-schema#Class")
(def ^:const iri-lang-string "http://www.w3.org/1999/02/22-rdf-syntax-ns#langString")
(def ^:const iri-string "http://www.w3.org/2001/XMLSchema#string")

;; rdfs
(def ^:const iri-rdfs:Class "http://www.w3.org/2000/01/rdf-schema#Class")
Expand Down
7 changes: 6 additions & 1 deletion src/clj/fluree/db/query/exec/eval.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -285,9 +285,13 @@
[x]
(str x))

(defn in
[term expressions]
(contains? (set expressions) term))

(def allowed-scalar-fns
'#{&& || ! > < >= <= = + - * / quot and bound coalesce if lang nil? as
not not= or re-find re-pattern
not not= or re-find re-pattern in
;; string fns
strStarts strEnds subStr strLen ucase lcase contains strBefore strAfter concat regex replace
;; numeric fns
Expand Down Expand Up @@ -320,6 +324,7 @@
count clojure.core/count
floor fluree.db.query.exec.eval/floor
groupconcat fluree.db.query.exec.eval/groupconcat
in fluree.db.query.exec.eval/in
lang fluree.db.query.exec.eval/lang
lcase fluree.db.query.exec.eval/lcase
median fluree.db.query.exec.eval/median
Expand Down
2 changes: 1 addition & 1 deletion src/clj/fluree/db/query/exec/update.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@
where/get-datatype-iri
(->> (generate-sid! db-vol)))
(dbproto/-p-prop @db-vol :datatype p-iri)
(datatype/infer v))
(datatype/infer v (:lang m)))
v* (datatype/coerce-value v dt)]
(flake/create sid pid v* dt t true m)))

Expand Down
27 changes: 27 additions & 0 deletions src/clj/fluree/db/query/exec/where.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -533,6 +533,20 @@
(dataset/activate alias)
(match-clause fuel-tracker solution clause error-ch)))

(defmethod match-pattern :exists
[ds fuel-tracker solution pattern error-ch]
(let [clause (pattern-data pattern)]
(go
(when (async/<! (match-clause ds fuel-tracker solution clause error-ch))
solution))))

(defmethod match-pattern :not-exists
[ds fuel-tracker solution pattern error-ch]
(let [clause (pattern-data pattern)]
(go
(when-not (async/<! (match-clause ds fuel-tracker solution clause error-ch))
solution))))

(defmethod match-pattern :graph
[ds fuel-tracker solution pattern error-ch]
(let [[g clause] (pattern-data pattern)]
Expand Down Expand Up @@ -566,6 +580,19 @@
clause-ch)
out-ch))

(defmethod match-pattern :values
[db fuel-tracker solution pattern error-ch]
(let [inline-solutions (pattern-data pattern)
;; transform a match into its identity for equality checks
match-identity (juxt get-iri get-value get-datatype-iri (comp get-meta :lang))
solution* (update-vals solution match-identity)]
;; filter out any inline solutions whose matches don't match the solution's matches
(->> inline-solutions
(filterv (fn [inline-solution] (= (select-keys solution* (keys inline-solution))
(update-vals inline-solution match-identity))))
(mapv (partial merge solution) inline-solutions)
(async/to-chan!))))

(defn with-default
"Return a transducer that transforms an input stream of solutions to include the
`default-solution` if and only if the stream was empty."
Expand Down
37 changes: 27 additions & 10 deletions src/clj/fluree/db/query/fql/parse.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,9 @@
(json-ld/expand-iri context)
(where/anonymous-value dt-iri))
(where/anonymous-value v dt-iri))
(where/anonymous-value v)))
(if-let [lang (get attrs const/iri-language)]
(where/anonymous-value v const/iri-lang-string {:lang lang})
(where/anonymous-value v))))

(defn parse-value-attributes
[v attrs context]
Expand All @@ -79,8 +81,10 @@
(let [expanded (json-ld/expand-iri val context)]
(where/match-iri var-match expanded))
(where/match-value var-match val dt-iri))
(let [dt (datatype/infer-iri val)]
(where/match-value var-match val dt)))))
(if-let [lang (get attrs const/iri-language)]
(where/match-value var-match val const/iri-lang-string {:lang lang})
(let [dt (datatype/infer-iri val)]
(where/match-value var-match val dt))))))

(defn match-value-binding
[var-match value context]
Expand All @@ -98,11 +102,11 @@
(zipmap vars binding)))

(defn parse-values
[q context]
(when-let [values (:values q)]
[values context]
(when values
(let [[vars vals] values
vars* (keep parse-var-name (util/sequential vars))
vals* (mapv util/sequential vals)
vars* (keep parse-var-name (util/sequential vars))
vals* (mapv util/sequential vals)
var-count (count vars*)]
(if (every? (fn [binding]
(= (count binding) var-count))
Expand Down Expand Up @@ -408,6 +412,19 @@
(let [parsed (parse-bind-map binds)]
[(where/->pattern :bind parsed)]))

(defmethod parse-pattern :values
[[_ values] vars context]
(let [[_vars solutions] (parse-values values context)]
[(where/->pattern :values solutions)]))

(defmethod parse-pattern :exists
[[_ patterns] vars context]
[(where/->pattern :exists (parse-where-clause patterns vars context))])

(defmethod parse-pattern :not-exists
[[_ patterns] vars context]
[(where/->pattern :not-exists (parse-where-clause patterns vars context))])

(defmethod parse-pattern :graph
[[_ graph where] vars context]
(let [graph* (or (parse-variable graph)
Expand Down Expand Up @@ -570,7 +587,7 @@
(defn parse-analytical-query
[q]
(let [context (context/extract q)
[vars values] (parse-values q context)
[vars values] (parse-values (:values q) context)
where (parse-where q vars context)
grouping (parse-grouping q)
ordering (parse-ordering q)]
Expand Down Expand Up @@ -684,8 +701,8 @@

(defn parse-txn
[txn context]
(let [vals-map {:values (util/get-first-value txn const/iri-values)}
[vars values] (parse-values vals-map context)
(let [values (util/get-first-value txn const/iri-values)
[vars values] (parse-values values context)
where-map {:where (util/get-first-value txn const/iri-where)}
where (parse-where where-map vars context)
bound-vars (-> where where/bound-variables (into vars))
Expand Down
Loading
Loading