sequel 4.44.0 → 4.45.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (140) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +110 -0
  3. data/README.rdoc +8 -9
  4. data/doc/active_record.rdoc +2 -3
  5. data/doc/model_plugins.rdoc +1 -1
  6. data/doc/opening_databases.rdoc +0 -46
  7. data/doc/release_notes/4.45.0.txt +370 -0
  8. data/lib/sequel/adapters/cubrid.rb +2 -0
  9. data/lib/sequel/adapters/do.rb +2 -0
  10. data/lib/sequel/adapters/jdbc/as400.rb +2 -0
  11. data/lib/sequel/adapters/jdbc/cubrid.rb +2 -0
  12. data/lib/sequel/adapters/jdbc/firebirdsql.rb +2 -0
  13. data/lib/sequel/adapters/jdbc/informix-sqli.rb +2 -0
  14. data/lib/sequel/adapters/jdbc/jdbcprogress.rb +2 -0
  15. data/lib/sequel/adapters/jdbc/mysql.rb +1 -0
  16. data/lib/sequel/adapters/jdbc/postgresql.rb +5 -0
  17. data/lib/sequel/adapters/mysql.rb +1 -0
  18. data/lib/sequel/adapters/mysql2.rb +1 -0
  19. data/lib/sequel/adapters/odbc/oracle.rb +11 -0
  20. data/lib/sequel/adapters/odbc/progress.rb +2 -0
  21. data/lib/sequel/adapters/postgres.rb +0 -2
  22. data/lib/sequel/adapters/shared/cubrid.rb +2 -0
  23. data/lib/sequel/adapters/shared/firebird.rb +2 -0
  24. data/lib/sequel/adapters/shared/informix.rb +2 -0
  25. data/lib/sequel/adapters/shared/mssql.rb +47 -7
  26. data/lib/sequel/adapters/shared/mysql.rb +16 -1
  27. data/lib/sequel/adapters/shared/postgres.rb +9 -1
  28. data/lib/sequel/adapters/shared/progress.rb +2 -0
  29. data/lib/sequel/adapters/shared/sqlanywhere.rb +1 -1
  30. data/lib/sequel/adapters/swift.rb +2 -0
  31. data/lib/sequel/ast_transformer.rb +13 -6
  32. data/lib/sequel/core.rb +13 -16
  33. data/lib/sequel/database/connecting.rb +25 -10
  34. data/lib/sequel/database/dataset.rb +6 -1
  35. data/lib/sequel/database/dataset_defaults.rb +9 -2
  36. data/lib/sequel/database/misc.rb +10 -3
  37. data/lib/sequel/database/schema_methods.rb +4 -0
  38. data/lib/sequel/dataset/mutation.rb +8 -20
  39. data/lib/sequel/dataset/prepared_statements.rb +2 -0
  40. data/lib/sequel/dataset/query.rb +32 -7
  41. data/lib/sequel/dataset/sql.rb +13 -3
  42. data/lib/sequel/deprecated.rb +9 -1
  43. data/lib/sequel/exceptions.rb +37 -8
  44. data/lib/sequel/extensions/_deprecated_identifier_mangling.rb +117 -0
  45. data/lib/sequel/extensions/date_arithmetic.rb +1 -0
  46. data/lib/sequel/extensions/identifier_mangling.rb +3 -2
  47. data/lib/sequel/extensions/pg_hstore.rb +1 -5
  48. data/lib/sequel/extensions/schema_dumper.rb +3 -1
  49. data/lib/sequel/extensions/sequel_3_dataset_methods.rb +2 -2
  50. data/lib/sequel/extensions/string_agg.rb +1 -0
  51. data/lib/sequel/model.rb +23 -10
  52. data/lib/sequel/model/associations.rb +17 -5
  53. data/lib/sequel/model/base.rb +115 -62
  54. data/lib/sequel/model/dataset_module.rb +10 -3
  55. data/lib/sequel/model/exceptions.rb +7 -5
  56. data/lib/sequel/plugins/association_pks.rb +13 -1
  57. data/lib/sequel/plugins/association_proxies.rb +8 -1
  58. data/lib/sequel/plugins/before_after_save.rb +1 -0
  59. data/lib/sequel/plugins/class_table_inheritance.rb +7 -3
  60. data/lib/sequel/plugins/columns_updated.rb +42 -0
  61. data/lib/sequel/plugins/composition.rb +10 -5
  62. data/lib/sequel/plugins/error_splitter.rb +1 -1
  63. data/lib/sequel/plugins/hook_class_methods.rb +39 -5
  64. data/lib/sequel/plugins/instance_hooks.rb +58 -5
  65. data/lib/sequel/plugins/lazy_attributes.rb +10 -5
  66. data/lib/sequel/plugins/nested_attributes.rb +10 -5
  67. data/lib/sequel/plugins/prepared_statements.rb +7 -0
  68. data/lib/sequel/plugins/prepared_statements_associations.rb +2 -0
  69. data/lib/sequel/plugins/prepared_statements_with_pk.rb +2 -0
  70. data/lib/sequel/plugins/schema.rb +2 -0
  71. data/lib/sequel/plugins/scissors.rb +2 -0
  72. data/lib/sequel/plugins/serialization.rb +10 -5
  73. data/lib/sequel/plugins/split_values.rb +5 -1
  74. data/lib/sequel/plugins/static_cache.rb +2 -2
  75. data/lib/sequel/plugins/tactical_eager_loading.rb +1 -1
  76. data/lib/sequel/plugins/validation_contexts.rb +49 -0
  77. data/lib/sequel/plugins/validation_helpers.rb +1 -0
  78. data/lib/sequel/sql.rb +1 -1
  79. data/lib/sequel/version.rb +1 -1
  80. data/spec/adapters/mssql_spec.rb +31 -0
  81. data/spec/adapters/mysql_spec.rb +20 -2
  82. data/spec/adapters/postgres_spec.rb +43 -12
  83. data/spec/adapters/spec_helper.rb +5 -8
  84. data/spec/core/database_spec.rb +47 -12
  85. data/spec/core/dataset_mutation_spec.rb +22 -22
  86. data/spec/core/dataset_spec.rb +88 -20
  87. data/spec/core/deprecated_spec.rb +1 -1
  88. data/spec/core/expression_filters_spec.rb +1 -1
  89. data/spec/core/mock_adapter_spec.rb +0 -3
  90. data/spec/core/placeholder_literalizer_spec.rb +1 -1
  91. data/spec/core/schema_spec.rb +8 -1
  92. data/spec/core/spec_helper.rb +6 -1
  93. data/spec/core_extensions_spec.rb +4 -0
  94. data/spec/deprecation_helper.rb +17 -0
  95. data/spec/extensions/_deprecated_identifier_mangling_spec.rb +314 -0
  96. data/spec/extensions/association_pks_spec.rb +61 -13
  97. data/spec/extensions/association_proxies_spec.rb +3 -3
  98. data/spec/extensions/class_table_inheritance_spec.rb +39 -0
  99. data/spec/extensions/columns_updated_spec.rb +35 -0
  100. data/spec/extensions/composition_spec.rb +6 -1
  101. data/spec/extensions/hook_class_methods_spec.rb +114 -26
  102. data/spec/extensions/identifier_mangling_spec.rb +107 -73
  103. data/spec/extensions/instance_hooks_spec.rb +78 -14
  104. data/spec/extensions/lazy_attributes_spec.rb +8 -2
  105. data/spec/extensions/many_through_many_spec.rb +2 -2
  106. data/spec/extensions/mssql_optimistic_locking_spec.rb +1 -1
  107. data/spec/extensions/nested_attributes_spec.rb +8 -2
  108. data/spec/extensions/pg_array_spec.rb +18 -4
  109. data/spec/extensions/prepared_statements_associations_spec.rb +48 -39
  110. data/spec/extensions/prepared_statements_with_pk_spec.rb +13 -11
  111. data/spec/extensions/query_spec.rb +1 -1
  112. data/spec/extensions/schema_dumper_spec.rb +34 -6
  113. data/spec/extensions/schema_spec.rb +13 -7
  114. data/spec/extensions/scissors_spec.rb +3 -1
  115. data/spec/extensions/sequel_3_dataset_methods_spec.rb +4 -4
  116. data/spec/extensions/serialization_spec.rb +7 -1
  117. data/spec/extensions/set_overrides_spec.rb +2 -2
  118. data/spec/extensions/shared_caching_spec.rb +19 -15
  119. data/spec/extensions/spec_helper.rb +7 -3
  120. data/spec/extensions/split_values_spec.rb +45 -10
  121. data/spec/extensions/string_agg_spec.rb +2 -2
  122. data/spec/extensions/subset_conditions_spec.rb +3 -3
  123. data/spec/extensions/tactical_eager_loading_spec.rb +1 -1
  124. data/spec/extensions/validation_contexts_spec.rb +31 -0
  125. data/spec/guards_helper.rb +2 -0
  126. data/spec/integration/associations_test.rb +22 -20
  127. data/spec/integration/dataset_test.rb +25 -2
  128. data/spec/integration/model_test.rb +1 -1
  129. data/spec/integration/plugin_test.rb +11 -16
  130. data/spec/integration/prepared_statement_test.rb +40 -32
  131. data/spec/integration/spec_helper.rb +5 -8
  132. data/spec/model/association_reflection_spec.rb +4 -0
  133. data/spec/model/associations_spec.rb +37 -10
  134. data/spec/model/base_spec.rb +6 -0
  135. data/spec/model/hooks_spec.rb +56 -35
  136. data/spec/model/model_spec.rb +21 -5
  137. data/spec/model/record_spec.rb +14 -11
  138. data/spec/model/spec_helper.rb +7 -1
  139. data/spec/sequel_warning.rb +11 -0
  140. metadata +13 -3
