sequel 5.2.0 → 5.3.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 (59) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +32 -0
  3. data/bin/sequel +5 -6
  4. data/doc/release_notes/5.3.0.txt +121 -0
  5. data/doc/schema_modification.rdoc +15 -4
  6. data/doc/testing.rdoc +1 -0
  7. data/lib/sequel/adapters/jdbc.rb +4 -0
  8. data/lib/sequel/adapters/jdbc/postgresql.rb +15 -0
  9. data/lib/sequel/adapters/oracle.rb +2 -1
  10. data/lib/sequel/adapters/postgres.rb +4 -0
  11. data/lib/sequel/adapters/shared/mysql.rb +38 -3
  12. data/lib/sequel/adapters/shared/postgres.rb +15 -6
  13. data/lib/sequel/adapters/shared/sqlite.rb +10 -0
  14. data/lib/sequel/adapters/utils/mysql_mysql2.rb +2 -0
  15. data/lib/sequel/connection_pool.rb +12 -0
  16. data/lib/sequel/database/misc.rb +13 -0
  17. data/lib/sequel/dataset/dataset_module.rb +1 -1
  18. data/lib/sequel/dataset/features.rb +5 -0
  19. data/lib/sequel/dataset/query.rb +20 -6
  20. data/lib/sequel/dataset/sql.rb +3 -0
  21. data/lib/sequel/extensions/pg_extended_date_support.rb +15 -0
  22. data/lib/sequel/extensions/synchronize_sql.rb +45 -0
  23. data/lib/sequel/model/associations.rb +1 -0
  24. data/lib/sequel/model/base.rb +4 -11
  25. data/lib/sequel/plugins/validation_helpers.rb +2 -2
  26. data/lib/sequel/version.rb +1 -1
  27. data/spec/adapters/postgres_spec.rb +5 -34
  28. data/spec/core/database_spec.rb +32 -0
  29. data/spec/core/dataset_spec.rb +19 -0
  30. data/spec/core/mock_adapter_spec.rb +65 -0
  31. data/spec/extensions/association_pks_spec.rb +26 -33
  32. data/spec/extensions/class_table_inheritance_spec.rb +18 -32
  33. data/spec/extensions/composition_spec.rb +7 -23
  34. data/spec/extensions/list_spec.rb +4 -5
  35. data/spec/extensions/many_through_many_spec.rb +24 -32
  36. data/spec/extensions/optimistic_locking_spec.rb +1 -1
  37. data/spec/extensions/pg_array_associations_spec.rb +18 -25
  38. data/spec/extensions/pg_extended_date_support_spec.rb +13 -0
  39. data/spec/extensions/pg_hstore_spec.rb +2 -2
  40. data/spec/extensions/prepared_statements_safe_spec.rb +6 -6
  41. data/spec/extensions/pretty_table_spec.rb +39 -8
  42. data/spec/extensions/rcte_tree_spec.rb +22 -33
  43. data/spec/extensions/schema_dumper_spec.rb +42 -31
  44. data/spec/extensions/serialization_spec.rb +3 -3
  45. data/spec/extensions/synchronize_sql_spec.rb +124 -0
  46. data/spec/extensions/timestamps_spec.rb +2 -4
  47. data/spec/extensions/update_or_create_spec.rb +11 -15
  48. data/spec/extensions/uuid_spec.rb +2 -3
  49. data/spec/extensions/xml_serializer_spec.rb +5 -10
  50. data/spec/integration/database_test.rb +1 -1
  51. data/spec/integration/dataset_test.rb +7 -0
  52. data/spec/integration/plugin_test.rb +1 -1
  53. data/spec/integration/schema_test.rb +3 -3
  54. data/spec/integration/spec_helper.rb +4 -0
  55. data/spec/model/base_spec.rb +6 -0
  56. data/spec/model/eager_loading_spec.rb +31 -6
  57. data/spec/model/model_spec.rb +9 -19
  58. data/spec/model/record_spec.rb +4 -8
  59. metadata +6 -2
@@ -102,6 +102,18 @@ describe "A new Database" do
102
102
  end
103
103
  end
104
104
 
105
+ describe "Database :connect_sqls option" do
106
+ it "should issue the each sql query for each new connection" do
107
+ db = Sequel.mock(:connect_sqls=>['SELECT 1', 'SELECT 2'])
108
+ db.sqls.must_equal ['SELECT 1', 'SELECT 2']
109
+ db['SELECT 3'].get
110
+ db.sqls.must_equal ['SELECT 3']
111
+ db.disconnect
112
+ db['SELECT 3'].get
113
+ db.sqls.must_equal ['SELECT 1', 'SELECT 2', 'SELECT 3']
114
+ end
115
+ end
116
+
105
117
  describe "Database#freeze" do
106
118
  before do
107
119
  @db = Sequel.mock.freeze
@@ -510,6 +522,12 @@ describe "Database#extend_datasets custom methods" do
510
522
  ds.order(:bar).foo.sql.must_equal 'SELECT * FROM items ORDER BY baz, bar'
511
523
  end
512
524
 
525
+ it "should have dataset_module support a reverse method" do
526
+ @db.extend_datasets{reverse(:foo){:baz}}
527
+ ds.foo.sql.must_equal 'SELECT * FROM items ORDER BY baz DESC'
528
+ ds.where(:bar).foo.sql.must_equal 'SELECT * FROM items WHERE bar ORDER BY baz DESC'
529
+ end
530
+
513
531
  it "should have dataset_module support a select method" do
514
532
  @db.extend_datasets{select :foo, :baz}
515
533
  ds.foo.sql.must_equal 'SELECT baz FROM items'
@@ -2547,6 +2565,20 @@ describe "Database extensions" do
2547
2565
  Sequel.mock.a.must_equal 1
