sequel 3.46.0 → 3.47.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 (170) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +96 -0
  3. data/Rakefile +7 -1
  4. data/bin/sequel +6 -4
  5. data/doc/active_record.rdoc +1 -1
  6. data/doc/advanced_associations.rdoc +14 -35
  7. data/doc/association_basics.rdoc +66 -4
  8. data/doc/migration.rdoc +4 -0
  9. data/doc/opening_databases.rdoc +6 -0
  10. data/doc/postgresql.rdoc +302 -0
  11. data/doc/release_notes/3.47.0.txt +270 -0
  12. data/doc/security.rdoc +6 -0
  13. data/lib/sequel/adapters/ibmdb.rb +9 -9
  14. data/lib/sequel/adapters/jdbc.rb +22 -7
  15. data/lib/sequel/adapters/jdbc/postgresql.rb +7 -2
  16. data/lib/sequel/adapters/mock.rb +2 -0
  17. data/lib/sequel/adapters/postgres.rb +44 -13
  18. data/lib/sequel/adapters/shared/mssql.rb +1 -1
  19. data/lib/sequel/adapters/shared/mysql.rb +2 -2
  20. data/lib/sequel/adapters/shared/postgres.rb +94 -55
  21. data/lib/sequel/adapters/shared/sqlite.rb +3 -1
  22. data/lib/sequel/adapters/sqlite.rb +2 -2
  23. data/lib/sequel/adapters/utils/pg_types.rb +1 -14
  24. data/lib/sequel/adapters/utils/split_alter_table.rb +3 -3
  25. data/lib/sequel/connection_pool/threaded.rb +1 -1
  26. data/lib/sequel/core.rb +1 -1
  27. data/lib/sequel/database/connecting.rb +2 -2
  28. data/lib/sequel/database/features.rb +5 -0
  29. data/lib/sequel/database/misc.rb +47 -5
  30. data/lib/sequel/database/query.rb +2 -2
  31. data/lib/sequel/dataset/actions.rb +4 -2
  32. data/lib/sequel/dataset/misc.rb +1 -1
  33. data/lib/sequel/dataset/prepared_statements.rb +1 -1
  34. data/lib/sequel/dataset/query.rb +8 -6
  35. data/lib/sequel/dataset/sql.rb +8 -6
  36. data/lib/sequel/extensions/constraint_validations.rb +5 -2
  37. data/lib/sequel/extensions/migration.rb +10 -8
  38. data/lib/sequel/extensions/pagination.rb +3 -0
  39. data/lib/sequel/extensions/pg_array.rb +85 -25
  40. data/lib/sequel/extensions/pg_hstore.rb +8 -1
  41. data/lib/sequel/extensions/pg_hstore_ops.rb +4 -1
  42. data/lib/sequel/extensions/pg_inet.rb +16 -13
  43. data/lib/sequel/extensions/pg_interval.rb +6 -2
  44. data/lib/sequel/extensions/pg_json.rb +18 -11
  45. data/lib/sequel/extensions/pg_range.rb +17 -2
  46. data/lib/sequel/extensions/pg_range_ops.rb +7 -5
  47. data/lib/sequel/extensions/pg_row.rb +29 -12
  48. data/lib/sequel/extensions/pretty_table.rb +3 -0
  49. data/lib/sequel/extensions/query.rb +3 -0
  50. data/lib/sequel/extensions/schema_caching.rb +2 -0
  51. data/lib/sequel/extensions/schema_dumper.rb +3 -1
  52. data/lib/sequel/extensions/select_remove.rb +3 -0
  53. data/lib/sequel/model.rb +8 -2
  54. data/lib/sequel/model/associations.rb +39 -27
  55. data/lib/sequel/model/base.rb +99 -38
  56. data/lib/sequel/model/plugins.rb +25 -0
  57. data/lib/sequel/plugins/association_autoreloading.rb +27 -22
  58. data/lib/sequel/plugins/association_dependencies.rb +1 -7
  59. data/lib/sequel/plugins/auto_validations.rb +110 -0
  60. data/lib/sequel/plugins/boolean_readers.rb +1 -6
  61. data/lib/sequel/plugins/caching.rb +6 -13
  62. data/lib/sequel/plugins/class_table_inheritance.rb +1 -0
  63. data/lib/sequel/plugins/composition.rb +14 -7
  64. data/lib/sequel/plugins/constraint_validations.rb +2 -13
  65. data/lib/sequel/plugins/defaults_setter.rb +1 -6
  66. data/lib/sequel/plugins/dirty.rb +8 -0
  67. data/lib/sequel/plugins/error_splitter.rb +54 -0
  68. data/lib/sequel/plugins/force_encoding.rb +1 -5
  69. data/lib/sequel/plugins/hook_class_methods.rb +1 -6
  70. data/lib/sequel/plugins/input_transformer.rb +79 -0
  71. data/lib/sequel/plugins/instance_filters.rb +7 -1
  72. data/lib/sequel/plugins/instance_hooks.rb +7 -1
  73. data/lib/sequel/plugins/json_serializer.rb +5 -10
  74. data/lib/sequel/plugins/lazy_attributes.rb +20 -7
  75. data/lib/sequel/plugins/list.rb +1 -6
  76. data/lib/sequel/plugins/many_through_many.rb +1 -2
  77. data/lib/sequel/plugins/many_to_one_pk_lookup.rb +23 -39
  78. data/lib/sequel/plugins/optimistic_locking.rb +1 -5
  79. data/lib/sequel/plugins/pg_row.rb +4 -2
  80. data/lib/sequel/plugins/pg_typecast_on_load.rb +3 -7
  81. data/lib/sequel/plugins/prepared_statements.rb +1 -5
  82. data/lib/sequel/plugins/prepared_statements_safe.rb +2 -11
  83. data/lib/sequel/plugins/rcte_tree.rb +2 -2
  84. data/lib/sequel/plugins/serialization.rb +11 -13
  85. data/lib/sequel/plugins/serialization_modification_detection.rb +13 -1
  86. data/lib/sequel/plugins/single_table_inheritance.rb +4 -4
  87. data/lib/sequel/plugins/static_cache.rb +67 -19
  88. data/lib/sequel/plugins/string_stripper.rb +7 -27
  89. data/lib/sequel/plugins/subclasses.rb +3 -5
  90. data/lib/sequel/plugins/tactical_eager_loading.rb +2 -2
  91. data/lib/sequel/plugins/timestamps.rb +2 -7
  92. data/lib/sequel/plugins/touch.rb +5 -8
  93. data/lib/sequel/plugins/tree.rb +1 -6
  94. data/lib/sequel/plugins/typecast_on_load.rb +1 -5
  95. data/lib/sequel/plugins/update_primary_key.rb +26 -14
  96. data/lib/sequel/plugins/validation_class_methods.rb +31 -16
  97. data/lib/sequel/plugins/validation_helpers.rb +50 -26
  98. data/lib/sequel/plugins/xml_serializer.rb +3 -6
  99. data/lib/sequel/sql.rb +1 -1
  100. data/lib/sequel/version.rb +1 -1
  101. data/spec/adapters/postgres_spec.rb +131 -15
  102. data/spec/adapters/sqlite_spec.rb +1 -1
  103. data/spec/core/connection_pool_spec.rb +16 -17
  104. data/spec/core/database_spec.rb +111 -40
  105. data/spec/core/dataset_spec.rb +65 -74
  106. data/spec/core/expression_filters_spec.rb +6 -5
  107. data/spec/core/object_graph_spec.rb +0 -1
  108. data/spec/core/schema_spec.rb +23 -23
  109. data/spec/core/spec_helper.rb +5 -1
  110. data/spec/extensions/association_dependencies_spec.rb +1 -1
  111. data/spec/extensions/association_proxies_spec.rb +1 -1
  112. data/spec/extensions/auto_validations_spec.rb +90 -0
  113. data/spec/extensions/caching_spec.rb +6 -0
  114. data/spec/extensions/class_table_inheritance_spec.rb +8 -1
  115. data/spec/extensions/composition_spec.rb +12 -5
  116. data/spec/extensions/constraint_validations_spec.rb +4 -4
  117. data/spec/extensions/core_refinements_spec.rb +29 -79
  118. data/spec/extensions/dirty_spec.rb +14 -0
  119. data/spec/extensions/error_splitter_spec.rb +18 -0
  120. data/spec/extensions/identity_map_spec.rb +0 -1
  121. data/spec/extensions/input_transformer_spec.rb +54 -0
  122. data/spec/extensions/instance_filters_spec.rb +6 -0
  123. data/spec/extensions/instance_hooks_spec.rb +12 -1
  124. data/spec/extensions/json_serializer_spec.rb +0 -1
  125. data/spec/extensions/lazy_attributes_spec.rb +64 -55
  126. data/spec/extensions/looser_typecasting_spec.rb +1 -1
  127. data/spec/extensions/many_through_many_spec.rb +3 -4
  128. data/spec/extensions/many_to_one_pk_lookup_spec.rb +53 -15
  129. data/spec/extensions/migration_spec.rb +16 -0
  130. data/spec/extensions/null_dataset_spec.rb +1 -1
  131. data/spec/extensions/pg_array_spec.rb +48 -1
  132. data/spec/extensions/pg_hstore_ops_spec.rb +10 -2
  133. data/spec/extensions/pg_hstore_spec.rb +5 -0
  134. data/spec/extensions/pg_inet_spec.rb +5 -0
  135. data/spec/extensions/pg_interval_spec.rb +7 -3
  136. data/spec/extensions/pg_json_spec.rb +6 -1
  137. data/spec/extensions/pg_range_ops_spec.rb +4 -1
  138. data/spec/extensions/pg_range_spec.rb +5 -0
  139. data/spec/extensions/pg_row_plugin_spec.rb +13 -0
  140. data/spec/extensions/pg_row_spec.rb +28 -19
  141. data/spec/extensions/pg_typecast_on_load_spec.rb +6 -1
  142. data/spec/extensions/prepared_statements_associations_spec.rb +1 -1
  143. data/spec/extensions/query_literals_spec.rb +1 -1
  144. data/spec/extensions/rcte_tree_spec.rb +2 -2
  145. data/spec/extensions/schema_spec.rb +2 -2
  146. data/spec/extensions/serialization_modification_detection_spec.rb +8 -0
  147. data/spec/extensions/serialization_spec.rb +15 -1
  148. data/spec/extensions/sharding_spec.rb +1 -1
  149. data/spec/extensions/single_table_inheritance_spec.rb +1 -1
  150. data/spec/extensions/static_cache_spec.rb +59 -9
  151. data/spec/extensions/tactical_eager_loading_spec.rb +19 -4
  152. data/spec/extensions/update_primary_key_spec.rb +17 -1
  153. data/spec/extensions/validation_class_methods_spec.rb +25 -0
  154. data/spec/extensions/validation_helpers_spec.rb +59 -3
  155. data/spec/integration/associations_test.rb +5 -5
  156. data/spec/integration/eager_loader_test.rb +32 -63
  157. data/spec/integration/model_test.rb +2 -2
  158. data/spec/integration/plugin_test.rb +88 -56
  159. data/spec/integration/prepared_statement_test.rb +1 -1
  160. data/spec/integration/schema_test.rb +1 -1
  161. data/spec/integration/timezone_test.rb +0 -1
  162. data/spec/integration/transaction_test.rb +0 -1
  163. data/spec/model/association_reflection_spec.rb +1 -1
  164. data/spec/model/associations_spec.rb +106 -84
  165. data/spec/model/base_spec.rb +4 -4
  166. data/spec/model/eager_loading_spec.rb +8 -8
  167. data/spec/model/model_spec.rb +27 -9
  168. data/spec/model/plugins_spec.rb +71 -0
  169. data/spec/model/record_spec.rb +99 -13
  170. metadata +12 -2
