sequel_core 1.5.1 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. data/CHANGELOG +116 -0
  2. data/COPYING +19 -19
  3. data/README +83 -32
  4. data/Rakefile +9 -20
  5. data/bin/sequel +43 -112
  6. data/doc/cheat_sheet.rdoc +225 -0
  7. data/doc/dataset_filtering.rdoc +257 -0
  8. data/lib/sequel_core/adapters/adapter_skeleton.rb +4 -2
  9. data/lib/sequel_core/adapters/ado.rb +3 -1
  10. data/lib/sequel_core/adapters/db2.rb +4 -2
  11. data/lib/sequel_core/adapters/dbi.rb +127 -113
  12. data/lib/sequel_core/adapters/informix.rb +4 -2
  13. data/lib/sequel_core/adapters/jdbc.rb +5 -3
  14. data/lib/sequel_core/adapters/mysql.rb +112 -46
  15. data/lib/sequel_core/adapters/odbc.rb +5 -7
  16. data/lib/sequel_core/adapters/odbc_mssql.rb +12 -3
  17. data/lib/sequel_core/adapters/openbase.rb +3 -1
  18. data/lib/sequel_core/adapters/oracle.rb +11 -9
  19. data/lib/sequel_core/adapters/postgres.rb +261 -262
  20. data/lib/sequel_core/adapters/sqlite.rb +72 -22
  21. data/lib/sequel_core/connection_pool.rb +140 -73
  22. data/lib/sequel_core/core_ext.rb +201 -66
  23. data/lib/sequel_core/core_sql.rb +123 -153
  24. data/lib/sequel_core/database/schema.rb +156 -0
  25. data/lib/sequel_core/database.rb +321 -338
  26. data/lib/sequel_core/dataset/callback.rb +11 -12
  27. data/lib/sequel_core/dataset/convenience.rb +213 -240
  28. data/lib/sequel_core/dataset/pagination.rb +58 -43
  29. data/lib/sequel_core/dataset/parse_tree_sequelizer.rb +331 -0
  30. data/lib/sequel_core/dataset/query.rb +41 -0
  31. data/lib/sequel_core/dataset/schema.rb +15 -0
  32. data/lib/sequel_core/dataset/sequelizer.rb +41 -373
  33. data/lib/sequel_core/dataset/sql.rb +741 -632
  34. data/lib/sequel_core/dataset.rb +183 -168
  35. data/lib/sequel_core/deprecated.rb +1 -169
  36. data/lib/sequel_core/exceptions.rb +24 -19
  37. data/lib/sequel_core/migration.rb +44 -52
  38. data/lib/sequel_core/object_graph.rb +43 -42
  39. data/lib/sequel_core/pretty_table.rb +71 -76
  40. data/lib/sequel_core/schema/generator.rb +163 -105
  41. data/lib/sequel_core/schema/sql.rb +250 -93
  42. data/lib/sequel_core/schema.rb +2 -8
  43. data/lib/sequel_core/sql.rb +394 -0
  44. data/lib/sequel_core/worker.rb +37 -27
  45. data/lib/sequel_core.rb +99 -45
  46. data/spec/adapters/informix_spec.rb +0 -1
  47. data/spec/adapters/mysql_spec.rb +177 -124
  48. data/spec/adapters/oracle_spec.rb +0 -1
  49. data/spec/adapters/postgres_spec.rb +98 -58
  50. data/spec/adapters/sqlite_spec.rb +45 -4
  51. data/spec/blockless_filters_spec.rb +269 -0
  52. data/spec/connection_pool_spec.rb +21 -18
  53. data/spec/core_ext_spec.rb +169 -19
  54. data/spec/core_sql_spec.rb +56 -49
  55. data/spec/database_spec.rb +78 -17
  56. data/spec/dataset_spec.rb +300 -428
  57. data/spec/migration_spec.rb +1 -1
  58. data/spec/object_graph_spec.rb +5 -11
  59. data/spec/rcov.opts +1 -1
  60. data/spec/schema_generator_spec.rb +16 -4
  61. data/spec/schema_spec.rb +89 -10
  62. data/spec/sequelizer_spec.rb +56 -56
  63. data/spec/spec.opts +0 -5
  64. data/spec/spec_config.rb +7 -0
  65. data/spec/spec_config.rb.example +5 -5
  66. data/spec/spec_helper.rb +6 -0
  67. data/spec/worker_spec.rb +1 -1
  68. metadata +78 -63
