sequel 3.32.0 → 3.33.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 (58) hide show
  1. data/CHANGELOG +42 -0
  2. data/Rakefile +3 -2
  3. data/doc/migration.rdoc +41 -14
  4. data/doc/opening_databases.rdoc +2 -0
  5. data/doc/release_notes/3.29.0.txt +1 -1
  6. data/doc/release_notes/3.33.0.txt +157 -0
  7. data/doc/sharding.rdoc +93 -7
  8. data/doc/testing.rdoc +1 -1
  9. data/lib/sequel/adapters/do.rb +1 -0
  10. data/lib/sequel/adapters/do/mysql.rb +6 -0
  11. data/lib/sequel/adapters/jdbc.rb +1 -0
  12. data/lib/sequel/adapters/jdbc/mysql.rb +0 -5
  13. data/lib/sequel/adapters/mock.rb +10 -5
  14. data/lib/sequel/adapters/mysql.rb +23 -1
  15. data/lib/sequel/adapters/mysql2.rb +16 -2
  16. data/lib/sequel/adapters/postgres.rb +22 -4
  17. data/lib/sequel/adapters/shared/mysql.rb +51 -10
  18. data/lib/sequel/adapters/shared/postgres.rb +101 -63
  19. data/lib/sequel/adapters/shared/sqlite.rb +19 -0
  20. data/lib/sequel/adapters/sqlite.rb +71 -16
  21. data/lib/sequel/adapters/swift.rb +1 -0
  22. data/lib/sequel/connection_pool.rb +1 -1
  23. data/lib/sequel/connection_pool/sharded_single.rb +6 -1
  24. data/lib/sequel/connection_pool/sharded_threaded.rb +6 -1
  25. data/lib/sequel/connection_pool/threaded.rb +12 -11
  26. data/lib/sequel/database/connecting.rb +2 -0
  27. data/lib/sequel/database/misc.rb +6 -0
  28. data/lib/sequel/database/query.rb +1 -1
  29. data/lib/sequel/extensions/arbitrary_servers.rb +108 -0
  30. data/lib/sequel/extensions/migration.rb +45 -7
  31. data/lib/sequel/extensions/server_block.rb +139 -0
  32. data/lib/sequel/model/associations.rb +9 -9
  33. data/lib/sequel/model/inflections.rb +1 -1
  34. data/lib/sequel/plugins/instance_hooks.rb +1 -1
  35. data/lib/sequel/plugins/json_serializer.rb +1 -1
  36. data/lib/sequel/plugins/list.rb +12 -2
  37. data/lib/sequel/version.rb +1 -1
  38. data/spec/adapters/mysql_spec.rb +64 -8
  39. data/spec/adapters/postgres_spec.rb +139 -78
  40. data/spec/adapters/sqlite_spec.rb +87 -0
  41. data/spec/core/connection_pool_spec.rb +14 -0
  42. data/spec/core/database_spec.rb +5 -0
  43. data/spec/core/mock_adapter_spec.rb +21 -9
  44. data/spec/extensions/arbitrary_servers_spec.rb +114 -0
  45. data/spec/extensions/instance_hooks_spec.rb +19 -0
  46. data/spec/extensions/list_spec.rb +31 -0
  47. data/spec/extensions/migration_spec.rb +61 -4
  48. data/spec/extensions/server_block_spec.rb +90 -0
  49. data/spec/extensions/spec_helper.rb +1 -1
  50. data/spec/files/transaction_migrations/001_create_alt_basic.rb +3 -0
  51. data/spec/files/transaction_migrations/002_create_basic.rb +3 -0
  52. data/spec/files/transactionless_migrations/001_create_alt_basic.rb +4 -0
  53. data/spec/files/transactionless_migrations/002_create_basic.rb +4 -0
  54. data/spec/integration/dataset_test.rb +2 -2
  55. data/spec/integration/plugin_test.rb +9 -9
  56. data/spec/integration/schema_test.rb +3 -1
  57. data/spec/integration/transaction_test.rb +2 -2
  58. metadata +12 -2
@@ -139,6 +139,93 @@ describe "An SQLite database" do
139
139
  end
140
140
  end
141
141
 
