sequel 4.6.0 → 4.7.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.
- checksums.yaml +4 -4
- data/CHANGELOG +32 -0
- data/doc/association_basics.rdoc +18 -0
- data/doc/migration.rdoc +30 -0
- data/doc/release_notes/4.7.0.txt +103 -0
- data/doc/security.rdoc +5 -0
- data/doc/sql.rdoc +21 -12
- data/doc/validations.rdoc +10 -2
- data/doc/virtual_rows.rdoc +22 -29
- data/lib/sequel/adapters/jdbc.rb +4 -1
- data/lib/sequel/adapters/jdbc/h2.rb +5 -0
- data/lib/sequel/adapters/odbc.rb +0 -1
- data/lib/sequel/adapters/postgres.rb +8 -1
- data/lib/sequel/adapters/shared/db2.rb +5 -0
- data/lib/sequel/adapters/shared/mssql.rb +1 -1
- data/lib/sequel/adapters/shared/oracle.rb +5 -0
- data/lib/sequel/adapters/shared/postgres.rb +5 -0
- data/lib/sequel/adapters/shared/sqlanywhere.rb +1 -1
- data/lib/sequel/adapters/shared/sqlite.rb +6 -1
- data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +1 -1
- data/lib/sequel/database/schema_methods.rb +1 -0
- data/lib/sequel/database/transactions.rb +11 -26
- data/lib/sequel/dataset/actions.rb +3 -3
- data/lib/sequel/dataset/features.rb +5 -0
- data/lib/sequel/dataset/sql.rb +16 -1
- data/lib/sequel/model/associations.rb +22 -7
- data/lib/sequel/model/base.rb +2 -2
- data/lib/sequel/plugins/auto_validations.rb +5 -1
- data/lib/sequel/plugins/instance_hooks.rb +21 -3
- data/lib/sequel/plugins/pg_array_associations.rb +21 -5
- data/lib/sequel/plugins/update_or_create.rb +60 -0
- data/lib/sequel/plugins/validation_helpers.rb +5 -2
- data/lib/sequel/sql.rb +55 -9
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/postgres_spec.rb +25 -4
- data/spec/core/database_spec.rb +1 -1
- data/spec/core/dataset_spec.rb +1 -1
- data/spec/core/expression_filters_spec.rb +53 -1
- data/spec/extensions/auto_validations_spec.rb +18 -0
- data/spec/extensions/instance_hooks_spec.rb +14 -0
- data/spec/extensions/pg_array_associations_spec.rb +40 -0
- data/spec/extensions/to_dot_spec.rb +1 -1
- data/spec/extensions/update_or_create_spec.rb +81 -0
- data/spec/extensions/validation_helpers_spec.rb +15 -11
- data/spec/integration/associations_test.rb +1 -1
- data/spec/integration/database_test.rb +8 -0
- data/spec/integration/dataset_test.rb +15 -10
- data/spec/integration/type_test.rb +4 -0
- data/spec/model/associations_spec.rb +20 -0
- data/spec/spec_config.rb +1 -1
- metadata +364 -360
@@ -382,6 +382,11 @@ module Sequel
|
|
382
382
|
end
|
383
383
|
end
|
384
384
|
|
385
|
+
# DB2 supports quoted function names.
|
386
|
+
def supports_quoted_function_names?
|
387
|
+
true
|
388
|
+
end
|
389
|
+
|
385
390
|
def _truncate_sql(table)
|
386
391
|
# "TRUNCATE #{table} IMMEDIATE" is only for newer version of db2, so we
|
387
392
|
# use the following one
|
@@ -301,7 +301,7 @@ module Sequel
|
|
301
301
|
end
|
302
302
|
|
303
303
|
DATABASE_ERROR_REGEXPS = {
|
304
|
-
/Violation of UNIQUE KEY constraint/ => UniqueConstraintViolation,
|
304
|
+
/Violation of UNIQUE KEY constraint|Violation of PRIMARY KEY constraint.+Cannot insert duplicate key/ => UniqueConstraintViolation,
|
305
305
|
/conflicted with the (FOREIGN KEY.*|REFERENCE) constraint/ => ForeignKeyConstraintViolation,
|
306
306
|
/conflicted with the CHECK constraint/ => CheckConstraintViolation,
|
307
307
|
/column does not allow nulls/ => NotNullConstraintViolation,
|
@@ -1485,6 +1485,11 @@ module Sequel
|
|
1485
1485
|
db.server_version(@opts[:server])
|
1486
1486
|
end
|
1487
1487
|
|
1488
|
+
# PostgreSQL supports quoted function names.
|
1489
|
+
def supports_quoted_function_names?
|
1490
|
+
true
|
1491
|
+
end
|
1492
|
+
|
1488
1493
|
# Concatenate the expressions with a space in between
|
1489
1494
|
def full_text_string_join(cols)
|
1490
1495
|
cols = Array(cols).map{|x| SQL::Function.new(:COALESCE, x, EMPTY_STRING)}
|
@@ -121,7 +121,7 @@ module Sequel
|
|
121
121
|
private
|
122
122
|
|
123
123
|
DATABASE_ERROR_REGEXPS = {
|
124
|
-
/would not be unique/ => Sequel::UniqueConstraintViolation,
|
124
|
+
/would not be unique|Primary key for table.+is not unique/ => Sequel::UniqueConstraintViolation,
|
125
125
|
/Column .* in table .* cannot be NULL/ => Sequel::NotNullConstraintViolation,
|
126
126
|
/Constraint .* violated: Invalid value in table .*/ => Sequel::CheckConstraintViolation,
|
127
127
|
/No primary key value for foreign key .* in table .*/ => Sequel::ForeignKeyConstraintViolation,
|
@@ -332,7 +332,7 @@ module Sequel
|
|
332
332
|
end
|
333
333
|
|
334
334
|
DATABASE_ERROR_REGEXPS = {
|
335
|
-
/is not unique\z/ => UniqueConstraintViolation,
|
335
|
+
/(is|are) not unique\z/ => UniqueConstraintViolation,
|
336
336
|
/foreign key constraint failed\z/ => ForeignKeyConstraintViolation,
|
337
337
|
/\A(SQLITE ERROR 19 \(CONSTRAINT\) : )?constraint failed\z/ => ConstraintViolation,
|
338
338
|
/may not be NULL\z/ => NotNullConstraintViolation,
|
@@ -692,6 +692,11 @@ module Sequel
|
|
692
692
|
super unless @opts[:lock] == :update
|
693
693
|
end
|
694
694
|
|
695
|
+
# SQLite supports quoted function names.
|
696
|
+
def supports_quoted_function_names?
|
697
|
+
true
|
698
|
+
end
|
699
|
+
|
695
700
|
# SQLite treats a DELETE with no WHERE clause as a TRUNCATE
|
696
701
|
def _truncate_sql(table)
|
697
702
|
"DELETE FROM #{table}"
|
@@ -26,7 +26,7 @@ module Sequel
|
|
26
26
|
sql = @opts[:append_sql] || ''
|
27
27
|
subselect_sql_append(sql, unlimited.
|
28
28
|
unordered.
|
29
|
-
select_append{ROW_NUMBER(:
|
29
|
+
select_append{ROW_NUMBER{}.over(:order=>order).as(rn)}.
|
30
30
|
from_self(:alias=>dsa1).
|
31
31
|
select(*columns).
|
32
32
|
limit(@opts[:limit]).
|
@@ -216,32 +216,17 @@ module Sequel
|
|
216
216
|
SQL_BEGIN
|
217
217
|
end
|
218
218
|
|
219
|
-
|
220
|
-
#
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
rollback_transaction(conn, opts)
|
231
|
-
false
|
232
|
-
else
|
233
|
-
commit_transaction(conn, opts)
|
234
|
-
true
|
235
|
-
end
|
236
|
-
end
|
237
|
-
end
|
238
|
-
# :nocov:
|
239
|
-
else
|
240
|
-
# Whether to commit the current transaction. On ruby 1.9 and JRuby,
|
241
|
-
# transactions will be committed if Thread#kill is used on an thread
|
242
|
-
# that has a transaction open, and there isn't a work around.
|
243
|
-
def commit_or_rollback_transaction(exception, conn, opts)
|
244
|
-
if exception
|
219
|
+
# Whether to commit the current transaction. Thread.current.status is
|
220
|
+
# checked because Thread#kill skips rescue blocks (so exception would be
|
221
|
+
# nil), but the transaction should still be rolled back. On Ruby 1.9 (but
|
222
|
+
# not 1.8 or 2.0), the thread status will still be "run", so Thread#kill
|
223
|
+
# will erroneously commit the transaction, and there isn't a workaround.
|
224
|
+
def commit_or_rollback_transaction(exception, conn, opts)
|
225
|
+
if exception
|
226
|
+
false
|
227
|
+
else
|
228
|
+
if Thread.current.status == 'aborting'
|
229
|
+
rollback_transaction(conn, opts)
|
245
230
|
false
|
246
231
|
else
|
247
232
|
commit_transaction(conn, opts)
|
@@ -102,14 +102,14 @@ module Sequel
|
|
102
102
|
if no_arg
|
103
103
|
if block
|
104
104
|
arg = Sequel.virtual_row(&block)
|
105
|
-
aggregate_dataset.get{count(arg).as(count)}
|
105
|
+
aggregate_dataset.get{count(arg).as(:count)}
|
106
106
|
else
|
107
|
-
aggregate_dataset.get{count
|
107
|
+
aggregate_dataset.get{count{}.*.as(:count)}.to_i
|
108
108
|
end
|
109
109
|
elsif block
|
110
110
|
raise Error, 'cannot provide both argument and block to Dataset#count'
|
111
111
|
else
|
112
|
-
aggregate_dataset.get{count(arg).as(count)}
|
112
|
+
aggregate_dataset.get{count(arg).as(:count)}
|
113
113
|
end
|
114
114
|
end
|
115
115
|
|
@@ -167,6 +167,11 @@ module Sequel
|
|
167
167
|
true
|
168
168
|
end
|
169
169
|
|
170
|
+
# Whether the database supports quoting function names, false by default.
|
171
|
+
def supports_quoted_function_names?
|
172
|
+
false
|
173
|
+
end
|
174
|
+
|
170
175
|
# Whether the RETURNING clause is used for the given dataset.
|
171
176
|
# +type+ can be :insert, :update, or :delete.
|
172
177
|
def uses_returning?(type)
|
data/lib/sequel/dataset/sql.rb
CHANGED
@@ -743,7 +743,22 @@ module Sequel
|
|
743
743
|
|
744
744
|
# Backbone of function_sql_append and emulated_function_sql_append.
|
745
745
|
def _function_sql_append(sql, name, args)
|
746
|
-
|
746
|
+
case name
|
747
|
+
when SQL::Identifier
|
748
|
+
if supports_quoted_function_names?
|
749
|
+
literal_append(sql, name)
|
750
|
+
else
|
751
|
+
sql << name.value.to_s
|
752
|
+
end
|
753
|
+
when SQL::QualifiedIdentifier
|
754
|
+
if supports_quoted_function_names?
|
755
|
+
literal_append(sql, name)
|
756
|
+
else
|
757
|
+
sql << split_qualifiers(name).join(DOT)
|
758
|
+
end
|
759
|
+
else
|
760
|
+
sql << name.to_s
|
761
|
+
end
|
747
762
|
if args.empty?
|
748
763
|
sql << FUNCTION_EMPTY
|
749
764
|
else
|
@@ -152,6 +152,12 @@ module Sequel
|
|
152
152
|
{filter_by_associations_conditions_key=>ds}
|
153
153
|
end
|
154
154
|
|
155
|
+
# Whether to handle silent modification failure when adding/removing
|
156
|
+
# associated records, false by default.
|
157
|
+
def handle_silent_modification_failure?
|
158
|
+
false
|
159
|
+
end
|
160
|
+
|
155
161
|
# The limit and offset for this association (returned as a two element array).
|
156
162
|
def limit_and_offset
|
157
163
|
if (v = self[:limit]).is_a?(Array)
|
@@ -479,6 +485,11 @@ module Sequel
|
|
479
485
|
:"#{underscore(demodulize(self[:model].name))}_id"
|
480
486
|
end
|
481
487
|
|
488
|
+
# Handle silent failure of add/remove methods if raise_on_save_failure is false.
|
489
|
+
def handle_silent_modification_failure?
|
490
|
+
self[:raise_on_save_failure] == false
|
491
|
+
end
|
492
|
+
|
482
493
|
# The hash key to use for the eager loading predicate (left side of IN (1, 2, 3))
|
483
494
|
def predicate_key
|
484
495
|
cached_fetch(:predicate_key){qualify_assoc(self[:key])}
|
@@ -975,6 +986,8 @@ module Sequel
|
|
975
986
|
# to the model method call, where :primary_key_column refers to the underlying column.
|
976
987
|
# Should only be used if the model method differs from the primary key column, in
|
977
988
|
# conjunction with defining a model alias method for the primary key column.
|
989
|
+
# :raise_on_save_failure :: Do not raise exceptions for hook or validation failures when saving associated
|
990
|
+
# objects in the add/remove methods (return nil instead) [one_to_many only].
|
978
991
|
# === :many_to_many
|
979
992
|
# :graph_join_table_block :: The block to pass to +join_table+ for
|
980
993
|
# the join table when eagerly loading the association via +eager_graph+.
|
@@ -1116,7 +1129,7 @@ module Sequel
|
|
1116
1129
|
def apply_window_function_eager_limit_strategy(ds, opts)
|
1117
1130
|
rn = ds.row_number_column
|
1118
1131
|
limit, offset = opts.limit_and_offset
|
1119
|
-
ds = ds.unordered.select_append{row_number(:
|
1132
|
+
ds = ds.unordered.select_append{row_number{}.over(:partition=>opts.predicate_key, :order=>ds.opts[:order]).as(rn)}.from_self
|
1120
1133
|
ds = if opts[:type] == :one_to_one
|
1121
1134
|
ds.where(rn => offset ? offset+1 : 1)
|
1122
1135
|
elsif offset
|
@@ -1426,7 +1439,7 @@ module Sequel
|
|
1426
1439
|
cks.each{|k| ck_nil_hash[k] = nil}
|
1427
1440
|
|
1428
1441
|
unless opts[:read_only]
|
1429
|
-
|
1442
|
+
save_opts = {:validate=>opts[:validate]}
|
1430
1443
|
|
1431
1444
|
if one_to_one
|
1432
1445
|
setter = opts[:setter] || proc do |o|
|
@@ -1437,21 +1450,23 @@ module Sequel
|
|
1437
1450
|
end
|
1438
1451
|
checked_transaction do
|
1439
1452
|
up_ds.update(ck_nil_hash)
|
1440
|
-
o.save(
|
1453
|
+
o.save(save_opts) || raise(Sequel::Error, "invalid associated object, cannot save") if o
|
1441
1454
|
end
|
1442
1455
|
end
|
1443
1456
|
association_module_private_def(opts._setter_method, opts, &setter)
|
1444
1457
|
association_module_def(opts.setter_method, opts){|o| set_one_to_one_associated_object(opts, o)}
|
1445
1458
|
else
|
1459
|
+
save_opts[:raise_on_failure] = opts[:raise_on_save_failure] != false
|
1460
|
+
|
1446
1461
|
adder = opts[:adder] || proc do |o|
|
1447
1462
|
cks.zip(cpks).each{|k, pk| o.send(:"#{k}=", send(pk))}
|
1448
|
-
o.save(
|
1463
|
+
o.save(save_opts)
|
1449
1464
|
end
|
1450
1465
|
association_module_private_def(opts._add_method, opts, &adder)
|
1451
1466
|
|
1452
1467
|
remover = opts[:remover] || proc do |o|
|
1453
1468
|
cks.each{|k| o.send(:"#{k}=", nil)}
|
1454
|
-
o.save(
|
1469
|
+
o.save(save_opts)
|
1455
1470
|
end
|
1456
1471
|
association_module_private_def(opts._remove_method, opts, &remover)
|
1457
1472
|
|
@@ -1590,7 +1605,7 @@ module Sequel
|
|
1590
1605
|
raise(Sequel::Error, "model object #{inspect} does not have a primary key") if opts.dataset_need_primary_key? && !pk
|
1591
1606
|
ensure_associated_primary_key(opts, o, *args)
|
1592
1607
|
return if run_association_callbacks(opts, :before_add, o) == false
|
1593
|
-
send(opts._add_method, o, *args)
|
1608
|
+
return if !send(opts._add_method, o, *args) && opts.handle_silent_modification_failure?
|
1594
1609
|
if array = associations[opts[:name]] and !array.include?(o)
|
1595
1610
|
array.push(o)
|
1596
1611
|
end
|
@@ -1699,7 +1714,7 @@ module Sequel
|
|
1699
1714
|
raise(Sequel::Error, "model object #{inspect} does not have a primary key") if opts.dataset_need_primary_key? && !pk
|
1700
1715
|
raise(Sequel::Error, "associated object #{o.inspect} does not have a primary key") if opts.need_associated_primary_key? && !o.pk
|
1701
1716
|
return if run_association_callbacks(opts, :before_remove, o) == false
|
1702
|
-
send(opts._remove_method, o, *args)
|
1717
|
+
return if !send(opts._remove_method, o, *args) && opts.handle_silent_modification_failure?
|
1703
1718
|
associations[opts[:name]].delete_if{|x| o === x} if associations.include?(opts[:name])
|
1704
1719
|
remove_reciprocal_object(opts, o)
|
1705
1720
|
run_association_callbacks(opts, :after_remove, o)
|
data/lib/sequel/model/base.rb
CHANGED
@@ -41,8 +41,8 @@ module Sequel
|
|
41
41
|
attr_reader :primary_key
|
42
42
|
|
43
43
|
# Whether to raise an error instead of returning nil on a failure
|
44
|
-
# to save/create/save_changes/
|
45
|
-
# a before_* hook returning false.
|
44
|
+
# to save/create/save_changes/update/destroy due to a validation failure or
|
45
|
+
# a before_* hook returning false (default: true).
|
46
46
|
attr_accessor :raise_on_save_failure
|
47
47
|
|
48
48
|
# Whether to raise an error when unable to typecast data for a column
|
@@ -136,7 +136,11 @@ module Sequel
|
|
136
136
|
|
137
137
|
validates_schema_types if model.auto_validate_types?
|
138
138
|
|
139
|
-
|
139
|
+
unique_opts = {}
|
140
|
+
if model.respond_to?(:sti_dataset)
|
141
|
+
unique_opts[:dataset] = model.sti_dataset
|
142
|
+
end
|
143
|
+
model.auto_validate_unique_columns.each{|cols| validates_unique(cols, unique_opts)}
|
140
144
|
end
|
141
145
|
end
|
142
146
|
end
|
@@ -4,7 +4,7 @@ module Sequel
|
|
4
4
|
# by passing a block to a _hook method (e.g. before_save_hook{do_something}).
|
5
5
|
# The block is executed when the hook is called (e.g. before_save).
|
6
6
|
#
|
7
|
-
# All of the standard hooks are supported
|
7
|
+
# All of the standard hooks are supported.
|
8
8
|
# Instance level before hooks are executed in reverse order of addition before
|
9
9
|
# calling super. Instance level after hooks are executed in order of addition
|
10
10
|
# after calling super. If any of the instance level before hook blocks return
|
@@ -16,6 +16,8 @@ module Sequel
|
|
16
16
|
# be run the first time you save the object (creating it), and the before_update
|
17
17
|
# hook will be run the second time you save the object (updating it), and no
|
18
18
|
# hooks will be run the third time you save the object.
|
19
|
+
#
|
20
|
+
# Validation hooks are not cleared until after a successful save.
|
19
21
|
#
|
20
22
|
# Usage:
|
21
23
|
#
|
@@ -27,7 +29,7 @@ module Sequel
|
|
27
29
|
module InstanceHooks
|
28
30
|
module InstanceMethods
|
29
31
|
BEFORE_HOOKS = Sequel::Model::BEFORE_HOOKS
|
30
|
-
AFTER_HOOKS = Sequel::Model::AFTER_HOOKS
|
32
|
+
AFTER_HOOKS = Sequel::Model::AFTER_HOOKS
|
31
33
|
HOOKS = BEFORE_HOOKS + AFTER_HOOKS
|
32
34
|
HOOKS.each{|h| class_eval(<<-END , __FILE__, __LINE__+1)}
|
33
35
|
def #{h}_hook(&block)
|
@@ -38,7 +40,7 @@ module Sequel
|
|
38
40
|
END
|
39
41
|
|
40
42
|
BEFORE_HOOKS.each{|h| class_eval("def #{h}; run_before_instance_hooks(:#{h}) == false ? false : super end", __FILE__, __LINE__)}
|
41
|
-
AFTER_HOOKS.each{|h| class_eval(<<-END, __FILE__, __LINE__ + 1)}
|
43
|
+
(AFTER_HOOKS - [:after_validation, :after_save]).each{|h| class_eval(<<-END, __FILE__, __LINE__ + 1)}
|
42
44
|
def #{h}
|
43
45
|
super
|
44
46
|
run_after_instance_hooks(:#{h})
|
@@ -46,6 +48,22 @@ module Sequel
|
|
46
48
|
@instance_hooks.delete(:#{h.to_s.sub('after', 'before')})
|
47
49
|
end
|
48
50
|
END
|
51
|
+
|
52
|
+
# Run after validation hooks, without clearing the validation hooks.
|
53
|
+
def after_validation
|
54
|
+
super
|
55
|
+
run_after_instance_hooks(:after_validation)
|
56
|
+
end
|
57
|
+
|
58
|
+
# Run after save hooks, clearing both the save and validation hooks.
|
59
|
+
def after_save
|
60
|
+
super
|
61
|
+
run_after_instance_hooks(:after_save)
|
62
|
+
@instance_hooks.delete(:after_save)
|
63
|
+
@instance_hooks.delete(:before_save)
|
64
|
+
@instance_hooks.delete(:after_validation)
|
65
|
+
@instance_hooks.delete(:before_validation)
|
66
|
+
end
|
49
67
|
|
50
68
|
private
|
51
69
|
|
@@ -52,6 +52,8 @@ module Sequel
|
|
52
52
|
# such as when this plugin needs to create an array type,
|
53
53
|
# and typecasting is turned off or not setup correctly
|
54
54
|
# for the model object.
|
55
|
+
# :raise_on_save_failure :: Do not raise exceptions for hook or validation failures when saving associated
|
56
|
+
# objects in the add/remove methods (return nil instead).
|
55
57
|
# :save_after_modify :: For pg_array_to_many associations, this makes the
|
56
58
|
# the modification methods save the current object,
|
57
59
|
# so they operate more similarly to the one_to_many
|
@@ -93,6 +95,11 @@ module Sequel
|
|
93
95
|
:"#{underscore(demodulize(self[:model].name))}_ids"
|
94
96
|
end
|
95
97
|
|
98
|
+
# Handle silent failure of add/remove methods if raise_on_save_failure is false.
|
99
|
+
def handle_silent_modification_failure?
|
100
|
+
self[:raise_on_save_failure] == false
|
101
|
+
end
|
102
|
+
|
96
103
|
# The hash key to use for the eager loading predicate (left side of IN (1, 2, 3))
|
97
104
|
def predicate_key
|
98
105
|
cached_fetch(:predicate_key){qualify_assoc(self[:key_column])}
|
@@ -159,6 +166,12 @@ module Sequel
|
|
159
166
|
:"#{singularize(self[:name])}_ids"
|
160
167
|
end
|
161
168
|
|
169
|
+
# Handle silent failure of add/remove methods if raise_on_save_failure is false
|
170
|
+
# and save_after_modify is true.
|
171
|
+
def handle_silent_modification_failure?
|
172
|
+
self[:raise_on_save_failure] == false && self[:save_after_modify]
|
173
|
+
end
|
174
|
+
|
162
175
|
# A qualified version of the associated primary key.
|
163
176
|
def predicate_key
|
164
177
|
cached_fetch(:predicate_key){qualify_assoc(primary_key)}
|
@@ -286,7 +299,8 @@ module Sequel
|
|
286
299
|
def_association_dataset_methods(opts)
|
287
300
|
|
288
301
|
unless opts[:read_only]
|
289
|
-
|
302
|
+
save_opts = {:validate=>opts[:validate]}
|
303
|
+
save_opts[:raise_on_failure] = opts[:raise_on_save_failure] != false
|
290
304
|
|
291
305
|
array_type = opts[:array_type] ||= :integer
|
292
306
|
adder = opts[:adder] || proc do |o|
|
@@ -295,14 +309,14 @@ module Sequel
|
|
295
309
|
else
|
296
310
|
o.send("#{key}=", Sequel.pg_array([send(pk)], array_type))
|
297
311
|
end
|
298
|
-
o.save(
|
312
|
+
o.save(save_opts)
|
299
313
|
end
|
300
314
|
association_module_private_def(opts._add_method, opts, &adder)
|
301
315
|
|
302
316
|
remover = opts[:remover] || proc do |o|
|
303
317
|
if (array = o.send(key)) && !array.empty?
|
304
318
|
array.delete(send(pk))
|
305
|
-
o.save(
|
319
|
+
o.save(save_opts)
|
306
320
|
end
|
307
321
|
end
|
308
322
|
association_module_private_def(opts._remove_method, opts, &remover)
|
@@ -388,11 +402,13 @@ module Sequel
|
|
388
402
|
def_association_dataset_methods(opts)
|
389
403
|
|
390
404
|
unless opts[:read_only]
|
391
|
-
|
405
|
+
save_opts = {:validate=>opts[:validate]}
|
406
|
+
save_opts[:raise_on_failure] = opts[:raise_on_save_failure] != false
|
392
407
|
array_type = opts[:array_type] ||= :integer
|
408
|
+
|
393
409
|
if opts[:save_after_modify]
|
394
410
|
save_after_modify = proc do |obj|
|
395
|
-
obj.save(
|
411
|
+
obj.save(save_opts)
|
396
412
|
end
|
397
413
|
end
|
398
414
|
|