sequel_core 1.5.1 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +116 -0
- data/COPYING +19 -19
- data/README +83 -32
- data/Rakefile +9 -20
- data/bin/sequel +43 -112
- data/doc/cheat_sheet.rdoc +225 -0
- data/doc/dataset_filtering.rdoc +257 -0
- data/lib/sequel_core/adapters/adapter_skeleton.rb +4 -2
- data/lib/sequel_core/adapters/ado.rb +3 -1
- data/lib/sequel_core/adapters/db2.rb +4 -2
- data/lib/sequel_core/adapters/dbi.rb +127 -113
- data/lib/sequel_core/adapters/informix.rb +4 -2
- data/lib/sequel_core/adapters/jdbc.rb +5 -3
- data/lib/sequel_core/adapters/mysql.rb +112 -46
- data/lib/sequel_core/adapters/odbc.rb +5 -7
- data/lib/sequel_core/adapters/odbc_mssql.rb +12 -3
- data/lib/sequel_core/adapters/openbase.rb +3 -1
- data/lib/sequel_core/adapters/oracle.rb +11 -9
- data/lib/sequel_core/adapters/postgres.rb +261 -262
- data/lib/sequel_core/adapters/sqlite.rb +72 -22
- data/lib/sequel_core/connection_pool.rb +140 -73
- data/lib/sequel_core/core_ext.rb +201 -66
- data/lib/sequel_core/core_sql.rb +123 -153
- data/lib/sequel_core/database/schema.rb +156 -0
- data/lib/sequel_core/database.rb +321 -338
- data/lib/sequel_core/dataset/callback.rb +11 -12
- data/lib/sequel_core/dataset/convenience.rb +213 -240
- data/lib/sequel_core/dataset/pagination.rb +58 -43
- data/lib/sequel_core/dataset/parse_tree_sequelizer.rb +331 -0
- data/lib/sequel_core/dataset/query.rb +41 -0
- data/lib/sequel_core/dataset/schema.rb +15 -0
- data/lib/sequel_core/dataset/sequelizer.rb +41 -373
- data/lib/sequel_core/dataset/sql.rb +741 -632
- data/lib/sequel_core/dataset.rb +183 -168
- data/lib/sequel_core/deprecated.rb +1 -169
- data/lib/sequel_core/exceptions.rb +24 -19
- data/lib/sequel_core/migration.rb +44 -52
- data/lib/sequel_core/object_graph.rb +43 -42
- data/lib/sequel_core/pretty_table.rb +71 -76
- data/lib/sequel_core/schema/generator.rb +163 -105
- data/lib/sequel_core/schema/sql.rb +250 -93
- data/lib/sequel_core/schema.rb +2 -8
- data/lib/sequel_core/sql.rb +394 -0
- data/lib/sequel_core/worker.rb +37 -27
- data/lib/sequel_core.rb +99 -45
- data/spec/adapters/informix_spec.rb +0 -1
- data/spec/adapters/mysql_spec.rb +177 -124
- data/spec/adapters/oracle_spec.rb +0 -1
- data/spec/adapters/postgres_spec.rb +98 -58
- data/spec/adapters/sqlite_spec.rb +45 -4
- data/spec/blockless_filters_spec.rb +269 -0
- data/spec/connection_pool_spec.rb +21 -18
- data/spec/core_ext_spec.rb +169 -19
- data/spec/core_sql_spec.rb +56 -49
- data/spec/database_spec.rb +78 -17
- data/spec/dataset_spec.rb +300 -428
- data/spec/migration_spec.rb +1 -1
- data/spec/object_graph_spec.rb +5 -11
- data/spec/rcov.opts +1 -1
- data/spec/schema_generator_spec.rb +16 -4
- data/spec/schema_spec.rb +89 -10
- data/spec/sequelizer_spec.rb +56 -56
- data/spec/spec.opts +0 -5
- data/spec/spec_config.rb +7 -0
- data/spec/spec_config.rb.example +5 -5
- data/spec/spec_helper.rb +6 -0
- data/spec/worker_spec.rb +1 -1
- metadata +78 -63
@@ -0,0 +1,269 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
|
+
|
3
|
+
context "Blockless Ruby Filters" do
|
4
|
+
before do
|
5
|
+
db = Sequel::Database.new
|
6
|
+
db.quote_identifiers = false
|
7
|
+
@d = db[:items]
|
8
|
+
def @d.l(*args)
|
9
|
+
literal(filter_expr(*args))
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should support boolean columns directly" do
|
14
|
+
@d.l(:x).should == 'x'
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should support NOT via Symbol#~" do
|
18
|
+
@d.l(~:x).should == 'NOT x'
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should support qualified columns" do
|
22
|
+
@d.l(:x__y).should == 'x.y'
|
23
|
+
@d.l(~:x__y).should == 'NOT x.y'
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should support NOT with SQL functions" do
|
27
|
+
@d.l(~:is_blah[]).should == 'NOT is_blah()'
|
28
|
+
@d.l(~:is_blah[:x]).should == 'NOT is_blah(x)'
|
29
|
+
@d.l(~:is_blah[:x__y]).should == 'NOT is_blah(x.y)'
|
30
|
+
@d.l(~:is_blah[:x, :x__y]).should == 'NOT is_blah(x, x.y)'
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should handle multiple ~" do
|
34
|
+
@d.l(~~:x).should == 'x'
|
35
|
+
@d.l(~~~:x).should == 'NOT x'
|
36
|
+
@d.l(~~(:x > 100)).should == '(x > 100)'
|
37
|
+
@d.l(~~(:x & :y)).should == '(x AND y)'
|
38
|
+
@d.l(~~(:x | :y)).should == '(x OR y)'
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should support >, <, >=, and <= via Symbol#>,<,>=,<=" do
|
42
|
+
@d.l(:x > 100).should == '(x > 100)'
|
43
|
+
@d.l(:x < 100.01).should == '(x < 100.01)'
|
44
|
+
@d.l(:x >= 100000000000000000000000000000000000).should == '(x >= 100000000000000000000000000000000000)'
|
45
|
+
@d.l(:x <= 100).should == '(x <= 100)'
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should support negation of >, <, >=, and <= via Symbol#~" do
|
49
|
+
@d.l(~(:x > 100)).should == '(x <= 100)'
|
50
|
+
@d.l(~(:x < 100.01)).should == '(x >= 100.01)'
|
51
|
+
@d.l(~(:x >= 100000000000000000000000000000000000)).should == '(x < 100000000000000000000000000000000000)'
|
52
|
+
@d.l(~(:x <= 100)).should == '(x > 100)'
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should support = via Hash" do
|
56
|
+
@d.l(:x => 100).should == '(x = 100)'
|
57
|
+
@d.l(:x => 'a').should == '(x = \'a\')'
|
58
|
+
@d.l(:x => true).should == '(x = \'t\')'
|
59
|
+
@d.l(:x => false).should == '(x = \'f\')'
|
60
|
+
@d.l(:x => nil).should == '(x IS NULL)'
|
61
|
+
@d.l(:x => [1,2,3]).should == '(x IN (1, 2, 3))'
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should support != via Hash#~" do
|
65
|
+
@d.l(~{:x => 100}).should == '(x != 100)'
|
66
|
+
@d.l(~{:x => 'a'}).should == '(x != \'a\')'
|
67
|
+
@d.l(~{:x => true}).should == '(x != \'t\')'
|
68
|
+
@d.l(~{:x => false}).should == '(x != \'f\')'
|
69
|
+
@d.l(~{:x => nil}).should == '(x IS NOT NULL)'
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should support ~ via Hash and Regexp (if supported by database)" do
|
73
|
+
@d.l(:x => /blah/).should == '(x ~ \'blah\')'
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should support !~ via Hash#~ and Regexp" do
|
77
|
+
@d.l(~{:x => /blah/}).should == '(x !~ \'blah\')'
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should support LIKE via Symbol#like" do
|
81
|
+
@d.l(:x.like('a')).should == '(x LIKE \'a\')'
|
82
|
+
@d.l(:x.like(/a/)).should == '(x ~ \'a\')'
|
83
|
+
@d.l(:x.like('a', 'b')).should == '((x LIKE \'a\') OR (x LIKE \'b\'))'
|
84
|
+
@d.l(:x.like(/a/, /b/)).should == '((x ~ \'a\') OR (x ~ \'b\'))'
|
85
|
+
@d.l(:x.like('a', /b/)).should == '((x LIKE \'a\') OR (x ~ \'b\'))'
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should support NOT LIKE via Symbol#like and Symbol#~" do
|
89
|
+
@d.l(~:x.like('a')).should == '(x NOT LIKE \'a\')'
|
90
|
+
@d.l(~:x.like(/a/)).should == '(x !~ \'a\')'
|
91
|
+
@d.l(~:x.like('a', 'b')).should == '((x NOT LIKE \'a\') AND (x NOT LIKE \'b\'))'
|
92
|
+
@d.l(~:x.like(/a/, /b/)).should == '((x !~ \'a\') AND (x !~ \'b\'))'
|
93
|
+
@d.l(~:x.like('a', /b/)).should == '((x NOT LIKE \'a\') AND (x !~ \'b\'))'
|
94
|
+
end
|
95
|
+
|
96
|
+
it "should support negating ranges via Hash#~ and Range" do
|
97
|
+
@d.l(~{:x => 1..5}).should == '((x < 1) OR (x > 5))'
|
98
|
+
@d.l(~{:x => 1...5}).should == '((x < 1) OR (x >= 5))'
|
99
|
+
end
|
100
|
+
|
101
|
+
it "should support negating NOT IN via Hash#~ and Dataset or Array" do
|
102
|
+
@d.l(~{:x => @d.select(:i)}).should == '(x NOT IN (SELECT i FROM items))'
|
103
|
+
@d.l(~{:x => [1,2,3]}).should == '(x NOT IN (1, 2, 3))'
|
104
|
+
end
|
105
|
+
|
106
|
+
it "should support + - * / via Symbol#+,-,*,/" do
|
107
|
+
@d.l(:x + 1 > 100).should == '((x + 1) > 100)'
|
108
|
+
@d.l((:x * :y) < 100.01).should == '((x * y) < 100.01)'
|
109
|
+
@d.l((:x - :y/2) >= 100000000000000000000000000000000000).should == '((x - (y / 2)) >= 100000000000000000000000000000000000)'
|
110
|
+
@d.l((((:x - :y)/(:x + :y))*:z) <= 100).should == '((((x - y) / (x + y)) * z) <= 100)'
|
111
|
+
@d.l(~((((:x - :y)/(:x + :y))*:z) <= 100)).should == '((((x - y) / (x + y)) * z) > 100)'
|
112
|
+
end
|
113
|
+
|
114
|
+
it "should not allow negation of non-boolean expressions" do
|
115
|
+
proc{~(:x + 1 > 100)}.should_not raise_error
|
116
|
+
proc{~(:x + 1)}.should raise_error(Sequel::Error)
|
117
|
+
end
|
118
|
+
|
119
|
+
it "should not allow mathematical, inequality, or string operations on true, false, or nil" do
|
120
|
+
proc{:x + 1}.should_not raise_error
|
121
|
+
proc{:x - true}.should raise_error(Sequel::Error)
|
122
|
+
proc{:x / false}.should raise_error(Sequel::Error)
|
123
|
+
proc{:x * nil}.should raise_error(Sequel::Error)
|
124
|
+
proc{:x > 1}.should_not raise_error
|
125
|
+
proc{:x < true}.should raise_error(Sequel::Error)
|
126
|
+
proc{:x >= false}.should raise_error(Sequel::Error)
|
127
|
+
proc{:x <= nil}.should raise_error(Sequel::Error)
|
128
|
+
proc{[:x, nil].sql_string_join}.should raise_error(Sequel::Error)
|
129
|
+
end
|
130
|
+
|
131
|
+
it "should not allow mathematical, inequality, or string operations on boolean complex expressions" do
|
132
|
+
proc{:x + (:y + 1)}.should_not raise_error
|
133
|
+
proc{:x - (~:y)}.should raise_error(Sequel::Error)
|
134
|
+
proc{:x / (:y & :z)}.should raise_error(Sequel::Error)
|
135
|
+
proc{:x * (:y | :z)}.should raise_error(Sequel::Error)
|
136
|
+
proc{:x > (:y > 5)}.should raise_error(Sequel::Error)
|
137
|
+
proc{:x < (:y < 5)}.should raise_error(Sequel::Error)
|
138
|
+
proc{:x >= (:y >= 5)}.should raise_error(Sequel::Error)
|
139
|
+
proc{:x <= (:y <= 5)}.should raise_error(Sequel::Error)
|
140
|
+
proc{:x > {:y => nil}}.should raise_error(Sequel::Error)
|
141
|
+
proc{:x < ~{:y => nil}}.should raise_error(Sequel::Error)
|
142
|
+
proc{:x >= {:y => 5}}.should raise_error(Sequel::Error)
|
143
|
+
proc{:x <= ~{:y => 5}}.should raise_error(Sequel::Error)
|
144
|
+
proc{:x >= {:y => [1,2,3]}}.should raise_error(Sequel::Error)
|
145
|
+
proc{:x <= ~{:y => [1,2,3]}}.should raise_error(Sequel::Error)
|
146
|
+
proc{:x + :y.like('a')}.should raise_error(Sequel::Error)
|
147
|
+
proc{:x - :y.like(/a/)}.should raise_error(Sequel::Error)
|
148
|
+
proc{:x * :y.like(/a/i)}.should raise_error(Sequel::Error)
|
149
|
+
proc{:x + ~:y.like('a')}.should raise_error(Sequel::Error)
|
150
|
+
proc{:x - ~:y.like(/a/)}.should raise_error(Sequel::Error)
|
151
|
+
proc{:x * ~:y.like(/a/i)}.should raise_error(Sequel::Error)
|
152
|
+
proc{[:x, ~:y.like(/a/i)].sql_string_join}.should raise_error(Sequel::Error)
|
153
|
+
end
|
154
|
+
|
155
|
+
it "should support AND conditions via &" do
|
156
|
+
@d.l(:x & :y).should == '(x AND y)'
|
157
|
+
@d.l(:x & :y & :z).should == '((x AND y) AND z)'
|
158
|
+
@d.l(:x & {:y => :z}).should == '(x AND (y = z))'
|
159
|
+
@d.l({:y => :z} & :x).should == '((y = z) AND x)'
|
160
|
+
@d.l({:x => :a} & {:y => :z}).should == '((x = a) AND (y = z))'
|
161
|
+
@d.l((:x > 200) & (:y < 200)).should == '((x > 200) AND (y < 200))'
|
162
|
+
@d.l(:x & ~:y).should == '(x AND NOT y)'
|
163
|
+
@d.l(~:x & :y).should == '(NOT x AND y)'
|
164
|
+
@d.l(~:x & ~:y).should == '(NOT x AND NOT y)'
|
165
|
+
end
|
166
|
+
|
167
|
+
it "should support OR conditions via |" do
|
168
|
+
@d.l(:x | :y).should == '(x OR y)'
|
169
|
+
@d.l(:x | :y | :z).should == '((x OR y) OR z)'
|
170
|
+
@d.l(:x | {:y => :z}).should == '(x OR (y = z))'
|
171
|
+
@d.l({:y => :z} | :x).should == '((y = z) OR x)'
|
172
|
+
@d.l({:x => :a} | {:y => :z}).should == '((x = a) OR (y = z))'
|
173
|
+
@d.l((:x > 200) | (:y < 200)).should == '((x > 200) OR (y < 200))'
|
174
|
+
end
|
175
|
+
|
176
|
+
it "should support & | combinations" do
|
177
|
+
@d.l((:x | :y) & :z).should == '((x OR y) AND z)'
|
178
|
+
@d.l(:x | (:y & :z)).should == '(x OR (y AND z))'
|
179
|
+
@d.l((:x & :w) | (:y & :z)).should == '((x AND w) OR (y AND z))'
|
180
|
+
end
|
181
|
+
|
182
|
+
it "should support & | with ~" do
|
183
|
+
@d.l(~((:x | :y) & :z)).should == '((NOT x AND NOT y) OR NOT z)'
|
184
|
+
@d.l(~(:x | (:y & :z))).should == '(NOT x AND (NOT y OR NOT z))'
|
185
|
+
@d.l(~((:x & :w) | (:y & :z))).should == '((NOT x OR NOT w) AND (NOT y OR NOT z))'
|
186
|
+
@d.l(~((:x > 200) | (:y & :z))).should == '((x <= 200) AND (NOT y OR NOT z))'
|
187
|
+
end
|
188
|
+
|
189
|
+
it "should support LiteralString" do
|
190
|
+
@d.l('x'.lit).should == '(x)'
|
191
|
+
@d.l(~'x'.lit).should == 'NOT x'
|
192
|
+
@d.l(~~'x'.lit).should == '(x)'
|
193
|
+
@d.l(~(('x'.lit | :y) & :z)).should == '((NOT x AND NOT y) OR NOT z)'
|
194
|
+
@d.l(~(:x | 'y'.lit)).should == '(NOT x AND NOT y)'
|
195
|
+
@d.l(~('x'.lit & 'y'.lit)).should == '(NOT x OR NOT y)'
|
196
|
+
@d.l({'y'.lit => 'z'.lit} & 'x'.lit).should == '((y = z) AND x)'
|
197
|
+
@d.l(('x'.lit > 200) & ('y'.lit < 200)).should == '((x > 200) AND (y < 200))'
|
198
|
+
@d.l(~('x'.lit + 1 > 100)).should == '((x + 1) <= 100)'
|
199
|
+
@d.l('x'.lit.like(/a/)).should == '(x ~ \'a\')'
|
200
|
+
@d.l('x'.lit + 1 > 100).should == '((x + 1) > 100)'
|
201
|
+
@d.l(('x'.lit * :y) < 100.01).should == '((x * y) < 100.01)'
|
202
|
+
@d.l(('x'.lit - :y/2) >= 100000000000000000000000000000000000).should == '((x - (y / 2)) >= 100000000000000000000000000000000000)'
|
203
|
+
@d.l(('z'.lit * (('x'.lit / :y)/(:x + :y))) <= 100).should == '((z * ((x / y) / (x + y))) <= 100)'
|
204
|
+
@d.l(~(((('x'.lit - :y)/(:x + :y))*:z) <= 100)).should == '((((x - y) / (x + y)) * z) > 100)'
|
205
|
+
end
|
206
|
+
|
207
|
+
it "should support hashes by ANDing the conditions" do
|
208
|
+
@d.l(:x => 100, :y => 'a')[1...-1].split(' AND ').sort.should == ['(x = 100)', '(y = \'a\')']
|
209
|
+
@d.l(:x => true, :y => false)[1...-1].split(' AND ').sort.should == ['(x = \'t\')', '(y = \'f\')']
|
210
|
+
@d.l(:x => nil, :y => [1,2,3])[1...-1].split(' AND ').sort.should == ['(x IS NULL)', '(y IN (1, 2, 3))']
|
211
|
+
end
|
212
|
+
|
213
|
+
it "should support sql_negate on hashes" do
|
214
|
+
@d.l({:x => 100, :y => 'a'}.sql_negate)[1...-1].split(' AND ').sort.should == ['(x != 100)', '(y != \'a\')']
|
215
|
+
@d.l({:x => true, :y => false}.sql_negate)[1...-1].split(' AND ').sort.should == ['(x != \'t\')', '(y != \'f\')']
|
216
|
+
@d.l({:x => nil, :y => [1,2,3]}.sql_negate)[1...-1].split(' AND ').sort.should == ['(x IS NOT NULL)', '(y NOT IN (1, 2, 3))']
|
217
|
+
end
|
218
|
+
|
219
|
+
it "should support ~ on hashes" do
|
220
|
+
@d.l(~{:x => 100, :y => 'a'})[1...-1].split(' OR ').sort.should == ['(x != 100)', '(y != \'a\')']
|
221
|
+
@d.l(~{:x => true, :y => false})[1...-1].split(' OR ').sort.should == ['(x != \'t\')', '(y != \'f\')']
|
222
|
+
@d.l(~{:x => nil, :y => [1,2,3]})[1...-1].split(' OR ').sort.should == ['(x IS NOT NULL)', '(y NOT IN (1, 2, 3))']
|
223
|
+
end
|
224
|
+
|
225
|
+
it "should support sql_or on hashes" do
|
226
|
+
@d.l({:x => 100, :y => 'a'}.sql_or)[1...-1].split(' OR ').sort.should == ['(x = 100)', '(y = \'a\')']
|
227
|
+
@d.l({:x => true, :y => false}.sql_or)[1...-1].split(' OR ').sort.should == ['(x = \'t\')', '(y = \'f\')']
|
228
|
+
@d.l({:x => nil, :y => [1,2,3]}.sql_or)[1...-1].split(' OR ').sort.should == ['(x IS NULL)', '(y IN (1, 2, 3))']
|
229
|
+
end
|
230
|
+
|
231
|
+
it "should support arrays with all two pairs the same as hashes" do
|
232
|
+
@d.l([[:x, 100],[:y, 'a']]).should == '((x = 100) AND (y = \'a\'))'
|
233
|
+
@d.l([[:x, true], [:y, false]]).should == '((x = \'t\') AND (y = \'f\'))'
|
234
|
+
@d.l([[:x, nil], [:y, [1,2,3]]]).should == '((x IS NULL) AND (y IN (1, 2, 3)))'
|
235
|
+
end
|
236
|
+
|
237
|
+
it "should support sql_negate on arrays with all two pairs" do
|
238
|
+
@d.l([[:x, 100],[:y, 'a']].sql_negate).should == '((x != 100) AND (y != \'a\'))'
|
239
|
+
@d.l([[:x, true], [:y, false]].sql_negate).should == '((x != \'t\') AND (y != \'f\'))'
|
240
|
+
@d.l([[:x, nil], [:y, [1,2,3]]].sql_negate).should == '((x IS NOT NULL) AND (y NOT IN (1, 2, 3)))'
|
241
|
+
end
|
242
|
+
|
243
|
+
it "should support ~ on arrays with all two pairs" do
|
244
|
+
@d.l(~[[:x, 100],[:y, 'a']]).should == '((x != 100) OR (y != \'a\'))'
|
245
|
+
@d.l(~[[:x, true], [:y, false]]).should == '((x != \'t\') OR (y != \'f\'))'
|
246
|
+
@d.l(~[[:x, nil], [:y, [1,2,3]]]).should == '((x IS NOT NULL) OR (y NOT IN (1, 2, 3)))'
|
247
|
+
end
|
248
|
+
|
249
|
+
it "should support sql_or on arrays with all two pairs" do
|
250
|
+
@d.l([[:x, 100],[:y, 'a']].sql_or).should == '((x = 100) OR (y = \'a\'))'
|
251
|
+
@d.l([[:x, true], [:y, false]].sql_or).should == '((x = \'t\') OR (y = \'f\'))'
|
252
|
+
@d.l([[:x, nil], [:y, [1,2,3]]].sql_or).should == '((x IS NULL) OR (y IN (1, 2, 3)))'
|
253
|
+
end
|
254
|
+
|
255
|
+
it "should support Array#sql_string_join for concatenation of SQL strings" do
|
256
|
+
@d.l([:x].sql_string_join).should == '(x)'
|
257
|
+
@d.l([:x].sql_string_join(', ')).should == '(x)'
|
258
|
+
@d.l([:x, :y].sql_string_join).should == '(x || y)'
|
259
|
+
@d.l([:x, :y].sql_string_join(', ')).should == "(x || ', ' || y)"
|
260
|
+
@d.l([:x[1], :y|1].sql_string_join).should == '(x(1) || y[1])'
|
261
|
+
@d.l([:x[1], 'y.z'.lit].sql_string_join(', ')).should == "(x(1) || ', ' || y.z)"
|
262
|
+
@d.l([:x, 1, :y].sql_string_join).should == "(x || '1' || y)"
|
263
|
+
@d.l([:x, 1, :y].sql_string_join(', ')).should == "(x || ', ' || '1' || ', ' || y)"
|
264
|
+
@d.l([:x, 1, :y].sql_string_join(:y__z)).should == "(x || y.z || '1' || y.z || y)"
|
265
|
+
@d.l([:x, 1, :y].sql_string_join(1)).should == "(x || '1' || '1' || '1' || y)"
|
266
|
+
@d.l([:x, :y].sql_string_join('y.x || x.y'.lit)).should == "(x || y.x || x.y || y)"
|
267
|
+
@d.l([[:x, :y].sql_string_join, [:a, :b].sql_string_join].sql_string_join).should == "((x || y) || (a || b))"
|
268
|
+
end
|
269
|
+
end
|
@@ -1,8 +1,10 @@
|
|
1
1
|
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
|
+
CONNECTION_POOL_DEFAULTS = {:pool_timeout=>5, :pool_sleep_time=>0.001,
|
3
|
+
:pool_reuse_connections=>:allow, :pool_convert_exceptions=>true, :max_connections=>4}
|
2
4
|
|
3
5
|
context "An empty ConnectionPool" do
|
4
6
|
setup do
|
5
|
-
@cpool = ConnectionPool.new
|
7
|
+
@cpool = ConnectionPool.new(CONNECTION_POOL_DEFAULTS)
|
6
8
|
end
|
7
9
|
|
8
10
|
specify "should have no available connections" do
|
@@ -10,7 +12,7 @@ context "An empty ConnectionPool" do
|
|
10
12
|
end
|
11
13
|
|
12
14
|
specify "should have no allocated connections" do
|
13
|
-
@cpool.allocated.should ==
|
15
|
+
@cpool.allocated.should == []
|
14
16
|
end
|
15
17
|
|
16
18
|
specify "should have a created_count of zero" do
|
@@ -21,21 +23,22 @@ end
|
|
21
23
|
context "A connection pool handling connections" do
|
22
24
|
setup do
|
23
25
|
@max_size = 2
|
24
|
-
@cpool = ConnectionPool.new(
|
26
|
+
@cpool = ConnectionPool.new(CONNECTION_POOL_DEFAULTS.merge(:max_connections=>@max_size)) {:got_connection}
|
25
27
|
end
|
26
28
|
|
27
29
|
specify "#hold should increment #created_count" do
|
28
30
|
@cpool.hold do
|
29
31
|
@cpool.created_count.should == 1
|
30
|
-
@cpool.hold {@cpool.created_count.should ==
|
32
|
+
@cpool.hold {@cpool.created_count.should == 2}
|
33
|
+
@cpool.hold {@cpool.hold {@cpool.created_count.should == 2}}
|
31
34
|
end
|
32
35
|
end
|
33
36
|
|
34
|
-
specify "#hold should add the connection to the #allocated
|
37
|
+
specify "#hold should add the connection to the #allocated array" do
|
35
38
|
@cpool.hold do
|
36
39
|
@cpool.allocated.size.should == 1
|
37
40
|
|
38
|
-
@cpool.allocated.
|
41
|
+
@cpool.allocated.should == [[Thread.current, :got_connection]]
|
39
42
|
end
|
40
43
|
end
|
41
44
|
|
@@ -73,7 +76,7 @@ end
|
|
73
76
|
|
74
77
|
context "ConnectionPool#hold" do
|
75
78
|
setup do
|
76
|
-
@pool = ConnectionPool.new {DummyConnection.new}
|
79
|
+
@pool = ConnectionPool.new(CONNECTION_POOL_DEFAULTS) {DummyConnection.new}
|
77
80
|
end
|
78
81
|
|
79
82
|
specify "should pass the result of the connection maker proc to the supplied block" do
|
@@ -109,7 +112,7 @@ end
|
|
109
112
|
|
110
113
|
context "ConnectionPool#connection_proc" do
|
111
114
|
setup do
|
112
|
-
@pool = ConnectionPool.new
|
115
|
+
@pool = ConnectionPool.new(CONNECTION_POOL_DEFAULTS)
|
113
116
|
end
|
114
117
|
|
115
118
|
specify "should be nil if no block is supplied to the pool" do
|
@@ -128,7 +131,7 @@ end
|
|
128
131
|
context "A connection pool with a max size of 1" do
|
129
132
|
setup do
|
130
133
|
@invoked_count = 0
|
131
|
-
@pool = ConnectionPool.new(1) {@invoked_count += 1; 'herro'}
|
134
|
+
@pool = ConnectionPool.new(CONNECTION_POOL_DEFAULTS.merge(:max_connections=>1)) {@invoked_count += 1; 'herro'}
|
132
135
|
end
|
133
136
|
|
134
137
|
specify "should let only one thread access the connection at any time" do
|
@@ -151,7 +154,7 @@ context "A connection pool with a max size of 1" do
|
|
151
154
|
c2.should be_nil
|
152
155
|
|
153
156
|
@pool.available_connections.should be_empty
|
154
|
-
@pool.allocated.should ==
|
157
|
+
@pool.allocated.should == [[t1, cc]]
|
155
158
|
|
156
159
|
cc.gsub!('rr', 'll')
|
157
160
|
sleep 0.5
|
@@ -163,7 +166,7 @@ context "A connection pool with a max size of 1" do
|
|
163
166
|
c2.should == 'hello'
|
164
167
|
|
165
168
|
@pool.available_connections.should be_empty
|
166
|
-
@pool.allocated.should ==
|
169
|
+
@pool.allocated.should == [[t2, cc]]
|
167
170
|
|
168
171
|
cc.gsub!('ll', 'rr')
|
169
172
|
sleep 0.5
|
@@ -204,7 +207,7 @@ end
|
|
204
207
|
context "A connection pool with a max size of 5" do
|
205
208
|
setup do
|
206
209
|
@invoked_count = 0
|
207
|
-
@pool = ConnectionPool.new(5) {@invoked_count += 1}
|
210
|
+
@pool = ConnectionPool.new(CONNECTION_POOL_DEFAULTS.merge(:max_connections=>5)) {@invoked_count += 1}
|
208
211
|
end
|
209
212
|
|
210
213
|
specify "should let five threads simultaneously access separate connections" do
|
@@ -219,8 +222,8 @@ context "A connection pool with a max size of 5" do
|
|
219
222
|
@invoked_count.should == 5
|
220
223
|
@pool.size.should == 5
|
221
224
|
@pool.available_connections.should be_empty
|
222
|
-
|
223
|
-
|
225
|
+
i = 0
|
226
|
+
@pool.allocated.should == threads.collect{|t| [t,i+=1]}
|
224
227
|
|
225
228
|
threads[0].raise "your'e dead"
|
226
229
|
sleep 0.1
|
@@ -229,7 +232,7 @@ context "A connection pool with a max size of 5" do
|
|
229
232
|
sleep 0.1
|
230
233
|
|
231
234
|
@pool.available_connections.should == [1, 4]
|
232
|
-
@pool.allocated.should ==
|
235
|
+
@pool.allocated.should == [[threads[1], 2], [threads[2], 3], [threads[4], 5]]
|
233
236
|
|
234
237
|
stop = true
|
235
238
|
sleep 0.2
|
@@ -274,7 +277,7 @@ end
|
|
274
277
|
context "ConnectionPool#disconnect" do
|
275
278
|
setup do
|
276
279
|
@count = 0
|
277
|
-
@pool = ConnectionPool.new(5) {{:id => @count += 1}}
|
280
|
+
@pool = ConnectionPool.new(CONNECTION_POOL_DEFAULTS.merge(:max_connections=>5)) {{:id => @count += 1}}
|
278
281
|
end
|
279
282
|
|
280
283
|
specify "should invoke the given block for each available connection" do
|
@@ -338,7 +341,7 @@ end
|
|
338
341
|
|
339
342
|
context "SingleThreadedPool" do
|
340
343
|
setup do
|
341
|
-
@pool = SingleThreadedPool.new
|
344
|
+
@pool = SingleThreadedPool.new(CONNECTION_POOL_DEFAULTS){1234}
|
342
345
|
end
|
343
346
|
|
344
347
|
specify "should provide a #hold method" do
|
@@ -355,4 +358,4 @@ context "SingleThreadedPool" do
|
|
355
358
|
conn.should == 1234
|
356
359
|
@pool.conn.should be_nil
|
357
360
|
end
|
358
|
-
end
|
361
|
+
end
|
data/spec/core_ext_spec.rb
CHANGED
@@ -1,19 +1,169 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
|
-
|
3
|
-
context "
|
4
|
-
specify "should
|
5
|
-
a = [
|
6
|
-
a.
|
7
|
-
a.should == [
|
8
|
-
end
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
|
+
|
3
|
+
context "Array#extract_options!" do
|
4
|
+
specify "should pop the last item if it is a hash" do
|
5
|
+
a = [1,2,{1=>2}]
|
6
|
+
a.extract_options!.should == {1=>2}
|
7
|
+
a.should == [1,2]
|
8
|
+
end
|
9
|
+
|
10
|
+
specify "should return an empty hash if the last item is not a hash" do
|
11
|
+
a = [1,2]
|
12
|
+
a.extract_options!.should == {}
|
13
|
+
a.should == [1,2]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
context "Enumerable#send_each" do
|
18
|
+
specify "should send the supplied method to each item" do
|
19
|
+
a = ['abbc', 'bbccdd', 'hebtre']
|
20
|
+
a.send_each(:gsub!, 'b', '_')
|
21
|
+
a.should == ['a__c', '__ccdd', 'he_tre']
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context "Range#interval" do
|
26
|
+
specify "should return the interval between the beginning and end for an inclusive range" do
|
27
|
+
(1..10).interval.should == 9
|
28
|
+
|
29
|
+
r = rand(100000) + 10
|
30
|
+
t1 = Time.now; t2 = t1 + r
|
31
|
+
(t1..t2).interval.should == r
|
32
|
+
end
|
33
|
+
|
34
|
+
specify "should return the interval between the beginning and end for an exclusive range" do
|
35
|
+
(1...10).interval.should == 8
|
36
|
+
|
37
|
+
r = rand(100000) + 10
|
38
|
+
t1 = Time.now; t2 = t1 + r
|
39
|
+
(t1...t2).interval.should == r - 1
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context "Module#class_attr_reader" do
|
44
|
+
specify "it should create instance methods that call class methods of the same name" do
|
45
|
+
@c = Class.new do
|
46
|
+
def self.x; 1; end
|
47
|
+
class_attr_reader :x
|
48
|
+
end
|
49
|
+
@c.new.x.should == 1
|
50
|
+
def @c.x; 2; end
|
51
|
+
@c.new.x.should == 2
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
context "Module#metaalias" do
|
56
|
+
specify "it should create aliases of singleton/class methods" do
|
57
|
+
@c = Class.new do
|
58
|
+
def self.x; 1; end
|
59
|
+
metaalias :y, :x
|
60
|
+
end
|
61
|
+
@c.y.should == 1
|
62
|
+
def @c.x; 2; end
|
63
|
+
@c.y.should == 1
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context "Module#metaattr_reader" do
|
68
|
+
specify "it should create attr_readers of singleton/class methods" do
|
69
|
+
@c = Class.new do
|
70
|
+
@y = 1
|
71
|
+
@x = 2
|
72
|
+
metaattr_reader :y, :x
|
73
|
+
end
|
74
|
+
@c.y.should == 1
|
75
|
+
@c.x.should == 2
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
context "Module#metaprivate" do
|
80
|
+
specify "it should create aliases of singleton/class methods" do
|
81
|
+
@c = Class.new do
|
82
|
+
def self.x; 1; end
|
83
|
+
end
|
84
|
+
@c.x.should == 1
|
85
|
+
@c.class_eval do
|
86
|
+
metaprivate :x
|
87
|
+
end
|
88
|
+
proc{@c.x}.should raise_error(NoMethodError)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
context "Object#is_one_of?" do
|
93
|
+
specify "it should be true if the object is one of the classes" do
|
94
|
+
1.is_one_of?(Numeric, Array).should == true
|
95
|
+
[].is_one_of?(Numeric, Array).should == true
|
96
|
+
{}.is_one_of?(Numeric, Enumerable).should == true
|
97
|
+
end
|
98
|
+
|
99
|
+
specify "it should be false if the object is not one of the classes" do
|
100
|
+
'a'.is_one_of?(Numeric, Array).should == false
|
101
|
+
Object.new.is_one_of?(Numeric, Array).should == false
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
context "Object#blank?" do
|
106
|
+
specify "it should be true if the object responds true to empty?" do
|
107
|
+
[].blank?.should == true
|
108
|
+
{}.blank?.should == true
|
109
|
+
o = Object.new
|
110
|
+
def o.empty?; true; end
|
111
|
+
o.blank?.should == true
|
112
|
+
end
|
113
|
+
|
114
|
+
specify "it should be false if the object doesn't respond true to empty?" do
|
115
|
+
[2].blank?.should == false
|
116
|
+
{1=>2}.blank?.should == false
|
117
|
+
Object.new.blank?.should == false
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
context "Numeric#blank?" do
|
122
|
+
specify "it should always be false" do
|
123
|
+
1.blank?.should == false
|
124
|
+
0.blank?.should == false
|
125
|
+
-1.blank?.should == false
|
126
|
+
1.0.blank?.should == false
|
127
|
+
0.0.blank?.should == false
|
128
|
+
-1.0.blank?.should == false
|
129
|
+
10000000000000000.blank?.should == false
|
130
|
+
-10000000000000000.blank?.should == false
|
131
|
+
10000000000000000.0.blank?.should == false
|
132
|
+
-10000000000000000.0.blank?.should == false
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
context "NilClass#blank?" do
|
137
|
+
specify "it should always be true" do
|
138
|
+
nil.blank?.should == true
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
context "TrueClass#blank?" do
|
143
|
+
specify "it should always be false" do
|
144
|
+
true.blank?.should == false
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
context "FalseClass#blank?" do
|
149
|
+
specify "it should always be true" do
|
150
|
+
false.blank?.should == true
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
context "FalseClass#blank?" do
|
155
|
+
specify "it should be true if the string is empty" do
|
156
|
+
''.blank?.should == true
|
157
|
+
end
|
158
|
+
specify "it should be true if the string is composed of just whitespace" do
|
159
|
+
' '.blank?.should == true
|
160
|
+
"\r\n\t".blank?.should == true
|
161
|
+
(' '*4000).blank?.should == true
|
162
|
+
("\r\n\t"*4000).blank?.should == true
|
163
|
+
end
|
164
|
+
specify "it should be false if the string has any non whitespace characters" do
|
165
|
+
'1'.blank?.should == false
|
166
|
+
("\r\n\t"*4000 + 'a').blank?.should == false
|
167
|
+
("\r\na\t"*4000).blank?.should == false
|
168
|
+
end
|
169
|
+
end
|