sequel 3.47.0 → 3.48.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (243) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +230 -0
  3. data/README.rdoc +31 -40
  4. data/Rakefile +1 -14
  5. data/doc/active_record.rdoc +29 -29
  6. data/doc/association_basics.rdoc +4 -13
  7. data/doc/cheat_sheet.rdoc +8 -6
  8. data/doc/code_order.rdoc +89 -0
  9. data/doc/core_extensions.rdoc +3 -3
  10. data/doc/dataset_basics.rdoc +7 -8
  11. data/doc/dataset_filtering.rdoc +7 -2
  12. data/doc/mass_assignment.rdoc +2 -3
  13. data/doc/migration.rdoc +8 -8
  14. data/doc/model_hooks.rdoc +11 -7
  15. data/doc/object_model.rdoc +2 -2
  16. data/doc/opening_databases.rdoc +5 -14
  17. data/doc/prepared_statements.rdoc +5 -9
  18. data/doc/querying.rdoc +23 -28
  19. data/doc/reflection.rdoc +11 -0
  20. data/doc/release_notes/3.48.0.txt +477 -0
  21. data/doc/schema_modification.rdoc +12 -5
  22. data/doc/security.rdoc +2 -2
  23. data/doc/sharding.rdoc +1 -2
  24. data/doc/sql.rdoc +10 -13
  25. data/doc/testing.rdoc +8 -4
  26. data/doc/transactions.rdoc +2 -2
  27. data/doc/validations.rdoc +40 -17
  28. data/doc/virtual_rows.rdoc +2 -2
  29. data/lib/sequel/adapters/ado.rb +25 -20
  30. data/lib/sequel/adapters/ado/access.rb +1 -0
  31. data/lib/sequel/adapters/ado/mssql.rb +1 -0
  32. data/lib/sequel/adapters/db2.rb +9 -7
  33. data/lib/sequel/adapters/dbi.rb +16 -16
  34. data/lib/sequel/adapters/do.rb +17 -18
  35. data/lib/sequel/adapters/do/mysql.rb +1 -0
  36. data/lib/sequel/adapters/do/postgres.rb +2 -0
  37. data/lib/sequel/adapters/do/sqlite.rb +1 -0
  38. data/lib/sequel/adapters/firebird.rb +5 -7
  39. data/lib/sequel/adapters/ibmdb.rb +23 -20
  40. data/lib/sequel/adapters/informix.rb +8 -2
  41. data/lib/sequel/adapters/jdbc.rb +39 -35
  42. data/lib/sequel/adapters/jdbc/as400.rb +1 -0
  43. data/lib/sequel/adapters/jdbc/cubrid.rb +1 -0
  44. data/lib/sequel/adapters/jdbc/db2.rb +1 -0
  45. data/lib/sequel/adapters/jdbc/derby.rb +1 -0
  46. data/lib/sequel/adapters/jdbc/firebird.rb +1 -0
  47. data/lib/sequel/adapters/jdbc/h2.rb +1 -0
  48. data/lib/sequel/adapters/jdbc/hsqldb.rb +1 -0
  49. data/lib/sequel/adapters/jdbc/informix.rb +1 -0
  50. data/lib/sequel/adapters/jdbc/jtds.rb +1 -0
  51. data/lib/sequel/adapters/jdbc/mssql.rb +1 -0
  52. data/lib/sequel/adapters/jdbc/mysql.rb +1 -0
  53. data/lib/sequel/adapters/jdbc/oracle.rb +1 -0
  54. data/lib/sequel/adapters/jdbc/postgresql.rb +2 -0
  55. data/lib/sequel/adapters/jdbc/progress.rb +1 -0
  56. data/lib/sequel/adapters/jdbc/sqlite.rb +1 -0
  57. data/lib/sequel/adapters/jdbc/sqlserver.rb +1 -0
  58. data/lib/sequel/adapters/mock.rb +30 -31
  59. data/lib/sequel/adapters/mysql.rb +6 -7
  60. data/lib/sequel/adapters/mysql2.rb +5 -6
  61. data/lib/sequel/adapters/odbc.rb +22 -20
  62. data/lib/sequel/adapters/odbc/mssql.rb +1 -0
  63. data/lib/sequel/adapters/openbase.rb +4 -1
  64. data/lib/sequel/adapters/oracle.rb +10 -8
  65. data/lib/sequel/adapters/postgres.rb +12 -10
  66. data/lib/sequel/adapters/shared/access.rb +6 -0
  67. data/lib/sequel/adapters/shared/cubrid.rb +2 -0
  68. data/lib/sequel/adapters/shared/db2.rb +2 -0
  69. data/lib/sequel/adapters/shared/firebird.rb +2 -0
  70. data/lib/sequel/adapters/shared/informix.rb +2 -0
  71. data/lib/sequel/adapters/shared/mssql.rb +14 -8
  72. data/lib/sequel/adapters/shared/mysql.rb +6 -0
  73. data/lib/sequel/adapters/shared/oracle.rb +2 -0
  74. data/lib/sequel/adapters/shared/postgres.rb +14 -4
  75. data/lib/sequel/adapters/shared/progress.rb +1 -0
  76. data/lib/sequel/adapters/shared/sqlite.rb +4 -3
  77. data/lib/sequel/adapters/sqlite.rb +6 -7
  78. data/lib/sequel/adapters/swift.rb +20 -21
  79. data/lib/sequel/adapters/swift/mysql.rb +1 -0
  80. data/lib/sequel/adapters/swift/postgres.rb +2 -0
  81. data/lib/sequel/adapters/swift/sqlite.rb +1 -0
  82. data/lib/sequel/adapters/tinytds.rb +5 -6
  83. data/lib/sequel/adapters/utils/emulate_offset_with_reverse_and_count.rb +68 -0
  84. data/lib/sequel/connection_pool.rb +1 -1
  85. data/lib/sequel/core.rb +57 -50
  86. data/lib/sequel/database/connecting.rb +9 -10
  87. data/lib/sequel/database/dataset.rb +11 -6
  88. data/lib/sequel/database/dataset_defaults.rb +61 -69
  89. data/lib/sequel/database/features.rb +21 -0
  90. data/lib/sequel/database/misc.rb +23 -3
  91. data/lib/sequel/database/query.rb +13 -7
  92. data/lib/sequel/database/schema_methods.rb +6 -6
  93. data/lib/sequel/database/transactions.rb +1 -0
  94. data/lib/sequel/dataset/actions.rb +51 -38
  95. data/lib/sequel/dataset/features.rb +1 -0
  96. data/lib/sequel/dataset/graph.rb +9 -33
  97. data/lib/sequel/dataset/misc.rb +30 -5
  98. data/lib/sequel/dataset/mutation.rb +2 -3
  99. data/lib/sequel/dataset/prepared_statements.rb +1 -1
  100. data/lib/sequel/dataset/query.rb +91 -27
  101. data/lib/sequel/dataset/sql.rb +40 -6
  102. data/lib/sequel/deprecated.rb +74 -0
  103. data/lib/sequel/deprecated_core_extensions.rb +135 -0
  104. data/lib/sequel/extensions/columns_introspection.rb +1 -5
  105. data/lib/sequel/extensions/core_extensions.rb +10 -3
  106. data/lib/sequel/extensions/date_arithmetic.rb +1 -0
  107. data/lib/sequel/extensions/empty_array_ignore_nulls.rb +33 -0
  108. data/lib/sequel/extensions/filter_having.rb +58 -0
  109. data/lib/sequel/extensions/graph_each.rb +63 -0
  110. data/lib/sequel/extensions/hash_aliases.rb +44 -0
  111. data/lib/sequel/extensions/looser_typecasting.rb +14 -3
  112. data/lib/sequel/extensions/migration.rb +2 -3
  113. data/lib/sequel/extensions/named_timezones.rb +14 -1
  114. data/lib/sequel/extensions/null_dataset.rb +7 -1
  115. data/lib/sequel/extensions/pagination.rb +15 -5
  116. data/lib/sequel/extensions/pg_auto_parameterize.rb +1 -0
  117. data/lib/sequel/extensions/pg_hstore_ops.rb +48 -14
  118. data/lib/sequel/extensions/pg_json.rb +7 -7
  119. data/lib/sequel/extensions/pg_range_ops.rb +8 -2
  120. data/lib/sequel/extensions/pg_statement_cache.rb +1 -0
  121. data/lib/sequel/extensions/pretty_table.rb +13 -4
  122. data/lib/sequel/extensions/query.rb +21 -4
  123. data/lib/sequel/extensions/ruby18_symbol_extensions.rb +22 -0
  124. data/lib/sequel/extensions/schema_caching.rb +10 -7
  125. data/lib/sequel/extensions/schema_dumper.rb +35 -48
  126. data/lib/sequel/extensions/select_remove.rb +13 -4
  127. data/lib/sequel/extensions/sequel_3_dataset_methods.rb +117 -0
  128. data/lib/sequel/extensions/set_overrides.rb +43 -0
  129. data/lib/sequel/extensions/to_dot.rb +6 -0
  130. data/lib/sequel/model.rb +12 -6
  131. data/lib/sequel/model/associations.rb +80 -38
  132. data/lib/sequel/model/base.rb +137 -52
  133. data/lib/sequel/model/errors.rb +7 -2
  134. data/lib/sequel/plugins/active_model.rb +13 -0
  135. data/lib/sequel/plugins/after_initialize.rb +43 -0
  136. data/lib/sequel/plugins/association_proxies.rb +63 -7
  137. data/lib/sequel/plugins/auto_validations.rb +56 -16
  138. data/lib/sequel/plugins/blacklist_security.rb +63 -0
  139. data/lib/sequel/plugins/class_table_inheritance.rb +9 -0
  140. data/lib/sequel/plugins/constraint_validations.rb +50 -8
  141. data/lib/sequel/plugins/dataset_associations.rb +2 -0
  142. data/lib/sequel/plugins/hook_class_methods.rb +7 -1
  143. data/lib/sequel/plugins/identity_map.rb +4 -0
  144. data/lib/sequel/plugins/json_serializer.rb +32 -13
  145. data/lib/sequel/plugins/optimistic_locking.rb +1 -1
  146. data/lib/sequel/plugins/rcte_tree.rb +4 -4
  147. data/lib/sequel/plugins/scissors.rb +33 -0
  148. data/lib/sequel/plugins/serialization.rb +1 -1
  149. data/lib/sequel/plugins/single_table_inheritance.rb +6 -0
  150. data/lib/sequel/plugins/tree.rb +5 -1
  151. data/lib/sequel/plugins/validation_class_methods.rb +2 -1
  152. data/lib/sequel/plugins/validation_helpers.rb +15 -11
  153. data/lib/sequel/plugins/xml_serializer.rb +12 -3
  154. data/lib/sequel/sql.rb +12 -2
  155. data/lib/sequel/timezones.rb +1 -1
  156. data/lib/sequel/version.rb +1 -1
  157. data/lib/sequel_core.rb +1 -0
  158. data/lib/sequel_model.rb +1 -0
  159. data/spec/adapters/mssql_spec.rb +24 -57
  160. data/spec/adapters/postgres_spec.rb +27 -55
  161. data/spec/adapters/spec_helper.rb +1 -1
  162. data/spec/adapters/sqlite_spec.rb +1 -1
  163. data/spec/bin_spec.rb +251 -0
  164. data/spec/core/database_spec.rb +46 -32
  165. data/spec/core/dataset_spec.rb +233 -181
  166. data/spec/core/deprecated_spec.rb +78 -0
  167. data/spec/core/expression_filters_spec.rb +3 -4
  168. data/spec/core/mock_adapter_spec.rb +9 -9
  169. data/spec/core/object_graph_spec.rb +9 -19
  170. data/spec/core/schema_spec.rb +3 -1
  171. data/spec/core/spec_helper.rb +19 -0
  172. data/spec/core_extensions_spec.rb +80 -30
  173. data/spec/extensions/after_initialize_spec.rb +24 -0
  174. data/spec/extensions/association_proxies_spec.rb +37 -1
  175. data/spec/extensions/auto_validations_spec.rb +20 -4
  176. data/spec/extensions/blacklist_security_spec.rb +87 -0
  177. data/spec/extensions/boolean_readers_spec.rb +2 -1
  178. data/spec/extensions/class_table_inheritance_spec.rb +7 -0
  179. data/spec/extensions/columns_introspection_spec.rb +3 -3
  180. data/spec/extensions/constraint_validations_plugin_spec.rb +83 -5
  181. data/spec/extensions/core_refinements_spec.rb +7 -7
  182. data/spec/extensions/dataset_associations_spec.rb +2 -2
  183. data/spec/extensions/date_arithmetic_spec.rb +1 -1
  184. data/spec/extensions/defaults_setter_spec.rb +2 -1
  185. data/spec/extensions/empty_array_ignore_nulls_spec.rb +24 -0
  186. data/spec/extensions/filter_having_spec.rb +40 -0
  187. data/spec/extensions/graph_each_spec.rb +109 -0
  188. data/spec/extensions/hash_aliases_spec.rb +16 -0
  189. data/spec/extensions/hook_class_methods_spec.rb +2 -2
  190. data/spec/extensions/identity_map_spec.rb +3 -3
  191. data/spec/extensions/json_serializer_spec.rb +19 -19
  192. data/spec/extensions/lazy_attributes_spec.rb +1 -0
  193. data/spec/extensions/list_spec.rb +13 -13
  194. data/spec/extensions/looser_typecasting_spec.rb +10 -3
  195. data/spec/extensions/many_through_many_spec.rb +1 -1
  196. data/spec/extensions/migration_spec.rb +7 -7
  197. data/spec/extensions/named_timezones_spec.rb +6 -0
  198. data/spec/extensions/nested_attributes_spec.rb +2 -2
  199. data/spec/extensions/null_dataset_spec.rb +1 -1
  200. data/spec/extensions/pagination_spec.rb +2 -2
  201. data/spec/extensions/pg_hstore_ops_spec.rb +75 -0
  202. data/spec/extensions/pg_range_ops_spec.rb +4 -2
  203. data/spec/extensions/pg_row_plugin_spec.rb +1 -1
  204. data/spec/extensions/pretty_table_spec.rb +1 -1
  205. data/spec/extensions/query_literals_spec.rb +1 -1
  206. data/spec/extensions/query_spec.rb +3 -3
  207. data/spec/extensions/schema_caching_spec.rb +3 -3
  208. data/spec/extensions/schema_dumper_spec.rb +27 -2
  209. data/spec/extensions/schema_spec.rb +2 -2
  210. data/spec/extensions/scissors_spec.rb +26 -0
  211. data/spec/extensions/select_remove_spec.rb +1 -1
  212. data/spec/extensions/sequel_3_dataset_methods_spec.rb +102 -0
  213. data/spec/extensions/set_overrides_spec.rb +45 -0
  214. data/spec/extensions/single_table_inheritance_spec.rb +10 -0
  215. data/spec/extensions/spec_helper.rb +24 -1
  216. data/spec/extensions/static_cache_spec.rb +1 -1
  217. data/spec/extensions/string_stripper_spec.rb +2 -1
  218. data/spec/extensions/to_dot_spec.rb +1 -1
  219. data/spec/extensions/typecast_on_load_spec.rb +3 -2
  220. data/spec/extensions/update_primary_key_spec.rb +2 -2
  221. data/spec/extensions/validation_class_methods_spec.rb +19 -19
  222. data/spec/extensions/validation_helpers_spec.rb +30 -21
  223. data/spec/extensions/xml_serializer_spec.rb +5 -5
  224. data/spec/integration/associations_test.rb +10 -30
  225. data/spec/integration/dataset_test.rb +20 -24
  226. data/spec/integration/eager_loader_test.rb +5 -5
  227. data/spec/integration/model_test.rb +3 -3
  228. data/spec/integration/plugin_test.rb +7 -39
  229. data/spec/integration/schema_test.rb +4 -38
  230. data/spec/integration/spec_helper.rb +2 -1
  231. data/spec/model/association_reflection_spec.rb +70 -5
  232. data/spec/model/associations_spec.rb +11 -11
  233. data/spec/model/base_spec.rb +25 -8
  234. data/spec/model/class_dataset_methods_spec.rb +143 -0
  235. data/spec/model/dataset_methods_spec.rb +1 -1
  236. data/spec/model/eager_loading_spec.rb +25 -25
  237. data/spec/model/hooks_spec.rb +1 -1
  238. data/spec/model/model_spec.rb +22 -7
  239. data/spec/model/plugins_spec.rb +1 -6
  240. data/spec/model/record_spec.rb +37 -29
  241. data/spec/model/spec_helper.rb +23 -1
  242. data/spec/model/validations_spec.rb +15 -17
  243. metadata +32 -3
