audrey 0.2 → 0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,342 @@
1
+ #===============================================================================
2
+ # Audrey::Engine::SQLite3::Query::Q0
3
+ #
4
+ class Audrey::Engine::SQLite3::Query::Q0
5
+ #---------------------------------------------------------------------------
6
+ # initialize
7
+ #
8
+ def initialize(p_engine, p_fquery)
9
+ @engine = p_engine
10
+ @dbh = @engine.dbh
11
+ @fquery = p_fquery
12
+ set_query_pk()
13
+ end
14
+ #
15
+ # initialize
16
+ #---------------------------------------------------------------------------
17
+
18
+
19
+ #---------------------------------------------------------------------------
20
+ # set_query_pk
21
+ #
22
+ def set_query_pk
23
+ @qpk = Audrey::Util.randstr(40)
24
+ sql = 'insert into queries(pk) values(:qpk)'
25
+ @dbh.execute sql, 'qpk'=>@qpk
26
+ end
27
+ #
28
+ # set_query_pk
29
+ #---------------------------------------------------------------------------
30
+
31
+
32
+ #---------------------------------------------------------------------------
33
+ # sub_query_pk
34
+ #
35
+ def sub_query_pk()
36
+ # $tm.hrm
37
+ rv = Audrey::Util.randstr(40)
38
+ sql = 'insert into subqueries(pk, query) values(:sqpk, :qpk)'
39
+ @dbh.execute sql, 'sqpk'=>rv, 'qpk'=>@qpk
40
+ return rv
41
+ end
42
+ #
43
+ # sub_query_pk
44
+ #---------------------------------------------------------------------------
45
+
46
+
47
+ #---------------------------------------------------------------------------
48
+ # iterator
49
+ #
50
+ def iterator(opts={})
51
+ # $tm.hrm
52
+ subqueries = prepare_subqueries()
53
+ exec_opts = {}
54
+
55
+ # sql
56
+ sql = <<~'SQL'
57
+ select o.pk
58
+ from objects o, query_rows qr
59
+ where
60
+ o.pk = qr.parent and
61
+ qr.subquery = :sqpk
62
+ SQL
63
+
64
+ # options
65
+ exec_opts['sqpk'] = subqueries['objects']
66
+
67
+ # limit
68
+ if @fquery.limit
69
+ exec_opts['limit'] = @fquery.limit
70
+ sql += "limit :limit\n"
71
+ end
72
+
73
+ # offset
74
+ if @fquery.offset
75
+ exec_opts['offset'] = @fquery.offset
76
+ sql += "offset :offset\n"
77
+ end
78
+
79
+ # stmt and resultset
80
+ stmt = @dbh.prepare(sql)
81
+ return stmt.execute(exec_opts)
82
+ end
83
+ #
84
+ # iterator
85
+ #---------------------------------------------------------------------------
86
+
87
+
88
+ #---------------------------------------------------------------------------
89
+ # each
90
+ #
91
+ def each(opts={})
92
+ itr = iterator(opts)
93
+
94
+ itr.each do |row|
95
+ yield row['pk']
96
+ end
97
+ ensure
98
+ itr and itr.close
99
+ end
100
+ #
101
+ # each
102
+ #---------------------------------------------------------------------------
103
+
104
+
105
+ #---------------------------------------------------------------------------
106
+ # select_objects
107
+ #
108
+ def select_objects(subqueries)
109
+ # $tm.hrm
110
+
111
+ # query params
112
+ params = {}
113
+ subqueries['objects'] = params['sqpk'] = sub_query_pk()
114
+
115
+ # initial sql
116
+ sql = <<~'SQL'
117
+ select
118
+ :sqpk as sqpk, pk
119
+ from
120
+ objects
121
+ where
122
+ (partition = :partition)
123
+ SQL
124
+
125
+ # partition pk
126
+ params['partition'] = @engine.partition
127
+
128
+ # fclasses
129
+ if (fclasses = @fquery.fclasses) and fclasses.any?
130
+ wheres = []
131
+
132
+ fclasses.each do |fclass|
133
+ rs = Audrey::Util.randstr(40)
134
+ wheres.push ":#{rs}"
135
+ params[rs] = fclass
136
+ end
137
+
138
+ # add wheres
139
+ sql += " and\n" + ' (fclass in (' + wheres.join(', ') + '))'
140
+ end
141
+
142
+ # limit to hashes
143
+ if subqueries['hash']
144
+ sql = <<~"SQL"
145
+ #{sql} and
146
+ (pk in (select parent from query_rows where subquery=:hashsqpk))
147
+ SQL
148
+
149
+ params['hashsqpk'] = subqueries['hash']
150
+ end
151
+
152
+ # prepend insert into
153
+ sql = <<~"SQL"
154
+ insert into
155
+ query_rows(subquery, parent)
156
+ #{sql}
157
+ SQL
158
+
159
+ # execute
160
+ @dbh.execute sql, params
161
+ end
162
+ #
163
+ # select_objects
164
+ #---------------------------------------------------------------------------
165
+
166
+
167
+ #---------------------------------------------------------------------------
168
+ # select_hash_elements
169
+ #
170
+ def select_hash_elements(subqueries)
171
+ # $tm.hrm
172
+
173
+ # early exit
174
+ @fquery.fields.any? or return
175
+
176
+ # build sql and params
177
+ sql = "select distinct :sqpk as sqpk, hv.parent\nfrom hash_pairs hv\nwhere"
178
+ wheres = []
179
+ params = {}
180
+
181
+ # sub_query_pk
182
+ subqueries['hash'] = params['sqpk'] = sub_query_pk()
183
+
184
+ # hash values
185
+ hash_pairs wheres, params
186
+
187
+ # add wheres
188
+ sql += "\n(" + wheres.join(") and\n(") + ')'
189
+
190
+ # wrap in insert
191
+ sql = <<~"SQL"
192
+ insert into query_rows
193
+ #{sql}
194
+ SQL
195
+
196
+ # execute
197
+ @engine.dbh.execute sql, params
198
+ end
199
+ #
200
+ # select_hash_elements
201
+ #---------------------------------------------------------------------------
202
+
203
+
204
+ #---------------------------------------------------------------------------
205
+ # count
206
+ #
207
+ def count
208
+ # $tm.hrm
209
+ subqueries = prepare_subqueries()
210
+
211
+ # sql
212
+ sql = <<~'SQL'
213
+ select count(*) as count
214
+ from objects o, query_rows qr
215
+ where
216
+ o.pk = qr.parent and
217
+ qr.subquery = :sqpk
218
+ SQL
219
+
220
+ # return count
221
+ return @dbh.get_first_value(sql, 'sqpk'=>subqueries['objects'])
222
+ end
223
+ #
224
+ # count
225
+ #---------------------------------------------------------------------------
226
+
227
+
228
+ #---------------------------------------------------------------------------
229
+ # fclasses
230
+ #
231
+ def fclasses(wheres, params)
232
+ fcs = @fquery.fclasses
233
+ fcs.any? or return
234
+ where = []
235
+
236
+ # loop through fclasses
237
+ fcs.each do |fc|
238
+ rs = Audrey::Util.randstr(40)
239
+ params[rs] = fc
240
+ where.push ':' + rs
241
+ end
242
+
243
+ # add to wheres
244
+ wheres.push 'fclass in (' + where.join(', ') + ')'
245
+ end
246
+ #
247
+ # fclasses
248
+ #---------------------------------------------------------------------------
249
+
250
+
251
+ #---------------------------------------------------------------------------
252
+ # hash_pairs
253
+ #
254
+ def hash_pairs(wheres, params)
255
+ # $tm.hrm
256
+
257
+ # loop through fields
258
+ @fquery.fields.each do |k, vals|
259
+ # key
260
+ krs = Audrey::Util.randstr(40)
261
+ params[krs] = k
262
+
263
+ # if we're looking for a null value
264
+ is_null = false
265
+
266
+ # initialize clause
267
+ clause = '(hkey=:' + krs + ')'
268
+
269
+ # if specific values are wanted
270
+ unless [*vals].include?(Audrey::Query::Q0::Defined)
271
+ send_vals = []
272
+
273
+ # force to array
274
+ # Note: just using [*vals] doesn't work because if vals is nil
275
+ # then [*vals] is an empty array
276
+ if not vals.is_a?(Array)
277
+ vals = [vals]
278
+ end
279
+
280
+ vals.each do |val|
281
+ if val.nil?
282
+ is_null = true
283
+ else
284
+ vrs = Audrey::Util.randstr(40)
285
+ params[vrs] = val
286
+ send_vals.push ':' + vrs
287
+ end
288
+ end
289
+
290
+ # ors
291
+ ors = []
292
+
293
+ # send_vals
294
+ if send_vals.any?
295
+ ors.push 'scalar in (' + send_vals.join(', ') + ')'
296
+ end
297
+
298
+ # if null
299
+ if is_null
300
+ ors.push 'scalar is null'
301
+ end
302
+
303
+ # add scalar conditions to clause
304
+ clause += ' and (' + ors.join(') or (') + ')'
305
+ end
306
+
307
+ # if looking for a null value, add condition in which the parent
308
+ # element is selected if no such key/value pair exists
309
+ if is_null
310
+ null_clause = "((select count(*) from hash_pairs hp where parent=hv.parent and hkey=:#{krs} ) = 0)"
311
+ clause = "(#{clause}) or #{null_clause}"
312
+ end
313
+
314
+ # add where clause
315
+ wheres.push clause
316
+ end
317
+ end
318
+ #
319
+ # hash_pairs
320
+ #---------------------------------------------------------------------------
321
+
322
+
323
+ # private
324
+ private
325
+
326
+
327
+ #---------------------------------------------------------------------------
328
+ # prepare_subqueries
329
+ #
330
+ def prepare_subqueries
331
+ subqueries = {}
332
+ select_hash_elements subqueries
333
+ select_objects subqueries
334
+ return subqueries
335
+ end
336
+ #
337
+ # prepare_subqueries
338
+ #---------------------------------------------------------------------------
339
+ end
340
+ #
341
+ # Audrey::Engine::SQLite3::Query::Q0
342
+ #===============================================================================