@@ -29,6 +29,12 @@ module Sequel
29
29
  # objects, and the setting will not be persisted until after the object has
30
30
  # been saved.
31
31
  #
32
+ # SEQUEL5: Starting in Sequel 5, the :delay_pks association option will default
33
+ # to :delay_pks=>:always. If you would like to use the Sequel 4 behavior of
34
+ # having the setter make modifications immediately, explicitly use the
35
+ # :delay_pks=>false option. Additionally, Sequel 5 will not support the current
36
+ # :delay_pks=>true behavior, treating it as :delay_pks=>:always.
37
+ #
32
38
  # By default, if you pass a nil value to the setter, an exception will be raised.
33
39
  # You can change this behavior by using the :association_pks_nil association option.
34
40
  # If set to :ignore, the setter will take no action if nil is given.
@@ -201,11 +207,17 @@ module Sequel
201
207
 
202
208
  pks = convert_pk_array(opts, pks)
203
209
 
204
- delay = opts[:delay_pks]
210
+ delay = opts.fetch(:delay_pks) do
211
+ Sequel::Deprecation.deprecate("association_pks will default to assuming the :delay_pks=>:always association option starting in Sequel 5. Explicitly set :delay_pks=>false option for the association if you want changes to take effect immediately instead of being delayed until the object is saved (association: #{opts.inspect}).")
212
+ false
213
+ end
205
214
  if (new? && delay) || (delay == :always)