2548
2566
  Sequel.mock.b.must_equal 2
2549
2567
  end
2568
+
2569
+ it "should be loadable via the :extensions Database option" do
2570
+ Sequel::Database.register_extension(:a, Module.new{def a; 1; end})
2571
+ Sequel::Database.register_extension(:b, Module.new{def b; 2; end})
2572
+ Sequel.mock(:extensions=>:a).a.must_equal 1
2573
+ db = Sequel.mock(:extensions=>'a,b')
2574
+ db.a.must_equal 1
2575
+ db.b.must_equal 2
2576
+ db = Sequel.mock(:extensions=>[:a, :b])
2577
+ db.a.must_equal 1
2578
+ db.b.must_equal 2
2579
+ proc{Sequel.mock(:extensions=>nil).a}.must_raise NoMethodError
2580
+ proc{Sequel.mock(:extensions=>Object.new)}.must_raise Sequel::Error
2581
+ end
2550
2582
  end
2551
2583
 
2552
2584
  describe "Database specific exception classes" do
@@ -378,6 +378,15 @@ describe "Dataset#where" do
378
378
  @dataset.where(nil).sql.must_equal "SELECT * FROM test WHERE NULL"
379
379
  end
380
380
 
381
+ deprecated "should handle nil block result has no existing filter" do
382
+ @dataset.where{nil}.sql.must_equal "SELECT * FROM test"
383
+ end
384
+
385
+ # SEQUEL54
386
+ it "should handle nil block result has no existing filter" do
387
+ @dataset.where{nil}.sql.must_equal "SELECT * FROM test WHERE NULL"
388
+ end if false
389
+
381
390
  it "should just clone if given an empty array or hash argument" do
382
391
  @dataset.where({}).sql.must_equal @dataset.sql
383
392
  @dataset.where([]).sql.must_equal @dataset.sql
@@ -3568,6 +3577,16 @@ describe "Dataset#insert_sql" do
3568
3577
  it "should use unaliased table name" do
3569
3578
  @ds.from(Sequel.as(:items, :i)).insert_sql(1).must_equal "INSERT INTO items VALUES (1)"
3570
3579
  end
3580
+
3581
+ it "should hoist WITH clauses from query if the dataset doesn't support CTEs in subselects" do
3582
+ @ds = @ds.with_extend do
3583
+ Sequel::Dataset.def_sql_method(self, :insert, %w'with insert into columns values')
3584
+ def supports_cte?(type=:select); true end
3585
+ def supports_cte_in_subselect?; false end
3586
+ end
3587
+ @ds.insert_sql(@ds.from(:foo).with(:foo, @ds.select(:bar))).must_equal 'WITH foo AS (SELECT bar FROM items) INSERT INTO items SELECT * FROM foo'
3588
+ @ds.insert_sql([:a], @ds.from(:foo).with(:foo, @ds.select(:bar))).must_equal 'WITH foo AS (SELECT bar FROM items) INSERT INTO items (a) SELECT * FROM foo'
3589
+ end
3571
3590
  end
3572
3591
 
3573
3592
  describe "Dataset#inspect" do
@@ -577,6 +577,71 @@ describe "PostgreSQL support" do
577
577
  inf = -1.0/0.0
578
578
  @db[:test5].insert_sql(:value => inf).must_equal %q{INSERT INTO "test5" ("value") VALUES ('-Infinity')}
579
579
  end