@@ -33,7 +33,7 @@ describe "Model attribute setters" do
33
33
  @o.changed_columns.should == [:x, :y]
34
34
  end
35
35
 
36
- it "should have columns that can't be called like normal ruby methods" do
36
+ it "should handle columns that can't be called like normal ruby methods" do
37
37
  @o.send(:"x y=", 3)
38
38
  @o.changed_columns.should == [:"x y"]
39
39
  @o.values.should == {:"x y"=>3}
@@ -385,7 +385,7 @@ describe "Model.db" do
385
385
  Sequel::Model.db = @model_db
386
386
  end
387
387
 
388
- specify "should be required when create named model classes" do
388
+ specify "should be required when creating named model classes" do
389
389
  begin
390
390
  proc{class ModelTest < Sequel::Model; end}.should raise_error(Sequel::Error)
391
391
  ensure
@@ -655,7 +655,7 @@ describe Sequel::Model, ".[] optimization" do
655
655
  @c.simple_table.should == '"b"."a"'
656
656
  end
657
657
 
658
- it "should simple_pk and simple_table respect dataset's identifier input methods" do
658
+ it "should have simple_pk and simple_table respect dataset's identifier input methods" do
659
659
  ds = @db[:ab]
660
660
  ds.identifier_input_method = :reverse