@@ -0,0 +1,43 @@
1
+ # The set_overrides extension adds the Dataset#set_overrides and
2
+ # Dataset#set_defaults methods which provide a crude way to
3
+ # control the values used in INSERT/UPDATE statements if a hash
4
+ # of values is passed to Dataset#insert or Dataset#update.
5
+ # It is only recommended to use this for backwards compatibility.
6
+ #
7
+ # You can load this extension into specific datasets:
8
+ #
9
+ # ds = DB[:table]
10
+ # ds.extension(:set_overrides)
11
+ #
12
+ # Or you can load it into all of a database's datasets, which
13
+ # is probably the desired behavior if you are using this extension:
14
+ #
15
+ # DB.extension(:set_overrides)
16
+
17
+ module Sequel
18
+ module SetOverrides
19
+ Dataset.def_mutation_method(:set_defaults, :set_overrides, :module=>self)
20
+
21
+ # Set the default values for insert and update statements. The values hash passed
22
+ # to insert or update are merged into this hash, so any values in the hash passed
23
+ # to insert or update will override values passed to this method.
24
+ #
25
+ # DB[:items].set_defaults(:a=>'a', :c=>'c').insert(:a=>'d', :b=>'b')
26
+ # # INSERT INTO items (a, c, b) VALUES ('d', 'c', 'b')
27
+ def set_defaults(hash)
28
+ clone(:defaults=>(@opts[:defaults]||{}).merge(hash))
29
+ end
30
+
31
+ # Set values that override hash arguments given to insert and update statements.
32
+ # This hash is merged into the hash provided to insert or update, so values
33
+ # will override any values given in the insert/update hashes.
34
+ #
35
+ # DB[:items].set_overrides(:a=>'a', :c=>'c').insert(:a=>'d', :b=>'b')
36
+ # # INSERT INTO items (a, c, b) VALUES ('a', 'c', 'b')
37
+ def set_overrides(hash)
38
+ clone(:overrides=>hash.merge(@opts[:overrides]||{}))
39
+ end
40
+ end
41
+
42
+ Dataset.register_extension(:set_overrides, SetOverrides)
43
+ end
@@ -9,6 +9,9 @@
9
9
 
