arel_ruby 0.0.1 → 0.1.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.
- data/README.md +13 -1
- data/examples/active_record.rb +2 -2
- data/lib/arel/visitors/ruby.rb +63 -23
- data/lib/arel_ruby/version.rb +1 -1
- metadata +2 -2
data/README.md
CHANGED
@@ -18,7 +18,19 @@ Or install it yourself as:
|
|
18
18
|
|
19
19
|
## Usage
|
20
20
|
|
21
|
-
|
21
|
+
This gem adds `to_ruby` method onto ARel.
|
22
|
+
The `to_ruby` method transforms ARel AST into pure Ruby Enumerable manipulations, so that you can execute queries without using any RDBMS engine.
|
23
|
+
Try this on your Rails app and you will realize what's actually gonna happen.
|
24
|
+
|
25
|
+
YourActiveRecordModel.where(name: 'foo').to_ruby.to_source
|
26
|
+
YourActiveRecordModel.order('id').to_ruby.to_source
|
27
|
+
YourActiveRecordModel.offset(10).limit(5).to_ruby.to_source
|
28
|
+
YourActiveRecordModel.group('created_at').to_ruby.to_source
|
29
|
+
|
30
|
+
|
31
|
+
## Examples
|
32
|
+
|
33
|
+
See examples directory
|
22
34
|
|
23
35
|
## Contributing
|
24
36
|
|
data/examples/active_record.rb
CHANGED
@@ -3,8 +3,8 @@ module ActiveRecord
|
|
3
3
|
def exec_queries_in_ruby
|
4
4
|
return @records if loaded?
|
5
5
|
ruby = build_arel.to_ruby
|
6
|
-
connection.send(:log, ruby, 'RUBY') do
|
7
|
-
self.klass.all
|
6
|
+
connection.send(:log, ruby.to_source, 'RUBY') do
|
7
|
+
ruby.call self.klass.all
|
8
8
|
end
|
9
9
|
end
|
10
10
|
end
|
data/lib/arel/visitors/ruby.rb
CHANGED
@@ -6,7 +6,6 @@ module Arel
|
|
6
6
|
class Ruby < Arel::Visitors::Visitor
|
7
7
|
def initialize
|
8
8
|
@connection = Object.new.extend(ActiveRecord::ConnectionAdapters::Quoting)
|
9
|
-
@chains = []
|
10
9
|
@dummy_column = Struct.new(:type).new
|
11
10
|
end
|
12
11
|
|
@@ -36,28 +35,34 @@ module Arel
|
|
36
35
|
# end
|
37
36
|
|
38
37
|
def visit_Arel_Nodes_SelectStatement o
|
39
|
-
[
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
38
|
+
ProcWithSourceCollection.new([
|
39
|
+
o.cores.map { |x| visit_Arel_Nodes_SelectCore x },
|
40
|
+
(o.orders.map { |x| visit_Arel_Nodes_OrderCore x } unless o.orders.empty?),
|
41
|
+
(visit(o.offset) if o.offset),
|
42
|
+
(visit(o.limit) if o.limit),
|
43
|
+
o.cores.map { |x| x.groups.map { |x| visit x} },
|
44
|
+
])
|
46
45
|
end
|
47
46
|
|
48
47
|
def visit_Arel_Nodes_SelectCore o
|
49
48
|
[
|
50
49
|
# ("#{o.projections.map { |x| visit x }.join ', '}" unless o.projections.empty?),
|
51
50
|
# (visit(o.source) if o.source && !o.source.empty?),
|
52
|
-
(
|
51
|
+
(o.wheres.map { |x| visit x } unless o.wheres.empty?)
|
53
52
|
# (visit(o.having) if o.having),
|
54
|
-
]
|
55
|
-
|
53
|
+
]
|
54
|
+
end
|
56
55
|
|
57
56
|
def visit_Arel_Nodes_OrderCore order
|
58
|
-
|
57
|
+
#FIXME order_by('a, b') shouldn't actaully be sort_by(&:a).sort_by(&:b)
|
58
|
+
order.split(',').map(&:strip).map do |o|
|
59
59
|
attr, direction = o.split(/\s+/)
|
60
|
-
|
60
|
+
v = visit attr
|
61
|
+
ProcWithSource.new("sort_by(&:#{v})#{'.reverse' if direction == 'desc'}") do |collection|
|
62
|
+
col = collection.sort_by {|c| c.send v}
|
63
|
+
col.reverse! if direction == 'desc'
|
64
|
+
col
|
65
|
+
end
|
61
66
|
end
|
62
67
|
end
|
63
68
|
|
@@ -116,11 +121,13 @@ module Arel
|
|
116
121
|
# end
|
117
122
|
|
118
123
|
def visit_Arel_Nodes_Offset o
|
119
|
-
|
124
|
+
v = visit o.expr
|
125
|
+
ProcWithSource.new("from(#{v})") {|collection| collection.from(v) }
|
120
126
|
end
|
121
127
|
|
122
128
|
def visit_Arel_Nodes_Limit o
|
123
|
-
|
129
|
+
v = visit o.expr
|
130
|
+
ProcWithSource.new("take(#{v})") {|collection| collection.take(v) }
|
124
131
|
end
|
125
132
|
|
126
133
|
# def visit_Arel_Nodes_Grouping o
|
@@ -133,7 +140,8 @@ module Arel
|
|
133
140
|
# end
|
134
141
|
|
135
142
|
def visit_Arel_Nodes_Group o
|
136
|
-
|
143
|
+
v = visit o.expr
|
144
|
+
ProcWithSource.new("group_by {|g| g.#{v} }") {|collection| collection.group_by {|g| g.send v } }
|
137
145
|
end
|
138
146
|
|
139
147
|
# def visit_Arel_Nodes_NamedFunction o
|
@@ -210,7 +218,7 @@ module Arel
|
|
210
218
|
# end
|
211
219
|
|
212
220
|
def visit_Arel_Nodes_And o
|
213
|
-
o.children.map { |x| "select {|o|
|
221
|
+
o.children.map { |x| ProcWithSource.new("select {|o| o.#{visit(x).to_source}}") { |collection| collection.select {|obj| visit(x).call(obj) } } }
|
214
222
|
end
|
215
223
|
|
216
224
|
# def visit_Arel_Nodes_Or o
|
@@ -220,7 +228,8 @@ module Arel
|
|
220
228
|
# end
|
221
229
|
|
222
230
|
def visit_Arel_Nodes_Equality o
|
223
|
-
|
231
|
+
l, r = visit(o.left), visit(o.right)
|
232
|
+
ProcWithSource.new("#{l} == #{r}") { |o| o.send(l) == r }
|
224
233
|
end
|
225
234
|
|
226
235
|
# def visit_Arel_Nodes_NotEqual o
|
@@ -234,7 +243,7 @@ module Arel
|
|
234
243
|
|
235
244
|
|
236
245
|
def visit_Arel_Attributes_Attribute o
|
237
|
-
|
246
|
+
o.name
|
238
247
|
end
|
239
248
|
alias :visit_Arel_Attributes_Integer :visit_Arel_Attributes_Attribute
|
240
249
|
alias :visit_Arel_Attributes_Float :visit_Arel_Attributes_Attribute
|
@@ -251,7 +260,8 @@ module Arel
|
|
251
260
|
alias :visit_Fixnum :literal
|
252
261
|
|
253
262
|
def quoted o
|
254
|
-
quote
|
263
|
+
# don't actually quote...
|
264
|
+
o
|
255
265
|
end
|
256
266
|
|
257
267
|
alias :visit_ActiveSupport_Multibyte_Chars :quoted
|
@@ -278,13 +288,43 @@ module Arel
|
|
278
288
|
# alias :visit_Arel_Nodes_Multiplication :visit_Arel_Nodes_InfixOperation
|
279
289
|
# alias :visit_Arel_Nodes_Division :visit_Arel_Nodes_InfixOperation
|
280
290
|
|
281
|
-
|
282
|
-
|
283
|
-
|
291
|
+
def visit_Array o
|
292
|
+
o.map { |x| visit x }
|
293
|
+
end
|
284
294
|
|
285
295
|
def quote value
|
286
296
|
@connection.quote value, @dummy_column
|
287
297
|
end
|
288
298
|
end
|
299
|
+
|
300
|
+
class ProcWithSource
|
301
|
+
def initialize(source, &block)
|
302
|
+
@source, @block = source, block
|
303
|
+
end
|
304
|
+
|
305
|
+
def call(*args)
|
306
|
+
@block.call(*args)
|
307
|
+
end
|
308
|
+
|
309
|
+
def to_source
|
310
|
+
@source
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
314
|
+
class ProcWithSourceCollection
|
315
|
+
def initialize(procs)
|
316
|
+
@procs = procs.flatten.compact
|
317
|
+
end
|
318
|
+
|
319
|
+
def call(collection)
|
320
|
+
@procs.inject(collection) do |result, lmd|
|
321
|
+
lmd.call result
|
322
|
+
end
|
323
|
+
end
|
324
|
+
|
325
|
+
def to_source
|
326
|
+
@procs.map(&:to_source).join('.')
|
327
|
+
end
|
328
|
+
end
|
289
329
|
end
|
290
330
|
end
|
data/lib/arel_ruby/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: arel_ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-07-
|
12
|
+
date: 2012-07-13 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: ARel Ruby visitor
|
15
15
|
email:
|