squeel 0.8.6 → 0.8.7

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.
@@ -38,14 +38,14 @@ module Squeel
38
38
  # already bound to the proper table.
39
39
  #
40
40
  # Squeel, on the other hand, needs to do its best to ensure the predicates are still
41
- # winding up against the proper table. Merging relations is a really nifty shortcut
42
- # but another little corner of ActiveRecord where the magic quickly fades. :(
43
- def merge(r, association_name = nil)
44
- if association_name || relation_with_different_base?(r)
45
- r = r.clone
46
- association_name ||= infer_association_for_relation_merge(r)
47
- prepare_relation_for_association_merge!(r, association_name)
48
- self.joins_values += [association_name] if reflect_on_association(association_name)
41
+ # winding up against the proper table. The most "correct" way I can think of to do
42
+ # this is to try to emulate the default AR behavior -- that is, de-squeelifying
43
+ # the *_values, erm... values by visiting them and converting them to ARel nodes
44
+ # before merging. Merging relations is a nifty little trick, but it's another
45
+ # little corner of ActiveRecord where the magic quickly fades. :(
46
+ def merge(r)
47
+ if relation_with_different_base?(r)
48
+ r = r.clone.visit!
49
49
  end
50
50
 
51
51
  super(r)
@@ -56,11 +56,6 @@ module Squeel
56
56
  base_class.name != r.klass.base_class.name
57
57
  end
58
58
 
59
- def infer_association_for_relation_merge(r)
60
- default_association = reflect_on_all_associations.detect {|a| a.class_name == r.klass.name}
61
- default_association ? default_association.name : r.table_name.to_sym
62
- end
63
-
64
59
  def prepare_relation_for_association_merge!(r, association_name)
65
60
  r.where_values.map! {|w| Squeel::Visitors::PredicateVisitor.can_visit?(w) ? {association_name => w} : w}
66
61
  r.having_values.map! {|h| Squeel::Visitors::PredicateVisitor.can_visit?(h) ? {association_name => h} : h}
@@ -71,6 +66,19 @@ module Squeel
71
66
  r.includes_values.map! {|i| [Symbol, Hash, Nodes::Stub, Nodes::Join, Nodes::KeyPath].include?(i.class) ? {association_name => i} : i}
72
67
  end
73
68
 
69
+ def visit!
70
+ predicate_viz = predicate_visitor
71
+ attribute_viz = attribute_visitor
72
+
73
+ @where_values = predicate_viz.accept((@where_values - ['']).uniq)
74
+ @having_values = predicate_viz.accept(@having_values.uniq.reject{|h| h.blank?})
75
+ @group_values = attribute_viz.accept(@group_values.uniq.reject{|g| g.blank?})
76
+ @order_values = attribute_viz.accept(@order_values.uniq.reject{|o| o.blank?})
77
+ @select_values = attribute_viz.accept(@select_values.uniq)
78
+
79
+ self
80
+ end
81
+
74
82
  def build_arel
75
83
  arel = table
76
84
 
@@ -38,13 +38,14 @@ module Squeel
38
38
  # already bound to the proper table.
39
39
  #
40
40
  # Squeel, on the other hand, needs to do its best to ensure the predicates are still
41
- # winding up against the proper table. Merging relations is a really nifty shortcut
42
- # but another little corner of ActiveRecord where the magic quickly fades. :(
43
- def merge(r, association_name = nil)
44
- if association_name || relation_with_different_base?(r)
45
- r = r.clone
46
- association_name ||= infer_association_for_relation_merge(r)
47
- prepare_relation_for_association_merge!(r, association_name)
41
+ # winding up against the proper table. The most "correct" way I can think of to do
42
+ # this is to try to emulate the default AR behavior -- that is, de-squeelifying
43
+ # the *_values, erm... values by visiting them and converting them to ARel nodes
44
+ # before merging. Merging relations is a nifty little trick, but it's another
45
+ # little corner of ActiveRecord where the magic quickly fades. :(
46
+ def merge(r)
47
+ if relation_with_different_base?(r)
48
+ r = r.clone.visit!
48
49
  end
49
50
 
50
51
  super(r)
@@ -55,11 +56,6 @@ module Squeel
55
56
  base_class.name != r.klass.base_class.name
56
57
  end
57
58
 