10
10
  module Sequel
11
11
  class ToDot
12
+ module DatasetMethods
13
+ end
14
+
12
15
  # The option keys that should be included in the dot output.
13
16
  TO_DOT_OPTIONS = [:with, :distinct, :select, :from, :join, :where, :group, :having, :compounds, :order, :limit, :offset, :lock].freeze
14
17
 
@@ -147,7 +150,10 @@ module Sequel
147
150
  # with graphviz) in order to see a visualization of the dataset's
148
151
  # abstract syntax tree.
149
152
  def to_dot
153
+ Sequel::Deprecation.deprecate('Loading the to_dot extension globally', "Please use Database/Dataset#extension to load the extension into this dataset") unless is_a?(ToDot::DatasetMethods)
150
154
  ToDot.output(self)
151
155
  end
152
156
  end
157
+
158
+ Dataset.register_extension(:to_dot, ToDot::DatasetMethods)
153
159
  end
@@ -35,7 +35,7 @@ module Sequel
35
35
  # dataset # => DB1[:comments]
36
36
  # end
37
37
  def self.Model(source)
38
- if Sequel::Model.cache_anonymous_models && (klass = Sequel.synchronize{Model::ANONYMOUS_MODEL_CLASSES[source]})
38
+ if cache_anonymous_models && (klass = Sequel.synchronize{Model::ANONYMOUS_MODEL_CLASSES[source]})
39
39
  return klass
40
40
  end
41
41
  klass = if source.is_a?(Database)
@@ -45,10 +45,19 @@ module Sequel
45
45
  else
46
46
  Class.new(Model).set_dataset(source)
47
47
  end
48
- Sequel.synchronize{Model::ANONYMOUS_MODEL_CLASSES[source] = klass} if Sequel::Model.cache_anonymous_models
48
+ Sequel.synchronize{Model::ANONYMOUS_MODEL_CLASSES[source] = klass} if cache_anonymous_models
49
49
  klass
50
50
  end
51
51
 
52
+ @cache_anonymous_models = true
53
+
54
+ class << self
55
+ # Whether to cache the anonymous models created by Sequel::Model(). This is
56
+ # required for reloading them correctly (avoiding the superclass mismatch). True
57
+ # by default for backwards compatibility.
58
+ attr_accessor :cache_anonymous_models
59
+ end
60
+
52
61
  # <tt>Sequel::Model</tt> is an object relational mapper built on top of Sequel core. Each
53
62
  # model class is backed by a dataset instance, and many dataset methods can be
54
63
  # called directly on the class. Model datasets return rows as model instances,
