Rubernate 0.1.4 → 0.1.5
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.
- data/lib/rubernate/callbacks.rb +1 -2
- data/lib/rubernate/impl/dbi_generic.rb +39 -33
- data/lib/rubernate/impl/dbi_mysql.rb +1 -0
- data/lib/rubernate/impl/dbi_oracle.rb +1 -3
- data/lib/rubernate/impl/dbi_pg.rb +33 -0
- data/lib/rubernate/impl/memory.rb +13 -7
- data/lib/rubernate/init/init_generic.rb +25 -0
- data/lib/rubernate/init/init_mysql.rb +8 -14
- data/lib/rubernate/init/init_oracle.rb +9 -16
- data/lib/rubernate/init/init_pg.rb +78 -0
- data/lib/rubernate/queries.rb +341 -339
- data/lib/rubernate/runtime.rb +18 -0
- data/lib/rubernate.rb +33 -10
- data/tests/all_tests.rb +5 -0
- data/tests/config.rb +18 -8
- data/tests/rubernate/callbacks_test.rb +20 -0
- data/tests/rubernate/fixtures.rb +1 -1
- data/tests/rubernate/impl/dbi_generic_stub.rb +48 -44
- data/tests/rubernate/impl/dbi_oracle_test.rb +15 -10
- data/tests/rubernate/impl/dbi_pg_test.rb +23 -0
- data/tests/rubernate/impl/memory_test.rb +8 -8
- data/tests/rubernate/impl/queries_oracle_test.rb +0 -1
- data/tests/rubernate/impl/queries_pg_test.rb +14 -0
- data/tests/rubernate/impl/queries_stub.rb +18 -0
- data/tests/rubernate/queries_test.rb +2 -2
- metadata +7 -2
data/lib/rubernate/queries.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
|
+
require 'rubernate/impl/dbi_generic'
|
2
|
+
|
1
3
|
# Contains users methods for building queries
|
2
4
|
module Rubernate
|
5
|
+
# This module contains classes and modules used for query building
|
3
6
|
module Queries
|
4
7
|
# Log instance for Queries
|
5
8
|
Log = Rubernate::Log
|
@@ -9,12 +12,12 @@ module Queries
|
|
9
12
|
|
10
13
|
# Contains operations definitions
|
11
14
|
module Operations
|
12
|
-
# Declares
|
15
|
+
# Declares AND sql clause.
|
13
16
|
def And expr1, expr2
|
14
17
|
@factory.bin_op expr1, expr2, 'and'
|
15
18
|
end
|
16
19
|
|
17
|
-
# Declares
|
20
|
+
# Declares OR sql clause.
|
18
21
|
def Or expr1, expr2
|
19
22
|
@factory.bin_op expr1, expr2, 'or', true
|
20
23
|
end
|
@@ -24,22 +27,22 @@ module Queries
|
|
24
27
|
@factory.bin_op expr1, expr2, '='
|
25
28
|
end
|
26
29
|
|
27
|
-
# Declares
|
30
|
+
# Declares NOT sql clause.
|
28
31
|
def Not expr
|
29
32
|
@factory.un_op expr, 'not', true
|
30
33
|
end
|
31
34
|
|
32
|
-
# Declares
|
35
|
+
# Declares IS NULL sql clause
|
33
36
|
def IsNil expr
|
34
37
|
@factory.bin_op expr, @factory.expr(nil), 'is'
|
35
38
|
end
|
36
39
|
|
37
|
-
# Declares
|
40
|
+
# Declares IS NOT NULL sql clause
|
38
41
|
def IsNotNil expr
|
39
42
|
@factory.bin_op expr, @factory.expr(nil), 'is not'
|
40
43
|
end
|
41
44
|
|
42
|
-
# Declares
|
45
|
+
# Declares IN sql clause
|
43
46
|
def In expr, list
|
44
47
|
@factory.bin_op expr, @factory.list(list), 'in'
|
45
48
|
end
|
@@ -54,8 +57,8 @@ module Queries
|
|
54
57
|
end
|
55
58
|
end
|
56
59
|
|
57
|
-
# Defines query elements factory. By default it creates elements defined
|
58
|
-
#
|
60
|
+
# Defines query elements factory. By default it creates elements defined in module Queries.
|
61
|
+
# This behaviour can be changed to provide support for kinds of queries other then ANSI SQL.
|
59
62
|
# Following example changes implementation of BinOpConst
|
60
63
|
#
|
61
64
|
# :call-seq:
|
@@ -68,15 +71,15 @@ module Queries
|
|
68
71
|
attr_reader :cache # Queries cache. TODO: limit size!
|
69
72
|
# Initalizes default implementations
|
70
73
|
def initialize
|
71
|
-
@expr =
|
72
|
-
@un_op =
|
73
|
-
@bin_op =
|
74
|
-
@field =
|
75
|
-
@key_ref =
|
76
|
-
@list =
|
77
|
-
@r_param =
|
78
|
-
@r_object =
|
79
|
-
@query =
|
74
|
+
@expr = Expr
|
75
|
+
@un_op = UnOpConstr
|
76
|
+
@bin_op = BinOpConstr
|
77
|
+
@field = FieldExpr
|
78
|
+
@key_ref = KeyRefExpr
|
79
|
+
@list = ExprsList
|
80
|
+
@r_param = RParam
|
81
|
+
@r_object = RObject
|
82
|
+
@query = Query
|
80
83
|
@cache = {}
|
81
84
|
end
|
82
85
|
def query query=nil, &block
|
@@ -100,365 +103,364 @@ module Queries
|
|
100
103
|
end
|
101
104
|
|
102
105
|
# Contains classes for standart ANSY SQL.
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
attr_reader :r_params, :markers
|
106
|
+
# Represent abstract expression
|
107
|
+
class Expr
|
108
|
+
include Operations
|
109
|
+
attr_reader :r_params, :markers
|
108
110
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
# Generates SQL for expression
|
115
|
-
def to_sql
|
116
|
-
case @value
|
117
|
-
when Symbol: '?'
|
118
|
-
when Integer: @value
|
119
|
-
when nil: 'null'
|
120
|
-
else "'#{@value.to_s}'"
|
121
|
-
end
|
122
|
-
end
|
123
|
-
private
|
124
|
-
def fit_type expr
|
125
|
-
case expr
|
126
|
-
when RObject: expr.pk
|
127
|
-
when RParam: expr.ref
|
128
|
-
when Expr: expr
|
129
|
-
else @factory.expr expr
|
130
|
-
end
|
131
|
-
end
|
132
|
-
def self.def_bin_op ruby_op, sql_op
|
133
|
-
module_eval %{
|
134
|
-
def #{ruby_op} (other) @factory.bin_op self, other, '#{sql_op}'; end
|
135
|
-
}
|
136
|
-
end
|
137
|
-
for op in [['==', '='], ['=~', '<>'], '<', '>', '<=', '>=']
|
138
|
-
if op.is_a? Array
|
139
|
-
def_bin_op(*op)
|
140
|
-
else
|
141
|
-
def_bin_op op, op
|
142
|
-
end
|
143
|
-
end
|
144
|
-
end
|
111
|
+
def initialize factory, value = nil
|
112
|
+
@factory, @value, @r_params, @markers = factory, value, [], []
|
113
|
+
@markers << @value if @value.is_a? Symbol
|
114
|
+
end
|
145
115
|
|
146
|
-
#
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
116
|
+
# Generates SQL for expression
|
117
|
+
def to_sql
|
118
|
+
case @value
|
119
|
+
when Symbol: '?'
|
120
|
+
when Integer: @value
|
121
|
+
when nil: 'null'
|
122
|
+
else "'#{@value.to_s}'"
|
123
|
+
end
|
124
|
+
end
|
125
|
+
private
|
126
|
+
def fit_type expr
|
127
|
+
case expr
|
128
|
+
when RObject: expr.pk
|
129
|
+
when RParam: expr.name
|
130
|
+
when Expr: expr
|
131
|
+
else @factory.expr expr
|
132
|
+
end
|
155
133
|
end
|
156
|
-
|
157
|
-
|
158
|
-
|
134
|
+
def self.def_bin_op ruby_op, sql_op
|
135
|
+
module_eval %{
|
136
|
+
def #{ruby_op} (other) @factory.bin_op self, other, '#{sql_op}'; end
|
137
|
+
}
|
159
138
|
end
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
"#{@op} (#{@expr.to_sql})"
|
139
|
+
for op in [['==', '='], ['=~', '<>'], '<', '>', '<=', '>=']
|
140
|
+
if op.is_a? Array
|
141
|
+
def_bin_op(*op)
|
164
142
|
else
|
165
|
-
|
143
|
+
def_bin_op op, op
|
166
144
|
end
|
167
145
|
end
|
146
|
+
end
|
147
|
+
|
148
|
+
# Represents constraint for one columns.
|
149
|
+
class UnOpConstr < Expr
|
150
|
+
def initialize factory, expr, op, braces = false
|
151
|
+
@factory, @op, @braces = factory, op, braces
|
152
|
+
@expr = fit_type expr
|
168
153
|
end
|
169
154
|
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
@factory, @sign, @braces = factory, sign, braces
|
174
|
-
@expr1, @expr2 = fit_type(expr1), fit_type(expr2)
|
175
|
-
end
|
176
|
-
|
177
|
-
# Returns r_params used in both expressions
|
178
|
-
def r_params
|
179
|
-
@expr1.r_params + @expr2.r_params
|
180
|
-
end
|
181
|
-
|
182
|
-
# Returns markers used in both expressions
|
183
|
-
def markers
|
184
|
-
@expr1.markers + @expr2.markers
|
185
|
-
end
|
186
|
-
|
187
|
-
# Generates SQL for constraint
|
188
|
-
def to_sql
|
189
|
-
if @braces
|
190
|
-
"(#{@expr1.to_sql} #{@sign} #{@expr2.to_sql})"
|
191
|
-
else
|
192
|
-
"#{@expr1.to_sql} #{@sign} #{@expr2.to_sql}"
|
193
|
-
end
|
194
|
-
end
|
195
|
-
end
|
155
|
+
def r_params
|
156
|
+
@expr.r_params
|
157
|
+
end
|
196
158
|
|
197
|
-
|
198
|
-
|
199
|
-
def initialize factory, table, field
|
200
|
-
@factory, @table, @field, @markers = factory, table, field, []
|
201
|
-
@r_params = table.is_a?(RParam) ? [table] : []
|
202
|
-
end
|
203
|
-
# Creates constraint that check if this field is nil
|
204
|
-
def is_nil
|
205
|
-
IsNil self
|
206
|
-
end
|
207
|
-
# Creates constraint that check if this field is not nil
|
208
|
-
def is_not_nil
|
209
|
-
IsNotNil self
|
210
|
-
end
|
211
|
-
|
212
|
-
def to_sql
|
213
|
-
@table.to_sql + '.' + @field
|
214
|
-
end
|
159
|
+
def markers
|
160
|
+
@expr.markers
|
215
161
|
end
|
216
162
|
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
end
|
223
|
-
def == expr
|
224
|
-
And self, Eq(@r_param.ref, expr)
|
163
|
+
def to_sql
|
164
|
+
if @braces
|
165
|
+
"#{@op} (#{@expr.to_sql})"
|
166
|
+
else
|
167
|
+
"#{@op} #{@expr.to_sql}"
|
225
168
|
end
|
226
169
|
end
|
170
|
+
end
|
227
171
|
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
def to_sql
|
234
|
-
'(' + @exprs.collect{|expr| expr.to_sql}.join(', ') + ')'
|
235
|
-
end
|
236
|
-
def markers
|
237
|
-
@exprs.inject([]) {|res, expr| res.concat expr.markers}
|
238
|
-
end
|
239
|
-
def r_params
|
240
|
-
@exprs.inject([]) {|res, expr| res.concat expr.r_params}
|
241
|
-
end
|
172
|
+
# Represent constraint that applied on two columns.
|
173
|
+
class BinOpConstr < Expr
|
174
|
+
def initialize factory, expr1, expr2, sign, braces = false
|
175
|
+
@factory, @sign, @braces = factory, sign, braces
|
176
|
+
@expr1, @expr2 = fit_type(expr1), fit_type(expr2)
|
242
177
|
end
|
243
178
|
|
244
|
-
#
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
179
|
+
# Returns r_params used in both expressions
|
180
|
+
def r_params
|
181
|
+
@expr1.r_params + @expr2.r_params
|
182
|
+
end
|
183
|
+
|
184
|
+
# Returns markers used in both expressions
|
185
|
+
def markers
|
186
|
+
@expr1.markers + @expr2.markers
|
187
|
+
end
|
188
|
+
|
189
|
+
# Generates SQL for constraint
|
190
|
+
def to_sql
|
191
|
+
if @braces
|
192
|
+
"(#{@expr1.to_sql} #{@sign} #{@expr2.to_sql})"
|
193
|
+
else
|
194
|
+
"#{@expr1.to_sql} #{@sign} #{@expr2.to_sql}"
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
# Represent expression with table's field
|
200
|
+
class FieldExpr < Expr
|
201
|
+
def initialize factory, table, field
|
202
|
+
@factory, @table, @field, @markers = factory, table, field, []
|
203
|
+
@r_params = table.is_a?(RParam) ? [table] : []
|
204
|
+
end
|
205
|
+
# Creates constraint that check if this field is nil
|
206
|
+
def is_nil
|
207
|
+
IsNil self
|
208
|
+
end
|
209
|
+
# Creates constraint that check if this field is not nil
|
210
|
+
def is_not_nil
|
211
|
+
IsNotNil self
|
212
|
+
end
|
213
|
+
|
214
|
+
def to_sql
|
215
|
+
@table.to_sql + '.' + @field
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
# Represent r_params for hashes and arrays constrained by key
|
220
|
+
class KeyRefExpr < BinOpConstr
|
221
|
+
def initialize factory, r_param, key_field, key_value
|
222
|
+
@factory, @r_param, @key_field, @key_value = factory, r_param, key_field, key_value
|
223
|
+
super factory, key_field, key_value, '='
|
224
|
+
end
|
225
|
+
def == expr
|
226
|
+
And self, Eq(@r_param.ref, expr)
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
# Reresents List of expressions
|
231
|
+
class ExprsList < Expr
|
232
|
+
def initialize factory, list
|
233
|
+
@factory, @exprs = factory, list.collect{|expr| Expr === expr ? expr : factory.expr(expr)}
|
234
|
+
end
|
235
|
+
def to_sql
|
236
|
+
'(' + @exprs.collect{|expr| expr.to_sql}.join(', ') + ')'
|
237
|
+
end
|
238
|
+
def markers
|
239
|
+
@exprs.inject([]) {|res, expr| res.concat expr.markers}
|
240
|
+
end
|
241
|
+
def r_params
|
242
|
+
@exprs.inject([]) {|res, expr| res.concat expr.r_params}
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
# Represents r_params table
|
247
|
+
class RParam < Expr
|
248
|
+
include Rubernate::DBI
|
249
|
+
|
250
|
+
attr_reader :r_object, :p_name
|
251
|
+
|
252
|
+
# Init Param accepts table and name of param
|
253
|
+
def initialize factory, r_object, p_name
|
254
|
+
@factory, @r_object, @p_name = factory, r_object, p_name
|
255
|
+
@markers, @r_params = [], [self]
|
256
|
+
end
|
257
|
+
|
258
|
+
# Returns full param table name with object tables prefix
|
259
|
+
def to_sql
|
260
|
+
@r_object.to_sql + @p_name
|
261
|
+
end
|
262
|
+
|
263
|
+
# Fields accessors.
|
264
|
+
def pk () f_expr 'object_pk'; end
|
265
|
+
def int () f_expr 'int_value'; end
|
266
|
+
def float() f_expr 'flt_value'; end
|
267
|
+
def str () f_expr 'str_value'; end
|
268
|
+
def time () f_expr 'dat_value'; end
|
269
|
+
def date () f_expr 'dat_value'; end
|
270
|
+
def ref () f_expr 'ref_value'; end
|
271
|
+
def flags() f_expr 'flags'; end
|
272
|
+
def name () f_expr 'name'; end
|
273
|
+
|
274
|
+
# The following methods checks r_param.flags value. (r_param.flags)
|
275
|
+
def is_int () Eq flags, PARAM_FLAG_INT; end
|
276
|
+
def is_str () Eq flags, PARAM_FLAG_STRING; end
|
277
|
+
def is_time() Eq flags, PARAM_FLAG_TIME; end
|
278
|
+
def is_ref () Eq flags, PARAM_FLAG_REF; end
|
279
|
+
|
280
|
+
# Shortcut for Eq method
|
281
|
+
def == expr
|
282
|
+
expr.is_a?(RObject) ?
|
283
|
+
@factory.bin_op(ref, expr.pk, '=') :
|
284
|
+
@factory.bin_op(ref, expr, '=')
|
285
|
+
end
|
286
|
+
|
287
|
+
# Shortcut for arrays and hashes
|
288
|
+
def [] key
|
289
|
+
case key
|
290
|
+
when Integer: key_ref int, key
|
291
|
+
when String: key_ref str, key
|
292
|
+
when Time: key_ref dat, key
|
293
|
+
when Symbol: key_ref int, key
|
294
|
+
else raise "invalid key value #{key}"
|
259
295
|
end
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
def
|
264
|
-
|
265
|
-
def str () f_expr 'str_value'; end
|
266
|
-
def time () f_expr 'dat_value'; end
|
267
|
-
def date () f_expr 'dat_value'; end
|
268
|
-
def ref () f_expr 'ref_value'; end
|
269
|
-
def flags() f_expr 'flags'; end
|
270
|
-
|
271
|
-
# The following methods checks r_param.flags value. (r_param.flags)
|
272
|
-
def is_int () Eq flags, PARAM_FLAG_INT; end
|
273
|
-
def is_str () Eq flags, PARAM_FLAG_STRING; end
|
274
|
-
def is_time() Eq flags, PARAM_FLAG_TIME; end
|
275
|
-
def is_ref () Eq flags, PARAM_FLAG_REF; end
|
276
|
-
|
277
|
-
# Shortcut for Eq method
|
278
|
-
def == expr
|
279
|
-
expr.is_a?(RObject) ?
|
280
|
-
@factory.bin_op(ref, expr.pk, '=') :
|
281
|
-
@factory.bin_op(ref, expr, '=')
|
296
|
+
end
|
297
|
+
private
|
298
|
+
# Creates FieldExpr witch field of this (r_param) table
|
299
|
+
def f_expr field
|
300
|
+
@factory.field self, field
|
282
301
|
end
|
283
|
-
|
284
|
-
|
285
|
-
def [] key
|
286
|
-
case key
|
287
|
-
when Integer: key_ref int, key
|
288
|
-
when String: key_ref str, key
|
289
|
-
when Time: key_ref dat, key
|
290
|
-
when Symbol: key_ref int, key
|
291
|
-
else raise "invalid key value #{key}"
|
292
|
-
end
|
302
|
+
def key_ref key_field, key_value
|
303
|
+
@factory.key_ref self, key_field, key_value
|
293
304
|
end
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
305
|
+
end
|
306
|
+
|
307
|
+
# Represent r_objects table
|
308
|
+
class RObject < Expr
|
309
|
+
# Init Table accepts query and name of table
|
310
|
+
def initialize factory, name
|
311
|
+
@factory, @to_sql, @r_params = factory, name.to_s + '_', {}
|
312
|
+
@pk, @klass = @factory.field(self, 'object_pk'), @factory.field(self, 'object_class')
|
302
313
|
end
|
303
314
|
|
304
|
-
#
|
305
|
-
|
306
|
-
# Init Table accepts query and name of table
|
307
|
-
def initialize factory, name
|
308
|
-
@factory, @to_sql, @r_params = factory, name.to_s + '_', {}
|
309
|
-
@pk, @klass = @factory.field(self, 'object_pk'), @factory.field(self, 'object_class')
|
310
|
-
end
|
311
|
-
|
312
|
-
# Fiends access expressions
|
313
|
-
attr_reader :pk, :klass, :to_sql
|
315
|
+
# Fiends access expressions
|
316
|
+
attr_reader :pk, :klass, :to_sql
|
314
317
|
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
end
|
329
|
-
|
330
|
-
private
|
331
|
-
# Defines accessor for new param. (joins r_param to r_objects)
|
332
|
-
def def_param name
|
333
|
-
instance_eval "def #{name}() @r_params[:#{name}]; end"
|
334
|
-
@r_params[name] = @factory.r_param self, name.to_s
|
335
|
-
end
|
318
|
+
# Creates subclasses constraint
|
319
|
+
def derived klass
|
320
|
+
if klass.subclasses and not klass.subclasses.empty?
|
321
|
+
In self.klass, [klass].concat(klass.subclasses)
|
322
|
+
else
|
323
|
+
Eq self.klass, klass
|
324
|
+
end
|
325
|
+
end
|
326
|
+
|
327
|
+
# Tracks missing methods and creates accessor for params.
|
328
|
+
def method_missing name, *params
|
329
|
+
return super if params.size != 0
|
330
|
+
def_param name
|
336
331
|
end
|
337
332
|
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
# Accepts query as string or as block and executes it.
|
344
|
-
def initialize factory, query = nil, &block
|
345
|
-
@factory, @r_objects, @exprs, @order, @query = factory, {}, [], [], query
|
346
|
-
@query = block if block_given?
|
333
|
+
private
|
334
|
+
# Defines accessor for new param. (joins r_param to r_objects)
|
335
|
+
def def_param name
|
336
|
+
instance_eval "def #{name}() @r_params[:#{name}]; end"
|
337
|
+
@r_params[name] = @factory.r_param self, name.to_s
|
347
338
|
end
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
339
|
+
end
|
340
|
+
|
341
|
+
# Represents context in which query building executes
|
342
|
+
# Holds constraints tables and so on.
|
343
|
+
class Query < Expr
|
344
|
+
include Operations
|
345
|
+
|
346
|
+
# Accepts query as string or as block and executes it.
|
347
|
+
def initialize factory, query = nil, &block
|
348
|
+
@factory, @r_objects, @exprs, @order, @query = factory, {}, [], [], query
|
349
|
+
@query = block if block_given?
|
350
|
+
end
|
351
|
+
|
352
|
+
# Next section contains methods available during query construction.
|
353
|
+
# Declares objects for selection. The first argument will be result object.
|
354
|
+
def Select main, *tables
|
355
|
+
for t in [main, *tables].flatten
|
356
|
+
@r_objects[t] = @factory.r_object t.to_s
|
357
|
+
instance_eval "def #{t}() @r_objects[:#{t}]; end"
|
358
|
+
end
|
359
|
+
@main = @r_objects[main]
|
360
|
+
end
|
361
|
+
|
362
|
+
# Declares +Where+ clause.
|
363
|
+
def Where *exprs
|
364
|
+
@exprs = exprs
|
365
|
+
end
|
366
|
+
|
367
|
+
# Declares +Order By+ clause.
|
368
|
+
def OrderBy expr, *exprs
|
369
|
+
@order << expr
|
370
|
+
@order.concat exprs
|
371
|
+
end
|
372
|
+
|
373
|
+
# Returns markers used in query in valid order.
|
374
|
+
def markers
|
375
|
+
to_sql
|
376
|
+
@markers
|
377
|
+
end
|
378
|
+
|
379
|
+
# Arranges map: values {marker=>value} to ordered array of values
|
380
|
+
# accroding to markers in query.
|
381
|
+
def params values
|
382
|
+
markers.inject([]){|r, m| r << values[m]}
|
383
|
+
end
|
384
|
+
|
385
|
+
# Generates SQL for entire query.
|
386
|
+
def to_sql
|
387
|
+
return @sql if @sql
|
388
|
+
if @query.is_a? String
|
389
|
+
@sql, @markers = @factory.cache[@query]
|
390
|
+
unless @sql
|
391
|
+
@sql, @markers = eval_query
|
392
|
+
@factory.cache[@query] = [@sql, @markers]
|
355
393
|
end
|
356
|
-
|
394
|
+
else
|
395
|
+
@sql, @markers = eval_query
|
357
396
|
end
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
397
|
+
@sql
|
398
|
+
end
|
399
|
+
|
400
|
+
private
|
401
|
+
# Prints debug message
|
402
|
+
def log_debug_query sql
|
403
|
+
return unless Log.debug?
|
404
|
+
query = @query.is_a?(Proc) ? 'query given as block' : @query
|
405
|
+
Log.debug "Translate: <<#{query}>> to sql: <<#{sql}>>"
|
362
406
|
end
|
363
407
|
|
364
|
-
#
|
365
|
-
def
|
366
|
-
@
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
@
|
408
|
+
# Evaluates query withing the object context. Returns sql, and array of markers: [sql, [m1,m2,..]]
|
409
|
+
def eval_query
|
410
|
+
if @query.is_a? Proc
|
411
|
+
instance_eval(&@query)
|
412
|
+
else
|
413
|
+
instance_eval @query
|
414
|
+
end
|
415
|
+
sql = "select #{@main.to_sql}.* from #{tables_sql}"
|
416
|
+
sql+= "\n\twhere #{where_sql}"
|
417
|
+
sql+= "\n\torder by #{order_by_sql}" unless @order.empty?
|
418
|
+
log_debug_query sql
|
419
|
+
[sql, @exprs.inject([]){|result, expr| result.concat expr.markers}]
|
420
|
+
end
|
421
|
+
|
422
|
+
# Generates where clause for each expression joined by and clause
|
423
|
+
def where_sql
|
424
|
+
r_params.collect{|rp| rp.to_sql + '.name = \'' + rp.p_name + '\''}.concat(
|
425
|
+
@exprs.collect{|ex| ex.to_sql}).join(" and\n\t\t")
|
374
426
|
end
|
375
427
|
|
376
|
-
#
|
377
|
-
|
378
|
-
|
379
|
-
markers.inject([]){|r, m| r << values[m]}
|
428
|
+
# Generates order by sql clause
|
429
|
+
def order_by_sql
|
430
|
+
@order.collect{|ord| ord.to_sql}.join(', ')
|
380
431
|
end
|
381
432
|
|
382
|
-
# Generates
|
383
|
-
def
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
433
|
+
# Generates left outer join for each r_params used in query
|
434
|
+
def tables_sql
|
435
|
+
r_joins = {}
|
436
|
+
r_objects.each{|r_o| r_joins[r_o.to_sql] ||= []} # Collect all r_objects used in query
|
437
|
+
r_params.each{|r_p| r_joins[r_p.r_object.to_sql] << r_p.to_sql} #Join all r_params to r_objects
|
438
|
+
|
439
|
+
result = nil
|
440
|
+
for obj, params in r_joins
|
441
|
+
result = result ? result << ",\n\t\t" : ''
|
442
|
+
result << 'r_objects ' + obj
|
443
|
+
for param in params
|
444
|
+
result << " left outer join r_params #{param} on (#{obj}.object_pk = #{param}.object_pk)"
|
390
445
|
end
|
391
|
-
else
|
392
|
-
@sql, @markers = eval_query
|
393
446
|
end
|
394
|
-
|
447
|
+
result
|
448
|
+
end
|
449
|
+
|
450
|
+
# Retruns r_params used in query. List of RParam.
|
451
|
+
def r_params
|
452
|
+
res = @exprs.inject([]) {|res, exp| res.concat exp.r_params}
|
453
|
+
@order.inject(res) {|res, ord| res.concat ord.r_params}
|
454
|
+
res.uniq!
|
455
|
+
res
|
456
|
+
end
|
457
|
+
|
458
|
+
# Retruns r_objects used in query. List of RObject.
|
459
|
+
def r_objects
|
460
|
+
res = (@r_objects.values + r_params.inject([]){|res, rp| res << rp.r_object})
|
461
|
+
res.uniq!
|
462
|
+
res
|
395
463
|
end
|
396
|
-
|
397
|
-
private
|
398
|
-
# Prints debug message
|
399
|
-
def log_debug_query sql
|
400
|
-
return unless Log.debug?
|
401
|
-
query = @query.is_a?(Proc) ? 'query given as block' : @query
|
402
|
-
Log.debug "Translate: <<#{query}>> to sql: <<#{sql}>>"
|
403
|
-
end
|
404
|
-
|
405
|
-
# Evaluates query withing the object context. Returns sql, and array of markers: [sql, [m1,m2,..]]
|
406
|
-
def eval_query
|
407
|
-
if @query.is_a? Proc
|
408
|
-
instance_eval(&@query)
|
409
|
-
else
|
410
|
-
instance_eval @query
|
411
|
-
end
|
412
|
-
sql = "select #{@main.to_sql}.* from #{tables_sql}"
|
413
|
-
sql+= "\n\twhere #{where_sql}"
|
414
|
-
sql+= "\n\torder by #{order_by_sql}" unless @order.empty?
|
415
|
-
log_debug_query sql
|
416
|
-
[sql, @exprs.inject([]){|result, expr| result.concat expr.markers}]
|
417
|
-
end
|
418
|
-
|
419
|
-
# Generates where clause for each expression joined by and clause
|
420
|
-
def where_sql
|
421
|
-
r_params.collect{|rp| rp.to_sql + '.name = \'' + rp.name + '\''}.concat(
|
422
|
-
@exprs.collect{|ex| ex.to_sql}).join(" and\n\t\t")
|
423
|
-
end
|
424
|
-
|
425
|
-
# Generates order by sql clause
|
426
|
-
def order_by_sql
|
427
|
-
@order.collect{|ord| ord.to_sql}.join(', ')
|
428
|
-
end
|
429
|
-
|
430
|
-
# Generates left outer join for each r_params used in query
|
431
|
-
def tables_sql
|
432
|
-
r_joins = {}
|
433
|
-
r_objects.each{|r_o| r_joins[r_o.to_sql] ||= []} # Collect all r_objects used in query
|
434
|
-
r_params.each{|r_p| r_joins[r_p.r_object.to_sql] << r_p.to_sql} #Join all r_params to r_objects
|
435
|
-
|
436
|
-
result = nil
|
437
|
-
for obj, params in r_joins
|
438
|
-
result = result ? result << ",\n\t\t" : ''
|
439
|
-
result << 'r_objects ' + obj
|
440
|
-
for param in params
|
441
|
-
result << " left outer join r_params #{param} on (#{obj}.object_pk = #{param}.object_pk)"
|
442
|
-
end
|
443
|
-
end
|
444
|
-
result
|
445
|
-
end
|
446
|
-
|
447
|
-
# Retruns r_params used in query. List of RParam.
|
448
|
-
def r_params
|
449
|
-
res = @exprs.inject([]) {|res, exp| res.concat exp.r_params}
|
450
|
-
@order.inject(res) {|res, ord| res.concat ord.r_params}
|
451
|
-
res.uniq!
|
452
|
-
res
|
453
|
-
end
|
454
|
-
|
455
|
-
# Retruns r_objects used in query. List of RObject.
|
456
|
-
def r_objects
|
457
|
-
res = (@r_objects.values + r_params.inject([]){|res, rp| res << rp.r_object})
|
458
|
-
res.uniq!
|
459
|
-
res
|
460
|
-
end
|
461
|
-
end
|
462
464
|
end
|
463
465
|
@@generic_factory = Factory.new
|
464
466
|
end
|