]> gitweb.factorcode.org Git - factor.git/blob - basis/db/queries/queries.factor
e5334703f623c6d216dc302f38e491032d384ea7
[factor.git] / basis / db / queries / queries.factor
1 ! Copyright (C) 2008 Doug Coleman.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: accessors kernel math namespaces sequences random
4 strings math.parser math.intervals combinators
5 math.bitfields.lib namespaces.lib db db.tuples db.types
6 sequences.lib db.sql classes words shuffle arrays ;
7 IN: db.queries
8
9 GENERIC: where ( specs obj -- )
10
11 : maybe-make-retryable ( statement -- statement )
12     dup in-params>> [ generator-bind? ] contains?
13     [ make-retryable ] when ;
14
15 : query-make ( class quot -- )
16     >r sql-props r>
17     [ 0 sql-counter rot with-variable ] curry { "" { } { } } nmake
18     <simple-statement> maybe-make-retryable ; inline
19
20 M: db begin-transaction ( -- ) "BEGIN" sql-command ;
21 M: db commit-transaction ( -- ) "COMMIT" sql-command ;
22 M: db rollback-transaction ( -- ) "ROLLBACK" sql-command ;
23
24 : where-primary-key% ( specs -- )
25     " where " 0%
26     find-primary-key dup column-name>> 0% " = " 0% bind% ;
27
28 M: db <update-tuple-statement> ( class -- statement )
29     [
30         "update " 0% 0%
31         " set " 0%
32         dup remove-id
33         [ ", " 0% ] [ dup column-name>> 0% " = " 0% bind% ] interleave
34         where-primary-key%
35     ] query-make ;
36
37 M: random-id-generator eval-generator ( singleton -- obj )
38     drop
39     system-random-generator get [
40         63 [ 2^ random ] keep 1 - set-bit
41     ] with-random ;
42
43 : interval-comparison ( ? str -- str )
44     "from" = " >" " <" ? swap [ "= " append ] when ;
45
46 : (infinite-interval?) ( interval -- ?1 ?2 )
47     [ from>> ] [ to>> ] bi
48     [ first fp-infinity? ] bi@ ;
49
50 : double-infinite-interval? ( obj -- ? )
51     dup interval? [ (infinite-interval?) and ] [ drop f ] if ;
52
53 : infinite-interval? ( obj -- ? )
54     dup interval? [ (infinite-interval?) or ] [ drop f ] if ;
55
56 : where-interval ( spec obj from/to -- )
57     over first fp-infinity? [
58         3drop
59     ] [
60         pick column-name>> 0%
61         >r first2 r> interval-comparison 0%
62         bind#
63     ] if ;
64
65 : in-parens ( quot -- )
66     "(" 0% call ")" 0% ; inline
67
68 M: interval where ( spec obj -- )
69     [
70         [ from>> "from" where-interval ] [
71             nip infinite-interval? [ " and " 0% ] unless
72         ] [ to>> "to" where-interval ] 2tri
73     ] in-parens ;
74
75 M: sequence where ( spec obj -- )
76     [
77         [ " or " 0% ] [ dupd where ] interleave drop
78     ] in-parens ;
79
80 : object-where ( spec obj -- )
81     over column-name>> 0% " = " 0% bind# ;
82
83 M: object where ( spec obj -- ) object-where ;
84
85 M: integer where ( spec obj -- ) object-where ;
86
87 M: string where ( spec obj -- ) object-where ;
88
89 : filter-slots ( tuple specs -- specs' )
90     [
91         slot-name>> swap get-slot-named
92         dup double-infinite-interval? [ drop f ] when
93     ] with filter ;
94
95 : where-clause ( tuple specs -- )
96     dupd filter-slots [
97         drop
98     ] [
99         " where " 0% [
100             " and " 0%
101         ] [
102             2dup slot-name>> swap get-slot-named where
103         ] interleave drop
104     ] if-empty ;
105
106 M: db <delete-tuples-statement> ( tuple table -- sql )
107     [
108         "delete from " 0% 0%
109         where-clause
110     ] query-make ;
111
112 M: db <select-by-slots-statement> ( tuple class -- statement )
113     [
114         "select " 0%
115         over [ ", " 0% ]
116         [ dup column-name>> 0% 2, ] interleave
117
118         " from " 0% 0%
119         where-clause
120     ] query-make ;
121
122 : do-group ( tuple groups -- )
123     [
124         ", " join " group by " prepend append
125     ] curry change-sql drop ;
126
127 : do-order ( tuple order -- )
128     [
129         ", " join " order by " prepend append
130     ] curry change-sql drop ;
131
132 : do-offset ( tuple n -- )
133     [
134         number>string " offset " prepend append
135     ] curry change-sql drop ;
136
137 : do-limit ( tuple n -- )
138     [
139         number>string " limit " prepend append
140     ] curry change-sql drop ;
141
142 : make-query ( tuple query -- tuple' )
143     dupd
144     {
145         [ group>> [ do-group ] [ drop ] if-seq ]
146         [ order>> [ do-order ] [ drop ] if-seq ]
147         [ limit>> [ do-limit ] [ drop ] if* ]
148         [ offset>> [ do-offset ] [ drop ] if* ]
149     } 2cleave ;
150
151 M: db <query> ( tuple class query -- tuple )
152     [ <select-by-slots-statement> ] dip make-query ;
153
154 ! select ID, NAME, SCORE from EXAM limit 1 offset 3
155
156 : select-tuples* ( tuple -- statement )
157     dup
158     [
159         select 0,
160         dup class db-columns [ ", " 0, ]
161         [ dup column-name>> 0, 2, ] interleave
162         from 0,
163         class name>> 0,
164     ] { { } { } { } } nmake
165     >r >r parse-sql 4drop r> r>
166     <simple-statement> maybe-make-retryable do-select ;
167
168 M: db <count-statement> ( tuple class groups -- statement )
169     \ query new
170         swap >>group
171     [ [ "select count(*) from " 0% 0% where-clause ] query-make ]
172     dip make-query ;
173
174 : create-index ( index-name table-name columns -- )
175     [
176         >r >r "create index " % % r> " on " % % r> "(" %
177         "," join % ")" %
178     ] "" make sql-command ;
179
180 : drop-index ( index-name -- )
181     [ "drop index " % % ] "" make sql-command ;