@@ -1,6 +1,4 @@
1
- require File.join(File.dirname(__FILE__), '../../lib/sequel_core')
2
1
  require File.join(File.dirname(__FILE__), '../spec_helper.rb')
3
- require 'logger'
4
2
 
5
3
  unless defined?(MYSQL_DB)
6
4
  MYSQL_URL = (ENV['SEQUEL_MY_SPEC_DB']||'mysql://root@localhost/sandbox') unless defined? MYSQL_URL
@@ -11,18 +9,28 @@ unless defined?(MYSQL_SOCKET_FILE)
11
9
  end
12
10
 
13
11
  MYSQL_URI = URI.parse(MYSQL_DB.uri)
14
- MYSQL_DB_NAME = MYSQL_URI.path =~ /\/(.*)/ && $1
12
+ MYSQL_DB_NAME = (m = /\/(.*)/.match(MYSQL_URI.path)) && m[1]
15
13
 
16
- MYSQL_DB.drop_table(:items) if MYSQL_DB.table_exists?(:items)
17
- MYSQL_DB.drop_table(:test2) if MYSQL_DB.table_exists?(:test2)
18
- MYSQL_DB.create_table :items do
14
+ MYSQL_DB.create_table! :items do
19
15
  text :name
20
16
  integer :value, :index => true
21
17
  end
22
- MYSQL_DB.create_table :test2 do
18
+ MYSQL_DB.create_table! :test2 do
23
19
  text :name
24
20
  integer :value
25
21
  end
22
+ MYSQL_DB.create_table! :booltest do
23
+ tinyint :value
24
+ end
25
+ class Sequel::MySQL::Database
26
+ attr_accessor :sqls
27
+ end
28
+ logger = Object.new
29
+ def logger.method_missing(m, msg)
30
+ MYSQL_DB.sqls << msg
31
+ end
32
+ MYSQL_DB.logger = logger
33
+ MYSQL_DB.sqls = []
26
34
 
27
35
  context "A MySQL database" do
28
36
  setup do
@@ -51,12 +59,25 @@ context "A MySQL database" do
51
59
  {:id => 3, :name => 'ghi'}
52
60
  ]
53
61
  end
62
+
63
+ specify "should convert Mysql::Errors to Sequel::Errors" do
64
+ proc{@db << "SELECT 1 + blah;"}.should raise_error(Sequel::Error)
65
+ end
66
+
67
+ specify "should correctly parse the schema" do
68
+ @db.schema(:booltest, :reload=>true).should == [[:value, {:type=>:boolean, :allow_null=>true, :max_chars=>nil, :default=>nil, :db_type=>"tinyint", :numeric_precision=>3}]]
69
+ end
70
+
71
+ specify "should get the schema all database tables if no table name is used" do
72
+ @db.schema(:booltest, :reload=>true).should == @db.schema(nil, :reload=>true)[:booltest]
73
+ end
54
74
  end
55
75
 
56
76
  context "A MySQL dataset" do
57
77
  setup do
58
78
  @d = MYSQL_DB[:items]
59
79
  @d.delete # remove all records
80
+ MYSQL_DB.sqls.clear
60
81
  end
61
82
 
62
83
  specify "should return the correct record count" do
@@ -107,72 +128,74 @@ context "A MySQL dataset" do
107
128
  proc {@d.literal(false)}.should_not raise_error
108
129
  end
109
130
 
110
- specify "should quote columns using back-ticks" do
131
+ specify "should quote columns and tables using back-ticks if quoting identifiers" do
132
+ @d.quote_identifiers = true
111
133
  @d.select(:name).sql.should == \
112
- 'SELECT `name` FROM items'
134
+ 'SELECT `name` FROM `items`'
113
135
 
114
136
  @d.select('COUNT(*)'.lit).sql.should == \
115
- 'SELECT COUNT(*) FROM items'
137
+ 'SELECT COUNT(*) FROM `items`'
116
138
 
117
139
  @d.select(:max[:value]).sql.should == \
118
- 'SELECT max(`value`) FROM items'
140
+ 'SELECT max(`value`) FROM `items`'
119
141
 
120
142
  @d.select(:NOW[]).sql.should == \
121
- 'SELECT NOW() FROM items'
143
+ 'SELECT NOW() FROM `items`'
122
144
 
123
145
  @d.select(:max[:items__value]).sql.should == \
124
- 'SELECT max(items.`value`) FROM items'
146
+ 'SELECT max(`items`.`value`) FROM `items`'
125
147
 
126
148
  @d.order(:name.desc).sql.should == \
127
- 'SELECT * FROM items ORDER BY `name` DESC'
149
+ 'SELECT * FROM `items` ORDER BY `name` DESC'
128
150
 
129
151
  @d.select('items.name AS item_name'.lit).sql.should == \
130
- 'SELECT items.name AS item_name FROM items'
152
+ 'SELECT items.name AS item_name FROM `items`'
131
153
 
132
154
  @d.select('`name`'.lit).sql.should == \
133
- 'SELECT `name` FROM items'
155
+ 'SELECT `name` FROM `items`'
134
156
 
135
157
  @d.select('max(items.`name`) AS `max_name`'.lit).sql.should == \
136
- 'SELECT max(items.`name`) AS `max_name` FROM items'
158
+ 'SELECT max(items.`name`) AS `max_name` FROM `items`'
137
159
 
138
160
  @d.select(:test[:abc, 'hello']).sql.should == \
139
- "SELECT test(`abc`, 'hello') FROM items"
161
+ "SELECT test(`abc`, 'hello') FROM `items`"
140
162
 
141
163
  @d.select(:test[:abc__def, 'hello']).sql.should == \
142
- "SELECT test(abc.`def`, 'hello') FROM items"
164
+ "SELECT test(`abc`.`def`, 'hello') FROM `items`"
143
165
 
144
166
  @d.select(:test[:abc__def, 'hello'].as(:x2)).sql.should == \
145
- "SELECT test(abc.`def`, 'hello') AS `x2` FROM items"
167
+ "SELECT test(`abc`.`def`, 'hello') AS `x2` FROM `items`"
146
168
 
147
169
  @d.insert_sql(:value => 333).should == \
148
- 'INSERT INTO items (`value`) VALUES (333)'
170
+ 'INSERT INTO `items` (`value`) VALUES (333)'
149
171
 
150
172
  @d.insert_sql(:x => :y).should == \
151
- 'INSERT INTO items (`x`) VALUES (`y`)'
173
+ 'INSERT INTO `items` (`x`) VALUES (`y`)'
152
174
  end
153
175
 
154
176
  specify "should quote fields correctly when reversing the order" do
177
+ @d.quote_identifiers = true
155
178
  @d.reverse_order(:name).sql.should == \
156
- 'SELECT * FROM items ORDER BY `name` DESC'
179
+ 'SELECT * FROM `items` ORDER BY `name` DESC'
157
180
 
158
181
  @d.reverse_order(:name.desc).sql.should == \
159
- 'SELECT * FROM items ORDER BY `name`'
182
+ 'SELECT * FROM `items` ORDER BY `name`'
160
183
 
161
184
  @d.reverse_order(:name, :test.desc).sql.should == \
162
- 'SELECT * FROM items ORDER BY `name` DESC, `test`'
185
+ 'SELECT * FROM `items` ORDER BY `name` DESC, `test`'
163
186
 
164
187
  @d.reverse_order(:name.desc, :test).sql.should == \
165
- 'SELECT * FROM items ORDER BY `name`, `test` DESC'
188
+ 'SELECT * FROM `items` ORDER BY `name`, `test` DESC'
166
189
  end
167
190
 
168
191
  specify "should support ORDER clause in UPDATE statements" do
169
192
  @d.order(:name).update_sql(:value => 1).should == \
170
- 'UPDATE items SET `value` = 1 ORDER BY `name`'
193
+ 'UPDATE items SET value = 1 ORDER BY name'
171
194
  end
172
195
 
173
196
  specify "should support LIMIT clause in UPDATE statements" do
174
197
  @d.limit(10).update_sql(:value => 1).should == \
