sequel 3.46.0 → 3.47.0

Sign up to get free protection for your applications and to get access to all the features.
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