142
+ describe "SQLite type conversion" do
143
+ before do
144
+ @db = SQLITE_DB
145
+ @integer_booleans = @db.integer_booleans
146
+ @db.integer_booleans = true
147
+ @ds = @db[:items]
148
+ @db.drop_table(:items) rescue nil
149
+ end
150
+ after do
151
+ @db.integer_booleans = @integer_booleans
152
+ Sequel.datetime_class = Time
153
+ @db.drop_table(:items)
154
+ end
155
+
156
+ specify "should handle integers in boolean columns" do
157
+ @db.create_table(:items){TrueClass :a}
158
+ @db[:items].insert(false)
159
+ @db[:items].select_map(:a).should == [false]
160
+ @db[:items].select_map(:a+:a).should == [0]
161
+ @db[:items].update(:a=>true)
162
+ @db[:items].select_map(:a).should == [true]
163
+ @db[:items].select_map(:a+:a).should == [2]
164
+ end
165
+
166
+ specify "should handle integers/floats/strings/decimals in numeric/decimal columns" do
167
+ @db.create_table(:items){Numeric :a}
168
+ @db[:items].insert(100)
169
+ @db[:items].select_map(:a).should == [BigDecimal.new('100')]
170
+ @db[:items].get(:a).should be_a_kind_of(BigDecimal)
171
+
172
+ @db[:items].update(:a=>100.1)
173
+ @db[:items].select_map(:a).should == [BigDecimal.new('100.1')]
174
+ @db[:items].get(:a).should be_a_kind_of(BigDecimal)
175
+
176
+ @db[:items].update(:a=>'100.1')
177
+ @db[:items].select_map(:a).should == [BigDecimal.new('100.1')]
178
+ @db[:items].get(:a).should be_a_kind_of(BigDecimal)
179
+
180
+ @db[:items].update(:a=>BigDecimal.new('100.1'))
181
+ @db[:items].select_map(:a).should == [BigDecimal.new('100.1')]
182
+ @db[:items].get(:a).should be_a_kind_of(BigDecimal)
183
+ end
184
+
185
+ specify "should handle integer/float date columns as julian date" do
186
+ @db.create_table(:items){Date :a}
187
+ i = 2455979
188
+ @db[:items].insert(i)
189
+ @db[:items].first.should == {:a=>Date.jd(i)}
190
+ @db[:items].update(:a=>2455979.1)
191
+ @db[:items].first.should == {:a=>Date.jd(i)}
192
+ end
193
+
194
+ specify "should handle integer/float time columns as seconds" do
195
+ @db.create_table(:items){Time :a, :only_time=>true}
196
+ @db[:items].insert(3661)
197
+ @db[:items].first.should == {:a=>Sequel::SQLTime.create(1, 1, 1)}
198
+ @db[:items].update(:a=>3661.000001)
199
+ @db[:items].first.should == {:a=>Sequel::SQLTime.create(1, 1, 1, 1)}
200
+ end
201
+
202
+ specify "should handle integer datetime columns as unix timestamp" do
203
+ @db.create_table(:items){DateTime :a}
204
+ i = 1329860756
205
+ @db[:items].insert(i)
206
+ @db[:items].first.should == {:a=>Time.at(i)}
207
+ Sequel.datetime_class = DateTime
208
+ @db[:items].first.should == {:a=>DateTime.strptime(i.to_s, '%s')}
209
+ end
210
+
211
+ specify "should handle float datetime columns as julian date" do
212
+ @db.create_table(:items){DateTime :a}
213
+ i = 2455979.5
214
+ @db[:items].insert(i)
215
+ @db[:items].first.should == {:a=>Time.at(1329825600)}
216
+ Sequel.datetime_class = DateTime
217
+ @db[:items].first.should == {:a=>DateTime.jd(2455979.5)}
218
+ end
219
+
220
+ specify "should handle integer/float blob columns" do
221
+ @db.create_table(:items){File :a}
222
+ @db[:items].insert(1)
223
+ @db[:items].first.should == {:a=>Sequel::SQL::Blob.new('1')}
224
+ @db[:items].update(:a=>'1.1')
225
+ @db[:items].first.should == {:a=>Sequel::SQL::Blob.new(1.1.to_s)}
226
+ end
227
+ end if SQLITE_DB.adapter_scheme == :sqlite
228
+
142
229
  describe "An SQLite dataset" do
143
230
  before do
144
231
  @d = SQLITE_DB[:items]