175
- 'UPDATE items SET `value` = 1 LIMIT 10'
198
+ 'UPDATE items SET value = 1 LIMIT 10'
176
199
  end
177
200
 
178
201
  specify "should support transactions" do
@@ -183,6 +206,29 @@ context "A MySQL dataset" do
183
206
  @d.count.should == 1
184
207
  end
185
208
 
209
+ specify "should correctly rollback transactions" do
210
+ proc do
211
+ MYSQL_DB.transaction do
212
+ @d << {:name => 'abc'}
213
+ raise Interrupt, 'asdf'
214
+ end
215
+ end.should raise_error(Interrupt)
216
+
217
+ MYSQL_DB.sqls.should == ['BEGIN', "INSERT INTO items (name) VALUES ('abc')", 'ROLLBACK']
218
+ end
219
+
220
+ specify "should handle returning inside of the block by committing" do
221
+ def MYSQL_DB.ret_commit
222
+ transaction do
223
+ self[:items] << {:name => 'abc'}
224
+ return
225
+ self[:items] << {:name => 'd'}
226
+ end
227
+ end
228
+ MYSQL_DB.ret_commit
229
+ MYSQL_DB.sqls.should == ['BEGIN', "INSERT INTO items (name) VALUES ('abc')", 'COMMIT']
230
+ end
231
+
186
232
  specify "should support regexps" do
187
233
  @d << {:name => 'abc', :value => 1}
188
234
  @d << {:name => 'bcd', :value => 2}
@@ -204,6 +250,7 @@ context "MySQL datasets" do
204
250
  end
205
251
 
206
252
  specify "should correctly quote column references" do
253
+ @d.quote_identifiers = true
207
254
  market = 'ICE'
208
255
  ack_stamp = Time.now - 15 * 60 # 15 minutes ago
209
256
  @d.query do
@@ -214,7 +261,16 @@ context "MySQL datasets" do
214
261
  end
215
262
  group_by :minute[:from_unixtime[:ack]]
216
263
  end.sql.should == \
217
- "SELECT `market`, minute(from_unixtime(`ack`)) AS `minute` FROM orders WHERE ((`ack` > #{@d.literal(ack_stamp)}) AND (`market` = 'ICE')) GROUP BY minute(from_unixtime(`ack`))"
264
+ "SELECT `market`, minute(from_unixtime(`ack`)) AS `minute` FROM `orders` WHERE ((`ack` > #{@d.literal(ack_stamp)}) AND (`market` = 'ICE')) GROUP BY minute(from_unixtime(`ack`))"
265
+ end
266
+
267
+ specify "should accept and return tinyints as bools" do
268
+ MYSQL_DB[:booltest].delete
269
+ MYSQL_DB[:booltest] << {:value=>true}
270
+ MYSQL_DB[:booltest].all.should == [{:value=>true}]
271
+ MYSQL_DB[:booltest].delete
272
+ MYSQL_DB[:booltest] << {:value=>false}
273
+ MYSQL_DB[:booltest].all.should == [{:value=>false}]
218
274
  end
219
275
  end
220
276
 
@@ -240,67 +296,67 @@ context "MySQL join expressions" do
240
296
  end
241
297
 
242
298
  specify "should raise error for :full_outer join requests." do
243
- lambda{@ds.join_expr(:full_outer, :nodes)}.should raise_error(Sequel::Error::InvalidJoinType)
299
+ lambda{@ds.join_table(:full_outer, :nodes)}.should raise_error(Sequel::Error::InvalidJoinType)
244
300
  end
245
301
  specify "should support natural left joins" do
246
- @ds.join_expr(:natural_left, :nodes).should == \
247
- 'NATURAL LEFT JOIN nodes'
302
+ @ds.join_table(:natural_left, :nodes).sql.should == \
303
+ 'SELECT * FROM nodes NATURAL LEFT JOIN nodes'
248
304
  end
249
305
  specify "should support natural right joins" do
250
- @ds.join_expr(:natural_right, :nodes).should == \
251
- 'NATURAL RIGHT JOIN nodes'
306
+ @ds.join_table(:natural_right, :nodes).sql.should == \
307
+ 'SELECT * FROM nodes NATURAL RIGHT JOIN nodes'
252
308
  end
253
309
  specify "should support natural left outer joins" do
