audrey 0.2 → 0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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
+ #===============================================================================