sequel 3.29.0 → 3.30.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +35 -3
- data/Rakefile +2 -1
- data/doc/association_basics.rdoc +11 -0
- data/doc/opening_databases.rdoc +2 -0
- data/doc/release_notes/3.30.0.txt +135 -0
- data/doc/testing.rdoc +17 -3
- data/lib/sequel/adapters/amalgalite.rb +2 -2
- data/lib/sequel/adapters/do/mysql.rb +5 -2
- data/lib/sequel/adapters/ibmdb.rb +2 -2
- data/lib/sequel/adapters/jdbc.rb +126 -43
- data/lib/sequel/adapters/jdbc/as400.rb +11 -3
- data/lib/sequel/adapters/jdbc/db2.rb +2 -1
- data/lib/sequel/adapters/jdbc/derby.rb +44 -19
- data/lib/sequel/adapters/jdbc/h2.rb +32 -19
- data/lib/sequel/adapters/jdbc/hsqldb.rb +21 -17
- data/lib/sequel/adapters/jdbc/jtds.rb +9 -4
- data/lib/sequel/adapters/jdbc/mssql.rb +3 -1
- data/lib/sequel/adapters/jdbc/mysql.rb +2 -1
- data/lib/sequel/adapters/jdbc/oracle.rb +21 -7
- data/lib/sequel/adapters/jdbc/postgresql.rb +3 -2
- data/lib/sequel/adapters/jdbc/sqlite.rb +2 -1
- data/lib/sequel/adapters/jdbc/sqlserver.rb +48 -18
- data/lib/sequel/adapters/mock.rb +2 -1
- data/lib/sequel/adapters/mysql.rb +4 -2
- data/lib/sequel/adapters/mysql2.rb +2 -2
- data/lib/sequel/adapters/odbc/mssql.rb +1 -1
- data/lib/sequel/adapters/openbase.rb +1 -1
- data/lib/sequel/adapters/oracle.rb +6 -6
- data/lib/sequel/adapters/postgres.rb +25 -12
- data/lib/sequel/adapters/shared/access.rb +14 -6
- data/lib/sequel/adapters/shared/db2.rb +36 -13
- data/lib/sequel/adapters/shared/firebird.rb +12 -5
- data/lib/sequel/adapters/shared/informix.rb +11 -3
- data/lib/sequel/adapters/shared/mssql.rb +94 -47
- data/lib/sequel/adapters/shared/mysql.rb +107 -49
- data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +2 -2
- data/lib/sequel/adapters/shared/oracle.rb +54 -27
- data/lib/sequel/adapters/shared/postgres.rb +65 -26
- data/lib/sequel/adapters/shared/progress.rb +4 -1
- data/lib/sequel/adapters/shared/sqlite.rb +36 -20
- data/lib/sequel/adapters/sqlite.rb +2 -3
- data/lib/sequel/adapters/swift/mysql.rb +3 -2
- data/lib/sequel/adapters/swift/sqlite.rb +2 -2
- data/lib/sequel/adapters/tinytds.rb +14 -8
- data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +7 -4
- data/lib/sequel/database/misc.rb +6 -2
- data/lib/sequel/dataset/graph.rb +33 -7
- data/lib/sequel/dataset/prepared_statements.rb +19 -5
- data/lib/sequel/dataset/sql.rb +611 -201
- data/lib/sequel/model/associations.rb +12 -5
- data/lib/sequel/model/base.rb +20 -5
- data/lib/sequel/plugins/sharding.rb +9 -29
- data/lib/sequel/sql.rb +2 -1
- data/lib/sequel/timezones.rb +14 -4
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/mysql_spec.rb +10 -0
- data/spec/adapters/oracle_spec.rb +1 -1
- data/spec/core/core_sql_spec.rb +3 -1
- data/spec/core/database_spec.rb +42 -0
- data/spec/core/dataset_spec.rb +10 -3
- data/spec/core/mock_adapter_spec.rb +4 -0
- data/spec/core/object_graph_spec.rb +38 -0
- data/spec/extensions/association_autoreloading_spec.rb +1 -10
- data/spec/extensions/association_dependencies_spec.rb +2 -12
- data/spec/extensions/association_pks_spec.rb +35 -39
- data/spec/extensions/caching_spec.rb +23 -50
- data/spec/extensions/class_table_inheritance_spec.rb +30 -82
- data/spec/extensions/composition_spec.rb +18 -13
- data/spec/extensions/hook_class_methods_spec.rb +65 -91
- data/spec/extensions/identity_map_spec.rb +33 -103
- data/spec/extensions/instance_filters_spec.rb +10 -21
- data/spec/extensions/instance_hooks_spec.rb +6 -24
- data/spec/extensions/json_serializer_spec.rb +4 -5
- data/spec/extensions/lazy_attributes_spec.rb +16 -20
- data/spec/extensions/list_spec.rb +17 -39
- data/spec/extensions/many_through_many_spec.rb +135 -277
- data/spec/extensions/migration_spec.rb +18 -15
- data/spec/extensions/named_timezones_spec.rb +1 -1
- data/spec/extensions/nested_attributes_spec.rb +97 -92
- data/spec/extensions/optimistic_locking_spec.rb +9 -20
- data/spec/extensions/prepared_statements_associations_spec.rb +22 -37
- data/spec/extensions/prepared_statements_safe_spec.rb +9 -27
- data/spec/extensions/prepared_statements_spec.rb +11 -30
- data/spec/extensions/prepared_statements_with_pk_spec.rb +6 -13
- data/spec/extensions/pretty_table_spec.rb +1 -6
- data/spec/extensions/rcte_tree_spec.rb +41 -43
- data/spec/extensions/schema_dumper_spec.rb +3 -6
- data/spec/extensions/serialization_spec.rb +20 -32
- data/spec/extensions/sharding_spec.rb +66 -140
- data/spec/extensions/single_table_inheritance_spec.rb +14 -36
- data/spec/extensions/spec_helper.rb +10 -64
- data/spec/extensions/sql_expr_spec.rb +20 -60
- data/spec/extensions/tactical_eager_loading_spec.rb +9 -19
- data/spec/extensions/timestamps_spec.rb +6 -6
- data/spec/extensions/to_dot_spec.rb +1 -2
- data/spec/extensions/touch_spec.rb +13 -14
- data/spec/extensions/tree_spec.rb +11 -26
- data/spec/extensions/update_primary_key_spec.rb +30 -24
- data/spec/extensions/validation_class_methods_spec.rb +30 -51
- data/spec/extensions/validation_helpers_spec.rb +16 -35
- data/spec/integration/dataset_test.rb +16 -4
- data/spec/integration/prepared_statement_test.rb +4 -2
- data/spec/model/eager_loading_spec.rb +16 -0
- data/spec/model/model_spec.rb +15 -1
- data/spec/model/record_spec.rb +60 -0
- metadata +23 -40
@@ -6,17 +6,9 @@ describe "AssociationDependencies plugin" do
|
|
6
6
|
@c = Class.new(Sequel::Model)
|
7
7
|
@c.plugin :association_dependencies
|
8
8
|
@Artist = Class.new(@c).set_dataset(:artists)
|
9
|
-
|
10
|
-
def ds1.fetch_rows(s)
|
11
|
-
(MODEL_DB.sqls ||= []) << s
|
12
|
-
yield({:id=>2, :name=>'Ar'})
|
13
|
-
end
|
9
|
+
@Artist.dataset._fetch = {:id=>2, :name=>'Ar'}
|
14
10
|
@Album = Class.new(@c).set_dataset(:albums)
|
15
|
-
|
16
|
-
def ds1.fetch_rows(s)
|
17
|
-
(MODEL_DB.sqls ||= []) << s
|
18
|
-
yield({:id=>1, :name=>'Al', :artist_id=>2})
|
19
|
-
end
|
11
|
+
@Album.dataset._fetch = {:id=>1, :name=>'Al', :artist_id=>2}
|
20
12
|
@Artist.columns :id, :name
|
21
13
|
@Album.columns :id, :name, :artist_id
|
22
14
|
@Artist.one_to_many :albums, :class=>@Album, :key=>:artist_id
|
@@ -113,11 +105,9 @@ describe "AssociationDependencies plugin" do
|
|
113
105
|
c.add_association_dependencies :artist=>:destroy
|
114
106
|
c.load(:id=>1, :name=>'Al', :artist_id=>2).destroy
|
115
107
|
MODEL_DB.sqls.should == ['DELETE FROM albums WHERE (id = 1)', 'SELECT * FROM artists WHERE (artists.id = 2) LIMIT 1', 'DELETE FROM artists WHERE (id = 2)']
|
116
|
-
MODEL_DB.reset
|
117
108
|
|
118
109
|
@Album.load(:id=>1, :name=>'Al', :artist_id=>2).destroy
|
119
110
|
MODEL_DB.sqls.should == ['DELETE FROM albums WHERE (id = 1)']
|
120
|
-
MODEL_DB.reset
|
121
111
|
|
122
112
|
@Album.add_association_dependencies :artist=>:destroy
|
123
113
|
c2 = Class.new(@Album)
|
@@ -2,31 +2,18 @@ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
|
|
2
2
|
|
3
3
|
describe "Sequel::Plugins::AssociationPks" do
|
4
4
|
before do
|
5
|
-
@db =
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
yield({:tag_id=>2}) if $1 != '3'
|
16
|
-
yield({:tag_id=>3}) if $1 == '2'
|
17
|
-
end
|
5
|
+
@db = Sequel.mock(:fetch=>proc do |sql|
|
6
|
+
case sql
|
7
|
+
when "SELECT id FROM albums WHERE (albums.artist_id = 1)"
|
8
|
+
[{:id=>1}, {:id=>2}, {:id=>3}]
|
9
|
+
when /SELECT tag_id FROM albums_tags WHERE \(album_id = (\d)\)/
|
10
|
+
a = []
|
11
|
+
a << {:tag_id=>1} if $1 == '1'
|
12
|
+
a << {:tag_id=>2} if $1 != '3'
|
13
|
+
a << {:tag_id=>3} if $1 == '2'
|
14
|
+
a
|
18
15
|
end
|
19
|
-
end
|
20
|
-
@db.meta_def(:dataset) do |*opts|
|
21
|
-
ds = super(*opts)
|
22
|
-
ds.extend mod
|
23
|
-
ds
|
24
|
-
end
|
25
|
-
def @db.transaction(opts)
|
26
|
-
execute('BEGIN')
|
27
|
-
yield
|
28
|
-
execute('COMMIT')
|
29
|
-
end
|
16
|
+
end)
|
30
17
|
@Artist = Class.new(Sequel::Model(@db[:artists]))
|
31
18
|
@Artist.columns :id
|
32
19
|
@Album= Class.new(Sequel::Model(@db[:albums]))
|
@@ -37,7 +24,7 @@ describe "Sequel::Plugins::AssociationPks" do
|
|
37
24
|
@Album.plugin :association_pks
|
38
25
|
@Artist.one_to_many :albums, :class=>@Album, :key=>:artist_id
|
39
26
|
@Album.many_to_many :tags, :class=>@Tag, :join_table=>:albums_tags, :left_key=>:album_id
|
40
|
-
@db.
|
27
|
+
@db.sqls
|
41
28
|
end
|
42
29
|
|
43
30
|
specify "should return correct associated pks for one_to_many associations" do
|
@@ -66,8 +53,11 @@ describe "Sequel::Plugins::AssociationPks" do
|
|
66
53
|
|
67
54
|
specify "should set associated pks correctly for a many_to_many association" do
|
68
55
|
@Album.load(:id=>2).tag_pks = [1, 3]
|
69
|
-
@db.sqls
|
70
|
-
|
56
|
+
sqls = @db.sqls
|
57
|
+
sqls[0].should == "DELETE FROM albums_tags WHERE ((album_id = 2) AND (tag_id NOT IN (1, 3)))"
|
58
|
+
sqls[1].should == 'SELECT tag_id FROM albums_tags WHERE (album_id = 2)'
|
59
|
+
sqls[2].should =~ /INSERT INTO albums_tags \((album_id, tag_id|tag_id, album_id)\) VALUES \((2, 1|1, 2)\)/
|
60
|
+
sqls.length.should == 3
|
71
61
|
end
|
72
62
|
|
73
63
|
specify "should use transactions if the object is configured to use transactions" do
|
@@ -78,15 +68,17 @@ describe "Sequel::Plugins::AssociationPks" do
|
|
78
68
|
"UPDATE albums SET artist_id = 1 WHERE (id IN (1, 2))",
|
79
69
|
"UPDATE albums SET artist_id = NULL WHERE ((albums.artist_id = 1) AND (id NOT IN (1, 2)))",
|
80
70
|
"COMMIT"]
|
81
|
-
@db.reset
|
82
71
|
|
83
72
|
album = @Album.load(:id=>2)
|
84
73
|
album.use_transactions = true
|
85
74
|
album.tag_pks = [1, 3]
|
86
|
-
@db.sqls
|
87
|
-
|
88
|
-
|
89
|
-
|
75
|
+
sqls = @db.sqls
|
76
|
+
sqls[0].should == "BEGIN"
|
77
|
+
sqls[1].should == "DELETE FROM albums_tags WHERE ((album_id = 2) AND (tag_id NOT IN (1, 3)))"
|
78
|
+
sqls[2].should == 'SELECT tag_id FROM albums_tags WHERE (album_id = 2)'
|
79
|
+
sqls[3].should =~ /INSERT INTO albums_tags \((album_id, tag_id|tag_id, album_id)\) VALUES \((2, 1|1, 2)\)/
|
80
|
+
sqls[4].should == "COMMIT"
|
81
|
+
sqls.length.should == 5
|
90
82
|
end
|
91
83
|
|
92
84
|
specify "should automatically convert keys to numbers if the primary key is an integer for one_to_many associations" do
|
@@ -106,18 +98,22 @@ describe "Sequel::Plugins::AssociationPks" do
|
|
106
98
|
specify "should automatically convert keys to numbers if the primary key is an integer for one_to_many associations" do
|
107
99
|
@Tag.db_schema[:id][:type] = :integer
|
108
100
|
@Album.load(:id=>2).tag_pks = %w'1 3'
|
109
|
-
@db.sqls
|
110
|
-
|
111
|
-
|
101
|
+
sqls = @db.sqls
|
102
|
+
sqls[0].should == "DELETE FROM albums_tags WHERE ((album_id = 2) AND (tag_id NOT IN (1, 3)))"
|
103
|
+
sqls[1].should == 'SELECT tag_id FROM albums_tags WHERE (album_id = 2)'
|
104
|
+
sqls[2].should =~ /INSERT INTO albums_tags \((album_id, tag_id|tag_id, album_id)\) VALUES \((2, 1|1, 2)\)/
|
105
|
+
sqls.length.should == 3
|
112
106
|
end
|
113
107
|
|
114
108
|
specify "should not automatically convert keys to numbers if the primary key is an integer for many_to_many associations" do
|
115
109
|
@Tag.db_schema[:id][:type] = :string
|
116
110
|
@Album.load(:id=>2).tag_pks = %w'1 3'
|
117
|
-
@db.sqls
|
118
|
-
|
119
|
-
|
120
|
-
|
111
|
+
sqls = @db.sqls
|
112
|
+
sqls[0].should == "DELETE FROM albums_tags WHERE ((album_id = 2) AND (tag_id NOT IN ('1', '3')))"
|
113
|
+
sqls[1].should == 'SELECT tag_id FROM albums_tags WHERE (album_id = 2)'
|
114
|
+
sqls[2].should =~ /INSERT INTO albums_tags \((album_id, tag_id|tag_id, album_id)\) VALUES \((2, '1'|'1', 2)\)/
|
115
|
+
sqls[3].should =~ /INSERT INTO albums_tags \((album_id, tag_id|tag_id, album_id)\) VALUES \((2, '3'|'3', 2)\)/
|
116
|
+
sqls.length.should == 4
|
121
117
|
end
|
122
118
|
|
123
119
|
end
|
@@ -2,8 +2,6 @@ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
|
|
2
2
|
|
3
3
|
describe Sequel::Model, "caching" do
|
4
4
|
before do
|
5
|
-
MODEL_DB.reset
|
6
|
-
|
7
5
|
@cache_class = Class.new(Hash) do
|
8
6
|
attr_accessor :ttl
|
9
7
|
def set(k, v, ttl); self[k] = v; @ttl = ttl; end
|
@@ -44,31 +42,14 @@ describe Sequel::Model, "caching" do
|
|
44
42
|
columns :name, :id
|
45
43
|
end
|
46
44
|
|
47
|
-
|
48
|
-
$cache_dataset_row = {:name => 'sharon', :id => 1}
|
49
45
|
@dataset = @c.dataset = @c3.dataset = @c4.dataset
|
50
|
-
|
51
|
-
@dataset.
|
52
|
-
def fetch_rows(sql)
|
53
|
-
$sqls << sql
|
54
|
-
yield $cache_dataset_row
|
55
|
-
end
|
56
|
-
|
57
|
-
def update(values)
|
58
|
-
$sqls << update_sql(values)
|
59
|
-
$cache_dataset_row.merge!(values)
|
60
|
-
1
|
61
|
-
end
|
62
|
-
|
63
|
-
def delete
|
64
|
-
$sqls << delete_sql
|
65
|
-
1
|
66
|
-
end
|
67
|
-
})
|
46
|
+
@dataset._fetch = {:name => 'sharon', :id => 1}
|
47
|
+
@dataset.numrows = 1
|
68
48
|
|
69
49
|
@c2 = Class.new(@c) do
|
70
50
|
def self.name; 'SubItem' end
|
71
51
|
end
|
52
|
+
@c.db.reset
|
72
53
|
end
|
73
54
|
|
74
55
|
it "should set the model's cache store" do
|
@@ -154,27 +135,26 @@ describe Sequel::Model, "caching" do
|
|
154
135
|
end
|
155
136
|
|
156
137
|
it "should set the cache when reading from the database" do
|
157
|
-
|
138
|
+
@c.db.sqls.should == []
|
158
139
|
@cache.should be_empty
|
159
140
|
|
160
141
|
m = @c[1]
|
161
|
-
|
162
|
-
m.values.should ==
|
142
|
+
@c.db.sqls.should == ['SELECT * FROM items WHERE id = 1']
|
143
|
+
m.values.should == {:name=>"sharon", :id=>1}
|
163
144
|
@cache[m.cache_key].should == m
|
164
145
|
m2 = @c[1]
|
165
|
-
|
146
|
+
@c.db.sqls.should == []
|
166
147
|
m2.should == m
|
167
|
-
m2.values.should ==
|
148
|
+
m2.values.should == {:name=>"sharon", :id=>1}
|
168
149
|
|
169
|
-
$sqls.clear
|
170
150
|
m = @c2[1]
|
171
|
-
|
172
|
-
m.values.should ==
|
151
|
+
@c.db.sqls.should == ['SELECT * FROM items WHERE id = 1']
|
152
|
+
m.values.should == {:name=>"sharon", :id=>1}
|
173
153
|
@cache[m.cache_key].should == m
|
174
154
|
m2 = @c2[1]
|
175
|
-
|
155
|
+
@c.db.sqls.should == []
|
176
156
|
m2.should == m
|
177
|
-
m2.values.should ==
|
157
|
+
m2.values.should == {:name=>"sharon", :id=>1}
|
178
158
|
end
|
179
159
|
|
180
160
|
it "should delete the cache when writing to the database" do
|
@@ -183,14 +163,14 @@ describe Sequel::Model, "caching" do
|
|
183
163
|
m.name = 'hey'
|
184
164
|
m.save
|
185
165
|
@cache.has_key?(m.cache_key).should be_false
|
186
|
-
|
166
|
+
@c.db.sqls.should == ["SELECT * FROM items WHERE id = 1", "UPDATE items SET name = 'hey' WHERE (id = 1)"]
|
187
167
|
|
188
168
|
m = @c2[1]
|
189
169
|
@cache[m.cache_key].should == m
|
190
170
|
m.name = 'hey'
|
191
171
|
m.save
|
192
172
|
@cache.has_key?(m.cache_key).should be_false
|
193
|
-
|
173
|
+
@c.db.sqls.should == ["SELECT * FROM items WHERE id = 1", "UPDATE items SET name = 'hey' WHERE (id = 1)"]
|
194
174
|
end
|
195
175
|
|
196
176
|
it "should delete the cache when deleting the record" do
|
@@ -198,40 +178,33 @@ describe Sequel::Model, "caching" do
|
|
198
178
|
@cache[m.cache_key].should == m
|
199
179
|
m.delete
|
200
180
|
@cache.has_key?(m.cache_key).should be_false
|
201
|
-
|
181
|
+
@c.db.sqls.should == ["SELECT * FROM items WHERE id = 1", "DELETE FROM items WHERE (id = 1)"]
|
202
182
|
|
203
183
|
m = @c2[1]
|
204
184
|
@cache[m.cache_key].should == m
|
205
185
|
m.delete
|
206
186
|
@cache.has_key?(m.cache_key).should be_false
|
207
|
-
|
187
|
+
@c.db.sqls.should == ["SELECT * FROM items WHERE id = 1", "DELETE FROM items WHERE (id = 1)"]
|
208
188
|
end
|
209
189
|
|
210
190
|
it "should support #[] as a shortcut to #find with hash" do
|
211
191
|
m = @c[:id => 3]
|
212
192
|
@cache[m.cache_key].should be_nil
|
213
|
-
|
193
|
+
@c.db.sqls.should == ["SELECT * FROM items WHERE (id = 3) LIMIT 1"]
|
214
194
|
m = @c[1]
|
215
195
|
@cache[m.cache_key].should == m
|
216
|
-
|
217
|
-
"SELECT * FROM items WHERE (id = 1) LIMIT 1"]
|
196
|
+
@c.db.sqls.should == ["SELECT * FROM items WHERE id = 1"]
|
218
197
|
@c[:id => 4]
|
219
|
-
|
220
|
-
"SELECT * FROM items WHERE (id = 1) LIMIT 1", \
|
221
|
-
"SELECT * FROM items WHERE (id = 4) LIMIT 1"]
|
198
|
+
@c.db.sqls.should == ["SELECT * FROM items WHERE (id = 4) LIMIT 1"]
|
222
199
|
|
223
|
-
$sqls.clear
|
224
200
|
m = @c2[:id => 3]
|
225
201
|
@cache[m.cache_key].should be_nil
|
226
|
-
|
202
|
+
@c.db.sqls.should == ["SELECT * FROM items WHERE (id = 3) LIMIT 1"]
|
227
203
|
m = @c2[1]
|
228
204
|
@cache[m.cache_key].should == m
|
229
|
-
|
230
|
-
"SELECT * FROM items WHERE (id = 1) LIMIT 1"]
|
205
|
+
@c.db.sqls.should == ["SELECT * FROM items WHERE id = 1"]
|
231
206
|
@c2[:id => 4]
|
232
|
-
|
233
|
-
"SELECT * FROM items WHERE (id = 1) LIMIT 1", \
|
234
|
-
"SELECT * FROM items WHERE (id = 4) LIMIT 1"]
|
207
|
+
@c.db.sqls.should == ["SELECT * FROM items WHERE (id = 4) LIMIT 1"]
|
235
208
|
end
|
236
209
|
|
237
210
|
it "should support ignore_exception option" do
|
@@ -245,6 +218,6 @@ describe Sequel::Model, "caching" do
|
|
245
218
|
end
|
246
219
|
|
247
220
|
it "should rescue an exception if cache_store is memcached and ignore_exception is enabled" do
|
248
|
-
@c4[1].values.should ==
|
221
|
+
@c4[1].values.should == {:name => 'sharon', :id => 1}
|
249
222
|
end
|
250
223
|
end
|
@@ -2,17 +2,16 @@ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
|
|
2
2
|
|
3
3
|
describe "class_table_inheritance plugin" do
|
4
4
|
before do
|
5
|
-
@db =
|
6
|
-
def db.schema(table, opts={})
|
5
|
+
@db = Sequel.mock(:autoid=>proc{|sql| 1})
|
6
|
+
def @db.schema(table, opts={})
|
7
7
|
{:employees=>[[:id, {:primary_key=>true, :type=>:integer}], [:name, {:type=>:string}], [:kind, {:type=>:string}]],
|
8
8
|
:managers=>[[:id, {:type=>:integer}], [:num_staff, {:type=>:integer}]],
|
9
9
|
:executives=>[[:id, {:type=>:integer}], [:num_managers, {:type=>:integer}]],
|
10
10
|
:staff=>[[:id, {:type=>:integer}], [:manager_id, {:type=>:integer}]],
|
11
11
|
}[table.is_a?(Sequel::Dataset) ? table.first_source_table : table]
|
12
12
|
end
|
13
|
-
|
14
|
-
|
15
|
-
def ds.columns
|
13
|
+
@db.extend_datasets do
|
14
|
+
def columns
|
16
15
|
{[:employees]=>[:id, :name, :kind],
|
17
16
|
[:managers]=>[:id, :num_staff],
|
18
17
|
[:executives]=>[:id, :num_managers],
|
@@ -22,13 +21,8 @@ describe "class_table_inheritance plugin" do
|
|
22
21
|
[:employees, :staff]=>[:id, :name, :kind, :manager_id],
|
23
22
|
}[opts[:from] + (opts[:join] || []).map{|x| x.table}]
|
24
23
|
end
|
25
|
-
def ds.insert(*args)
|
26
|
-
db << insert_sql(*args)
|
27
|
-
1
|
28
|
-
end
|
29
|
-
ds
|
30
24
|
end
|
31
|
-
class ::Employee < Sequel::Model(db)
|
25
|
+
class ::Employee < Sequel::Model(@db)
|
32
26
|
def _refresh(x); @values[:id] = 1 end
|
33
27
|
def self.columns
|
34
28
|
dataset.columns
|
@@ -44,7 +38,7 @@ describe "class_table_inheritance plugin" do
|
|
44
38
|
many_to_one :manager
|
45
39
|
end
|
46
40
|
@ds = Employee.dataset
|
47
|
-
@db.
|
41
|
+
@db.sqls
|
48
42
|
end
|
49
43
|
after do
|
50
44
|
Object.send(:remove_const, :Executive)
|
@@ -53,8 +47,8 @@ describe "class_table_inheritance plugin" do
|
|
53
47
|
Object.send(:remove_const, :Employee)
|
54
48
|
end
|
55
49
|
|
56
|
-
specify "should have simple_table = nil" do
|
57
|
-
Employee.simple_table.should ==
|
50
|
+
specify "should have simple_table = nil for subclasses" do
|
51
|
+
Employee.simple_table.should == "employees"
|
58
52
|
Manager.simple_table.should == nil
|
59
53
|
Executive.simple_table.should == nil
|
60
54
|
Staff.simple_table.should == nil
|
@@ -68,33 +62,18 @@ describe "class_table_inheritance plugin" do
|
|
68
62
|
end
|
69
63
|
|
70
64
|
it "should return rows with the correct class based on the polymorphic_key value" do
|
71
|
-
|
72
|
-
yield({:kind=>'Employee'})
|
73
|
-
yield({:kind=>'Manager'})
|
74
|
-
yield({:kind=>'Executive'})
|
75
|
-
yield({:kind=>'Staff'})
|
76
|
-
end
|
65
|
+
@ds._fetch = [{:kind=>'Employee'}, {:kind=>'Manager'}, {:kind=>'Executive'}, {:kind=>'Staff'}]
|
77
66
|
Employee.all.collect{|x| x.class}.should == [Employee, Manager, Executive, Staff]
|
78
67
|
end
|
79
68
|
|
80
69
|
it "should return rows with the correct class based on the polymorphic_key value for subclasses" do
|
81
|
-
|
82
|
-
def ds.fetch_rows(sql)
|
83
|
-
yield({:kind=>'Manager'})
|
84
|
-
yield({:kind=>'Executive'})
|
85
|
-
end
|
70
|
+
Manager.dataset._fetch = [{:kind=>'Manager'}, {:kind=>'Executive'}]
|
86
71
|
Manager.all.collect{|x| x.class}.should == [Manager, Executive]
|
87
72
|
end
|
88
73
|
|
89
74
|
it "should return rows with the current class if cti_key is nil" do
|
90
75
|
Employee.plugin(:class_table_inheritance)
|
91
|
-
ds = Employee
|
92
|
-
def ds.fetch_rows(sql)
|
93
|
-
yield({:kind=>'Employee'})
|
94
|
-
yield({:kind=>'Manager'})
|
95
|
-
yield({:kind=>'Executive'})
|
96
|
-
yield({:kind=>'Staff'})
|
97
|
-
end
|
76
|
+
@ds._fetch = [{:kind=>'Employee'}, {:kind=>'Manager'}, {:kind=>'Executive'}, {:kind=>'Staff'}]
|
98
77
|
Employee.all.collect{|x| x.class}.should == [Employee, Employee, Employee, Employee]
|
99
78
|
end
|
100
79
|
|
@@ -102,35 +81,19 @@ describe "class_table_inheritance plugin" do
|
|
102
81
|
Employee.plugin(:class_table_inheritance)
|
103
82
|
Object.send(:remove_const, :Executive)
|
104
83
|
Object.send(:remove_const, :Manager)
|
105
|
-
class ::Manager < Employee
|
106
|
-
end
|
107
|
-
|
108
|
-
end
|
109
|
-
ds = Manager.dataset
|
110
|
-
def ds.fetch_rows(sql)
|
111
|
-
yield({:kind=>'Manager'})
|
112
|
-
yield({:kind=>'Executive'})
|
113
|
-
end
|
84
|
+
class ::Manager < Employee; end
|
85
|
+
class ::Executive < Manager; end
|
86
|
+
Manager.dataset._fetch = [{:kind=>'Manager'}, {:kind=>'Executive'}]
|
114
87
|
Manager.all.collect{|x| x.class}.should == [Manager, Manager]
|
115
88
|
end
|
116
89
|
|
117
90
|
it "should fallback to the main class if the given class does not exist" do
|
118
|
-
|
119
|
-
yield({:kind=>'Employee'})
|
120
|
-
yield({:kind=>'Manager'})
|
121
|
-
yield({:kind=>'Blah'})
|
122
|
-
yield({:kind=>'Staff'})
|
123
|
-
end
|
91
|
+
@ds._fetch = [{:kind=>'Employee'}, {:kind=>'Manager'}, {:kind=>'Blah'}, {:kind=>'Staff'}]
|
124
92
|
Employee.all.collect{|x| x.class}.should == [Employee, Manager, Employee, Staff]
|
125
93
|
end
|
126
94
|
|
127
95
|
it "should fallback to the main class if the given class does not exist in subclasses" do
|
128
|
-
|
129
|
-
def ds.fetch_rows(sql)
|
130
|
-
yield({:kind=>'Manager'})
|
131
|
-
yield({:kind=>'Executive'})
|
132
|
-
yield({:kind=>'Blah'})
|
133
|
-
end
|
96
|
+
Manager.dataset._fetch = [{:kind=>'Manager'}, {:kind=>'Executive'}, {:kind=>'Blah'}]
|
134
97
|
Manager.all.collect{|x| x.class}.should == [Manager, Executive, Manager]
|
135
98
|
end
|
136
99
|
|
@@ -167,19 +130,10 @@ describe "class_table_inheritance plugin" do
|
|
167
130
|
end
|
168
131
|
|
169
132
|
it "should lazily load attributes for columns in subclass tables" do
|
170
|
-
|
171
|
-
def ds.fetch_rows(sql)
|
172
|
-
@db << sql
|
173
|
-
yield({:id=>1, :name=>'J', :kind=>'Executive', :num_staff=>2})
|
174
|
-
end
|
133
|
+
Manager.dataset._fetch = {:id=>1, :name=>'J', :kind=>'Executive', :num_staff=>2}
|
175
134
|
m = Manager[1]
|
176
135
|
@db.sqls.should == ['SELECT * FROM employees INNER JOIN managers USING (id) WHERE (id = 1) LIMIT 1']
|
177
|
-
|
178
|
-
ds = Executive.dataset
|
179
|
-
def ds.fetch_rows(sql)
|
180
|
-
@db << sql
|
181
|
-
yield({:num_managers=>3})
|
182
|
-
end
|
136
|
+
Executive.dataset._fetch = {:num_managers=>3}
|
183
137
|
m.num_managers.should == 3
|
184
138
|
@db.sqls.should == ['SELECT num_managers FROM employees INNER JOIN managers USING (id) INNER JOIN executives USING (id) WHERE (id = 1) LIMIT 1']
|
185
139
|
m.values.should == {:id=>1, :name=>'J', :kind=>'Executive', :num_staff=>2, :num_managers=>3}
|
@@ -210,20 +164,22 @@ describe "class_table_inheritance plugin" do
|
|
210
164
|
|
211
165
|
it "should insert the correct rows into all tables when inserting" do
|
212
166
|
Executive.create(:num_managers=>3, :num_staff=>2, :name=>'E')
|
213
|
-
@db.sqls
|
214
|
-
|
215
|
-
|
216
|
-
|
167
|
+
sqls = @db.sqls
|
168
|
+
sqls.length.should == 3
|
169
|
+
sqls[0].should =~ /INSERT INTO employees \((name|kind), (name|kind)\) VALUES \('(E|Executive)', '(E|Executive)'\)/
|
170
|
+
sqls[1].should =~ /INSERT INTO managers \((num_staff|id), (num_staff|id)\) VALUES \([12], [12]\)/
|
171
|
+
sqls[2].should =~ /INSERT INTO executives \((num_managers|id), (num_managers|id)\) VALUES \([13], [13]\)/
|
217
172
|
end
|
218
173
|
|
219
174
|
it "should insert the correct rows into all tables with a given primary key" do
|
220
175
|
e = Executive.new(:num_managers=>3, :num_staff=>2, :name=>'E')
|
221
176
|
e.id = 2
|
222
177
|
e.save
|
223
|
-
@db.sqls
|
224
|
-
|
225
|
-
|
226
|
-
|
178
|
+
sqls = @db.sqls
|
179
|
+
sqls.length.should == 3
|
180
|
+
sqls[0].should =~ /INSERT INTO employees \((name|kind|id), (name|kind|id), (name|kind|id)\) VALUES \(('E'|'Executive'|2), ('E'|'Executive'|2), ('E'|'Executive'|2)\)/
|
181
|
+
sqls[1].should =~ /INSERT INTO managers \((num_staff|id), (num_staff|id)\) VALUES \(2, 2\)/
|
182
|
+
sqls[2].should =~ /INSERT INTO executives \((num_managers|id), (num_managers|id)\) VALUES \([23], [23]\)/
|
227
183
|
end
|
228
184
|
|
229
185
|
it "should update the correct rows in all tables when updating" do
|
@@ -232,21 +188,13 @@ describe "class_table_inheritance plugin" do
|
|
232
188
|
end
|
233
189
|
|
234
190
|
it "should handle many_to_one relationships correctly" do
|
235
|
-
|
236
|
-
def ds.fetch_rows(sql)
|
237
|
-
@db << sql
|
238
|
-
yield({:id=>3, :name=>'E', :kind=>'Executive', :num_managers=>3})
|
239
|
-
end
|
191
|
+
Manager.dataset._fetch = {:id=>3, :name=>'E', :kind=>'Executive', :num_managers=>3}
|
240
192
|
Staff.load(:manager_id=>3).manager.should == Executive.load(:id=>3, :name=>'E', :kind=>'Executive', :num_managers=>3)
|
241
193
|
@db.sqls.should == ['SELECT * FROM employees INNER JOIN managers USING (id) WHERE (managers.id = 3) LIMIT 1']
|
242
194
|
end
|
243
195
|
|
244
196
|
it "should handle one_to_many relationships correctly" do
|
245
|
-
|
246
|
-
def ds.fetch_rows(sql)
|
247
|
-
@db << sql
|
248
|
-
yield({:id=>1, :name=>'S', :kind=>'Staff', :manager_id=>3})
|
249
|
-
end
|
197
|
+
Staff.dataset._fetch = {:id=>1, :name=>'S', :kind=>'Staff', :manager_id=>3}
|
250
198
|
Executive.load(:id=>3).staff_members.should == [Staff.load(:id=>1, :name=>'S', :kind=>'Staff', :manager_id=>3)]
|
251
199
|
@db.sqls.should == ['SELECT * FROM employees INNER JOIN staff USING (id) WHERE (staff.manager_id = 3)']
|
252
200
|
end
|