@@ -63,16 +72,13 @@ module Sequel
63
72
  # You can set the +SEQUEL_NO_ASSOCIATIONS+ constant or environment variable to
64
73
  # make Sequel not load the associations plugin by default.
65
74
  class Model
66
- # Cache anonymous models created by Sequel::Model()
67
- @cache_anonymous_models = true
68
-
69
75
  # Map that stores model classes created with <tt>Sequel::Model()</tt>, to allow the reopening
70
76
  # of classes when dealing with code reloading.
71
77
  ANONYMOUS_MODEL_CLASSES = {}
72
78
 
73
79
  # Class methods added to model that call the method of the same name on the dataset
74
80
  DATASET_METHODS = (Dataset::ACTION_METHODS + Dataset::QUERY_METHODS +
75
- [:each_page, :each_server, :print, :destroy, :with_pk, :with_pk!]) - [:and, :or, :[], :[]=, :columns, :columns!]
81
+ [:each_server]) - [:and, :or, :[], :[]=, :columns, :columns!, :delete, :update, :add_graph_aliases]
76
82
 
77
83
  # Class instance variables to set to nil when a subclass is created, for -w compliance
78
84
  EMPTY_INSTANCE_VARIABLES = [:@overridable_methods_module, :@db]
@@ -188,20 +188,32 @@ module Sequel
188
188
  # it sets album.artist to this_artist.
189
189
  def reciprocal
190
190
  cached_fetch(:reciprocal) do
191
- r_types = Array(reciprocal_type)
192
- keys = self[:keys]
193
- recip = nil
191
+ possible_recips = []
192
+ fallback_recips = []
193
+
194
194
  associated_class.all_association_reflections.each do |assoc_reflect|
195
- if r_types.include?(assoc_reflect[:type]) && assoc_reflect[:keys] == keys && assoc_reflect.associated_class == self[:model]
196
- cached_set(:reciprocal_type, assoc_reflect[:type])
197
- recip = assoc_reflect[:name]
198
- break
195
+ if reciprocal_association?(assoc_reflect)
196
+ if deprecated_reciprocal_association?(assoc_reflect)
197
+ fallback_recips << assoc_reflect
198
+ else
199
+ possible_recips << assoc_reflect
200
+ end
199
201
  end
200
202
  end
201
- recip
203
+
204
+ Sequel::Deprecation.deprecate("Multiple reciprocal association candidates found for #{self[:name]} association (#{possible_recips.map{|r| r[:name]}.join(', ')}). Choosing the first candidate is", "Please explicitly specify the reciprocal option for the #{self[:name]} association") if possible_recips.size >= 2
205
+ if possible_recips.empty? && !fallback_recips.empty?
206
+ possible_recips = fallback_recips
207
+ Sequel::Deprecation.deprecate("All reciprocal association candidates found for #{self[:name]} association have conditions, blocks, or differing primary keys (#{possible_recips.map{|r| r[:name]}.join(', ')}). Automatic choosing of an reciprocal association with conditions or blocks is", "Please explicitly specify the reciprocal option for the #{self[:name]} association")
208
+ end
209
+
210
+ unless possible_recips.empty?
211
+ cached_set(:reciprocal_type, possible_recips.first[:type]) if reciprocal_type.is_a?(Array)
212
+ possible_recips.first[:name]
213
+ end
202
214
  end
203
215
  end
204
-
216
+
205
217
  # Whether the reciprocal of this association returns an array of objects instead of a single object,
206
218
  # true by default.
207
219
  def reciprocal_array?
@@ -288,6 +300,16 @@ module Sequel
288
300
  end
289
301
  end
290
302
 
303
+ # REMOVE40: merge into reciprocal_association?
304
+ def deprecated_reciprocal_association?(assoc_reflect)
305
+ assoc_reflect[:conditions] || assoc_reflect[:block]
306
+ end
307
+
308
+ def reciprocal_association?(assoc_reflect)
309
+ Array(reciprocal_type).include?(assoc_reflect[:type]) &&
310
+ assoc_reflect.associated_class == self[:model]
311
+ end
312
+
291
313
  # If +s+ is an array, map +s+ over the block. Otherwise, just call the
292
314
  # block with +s+.
293
315
  def transform(s)
@@ -378,6 +400,15 @@ module Sequel
378
400
 
379
401
  private
380
402
 
403
+ # REMOVE40: merge into reciprocal_association?
404
+ def deprecated_reciprocal_association?(assoc_reflect)
405
+ super || primary_key != assoc_reflect.primary_key
406
+ end
407
+
408
+ def reciprocal_association?(assoc_reflect)
409
+ super && self[:keys] == assoc_reflect[:keys]
410
+ end
411
+
381
412
  # The reciprocal type of a many_to_one association is either
382
413
  # a one_to_many or a one_to_one association.
383
414
  def reciprocal_type
@@ -444,6 +475,15 @@ module Sequel
444
475
 
445
476
  private
446
477
 
478
+ # REMOVE40: merge into reciprocal_association?
479
+ def deprecated_reciprocal_association?(assoc_reflect)
480
+ super || primary_key != assoc_reflect.primary_key
481
+ end
482
+
483
+ def reciprocal_association?(assoc_reflect)
484
+ super && self[:keys] == assoc_reflect[:keys]
485
+ end
486
+
447
487
  # The reciprocal type of a one_to_many association is a many_to_one association.
448
488
  def reciprocal_type
449
489
  :many_to_one
@@ -570,25 +610,6 @@ module Sequel
570
610
  true
571
611
  end
572
612
 
573
- # Returns the reciprocal association symbol, if one exists.
574
- def reciprocal
575
- cached_fetch(:reciprocal) do
576
- left_keys = self[:left_keys]
577
- right_keys = self[:right_keys]
578
- join_table = self[:join_table]
579
- recip = nil
580
- associated_class.all_association_reflections.each do |assoc_reflect|
581
- if assoc_reflect[:type] == :many_to_many && assoc_reflect[:left_keys] == right_keys &&
582
- assoc_reflect[:right_keys] == left_keys && assoc_reflect[:join_table] == join_table &&
583
- assoc_reflect.associated_class == self[:model]
584
- recip = assoc_reflect[:name]
585
- break
586
- end
587
- end
588
- recip
589
- end
590
- end
591
-
592
613
  # #right_primary_key qualified by the associated table
593
614
  def qualified_right_primary_key
594
615
  cached_fetch(:qualified_right_primary_key){qualify_assoc(right_primary_key)}
@@ -623,6 +644,21 @@ module Sequel
623
644
 
624
645
  private
625
646
 
647
+ # REMOVE40: merge into reciprocal_association?
648
+ def deprecated_reciprocal_association?(assoc_reflect)
649
+ super || right_primary_keys != assoc_reflect[:left_primary_key_columns] || self[:left_primary_key_columns] != assoc_reflect.right_primary_keys
650
+ end
651
+
652
+ def reciprocal_association?(assoc_reflect)
653
+ super && assoc_reflect[:left_keys] == self[:right_keys] &&
654
+ assoc_reflect[:right_keys] == self[:left_keys] &&
655
+ assoc_reflect[:join_table] == self[:join_table]
656
+ end
657
+
658
+ def reciprocal_type
659
+ :many_to_many
660
+ end
661
+
626
662
  # Split the join table into source and alias parts.
