squeel 0.7.0 → 0.7.1

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.
@@ -49,7 +49,7 @@ module Squeel
49
49
  private
50
50
 
51
51
  def get_table(object)
52
- if [Symbol, Nodes::Stub].include?(object.class)
52
+ if [Symbol, String, Nodes::Stub].include?(object.class)
53
53
  Arel::Table.new(object.to_sym, :engine => @engine)
54
54
  elsif Nodes::Join === object
55
55
  object._klass ? object._klass.arel_table : Arel::Table.new(object._name, :engine => @engine)
@@ -49,7 +49,7 @@ module Squeel
49
49
  private
50
50
 
51
51
  def get_table(object)
52
- if [Symbol, Nodes::Stub].include?(object.class)
52
+ if [Symbol, String, Nodes::Stub].include?(object.class)
53
53
  Arel::Table.new(object.to_sym, :engine => @engine)
54
54
  elsif Nodes::Join === object
55
55
  object._klass ? object._klass.arel_table : Arel::Table.new(object._name, :engine => @engine)
@@ -1,3 +1,3 @@
1
1
  module Squeel
2
- VERSION = "0.7.0"
2
+ VERSION = "0.7.1"
3
3
  end
@@ -24,47 +24,6 @@ module Squeel
24
24
  end.flatten
25
25
  end
26
26
 
27
- # @return [Boolean] Whether the given value implies a context change
28
- # @param v The value to consider
29
- def implies_context_change?(v)
30
- can_accept?(v)
31
- end
32
-
33
- # Change context (by setting the new parent to the result of a #find or
34
- # #traverse on the key), then accept the given value.
35
- #
36
- # @param k The hash key
37
- # @param v The hash value
38
- # @param parent The current parent object in the context
39
- # @return The visited value
40
- def visit_with_context_change(k, v, parent)
41
- parent = case k
42
- when Nodes::KeyPath
43
- traverse(k, parent, true)
44
- else
45
- find(k, parent)
46
- end
47
-
48
- if Array === v
49
- v.map {|val| accept(val, parent || k)}
50
- else
51
- can_accept?(v) ? accept(v, parent || k) : v
52
- end
53
- end
54
-
55
- # If there is no context change, we'll just return the value unchanged,
56
- # currently. Is this really the right behavior? I don't think so, but
57
- # it works in this case.
58
- #
59
- # @param k The hash key
60
- # @param v The hash value
61
- # @param parent The current parent object in the context
62
- # @return The same value we just received. Yeah, this method's pretty pointless,
63
- # for now, and only here for consistency's sake.
64
- def visit_without_context_change(k, v, parent)
65
- v
66
- end
67
-
68
27
  # Visit elements of an array that it's possible to visit -- leave other
69
28
  # elements untouched.
70
29
  #
@@ -177,6 +136,47 @@ module Squeel
177
136
  o.alias ? op.as(o.alias) : op
178
137
  end
179
138
 
139
+ # @return [Boolean] Whether the given value implies a context change
140
+ # @param v The value to consider
141
+ def implies_context_change?(v)
142
+ can_accept?(v)
143
+ end
144
+
145
+ # Change context (by setting the new parent to the result of a #find or
146
+ # #traverse on the key), then accept the given value.
147
+ #
148
+ # @param k The hash key
149
+ # @param v The hash value
150
+ # @param parent The current parent object in the context
151
+ # @return The visited value
152
+ def visit_with_context_change(k, v, parent)
153
+ parent = case k
154
+ when Nodes::KeyPath
155
+ traverse(k, parent, true)
156
+ else
157
+ find(k, parent)
158
+ end
159
+
160
+ if Array === v
161
+ v.map {|val| accept(val, parent || k)}
162
+ else
163
+ can_accept?(v) ? accept(v, parent || k) : v
164
+ end
165
+ end
166
+
167
+ # If there is no context change, we'll just return the value unchanged,
168
+ # currently. Is this really the right behavior? I don't think so, but
169
+ # it works in this case.
170
+ #
171
+ # @param k The hash key
172
+ # @param v The hash value
173
+ # @param parent The current parent object in the context
174
+ # @return The same value we just received. Yeah, this method's pretty pointless,
175
+ # for now, and only here for consistency's sake.
176
+ def visit_without_context_change(k, v, parent)
177
+ v
178
+ end
179
+
180
180
  end
181
181
  end
182
182
  end
@@ -6,6 +6,12 @@ module Squeel
6
6
 
7
7
  private
8
8
 
9
+ # Visit a Hash. This entails iterating through each key and value and
10
+ # visiting each value in turn.
11
+ #
12
+ # @param [Hash] o The Hash to visit
13
+ # @param parent The current parent object in the context
14
+ # @return [Array] An array of values for use in a where or having clause
9
15
  def visit_Hash(o, parent)
10
16
  predicates = o.map do |k, v|
