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

Add option to return query results w/ order matching SELECT bindings #23

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
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
33 changes: 23 additions & 10 deletions src/stardog/core.clj
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,12 @@
;; limitations under the License.

(ns stardog.core
(:require [clojure.string :as str]
[stardog.values :as values])
(:require [stardog.values :as values])
(:import [com.complexible.stardog.api
Connection ConnectionPool ConnectionPoolConfig ConnectionConfiguration
Query ReadQuery]
[clojure.lang IFn]
[java.util Map Iterator]
[com.complexible.stardog.reasoning.api ReasoningType]
[java.util Map List]
[com.complexible.common.base CloseableIterator]
[com.stardog.stark Values Namespace]
[com.stardog.stark.query SelectQueryResult GraphQueryResult BindingSet Binding]
Expand Down Expand Up @@ -98,11 +96,12 @@

(defn key-map-results
"Converts a Iteration of bindings into a seq of keymaps."
[^IFn keyfn ^IFn valfn ^CloseableIterator results]
[^IFn keyfn ^IFn valfn ^SelectQueryResult results]
Copy link
Contributor Author

@dannyfreeman dannyfreeman Aug 31, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changing this to a more specific interface, which implements CLoseableIterator. See https://docs.stardog.com/javadoc/snarl/com/stardog/stark/query/SelectQueryResult.html

Necessary to avoid reflecting when calling the variables method.

(let [mapper (partial binding->map keyfn valfn)
realized-results (into [] (map mapper) (iterator-seq results))]
realized-results (into [] (map mapper) (iterator-seq results))
variables (map keyfn (.variables results))]
(.close results)
realized-results))
(vary-meta realized-results assoc :variables variables)))

(defn vector-map-results
"Converts a Graph of statements into a seq of vectors."
Expand All @@ -122,7 +121,7 @@
(let [namespaces (into {}
(map (fn [^Namespace ns] [(.prefix ns) (.iri ns)]))
(iterator-seq (.. results namespaces iterator)))]
(with-meta (vector-map-results valfn results) {:namespaces namespaces})))
(vary-meta (vector-map-results valfn results) assoc :namespaces namespaces)))
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

with-meta sets the metadata, overriding any previous metadata that may or may not have been present. vary-meta updates existing metadata, and has the same signature as update. We almost always want to accumulate metadata, never override it with new values.

SelectQueryResult
(clojure-data* [results keyfn valfn] (key-map-results keyfn valfn results))
nil
Expand Down Expand Up @@ -191,6 +190,18 @@
(filter second)
(into {})))))

(defn- order-results [results]
(let [{:keys [^List variables] :as metadata} (meta results)
order-result-set (fn [result-set]
(into (sorted-map-by (fn [binding1 binding2]
(compare
(.indexOf variables binding1)
(.indexOf variables binding2))))
result-set))]
(if (not-empty variables)
(-> (map order-result-set results)
(with-meta metadata))
results)))

(defn query
"Executes a query and returns results.
Expand All @@ -207,11 +218,13 @@
- converter: A function to convert returned values with (Function).
- key-converter: A function to convert returned binding names with (Function).
- limit: The limit for the result. Must be present to use offset (integer).
- offset: The offset to start the result (integer)."
- offset: The offset to start the result (integer).
- ordered?: Preserve the order of the variable bindings present in the SELECT clause"
[^Connection connection ^String text & args]
(let [args (convert-to-map args)
q (create-query #(.select connection text %) #(.select connection text) args)]
(execute* q args)))
(cond-> (execute* q args)
(get-in args [:parameters :ordered?]) (order-results))))


(defn ask
Expand Down