@@ -787,6 +787,20 @@ shared_examples_for "All connection pools classes" do
787
787
  y.should == 123
788
788
  end
789
789
 
790
+ specify "should have a reentrent hold method" do
791
+ o = Object.new
792
+ c = @class.new({}){o}
793
+ c.hold do |x|
794
+ x.should == o
795
+ c.hold do |x1|
796
+ x1.should == o
797
+ c.hold do |x2|
798
+ x2.should == o
799
+ end
800
+ end
801
+ end
802
+ end
803
+
790
804
  specify "should have a servers method that returns an array of shard/server symbols" do
791
805
  @class.new({}){123}.servers.should == [:default]
792
806
  end
@@ -1396,6 +1396,11 @@ describe "Database#server_opts" do
1396
1396
  opts = {:host=>1, :database=>2, :servers=>{:server1=>2}}
1397
1397
  proc{Sequel::Database.new(opts).send(:server_opts, :server1)}.should raise_error(Sequel::Error)
1398
1398
  end
1399
+
1400
+ specify "should return the general opts merged with given opts if given opts is a Hash" do
1401
+ opts = {:host=>1, :database=>2}
1402
+ Sequel::Database.new(opts).send(:server_opts, :host=>2)[:host].should == 2
1403
+ end
1399
1404
  end
1400
1405
 
1401
1406
  describe "Database#add_servers" do
@@ -406,14 +406,26 @@ describe "Sequel Mock Adapter" do
406
406
  end
407
407
 
408
408
  specify "should be able to load dialects based on the database name" do
409
- Sequel.mock(:host=>'access').select(Date.new(2011, 12, 13)).sql.should == 'SELECT #2011-12-13#'
410
- Sequel.mock(:host=>'db2').select(1).sql.should == 'SELECT 1 FROM "SYSIBM"."SYSDUMMY1"'
411
- Sequel.mock(:host=>'firebird')[:a].distinct.limit(1, 2).sql.should == 'SELECT DISTINCT FIRST 1 SKIP 2 * FROM a'
412
- Sequel.mock(:host=>'informix')[:a].distinct.limit(1, 2).sql.should == 'SELECT SKIP 2 FIRST 1 DISTINCT * FROM a'
413
- Sequel.mock(:host=>'mssql', :quote_identifiers=>true, :identifier_input_method=>:upcase)[:a].full_text_search(:b, 'c').sql.should == "SELECT * FROM [A] WHERE (CONTAINS ([B], 'c'))"
414
- Sequel.mock(:host=>'mysql', :quote_identifiers=>true)[:a].full_text_search(:b, 'c').sql.should == "SELECT * FROM `a` WHERE (MATCH (`b`) AGAINST ('c'))"
415
- Sequel.mock(:host=>'oracle', :quote_identifiers=>true)[:a].limit(1).sql.should == 'SELECT * FROM (SELECT * FROM "a") "t1" WHERE (ROWNUM <= 1)'
416
- Sequel.mock(:host=>'postgres', :quote_identifiers=>true)[:a].full_text_search(:b, 'c').sql.should == "SELECT * FROM \"a\" WHERE (to_tsvector('simple', (COALESCE(\"b\", ''))) @@ to_tsquery('simple', 'c'))"
417
- Sequel.mock(:host=>'sqlite', :quote_identifiers=>true)[:a___b].sql.should == "SELECT * FROM `a` AS 'b'"
409
+ begin
410
+ qi = class Sequel::Database; @@quote_identifiers; end
411
+ ii = class Sequel::Database; @@identifier_input_method; end
412
+ io = class Sequel::Database; @@identifier_output_method; end
413
+ Sequel.quote_identifiers = nil
414
+ class Sequel::Database; @@identifier_input_method=nil; end
415
+ class Sequel::Database; @@identifier_output_method=nil; end
416
+ Sequel.mock(:host=>'access').select(Date.new(2011, 12, 13)).sql.should == 'SELECT #2011-12-13#'
417
+ Sequel.mock(:host=>'db2').select(1).sql.should == 'SELECT 1 FROM "SYSIBM"."SYSDUMMY1"'
418
+ Sequel.mock(:host=>'firebird')[:a].distinct.limit(1, 2).sql.should == 'SELECT DISTINCT FIRST 1 SKIP 2 * FROM "A"'
419
+ Sequel.mock(:host=>'informix')[:a].distinct.limit(1, 2).sql.should == 'SELECT SKIP 2 FIRST 1 DISTINCT * FROM A'
420
+ Sequel.mock(:host=>'mssql')[:a].full_text_search(:b, 'c').sql.should == "SELECT * FROM [A] WHERE (CONTAINS ([B], 'c'))"
421
+ Sequel.mock(:host=>'mysql')[:a].full_text_search(:b, 'c').sql.should == "SELECT * FROM `a` WHERE (MATCH (`b`) AGAINST ('c'))"
422
+ Sequel.mock(:host=>'oracle')[:a].limit(1).sql.should == 'SELECT * FROM (SELECT * FROM "A") "T1" WHERE (ROWNUM <= 1)'
423
+ Sequel.mock(:host=>'postgres')[:a].full_text_search(:b, 'c').sql.should == "SELECT * FROM \"a\" WHERE (to_tsvector('simple', (COALESCE(\"b\", ''))) @@ to_tsquery('simple', 'c'))"
424
+ Sequel.mock(:host=>'sqlite')[:a___b].sql.should == "SELECT * FROM `a` AS 'b'"
425
+ ensure
426
+ Sequel.quote_identifiers = qi
427
+ Sequel::Database.send(:class_variable_set, :@@identifier_input_method, ii)
428
+ Sequel::Database.send(:class_variable_set, :@@identifier_output_method, io)
429
+ end
418
430
  end
