honeysql/test/honey/sql/xtdb_test.cljc
Sean Corfield f0eb68f151
add helper for #567 and helper-based tests
Signed-off-by: Sean Corfield <sean@corfield.org>
2025-02-20 17:12:31 -08:00

148 lines
7.6 KiB
Clojure

;; copyright (c) 2020-2025 sean corfield, all rights reserved
(ns honey.sql.xtdb-test
(:require [clojure.test :refer [deftest is testing]]
[honey.sql :as sql]
[honey.sql.helpers :as h
:refer [select exclude rename from]]))
(deftest select-tests
(testing "select, exclude, rename"
(is (= ["SELECT * EXCLUDE _id RENAME value AS foo_value FROM foo"]
(sql/format (-> (select :*) (exclude :_id) (rename [:value :foo_value])
(from :foo)))))
(is (= ["SELECT * EXCLUDE (_id, a) RENAME value AS foo_value FROM foo"]
(sql/format (-> (select :*) (exclude :_id :a) (rename [:value :foo_value])
(from :foo)))))
(is (= ["SELECT * EXCLUDE _id RENAME (value AS foo_value, a AS b) FROM foo"]
(sql/format (-> (select :*) (exclude :_id)
(rename [:value :foo_value]
[:a :b])
(from :foo)))))
(is (= ["SELECT * EXCLUDE _id RENAME value AS foo_value, c.x FROM foo"]
(sql/format (-> (select [:* (-> (exclude :_id) (rename [:value :foo_value]))]
:c.x)
(from :foo)))))
(is (= ["SELECT * EXCLUDE (_id, a) RENAME value AS foo_value, c.x FROM foo"]
(sql/format (-> (select [:* (-> (exclude :_id :a) (rename [:value :foo_value]))]
:c.x)
(from :foo)))))
(is (= ["SELECT * EXCLUDE _id RENAME (value AS foo_value, a AS b), c.x FROM foo"]
(sql/format (-> (select [:* (-> (exclude :_id)
(rename [:value :foo_value]
[:a :b]))]
:c.x)
(from :foo))))))
(testing "select, nest_one, nest_many"
(is (= ["SELECT a._id, NEST_ONE (SELECT * FROM foo AS b WHERE b_id = a._id) FROM bar AS a"]
(sql/format '{select (a._id,
((nest_one {select * from ((foo b)) where (= b_id a._id)})))
from ((bar a))})))
(is (= ["SELECT a._id, NEST_MANY (SELECT * FROM foo AS b) FROM bar AS a"]
(sql/format '{select (a._id,
((nest_many {select * from ((foo b))})))
from ((bar a))})))))
(deftest dotted-array-access-tests
(is (= ["SELECT (a.b).c"] ; old, partial support:
(sql/format '{select (((. (nest :a.b) :c)))})))
(is (= ["SELECT (a.b).c"] ; new, complete support:
(sql/format '{select (((:get-in :a.b :c)))})))
(is (= ["SELECT (a).b.c"] ; the first expression is always parenthesized:
(sql/format '{select (((:get-in :a :b :c)))}))))
(deftest erase-from-test
(is (= ["ERASE FROM foo WHERE foo.id = ?" 42]
(-> {:erase-from :foo
:where [:= :foo.id 42]}
(sql/format))))
(is (= ["ERASE FROM foo WHERE foo.id = ?" 42]
(-> (h/erase-from :foo)
(h/where [:= :foo.id 42])
(sql/format)))))
(deftest inline-record-body
(is (= ["{_id: 1, name: 'foo', info: {contact: [{loc: 'home', tel: '123'}, {loc: 'work', tel: '456'}]}}"]
(sql/format [:inline {:_id 1 :name "foo"
:info {:contact [{:loc "home" :tel "123"}
{:loc "work" :tel "456"}]}}]))))
(deftest records-statement
(testing "auto-lift maps"
(is (= ["RECORDS ?, ?" {:_id 1 :name "cat"} {:_id 2 :name "dog"}]
(sql/format {:records [{:_id 1 :name "cat"}
{:_id 2 :name "dog"}]}))))
(testing "explicit inline"
(is (= ["RECORDS {_id: 1, name: 'cat'}, {_id: 2, name: 'dog'}"]
(sql/format {:records [[:inline {:_id 1 :name "cat"}]
[:inline {:_id 2 :name "dog"}]]}))))
(testing "insert with records"
(is (= ["INSERT INTO foo RECORDS {_id: 1, name: 'cat'}, {_id: 2, name: 'dog'}"]
(sql/format {:insert-into :foo
:records [[:inline {:_id 1 :name "cat"}]
[:inline {:_id 2 :name "dog"}]]})))
(is (= ["INSERT INTO foo RECORDS {_id: 1, name: 'cat'}, {_id: 2, name: 'dog'}"]
(sql/format {:insert-into :foo
:records [[:inline {:_id 1 :name "cat"}]
[:inline {:_id 2 :name "dog"}]]})))
(is (= ["INSERT INTO foo RECORDS ?, ?" {:_id 1 :name "cat"} {:_id 2 :name "dog"}]
(sql/format {:insert-into [:foo ; as a sub-clause
{:records [{:_id 1 :name "cat"}
{:_id 2 :name "dog"}]}]})))))
(deftest patch-statement
(testing "patch with records"
(is (= ["PATCH INTO foo RECORDS {_id: 1, name: 'cat'}, {_id: 2, name: 'dog'}"]
(sql/format {:patch-into [:foo]
:records [[:inline {:_id 1 :name "cat"}]
[:inline {:_id 2 :name "dog"}]]})))
(is (= ["PATCH INTO foo RECORDS ?, ?" {:_id 1 :name "cat"} {:_id 2 :name "dog"}]
(sql/format {:patch-into [:foo ; as a sub-clause
{:records [{:_id 1 :name "cat"}
{:_id 2 :name "dog"}]}]})))
(is (= ["PATCH INTO foo RECORDS ?, ?" {:_id 1 :name "cat"} {:_id 2 :name "dog"}]
(sql/format (h/patch-into :foo
(h/records [{:_id 1 :name "cat"}
{:_id 2 :name "dog"}])))))))
(deftest object-record-expr
(testing "object literal"
(is (= ["SELECT OBJECT (_id: 1, name: 'foo')"]
(sql/format {:select [[[:object {:_id 1 :name "foo"}]]]})))
(is (= ["SELECT OBJECT (_id: 1, name: 'foo')"]
(sql/format '{select (((:object {:_id 1 :name "foo"})))}))))
(testing "record literal"
(is (= ["SELECT RECORD (_id: 1, name: 'foo')"]
(sql/format {:select [[[:record {:_id 1 :name "foo"}]]]})))
(is (= ["SELECT RECORD (_id: 1, name: 'foo')"]
(sql/format '{select (((:record {:_id 1 :name "foo"})))}))))
(testing "inline map literal"
(is (= ["SELECT {_id: 1, name: 'foo'}"]
(sql/format {:select [[[:inline {:_id 1 :name "foo"}]]]})))))
(deftest navigation-dot-index
(is (= ["SELECT (a.b).c[1].d"]
(sql/format '{select (((get-in a.b c 1 d)))})))
(is (= ["SELECT (a.b).c[?].d" 1]
(sql/format '{select (((get-in a.b c (lift 1) d)))})))
(is (= ["SELECT (a.b).c[?].d" 1]
(sql/format '{select (((get-in (. a b) c (lift 1) d)))})))
(is (= ["SELECT (OBJECT (_id: 1, b: 'thing').b).c[?].d" 1]
(sql/format '{select (((get-in (. (object {_id 1 b "thing"}) b) c (lift 1) d)))}))))
(deftest assert-statement
(testing "quoted sql"
(is (= ["ASSERT NOT EXISTS (SELECT 1 FROM users WHERE email = 'james @example.com')"]
(sql/format '{assert (not-exists {select 1 from users where (= email "james @example.com")})}
:inline true)))
(is (= ["ASSERT TRUE"]
(sql/format '{assert true}
:inline true))))
(testing "helper"
(is (= ["ASSERT NOT EXISTS (SELECT 1 FROM users WHERE email = 'james @example.com')"]
(-> (h/assert [:not-exists {:select 1 :from :users :where [:= :email "james @example.com"]}])
(sql/format {:inline true}))))
(is (= ["ASSERT NOT EXISTS (SELECT 1 FROM users WHERE email = 'james @example.com')"]
(-> {}
(h/assert [:not-exists {:select 1 :from :users :where [:= :email "james @example.com"]}])
(sql/format {:inline true}))))))