661
661
  @c.set_dataset ds
@@ -672,7 +672,7 @@ describe Sequel::Model, ".[] optimization" do
672
672
  @c.simple_table.should == nil
673
673
  end
674
674
 
675
- it "should have simple_table superclasses setting if inheriting" do
675
+ it "should have simple_table inherit superclass's setting" do
676
676
  Class.new(@c).simple_table.should == nil
677
677
  @c.set_dataset :a
678
678
  Class.new(@c).simple_table.should == '"a"'
@@ -293,13 +293,13 @@ describe Sequel::Model, "#eager" do
293
293
 
294
294
  it "should correctly handle a :select=>[] option to many_to_many" do
295
295
  EagerAlbum.many_to_many :sgenres, :clone=>:genres, :select=>[]
296
- a = EagerAlbum.eager(:sgenres).all
296
+ EagerAlbum.eager(:sgenres).all
297
297
  MODEL_DB.sqls.should == ['SELECT * FROM albums', "SELECT *, ag.album_id AS x_foreign_key_x FROM genres INNER JOIN ag ON ((ag.genre_id = genres.id) AND (ag.album_id IN (1)))"]
298
298
  end
299
299
 
300
300
  it "should correctly handle an aliased join table in many_to_many" do
301
301
  EagerAlbum.many_to_many :sgenres, :clone=>:genres, :join_table=>:ag___ga