419
431
  end
@@ -0,0 +1,114 @@
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
+
3
+ if RUBY_VERSION >= '1.8.7'
4
+ describe "arbtirary servers" do
5
+ before do
6
+ @db = Sequel.mock(:servers=>{})
7
+ @db.pool.extend Sequel::ArbitraryServers
8
+ end
9
+
10
+ specify "should allow arbitrary server options using a hash" do
11
+ @db.synchronize(:host=>'host1', :database=>'db1') do |c|
12
+ c.opts[:host].should == 'host1'
13
+ c.opts[:database].should == 'db1'
14
+ end
15
+ end
16
+
17
+ specify "should not cache connections to arbitrary servers" do
18
+ x = nil
19
+ @db.synchronize(:host=>'host1', :database=>'db1') do |c|
20
+ x = c
21
+ end
22
+ @db.synchronize(:host=>'host1', :database=>'db1') do |c2|
23
+ c2.should_not equal(x)
24
+ end
25
+ end
26
+
27
+ specify "should yield same connection correctly when nesting" do
28
+ @db.synchronize(:host=>'host1', :database=>'db1') do |c|
29
+ @db.synchronize(:host=>'host1', :database=>'db1') do |c2|
30
+ c2.should equal(c)
31
+ end
32
+ end
33
+ end
34
+
35
+ specify "should disconnect when connection is finished" do
36
+ x, x1 = nil, nil
37
+ @db.meta_def(:disconnect_connection){|c| x = c}
38
+ @db.synchronize(:host=>'host1', :database=>'db1') do |c|
39
+ x1 = c
40
+ @db.synchronize(:host=>'host1', :database=>'db1') do |c2|
41
+ c2.should equal(c)
42
+ end
43
+ x.should equal(nil)
44
+ end
45
+ x.should equal(x1)
46
+ end
47
+
48
+ specify "should yield different connection correctly when nesting" do
49
+ @db.synchronize(:host=>'host1', :database=>'db1') do |c|
50
+ c.opts[:host].should == 'host1'
51
+ @db.synchronize(:host=>'host2', :database=>'db1') do |c2|
52
+ c2.opts[:host].should == 'host2'
53
+ c2.should_not equal(c)
54
+ end
55
+ end
56
+ end
57
+
58
+ specify "should respect multithreaded access" do
59
+ @db.synchronize(:host=>'host1', :database=>'db1') do |c|
60
+ Thread.new do
61
+ @db.synchronize(:host=>'host1', :database=>'db1') do |c2|
62
+ c2.should_not equal(c)
63
+ end
64
+ end.join
65
+ end
66
+ end
67
+
68
+ specify "should work correctly with server_block plugin" do
69
+ @db.extend Sequel::ServerBlock
70
+ @db.with_server(:host=>'host1', :database=>'db1') do
71
+ @db.synchronize do |c|
72
+ c.opts[:host].should == 'host1'
73
+ c.opts[:database].should == 'db1'
74
+ @db.synchronize do |c2|
75
+ c2.should equal(c)
76
+ end
77
+ end
78
+ end
79
+ end
80
+
81
+
82
+ specify "should respect multithreaded access with server block plugin" do
83
+ @db.extend Sequel::ServerBlock
84
+ q, q1 = Queue.new, Queue.new
85
+
86
+ t = nil
87
+ @db[:t].all
88
+ @db.with_server(:host=>'a') do
89
+ @db[:t].all
90
+ t = Thread.new do
91
+ @db[:t].all
92
+ @db.with_server(:host=>'c') do
93
+ @db[:t].all
94
+ @db.with_server(:host=>'d'){@db[:t].all}
95
+ q.push nil
96
+ q1.pop
97
+ @db[:t].all
98
+ end
99
+ @db[:t].all
100
+ end
101
+ q.pop
102
+ @db.with_server(:host=>'b'){@db[:t].all}
103
+ @db[:t].all
104
+ end
105
+ @db[:t].all
106
+ q1.push nil
107
+ t.join
108
+ @db.sqls.should == ['SELECT * FROM t', 'SELECT * FROM t -- {:host=>"a"}', 'SELECT * FROM t', 'SELECT * FROM t -- {:host=>"c"}', 'SELECT * FROM t -- {:host=>"d"}',
109
+ 'SELECT * FROM t -- {:host=>"b"}', 'SELECT * FROM t -- {:host=>"a"}', 'SELECT * FROM t', 'SELECT * FROM t -- {:host=>"c"}', 'SELECT * FROM t']
110
+ end
111
+ end
112
+ else
113
+ skip_warn "arbitrary_servers plugin: only works on ruby 1.8.7+"
114
+ end
@@ -229,4 +229,23 @@ describe "InstanceHooks plugin with transactions" do
229
229
  @or.destroy.should be_nil
