squeel 1.0.15 → 1.0.16

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/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ ## 1.0.16 (2013-02-12)
2
+
3
+ * Port workaround for MySQL's "helpful" casting behavior from Rails 3.2.12
4
+
1
5
  ## 1.0.15 (2013-01-23)
2
6
 
3
7
  * Fix issue #214, don't alter table name when mergine a relation with a default
@@ -142,6 +142,8 @@ module Arel
142
142
  table = attr.relation.table_name
143
143
 
144
144
  column_cache[table][name]
145
+ rescue ActiveRecord::StatementInvalid # non-existent tables
146
+ nil
145
147
  end
146
148
 
147
149
  def column_cache
@@ -1,3 +1,3 @@
1
1
  module Squeel
2
- VERSION = "1.0.15"
2
+ VERSION = "1.0.16"
3
3
  end
@@ -40,7 +40,7 @@ module Squeel
40
40
  value = visit(value, parent) if can_visit?(value)
41
41
  end
42
42
 
43
- value = quote_for_node(o.expr, value)
43
+ value = quote_for_node(value, o.expr, parent)
44
44
 
45
45
  attribute = case o.expr
46
46
  when Nodes::Stub, Nodes::Function, Nodes::Literal, Nodes::Grouping
@@ -68,6 +68,7 @@ module Squeel
68
68
  value = visit(value.select(value.klass.arel_table[value.klass.primary_key]), parent)
69
69
  else
70
70
  value = can_visit?(value) ? visit(value, parent) : value
71
+ value = quote_for_attribute(value, attribute)
71
72
  end
72
73
 
73
74
  case value
@@ -108,14 +109,48 @@ module Squeel
108
109
  # can end up with annoyances like having "joe" quoted to 0, if the
109
110
  # last visited column was of an integer type.
110
111
  #
111
- # @param node The node we (might) be quoting for
112
112
  # @param v The value to (possibly) quote
113
- def quote_for_node(node, v)
113
+ # @param node The node we (might) be quoting for
114
+ # @param parent The parent of the node being quoted for
115
+ def quote_for_node(v, node, parent)
114
116
  case node
115
117
  when Nodes::Function, Nodes::Literal
116
118
  quote(v)
117
119
  when Nodes::Predicate
118
- quote_for_node(node.expr, v)
120
+ quote_for_node(v, node.expr, parent)
121
+ when Symbol, Nodes::Stub # MySQL hates freedom
122
+ quote_for_attribute v, visit(node, parent)
123
+ else
124
+ v
125
+ end
126
+ end
127
+
128
+ # Because MySQL hates doing sane things, we are forced to try to quote
129
+ # certain values for a specific column type. Otherwise, MySQL might
130
+ # "helpfully" cast the column we're checking to the type we're comparing
131
+ # it to, resulting in such wonderful queries as...
132
+ #
133
+ # SELECT * FROM table WHERE str_column = 0
134
+ #
135
+ # ...returning every record in the table that doesn't have a number in
136
+ # str_column.
137
+ #
138
+ # Everything about this method is awful. 2 x private method calls to ARel,
139
+ # wrapping a pre-quoted value in an SqlLiteral... Everything. My only
140
+ # solace is that I think we can fix it in ARel in the longer term.
141
+ def quote_for_attribute(v, attr)
142
+ case v
143
+ when Array
144
+ v.map { |v| quote_for_attribute(v, attr) }
145
+ when Range
146
+ Range.new(
147
+ quote_for_attribute(v.begin, attr),
148
+ quote_for_attribute(v.end, attr),
149
+ v.exclude_end?
150
+ )
151
+ when Bignum, Fixnum, Integer, ActiveSupport::Duration
152
+ column = arel_visitor.send(:column_for, attr)
153
+ Arel::Nodes::SqlLiteral.new arel_visitor.send(:quote, v, column)
119
154
  else
120
155
  v
121
156
  end
@@ -56,11 +56,11 @@ module Squeel
56
56
 
57
57
  case k
58
58
  when Nodes::Predicate
59
- visit(k % quote_for_node(k.expr, v), parent)
59
+ visit(k % quote_for_node(v, k.expr, parent), parent)
60
60
  when Nodes::Function, Nodes::Literal
61
61
  arel_predicate_for(visit(k, parent), quote(v), parent)
62
62
  when Nodes::KeyPath