11
17
  if implies_context_change?(v)
@@ -24,24 +30,53 @@ module Squeel
24
30
  end
25
31
  end
26
32
 
33
+ # Visit an array, which involves accepting any values we know how to
34
+ # accept, and skipping the rest.
35
+ #
36
+ # @param [Array] o The Array to visit
37
+ # @param parent The current parent object in the context
38
+ # @return [Array] The visited array
27
39
  def visit_Array(o, parent)
28
40
  o.map { |v| can_accept?(v) ? accept(v, parent) : v }.flatten
29
41
  end
30
42
 
43
+ # Visit ActiveRecord::Base objects. These should be converted to their
44
+ # id before being used in a comparison.
45
+ #
46
+ # @param [ActiveRecord::Base] o The AR::Base object to visit
47
+ # @param parent The current parent object in the context
48
+ # @return [Fixnum] The id of the object
31
49
  def visit_ActiveRecord_Base(o, parent)
32
50
  o.id
33
51
  end
34
52
 
53
+ # Visit a KeyPath by traversing the path and then visiting the endpoint.
54
+ #
55
+ # @param [Nodes::KeyPath] o The KeyPath to visit
56
+ # @param parent The parent object in the context
57
+ # @return The visited endpoint, in the context of the KeyPath's path
35
58
  def visit_Squeel_Nodes_KeyPath(o, parent)
36
59
  parent = traverse(o, parent)
37
60
 
38
61
  accept(o.endpoint, parent)
39
62
  end
40
63
 
64
+ # Visit a Stub by converting it to an ARel attribute
65
+ #
66
+ # @param [Nodes::Stub] o The Stub to visit
67
+ # @param parent The parent object in the context
68
+ # @return [Arel::Attribute] An attribute of the parent table with the
69
+ # Stub's column
41
70
  def visit_Squeel_Nodes_Stub(o, parent)
42
71
  contextualize(parent)[o.symbol]
43
72
  end
44
73
 
74
+ # Visit a Squeel predicate, converting it into an ARel predicate
75
+ #
76
+ # @param [Nodes::Predicate] o The predicate to visit
77
+ # @param parent The parent object in the context
78
+ # @return An ARel predicate node
79
+ # (Arel::Nodes::Equality, Arel::Nodes::Matches, etc)
45
80
  def visit_Squeel_Nodes_Predicate(o, parent)
46
81
  value = o.value
47
82
  if Nodes::KeyPath === value
@@ -60,6 +95,12 @@ module Squeel
60
95
  end
61
96
  end
62
97
 
98
+ # Visit a Squeel function, returning an ARel NamedFunction node.
99
+ #
100
+ # @param [Nodes::Function] o The function node to visit
101
+ # @param parent The parent object in the context
102
+ # @return [Arel::Nodes::NamedFunction] A named function node. Function
103
+ # arguments are visited, if necessary, before being passed to the NamedFunction.
63
104
  def visit_Squeel_Nodes_Function(o, parent)
64
105
  args = o.args.map do |arg|
65
106
  case arg
@@ -76,10 +117,22 @@ module Squeel
76
117
  Arel::Nodes::NamedFunction.new(o.name, args, o.alias)
77
118
  end
78
119
 
120
+ # Visit an ActiveRecord Relation, returning an Arel::SelectManager
121
+ # @param [ActiveRecord::Relation] o The Relation to visit
122
+ # @param parent The parent object in the context
123
+ # @return [Arel::SelectManager] The ARel select manager that represents
124
+ # the relation's query
79
125
  def visit_ActiveRecord_Relation(o, parent)
80
126
  o.arel
81
127
  end
82
128
 
129
+ # Visit a Squeel operation node, convering it to an ARel InfixOperation
130
+ # (or subclass, as appropriate)
131
+ #
132
+ # @param [Nodes::Operation] o The Operation node to visit
133
+ # @param parent The parent object in the context
134
+ # @return [Arel::Nodes::InfixOperation] The InfixOperation (or Addition,
135
+ # Multiplication, etc) node, with both operands visited, if needed.
83
136
  def visit_Squeel_Nodes_Operation(o, parent)
84
137
  args = o.args.map do |arg|
85
138
  case arg
@@ -109,10 +162,23 @@ module Squeel
109
162
  o.alias ? op.as(o.alias) : op
110
163
  end
111
164
 
165
+ # Visit a Squeel And node, returning an ARel Grouping containing an
166
+ # ARel And node.
167
+ #
168
+ # @param [Nodes::And] The And node to visit
169
+ # @param parent The parent object in the context
170
+ # @return [Arel::Nodes::Grouping] A grouping node, containnig an ARel
171
+ # And node as its expression. All children will be visited before
172
+ # being passed to the And.
112
173
  def visit_Squeel_Nodes_And(o, parent)
113
174
  Arel::Nodes::Grouping.new(Arel::Nodes::And.new(accept(o.children, parent)))
