-- :name get-user-type :? :*
-- :doc get user by type
select id, name from users where type = :type order by id
Now comes the mythical test code. Let's suppose "db/add-user!" exists, performs database inserts into the users table and returns 1 as return value.
(deftest test-user
(jdbc/with-db-transaction [t-conn *db*]
(jdbc/db-set-rollback-only! t-conn)
(is (= 1 (db/add-user!
t-conn
{:username "u123"
:type "admin"})))
(is (= {:username "u123"
:type "admin"}
(db/get-user-type t-conn {:type "admin"}))))))
But alas! This is an epic failure!
(expected: {:username "u123",
:type "admin"}
actual: ({:id 1,
:username "u123",
:type "admin"})
It appears that ":id" value is an auto-generated primary key and this equality test is not going to work.
Perhaps, I could define a function to remove the id before comparing? This might work as the id is a surrogated key automatically populated by the database.
(defn match-record
[expected record]
(= expected (dissoc record :id)))
Or perhaps I could raise the bar higher by writing a macro? After all, I've heard Clojure macro is a powerful language extension.
(defmacro match-record
[expected record]
`(= ~expected (dissoc ~record :id)))
This is really exciting - my first ever Clojure macro!
So, rewriting my test code gives me,
(deftest test-user
(jdbc/with-db-transaction [t-conn *db*]
(jdbc/db-set-rollback-only! t-conn)
(is (= 1 (db/add-user!
t-conn
{:username "u123"
:type "admin"})))
(let [result (db/get-user-type t-conn {:type "admin"})](jdbc/with-db-transaction [t-conn *db*]
(jdbc/db-set-rollback-only! t-conn)
(is (= 1 (db/add-user!
t-conn
{:username "u123"
:type "admin"})))
(is (match-record {:username "u123"
:type "admin"}
(first result))))))
I know my macro is sub-optimal here and there are better ways of doing this. But hey! I'm certain my dear mother will be proud of me!