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.
Files changed (106) hide show
  1. data/CHANGELOG +35 -3
  2. data/Rakefile +2 -1
  3. data/doc/association_basics.rdoc +11 -0
  4. data/doc/opening_databases.rdoc +2 -0
  5. data/doc/release_notes/3.30.0.txt +135 -0
  6. data/doc/testing.rdoc +17 -3
  7. data/lib/sequel/adapters/amalgalite.rb +2 -2
  8. data/lib/sequel/adapters/do/mysql.rb +5 -2
  9. data/lib/sequel/adapters/ibmdb.rb +2 -2
  10. data/lib/sequel/adapters/jdbc.rb +126 -43
  11. data/lib/sequel/adapters/jdbc/as400.rb +11 -3
  12. data/lib/sequel/adapters/jdbc/db2.rb +2 -1
  13. data/lib/sequel/adapters/jdbc/derby.rb +44 -19
  14. data/lib/sequel/adapters/jdbc/h2.rb +32 -19
  15. data/lib/sequel/adapters/jdbc/hsqldb.rb +21 -17
  16. data/lib/sequel/adapters/jdbc/jtds.rb +9 -4
  17. data/lib/sequel/adapters/jdbc/mssql.rb +3 -1
  18. data/lib/sequel/adapters/jdbc/mysql.rb +2 -1
  19. data/lib/sequel/adapters/jdbc/oracle.rb +21 -7
  20. data/lib/sequel/adapters/jdbc/postgresql.rb +3 -2
  21. data/lib/sequel/adapters/jdbc/sqlite.rb +2 -1
  22. data/lib/sequel/adapters/jdbc/sqlserver.rb +48 -18
  23. data/lib/sequel/adapters/mock.rb +2 -1
  24. data/lib/sequel/adapters/mysql.rb +4 -2
  25. data/lib/sequel/adapters/mysql2.rb +2 -2
  26. data/lib/sequel/adapters/odbc/mssql.rb +1 -1
  27. data/lib/sequel/adapters/openbase.rb +1 -1
  28. data/lib/sequel/adapters/oracle.rb +6 -6
  29. data/lib/sequel/adapters/postgres.rb +25 -12
  30. data/lib/sequel/adapters/shared/access.rb +14 -6
  31. data/lib/sequel/adapters/shared/db2.rb +36 -13
  32. data/lib/sequel/adapters/shared/firebird.rb +12 -5
  33. data/lib/sequel/adapters/shared/informix.rb +11 -3
  34. data/lib/sequel/adapters/shared/mssql.rb +94 -47
  35. data/lib/sequel/adapters/shared/mysql.rb +107 -49
  36. data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +2 -2
  37. data/lib/sequel/adapters/shared/oracle.rb +54 -27
  38. data/lib/sequel/adapters/shared/postgres.rb +65 -26
  39. data/lib/sequel/adapters/shared/progress.rb +4 -1
  40. data/lib/sequel/adapters/shared/sqlite.rb +36 -20
  41. data/lib/sequel/adapters/sqlite.rb +2 -3
  42. data/lib/sequel/adapters/swift/mysql.rb +3 -2
  43. data/lib/sequel/adapters/swift/sqlite.rb +2 -2
  44. data/lib/sequel/adapters/tinytds.rb +14 -8
  45. data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +7 -4
  46. data/lib/sequel/database/misc.rb +6 -2
  47. data/lib/sequel/dataset/graph.rb +33 -7
  48. data/lib/sequel/dataset/prepared_statements.rb +19 -5
  49. data/lib/sequel/dataset/sql.rb +611 -201
  50. data/lib/sequel/model/associations.rb +12 -5
  51. data/lib/sequel/model/base.rb +20 -5
  52. data/lib/sequel/plugins/sharding.rb +9 -29
  53. data/lib/sequel/sql.rb +2 -1
  54. data/lib/sequel/timezones.rb +14 -4
  55. data/lib/sequel/version.rb +1 -1
  56. data/spec/adapters/mysql_spec.rb +10 -0
  57. data/spec/adapters/oracle_spec.rb +1 -1
  58. data/spec/core/core_sql_spec.rb +3 -1
  59. data/spec/core/database_spec.rb +42 -0
  60. data/spec/core/dataset_spec.rb +10 -3
  61. data/spec/core/mock_adapter_spec.rb +4 -0
  62. data/spec/core/object_graph_spec.rb +38 -0
  63. data/spec/extensions/association_autoreloading_spec.rb +1 -10
  64. data/spec/extensions/association_dependencies_spec.rb +2 -12
  65. data/spec/extensions/association_pks_spec.rb +35 -39
  66. data/spec/extensions/caching_spec.rb +23 -50
  67. data/spec/extensions/class_table_inheritance_spec.rb +30 -82
  68. data/spec/extensions/composition_spec.rb +18 -13
  69. data/spec/extensions/hook_class_methods_spec.rb +65 -91
  70. data/spec/extensions/identity_map_spec.rb +33 -103
  71. data/spec/extensions/instance_filters_spec.rb +10 -21
  72. data/spec/extensions/instance_hooks_spec.rb +6 -24
  73. data/spec/extensions/json_serializer_spec.rb +4 -5
  74. data/spec/extensions/lazy_attributes_spec.rb +16 -20
  75. data/spec/extensions/list_spec.rb +17 -39
  76. data/spec/extensions/many_through_many_spec.rb +135 -277
  77. data/spec/extensions/migration_spec.rb +18 -15
  78. data/spec/extensions/named_timezones_spec.rb +1 -1
  79. data/spec/extensions/nested_attributes_spec.rb +97 -92
  80. data/spec/extensions/optimistic_locking_spec.rb +9 -20
  81. data/spec/extensions/prepared_statements_associations_spec.rb +22 -37
  82. data/spec/extensions/prepared_statements_safe_spec.rb +9 -27
  83. data/spec/extensions/prepared_statements_spec.rb +11 -30
  84. data/spec/extensions/prepared_statements_with_pk_spec.rb +6 -13
  85. data/spec/extensions/pretty_table_spec.rb +1 -6
  86. data/spec/extensions/rcte_tree_spec.rb +41 -43
  87. data/spec/extensions/schema_dumper_spec.rb +3 -6
  88. data/spec/extensions/serialization_spec.rb +20 -32
  89. data/spec/extensions/sharding_spec.rb +66 -140
  90. data/spec/extensions/single_table_inheritance_spec.rb +14 -36
  91. data/spec/extensions/spec_helper.rb +10 -64
  92. data/spec/extensions/sql_expr_spec.rb +20 -60
  93. data/spec/extensions/tactical_eager_loading_spec.rb +9 -19
  94. data/spec/extensions/timestamps_spec.rb +6 -6
  95. data/spec/extensions/to_dot_spec.rb +1 -2
  96. data/spec/extensions/touch_spec.rb +13 -14
  97. data/spec/extensions/tree_spec.rb +11 -26
  98. data/spec/extensions/update_primary_key_spec.rb +30 -24
  99. data/spec/extensions/validation_class_methods_spec.rb +30 -51
  100. data/spec/extensions/validation_helpers_spec.rb +16 -35
  101. data/spec/integration/dataset_test.rb +16 -4
  102. data/spec/integration/prepared_statement_test.rb +4 -2
  103. data/spec/model/eager_loading_spec.rb +16 -0
  104. data/spec/model/model_spec.rb +15 -1
  105. data/spec/model/record_spec.rb +60 -0
  106. 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
