sequel 5.11.0 → 5.12.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/doc/advanced_associations.rdoc +132 -14
- data/doc/postgresql.rdoc +14 -0
- data/doc/release_notes/5.12.0.txt +141 -0
- data/lib/sequel/adapters/ado/mssql.rb +1 -1
- data/lib/sequel/adapters/oracle.rb +5 -6
- data/lib/sequel/adapters/postgres.rb +18 -5
- data/lib/sequel/adapters/shared/mysql.rb +5 -5
- data/lib/sequel/adapters/sqlite.rb +0 -5
- data/lib/sequel/adapters/tinytds.rb +0 -5
- data/lib/sequel/adapters/utils/emulate_offset_with_reverse_and_count.rb +2 -5
- data/lib/sequel/core.rb +6 -1
- data/lib/sequel/dataset/graph.rb +25 -9
- data/lib/sequel/dataset/placeholder_literalizer.rb +47 -17
- data/lib/sequel/dataset/prepared_statements.rb +86 -18
- data/lib/sequel/dataset/sql.rb +5 -1
- data/lib/sequel/extensions/caller_logging.rb +79 -0
- data/lib/sequel/extensions/constraint_validations.rb +1 -1
- data/lib/sequel/extensions/pg_static_cache_updater.rb +2 -2
- data/lib/sequel/model/associations.rb +56 -23
- data/lib/sequel/model/base.rb +3 -3
- data/lib/sequel/plugins/eager_graph_eager.rb +139 -0
- data/lib/sequel/plugins/static_cache.rb +9 -8
- data/lib/sequel/plugins/tactical_eager_loading.rb +63 -1
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/oracle_spec.rb +44 -0
- data/spec/adapters/postgres_spec.rb +39 -0
- data/spec/core/dataset_spec.rb +23 -9
- data/spec/core/object_graph_spec.rb +314 -284
- data/spec/extensions/caller_logging_spec.rb +52 -0
- data/spec/extensions/eager_graph_eager_spec.rb +100 -0
- data/spec/extensions/finder_spec.rb +1 -1
- data/spec/extensions/prepared_statements_spec.rb +7 -12
- data/spec/extensions/static_cache_spec.rb +14 -0
- data/spec/extensions/tactical_eager_loading_spec.rb +262 -1
- data/spec/integration/associations_test.rb +72 -0
- data/spec/integration/dataset_test.rb +3 -3
- data/spec/model/eager_loading_spec.rb +90 -0
- metadata +8 -2
@@ -0,0 +1,52 @@
|
|
1
|
+
require_relative "spec_helper"
|
2
|
+
require 'logger'
|
3
|
+
|
4
|
+
describe "caller_logging extension" do
|
5
|
+
before do
|
6
|
+
@db = Sequel.mock(:extensions=>[:caller_logging])
|
7
|
+
@log_stream = StringIO.new
|
8
|
+
@db.loggers << Logger.new(@log_stream)
|
9
|
+
@ds = @db[:items]
|
10
|
+
end
|
11
|
+
|
12
|
+
exec_sql_line = __LINE__ + 2
|
13
|
+
def exec_sql(sql)
|
14
|
+
@db[sql].all
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should log caller information, skipping internal Sequel code" do
|
18
|
+
exec_sql("SELECT * FROM items")
|
19
|
+
@log_stream.rewind
|
20
|
+
lines = @log_stream.read.split("\n")
|
21
|
+
lines.length.must_equal 1
|
22
|
+
lines[0].must_match(/ \(source: #{__FILE__}:#{exec_sql_line}:in `exec_sql'\) SELECT \* FROM items\z/)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should allow formatting of caller information" do
|
26
|
+
@db.caller_logging_formatter = lambda{|line| line.sub(/\A.+(caller_logging_spec\.rb:\d+).+\z/, '\1:')}
|
27
|
+
exec_sql("SELECT * FROM items")
|
28
|
+
@log_stream.rewind
|
29
|
+
lines = @log_stream.read.split("\n")
|
30
|
+
lines.length.must_equal 1
|
31
|
+
lines[0].must_match(/ caller_logging_spec\.rb:#{exec_sql_line}: SELECT \* FROM items\z/)
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should allow ignoring additional caller lines in application" do
|
35
|
+
@db.caller_logging_ignore = /exec_sql/
|
36
|
+
exec_sql("SELECT * FROM items"); line = __LINE__
|
37
|
+
@log_stream.rewind
|
38
|
+
lines = @log_stream.read.split("\n")
|
39
|
+
lines.length.must_equal 1
|
40
|
+
lines[0].must_match(/ \(source: #{__FILE__}:#{line}:in `block.+\) SELECT \* FROM items\z/)
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should not log caller information if all callers lines are filtered" do
|
44
|
+
@db.caller_logging_ignore = /./
|
45
|
+
exec_sql("SELECT * FROM items"); line = __LINE__
|
46
|
+
@log_stream.rewind
|
47
|
+
lines = @log_stream.read.split("\n")
|
48
|
+
lines.length.must_equal 1
|
49
|
+
lines[0].must_match(/ SELECT \* FROM items\z/)
|
50
|
+
lines[0].wont_match(/ source: #{__FILE__}/)
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require_relative "spec_helper"
|
2
|
+
|
3
|
+
describe "eager_graph_eager plugin" do
|
4
|
+
before do
|
5
|
+
@c = Class.new(Sequel::Model(:items))
|
6
|
+
@c.columns :id, :parent_id
|
7
|
+
@c.plugin :eager_graph_eager
|
8
|
+
@c.one_to_many :children, :class=>@c, :key=>:parent_id
|
9
|
+
@c.many_to_one :parent, :class=>@c
|
10
|
+
@c.db.sqls
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should support Dataset#eager_graph_eager for eager loading dependencies of eager_graph associations for one_to_many associations" do
|
14
|
+
a = @c.eager_graph(:children).
|
15
|
+
with_fetch([{:id=>1, :parent_id=>nil, :children_id=>3, :children_parent_id=>1}, {:id=>2, :parent_id=>nil}]).
|
16
|
+
eager_graph_eager([:children], :children=>proc{|ds| ds.with_fetch(:id=>4, :parent_id=>3)}).
|
17
|
+
all
|
18
|
+
@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)",
|
19
|
+
"SELECT * FROM items WHERE (items.parent_id IN (3))"]
|
20
|
+
|
21
|
+
a.must_equal [@c.load(:id=>1, :parent_id=>nil), @c.load(:id=>2, :parent_id=>nil)]
|
22
|
+
a.map(&:children).must_equal [[@c.load(:id=>3, :parent_id=>1)], []]
|
23
|
+
a.first.children.first.children.must_equal [@c.load(:id=>4, :parent_id=>3)]
|
24
|
+
@c.db.sqls.must_equal []
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should support Dataset#eager_graph_eager for eager loading dependencies of eager_graph associations for many_to_one associations" do
|
28
|
+
a = @c.eager_graph(:parent).
|
29
|
+
with_fetch([{:id=>4, :parent_id=>3, :parent_id_0=>3, :parent_parent_id=>1}, {:id=>2, :parent_id=>nil}]).
|
30
|
+
eager_graph_eager([:parent], :parent=>proc{|ds| ds.with_fetch(:id=>1, :parent_id=>nil)}).
|
31
|
+
all
|
32
|
+
@c.db.sqls.must_equal ["SELECT items.id, items.parent_id, parent.id AS parent_id_0, parent.parent_id AS parent_parent_id FROM items LEFT OUTER JOIN items AS parent ON (parent.id = items.parent_id)",
|
33
|
+
"SELECT * FROM items WHERE (items.id IN (1))"]
|
34
|
+
|
35
|
+
a.must_equal [@c.load(:id=>4, :parent_id=>3), @c.load(:id=>2, :parent_id=>nil)]
|
36
|
+
a.map(&:parent).must_equal [@c.load(:id=>3, :parent_id=>1), nil]
|
37
|
+
a.first.parent.parent.must_equal @c.load(:id=>1, :parent_id=>nil)
|
38
|
+
@c.db.sqls.must_equal []
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should support multiple entries in dependency chain" do
|
42
|
+
a = @c.eager_graph(:children=>:children).
|
43
|
+
with_fetch([{:id=>1, :parent_id=>nil, :children_id=>3, :children_parent_id=>1, :children_0_id=>4, :children_0_parent_id=>3}, {:id=>2, :parent_id=>nil}]).
|
44
|
+
eager_graph_eager([:children, :children], :children=>proc{|ds| ds.with_fetch(:id=>5, :parent_id=>4)}).
|
45
|
+
all
|
46
|
+
@c.db.sqls.must_equal ["SELECT items.id, items.parent_id, children.id AS children_id, children.parent_id AS children_parent_id, children_0.id AS children_0_id, children_0.parent_id AS children_0_parent_id FROM items LEFT OUTER JOIN items AS children ON (children.parent_id = items.id) LEFT OUTER JOIN items AS children_0 ON (children_0.parent_id = children.id)",
|
47
|
+
"SELECT * FROM items WHERE (items.parent_id IN (4))"]
|
48
|
+
|
49
|
+
a.must_equal [@c.load(:id=>1, :parent_id=>nil), @c.load(:id=>2, :parent_id=>nil)]
|
50
|
+
a.map(&:children).must_equal [[@c.load(:id=>3, :parent_id=>1)], []]
|
51
|
+
a.first.children.first.children.must_equal [@c.load(:id=>4, :parent_id=>3)]
|
52
|
+
a.first.children.first.children.first.children.must_equal [@c.load(:id=>5, :parent_id=>4)]
|
53
|
+
@c.db.sqls.must_equal []
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should support multiple dependency chains" do
|
57
|
+
a = @c.eager_graph(:children, :parent).
|
58
|
+
with_fetch([{:id=>4, :parent_id=>3, :children_id=>5, :children_parent_id=>4, :parent_id_0=>3, :parent_parent_id=>1}, {:id=>2, :parent_id=>nil}]).
|
59
|
+
eager_graph_eager([:children], :children=>proc{|ds| ds.with_fetch(:id=>6, :parent_id=>5)}).
|
60
|
+
eager_graph_eager([:parent], :parent=>proc{|ds| ds.with_fetch(:id=>1, :parent_id=>nil)}).
|
61
|
+
all
|
62
|
+
@c.db.sqls.must_equal ["SELECT items.id, items.parent_id, children.id AS children_id, children.parent_id AS children_parent_id, parent.id AS parent_id_0, parent.parent_id AS parent_parent_id FROM items LEFT OUTER JOIN items AS children ON (children.parent_id = items.id) LEFT OUTER JOIN items AS parent ON (parent.id = items.parent_id)",
|
63
|
+
"SELECT * FROM items WHERE (items.parent_id IN (5))",
|
64
|
+
"SELECT * FROM items WHERE (items.id IN (1))"]
|
65
|
+
|
66
|
+
a.must_equal [@c.load(:id=>4, :parent_id=>3), @c.load(:id=>2, :parent_id=>nil)]
|
67
|
+
a.map(&:children).must_equal [[@c.load(:id=>5, :parent_id=>4)], []]
|
68
|
+
a.map(&:parent).must_equal [@c.load(:id=>3, :parent_id=>1), nil]
|
69
|
+
a.first.children.first.children.must_equal [@c.load(:id=>6, :parent_id=>5)]
|
70
|
+
a.first.parent.parent.must_equal @c.load(:id=>1, :parent_id=>nil)
|
71
|
+
@c.db.sqls.must_equal []
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should raise for invalid dependency chains" do
|
75
|
+
proc{@c.dataset.eager_graph_eager([], :children)}.must_raise Sequel::Error
|
76
|
+
proc{@c.dataset.eager_graph_eager(:children, :children)}.must_raise Sequel::Error
|
77
|
+
proc{@c.dataset.eager_graph_eager(['foo'], :children)}.must_raise Sequel::Error
|
78
|
+
proc{@c.dataset.eager_graph_eager([:foo], :children)}.must_raise Sequel::Error
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should handle cases where not all associated objects are unique" do
|
82
|
+
a = @c.eager_graph(:parent=>:children).
|
83
|
+
with_fetch([
|
84
|
+
{:id=>4, :parent_id=>3, :parent_id_0=>3, :parent_parent_id=>1, :children_id=>4, :children_parent_id=>3},
|
85
|
+
{:id=>5, :parent_id=>3, :parent_id_0=>3, :parent_parent_id=>1, :children_id=>4, :children_parent_id=>3},
|
86
|
+
{:id=>4, :parent_id=>3, :parent_id_0=>3, :parent_parent_id=>1, :children_id=>5, :children_parent_id=>3},
|
87
|
+
{:id=>5, :parent_id=>3, :parent_id_0=>3, :parent_parent_id=>1, :children_id=>5, :children_parent_id=>3}
|
88
|
+
]).
|
89
|
+
eager_graph_eager([:parent], :parent=>proc{|ds| ds.with_fetch(:id=>1, :parent_id=>nil)}).
|
90
|
+
all
|
91
|
+
@c.db.sqls.must_equal ["SELECT items.id, items.parent_id, parent.id AS parent_id_0, parent.parent_id AS parent_parent_id, children.id AS children_id, children.parent_id AS children_parent_id FROM items LEFT OUTER JOIN items AS parent ON (parent.id = items.parent_id) LEFT OUTER JOIN items AS children ON (children.parent_id = parent.id)",
|
92
|
+
"SELECT * FROM items WHERE (items.id IN (1))"]
|
93
|
+
|
94
|
+
a.must_equal [@c.load(:id=>4, :parent_id=>3), @c.load(:id=>5, :parent_id=>3)]
|
95
|
+
a.map(&:parent).must_equal [@c.load(:id=>3, :parent_id=>1), @c.load(:id=>3, :parent_id=>1)]
|
96
|
+
a.map(&:parent).map(&:children).must_equal [a, a]
|
97
|
+
a.map(&:parent).map(&:parent).must_equal [@c.load(:id=>1, :parent_id=>nil), @c.load(:id=>1, :parent_id=>nil)]
|
98
|
+
@c.db.sqls.must_equal []
|
99
|
+
end
|
100
|
+
end
|
@@ -118,7 +118,7 @@ describe Sequel::Model, ".prepared_finder" do
|
|
118
118
|
@db.extend_datasets do
|
119
119
|
def select_sql
|
120
120
|
sql = super
|
121
|
-
sql << ' -- prepared' if is_a?(Sequel::Dataset::PreparedStatementMethods)
|
121
|
+
sql << ' -- prepared' if is_a?(Sequel::Dataset::PreparedStatementMethods) && !opts[:sql]
|
122
122
|
sql
|
123
123
|
end
|
124
124
|
end
|
@@ -61,7 +61,7 @@ describe "prepared_statements plugin" do
|
|
61
61
|
server(:default).with_sql_first(insert_select_sql(h))
|
62
62
|
end
|
63
63
|
def insert_select_sql(*v)
|
64
|
-
|
64
|
+
insert_sql(*v) << " RETURNING #{(opts[:returning] && !opts[:returning].empty?) ? opts[:returning].map{|c| literal(c)}.join(', ') : '*'}"
|
65
65
|
end
|
66
66
|
end
|
67
67
|
@c.create(:name=>'foo').must_equal @c.load(:id=>1, :name=>'foo', :i => 2)
|
@@ -107,7 +107,7 @@ describe "prepared_statements plugin" do
|
|
107
107
|
server(:default).with_sql_first(insert_select_sql(h))
|
108
108
|
end
|
109
109
|
def insert_select_sql(*v)
|
110
|
-
|
110
|
+
insert_sql(*v) << " RETURNING #{(opts[:returning] && !opts[:returning].empty?) ? opts[:returning].map{|c| literal(c)}.join(', ') : '*'}"
|
111
111
|
end
|
112
112
|
end
|
113
113
|
@c.new(:name=>'foo').set_server(:read_only).save.must_equal @c.load(:id=>1, :name=>'foo', :i => 2)
|
@@ -130,21 +130,16 @@ describe "prepared_statements plugin" do
|
|
130
130
|
it "should correctly handle with schema type when placeholder type specifiers are required" do
|
131
131
|
@c.dataset = @ds.with_extend do
|
132
132
|
def requires_placeholder_type_specifiers?; true end
|
133
|
-
def
|
134
|
-
|
133
|
+
def prepared_statement_modules
|
134
|
+
[Module.new do
|
135
135
|
def literal_symbol_append(sql, v)
|
136
|
-
if @opts[:bind_vars] &&
|
137
|
-
|
138
|
-
if prepared_arg?(s)
|
139
|
-
literal_append(sql, prepared_arg(s))
|
140
|
-
else
|
141
|
-
sql << v.to_s
|
142
|
-
end
|
136
|
+
if @opts[:bind_vars] && /\A\$(.*)\z/ =~ v
|
137
|
+
literal_append(sql, prepared_arg($1.split('__')[0].to_sym))
|
143
138
|
else
|
144
139
|
super
|
145
140
|
end
|
146
141
|
end
|
147
|
-
end
|
142
|
+
end]
|
148
143
|
end
|
149
144
|
end
|
150
145
|
@c.db_schema[:id][:type] = :integer
|
@@ -264,6 +264,20 @@ describe "Sequel::Plugins::StaticCache" do
|
|
264
264
|
@c.as_hash[3].must_equal @c.all.first
|
265
265
|
@db.sqls.must_equal ['SELECT * FROM t2']
|
266
266
|
end
|
267
|
+
|
268
|
+
it "should have load_cache" do
|
269
|
+
a = @c.all.sort_by{|o| o.id}
|
270
|
+
a.first.must_equal @c1
|
271
|
+
a.last.must_equal @c2
|
272
|
+
@db.sqls.must_equal []
|
273
|
+
|
274
|
+
@c.load_cache
|
275
|
+
|
276
|
+
a = @c.all.sort_by{|o| o.id}
|
277
|
+
a.first.must_equal @c1
|
278
|
+
a.last.must_equal @c2
|
279
|
+
@db.sqls.must_equal ['SELECT * FROM t']
|
280
|
+
end
|
267
281
|
end
|
268
282
|
|
269
283
|
describe "without options" do
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require_relative "spec_helper"
|
2
2
|
|
3
|
-
describe "
|
3
|
+
describe "tactical_eager_loading plugin" do
|
4
4
|
def sql_match(*args)
|
5
5
|
sqls = DB.sqls
|
6
6
|
sqls.length.must_equal args.length
|
@@ -139,3 +139,264 @@ describe "Sequel::Plugins::TacticalEagerLoading" do
|
|
139
139
|
Marshal.dump(ts.map{|x| x.marshallable!})
|
140
140
|
end
|
141
141
|
end
|
142
|
+
|
143
|
+
describe "tactical_eager_loading plugin eager_graph_support" do
|
144
|
+
before do
|
145
|
+
@c = Class.new(Sequel::Model)
|
146
|
+
@c.class_eval do
|
147
|
+
set_dataset DB[:t]
|
148
|
+
columns :id, :parent_id
|
149
|
+
plugin :tactical_eager_loading
|
150
|
+
many_to_one :parent, :class=>self
|
151
|
+
one_to_many :children, :class=>self, :key=>:parent_id
|
152
|
+
end
|
153
|
+
DB.reset
|
154
|
+
end
|
155
|
+
|
156
|
+
it "should allow eager loading of associated objects from one_to_many associated objects retrieved via eager_graph" do
|
157
|
+
a = @c.eager_graph(:children).
|
158
|
+
with_fetch([
|
159
|
+
{:id=>1, :parent_id=>nil, :children_id=>3, :children_parent_id=>1},
|
160
|
+
{:id=>1, :parent_id=>nil, :children_id=>4, :children_parent_id=>1},
|
161
|
+
{:id=>2, :parent_id=>nil, :children_id=>5, :children_parent_id=>2}
|
162
|
+
]).all
|
163
|
+
@c.db.sqls.must_equal ["SELECT t.id, t.parent_id, children.id AS children_id, children.parent_id AS children_parent_id FROM t LEFT OUTER JOIN t AS children ON (children.parent_id = t.id)"]
|
164
|
+
|
165
|
+
a.must_equal [@c.load(:id=>1, :parent_id=>nil), @c.load(:id=>2, :parent_id=>nil)]
|
166
|
+
a.map(&:children).must_equal [
|
167
|
+
[@c.load(:id=>3, :parent_id=>1),
|
168
|
+
@c.load(:id=>4, :parent_id=>1)],
|
169
|
+
[@c.load(:id=>5, :parent_id=>2)]]
|
170
|
+
@c.db.sqls.must_equal []
|
171
|
+
|
172
|
+
@c.dataset = @c.dataset.with_fetch([[{:id=>6, :parent_id=>3}, {:id=>7, :parent_id=>4}, {:id=>8, :parent_id=>5}],
|
173
|
+
[{:id=>9, :parent_id=>6}, {:id=>10, :parent_id=>7}, {:id=>11, :parent_id=>8}]])
|
174
|
+
|
175
|
+
a.map(&:children).map{|v| v.map(&:children)}.must_equal [
|
176
|
+
[[@c.load(:id=>6, :parent_id=>3)],
|
177
|
+
[@c.load(:id=>7, :parent_id=>4)]],
|
178
|
+
[[@c.load(:id=>8, :parent_id=>5)]]]
|
179
|
+
@c.db.sqls.must_equal ["SELECT * FROM t WHERE (t.parent_id IN (3, 4, 5))"]
|
180
|
+
|
181
|
+
a.map(&:children).map{|v| v.map(&:children).map{|v1| v1.map(&:children)}}.must_equal [
|
182
|
+
[[[@c.load(:id=>9, :parent_id=>6)]],
|
183
|
+
[[@c.load(:id=>10, :parent_id=>7)]]],
|
184
|
+
[[[@c.load(:id=>11, :parent_id=>8)]]]]
|
185
|
+
@c.db.sqls.must_equal ["SELECT * FROM t WHERE (t.parent_id IN (6, 7, 8))"]
|
186
|
+
end
|
187
|
+
|
188
|
+
it "should allow eager loading of associated objects from many_to_one associated objects retrieved via eager_graph" do
|
189
|
+
a = @c.eager_graph(:parent).
|
190
|
+
with_fetch([
|
191
|
+
{:id=>9, :parent_id=>6, :parent_id_0=>6, :parent_parent_id=>3},
|
192
|
+
{:id=>10, :parent_id=>7, :parent_id_0=>7, :parent_parent_id=>4},
|
193
|
+
{:id=>11, :parent_id=>8, :parent_id_0=>8, :parent_parent_id=>5}
|
194
|
+
]).all
|
195
|
+
@c.db.sqls.must_equal ["SELECT t.id, t.parent_id, parent.id AS parent_id_0, parent.parent_id AS parent_parent_id FROM t LEFT OUTER JOIN t AS parent ON (parent.id = t.parent_id)"]
|
196
|
+
|
197
|
+
a.must_equal [@c.load(:id=>9, :parent_id=>6), @c.load(:id=>10, :parent_id=>7), @c.load(:id=>11, :parent_id=>8)]
|
198
|
+
a.map(&:parent).must_equal [@c.load(:id=>6, :parent_id=>3), @c.load(:id=>7, :parent_id=>4), @c.load(:id=>8, :parent_id=>5)]
|
199
|
+
@c.db.sqls.must_equal []
|
200
|
+
|
201
|
+
@c.dataset = @c.dataset.with_fetch([[{:id=>5, :parent_id=>2}, {:id=>4, :parent_id=>nil}, {:id=>3, :parent_id=>1}],
|
202
|
+
[{:id=>2, :parent_id=>nil}, {:id=>1, :parent_id=>nil}]])
|
203
|
+
|
204
|
+
a.map(&:parent).map(&:parent).must_equal [@c.load(:id=>3, :parent_id=>1), @c.load(:id=>4, :parent_id=>nil), @c.load(:id=>5, :parent_id=>2)]
|
205
|
+
@c.db.sqls.must_equal ["SELECT * FROM t WHERE (t.id IN (3, 4, 5))"]
|
206
|
+
a.map(&:parent).map(&:parent).map(&:parent).must_equal [@c.load(:id=>1, :parent_id=>nil), nil, @c.load(:id=>2, :parent_id=>nil)]
|
207
|
+
@c.db.sqls.must_equal ["SELECT * FROM t WHERE (t.id IN (2, 1))"]
|
208
|
+
end
|
209
|
+
|
210
|
+
it "should allow eager loading of associated objects when using chained one_to_many associations" do
|
211
|
+
a = @c.eager_graph(:children=>:children).
|
212
|
+
with_fetch([
|
213
|
+
{:id=>1, :parent_id=>nil, :children_id=>3, :children_parent_id=>1, :children_0_id=>6, :children_0_parent_id=>3},
|
214
|
+
{:id=>1, :parent_id=>nil, :children_id=>4, :children_parent_id=>1, :children_0_id=>7, :children_0_parent_id=>4},
|
215
|
+
{:id=>2, :parent_id=>nil, :children_id=>5, :children_parent_id=>2, :children_0_id=>8, :children_0_parent_id=>5}
|
216
|
+
]).all
|
217
|
+
@c.db.sqls.must_equal ["SELECT t.id, t.parent_id, children.id AS children_id, children.parent_id AS children_parent_id, children_0.id AS children_0_id, children_0.parent_id AS children_0_parent_id FROM t LEFT OUTER JOIN t AS children ON (children.parent_id = t.id) LEFT OUTER JOIN t AS children_0 ON (children_0.parent_id = children.id)"]
|
218
|
+
|
219
|
+
a.must_equal [@c.load(:id=>1, :parent_id=>nil), @c.load(:id=>2, :parent_id=>nil)]
|
220
|
+
a.map(&:children).must_equal [
|
221
|
+
[@c.load(:id=>3, :parent_id=>1),
|
222
|
+
@c.load(:id=>4, :parent_id=>1)],
|
223
|
+
[@c.load(:id=>5, :parent_id=>2)]]
|
224
|
+
|
225
|
+
a.map(&:children).map{|v| v.map(&:children)}.must_equal [
|
226
|
+
[[@c.load(:id=>6, :parent_id=>3)],
|
227
|
+
[@c.load(:id=>7, :parent_id=>4)]],
|
228
|
+
[[@c.load(:id=>8, :parent_id=>5)]]]
|
229
|
+
@c.db.sqls.must_equal []
|
230
|
+
|
231
|
+
@c.dataset = @c.dataset.with_fetch([{:id=>9, :parent_id=>6}, {:id=>10, :parent_id=>7}, {:id=>11, :parent_id=>8}])
|
232
|
+
a.map(&:children).map{|v| v.map(&:children).map{|v1| v1.map(&:children)}}.must_equal [
|
233
|
+
[[[@c.load(:id=>9, :parent_id=>6)]],
|
234
|
+
[[@c.load(:id=>10, :parent_id=>7)]]],
|
235
|
+
[[[@c.load(:id=>11, :parent_id=>8)]]]]
|
236
|
+
@c.db.sqls.must_equal ["SELECT * FROM t WHERE (t.parent_id IN (6, 7, 8))"]
|
237
|
+
end
|
238
|
+
|
239
|
+
it "should allow eager loading of associated objects when using chained many_to_one associations" do
|
240
|
+
a = @c.eager_graph(:parent=>:parent).
|
241
|
+
with_fetch([
|
242
|
+
{:id=>9, :parent_id=>6, :parent_id_0=>6, :parent_parent_id=>3, :parent_0_id=>3, :parent_0_parent_id=>1},
|
243
|
+
{:id=>10, :parent_id=>7, :parent_id_0=>7, :parent_parent_id=>4, :parent_0_id=>4, :parent_0_parent_id=>1},
|
244
|
+
{:id=>11, :parent_id=>8, :parent_id_0=>8, :parent_parent_id=>5, :parent_0_id=>5, :parent_0_parent_id=>2}
|
245
|
+
]).all
|
246
|
+
@c.db.sqls.must_equal ["SELECT t.id, t.parent_id, parent.id AS parent_id_0, parent.parent_id AS parent_parent_id, parent_0.id AS parent_0_id, parent_0.parent_id AS parent_0_parent_id FROM t LEFT OUTER JOIN t AS parent ON (parent.id = t.parent_id) LEFT OUTER JOIN t AS parent_0 ON (parent_0.id = parent.parent_id)"]
|
247
|
+
|
248
|
+
a.must_equal [@c.load(:id=>9, :parent_id=>6), @c.load(:id=>10, :parent_id=>7), @c.load(:id=>11, :parent_id=>8)]
|
249
|
+
a.map(&:parent).must_equal [@c.load(:id=>6, :parent_id=>3), @c.load(:id=>7, :parent_id=>4), @c.load(:id=>8, :parent_id=>5)]
|
250
|
+
a.map(&:parent).map(&:parent).must_equal [@c.load(:id=>3, :parent_id=>1), @c.load(:id=>4, :parent_id=>1), @c.load(:id=>5, :parent_id=>2)]
|
251
|
+
@c.db.sqls.must_equal []
|
252
|
+
|
253
|
+
@c.dataset = @c.dataset.with_fetch([{:id=>2, :parent_id=>nil}, {:id=>1, :parent_id=>nil}])
|
254
|
+
a.map(&:parent).map(&:parent).map(&:parent).must_equal [@c.load(:id=>1, :parent_id=>nil), @c.load(:id=>1, :parent_id=>nil), @c.load(:id=>2, :parent_id=>nil)]
|
255
|
+
@c.db.sqls.must_equal ["SELECT * FROM t WHERE (t.id IN (1, 2))"]
|
256
|
+
end
|
257
|
+
|
258
|
+
it "should allow eager loading of associated objects when using chained many_to_one=>one_to_many associations" do
|
259
|
+
a = @c.eager_graph(:parent=>:children).
|
260
|
+
with_fetch([
|
261
|
+
{:id=>9, :parent_id=>6, :parent_id_0=>6, :parent_parent_id=>3, :children_id=>9, :children_parent_id=>6},
|
262
|
+
{:id=>10, :parent_id=>7, :parent_id_0=>7, :parent_parent_id=>4, :children_id=>10, :children_parent_id=>7},
|
263
|
+
{:id=>11, :parent_id=>8, :parent_id_0=>8, :parent_parent_id=>5, :children_id=>11, :children_parent_id=>8},
|
264
|
+
{:id=>9, :parent_id=>6, :parent_id_0=>6, :parent_parent_id=>3, :children_id=>12, :children_parent_id=>6},
|
265
|
+
{:id=>10, :parent_id=>7, :parent_id_0=>7, :parent_parent_id=>4, :children_id=>13, :children_parent_id=>7},
|
266
|
+
{:id=>11, :parent_id=>8, :parent_id_0=>8, :parent_parent_id=>5, :children_id=>14, :children_parent_id=>8}
|
267
|
+
]).all
|
268
|
+
@c.db.sqls.must_equal ["SELECT t.id, t.parent_id, parent.id AS parent_id_0, parent.parent_id AS parent_parent_id, children.id AS children_id, children.parent_id AS children_parent_id FROM t LEFT OUTER JOIN t AS parent ON (parent.id = t.parent_id) LEFT OUTER JOIN t AS children ON (children.parent_id = parent.id)"]
|
269
|
+
|
270
|
+
a.must_equal [@c.load(:id=>9, :parent_id=>6), @c.load(:id=>10, :parent_id=>7), @c.load(:id=>11, :parent_id=>8)]
|
271
|
+
a.map(&:parent).must_equal [@c.load(:id=>6, :parent_id=>3), @c.load(:id=>7, :parent_id=>4), @c.load(:id=>8, :parent_id=>5)]
|
272
|
+
a.map(&:parent).map(&:children).must_equal [
|
273
|
+
[@c.load(:id=>9, :parent_id=>6), @c.load(:id=>12, :parent_id=>6)],
|
274
|
+
[@c.load(:id=>10, :parent_id=>7), @c.load(:id=>13, :parent_id=>7)],
|
275
|
+
[@c.load(:id=>11, :parent_id=>8), @c.load(:id=>14, :parent_id=>8)]]
|
276
|
+
@c.db.sqls.must_equal []
|
277
|
+
|
278
|
+
@c.dataset = @c.dataset.with_fetch([{:id=>19, :parent_id=>9}, {:id=>24, :parent_id=>14}])
|
279
|
+
a.map(&:parent).map(&:children).map{|v| v.map(&:children)}
|
280
|
+
#.must_equal [
|
281
|
+
# [[@c.load(:id=>19, :parent_id=>9)], []],
|
282
|
+
# [[], []],
|
283
|
+
# [[], @c.load(:id=>24, :parent_id=>14)]]
|
284
|
+
@c.db.sqls.must_equal ["SELECT * FROM t WHERE (t.parent_id IN (9, 10, 11, 12, 13, 14))"]
|
285
|
+
end
|
286
|
+
|
287
|
+
it "should allow eager loading of associated objects when using chained one_to_many associations with partial data" do
|
288
|
+
a = @c.eager_graph(:children=>:children).
|
289
|
+
with_fetch([
|
290
|
+
{:id=>1, :parent_id=>nil, :children_id=>3, :children_parent_id=>1, :children_0_id=>6, :children_0_parent_id=>3},
|
291
|
+
{:id=>1, :parent_id=>nil, :children_id=>4, :children_parent_id=>1, :children_0_id=>nil, :children_0_parent_id=>nil},
|
292
|
+
{:id=>2, :parent_id=>nil, :children_id=>nil, :children_parent_id=>nil, :children_0_id=>nil, :children_0_parent_id=>nil}
|
293
|
+
]).all
|
294
|
+
@c.db.sqls.must_equal ["SELECT t.id, t.parent_id, children.id AS children_id, children.parent_id AS children_parent_id, children_0.id AS children_0_id, children_0.parent_id AS children_0_parent_id FROM t LEFT OUTER JOIN t AS children ON (children.parent_id = t.id) LEFT OUTER JOIN t AS children_0 ON (children_0.parent_id = children.id)"]
|
295
|
+
|
296
|
+
a.must_equal [@c.load(:id=>1, :parent_id=>nil), @c.load(:id=>2, :parent_id=>nil)]
|
297
|
+
a.map(&:children).must_equal [
|
298
|
+
[@c.load(:id=>3, :parent_id=>1),
|
299
|
+
@c.load(:id=>4, :parent_id=>1)],
|
300
|
+
[]]
|
301
|
+
|
302
|
+
a.map(&:children).map{|v| v.map(&:children)}.must_equal [
|
303
|
+
[[@c.load(:id=>6, :parent_id=>3)],
|
304
|
+
[]],
|
305
|
+
[]]
|
306
|
+
@c.db.sqls.must_equal []
|
307
|
+
|
308
|
+
@c.dataset = @c.dataset.with_fetch([{:id=>9, :parent_id=>6}])
|
309
|
+
a.map(&:children).map{|v| v.map(&:children).map{|v1| v1.map(&:children)}}.must_equal [
|
310
|
+
[[[@c.load(:id=>9, :parent_id=>6)]],
|
311
|
+
[]],
|
312
|
+
[]]
|
313
|
+
@c.db.sqls.must_equal ["SELECT * FROM t WHERE (t.parent_id IN (6))"]
|
314
|
+
end
|
315
|
+
|
316
|
+
it "should allow eager loading of associated objects when using chained many_to_one associations with partial data" do
|
317
|
+
a = @c.eager_graph(:parent=>:parent).
|
318
|
+
with_fetch([
|
319
|
+
{:id=>9, :parent_id=>6, :parent_id_0=>6, :parent_parent_id=>3, :parent_0_id=>3, :parent_0_parent_id=>1},
|
320
|
+
{:id=>10, :parent_id=>7, :parent_id_0=>7, :parent_parent_id=>nil, :parent_0_id=>nil, :parent_0_parent_id=>nil},
|
321
|
+
{:id=>11, :parent_id=>nil, :parent_id_0=>nil, :parent_parent_id=>nil, :parent_0_id=>nil, :parent_0_parent_id=>nil}
|
322
|
+
]).all
|
323
|
+
@c.db.sqls.must_equal ["SELECT t.id, t.parent_id, parent.id AS parent_id_0, parent.parent_id AS parent_parent_id, parent_0.id AS parent_0_id, parent_0.parent_id AS parent_0_parent_id FROM t LEFT OUTER JOIN t AS parent ON (parent.id = t.parent_id) LEFT OUTER JOIN t AS parent_0 ON (parent_0.id = parent.parent_id)"]
|
324
|
+
|
325
|
+
a.must_equal [@c.load(:id=>9, :parent_id=>6), @c.load(:id=>10, :parent_id=>7), @c.load(:id=>11, :parent_id=>nil)]
|
326
|
+
a.map(&:parent).must_equal [@c.load(:id=>6, :parent_id=>3), @c.load(:id=>7, :parent_id=>nil), nil]
|
327
|
+
a.map(&:parent).map{|v| v.parent if v}.must_equal [@c.load(:id=>3, :parent_id=>1), nil, nil]
|
328
|
+
@c.db.sqls.must_equal []
|
329
|
+
|
330
|
+
@c.dataset = @c.dataset.with_fetch([{:id=>1, :parent_id=>nil}])
|
331
|
+
a.map(&:parent).map{|v| v.parent.parent if v && v.parent}.must_equal [@c.load(:id=>1, :parent_id=>nil), nil, nil]
|
332
|
+
@c.db.sqls.must_equal ["SELECT * FROM t WHERE (t.id IN (1))"]
|
333
|
+
end
|
334
|
+
|
335
|
+
it "should skip setup of eager loading when using eager_graph for association not using plugin" do
|
336
|
+
c = Class.new(Sequel::Model)
|
337
|
+
c.class_eval do
|
338
|
+
set_dataset DB[:t]
|
339
|
+
columns :id, :t_id
|
340
|
+
end
|
341
|
+
@c.many_to_one :f, :class=>c, :key=>:parent_id
|
342
|
+
@c.one_to_many :fs, :class=>c
|
343
|
+
c.many_to_one :t, :class=>@c
|
344
|
+
c.one_to_many :ts, :class=>@c, :key=>:parent_id
|
345
|
+
|
346
|
+
a = @c.eager_graph(:f, :parent, :fs=>:t).
|
347
|
+
with_fetch([
|
348
|
+
{:id=>5, :parent_id=>4, :f_id=>4, :t_id=>20, :parent_id_0=>4, :parent_parent_id=>3, :fs_id=>5, :fs_t_id=>30, :t_0_id=>30, :t_0_parent_id=>40},
|
349
|
+
{:id=>15, :parent_id=>14, :f_id=>14, :t_id=>30, :parent_id_0=>14, :parent_parent_id=>13, :fs_id=>15, :fs_t_id=>40, :t_0_id=>40, :t_0_parent_id=>50},
|
350
|
+
]).
|
351
|
+
all
|
352
|
+
@c.db.sqls.must_equal ["SELECT t.id, t.parent_id, f.id AS f_id, f.t_id, parent.id AS parent_id_0, parent.parent_id AS parent_parent_id, fs.id AS fs_id, fs.t_id AS fs_t_id, t_0.id AS t_0_id, t_0.parent_id AS t_0_parent_id FROM t LEFT OUTER JOIN t AS f ON (f.id = t.parent_id) LEFT OUTER JOIN t AS parent ON (parent.id = t.parent_id) LEFT OUTER JOIN t AS fs ON (fs._id = t.id) LEFT OUTER JOIN t AS t_0 ON (t_0.id = fs.t_id)"]
|
353
|
+
|
354
|
+
a.must_equal [@c.load(:id=>5, :parent_id=>4), @c.load(:id=>15, :parent_id=>14)]
|
355
|
+
a.map(&:f).must_equal [c.load(:id=>4, :t_id=>20), c.load(:id=>14, :t_id=>30)]
|
356
|
+
a.map(&:parent).must_equal [@c.load(:id=>4, :parent_id=>3), @c.load(:id=>14, :parent_id=>13)]
|
357
|
+
a.map(&:fs).must_equal [[c.load(:id=>5, :t_id=>30)], [c.load(:id=>15, :t_id=>40)]]
|
358
|
+
a.map(&:fs).map{|v| v.map(&:t)}.must_equal [[@c.load(:id=>30, :parent_id=>40)], [@c.load(:id=>40, :parent_id=>50)]]
|
359
|
+
@c.db.sqls.must_equal []
|
360
|
+
|
361
|
+
@c.dataset = @c.dataset.with_fetch([[{:id=>3, :parent_id=>1}, {:id=>13, :parent_id=>1}],
|
362
|
+
[{:id=>1, :parent_id=>nil}],
|
363
|
+
[{:id=>20, :parent_id=>nil}],
|
364
|
+
[{:id=>30, :parent_id=>nil}],
|
365
|
+
[{:id=>50, :parent_id=>nil}, {:id=>40, :parent_id=>nil}]
|
366
|
+
])
|
367
|
+
a.map(&:parent).map(&:parent).must_equal [@c.load(:id=>3, :parent_id=>1), @c.load(:id=>13, :parent_id=>1)]
|
368
|
+
@c.db.sqls.must_equal ["SELECT * FROM t WHERE (t.id IN (3, 13))"]
|
369
|
+
a.map(&:parent).map(&:parent).map(&:parent).must_equal [@c.load(:id=>1, :parent_id=>nil), @c.load(:id=>1, :parent_id=>nil)]
|
370
|
+
@c.db.sqls.must_equal ["SELECT * FROM t WHERE (t.id IN (1))"]
|
371
|
+
|
372
|
+
a.map(&:f).map(&:t).must_equal [@c.load(:id=>20, :parent_id=>nil), @c.load(:id=>30, :parent_id=>nil)]
|
373
|
+
@c.db.sqls.must_equal ["SELECT * FROM t WHERE id = 20", "SELECT * FROM t WHERE id = 30"]
|
374
|
+
|
375
|
+
a.map(&:fs).map{|v| v.map(&:t).map(&:parent)}.must_equal [[@c.load(:id=>40, :parent_id=>nil)], [@c.load(:id=>50, :parent_id=>nil)]]
|
376
|
+
@c.db.sqls.must_equal ["SELECT * FROM t WHERE (t.id IN (40, 50))"]
|
377
|
+
end
|
378
|
+
|
379
|
+
it "should skip frozen objects when eager loading for model objects" do
|
380
|
+
a = @c.eager_graph(:parent).
|
381
|
+
with_fetch([
|
382
|
+
{:id=>9, :parent_id=>6, :parent_id_0=>6, :parent_parent_id=>3},
|
383
|
+
{:id=>10, :parent_id=>7, :parent_id_0=>7, :parent_parent_id=>4},
|
384
|
+
{:id=>11, :parent_id=>8, :parent_id_0=>8, :parent_parent_id=>5}
|
385
|
+
]).all
|
386
|
+
@c.db.sqls.must_equal ["SELECT t.id, t.parent_id, parent.id AS parent_id_0, parent.parent_id AS parent_parent_id FROM t LEFT OUTER JOIN t AS parent ON (parent.id = t.parent_id)"]
|
387
|
+
|
388
|
+
a.must_equal [@c.load(:id=>9, :parent_id=>6), @c.load(:id=>10, :parent_id=>7), @c.load(:id=>11, :parent_id=>8)]
|
389
|
+
a.map(&:parent).must_equal [@c.load(:id=>6, :parent_id=>3), @c.load(:id=>7, :parent_id=>4), @c.load(:id=>8, :parent_id=>5)]
|
390
|
+
@c.db.sqls.must_equal []
|
391
|
+
|
392
|
+
@c.dataset = @c.dataset.with_fetch([[{:id=>3, :parent_id=>1}, {:id=>5, :parent_id=>2}], [{:id=>4, :parent_id=>nil}]])
|
393
|
+
parents = a.map(&:parent)
|
394
|
+
parents[1].freeze
|
395
|
+
parents[0].parent.must_equal @c.load(:id=>3, :parent_id=>1)
|
396
|
+
@c.db.sqls.must_equal ["SELECT * FROM t WHERE (t.id IN (3, 5))"]
|
397
|
+
parents[1].parent.must_equal @c.load(:id=>4, :parent_id=>nil)
|
398
|
+
@c.db.sqls.must_equal ["SELECT * FROM t WHERE id = 4"]
|
399
|
+
parents[2].parent.must_equal @c.load(:id=>5, :parent_id=>2)
|
400
|
+
@c.db.sqls.must_equal []
|
401
|
+
end
|
402
|
+
end
|