Skip to content

Commit

Permalink
Merge pull request #151 from fukamachi/do-for-dao
Browse files Browse the repository at this point in the history
Rename `do-cursor` -> `do-select`, and make it work in all RDBMS
  • Loading branch information
fukamachi authored Aug 9, 2024
2 parents a0fb9dd + 8821024 commit 7c71f59
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 16 deletions.
18 changes: 18 additions & 0 deletions README.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -608,6 +608,24 @@ Since `insert-dao`, `update-dao` and `delete-dao` are defined as generic functio
;=> #<USER {100835FB33}>
```

### Iteration (Experimental)

`do-select` is a macro to iterate over results from SELECT one by one. It's the same as `cl:loop`, but it uses CURSOR for PostgreSQL, which can reduce memory usage since it won't load whole results on memory.

```common-lisp
(do-select (dao (select-dao 'user
(where (:< "2024-07-01" :created_at))))
;; Can be a more complex condition
(when (equal (user-name dao) "Eitaro")
(return dao)))
;; Same but without using CURSOR
(loop for dao in (select-dao 'user
(where (:< "2024-07-01" :created_at)))
when (equal (user-name dao) "Eitaro")
do (return dao))
```

## Installation

```common-lisp
Expand Down
40 changes: 26 additions & 14 deletions src/core/dao.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
#:recreate-table
#:ensure-table-exists
#:deftable
#:do-cursor))
#:do-select))
(in-package #:mito.dao)

(defun foreign-value (obj slot)
Expand Down Expand Up @@ -453,16 +453,28 @@
`((:conc-name ,(intern (format nil "~@:(~A-~)" name) (symbol-package name)))))
,@options))

(defmacro do-cursor ((dao select &optional index) &body body)
(with-gensyms (main cursor)
`(flet ((,main ()
(let* ((*want-cursor* t)
(,cursor ,select))
(loop ,@(and index `(for ,index from 0))
for ,dao = (fetch-dao-from-cursor ,cursor)
while ,dao
do (progn ,@body)))))
(if (dbi:in-transaction *connection*)
(,main)
(dbi:with-transaction *connection*
(,main))))))
(defmacro do-select ((dao select &optional index) &body body)
(with-gensyms (main main-body select-fn cursor i)
`(block nil
(labels ((,main-body (,dao ,(or index i))
,@(and (not index)
`((declare (ignore ,i))))
,@body)
(,select-fn () ,select)
(,main ()
(case (dbi:connection-driver-type *connection*)
(:postgres
(let ((,cursor (let ((*want-cursor* t))
(,select-fn))))
(loop ,@(and index `(for ,i from 0))
for ,dao = (fetch-dao-from-cursor ,cursor)
while ,dao
do (,main-body ,dao ,i))))
(otherwise
(loop ,@(and index `(for ,i from 0))
for ,dao in (,select-fn)
do (,main-body ,dao ,i))))))
(if (dbi:in-transaction *connection*)
(,main)
(dbi:with-transaction *connection*
(,main)))))))
4 changes: 2 additions & 2 deletions t/dao.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -270,8 +270,8 @@
(ok (null (mito.dao::fetch-dao-from-cursor cursor)))))

(let ((records '()))
(do-cursor (dao (mito.dao:select-dao 'user) i)
(push (cons i dao) records)
(do-select (user (mito.dao:select-dao 'user) i)
(push (cons i user) records)
(when (<= 1 i)
(return)))
(ok (= (length records) 2))
Expand Down

0 comments on commit 7c71f59

Please sign in to comment.