254
- @ds.join_expr(:natural_left_outer, :nodes).should == \
255
- 'NATURAL LEFT OUTER JOIN nodes'
310
+ @ds.join_table(:natural_left_outer, :nodes).sql.should == \
311
+ 'SELECT * FROM nodes NATURAL LEFT OUTER JOIN nodes'
256
312
  end
257
313
  specify "should support natural right outer joins" do
258
- @ds.join_expr(:natural_right_outer, :nodes).should == \
259
- 'NATURAL RIGHT OUTER JOIN nodes'
314
+ @ds.join_table(:natural_right_outer, :nodes).sql.should == \
315
+ 'SELECT * FROM nodes NATURAL RIGHT OUTER JOIN nodes'
260
316
  end
261
317
  specify "should support natural inner joins" do
262
- @ds.join_expr(:natural_inner, :nodes).should == \
263
- 'NATURAL LEFT JOIN nodes'
318
+ @ds.join_table(:natural_inner, :nodes).sql.should == \
319
+ 'SELECT * FROM nodes NATURAL LEFT JOIN nodes'
264
320
  end
265
321
  specify "should support cross joins (equivalent to inner join in MySQL, not in std SQL)" do
266
- @ds.join_expr(:cross, :nodes).should == \
267
- 'INNER JOIN nodes'
322
+ @ds.join_table(:cross, :nodes).sql.should == \
323
+ 'SELECT * FROM nodes INNER JOIN nodes'
268
324
  end
269
325
  specify "should support straight joins (force left table to be read before right)" do
270
- @ds.join_expr(:straight, :nodes).should == \
271
- 'STRAIGHT_JOIN nodes'
326
+ @ds.join_table(:straight, :nodes).sql.should == \
327
+ 'SELECT * FROM nodes STRAIGHT_JOIN nodes'
272
328
  end
273
329
  specify "should support natural joins on multiple tables." do
274
- @ds.join_expr(:natural_left_outer, [:nodes, :branches]).should == \
275
- 'NATURAL LEFT OUTER JOIN ( `nodes`, `branches` )'
330
+ @ds.join_table(:natural_left_outer, [:nodes, :branches]).sql.should == \
331
+ 'SELECT * FROM nodes NATURAL LEFT OUTER JOIN ( nodes, branches )'
276
332
  end
277
333
  specify "should support straight joins on multiple tables." do
278
- @ds.join_expr(:straight, [:nodes,:branches]).should == \
279
- 'STRAIGHT_JOIN ( `nodes`, `branches` )'
334
+ @ds.join_table(:straight, [:nodes,:branches]).sql.should == \
335
+ 'SELECT * FROM nodes STRAIGHT_JOIN ( nodes, branches )'
280
336
  end
281
337
  end
282
338
 
283
339
  context "Joined MySQL dataset" do
284
340
  setup do
285
- @ds = MYSQL_DB[:nodes].join(:attributes, :node_id => :id)
286
- @ds2 = MYSQL_DB[:nodes]
341
+ @ds = MYSQL_DB[:nodes]
287
342
  end
288
343
 
289
344
  specify "should quote fields correctly" do
290
- @ds.sql.should == \
291
- "SELECT * FROM nodes INNER JOIN attributes ON (attributes.`node_id` = nodes.`id`)"
345
+ @ds.quote_identifiers = true
346
+ @ds.join(:attributes, :node_id => :id).sql.should == \
347
+ "SELECT * FROM `nodes` INNER JOIN `attributes` ON (`attributes`.`node_id` = `nodes`.`id`)"
292
348
  end
293
349
 
294
350
  specify "should allow a having clause on ungrouped datasets" do
295
- proc {@ds2.having('blah')}.should_not raise_error
351
+ proc {@ds.having('blah')}.should_not raise_error
296
352
 
297
- @ds2.having('blah').sql.should == \
298
- "SELECT * FROM nodes HAVING blah"
353
+ @ds.having('blah').sql.should == \
354
+ "SELECT * FROM nodes HAVING (blah)"
299
355
  end
300
356
 
301
357
  specify "should put a having clause before an order by clause" do
