-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathsqlite.lisp
57 lines (52 loc) · 1.86 KB
/
sqlite.lisp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
(defpackage #:cl-yesql/sqlite
(:use
#:cl #:alexandria #:serapeum #:cl-yesql #:sqlite
:cl-yesql/sqlite-common)
(:shadowing-import-from #:cl-yesql #:import)
(:shadowing-import-from #:cl-yesql/lang
#:read-module
#:module-progn)
(:export #:yesql-sqlite #:read-module #:module-progn #:static-exports))
(in-package #:cl-yesql/sqlite)
(defmacro defquery (name args &body (docstring query))
(with-gensyms (db)
`(defun ,name
,(if (eql :setter (query-annotation query))
(list* (first args)
db
(rest args))
`(,db ,@args))
,docstring
,(build-query-tree
query
(lambda (q)
(query-body db q))))))
(defun static-exports (source)
(yesql-static-exports source))
;;; Although SQLite supports named arguments, we don't use them, so we
;;; don't have to worry about escaping. It should be straightforward
;;; to switch if that turns out to be a mistake.
(defun query-body (db q)
(let* ((string (query-string q))
(vars (query-vars q))
(args `(,db ,string ,@vars)))
(ecase-of annotation (query-annotation q)
(:rows `(execute-to-list ,@args))
(:execute `(execute-non-query ,@args))
(:setter
`(progn
(execute-non-query ,@args)
,(first (query-args q))))
(:last-id
`(progn
(execute-non-query ,@args)
(last-insert-rowid ,db)))
(:values `(execute-one-row-m-v ,@args))
(:row `(multiple-value-list (execute-one-row-m-v ,@args)))
(:column `(execute-to-column ,@args))
(:single `(execute-single ,@args)))))
(defun execute-to-column (db sql &rest parameters)
(declare (dynamic-extent parameters))
(sqlite::with-prepared-statement stmt (db sql parameters)
(loop while (step-statement stmt)
collect (statement-column-value stmt 0))))