From 057156938e35288083d75d7219aaad48d46a689d Mon Sep 17 00:00:00 2001 From: Daniel Petranek Date: Tue, 28 Oct 2025 10:40:22 -0500 Subject: [PATCH] add support for empty result set with selectOne --- src/fluree/server/handler.clj | 12 +++++- .../server/integration/basic_query_test.clj | 42 ++++++++++++------- 2 files changed, 38 insertions(+), 16 deletions(-) diff --git a/src/fluree/server/handler.clj b/src/fluree/server/handler.clj index f389d98..a6fce26 100644 --- a/src/fluree/server/handler.clj +++ b/src/fluree/server/handler.clj @@ -106,7 +106,7 @@ (def QueryResponse (m/schema [:orn [:select [:sequential [:or coll? map?]]] - [:select-one [:or coll? map?]] + [:select-one [:or coll? map? nil? [:enum "null"]]] [:construct map?]])) (def HistoryQuery @@ -235,6 +235,15 @@ :fluree/subscriptions subscriptions) handler))) +(defn wrap-no-result + "Handle a nil response from a selectOne query with no results." + [handler] + (fn [req] + (let [{:keys [status body] :as result} (handler req)] + (if (and (= 200 status) (nil? body)) + (assoc result :body "null") + result)))) + (defn wrap-cors [cors-origins handler] (let [origins (or cors-origins [#".*"])] @@ -523,6 +532,7 @@ coercion/coerce-exceptions-middleware coercion/coerce-response-middleware coercion/coerce-request-middleware + wrap-no-result wrap-request-header-opts (wrap-closed-mode root-identities closed-mode) exception-middleware])) diff --git a/test/fluree/server/integration/basic_query_test.clj b/test/fluree/server/integration/basic_query_test.clj index 93b9ed6..15a70ea 100644 --- a/test/fluree/server/integration/basic_query_test.clj +++ b/test/fluree/server/integration/basic_query_test.clj @@ -118,21 +118,33 @@ "type" "schema:Test" "ex:name" "query-test"}]}) :headers json-headers} - txn-res (api-post :transact txn-req) - _ (assert (= 200 (:status txn-res))) - query-req {:body - (json/stringify - {"@context" test-system/default-context - "from" ledger-name - "selectOne" '{?t ["*"]} - "where" '{"id" ?t, "type" "schema:Test"}}) - :headers json-headers} - query-res (api-post :query query-req)] - (is (= 200 (:status query-res))) - (is (= {"id" "ex:query-test" - "type" "schema:Test" - "ex:name" "query-test"} - (-> query-res :body (json/parse false)))))) + txn-res (api-post :transact txn-req)] + (assert (= 200 (:status txn-res))) + (testing "with result" + (let [query-req {:body + (json/stringify + {"@context" test-system/default-context + "from" ledger-name + "selectOne" '{?t ["*"]} + "where" '{"id" ?t, "type" "schema:Test"}}) + :headers json-headers} + query-res (api-post :query query-req)] + (is (= 200 (:status query-res))) + (is (= {"id" "ex:query-test" + "type" "schema:Test" + "ex:name" "query-test"} + (-> query-res :body (json/parse false)))))) + (testing "without result" + (let [query-req {:body + (json/stringify + {"@context" test-system/default-context + "from" ledger-name + "selectOne" '{?t ["*"]} + "where" '{"id" ?t, "type" "schema:Foo"}}) + :headers json-headers} + query-res (api-post :query query-req)] + (is (= 200 (:status query-res))) + (is (nil? (-> query-res :body (json/parse false)))))))) (testing "bind query works" (let [ledger-name (create-rand-ledger "query-endpoint-bind-test")