114
175
  end
115
176
 
177
+ # Visit a Squeel Or node, returning an ARel Or node.
178
+ #
179
+ # @param [Nodes::Or] The Or node to visit
180
+ # @param parent The parent object in the context
181
+ # @return [Arel::Nodes::Or] An ARel Or node, with left and ride sides visited
116
182
  def visit_Squeel_Nodes_Or(o, parent)
117
183
  accept(o.left, parent).or(accept(o.right, parent))
118
184
  end
@@ -121,6 +187,8 @@ module Squeel
121
187
  accept(o.expr, parent).not
122
188
  end
123
189
 
190
+ # @return [Boolean] Whether the given value implies a context change
191
+ # @param v The value to consider
124
192
  def implies_context_change?(v)
125
193
  case v
126
194
  when Hash, Nodes::Predicate, Nodes::Unary, Nodes::Binary, Nodes::Nary
@@ -132,6 +200,13 @@ module Squeel
132
200
  end
133
201
  end
134
202
 
203
+ # Change context (by setting the new parent to the result of a #find or
204
+ # #traverse on the key), then accept the given value.
205
+ #
206
+ # @param k The hash key
207
+ # @param v The hash value
208
+ # @param parent The current parent object in the context
209
+ # @return The visited value
135
210
  def visit_with_context_change(k, v, parent)
136
211
  parent = case k
137
212
  when Nodes::KeyPath
@@ -154,6 +229,14 @@ module Squeel
154
229
  end
155
230
  end
156
231
 
232
+ # Create a predicate for a given key/value pair. If the value is
233
+ # a Symbol, Stub, or KeyPath, it's converted to a table.column for
234
+ # the predicate value.
235
+ #
236
+ # @param k The hash key
237
+ # @param v The hash value
238
+ # @param parent The current parent object in the context
239
+ # @return An ARel predicate
157
240
  def visit_without_context_change(k, v, parent)
158
241
  case v
159
242
  when Nodes::Stub, Symbol
@@ -175,6 +258,13 @@ module Squeel
175
258
  end
176
259
  end
177
260
 
261
+ # Determine whether to use IN or equality testing for a predicate,
262
+ # based on its value class, then return the appropriate predicate.
263
+ #
264
+ # @param attribute The ARel attribute (or function/operation) the
265
+ # predicate will be created for
266
+ # @param value The value to be compared against
267
+ # @return [Arel::Nodes::Node] An ARel predicate node
178
268
  def arel_predicate_for(attribute, value, parent)
179
269
  value = can_accept?(value) ? accept(value, parent) : value
180
270
  if [Array, Range, Arel::SelectManager].include?(value.class)
@@ -184,6 +274,14 @@ module Squeel
184
274
  end
185
275
  end
186
276
 
277
+ # Function nodes require us to do the quoting before the ARel
278
+ # visitor gets a chance to try, because we want to avoid having our
279
+ # values quoted as a type of the last visited column. Otherwise, we
280
+ # can end up with annoyances like having "joe" quoted to 0, if the
281
+ # last visited column was of an integer type.
282
+ #
283
+ # @param node The node we (might) be quoting for
284
+ # @param v The value to (possibly) quote
187
285
  def quote_for_node(node, v)
188
286
  case node
189
287
  when Nodes::Function
@@ -37,6 +37,7 @@ module Squeel
37
37
  table.name.should eq 'notes'
38
38
  table.table_alias.should be_nil
39
39
  end
40
+
40
41
  end
41
42
  end
42
43
  end
@@ -589,6 +589,12 @@ module Squeel
589
589
  sql.should match /"articles"."title" = 'Hello world!'/
590
590
  end
591
591
 
592
+ it 'does not break hm:t with conditions' do
593
+ relation = Person.first.condition_article_comments
594
+ sql = relation.to_sql
595
+ sql.should match /"articles"."title" = 'Condition'/
596
+ end
597
+
592
598
  end
593
599
 
594
600
  describe '#to_a' do
@@ -9,7 +9,9 @@ class Person < ActiveRecord::Base
9
9
  belongs_to :parent, :class_name => 'Person', :foreign_key => :parent_id
10
10
  has_many :children, :class_name => 'Person', :foreign_key => :parent_id
11
11
  has_many :articles
12
+ has_many :articles_with_condition, :class_name => 'Article', :conditions => {:title => 'Condition'}
12
13
  has_many :comments
14
+ has_many :condition_article_comments, :through => :articles_with_condition, :source => :comments
13
15
  has_many :authored_article_comments, :through => :articles,
14
16
  :source => :comments
15
17
  has_many :notes, :as => :notable
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: squeel
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.7.0
5
+ version: 0.7.1
6
6
  platform: ruby
7
7
  authors:
8
8
  - Ernie Miller
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-05-13 00:00:00 Z
13
+ date: 2011-05-16 00:00:00 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activerecord