580
+
581
+ it "Dataset#insert_conflict should respect expressions in the target argument" do
582
+ @ds = @db[:ic_test]
583
+ @ds.insert_conflict(:target=>:a).insert_sql(1, 2, 3).must_equal "INSERT INTO \"ic_test\" VALUES (1, 2, 3) ON CONFLICT (\"a\") DO NOTHING"
584
+ @ds.insert_conflict(:target=>:c, :conflict_where=>{:c_is_unique=>true}).insert_sql(1, 2, 3).must_equal "INSERT INTO \"ic_test\" VALUES (1, 2, 3) ON CONFLICT (\"c\") WHERE (\"c_is_unique\" IS TRUE) DO NOTHING"
585
+ @ds.insert_conflict(:target=>[:b, :c]).insert_sql(1, 2, 3).must_equal "INSERT INTO \"ic_test\" VALUES (1, 2, 3) ON CONFLICT (\"b\", \"c\") DO NOTHING"
586
+ @ds.insert_conflict(:target=>[:b, Sequel.function(:round, :c)]).insert_sql(1, 2, 3).must_equal "INSERT INTO \"ic_test\" VALUES (1, 2, 3) ON CONFLICT (\"b\", round(\"c\")) DO NOTHING"
587
+ @ds.insert_conflict(:target=>[:b, Sequel.virtual_row{|o| o.round(:c)}]).insert_sql(1, 2, 3).must_equal "INSERT INTO \"ic_test\" VALUES (1, 2, 3) ON CONFLICT (\"b\", round(\"c\")) DO NOTHING"
588
+ end
589
+
590
+ it "should support creating and dropping foreign tables" do
591
+ @db.create_table(:t, :foreign=>:f, :options=>{:o=>1}){Integer :a}
592
+ @db.drop_table(:t, :foreign=>true)
593
+ @db.sqls.must_equal ['CREATE FOREIGN TABLE "t" ("a" integer) SERVER "f" OPTIONS (o \'1\')',
594
+ 'DROP FOREIGN TABLE "t"']
595
+ end
596
+
597
+ it "#create_function and #drop_function should create and drop functions" do
598
+ @db.create_function('tf', 'SELECT 1', :returns=>:integer)
599
+ @db.drop_function('tf')
600
+ @db.sqls.map{|s| s.gsub(/\s+/, ' ').strip}.must_equal ["CREATE FUNCTION tf() RETURNS integer LANGUAGE SQL AS 'SELECT 1'",
601
+ 'DROP FUNCTION tf()']
602
+ end
603
+
604
+ it "#create_function and #drop_function should support options" do
605
+ @db.create_function('tf', 'SELECT $1 + $2', :args=>[[:integer, :a], :integer], :replace=>true, :returns=>:integer, :language=>'SQL', :behavior=>:immutable, :strict=>true, :security_definer=>true, :cost=>2, :set=>{:search_path => 'public'})
606
+ @db.drop_function('tf', :if_exists=>true, :cascade=>true, :args=>[[:integer, :a], :integer])
607
+ @db.sqls.map{|s| s.gsub(/\s+/, ' ').strip}.must_equal ["CREATE OR REPLACE FUNCTION tf(a integer, integer) RETURNS integer LANGUAGE SQL IMMUTABLE STRICT SECURITY DEFINER COST 2 SET search_path = public AS 'SELECT $1 + $2'",
608
+ 'DROP FUNCTION IF EXISTS tf(a integer, integer) CASCADE']
609
+ end
610
+
611
+ it "#create_language and #drop_language should create and drop languages" do
612
+ @db.create_language(:plpgsql)
613
+ @db.create_language(:plpgsql, :replace=>true, :trusted=>true, :handler=>:a, :validator=>:b)
614
+ @db.drop_language(:plpgsql)
615
+ @db.drop_language(:plpgsql, :if_exists=>true, :cascade=>true)
616
+ @db.sqls.map{|s| s.gsub(/\s+/, ' ').strip}.must_equal ['CREATE LANGUAGE plpgsql',
617
+ 'CREATE OR REPLACE TRUSTED LANGUAGE plpgsql HANDLER a VALIDATOR b',
618
+ 'DROP LANGUAGE plpgsql',
619
+ 'DROP LANGUAGE IF EXISTS plpgsql CASCADE']
620
+ end
621
+
622
+ it "#create_schema and #drop_schema should create and drop schemas" do
623
+ @db.create_schema(:sequel)
624
+ @db.create_schema(:sequel, :if_not_exists=>true, :owner=>:foo)
625
+ @db.drop_schema(:sequel)
626
+ @db.drop_schema(:sequel, :if_exists=>true, :cascade=>true)
627
+ @db.sqls.must_equal ['CREATE SCHEMA "sequel"',
628
+ 'CREATE SCHEMA IF NOT EXISTS "sequel" AUTHORIZATION "foo"',
629
+ 'DROP SCHEMA "sequel"',
630
+ 'DROP SCHEMA IF EXISTS "sequel" CASCADE']
631
+ end
632
+
633
+ it "#create_trigger and #drop_trigger should create and drop triggers" do
634
+ @db.create_trigger(:test, :identity, :tf, :each_row=>true)
635
+ @db.create_trigger(:test, :identity, :tf, :after=>true, :events=>:insert, :args=>[1, 'a'])
636
+ @db.create_trigger(:test, :identity, :tf, :each_row=>true, :when=> {Sequel[:new][:name] => 'b'})
637
+ @db.drop_trigger(:test, :identity)
638
+ @db.drop_trigger(:test, :identity, :if_exists=>true, :cascade=>true)
639
+ @db.sqls.map{|s| s.gsub(/\s+/, ' ').strip}.must_equal ['CREATE TRIGGER identity BEFORE INSERT OR UPDATE OR DELETE ON "test" FOR EACH ROW EXECUTE PROCEDURE tf()',
640
+ 'CREATE TRIGGER identity AFTER INSERT ON "test" EXECUTE PROCEDURE tf(1, \'a\')',
641
+ %q{CREATE TRIGGER identity BEFORE INSERT OR UPDATE OR DELETE ON "test" FOR EACH ROW WHEN ("new"."name" = 'b') EXECUTE PROCEDURE tf()},
642
+ 'DROP TRIGGER identity ON "test"',
643
+ 'DROP TRIGGER IF EXISTS identity ON "test" CASCADE']
644
+ end
580
645
  end
581
646
 
582
647
  describe "MySQL support" do
@@ -105,13 +105,11 @@ describe "Sequel::Plugins::AssociationPks" do
105
105
 
106
106
  it "should set associated pks correctly for a many_to_many association" do
107
107
  @Album.load(:id=>2).tag_pks = [1, 3]
108
- sqls = @db.sqls
109
- sqls[0].must_equal "DELETE FROM albums_tags WHERE ((album_id = 2) AND (tag_id NOT IN (1, 3)))"
110
- sqls[1].must_equal 'SELECT tag_id FROM albums_tags WHERE (album_id = 2)'
111
- sqls[2].must_equal 'BEGIN'
112
- sqls[3].must_match(/INSERT INTO albums_tags \((album_id, tag_id|tag_id, album_id)\) VALUES \((2, 1|1, 2)\)/)
113
- sqls[4].must_equal 'COMMIT'
114
- sqls.length.must_equal 5
108
+ @db.sqls.must_equal ["DELETE FROM albums_tags WHERE ((album_id = 2) AND (tag_id NOT IN (1, 3)))",
109
+ 'SELECT tag_id FROM albums_tags WHERE (album_id = 2)',
110
+ 'BEGIN',
111
+ 'INSERT INTO albums_tags (album_id, tag_id) VALUES (2, 1)',
112
+ 'COMMIT']
115
113
  end
116
114
 
117
115
  it "should return correct right-side associated cpks for one_to_many associations" do
@@ -161,10 +159,8 @@ describe "Sequel::Plugins::AssociationPks" do
161
159
  it "should set associated pks correctly for left-side cpks for a one_to_many association" do
162
160
  @Vocalist.one_to_many :instruments, :class=>@Instrument, :key=>[:first, :last], :delay_pks=>false
