/
single_table_inheritance_spec.rb
175 lines (156 loc) · 7.33 KB
/
single_table_inheritance_spec.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
require File.join(File.dirname(__FILE__), "spec_helper")
describe Sequel::Model, "#sti_key" do
before do
class ::StiTest < Sequel::Model
def kind; self[:kind]; end
def kind=(x); self[:kind] = x; end
def _refresh(x); end
plugin :single_table_inheritance, :kind
end
class ::StiTestSub1 < StiTest
end
class ::StiTestSub2 < StiTest
end
@ds = StiTest.dataset
MODEL_DB.reset
end
after do
Object.send(:remove_const, :StiTestSub1)
Object.send(:remove_const, :StiTestSub2)
Object.send(:remove_const, :StiTest)
end
specify "should have simple_table = nil" do
StiTest.simple_table.should == nil
StiTestSub1.simple_table.should == nil
end
it "should allow changing the inheritance column via a plugin :single_table_inheritance call" do
StiTest.plugin :single_table_inheritance, :blah
Object.send(:remove_const, :StiTestSub1)
Object.send(:remove_const, :StiTestSub2)
class ::StiTestSub1 < StiTest
end
class ::StiTestSub2 < StiTest
end
def @ds.fetch_rows(sql)
yield({:blah=>'StiTest'})
yield({:blah=>'StiTestSub1'})
yield({:blah=>'StiTestSub2'})
end
StiTest.all.collect{|x| x.class}.should == [StiTest, StiTestSub1, StiTestSub2]
StiTest.dataset.sql.should == "SELECT * FROM sti_tests"
StiTestSub1.dataset.sql.should == "SELECT * FROM sti_tests WHERE (sti_tests.blah IN ('StiTestSub1'))"
StiTestSub2.dataset.sql.should == "SELECT * FROM sti_tests WHERE (sti_tests.blah IN ('StiTestSub2'))"
end
it "should return rows with the correct class based on the polymorphic_key value" do
def @ds.fetch_rows(sql)
yield({:kind=>'StiTest'})
yield({:kind=>'StiTestSub1'})
yield({:kind=>'StiTestSub2'})
end
StiTest.all.collect{|x| x.class}.should == [StiTest, StiTestSub1, StiTestSub2]
end
it "should fallback to the main class if the given class does not exist" do
def @ds.fetch_rows(sql)
yield({:kind=>'StiTestSub3'})
end
StiTest.all.collect{|x| x.class}.should == [StiTest]
end
it "should fallback to the main class if the sti_key field is empty or nil without calling constantize" do
called = false
StiTest.meta_def(:constantize) do |s|
called = true
Object
end
StiTest.plugin :single_table_inheritance, :kind
def @ds.fetch_rows(sql)
yield({:kind=>''})
yield({:kind=>nil})
end
StiTest.all.collect{|x| x.class}.should == [StiTest, StiTest]
called.should == false
end
it "should add a before_create hook that sets the model class name for the key" do
StiTest.new.save
StiTestSub1.new.save
StiTestSub2.new.save
MODEL_DB.sqls.should == ["INSERT INTO sti_tests (kind) VALUES ('StiTest')", "INSERT INTO sti_tests (kind) VALUES ('StiTestSub1')", "INSERT INTO sti_tests (kind) VALUES ('StiTestSub2')"]
end
it "should have the before_create hook not override an existing value" do
StiTest.create(:kind=>'StiTestSub1')
MODEL_DB.sqls.should == ["INSERT INTO sti_tests (kind) VALUES ('StiTestSub1')"]
end
it "should add a filter to model datasets inside subclasses hook to only retreive objects with the matching key" do
StiTest.dataset.sql.should == "SELECT * FROM sti_tests"
StiTestSub1.dataset.sql.should == "SELECT * FROM sti_tests WHERE (sti_tests.kind IN ('StiTestSub1'))"
StiTestSub2.dataset.sql.should == "SELECT * FROM sti_tests WHERE (sti_tests.kind IN ('StiTestSub2'))"
end
it "should add a correct filter for multiple levels of subclasses" do
class ::StiTestSub1A < StiTestSub1; end
StiTestSub1.dataset.sql.should == "SELECT * FROM sti_tests WHERE (sti_tests.kind IN ('StiTestSub1', 'StiTestSub1A'))"
StiTestSub1A.dataset.sql.should == "SELECT * FROM sti_tests WHERE (sti_tests.kind IN ('StiTestSub1A'))"
class ::StiTestSub2A < StiTestSub2; end
StiTestSub2.dataset.sql.should == "SELECT * FROM sti_tests WHERE (sti_tests.kind IN ('StiTestSub2', 'StiTestSub2A'))"
StiTestSub2A.dataset.sql.should == "SELECT * FROM sti_tests WHERE (sti_tests.kind IN ('StiTestSub2A'))"
class ::StiTestSub1B < StiTestSub1A; end
StiTestSub1.dataset.sql.should == "SELECT * FROM sti_tests WHERE (sti_tests.kind IN ('StiTestSub1', 'StiTestSub1A', 'StiTestSub1B'))"
StiTestSub1A.dataset.sql.should == "SELECT * FROM sti_tests WHERE (sti_tests.kind IN ('StiTestSub1A', 'StiTestSub1B'))"
StiTestSub1B.dataset.sql.should == "SELECT * FROM sti_tests WHERE (sti_tests.kind IN ('StiTestSub1B'))"
end
context "with custom options" do
before do
class ::StiTest2 < Sequel::Model
columns :id, :kind
def _refresh(x); end
end
end
after do
Object.send(:remove_const, :StiTest2)
Object.send(:remove_const, :StiTest3)
Object.send(:remove_const, :StiTest4)
end
it "should work with custom procs with strings" do
StiTest2.plugin :single_table_inheritance, :kind, :model_map=>proc{|v| v == 1 ? 'StiTest3' : 'StiTest4'}, :key_map=>proc{|klass| klass.name == 'StiTest3' ? 1 : 2}
class ::StiTest3 < ::StiTest2; end
class ::StiTest4 < ::StiTest2; end
StiTest2.dataset.row_proc.call(:kind=>0).should be_a_instance_of(StiTest4)
StiTest2.dataset.row_proc.call(:kind=>1).should be_a_instance_of(StiTest3)
StiTest2.dataset.row_proc.call(:kind=>2).should be_a_instance_of(StiTest4)
StiTest2.create.kind.should == 2
StiTest3.create.kind.should == 1
StiTest4.create.kind.should == 2
end
it "should work with custom procs with symbols" do
StiTest2.plugin :single_table_inheritance, :kind, :model_map=>proc{|v| v == 1 ? :StiTest3 : :StiTest4}, :key_map=>proc{|klass| klass.name == 'StiTest3' ? 1 : 2}
class ::StiTest3 < ::StiTest2; end
class ::StiTest4 < ::StiTest2; end
StiTest2.dataset.row_proc.call(:kind=>0).should be_a_instance_of(StiTest4)
StiTest2.dataset.row_proc.call(:kind=>1).should be_a_instance_of(StiTest3)
StiTest2.dataset.row_proc.call(:kind=>2).should be_a_instance_of(StiTest4)
StiTest2.create.kind.should == 2
StiTest3.create.kind.should == 1
StiTest4.create.kind.should == 2
end
it "should work with custom hashes" do
StiTest2.plugin :single_table_inheritance, :kind, :model_map=>{0=>StiTest2, 1=>:StiTest3, 2=>'StiTest4'}, :key_map=>{StiTest2=>4, 'StiTest3'=>5, 'StiTest4'=>6}
class ::StiTest3 < ::StiTest2; end
class ::StiTest4 < ::StiTest2; end
StiTest2.dataset.row_proc.call(:kind=>0).should be_a_instance_of(StiTest2)
StiTest2.dataset.row_proc.call(:kind=>1).should be_a_instance_of(StiTest3)
StiTest2.dataset.row_proc.call(:kind=>2).should be_a_instance_of(StiTest4)
StiTest2.create.kind.should == 4
StiTest3.create.kind.should == 5
StiTest4.create.kind.should == 6
end
it "should infer key_map from model_map if provided as a hash" do
StiTest2.plugin :single_table_inheritance, :kind, :model_map=>{0=>StiTest2, 1=>'StiTest3', 2=>:StiTest4}
class ::StiTest3 < ::StiTest2; end
class ::StiTest4 < ::StiTest2; end
StiTest2.dataset.row_proc.call(:kind=>0).should be_a_instance_of(StiTest2)
StiTest2.dataset.row_proc.call(:kind=>1).should be_a_instance_of(StiTest3)
StiTest2.dataset.row_proc.call(:kind=>2).should be_a_instance_of(StiTest4)
StiTest2.create.kind.should == 0
StiTest3.create.kind.should == 1
StiTest4.create.kind.should == 2
end
end
end