302
- @ds2.order(:aaa).having(:bbb => :ccc).sql.should == \
303
- "SELECT * FROM nodes HAVING (`bbb` = `ccc`) ORDER BY `aaa`"
358
+ @ds.order(:aaa).having(:bbb => :ccc).sql.should == \
359
+ "SELECT * FROM nodes HAVING (bbb = ccc) ORDER BY aaa"
304
360
  end
305
361
  end
306
362
 
@@ -376,7 +432,7 @@ context "A MySQL database" do
376
432
  end
377
433
  statements = @db.create_table_sql_list(:items, *g.create_info)
378
434
  statements.should == [
379
- "CREATE TABLE items (`active1` boolean DEFAULT 1, `active2` boolean DEFAULT 0)"
435
+ "CREATE TABLE items (active1 boolean DEFAULT 1, active2 boolean DEFAULT 0)"
380
436
  ]
381
437
  end
382
438
 
@@ -386,7 +442,7 @@ context "A MySQL database" do
386
442
  :null => false, :on_delete => :cascade
387
443
  end
388
444
  @db.create_table_sql_list(:items, *g.create_info).should == [
389
- "CREATE TABLE items (`p_id` integer NOT NULL, FOREIGN KEY (`p_id`) REFERENCES users(`id`) ON DELETE CASCADE)"
445
+ "CREATE TABLE items (p_id integer NOT NULL, FOREIGN KEY (p_id) REFERENCES users(id) ON DELETE CASCADE)"
390
446
  ]
391
447
  end
392
448
 
@@ -402,20 +458,23 @@ context "A MySQL database" do
402
458
  end
403
459
  end
404
460
 
405
- context "A MySQL database" do
406
- specify "should accept a socket option" do
407
- db = Sequel.mysql(MYSQL_DB_NAME, :host => 'localhost', :user => 'root', :socket => MYSQL_SOCKET_FILE)
408
- proc {db.test_connection}.should_not raise_error
409
- end
410
-
411
- specify "should accept a socket option without host option" do
412
- db = Sequel.mysql(MYSQL_DB_NAME, :user => 'root', :socket => MYSQL_SOCKET_FILE)
413
- proc {db.test_connection}.should_not raise_error
414
- end
415
-
416
- specify "should fail to connect with invalid socket" do
417
- db = Sequel.mysql(MYSQL_DB_NAME, :host => 'localhost', :user => 'root', :socket => 'blah')
418
- proc {db.test_connection}.should raise_error
461
+ # Socket tests should only be run if the MySQL server is on localhost
462
+ if %w'localhost 127.0.0.1 ::1'.include? MYSQL_URI.host
463
+ context "A MySQL database" do
464
+ specify "should accept a socket option" do
465
+ db = Sequel.mysql(MYSQL_DB_NAME, :host => 'localhost', :user => 'root', :socket => MYSQL_SOCKET_FILE)
466
+ proc {db.test_connection}.should_not raise_error
467
+ end
468
+
469
+ specify "should accept a socket option without host option" do
470
+ db = Sequel.mysql(MYSQL_DB_NAME, :user => 'root', :socket => MYSQL_SOCKET_FILE)
471
+ proc {db.test_connection}.should_not raise_error
472
+ end
473
+
474
+ specify "should fail to connect with invalid socket" do
475
+ db = Sequel.mysql(MYSQL_DB_NAME, :host => 'localhost', :user => 'root', :socket => 'blah')
476
+ proc {db.test_connection}.should raise_error
477
+ end
419
478
  end
420
479
  end
421
480
 
@@ -452,20 +511,20 @@ context "A MySQL database" do
452
511
  full_text_index [:title, :body]
453
512
  end
454
513
  MYSQL_DB.create_table_sql_list(:posts, *g.create_info).should == [
455
- "CREATE TABLE posts (`title` text, `body` text)",
456
- "CREATE FULLTEXT INDEX posts_title_body_index ON posts (`title`, `body`)"
514
+ "CREATE TABLE posts (title text, body text)",
515
+ "CREATE FULLTEXT INDEX posts_title_body_index ON posts (title, body)"
457
516
  ]
458
517
  end
459
518
 
460
519
  specify "should support full_text_search" do
461
520
  MYSQL_DB[:posts].full_text_search(:title, 'ruby').sql.should ==