163
161
  @Vocalist.load(:first=>'F1', :last=>'L1').instrument_pks = [1, 2]
164
- sqls = @db.sqls
165
- sqls[0].must_match(/UPDATE instruments SET (first = 'F1', last = 'L1'|last = 'L1', first = 'F1') WHERE \(id IN \(1, 2\)\)/)
166
- sqls[1].must_match(/UPDATE instruments SET (first = NULL, last = NULL|last = NULL, first = NULL) WHERE \(\(instruments.first = 'F1'\) AND \(instruments.last = 'L1'\) AND \(id NOT IN \(1, 2\)\)\)/)
167
- sqls.length.must_equal 2
162
+ @db.sqls.must_equal ["UPDATE instruments SET first = 'F1', last = 'L1' WHERE (id IN (1, 2))",
163
+ "UPDATE instruments SET first = NULL, last = NULL WHERE ((instruments.first = 'F1') AND (instruments.last = 'L1') AND (id NOT IN (1, 2)))"]
168
164
  end
169
165
 
170
166
  it "should set associated pks correctly for left-side cpks for a many_to_many association" do
@@ -209,10 +205,8 @@ describe "Sequel::Plugins::AssociationPks" do
209
205
  it "should set associated right-side cpks correctly for left-side cpks for a one_to_many association" do
210
206
  @Vocalist.one_to_many :hits, :class=>@Hit, :key=>[:first, :last], :order=>:week, :delay_pks=>false
211
207
  @Vocalist.load(:first=>'F1', :last=>'L1').hit_pks = [[1997, 1], [1997, 2]]
212
- sqls = @db.sqls
213
- sqls[0].must_match(/UPDATE hits SET (first = 'F1', last = 'L1'|last = 'L1', first = 'F1') WHERE \(\(year, week\) IN \(\(1997, 1\), \(1997, 2\)\)\)/)
214
- sqls[1].must_match(/UPDATE hits SET (first = NULL, last = NULL|last = NULL, first = NULL) WHERE \(\(hits.first = 'F1'\) AND \(hits.last = 'L1'\) AND \(\(year, week\) NOT IN \(\(1997, 1\), \(1997, 2\)\)\)\)/)
215
- sqls.length.must_equal 2
208
+ @db.sqls.must_equal ["UPDATE hits SET first = 'F1', last = 'L1' WHERE ((year, week) IN ((1997, 1), (1997, 2)))",
209
+ "UPDATE hits SET first = NULL, last = NULL WHERE ((hits.first = 'F1') AND (hits.last = 'L1') AND ((year, week) NOT IN ((1997, 1), (1997, 2))))"]
216
210
  end
217
211
 
218
212
  it "should set associated right-side cpks correctly for left-side cpks for a many_to_many association" do
@@ -238,13 +232,11 @@ describe "Sequel::Plugins::AssociationPks" do
238
232
  album = @Album.load(:id=>2)
239
233
  album.use_transactions = true
240
234
  album.tag_pks = [1, 3]
241
- sqls = @db.sqls
242
- sqls[0].must_equal "BEGIN"
243
- sqls[1].must_equal "DELETE FROM albums_tags WHERE ((album_id = 2) AND (tag_id NOT IN (1, 3)))"
244
- sqls[2].must_equal 'SELECT tag_id FROM albums_tags WHERE (album_id = 2)'
245
- sqls[3].must_match(/INSERT INTO albums_tags \((album_id, tag_id|tag_id, album_id)\) VALUES \((2, 1|1, 2)\)/)
246
- sqls[4].must_equal "COMMIT"
247
- sqls.length.must_equal 5
235
+ @db.sqls.must_equal ["BEGIN",
236
+ "DELETE FROM albums_tags WHERE ((album_id = 2) AND (tag_id NOT IN (1, 3)))",
237
+ 'SELECT tag_id FROM albums_tags WHERE (album_id = 2)',
238
+ 'INSERT INTO albums_tags (album_id, tag_id) VALUES (2, 1)',
239
+ "COMMIT"]
248
240
  end
249
241
 
250
242
  it "should automatically convert keys to numbers if the primary key is an integer for one_to_many associations" do
@@ -264,22 +256,23 @@ describe "Sequel::Plugins::AssociationPks" do
264
256
  it "should automatically convert keys to numbers if the primary key is an integer for many_to_many associations" do
265
257
  @Tag.db_schema[:id][:type] = :integer
266
258
  @Album.load(:id=>2).tag_pks = %w'1 3'
267
- sqls = @db.sqls
268
- sqls[0].must_equal "DELETE FROM albums_tags WHERE ((album_id = 2) AND (tag_id NOT IN (1, 3)))"
269
- sqls[1].must_equal 'SELECT tag_id FROM albums_tags WHERE (album_id = 2)'
270
- sqls[3].must_match(/INSERT INTO albums_tags \((album_id, tag_id|tag_id, album_id)\) VALUES \((2, 1|1, 2)\)/)
271
- sqls.length.must_equal 5
259
+ @db.sqls.must_equal ["DELETE FROM albums_tags WHERE ((album_id = 2) AND (tag_id NOT IN (1, 3)))",
260
+ 'SELECT tag_id FROM albums_tags WHERE (album_id = 2)',
261
+ 'BEGIN',
262
+ 'INSERT INTO albums_tags (album_id, tag_id) VALUES (2, 1)',
263
+ 'COMMIT']
272
264
  end
273
265
 
274
266
  it "should not automatically convert keys to numbers if the primary key is an integer for many_to_many associations" do
275
267
  @Tag.db_schema[:id][:type] = :string
276
268
  @Album.load(:id=>2).tag_pks = %w'1 3'
