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.
- 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)
|