1 ! Copyright (C) 2008 Doug Coleman.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: arrays assocs classes continuations destructors kernel math
4 namespaces sequences classes.tuple words strings
5 tools.walker accessors combinators fry ;
16 : new-db-connection ( class -- obj )
18 H{ } clone >>insert-statements
19 H{ } clone >>update-statements
20 H{ } clone >>delete-statements ; inline
24 GENERIC: db-open ( db -- db-connection )
25 HOOK: db-close db-connection ( handle -- )
27 : dispose-statements ( assoc -- ) values dispose-each ;
29 M: db-connection dispose ( db-connection -- )
31 [ dispose-statements H{ } clone ] change-insert-statements
32 [ dispose-statements H{ } clone ] change-update-statements
33 [ dispose-statements H{ } clone ] change-delete-statements
34 [ db-close f ] change-handle
38 TUPLE: result-set sql in-params out-params handle n max ;
40 GENERIC: query-results ( query -- result-set )
41 GENERIC: #rows ( result-set -- n )
42 GENERIC: #columns ( result-set -- n )
43 GENERIC# row-column 1 ( result-set column -- obj )
44 GENERIC# row-column-typed 1 ( result-set column -- sql )
45 GENERIC: advance-row ( result-set -- )
46 GENERIC: more-rows? ( result-set -- ? )
48 : init-result-set ( result-set -- )
52 : new-result-set ( query handle class -- result-set )
55 [ [ sql>> ] [ in-params>> ] [ out-params>> ] tri ] dip
60 TUPLE: statement handle sql in-params out-params bind-params bound? type retries ;
61 TUPLE: simple-statement < statement ;
62 TUPLE: prepared-statement < statement ;
64 : new-statement ( sql in out class -- statement )
70 HOOK: <simple-statement> db-connection ( string in out -- statement )
71 HOOK: <prepared-statement> db-connection ( string in out -- statement )
72 GENERIC: prepare-statement ( statement -- )
73 GENERIC: bind-statement* ( statement -- )
74 GENERIC: low-level-bind ( statement -- )
75 GENERIC: bind-tuple ( tuple statement -- )
77 GENERIC: execute-statement* ( statement type -- )
79 M: object execute-statement* ( statement type -- )
80 drop query-results dispose ;
82 : execute-one-statement ( statement -- )
83 dup type>> execute-statement* ;
85 : execute-statement ( statement -- )
87 [ execute-one-statement ] each
92 : bind-statement ( obj statement -- )
94 [ bind-statement* ] keep
97 : sql-row ( result-set -- seq )
98 dup #columns [ row-column ] with map ;
100 : sql-row-typed ( result-set -- seq )
101 dup #columns [ row-column-typed ] with map ;
103 : query-each ( statement quot: ( statement -- ) -- )
105 [ call ] 2keep over advance-row query-each
108 ] if ; inline recursive
110 : query-map ( statement quot -- seq )
111 accumulator [ query-each ] dip { } like ; inline
113 : with-db ( db quot -- )
114 [ db-open db-connection ] dip
115 '[ db-connection get [ drop @ ] with-disposal ] with-variable ; inline
117 ! Words for working with raw SQL statements
118 : default-query ( query -- result-set )
119 query-results [ [ sql-row ] query-map ] with-disposal ;
121 : sql-query ( sql -- rows )
122 f f <simple-statement> [ default-query ] with-disposal ;
124 : (sql-command) ( string -- )
125 f f <simple-statement> [ execute-statement ] with-disposal ;
127 : sql-command ( sql -- )
128 dup string? [ (sql-command) ] [ [ (sql-command) ] each ] if ;
131 SYMBOL: in-transaction
133 HOOK: begin-transaction db-connection ( -- )
134 HOOK: commit-transaction db-connection ( -- )
135 HOOK: rollback-transaction db-connection ( -- )
137 M: db-connection begin-transaction ( -- ) "BEGIN" sql-command ;
138 M: db-connection commit-transaction ( -- ) "COMMIT" sql-command ;
139 M: db-connection rollback-transaction ( -- ) "ROLLBACK" sql-command ;
141 : in-transaction? ( -- ? ) in-transaction get ;
143 : with-transaction ( quot -- )
146 [ ] [ rollback-transaction ] cleanup commit-transaction