58
- def infer_association_for_relation_merge(r)
59
- default_association = reflect_on_all_associations.detect {|a| a.class_name == r.klass.name}
60
- default_association ? default_association.name : r.table_name.to_sym
61
- end
62
-
63
59
  def prepare_relation_for_association_merge!(r, association_name)
64
60
  r.where_values.map! {|w| Squeel::Visitors::PredicateVisitor.can_visit?(w) ? {association_name => w} : w}
65
61
  r.having_values.map! {|h| Squeel::Visitors::PredicateVisitor.can_visit?(h) ? {association_name => h} : h}
@@ -70,6 +66,19 @@ module Squeel
70
66
  r.includes_values.map! {|i| [Symbol, Hash, Nodes::Stub, Nodes::Join, Nodes::KeyPath].include?(i.class) ? {association_name => i} : i}
71
67
  end
72
68
 
69
+ def visit!
70
+ predicate_viz = predicate_visitor
71
+ attribute_viz = attribute_visitor
72
+
73
+ @where_values = predicate_viz.accept((@where_values - ['']).uniq)
74
+ @having_values = predicate_viz.accept(@having_values.uniq.reject{|h| h.blank?})
75
+ @group_values = attribute_viz.accept(@group_values.uniq.reject{|g| g.blank?})
76
+ @order_values = attribute_viz.accept(@order_values.uniq.reject{|o| o.blank?})
77
+ @select_values = attribute_viz.accept(@select_values.uniq)
78
+
79
+ self
80
+ end
81
+
73
82
  def build_arel
74
83
  arel = table.from table
75
84
 
@@ -263,7 +272,7 @@ module Squeel
263
272
  end
264
273
 
265
274
  def collapse_wheres(arel, wheres)
266
- wheres = [wheres] unless Array === wheres
275
+ wheres = Array(wheres)
267
276
  binaries = wheres.grep(Arel::Nodes::Binary)
268
277
 
269
278
  groups = binaries.group_by {|b| [b.class, b.left]}
@@ -21,9 +21,9 @@ module Squeel
21
21
 
22
22
  # Comparison with other nodes
23
23
  def eql?(other)
24
- self.class == other.class &&
25
- self.left == other.left &&
26
- self.right == other.right
24
+ self.class.eql?(other.class) &&
25
+ self.left.eql?(other.left) &&
26
+ self.right.eql?(other.right)
27
27
  end
28
28
  alias :== :eql?
29
29
 
@@ -52,10 +52,10 @@ module Squeel
52
52
 
53
53
  # Compare with other objects
54
54
  def eql?(other)
55
- self.class == other.class &&
56
- self._name == other._name &&
57
- self._type == other._type &&
58
- self._klass == other._klass
55
+ self.class.eql?(other.class) &&
56
+ self._name.eql?(other._name) &&
57
+ self._type.eql?(other._type) &&
58
+ self._klass.eql?(other._klass)
59
59
  end
60
60
  alias :== :eql?
61
61
 
@@ -42,10 +42,10 @@ module Squeel
42
42
 
43
43
  # Object comparison
44
44
  def eql?(other)
45
- self.class == other.class &&
46
- self.path == other.path &&
45
+ self.class.eql?(other.class) &&
46
+ self.path.eql?(other.path) &&
47
47
  self.endpoint.eql?(other.endpoint) &&
48
- self.absolute? == other.absolute?
48
+ self.absolute?.eql?(other.absolute?)
49
49
  end
50
50
 
51
51
  # Allow KeyPath to function like its endpoint, in the case where its endpoint
@@ -161,6 +161,7 @@ module Squeel
161
161
  # @return [KeyPath] The updated KeyPath
162
162
  def method_missing(method_id, *args)
163
163
  super if method_id == :to_ary
164
+
164
165
  if endpoint.respond_to? method_id
165
166
  @endpoint = @endpoint.send(method_id, *args)
166
167
  self
@@ -42,8 +42,8 @@ module Squeel
42
42
 
43
43
  # Object comparison
44
44
  def eql?(other)
45
- self.class == other.class &&
46
- self.expr == other.expr
45
+ self.class.eql?(other.class) &&
46
+ self.expr.eql?(other.expr)
47
47
  end
48
48
 
49
49
  # To support object equality tests
@@ -33,10 +33,15 @@ module Squeel
33
33
  self