302
- a = EagerAlbum.eager(:sgenres).all
302
+ EagerAlbum.eager(:sgenres).all
303
303
  MODEL_DB.sqls.should == ['SELECT * FROM albums', "SELECT genres.*, ga.album_id AS x_foreign_key_x FROM genres INNER JOIN ag AS ga ON ((ga.genre_id = genres.id) AND (ga.album_id IN (1)))"]
304
304
  end
305
305
 
@@ -1469,7 +1469,7 @@ describe Sequel::Model, "#eager_graph" do
1469
1469
  end
1470
1470
 
1471
1471
  it "should eagerly load a many_to_one association with a custom callback" do
1472
- ds = GraphAlbum.eager_graph(:band => proc {|ds| ds.select(:id).columns(:id)})
1472
+ ds = GraphAlbum.eager_graph(:band => proc {|ds1| ds1.select(:id).columns(:id)})
1473
1473
  ds.sql.should == 'SELECT albums.id, albums.band_id, band.id AS band_id_0 FROM albums LEFT OUTER JOIN (SELECT id FROM bands) AS band ON (band.id = albums.band_id)'
1474
1474
  ds._fetch = {:id=>1, :band_id=>2, :band_id_0=>2}
1475
1475
  a = ds.all
@@ -1479,7 +1479,7 @@ describe Sequel::Model, "#eager_graph" do
1479
1479
 
1480
1480
  it "should eagerly load a one_to_one association with a custom callback" do
1481
1481
  GraphAlbum.one_to_one :track, :class=>'GraphTrack', :key=>:album_id
1482
- ds = GraphAlbum.eager_graph(:track => proc {|ds| ds.select(:album_id).columns(:album_id)})
1482
+ ds = GraphAlbum.eager_graph(:track => proc {|ds1| ds1.select(:album_id).columns(:album_id)})
1483
1483
  ds.sql.should == 'SELECT albums.id, albums.band_id, track.album_id FROM albums LEFT OUTER JOIN (SELECT album_id FROM tracks) AS track ON (track.album_id = albums.id)'
1484
1484
  ds._fetch = {:id=>1, :band_id=>2, :album_id=>1}
1485
1485
  a = ds.all
@@ -1488,7 +1488,7 @@ describe Sequel::Model, "#eager_graph" do
1488
1488
  end
1489
1489
 
1490
1490
  it "should eagerly load a one_to_many association with a custom callback" do
1491
- ds = GraphAlbum.eager_graph(:tracks => proc {|ds| ds.select(:album_id).columns(:album_id)})
1491
+ ds = GraphAlbum.eager_graph(:tracks => proc {|ds1| ds1.select(:album_id).columns(:album_id)})
1492
1492
  ds.sql.should == 'SELECT albums.id, albums.band_id, tracks.album_id FROM albums LEFT OUTER JOIN (SELECT album_id FROM tracks) AS tracks ON (tracks.album_id = albums.id)'
1493
1493
  ds._fetch = {:id=>1, :band_id=>2, :album_id=>1}
1494
1494
  a = ds.all
@@ -1497,7 +1497,7 @@ describe Sequel::Model, "#eager_graph" do
1497
1497
  end
1498
1498
 
1499
1499
  it "should eagerly load a many_to_many association with a custom callback" do
1500
- ds = GraphAlbum.eager_graph(:genres => proc {|ds| ds.select(:id).columns(:id)})
1500
+ ds = GraphAlbum.eager_graph(:genres => proc {|ds1| ds1.select(:id).columns(:id)})
1501
1501
  ds.sql.should == 'SELECT albums.id, albums.band_id, genres.id AS genres_id FROM albums LEFT OUTER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN (SELECT id FROM genres) AS genres ON (genres.id = ag.genre_id)'
1502
1502
  ds._fetch = {:id=>1, :band_id=>2, :genres_id=>4}
1503
1503
  a = ds.all
@@ -1506,7 +1506,7 @@ describe Sequel::Model, "#eager_graph" do
1506
1506
  end
1507
1507
 
1508
1508
  it "should allow cascading of eager loading with a custom callback with hash value" do
