Conversation
|
There's still room for further cleanup, especially around the |
| "Format a where-pattern match for presentation based on the match's datatype. | ||
| Return an async channel that will eventually contain the formatted match." | ||
| (fn [match _compact] | ||
| (fn [match output-format _compact] |
There was a problem hiding this comment.
This new output-format binding exists only to provide runtime polymorphism. This implementation also litters this output-format argument throughout the call stack forcing already working existing code to be modified to support this new feature.
We should use the built in language facilities to support run time polymorphism instead of rolling our own. Either new implementations of existing protocols/multi-methods, or a new protocol or multimethod would be a better fit.
There was a problem hiding this comment.
My current plan is to change the where/match into a record and implement a display method for it. I've got it work-in-progress for construct support, but didn't want to block Nexus and CAM work while I was still figuring out the proper abstraction.
b15d51b to
511e200
Compare
|
Ok, I've overhauled the approach here. Instead of checking the output type each time we format a result, we now just check during query parsing and add the correct implementation of |
f74b898 to
4b1fd82
Compare
|
Rebased on |
Instead of always inferring the datatype and throwing away lang, just use the result from the TypedResult if it's available.
Instead of checking what the output should be on each match, decide the `display` implementation at parse time and use that.
4b1fd82 to
1193d39
Compare
|
Rebased on main. |
src/fluree/db/query/api.cljc
Outdated
| @@ -35,6 +35,7 @@ | |||
| ;; ensure :max-fuel key is present | |||
| (-> (assoc opts :max-fuel max-fuel) | |||
| (merge opts override-opts) | |||
There was a problem hiding this comment.
Though not explicitly part of this pr, there is an extra opts on line 36. I think line 36 and 37 should be replaced with:
(-> opts
(assoc :max-fuel max-fuel)
(merge override-opts)
...
src/fluree/db/query/api.cljc
Outdated
|
|
||
| (defn wrap-sparql-results | ||
| [results] | ||
| (let [format (fn [results] {"head" {"vars" (vec (sort (keys (first results))))} |
There was a problem hiding this comment.
why isn't this anonymous function defined at the top level? it doesn't look like it closes over anything.
There was a problem hiding this comment.
It was to keep the function definition local. This entire function is obsolete, in the CONSTRUCT PR (#985) I move all the wrapping into the collect-results phase of query execution.
There was a problem hiding this comment.
I'll merge that PR into this one so the whole chain is visible.
src/fluree/db/query/api.cljc
Outdated
| _ (log/debug "query-connection SPARQL fql: " fql "override-opts:" override-opts) | ||
| results (<? (query-connection-fql conn fql override-opts))] | ||
| (if (= (:output override-opts) :sparql) | ||
| (wrap-sparql-results results) |
There was a problem hiding this comment.
Is there any reason to disallow someone from setting the output format to sparql for an fql query?
There was a problem hiding this comment.
No, and this is made possible in the CONSTRUCT PR by moving the wrapping into the collect-results phase of query execution.
src/fluree/db/query/exec/group.cljc
Outdated
|
|
||
| (defmethod display/fql ::grouping | ||
| [match compact] | ||
| ((display-aggregate display/fql) match compact)) |
There was a problem hiding this comment.
I think this code would be easier to understand if these functions derived from apply display-aggregate were pre-defined at the top level.
| (some-> match where/get-value vec)) | ||
|
|
||
| (defprotocol ValueSelector | ||
| :extend-via-metadata true |
There was a problem hiding this comment.
I think this namespace is convoluted by relying on this, and I don't see any benefit.
I think instead, there should be two additional namespaces: fluree.db.query.exec.select.fql, and fluree.db.query.exec.select.sparql for the different output formats, each with their own implementations of the ValueSelector protocol that don't reference each other.
Then, during parse time, you can read the output format once and decide which ValueSelector records to instantiate based on the select clause.
There was a problem hiding this comment.
I chose :extend-via-metadata because the other protocols the records implement (ValueAdapter, SolutionModifier) aren't affected by the display and if I create separate Selector records for FQL vs SPARQL I'd have to move the common implementations to a third, common namespace or duplicate them, and on the balance it seemed that :extend-via-metadata was the simpler choice.
There was a problem hiding this comment.
Ok. I'm worried about the performance implications of extending via metadata as well as the semantic implications of having opaque functions hanging off of records.
This pr has been held open for long enough so I'll let this through and we can address these concerns later if they prove to be a problem.
| [fluree.db.query.exec.where :as where] | ||
| [fluree.db.util.json :as json])) | ||
|
|
||
| (defmulti fql (fn [match compact] (where/get-datatype-iri match))) |
There was a problem hiding this comment.
I think this should also be split. Instead of this new namespace with these two multimethods, we should instead put the display/fql multimethod in fluree.db.query.exec.select.fql and the sparql multimethod in the sparql ns.
Essentially, we should take everything except for the protocol definitions from fluree.db.exec.select.fql and move them to a new namespace fluree.db.query.exec.select.fql, and then define a parallel fluree.db.query.exec.select.sparql namespace with the sparql functionality.
The official grammar only has it in all caps, but even the examples in the spec use lower case, so we may as well support it.
Also added compact iris to construct results, which required holding on to the original unparsed context.
Since solutions are processed concurrently there's no guarantee on the order blank node labels will be assigned.
Support for SPARQL CONSTRUCT clauses
| variable is a string, symbol, or keyword whose name starts with '?'." | ||
| [x] | ||
| (when (v/variable? x) | ||
| (when (or (v/variable? x) |
There was a problem hiding this comment.
I think it would be useful to define a more general function for detecting variables because you repeat this or call a lot. It might even be useful to just change the definition of the variable? function to include that of bnode-variable? if the current variable? function is never called alone.
There was a problem hiding this comment.
We actually need to distinguish between the two types - in a transaction you can have bnodes and they are not variables, they are "fresh" identifiers that will be mapped to new, internal identifiers. So it's only inside of a query where pattern that we need these or statements.
There was a problem hiding this comment.
Ok, so I think it makes sense to have a general function for detecting variables in queries to remove the or repetition here.
I see this branch is already merged, so we can address this later.
There was a problem hiding this comment.
Here's a follow-up PR to address it:
#989
src/fluree/db/query/exec/select.cljc
Outdated
| (solution-value | ||
| [_ _ solution] | ||
| solution)) | ||
| (solution-value [_ _ solution] solution)) |
There was a problem hiding this comment.
I think the argument list and function definitions should both be on new lines.
src/fluree/db/query/exec/select.cljc
Outdated
| ValueSelector | ||
| (format-value | ||
| [_ _ _ _ _ _ error-ch solution] | ||
| [_ _ _ _ compact _ error-ch solution] |
There was a problem hiding this comment.
It doesn't look like compact is used.
| (some-> match where/get-value vec)) | ||
|
|
||
| (defprotocol ValueSelector | ||
| :extend-via-metadata true |
There was a problem hiding this comment.
Ok. I'm worried about the performance implications of extending via metadata as well as the semantic implications of having opaque functions hanging off of records.
This pr has been held open for long enough so I'll let this through and we can address these concerns later if they prove to be a problem.
This adds the ability to produce query results in SPARQL 1.1 Query Results JSON Format.
https://github.com/fluree/core/issues/170
This introduces the
:outputquery option. If it is not supplied it defaults to:fql, which is what we currently return. Supplying:sparqlprovides the output like this:Note that it retains the datatype and language metadata about values, as well as distinguishes IRIs from strings. It's also a tabular format, so aggregates are "unnested" and flattened.