|
| 1 | +(ns otus-27.repl |
| 2 | + (:require [next.jdbc :as jdbc] |
| 3 | + [next.jdbc.result-set :as rs] |
| 4 | + [next.jdbc.sql :as jdbc.sql])) |
| 5 | + |
| 6 | +(comment |
| 7 | + ;; https://clojuredocs.org/clojure.core/*print-namespace-maps* |
| 8 | + (set! *print-namespace-maps* false) |
| 9 | + (set! *print-namespace-maps* true)) |
| 10 | + |
| 11 | +;; next.jdbc |
| 12 | + |
| 13 | +;; db-spec -> DataSource -> Connection |
| 14 | +(def db {:dbtype "h2" ; h2:mem |
| 15 | + :dbname "example"}) |
| 16 | + |
| 17 | +(def ds (jdbc/get-datasource db)) |
| 18 | + |
| 19 | +(with-open [conn (jdbc/get-connection ds)] |
| 20 | + (jdbc/execute! conn ...)) |
| 21 | + |
| 22 | +;; Primary API |
| 23 | +(jdbc/execute! ds ["select * from information_schema.tables"]) |
| 24 | + |
| 25 | +(reduce (fn [res row] |
| 26 | + (conj res |
| 27 | + (select-keys row |
| 28 | + [:tables/table_name |
| 29 | + :tables/table_type]))) |
| 30 | + [] |
| 31 | + (jdbc/plan ; [connectable sql-params opts] |
| 32 | + ds |
| 33 | + ["select * from information_schema.tables"])) |
| 34 | + |
| 35 | + |
| 36 | +(jdbc/execute-one! ds [" |
| 37 | +create table address ( |
| 38 | + id int auto_increment primary key, |
| 39 | + name varchar(32), |
| 40 | + email varchar(255) |
| 41 | +)"]) |
| 42 | + |
| 43 | +(jdbc/execute-one! ds [" |
| 44 | +insert into address(name, email) |
| 45 | + values('Clojure Developer', '[email protected]')"]) |
| 46 | + |
| 47 | +(jdbc/execute! ds ["select * from address"]) |
| 48 | + |
| 49 | +(jdbc/execute-one! ds ["insert into address(name, email) |
| 50 | + values('Java Developer', '[email protected]') |
| 51 | +"] {:return-keys true}) |
| 52 | + |
| 53 | +(jdbc/execute-one! ds ["select * from address where id = ?" 2]) |
| 54 | +(jdbc/execute-one! ds ["select * from address where id = ?" 3]) |
| 55 | + |
| 56 | +;; Options & Result Set Builders |
| 57 | +;; https://cljdoc.org/d/com.github.seancorfield/next.jdbc/1.3.909/doc/all-the-options#generating-rows-and-result-sets |
| 58 | +(require '[next.jdbc.result-set :as rs]) |
| 59 | + |
| 60 | +(jdbc/execute-one! ds ["select * from address where id = ?" 2] |
| 61 | + {:builder-fn rs/as-unqualified-lower-maps}) |
| 62 | + |
| 63 | +;; plan & Reducing Result Sets |
| 64 | +(jdbc/execute-one! ds [" |
| 65 | +create table invoice ( |
| 66 | + id int auto_increment primary key, |
| 67 | + product varchar(32), |
| 68 | + unit_price decimal(10,2), |
| 69 | + unit_count int, |
| 70 | + customer_id int |
| 71 | +)"]) |
| 72 | + |
| 73 | +(jdbc/execute-one! ds [" |
| 74 | +insert into invoice (product, unit_price, unit_count, customer_id) |
| 75 | +values ('apple', 0.99, 6, 100), |
| 76 | + ('banana', 1.25, 3, 100), |
| 77 | + ('cucumber', 2.49, 2, 100) |
| 78 | +"]) |
| 79 | + |
| 80 | +(reduce |
| 81 | + (fn [cost row] |
| 82 | + (+ cost (* (:unit_price row) |
| 83 | + (:unit_count row)))) |
| 84 | + 0 |
| 85 | + (jdbc/plan ds ["select * from invoice where customer_id = ?" 100])) |
| 86 | + |
| 87 | +(transduce |
| 88 | + (map #(* (:unit_price %) (:unit_count %))) |
| 89 | + + |
| 90 | + 0 |
| 91 | + (jdbc/plan ds ["select * from invoice where customer_id = ?" 100])) |
| 92 | + |
| 93 | +(transduce |
| 94 | + (comp (map (juxt :unit_price :unit_count)) |
| 95 | + (map #(apply * %))) |
| 96 | + + |
| 97 | + 0 |
| 98 | + (jdbc/plan ds ["select * from invoice where customer_id = ?" 100])) |
| 99 | + |
| 100 | +(transduce |
| 101 | + (map :unit_count) |
| 102 | + + |
| 103 | + 0 |
| 104 | + (jdbc/plan ds ["select * from invoice where customer_id = ?" 100])) |
| 105 | + |
| 106 | +;; set of unique products |
| 107 | +(into #{} |
| 108 | + (map :product) |
| 109 | + (jdbc/plan ds ["select * from invoice where customer_id = ?" 100])) |
| 110 | + |
| 111 | +;; use run! for side-effects |
| 112 | +(run! #(println (:product %)) |
| 113 | + (jdbc/plan ds ["select * from invoice where customer_id = ?" 100])) |
| 114 | + |
| 115 | + |
| 116 | +;; selects specific keys (as simple keywords): |
| 117 | +(into [] |
| 118 | + (map #(select-keys % [:id :product :unit_price :unit_count :customer_id])) |
| 119 | + (jdbc/plan ds ["select * from invoice where customer_id = ?" 100])) |
| 120 | + |
| 121 | +;; selects specific keys (as qualified keywords): |
| 122 | +(into [] |
| 123 | + (map #(select-keys % [:invoice/id :invoice/product |
| 124 | + :invoice/unit_price :invoice/unit_count |
| 125 | + :invoice/customer_id])) |
| 126 | + (jdbc/plan ds ["select * from invoice where customer_id = ?" 100])) |
| 127 | + |
| 128 | +;; selects specific keys (as qualified keywords -- ignoring the table name): |
| 129 | +(into [] |
| 130 | + (map #(select-keys % [:foo/id :bar/product |
| 131 | + :quux/unit_price :wibble/unit_count |
| 132 | + :blah/customer_id])) |
| 133 | + (jdbc/plan ds ["select * from invoice where customer_id = ?" 100])) |
| 134 | + |
| 135 | +;; do not do this: |
| 136 | +(into [] |
| 137 | + (map #(into {} %)) |
| 138 | + (jdbc/plan ds ["select * from invoice where customer_id = ?" 100])) |
| 139 | + |
| 140 | +;; https://clojure.org/reference/datafy |
| 141 | +;; do this if you just want realized rows with default qualified names: |
| 142 | +(into [] |
| 143 | + (map #(rs/datafiable-row % ds {})) |
| 144 | + (jdbc/plan ds ["select * from invoice where customer_id = ?" 100])) |
| 145 | + |
| 146 | + |
| 147 | +;; Datasources, Connections & Transactions |
| 148 | +(with-open [con (jdbc/get-connection ds)] |
| 149 | + (jdbc/execute! con ...) |
| 150 | + (jdbc/execute! con ...) |
| 151 | + (into [] (map :column) (jdbc/plan con ...))) |
| 152 | + |
| 153 | + |
| 154 | +(jdbc/with-transaction [tx ds] |
| 155 | + (jdbc/execute! tx ...) |
| 156 | + (jdbc/execute! tx ...) |
| 157 | + (into [] (map :column) (jdbc/plan tx ...))) |
| 158 | + |
| 159 | +;; Joins |
| 160 | +(jdbc/execute-one! ds [" |
| 161 | +create table owners ( |
| 162 | + id int auto_increment primary key, |
| 163 | + name varchar(255) not null |
| 164 | +)"]) |
| 165 | + |
| 166 | +(jdbc/execute-one! ds [" |
| 167 | +create table pets ( |
| 168 | + id int auto_increment primary key, |
| 169 | + name varchar(255) not null, |
| 170 | + owner int not null |
| 171 | + references owners(id) |
| 172 | + on delete cascade |
| 173 | +)"]) |
| 174 | + |
| 175 | +(jdbc/execute! ds ["insert into owners (name) values (?), (?)" |
| 176 | + "Bob" |
| 177 | + "Alice"]) |
| 178 | + |
| 179 | +;; Friendly SQL Functions |
| 180 | +;; https://cljdoc.org/d/com.github.seancorfield/next.jdbc/1.3.909/doc/getting-started/friendly-sql-functions |
| 181 | +(require '[next.jdbc.sql :as jdbc.sql]) |
| 182 | + |
| 183 | +(jdbc.sql/insert! ds :owners {:name "Tom"}) |
| 184 | + |
| 185 | +(jdbc/execute! ds ["select id, name from owners"]) |
| 186 | + |
| 187 | +(jdbc/with-transaction [tx ds] |
| 188 | + (jdbc.sql/insert-multi! |
| 189 | + tx |
| 190 | + :pets |
| 191 | + [{:name "Skipper" :owner 1} |
| 192 | + {:name "Spot" :owner 2} |
| 193 | + {:name "Stinky" :owner 2} |
| 194 | + {:name "Jerry" :owner 3}])) |
| 195 | + |
| 196 | +(jdbc.sql/find-by-keys ds :pets {:owner 2}) |
| 197 | + |
| 198 | +(jdbc/execute! ds [" |
| 199 | +select |
| 200 | + o.name as owner, |
| 201 | + p.name as pet |
| 202 | +from owners as o |
| 203 | + left join pets as p |
| 204 | + on p.owner = o.id |
| 205 | +"]) |
| 206 | + |
| 207 | +;; HoneySQL |
| 208 | +(require '[honey.sql :as sql]) |
| 209 | + |
| 210 | +(jdbc/execute! |
| 211 | + ds |
| 212 | + (sql/format {:from [[:pets :p]] |
| 213 | + :select [:p.name :o.name] |
| 214 | + :where [[:= :p.name [:param :?]]] |
| 215 | + :left-join [[:owners :o] |
| 216 | + [:= :p.owner :o.id]]} |
| 217 | + {:params {:? "Skipper"}})) |
| 218 | + |
| 219 | +(jdbc/execute! |
| 220 | + ds |
| 221 | + (sql/format '{from ((pets p)) |
| 222 | + select (p.name, o.name) |
| 223 | + where ((= p.name (param :?))) |
| 224 | + left-join ((owners o) |
| 225 | + (= p.owner o.id))} |
| 226 | + {:params {:? "Jerry"}})) |
| 227 | + |
| 228 | +(require '[honey.sql.helpers :as h]) |
| 229 | + |
| 230 | +(jdbc/execute! |
| 231 | + ds |
| 232 | + (sql/format (-> {} |
| 233 | + (h/select :p.name :p.name) |
| 234 | + (h/from [:pets :p]) |
| 235 | + (h/where [:= :p.name [:param :?]]) |
| 236 | + (h/left-join [:owners :o] |
| 237 | + [:= :p.owner :o.id])) |
| 238 | + {:params {:? "Jerry"}})) |
0 commit comments