sequel 3.29.0 → 3.30.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 +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
|