627
663
  def split_join_table_alias
628
664
  associated_class.dataset.split_alias(self[:join_table])
@@ -782,12 +818,10 @@ module Sequel
782
818
  # :eager_graph :: The associations to eagerly load via +eager_graph+ when loading the associated object(s).
783
819
  # many_to_many associations with this option cannot be eagerly loaded via +eager+.
784
820
  # :eager_grapher :: A proc to use to implement eager loading via +eager_graph+, overriding the default.
785
- # Takes one or three arguments. If three arguments, they are a dataset, an alias to use for
786
- # the table to graph for this association, and the alias that was used for the current table
787
- # (since you can cascade associations). If one argument, is passed a hash with keys :self,
788
- # :table_alias, and :implicit_qualifier, corresponding to the three arguments, and an optional
789
- # additional key :eager_block, a callback accepting one argument, the associated dataset. This
790
- # is used to customize the association at query time.
821
+ # Takes an options hash with the entries :self (the receiver of the eager_graph call),
822
+ # :table_alias (the alias to use for table to graph into the association), :implicit_qualifier
823
+ # (the alias that was used for the current table), and possibly :eager_block (a callback
824
+ # proc accepting the associated dataset, for per-call customization).
791
825
  # Should return a copy of the dataset with the association graphed into it.
792
826
  # :eager_limit_strategy :: Determines the strategy used for enforcing limits when eager loading associations via
793
827
  # the +eager+ method. For one_to_one associations, no strategy is used by default, and
@@ -795,8 +829,8 @@ module Sequel
795
829
  # all records but slices the resulting array after the association is retrieved. You
796
830
  # can pass a +true+ value for this option to have Sequel pick what it thinks is the best
797
831
  # choice for the database, or specify a specific symbol to manually select a strategy.
798
- # one_to_one associations support :distinct_on, :window_function, and :correlated_subquery.
799
- # *_many associations support :ruby, :window_function, and :correlated_subquery.
832
+ # one_to_one associations support :distinct_on and :window_function.
833
+ # *_many associations support :ruby, and :window_function.
800
834
  # :eager_loader :: A proc to use to implement eager loading, overriding the default. Takes a single hash argument,
801
835
  # with at least the keys: :rows, which is an array of current model instances, :associations,
802
836
  # which is a hash of dependent associations, :self, which is the dataset doing the eager loading,
@@ -922,12 +956,18 @@ module Sequel
922
956
  # Defaults to :right_primary_key option.
923
957
  # :uniq :: Adds a after_load callback that makes the array of objects unique.
924
958
  def associate(type, name, opts = {}, &block)
925
- raise(Error, 'one_to_many association type with :one_to_one option removed, used one_to_one association type') if opts[:one_to_one] && type == :one_to_many
959
+ if opts[:one_to_one] && type == :one_to_many
960
+ Sequel::Deprecation.deprecate('Raising an Error when the one_to_many type uses the :one_to_one option', "Use the one_to_one associationtype")
961
+ raise(Error, 'one_to_many association type with :one_to_one option removed, used one_to_one association type')
962
+ end
926
963
  raise(Error, 'invalid association type') unless assoc_class = ASSOCIATION_TYPES[type]
927
- raise(Error, 'Model.associate name argument must be a symbol') unless Symbol === name
964
+ raise(Error, 'Model.associate name argument must be a symbol') unless name.is_a?(Symbol)
928
965
  raise(Error, ':eager_loader option must have an arity of 1 or 3') if opts[:eager_loader] && ![1, 3].include?(opts[:eager_loader].arity)
929
966
  raise(Error, ':eager_grapher option must have an arity of 1 or 3') if opts[:eager_grapher] && ![1, 3].include?(opts[:eager_grapher].arity)
930
967
 
968
+ Sequel::Deprecation.deprecate('The :eager_loader association option accepting 3 arguments', "Please switch to accepting a single options hash") if opts[:eager_loader] && opts[:eager_loader].arity == 3
969
+ Sequel::Deprecation.deprecate('The :eager_grapher association option accepting 3 arguments', "Please switch to accepting a single options hash") if opts[:eager_grapher] && opts[:eager_grapher].arity == 3
970
+
931
971
  # dup early so we don't modify opts
932
972
  orig_opts = opts.dup
933
973
  if opts[:clone]
@@ -1023,6 +1063,7 @@ module Sequel
1023
1063
 
1024
1064
  # Use a correlated subquery to limit the results of the eager loading dataset.
1025
1065
  def apply_correlated_subquery_eager_limit_strategy(ds, opts)
1066
+ Sequel::Deprecation.deprecate('The correlated_subquery eager limit strategy', 'Switch to another eager limit strategy.')
1026
1067
  klass = opts.associated_class
1027
1068
  kds = klass.dataset
1028
1069
  dsa = ds.send(:dataset_alias, 1)
@@ -1460,6 +1501,7 @@ module Sequel
1460
1501
  # Formally used internally by the associations code, like pk but doesn't raise
1461
1502
  # an Error if the model has no primary key. Not used any longer, deprecated.
1462
1503
  def pk_or_nil
1504
+ Sequel::Deprecation.deprecate('Model#pk_or_nil', 'There is no replacement')
1463
1505
  key = primary_key
1464
1506
  key.is_a?(Array) ? key.map{|k| @values[k]} : @values[key]
1465
1507
  end
@@ -12,10 +12,15 @@ module Sequel
12
12
  # (default: not set, so all columns not otherwise restricted are allowed).
13
13
  attr_reader :allowed_columns
14
14
 
15
- # Whether to cache the anonymous models created by Sequel::Model(). This is
16
- # required for reloading them correctly (avoiding the superclass mismatch). True
17
- # by default for backwards compatibility.
18
- attr_accessor :cache_anonymous_models
15
+ # REMOVE40
16
+ def cache_anonymous_models
17
+ Sequel::Deprecation.deprecate('Model.cache_anonymous_models', 'Please switch to Sequel.cache_anonymous_models')
18
+ Sequel.cache_anonymous_models
19
+ end
20
+ def cache_anonymous_models=(v)
21
+ Sequel::Deprecation.deprecate('Model.cache_anonymous_models=', 'Please switch to Sequel.cache_anonymous_models=')
22
+ Sequel.cache_anonymous_models = v
23
+ end
19
24
 
20
25
  # Array of modules that extend this model's dataset. Stored
21
26
  # so that if the model's dataset is changed, it will be extended
@@ -63,10 +68,14 @@ module Sequel
63
68
  # Sequel will not check the number of rows modified (default: true).
64
69
  attr_accessor :require_modification
65
70
 
66
- # Which columns are specifically restricted in a call to set/update/new/etc.
67
- # (default: not set). Some columns are restricted regardless of
68
- # this setting, such as the primary key column and columns in Model::RESTRICTED_SETTER_METHODS.
69
- attr_reader :restricted_columns
71
+ # REMOVE40
72
+ def restricted_columns
73
+ Sequel::Deprecation.deprecate('Model.restricted_columns', 'Please load the blacklist_security plugin to continue using it')
74
+ @restricted_columns
75
+ end
76
+ def _restricted_columns
77
+ @restricted_columns
78
+ end
70
79
 
71
80
  # Should be the literal primary key column name if this Model's table has a simple primary key, or
