squeel 1.0.15 → 1.0.16

Sign up to get free protection for your applications and to get access to all the features.
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