Skip to content

Commit 61105be

Browse files
Implement type-fns support for PK (#87)
1 parent dfe0bf4 commit 61105be

File tree

5 files changed

+66
-11
lines changed

5 files changed

+66
-11
lines changed

src/toucan/db.clj

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -456,10 +456,11 @@
456456
*plus* other clauses).
457457
458458
(where+ {} [:id 1 {:limit 10}]) -> {:where [:= :id 1], :limit 10}"
459-
[honeysql-form args]
459+
[model honeysql-form args]
460460
(loop [honeysql-form honeysql-form, [first-arg & [second-arg & more, :as butfirst]] args]
461461
(cond
462-
(keyword? first-arg) (recur (where honeysql-form first-arg second-arg) more)
462+
(keyword? first-arg) (recur (where honeysql-form first-arg
463+
(models/do-type-fn model first-arg second-arg :in)) more)
463464
first-arg (recur (merge honeysql-form first-arg) butfirst)
464465
:else honeysql-form)))
465466

@@ -486,10 +487,10 @@
486487
{:pre [(some? id) (map? kvs) (every? keyword? (keys kvs))]}
487488
(let [model (resolve-model model)
488489
primary-key (models/primary-key model)
489-
kvs (-> (models/do-pre-update model (assoc kvs primary-key id))
490-
(dissoc primary-key))
490+
kvs-with-pk (models/do-pre-update model (assoc kvs primary-key id))
491+
kvs (dissoc kvs-with-pk primary-key)
491492
updated? (update! model (-> (h/sset {} kvs)
492-
(where primary-key id)))]
493+
(where primary-key (primary-key kvs-with-pk))))]
493494
(when (and updated?
494495
(method-implemented? :post-update model))
495496
(models/post-update (model id)))
@@ -608,7 +609,7 @@
608609
{:pre [(map? row-map) (every? keyword? (keys row-map))]}
609610
(let [model (resolve-model model)]
610611
(when-let [id (simple-insert! model (models/do-pre-insert model row-map))]
611-
(models/post-insert (model id)))))
612+
(models/post-insert (model (models/do-type-fn model (models/primary-key model) id :out))))))
612613
([model k v & more]
613614
(insert! model (apply array-map k v more))))
614615

@@ -624,7 +625,7 @@
624625
{:style/indent 1}
625626
[model & options]
626627
(let [fields (model->fields model)]
627-
(simple-select-one model (where+ {:select (or fields [:*])} options))))
628+
(simple-select-one model (where+ (resolve-model model) {:select (or fields [:*])} options))))
628629

629630
(defn select-one-field
630631
"Select a single `field` of a single object from the database.
@@ -659,7 +660,8 @@
659660
(select 'Database :name [:not= nil] {:limit 2}) -> [...]"
660661
{:style/indent 1}
661662
[model & options]
662-
(simple-select model (where+ {:select (or (model->fields model)
663+
(simple-select model (where+ (resolve-model model)
664+
{:select (or (model->fields model)
663665
[:*])}
664666
options)))
665667

@@ -670,7 +672,8 @@
670672
-> [\"name1\", \"name2\"]"
671673
{:style/indent 1}
672674
[model & options]
673-
(simple-select-reducible model (where+ {:select (or (model->fields model)
675+
(simple-select-reducible model (where+ (resolve-model model)
676+
{:select (or (model->fields model)
674677
[:*])}
675678
options)))
676679

@@ -768,4 +771,5 @@
768771
primary-key (models/primary-key model)]
769772
(doseq [object (apply select model conditions)]
770773
(models/pre-delete object)
771-
(simple-delete! model primary-key (primary-key object)))))
774+
(simple-delete! model primary-key
775+
(models/do-type-fn model primary-key (primary-key object) :in)))))

src/toucan/models.clj

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,13 @@
351351
(map-> model <>)
352352
(apply-property-fns :select <>)))
353353

354+
(defn do-type-fn
355+
"Don't call this directly! This is automatically applied when doing select."
356+
[model col v direction]
357+
(if-let [type (col (types model))]
358+
((get-in @type-fns [type direction]) v)
359+
v))
360+
354361
(def IModelDefaults
355362
"Default implementations for `IModel` methods."
356363
{:default-fields (constantly nil)

test/toucan/db_test.clj

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
[toucan.test-models
1111
[address :refer [Address]]
1212
[category :refer [Category]]
13+
[food :refer [Food]]
1314
[phone-number :refer [PhoneNumber]]
1415
[user :refer [User]]
1516
[venue :refer [Venue]]])
@@ -286,6 +287,13 @@
286287
(db/update! PhoneNumber id :country_code "AU")
287288
(db/select-one PhoneNumber :number id))))
288289

290+
(expect
291+
#toucan.test_models.food.FoodInstance{:id "F4", :price 42.42M}
292+
(test/with-clean-db
293+
(db/insert! Food {:id "F4" :price 9.01M})
294+
(db/update! Food "F4" :price 42.42M)
295+
(db/select-one Food :id "F4")))
296+
289297
;; Test update-where!
290298
(expect
291299
[#toucan.test_models.user.UserInstance{:id 1, :first-name "Cam", :last-name "Saul"}
@@ -502,3 +510,11 @@
502510
(db/exists? User, :first-name "Kanye", :last-name "Nest"))
503511

504512
;; TODO - Test delete!
513+
514+
;; Test delete! with transformed PK
515+
(expect
516+
0
517+
(test/with-clean-db
518+
(db/insert! Food {:id "F4" :price 9.01M})
519+
(db/delete! Food :id "F4")
520+
(db/count Food :id "F4")))

test/toucan/test_models/food.clj

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
(ns toucan.test-models.food
2+
"A model with BYTEA as primary key."
3+
(:require [toucan.models :as models])
4+
(:import (java.nio.charset StandardCharsets)))
5+
6+
(defn- str->bytes [s]
7+
(when s
8+
(.getBytes s StandardCharsets/UTF_8)))
9+
10+
(defn- bytes->str [b]
11+
(when b
12+
(String. b StandardCharsets/UTF_8)))
13+
14+
;; Store string as byte array in the database
15+
(models/add-type! :string-as-bytes
16+
:in str->bytes
17+
:out bytes->str)
18+
19+
(models/defmodel Food :foods
20+
models/IModel
21+
(types [_]
22+
{:id :string-as-bytes}))

test/toucan/test_setup.clj

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,13 @@
7070
number TEXT PRIMARY KEY,
7171
country_code VARCHAR(3) NOT NULL
7272
);"
73-
"TRUNCATE TABLE phone_numbers;"))
73+
"TRUNCATE TABLE phone_numbers;"
74+
;; Food
75+
"CREATE TABLE IF NOT EXISTS foods (
76+
id BYTEA PRIMARY KEY,
77+
price DECIMAL(10,2) NOT NULL
78+
);"
79+
"TRUNCATE TABLE foods;"))
7480

7581

7682
(def ^java.sql.Timestamp jan-first-2017 (Timestamp/valueOf "2017-01-01 00:00:00"))

0 commit comments

Comments
 (0)