From 54579cab94db606e00f378b737453b3887fa2988 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Ritschard Date: Thu, 14 Sep 2023 13:20:14 +0200 Subject: [PATCH] mutation: support running multiple queries --- src/seql/mutation.clj | 18 +++++--- test/seql/multi_query_integration_test.clj | 52 ++++++++++++++++++++++ 2 files changed, 64 insertions(+), 6 deletions(-) create mode 100644 test/seql/multi_query_integration_test.clj diff --git a/src/seql/mutation.clj b/src/seql/mutation.clj index f4a8662..483af48 100644 --- a/src/seql/mutation.clj +++ b/src/seql/mutation.clj @@ -40,6 +40,12 @@ :pre (dissoc pre :valid? :query)})))))) pre))) +(defn- wrap-statements + "Transform returned statement value into a vector, allowing handlers to return + multiple statements" + [x] + (if (vector? x) x [x])) + (defn mutate! "Perform a mutation. Since mutations are spec'd, parameters are expected to conform it." @@ -56,15 +62,15 @@ :code 400 :explain (s/explain-str spec params)}))) (let [cparams (c/write-map params) - statement (-> cparams - (assoc ::schema (env/schema env)) - (assoc ::metadata metadata) - handler - sql/format) + statements (map sql/format (-> cparams + (assoc ::schema (env/schema env)) + (assoc ::metadata metadata) + handler + wrap-statements)) result (jdbc/with-transaction [tx (env/jdbc env)] ;; if we have preconditions check these first (run-preconditions! tx mutation (dissoc cparams ::schema ::metadata) pre) - (jdbc/execute! tx statement))] + (last (map #(jdbc/execute! tx %) statements)))] (when-not (success-result? result) (throw (ex-info (format "the mutation has failed: %s" mutation) {:type :error/mutation-failed diff --git a/test/seql/multi_query_integration_test.clj b/test/seql/multi_query_integration_test.clj new file mode 100644 index 0000000..b9959a4 --- /dev/null +++ b/test/seql/multi_query_integration_test.clj @@ -0,0 +1,52 @@ +(ns seql.multi-query-integration-test + (:require [seql.mutation :refer [mutate!]] + [clojure.spec.alpha :as s] + [seql.env :as env] + [seql.query :as q] + [seql.helpers :refer [make-schema entity-from-spec mutation-fn]] + [db.fixtures :refer [jdbc-config with-db-fixtures]] + [clojure.test :refer [use-fixtures testing deftest is]])) + +(use-fixtures :each (with-db-fixtures :small)) + +(create-ns 'my.entities) +(create-ns 'my.entities.account) +(alias 'account 'my.entities.account) + +(s/def ::account/name string?) +(s/def ::account/id nat-int?) +(s/def ::account/state #{:active :suspended :terminated}) +(s/def ::account/account (s/keys :req [::account/name ::account/state])) +(s/def ::account/create ::account/account) + +(def schema + "As gradually explained in the project's README" + (make-schema + (entity-from-spec ::account/account + (mutation-fn ::account/delete-two any? + (constantly + [{:delete-from :account :where [:= :id 1]} + {:delete-from :account :where [:= :id 2]}])) + (mutation-fn ::account/add-two any? + (constantly + [{:insert-into :account + :columns [:id :name :state] + :values [[1 "hello" "active"]]} + {:insert-into :account + :columns [:id :name :state] + :values [[2 "bye" "suspended"]]}]))))) + +(def env + (env/make-env jdbc-config schema)) + +(deftest multi-query-test + (testing "adding two new accounts via a multi query mutation" + (mutate! env ::account/add-two {})) + + (testing "retrieving newly created account by name" + (let [{::account/keys [state]} (q/execute env [::account/name "hello"])] + (is (= state :active))) + (let [{::account/keys [state]} (q/execute env [::account/name "bye"])] + (is (= state :suspended)))) + + (mutate! env ::account/delete-two {}))