sequel 4.31.0 → 4.32.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +24 -0
- data/Rakefile +17 -15
- data/doc/association_basics.rdoc +7 -3
- data/doc/opening_databases.rdoc +7 -0
- data/doc/release_notes/4.32.0.txt +132 -0
- data/doc/schema_modification.rdoc +1 -1
- data/doc/security.rdoc +70 -26
- data/doc/testing.rdoc +1 -0
- data/lib/sequel/adapters/jdbc.rb +2 -1
- data/lib/sequel/adapters/postgres.rb +3 -4
- data/lib/sequel/adapters/shared/mysql.rb +14 -1
- data/lib/sequel/adapters/shared/sqlite.rb +2 -2
- data/lib/sequel/extensions/_pretty_table.rb +2 -0
- data/lib/sequel/extensions/arbitrary_servers.rb +2 -0
- data/lib/sequel/extensions/columns_introspection.rb +2 -0
- data/lib/sequel/extensions/connection_validator.rb +2 -0
- data/lib/sequel/extensions/constraint_validations.rb +2 -0
- data/lib/sequel/extensions/core_extensions.rb +1 -5
- data/lib/sequel/extensions/current_datetime_timestamp.rb +2 -0
- data/lib/sequel/extensions/dataset_source_alias.rb +2 -0
- data/lib/sequel/extensions/date_arithmetic.rb +2 -0
- data/lib/sequel/extensions/empty_array_consider_nulls.rb +3 -1
- data/lib/sequel/extensions/error_sql.rb +2 -0
- data/lib/sequel/extensions/eval_inspect.rb +2 -0
- data/lib/sequel/extensions/filter_having.rb +2 -0
- data/lib/sequel/extensions/from_block.rb +2 -0
- data/lib/sequel/extensions/graph_each.rb +2 -0
- data/lib/sequel/extensions/hash_aliases.rb +2 -0
- data/lib/sequel/extensions/inflector.rb +2 -0
- data/lib/sequel/extensions/looser_typecasting.rb +3 -1
- data/lib/sequel/extensions/meta_def.rb +2 -0
- data/lib/sequel/extensions/migration.rb +4 -0
- data/lib/sequel/extensions/mssql_emulate_lateral_with_apply.rb +2 -0
- data/lib/sequel/extensions/named_timezones.rb +2 -0
- data/lib/sequel/extensions/no_auto_literal_strings.rb +84 -0
- data/lib/sequel/extensions/null_dataset.rb +2 -0
- data/lib/sequel/extensions/pagination.rb +2 -0
- data/lib/sequel/extensions/pg_array.rb +2 -4
- data/lib/sequel/extensions/pg_array_ops.rb +2 -0
- data/lib/sequel/extensions/pg_enum.rb +2 -0
- data/lib/sequel/extensions/pg_hstore.rb +2 -4
- data/lib/sequel/extensions/pg_hstore_ops.rb +2 -0
- data/lib/sequel/extensions/pg_inet.rb +2 -4
- data/lib/sequel/extensions/pg_inet_ops.rb +2 -0
- data/lib/sequel/extensions/pg_interval.rb +2 -4
- data/lib/sequel/extensions/pg_json.rb +4 -4
- data/lib/sequel/extensions/pg_json_ops.rb +3 -0
- data/lib/sequel/extensions/pg_loose_count.rb +2 -0
- data/lib/sequel/extensions/pg_range.rb +2 -4
- data/lib/sequel/extensions/pg_range_ops.rb +2 -0
- data/lib/sequel/extensions/pg_row.rb +2 -4
- data/lib/sequel/extensions/pg_row_ops.rb +2 -0
- data/lib/sequel/extensions/pg_static_cache_updater.rb +2 -0
- data/lib/sequel/extensions/pretty_table.rb +2 -0
- data/lib/sequel/extensions/query.rb +3 -0
- data/lib/sequel/extensions/query_literals.rb +7 -5
- data/lib/sequel/extensions/round_timestamps.rb +4 -3
- data/lib/sequel/extensions/schema_caching.rb +2 -0
- data/lib/sequel/extensions/schema_dumper.rb +2 -0
- data/lib/sequel/extensions/select_remove.rb +2 -0
- data/lib/sequel/extensions/sequel_3_dataset_methods.rb +2 -0
- data/lib/sequel/extensions/server_block.rb +3 -0
- data/lib/sequel/extensions/set_overrides.rb +2 -0
- data/lib/sequel/extensions/split_array_nil.rb +2 -0
- data/lib/sequel/extensions/thread_local_timezones.rb +2 -0
- data/lib/sequel/extensions/to_dot.rb +2 -0
- data/lib/sequel/model/associations.rb +95 -55
- data/lib/sequel/plugins/association_pks.rb +58 -33
- data/lib/sequel/plugins/eager_each.rb +22 -0
- data/lib/sequel/plugins/pg_typecast_on_load.rb +3 -2
- data/lib/sequel/plugins/tactical_eager_loading.rb +44 -3
- data/lib/sequel/version.rb +2 -2
- data/spec/adapters/mysql_spec.rb +34 -6
- data/spec/adapters/oracle_spec.rb +1 -1
- data/spec/bin_spec.rb +2 -2
- data/spec/core/dataset_spec.rb +7 -0
- data/spec/extensions/association_pks_spec.rb +38 -0
- data/spec/extensions/class_table_inheritance_spec.rb +24 -0
- data/spec/extensions/eager_each_spec.rb +25 -1
- data/spec/extensions/no_auto_literal_strings_spec.rb +65 -0
- data/spec/extensions/pg_range_spec.rb +1 -0
- data/spec/extensions/spec_helper.rb +5 -5
- data/spec/extensions/tactical_eager_loading_spec.rb +71 -17
- data/spec/integration/associations_test.rb +77 -62
- data/spec/integration/dataset_test.rb +3 -3
- data/spec/integration/plugin_test.rb +22 -0
- data/spec/integration/prepared_statement_test.rb +8 -8
- data/spec/integration/spec_helper.rb +4 -0
- data/spec/model/association_reflection_spec.rb +30 -0
- data/spec/model/associations_spec.rb +177 -16
- metadata +6 -2
@@ -26,7 +26,6 @@ describe "Sequel::Plugins::EagerEach" do
|
|
26
26
|
it "should make #each on an eager_graph dataset do eager loading" do
|
27
27
|
a = []
|
28
28
|
ds = @c.eager_graph(:children)
|
29
|
-
ds._fetch = []
|
30
29
|
ds._fetch = [{:id=>1, :parent_id=>nil, :children_id=>3, :children_parent_id=>1}, {:id=>1, :parent_id=>nil, :children_id=>4, :children_parent_id=>1}, {:id=>2, :parent_id=>nil, :children_id=>5, :children_parent_id=>2}, {:id=>2, :parent_id=>nil, :children_id=>6, :children_parent_id=>2}]
|
31
30
|
ds.each{|c| a << c}
|
32
31
|
a.must_equal [@c.load(:id=>1, :parent_id=>nil), @c.load(:id=>2, :parent_id=>nil)]
|
@@ -34,6 +33,31 @@ describe "Sequel::Plugins::EagerEach" do
|
|
34
33
|
@c.db.sqls.must_equal ['SELECT items.id, items.parent_id, children.id AS children_id, children.parent_id AS children_parent_id FROM items LEFT OUTER JOIN items AS children ON (children.parent_id = items.id)']
|
35
34
|
end
|
36
35
|
|
36
|
+
it "should make #first on an eager dataset do eager loading" do
|
37
|
+
ds = @c.eager(:children)
|
38
|
+
ds._fetch = [{:id=>1, :parent_id=>nil}]
|
39
|
+
@c.dataset._fetch = [{:id=>3, :parent_id=>1}, {:id=>4, :parent_id=>1}]
|
40
|
+
a = ds.first
|
41
|
+
a.values.must_equal(:id=>1, :parent_id=>nil)
|
42
|
+
a.associations[:children].must_equal [@c.load(:id=>3, :parent_id=>1), @c.load(:id=>4, :parent_id=>1)]
|
43
|
+
@c.db.sqls.must_equal ['SELECT * FROM items LIMIT 1','SELECT * FROM items WHERE (items.parent_id IN (1))']
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should make #first on an eager_graph dataset do eager loading" do
|
47
|
+
ds = @c.eager_graph(:children)
|
48
|
+
ds._fetch = [[{:id=>1, :parent_id=>nil, :children_id=>3, :children_parent_id=>1}], [{:id=>1, :parent_id=>nil, :children_id=>3, :children_parent_id=>1}, {:id=>1, :parent_id=>nil, :children_id=>4, :children_parent_id=>1}]]
|
49
|
+
a = ds.first
|
50
|
+
a.values.must_equal(:id=>1, :parent_id=>nil)
|
51
|
+
a.associations[:children].must_equal [@c.load(:id=>3, :parent_id=>1), @c.load(:id=>4, :parent_id=>1)]
|
52
|
+
@c.db.sqls.must_equal ['SELECT items.id, items.parent_id, children.id AS children_id, children.parent_id AS children_parent_id FROM items LEFT OUTER JOIN items AS children ON (children.parent_id = items.id) LIMIT 1',
|
53
|
+
'SELECT items.id, items.parent_id, children.id AS children_id, children.parent_id AS children_parent_id FROM items LEFT OUTER JOIN items AS children ON (children.parent_id = items.id) WHERE (items.id = 1)']
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should make #first on a non-eager dataset work correctly" do
|
57
|
+
@c.dataset._fetch = [{:id=>1, :parent_id=>nil}]
|
58
|
+
@c.first.must_equal @c.load(:id=>1, :parent_id=>nil)
|
59
|
+
end
|
60
|
+
|
37
61
|
it "should not attempt to eager load when getting the columns" do
|
38
62
|
ds = @c.eager(:children)
|
39
63
|
def ds.all; raise; end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
|
2
|
+
|
3
|
+
describe "no_auto_literal_strings extension" do
|
4
|
+
before do
|
5
|
+
@ds = Sequel.mock[:t].extension(:no_auto_literal_strings)
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should raise exception for plain strings in filter methods" do
|
9
|
+
proc{@ds.where("a")}.must_raise Sequel::Error
|
10
|
+
proc{@ds.having("a")}.must_raise Sequel::Error
|
11
|
+
proc{@ds.filter("a")}.must_raise Sequel::Error
|
12
|
+
proc{@ds.exclude_where("a")}.must_raise Sequel::Error
|
13
|
+
proc{@ds.exclude_having("a")}.must_raise Sequel::Error
|
14
|
+
proc{@ds.and("a")}.must_raise Sequel::Error
|
15
|
+
proc{@ds.where(:a).or("a")}.must_raise Sequel::Error
|
16
|
+
proc{@ds.first("a")}.must_raise Sequel::Error
|
17
|
+
proc{@ds.order(:a).last("a")}.must_raise Sequel::Error
|
18
|
+
proc{@ds["a"]}.must_raise Sequel::Error
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should raise exception for plain strings arrays in filter methods" do
|
22
|
+
proc{@ds.where(["a"])}.must_raise Sequel::Error
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should handle explicit literal strings in filter methods" do
|
26
|
+
@ds.where(Sequel.lit("a")).sql.must_equal 'SELECT * FROM t WHERE (a)'
|
27
|
+
@ds.having(Sequel.lit("a")).sql.must_equal 'SELECT * FROM t HAVING (a)'
|
28
|
+
@ds.filter(Sequel.lit("a")).sql.must_equal 'SELECT * FROM t WHERE (a)'
|
29
|
+
@ds.exclude_where(Sequel.lit("a")).sql.must_equal 'SELECT * FROM t WHERE NOT (a)'
|
30
|
+
@ds.exclude_having(Sequel.lit("a")).sql.must_equal 'SELECT * FROM t HAVING NOT (a)'
|
31
|
+
@ds.and(Sequel.lit("a")).sql.must_equal 'SELECT * FROM t WHERE (a)'
|
32
|
+
@ds.where(:a).or(Sequel.lit("a")).sql.must_equal 'SELECT * FROM t WHERE (a OR (a))'
|
33
|
+
@ds.first(Sequel.lit("a"))
|
34
|
+
@ds.order(:a).last(Sequel.lit("a"))
|
35
|
+
@ds[Sequel.lit("a")]
|
36
|
+
@ds.db.sqls.must_equal ["SELECT * FROM t WHERE (a) LIMIT 1",
|
37
|
+
"SELECT * FROM t WHERE (a) ORDER BY a DESC LIMIT 1",
|
38
|
+
"SELECT * FROM t WHERE (a) LIMIT 1"]
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should handle literal strings in arrays in filter methods" do
|
42
|
+
@ds.where([Sequel.lit("a")]).sql.must_equal 'SELECT * FROM t WHERE (a)'
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should handle other objects in filter methods" do
|
46
|
+
@ds.where(:a).sql.must_equal 'SELECT * FROM t WHERE a'
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should raise exception for plain strings in update methods" do
|
50
|
+
proc{@ds.update("a = a + 1")}.must_raise Sequel::Error
|
51
|
+
proc{@ds.update_sql("a = a + 1")}.must_raise Sequel::Error
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should handle explicit literal strings in update methods" do
|
55
|
+
@ds.update_sql(Sequel.lit("a = a + 1")).must_equal "UPDATE t SET a = a + 1"
|
56
|
+
@ds.update(Sequel.lit("a = a + 1"))
|
57
|
+
@ds.db.sqls.must_equal ["UPDATE t SET a = a + 1"]
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should handle other objects in update methods" do
|
61
|
+
@ds.update_sql(:a=>:a).must_equal "UPDATE t SET a = a"
|
62
|
+
@ds.update(:a=>:a)
|
63
|
+
@ds.db.sqls.must_equal ["UPDATE t SET a = a"]
|
64
|
+
end
|
65
|
+
end
|
@@ -38,6 +38,7 @@ describe "pg_range extension" do
|
|
38
38
|
@db.literal(@R.new(1, nil)).must_equal "'[1,]'"
|
39
39
|
@db.literal(@R.new(1, 2, :db_type=>'int8range')).must_equal "int8range(1,2,'[]')"
|
40
40
|
@db.literal(@R.new(nil, nil, :empty=>true)).must_equal "'empty'"
|
41
|
+
@db.literal(@R.new(nil, nil, :empty=>true, :db_type=>'int8range')).must_equal "'empty'::int8range"
|
41
42
|
@db.literal(@R.new("", 2)).must_equal "'[\"\",2]'"
|
42
43
|
end
|
43
44
|
|
@@ -1,15 +1,15 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
|
3
|
-
gem 'minitest'
|
4
|
-
require 'minitest/autorun'
|
5
|
-
require 'minitest/hooks/default'
|
6
|
-
require 'minitest/shared_description'
|
7
|
-
|
8
3
|
if ENV['COVERAGE']
|
9
4
|
require File.join(File.dirname(File.expand_path(__FILE__)), "../sequel_coverage")
|
10
5
|
SimpleCov.sequel_coverage(:filter=>%r{lib/sequel/(extensions|plugins)/\w+\.rb\z})
|
11
6
|
end
|
12
7
|
|
8
|
+
gem 'minitest'
|
9
|
+
require 'minitest/autorun'
|
10
|
+
require 'minitest/hooks/default'
|
11
|
+
require 'minitest/shared_description'
|
12
|
+
|
13
13
|
unless Object.const_defined?('Sequel') && Sequel.const_defined?('Model')
|
14
14
|
$:.unshift(File.join(File.dirname(File.expand_path(__FILE__)), "../../lib/"))
|
15
15
|
require 'sequel'
|
@@ -1,8 +1,22 @@
|
|
1
1
|
require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
|
2
2
|
|
3
3
|
describe "Sequel::Plugins::TacticalEagerLoading" do
|
4
|
+
def sql_match(*args)
|
5
|
+
sqls = DB.sqls
|
6
|
+
sqls.length.must_equal args.length
|
7
|
+
sqls.zip(args).each do |is, should|
|
8
|
+
if should.is_a?(Regexp)
|
9
|
+
is.must_match should
|
10
|
+
else
|
11
|
+
is.must_equal should
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
attr_reader :ts
|
17
|
+
|
4
18
|
before do
|
5
|
-
class ::TacticalEagerLoadingModel < Sequel::Model
|
19
|
+
class ::TacticalEagerLoadingModel < Sequel::Model(:t)
|
6
20
|
plugin :tactical_eager_loading
|
7
21
|
columns :id, :parent_id
|
8
22
|
many_to_one :parent, :class=>self
|
@@ -22,61 +36,101 @@ describe "Sequel::Plugins::TacticalEagerLoading" do
|
|
22
36
|
@c = ::TacticalEagerLoadingModel
|
23
37
|
@ds = TacticalEagerLoadingModel.dataset
|
24
38
|
DB.reset
|
39
|
+
@ts = @c.all
|
40
|
+
sql_match('SELECT * FROM t')
|
25
41
|
end
|
26
42
|
after do
|
27
43
|
Object.send(:remove_const, :TacticalEagerLoadingModel)
|
44
|
+
sql_match
|
28
45
|
end
|
29
46
|
|
30
47
|
it "Dataset#all should set the retrieved_by and retrieved_with attributes" do
|
31
|
-
ts = @c.all
|
32
48
|
ts.map{|x| [x.retrieved_by, x.retrieved_with]}.must_equal [[@ds,ts], [@ds,ts], [@ds,ts], [@ds,ts]]
|
33
49
|
end
|
34
50
|
|
35
51
|
it "Dataset#all shouldn't raise an error if a Sequel::Model instance is not returned" do
|
36
52
|
@c.naked.all
|
53
|
+
sql_match('SELECT * FROM t')
|
37
54
|
end
|
38
55
|
|
39
56
|
it "association getter methods should eagerly load the association if the association isn't cached" do
|
40
|
-
DB.sqls.length.must_equal 0
|
41
|
-
ts = @c.all
|
42
|
-
DB.sqls.length.must_equal 1
|
43
57
|
ts.map{|x| x.parent}.must_equal [ts[2], ts[3], nil, nil]
|
44
|
-
|
58
|
+
sql_match(/\ASELECT \* FROM t WHERE \(t\.id IN \(10[12], 10[12]\)\)\z/)
|
45
59
|
ts.map{|x| x.children}.must_equal [[], [], [ts[0]], [ts[1]]]
|
46
|
-
|
60
|
+
sql_match(/\ASELECT \* FROM t WHERE \(t\.parent_id IN/)
|
47
61
|
end
|
48
62
|
|
49
63
|
it "association getter methods should not eagerly load the association if the association is cached" do
|
50
|
-
DB.sqls.length.must_equal 0
|
51
|
-
ts = @c.all
|
52
|
-
DB.sqls.length.must_equal 1
|
53
64
|
ts.map{|x| x.parent}.must_equal [ts[2], ts[3], nil, nil]
|
65
|
+
sql_match(/\ASELECT \* FROM t WHERE \(t\.id IN \(10[12], 10[12]\)\)\z/)
|
54
66
|
def @ds.eager_load(*) raise end
|
55
67
|
ts.map{|x| x.parent}.must_equal [ts[2], ts[3], nil, nil]
|
56
68
|
end
|
57
69
|
|
70
|
+
it "association getter methods should not eagerly load the association if a block is given" do
|
71
|
+
ts.map{|x| x.parent{|ds| ds}}.must_equal [ts[2], ts[3], nil, nil]
|
72
|
+
sql_match('SELECT * FROM t WHERE (t.id = 101) LIMIT 1', 'SELECT * FROM t WHERE (t.id = 102) LIMIT 1')
|
73
|
+
end
|
74
|
+
|
75
|
+
it "association getter methods should not eagerly load the association if a callback proc is given" do
|
76
|
+
ts.map{|x| x.parent(:callback=>proc{|ds| ds})}.must_equal [ts[2], ts[3], nil, nil]
|
77
|
+
sql_match('SELECT * FROM t WHERE (t.id = 101) LIMIT 1', 'SELECT * FROM t WHERE (t.id = 102) LIMIT 1')
|
78
|
+
end
|
79
|
+
|
80
|
+
it "association getter methods should not eagerly load the association if true is passed" do
|
81
|
+
ts.map{|x| x.parent(true)}.must_equal [ts[2], ts[3], nil, nil]
|
82
|
+
sql_match('SELECT * FROM t WHERE id = 101', 'SELECT * FROM t WHERE id = 102')
|
83
|
+
end
|
84
|
+
|
85
|
+
it "association getter methods should not eagerly load the association if :reload=>true is passed" do
|
86
|
+
ts.map{|x| x.parent(:reload=>true)}.must_equal [ts[2], ts[3], nil, nil]
|
87
|
+
sql_match('SELECT * FROM t WHERE id = 101', 'SELECT * FROM t WHERE id = 102')
|
88
|
+
end
|
89
|
+
|
90
|
+
it "association getter methods should eagerly reload the association if :eager_reload=>true is passed" do
|
91
|
+
ts.first.parent(:reload=>true)
|
92
|
+
sql_match('SELECT * FROM t WHERE id = 101')
|
93
|
+
ts.map{|x| x.associations.fetch(:parent, 1)}.must_equal [ts[2], 1, 1, 1]
|
94
|
+
ts.first.parent(:eager_reload=>true)
|
95
|
+
sql_match(/\ASELECT \* FROM t WHERE \(t\.id IN \(10[12], 10[12]\)\)\z/)
|
96
|
+
ts.map{|x| x.associations.fetch(:parent, 1)}.must_equal [ts[2], ts[3], nil, nil]
|
97
|
+
end
|
98
|
+
|
99
|
+
it "association getter methods should support eagerly loading dependent associations via :eager" do
|
100
|
+
parents = ts.map{|x| x.parent(:eager=>:children)}
|
101
|
+
sql_match(/\ASELECT \* FROM t WHERE \(t\.id IN \(10[12], 10[12]\)\)\z/, /\ASELECT \* FROM t WHERE \(t\.parent_id IN/)
|
102
|
+
parents.must_equal [ts[2], ts[3], nil, nil]
|
103
|
+
parents[0..1].map{|x| x.children}.must_equal [[ts[0]], [ts[1]]]
|
104
|
+
end
|
105
|
+
|
106
|
+
it "association getter methods should support eager callbacks via :eager" do
|
107
|
+
parents = ts.map{|x| x.parent(:eager=>proc{|ds| ds.where{name > 'M'}.eager(:children)})}
|
108
|
+
sql_match(/\ASELECT \* FROM t WHERE \(\(t\.id IN \(10[12], 10[12]\)\) AND \(name > 'M'\)\)\z/, /\ASELECT \* FROM t WHERE \(t\.parent_id IN/)
|
109
|
+
parents.must_equal [ts[2], ts[3], nil, nil]
|
110
|
+
parents[0..1].map{|x| x.children}.must_equal [[ts[0]], [ts[1]]]
|
111
|
+
end
|
112
|
+
|
58
113
|
it "should handle case where an association is valid on an instance, but not on all instances" do
|
59
114
|
c = Class.new(@c)
|
60
115
|
c.many_to_one :parent2, :class=>@c, :key=>:parent_id
|
61
116
|
@c.dataset.row_proc = proc{|r| (r[:parent_id] == 101 ? c : @c).call(r)}
|
62
117
|
@c.all{|x| x.parent2 if x.is_a?(c)}
|
118
|
+
sql_match('SELECT * FROM t', 'SELECT * FROM t WHERE id = 101')
|
63
119
|
end
|
64
120
|
|
65
121
|
it "association getter methods should not eagerly load the association if an instance is frozen" do
|
66
|
-
ts = @c.all
|
67
122
|
ts.first.freeze
|
68
|
-
DB.sqls.length.must_equal 1
|
69
123
|
ts.map{|x| x.parent}.must_equal [ts[2], ts[3], nil, nil]
|
70
|
-
|
124
|
+
sql_match('SELECT * FROM t WHERE id = 101', 'SELECT * FROM t WHERE (t.id IN (102))')
|
71
125
|
ts.map{|x| x.children}.must_equal [[], [], [ts[0]], [ts[1]]]
|
72
|
-
|
126
|
+
sql_match('SELECT * FROM t WHERE (t.parent_id = 1)', /\ASELECT \* FROM t WHERE \(t\.parent_id IN/)
|
73
127
|
ts.map{|x| x.parent}.must_equal [ts[2], ts[3], nil, nil]
|
74
|
-
|
128
|
+
sql_match('SELECT * FROM t WHERE id = 101')
|
75
129
|
ts.map{|x| x.children}.must_equal [[], [], [ts[0]], [ts[1]]]
|
76
|
-
|
130
|
+
sql_match('SELECT * FROM t WHERE (t.parent_id = 1)')
|
77
131
|
end
|
78
132
|
|
79
133
|
it "#marshallable should make marshalling not fail" do
|
80
|
-
Marshal.dump(
|
134
|
+
Marshal.dump(ts.map{|x| x.marshallable!})
|
81
135
|
end
|
82
136
|
end
|
@@ -1501,22 +1501,83 @@ BasicRegularAndCompositeKeyAssociations = shared_description do
|
|
1501
1501
|
@album.tags.must_equal []
|
1502
1502
|
@album.alias_tags.must_equal []
|
1503
1503
|
@tag.albums.must_equal []
|
1504
|
+
unless @no_many_through_many
|
1505
|
+
@album.first_tag.must_equal nil
|
1506
|
+
end
|
1504
1507
|
end
|
1505
1508
|
|
1506
|
-
it "should have
|
1509
|
+
it "should have set methods work" do
|
1510
|
+
# many to one
|
1507
1511
|
@album.update(:artist => @artist)
|
1512
|
+
@album.reload.artist.must_equal @artist
|
1513
|
+
@album.update(:artist => nil)
|
1514
|
+
@album.reload.artist.must_equal nil
|
1515
|
+
|
1516
|
+
# one to one
|
1517
|
+
@artist.update(:first_album => @album)
|
1518
|
+
@artist.reload.first_album.must_equal @album
|
1519
|
+
@artist.update(:first_album => nil)
|
1520
|
+
@artist.reload.first_album.must_equal nil
|
1521
|
+
|
1522
|
+
unless @no_many_through_many
|
1523
|
+
tag = @pr.call.last
|
1524
|
+
# one through one
|
1525
|
+
@album.update(:first_tag => @tag)
|
1526
|
+
@album.reload.first_tag.must_equal @tag
|
1527
|
+
@album.update(:first_tag => @tag)
|
1528
|
+
@album.reload.first_tag.must_equal @tag
|
1529
|
+
@album.update(:first_tag => tag)
|
1530
|
+
@album.reload.first_tag.must_equal tag
|
1531
|
+
@album.update(:first_tag => nil)
|
1532
|
+
@album.reload.first_tag.must_equal nil
|
1533
|
+
@album.update(:first_tag => nil)
|
1534
|
+
@album.reload.first_tag.must_equal nil
|
1535
|
+
|
1536
|
+
# one through one with alias
|
1537
|
+
@album.update(:alias_t_tag => @tag)
|
1538
|
+
@album.reload.alias_t_tag.must_equal @tag
|
1539
|
+
@album.update(:alias_t_tag => nil)
|
1540
|
+
@album.reload.alias_t_tag.must_equal nil
|
1541
|
+
end
|
1542
|
+
end
|
1543
|
+
|
1544
|
+
it "should have add and remove methods work" do
|
1545
|
+
# one to many
|
1546
|
+
@artist.add_album(@album)
|
1547
|
+
@artist.reload.albums.must_equal [@album]
|
1548
|
+
@artist.remove_album(@album)
|
1549
|
+
@artist.reload.albums.must_equal []
|
1550
|
+
|
1551
|
+
# many to many
|
1508
1552
|
@album.add_tag(@tag)
|
1509
|
-
|
1510
|
-
@
|
1511
|
-
@artist.reload
|
1512
|
-
@tag.reload
|
1513
|
-
|
1514
|
-
@album.artist.must_equal @artist
|
1515
|
-
@artist.first_album.must_equal @album
|
1516
|
-
@artist.albums.must_equal [@album]
|
1517
|
-
@album.tags.must_equal [@tag]
|
1553
|
+
@album.reload.tags.must_equal [@tag]
|
1554
|
+
@tag.reload.albums.must_equal [@album]
|
1518
1555
|
@album.alias_tags.must_equal [@tag]
|
1519
|
-
@
|
1556
|
+
@album.remove_tag(@tag)
|
1557
|
+
@album.reload.tags.must_equal []
|
1558
|
+
|
1559
|
+
# many to many with alias
|
1560
|
+
@album.add_alias_tag(@tag)
|
1561
|
+
@album.reload.alias_tags.must_equal [@tag]
|
1562
|
+
@album.remove_alias_tag(@tag)
|
1563
|
+
@album.reload.alias_tags.must_equal []
|
1564
|
+
end
|
1565
|
+
|
1566
|
+
it "should have remove_all methods work" do
|
1567
|
+
# one to many
|
1568
|
+
@artist.add_album(@album)
|
1569
|
+
@artist.remove_all_albums
|
1570
|
+
@artist.reload.albums.must_equal []
|
1571
|
+
|
1572
|
+
# many to many
|
1573
|
+
@album.add_tag(@tag)
|
1574
|
+
@album.remove_all_tags
|
1575
|
+
@album.reload.tags.must_equal []
|
1576
|
+
|
1577
|
+
# many to many with alias
|
1578
|
+
@album.add_alias_tag(@tag)
|
1579
|
+
@album.remove_all_alias_tags
|
1580
|
+
@album.reload.alias_tags.must_equal []
|
1520
1581
|
end
|
1521
1582
|
|
1522
1583
|
it "should work correctly with prepared_statements_association plugin" do
|
@@ -1534,6 +1595,9 @@ BasicRegularAndCompositeKeyAssociations = shared_description do
|
|
1534
1595
|
@album.tags.must_equal [@tag]
|
1535
1596
|
@album.alias_tags.must_equal [@tag]
|
1536
1597
|
@tag.albums.must_equal [@album]
|
1598
|
+
unless @no_many_through_many
|
1599
|
+
@album.first_tag.must_equal @tag
|
1600
|
+
end
|
1537
1601
|
end
|
1538
1602
|
|
1539
1603
|
it "should have working dataset associations" do
|
@@ -1599,55 +1663,6 @@ BasicRegularAndCompositeKeyAssociations = shared_description do
|
|
1599
1663
|
Artist.filter(Artist.qualified_primary_key_hash(artist.pk)).albums.filter(Album.qualified_primary_key_hash(@album.pk)).tags.all.must_equal []
|
1600
1664
|
end
|
1601
1665
|
|
1602
|
-
it "should have remove methods work" do
|
1603
|
-
@album.update(:artist => @artist)
|
1604
|
-
@album.add_tag(@tag)
|
1605
|
-
|
1606
|
-
@album.update(:artist => nil)
|
1607
|
-
@album.remove_tag(@tag)
|
1608
|
-
|
1609
|
-
@album.add_alias_tag(@tag)
|
1610
|
-
@album.remove_alias_tag(@tag)
|
1611
|
-
|
1612
|
-
@album.reload
|
1613
|
-
@artist.reload
|
1614
|
-
@tag.reload
|
1615
|
-
|
1616
|
-
@album.artist.must_equal nil
|
1617
|
-
@artist.albums.must_equal []
|
1618
|
-
@album.tags.must_equal []
|
1619
|
-
@tag.albums.must_equal []
|
1620
|
-
|
1621
|
-
@album.add_alias_tag(@tag)
|
1622
|
-
@album.remove_alias_tag(@tag)
|
1623
|
-
|
1624
|
-
@album.reload
|
1625
|
-
@album.alias_tags.must_equal []
|
1626
|
-
end
|
1627
|
-
|
1628
|
-
it "should have remove_all methods work" do
|
1629
|
-
@artist.add_album(@album)
|
1630
|
-
@album.add_tag(@tag)
|
1631
|
-
|
1632
|
-
@album.remove_all_tags
|
1633
|
-
@artist.remove_all_albums
|
1634
|
-
|
1635
|
-
@album.reload
|
1636
|
-
@artist.reload
|
1637
|
-
@tag.reload
|
1638
|
-
|
1639
|
-
@album.artist.must_equal nil
|
1640
|
-
@artist.albums.must_equal []
|
1641
|
-
@album.tags.must_equal []
|
1642
|
-
@tag.albums.must_equal []
|
1643
|
-
|
1644
|
-
@album.add_alias_tag(@tag)
|
1645
|
-
@album.remove_all_alias_tags
|
1646
|
-
|
1647
|
-
@album.reload
|
1648
|
-
@album.alias_tags.must_equal []
|
1649
|
-
end
|
1650
|
-
|
1651
1666
|
it "should eager load via eager correctly" do
|
1652
1667
|
@album.update(:artist => @artist)
|
1653
1668
|
@album.add_tag(@tag)
|
@@ -1684,8 +1699,6 @@ BasicRegularAndCompositeKeyAssociations = shared_description do
|
|
1684
1699
|
end
|
1685
1700
|
|
1686
1701
|
RegularAndCompositeKeyAssociations = shared_description do
|
1687
|
-
include BasicRegularAndCompositeKeyAssociations
|
1688
|
-
|
1689
1702
|
describe "when filtering/excluding by associations when joining" do
|
1690
1703
|
def self_join(c)
|
1691
1704
|
c.join(Sequel.as(c.table_name, :b), Array(c.primary_key).zip(Array(c.primary_key))).select_all(c.table_name)
|
@@ -1884,6 +1897,7 @@ describe "Sequel::Model Simple Associations" do
|
|
1884
1897
|
@db.drop_table?(:albums_tags, :tags, :albums, :artists)
|
1885
1898
|
end
|
1886
1899
|
|
1900
|
+
include BasicRegularAndCompositeKeyAssociations
|
1887
1901
|
include RegularAndCompositeKeyAssociations
|
1888
1902
|
|
1889
1903
|
describe "with :correlated_subquery limit strategy" do
|
@@ -2160,6 +2174,7 @@ describe "Sequel::Model Composite Key Associations" do
|
|
2160
2174
|
@db.drop_table?(:albums_tags, :tags, :albums, :artists)
|
2161
2175
|
end
|
2162
2176
|
|
2177
|
+
include BasicRegularAndCompositeKeyAssociations
|
2163
2178
|
include RegularAndCompositeKeyAssociations
|
2164
2179
|
|
2165
2180
|
describe "with :correlated_subquery limit strategy" do
|