277
- sqls = @db.sqls
278
- sqls[0].must_equal "DELETE FROM albums_tags WHERE ((album_id = 2) AND (tag_id NOT IN ('1', '3')))"
279
- sqls[1].must_equal 'SELECT tag_id FROM albums_tags WHERE (album_id = 2)'
280
- sqls[3].must_match(/INSERT INTO albums_tags \((album_id, tag_id|tag_id, album_id)\) VALUES \((2, '1'|'1', 2)\)/)
281
- sqls[4].must_match(/INSERT INTO albums_tags \((album_id, tag_id|tag_id, album_id)\) VALUES \((2, '3'|'3', 2)\)/)
282
- sqls.length.must_equal 6
269
+ sqls = @db.sqls.must_equal [
270
+ "DELETE FROM albums_tags WHERE ((album_id = 2) AND (tag_id NOT IN ('1', '3')))",
271
+ 'SELECT tag_id FROM albums_tags WHERE (album_id = 2)',
272
+ 'BEGIN',
273
+ "INSERT INTO albums_tags (album_id, tag_id) VALUES (2, '1')",
274
+ "INSERT INTO albums_tags (album_id, tag_id) VALUES (2, '3')",
275
+ 'COMMIT']
283
276
  end
284
277
 
285
278
  it "should automatically convert keys to numbers for appropriate integer primary key for composite key associations" do
@@ -274,25 +274,19 @@ describe "class_table_inheritance plugin" do
274
274
 
275
275
  it "should insert the correct rows into all tables when inserting into parent class" do
276
276
  Employee.create(:name=>'E')
277
- sqls = @db.sqls
278
- sqls.length.must_equal 1
279
- sqls[0].must_match(/INSERT INTO employees \((name|kind), (name|kind)\) VALUES \('(E|Employee)', '(E|Employee)'\)/)
277
+ @db.sqls.must_equal ["INSERT INTO employees (name, kind) VALUES ('E', 'Employee')"]
280
278
  end
281
279
 
282
280
  it "should insert the correct rows into all tables when inserting into subclass without separate table" do
283
281
  Intern.create(:name=>'E')
284
- sqls = @db.sqls
285
- sqls.length.must_equal 1
286
- sqls[0].must_match(/INSERT INTO employees \((name|kind), (name|kind)\) VALUES \('(E|Intern)', '(E|Intern)'\)/)
282
+ @db.sqls.must_equal ["INSERT INTO employees (name, kind) VALUES ('E', 'Intern')"]
287
283
  end
288
284
 
289
285
  it "should insert the correct rows into all tables when inserting" do
290
286
  Ceo.create(:num_managers=>3, :num_staff=>2, :name=>'E')
291
- sqls = @db.sqls
292
- sqls.length.must_equal 3
293
- sqls[0].must_match(/INSERT INTO employees \((name|kind), (name|kind)\) VALUES \('(E|Ceo)', '(E|Ceo)'\)/)
294
- sqls[1].must_match(/INSERT INTO managers \((num_staff|id), (num_staff|id)\) VALUES \([12], [12]\)/)
295
- sqls[2].must_match(/INSERT INTO executives \((num_managers|id), (num_managers|id)\) VALUES \([13], [13]\)/)
287
+ @db.sqls.must_equal ["INSERT INTO employees (name, kind) VALUES ('E', 'Ceo')",
288
+ "INSERT INTO managers (id, num_staff) VALUES (1, 2)",
289
+ "INSERT INTO executives (id, num_managers) VALUES (1, 3)"]
296
290
  end
297
291
 
298
292
  it "should insert the correct rows into all tables when inserting when insert_select is supported" do
@@ -306,22 +300,18 @@ describe "class_table_inheritance plugin" do
306
300
  end)
307
301
  end
308
302
  Ceo.create(:num_managers=>3, :num_staff=>2, :name=>'E')
309
- sqls = @db.sqls
310
- sqls.length.must_equal 3
311
- sqls[0].must_match(/INSERT INTO employees \((name|kind), (name|kind)\) VALUES \('(E|Ceo)', '(E|Ceo)'\) RETURNING \*/)
312
- sqls[1].must_match(/INSERT INTO managers \((num_staff|id), (num_staff|id)\) VALUES \([12], [12]\) RETURNING \*/)
313
- sqls[2].must_match(/INSERT INTO executives \((num_managers|id), (num_managers|id)\) VALUES \([13], [13]\) RETURNING \*/)
303
+ @db.sqls.must_equal ["INSERT INTO employees (name, kind) VALUES ('E', 'Ceo') RETURNING *",
304
+ "INSERT INTO managers (id, num_staff) VALUES (1, 2) RETURNING *",
305
+ "INSERT INTO executives (id, num_managers) VALUES (1, 3) RETURNING *"]
314
306
  end
315
307
 
316
308
  it "should insert the correct rows into all tables with a given primary key" do
317
309
  e = Ceo.new(:num_managers=>3, :num_staff=>2, :name=>'E')
318
310
  e.id = 2
319
311
  e.save
320
- sqls = @db.sqls
321
- sqls.length.must_equal 3
322
- sqls[0].must_match(/INSERT INTO employees \((name|kind|id), (name|kind|id), (name|kind|id)\) VALUES \(('E'|'Ceo'|2), ('E'|'Ceo'|2), ('E'|'Ceo'|2)\)/)
323
- sqls[1].must_match(/INSERT INTO managers \((num_staff|id), (num_staff|id)\) VALUES \(2, 2\)/)
324
- sqls[2].must_match(/INSERT INTO executives \((num_managers|id), (num_managers|id)\) VALUES \([23], [23]\)/)
312
+ @db.sqls.must_equal ["INSERT INTO employees (id, name, kind) VALUES (2, 'E', 'Ceo')",
313
+ "INSERT INTO managers (id, num_staff) VALUES (2, 2)",
314
+ "INSERT INTO executives (id, num_managers) VALUES (2, 3)"]
325
315
  end