206
215
  modified!
207
216
  (@_association_pks ||= {})[opts[:name]] = pks
208
217
  else
218
+ if !new? && delay && delay != :always
219
+ Sequel::Deprecation.deprecate("association_pks with the :delay_pks=>true association option will also delay setting of associated values for existing objects in Sequel 5 (currently it just delays setting of associated values for new objects). Please change to using :delay_pks=>:always to avoid this message. Sequel 5 will not support the existing :delay_pks=>true behavior for only delaying for new objects and not for existing objects.")
220
+ end
209
221
  instance_exec(pks, &opts[:pks_setter])
210
222
  end
211
223
  end
@@ -99,7 +99,14 @@ module Sequel
99
99
  # Changes the association method to return a proxy instead of the associated objects
100
100
  # directly.
101
101
  def def_association_method(opts)
102
- opts.returns_array? ? association_module_def(opts.association_method, opts){|*r, &block| AssociationProxy.new(self, opts, r[0], &block)} : super
102
+ if opts.returns_array?
103
+ association_module_def(opts.association_method, opts) do |*dynamic_opts, &block|
104
+ Sequel::Deprecation.deprecate("Passing multiple arguments to ##{opts.association_method}", "Additional arguments are currently ignored.") if dynamic_opts.length > 1
105
+ AssociationProxy.new(self, opts, dynamic_opts.length == 0 ? OPTS : dynamic_opts[0], &block)
106
+ end
107
+ else
108
+ super
109
+ end
103
110
  end
104
111
  end
105
112
  end
@@ -21,6 +21,7 @@ module Sequel
21
21
  # Album.plugin :before_after_save
22
22
  module BeforeAfterSave
23
23
  module InstanceMethods
24
+ # SEQUEL5: Make module empty as it will be the default behavior
24
25
  private
25
26
 
26
27
  # Refresh and reset modified flag right after INSERT query.
@@ -100,7 +100,7 @@ module Sequel
100
100
  # by explicitly qualifying it:
101
101
  #
