sequel 3.47.0 → 3.48.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 (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