sequel 4.6.0 → 4.7.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|