72
81
  # nil if the model has a compound primary key or no primary key.
@@ -254,7 +263,7 @@ module Sequel
254
263
  # sharding support.
255
264
  def db=(db)
256
265
  @db = db
257
- set_dataset(db.dataset(@dataset.opts)) if @dataset
266
+ set_dataset(db.dataset.clone(@dataset.opts)) if @dataset
258
267
  end
259
268
 
260
269
  # Returns the cached schema information if available or gets it
@@ -342,9 +351,11 @@ module Sequel
342
351
  # may contain setter methods.
343
352
  def include(mod)
344
353
  clear_setter_methods_cache
354
+ check_deprecated_after_initialize(mod.instance_methods) unless allowed_after_initialize_implementation?(mod)
355
+ Sequel::Deprecation.deprecate('Model#set_values', 'Please override Model.call, Model#_refresh_set_values, and/or Model#_create_set_values depending on the type of behavior you want to change') if mod.public_instance_methods.map{|x| x.to_s}.include?('set_values') && mod.name.to_s !~ /\ASequel::(Model|Model::Associations|Plugins::(ForceEncoding|Serialization|TypecastOnLoad|Composition|PreparedStatementsSafe|Dirty|PgTypecastOnLoad))::InstanceMethods\z/
345
356
  super
346
357
  end
347
-
358
+
348
359
  # If possible, set the dataset for the model subclass as soon as it
349
360
  # is created. Also, make sure the inherited class instance variables
350
361
  # are copied into the subclass.
@@ -405,6 +416,8 @@ module Sequel
405
416
  # Clear the setter_methods cache when a setter method is added
406
417
  def method_added(meth)
407
418
  clear_setter_methods_cache if meth.to_s =~ SETTER_METHOD_REGEXP
419
+ check_deprecated_after_initialize(meth)
420
+ Sequel::Deprecation.deprecate('Model#set_values', 'Please override Model.call, Model#_refresh_set_values, and/or Model#_create_set_values depending on the type of behavior you want to change') if meth.to_s == 'set_values'
408
421
  super
409
422
  end
410
423
 
@@ -431,7 +444,18 @@ module Sequel
431
444
  m.apply(self, *args, &block) if m.respond_to?(:apply)
432
445
  include(m::InstanceMethods) if plugin_module_defined?(m, :InstanceMethods)
433
446
  extend(m::ClassMethods)if plugin_module_defined?(m, :ClassMethods)
434
- dataset_extend(m::DatasetMethods) if plugin_module_defined?(m, :DatasetMethods)
447
+ if plugin_module_defined?(m, :DatasetMethods)
448
+ dataset_extend(m::DatasetMethods, :create_class_methods=>false)
449
+ # REMOVE40
450
+ m::DatasetMethods.public_instance_methods.each do |meth|
451
+ unless respond_to?(meth, true)
452
+ (class << self; self; end).send(:define_method, meth) do |*args, &block|
453
+ Sequel::Deprecation.deprecate('Automatically defining Model class methods for plugin public dataset methods', "Please modify the plugin to use Plugins.def_dataset_method for #{meth}")
454
+ dataset.send(meth, *args, &block)
455
+ end
456
+ end
457
+ end
458
+ end
435
459
  end
436
460
  m.configure(self, *args, &block) if m.respond_to?(:configure)
437
461
  end
@@ -521,10 +545,10 @@ module Sequel
521
545
  # sharding support.
522
546
  def set_dataset(ds, opts={})
523
547
  inherited = opts[:inherited]
524
- @dataset = case ds
548
+ case ds
525
549
  when Symbol, SQL::Identifier, SQL::QualifiedIdentifier, SQL::AliasedExpression, LiteralString
526
550
  self.simple_table = db.literal(ds)
527
- db.from(ds)
551
+ ds = db.from(ds)
528
552
  when Dataset
529
553
  self.simple_table = if ds.send(:simple_select_all?)
530
554
  ds.literal(ds.first_source_table)
@@ -532,11 +556,11 @@ module Sequel
532
556
  nil
533
557
  end
534
558
  @db = ds.db
535
- ds
536
559
  else
537
560
  raise(Error, "Model.set_dataset takes one of the following classes as an argument: Symbol, LiteralString, SQL::Identifier, SQL::QualifiedIdentifier, SQL::AliasedExpression, Dataset")
538
561
  end
539
- @dataset.row_proc = self
562
+ set_dataset_row_proc(ds)
563
+ @dataset = ds
540
564
  @require_modification = Sequel::Model.require_modification.nil? ? @dataset.provides_accurate_rows_matched? : Sequel::Model.require_modification
541
565
  if inherited
542
566
  self.simple_table = superclass.simple_table
@@ -565,6 +589,9 @@ module Sequel
565
589
  # set_primary_key [:taggable_id, :tag_id]
566
590
  # end
567
591
  def set_primary_key(*key)
592
+ Sequel::Deprecation.deprecate('Calling set_primary_key without arguments is deprecated and will raise an exception in Sequel 4. Please use no_primary_key to mark the model as not having a primary key.') if key.length == 0
593
+ Sequel::Deprecation.deprecate('Calling set_primary_key with multiple arguments is deprecated and will raise an exception in Sequel 4. Please pass an array of keys to setup a composite primary key.') if key.length > 1
594
+
568
595
  clear_setter_methods_cache
569
596
  key = key.flatten
570
597
  self.simple_pk = if key.length == 1
@@ -590,6 +617,7 @@ module Sequel
590
617
  # Artist.set(:name=>'Bob', :records_sold=>30000) # Error
591
618
  def set_restricted_columns(*cols)
592
619
  clear_setter_methods_cache
620
+ Sequel::Deprecation.deprecate('Model.set_restricted_columns', 'Please switch to Model.set_allowed_columns or use the blacklist_security plugin')
593
621
  @restricted_columns = cols
594
622
  end
595
623
 
@@ -600,7 +628,7 @@ module Sequel
600
628
  else
601
629
  meths = instance_methods.collect{|x| x.to_s}.grep(SETTER_METHOD_REGEXP) - RESTRICTED_SETTER_METHODS
602
630
  meths -= Array(primary_key).map{|x| "#{x}="} if primary_key && restrict_primary_key?
603
- meths -= restricted_columns.map{|x| "#{x}="} if restricted_columns
631
+ meths -= _restricted_columns.map{|x| "#{x}="} if _restricted_columns
604
632
  meths
605
633
  end
606
634
  end
@@ -651,6 +679,37 @@ module Sequel
651
679
  clear_setter_methods_cache
652
680
  @restrict_primary_key = false
653
681
  end
