arel_ruby 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -18,7 +18,19 @@ Or install it yourself as:
18
18
 
19
19
  ## Usage
20
20
 
21
- See examples
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
 
@@ -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.instance_eval ruby
6
+ connection.send(:log, ruby.to_source, 'RUBY') do
7
+ ruby.call self.klass.all
8
8
  end
9
9
  end
10
10
  end
@@ -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
- o.cores.map { |x| visit_Arel_Nodes_SelectCore x }.join,
41
- ("#{o.orders.map { |x| visit_Arel_Nodes_OrderCore x }.join('.')}" unless o.orders.empty?),
42
- (visit(o.offset) if o.offset),
43
- (visit(o.limit) if o.limit),
44
- o.cores.map { |x| x.groups.map { |x| visit x}.join '.' }.flatten.join,
45
- ].compact.delete_if {|e| e.respond_to?(:empty?) && e.empty? }.join '.'
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
- ("#{o.wheres.map { |x| visit x }.join '.' }" unless o.wheres.empty?),
51
+ (o.wheres.map { |x| visit x } unless o.wheres.empty?)
53
52
  # (visit(o.having) if o.having),
54
- ].compact.join '.'
55
- end
53
+ ]
54
+ end
56
55
 
57
56
  def visit_Arel_Nodes_OrderCore order
58
- order.split(',').map do |o|
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
- "sort_by(&:#{visit attr})#{'.reverse' if direction == 'desc'}"
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
- "from(#{visit o.expr})"
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
- "take(#{visit o.expr})"
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
- "group_by {|g| g.#{visit o.expr}}"
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| #{visit x}}"}.join '.'
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
- "#{visit o.left} == #{visit o.right}"
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
- "o.#{o.name}"
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 o
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
- # def visit_Array o
282
- # o.map { |x| visit x }.join(', ')
283
- # end
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
@@ -1,3 +1,3 @@
1
1
  module ArelRuby
2
- VERSION = '0.0.1'
2
+ VERSION = '0.1.0'
3
3
  end
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.1
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-06 00:00:00.000000000 Z
12
+ date: 2012-07-13 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: ARel Ruby visitor
15
15
  email: