Skip to content

Commit b89738f

Browse files
author
Blue
authored
databases.md: Prefer deftable to defclass when appropriate (#392)
The deftable macro automates the creation of accessors and initargs, making it much less verbose and more closely resembling the library's documentation. All instances of defclass where the metaclass is mito:dao-table-class have been replaced with an equivalent deftable form.
1 parent 9d28ecb commit b89738f

File tree

1 file changed

+46
-110
lines changed

1 file changed

+46
-110
lines changed

databases.md

Lines changed: 46 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ The driver type can be of `:mysql`, `:sqlite3` and `:postgres`.
7070
With sqlite you don't need the username and password:
7171

7272
~~~lisp
73-
(connect-toplevel :sqlite3 :database-name "myapp")
73+
(mito:connect-toplevel :sqlite3 :database-name "myapp")
7474
~~~
7575

7676
As usual, you need to create the MySQL or PostgreSQL database beforehand.
@@ -80,36 +80,28 @@ Connecting sets `mito:*connection*` to the new connection and returns it.
8080

8181
Disconnect with `disconnect-toplevel`.
8282

83-
=> you might make good use of a wrapper function:
83+
You might make good use of a wrapper function:
8484

8585
~~~lisp
8686
(defun connect ()
8787
"Connect to the DB."
88-
(connect-toplevel :sqlite3 :database-name "myapp"))
88+
(mito:connect-toplevel :sqlite3 :database-name "myapp"))
8989
~~~
9090

9191
### Models
9292

9393
#### Defining models
9494

95-
In Mito, you can define a class which corresponds to a database table
96-
by specifying `(:metaclass mito:dao-table-class)`:
95+
In Mito, you can define a class which corresponds to a database table with the `deftable` macro:
9796