102
102
  # a = Executive.where(:id=>1).first # database error
103
- # a = Executive.where(:executives__id=>1).first # no error
103
+ # a = Executive.where{{executives[:id]=>1}}.first # no error
104
104
  #
105
105
  # = Usage
106
106
  #
@@ -287,12 +287,16 @@ module Sequel
287
287
  if cti_tables.length == 1
288
288
  ds = ds.select(*self.columns.map{|cc| Sequel.qualify(table_name, Sequel.identifier(cc))})
289
289
  end
290
- sel_app = (columns - [pk]).map{|cc| Sequel.qualify(table, Sequel.identifier(cc))}
290
+ cols = columns - [pk]
291
+ unless (cols & ds.columns).empty?
292
+ Sequel::Deprecation.deprecate('Using class_table_inheritance with duplicate column names in subclass tables (other than the primary key column)', 'Make sure all tables used have unique column names, or implement support for handling duplicate column names in the class_table_inheritance plugin')
293
+ end
294
+ sel_app = cols.map{|cc| Sequel.qualify(table, Sequel.identifier(cc))}
291
295
  @sti_dataset = ds.join(table, pk=>pk).select_append(*sel_app)
292
296
  set_dataset(@sti_dataset)
293
297
  set_columns(self.columns)
294
298
  @dataset = @dataset.with_row_proc(lambda{|r| subclass.sti_load(r)})
295
- (columns - [pk]).each{|a| define_lazy_attribute_getter(a, :dataset=>dataset, :table=>table)}
299
+ cols.each{|a| define_lazy_attribute_getter(a, :dataset=>dataset, :table=>table)}
296
300
 
297
301
  @cti_models += [self]
298
302
  @cti_tables += [table]
@@ -0,0 +1,42 @@
1
+ # frozen-string-literal: true
2
+
3
+ module Sequel
4
+ module Plugins
5
+ # The columns_updated plugin stores the columns hash used in the
6
+ # UPDATE query when saving the instance, and makes it available
7
+ # in the after_update and after_save hooks via the +columns_updated+
8
+ # accessor. The data is cleared before returning from +save+.
9
+ #
10
+ # Usage:
11
+ #
12
+ # # Make all model subclasses store the columns hash used for updating
13
+ # Sequel::Model.plugin :columns_updated
14
+ #
15
+ # # Make the Album class store the columns hash used for updating
16
+ # Album.plugin :columns_updated
17
+ module ColumnsUpdated
18
+ module InstanceMethods
19
+ private
20
+
21
+ # The hash used for updating records. This should only be called
22
+ # in the after_update and after_save hooks.
23
+ attr_reader :columns_updated
24
+
25
+ # Store the hash used for updating the record, so it can be accessed
26
+ # in the after_hooks.
27
+ def _update_columns(columns_updated)
28
+ @columns_updated = columns_updated
29
+ super
30
+ end
31
+
32
+ # Unset the updated columns hash before returning from save.
33
+ def _save(opts)
34
+ super
35
+ ensure
36
+ @columns_updated = nil
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+
@@ -69,9 +69,14 @@ module Sequel
69
69
  # hash values.
70
70
  attr_reader :compositions
71
71
 
72
- # A module included in the class holding the composition
73
- # getter and setter methods.
74
- attr_reader :composition_module
72
+ def composition_module
73
+ Sequel::Deprecation.deprecate('Sequel::Model.composition_module', 'There is no replacement')
74
+ @composition_module
75
+ end
76
+ def composition_module=(v)
77
+ Sequel::Deprecation.deprecate('Sequel::Model.composition_module=', 'There is no replacement')
78
+ @composition_module = v
79
+ end
75
80
 
76
81
  # Define a composition for this model, with name being the name of the composition.
77
82
  # You must provide either a :mapping option or both the :composer and :decomposer options.
@@ -134,7 +139,7 @@ module Sequel
134
139
  # Define getter and setter methods for the composition object.
135
140
  def define_composition_accessor(name, opts=OPTS)
136
141
  composer = opts[:composer]
137
- composition_module.class_eval do
142
+ @composition_module.class_eval do
138
143
  define_method(name) do
139
144
  if compositions.has_key?(name)
140
145
  compositions[name]
@@ -154,7 +159,7 @@ module Sequel
154
159
  # Freeze composition information when freezing model class.
155
160
  def freeze
156
161
  compositions.freeze.each_value(&:freeze)
157
- composition_module.freeze
162
+ @composition_module.freeze
158
163
 