230
230
  @db.sqls.should == ['BEGIN', "DELETE FROM items WHERE (id = 1)", 'ad', 'ROLLBACK', 'adr1', 'adr2']
231
231
  end
232
+
233
+ it "should have *_hook methods return self "do
234
+ @o.before_destroy_hook{r 1}.should equal(@o)
235
+ @o.before_validation_hook{r 1}.should equal(@o)
236
+ @o.before_save_hook{r 1}.should equal(@o)
237
+ @o.before_update_hook{r 1}.should equal(@o)
238
+ @o.before_create_hook{r 1}.should equal(@o)
239
+
240
+ @o.after_destroy_hook{r 1}.should equal(@o)
241
+ @o.after_validation_hook{r 1}.should equal(@o)
242
+ @o.after_save_hook{r 1}.should equal(@o)
243
+ @o.after_update_hook{r 1}.should equal(@o)
244
+ @o.after_create_hook{r 1}.should equal(@o)
245
+ @o.after_commit_hook{r 1}.should equal(@o)
246
+ @o.after_rollback_hook{r 1}.should equal(@o)
247
+ @o.after_destroy_commit_hook{r 1}.should equal(@o)
248
+ @o.after_destroy_rollback_hook{r 1}.should equal(@o)
249
+ end
250
+
232
251
  end
@@ -75,6 +75,37 @@ describe "List plugin" do
75
75
  "SELECT * FROM items WHERE ((scope_id = 5) AND (position = 20)) ORDER BY scope_id, position LIMIT 1"]
76
76
  end
77
77
 