326
316
 
327
317
  it "should update the correct rows in all tables when updating parent class" do
@@ -463,22 +453,18 @@ describe "class_table_inheritance plugin without sti_key with :alias option" do
463
453
 
464
454
  it "should insert the correct rows into all tables when inserting" do
465
455
  Executive.create(:num_managers=>3, :num_staff=>2, :name=>'E')
466
- sqls = @db.sqls
467
- sqls.length.must_equal 3
468
- sqls[0].must_match(/INSERT INTO employees \(name\) VALUES \('E'\)/)
469
- sqls[1].must_match(/INSERT INTO managers \((num_staff|id), (num_staff|id)\) VALUES \([12], [12]\)/)
470
- sqls[2].must_match(/INSERT INTO executives \((num_managers|id), (num_managers|id)\) VALUES \([13], [13]\)/)
471
- end
456
+ @db.sqls.must_equal ["INSERT INTO employees (name) VALUES ('E')",
457
+ "INSERT INTO managers (id, num_staff) VALUES (1, 2)",
458
+ "INSERT INTO executives (id, num_managers) VALUES (1, 3)"]
459
+ end
472
460
 
473
461
  it "should insert the correct rows into all tables with a given primary key" do
474
462
  e = Executive.new(:num_managers=>3, :num_staff=>2, :name=>'E')
475
463
  e.id = 2
476
464
  e.save
477
- sqls = @db.sqls
478
- sqls.length.must_equal 3
479
- sqls[0].must_match(/INSERT INTO employees \((name|id), (name|id)\) VALUES \(('E'|2), ('E'|2)\)/)
480
- sqls[1].must_match(/INSERT INTO managers \((num_staff|id), (num_staff|id)\) VALUES \(2, 2\)/)
481
- sqls[2].must_match(/INSERT INTO executives \((num_managers|id), (num_managers|id)\) VALUES \([23], [23]\)/)
465
+ @db.sqls.must_equal ["INSERT INTO employees (id, name) VALUES (2, 'E')",
466
+ "INSERT INTO managers (id, num_staff) VALUES (2, 2)",
467
+ "INSERT INTO executives (id, num_managers) VALUES (2, 3)"]
482
468
  end
483
469
 
484
470
  it "should update the correct rows in all tables when updating" do
@@ -53,11 +53,8 @@ describe "Composition plugin" do
53
53
 
54
54
  it "should set column values even when not validating" do
55
55
  @c.composition :date, :mapping=>[:year, :month, :day]
56
- @c.load({}).set(:date=>Date.new(4, 8, 12)).save(:validate=>false)
57
- sql = DB.sqls.last
58
- sql.must_include("year = 4")
59
- sql.must_include("month = 8")
60
- sql.must_include("day = 12")
56
+ @c.load(id: 1).set(:date=>Date.new(4, 8, 12)).save(:validate=>false)
57
+ DB.sqls.must_equal ['UPDATE items SET year = 4, month = 8, day = 12 WHERE (id = 1)']
61
58
  end
62
59
 
63
60
  it ".compositions should return the reflection hash of compositions" do
@@ -81,10 +78,7 @@ describe "Composition plugin" do
81
78
  @c.composition :date, :composer=>proc{Date.new(year+1, month+2, day+3)}, :decomposer=>proc{[:year, :month, :day].each{|s| self.send("#{s}=", date.send(s) * 2)}}
82
79
  @o.date.must_equal Date.new(2, 4, 6)
83
80
  @o.save
84
- sql = DB.sqls.last
85
- sql.must_include("year = 4")
86
- sql.must_include("month = 8")
87
- sql.must_include("day = 12")
81
+ DB.sqls.must_equal ['UPDATE items SET year = 4, month = 8, day = 12 WHERE (id = 1)']
88
82
  end
89
83
 
90
84
  it "should allow call super in composition getter and setter method definition in class" do
@@ -187,9 +181,7 @@ describe "Composition plugin" do
187
181
  @o.date.month.must_equal 6
188
182
  @o.date = c.new(3, 4)
189
183
  @o.save
190
- sql = DB.sqls.last
191
- sql.must_include("year = 6")
192
- sql.must_include("month = 12")
184
+ DB.sqls.must_equal ['UPDATE items SET year = 6, month = 12, day = 3 WHERE (id = 1)']
193
185
  end
194
186
 
195
187
  it ":mapping option should work with an array of two pairs of symbols" do
@@ -209,9 +201,7 @@ describe "Composition plugin" do
209
201
  @o.date.m.must_equal 6
210
202
  @o.date = c.new(3, 4)
211
203
  @o.save
212
- sql = DB.sqls.last
213
- sql.must_include("year = 6")
214
- sql.must_include("month = 12")
204
+ DB.sqls.must_equal ['UPDATE items SET year = 6, month = 12, day = 3 WHERE (id = 1)']
215
205
  end
216
206
 
217
207
  it ":mapping option :composer should return nil if all values are nil" do
@@ -223,10 +213,7 @@ describe "Composition plugin" do
223
213
  @c.composition :date, :mapping=>[:year, :month, :day]
224
214
  @o.date = nil
225
215
  @o.save
226
- sql = DB.sqls.last
227
- sql.must_include("year = NULL")
228
- sql.must_include("month = NULL")
229
- sql.must_include("day = NULL")
216
+ DB.sqls.must_equal ['UPDATE items SET year = NULL, month = NULL, day = NULL WHERE (id = 1)']
230
217
  end
231
218
 
232
219
  it "should work with frozen instances" do
@@ -249,10 +236,7 @@ describe "Composition plugin" do
249
236
  o = c.load(:id=>1, :year=>1, :month=>2, :day=>3)
