sequel_core 1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. data/CHANGELOG +1003 -0
  2. data/COPYING +18 -0
  3. data/README +81 -0
  4. data/Rakefile +176 -0
  5. data/bin/sequel +41 -0
  6. data/lib/sequel_core.rb +59 -0
  7. data/lib/sequel_core/adapters/adapter_skeleton.rb +68 -0
  8. data/lib/sequel_core/adapters/ado.rb +100 -0
  9. data/lib/sequel_core/adapters/db2.rb +158 -0
  10. data/lib/sequel_core/adapters/dbi.rb +126 -0
  11. data/lib/sequel_core/adapters/informix.rb +87 -0
  12. data/lib/sequel_core/adapters/jdbc.rb +108 -0
  13. data/lib/sequel_core/adapters/mysql.rb +269 -0
  14. data/lib/sequel_core/adapters/odbc.rb +145 -0
  15. data/lib/sequel_core/adapters/odbc_mssql.rb +93 -0
  16. data/lib/sequel_core/adapters/openbase.rb +90 -0
  17. data/lib/sequel_core/adapters/oracle.rb +99 -0
  18. data/lib/sequel_core/adapters/postgres.rb +519 -0
  19. data/lib/sequel_core/adapters/sqlite.rb +192 -0
  20. data/lib/sequel_core/array_keys.rb +296 -0
  21. data/lib/sequel_core/connection_pool.rb +152 -0
  22. data/lib/sequel_core/core_ext.rb +59 -0
  23. data/lib/sequel_core/core_sql.rb +191 -0
  24. data/lib/sequel_core/database.rb +433 -0
  25. data/lib/sequel_core/dataset.rb +409 -0
  26. data/lib/sequel_core/dataset/convenience.rb +321 -0
  27. data/lib/sequel_core/dataset/sequelizer.rb +354 -0
  28. data/lib/sequel_core/dataset/sql.rb +586 -0
  29. data/lib/sequel_core/exceptions.rb +45 -0
  30. data/lib/sequel_core/migration.rb +191 -0
  31. data/lib/sequel_core/model.rb +8 -0
  32. data/lib/sequel_core/pretty_table.rb +73 -0
  33. data/lib/sequel_core/schema.rb +8 -0
  34. data/lib/sequel_core/schema/schema_generator.rb +131 -0
  35. data/lib/sequel_core/schema/schema_sql.rb +131 -0
  36. data/lib/sequel_core/worker.rb +58 -0
  37. data/spec/adapters/informix_spec.rb +139 -0
  38. data/spec/adapters/mysql_spec.rb +330 -0
  39. data/spec/adapters/oracle_spec.rb +130 -0
  40. data/spec/adapters/postgres_spec.rb +189 -0
  41. data/spec/adapters/sqlite_spec.rb +345 -0
  42. data/spec/array_keys_spec.rb +679 -0
  43. data/spec/connection_pool_spec.rb +356 -0
  44. data/spec/core_ext_spec.rb +67 -0
  45. data/spec/core_sql_spec.rb +301 -0
  46. data/spec/database_spec.rb +812 -0
  47. data/spec/dataset_spec.rb +2381 -0
  48. data/spec/migration_spec.rb +261 -0
  49. data/spec/pretty_table_spec.rb +66 -0
  50. data/spec/rcov.opts +4 -0
  51. data/spec/schema_generator_spec.rb +86 -0
  52. data/spec/schema_spec.rb +230 -0
  53. data/spec/sequelizer_spec.rb +448 -0
  54. data/spec/spec.opts +5 -0
  55. data/spec/spec_helper.rb +44 -0
  56. data/spec/worker_spec.rb +96 -0
  57. metadata +162 -0