34
34
  end
35
35
 
36
+ # Implemented for equality testing
37
+ def hash
38
+ [self.class].concat(self.children).hash
39
+ end
40
+
36
41
  # Object comparison
37
42
  def eql?(other)
38
- self.class == other.class &&
39
- self.children == other.children
43
+ self.class.eql?(other.class) &&
44
+ self.children.eql?(other.children)
40
45
  end
41
46
  alias :== :eql?
42
47
 
@@ -37,8 +37,8 @@ module Squeel
37
37
 
38
38
  # Object comparison
39
39
  def eql?(other)
40
- self.class == other.class &&
41
- self.symbol == other.symbol
40
+ self.class.eql?(other.class) &&
41
+ self.symbol.eql?(other.symbol)
42
42
  end
43
43
 
44
44
  # To support object equality tests
@@ -18,8 +18,8 @@ module Squeel
18
18
 
19
19
  # Object comparison
20
20
  def eql?(other)
21
- self.class == other.class &&
22
- self.expr == other.expr
21
+ self.class.eql?(other.class) &&
22
+ self.expr.eql?(other.expr)
23
23
  end
24
24
  alias :== :eql?
25
25
 
@@ -1,3 +1,3 @@
1
1
  module Squeel
2
- VERSION = "0.8.6"
2
+ VERSION = "0.8.7"
3
3
  end
@@ -189,6 +189,15 @@ module Squeel
189
189
  arel.to_sql.should match /ORDER BY "parents_people_2"."id" ASC/
190
190
  end
191
191
 
192
+ it 'does not inadvertently convert KeyPaths to booleans when uniqing where_values' do
193
+ 100.times do # Doesn't happen reliably because of #hash behavior
194
+ persons = Person.joins{[outgoing_messages.outer, incoming_messages.outer]}
195
+ persons = persons.where { (outgoing_messages.author_id.not_eq 7) & (incoming_messages.author_id.not_eq 7) }
196
+ persons = persons.where{(outgoing_messages.recipient_id.not_eq 7) & (incoming_messages.recipient_id.not_eq 7)}
197
+ expect { persons.to_sql }.not_to raise_error TypeError
198
+ end
199
+ end
200
+
192
201
  end
193
202
 
194
203
  describe '#to_sql' do
@@ -616,7 +625,7 @@ module Squeel
616
625
  end
617
626
 
618
627
  it 'merges relations with a different base' do
619
- relation = Person.where{name == 'bob'}.joins(:articles).merge(Article.where{title == 'Hello world!'}, :articles)
628
+ relation = Person.where{name == 'bob'}.joins(:articles).merge(Article.where{title == 'Hello world!'})
620
629
  sql = relation.to_sql
621
630
  sql.should match /INNER JOIN "articles" ON "articles"."person_id" = "people"."id"/
622
631
  sql.should match /"people"."name" = 'bob'/
@@ -369,4 +369,4 @@ module Squeel
369
369
 
370
370
  end
371
371
  end
372
- end
372
+ end
@@ -16,6 +16,15 @@ class Person < ActiveRecord::Base
16
16
  :source => :comments
17
17
  has_many :notes, :as => :notable
18
18
  has_many :unidentified_objects
19
+
20
+ has_many :outgoing_messages, :class_name => 'Message', :foreign_key => :author_id
21
+ has_many :incoming_messages, :class_name => 'Message', :foreign_key => :recipient_id
22
+
23
+ end
24
+
25
+ class Message < ActiveRecord::Base
26
+ belongs_to :author, :class_name => 'Person'
27
+ belongs_to :recipient, :class_name => 'Person'
19
28
  end
20
29
 
21
30
  class UnidentifiedObject < ActiveRecord::Base
@@ -55,6 +64,11 @@ module Schema
55
64
  t.integer :salary
56
65
  end
57
66
 
67
+ create_table :messages, :force => true do |t|
68
+ t.integer :author_id
69
+ t.integer :recipient_id
70
+ end
71
+
58
72
  create_table :unidentified_objects, :id => false, :force => true do |t|
59
73
  t.integer :person_id
60
74
  t.string :name
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: squeel
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.6
4
+ version: 0.8.7
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,12 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-08-01 00:00:00.000000000 -04:00
13
- default_executable:
12
+ date: 2011-08-08 00:00:00.000000000Z
14
13
  dependencies:
