sequel 3.35.0 → 3.36.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +78 -0
- data/Rakefile +3 -3
- data/bin/sequel +3 -1
- data/doc/advanced_associations.rdoc +154 -11
- data/doc/migration.rdoc +18 -0
- data/doc/object_model.rdoc +541 -0
- data/doc/opening_databases.rdoc +4 -1
- data/doc/release_notes/3.36.0.txt +245 -0
- data/doc/schema_modification.rdoc +0 -6
- data/lib/sequel/adapters/do/mysql.rb +7 -0
- data/lib/sequel/adapters/jdbc.rb +11 -3
- data/lib/sequel/adapters/jdbc/mysql.rb +3 -5
- data/lib/sequel/adapters/jdbc/postgresql.rb +10 -8
- data/lib/sequel/adapters/jdbc/progress.rb +21 -0
- data/lib/sequel/adapters/mock.rb +2 -6
- data/lib/sequel/adapters/mysql.rb +3 -9
- data/lib/sequel/adapters/mysql2.rb +12 -11
- data/lib/sequel/adapters/postgres.rb +32 -40
- data/lib/sequel/adapters/shared/mssql.rb +15 -11
- data/lib/sequel/adapters/shared/mysql.rb +28 -3
- data/lib/sequel/adapters/shared/oracle.rb +5 -0
- data/lib/sequel/adapters/shared/postgres.rb +59 -5
- data/lib/sequel/adapters/shared/sqlite.rb +3 -13
- data/lib/sequel/adapters/sqlite.rb +0 -7
- data/lib/sequel/adapters/swift/mysql.rb +2 -5
- data/lib/sequel/adapters/tinytds.rb +1 -2
- data/lib/sequel/connection_pool/sharded_threaded.rb +5 -1
- data/lib/sequel/connection_pool/threaded.rb +9 -1
- data/lib/sequel/database/dataset_defaults.rb +3 -1
- data/lib/sequel/database/misc.rb +7 -1
- data/lib/sequel/database/query.rb +11 -3
- data/lib/sequel/database/schema_generator.rb +40 -9
- data/lib/sequel/database/schema_methods.rb +6 -1
- data/lib/sequel/dataset/actions.rb +5 -5
- data/lib/sequel/dataset/prepared_statements.rb +3 -1
- data/lib/sequel/dataset/query.rb +1 -1
- data/lib/sequel/extensions/migration.rb +28 -0
- data/lib/sequel/extensions/pg_auto_parameterize.rb +0 -9
- data/lib/sequel/extensions/pg_inet.rb +89 -0
- data/lib/sequel/extensions/pg_json.rb +178 -0
- data/lib/sequel/extensions/schema_dumper.rb +24 -6
- data/lib/sequel/model/associations.rb +19 -15
- data/lib/sequel/model/base.rb +11 -12
- data/lib/sequel/plugins/composition.rb +1 -2
- data/lib/sequel/plugins/eager_each.rb +59 -0
- data/lib/sequel/plugins/json_serializer.rb +41 -4
- data/lib/sequel/plugins/nested_attributes.rb +72 -52
- data/lib/sequel/plugins/optimistic_locking.rb +8 -0
- data/lib/sequel/plugins/tactical_eager_loading.rb +7 -7
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/postgres_spec.rb +271 -1
- data/spec/adapters/sqlite_spec.rb +11 -0
- data/spec/core/connection_pool_spec.rb +26 -1
- data/spec/core/database_spec.rb +19 -0
- data/spec/core/dataset_spec.rb +45 -5
- data/spec/core/expression_filters_spec.rb +31 -67
- data/spec/core/mock_adapter_spec.rb +4 -0
- data/spec/extensions/core_extensions_spec.rb +83 -0
- data/spec/extensions/eager_each_spec.rb +34 -0
- data/spec/extensions/inflector_spec.rb +0 -4
- data/spec/extensions/json_serializer_spec.rb +32 -1
- data/spec/extensions/migration_spec.rb +28 -0
- data/spec/extensions/nested_attributes_spec.rb +134 -1
- data/spec/extensions/optimistic_locking_spec.rb +15 -1
- data/spec/extensions/pg_hstore_spec.rb +1 -1
- data/spec/extensions/pg_inet_spec.rb +44 -0
- data/spec/extensions/pg_json_spec.rb +101 -0
- data/spec/extensions/prepared_statements_spec.rb +30 -0
- data/spec/extensions/rcte_tree_spec.rb +9 -0
- data/spec/extensions/schema_dumper_spec.rb +195 -7
- data/spec/extensions/serialization_spec.rb +4 -0
- data/spec/extensions/spec_helper.rb +9 -1
- data/spec/extensions/tactical_eager_loading_spec.rb +8 -0
- data/spec/integration/database_test.rb +5 -1
- data/spec/integration/prepared_statement_test.rb +20 -2
- data/spec/model/associations_spec.rb +27 -0
- data/spec/model/base_spec.rb +54 -0
- data/spec/model/model_spec.rb +6 -0
- data/spec/model/record_spec.rb +18 -0
- data/spec/rcov.opts +2 -0
- metadata +14 -3
@@ -54,4 +54,34 @@ describe "prepared_statements plugin" do
|
|
54
54
|
c[1].should == c.load(:id=>1, :name=>'foo', :i=>2)
|
55
55
|
@db.sqls.should == ["SELECT * FROM people WHERE (id = 1) LIMIT 1 -- read_only"]
|
56
56
|
end
|
57
|
+
|
58
|
+
describe " with placeholder type specifiers" do
|
59
|
+
before do
|
60
|
+
@ds.meta_def(:requires_placeholder_type_specifiers?){true}
|
61
|
+
end
|
62
|
+
|
63
|
+
specify "should correctly handle without schema type" do
|
64
|
+
@c[1].should == @p
|
65
|
+
@db.sqls.should == ["SELECT * FROM people WHERE (id = 1) LIMIT 1 -- read_only"]
|
66
|
+
end
|
67
|
+
|
68
|
+
specify "should correctly handle with schema type" do
|
69
|
+
@c.db_schema[:id][:type] = :integer
|
70
|
+
ds = @c.send(:prepared_lookup)
|
71
|
+
def ds.literal_symbol_append(sql, v)
|
72
|
+
if @opts[:bind_vars] and match = /\A\$(.*)\z/.match(v.to_s)
|
73
|
+
s = match[1].split('__')[0].to_sym
|
74
|
+
if prepared_arg?(s)
|
75
|
+
literal_append(sql, prepared_arg(s))
|
76
|
+
else
|
77
|
+
sql << v.to_s
|
78
|
+
end
|
79
|
+
else
|
80
|
+
super
|
81
|
+
end
|
82
|
+
end
|
83
|
+
@c[1].should == @p
|
84
|
+
@db.sqls.should == ["SELECT * FROM people WHERE (id = 1) LIMIT 1 -- read_only"]
|
85
|
+
end
|
86
|
+
end
|
57
87
|
end
|
@@ -30,6 +30,15 @@ describe Sequel::Model, "rcte_tree" do
|
|
30
30
|
@o.descendants_dataset.sql.should == 'WITH t AS (SELECT * FROM nodes WHERE (parent_id = 2) UNION ALL SELECT nodes.* FROM nodes INNER JOIN t ON (t.id = nodes.parent_id)) SELECT * FROM t AS nodes'
|
31
31
|
end
|
32
32
|
|
33
|
+
it "should use the correct SQL for lazy associations when recursive CTEs require column aliases" do
|
34
|
+
@c.dataset.meta_def(:recursive_cte_requires_column_aliases?){true}
|
35
|
+
@c.plugin :rcte_tree
|
36
|
+
@o.parent_dataset.sql.should == 'SELECT * FROM nodes WHERE (nodes.id = 1) LIMIT 1'
|
37
|
+
@o.children_dataset.sql.should == 'SELECT * FROM nodes WHERE (nodes.parent_id = 2)'
|
38
|
+
@o.ancestors_dataset.sql.should == 'WITH t(id, name, parent_id, i, pi) AS (SELECT id, name, parent_id, i, pi FROM nodes WHERE (id = 1) UNION ALL SELECT nodes.id, nodes.name, nodes.parent_id, nodes.i, nodes.pi FROM nodes INNER JOIN t ON (t.parent_id = nodes.id)) SELECT * FROM t AS nodes'
|
39
|
+
@o.descendants_dataset.sql.should == 'WITH t(id, name, parent_id, i, pi) AS (SELECT id, name, parent_id, i, pi FROM nodes WHERE (parent_id = 2) UNION ALL SELECT nodes.id, nodes.name, nodes.parent_id, nodes.i, nodes.pi FROM nodes INNER JOIN t ON (t.id = nodes.parent_id)) SELECT * FROM t AS nodes'
|
40
|
+
end
|
41
|
+
|
33
42
|
it "should use the correct SQL for lazy associations when giving options" do
|
34
43
|
@c.plugin :rcte_tree, :primary_key=>:i, :key=>:pi, :cte_name=>:cte, :order=>:name, :ancestors=>{:name=>:as}, :children=>{:name=>:cs}, :descendants=>{:name=>:ds}, :parent=>{:name=>:p}
|
35
44
|
@o.p_dataset.sql.should == 'SELECT * FROM nodes WHERE (nodes.i = 4) ORDER BY name LIMIT 1'
|
@@ -50,9 +50,9 @@ add_index :t, [:b, :c], :unique=>true
|
|
50
50
|
END_CODE
|
51
51
|
|
52
52
|
g.dump_indexes(:drop_index=>:t).should == (<<END_CODE).strip
|
53
|
-
drop_index :t, [:a]
|
54
|
-
drop_index :t, [:c, :e], :name=>:blah
|
55
53
|
drop_index :t, [:b, :c], :unique=>true
|
54
|
+
drop_index :t, [:c, :e], :name=>:blah
|
55
|
+
drop_index :t, [:a]
|
56
56
|
END_CODE
|
57
57
|
end
|
58
58
|
|
@@ -340,6 +340,112 @@ end
|
|
340
340
|
END_MIG
|
341
341
|
end
|
342
342
|
|
343
|
+
it "should honor the :index_names => false option to not include names of indexes" do
|
344
|
+
@d.meta_def(:indexes) do |t|
|
345
|
+
{:i1=>{:columns=>[:c1], :unique=>false},
|
346
|
+
:t1_c2_c1_index=>{:columns=>[:c2, :c1], :unique=>true}}
|
347
|
+
end
|
348
|
+
@d.dump_table_schema(:t1, :index_names=>false).should == "create_table(:t1, :ignore_index_errors=>true) do\n primary_key :c1\n String :c2, :size=>20\n \n index [:c1]\n index [:c2, :c1], :unique=>true\nend"
|
349
|
+
@d.dump_schema_migration(:index_names=>false).should == <<-END_MIG
|
350
|
+
Sequel.migration do
|
351
|
+
up do
|
352
|
+
create_table(:t1, :ignore_index_errors=>true) do
|
353
|
+
primary_key :c1
|
354
|
+
String :c2, :size=>20
|
355
|
+
|
356
|
+
index [:c1]
|
357
|
+
index [:c2, :c1], :unique=>true
|
358
|
+
end
|
359
|
+
|
360
|
+
create_table(:t2, :ignore_index_errors=>true) do
|
361
|
+
Integer :c1, :null=>false
|
362
|
+
BigDecimal :c2, :null=>false
|
363
|
+
|
364
|
+
primary_key [:c1, :c2]
|
365
|
+
|
366
|
+
index [:c1]
|
367
|
+
index [:c2, :c1], :unique=>true
|
368
|
+
end
|
369
|
+
end
|
370
|
+
|
371
|
+
down do
|
372
|
+
drop_table(:t2, :t1)
|
373
|
+
end
|
374
|
+
end
|
375
|
+
END_MIG
|
376
|
+
end
|
377
|
+
|
378
|
+
it "should make :index_names => :namespace option a noop if there is a global index namespace" do
|
379
|
+
@d.meta_def(:indexes) do |t|
|
380
|
+
{:i1=>{:columns=>[:c1], :unique=>false},
|
381
|
+
:t1_c2_c1_index=>{:columns=>[:c2, :c1], :unique=>false}}
|
382
|
+
end
|
383
|
+
@d.dump_table_schema(:t1, :index_names=>:namespace).should == "create_table(:t1, :ignore_index_errors=>true) do\n primary_key :c1\n String :c2, :size=>20\n \n index [:c1], :name=>:i1\n index [:c2, :c1]\nend"
|
384
|
+
@d.dump_schema_migration(:index_names=>:namespace).should == <<-END_MIG
|
385
|
+
Sequel.migration do
|
386
|
+
up do
|
387
|
+
create_table(:t1, :ignore_index_errors=>true) do
|
388
|
+
primary_key :c1
|
389
|
+
String :c2, :size=>20
|
390
|
+
|
391
|
+
index [:c1], :name=>:i1
|
392
|
+
index [:c2, :c1]
|
393
|
+
end
|
394
|
+
|
395
|
+
create_table(:t2, :ignore_index_errors=>true) do
|
396
|
+
Integer :c1, :null=>false
|
397
|
+
BigDecimal :c2, :null=>false
|
398
|
+
|
399
|
+
primary_key [:c1, :c2]
|
400
|
+
|
401
|
+
index [:c1], :name=>:i1
|
402
|
+
index [:c2, :c1], :name=>:t1_c2_c1_index
|
403
|
+
end
|
404
|
+
end
|
405
|
+
|
406
|
+
down do
|
407
|
+
drop_table(:t2, :t1)
|
408
|
+
end
|
409
|
+
end
|
410
|
+
END_MIG
|
411
|
+
end
|
412
|
+
|
413
|
+
it "should honor the :index_names => :namespace option to include names of indexes with prepended table name if there is no global index namespace" do
|
414
|
+
@d.meta_def(:global_index_namespace?){false}
|
415
|
+
@d.meta_def(:indexes) do |t|
|
416
|
+
{:i1=>{:columns=>[:c1], :unique=>false},
|
417
|
+
:t1_c2_c1_index=>{:columns=>[:c2, :c1], :unique=>false}}
|
418
|
+
end
|
419
|
+
@d.dump_table_schema(:t1, :index_names=>:namespace).should == "create_table(:t1, :ignore_index_errors=>true) do\n primary_key :c1\n String :c2, :size=>20\n \n index [:c1], :name=>:t1_i1\n index [:c2, :c1]\nend"
|
420
|
+
@d.dump_schema_migration(:index_names=>:namespace).should == <<-END_MIG
|
421
|
+
Sequel.migration do
|
422
|
+
up do
|
423
|
+
create_table(:t1, :ignore_index_errors=>true) do
|
424
|
+
primary_key :c1
|
425
|
+
String :c2, :size=>20
|
426
|
+
|
427
|
+
index [:c1], :name=>:t1_i1
|
428
|
+
index [:c2, :c1]
|
429
|
+
end
|
430
|
+
|
431
|
+
create_table(:t2, :ignore_index_errors=>true) do
|
432
|
+
Integer :c1, :null=>false
|
433
|
+
BigDecimal :c2, :null=>false
|
434
|
+
|
435
|
+
primary_key [:c1, :c2]
|
436
|
+
|
437
|
+
index [:c1], :name=>:t2_i1
|
438
|
+
index [:c2, :c1], :name=>:t2_t1_c2_c1_index
|
439
|
+
end
|
440
|
+
end
|
441
|
+
|
442
|
+
down do
|
443
|
+
drop_table(:t2, :t1)
|
444
|
+
end
|
445
|
+
end
|
446
|
+
END_MIG
|
447
|
+
end
|
448
|
+
|
343
449
|
it "should honor the :indexes => false option to not include indexes" do
|
344
450
|
@d.meta_def(:indexes) do |t|
|
345
451
|
{:i1=>{:columns=>[:c1], :unique=>false},
|
@@ -397,8 +503,84 @@ Sequel.migration do
|
|
397
503
|
end
|
398
504
|
|
399
505
|
down do
|
506
|
+
drop_index :t1, [:c2, :c1], :ignore_errors=>true, :unique=>true
|
400
507
|
drop_index :t1, [:c1], :ignore_errors=>true, :name=>:i1
|
508
|
+
end
|
509
|
+
end
|
510
|
+
END_MIG
|
511
|
+
end
|
512
|
+
|
513
|
+
it "should honor the :index_names => false option to not include names of indexes when dumping just indexes as a migration" do
|
514
|
+
@d.meta_def(:tables){|o| [:t1]}
|
515
|
+
@d.meta_def(:indexes) do |t|
|
516
|
+
{:i1=>{:columns=>[:c1], :unique=>false},
|
517
|
+
:t1_c2_c1_index=>{:columns=>[:c2, :c1], :unique=>true}}
|
518
|
+
end
|
519
|
+
@d.dump_indexes_migration(:index_names=>false).should == <<-END_MIG
|
520
|
+
Sequel.migration do
|
521
|
+
up do
|
522
|
+
add_index :t1, [:c1], :ignore_errors=>true
|
523
|
+
add_index :t1, [:c2, :c1], :ignore_errors=>true, :unique=>true
|
524
|
+
end
|
525
|
+
|
526
|
+
down do
|
401
527
|
drop_index :t1, [:c2, :c1], :ignore_errors=>true, :unique=>true
|
528
|
+
drop_index :t1, [:c1], :ignore_errors=>true
|
529
|
+
end
|
530
|
+
end
|
531
|
+
END_MIG
|
532
|
+
end
|
533
|
+
|
534
|
+
it "should honor the :index_names => :namespace option be a noop if there is a global index namespace" do
|
535
|
+
@d.meta_def(:tables){|o| [:t1, :t2]}
|
536
|
+
@d.meta_def(:indexes) do |t|
|
537
|
+
{:i1=>{:columns=>[:c1], :unique=>false},
|
538
|
+
:t1_c2_c1_index=>{:columns=>[:c2, :c1], :unique=>false}}
|
539
|
+
end
|
540
|
+
@d.dump_indexes_migration(:index_names=>:namespace).should == <<-END_MIG
|
541
|
+
Sequel.migration do
|
542
|
+
up do
|
543
|
+
add_index :t1, [:c1], :ignore_errors=>true, :name=>:i1
|
544
|
+
add_index :t1, [:c2, :c1], :ignore_errors=>true
|
545
|
+
|
546
|
+
add_index :t2, [:c1], :ignore_errors=>true, :name=>:i1
|
547
|
+
add_index :t2, [:c2, :c1], :ignore_errors=>true, :name=>:t1_c2_c1_index
|
548
|
+
end
|
549
|
+
|
550
|
+
down do
|
551
|
+
drop_index :t2, [:c2, :c1], :ignore_errors=>true, :name=>:t1_c2_c1_index
|
552
|
+
drop_index :t2, [:c1], :ignore_errors=>true, :name=>:i1
|
553
|
+
|
554
|
+
drop_index :t1, [:c2, :c1], :ignore_errors=>true
|
555
|
+
drop_index :t1, [:c1], :ignore_errors=>true, :name=>:i1
|
556
|
+
end
|
557
|
+
end
|
558
|
+
END_MIG
|
559
|
+
end
|
560
|
+
|
561
|
+
it "should honor the :index_names => :namespace option to include names of indexes with prepended table name when dumping just indexes as a migration if there is no global index namespace" do
|
562
|
+
@d.meta_def(:global_index_namespace?){false}
|
563
|
+
@d.meta_def(:tables){|o| [:t1, :t2]}
|
564
|
+
@d.meta_def(:indexes) do |t|
|
565
|
+
{:i1=>{:columns=>[:c1], :unique=>false},
|
566
|
+
:t1_c2_c1_index=>{:columns=>[:c2, :c1], :unique=>false}}
|
567
|
+
end
|
568
|
+
@d.dump_indexes_migration(:index_names=>:namespace).should == <<-END_MIG
|
569
|
+
Sequel.migration do
|
570
|
+
up do
|
571
|
+
add_index :t1, [:c1], :ignore_errors=>true, :name=>:t1_i1
|
572
|
+
add_index :t1, [:c2, :c1], :ignore_errors=>true
|
573
|
+
|
574
|
+
add_index :t2, [:c1], :ignore_errors=>true, :name=>:t2_i1
|
575
|
+
add_index :t2, [:c2, :c1], :ignore_errors=>true, :name=>:t2_t1_c2_c1_index
|
576
|
+
end
|
577
|
+
|
578
|
+
down do
|
579
|
+
drop_index :t2, [:c2, :c1], :ignore_errors=>true, :name=>:t2_t1_c2_c1_index
|
580
|
+
drop_index :t2, [:c1], :ignore_errors=>true, :name=>:t2_i1
|
581
|
+
|
582
|
+
drop_index :t1, [:c2, :c1], :ignore_errors=>true
|
583
|
+
drop_index :t1, [:c1], :ignore_errors=>true, :name=>:t1_i1
|
402
584
|
end
|
403
585
|
end
|
404
586
|
END_MIG
|
@@ -508,7 +690,9 @@ END_MIG
|
|
508
690
|
["double precision", "timestamp with time zone", "timestamp without time zone",
|
509
691
|
"time with time zone", "time without time zone", "character varying(20)"] +
|
510
692
|
%w"nvarchar ntext smalldatetime smallmoney binary varbinary nchar" +
|
511
|
-
["timestamp(6) without time zone", "timestamp(6) with time zone",
|
693
|
+
["timestamp(6) without time zone", "timestamp(6) with time zone", 'mediumint(10) unsigned', 'int(9) unsigned',
|
694
|
+
'int(10) unsigned', "int(12) unsigned", 'bigint unsigned', 'tinyint(3) unsigned', 'identity', 'int identity'] +
|
695
|
+
%w"integer(10)"
|
512
696
|
@d.meta_def(:schema) do |t, *o|
|
513
697
|
i = 0
|
514
698
|
types.map{|x| [:"c#{i+=1}", {:db_type=>x, :allow_null=>true}]}
|
@@ -579,10 +763,14 @@ create_table(:x) do
|
|
579
763
|
DateTime :c62, :size=>6
|
580
764
|
DateTime :c63, :size=>6
|
581
765
|
Integer :c64
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
766
|
+
Integer :c65
|
767
|
+
Bignum :c66
|
768
|
+
Bignum :c67
|
769
|
+
Bignum :c68
|
770
|
+
Integer :c69
|
771
|
+
Integer :c70
|
772
|
+
Integer :c71
|
773
|
+
Integer :c72
|
586
774
|
end
|
587
775
|
END_MIG
|
588
776
|
end
|
@@ -72,6 +72,10 @@ describe "Serialization plugin" do
|
|
72
72
|
MODEL_DB.sqls.should == ["INSERT INTO items (abc) VALUES ('olleh')"]
|
73
73
|
end
|
74
74
|
|
75
|
+
it "should raise an error if specificing serializer as an unregistered symbol" do
|
76
|
+
proc{@c.plugin :serialization, :foo, :abc}.should raise_error(Sequel::Error)
|
77
|
+
end
|
78
|
+
|
75
79
|
it "should translate values to and from yaml serialization format using accessor methods" do
|
76
80
|
@c.set_primary_key :id
|
77
81
|
@c.plugin :serialization, :yaml, :abc, :def
|
@@ -8,7 +8,15 @@ unless Sequel.const_defined?('Model')
|
|
8
8
|
require 'sequel/model'
|
9
9
|
end
|
10
10
|
|
11
|
-
|
11
|
+
begin
|
12
|
+
# Attempt to load ActiveSupport inflector first, so Sequel inflector
|
13
|
+
# can override it.
|
14
|
+
require 'active_support/inflector'
|
15
|
+
require 'active_support/string/inflections'
|
16
|
+
rescue LoadError
|
17
|
+
end
|
18
|
+
|
19
|
+
Sequel.extension(*%w'string_date_time inflector pagination query pretty_table blank migration schema_dumper looser_typecasting sql_expr thread_local_timezones to_dot columns_introspection server_block arbitrary_servers pg_auto_parameterize pg_statement_cache pg_hstore pg_hstore_ops pg_inet schema_caching null_dataset select_remove query_literals')
|
12
20
|
{:hook_class_methods=>[], :schema=>[], :validation_class_methods=>[]}.each{|p, opts| Sequel::Model.plugin(p, *opts)}
|
13
21
|
|
14
22
|
Sequel::Dataset.introspect_all_columns if ENV['SEQUEL_COLUMNS_INTROSPECTION']
|
@@ -52,4 +52,12 @@ describe "Sequel::Plugins::TacticalEagerLoading" do
|
|
52
52
|
@ds.should_not_receive(:eager_load)
|
53
53
|
ts.map{|x| x.parent}.should == [ts[2], ts[3], nil, nil]
|
54
54
|
end
|
55
|
+
|
56
|
+
it "should handle case where an association is valid on an instance, but not on all instances" do
|
57
|
+
c = Class.new(@c)
|
58
|
+
c.many_to_one :parent2, :class=>@c, :key=>:parent_id
|
59
|
+
@c.dataset.row_proc = proc{|r| (r[:parent_id] == 101 ? c : @c).call(r)}
|
60
|
+
@c.all{|x| x.parent2 if x.is_a?(c)}
|
61
|
+
end
|
62
|
+
|
55
63
|
end
|
@@ -24,7 +24,11 @@ describe Sequel::Database do
|
|
24
24
|
begin
|
25
25
|
INTEGRATION_DB << "SELECT"
|
26
26
|
rescue Sequel::DatabaseError=>e
|
27
|
-
|
27
|
+
if defined?(Java::JavaLang::Exception)
|
28
|
+
(e.wrapped_exception.is_a?(Exception) || e.wrapped_exception.is_a?(Java::JavaLang::Exception)).should be_true
|
29
|
+
else
|
30
|
+
e.wrapped_exception.should be_a_kind_of(Exception)
|
31
|
+
end
|
28
32
|
end
|
29
33
|
end
|
30
34
|
|
@@ -17,6 +17,7 @@ describe "Prepared Statements and Bound Arguments" do
|
|
17
17
|
end
|
18
18
|
|
19
19
|
specify "should support bound variables when selecting" do
|
20
|
+
@ds.filter(:numb=>:$n).call(:each, :n=>10){|h| h.should == {:id=>1, :numb=>10}}
|
20
21
|
@ds.filter(:numb=>:$n).call(:select, :n=>10).should == [{:id=>1, :numb=>10}]
|
21
22
|
@ds.filter(:numb=>:$n).call(:all, :n=>10).should == [{:id=>1, :numb=>10}]
|
22
23
|
@ds.filter(:numb=>:$n).call(:first, :n=>10).should == {:id=>1, :numb=>10}
|
@@ -25,7 +26,9 @@ describe "Prepared Statements and Bound Arguments" do
|
|
25
26
|
@ds.filter(:numb=>:$n).call([:to_hash_groups, :id, :numb], :n=>10).should == {1=>[10]}
|
26
27
|
end
|
27
28
|
|
28
|
-
specify "should support blocks for select, all, and map " do
|
29
|
+
specify "should support blocks for each, select, all, and map when using bound variables" do
|
30
|
+
a = []
|
31
|
+
@ds.filter(:numb=>:$n).call(:each, :n=>10){|r| r[:numb] *= 2; a << r}; a.should == [{:id=>1, :numb=>20}]
|
29
32
|
@ds.filter(:numb=>:$n).call(:select, :n=>10){|r| r[:numb] *= 2}.should == [{:id=>1, :numb=>20}]
|
30
33
|
@ds.filter(:numb=>:$n).call(:all, :n=>10){|r| r[:numb] *= 2}.should == [{:id=>1, :numb=>20}]
|
31
34
|
@ds.filter(:numb=>:$n).call([:map], :n=>10){|r| r[:numb] * 2}.should == [20]
|
@@ -125,6 +128,8 @@ describe "Prepared Statements and Bound Arguments" do
|
|
125
128
|
end
|
126
129
|
|
127
130
|
specify "should support prepared statements when selecting" do
|
131
|
+
@ds.filter(:numb=>:$n).prepare(:each, :select_n)
|
132
|
+
@db.call(:select_n, :n=>10){|h| h.should == {:id=>1, :numb=>10}}
|
128
133
|
@ds.filter(:numb=>:$n).prepare(:select, :select_n)
|
129
134
|
@db.call(:select_n, :n=>10).should == [{:id=>1, :numb=>10}]
|
130
135
|
@ds.filter(:numb=>:$n).prepare(:all, :select_n)
|
@@ -137,7 +142,20 @@ describe "Prepared Statements and Bound Arguments" do
|
|
137
142
|
@db.call(:select_n, :n=>10).should == {1=>10}
|
138
143
|
end
|
139
144
|
|
140
|
-
specify "should support
|
145
|
+
specify "should support blocks for each, select, all, and map when using prepared statements" do
|
146
|
+
a = []
|
147
|
+
@ds.filter(:numb=>:$n).prepare(:each, :select_n).call(:n=>10){|r| r[:numb] *= 2; a << r}; a.should == [{:id=>1, :numb=>20}]
|
148
|
+
a = []
|
149
|
+
@db.call(:select_n, :n=>10){|r| r[:numb] *= 2; a << r}; a.should == [{:id=>1, :numb=>20}]
|
150
|
+
@ds.filter(:numb=>:$n).prepare(:select, :select_n).call(:n=>10){|r| r[:numb] *= 2}.should == [{:id=>1, :numb=>20}]
|
151
|
+
@db.call(:select_n, :n=>10){|r| r[:numb] *= 2}.should == [{:id=>1, :numb=>20}]
|
152
|
+
@ds.filter(:numb=>:$n).prepare(:all, :select_n).call(:n=>10){|r| r[:numb] *= 2}.should == [{:id=>1, :numb=>20}]
|
153
|
+
@db.call(:select_n, :n=>10){|r| r[:numb] *= 2}.should == [{:id=>1, :numb=>20}]
|
154
|
+
@ds.filter(:numb=>:$n).prepare([:map], :select_n).call(:n=>10){|r| r[:numb] *= 2}.should == [20]
|
155
|
+
@db.call(:select_n, :n=>10){|r| r[:numb] *= 2}.should == [20]
|
156
|
+
end
|
157
|
+
|
158
|
+
specify "should support prepared statements being called multiple times with different arguments" do
|
141
159
|
@ds.filter(:numb=>:$n).prepare(:select, :select_n)
|
142
160
|
@db.call(:select_n, :n=>10).should == [{:id=>1, :numb=>10}]
|
143
161
|
@db.call(:select_n, :n=>0).should == []
|
@@ -457,6 +457,20 @@ describe Sequel::Model, "many_to_one" do
|
|
457
457
|
MODEL_DB.sqls.should == []
|
458
458
|
end
|
459
459
|
|
460
|
+
it "should have the setter not modify the reciprocal if set to same value as current" do
|
461
|
+
@c2.many_to_one :parent, :class => @c2
|
462
|
+
@c2.one_to_many :children, :class => @c2, :key=>:parent_id
|
463
|
+
|
464
|
+
c1 = @c2.load(:id => 1, :parent_id=>nil)
|
465
|
+
c2 = @c2.load(:id => 2, :parent_id=>1)
|
466
|
+
c3 = @c2.load(:id => 3, :parent_id=>1)
|
467
|
+
c1.associations[:children] = [c2, c3]
|
468
|
+
c2.associations[:parent] = c1
|
469
|
+
c2.parent = c1
|
470
|
+
c1.children.should == [c2, c3]
|
471
|
+
MODEL_DB.sqls.should == []
|
472
|
+
end
|
473
|
+
|
460
474
|
it "should get all matching records and only return the first if :key option is set to nil" do
|
461
475
|
@c2.one_to_many :children, :class => @c2, :key=>:parent_id
|
462
476
|
@c2.many_to_one :first_grand_parent, :class => @c2, :key=>nil, :eager_graph=>:children, :dataset=>proc{model.filter(:children_id=>parent_id)}
|
@@ -959,6 +973,19 @@ describe Sequel::Model, "one_to_one" do
|
|
959
973
|
f.child.should == nil
|
960
974
|
end
|
961
975
|
|
976
|
+
it "should have the setter not modify the reciprocal if set to same value as current" do
|
977
|
+
@c2.one_to_one :parent, :class => @c2, :key=>:parent_id
|
978
|
+
@c2.many_to_one :child, :class => @c2, :key=>:parent_id
|
979
|
+
|
980
|
+
c1 = @c2.load(:id => 1, :parent_id=>nil)
|
981
|
+
c2 = @c2.load(:id => 2, :parent_id=>1)
|
982
|
+
c1.associations[:child] = c2
|
983
|
+
c2.associations[:parent] = c1
|
984
|
+
c2.parent = c1
|
985
|
+
c1.child.should == c2
|
986
|
+
MODEL_DB.sqls.should == []
|
987
|
+
end
|
988
|
+
|
962
989
|
it "should not add associations methods directly to class" do
|
963
990
|
@c2.one_to_one :parent, :class => @c2
|
964
991
|
@c2.instance_methods.collect{|x| x.to_s}.should(include('parent'))
|
data/spec/model/base_spec.rb
CHANGED
@@ -9,6 +9,12 @@ describe "Model attribute setters" do
|
|
9
9
|
MODEL_DB.reset
|
10
10
|
end
|
11
11
|
|
12
|
+
specify "refresh should return self" do
|
13
|
+
@o = @c[1]
|
14
|
+
@o.stub(:_refresh).and_return([])
|
15
|
+
@o.refresh.should == @o
|
16
|
+
end
|
17
|
+
|
12
18
|
it "should mark the column value as changed" do
|
13
19
|
@o.changed_columns.should == []
|
14
20
|
|
@@ -349,6 +355,54 @@ describe "Model.qualified_primary_key_hash" do
|
|
349
355
|
end
|
350
356
|
end
|
351
357
|
|
358
|
+
describe "Model.db" do
|
359
|
+
before do
|
360
|
+
@db = Sequel.mock
|
361
|
+
@databases = Sequel::DATABASES.dup
|
362
|
+
@model_db = Sequel::Model.db
|
363
|
+
Sequel::Model.db = nil
|
364
|
+
Sequel::DATABASES.clear
|
365
|
+
end
|
366
|
+
after do
|
367
|
+
Sequel::Model.instance_variable_get(:@db).should == nil
|
368
|
+
Sequel::DATABASES.replace(@databases)
|
369
|
+
Sequel::Model.db = @model_db
|
370
|
+
end
|
371
|
+
|
372
|
+
specify "should be required when create named model classes" do
|
373
|
+
begin
|
374
|
+
proc{class ModelTest < Sequel::Model; end}.should raise_error(Sequel::Error)
|
375
|
+
ensure
|
376
|
+
Object.send(:remove_const, :ModelTest)
|
377
|
+
end
|
378
|
+
end
|
379
|
+
|
380
|
+
specify "should be required when creating anonymous model classes without a database" do
|
381
|
+
proc{Sequel::Model(:foo)}.should raise_error(Sequel::Error)
|
382
|
+
end
|
383
|
+
|
384
|
+
specify "should not be required when creating anonymous model classes with a database" do
|
385
|
+
Sequel::Model(@db).db.should == @db
|
386
|
+
Sequel::Model(@db[:foo]).db.should == @db
|
387
|
+
end
|
388
|
+
|
389
|
+
specify "should work correctly when subclassing anonymous model classes with a database" do
|
390
|
+
begin
|
391
|
+
Class.new(Sequel::Model(@db)).db.should == @db
|
392
|
+
Class.new(Sequel::Model(@db[:foo])).db.should == @db
|
393
|
+
class ModelTest < Sequel::Model(@db)
|
394
|
+
db.should == @db
|
395
|
+
end
|
396
|
+
class ModelTest2 < Sequel::Model(@db[:foo])
|
397
|
+
db.should == @db
|
398
|
+
end
|
399
|
+
ensure
|
400
|
+
Object.send(:remove_const, :ModelTest)
|
401
|
+
Object.send(:remove_const, :ModelTest2)
|
402
|
+
end
|
403
|
+
end
|
404
|
+
end
|
405
|
+
|
352
406
|
describe "Model.db=" do
|
353
407
|
before do
|
354
408
|
@db1 = Sequel.mock
|