462
- "SELECT * FROM posts WHERE (MATCH (`title`) AGAINST ('ruby'))"
521
+ "SELECT * FROM posts WHERE (MATCH (title) AGAINST ('ruby'))"
463
522
 
464
523
  MYSQL_DB[:posts].full_text_search([:title, :body], ['ruby', 'sequel']).sql.should ==
465
- "SELECT * FROM posts WHERE (MATCH (`title`, `body`) AGAINST ('ruby', 'sequel'))"
524
+ "SELECT * FROM posts WHERE (MATCH (title, body) AGAINST ('ruby', 'sequel'))"
466
525
 
467
526
  MYSQL_DB[:posts].full_text_search(:title, '+ruby -rails', :boolean => true).sql.should ==
468
- "SELECT * FROM posts WHERE (MATCH (`title`) AGAINST ('+ruby -rails' IN BOOLEAN MODE))"
527
+ "SELECT * FROM posts WHERE (MATCH (title) AGAINST ('+ruby -rails' IN BOOLEAN MODE))"
469
528
  end
470
529
 
471
530
  specify "should support spatial indexes" do
@@ -474,8 +533,8 @@ context "A MySQL database" do
474
533
  spatial_index [:geom]
475
534
  end
476
535
  MYSQL_DB.create_table_sql_list(:posts, *g.create_info).should == [
477
- "CREATE TABLE posts (`geom` point)",
478
- "CREATE SPATIAL INDEX posts_geom_index ON posts (`geom`)"
536
+ "CREATE TABLE posts (geom point)",
537
+ "CREATE SPATIAL INDEX posts_geom_index ON posts (geom)"
479
538
  ]
480
539
  end
481
540
 
@@ -485,8 +544,8 @@ context "A MySQL database" do
485
544
  index :title, :type => :hash
486
545
  end
487
546
  MYSQL_DB.create_table_sql_list(:posts, *g.create_info).should == [
488
- "CREATE TABLE posts (`title` text)",
489
- "CREATE INDEX posts_title_index ON posts (`title`) USING hash"
547
+ "CREATE TABLE posts (title text)",
548
+ "CREATE INDEX posts_title_index ON posts (title) USING hash"
490
549
  ]
491
550
  end
492
551
 
@@ -496,45 +555,12 @@ context "A MySQL database" do
496
555
  index :title, :type => :hash, :unique => true
497
556
  end
498
557
  MYSQL_DB.create_table_sql_list(:posts, *g.create_info).should == [
499
- "CREATE TABLE posts (`title` text)",
500
- "CREATE UNIQUE INDEX posts_title_index ON posts (`title`) USING hash"
558
+ "CREATE TABLE posts (title text)",
559
+ "CREATE UNIQUE INDEX posts_title_index ON posts (title) USING hash"
501
560
  ]
502
561
  end
503
562
  end
504
563
 
505
- class Sequel::MySQL::Database
506
- alias_method :orig_execute, :execute
507
- attr_accessor :sqls
508
- def execute(sql, &block)
509
- @sqls ||= []; @sqls << sql
510
- orig_execute(sql, &block)
511
- end
512
-
513
- def transaction
514
- @pool.hold do |conn|
515
- @transactions ||= []
516
- if @transactions.include? Thread.current
517
- return yield(conn)
518
- end
519
- @sqls ||= []; @sqls << SQL_BEGIN
520
- conn.query(SQL_BEGIN)
521
- begin
522
- @transactions << Thread.current
523
- result = yield(conn)
524
- @sqls ||= []; @sqls << SQL_COMMIT
525
- conn.query(SQL_COMMIT)
526
- result
527
- rescue => e
528
- @sqls ||= []; @sqls << SQL_ROLLBACK
529
- conn.query(SQL_ROLLBACK)
530
- raise e unless Sequel::Error::Rollback === e
531
- ensure
532
- @transactions.delete(Thread.current)
533
- end
534
- end
535
- end
536
- end
537
-
538
564
  context "MySQL::Dataset#insert" do
539
565
  setup do
540
566
  @d = MYSQL_DB[:items]
@@ -555,7 +581,7 @@ context "MySQL::Dataset#insert" do
555
581
  end
556
582
 
557
583
  specify "should insert record with default values when empty hash given" do
558
- @d.insert {}
584
+ @d.insert({})
559
585
 