159
164
  super
160
165
  end
@@ -35,7 +35,7 @@ module Sequel
35
35
  # If the model instance is not valid, go through all of the errors entries. For
36
36
  # any that apply to multiple columns, remove them and add separate error entries,
37
37
  # one per column.
38
- def _valid?(*)
38
+ def _valid?(opts)
39
39
  v = super
40
40
  unless v
41
41
  errors.keys.select{|k| k.is_a?(Array)}.each do |ks|
@@ -34,6 +34,14 @@ module Sequel
34
34
  # # Allow the use of hook class methods in the Album class
35
35
  # Album.plugin :hook_class_methods
36
36
  module HookClassMethods
37
+ # SEQUEL5: Remove
38
+ DEPRECATION_REPLACEMENTS = {
39
+ :after_commit=>"Use after_save{db.after_commit{}} instead",
40
+ :after_destroy_commit=>"Use after_destroy{db.after_commit{}} instead",
41
+ :after_destroy_rollback=>"Use before_destroy{db.after_rollback{}} instead",
42
+ :after_rollback=>"Use before_save{db.after_rollback{}} instead"
43
+ }.freeze
44
+
37
45
  # Set up the hooks instance variable in the model.
38
46
  def self.apply(model)
39
47
  hooks = model.instance_variable_set(:@hooks, {})
@@ -41,7 +49,14 @@ module Sequel
41
49
  end
42
50
 
43
51
  module ClassMethods
