sequel 5.2.0 → 5.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +32 -0
- data/bin/sequel +5 -6
- data/doc/release_notes/5.3.0.txt +121 -0
- data/doc/schema_modification.rdoc +15 -4
- data/doc/testing.rdoc +1 -0
- data/lib/sequel/adapters/jdbc.rb +4 -0
- data/lib/sequel/adapters/jdbc/postgresql.rb +15 -0
- data/lib/sequel/adapters/oracle.rb +2 -1
- data/lib/sequel/adapters/postgres.rb +4 -0
- data/lib/sequel/adapters/shared/mysql.rb +38 -3
- data/lib/sequel/adapters/shared/postgres.rb +15 -6
- data/lib/sequel/adapters/shared/sqlite.rb +10 -0
- data/lib/sequel/adapters/utils/mysql_mysql2.rb +2 -0
- data/lib/sequel/connection_pool.rb +12 -0
- data/lib/sequel/database/misc.rb +13 -0
- data/lib/sequel/dataset/dataset_module.rb +1 -1
- data/lib/sequel/dataset/features.rb +5 -0
- data/lib/sequel/dataset/query.rb +20 -6
- data/lib/sequel/dataset/sql.rb +3 -0
- data/lib/sequel/extensions/pg_extended_date_support.rb +15 -0
- data/lib/sequel/extensions/synchronize_sql.rb +45 -0
- data/lib/sequel/model/associations.rb +1 -0
- data/lib/sequel/model/base.rb +4 -11
- data/lib/sequel/plugins/validation_helpers.rb +2 -2
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/postgres_spec.rb +5 -34
- data/spec/core/database_spec.rb +32 -0
- data/spec/core/dataset_spec.rb +19 -0
- data/spec/core/mock_adapter_spec.rb +65 -0
- data/spec/extensions/association_pks_spec.rb +26 -33
- data/spec/extensions/class_table_inheritance_spec.rb +18 -32
- data/spec/extensions/composition_spec.rb +7 -23
- data/spec/extensions/list_spec.rb +4 -5
- data/spec/extensions/many_through_many_spec.rb +24 -32
- data/spec/extensions/optimistic_locking_spec.rb +1 -1
- data/spec/extensions/pg_array_associations_spec.rb +18 -25
- data/spec/extensions/pg_extended_date_support_spec.rb +13 -0
- data/spec/extensions/pg_hstore_spec.rb +2 -2
- data/spec/extensions/prepared_statements_safe_spec.rb +6 -6
- data/spec/extensions/pretty_table_spec.rb +39 -8
- data/spec/extensions/rcte_tree_spec.rb +22 -33
- data/spec/extensions/schema_dumper_spec.rb +42 -31
- data/spec/extensions/serialization_spec.rb +3 -3
- data/spec/extensions/synchronize_sql_spec.rb +124 -0
- data/spec/extensions/timestamps_spec.rb +2 -4
- data/spec/extensions/update_or_create_spec.rb +11 -15
- data/spec/extensions/uuid_spec.rb +2 -3
- data/spec/extensions/xml_serializer_spec.rb +5 -10
- data/spec/integration/database_test.rb +1 -1
- data/spec/integration/dataset_test.rb +7 -0
- data/spec/integration/plugin_test.rb +1 -1
- data/spec/integration/schema_test.rb +3 -3
- data/spec/integration/spec_helper.rb +4 -0
- data/spec/model/base_spec.rb +6 -0
- data/spec/model/eager_loading_spec.rb +31 -6
- data/spec/model/model_spec.rb +9 -19
- data/spec/model/record_spec.rb +4 -8
- metadata +6 -2
data/spec/core/database_spec.rb
CHANGED
@@ -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
|
data/spec/core/dataset_spec.rb
CHANGED
@@ -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 =
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
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 =
|
165
|
-
|
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 =
|
213
|
-
|
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
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
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 =
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
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
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
292
|
-
|
293
|
-
|
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
|
-
|
310
|
-
|
311
|
-
|
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
|
-
|
321
|
-
|
322
|
-
|
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
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
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
|
-
|
478
|
-
|
479
|
-
|
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(
|
57
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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 =
|
96
|
-
|
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
|
466
|
-
im.must_include(
|
467
|
-
im.must_include(
|
468
|
-
im2 = @c1.instance_methods(false)
|
469
|
-
im2.wont_include(
|
470
|
-
im2.wont_include(
|
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
|
607
|
-
|
608
|
-
|
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
|
621
|
-
|
622
|
-
|
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
|
1589
|
-
im.must_include(
|
1590
|
-
im.must_include(
|
1591
|
-
im2 = @c1.instance_methods(false)
|
1592
|
-
im2.wont_include(
|
1593
|
-
im2.wont_include(
|
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
|
1685
|
-
|
1686
|
-
|
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
|
1699
|
-
|
1700
|
-
|
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)
|