1509
- ds = GraphTrack.eager_graph(:album=>{proc{|ds| ds.select(:id, :band_id).columns(:id, :band_id)}=>{:band=>:members}})
1509
+ ds = GraphTrack.eager_graph(:album=>{proc{|ds1| ds1.select(:id, :band_id).columns(:id, :band_id)}=>{:band=>:members}})
1510
1510
  ds.sql.should == 'SELECT tracks.id, tracks.album_id, album.id AS album_id_0, album.band_id, band.id AS band_id_0, band.vocalist_id, members.id AS members_id FROM tracks LEFT OUTER JOIN (SELECT id, band_id FROM albums) AS album ON (album.id = tracks.album_id) LEFT OUTER JOIN bands AS band ON (band.id = album.band_id) LEFT OUTER JOIN bm ON (bm.band_id = band.id) LEFT OUTER JOIN members ON (members.id = bm.member_id)'
1511
1511
  ds._fetch = {:id=>3, :album_id=>1, :album_id_0=>1, :band_id=>2, :members_id=>5, :band_id_0=>2, :vocalist_id=>6}
1512
1512
  a = ds.all
@@ -1518,7 +1518,7 @@ describe Sequel::Model, "#eager_graph" do
1518
1518
  end
1519
1519
 
1520
1520
  it "should allow cascading of eager loading with a custom callback with array value" do
1521
- ds = GraphTrack.eager_graph(:album=>{proc{|ds| ds.select(:id, :band_id).columns(:id, :band_id)}=>[:band, :tracks]})
1521
+ ds = GraphTrack.eager_graph(:album=>{proc{|ds1| ds1.select(:id, :band_id).columns(:id, :band_id)}=>[:band, :tracks]})
1522
1522
  ds.sql.should == 'SELECT tracks.id, tracks.album_id, album.id AS album_id_0, album.band_id, band.id AS band_id_0, band.vocalist_id, tracks_0.id AS tracks_0_id, tracks_0.album_id AS tracks_0_album_id FROM tracks LEFT OUTER JOIN (SELECT id, band_id FROM albums) AS album ON (album.id = tracks.album_id) LEFT OUTER JOIN bands AS band ON (band.id = album.band_id) LEFT OUTER JOIN tracks AS tracks_0 ON (tracks_0.album_id = album.id)'
1523
1523
  ds._fetch = {:id=>3, :album_id=>1, :album_id_0=>1, :band_id=>2, :band_id_0=>2, :vocalist_id=>6, :tracks_0_id=>3, :tracks_0_album_id=>1}
1524
1524
  a = ds.all
@@ -164,12 +164,12 @@ describe Sequel::Model do
164
164
  end
165
165
  end
166
166
 
167
- describe Sequel::Model, "dataset & schema" do
167
+ describe Sequel::Model do
168
168
  before do
169
169
  @model = Class.new(Sequel::Model(:items))
170
170
  end
171
171
 
172
- it "creates dynamic model subclass with set table name" do
172
+ it "has table_name return name of table" do
173
173
  @model.table_name.should == :items
174
174
  end
175
175
 
@@ -187,31 +187,31 @@ describe Sequel::Model, "dataset & schema" do
187
187
  @model.table_name.should == :foo
188
188
  end
189
189
 
190
- it "set_dataset should take a Symbol" do
190
+ it "allows set_dataset to accept a Symbol" do
191
191
  @model.db = MODEL_DB
192
192
  @model.set_dataset(:foo)
193
193
  @model.table_name.should == :foo
194
194
  end
195
195
 
196
- it "set_dataset should take a LiteralString" do
196
+ it "allows set_dataset to accept a LiteralString" do
197
197
  @model.db = MODEL_DB
198
198
  @model.set_dataset(Sequel.lit('foo'))
199
199
  @model.table_name.should == Sequel.lit('foo')
200
200
  end
201
201
 
202
- it "set_dataset should take an SQL::Identifier" do
202
+ it "allows set_dataset to acceptan SQL::Identifier" do
203
203
  @model.db = MODEL_DB
204
204
  @model.set_dataset(Sequel.identifier(:foo))
205
205
  @model.table_name.should == Sequel.identifier(:foo)
206
206
  end
207
207
 
208
- it "set_dataset should take an SQL::QualifiedIdentifier" do
208
+ it "allows set_dataset to acceptan SQL::QualifiedIdentifier" do
209
209
  @model.db = MODEL_DB
210
210
  @model.set_dataset(Sequel.qualify(:bar, :foo))
211
211
  @model.table_name.should == Sequel.qualify(:bar, :foo)
212
212
  end
213
213
 
214
- it "set_dataset should take an SQL::AliasedExpression" do
214
+ it "allows set_dataset to acceptan SQL::AliasedExpression" do
215
215
  @model.db = MODEL_DB
216
216
  @model.set_dataset(Sequel.as(:foo, :bar))
217
217
  @model.table_name.should == :bar
@@ -266,6 +266,25 @@ describe Sequel::Model, "dataset & schema" do
266
266
  def @model.set_dataset(*) raise Sequel::Error end
267
267
  proc{Class.new(@model)}.should_not raise_error
