sequel_core 2.0.1 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +50 -0
- data/README +1 -2
- data/Rakefile +1 -1
- data/bin/sequel +26 -11
- data/doc/dataset_filtering.rdoc +9 -2
- data/lib/sequel_core/adapters/adapter_skeleton.rb +0 -2
- data/lib/sequel_core/adapters/mysql.rb +11 -97
- data/lib/sequel_core/adapters/odbc_mssql.rb +1 -1
- data/lib/sequel_core/adapters/oracle.rb +1 -1
- data/lib/sequel_core/adapters/postgres.rb +33 -17
- data/lib/sequel_core/adapters/sqlite.rb +1 -1
- data/lib/sequel_core/connection_pool.rb +12 -35
- data/lib/sequel_core/core_ext.rb +5 -19
- data/lib/sequel_core/core_sql.rb +17 -6
- data/lib/sequel_core/database.rb +14 -2
- data/lib/sequel_core/dataset/callback.rb +0 -3
- data/lib/sequel_core/dataset/convenience.rb +4 -3
- data/lib/sequel_core/dataset/parse_tree_sequelizer.rb +0 -21
- data/lib/sequel_core/dataset/sequelizer.rb +42 -43
- data/lib/sequel_core/dataset/sql.rb +121 -62
- data/lib/sequel_core/dataset.rb +20 -4
- data/lib/sequel_core/deprecated.rb +0 -6
- data/lib/sequel_core/migration.rb +4 -0
- data/lib/sequel_core/object_graph.rb +8 -6
- data/lib/sequel_core/pretty_table.rb +1 -1
- data/lib/sequel_core/schema/sql.rb +2 -0
- data/lib/sequel_core/sql.rb +393 -153
- data/lib/sequel_core.rb +22 -7
- data/spec/adapters/mysql_spec.rb +11 -7
- data/spec/adapters/postgres_spec.rb +32 -4
- data/spec/blockless_filters_spec.rb +33 -6
- data/spec/connection_pool_spec.rb +18 -16
- data/spec/core_ext_spec.rb +0 -13
- data/spec/core_sql_spec.rb +59 -13
- data/spec/database_spec.rb +5 -5
- data/spec/dataset_spec.rb +167 -55
- data/spec/object_graph_spec.rb +9 -4
- data/spec/sequelizer_spec.rb +8 -17
- data/spec/spec_helper.rb +4 -3
- metadata +2 -2
data/lib/sequel_core.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
require f
|
3
3
|
end
|
4
4
|
%w"core_ext sql core_sql connection_pool exceptions pretty_table
|
5
|
-
dataset migration schema database worker object_graph".each do |f|
|
5
|
+
dataset migration schema database worker object_graph deprecated".each do |f|
|
6
6
|
require "sequel_core/#{f}"
|
7
7
|
end
|
8
8
|
|
@@ -17,18 +17,30 @@ end
|
|
17
17
|
# :password=>'password', :host=>'host', :port=>5432, \
|
18
18
|
# :max_connections=>10)
|
19
19
|
#
|
20
|
-
# If a block is given to these
|
21
|
-
# object, which is closed when the block exits. For example:
|
20
|
+
# If a block is given to these methods, it is passed the opened Database
|
21
|
+
# object, which is closed (disconnected) when the block exits. For example:
|
22
22
|
#
|
23
23
|
# Sequel.sqlite('blog.db'){|db| puts db.users.count}
|
24
24
|
#
|
25
25
|
# Sequel can use either Time or DateTime for times returned from the
|
26
26
|
# database. It defaults to Time. To change it to DateTime, use:
|
27
27
|
#
|
28
|
-
# Sequel.
|
28
|
+
# Sequel.datetime_class = DateTime
|
29
|
+
#
|
30
|
+
# Sequel can either use ParseTree for block filters (deprecated but works),
|
31
|
+
# or it can use the block filter syntax inside block filters (which will
|
32
|
+
# be the only behavior allowed in Sequel 2.2). To set it not to use
|
33
|
+
# ParseTree filters:
|
34
|
+
#
|
35
|
+
# Sequel.use_parse_tree = false
|
29
36
|
module Sequel
|
30
|
-
@
|
31
|
-
|
37
|
+
@datetime_class = Time
|
38
|
+
@use_parse_tree = !defined?(SEQUEL_NO_PARSE_TREE)
|
39
|
+
|
40
|
+
metaattr_accessor :datetime_class
|
41
|
+
metaattr_accessor :use_parse_tree
|
42
|
+
|
43
|
+
Deprecation.deprecation_message_stream = $stderr
|
32
44
|
|
33
45
|
# Creates a new database object based on the supplied connection string
|
34
46
|
# and optional arguments. The specified scheme determines the database
|
@@ -45,6 +57,8 @@ module Sequel
|
|
45
57
|
# closed when the block exits. For example:
|
46
58
|
#
|
47
59
|
# Sequel.connect('sqlite://blog.db'){|db| puts db.users.count}
|
60
|
+
#
|
61
|
+
# This is also aliased as Sequel.open.
|
48
62
|
def self.connect(*args, &block)
|
49
63
|
Database.connect(*args, &block)
|
50
64
|
end
|
@@ -107,7 +121,8 @@ module Sequel
|
|
107
121
|
instance_eval("def #{adapter}(*args, &block); adapter_method('#{adapter}', *args, &block) end")
|
108
122
|
end
|
109
123
|
end
|
110
|
-
|
124
|
+
|
125
|
+
private_class_method :adapter_method, :def_adapter_method
|
111
126
|
|
112
127
|
# Add the database adapter class methods to Sequel via metaprogramming
|
113
128
|
def_adapter_method(*Database::ADAPTERS)
|
data/spec/adapters/mysql_spec.rb
CHANGED
@@ -179,13 +179,13 @@ context "A MySQL dataset" do
|
|
179
179
|
'SELECT * FROM `items` ORDER BY `name` DESC'
|
180
180
|
|
181
181
|
@d.reverse_order(:name.desc).sql.should == \
|
182
|
-
'SELECT * FROM `items` ORDER BY `name`'
|
182
|
+
'SELECT * FROM `items` ORDER BY `name` ASC'
|
183
183
|
|
184
184
|
@d.reverse_order(:name, :test.desc).sql.should == \
|
185
|
-
'SELECT * FROM `items` ORDER BY `name` DESC, `test`'
|
185
|
+
'SELECT * FROM `items` ORDER BY `name` DESC, `test` ASC'
|
186
186
|
|
187
187
|
@d.reverse_order(:name.desc, :test).sql.should == \
|
188
|
-
'SELECT * FROM `items` ORDER BY `name
|
188
|
+
'SELECT * FROM `items` ORDER BY `name` ASC, `test` DESC'
|
189
189
|
end
|
190
190
|
|
191
191
|
specify "should support ORDER clause in UPDATE statements" do
|
@@ -318,9 +318,13 @@ context "MySQL join expressions" do
|
|
318
318
|
@ds.join_table(:natural_inner, :nodes).sql.should == \
|
319
319
|
'SELECT * FROM nodes NATURAL LEFT JOIN nodes'
|
320
320
|
end
|
321
|
-
specify "should support cross joins
|
321
|
+
specify "should support cross joins" do
|
322
322
|
@ds.join_table(:cross, :nodes).sql.should == \
|
323
|
-
'SELECT * FROM nodes
|
323
|
+
'SELECT * FROM nodes CROSS JOIN nodes'
|
324
|
+
end
|
325
|
+
specify "should support cross joins as inner joins if conditions are used" do
|
326
|
+
@ds.join_table(:cross, :nodes, :id=>:id).sql.should == \
|
327
|
+
'SELECT * FROM nodes INNER JOIN nodes ON (nodes.id = nodes.id)'
|
324
328
|
end
|
325
329
|
specify "should support straight joins (force left table to be read before right)" do
|
326
330
|
@ds.join_table(:straight, :nodes).sql.should == \
|
@@ -328,11 +332,11 @@ context "MySQL join expressions" do
|
|
328
332
|
end
|
329
333
|
specify "should support natural joins on multiple tables." do
|
330
334
|
@ds.join_table(:natural_left_outer, [:nodes, :branches]).sql.should == \
|
331
|
-
'SELECT * FROM nodes NATURAL LEFT OUTER JOIN (
|
335
|
+
'SELECT * FROM nodes NATURAL LEFT OUTER JOIN (nodes, branches)'
|
332
336
|
end
|
333
337
|
specify "should support straight joins on multiple tables." do
|
334
338
|
@ds.join_table(:straight, [:nodes,:branches]).sql.should == \
|
335
|
-
'SELECT * FROM nodes STRAIGHT_JOIN (
|
339
|
+
'SELECT * FROM nodes STRAIGHT_JOIN (nodes, branches)'
|
336
340
|
end
|
337
341
|
end
|
338
342
|
|
@@ -39,7 +39,10 @@ context "A PostgreSQL database" do
|
|
39
39
|
end
|
40
40
|
|
41
41
|
specify "should correctly parse the schema" do
|
42
|
-
@db.schema(:test3, :reload=>true).should == [
|
42
|
+
@db.schema(:test3, :reload=>true).should == [
|
43
|
+
[:value, {:type=>:integer, :allow_null=>true, :max_chars=>nil, :default=>nil, :db_type=>"integer", :numeric_precision=>32}],
|
44
|
+
[:time, {:type=>:datetime, :allow_null=>true, :max_chars=>nil, :default=>nil, :db_type=>"timestamp without time zone", :numeric_precision=>nil}]
|
45
|
+
]
|
43
46
|
end
|
44
47
|
|
45
48
|
specify "should get the schema all database tables if no table name is used" do
|
@@ -152,13 +155,13 @@ context "A PostgreSQL dataset" do
|
|
152
155
|
'SELECT * FROM "test" ORDER BY "name" DESC'
|
153
156
|
|
154
157
|
@d.reverse_order(:name.desc).sql.should == \
|
155
|
-
'SELECT * FROM "test" ORDER BY "name"'
|
158
|
+
'SELECT * FROM "test" ORDER BY "name" ASC'
|
156
159
|
|
157
160
|
@d.reverse_order(:name, :test.desc).sql.should == \
|
158
|
-
'SELECT * FROM "test" ORDER BY "name" DESC, "test"'
|
161
|
+
'SELECT * FROM "test" ORDER BY "name" DESC, "test" ASC'
|
159
162
|
|
160
163
|
@d.reverse_order(:name.desc, :test).sql.should == \
|
161
|
-
'SELECT * FROM "test" ORDER BY "name", "test" DESC'
|
164
|
+
'SELECT * FROM "test" ORDER BY "name" ASC, "test" DESC'
|
162
165
|
end
|
163
166
|
|
164
167
|
specify "should support transactions" do
|
@@ -202,6 +205,31 @@ context "A PostgreSQL dataset" do
|
|
202
205
|
@d.count.should == 2
|
203
206
|
end
|
204
207
|
|
208
|
+
specify "should support nested transactions through savepoints" do
|
209
|
+
POSTGRES_DB.transaction do
|
210
|
+
@d << {:name => '1'}
|
211
|
+
POSTGRES_DB.transaction do
|
212
|
+
@d << {:name => '2'}
|
213
|
+
POSTGRES_DB.transaction do
|
214
|
+
@d << {:name => '3'}
|
215
|
+
raise Sequel::Error::Rollback
|
216
|
+
end
|
217
|
+
@d << {:name => '4'}
|
218
|
+
POSTGRES_DB.transaction do
|
219
|
+
@d << {:name => '6'}
|
220
|
+
POSTGRES_DB.transaction do
|
221
|
+
@d << {:name => '7'}
|
222
|
+
end
|
223
|
+
raise Sequel::Error::Rollback
|
224
|
+
end
|
225
|
+
@d << {:name => '5'}
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
@d.count.should == 4
|
230
|
+
@d.order(:name).map(:name).should == %w{1 2 4 5}
|
231
|
+
end
|
232
|
+
|
205
233
|
specify "should support regexps" do
|
206
234
|
@d << {:name => 'abc', :value => 1}
|
207
235
|
@d << {:name => 'bcd', :value => 2}
|
@@ -5,13 +5,21 @@ context "Blockless Ruby Filters" do
|
|
5
5
|
db = Sequel::Database.new
|
6
6
|
db.quote_identifiers = false
|
7
7
|
@d = db[:items]
|
8
|
-
def @d.l(*args)
|
9
|
-
|
8
|
+
def @d.l(*args, &block)
|
9
|
+
if block_given?
|
10
|
+
literal(filter_expr(Proc.new(&block)))
|
11
|
+
else
|
12
|
+
literal(filter_expr(*args))
|
13
|
+
end
|
10
14
|
end
|
11
15
|
def @d.lit(*args)
|
12
16
|
literal(*args)
|
13
17
|
end
|
14
18
|
end
|
19
|
+
|
20
|
+
after do
|
21
|
+
Sequel.use_parse_tree = true
|
22
|
+
end
|
15
23
|
|
16
24
|
it "should support boolean columns directly" do
|
17
25
|
@d.l(:x).should == 'x'
|
@@ -130,11 +138,8 @@ context "Blockless Ruby Filters" do
|
|
130
138
|
@d.l(~((((:x - :y)/(:x + :y))*:z) <= 100)).should == '((((x - y) / (x + y)) * z) > 100)'
|
131
139
|
end
|
132
140
|
|
133
|
-
it "should not allow negation of
|
134
|
-
proc{~(:x + 1 > 100)}.should_not raise_error
|
135
|
-
proc{~(:x + 1)}.should raise_error
|
141
|
+
it "should not allow negation of string expressions" do
|
136
142
|
proc{~:x.sql_string}.should raise_error
|
137
|
-
proc{~:x.sql_number}.should raise_error
|
138
143
|
proc{~([:x, :y].sql_string_join)}.should raise_error
|
139
144
|
end
|
140
145
|
|
@@ -294,4 +299,26 @@ context "Blockless Ruby Filters" do
|
|
294
299
|
@d.lit([:x].sql_string_join + :y).should == '((x) || y)'
|
295
300
|
@d.lit([:x, :z].sql_string_join(' ') + :y).should == "((x || ' ' || z) || y)"
|
296
301
|
end
|
302
|
+
|
303
|
+
it "should be supported inside blocks if Sequel.use_parse_tree = false" do
|
304
|
+
@d.l{[[:x, nil], [:y, [1,2,3]]].sql_or}.should == '((x IS NULL) OR (y IN (1, 2, 3)))'
|
305
|
+
@d.l{~[[:x, nil], [:y, [1,2,3]]]}.should == '((x IS NOT NULL) OR (y NOT IN (1, 2, 3)))'
|
306
|
+
@d.l{~(((('x'.lit - :y)/(:x + :y))*:z) <= 100)}.should == '((((x - y) / (x + y)) * z) > 100)'
|
307
|
+
@d.l{{:x => :a} & {:y => :z}}.should == '((x = a) AND (y = z))'
|
308
|
+
end
|
309
|
+
|
310
|
+
it "should support &, |, ^, ~, <<, and >> for NumericExpressions" do
|
311
|
+
@d.l(:x.sql_number & 1 > 100).should == '((x & 1) > 100)'
|
312
|
+
@d.l(:x.sql_number | 1 > 100).should == '((x | 1) > 100)'
|
313
|
+
@d.l(:x.sql_number ^ 1 > 100).should == '((x ^ 1) > 100)'
|
314
|
+
@d.l(~:x.sql_number > 100).should == '(~x > 100)'
|
315
|
+
@d.l(:x.sql_number << 1 > 100).should == '((x << 1) > 100)'
|
316
|
+
@d.l(:x.sql_number >> 1 > 100).should == '((x >> 1) > 100)'
|
317
|
+
@d.l((:x + 1) & 1 > 100).should == '(((x + 1) & 1) > 100)'
|
318
|
+
@d.l((:x + 1) | 1 > 100).should == '(((x + 1) | 1) > 100)'
|
319
|
+
@d.l((:x + 1) ^ 1 > 100).should == '(((x + 1) ^ 1) > 100)'
|
320
|
+
@d.l(~(:x + 1) > 100).should == '(~(x + 1) > 100)'
|
321
|
+
@d.l((:x + 1) << 1 > 100).should == '(((x + 1) << 1) > 100)'
|
322
|
+
@d.l((:x + 1) >> 1 > 100).should == '(((x + 1) >> 1) > 100)'
|
323
|
+
end
|
297
324
|
end
|
@@ -4,7 +4,7 @@ CONNECTION_POOL_DEFAULTS = {:pool_timeout=>5, :pool_sleep_time=>0.001,
|
|
4
4
|
|
5
5
|
context "An empty ConnectionPool" do
|
6
6
|
setup do
|
7
|
-
@cpool = ConnectionPool.new(CONNECTION_POOL_DEFAULTS)
|
7
|
+
@cpool = Sequel::ConnectionPool.new(CONNECTION_POOL_DEFAULTS)
|
8
8
|
end
|
9
9
|
|
10
10
|
specify "should have no available connections" do
|
@@ -12,7 +12,7 @@ context "An empty ConnectionPool" do
|
|
12
12
|
end
|
13
13
|
|
14
14
|
specify "should have no allocated connections" do
|
15
|
-
@cpool.allocated.should ==
|
15
|
+
@cpool.allocated.should == {}
|
16
16
|
end
|
17
17
|
|
18
18
|
specify "should have a created_count of zero" do
|
@@ -23,14 +23,14 @@ end
|
|
23
23
|
context "A connection pool handling connections" do
|
24
24
|
setup do
|
25
25
|
@max_size = 2
|
26
|
-
@cpool = ConnectionPool.new(CONNECTION_POOL_DEFAULTS.merge(:max_connections=>@max_size)) {:got_connection}
|
26
|
+
@cpool = Sequel::ConnectionPool.new(CONNECTION_POOL_DEFAULTS.merge(:max_connections=>@max_size)) {:got_connection}
|
27
27
|
end
|
28
28
|
|
29
29
|
specify "#hold should increment #created_count" do
|
30
30
|
@cpool.hold do
|
31
31
|
@cpool.created_count.should == 1
|
32
|
-
@cpool.hold {@cpool.created_count.should ==
|
33
|
-
|
32
|
+
@cpool.hold {@cpool.hold {@cpool.created_count.should == 1}}
|
33
|
+
Thread.new{@cpool.hold {@cpool.created_count.should == 2}}.join
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
@@ -38,7 +38,7 @@ context "A connection pool handling connections" do
|
|
38
38
|
@cpool.hold do
|
39
39
|
@cpool.allocated.size.should == 1
|
40
40
|
|
41
|
-
@cpool.allocated.should ==
|
41
|
+
@cpool.allocated.should == {Thread.current=>:got_connection}
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
@@ -76,7 +76,7 @@ end
|
|
76
76
|
|
77
77
|
context "ConnectionPool#hold" do
|
78
78
|
setup do
|
79
|
-
@pool = ConnectionPool.new(CONNECTION_POOL_DEFAULTS) {DummyConnection.new}
|
79
|
+
@pool = Sequel::ConnectionPool.new(CONNECTION_POOL_DEFAULTS) {DummyConnection.new}
|
80
80
|
end
|
81
81
|
|
82
82
|
specify "should pass the result of the connection maker proc to the supplied block" do
|
@@ -112,7 +112,7 @@ end
|
|
112
112
|
|
113
113
|
context "ConnectionPool#connection_proc" do
|
114
114
|
setup do
|
115
|
-
@pool = ConnectionPool.new(CONNECTION_POOL_DEFAULTS)
|
115
|
+
@pool = Sequel::ConnectionPool.new(CONNECTION_POOL_DEFAULTS)
|
116
116
|
end
|
117
117
|
|
118
118
|
specify "should be nil if no block is supplied to the pool" do
|
@@ -131,7 +131,7 @@ end
|
|
131
131
|
context "A connection pool with a max size of 1" do
|
132
132
|
setup do
|
133
133
|
@invoked_count = 0
|
134
|
-
@pool = ConnectionPool.new(CONNECTION_POOL_DEFAULTS.merge(:max_connections=>1)) {@invoked_count += 1; 'herro'}
|
134
|
+
@pool = Sequel::ConnectionPool.new(CONNECTION_POOL_DEFAULTS.merge(:max_connections=>1)) {@invoked_count += 1; 'herro'}
|
135
135
|
end
|
136
136
|
|
137
137
|
specify "should let only one thread access the connection at any time" do
|
@@ -154,7 +154,7 @@ context "A connection pool with a max size of 1" do
|
|
154
154
|
c2.should be_nil
|
155
155
|
|
156
156
|
@pool.available_connections.should be_empty
|
157
|
-
@pool.allocated.should ==
|
157
|
+
@pool.allocated.should == {t1=>cc}
|
158
158
|
|
159
159
|
cc.gsub!('rr', 'll')
|
160
160
|
sleep 0.5
|
@@ -166,7 +166,7 @@ context "A connection pool with a max size of 1" do
|
|
166
166
|
c2.should == 'hello'
|
167
167
|
|
168
168
|
@pool.available_connections.should be_empty
|
169
|
-
@pool.allocated.should ==
|
169
|
+
@pool.allocated.should == {t2=>cc}
|
170
170
|
|
171
171
|
cc.gsub!('ll', 'rr')
|
172
172
|
sleep 0.5
|
@@ -207,7 +207,7 @@ end
|
|
207
207
|
context "A connection pool with a max size of 5" do
|
208
208
|
setup do
|
209
209
|
@invoked_count = 0
|
210
|
-
@pool = ConnectionPool.new(CONNECTION_POOL_DEFAULTS.merge(:max_connections=>5)) {@invoked_count += 1}
|
210
|
+
@pool = Sequel::ConnectionPool.new(CONNECTION_POOL_DEFAULTS.merge(:max_connections=>5)) {@invoked_count += 1}
|
211
211
|
end
|
212
212
|
|
213
213
|
specify "should let five threads simultaneously access separate connections" do
|
@@ -223,7 +223,9 @@ context "A connection pool with a max size of 5" do
|
|
223
223
|
@pool.size.should == 5
|
224
224
|
@pool.available_connections.should be_empty
|
225
225
|
i = 0
|
226
|
-
|
226
|
+
h = {}
|
227
|
+
threads.each{|t| h[t] = (i+=1)}
|
228
|
+
@pool.allocated.should == h
|
227
229
|
|
228
230
|
threads[0].raise "your'e dead"
|
229
231
|
sleep 0.1
|
@@ -232,7 +234,7 @@ context "A connection pool with a max size of 5" do
|
|
232
234
|
sleep 0.1
|
233
235
|
|
234
236
|
@pool.available_connections.should == [1, 4]
|
235
|
-
@pool.allocated.should ==
|
237
|
+
@pool.allocated.should == {threads[1]=>2, threads[2]=>3, threads[4]=>5}
|
236
238
|
|
237
239
|
stop = true
|
238
240
|
sleep 0.2
|
@@ -277,7 +279,7 @@ end
|
|
277
279
|
context "ConnectionPool#disconnect" do
|
278
280
|
setup do
|
279
281
|
@count = 0
|
280
|
-
@pool = ConnectionPool.new(CONNECTION_POOL_DEFAULTS.merge(:max_connections=>5)) {{:id => @count += 1}}
|
282
|
+
@pool = Sequel::ConnectionPool.new(CONNECTION_POOL_DEFAULTS.merge(:max_connections=>5)) {{:id => @count += 1}}
|
281
283
|
end
|
282
284
|
|
283
285
|
specify "should invoke the given block for each available connection" do
|
@@ -341,7 +343,7 @@ end
|
|
341
343
|
|
342
344
|
context "SingleThreadedPool" do
|
343
345
|
setup do
|
344
|
-
@pool = SingleThreadedPool.new(CONNECTION_POOL_DEFAULTS){1234}
|
346
|
+
@pool = Sequel::SingleThreadedPool.new(CONNECTION_POOL_DEFAULTS){1234}
|
345
347
|
end
|
346
348
|
|
347
349
|
specify "should provide a #hold method" do
|
data/spec/core_ext_spec.rb
CHANGED
@@ -76,19 +76,6 @@ context "Module#metaattr_reader" do
|
|
76
76
|
end
|
77
77
|
end
|
78
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
79
|
context "Object#is_one_of?" do
|
93
80
|
specify "it should be true if the object is one of the classes" do
|
94
81
|
1.is_one_of?(Numeric, Array).should == true
|
data/spec/core_sql_spec.rb
CHANGED
@@ -23,6 +23,31 @@ context "Array#all_two_pairs?" do
|
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
|
+
context "Array#case and Hash#case" do
|
27
|
+
setup do
|
28
|
+
@d = Sequel::Dataset.new(nil)
|
29
|
+
end
|
30
|
+
|
31
|
+
specify "should return SQL CASE expression" do
|
32
|
+
@d.literal({:x=>:y}.case(:z)).should == '(CASE WHEN x THEN y ELSE z END)'
|
33
|
+
['(CASE WHEN x THEN y WHEN a THEN b ELSE z END)',
|
34
|
+
'(CASE WHEN a THEN b WHEN x THEN y ELSE z END)'].should(include(@d.literal({:x=>:y, :a=>:b}.case(:z))))
|
35
|
+
@d.literal([[:x, :y]].case(:z)).should == '(CASE WHEN x THEN y ELSE z END)'
|
36
|
+
@d.literal([[:x, :y], [:a, :b]].case(:z)).should == '(CASE WHEN x THEN y WHEN a THEN b ELSE z END)'
|
37
|
+
end
|
38
|
+
|
39
|
+
specify "should raise an error if an array that isn't all two pairs is used" do
|
40
|
+
proc{[:b].case(:a)}.should raise_error(Sequel::Error)
|
41
|
+
proc{[:b, :c].case(:a)}.should raise_error(Sequel::Error)
|
42
|
+
proc{[[:b, :c], :d].case(:a)}.should raise_error(Sequel::Error)
|
43
|
+
end
|
44
|
+
|
45
|
+
specify "should raise an error if an empty array/hash is used" do
|
46
|
+
proc{[].case(:a)}.should raise_error(Sequel::Error)
|
47
|
+
proc{{}.case(:a)}.should raise_error(Sequel::Error)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
26
51
|
context "Array#to_sql" do
|
27
52
|
specify "should concatenate multiple lines into a single string" do
|
28
53
|
"SELECT * \r\nFROM items\r\n WHERE a = 1".split.to_sql. \
|
@@ -112,10 +137,6 @@ context "#desc" do
|
|
112
137
|
specify "should format a DESC clause for a function" do
|
113
138
|
:avg[:test].desc.to_s(@ds).should == 'avg(test) DESC'
|
114
139
|
end
|
115
|
-
|
116
|
-
specify "should format a DESC clause for a literal value" do
|
117
|
-
'abc'.desc.to_s(@ds).should == "'abc' DESC"
|
118
|
-
end
|
119
140
|
end
|
120
141
|
|
121
142
|
context "#asc" do
|
@@ -132,10 +153,6 @@ context "#asc" do
|
|
132
153
|
specify "should format a ASC clause for a function" do
|
133
154
|
:avg[:test].asc.to_s(@ds).should == 'avg(test) ASC'
|
134
155
|
end
|
135
|
-
|
136
|
-
specify "should format a ASC clause for a literal value" do
|
137
|
-
'abc'.asc.to_s(@ds).should == "'abc' ASC"
|
138
|
-
end
|
139
156
|
end
|
140
157
|
|
141
158
|
context "#as" do
|
@@ -191,7 +208,7 @@ context "Column references" do
|
|
191
208
|
|
192
209
|
specify "should be quoted properly in a cast function" do
|
193
210
|
@ds.literal(:x.cast_as(:integer)).should == "cast(`x` AS integer)"
|
194
|
-
@ds.literal(:x__y.cast_as(
|
211
|
+
@ds.literal(:x__y.cast_as('varchar(20)')).should == "cast(`x`.`y` AS varchar(20))"
|
195
212
|
end
|
196
213
|
end
|
197
214
|
|
@@ -211,6 +228,12 @@ context "Symbol#*" do
|
|
211
228
|
end
|
212
229
|
end
|
213
230
|
|
231
|
+
context "Symbol#qualify" do
|
232
|
+
specify "should format a qualified column" do
|
233
|
+
:xyz.qualify(:abc).to_s(Sequel::Dataset.new(nil)).should == 'abc.xyz'
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
214
237
|
context "Symbol#to_column_ref" do
|
215
238
|
setup do
|
216
239
|
@ds = MockDataset.new(nil)
|
@@ -262,8 +285,27 @@ context "Symbol" do
|
|
262
285
|
ds.select(:COUNT['1']).sql.should == "SELECT COUNT('1') FROM t"
|
263
286
|
end
|
264
287
|
|
265
|
-
specify "should support cast
|
288
|
+
specify "should support cast method and its cast_as alias" do
|
266
289
|
:abc.cast_as(:integer).to_s(@ds).should == "cast(abc AS integer)"
|
290
|
+
:abc.cast(:integer).to_s(@ds).should == "cast(abc AS integer)"
|
291
|
+
end
|
292
|
+
|
293
|
+
specify "should support cast_numeric and cast_string" do
|
294
|
+
x = :abc.cast_numeric
|
295
|
+
x.should be_a_kind_of(Sequel::SQL::NumericExpression)
|
296
|
+
x.to_s(@ds).should == "cast(abc AS integer)"
|
297
|
+
|
298
|
+
x = :abc.cast_numeric(:real)
|
299
|
+
x.should be_a_kind_of(Sequel::SQL::NumericExpression)
|
300
|
+
x.to_s(@ds).should == "cast(abc AS real)"
|
301
|
+
|
302
|
+
x = :abc.cast_string
|
303
|
+
x.should be_a_kind_of(Sequel::SQL::StringExpression)
|
304
|
+
x.to_s(@ds).should == "cast(abc AS text)"
|
305
|
+
|
306
|
+
x = :abc.cast_string(:varchar)
|
307
|
+
x.should be_a_kind_of(Sequel::SQL::StringExpression)
|
308
|
+
x.to_s(@ds).should == "cast(abc AS varchar)"
|
267
309
|
end
|
268
310
|
|
269
311
|
specify "should support subscript access using | operator" do
|
@@ -272,6 +314,10 @@ context "Symbol" do
|
|
272
314
|
(:abc|[1, 2]).to_s(@ds).should == 'abc[1, 2]'
|
273
315
|
(:abc|1|2).to_s(@ds).should == 'abc[1, 2]'
|
274
316
|
end
|
317
|
+
|
318
|
+
specify "should support SQL EXTRACT function via #extract " do
|
319
|
+
:abc.extract(:year).to_s(@ds).should == "extract(year FROM abc)"
|
320
|
+
end
|
275
321
|
end
|
276
322
|
|
277
323
|
context "String#to_time" do
|
@@ -307,7 +353,7 @@ end
|
|
307
353
|
|
308
354
|
context "String#to_sequel_time" do
|
309
355
|
after do
|
310
|
-
Sequel.
|
356
|
+
Sequel.datetime_class = Time
|
311
357
|
end
|
312
358
|
|
313
359
|
specify "should convert the string into a Time object by default" do
|
@@ -316,14 +362,14 @@ context "String#to_sequel_time" do
|
|
316
362
|
end
|
317
363
|
|
318
364
|
specify "should convert the string into a DateTime object if that is set" do
|
319
|
-
Sequel.
|
365
|
+
Sequel.datetime_class = DateTime
|
320
366
|
"2007-07-11 10:11:12a".to_sequel_time.class.should == DateTime
|
321
367
|
"2007-07-11 10:11:12a".to_sequel_time.should == DateTime.parse("2007-07-11 10:11:12a")
|
322
368
|
end
|
323
369
|
|
324
370
|
specify "should raise Error::InvalidValue for an invalid time" do
|
325
371
|
proc {'0000-00-00'.to_sequel_time}.should raise_error(Sequel::Error::InvalidValue)
|
326
|
-
Sequel.
|
372
|
+
Sequel.datetime_class = DateTime
|
327
373
|
proc {'0000-00-00'.to_sequel_time}.should raise_error(Sequel::Error::InvalidValue)
|
328
374
|
end
|
329
375
|
end
|