78
+ it "should have position field set to max+1 when creating if not already set" do
79
+ @c.dataset._fetch = [[{:pos=>nil}], [{:id=>1, :position=>1}], [{:pos=>1}], [{:id=>2, :position=>2}]]
80
+ @c.dataset.autoid = 1
81
+ @c.create.values.should == {:id=>1, :position=>1}
82
+ @c.create.values.should == {:id=>2, :position=>2}
83
+ @db.sqls.should == ["SELECT max(position) FROM items LIMIT 1",
84
+ "INSERT INTO items (position) VALUES (1)",
85
+ "SELECT * FROM items WHERE (id = 1) ORDER BY position LIMIT 1",
86
+ "SELECT max(position) FROM items LIMIT 1",
87
+ "INSERT INTO items (position) VALUES (2)",
88
+ "SELECT * FROM items WHERE (id = 2) ORDER BY position LIMIT 1"]
89
+ end
90
+
91
+ it "should have position field set to max+1 in scope when creating if not already set" do
92
+ @sc.dataset._fetch = [[{:pos=>nil}], [{:id=>1, :scope_id=>1, :position=>1}], [{:pos=>1}], [{:id=>2, :scope_id=>1, :position=>2}], [{:pos=>nil}], [{:id=>3, :scope_id=>2, :position=>1}]]
93
+ @sc.dataset.autoid = 1
94
+ @sc.create(:scope_id=>1).values.should == {:id=>1, :scope_id=>1, :position=>1}
95
+ @sc.create(:scope_id=>1).values.should == {:id=>2, :scope_id=>1, :position=>2}
96
+ @sc.create(:scope_id=>2).values.should == {:id=>3, :scope_id=>2, :position=>1}
97
+ sqls = @db.sqls
98
+ sqls.slice!(7).should =~ /INSERT INTO items \((scope_id|position), (scope_id|position)\) VALUES \([12], [12]\)/
99
+ sqls.slice!(4).should =~ /INSERT INTO items \((scope_id|position), (scope_id|position)\) VALUES \([12], [12]\)/
100
+ sqls.slice!(1).should =~ /INSERT INTO items \((scope_id|position), (scope_id|position)\) VALUES \(1, 1\)/
101
+ sqls.should == ["SELECT max(position) FROM items WHERE (scope_id = 1) LIMIT 1",
102
+ "SELECT * FROM items WHERE (id = 1) ORDER BY scope_id, position LIMIT 1",
103
+ "SELECT max(position) FROM items WHERE (scope_id = 1) LIMIT 1",
104
+ "SELECT * FROM items WHERE (id = 2) ORDER BY scope_id, position LIMIT 1",
105
+ "SELECT max(position) FROM items WHERE (scope_id = 2) LIMIT 1",
106
+ "SELECT * FROM items WHERE (id = 3) ORDER BY scope_id, position LIMIT 1"]
107
+ end
108
+
78
109
  it "should have last_position return the last position in the list" do
79
110
  @c.dataset._fetch = {:max=>10}
80
111
  @o.last_position.should == 10
@@ -311,6 +311,30 @@ describe "Sequel::IntegerMigrator" do
311
311
  Sequel::Migrator.apply(@db, @dirname, 0).should == 0
312
312
  Sequel::Migrator.apply(@db, @dirname).should == 3
313
313
  end
314
+
315
+ specify "should use IntegerMigrator if IntegerMigrator.apply called, even for timestamped migration directory" do
316
+ proc{Sequel::IntegerMigrator.apply(@db, "spec/files/timestamped_migrations")}.should raise_error(Sequel::Migrator::Error)
317
+ end
318
+
319
+ specify "should use transactions by default" do
320
+ Sequel::Migrator.apply(@db, "spec/files/transaction_migrations")
321
+ @db.sqls.should == ["CREATE TABLE schema_info (version integer DEFAULT 0 NOT NULL)", "SELECT 1 AS one FROM schema_info LIMIT 1", "INSERT INTO schema_info (version) VALUES (0)", "SELECT version FROM schema_info LIMIT 1", "BEGIN", "CREATE TABLE sm11111 (smc1 integer)", "UPDATE schema_info SET version = 1", "COMMIT", "BEGIN", "CREATE TABLE sm (smc1 integer)", "UPDATE schema_info SET version = 2", "COMMIT"]
322
+ end
323
+
324
+ specify "should not use transactions for migrations that disable it" do
325
+ Sequel::Migrator.apply(@db, "spec/files/transactionless_migrations")
326
+ @db.sqls.should == ["CREATE TABLE schema_info (version integer DEFAULT 0 NOT NULL)", "SELECT 1 AS one FROM schema_info LIMIT 1", "INSERT INTO schema_info (version) VALUES (0)", "SELECT version FROM schema_info LIMIT 1", "CREATE TABLE sm11111 (smc1 integer)", "UPDATE schema_info SET version = 1", "CREATE TABLE sm (smc1 integer)", "UPDATE schema_info SET version = 2"]
327
+ end
328
+
329
+ specify "should force transactions if enabled in the migrator" do
330
+ Sequel::Migrator.run(@db, "spec/files/transactionless_migrations", :use_transactions=>true)
331
+ @db.sqls.should == ["CREATE TABLE schema_info (version integer DEFAULT 0 NOT NULL)", "SELECT 1 AS one FROM schema_info LIMIT 1", "INSERT INTO schema_info (version) VALUES (0)", "SELECT version FROM schema_info LIMIT 1", "BEGIN", "CREATE TABLE sm11111 (smc1 integer)", "UPDATE schema_info SET version = 1", "COMMIT", "BEGIN", "CREATE TABLE sm (smc1 integer)", "UPDATE schema_info SET version = 2", "COMMIT"]
332
+ end
333
+
334
+ specify "should not use transactions if disabled in the migrator" do
335
+ Sequel::Migrator.run(@db, "spec/files/transaction_migrations", :use_transactions=>false)
336
+ @db.sqls.should == ["CREATE TABLE schema_info (version integer DEFAULT 0 NOT NULL)", "SELECT 1 AS one FROM schema_info LIMIT 1", "INSERT INTO schema_info (version) VALUES (0)", "SELECT version FROM schema_info LIMIT 1", "CREATE TABLE sm11111 (smc1 integer)", "UPDATE schema_info SET version = 1", "CREATE TABLE sm (smc1 integer)", "UPDATE schema_info SET version = 2"]
337
+ end
314
338
  end