268
268
  end
269
+
270
+ it "should raise if bad inherited instance variable value is used" do
271
+ def @model.inherited_instance_variables() super.merge(:@a=>:foo) end
272
+ @model.instance_eval{@a=1}
273
+ proc{Class.new(@model)}.should raise_error(Sequel::Error)
274
+ end
275
+
276
+ it "copy inherited instance variables into subclass if set" do
277
+ def @model.inherited_instance_variables() super.merge(:@a=>nil, :@b=>:dup, :@c=>:hash_dup, :@d=>proc{|v| v * 2}) end
278
+ @model.instance_eval{@a=1; @b=[2]; @c={3=>[4]}; @d=10}
279
+ m = Class.new(@model)
280
+ @model.instance_eval{@a=5; @b << 6; @c[3] << 7; @c[8] = [9]; @d=40}
281
+ m.instance_eval do
282
+ @a.should == 1
283
+ @b.should == [2]
284
+ @c.should == {3=>[4]}
285
+ @d.should == 20
286
+ end
287
+ end
269
288
  end
270
289
 
271
290
  describe Sequel::Model, "constructors" do
@@ -621,8 +640,7 @@ describe "Model.db_schema" do
621
640
  @dataset = @db[:items]
622
641
  end
623
642
 
624
- specify "should use the database's schema_for_table and set the columns and dataset columns" do
625
- d = @dataset.db
643
+ specify "should use the database's schema and set the columns and dataset columns" do
626
644
  def @db.schema(table, opts = {})
627
645
  [[:x, {:type=>:integer}], [:y, {:type=>:string}]]
628
646
  end
@@ -245,3 +245,74 @@ describe Sequel::Model, ".plugin" do
245
245
  @c.plugins.should include(m)
246
246
  end
247
247
  end
248
+
249
+ describe Sequel::Plugins do
250
+ before do
251
+ @c = Class.new(Sequel::Model(:items))
252
+ end
253
+
254
+ it "should have def_dataset_methods define methods that call methods on the dataset" do
255
+ m = Module.new do
256
+ module self::ClassMethods
257
+ Sequel::Plugins.def_dataset_methods(self, :one)
258
+ end
259
+ module self::DatasetMethods
260
+ def one
261
+ 1
262
+ end
263
+ end
264
+ end
265
+ @c.plugin m
266
+ @c.one.should == 1
267
+ end
268
+
269
+ it "should have def_dataset_methods accept an array with multiple methods" do
270
+ m = Module.new do
271
+ module self::ClassMethods
272
+ Sequel::Plugins.def_dataset_methods(self, [:one, :two])
273
+ end
274
+ module self::DatasetMethods
275
+ def one
276
+ 1
277
+ end
278
+ def two
279
+ 2
280
+ end
281
+ end
282
+ end
283
+ @c.plugin m
284
+ @c.one.should == 1
285
+ @c.two.should == 2
286
+ end
287
+
288
+ it "should have inherited_instance_variables add instance variables to copy into the subclass" do
289
+ m = Module.new do
290
+ def self.apply(model)
291
+ model.instance_variable_set(:@one, 1)
292
+ end
293
+ module self::ClassMethods
294
+ attr_reader :one
295
+ Sequel::Plugins.inherited_instance_variables(self, :@one=>nil)
296
+ end
297
+ end
298
+ @c.plugin m
299
+ Class.new(@c).one.should == 1
300
+ end
301
+
302
+ it "should have after_set_dataset add a method to call after set_dataset" do
303
+ m = Module.new do
304
+ module self::ClassMethods
305
+ Sequel::Plugins.after_set_dataset(self, :one)
306
+ private
307
+ def one
308
+ dataset.opts[:foo] = 1
309
+ end
310
+ end
311
+ end
312
+ @c.plugin m
313
+ @c.dataset.opts[:foo].should == nil
314
+ @c.set_dataset :blah
315
+ @c.dataset.opts[:foo].should == 1
316
+ end
317
+ end
318
+
@@ -367,6 +367,12 @@ describe "Model#freeze" do
367
367
  @o.frozen?.should be_true
368
368
  end
369
369
 
370
+ it "should freeze the object if the model doesn't have a primary key" do
371
+ Album.no_primary_key
372
+ @o = Album.load(:id=>1).freeze
373
+ @o.frozen?.should be_true
374
+ end
375
+
370
376
  it "should freeze the object's values, associations, changed_columns, errors, and this" do
371
377
  @o.values.frozen?.should be_true
372
378
  @o.changed_columns.frozen?.should be_true
@@ -433,7 +439,7 @@ describe "Model#marshallable" do
433
439
  end
434
440
  end
435
441
 
436
- describe "Model#modified[!?]" do
442
+ describe "Model#modified?" do
437
443
  before do
