sequel_core 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.
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
+