250
237
  o.date.must_equal Date.new(1, 2, 3)
251
238
  o.save
252
- sql = DB.sqls.last
253
- sql.must_include("year = 1")
254
- sql.must_include("month = 2")
255
- sql.must_include("day = 3")
239
+ DB.sqls.must_equal ['UPDATE items SET year = 1, month = 2, day = 3 WHERE (id = 1)']
256
240
  end
257
241
 
258
242
  it "should freeze composition metadata when freezing model class" do
@@ -92,15 +92,14 @@ describe "List plugin" do
92
92
  @sc.create(:scope_id=>1).values.must_equal(:id=>1, :scope_id=>1, :position=>1)
93
93
  @sc.create(:scope_id=>1).values.must_equal(:id=>2, :scope_id=>1, :position=>2)
94
94
  @sc.create(:scope_id=>2).values.must_equal(:id=>3, :scope_id=>2, :position=>1)
95
- sqls = @db.sqls
96
- sqls.slice!(7).must_match(/INSERT INTO items \((scope_id|position), (scope_id|position)\) VALUES \([12], [12]\)/)
97
- sqls.slice!(4).must_match(/INSERT INTO items \((scope_id|position), (scope_id|position)\) VALUES \([12], [12]\)/)
98
- sqls.slice!(1).must_match(/INSERT INTO items \((scope_id|position), (scope_id|position)\) VALUES \(1, 1\)/)
99
- sqls.must_equal ["SELECT max(position) AS max FROM items WHERE (scope_id = 1) LIMIT 1",
95
+ @db.sqls.must_equal ["SELECT max(position) AS max FROM items WHERE (scope_id = 1) LIMIT 1",
96
+ 'INSERT INTO items (scope_id, position) VALUES (1, 1)',
100
97
  "SELECT * FROM items WHERE (id = 1) ORDER BY scope_id, position LIMIT 1",
101
98
  "SELECT max(position) AS max FROM items WHERE (scope_id = 1) LIMIT 1",
99
+ 'INSERT INTO items (scope_id, position) VALUES (1, 2)',
102
100
  "SELECT * FROM items WHERE (id = 2) ORDER BY scope_id, position LIMIT 1",
103
101
  "SELECT max(position) AS max FROM items WHERE (scope_id = 2) LIMIT 1",
102
+ 'INSERT INTO items (scope_id, position) VALUES (2, 1)',
104
103
  "SELECT * FROM items WHERE (id = 3) ORDER BY scope_id, position LIMIT 1"]
105
104
  end
106
105
 
@@ -462,12 +462,12 @@ describe Sequel::Model, "many_through_many" do
462
462
 
463
463
  it "should not add associations methods directly to class" do
464
464
  @c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]]
465
- im = @c1.instance_methods.collect{|x| x.to_s}
466
- im.must_include('tags')
467
- im.must_include('tags_dataset')
468
- im2 = @c1.instance_methods(false).collect{|x| x.to_s}
469
- im2.wont_include('tags')
470
- im2.wont_include('tags_dataset')
465
+ im = @c1.instance_methods
466
+ im.must_include(:tags)
467
+ im.must_include(:tags_dataset)
468
+ im2 = @c1.instance_methods(false)
469
+ im2.wont_include(:tags)
470
+ im2.wont_include(:tags_dataset)
471
471
  end
472
472
 
473
473
  it "should support after_load association callback" do
@@ -603,11 +603,9 @@ describe "many_through_many eager loading methods" do
603
603
  it "should eagerly load multiple associations in a single call" do
604
604
  a = @c1.eager(:tags, :albums).all
605
605
  a.must_equal [@c1.load(:id=>1)]
606
- sqls = DB.sqls
607
- sqls.length.must_equal 3
608
- sqls[0].must_equal 'SELECT * FROM artists'
609
- sqls[1..-1].must_include('SELECT tags.*, albums_artists.artist_id AS x_foreign_key_x FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) INNER JOIN albums ON (albums.id = albums_tags.album_id) INNER JOIN albums_artists ON (albums_artists.album_id = albums.id) WHERE (albums_artists.artist_id IN (1))')
610
- sqls[1..-1].must_include('SELECT albums.*, albums_artists.artist_id AS x_foreign_key_x FROM albums INNER JOIN albums_artists ON (albums_artists.album_id = albums.id) WHERE (albums_artists.artist_id IN (1))')
606
+ DB.sqls.must_equal ['SELECT * FROM artists',
607
+ 'SELECT tags.*, albums_artists.artist_id AS x_foreign_key_x FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) INNER JOIN albums ON (albums.id = albums_tags.album_id) INNER JOIN albums_artists ON (albums_artists.album_id = albums.id) WHERE (albums_artists.artist_id IN (1))',
608
+ 'SELECT albums.*, albums_artists.artist_id AS x_foreign_key_x FROM albums INNER JOIN albums_artists ON (albums_artists.album_id = albums.id) WHERE (albums_artists.artist_id IN (1))']
611
609
  a = a.first
612
610
  a.tags.must_equal [Tag.load(:id=>2)]
613
611
  a.albums.must_equal [Album.load(:id=>3)]
@@ -617,11 +615,9 @@ describe "many_through_many eager loading methods" do
617
615
  it "should eagerly load multiple associations in separate" do
618
616
  a = @c1.eager(:tags).eager(:albums).all
619
617
  a.must_equal [@c1.load(:id=>1)]