438
444
  @c = Class.new(Sequel::Model(:items))
439
445
  @c.class_eval do
@@ -483,8 +489,47 @@ describe "Model#modified[!?]" do
483
489
  o.x = '2'
484
490
  o.modified?.should == true
485
491
  end
492
+
493
+ it "should be true if given a column argument and the column has been changed" do
494
+ o = @c.new
495
+ o.modified?(:id).should be_false
496
+ o.id = 1
497
+ o.modified?(:id).should be_true
498
+ end
486
499
  end
487
500
 
501
+ describe "Model#modified!" do
502
+ before do
503
+ @c = Class.new(Sequel::Model(:items))
504
+ @c.class_eval do
505
+ columns :id, :x
506
+ end
507
+ MODEL_DB.reset
508
+ end
509
+
510
+ it "should mark the object as modified so that save_changes still runs the callbacks" do
511
+ o = @c.load(:id=>1, :x=>2)
512
+ def o.after_save
513
+ values[:x] = 3
514
+ end
515
+ o.update({})
516
+ o.x.should == 2
517
+
518
+ o.modified!
519
+ o.update({})
520
+ o.x.should == 3
521
+ o.db.sqls.should == []
522
+ end
523
+
524
+ it "should mark given column argument as modified" do
525
+ o = @c.load(:id=>1, :x=>2)
526
+ o.modified!(:x)
527
+ o.changed_columns.should == [:x]
528
+ o.save
529
+ o.db.sqls.should == ["UPDATE items SET x = 2 WHERE (id = 1)"]
530
+ end
531
+ end
532
+
488
533
  describe "Model#save_changes" do
489
534
  before do
490
535
  @c = Class.new(Sequel::Model(:items)) do
@@ -618,8 +663,8 @@ describe "Model#new?" do
618
663
  end
619
664
  end
620
665
 
621
- describe Sequel::Model, "w/ primary key" do
622
- it "should default to ':id'" do
666
+ describe Sequel::Model, "with a primary key" do
667
+ it "should default to :id" do
623
668
  model_a = Class.new Sequel::Model
624
669
  model_a.primary_key.should == :id
625
670
  end
@@ -640,7 +685,7 @@ describe Sequel::Model, "w/ primary key" do
640
685
  end
641
686
  end
642
687
 
643
- describe Sequel::Model, "w/o primary key" do
688
+ describe Sequel::Model, "without a primary key" do
644
689
  it "should return nil for primary key" do
645
690
  Class.new(Sequel::Model){no_primary_key}.primary_key.should be_nil
646
691
  end
@@ -651,7 +696,7 @@ describe Sequel::Model, "w/o primary key" do
651
696
  end
652
697
  end
653
698
 
654
- describe Sequel::Model, "with this" do
699
+ describe Sequel::Model, "#this" do
655
700
  before do
656
701
  @example = Class.new(Sequel::Model(:examples))
657
702
  @example.columns :id, :a, :x, :y
@@ -682,18 +727,18 @@ describe "Model#pk" do
682
727
  @m.columns :id, :x, :y
683
728
  end
684
729
 
685
- it "should be default return the value of the :id column" do
730
+ it "should by default return the value of the :id column" do
686
731
  m = @m.load(:id => 111, :x => 2, :y => 3)
687
732
  m.pk.should == 111
688
733
  end
689
734
 
690
- it "should be return the primary key value for custom primary key" do
735
+ it "should return the primary key value for custom primary key" do
691
736
  @m.set_primary_key :x
692
737
  m = @m.load(:id => 111, :x => 2, :y => 3)
693
738
  m.pk.should == 2
694
739
  end
695
740
 
696
- it "should be return the primary key value for composite primary key" do
741
+ it "should return the primary key value for composite primary key" do
697
742
  @m.set_primary_key [:y, :x]
698
743
  m = @m.load(:id => 111, :x => 2, :y => 3)
699
744
  m.pk.should == [3, 2]
@@ -716,18 +761,18 @@ describe "Model#pk_hash" do
716
761
  @m.columns :id, :x, :y
717
762
  end
718
763
 
719
- it "should be default return the value of the :id column" do
764
+ it "should by default return a hash with the value of the :id column" do
720
765
  m = @m.load(:id => 111, :x => 2, :y => 3)
721
766
  m.pk_hash.should == {:id => 111}
722
767
  end
723
768
 
724
- it "should be return the primary key value for custom primary key" do
769
+ it "should return a hash with the primary key value for custom primary key" do
725
770
  @m.set_primary_key :x
726
771
  m = @m.load(:id => 111, :x => 2, :y => 3)
727
772
  m.pk_hash.should == {:x => 2}
728
773
  end
729
774
 
730
- it "should be return the primary key value for composite primary key" do
775
+ it "should return a hash with the primary key values for composite primary key" do
731
776
  @m.set_primary_key [:y, :x]
