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.
- data/CHANGELOG +116 -0
- data/COPYING +19 -19
- data/README +83 -32
- data/Rakefile +9 -20
- data/bin/sequel +43 -112
- data/doc/cheat_sheet.rdoc +225 -0
- data/doc/dataset_filtering.rdoc +257 -0
- data/lib/sequel_core/adapters/adapter_skeleton.rb +4 -2
- data/lib/sequel_core/adapters/ado.rb +3 -1
- data/lib/sequel_core/adapters/db2.rb +4 -2
- data/lib/sequel_core/adapters/dbi.rb +127 -113
- data/lib/sequel_core/adapters/informix.rb +4 -2
- data/lib/sequel_core/adapters/jdbc.rb +5 -3
- data/lib/sequel_core/adapters/mysql.rb +112 -46
- data/lib/sequel_core/adapters/odbc.rb +5 -7
- data/lib/sequel_core/adapters/odbc_mssql.rb +12 -3
- data/lib/sequel_core/adapters/openbase.rb +3 -1
- data/lib/sequel_core/adapters/oracle.rb +11 -9
- data/lib/sequel_core/adapters/postgres.rb +261 -262
- data/lib/sequel_core/adapters/sqlite.rb +72 -22
- data/lib/sequel_core/connection_pool.rb +140 -73
- data/lib/sequel_core/core_ext.rb +201 -66
- data/lib/sequel_core/core_sql.rb +123 -153
- data/lib/sequel_core/database/schema.rb +156 -0
- data/lib/sequel_core/database.rb +321 -338
- data/lib/sequel_core/dataset/callback.rb +11 -12
- data/lib/sequel_core/dataset/convenience.rb +213 -240
- data/lib/sequel_core/dataset/pagination.rb +58 -43
- data/lib/sequel_core/dataset/parse_tree_sequelizer.rb +331 -0
- data/lib/sequel_core/dataset/query.rb +41 -0
- data/lib/sequel_core/dataset/schema.rb +15 -0
- data/lib/sequel_core/dataset/sequelizer.rb +41 -373
- data/lib/sequel_core/dataset/sql.rb +741 -632
- data/lib/sequel_core/dataset.rb +183 -168
- data/lib/sequel_core/deprecated.rb +1 -169
- data/lib/sequel_core/exceptions.rb +24 -19
- data/lib/sequel_core/migration.rb +44 -52
- data/lib/sequel_core/object_graph.rb +43 -42
- data/lib/sequel_core/pretty_table.rb +71 -76
- data/lib/sequel_core/schema/generator.rb +163 -105
- data/lib/sequel_core/schema/sql.rb +250 -93
- data/lib/sequel_core/schema.rb +2 -8
- data/lib/sequel_core/sql.rb +394 -0
- data/lib/sequel_core/worker.rb +37 -27
- data/lib/sequel_core.rb +99 -45
- data/spec/adapters/informix_spec.rb +0 -1
- data/spec/adapters/mysql_spec.rb +177 -124
- data/spec/adapters/oracle_spec.rb +0 -1
- data/spec/adapters/postgres_spec.rb +98 -58
- data/spec/adapters/sqlite_spec.rb +45 -4
- data/spec/blockless_filters_spec.rb +269 -0
- data/spec/connection_pool_spec.rb +21 -18
- data/spec/core_ext_spec.rb +169 -19
- data/spec/core_sql_spec.rb +56 -49
- data/spec/database_spec.rb +78 -17
- data/spec/dataset_spec.rb +300 -428
- data/spec/migration_spec.rb +1 -1
- data/spec/object_graph_spec.rb +5 -11
- data/spec/rcov.opts +1 -1
- data/spec/schema_generator_spec.rb +16 -4
- data/spec/schema_spec.rb +89 -10
- data/spec/sequelizer_spec.rb +56 -56
- data/spec/spec.opts +0 -5
- data/spec/spec_config.rb +7 -0
- data/spec/spec_config.rb.example +5 -5
- data/spec/spec_helper.rb +6 -0
- data/spec/worker_spec.rb +1 -1
- metadata +78 -63
data/spec/adapters/mysql_spec.rb
CHANGED
@@ -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 =
|
12
|
+
MYSQL_DB_NAME = (m = /\/(.*)/.match(MYSQL_URI.path)) && m[1]
|
15
13
|
|
16
|
-
MYSQL_DB.
|
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
|
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
|
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
|
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
|
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
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
275
|
-
'NATURAL LEFT OUTER JOIN (
|
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.
|
279
|
-
'STRAIGHT_JOIN (
|
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]
|
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.
|
291
|
-
|
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 {@
|
351
|
+
proc {@ds.having('blah')}.should_not raise_error
|
296
352
|
|
297
|
-
@
|
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
|
-
@
|
303
|
-
"SELECT * FROM nodes HAVING (
|
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 (
|
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 (
|
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
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
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 (
|
456
|
-
"CREATE FULLTEXT INDEX posts_title_body_index ON posts (
|
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 (
|
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 (
|
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 (
|
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 (
|
478
|
-
"CREATE SPATIAL INDEX posts_geom_index ON posts (
|
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 (
|
489
|
-
"CREATE INDEX posts_title_index ON posts (
|
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 (
|
500
|
-
"CREATE UNIQUE INDEX posts_title_index ON posts (
|
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 (
|
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 (
|
635
|
+
"INSERT INTO items (value) VALUES (1), (2)",
|
610
636
|
'COMMIT',
|
611
637
|
'BEGIN',
|
612
|
-
"INSERT INTO items (
|
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 (
|
656
|
+
"INSERT INTO items (value) VALUES (1), (2)",
|
631
657
|
'COMMIT',
|
632
658
|
'BEGIN',
|
633
|
-
"INSERT INTO items (
|
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 (
|
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
|