sequel_core 1.5.1 → 2.0.0
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 +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
|