@@ -0,0 +1,356 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+
3
+ context "An empty ConnectionPool" do
4
+ setup do
5
+ @cpool = Sequel::ConnectionPool.new
6
+ end
7
+
8
+ specify "should have no available connections" do
9
+ @cpool.available_connections.should == []
10
+ end
11
+
12
+ specify "should have no allocated connections" do
13
+ @cpool.allocated.should == {}
14
+ end
15
+
16
+ specify "should have a created_count of zero" do
17
+ @cpool.created_count.should == 0
18
+ end
19
+ end
20
+
21
+ context "A connection pool handling connections" do
22
+ setup do
23
+ @max_size = 2
24
+ @cpool = Sequel::ConnectionPool.new(@max_size) {:got_connection}
25
+ end
26
+
27
+ specify "#hold should increment #created_count" do
28
+ @cpool.hold do
29
+ @cpool.created_count.should == 1
30
+ @cpool.hold {@cpool.created_count.should == 1}
31
+ end
32
+ end
33
+
34
+ specify "#hold should add the connection to the #allocated hash" do
35
+ @cpool.hold do
36
+ @cpool.allocated.size.should == 1
37
+
38
+ @cpool.allocated.values.should == [:got_connection]
39
+ end
40
+ end
41
+
42
+ specify "#hold should yield a new connection" do
43
+ @cpool.hold {|conn| conn.should == :got_connection}
44
+ end
45
+
46
+ specify "a connection should be de-allocated after it has been used in #hold" do
47
+ @cpool.hold {}
48
+ @cpool.allocated.size.should == 0
49
+ end
50
+
51
+ specify "#hold should return the value of its block" do
52
+ @cpool.hold {:block_return}.should == :block_return
53
+ end
54
+
55
+ specify "#make_new should not make more than max_size connections" do
56
+ @cpool.send(:make_new).should == :got_connection
57
+ @cpool.send(:make_new).should == :got_connection
58
+ @cpool.send(:make_new).should == nil
59
+ @cpool.created_count.should == 2
60
+ end
61
+ end
62
+
63
+ class DummyConnection
64
+ @@value = 0
65
+ def initialize
66
+ @@value += 1
67
+ end
68
+
69
+ def value
70
+ @@value
71
+ end
72
+ end
73
+
74
+ context "ConnectionPool#hold" do
75
+ setup do
76
+ @pool = Sequel::ConnectionPool.new {DummyConnection.new}
77
+ end
78
+
79
+ specify "should pass the result of the connection maker proc to the supplied block" do
80
+ res = nil
81
+ @pool.hold {|c| res = c}
82
+ res.should be_a_kind_of(DummyConnection)
83
+ res.value.should == 1
84
+ @pool.hold {|c| res = c}
85
+ res.should be_a_kind_of(DummyConnection)
86
+ res.value.should == 1 # the connection maker is invoked only once
87
+ end
88
+
89
+ specify "should be re-entrant by the same thread" do
90
+ cc = nil
91
+ @pool.hold {|c| @pool.hold {|c| @pool.hold {|c| cc = c}}}
92
+ cc.should be_a_kind_of(DummyConnection)
93
+ end
94
+
95
+ specify "should catch exceptions and reraise them" do
96
+ proc {@pool.hold {|c| c.foobar}}.should raise_error(NoMethodError)
97
+ end
98
+
99
+ specify "should handle Exception errors (normally not caught be rescue)" do
100
+ begin
101
+ @pool.hold {raise Exception}
102
+ rescue => e
103
+ e.should be_a_kind_of(RuntimeError)
104
+ end
105
+ end
106
+ end
107
+
108
+ context "ConnectionPool#connection_proc" do
109
+ setup do
110
+ @pool = Sequel::ConnectionPool.new
111
+ end
112
+
113
+ specify "should be nil if no block is supplied to the pool" do
114
+ @pool.connection_proc.should be_nil
115
+ proc {@pool.hold {}}.should raise_error
116
+ end
117
+
118
+ specify "should be mutable" do
119
+ @pool.connection_proc = proc {'herro'}
120
+ res = nil
121
+ proc {@pool.hold {|c| res = c}}.should_not raise_error
122
+ res.should == 'herro'
123
+ end
124
+ end
125
+
126
+ context "A connection pool with a max size of 1" do
127
+ setup do
128
+ @invoked_count = 0
129
+ @pool = Sequel::ConnectionPool.new(1) {@invoked_count += 1; 'herro'}
130
+ end
131
+
132
+ specify "should let only one thread access the connection at any time" do
133
+ cc,c1, c2 = nil
134
+
135
+ t1 = Thread.new {@pool.hold {|c| cc = c; c1 = c.dup; while c == 'herro';sleep 0.1;end}}
136
+ sleep 0.2
137
+ cc.should == 'herro'
138
+ c1.should == 'herro'
139
+
140
+ t2 = Thread.new {@pool.hold {|c| c2 = c.dup; while c == 'hello';sleep 0.1;end}}
141
+ sleep 0.2
142
+
143
+ # connection held by t1
144
+ t1.should be_alive
145
+ t2.should be_alive
146
+
147
+ cc.should == 'herro'
148
+ c1.should == 'herro'
149
+ c2.should be_nil
150
+
151
+ @pool.available_connections.should be_empty
152
+ @pool.allocated.should == {t1 => cc}
153
+
154
+ cc.gsub!('rr', 'll')
155
+ sleep 0.5
156
+
157
+ # connection held by t2
158
+ t1.should_not be_alive
159
+ t2.should be_alive
160
+
161
+ c2.should == 'hello'
162
+
163
+ @pool.available_connections.should be_empty
164
+ @pool.allocated.should == {t2 => cc}
165
+
166
+ cc.gsub!('ll', 'rr')
167
+ sleep 0.5
168
+
169
+ #connection released
170
+ t2.should_not be_alive
171
+
172
+ cc.should == 'herro'
173
+
174
+ @invoked_count.should == 1
175
+ @pool.size.should == 1
176
+ @pool.available_connections.should == [cc]
177
+ @pool.allocated.should be_empty
178
+ end
179
+
180
+ specify "should let the same thread reenter #hold" do
181
+ c1, c2, c3 = nil
182
+ @pool.hold do |c|
183
+ c1 = c
184
+ @pool.hold do |c|
185
+ c2 = c
186
+ @pool.hold do |c|
187
+ c3 = c
188
+ end
189
+ end
190
+ end
191
+ c1.should == 'herro'
192
+ c2.should == 'herro'
193
+ c3.should == 'herro'
194
+
195
+ @invoked_count.should == 1
196
+ @pool.size.should == 1
197
+ @pool.available_connections.size.should == 1
198
+ @pool.allocated.should be_empty
199
+ end
200
+ end
201
+
202
+ context "A connection pool with a max size of 5" do
203
+ setup do
204
+ @invoked_count = 0
205
+ @pool = Sequel::ConnectionPool.new(5) {@invoked_count += 1}
206
+ end
207
+
208
+ specify "should let five threads simultaneously access separate connections" do
209
+ cc = {}
210
+ threads = []
211
+ stop = nil
212
+
213
+ 5.times {|i| threads << Thread.new {@pool.hold {|c| cc[i] = c; while !stop;sleep 0.1;end}}; sleep 0.1}
214
+ sleep 0.2
215
+ threads.each {|t| t.should be_alive}
216
+ cc.size.should == 5
217
+ @invoked_count.should == 5
218
+ @pool.size.should == 5
219
+ @pool.available_connections.should be_empty
220
+ @pool.allocated.should == {threads[0] => 1, threads[1] => 2, threads[2] => 3,
221
+ threads[3] => 4, threads[4] => 5}
222
+
223
+ threads[0].raise "your'e dead"
224
+ sleep 0.1
225
+ threads[3].raise "your'e dead too"
226
+
227
+ sleep 0.1
228
+
229
+ @pool.available_connections.should == [1, 4]
230
+ @pool.allocated.should == {threads[1] => 2, threads[2] => 3, threads[4] => 5}
231
+
232
+ stop = true
233
+ sleep 0.2
234
+
235
+ @pool.available_connections.size.should == 5
236
+ @pool.allocated.should be_empty
237
+ end
238
+
239
+ specify "should block threads until a connection becomes available" do
240
+ cc = {}
241
+ threads = []
242
+ stop = nil
243
+
244
+ 5.times {|i| threads << Thread.new {@pool.hold {|c| cc[i] = c; while !stop;sleep 0.1;end}}; sleep 0.1}
245
+ sleep 0.2
246
+ threads.each {|t| t.should be_alive}
247
+ @pool.available_connections.should be_empty
248
+
249
+ 3.times {|i| threads << Thread.new {@pool.hold {|c| cc[i + 5] = c}}}
250
+
251
+ sleep 0.2
252
+ threads[5].should be_alive
253
+ threads[6].should be_alive
254
+ threads[7].should be_alive
255
+ cc.size.should == 5
256
+ cc[5].should be_nil
257
+ cc[6].should be_nil
258
+ cc[7].should be_nil
259
+
260
+ stop = true
261
+ sleep 0.3
262
+
263
+ threads.each {|t| t.should_not be_alive}
264
+
265
+ @pool.size.should == 5
266
+ @invoked_count.should == 5
267
+ @pool.available_connections.size.should == 5
268
+ @pool.allocated.should be_empty
269
+ end
270
+ end
271
+
272
+ context "ConnectionPool#disconnect" do
273
+ setup do
274
+ @count = 0
275
+ @pool = Sequel::ConnectionPool.new(5) {{:id => @count += 1}}
276
+ end
277
+
278
+ specify "should invoke the given block for each available connection" do
279
+ threads = []
280
+ stop = nil
281
+ 5.times {|i| threads << Thread.new {@pool.hold {|c| while !stop;sleep 0.1;end}}; sleep 0.1}
282
+ while @pool.size < 5
283
+ sleep 0.2
284
+ end
285
+ stop = true
286
+ sleep 1
287
+ threads.each {|t| t.join}
288
+
289
+ @pool.size.should == 5
290
+ @pool.available_connections.size.should == 5
291
+ @pool.available_connections.each {|c| c[:id].should_not be_nil}
292
+ conns = []
293
+ @pool.disconnect {|c| conns << c}
294
+ conns.size.should == 5
295
+ end
296
+
297
+ specify "should remove all available connections" do
298
+ threads = []
299
+ stop = nil
300
+ 5.times {|i| threads << Thread.new {@pool.hold {|c| while !stop;sleep 0.1;end}}; sleep 0.1}
301
+ while @pool.size < 5
302
+ sleep 0.2
303
+ end
304
+ stop = true
305
+ sleep 1
306
+ threads.each {|t| t.join}
307
+
308
+ @pool.size.should == 5
309
+ @pool.disconnect
310
+ @pool.size.should == 0
311
+ end
312
+
313
+ specify "should not touch connections in use" do
314
+ threads = []
315
+ stop = nil
316
+ 5.times {|i| threads << Thread.new {@pool.hold {|c| while !stop;sleep 0.1;end}}; sleep 0.1}
317
+ while @pool.size < 5
318
+ sleep 0.2
319
+ end
320
+ stop = true
321
+ sleep 1
322
+ threads.each {|t| t.join}
323
+
324
+ @pool.size.should == 5
325
+
326
+ @pool.hold do |conn|
327
+ @pool.available_connections.size.should == 4
328
+ @pool.available_connections.each {|c| c.should_not be(conn)}
329
+ conns = []
330
+ @pool.disconnect {|c| conns << c}
331
+ conns.size.should == 4
332
+ end
333
+ @pool.size.should == 1
334
+ end
335
+ end
336
+
337
+ context "SingleThreadedPool" do
338
+ setup do
339
+ @pool = Sequel::SingleThreadedPool.new {1234}
340
+ end
341
+
342
+ specify "should provide a #hold method" do
343
+ conn = nil
344
+ @pool.hold {|c| conn = c}
345
+ conn.should == 1234
346
+ end
347
+
348
+ specify "should provide a #disconnect method" do
349
+ @pool.hold {|c|}
350
+ @pool.conn.should == 1234
351
+ conn = nil
352
+ @pool.disconnect {|c| conn = c}
353
+ conn.should == 1234
354
+ @pool.conn.should be_nil
355
+ end
356
+ end
@@ -0,0 +1,67 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+
3
+ context "Enumerable#send_each" do
4
+ specify "should send the supplied method to each item" do
5
+ a = ['abbc', 'bbccdd', 'hebtre']
6
+ a.send_each(:gsub!, 'b', '_')
7
+ a.should == ['a__c', '__ccdd', 'he_tre']
8
+ end
9
+ end
10
+
11
+ context "Range#interval" do
12
+ specify "should return the interval between the beginning and end of the range" do
13
+ (1..10).interval.should == 9
14
+
15
+ r = rand(100000) + 10
16
+ t1 = Time.now; t2 = t1 + r
17
+ (t1..t2).interval.should == r
18
+ end
19
+ end
20
+
21
+ context "Numeric extensions" do
22
+ setup do
23
+ Sequel::NumericExtensions.enable
24
+ end
25
+
26
+ specify "should support conversion of minutes to seconds" do
27
+ 1.minute.should == 60
28
+ 3.minutes.should == 180
29
+ end
30
+
31
+ specify "should support conversion of hours to seconds" do
32
+ 1.hour.should == 3600
33
+ 3.hours.should == 3600 * 3
34
+ end
35
+
36
+ specify "should support conversion of days to seconds" do
37
+ 1.day.should == 86400
38
+ 3.days.should == 86400 * 3
39
+ end
40
+
41
+ specify "should support conversion of weeks to seconds" do
42
+ 1.week.should == 86400 * 7
43
+ 3.weeks.should == 86400 * 7 * 3
44
+ end
45
+
46
+ specify "should provide #ago functionality" do
47
+ t1 = Time.now
48
+ t2 = 1.day.ago
49
+ t1.should > t2
50
+ ((t1 - t2).to_i - 86400).abs.should < 2
51
+
52
+ t1 = Time.now
53
+ t2 = 1.day.before(t1)
54
+ t2.should == t1 - 1.day
55
+ end
56
+
57
+ specify "should provide #from_now functionality" do
58
+ t1 = Time.now
59
+ t2 = 1.day.from_now
60
+ t1.should < t2
61
+ ((t2 - t1).to_i - 86400).abs.should < 2
62
+
63
+ t1 = Time.now
64
+ t2 = 1.day.since(t1)
65
+ t2.should == t1 + 1.day
66
+ end
67
+ end
@@ -0,0 +1,301 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+
3
+ context "Array#to_sql" do
4
+ specify "should concatenate multiple lines into a single string" do
5
+ "SELECT * \r\nFROM items\r\n WHERE a = 1".split.to_sql. \
6
+ should == 'SELECT * FROM items WHERE a = 1'
7
+ end
8
+
9
+ specify "should remove superfluous white space and line breaks" do
10
+ "\tSELECT * \n FROM items ".split.to_sql. \
11
+ should == 'SELECT * FROM items'
12
+ end
13
+
14
+ specify "should remove ANSI SQL comments" do
15
+ "SELECT * --comment\r\n FROM items\r\n --comment".split.to_sql. \
16
+ should == 'SELECT * FROM items'
17
+ end
18
+
19
+ specify "should remove C-style comments" do
20
+ "SELECT * \r\n /* comment comment\r\n comment\r\n FROM items */\r\n FROM items\r\n--comment".split.to_sql. \
21
+ should == 'SELECT * FROM items'
22
+ end
23
+ end
24
+
25
+ context "String#to_sql" do
26
+ specify "should concatenate multiple lines into a single string" do
27
+ "SELECT * \r\nFROM items\r\nWHERE a = 1".to_sql. \
28
+ should == 'SELECT * FROM items WHERE a = 1'
29
+ end
30
+
31
+ specify "should remove superfluous white space and line breaks" do
32
+ "\tSELECT * \r\n FROM items ".to_sql. \
33
+ should == 'SELECT * FROM items'
34
+ end
35
+
36
+ specify "should remove ANSI SQL comments" do
37
+ "SELECT * --comment \r\n FROM items\r\n --comment".to_sql. \
38
+ should == 'SELECT * FROM items'
39
+ end
40
+
41
+ specify "should remove C-style comments" do
42
+ "SELECT * \r\n/* comment comment\r\ncomment\r\nFROM items */\r\nFROM items\r\n--comment".to_sql. \
43
+ should == 'SELECT * FROM items'
44
+ end
45
+ end
46
+
47
+ context "String#lit" do
48
+ specify "should return an LiteralString object" do
49
+ 'xyz'.lit.should be_a_kind_of(Sequel::LiteralString)
50
+ 'xyz'.lit.to_s.should == 'xyz'
51
+ end
52
+
53
+ specify "should inhibit string literalization" do
54
+ db = Sequel::Database.new
55
+ ds = db[:t]
56
+
57
+ ds.update_sql(:stamp => "NOW()".lit).should == \
58
+ "UPDATE t SET stamp = NOW()"
59
+ end
60
+ end
61
+
62
+ context "String#expr" do
63
+ specify "should return an LiteralString object" do
64
+ 'xyz'.expr.should be_a_kind_of(Sequel::LiteralString)
65
+ 'xyz'.expr.to_s.should == 'xyz'
66
+ end
67
+
68
+ specify "should inhibit string literalization" do
69
+ db = Sequel::Database.new
70
+ ds = db[:t]
71
+
72
+ ds.update_sql(:stamp => "NOW()".expr).should == \
73
+ "UPDATE t SET stamp = NOW()"
74
+ end
75
+ end
76
+
77
+ context "String#split_sql" do
78
+ specify "should split a string containing multiple statements" do
79
+ "DROP TABLE a; DROP TABLE c".split_sql.should == \
80
+ ['DROP TABLE a', 'DROP TABLE c']
81
+ end
82
+
83
+ specify "should remove comments from the string" do
84
+ "DROP TABLE a;/* DROP TABLE b; DROP TABLE c;*/DROP TABLE d".split_sql.should == \
85
+ ['DROP TABLE a', 'DROP TABLE d']
86
+ end
87
+ end
88
+
89
+ context "#DESC/#desc" do
90
+ setup do
91
+ @ds = Sequel::Dataset.new(nil)
92
+ end
93
+
94
+ specify "should format a DESC clause for a column ref" do
95
+ :test.DESC.to_s(@ds).should == 'test DESC'
96
+ :test.desc.to_s(@ds).should == 'test DESC'
97
+
98
+ :items__price.DESC.to_s(@ds).should == 'items.price DESC'
99
+ :items__price.desc.to_s(@ds).should == 'items.price DESC'
100
+ end
101
+
102
+ specify "should format a DESC clause for a function" do
103
+ :avg[:test].DESC.to_s(@ds).should == 'avg(test) DESC'
104
+ :avg[:test].desc.to_s(@ds).should == 'avg(test) DESC'
105
+ end
106
+
107
+ specify "should format a DESC clause for a literal value" do
108
+ 1.DESC.to_s(@ds).should == '1 DESC'
109
+ 'abc'.desc.to_s(@ds).should == "'abc' DESC"
110
+ end
111
+ end
112
+
113
+ context "#ASC/#asc" do
114
+ setup do
115
+ @ds = Sequel::Dataset.new(nil)
116
+ end
117
+
118
+ specify "should format a ASC clause for a column ref" do
119
+ :test.ASC.to_s(@ds).should == 'test ASC'
120
+ :test.asc.to_s(@ds).should == 'test ASC'
121
+
122
+ :items__price.ASC.to_s(@ds).should == 'items.price ASC'
123
+ :items__price.asc.to_s(@ds).should == 'items.price ASC'
124
+ end
125
+
126
+ specify "should format a ASC clause for a function" do
127
+ :avg[:test].ASC.to_s(@ds).should == 'avg(test) ASC'
128
+ :avg[:test].asc.to_s(@ds).should == 'avg(test) ASC'
129
+ end
130
+
131
+ specify "should format a ASC clause for a literal value" do
132
+ 1.ASC.to_s(@ds).should == '1 ASC'
133
+ 'abc'.asc.to_s(@ds).should == "'abc' ASC"
134
+ end
135
+ end
136
+
137
+ context "#AS/#as" do
138
+ setup do
139
+ @ds = Sequel::Dataset.new(nil)
140
+ end
141
+
142
+ specify "should format a AS clause for a column ref" do
143
+ :test.AS(:t).to_s(@ds).should == 'test AS t'
144
+ :test.as(:t).to_s(@ds).should == 'test AS t'
145
+
146
+ :items__price.AS(:p).to_s(@ds).should == 'items.price AS p'
147
+ :items__price.as(:p).to_s(@ds).should == 'items.price AS p'
148
+ end
149
+
150
+ specify "should format a AS clause for a function" do
151
+ :avg[:test].AS(:avg).to_s(@ds).should == 'avg(test) AS avg'
152
+ :avg[:test].as(:avg).to_s(@ds).should == 'avg(test) AS avg'
153
+ end
154
+
155
+ specify "should format a AS clause for a literal value" do
156
+ 1.AS(:one).to_s(@ds).should == '1 AS one'
157
+ 'abc'.as(:abc).to_s(@ds).should == "'abc' AS abc"
158
+ end
159
+ end
160
+
161
+ context "Column references" do
162
+ setup do
163
+ @c = Class.new(Sequel::Dataset) do
164
+ def quote_column_ref(c); "`#{c}`"; end
165
+ end
166
+ @ds = @c.new(nil)
167
+ end
168
+
169
+ specify "should be quoted properly" do
170
+ @ds.literal(:xyz).should == "`xyz`"
171
+ @ds.literal(:xyz__abc).should == "xyz.`abc`"
172
+
173
+ @ds.literal(:xyz.as(:x)).should == "`xyz` AS `x`"
174
+ @ds.literal(:xyz__abc.as(:x)).should == "xyz.`abc` AS `x`"
175
+
176
+ @ds.literal(:xyz___x).should == "`xyz` AS `x`"
177
+ @ds.literal(:xyz__abc___x).should == "xyz.`abc` AS `x`"
178
+ end
179
+
180
+ specify "should be quoted properly in SQL functions" do
181
+ @ds.literal(:avg[:xyz]).should == "avg(`xyz`)"
182
+ @ds.literal(:avg[:xyz, 1]).should == "avg(`xyz`, 1)"
183
+ @ds.literal(:avg[:xyz].as(:a)).should == "avg(`xyz`) AS `a`"
184
+ end
185
+
186
+ specify "should be quoted properly in ASC/DESC clauses" do
187
+ @ds.literal(:xyz.ASC).should == "`xyz` ASC"
188
+ @ds.literal(:avg[:xyz, 1].desc).should == "avg(`xyz`, 1) DESC"
189
+ end
190
+
191
+ specify "should be quoted properly in a cast function" do
192
+ @ds.literal(:x.cast_as(:integer)).should == "cast(`x` AS integer)"
193
+ @ds.literal(:x__y.cast_as(:varchar[20])).should == "cast(x.`y` AS varchar(20))"
194
+ end
195
+ end
196
+
197
+ context "Symbol#ALL/#all" do
198
+ setup do
199
+ @ds = Sequel::Dataset.new(nil)
200
+ end
201
+
202
+ specify "should format a qualified wildcard" do
203
+ :xyz.ALL.to_s(@ds).should == 'xyz.*'
204
+ :abc.all.to_s(@ds).should == 'abc.*'
205
+ end
206
+ end
207
+
208
+ context "Symbol#to_column_ref" do
209
+ setup do
210
+ @ds = Sequel::Dataset.new(nil)
211
+ end
212
+
213
+ specify "should convert qualified symbol notation into dot notation" do
214
+ :abc__def.to_column_ref(@ds).should == 'abc.def'
215
+ end
216
+
217
+ specify "should convert AS symbol notation into SQL AS notation" do
218
+ :xyz___x.to_column_ref(@ds).should == 'xyz AS x'
219
+ :abc__def___x.to_column_ref(@ds).should == 'abc.def AS x'
220
+ end
221
+
222
+ specify "should support names with digits" do
223
+ :abc2.to_column_ref(@ds).should == 'abc2'
224
+ :xx__yy3.to_column_ref(@ds).should == 'xx.yy3'
225
+ :ab34__temp3_4ax.to_column_ref(@ds).should == 'ab34.temp3_4ax'
226
+ :x1___y2.to_column_ref(@ds).should == 'x1 AS y2'
227
+ :abc2__def3___ggg4.to_column_ref(@ds).should == 'abc2.def3 AS ggg4'
228
+ end
229
+
230
+ specify "should support upper case and lower case" do
231
+ :ABC.to_column_ref(@ds).should == 'ABC'
232
+ :Zvashtoy__aBcD.to_column_ref(@ds).should == 'Zvashtoy.aBcD'
233
+ end
234
+ end
235
+
236
+ context "Symbol" do
237
+ setup do
238
+ @ds = Sequel::Dataset.new(nil)
239
+ end
240
+
241
+ specify "should support MIN for specifying min function" do
242
+ :abc__def.MIN.to_s(@ds).should == 'min(abc.def)'
243
+ end
244
+
245
+ specify "should support MAX for specifying max function" do
246
+ :abc__def.MAX.to_s(@ds).should == 'max(abc.def)'
247
+ end
248
+
249
+ specify "should support SUM for specifying sum function" do
250
+ :abc__def.SUM.to_s(@ds).should == 'sum(abc.def)'
251
+ end
252
+
253
+ specify "should support AVG for specifying avg function" do
254
+ :abc__def.AVG.to_s(@ds).should == 'avg(abc.def)'
255
+ end
256
+
257
+ specify "should support COUNT for specifying count function" do
258
+ :abc__def.COUNT.to_s(@ds).should == 'count(abc.def)'
259
+ end
260
+
261
+ specify "should support any other function using upper case letters" do
262
+ :abc__def.DADA.to_s(@ds).should == 'dada(abc.def)'
263
+ end
264
+
265
+ specify "should support upper case outer functions" do
266
+ :COUNT['1'].to_s(@ds).should == "COUNT('1')"
267
+ end
268
+
269
+ specify "should inhibit string literalization" do
270
+ db = Sequel::Database.new
271
+ ds = db[:t]
272
+ ds.select(:COUNT['1']).sql.should == "SELECT COUNT('1') FROM t"
273
+ end
274
+
275
+ specify "should support cast function" do
276
+ :abc.cast_as(:integer).to_s(@ds).should == "cast(abc AS integer)"
277
+ end
278
+
279
+ specify "should raise NoMethodError for non-uppercase invalid methods" do
280
+ proc {:abc.dfaxs}.should raise_error(NoMethodError)
281
+ end
282
+
283
+ specify "should support subscript access using | operator" do
284
+ (:abc|1).to_s(@ds).should == 'abc[1]'
285
+ (:abc|[1]).to_s(@ds).should == 'abc[1]'
286
+ (:abc|[1, 2]).to_s(@ds).should == 'abc[1, 2]'
287
+ (:abc|1|2).to_s(@ds).should == 'abc[1, 2]'
288
+ end
289
+ end
290
+
291
+ context "String#to_time" do
292
+ specify "should convert the string into a Time object" do
293
+ "2007-07-11".to_time.should == Time.parse("2007-07-11")
294
+ "06:30".to_time.should == Time.parse("06:30")
295
+ end
296
+
297
+ specify "should raise Error::InvalidValue for an invalid time" do
298
+ proc {'0000-00-00'.to_time}.should raise_error(Sequel::Error::InvalidValue)
299
+ end
300
+ end
301
+