sequel 4.44.0 → 4.45.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +110 -0
- data/README.rdoc +8 -9
- data/doc/active_record.rdoc +2 -3
- data/doc/model_plugins.rdoc +1 -1
- data/doc/opening_databases.rdoc +0 -46
- data/doc/release_notes/4.45.0.txt +370 -0
- data/lib/sequel/adapters/cubrid.rb +2 -0
- data/lib/sequel/adapters/do.rb +2 -0
- data/lib/sequel/adapters/jdbc/as400.rb +2 -0
- data/lib/sequel/adapters/jdbc/cubrid.rb +2 -0
- data/lib/sequel/adapters/jdbc/firebirdsql.rb +2 -0
- data/lib/sequel/adapters/jdbc/informix-sqli.rb +2 -0
- data/lib/sequel/adapters/jdbc/jdbcprogress.rb +2 -0
- data/lib/sequel/adapters/jdbc/mysql.rb +1 -0
- data/lib/sequel/adapters/jdbc/postgresql.rb +5 -0
- data/lib/sequel/adapters/mysql.rb +1 -0
- data/lib/sequel/adapters/mysql2.rb +1 -0
- data/lib/sequel/adapters/odbc/oracle.rb +11 -0
- data/lib/sequel/adapters/odbc/progress.rb +2 -0
- data/lib/sequel/adapters/postgres.rb +0 -2
- data/lib/sequel/adapters/shared/cubrid.rb +2 -0
- data/lib/sequel/adapters/shared/firebird.rb +2 -0
- data/lib/sequel/adapters/shared/informix.rb +2 -0
- data/lib/sequel/adapters/shared/mssql.rb +47 -7
- data/lib/sequel/adapters/shared/mysql.rb +16 -1
- data/lib/sequel/adapters/shared/postgres.rb +9 -1
- data/lib/sequel/adapters/shared/progress.rb +2 -0
- data/lib/sequel/adapters/shared/sqlanywhere.rb +1 -1
- data/lib/sequel/adapters/swift.rb +2 -0
- data/lib/sequel/ast_transformer.rb +13 -6
- data/lib/sequel/core.rb +13 -16
- data/lib/sequel/database/connecting.rb +25 -10
- data/lib/sequel/database/dataset.rb +6 -1
- data/lib/sequel/database/dataset_defaults.rb +9 -2
- data/lib/sequel/database/misc.rb +10 -3
- data/lib/sequel/database/schema_methods.rb +4 -0
- data/lib/sequel/dataset/mutation.rb +8 -20
- data/lib/sequel/dataset/prepared_statements.rb +2 -0
- data/lib/sequel/dataset/query.rb +32 -7
- data/lib/sequel/dataset/sql.rb +13 -3
- data/lib/sequel/deprecated.rb +9 -1
- data/lib/sequel/exceptions.rb +37 -8
- data/lib/sequel/extensions/_deprecated_identifier_mangling.rb +117 -0
- data/lib/sequel/extensions/date_arithmetic.rb +1 -0
- data/lib/sequel/extensions/identifier_mangling.rb +3 -2
- data/lib/sequel/extensions/pg_hstore.rb +1 -5
- data/lib/sequel/extensions/schema_dumper.rb +3 -1
- data/lib/sequel/extensions/sequel_3_dataset_methods.rb +2 -2
- data/lib/sequel/extensions/string_agg.rb +1 -0
- data/lib/sequel/model.rb +23 -10
- data/lib/sequel/model/associations.rb +17 -5
- data/lib/sequel/model/base.rb +115 -62
- data/lib/sequel/model/dataset_module.rb +10 -3
- data/lib/sequel/model/exceptions.rb +7 -5
- data/lib/sequel/plugins/association_pks.rb +13 -1
- data/lib/sequel/plugins/association_proxies.rb +8 -1
- data/lib/sequel/plugins/before_after_save.rb +1 -0
- data/lib/sequel/plugins/class_table_inheritance.rb +7 -3
- data/lib/sequel/plugins/columns_updated.rb +42 -0
- data/lib/sequel/plugins/composition.rb +10 -5
- data/lib/sequel/plugins/error_splitter.rb +1 -1
- data/lib/sequel/plugins/hook_class_methods.rb +39 -5
- data/lib/sequel/plugins/instance_hooks.rb +58 -5
- data/lib/sequel/plugins/lazy_attributes.rb +10 -5
- data/lib/sequel/plugins/nested_attributes.rb +10 -5
- data/lib/sequel/plugins/prepared_statements.rb +7 -0
- data/lib/sequel/plugins/prepared_statements_associations.rb +2 -0
- data/lib/sequel/plugins/prepared_statements_with_pk.rb +2 -0
- data/lib/sequel/plugins/schema.rb +2 -0
- data/lib/sequel/plugins/scissors.rb +2 -0
- data/lib/sequel/plugins/serialization.rb +10 -5
- data/lib/sequel/plugins/split_values.rb +5 -1
- data/lib/sequel/plugins/static_cache.rb +2 -2
- data/lib/sequel/plugins/tactical_eager_loading.rb +1 -1
- data/lib/sequel/plugins/validation_contexts.rb +49 -0
- data/lib/sequel/plugins/validation_helpers.rb +1 -0
- data/lib/sequel/sql.rb +1 -1
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/mssql_spec.rb +31 -0
- data/spec/adapters/mysql_spec.rb +20 -2
- data/spec/adapters/postgres_spec.rb +43 -12
- data/spec/adapters/spec_helper.rb +5 -8
- data/spec/core/database_spec.rb +47 -12
- data/spec/core/dataset_mutation_spec.rb +22 -22
- data/spec/core/dataset_spec.rb +88 -20
- data/spec/core/deprecated_spec.rb +1 -1
- data/spec/core/expression_filters_spec.rb +1 -1
- data/spec/core/mock_adapter_spec.rb +0 -3
- data/spec/core/placeholder_literalizer_spec.rb +1 -1
- data/spec/core/schema_spec.rb +8 -1
- data/spec/core/spec_helper.rb +6 -1
- data/spec/core_extensions_spec.rb +4 -0
- data/spec/deprecation_helper.rb +17 -0
- data/spec/extensions/_deprecated_identifier_mangling_spec.rb +314 -0
- data/spec/extensions/association_pks_spec.rb +61 -13
- data/spec/extensions/association_proxies_spec.rb +3 -3
- data/spec/extensions/class_table_inheritance_spec.rb +39 -0
- data/spec/extensions/columns_updated_spec.rb +35 -0
- data/spec/extensions/composition_spec.rb +6 -1
- data/spec/extensions/hook_class_methods_spec.rb +114 -26
- data/spec/extensions/identifier_mangling_spec.rb +107 -73
- data/spec/extensions/instance_hooks_spec.rb +78 -14
- data/spec/extensions/lazy_attributes_spec.rb +8 -2
- data/spec/extensions/many_through_many_spec.rb +2 -2
- data/spec/extensions/mssql_optimistic_locking_spec.rb +1 -1
- data/spec/extensions/nested_attributes_spec.rb +8 -2
- data/spec/extensions/pg_array_spec.rb +18 -4
- data/spec/extensions/prepared_statements_associations_spec.rb +48 -39
- data/spec/extensions/prepared_statements_with_pk_spec.rb +13 -11
- data/spec/extensions/query_spec.rb +1 -1
- data/spec/extensions/schema_dumper_spec.rb +34 -6
- data/spec/extensions/schema_spec.rb +13 -7
- data/spec/extensions/scissors_spec.rb +3 -1
- data/spec/extensions/sequel_3_dataset_methods_spec.rb +4 -4
- data/spec/extensions/serialization_spec.rb +7 -1
- data/spec/extensions/set_overrides_spec.rb +2 -2
- data/spec/extensions/shared_caching_spec.rb +19 -15
- data/spec/extensions/spec_helper.rb +7 -3
- data/spec/extensions/split_values_spec.rb +45 -10
- data/spec/extensions/string_agg_spec.rb +2 -2
- data/spec/extensions/subset_conditions_spec.rb +3 -3
- data/spec/extensions/tactical_eager_loading_spec.rb +1 -1
- data/spec/extensions/validation_contexts_spec.rb +31 -0
- data/spec/guards_helper.rb +2 -0
- data/spec/integration/associations_test.rb +22 -20
- data/spec/integration/dataset_test.rb +25 -2
- data/spec/integration/model_test.rb +1 -1
- data/spec/integration/plugin_test.rb +11 -16
- data/spec/integration/prepared_statement_test.rb +40 -32
- data/spec/integration/spec_helper.rb +5 -8
- data/spec/model/association_reflection_spec.rb +4 -0
- data/spec/model/associations_spec.rb +37 -10
- data/spec/model/base_spec.rb +6 -0
- data/spec/model/hooks_spec.rb +56 -35
- data/spec/model/model_spec.rb +21 -5
- data/spec/model/record_spec.rb +14 -11
- data/spec/model/spec_helper.rb +7 -1
- data/spec/sequel_warning.rb +11 -0
- 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
|
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?
|
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
|
@@ -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
|
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
|
-
|
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
|
-
|
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
|
-
|
73
|
-
|
74
|
-
|
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
|
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}
|
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
|
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
|
-
|
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
|
-
|
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
|
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
|
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
|
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
|
-
|
42
|
-
|
43
|
-
|
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(
|
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
|
-
|
85
|
-
|
86
|
-
|
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(
|
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
|