315
339
 
316
340
  describe "Sequel::TimestampMigrator" do
@@ -322,6 +346,7 @@ describe "Sequel::TimestampMigrator" do
322
346
  define_method(:sequel_migration_version=){|v| sequel_migration_version = v}
323
347
 
324
348
  def columns
349
+ super
325
350
  case opts[:from].first
326
351
  when :schema_info, 'schema_info'
327
352
  [:version]
@@ -333,6 +358,7 @@ describe "Sequel::TimestampMigrator" do
333
358
  end
334
359
 
335
360
  def fetch_rows(sql)
361
+ super
336
362
  case opts[:from].first
337
363
  when :schema_info, 'schema_info'
338
364
  yield({:version=>sequel_migration_version})
@@ -344,6 +370,7 @@ describe "Sequel::TimestampMigrator" do
344
370
  end
345
371
 
346
372
  def insert(h={})
373
+ super
347
374
  case opts[:from].first
348
375
  when :schema_info, 'schema_info'
349
376
  self.sequel_migration_version = h.values.first
@@ -353,6 +380,7 @@ describe "Sequel::TimestampMigrator" do
353
380
  end
354
381
 
355
382
  def update(h={})
383
+ super
356
384
  case opts[:from].first
357
385
  when :schema_info, 'schema_info'
358
386
  self.sequel_migration_version = h.values.first
@@ -360,6 +388,7 @@ describe "Sequel::TimestampMigrator" do
360
388
  end
361
389
 
362
390
  def delete
391
+ super
363
392
  case opts[:from].first
364
393
  when :schema_migrations, :sm, 'schema_migrations', 'sm'
365
394
  self.class::FILES.delete(opts[:where].args.last)
@@ -367,11 +396,14 @@ describe "Sequel::TimestampMigrator" do
367
396
  end
368
397
  end
369
398
  dbc = Class.new(Sequel::Mock::Database) do
370
- tables = {}
399
+ self::Tables = tables= {}
371
400
  define_method(:dataset){|*a| dsc.new(self, *a)}
372
- define_method(:create_table){|name, *args| tables[name.to_sym] = true}
373
- define_method(:drop_table){|*names| names.each{|n| tables.delete(n.to_sym)}}
374
- define_method(:table_exists?){|name| tables.has_key?(name.to_sym)}
401
+ def create_table(name, *args, &block)
402
+ super
403
+ self.class::Tables[name.to_sym] = true
404
+ end
405
+ define_method(:drop_table){|*names| super(*names); names.each{|n| tables.delete(n.to_sym)}}
406
+ define_method(:table_exists?){|name| super(name); tables.has_key?(name.to_sym)}
375
407
  end
376
408
  @db = dbc.new
377
409
  @m = Sequel::Migrator
@@ -559,4 +591,29 @@ describe "Sequel::TimestampMigrator" do
559
591
  @m.apply(@db, @dir, 0).should == nil
560
592
  @m.apply(@db, @dir).should == nil
561
593
  end
