;; copyright (c) 2024 Sean Corfield, all rights reserved

(ns next.jdbc.defer-test
  "The idea behind the next.jdbc.defer namespace is to provide a
   way to defer the execution of a series of SQL statements until
   a later time, but still provide a way for inserted keys to be
   used in later SQL statements.

   The principle is to provide a core subset of the next.jdbc
   and next.jdbc.sql API that produces a data structure that
   describes a series of SQL operations to be performed, that
   are held in a dynamic var, and that can be executed at a
   later time, in a transaction."
  (:require [clojure.test :refer [deftest is testing use-fixtures]]
            [next.jdbc :as jdbc]
            [next.jdbc.defer :as sut]
            [next.jdbc.test-fixtures
             :refer [ds with-test-db]]))

(set! *warn-on-reflection* true)

(use-fixtures :once with-test-db)

(deftest basic-test
  (testing "data structures"
    (is (= [{:sql-p ["INSERT INTO foo (name) VALUES (?)" "Sean"]
             :key-fn :GENERATED_KEY
             :key    :id
             :opts   {:key-fn :GENERATED_KEY :key :id}}]
           @(sut/defer-ops
             #(sut/insert! :foo {:name "Sean"} {:key-fn :GENERATED_KEY :key :id})))))
  (testing "execution"
    (let [effects (sut/with-deferred (ds)
                    (sut/insert! :fruit {:name "Mango"} {:key :test}))]
      (is (= {:test 1} @effects))
      (is (= 1 (count (jdbc/execute! (ds)
                                     ["select * from fruit where name = ?"
                                      "Mango"])))))
    (let [effects (sut/with-deferred (ds)
                    (sut/insert! :fruit {:name "Dragonfruit"} {:key :test})
                    (sut/update! :fruit {:cost 123} {:name "Dragonfruit"})
                    (sut/delete! :fruit {:name "Dragonfruit"}))]
      (is (= {:test 1} @effects))
      (is (= 0 (count (jdbc/execute! (ds)
                                     ["select * from fruit where name = ?"
                                      "Dragonfruit"])))))
    (let [effects (sut/with-deferred (ds)
                    (sut/insert! :fruit {:name "Grapefruit" :bad_column 0} {:key :test}))]
      (is (= :failed (try @effects
                          (catch Exception _ :failed))))
      (is (= 0 (count (jdbc/execute! (ds)
                                     ["select * from fruit where name = ?"
                                      "Grapefruit"])))))))
