Is this a bug or a misunderstanding of the xtql query syntax ?
(ns scratchpad.xtql-binding-spec-bug
"Minimal reproduction: XTQL $ parameters in binding specs don't filter results
Bug: When using $ parameters in from binding specs like {:xt/id $param},
the constraint is ignored and all rows are returned."
(:require [xtdb.node :as xtn]
[xtdb.api :as xt]))
(defn minimal-repro []
(with-open [node (xtn/start-node {})]
;; Setup: Insert 3 employees
(xt/submit-tx node
[[:put-docs :employees {:xt/id "emp1" :name "Alice"}]
[:put-docs :employees {:xt/id "emp2" :name "Bob"}]
[:put-docs :employees {:xt/id "emp3" :name "Charlie"}]])
(Thread/sleep 100)
(println "\n=== XTQL Binding Spec Parameter Bug ===\n")
;; Expected: Only return Bob (emp2)
;; Actual: Returns ALL employees
(println "Query: '(from :employees [{:xt/id $uid :name name}])")
(println "Args: {:args {:uid \"emp2\"}}")
(println "\nExpected result: [{:name \"Bob\"}]")
(println "\nActual result:")
(let [result (xt/q node
'(from :employees [{:xt/id $uid :name name}])
{:args {:uid "emp2"}})]
(doseq [row result]
(println " " row)))
(println "\nā BUG: Returns all 3 employees instead of filtering by :xt/id = \"emp2\"")
;; Show that function syntax works correctly
(println "\n\nFor comparison, function syntax works correctly:")
(println "Query: ['(fn [uid] (from :employees [{:xt/id uid :name name}])) \"emp2\"]")
(println "Result:" (xt/q node
['(fn [uid]
(from :employees [{:xt/id uid :name name}]))
"emp2"]))
(println "ā
Correctly returns only Bob")))
(comment
(minimal-repro)
;; The issue appears to be that $ parameters in binding specs
;; are treated as output bindings rather than filter constraints
;; This explains why we see :uid in the output with the parameter value
)
=== XTQL Binding Spec Parameter Bug ===
Query: '(from :employees [{:xt/id $uid :name name}])
Args: {:args {:uid "emp2"}}
Expected result: [{:name "Bob"}]
Actual result:
{#clerk/unreadable-edn (keyword uid) emp3, :name Charlie}
{#clerk/unreadable-edn (keyword uid) emp1, :name Alice}
{#clerk/unreadable-edn (keyword uid) emp2, :name Bob}
ā BUG: Returns all 3 employees instead of filtering by :xt/id = "emp2"
For comparison, function syntax works correctly:
Query: ['(fn [uid] (from :employees [{:xt/id uid :name name}])) "emp2"]
Result: [{:name Bob}]
ā
Correctly returns only BobThe XTQL behavior changed here as part of bringing it into SQL so I think you have to use the fn form now for XTQL parameters.yep - this was part of https://github.com/xtdb/xtdb/releases/tag/v2.0.0-beta8. AFAICT we updated the docs for this but would be grateful to be pointed at any we've missed š@seancorfield Can you point me to a sample app using honeysql with XTDB 2, specifically one embedding XTQL in it?
I can point you at the examples in the docs: https://cljdoc.org/d/com.github.seancorfield/honeysql/2.7.1325/doc/getting-started/xtdb-support#inline-xtql
The XTQL behavior changed here as part of bringing it into SQL so I think you have to use the fn form now for XTQL parameters. Perhaps the documentation hasn't caught up with that change in some places?
Perhaps worth noting that you can now use next.jdbc to interact with XTDB as if it were PostgreSQL, and still embed XTQL into SQL expressions if you want. And you can use HoneySQL to build SQL queries for next.jdbc, including embedding XTQL. The Clojure API is not really useful now, IMO.
I'll take the suggestion, I wanted to avoid bringing other deps and experiment with unify to get a datalog like experience.