594
+
595
+ specify "should use TimestampMigrator if TimestampMigrator.apply is called even for integer migrations directory" do
596
+ Sequel::TimestampMigrator.apply(@db, "spec/files/integer_migrations")
597
+ @db.sqls.should == ["SELECT NULL FROM schema_migrations LIMIT 1", "CREATE TABLE schema_migrations (filename varchar(255) PRIMARY KEY)", "SELECT NULL FROM schema_info LIMIT 1", "SELECT filename FROM schema_migrations ORDER BY filename", "BEGIN", "CREATE TABLE sm1111 (smc1 integer)", "INSERT INTO schema_migrations (filename) VALUES ('001_create_sessions.rb')", "COMMIT", "BEGIN", "CREATE TABLE sm2222 (smc2 integer)", "INSERT INTO schema_migrations (filename) VALUES ('002_create_nodes.rb')", "COMMIT", "BEGIN", "CREATE TABLE sm3333 (smc3 integer)", "INSERT INTO schema_migrations (filename) VALUES ('003_3_create_users.rb')", "COMMIT"]
598
+ end
599
+
600
+ specify "should use transactions by default" do
601
+ Sequel::TimestampMigrator.apply(@db, "spec/files/transaction_migrations")
602
+ @db.sqls.should == ["SELECT NULL FROM schema_migrations LIMIT 1", "CREATE TABLE schema_migrations (filename varchar(255) PRIMARY KEY)", "SELECT NULL FROM schema_info LIMIT 1", "SELECT filename FROM schema_migrations ORDER BY filename", "BEGIN", "CREATE TABLE sm11111 (smc1 integer)", "INSERT INTO schema_migrations (filename) VALUES ('001_create_alt_basic.rb')", "COMMIT", "BEGIN", "CREATE TABLE sm (smc1 integer)", "INSERT INTO schema_migrations (filename) VALUES ('002_create_basic.rb')", "COMMIT"]
603
+ end
604
+
605
+ specify "should not use transactions for migrations that disable it" do
606
+ Sequel::TimestampMigrator.apply(@db, "spec/files/transactionless_migrations")
607
+ @db.sqls.should == ["SELECT NULL FROM schema_migrations LIMIT 1", "CREATE TABLE schema_migrations (filename varchar(255) PRIMARY KEY)", "SELECT NULL FROM schema_info LIMIT 1", "SELECT filename FROM schema_migrations ORDER BY filename", "CREATE TABLE sm11111 (smc1 integer)", "INSERT INTO schema_migrations (filename) VALUES ('001_create_alt_basic.rb')", "CREATE TABLE sm (smc1 integer)", "INSERT INTO schema_migrations (filename) VALUES ('002_create_basic.rb')"]
608
+ end
609
+
610
+ specify "should force transactions if enabled by the migrator" do
611
+ Sequel::TimestampMigrator.run(@db, "spec/files/transactionless_migrations", :use_transactions=>true)
612
+ @db.sqls.should == ["SELECT NULL FROM schema_migrations LIMIT 1", "CREATE TABLE schema_migrations (filename varchar(255) PRIMARY KEY)", "SELECT NULL FROM schema_info LIMIT 1", "SELECT filename FROM schema_migrations ORDER BY filename", "BEGIN", "CREATE TABLE sm11111 (smc1 integer)", "INSERT INTO schema_migrations (filename) VALUES ('001_create_alt_basic.rb')", "COMMIT", "BEGIN", "CREATE TABLE sm (smc1 integer)", "INSERT INTO schema_migrations (filename) VALUES ('002_create_basic.rb')", "COMMIT"]
613
+ end
614
+
615
+ specify "should not use transactions if disabled in the migrator" do
616
+ Sequel::TimestampMigrator.run(@db, "spec/files/transaction_migrations", :use_transactions=>false)
617
+ @db.sqls.should == ["SELECT NULL FROM schema_migrations LIMIT 1", "CREATE TABLE schema_migrations (filename varchar(255) PRIMARY KEY)", "SELECT NULL FROM schema_info LIMIT 1", "SELECT filename FROM schema_migrations ORDER BY filename", "CREATE TABLE sm11111 (smc1 integer)", "INSERT INTO schema_migrations (filename) VALUES ('001_create_alt_basic.rb')", "CREATE TABLE sm (smc1 integer)", "INSERT INTO schema_migrations (filename) VALUES ('002_create_basic.rb')"]
618
+ end
562
619
  end