9897
~~~lisp
99-
(defclass user ()
100-
((name :col-type (:varchar 64)
101-
:initarg :name
102-
:accessor user-name)
103-
(email :col-type (or (:varchar 128) :null)
104-
:initarg :email
105-
:accessor user-email))
106-
(:metaclass mito:dao-table-class))
98+
(mito:deftable user ()
99+
((name :col-type (:varchar 64))
100+
(email :col-type (or (:varchar 128) :null)))
107101
~~~
102+
Alternatively, you can specify `(:metaclass mito:dao-table-class)` in a regular class definition.
108103

109-
Note that the class automatically adds some slots: a primary key named `id`
110-
if there's no primary keys, `created_at` and `updated_at` for
111-
recording timestamps. To disable these behaviors, specify `:auto-pk
112-
nil` or `:record-timestamps nil` to the defclass forms.
104+
The `deftable` macro automatically adds some slots: a primary key named `id` if there's no primary key, and `created_at` and `updated_at` for recording timestamps. Specifying `(:auto-pk nil)` and `(:record-timestamps nil)` in the `deftable` form will disable these behaviours. A `deftable` class will also come with initializers, named after the slot, and accessors, of form `<class-name>-<slot-name>`, for each named slot. For example, for the `name` slot in the above table definition, the initarg `:name` will be added to the constuctor, and the accessor `user-name` will be created.
113105

114106
You can inspect the new class:
115107

@@ -151,7 +143,7 @@ So a helper function:
151143

152144
~~~lisp
153145
(defun ensure-tables ()
154-
(mapcar #'mito:ensure-table-exists '('user 'foo 'bar)))
146+
(mapcar #'mito:ensure-table-exists '(user foo bar)))
155147
~~~
156148

157149

@@ -180,9 +172,7 @@ Field types are:
180172
Use `(or <real type> :null)`:
181173

182174
~~~lisp
183-
(email :col-type (or (:varchar 128) :null)
184-
:initarg :email
185-
:accessor user-email))
175+
(email :col-type (or (:varchar 128) :null))
186176
~~~
187177

188178

@@ -191,14 +181,9 @@ Use `(or <real type> :null)`:
191181
`:unique-keys` can be used like so:
192182

193183
~~~lisp
194-
(defclass user ()
195-
((name :col-type (:varchar 64)
196-
:initarg :name
197-
:accessor user-name)
198-
(email :col-type (:varchar 128)
199-
:initarg :email
200-
:accessor user-email))
201-
(:metaclass mito:dao-table-class)
184+
(mito:deftable user ()
185+
((name :col-type (:varchar 64))
186+
(email :col-type (:varchar 128))
202187
(:unique-keys email))
203188
~~~
204189

@@ -211,15 +196,10 @@ You can change the table name with `:table-name`.
211196
You can define a relationship by specifying a foreign class with `:col-type`:
212197

213198
~~~lisp
214-
(defclass tweet ()
215-
((status :col-type :text
216-
:initarg :status
217-
:accessor tweet-status)
199+
(mito:deftable tweet ()
200+
((status :col-type :text)
218201
;; This slot refers to USER class
219-
(user :col-type user
220-
:initarg :user
221-
:accessor tweet-user))
222-
(:metaclass mito:dao-table-class))
202+
(user :col-type user))
223203
224204
(table-definition (find-class 'tweet))
225205
;=> (#<SXQL-STATEMENT: CREATE TABLE tweet (
@@ -272,31 +252,19 @@ And, thanks to the join table, we can store more information about the relations
272252
Let's define a `book` class:
273253

274254
~~~lisp
275-
(defclass book ()
276-
((title
277-
:col-type (:varchar 128)
278-
:initarg :title
279-
:accessor title)
280-
(ean
281-
:col-type (or (:varchar 128) :null)
282-
:initarg :ean
283-
:accessor ean))
284-
(:metaclass mito:dao-table-class))
255+
(mito:deftable book ()
256+
((title :col-type (:varchar 128))
257+
(ean :col-type (or (:varchar 128) :null))))
285258
~~~
286259

287260
A user can have many books, and a book (as the title, not the physical
288261
copy) is likely to be in many people's library. Here's the
289262
intermediate class:
290263

291264
~~~lisp
292-
(defclass user-books ()
293-
((user
294-
:col-type user
295-
:initarg :user)
296-
(book
297-
:col-type book
298-
:initarg :book))
299-
(:metaclass mito:dao-table-class))
265+
(mito:deftable user-books ()
266+
((user :col-type user)
267+
(book :col-type book)))
300268
~~~
301269

302270
Each time we want to add a book to a user's collection (say in
@@ -306,20 +274,11 @@ But someone may very well own many copies of one book. This is an
306274
information we can store in the join table:
307275

308276
~~~lisp
309-
(defclass user-books ()
310-
((user
311-
:col-type user
312-
:initarg :user)
313-
(book
314-
:col-type book
315-
:initarg :book)
277+
(mito:deftable user-books ()
278+
((user :col-type user)
279+
(book :col-type book)
316280
;; Set the quantity, 1 by default:
317-
(quantity
318-
:col-type :integer
319-
:initarg :quantity
320-
:initform 1
321-
:accessor quantity))
322-
(:metaclass mito:dao-table-class))
281+
(quantity :col-type :integer)))
323282
~~~
324283

325284

@@ -329,21 +288,13 @@ A subclass of DAO-CLASS is allowed to be inherited. This may be useful
329288
when you need classes which have similar columns:
330289

331290
~~~lisp
332-
(defclass user ()
333-
((name :col-type (:varchar 64)
334-
:initarg :name
335-
:accessor user-name)
336-
(email :col-type (:varchar 128)
337-
:initarg :email
338-
:accessor user-email))
339-
(:metaclass mito:dao-table-class)
291+
(mito:deftable user ()
292+
((name :col-type (:varchar 64))
293+
(email :col-type (:varchar 128)))
340294
(:unique-keys email))
341295
342-
(defclass temporary-user (user)
343-
((registered-at :col-type :timestamp
344-
:initarg :registered-at
345-
:accessor temporary-user-registered-at))
346-
(:metaclass mito:dao-table-class))
296+
(mito:deftable temporary-user (user)
297+
((registered-at :col-type :timestamp)))
347298
348299
(mito:table-definition 'temporary-user)
349300
;=> (#<SXQL-STATEMENT: CREATE TABLE temporary_user (
@@ -357,9 +308,9 @@ when you need classes which have similar columns:
357308
; )>)
358309
~~~
359310

360-
If you need a 'template' for tables which doesn't related to any
361-
database tables, you can use `DAO-TABLE-MIXIN`. Below the `has-email`
362-
class will not create a table.
311+
If you need a 'template' for tables which aren't related to any
312+
database tables, you can use `DAO-TABLE-MIXIN` in a `defclass` form. The `has-email`
313+
class below will not create a table.
363314

364315
~~~lisp
365316
(defclass has-email ()
@@ -370,11 +321,8 @@ class will not create a table.
370321
(:unique-keys email))
371322
;=> #<MITO.DAO.MIXIN:DAO-TABLE-MIXIN COMMON-LISP-USER::HAS-EMAIL>
372323
373-
(defclass user (has-email)
374-
((name :col-type (:varchar 64)
375-
:initarg :name
376-
:accessor user-name))
377-
(:metaclass mito:dao-table-class))
324+
(mito:deftable user (has-email)
325+
((name :col-type (:varchar 64))))
378326
;=> #<MITO.DAO.TABLE:DAO-TABLE-CLASS COMMON-LISP-USER::USER>
379327
380328
(mito:table-definition 'user)
@@ -420,9 +368,9 @@ More info [here](https://stackoverflow.com/questions/38811931/how-to-change-clas
420368

421369
### Migrations
422370

423-
We can run database migrations manually, as shown below, and we can
371+
We can run database migrations manually, as shown below, or we can
424372
automatically run migrations after a change to the model
425-
definitions. To do that, set `mito:*auto-migration-mode*` to `t`.
373+
definitions. To enable automatic migrations, set `mito:*auto-migration-mode*` to `t`.
426374

427375
The first step is to create the tables, if needed:
428376

@@ -460,14 +408,9 @@ There are no changes from the previous user definition:
460408
Now let's add a unique `email` field:
461409

462410
~~~lisp
463-
(defclass user ()
464-
((name :col-type (:varchar 64)
465-
:initarg :name
466-
:accessor user-name)
467-
(email :col-type (:varchar 128)
468-
:initarg :email
469-
:accessor user-email))
470-
(:metaclass mito:dao-table-class)
411+
(mito:deftable user ()
412+
((name :col-type (:varchar 64))
413+
(email :col-type (:varchar 128)))
471414
(:unique-keys email))
472415
~~~
473416

@@ -714,21 +657,14 @@ functions, you can define `:before`, `:after` or `:around` methods to those, lik
714657
Inflation/Deflation is a function to convert values between Mito and RDBMS.
715658

716659
~~~lisp
717-
(defclass user-report ()
718-
((title :col-type (:varchar 100)
719-
:initarg :title
720-
:accessor report-title)
660+
(mito:deftable user-report ()
661+
((title :col-type (:varchar 100))
721662
(body :col-type :text
722-
:initarg :body
723-
:initform ""
724-
:accessor report-body)
663+
:initform "")
725664
(reported-at :col-type :timestamp
726-
:initarg :reported-at
727665
:initform (local-time:now)
728-
:accessor report-reported-at
729666
:inflate #'local-time:universal-to-timestamp
730-
:deflate #'local-time:timestamp-to-universal))
731-
(:metaclass mito:dao-table-class))
667+
:deflate #'local-time:timestamp-to-universal)))
732668
~~~
733669

734670
### Eager loading

0 commit comments

Comments
 (0)