682
+
683
+ # Return the model instance with the primary key, or nil if there is no matching record.
684
+ def with_pk(pk)
685
+ primary_key_lookup(pk)
686
+ end
687
+
688
+ # Return the model instance with the primary key, or raise NoMatchingRow if there is no matching record.
689
+ def with_pk!(pk)
690
+ with_pk(pk) || raise(NoMatchingRow)
691
+ end
692
+
693
+ # Add model methods that call dataset methods
694
+ Plugins.def_dataset_methods(self, DATASET_METHODS)
695
+
696
+ # REMOVE40
697
+ %w'print each_page set add_graph_aliases insert_multiple query set_overrides set_defaults to_csv paginate'.each do |meth|
698
+ class_eval(<<-END, __FILE__, __LINE__+1)
699
+ def #{meth}(*args, &block)
700
+ Sequel::Deprecation.deprecate('Model.#{meth}', 'Please use Model.dataset.#{meth} instead')
701
+ dataset.#{meth}(*args, &block)
702
+ end
703
+ END
704
+ end
705
+ %w'destroy delete update'.each do |meth|
706
+ class_eval(<<-END, __FILE__, __LINE__+1)
707
+ def #{meth}(*args, &block)
708
+ Sequel::Deprecation.deprecate('Model.#{meth}', 'Please use the scissors plugin or Model.dataset.#{meth} instead')
709
+ dataset.#{meth}(*args, &block)
710
+ end
711
+ END
712
+ end
654
713
 
655
714
  private
656
715
 
@@ -665,14 +724,28 @@ module Sequel
665
724
  end
666
725
  end
667
726
 
727
+ # REMOVE40
728
+ def allowed_after_initialize_implementation?(mod)
729
+ mod == InstanceMethods || mod.to_s == 'Sequel::Plugins::HookClassMethods::InstanceMethods'
730
+ end
731
+
732
+ # REMOVE40
733
+ def check_deprecated_after_initialize(meths)
734
+ Array(meths).each do |meth|
735
+ Sequel::Deprecation.deprecate('The Model after_initialize hook', 'Please use the after_initialize plugin to continue using the hook') if meth.to_s == 'after_initialize'
736
+ end
737
+ end
738
+
668
739
  # Add the module to the class's dataset_method_modules. Extend the dataset with the
669
740
  # module if the model has a dataset. Add dataset methods to the class for all
670
741
  # public dataset methods.
671
- def dataset_extend(mod)
672
- @dataset.extend(mod) if defined?(@dataset) && @dataset
742
+ def dataset_extend(mod, opts={})
743
+ @dataset.extend(mod) if @dataset
673
744
  reset_instance_dataset
674
745
  dataset_method_modules << mod
675
- mod.public_instance_methods.each{|meth| def_model_dataset_method(meth)}
746
+ unless opts[:create_class_methods] == false
747
+ mod.public_instance_methods.each{|meth| def_model_dataset_method(meth)}
748
+ end
676
749
  end
677
750
 
678
751
  # Create a column accessor for a column with a method name that is hard to use in ruby code.
@@ -719,7 +792,7 @@ module Sequel
719
792
  schema_hash = {}
720
793
  ds_opts = dataset.opts
721
794
  get_columns = proc{check_non_connection_error{columns} || []}
722
- schema_array = check_non_connection_error{db.schema(dataset, :reload=>reload)}
795
+ schema_array = check_non_connection_error{db.schema(dataset, :reload=>reload)} if db.supports_schema_parsing?
723
796
  if schema_array
724
797
  schema_array.each{|k,v| schema_hash[k] = v}
725
798
  if ds_opts.include?(:select)
@@ -739,7 +812,7 @@ module Sequel
739
812
  # if the schema information includes primary key information
740
813
  if schema_array.all?{|k,v| v.has_key?(:primary_key)}
741
814
  pks = schema_array.collect{|k,v| k if v[:primary_key]}.compact
742
- pks.length > 0 ? set_primary_key(*pks) : no_primary_key
815
+ pks.length > 0 ? set_primary_key(pks) : no_primary_key
743
816
  end
744
817
  # Also set the columns for the dataset, so the dataset
745
818
  # doesn't have to do a query to get them.
@@ -780,7 +853,7 @@ module Sequel
780
853
  # Module that the class includes that holds methods the class adds for column accessors and
781
854
  # associations so that the methods can be overridden with +super+.
782
855
  def overridable_methods_module
783
- include(@overridable_methods_module = Module.new) unless defined?(@overridable_methods_module) && @overridable_methods_module
856
+ include(@overridable_methods_module = Module.new) unless @overridable_methods_module
784
857
  @overridable_methods_module
785
858
  end
786
859
 
@@ -792,10 +865,10 @@ module Sequel
792
865
  (Sequel.const_defined?(module_name) &&
793
866
  Sequel::Plugins.const_get(module_name) == Sequel.const_get(module_name))
794
867
  begin
795
- Sequel.tsk_require "sequel/plugins/#{plugin}"
868
+ require "sequel/plugins/#{plugin}"
796
869
  rescue LoadError => e
797
870
  begin
798
- Sequel.tsk_require "sequel_#{plugin}"
871
+ require "sequel_#{plugin}"
799
872
  rescue LoadError => e2
800
873
  e.message << "; #{e2.message}"
801
874
  raise e
@@ -848,7 +921,7 @@ module Sequel
848
921
  # Reset the instance dataset to a modified copy of the current dataset,
849
922
  # should be used whenever the model's dataset is modified.
850
923
  def reset_instance_dataset
851
- @instance_dataset = @dataset.limit(1).naked if defined?(@dataset) && @dataset
924
+ @instance_dataset = @dataset.limit(1).naked if @dataset
852
925
  end
853
926
 
854
927
  # Set the columns for this model and create accessor methods for each column.
@@ -858,6 +931,11 @@ module Sequel
858
931
  @columns
859
932
  end
860
933
 
934
+ # Set the dataset's row_proc to the current model.
935
+ def set_dataset_row_proc(ds)
936
+ ds.row_proc = self
937
+ end
938
+
861
939
  # Reset the fast primary key lookup SQL when the simple_pk value changes.
862
940
  def simple_pk=(pk)
863
941
  @simple_pk = pk
@@ -870,9 +948,6 @@ module Sequel
870
948
  reset_fast_pk_lookup_sql
871
949
  end
872
950
 
873
- # Add model methods that call dataset methods
874
- Plugins.def_dataset_methods(self, DATASET_METHODS)
875
-
876
951
  # Returns a copy of the model's dataset with custom SQL
877
952
  #
878
953
  # Artist.fetch("SELECT * FROM artists WHERE name LIKE 'A%'")
@@ -896,32 +971,29 @@ module Sequel
896
971
  HOOKS.each{|h| class_eval("def #{h}; end", __FILE__, __LINE__)}
897
972
  AROUND_HOOKS.each{|h| class_eval("def #{h}; yield end", __FILE__, __LINE__)}
898
973
 
899
- # Define instance method(s) that calls class method(s) of the
900
- # same name, caching the result in an instance variable. Define
901
- # standard attr_writer method for modifying that instance variable.
902
- #
903
- # Do not call this method with untrusted input, as that can result in
904
- # arbitrary code execution.
974
+ # REMOVE40
905
975
  def self.class_attr_overridable(*meths) # :nodoc:
976
+ Sequel::Deprecation.deprecate('Model::InstanceMethods.class_attr_overridable', "There is no replacement planned")
906
977
  meths.each{|meth| class_eval("def #{meth}; !defined?(@#{meth}) ? (frozen? ? self.class.#{meth} : (@#{meth} = self.class.#{meth})) : @#{meth} end", __FILE__, __LINE__)}
907
978
  attr_writer(*meths)
908
979
  end