15
14
  - !ruby/object:Gem::Dependency
16
15
  name: activerecord
17
- requirement: &70148779727860 !ruby/object:Gem::Requirement
16
+ requirement: &70170737358180 !ruby/object:Gem::Requirement
18
17
  none: false
19
18
  requirements:
20
19
  - - ~>
@@ -22,10 +21,10 @@ dependencies:
22
21
  version: '3.0'
23
22
  type: :runtime
24
23
  prerelease: false
25
- version_requirements: *70148779727860
24
+ version_requirements: *70170737358180
26
25
  - !ruby/object:Gem::Dependency
27
26
  name: activesupport
28
- requirement: &70148779727360 !ruby/object:Gem::Requirement
27
+ requirement: &70170737357560 !ruby/object:Gem::Requirement
29
28
  none: false
30
29
  requirements:
31
30
  - - ~>
@@ -33,10 +32,10 @@ dependencies:
33
32
  version: '3.0'
34
33
  type: :runtime
35
34
  prerelease: false
36
- version_requirements: *70148779727360
35
+ version_requirements: *70170737357560
37
36
  - !ruby/object:Gem::Dependency
38
37
  name: rspec
39
- requirement: &70148779726900 !ruby/object:Gem::Requirement
38
+ requirement: &70170737356940 !ruby/object:Gem::Requirement
40
39
  none: false
41
40
  requirements:
42
41
  - - ~>
@@ -44,10 +43,10 @@ dependencies:
44
43
  version: 2.6.0
45
44
  type: :development
46
45
  prerelease: false
47
- version_requirements: *70148779726900
46
+ version_requirements: *70170737356940
48
47
  - !ruby/object:Gem::Dependency
49
48
  name: machinist
50
- requirement: &70148779726440 !ruby/object:Gem::Requirement
49
+ requirement: &70170737356480 !ruby/object:Gem::Requirement
51
50
  none: false
52
51
  requirements:
53
52
  - - ~>
@@ -55,10 +54,10 @@ dependencies:
55
54
  version: 1.0.6
56
55
  type: :development
57
56
  prerelease: false
58
- version_requirements: *70148779726440
57
+ version_requirements: *70170737356480
59
58
  - !ruby/object:Gem::Dependency
60
59
  name: faker
61
- requirement: &70148779725980 !ruby/object:Gem::Requirement
60
+ requirement: &70170737356000 !ruby/object:Gem::Requirement
62
61
  none: false
63
62
  requirements:
64
63
  - - ~>
@@ -66,10 +65,10 @@ dependencies:
66
65
  version: 0.9.5
67
66
  type: :development
68
67
  prerelease: false
69
- version_requirements: *70148779725980
68
+ version_requirements: *70170737356000
70
69
  - !ruby/object:Gem::Dependency
71
70
  name: sqlite3
72
- requirement: &70148779725520 !ruby/object:Gem::Requirement
71
+ requirement: &70170737355320 !ruby/object:Gem::Requirement
73
72
  none: false
74
73
  requirements:
75
74
  - - ~>
@@ -77,7 +76,7 @@ dependencies:
77
76
  version: 1.3.3
78
77
  type: :development
79
78
  prerelease: false
80
- version_requirements: *70148779725520
79
+ version_requirements: *70170737355320
81
80
  description: ! "\n Squeel unlocks the power of ARel in your Rails 3 application
82
81
  with\n a handy block-based syntax. You can write subqueries, access named\n
83
82
  \ functions provided by your RDBMS, and more, all without writing\n SQL
@@ -170,7 +169,6 @@ files:
170
169
  - spec/squeel/visitors/symbol_visitor_spec.rb
171
170
  - spec/support/schema.rb
172
171
  - squeel.gemspec
173
- has_rdoc: true
174
172
  homepage: http://metautonomo.us/projects/squeel
175
173
  licenses: []
176
174
  post_install_message: ! '
@@ -204,7 +202,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
204
202
  version: '0'
205
203
  requirements: []
206
204
  rubyforge_project: squeel
207
- rubygems_version: 1.6.2
205
+ rubygems_version: 1.8.6
208
206
  signing_key:
209
207
  specification_version: 3
210
208
  summary: ActiveRecord 3, improved.