63
- visit(k % quote_for_node(k.endpoint, v), parent)
63
+ visit(k % quote_for_node(v, k.endpoint, parent), parent)
64
64
  else
65
65
  attr_name = k.to_s
66
66
  attribute = if !hash_context_shifted? && attr_name.include?('.')
@@ -23,6 +23,44 @@ module Squeel
23
23
  node.right.should be_a Arel::Nodes::SelectStatement
24
24
  end
25
25
 
26
+ it 'quotes the value of a predicate based on its key' do
27
+ predicate = Nodes::Predicate.new(Nodes::Stub.new(:id), :eq, 1)
28
+ node = @v.accept(predicate)
29
+ node.to_sql.should be_like '"people"."id" = 1'
30
+ predicate = Nodes::Predicate.new(Nodes::Stub.new(:name), :eq, 1)
31
+ node = @v.accept(predicate)
32
+ node.to_sql.should be_like '"people"."name" = \'1\''
33
+ end
34
+
35
+ it 'quotes the value of a hash based on its key' do
36
+ node = @v.accept(:id => 1)
37
+ node.to_sql.should be_like '"people"."id" = 1'
38
+ node = @v.accept(:name => 1)
39
+ node.to_sql.should be_like '"people"."name" = \'1\''
40
+ end
41
+
42
+ it 'quotes array values for a Predicate based on its key' do
43
+ predicate = Nodes::Predicate.new(Nodes::Stub.new(:name), :in, [1, 2])
44
+ node = @v.accept(predicate)
45
+ node.to_sql.should be_like '"people"."name" IN (\'1\', \'2\')'
46
+ end
47
+
48
+ it 'quotes array values for a hash based on their key' do
49
+ node = @v.accept(:name => [1, 2])
50
+ node.to_sql.should be_like '"people"."name" IN (\'1\', \'2\')'
51
+ end
52
+
53
+ it 'quotes range values for a predicate based on its key' do
54
+ predicate = Nodes::Predicate.new(Nodes::Stub.new(:name), :in, 1..2)
55
+ node = @v.accept(predicate)
56
+ node.to_sql.should be_like '"people"."name" BETWEEN \'1\' AND \'2\''
57
+ end
58
+
59
+ it 'quotes range values for a hash based on its key' do
60
+ node = @v.accept(:name => 1..2)
61
+ node.to_sql.should be_like '"people"."name" BETWEEN \'1\' AND \'2\''
62
+ end
63
+
26
64
  it 'creates Equality nodes for simple hashes' do
27
65
  predicate = @v.accept(:name => 'Joe')
28
66
  predicate.should be_a Arel::Nodes::Equality
@@ -150,15 +188,13 @@ module Squeel
150
188
  it 'converts ActiveRecord::Base objects to their id' do
151
189
  predicate = @v.accept(:id => Person.first)
152
190
  predicate.should be_a Arel::Nodes::Equality
153
- predicate.left.name.to_s.should eq 'id'
154
- predicate.right.should eq 1
191
+ predicate.to_sql.should be_like '"people"."id" = 1'
155
192
  end
156
193
 
157
194
  it 'converts arrays of ActiveRecord::Base objects to their ids' do
158
195
  predicate = @v.accept(:id => [Person.first, Person.last])
159
196
  predicate.should be_a Arel::Nodes::In
160
- predicate.left.name.to_s.should eq 'id'
161
- predicate.right.should eq [1, 332]
197
+ predicate.to_sql.should be_like '"people"."id" IN (1, 332)'
162
198
  end
163
199
 
164
200
  it 'creates the node against the proper table for nested hashes' do
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: 1.0.15
4
+ version: 1.0.16
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: 2013-01-23 00:00:00.000000000 Z
12
+ date: 2013-02-12 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activerecord
@@ -255,7 +255,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
255
255
  version: '0'
256
256
  segments:
257
257
  - 0
258
- hash: 3781393016892573538
258
+ hash: -3974244035788001518
259
259
  required_rubygems_version: !ruby/object:Gem::Requirement
260
260
  none: false
261
261
  requirements:
@@ -264,7 +264,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
264
264
  version: '0'
265
265
  segments:
266
266
  - 0
267
- hash: 3781393016892573538
267
+ hash: -3974244035788001518
268
268
  requirements: []
269
269
  rubyforge_project: squeel
270
270
  rubygems_version: 1.8.24