44
- Model::HOOKS.each{|h| class_eval("def #{h}(method = nil, &block); add_hook(:#{h}, method, &block) end", __FILE__, __LINE__)}
52
+ Model::HOOKS.each do |h|
53
+ class_eval(<<-END, __FILE__, __LINE__ + 1)
54
+ def #{h}(method = nil, &block)
55
+ #{"Sequel::Deprecation.deprecate('Sequel::Model.#{h} in the hook_class_methods plugin', #{DEPRECATION_REPLACEMENTS[h].inspect})" if DEPRECATION_REPLACEMENTS[h]}
56
+ add_hook(:#{h}, method, &block)
57
+ end
58
+ END
59
+ end
45
60
 
46
61
  # This adds a new hook type. It will define both a class
47
62
  # method that you can use to add hooks, as well as an instance method
@@ -75,11 +90,12 @@ module Sequel
75
90
  # Do not call this method with untrusted input, as that can result in
76
91
  # arbitrary code execution.
77
92
  def add_hook_type(*hooks)
93
+ Sequel::Deprecation.deprecate("Sequel::Model.add_hook_type", "You should add your own hook types manually")
78
94
  Model::HOOKS.concat(hooks)
79
95
  hooks.each do |hook|
80
96
  @hooks[hook] = []
81
97
  instance_eval("def #{hook}(method = nil, &block); add_hook(:#{hook}, method, &block) end", __FILE__, __LINE__)
82
- class_eval("def #{hook}; model.hook_blocks(:#{hook}){|b| return false if instance_eval(&b) == false}; end", __FILE__, __LINE__)
98
+ class_eval("def #{hook}; model.hook_blocks(:#{hook}){|b| return false if instance_eval(&b) == false} end", __FILE__, __LINE__)
83
99
  end
84
100
  end
85
101
 
@@ -125,7 +141,19 @@ module Sequel
125
141
  end
126
142
 
127
143
  module InstanceMethods
128
- (Model::BEFORE_HOOKS - [:before_save, :before_destroy]).each{|h| class_eval("def #{h}; model.hook_blocks(:#{h}){|b| return false if instance_eval(&b) == false}; super; end", __FILE__, __LINE__)}
144
+ (Model::BEFORE_HOOKS - [:before_save, :before_destroy]).each do |h|
145
+ class_eval(<<-END, __FILE__, __LINE__+1)
146
+ def #{h}
147
+ model.hook_blocks(:#{h}) do |b|
148
+ if instance_eval(&b) == false
149
+ Sequel::Deprecation.deprecate("Having #{h} hook block return false to stop evaluation of further #{h} hook blocks", "Instead, call cancel_action inside #{h} hook block")
150
+ return false
151
+ end
152
+ end
153
+ super
154
+ end
155
+ END
156
+ end
129
157
  (Model::AFTER_HOOKS - [:after_save, :after_destroy, :after_commit, :after_rollback, :after_destroy_commit, :after_destroy_rollback]).each{|h| class_eval("def #{h}; super; model.hook_blocks(:#{h}){|b| instance_eval(&b)}; end", __FILE__, __LINE__)}
130
158
 
131
159
  def after_destroy
@@ -146,7 +174,10 @@ module Sequel
146
174
 
147
175
  def before_destroy
148
176
  model.hook_blocks(:before_destroy) do |b|
149
- return false if instance_eval(&b) == false
177
+ if instance_eval(&b) == false
178
+ Sequel::Deprecation.deprecate("Having before_destory hook block return false to stop evaluation of further before_destroy hook blocks", "Instead, call cancel_action inside before_destroy hook block")
179
+ return false
180
+ end
150
181
  end
151
182
  super
152
183
  if model.has_hooks?(:after_destroy_rollback)
@@ -156,7 +187,10 @@ module Sequel
156
187
 
157
188
  def before_save
158
189
  model.hook_blocks(:before_save) do |b|
159
- return false if instance_eval(&b) == false
190
+ if instance_eval(&b) == false
191
+ Sequel::Deprecation.deprecate("Having before_save hook block return false to stop evaluation of further before_save hook blocks", "Instead, call cancel_action inside before_save hook block")
192
+ return false
193
+ end
160
194
  end
161
195
  super
162
196
  if model.has_hooks?(:after_rollback)
@@ -32,40 +32,88 @@ module Sequel
32
32
  BEFORE_HOOKS = Sequel::Model::BEFORE_HOOKS
33
33
  AFTER_HOOKS = Sequel::Model::AFTER_HOOKS
34
34
  HOOKS = BEFORE_HOOKS + AFTER_HOOKS
35
+ # SEQUEL5: Remove
36
+ DEPRECATION_REPLACEMENTS = {
37
+ :after_commit=>"Use obj.after_save_hook{obj.db.after_commit{}} instead",
38
+ :after_destroy_commit=>"Use obj.after_destroy_hook{obj.db.after_commit{}} instead",
39
+ :after_destroy_rollback=>"Use obj.before_destroy_hook{obj.db.after_rollback{}} instead",
40
+ :after_rollback=>"Use obj.before_save_hook{obj.db.after_rollback{}} instead"
41
+ }.freeze
35
42
 
36
43
  module InstanceMethods
37
44
  HOOKS.each{|h| class_eval(<<-END , __FILE__, __LINE__+1)}
38
45
  def #{h}_hook(&block)
46
+ #{"Sequel::Deprecation.deprecate('Sequel::Model##{h}_hook in the instance_hooks plugin', #{DEPRECATION_REPLACEMENTS[h].inspect})" if DEPRECATION_REPLACEMENTS[h]}
39
47
  raise Sequel::Error, "can't add hooks to frozen object" if frozen?
40
48
  add_instance_hook(:#{h}, &block)
41
49
  self
42
50
  end
43
51
  END
44
52
 
45
- BEFORE_HOOKS.each{|h| class_eval("def #{h}; run_before_instance_hooks(:#{h}) == false ? false : super end", __FILE__, __LINE__)}
46
- (AFTER_HOOKS - [:after_validation, :after_save]).each{|h| class_eval(<<-END, __FILE__, __LINE__ + 1)}
53
+ (BEFORE_HOOKS - [:before_destroy, :before_save]).each{|h| class_eval("def #{h}; (@instance_hooks && run_before_instance_hooks(:#{h}) == false) ? false : super end", __FILE__, __LINE__)}
54
+ (AFTER_HOOKS - [:after_validation, :after_save, :after_destroy, :after_commit, :after_destroy_commit, :after_destroy_rollback, :after_rollback]).each{|h| class_eval(<<-END, __FILE__, __LINE__ + 1)}
47
55
  def #{h}
48
56
  super
57
+ return unless @instance_hooks
49
58
  run_after_instance_hooks(:#{h})
50
59
  @instance_hooks.delete(:#{h})
51
60
  @instance_hooks.delete(:#{h.to_s.sub('after', 'before')})
52
61
  end
53
62
  END
54
63
 
55
- # Run after validation hooks, without clearing the validation hooks.
64
+ # Run after destroy instance hooks.
65
+ def after_destroy
66
+ super
67
+ return unless @instance_hooks
68
+ if ad = @instance_hooks[:after_destroy_commit]
69
+ db.after_commit{ad.each(&:call)}
70
+ end
71
+ run_after_instance_hooks(:after_destroy)
72
+ @instance_hooks.delete(:after_destroy)
73
+ @instance_hooks.delete(:before_destroy)
74
+ @instance_hooks.delete(:after_destroy_commit)
75
+ @instance_hooks.delete(:after_destroy_rollback)
76
+ end
77
+
78
+ # Run after validation instance hooks.
56
79
  def after_validation
57
80
  super
81
+ return unless @instance_hooks
58
82
  run_after_instance_hooks(:after_validation)
59
83
  end
60
84
 
61
- # Run after save hooks, clearing both the save and validation hooks.
85
+ # Run after save instance hooks.
62
86
  def after_save
63
87
  super
88
+ return unless @instance_hooks
89
+ if (ac = @instance_hooks[:after_commit])
90
+ db.after_commit{ac.each(&:call)}
91
+ end
64
92
  run_after_instance_hooks(:after_save)
65
93
  @instance_hooks.delete(:after_save)
66
94
  @instance_hooks.delete(:before_save)
67
95
  @instance_hooks.delete(:after_validation)
68
96
  @instance_hooks.delete(:before_validation)
97
+ @instance_hooks.delete(:after_commit)
98
+ @instance_hooks.delete(:after_rollback)
99
+ end
100
+
101
+ # Run before_destroy instance hooks.
102
+ def before_destroy
103
+ return super unless @instance_hooks
104
+ if adr = @instance_hooks[:after_destroy_rollback]
105
+ db.after_rollback{adr.each(&:call)}
106
+ end
107
+ run_before_instance_hooks(:before_destroy) == false ? false : super
108
+ end
109
+
110
+ # Run before_save instance hooks.
111
+ def before_save
112
+ return super unless @instance_hooks
113
+ if ar = @instance_hooks[:after_rollback]
114
+ db.after_rollback{ar.each(&:call)}
115
+ end
116
+ run_before_instance_hooks(:before_save) == false ? false : super
69
117
  end
70
118
 
71
119
  private
@@ -91,7 +139,12 @@ module Sequel
91
139
  # Run all hook blocks of the given hook type. If a hook block returns false,
92
140
  # immediately return false without running the remaining blocks.
93
141
  def run_before_instance_hooks(hook)
94
- instance_hooks(hook).each{|b| return false if b.call == false}
142
+ instance_hooks(hook).each do |b|
143
+ if b.call == false
144
+ Sequel::Deprecation.deprecate("Having #{hook} instance hook block return false to stop evaluation of further #{hook} instance hook blocks", "Instead, call cancel_action inside #{hook} instance hook block")
145
+ return false
146
+ end
147
+ end
95
148
  end
96
149
  end
97
150
  end
@@ -38,9 +38,14 @@ module Sequel
38
38
  end
39
39
 
40
40
  module ClassMethods
41
- # Module to store the lazy attribute getter methods, so they can
42
- # be overridden and call super to get the lazy attribute behavior
43
- attr_accessor :lazy_attributes_module
41
+ def lazy_attributes_module
42
+ Sequel::Deprecation.deprecate('Sequel::Model.lazy_attributes_module', 'There is no replacement')
43
+ @lazy_attributes_module
44
+ end
45
+ def lazy_attributes_module=(v)
46
+ Sequel::Deprecation.deprecate('Sequel::Model.lazy_attributes_module=', 'There is no replacement')
47
+ @lazy_attributes_module= v
48
+ end
44
49
 
45
50
  # Freeze lazy attributes module when freezing model class.
46
51
  def freeze
@@ -66,8 +71,8 @@ module Sequel
66
71
  # :dataset :: The base dataset to use for the lazy attribute lookup
67
72
  # :table :: The table name to use to qualify the attribute and primary key columns.
68
73
  def define_lazy_attribute_getter(a, opts=OPTS)
69
- include(self.lazy_attributes_module ||= Module.new) unless lazy_attributes_module
70
- lazy_attributes_module.class_eval do
74
+ include(@lazy_attributes_module ||= Module.new) unless @lazy_attributes_module
75
+ @lazy_attributes_module.class_eval do
71
76
  define_method(a) do
72
77
  if !values.has_key?(a) && !new?
73
78
  lazy_attribute_lookup(a, opts)
@@ -81,9 +81,14 @@ module Sequel
81
81
  end
82
82
 
83
83
  module ClassMethods
84
- # Module to store the nested_attributes setter methods, so they can
85
- # call be overridden and call super to get the default behavior
86
- attr_accessor :nested_attributes_module
84
+ def nested_attributes_module
85
+ Sequel::Deprecation.deprecate('Sequel::Model.nested_attributes_module', 'There is no replacement')
86
+ @nested_attributes_module
87
+ end
88
+ def nested_attributes_module=(v)
89
+ Sequel::Deprecation.deprecate('Sequel::Model.nested_attributes_module=', 'There is no replacement')
90
+ @nested_attributes_module = v
91
+ end
87
92
 
88
93
  # Freeze nested_attributes_module when freezing model class.
89
94
  def freeze
@@ -117,7 +122,7 @@ module Sequel
117
122
  #
118
123
  # If a block is provided, it is used to set the :reject_if option.
119
124
  def nested_attributes(*associations, &block)
120
- include(self.nested_attributes_module ||= Module.new) unless nested_attributes_module
125
+ include(@nested_attributes_module ||= Module.new) unless @nested_attributes_module
121
126
  opts = associations.last.is_a?(Hash) ? associations.pop : {}
122
127
  reflections = associations.map{|a| association_reflection(a) || raise(Error, "no association named #{a} for #{self}")}
123
128
  reflections.each do |r|
@@ -133,7 +138,7 @@ module Sequel
133
138
  # Add a nested attribute setter method to a module included in the
134
139
  # class.
135
140
  def def_nested_attribute_method(reflection)
136
- nested_attributes_module.class_eval do
141
+ @nested_attributes_module.class_eval do
137
142
  define_method("#{reflection[:name]}_attributes=") do |v|
138
143
  set_nested_attributes(reflection[:name], v)
139
144
  end
@@ -32,6 +32,7 @@ module Sequel
32
32
 
33
33
  # Setup the datastructure used to hold the prepared statements in the model.
34
34
  def self.apply(model)
35
+ # SEQUEL5: Drop Support for :fixed/:lookup_sql SQL
35
36
  model.instance_variable_set(:@prepared_statements, {:insert=>{}, :insert_select=>{}, :update=>{}, :lookup_sql=>{}, :fixed=>{}}.freeze)
36
37
  end
37
38
 
@@ -66,6 +67,7 @@ module Sequel
66
67
 
67
68
  # Return a prepared statement that can be used to delete a row from this model's dataset.
68
69
  def prepared_delete
70
+ # SEQUEL5: Remove
69
71
  cached_prepared_statement(:fixed, :delete){prepare_statement(filter(prepared_statement_key_array(primary_key)), :delete)}
70
72
  end
71
73
 
@@ -84,11 +86,13 @@ module Sequel
84
86
 
85
87
  # Return a prepared statement that can be used to lookup a row solely based on the primary key.
86
88
  def prepared_lookup
89
+ # SEQUEL5: Remove
87
90
  cached_prepared_statement(:fixed, :lookup){prepare_explicit_statement(filter(prepared_statement_key_array(primary_key)), :first)}
88
91
  end
89
92
 
90
93
  # Return a prepared statement that can be used to refresh a row to get new column values after insertion.
91
94
  def prepared_refresh
95
+ # SEQUEL5: Remove
92
96
  cached_prepared_statement(:fixed, :refresh){prepare_explicit_statement(naked.clone(:server=>dataset.opts.fetch(:server, :default)).where(prepared_statement_key_array(primary_key)), :first)}
93
97
  end
94
98
 
@@ -122,6 +126,7 @@ module Sequel
122
126
  # Use a prepared statement to query the database for the row matching the given primary key.
123
127
  def primary_key_lookup(pk)
124
128
  return super unless use_prepared_statements_for_pk_lookup?
129
+ # SEQUEL5: Remove
125
130
  prepared_lookup.call(primary_key_hash(pk))
126
131
  end
127
132
 
@@ -150,6 +155,7 @@ module Sequel
150
155
 
151
156
  # Use a prepared statement to delete the row.
152
157
  def _delete_without_checking
158
+ # SEQUEL5: Remove
153
159
  if use_prepared_statements_for?(:delete)
154
160
  _set_prepared_statement_server(model.send(:prepared_delete)).call(pk_hash)
155
161
  else
@@ -180,6 +186,7 @@ module Sequel
180
186
 
181
187
  # Use a prepared statement to refresh this model's column values.
182
188
  def _refresh_get(ds)
189
+ # SEQUEL5: Remove
183
190
  if use_prepared_statements_for?(:refresh)
184
191
  _set_prepared_statement_server(model.send(:prepared_refresh)).call(pk_hash)
185
192
  else