620
- sqls = DB.sqls
621
- sqls.length.must_equal 3
622
- sqls[0].must_equal 'SELECT * FROM artists'
623
- sqls[1..-1].must_include('SELECT tags.*, albums_artists.artist_id AS x_foreign_key_x FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) INNER JOIN albums ON (albums.id = albums_tags.album_id) INNER JOIN albums_artists ON (albums_artists.album_id = albums.id) WHERE (albums_artists.artist_id IN (1))')
624
- sqls[1..-1].must_include('SELECT albums.*, albums_artists.artist_id AS x_foreign_key_x FROM albums INNER JOIN albums_artists ON (albums_artists.album_id = albums.id) WHERE (albums_artists.artist_id IN (1))')
618
+ DB.sqls.must_equal ['SELECT * FROM artists',
619
+ 'SELECT tags.*, albums_artists.artist_id AS x_foreign_key_x FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) INNER JOIN albums ON (albums.id = albums_tags.album_id) INNER JOIN albums_artists ON (albums_artists.album_id = albums.id) WHERE (albums_artists.artist_id IN (1))',
620
+ 'SELECT albums.*, albums_artists.artist_id AS x_foreign_key_x FROM albums INNER JOIN albums_artists ON (albums_artists.album_id = albums.id) WHERE (albums_artists.artist_id IN (1))']
625
621
  a = a.first
626
622
  a.tags.must_equal [Tag.load(:id=>2)]
627
623
  a.albums.must_equal [Album.load(:id=>3)]
@@ -1585,12 +1581,12 @@ describe Sequel::Model, "one_through_many" do
1585
1581
 
1586
1582
  it "should not add associations methods directly to class" do
1587
1583
  @c1.one_through_many :tag, [[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]]
1588
- im = @c1.instance_methods.collect{|x| x.to_s}
1589
- im.must_include('tag')
1590
- im.must_include('tag_dataset')
1591
- im2 = @c1.instance_methods(false).collect{|x| x.to_s}
1592
- im2.wont_include('tag')
1593
- im2.wont_include('tag_dataset')
1584
+ im = @c1.instance_methods
1585
+ im.must_include(:tag)
1586
+ im.must_include(:tag_dataset)
1587
+ im2 = @c1.instance_methods(false)
1588
+ im2.wont_include(:tag)
1589
+ im2.wont_include(:tag_dataset)
1594
1590
  end
1595
1591
 
1596
1592
  it "should support after_load association callback" do
@@ -1681,11 +1677,9 @@ describe "one_through_many eager loading methods" do
1681
1677
  it "should eagerly load multiple associations in a single call" do
1682
1678
  a = @c1.eager(:tag, :album).all
1683
1679
  a.must_equal [@c1.load(:id=>1)]
1684
- sqls = DB.sqls
1685
- sqls.length.must_equal 3
1686
- sqls[0].must_equal 'SELECT * FROM artists'
1687
- sqls[1..-1].must_include('SELECT tags.*, albums_artists.artist_id AS x_foreign_key_x FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) INNER JOIN albums ON (albums.id = albums_tags.album_id) INNER JOIN albums_artists ON (albums_artists.album_id = albums.id) WHERE (albums_artists.artist_id IN (1))')
1688
- sqls[1..-1].must_include('SELECT albums.*, albums_artists.artist_id AS x_foreign_key_x FROM albums INNER JOIN albums_artists ON (albums_artists.album_id = albums.id) WHERE (albums_artists.artist_id IN (1))')
1680
+ DB.sqls.must_equal ['SELECT * FROM artists',
1681
+ 'SELECT tags.*, albums_artists.artist_id AS x_foreign_key_x FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) INNER JOIN albums ON (albums.id = albums_tags.album_id) INNER JOIN albums_artists ON (albums_artists.album_id = albums.id) WHERE (albums_artists.artist_id IN (1))',
1682
+ 'SELECT albums.*, albums_artists.artist_id AS x_foreign_key_x FROM albums INNER JOIN albums_artists ON (albums_artists.album_id = albums.id) WHERE (albums_artists.artist_id IN (1))']
1689
1683
  a = a.first
1690
1684
  a.tag.must_equal Tag.load(:id=>2)
1691
1685
  a.album.must_equal Album.load(:id=>3)
@@ -1695,11 +1689,9 @@ describe "one_through_many eager loading methods" do
1695
1689
  it "should eagerly load multiple associations in separate" do
1696
1690
  a = @c1.eager(:tag).eager(:album).all
1697
1691
  a.must_equal [@c1.load(:id=>1)]
1698
- sqls = DB.sqls
1699
- sqls.length.must_equal 3
1700
- sqls[0].must_equal 'SELECT * FROM artists'
1701
- sqls[1..-1].must_include('SELECT tags.*, albums_artists.artist_id AS x_foreign_key_x FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) INNER JOIN albums ON (albums.id = albums_tags.album_id) INNER JOIN albums_artists ON (albums_artists.album_id = albums.id) WHERE (albums_artists.artist_id IN (1))')
1702
- sqls[1..-1].must_include('SELECT albums.*, albums_artists.artist_id AS x_foreign_key_x FROM albums INNER JOIN albums_artists ON (albums_artists.album_id = albums.id) WHERE (albums_artists.artist_id IN (1))')
1692
+ DB.sqls.must_equal ['SELECT * FROM artists',
1693
+ 'SELECT tags.*, albums_artists.artist_id AS x_foreign_key_x FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) INNER JOIN albums ON (albums.id = albums_tags.album_id) INNER JOIN albums_artists ON (albums_artists.album_id = albums.id) WHERE (albums_artists.artist_id IN (1))',
1694
+ 'SELECT albums.*, albums_artists.artist_id AS x_foreign_key_x FROM albums INNER JOIN albums_artists ON (albums_artists.album_id = albums.id) WHERE (albums_artists.artist_id IN (1))']
1703
1695
  a = a.first
1704
1696
  a.tag.must_equal Tag.load(:id=>2)
1705
1697
  a.album.must_equal Album.load(:id=>3)