732
777
  m = @m.load(:id => 111, :x => 2, :y => 3)
733
778
  m.pk_hash.should == {:y => 3, :x => 2}
@@ -918,7 +963,6 @@ describe Sequel::Model, "#set_fields" do
918
963
  set_primary_key :id
919
964
  columns :x, :y, :z, :id
920
965
  end
921
- @c.strict_param_setting = true
922
966
  @o1 = @c.new
923
967
  MODEL_DB.reset
924
968
  end
@@ -967,6 +1011,29 @@ describe Sequel::Model, "#set_fields" do
967
1011
  MODEL_DB.sqls.should == []
968
1012
  end
969
1013
 
1014
+ it "should respect model's default_set_fields_options" do
1015
+ @c.default_set_fields_options = {:missing=>:skip}
1016
+ @o1.set_fields({:x => 3}, [:x, :y])
1017
+ @o1.values.should == {:x => 3}
1018
+ @o1.set_fields({:x => 4}, [:x, :y], {})
1019
+ @o1.values.should == {:x => 4}
1020
+ proc{@o1.set_fields({:x => 3}, [:x, :y], :missing=>:raise)}.should raise_error(Sequel::Error)
1021
+ @c.default_set_fields_options = {:missing=>:raise}
1022
+ proc{@o1.set_fields({:x => 3}, [:x, :y])}.should raise_error(Sequel::Error)
1023
+ proc{@o1.set_fields({:x => 3}, [:x, :y], {})}.should raise_error(Sequel::Error)
1024
+ @o1.set_fields({:x => 5}, [:x, :y], :missing=>:skip)
1025
+ @o1.values.should == {:x => 5}
1026
+ @o1.set_fields({:x => 5}, [:x, :y], :missing=>nil)
1027
+ @o1.values.should == {:x => 5, :y=>nil}
1028
+ MODEL_DB.sqls.should == []
1029
+ end
1030
+
1031
+ it "should respect model's default_set_fields_options in a subclass" do
1032
+ @c.default_set_fields_options = {:missing=>:skip}
1033
+ o = Class.new(@c).new
1034
+ o.set_fields({:x => 3}, [:x, :y])
1035
+ o.values.should == {:x => 3}
1036
+ end
970
1037
  end
971
1038
 
972
1039
  describe Sequel::Model, "#update_fields" do
@@ -1001,6 +1068,17 @@ describe Sequel::Model, "#update_fields" do
1001
1068
  it "should support :missing=>:raise option" do
1002
1069
  proc{@o1.update_fields({:x => 1}, [:x, :y], :missing=>:raise)}.should raise_error(Sequel::Error)
1003
1070
  end
1071
+
1072
+ it "should respect model's default_set_fields_options" do
1073
+ @c.default_set_fields_options = {:missing=>:skip}
1074
+ @o1.update_fields({:x => 3}, [:x, :y])
1075
+ @o1.values.should == {:x => 3, :id=>1}
1076
+ MODEL_DB.sqls.should == ["UPDATE items SET x = 3 WHERE (id = 1)"]
1077
+
1078
+ @c.default_set_fields_options = {:missing=>:raise}
1079
+ proc{@o1.update_fields({:x => 3}, [:x, :y])}.should raise_error(Sequel::Error)
1080
+ MODEL_DB.sqls.should == []
1081
+ end
1004
1082
  end
1005
1083
 
1006
1084
  describe Sequel::Model, "#(set|update)_(all|except|only)" do
@@ -1449,7 +1527,7 @@ describe Sequel::Model, ".create" do
1449
1527
  MODEL_DB.sqls.should == ["INSERT INTO items DEFAULT VALUES", "SELECT * FROM items WHERE (id = 10) LIMIT 1"]
1450
1528
  end
1451
1529
 
1452
- it "should accept a block and run it" do
1530
+ it "should accept a block and call it" do
1453
1531
  o1, o2, o3 = nil, nil, nil
1454
1532
  o = @c.create {|o4| o1 = o4; o3 = o4; o2 = :blah; o3.x = 333}
1455
1533
  o.class.should == @c
@@ -1886,3 +1964,11 @@ describe "Model#lock!" do
1886
1964
  MODEL_DB.sqls.should == ["SELECT * FROM items WHERE (id = 1) LIMIT 1 FOR UPDATE"]
1887
1965
  end
1888
1966
  end
1967
+
1968
+ describe "Model#schema_type_class" do
1969
+ specify "should return the class or array of classes for the given type symbol" do
1970
+ @c = Class.new(Sequel::Model(:items))
1971
+ @c.class_eval{@db_schema = {:id=>{:type=>:integer}}}
1972
+ @c.new.send(:schema_type_class, :id).should == Integer
1973
+ end
1974
+ end