909
-
910
- # Define instance method(s) that calls class method(s) of the
911
- # same name. Replaces the construct:
912
- #
913
- # define_method(meth){self.class.send(meth)}
914
- #
915
- # Do not call this method with untrusted input, as that can result in
916
- # arbitrary code execution.
917
980
  def self.class_attr_reader(*meths) # :nodoc:
981
+ Sequel::Deprecation.deprecate('Model::InstanceMethods.class_attr_reader', "There is no replacement planned")
918
982
  meths.each{|meth| class_eval("def #{meth}; self.class.#{meth} end", __FILE__, __LINE__)}
919
983
  end
920
-
921
984
  private_class_method :class_attr_overridable, :class_attr_reader
922
985
 
923
- class_attr_reader :columns, :db, :primary_key, :db_schema
924
- class_attr_overridable(*BOOLEAN_SETTINGS)
986
+ # Define instance method(s) that calls class method(s) of the
987
+ # same name. Replaces the construct:
988
+ #
989
+ # define_method(meth){self.class.send(meth)}
990
+ [:columns, :db, :primary_key, :db_schema].each{|meth| class_eval("def #{meth}; self.class.#{meth} end", __FILE__, __LINE__)}
991
+
992
+ # Define instance method(s) that calls class method(s) of the
993
+ # same name, caching the result in an instance variable. Define
994
+ # standard attr_writer method for modifying that instance variable.
995
+ BOOLEAN_SETTINGS.each{|meth| class_eval("def #{meth}; !defined?(@#{meth}) ? (frozen? ? self.class.#{meth} : (@#{meth} = self.class.#{meth})) : @#{meth} end", __FILE__, __LINE__)}
996
+ attr_writer(*BOOLEAN_SETTINGS)
925
997
 
926
998
  # The hash of attribute values. Keys are symbols with the names of the
927
999
  # underlying database columns.
@@ -948,6 +1020,7 @@ module Sequel
948
1020
  # end
949
1021
  def initialize(values = {}, from_db = false)
950
1022
  if from_db
1023
+ Sequel::Deprecation.deprecate('Passing two arguments to Model.new', 'Please use Model.call instead')
951
1024
  set_values(values)
952
1025
  else
953
1026
  @values = {}
@@ -1074,7 +1147,7 @@ module Sequel
1074
1147
  # Returns the validation errors associated with this object.
1075
1148
  # See +Errors+.
1076
1149
  def errors
1077
- @errors ||= Errors.new
1150
+ @errors ||= errors_class.new
1078
1151
  end
1079
1152
 
1080
1153
  # Returns true when current instance exists, false otherwise.
@@ -1088,7 +1161,7 @@ module Sequel
1088
1161
  # Artist.new.exists?
1089
1162
  # # => false
1090
1163
  def exists?
1091
- new? ? false : !this.get(1).nil?
1164
+ new? ? false : !this.get(SQL::AliasedExpression.new(1, :one)).nil?
1092
1165
  end
1093
1166
 
1094
1167
  # Ignore the model's setter method cache when this instances extends a module, as the
@@ -1292,6 +1365,7 @@ module Sequel
1292
1365
  # Takes the following options:
1293
1366
  #
1294
1367
  # :changed :: save all changed columns, instead of all columns or the columns given
1368
+ # :columns :: array of specific columns that should be saved.
1295
1369
  # :raise_on_failure :: set to true or false to override the current
1296
1370
  # +raise_on_save_failure+ setting
1297
1371
  # :server :: set the server/shard on the object before saving, and use that
@@ -1302,6 +1376,10 @@ module Sequel
1302
1376
  def save(*columns)
1303
1377
  raise Sequel::Error, "can't save frozen object" if frozen?
1304
1378
  opts = columns.last.is_a?(Hash) ? columns.pop : {}
1379
+
1380
+ Sequel::Deprecation.deprecate('Passing columns as separate arguments to Model#save', 'Instead, provide a :columns option with the array of columns to save.') unless columns.empty?
1381
+ columns.concat(Array(opts[:columns])) if opts[:columns]
1382
+
1305
1383
  set_server(opts[:server]) if opts[:server]
1306
1384
  if opts[:validate] != false
1307
1385
  unless checked_save_failure(opts){_valid?(true, opts)}
@@ -1337,9 +1415,9 @@ module Sequel
1337
1415
  end
1338
1416
 
1339
1417
  # Set all values using the entries in the hash, ignoring any setting of
1340
- # allowed_columns or restricted columns in the model.
1418
+ # allowed_columns in the model.
1341
1419
  #
1342
- # Artist.set_restricted_columns(:name)
1420
+ # Artist.set_allowed_columns(:num_albums)
1343
1421
  # artist.set_all(:name=>'Jim')
1344
1422
  # artist.name # => 'Jim'
1345
1423
  def set_all(hash)
@@ -1353,6 +1431,7 @@ module Sequel
1353
1431
  # artist.set_except({:name=>'Jim'}, :hometown)
1354
1432
  # artist.name # => 'Jim'
1355
1433
  def set_except(hash, *except)
1434
+ Sequel::Deprecation.deprecate('Model#set_except', 'Please switch to Model#set_only or use the blacklist_security plugin')
1356
1435
  set_restricted(hash, false, except.flatten)
1357
1436
  end
1358
1437
 
@@ -1462,9 +1541,9 @@ module Sequel
1462
1541
  end
1463
1542
 
1464
1543
  # Update all values using the entries in the hash, ignoring any setting of
1465
- # +allowed_columns+ or +restricted_columns+ in the model.
1544
+ # +allowed_columns+ in the model.
1466
1545
  #
1467
- # Artist.set_restricted_columns(:name)
1546
+ # Artist.set_allowed_columns(:num_albums)
1468
1547
  # artist.update_all(:name=>'Jim') # UPDATE artists SET name = 'Jim' WHERE (id = 1)
1469
1548
  def update_all(hash)
1470
1549
  update_restricted(hash, false, false)
@@ -1476,6 +1555,7 @@ module Sequel
1476
1555
  #
1477
1556
  # artist.update_except({:name=>'Jim'}, :hometown) # UPDATE artists SET name = 'Jim' WHERE (id = 1)
1478
1557
  def update_except(hash, *except)
1558
+ Sequel::Deprecation.deprecate('Model#update_except', 'Please switch to Model#update_only or use the blacklist_security plugin')
1479
1559
  update_restricted(hash, false, except.flatten)
1480
1560
  end
1481
1561
 
@@ -1789,6 +1869,11 @@ module Sequel
1789
1869
  @values[column] = value
1790
1870
  end
1791
1871
 
1872
+ # Default error class used for errors.
1873
+ def errors_class
1874
+ Errors
1875
+ end
1876
+
1792
1877
  # Set the columns with the given hash. By default, the same as +set+, but
1793
1878
  # exists so it can be overridden. This is called only for new records, before
1794
1879
  # changed_columns is cleared.
@@ -1869,7 +1954,7 @@ module Sequel
1869
1954
  # well, see Model.unrestrict_primary_key to change this.
1870
1955
  def setter_methods(only, except)
1871
1956
  only = only.nil? ? model.allowed_columns : only
1872
- except = except.nil? ? model.restricted_columns : except
1957
+ except = except.nil? ? model._restricted_columns : except
1873
1958
  if only
1874
1959
  only.map{|x| "#{x}="}
1875
1960
  else