560
586
  MYSQL_DB.sqls.should == [
561
587
  "INSERT INTO items () VALUES ()"
@@ -591,7 +617,7 @@ context "MySQL::Dataset#multi_insert" do
591
617
 
592
618
  MYSQL_DB.sqls.should == [
593
619
  'BEGIN',
594
- "INSERT INTO items (`name`) VALUES ('abc'), ('def')",
620
+ "INSERT INTO items (name) VALUES ('abc'), ('def')",
595
621
  'COMMIT'
596
622
  ]
597
623
 
@@ -606,10 +632,10 @@ context "MySQL::Dataset#multi_insert" do
606
632
 
607
633
  MYSQL_DB.sqls.should == [
608
634
  'BEGIN',
609
- "INSERT INTO items (`value`) VALUES (1), (2)",
635
+ "INSERT INTO items (value) VALUES (1), (2)",
610
636
  'COMMIT',
611
637
  'BEGIN',
612
- "INSERT INTO items (`value`) VALUES (3), (4)",
638
+ "INSERT INTO items (value) VALUES (3), (4)",
613
639
  'COMMIT'
614
640
  ]
615
641
 
@@ -627,10 +653,10 @@ context "MySQL::Dataset#multi_insert" do
627
653
 
628
654
  MYSQL_DB.sqls.should == [
629
655
  'BEGIN',
630
- "INSERT INTO items (`value`) VALUES (1), (2)",
656
+ "INSERT INTO items (value) VALUES (1), (2)",
631
657
  'COMMIT',
632
658
  'BEGIN',
633
- "INSERT INTO items (`value`) VALUES (3), (4)",
659
+ "INSERT INTO items (value) VALUES (3), (4)",
634
660
  'COMMIT'
635
661
  ]
636
662
 
@@ -647,7 +673,7 @@ context "MySQL::Dataset#multi_insert" do
647
673
 
648
674
  MYSQL_DB.sqls.should == [
649
675
  'BEGIN',
650
- "INSERT INTO items (`name`, `value`) VALUES ('abc', 1), ('def', 2)",
676
+ "INSERT INTO items (name, value) VALUES ('abc', 1), ('def', 2)",
651
677
  'COMMIT'
652
678
  ]
653
679
 
@@ -681,3 +707,30 @@ context "MySQL::Dataset#replace" do
681
707
  @d.all.should == [{:id => 111, :value => 333}]
682
708
  end
683
709
  end
710
+
711
+ context "MySQL::Dataset#complex_expression_sql" do
712
+ setup do
713
+ @d = MYSQL_DB.dataset
714
+ end
715
+
716
+ specify "should handle case insensitive regular expressions with REGEXP" do
717
+ @d.literal(:x.like(/a/i)).should == "(x REGEXP 'a')"
718
+ @d.literal(~:x.like(/a/i)).should == "NOT (x REGEXP 'a')"
719
+ end
720
+
721
+ specify "should handle case sensitive regular expressions with REGEXP BINARY" do
722
+ @d.literal(:x.like(/a/)).should == "(x REGEXP BINARY 'a')"
723
+ @d.literal(~:x.like(/a/)).should == "NOT (x REGEXP BINARY 'a')"
724
+ end
725
+
726
+ specify "should handle string concatenation with CONCAT if more than one record" do
727
+ @d.literal([:x, :y].sql_string_join).should == "CONCAT(x, y)"
728
+ @d.literal([:x, :y].sql_string_join(' ')).should == "CONCAT(x, ' ', y)"
729
+ @d.literal([:x[:y], 1, 'z'.lit].sql_string_join(:y|1)).should == "CONCAT(x(y), y[1], '1', y[1], z)"
730
+ end
731
+
732
+ specify "should handle string concatenation as simple string if just one record" do
733
+ @d.literal([:x].sql_string_join).should == "x"
734
+ @d.literal([:x].sql_string_join(' ')).should == "x"
735
+ end
736
+ end
@@ -1,4 +1,3 @@
1
- require File.join(File.dirname(__FILE__), '../../lib/sequel_core')
2
1
  require File.join(File.dirname(__FILE__), '../spec_helper.rb')
3
2
 
4
3
  unless defined?(ORACLE_DB)