sunstone 0.1.0 → 1.0.0
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.
- checksums.yaml +4 -4
- data/lib/active_record/connection_adapters/sunstone/column.rb +19 -0
- data/lib/active_record/connection_adapters/sunstone/database_statements.rb +40 -0
- data/lib/active_record/connection_adapters/sunstone/schema_statements.rb +95 -0
- data/lib/active_record/connection_adapters/sunstone/type/date_time.rb +22 -0
- data/lib/active_record/connection_adapters/sunstone_adapter.rb +177 -0
- data/lib/arel/collectors/sunstone.rb +75 -0
- data/lib/arel/visitors/sunstone.rb +769 -0
- data/lib/ext/active_record/associations/builder/has_and_belongs_to_many.rb +48 -0
- data/lib/ext/active_record/relation.rb +26 -0
- data/lib/ext/active_record/statement_cache.rb +24 -0
- data/lib/sunstone.rb +37 -347
- data/lib/sunstone/connection.rb +337 -0
- data/sunstone.gemspec +3 -2
- data/test/sunstone/connection_test.rb +319 -0
- data/test/sunstone/parser_test.rb +21 -21
- metadata +30 -36
- data/lib/sunstone/model.rb +0 -23
- data/lib/sunstone/model/attributes.rb +0 -99
- data/lib/sunstone/model/persistence.rb +0 -168
- data/lib/sunstone/schema.rb +0 -38
- data/lib/sunstone/type/boolean.rb +0 -19
- data/lib/sunstone/type/date_time.rb +0 -20
- data/lib/sunstone/type/decimal.rb +0 -19
- data/lib/sunstone/type/integer.rb +0 -17
- data/lib/sunstone/type/mutable.rb +0 -16
- data/lib/sunstone/type/string.rb +0 -18
- data/lib/sunstone/type/value.rb +0 -97
- data/test/sunstone/model/associations_test.rb +0 -55
- data/test/sunstone/model/attributes_test.rb +0 -60
- data/test/sunstone/model/persistence_test.rb +0 -173
- data/test/sunstone/model_test.rb +0 -11
- data/test/sunstone/schema_test.rb +0 -25
- data/test/sunstone/type/boolean_test.rb +0 -24
- data/test/sunstone/type/date_time_test.rb +0 -31
- data/test/sunstone/type/decimal_test.rb +0 -27
- data/test/sunstone/type/integer_test.rb +0 -29
- data/test/sunstone/type/string_test.rb +0 -54
- data/test/sunstone/type/value_test.rb +0 -27
@@ -0,0 +1,769 @@
|
|
1
|
+
require 'arel/visitors/visitor'
|
2
|
+
class Arel::Visitors::Dot
|
3
|
+
def visit_Arel_Nodes_Casted o
|
4
|
+
# collector << quoted(o.val, o.attribute).to_s
|
5
|
+
visit_String o.val
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
module Arel
|
10
|
+
module Visitors
|
11
|
+
class Sunstone < Arel::Visitors::Reduce
|
12
|
+
|
13
|
+
def initialize connection
|
14
|
+
@connection = connection
|
15
|
+
@schema_cache = connection.schema_cache
|
16
|
+
|
17
|
+
@nodes = []
|
18
|
+
@edges = []
|
19
|
+
@node_stack = []
|
20
|
+
@edge_stack = []
|
21
|
+
@seen = {}
|
22
|
+
end
|
23
|
+
|
24
|
+
def compile node, &block
|
25
|
+
accept(node, Arel::Collectors::SQLString.new, &block).value
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def visit_Arel_Nodes_SelectStatement o, collector
|
31
|
+
collector = o.cores.inject(collector) { |c,x|
|
32
|
+
visit_Arel_Nodes_SelectCore(x, c)
|
33
|
+
}
|
34
|
+
|
35
|
+
if !o.orders.empty?
|
36
|
+
collector.order = o.orders.map { |x| visit(x, collector) }
|
37
|
+
end
|
38
|
+
|
39
|
+
collector = maybe_visit o.limit, collector
|
40
|
+
collector = maybe_visit o.offset, collector
|
41
|
+
# collector = maybe_visit o.lock, collector
|
42
|
+
|
43
|
+
collector
|
44
|
+
end
|
45
|
+
|
46
|
+
def visit_Arel_Nodes_SelectCore o, collector
|
47
|
+
collector.request_type = Net::HTTP::Get
|
48
|
+
|
49
|
+
unless o.projections.empty?
|
50
|
+
visit(o.projections.first, collector)
|
51
|
+
else
|
52
|
+
collector.operation = :select
|
53
|
+
end
|
54
|
+
|
55
|
+
if o.source && !o.source.empty?
|
56
|
+
collector.table = o.source.left.name
|
57
|
+
end
|
58
|
+
|
59
|
+
if !o.wheres.empty?
|
60
|
+
collector.where = o.wheres.map { |x| visit(x, collector) }.inject([]) { |c, w|
|
61
|
+
w.is_a?(Array) ? c += w : c << w
|
62
|
+
}
|
63
|
+
end
|
64
|
+
|
65
|
+
collector
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
#
|
70
|
+
# private
|
71
|
+
#
|
72
|
+
# def visit_Arel_Nodes_DeleteStatement o, collector
|
73
|
+
# collector << "DELETE FROM "
|
74
|
+
# collector = visit o.relation, collector
|
75
|
+
# if o.wheres.any?
|
76
|
+
# collector << " WHERE "
|
77
|
+
# inject_join o.wheres, collector, AND
|
78
|
+
# else
|
79
|
+
# collector
|
80
|
+
# end
|
81
|
+
# end
|
82
|
+
#
|
83
|
+
# # FIXME: we should probably have a 2-pass visitor for this
|
84
|
+
# def build_subselect key, o
|
85
|
+
# stmt = Nodes::SelectStatement.new
|
86
|
+
# core = stmt.cores.first
|
87
|
+
# core.froms = o.relation
|
88
|
+
# core.wheres = o.wheres
|
89
|
+
# core.projections = [key]
|
90
|
+
# stmt.limit = o.limit
|
91
|
+
# stmt.orders = o.orders
|
92
|
+
# stmt
|
93
|
+
# end
|
94
|
+
#
|
95
|
+
# def visit_Arel_Nodes_UpdateStatement o, collector
|
96
|
+
# if o.orders.empty? && o.limit.nil?
|
97
|
+
# wheres = o.wheres
|
98
|
+
# else
|
99
|
+
# wheres = [Nodes::In.new(o.key, [build_subselect(o.key, o)])]
|
100
|
+
# end
|
101
|
+
#
|
102
|
+
# collector << "UPDATE "
|
103
|
+
# collector = visit o.relation, collector
|
104
|
+
# unless o.values.empty?
|
105
|
+
# collector << " SET "
|
106
|
+
# collector = inject_join o.values, collector, ", "
|
107
|
+
# end
|
108
|
+
#
|
109
|
+
# unless wheres.empty?
|
110
|
+
# collector << " WHERE "
|
111
|
+
# collector = inject_join wheres, collector, " AND "
|
112
|
+
# end
|
113
|
+
#
|
114
|
+
# collector
|
115
|
+
# end
|
116
|
+
#
|
117
|
+
# def visit_Arel_Nodes_InsertStatement o, collector
|
118
|
+
# collector << "INSERT INTO "
|
119
|
+
# collector = visit o.relation, collector
|
120
|
+
# if o.columns.any?
|
121
|
+
# collector << " (#{o.columns.map { |x|
|
122
|
+
# quote_column_name x.name
|
123
|
+
# }.join ', '})"
|
124
|
+
# end
|
125
|
+
#
|
126
|
+
# if o.values
|
127
|
+
# maybe_visit o.values, collector
|
128
|
+
# elsif o.select
|
129
|
+
# maybe_visit o.select, collector
|
130
|
+
# else
|
131
|
+
# collector
|
132
|
+
# end
|
133
|
+
# end
|
134
|
+
#
|
135
|
+
# def visit_Arel_Nodes_Exists o, collector
|
136
|
+
# collector << "EXISTS ("
|
137
|
+
# collector = visit(o.expressions, collector) << ")"
|
138
|
+
# if o.alias
|
139
|
+
# collector << " AS "
|
140
|
+
# visit o.alias, collector
|
141
|
+
# else
|
142
|
+
# collector
|
143
|
+
# end
|
144
|
+
# end
|
145
|
+
#
|
146
|
+
def visit_Arel_Nodes_Casted o, collector
|
147
|
+
# collector << quoted(o.val, o.attribute).to_s
|
148
|
+
o.val
|
149
|
+
end
|
150
|
+
|
151
|
+
def visit_Arel_Nodes_Quoted o, collector
|
152
|
+
o.expr
|
153
|
+
end
|
154
|
+
#
|
155
|
+
# def visit_Arel_Nodes_True o, collector
|
156
|
+
# collector << "TRUE"
|
157
|
+
# end
|
158
|
+
#
|
159
|
+
# def visit_Arel_Nodes_False o, collector
|
160
|
+
# collector << "FALSE"
|
161
|
+
# end
|
162
|
+
#
|
163
|
+
# def table_exists? name
|
164
|
+
# @schema_cache.table_exists? name
|
165
|
+
# end
|
166
|
+
#
|
167
|
+
# def column_for attr
|
168
|
+
# return unless attr
|
169
|
+
# name = attr.name.to_s
|
170
|
+
# table = attr.relation.table_name
|
171
|
+
#
|
172
|
+
# return nil unless table_exists? table
|
173
|
+
#
|
174
|
+
# column_cache(table)[name]
|
175
|
+
# end
|
176
|
+
#
|
177
|
+
# def column_cache(table)
|
178
|
+
# @schema_cache.columns_hash(table)
|
179
|
+
# end
|
180
|
+
#
|
181
|
+
# def visit_Arel_Nodes_Values o, collector
|
182
|
+
# collector << "VALUES ("
|
183
|
+
#
|
184
|
+
# len = o.expressions.length - 1
|
185
|
+
# o.expressions.zip(o.columns).each_with_index { |(value, attr), i|
|
186
|
+
# if Nodes::SqlLiteral === value
|
187
|
+
# collector = visit value, collector
|
188
|
+
# else
|
189
|
+
# collector << quote(value, attr && column_for(attr)).to_s
|
190
|
+
# end
|
191
|
+
# unless i == len
|
192
|
+
# collector << ', '
|
193
|
+
# end
|
194
|
+
# }
|
195
|
+
#
|
196
|
+
# collector << ")"
|
197
|
+
# end
|
198
|
+
#
|
199
|
+
|
200
|
+
|
201
|
+
#
|
202
|
+
# def visit_Arel_Nodes_Bin o, collector
|
203
|
+
# visit o.expr, collector
|
204
|
+
# end
|
205
|
+
#
|
206
|
+
# def visit_Arel_Nodes_Distinct o, collector
|
207
|
+
# collector << DISTINCT
|
208
|
+
# end
|
209
|
+
#
|
210
|
+
# def visit_Arel_Nodes_DistinctOn o, collector
|
211
|
+
# raise NotImplementedError, 'DISTINCT ON not implemented for this db'
|
212
|
+
# end
|
213
|
+
#
|
214
|
+
# def visit_Arel_Nodes_With o, collector
|
215
|
+
# collector << "WITH "
|
216
|
+
# inject_join o.children, collector, ', '
|
217
|
+
# end
|
218
|
+
#
|
219
|
+
# def visit_Arel_Nodes_WithRecursive o, collector
|
220
|
+
# collector << "WITH RECURSIVE "
|
221
|
+
# inject_join o.children, collector, ', '
|
222
|
+
# end
|
223
|
+
#
|
224
|
+
# def visit_Arel_Nodes_Union o, collector
|
225
|
+
# collector << "( "
|
226
|
+
# infix_value(o, collector, " UNION ") << " )"
|
227
|
+
# end
|
228
|
+
#
|
229
|
+
# def visit_Arel_Nodes_UnionAll o, collector
|
230
|
+
# collector << "( "
|
231
|
+
# infix_value(o, collector, " UNION ALL ") << " )"
|
232
|
+
# end
|
233
|
+
#
|
234
|
+
# def visit_Arel_Nodes_Intersect o, collector
|
235
|
+
# collector << "( "
|
236
|
+
# infix_value(o, collector, " INTERSECT ") << " )"
|
237
|
+
# end
|
238
|
+
#
|
239
|
+
# def visit_Arel_Nodes_Except o, collector
|
240
|
+
# collector << "( "
|
241
|
+
# infix_value(o, collector, " EXCEPT ") << " )"
|
242
|
+
# end
|
243
|
+
#
|
244
|
+
# def visit_Arel_Nodes_NamedWindow o, collector
|
245
|
+
# collector << quote_column_name(o.name)
|
246
|
+
# collector << " AS "
|
247
|
+
# visit_Arel_Nodes_Window o, collector
|
248
|
+
# end
|
249
|
+
#
|
250
|
+
# def visit_Arel_Nodes_Window o, collector
|
251
|
+
# collector << "("
|
252
|
+
#
|
253
|
+
# if o.partitions.any?
|
254
|
+
# collector << "PARTITION BY "
|
255
|
+
# collector = inject_join o.partitions, collector, ", "
|
256
|
+
# end
|
257
|
+
#
|
258
|
+
# if o.orders.any?
|
259
|
+
# collector << ' ' if o.partitions.any?
|
260
|
+
# collector << "ORDER BY "
|
261
|
+
# collector = inject_join o.orders, collector, ", "
|
262
|
+
# end
|
263
|
+
#
|
264
|
+
# if o.framing
|
265
|
+
# collector << ' ' if o.partitions.any? or o.orders.any?
|
266
|
+
# collector = visit o.framing, collector
|
267
|
+
# end
|
268
|
+
#
|
269
|
+
# collector << ")"
|
270
|
+
# end
|
271
|
+
#
|
272
|
+
# def visit_Arel_Nodes_Rows o, collector
|
273
|
+
# if o.expr
|
274
|
+
# collector << "ROWS "
|
275
|
+
# visit o.expr, collector
|
276
|
+
# else
|
277
|
+
# collector << "ROWS"
|
278
|
+
# end
|
279
|
+
# end
|
280
|
+
#
|
281
|
+
# def visit_Arel_Nodes_Range o, collector
|
282
|
+
# if o.expr
|
283
|
+
# collector << "RANGE "
|
284
|
+
# visit o.expr, collector
|
285
|
+
# else
|
286
|
+
# collector << "RANGE"
|
287
|
+
# end
|
288
|
+
# end
|
289
|
+
#
|
290
|
+
# def visit_Arel_Nodes_Preceding o, collector
|
291
|
+
# collector = if o.expr
|
292
|
+
# visit o.expr, collector
|
293
|
+
# else
|
294
|
+
# collector << "UNBOUNDED"
|
295
|
+
# end
|
296
|
+
#
|
297
|
+
# collector << " PRECEDING"
|
298
|
+
# end
|
299
|
+
#
|
300
|
+
# def visit_Arel_Nodes_Following o, collector
|
301
|
+
# collector = if o.expr
|
302
|
+
# visit o.expr, collector
|
303
|
+
# else
|
304
|
+
# collector << "UNBOUNDED"
|
305
|
+
# end
|
306
|
+
#
|
307
|
+
# collector << " FOLLOWING"
|
308
|
+
# end
|
309
|
+
#
|
310
|
+
# def visit_Arel_Nodes_CurrentRow o, collector
|
311
|
+
# collector << "CURRENT ROW"
|
312
|
+
# end
|
313
|
+
#
|
314
|
+
# def visit_Arel_Nodes_Over o, collector
|
315
|
+
# case o.right
|
316
|
+
# when nil
|
317
|
+
# visit(o.left, collector) << " OVER ()"
|
318
|
+
# when Arel::Nodes::SqlLiteral
|
319
|
+
# infix_value o, collector, " OVER "
|
320
|
+
# when String, Symbol
|
321
|
+
# visit(o.left, collector) << " OVER #{quote_column_name o.right.to_s}"
|
322
|
+
# else
|
323
|
+
# infix_value o, collector, " OVER "
|
324
|
+
# end
|
325
|
+
# end
|
326
|
+
#
|
327
|
+
# def visit_Arel_Nodes_Having o, collector
|
328
|
+
# collector << "HAVING "
|
329
|
+
# visit o.expr, collector
|
330
|
+
# end
|
331
|
+
#
|
332
|
+
def visit_Arel_Nodes_Offset o, collector
|
333
|
+
collector.offset = visit(o.expr, collector)
|
334
|
+
collector
|
335
|
+
end
|
336
|
+
|
337
|
+
def visit_Arel_Nodes_Limit o, collector
|
338
|
+
collector.limit = visit(o.expr, collector)
|
339
|
+
collector
|
340
|
+
end
|
341
|
+
|
342
|
+
# FIXME: this does nothing on most databases, but does on MSSQL
|
343
|
+
def visit_Arel_Nodes_Top o, collector
|
344
|
+
collector
|
345
|
+
end
|
346
|
+
#
|
347
|
+
# def visit_Arel_Nodes_Lock o, collector
|
348
|
+
# visit o.expr, collector
|
349
|
+
# end
|
350
|
+
#
|
351
|
+
def visit_Arel_Nodes_Grouping o, collector
|
352
|
+
visit(o.expr, collector)
|
353
|
+
end
|
354
|
+
#
|
355
|
+
# def visit_Arel_SelectManager o, collector
|
356
|
+
# collector << "(#{o.to_sql.rstrip})"
|
357
|
+
# end
|
358
|
+
#
|
359
|
+
def visit_Arel_Nodes_Ascending o, collector
|
360
|
+
{ visit(o.expr, collector) => :asc }
|
361
|
+
end
|
362
|
+
|
363
|
+
def visit_Arel_Nodes_Descending o, collector
|
364
|
+
{ visit(o.expr, collector) => :desc }
|
365
|
+
end
|
366
|
+
#
|
367
|
+
# def visit_Arel_Nodes_Group o, collector
|
368
|
+
# visit o.expr, collector
|
369
|
+
# end
|
370
|
+
#
|
371
|
+
# def visit_Arel_Nodes_NamedFunction o, collector
|
372
|
+
# collector << o.name
|
373
|
+
# collector << "("
|
374
|
+
# collector << "DISTINCT " if o.distinct
|
375
|
+
# collector = inject_join(o.expressions, collector, ", ") << ")"
|
376
|
+
# if o.alias
|
377
|
+
# collector << " AS "
|
378
|
+
# visit o.alias, collector
|
379
|
+
# else
|
380
|
+
# collector
|
381
|
+
# end
|
382
|
+
# end
|
383
|
+
#
|
384
|
+
# def visit_Arel_Nodes_Extract o, collector
|
385
|
+
# collector << "EXTRACT(#{o.field.to_s.upcase} FROM "
|
386
|
+
# collector = visit o.expr, collector
|
387
|
+
# collector << ")"
|
388
|
+
# if o.alias
|
389
|
+
# collector << " AS "
|
390
|
+
# visit o.alias, collector
|
391
|
+
# else
|
392
|
+
# collector
|
393
|
+
# end
|
394
|
+
# end
|
395
|
+
#
|
396
|
+
def visit_Arel_Nodes_Count o, collector
|
397
|
+
collector.operation = :count
|
398
|
+
collector.columns = o.expressions.first
|
399
|
+
end
|
400
|
+
#
|
401
|
+
# def visit_Arel_Nodes_Sum o, collector
|
402
|
+
# aggregate "SUM", o, collector
|
403
|
+
# end
|
404
|
+
#
|
405
|
+
def visit_Arel_Nodes_Max o, collector
|
406
|
+
collector.operation = :max
|
407
|
+
if o.expressions.first.is_a?(Arel::Attributes::Attribute)
|
408
|
+
relation = o.expressions.first.relation
|
409
|
+
join_name = relation.table_alias || relation.name
|
410
|
+
collector.columns = join_name ? o.expressions.first.name : "#{join_name}.#{o.expressions.first.name}"
|
411
|
+
else
|
412
|
+
collector.columns = o.expressions.first
|
413
|
+
end
|
414
|
+
end
|
415
|
+
|
416
|
+
def visit_Arel_Nodes_Min o, collector
|
417
|
+
collector.operation = :min
|
418
|
+
if o.expressions.first.is_a?(Arel::Attributes::Attribute)
|
419
|
+
relation = o.expressions.first.relation
|
420
|
+
join_name = relation.table_alias || relation.name
|
421
|
+
collector.columns = join_name ? o.expressions.first.name : "#{join_name}.#{o.expressions.first.name}"
|
422
|
+
else
|
423
|
+
collector.columns = o.expressions.first
|
424
|
+
end
|
425
|
+
end
|
426
|
+
|
427
|
+
def visit_Arel_Nodes_Avg o, collector
|
428
|
+
# puts o.inspect
|
429
|
+
# #<Arel::Nodes::Avg:0x007fd863f55df0 @expressions=["rate_per_sqft_per_year"], @alias="avg_id", @distinct=false>
|
430
|
+
|
431
|
+
collector.operation = :average
|
432
|
+
if o.expressions.first.is_a?(Arel::Attributes::Attribute)
|
433
|
+
relation = o.expressions.first.relation
|
434
|
+
join_name = relation.table_alias || relation.name
|
435
|
+
collector.columns = join_name ? o.expressions.first.name : "#{join_name}.#{o.expressions.first.name}"
|
436
|
+
else
|
437
|
+
collector.columns = o.expressions.first
|
438
|
+
end
|
439
|
+
end
|
440
|
+
#
|
441
|
+
# def visit_Arel_Nodes_TableAlias o, collector
|
442
|
+
# collector = visit o.relation, collector
|
443
|
+
# collector << " "
|
444
|
+
# collector << quote_table_name(o.name)
|
445
|
+
# end
|
446
|
+
#
|
447
|
+
# def visit_Arel_Nodes_Between o, collector
|
448
|
+
# collector = visit o.left, collector
|
449
|
+
# collector << " BETWEEN "
|
450
|
+
# visit o.right, collector
|
451
|
+
# end
|
452
|
+
#
|
453
|
+
# def visit_Arel_Nodes_GreaterThanOrEqual o, collector
|
454
|
+
# collector = visit o.left, collector
|
455
|
+
# collector << " >= "
|
456
|
+
# visit o.right, collector
|
457
|
+
# end
|
458
|
+
#
|
459
|
+
# def visit_Arel_Nodes_GreaterThan o, collector
|
460
|
+
# collector = visit o.left, collector
|
461
|
+
# collector << " > "
|
462
|
+
# visit o.right, collector
|
463
|
+
# end
|
464
|
+
#
|
465
|
+
# def visit_Arel_Nodes_LessThanOrEqual o, collector
|
466
|
+
# collector = visit o.left, collector
|
467
|
+
# collector << " <= "
|
468
|
+
# visit o.right, collector
|
469
|
+
# end
|
470
|
+
#
|
471
|
+
# def visit_Arel_Nodes_LessThan o, collector
|
472
|
+
# collector = visit o.left, collector
|
473
|
+
# collector << " < "
|
474
|
+
# visit o.right, collector
|
475
|
+
# end
|
476
|
+
#
|
477
|
+
# def visit_Arel_Nodes_Matches o, collector
|
478
|
+
# collector = visit o.left, collector
|
479
|
+
# collector << " LIKE "
|
480
|
+
# visit o.right, collector
|
481
|
+
# end
|
482
|
+
#
|
483
|
+
# def visit_Arel_Nodes_DoesNotMatch o, collector
|
484
|
+
# collector = visit o.left, collector
|
485
|
+
# collector << " NOT LIKE "
|
486
|
+
# visit o.right, collector
|
487
|
+
# end
|
488
|
+
#
|
489
|
+
def visit_Arel_Nodes_JoinSource o, collector
|
490
|
+
if o.left
|
491
|
+
collector = visit o.left, collector
|
492
|
+
end
|
493
|
+
if o.right.any?
|
494
|
+
collector << " " if o.left
|
495
|
+
collector = inject_join o.right, collector, ' '
|
496
|
+
end
|
497
|
+
collector
|
498
|
+
end
|
499
|
+
#
|
500
|
+
# def visit_Arel_Nodes_Regexp o, collector
|
501
|
+
# raise NotImplementedError, '~ not implemented for this db'
|
502
|
+
# end
|
503
|
+
#
|
504
|
+
# def visit_Arel_Nodes_NotRegexp o, collector
|
505
|
+
# raise NotImplementedError, '!~ not implemented for this db'
|
506
|
+
# end
|
507
|
+
#
|
508
|
+
# def visit_Arel_Nodes_StringJoin o, collector
|
509
|
+
# visit o.left, collector
|
510
|
+
# end
|
511
|
+
#
|
512
|
+
# def visit_Arel_Nodes_FullOuterJoin o
|
513
|
+
# "FULL OUTER JOIN #{visit o.left} #{visit o.right}"
|
514
|
+
# end
|
515
|
+
#
|
516
|
+
# def visit_Arel_Nodes_OuterJoin o, collector
|
517
|
+
# collector << "LEFT OUTER JOIN "
|
518
|
+
# collector = visit o.left, collector
|
519
|
+
# collector << " "
|
520
|
+
# visit o.right, collector
|
521
|
+
# end
|
522
|
+
#
|
523
|
+
# def visit_Arel_Nodes_RightOuterJoin o
|
524
|
+
# "RIGHT OUTER JOIN #{visit o.left} #{visit o.right}"
|
525
|
+
# end
|
526
|
+
#
|
527
|
+
# def visit_Arel_Nodes_InnerJoin o, collector
|
528
|
+
# collector << "INNER JOIN "
|
529
|
+
# collector = visit o.left, collector
|
530
|
+
# if o.right
|
531
|
+
# collector << SPACE
|
532
|
+
# visit(o.right, collector)
|
533
|
+
# else
|
534
|
+
# collector
|
535
|
+
# end
|
536
|
+
# end
|
537
|
+
#
|
538
|
+
# def visit_Arel_Nodes_On o, collector
|
539
|
+
# collector << "ON "
|
540
|
+
# visit o.expr, collector
|
541
|
+
# end
|
542
|
+
#
|
543
|
+
# def visit_Arel_Nodes_Not o, collector
|
544
|
+
# collector << "NOT ("
|
545
|
+
# visit(o.expr, collector) << ")"
|
546
|
+
# end
|
547
|
+
#
|
548
|
+
def visit_Arel_Table o, collector
|
549
|
+
if o.table_alias
|
550
|
+
collector << "#{o.name} #{o.table_alias}"
|
551
|
+
else
|
552
|
+
collector << o.name
|
553
|
+
end
|
554
|
+
end
|
555
|
+
|
556
|
+
# def visit_Arel_Nodes_In o, collector
|
557
|
+
# if Array === o.right && o.right.empty?
|
558
|
+
# collector << '1=0'
|
559
|
+
# else
|
560
|
+
# collector = visit o.left, collector
|
561
|
+
# collector << " IN ("
|
562
|
+
# visit(o.right, collector) << ")"
|
563
|
+
# end
|
564
|
+
# end
|
565
|
+
#
|
566
|
+
# def visit_Arel_Nodes_NotIn o, collector
|
567
|
+
# if Array === o.right && o.right.empty?
|
568
|
+
# collector << '1=1'
|
569
|
+
# else
|
570
|
+
# collector = visit o.left, collector
|
571
|
+
# collector << " NOT IN ("
|
572
|
+
# collector = visit o.right, collector
|
573
|
+
# collector << ")"
|
574
|
+
# end
|
575
|
+
# end
|
576
|
+
#
|
577
|
+
def visit_Arel_Nodes_And o, collector
|
578
|
+
ors = []
|
579
|
+
ors << o.children.inject({}) do |c, x|
|
580
|
+
value = visit(x, collector)
|
581
|
+
if value.is_a?(Hash)
|
582
|
+
c.deep_merge(value)
|
583
|
+
elsif value.is_a?(Array)
|
584
|
+
value.size == 1 ? ors << value : ors += value
|
585
|
+
end
|
586
|
+
end
|
587
|
+
ors
|
588
|
+
end
|
589
|
+
|
590
|
+
def visit_Arel_Nodes_Or o, collector
|
591
|
+
ors = []
|
592
|
+
[o.left, o.right].each do |x|
|
593
|
+
value = visit(x, collector)
|
594
|
+
value.is_a?(Array) ? ors += value : ors << value
|
595
|
+
end
|
596
|
+
ors
|
597
|
+
end
|
598
|
+
|
599
|
+
# def visit_Arel_Nodes_Assignment o, collector
|
600
|
+
# case o.right
|
601
|
+
# when Arel::Nodes::UnqualifiedColumn, Arel::Attributes::Attribute, Arel::Nodes::BindParam
|
602
|
+
# collector = visit o.left, collector
|
603
|
+
# collector << " = "
|
604
|
+
# visit o.right, collector
|
605
|
+
# else
|
606
|
+
# collector = visit o.left, collector
|
607
|
+
# collector << " = "
|
608
|
+
# collector << quote(o.right, column_for(o.left)).to_s
|
609
|
+
# end
|
610
|
+
# end
|
611
|
+
|
612
|
+
def visit_Arel_Nodes_Equality o, collector
|
613
|
+
key = visit(o.left, collector).split('.')
|
614
|
+
value = (o.right.nil? ? nil : visit(o.right, collector))
|
615
|
+
|
616
|
+
hash = {
|
617
|
+
key.pop => value
|
618
|
+
}
|
619
|
+
|
620
|
+
while key.size > 0
|
621
|
+
hash = { key.pop => hash }
|
622
|
+
end
|
623
|
+
hash
|
624
|
+
end
|
625
|
+
|
626
|
+
# def visit_Arel_Nodes_NotEqual o, collector
|
627
|
+
# right = o.right
|
628
|
+
#
|
629
|
+
# collector = visit o.left, collector
|
630
|
+
#
|
631
|
+
# if right.nil?
|
632
|
+
# collector << " IS NOT NULL"
|
633
|
+
# else
|
634
|
+
# collector << " != "
|
635
|
+
# visit right, collector
|
636
|
+
# end
|
637
|
+
# end
|
638
|
+
#
|
639
|
+
# def visit_Arel_Nodes_As o, collector
|
640
|
+
# collector = visit o.left, collector
|
641
|
+
# collector << " AS "
|
642
|
+
# visit o.right, collector
|
643
|
+
# end
|
644
|
+
#
|
645
|
+
# def visit_Arel_Nodes_UnqualifiedColumn o, collector
|
646
|
+
# collector << "#{quote_column_name o.name}"
|
647
|
+
# collector
|
648
|
+
# end
|
649
|
+
#
|
650
|
+
def visit_Arel_Attributes_Attribute o, collector
|
651
|
+
join_name = o.relation.table_alias || o.relation.name
|
652
|
+
# collector <<
|
653
|
+
collector.table == join_name ? o.name : "#{join_name}.#{o.name}"
|
654
|
+
end
|
655
|
+
alias :visit_Arel_Attributes_Integer :visit_Arel_Attributes_Attribute
|
656
|
+
alias :visit_Arel_Attributes_Float :visit_Arel_Attributes_Attribute
|
657
|
+
alias :visit_Arel_Attributes_Decimal :visit_Arel_Attributes_Attribute
|
658
|
+
alias :visit_Arel_Attributes_String :visit_Arel_Attributes_Attribute
|
659
|
+
alias :visit_Arel_Attributes_Time :visit_Arel_Attributes_Attribute
|
660
|
+
alias :visit_Arel_Attributes_Boolean :visit_Arel_Attributes_Attribute
|
661
|
+
|
662
|
+
def visit_Arel_Nodes_BindParam o, collector
|
663
|
+
o
|
664
|
+
end
|
665
|
+
|
666
|
+
def literal(o, collector)
|
667
|
+
o.to_s;
|
668
|
+
end
|
669
|
+
alias :visit_Arel_Nodes_SqlLiteral :literal
|
670
|
+
alias :visit_Bignum :literal
|
671
|
+
alias :visit_Fixnum :literal
|
672
|
+
#
|
673
|
+
# def quoted o, a
|
674
|
+
# quote(o, column_for(a))
|
675
|
+
# end
|
676
|
+
#
|
677
|
+
# def unsupported o, collector
|
678
|
+
# raise "unsupported: #{o.class.name}"
|
679
|
+
# end
|
680
|
+
#
|
681
|
+
# alias :visit_ActiveSupport_Multibyte_Chars :unsupported
|
682
|
+
# alias :visit_ActiveSupport_StringInquirer :unsupported
|
683
|
+
# alias :visit_BigDecimal :unsupported
|
684
|
+
# alias :visit_Class :unsupported
|
685
|
+
# alias :visit_Date :unsupported
|
686
|
+
# alias :visit_DateTime :unsupported
|
687
|
+
# alias :visit_FalseClass :unsupported
|
688
|
+
# alias :visit_Float :unsupported
|
689
|
+
# alias :visit_Hash :unsupported
|
690
|
+
# alias :visit_NilClass :unsupported
|
691
|
+
# alias :visit_String :unsupported
|
692
|
+
# alias :visit_Symbol :unsupported
|
693
|
+
# alias :visit_Time :unsupported
|
694
|
+
# alias :visit_TrueClass :unsupported
|
695
|
+
#
|
696
|
+
# def visit_Arel_Nodes_InfixOperation o, collector
|
697
|
+
# collector = visit o.left, collector
|
698
|
+
# collector << " #{o.operator} "
|
699
|
+
# visit o.right, collector
|
700
|
+
# end
|
701
|
+
#
|
702
|
+
# alias :visit_Arel_Nodes_Addition :visit_Arel_Nodes_InfixOperation
|
703
|
+
# alias :visit_Arel_Nodes_Subtraction :visit_Arel_Nodes_InfixOperation
|
704
|
+
# alias :visit_Arel_Nodes_Multiplication :visit_Arel_Nodes_InfixOperation
|
705
|
+
# alias :visit_Arel_Nodes_Division :visit_Arel_Nodes_InfixOperation
|
706
|
+
|
707
|
+
def visit_Array o, collector
|
708
|
+
o.map { |x| visit(x, collector) }
|
709
|
+
end
|
710
|
+
|
711
|
+
# def quote value, column = nil
|
712
|
+
# return value if Arel::Nodes::SqlLiteral === value
|
713
|
+
# @connection.quote value, column
|
714
|
+
# end
|
715
|
+
#
|
716
|
+
# def quote_table_name name
|
717
|
+
# return name if Arel::Nodes::SqlLiteral === name
|
718
|
+
# @quoted_tables[name] ||= @connection.quote_table_name(name)
|
719
|
+
# end
|
720
|
+
#
|
721
|
+
# def quote_column_name name
|
722
|
+
# @quoted_columns[name] ||= Arel::Nodes::SqlLiteral === name ? name : @connection.quote_column_name(name)
|
723
|
+
# end
|
724
|
+
#
|
725
|
+
# def maybe_visit thing, collector
|
726
|
+
# return collector unless thing
|
727
|
+
# collector << " "
|
728
|
+
# visit thing, collector
|
729
|
+
# end
|
730
|
+
#
|
731
|
+
def inject_join list, collector, join_str
|
732
|
+
len = list.length - 1
|
733
|
+
list.each_with_index.inject(collector) { |c, (x,i)|
|
734
|
+
if i == len
|
735
|
+
visit x, c
|
736
|
+
else
|
737
|
+
visit(x, c) << join_str
|
738
|
+
end
|
739
|
+
}
|
740
|
+
end
|
741
|
+
#
|
742
|
+
# def infix_value o, collector, value
|
743
|
+
# collector = visit o.left, collector
|
744
|
+
# collector << value
|
745
|
+
# visit o.right, collector
|
746
|
+
# end
|
747
|
+
#
|
748
|
+
def aggregate name, o, collector
|
749
|
+
collector << "#{name}("
|
750
|
+
if o.distinct
|
751
|
+
collector << "DISTINCT "
|
752
|
+
end
|
753
|
+
collector = inject_join(o.expressions, collector, ", ") << ")"
|
754
|
+
if o.alias
|
755
|
+
collector << " AS "
|
756
|
+
visit o.alias, collector
|
757
|
+
else
|
758
|
+
collector
|
759
|
+
end
|
760
|
+
end
|
761
|
+
|
762
|
+
def maybe_visit thing, collector
|
763
|
+
return collector unless thing
|
764
|
+
collector << " "
|
765
|
+
visit thing, collector
|
766
|
+
end
|
767
|
+
end
|
768
|
+
end
|
769
|
+
end
|