- ds1 = @Artist.dataset
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
- ds1 = @Album.dataset
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 = MODEL_DB.clone
6
- mod = Module.new do
7
- def fetch_rows(sql)
8
- case sql
9
- when "SELECT id FROM albums WHERE (albums.artist_id = 1)"
10
- yield({:id=>1})
11
- yield({:id=>2})
12
- yield({:id=>3})
13
- when /SELECT tag_id FROM albums_tags WHERE \(album_id = (\d)\)/
14
- yield({:tag_id=>1}) if $1 == '1'
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.reset
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[0].should == "DELETE FROM albums_tags WHERE ((album_id = 2) AND (tag_id NOT IN (1, 3)))"
70
- @db.sqls[1].should =~ /INSERT INTO albums_tags \((album_id, tag_id|tag_id, album_id)\) VALUES \((2, 1|1, 2)\)/
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[0].should == "BEGIN"
87
- @db.sqls[1].should == "DELETE FROM albums_tags WHERE ((album_id = 2) AND (tag_id NOT IN (1, 3)))"
88
- @db.sqls[2].should =~ /INSERT INTO albums_tags \((album_id, tag_id|tag_id, album_id)\) VALUES \((2, 1|1, 2)\)/
89
- @db.sqls[3].should == "COMMIT"
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[0].should == "DELETE FROM albums_tags WHERE ((album_id = 2) AND (tag_id NOT IN (1, 3)))"
110
- @db.sqls[1].should =~ /INSERT INTO albums_tags \((album_id, tag_id|tag_id, album_id)\) VALUES \((2, 1|1, 2)\)/
111
- @db.sqls.length.should == 2
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[0].should == "DELETE FROM albums_tags WHERE ((album_id = 2) AND (tag_id NOT IN ('1', '3')))"
118
- @db.sqls[1].should =~ /INSERT INTO albums_tags \((album_id, tag_id|tag_id, album_id)\) VALUES \((2, '1'|'1', 2)\)/
119
- @db.sqls[2].should =~ /INSERT INTO albums_tags \((album_id, tag_id|tag_id, album_id)\) VALUES \((2, '3'|'3', 2)\)/
120
- @db.sqls.length.should == 3
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
- $sqls = []
51
- @dataset.extend(Module.new {
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
- $sqls.should == []
138
+ @c.db.sqls.should == []
158
139
  @cache.should be_empty
159
140
 
160
141
  m = @c[1]
161
- $sqls.should == ['SELECT * FROM items WHERE (id = 1) LIMIT 1']
162
- m.values.should == $cache_dataset_row
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
- $sqls.should == ['SELECT * FROM items WHERE (id = 1) LIMIT 1']
146
+ @c.db.sqls.should == []
166
147
  m2.should == m
167
- m2.values.should == $cache_dataset_row
148
+ m2.values.should == {:name=>"sharon", :id=>1}
168
149
 
169
- $sqls.clear
170
150
  m = @c2[1]
171
- $sqls.should == ['SELECT * FROM items WHERE (id = 1) LIMIT 1']
172
- m.values.should == $cache_dataset_row
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
- $sqls.should == ['SELECT * FROM items WHERE (id = 1) LIMIT 1']
155
+ @c.db.sqls.should == []
176
156
  m2.should == m
177
- m2.values.should == $cache_dataset_row
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
- $sqls.last.should == "UPDATE items SET name = 'hey' WHERE (id = 1)"
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
- $sqls.last.should == "UPDATE items SET name = 'hey' WHERE (id = 1)"
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
- $sqls.last.should == "DELETE FROM items WHERE (id = 1)"
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
- $sqls.last.should == "DELETE FROM items WHERE (id = 1)"
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
- $sqls.last.should == "SELECT * FROM items WHERE (id = 3) LIMIT 1"
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
- $sqls.should == ["SELECT * FROM items WHERE (id = 3) LIMIT 1", \
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
- $sqls.should == ["SELECT * FROM items WHERE (id = 3) LIMIT 1", \
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
- $sqls.last.should == "SELECT * FROM items WHERE (id = 3) LIMIT 1"
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
- $sqls.should == ["SELECT * FROM items WHERE (id = 3) LIMIT 1", \
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
- $sqls.should == ["SELECT * FROM items WHERE (id = 3) LIMIT 1", \
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 == $cache_dataset_row
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 = db = MODEL_DB.clone
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
- def db.dataset(*args)
14
- ds = super(*args)
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.reset
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 == nil
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
- def @ds.fetch_rows(sql)
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
- ds = Manager.dataset
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.dataset
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
- class ::Executive < Manager
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
- def @ds.fetch_rows(sql)
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
- ds = Manager.dataset
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
- ds = Manager.dataset
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
- @db.reset
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.length.should == 3
214
- @db.sqls[0].should =~ /INSERT INTO employees \((name|kind), (name|kind)\) VALUES \('(E|Executive)', '(E|Executive)'\)/
215
- @db.sqls[1].should =~ /INSERT INTO managers \((num_staff|id), (num_staff|id)\) VALUES \([12], [12]\)/
216
- @db.sqls[2].should =~ /INSERT INTO executives \((num_managers|id), (num_managers|id)\) VALUES \([13], [13]\)/
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.length.should == 3
224
- @db.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)\)/
225
- @db.sqls[1].should =~ /INSERT INTO managers \((num_staff|id), (num_staff|id)\) VALUES \(2, 2\)/
226
- @db.sqls[2].should =~ /INSERT INTO executives \((num_managers|id), (num_managers|id)\) VALUES \([23], [23]\)/
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
- ds = Manager.dataset
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
- ds = Staff.dataset
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