sequel_core 2.0.1 → 2.1.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 +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
|