sequel 5.107.0 → 5.109.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/bin/sequel +5 -5
- data/lib/sequel/adapters/ado.rb +1 -1
- data/lib/sequel/adapters/amalgalite.rb +34 -8
- data/lib/sequel/adapters/ibmdb.rb +2 -2
- data/lib/sequel/adapters/jdbc/hsqldb.rb +1 -1
- data/lib/sequel/adapters/jdbc/mssql.rb +28 -5
- data/lib/sequel/adapters/jdbc/mysql.rb +1 -1
- data/lib/sequel/adapters/jdbc/postgresql.rb +14 -3
- data/lib/sequel/adapters/jdbc.rb +4 -3
- data/lib/sequel/adapters/mock.rb +1 -1
- data/lib/sequel/adapters/mysql.rb +7 -2
- data/lib/sequel/adapters/mysql2.rb +5 -4
- data/lib/sequel/adapters/postgres.rb +42 -39
- data/lib/sequel/adapters/shared/db2.rb +5 -2
- data/lib/sequel/adapters/shared/mssql.rb +11 -5
- data/lib/sequel/adapters/shared/mysql.rb +2 -2
- data/lib/sequel/adapters/shared/postgres.rb +80 -1028
- data/lib/sequel/adapters/shared/sqlanywhere.rb +0 -32
- data/lib/sequel/adapters/shared/sqlite.rb +3 -3
- data/lib/sequel/adapters/sqlite.rb +13 -9
- data/lib/sequel/adapters/trilogy.rb +2 -1
- data/lib/sequel/adapters/utils/emulate_offset_with_reverse_and_count.rb +1 -1
- data/lib/sequel/adapters/utils/mysql_mysql2.rb +11 -1
- data/lib/sequel/connection_pool/sharded_single.rb +1 -1
- data/lib/sequel/connection_pool/sharded_threaded.rb +7 -5
- data/lib/sequel/connection_pool/sharded_timed_queue.rb +3 -3
- data/lib/sequel/connection_pool/threaded.rb +9 -7
- data/lib/sequel/connection_pool/timed_queue.rb +2 -2
- data/lib/sequel/connection_pool.rb +3 -3
- data/lib/sequel/core.rb +44 -24
- data/lib/sequel/database/connecting.rb +1 -1
- data/lib/sequel/database/features.rb +1 -1
- data/lib/sequel/database/misc.rb +6 -11
- data/lib/sequel/database/query.rb +2 -2
- data/lib/sequel/database/schema_generator.rb +4 -4
- data/lib/sequel/database/schema_methods.rb +2 -2
- data/lib/sequel/database/transactions.rb +5 -7
- data/lib/sequel/dataset/actions.rb +2 -2
- data/lib/sequel/dataset/features.rb +4 -4
- data/lib/sequel/dataset/graph.rb +1 -1
- data/lib/sequel/dataset/misc.rb +3 -3
- data/lib/sequel/dataset/prepared_statements.rb +2 -2
- data/lib/sequel/dataset/query.rb +8 -8
- data/lib/sequel/dataset/sql.rb +32 -13
- data/lib/sequel/dataset.rb +2 -2
- data/lib/sequel/deprecated.rb +2 -2
- data/lib/sequel/exceptions.rb +2 -2
- data/lib/sequel/extensions/_pretty_table.rb +1 -1
- data/lib/sequel/extensions/async_thread_pool.rb +3 -3
- data/lib/sequel/extensions/auto_cast_date_and_time.rb +2 -2
- data/lib/sequel/extensions/blank.rb +2 -2
- data/lib/sequel/extensions/constraint_validations.rb +1 -1
- data/lib/sequel/extensions/core_refinements.rb +7 -10
- data/lib/sequel/extensions/date_arithmetic.rb +1 -1
- data/lib/sequel/extensions/datetime_parse_to_time.rb +2 -2
- data/lib/sequel/extensions/duplicate_columns_handler.rb +1 -3
- data/lib/sequel/extensions/graph_each.rb +1 -1
- data/lib/sequel/extensions/index_caching.rb +1 -1
- data/lib/sequel/extensions/inflector.rb +5 -5
- data/lib/sequel/extensions/is_distinct_from.rb +2 -2
- data/lib/sequel/extensions/lit_require_frozen.rb +20 -4
- data/lib/sequel/extensions/migration.rb +21 -7
- data/lib/sequel/extensions/named_timezones.rb +9 -9
- data/lib/sequel/extensions/pg_array.rb +10 -8
- data/lib/sequel/extensions/pg_array_ops.rb +69 -14
- data/lib/sequel/extensions/pg_auto_parameterize.rb +2 -2
- data/lib/sequel/extensions/pg_auto_parameterize_in_array.rb +3 -3
- data/lib/sequel/extensions/pg_enum.rb +2 -2
- data/lib/sequel/extensions/pg_extended_date_support.rb +5 -5
- data/lib/sequel/extensions/pg_extended_integer_support.rb +1 -1
- data/lib/sequel/extensions/pg_hstore.rb +2 -2
- data/lib/sequel/extensions/pg_hstore_ops.rb +5 -5
- data/lib/sequel/extensions/pg_inet.rb +2 -2
- data/lib/sequel/extensions/pg_inet_ops.rb +2 -2
- data/lib/sequel/extensions/pg_interval.rb +6 -6
- data/lib/sequel/extensions/pg_json.rb +4 -4
- data/lib/sequel/extensions/pg_json_ops.rb +15 -13
- data/lib/sequel/extensions/pg_range.rb +6 -6
- data/lib/sequel/extensions/pg_range_ops.rb +7 -7
- data/lib/sequel/extensions/pg_row.rb +4 -4
- data/lib/sequel/extensions/pg_row_ops.rb +6 -6
- data/lib/sequel/extensions/provenance.rb +2 -2
- data/lib/sequel/extensions/query.rb +2 -2
- data/lib/sequel/extensions/s.rb +6 -10
- data/lib/sequel/extensions/schema_dumper.rb +10 -6
- data/lib/sequel/extensions/sequel_4_dataset_methods.rb +2 -0
- data/lib/sequel/extensions/sql_comments.rb +1 -1
- data/lib/sequel/extensions/sql_log_normalizer.rb +1 -1
- data/lib/sequel/extensions/sqlite_json_ops.rb +2 -2
- data/lib/sequel/extensions/string_agg.rb +5 -5
- data/lib/sequel/extensions/symbol_aref.rb +12 -32
- data/lib/sequel/extensions/symbol_aref_refinement.rb +2 -5
- data/lib/sequel/extensions/symbol_as.rb +1 -2
- data/lib/sequel/extensions/symbol_as_refinement.rb +1 -5
- data/lib/sequel/extensions/transaction_connection_validator.rb +1 -1
- data/lib/sequel/model/associations.rb +17 -17
- data/lib/sequel/model/base.rb +18 -15
- data/lib/sequel/model/inflections.rb +1 -1
- data/lib/sequel/model/plugins.rb +2 -2
- data/lib/sequel/model.rb +2 -2
- data/lib/sequel/plugins/association_pks.rb +1 -1
- data/lib/sequel/plugins/association_proxies.rb +4 -4
- data/lib/sequel/plugins/auto_restrict_eager_graph.rb +2 -0
- data/lib/sequel/plugins/caching.rb +28 -3
- data/lib/sequel/plugins/class_table_inheritance.rb +1 -1
- data/lib/sequel/plugins/column_encryption.rb +10 -10
- data/lib/sequel/plugins/concurrent_eager_loading.rb +2 -2
- data/lib/sequel/plugins/csv_serializer.rb +9 -20
- data/lib/sequel/plugins/deprecated_associations.rb +2 -2
- data/lib/sequel/plugins/eager_each.rb +1 -1
- data/lib/sequel/plugins/finder.rb +1 -1
- data/lib/sequel/plugins/forbid_lazy_load.rb +3 -3
- data/lib/sequel/plugins/insert_conflict.rb +1 -1
- data/lib/sequel/plugins/insert_returning_select.rb +1 -1
- data/lib/sequel/plugins/instance_filters.rb +8 -0
- data/lib/sequel/plugins/instance_hooks.rb +19 -0
- data/lib/sequel/plugins/json_serializer.rb +4 -4
- data/lib/sequel/plugins/lazy_attributes.rb +1 -1
- data/lib/sequel/plugins/many_through_many.rb +1 -1
- data/lib/sequel/plugins/mssql_optimistic_locking.rb +9 -0
- data/lib/sequel/plugins/optimistic_locking.rb +12 -2
- data/lib/sequel/plugins/optimistic_locking_base.rb +14 -0
- data/lib/sequel/plugins/pg_array_associations.rb +4 -4
- data/lib/sequel/plugins/pg_auto_constraint_validations.rb +3 -3
- data/lib/sequel/plugins/pg_eager_any_typed_array.rb +2 -2
- data/lib/sequel/plugins/pg_xmin_optimistic_locking.rb +11 -2
- data/lib/sequel/plugins/prepared_statements.rb +2 -2
- data/lib/sequel/plugins/select_on_skipped_update.rb +63 -0
- data/lib/sequel/plugins/serialization.rb +1 -1
- data/lib/sequel/plugins/sharding.rb +1 -1
- data/lib/sequel/plugins/single_table_inheritance.rb +21 -3
- data/lib/sequel/plugins/skip_saving_columns.rb +2 -2
- data/lib/sequel/plugins/split_values.rb +1 -1
- data/lib/sequel/plugins/sql_comments.rb +8 -8
- data/lib/sequel/plugins/subclasses.rb +6 -6
- data/lib/sequel/plugins/subset_conditions.rb +5 -16
- data/lib/sequel/plugins/tactical_eager_loading.rb +1 -1
- data/lib/sequel/plugins/throw_failures.rb +3 -3
- data/lib/sequel/plugins/unused_associations.rb +5 -5
- data/lib/sequel/plugins/validate_associated.rb +7 -1
- data/lib/sequel/plugins/validate_associated_context.rb +52 -0
- data/lib/sequel/plugins/validation_helpers.rb +1 -1
- data/lib/sequel/plugins/xml_serializer.rb +2 -0
- data/lib/sequel/sql.rb +120 -116
- data/lib/sequel/version.rb +1 -1
- metadata +5 -3
|
@@ -5,7 +5,7 @@ module Sequel
|
|
|
5
5
|
# The lazy_attributes plugin allows users to easily set that some attributes
|
|
6
6
|
# should not be loaded by default when loading model objects. If the attribute
|
|
7
7
|
# is needed after the instance has been retrieved, a database query is made to
|
|
8
|
-
#
|
|
8
|
+
# retrieve the value of the attribute.
|
|
9
9
|
#
|
|
10
10
|
# This plugin depends on the tactical_eager_loading plugin, and allows you to
|
|
11
11
|
# eagerly load lazy attributes for all objects retrieved with the current object.
|
|
@@ -243,7 +243,7 @@ module Sequel
|
|
|
243
243
|
# :conditions :: Extra conditions to add to the JOIN ON clause. Must be a hash or array of two pairs.
|
|
244
244
|
# :join_type :: The join type to use for the join, defaults to :left_outer.
|
|
245
245
|
# :only_conditions :: Conditions to use for the join instead of the ones specified by the keys.
|
|
246
|
-
# opts :: The options for the
|
|
246
|
+
# opts :: The options for the association. Takes the same options as many_to_many.
|
|
247
247
|
def many_through_many(name, through, opts=OPTS, &block)
|
|
248
248
|
associate(:many_through_many, name, opts.merge(through.is_a?(Hash) ? through : {:through=>through}), &block)
|
|
249
249
|
end
|
|
@@ -22,6 +22,13 @@ module Sequel
|
|
|
22
22
|
#
|
|
23
23
|
# plugin :mssql_optimistic_locking, lock_column: :column_name
|
|
24
24
|
#
|
|
25
|
+
# By default, the plugin allows using the lock column setter method to
|
|
26
|
+
# either increase or decrease the lock column value. To prevent increases,
|
|
27
|
+
# which could potentially be used to skip an update when it update should
|
|
28
|
+
# be made, you can use the +:prevent_increase+ plugin option:
|
|
29
|
+
#
|
|
30
|
+
# plugin :mssql_optimistic_locking, prevent_increase: true
|
|
31
|
+
#
|
|
25
32
|
# This plugin relies on the instance_filters plugin.
|
|
26
33
|
module MssqlOptimisticLocking
|
|
27
34
|
# Load the instance_filters plugin into the model.
|
|
@@ -32,6 +39,8 @@ module Sequel
|
|
|
32
39
|
# Set the lock column
|
|
33
40
|
def self.configure(model, opts=OPTS)
|
|
34
41
|
model.lock_column = opts[:lock_column] || model.lock_column || :timestamp
|
|
42
|
+
# SEQUEL6: Make prevent_increase true by default
|
|
43
|
+
model.send(:prevent_lock_column_increase!) if opts[:prevent_increase]
|
|
35
44
|
end
|
|
36
45
|
|
|
37
46
|
module InstanceMethods
|
|
@@ -20,6 +20,13 @@ module Sequel
|
|
|
20
20
|
#
|
|
21
21
|
# plugin :optimistic_locking, lock_column: :version
|
|
22
22
|
#
|
|
23
|
+
# By default, the plugin allows using the lock column setter method to
|
|
24
|
+
# either increase or decrease the lock column value. To prevent increases,
|
|
25
|
+
# which could potentially be used to skip an update when it update should
|
|
26
|
+
# be made, you can use the +:prevent_increase+ plugin option:
|
|
27
|
+
#
|
|
28
|
+
# plugin :optimistic_locking, prevent_increase: true
|
|
29
|
+
#
|
|
23
30
|
# This plugin relies on the instance_filters plugin.
|
|
24
31
|
module OptimisticLocking
|
|
25
32
|
# Exception class raised when trying to update or destroy a stale object.
|
|
@@ -32,6 +39,8 @@ module Sequel
|
|
|
32
39
|
# Set the lock column
|
|
33
40
|
def self.configure(model, opts=OPTS)
|
|
34
41
|
model.lock_column = opts[:lock_column] || model.lock_column || :lock_version
|
|
42
|
+
# SEQUEL6: Make prevent_increase true by default
|
|
43
|
+
model.send(:prevent_lock_column_increase!) if opts[:prevent_increase]
|
|
35
44
|
end
|
|
36
45
|
|
|
37
46
|
module InstanceMethods
|
|
@@ -42,9 +51,10 @@ module Sequel
|
|
|
42
51
|
def _update_columns(columns)
|
|
43
52
|
lc = model.lock_column
|
|
44
53
|
lcv = get_column_value(lc)
|
|
45
|
-
columns[lc] = lcv + 1
|
|
54
|
+
new_lcv = columns[lc] = lcv + 1
|
|
46
55
|
super
|
|
47
|
-
set_column_value("#{lc}=",
|
|
56
|
+
set_column_value("#{lc}=", nil)
|
|
57
|
+
set_column_value("#{lc}=", new_lcv)
|
|
48
58
|
changed_columns.delete(lc)
|
|
49
59
|
nil
|
|
50
60
|
end
|
|
@@ -12,6 +12,20 @@ module Sequel
|
|
|
12
12
|
module ClassMethods
|
|
13
13
|
# The column holding the version of the lock
|
|
14
14
|
attr_accessor :lock_column
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
# Prevent increasing the value of the lock column. If the lock column
|
|
19
|
+
# has an existing value, do not allow setting a value that is higher
|
|
20
|
+
# than it.
|
|
21
|
+
def prevent_lock_column_increase!
|
|
22
|
+
lc = lock_column
|
|
23
|
+
define_method(:"#{lc}=") do |v|
|
|
24
|
+
unless v && (lv = send(lc)) && v > lv
|
|
25
|
+
super(v)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
15
29
|
|
|
16
30
|
Plugins.inherited_instance_variables(self, :@lock_column=>nil)
|
|
17
31
|
end
|
|
@@ -534,9 +534,9 @@ module Sequel
|
|
|
534
534
|
def many_to_pg_array_association_filter_expression(op, ref, obj)
|
|
535
535
|
pk = ref.qualify(model.table_name, ref.primary_key)
|
|
536
536
|
key = ref[:key]
|
|
537
|
-
# :
|
|
537
|
+
# simplecov:disable
|
|
538
538
|
expr = case obj
|
|
539
|
-
# :
|
|
539
|
+
# simplecov:enable
|
|
540
540
|
when Sequel::Model
|
|
541
541
|
if (assoc_pks = obj.get_column_value(key)) && !assoc_pks.empty?
|
|
542
542
|
Sequel[pk=>assoc_pks.to_a]
|
|
@@ -556,9 +556,9 @@ module Sequel
|
|
|
556
556
|
# Support filtering by pg_array_to_many associations using a subquery.
|
|
557
557
|
def pg_array_to_many_association_filter_expression(op, ref, obj)
|
|
558
558
|
key = ref.qualify(model.table_name, ref[:key_column])
|
|
559
|
-
# :
|
|
559
|
+
# simplecov:disable
|
|
560
560
|
expr = case obj
|
|
561
|
-
# :
|
|
561
|
+
# simplecov:enable
|
|
562
562
|
when Sequel::Model
|
|
563
563
|
if pkv = obj.get_column_value(ref.primary_key_method)
|
|
564
564
|
Sequel.pg_array_op(key).contains(Sequel.pg_array([pkv], ref.array_type))
|
|
@@ -261,9 +261,9 @@ module Sequel
|
|
|
261
261
|
messages = model.pg_auto_constraint_validations_messages
|
|
262
262
|
|
|
263
263
|
unless override
|
|
264
|
-
# :
|
|
264
|
+
# simplecov:disable
|
|
265
265
|
case e
|
|
266
|
-
# :
|
|
266
|
+
# simplecov:enable
|
|
267
267
|
when Sequel::NotNullConstraintViolation
|
|
268
268
|
if column = info[:column]
|
|
269
269
|
add_pg_constraint_validation_error([m.call(column)], messages[:not_null])
|
|
@@ -297,7 +297,7 @@ module Sequel
|
|
|
297
297
|
end
|
|
298
298
|
end
|
|
299
299
|
rescue
|
|
300
|
-
# If there is an error trying to
|
|
300
|
+
# If there is an error trying to convert the constraint violation
|
|
301
301
|
# into a validation failure, it's best to just raise the constraint
|
|
302
302
|
# violation. This can make debugging the above block of code more
|
|
303
303
|
# difficult.
|
|
@@ -45,7 +45,7 @@ module Sequel
|
|
|
45
45
|
key = key.column
|
|
46
46
|
end
|
|
47
47
|
|
|
48
|
-
# :
|
|
48
|
+
# simplecov:disable
|
|
49
49
|
# many_to_pg_array association type does not need changes, as it
|
|
50
50
|
# already converts the values to a typed postgres array, it does
|
|
51
51
|
# not call the code that uses :eager_loading_predicate_transform.
|
|
@@ -54,7 +54,7 @@ module Sequel
|
|
|
54
54
|
# unless it is one of these types, but external association types
|
|
55
55
|
# could potentially reach it.
|
|
56
56
|
sch = case ref[:type]
|
|
57
|
-
# :
|
|
57
|
+
# simplecov:enable
|
|
58
58
|
when :many_to_one, :one_to_one, :one_to_many, :pg_array_to_many
|
|
59
59
|
ref.associated_class.db_schema
|
|
60
60
|
when :many_to_many, :one_through_one
|
|
@@ -21,6 +21,13 @@ module Sequel
|
|
|
21
21
|
# optimistic locking. The disadvantage is that testing can be
|
|
22
22
|
# more difficult if you are modifying the underlying row between
|
|
23
23
|
# when a model is retrieved and when it is saved.
|
|
24
|
+
|
|
25
|
+
# By default, the plugin allows using the +xmin=+ setter method to
|
|
26
|
+
# either increase or decrease the lock value. To prevent increases,
|
|
27
|
+
# which could potentially be used to skip an update when it update should
|
|
28
|
+
# be made, you can use the +:prevent_increase+ plugin argument:
|
|
29
|
+
#
|
|
30
|
+
# plugin :pg_xmin_optimistic_locking, prevent_increase: true
|
|
24
31
|
#
|
|
25
32
|
# This plugin may not work with the class_table_inheritance plugin.
|
|
26
33
|
#
|
|
@@ -29,7 +36,7 @@ module Sequel
|
|
|
29
36
|
WILDCARD = LiteralString.new('*').freeze
|
|
30
37
|
|
|
31
38
|
# Define the xmin column accessor
|
|
32
|
-
def self.apply(model)
|
|
39
|
+
def self.apply(model, prevent_increase: false)
|
|
33
40
|
model.instance_exec do
|
|
34
41
|
plugin(:optimistic_locking_base)
|
|
35
42
|
@lock_column = :xmin
|
|
@@ -39,9 +46,11 @@ module Sequel
|
|
|
39
46
|
|
|
40
47
|
# Update the dataset to append the xmin column if it is usable
|
|
41
48
|
# and there is a dataset for the model.
|
|
42
|
-
def self.configure(model)
|
|
49
|
+
def self.configure(model, prevent_increase: false)
|
|
43
50
|
model.instance_exec do
|
|
44
51
|
set_dataset(@dataset) if @dataset
|
|
52
|
+
# SEQUEL6: Make prevent_increase true by default
|
|
53
|
+
prevent_lock_column_increase! if prevent_increase
|
|
45
54
|
end
|
|
46
55
|
end
|
|
47
56
|
|
|
@@ -181,11 +181,11 @@ module Sequel
|
|
|
181
181
|
# Disabling usage of prepared statements for insert_select on SQLite seems to be the
|
|
182
182
|
# simplest way to workaround the problem.
|
|
183
183
|
db.database_type != :sqlite
|
|
184
|
-
# :
|
|
184
|
+
# simplecov:disable
|
|
185
185
|
when :delete, :refresh
|
|
186
186
|
Sequel::Deprecation.deprecate("The :delete and :refresh prepared statement types", "There should be no need to check if these types are supported")
|
|
187
187
|
false
|
|
188
|
-
# :
|
|
188
|
+
# simplecov:enable
|
|
189
189
|
else
|
|
190
190
|
raise Error, "unsupported type used: #{type.inspect}"
|
|
191
191
|
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
module Sequel
|
|
4
|
+
module Plugins
|
|
5
|
+
# This plugin changes the default model behavior so that for existing
|
|
6
|
+
# objects, if Model#save_changes skips the save as the object is not
|
|
7
|
+
# modified, or if the UPDATE query is skipped as there were no columns
|
|
8
|
+
# to update, Sequel will issue a SELECT query to make sure the object
|
|
9
|
+
# still exists. This is only done if require_modification is set for
|
|
10
|
+
# the object, so that these cases will raise the same error that
|
|
11
|
+
# Sequel would raise if the UPDATE require was run but did not modify
|
|
12
|
+
# a row.
|
|
13
|
+
#
|
|
14
|
+
# class Item < Sequel::Model
|
|
15
|
+
# plugin :select_on_skipped_update
|
|
16
|
+
# end
|
|
17
|
+
#
|
|
18
|
+
# item = Item[1]
|
|
19
|
+
#
|
|
20
|
+
# # Delete the item from the database
|
|
21
|
+
# Item.where(id: 1).delete
|
|
22
|
+
#
|
|
23
|
+
# # By default, this would return nil, but with the plugin,
|
|
24
|
+
# # this raises Sequel::NoExistingRow.
|
|
25
|
+
# item.save_changes
|
|
26
|
+
#
|
|
27
|
+
# # By default, this would return the object without issuing the
|
|
28
|
+
# # UPDATE query (as the columns to update is empty. With the plugin,
|
|
29
|
+
# # this raises Sequel::NoExistingRow.
|
|
30
|
+
# item.save(columns: [])
|
|
31
|
+
module SelectOnSkippedUpdate
|
|
32
|
+
COUNT = Sequel.function(:count).*.as(:count)
|
|
33
|
+
private_constant :COUNT
|
|
34
|
+
|
|
35
|
+
module InstanceMethods
|
|
36
|
+
# If an UPDATE statement was skipped as the object wasn't modified, run a SELECT query.
|
|
37
|
+
def save_changes(opts=OPTS)
|
|
38
|
+
ret = super
|
|
39
|
+
run_select_on_skipped_update if ret.nil? && require_modification
|
|
40
|
+
ret
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
private
|
|
44
|
+
|
|
45
|
+
# If an UPDATE statement was skipped as there were no columns to update, run a SELECT query.
|
|
46
|
+
def _update_columns(columns)
|
|
47
|
+
ret = super
|
|
48
|
+
run_select_on_skipped_update if ret.nil? && columns.empty? && require_modification
|
|
49
|
+
ret
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Run a SELECT query on the dataset to determine whether the object still exists in the database.
|
|
53
|
+
# This will result in an exception if a single row is not modified.
|
|
54
|
+
def run_select_on_skipped_update
|
|
55
|
+
ds = _update_dataset
|
|
56
|
+
unless ds.select(COUNT).single_value! == 1
|
|
57
|
+
raise(NoMatchingRow, "Attempt to select object did not result in a single row modification")
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -154,7 +154,7 @@ module Sequel
|
|
|
154
154
|
|
|
155
155
|
private
|
|
156
156
|
|
|
157
|
-
# Add serializated attribute
|
|
157
|
+
# Add serializated attribute accessor methods to the serialization_module
|
|
158
158
|
def define_serialized_attribute_accessor(serializer, deserializer, *columns)
|
|
159
159
|
m = self
|
|
160
160
|
include(@serialization_module ||= Sequel.set_temp_name(Module.new){"#{name}::@serialization_module"}) unless @serialization_module
|
|
@@ -6,7 +6,7 @@ module Sequel
|
|
|
6
6
|
# in the following ways:
|
|
7
7
|
#
|
|
8
8
|
# * It automatically saves model instances back to the
|
|
9
|
-
# shard they were
|
|
9
|
+
# shard they were retrieved from.
|
|
10
10
|
# * It makes model associations use the same shard as the model object.
|
|
11
11
|
# * It adds a slightly nicer API for creating model instances on
|
|
12
12
|
# specific shards.
|
|
@@ -12,6 +12,11 @@ module Sequel
|
|
|
12
12
|
# argument to the plugin) holds the class name as a string. However,
|
|
13
13
|
# you can override this by using the <tt>:model_map</tt> option and/or
|
|
14
14
|
# the <tt>:key_map</tt> option.
|
|
15
|
+
#
|
|
16
|
+
# The +sti_key+ column can be set via mass assignment, just like any
|
|
17
|
+
# non-primary key column. Make sure to follow the recommendations in the
|
|
18
|
+
# {mass assignment guide}[rdoc-ref:doc/mass_assignment.rdoc]
|
|
19
|
+
# to ensure this column is not set with untrusted data.
|
|
15
20
|
#
|
|
16
21
|
# You should only load this plugin in the parent class, not in the subclasses.
|
|
17
22
|
#
|
|
@@ -84,6 +89,7 @@ module Sequel
|
|
|
84
89
|
@sti_key_array = nil
|
|
85
90
|
@sti_key = key
|
|
86
91
|
@sti_dataset = dataset
|
|
92
|
+
@sti_root_class = self
|
|
87
93
|
@sti_model_map = opts[:model_map] || lambda{|v| v if v && v != ''}
|
|
88
94
|
@sti_key_map = if km = opts[:key_map]
|
|
89
95
|
if km.is_a?(Hash)
|
|
@@ -150,7 +156,7 @@ module Sequel
|
|
|
150
156
|
# This defaults to a lookup in the key map.
|
|
151
157
|
attr_reader :sti_key_chooser
|
|
152
158
|
|
|
153
|
-
Plugins.inherited_instance_variables(self, :@sti_dataset=>nil, :@sti_key=>nil, :@sti_key_map=>nil, :@sti_model_map=>nil, :@sti_key_chooser=>nil)
|
|
159
|
+
Plugins.inherited_instance_variables(self, :@sti_dataset=>nil, :@sti_key=>nil, :@sti_key_map=>nil, :@sti_model_map=>nil, :@sti_key_chooser=>nil, :@sti_root_class=>nil)
|
|
154
160
|
|
|
155
161
|
# Freeze STI information when freezing model class. Note that
|
|
156
162
|
# because of how STI works, you should not freeze an STI subclass
|
|
@@ -194,7 +200,7 @@ module Sequel
|
|
|
194
200
|
end
|
|
195
201
|
|
|
196
202
|
# Copy the necessary attributes to the subclasses, and filter the
|
|
197
|
-
# subclass's dataset based on the
|
|
203
|
+
# subclass's dataset based on the sti_key_map entry for the class.
|
|
198
204
|
def inherited(subclass)
|
|
199
205
|
super
|
|
200
206
|
key = Array(sti_key_map[subclass]).dup
|
|
@@ -221,11 +227,23 @@ module Sequel
|
|
|
221
227
|
# Return a class object. If a class is given, return it directly.
|
|
222
228
|
# Treat strings and symbols as class names. If nil is given or
|
|
223
229
|
# an invalid class name string or symbol is used, return self.
|
|
230
|
+
# If the class is valid but is not a subclass of the class that
|
|
231
|
+
# loaded the single_table_inheritance plugin, use the class that
|
|
232
|
+
# loaded the plugin.
|
|
224
233
|
# Raise an error for other types.
|
|
225
234
|
def sti_class(v)
|
|
226
235
|
case v
|
|
227
236
|
when String, Symbol
|
|
228
|
-
|
|
237
|
+
begin
|
|
238
|
+
klass = constantize(v)
|
|
239
|
+
if Class === klass && @sti_root_class >= klass
|
|
240
|
+
klass
|
|
241
|
+
else
|
|
242
|
+
@sti_root_class
|
|
243
|
+
end
|
|
244
|
+
rescue
|
|
245
|
+
self
|
|
246
|
+
end
|
|
229
247
|
when nil
|
|
230
248
|
self
|
|
231
249
|
when Class
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
module Sequel
|
|
4
4
|
module Plugins
|
|
5
|
-
# The
|
|
5
|
+
# The skip_saving_columns plugin allows skipping specific columns when
|
|
6
6
|
# saving. By default, it skips columns that the database schema
|
|
7
7
|
# indicates are generated columns:
|
|
8
8
|
#
|
|
@@ -90,7 +90,7 @@ module Sequel
|
|
|
90
90
|
|
|
91
91
|
# Skip the columns the model has marked to skip when updating
|
|
92
92
|
# only changed columns.
|
|
93
|
-
def
|
|
93
|
+
def _save_update_changed_columns_hash
|
|
94
94
|
_save_removed_skipped_columns(super)
|
|
95
95
|
end
|
|
96
96
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
module Sequel
|
|
4
4
|
module Plugins
|
|
5
|
-
# The split_values plugin splits the values hash
|
|
5
|
+
# The split_values plugin splits the values hash retrieved from the
|
|
6
6
|
# database, and moves keys from the values hash that are not columns
|
|
7
7
|
# in the model's dataset to a separate hash. This makes it so the
|
|
8
8
|
# values hash only stores columns from the model's dataset.
|
|
@@ -63,9 +63,9 @@ module Sequel
|
|
|
63
63
|
super(*a, &block)
|
|
64
64
|
end
|
|
65
65
|
end
|
|
66
|
-
# :
|
|
66
|
+
# simplecov:disable
|
|
67
67
|
mod.send(:ruby2_keywords, meth) if mod.respond_to?(:ruby2_keywords, true)
|
|
68
|
-
# :
|
|
68
|
+
# simplecov:enable
|
|
69
69
|
end
|
|
70
70
|
|
|
71
71
|
def self.apply(model)
|
|
@@ -101,9 +101,9 @@ module Sequel
|
|
|
101
101
|
super(*a, &block)
|
|
102
102
|
end
|
|
103
103
|
end
|
|
104
|
-
# :
|
|
104
|
+
# simplecov:disable
|
|
105
105
|
ruby2_keywords(meth) if respond_to?(:ruby2_keywords, true)
|
|
106
|
-
# :
|
|
106
|
+
# simplecov:enable
|
|
107
107
|
end
|
|
108
108
|
|
|
109
109
|
private
|
|
@@ -133,9 +133,9 @@ module Sequel
|
|
|
133
133
|
super(*a, &block)
|
|
134
134
|
end
|
|
135
135
|
end
|
|
136
|
-
# :
|
|
136
|
+
# simplecov:disable
|
|
137
137
|
ruby2_keywords(meth) if respond_to?(:ruby2_keywords, true)
|
|
138
|
-
# :
|
|
138
|
+
# simplecov:enable
|
|
139
139
|
end
|
|
140
140
|
|
|
141
141
|
private
|
|
@@ -163,9 +163,9 @@ module Sequel
|
|
|
163
163
|
super(*a, &block)
|
|
164
164
|
end
|
|
165
165
|
end
|
|
166
|
-
# :
|
|
166
|
+
# simplecov:disable
|
|
167
167
|
ruby2_keywords(meth) if respond_to?(:ruby2_keywords, true)
|
|
168
|
-
# :
|
|
168
|
+
# simplecov:enable
|
|
169
169
|
end
|
|
170
170
|
|
|
171
171
|
private
|
|
@@ -40,9 +40,9 @@ module Sequel
|
|
|
40
40
|
|
|
41
41
|
# Initialize the subclasses instance variable for the model.
|
|
42
42
|
def self.apply(model, &block)
|
|
43
|
-
# :
|
|
43
|
+
# simplecov:disable
|
|
44
44
|
model.instance_variable_set(:@subclasses, []) if NEED_SUBCLASSES
|
|
45
|
-
# :
|
|
45
|
+
# simplecov:enable
|
|
46
46
|
model.instance_variable_set(:@on_subclass, block)
|
|
47
47
|
end
|
|
48
48
|
|
|
@@ -51,13 +51,13 @@ module Sequel
|
|
|
51
51
|
# class created.
|
|
52
52
|
attr_reader :on_subclass
|
|
53
53
|
|
|
54
|
-
# :
|
|
54
|
+
# simplecov:disable
|
|
55
55
|
if NEED_SUBCLASSES
|
|
56
56
|
# All subclasses for the current model. Does not
|
|
57
57
|
# include the model itself.
|
|
58
58
|
attr_reader :subclasses
|
|
59
59
|
end
|
|
60
|
-
# :
|
|
60
|
+
# simplecov:enable
|
|
61
61
|
|
|
62
62
|
# All descendent classes of this model.
|
|
63
63
|
def descendants
|
|
@@ -85,9 +85,9 @@ module Sequel
|
|
|
85
85
|
# in the subclass.
|
|
86
86
|
def inherited(subclass)
|
|
87
87
|
super
|
|
88
|
-
# :
|
|
88
|
+
# simplecov:disable
|
|
89
89
|
Sequel.synchronize{subclasses << subclass} if NEED_SUBCLASSES
|
|
90
|
-
# :
|
|
90
|
+
# simplecov:enable
|
|
91
91
|
on_subclass.call(subclass) if on_subclass
|
|
92
92
|
end
|
|
93
93
|
end
|
|
@@ -105,22 +105,11 @@ module Sequel
|
|
|
105
105
|
|
|
106
106
|
private
|
|
107
107
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
where(name, Sequel.send(meth, *args.map{|a| self.instance_method(:"#{a}_conditions").bind(ds).call}))
|
|
114
|
-
end
|
|
115
|
-
else
|
|
116
|
-
# Cannot bind module method to arbitrary objects in Ruby 1.9.
|
|
117
|
-
# :nocov:
|
|
118
|
-
def _where_any_all(meth, name, args)
|
|
119
|
-
ds = model.dataset.clone
|
|
120
|
-
ds.extend(self)
|
|
121
|
-
where(name, Sequel.send(meth, *args.map{|a| ds.send(:"#{a}_conditions")}))
|
|
122
|
-
end
|
|
123
|
-
# :nocov:
|
|
108
|
+
# Backbone of #where_any and #where_all
|
|
109
|
+
def _where_any_all(meth, name, args)
|
|
110
|
+
ds = model.dataset
|
|
111
|
+
# #bind used here because the dataset module may not yet be included in the model's dataset
|
|
112
|
+
where(name, Sequel.send(meth, *args.map{|a| self.instance_method(:"#{a}_conditions").bind(ds).call}))
|
|
124
113
|
end
|
|
125
114
|
end
|
|
126
115
|
end
|
|
@@ -162,7 +162,7 @@ module Sequel
|
|
|
162
162
|
end
|
|
163
163
|
|
|
164
164
|
# Filter the objects used when tactical eager loading.
|
|
165
|
-
# By default, this removes frozen objects and objects that
|
|
165
|
+
# By default, this removes frozen objects and objects that already have the association loaded,
|
|
166
166
|
# as well as objects where the reflection for the association is not the same as the receiver's
|
|
167
167
|
# reflection for the association.
|
|
168
168
|
def _filter_tactical_eager_load_objects(opts)
|
|
@@ -64,7 +64,7 @@ module Sequel
|
|
|
64
64
|
end
|
|
65
65
|
end
|
|
66
66
|
|
|
67
|
-
if RUBY_VERSION >= '2.2' && (!defined?(JRUBY_VERSION) || JRUBY_VERSION > '9.1')
|
|
67
|
+
if RUBY_VERSION >= '2.2' && (!defined?(JRUBY_VERSION) || JRUBY_VERSION.to_r > Rational('9.1'))
|
|
68
68
|
# Throw HookFailed with the generated error. If the throw is not
|
|
69
69
|
# caught, just return the originally generated error.
|
|
70
70
|
def hook_failed_error(msg)
|
|
@@ -86,7 +86,7 @@ module Sequel
|
|
|
86
86
|
# UncaughtThrowError was added in Ruby 2.2. Older Ruby versions
|
|
87
87
|
# used ArgumentError with "uncaught throw" at the start of the message
|
|
88
88
|
|
|
89
|
-
# :
|
|
89
|
+
# simplecov:disable
|
|
90
90
|
def hook_failed_error(msg)
|
|
91
91
|
e = super
|
|
92
92
|
throw HookFailed, e
|
|
@@ -102,7 +102,7 @@ module Sequel
|
|
|
102
102
|
raise e2 unless e2.message.start_with?('uncaught throw')
|
|
103
103
|
e
|
|
104
104
|
end
|
|
105
|
-
# :
|
|
105
|
+
# simplecov:enable
|
|
106
106
|
end
|
|
107
107
|
end
|
|
108
108
|
end
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen-string-literal: true
|
|
2
2
|
|
|
3
|
-
# :
|
|
3
|
+
# simplecov:disable
|
|
4
4
|
|
|
5
5
|
# This entire file is excluded from coverage testing. This is because it
|
|
6
6
|
# requires coverage testing to work, and if you've already loaded Sequel
|
|
@@ -67,7 +67,7 @@ module Sequel
|
|
|
67
67
|
#
|
|
68
68
|
# You can use the output of the +unused_associations+ method to determine
|
|
69
69
|
# which associations are not used at all in your application, and can
|
|
70
|
-
# be
|
|
70
|
+
# be eliminated.
|
|
71
71
|
#
|
|
72
72
|
# You can also take that unused association data and pass it to the
|
|
73
73
|
# +unused_association_options+ method, which will return an array of
|
|
@@ -131,7 +131,7 @@ module Sequel
|
|
|
131
131
|
# = Automatic Usage of Unused Association Data
|
|
132
132
|
#
|
|
133
133
|
# Since it can be a pain to manually update all of your code
|
|
134
|
-
# to remove unused
|
|
134
|
+
# to remove unused associations or add options to prevent the
|
|
135
135
|
# definition of unused associations, the unused_associations
|
|
136
136
|
# plugin comes with support to take previously saved unused
|
|
137
137
|
# association data, and use it to not create unused associations,
|
|
@@ -265,7 +265,7 @@ module Sequel
|
|
|
265
265
|
module ClassMethods
|
|
266
266
|
# Only the data is copied to subclasses, to allow the :modify_associations
|
|
267
267
|
# plugin option to affect them. The :file and :coverage_file are not copied
|
|
268
|
-
# to subclasses, as users are expected
|
|
268
|
+
# to subclasses, as users are expected to call methods such as
|
|
269
269
|
# unused_associations only on the class that is loading the plugin.
|
|
270
270
|
Plugins.inherited_instance_variables(self, :@unused_associations_data=>nil)
|
|
271
271
|
|
|
@@ -526,4 +526,4 @@ module Sequel
|
|
|
526
526
|
end
|
|
527
527
|
end
|
|
528
528
|
end
|
|
529
|
-
# :
|
|
529
|
+
# simplecov:enable
|
|
@@ -43,6 +43,12 @@ module Sequel
|
|
|
43
43
|
module InstanceMethods
|
|
44
44
|
private
|
|
45
45
|
|
|
46
|
+
# Whether the associated object is valid. By default, the same as calling
|
|
47
|
+
# +valid?+ on the object, but exists so it can be overridden.
|
|
48
|
+
def associated_object_valid?(reflection, obj)
|
|
49
|
+
obj.valid?
|
|
50
|
+
end
|
|
51
|
+
|
|
46
52
|
# Delay validating the associated object until validating the current object.
|
|
47
53
|
def delay_validate_associated_object(reflection, obj)
|
|
48
54
|
after_validation_hook{validate_associated_object(reflection, obj)}
|
|
@@ -62,7 +68,7 @@ module Sequel
|
|
|
62
68
|
end
|
|
63
69
|
end
|
|
64
70
|
|
|
65
|
-
unless obj
|
|
71
|
+
unless associated_object_valid?(reflection, obj)
|
|
66
72
|
if ignore_key_errors
|
|
67
73
|
# Ignore errors on the key column in the associated object. This column
|
|
68
74
|
# will be set when saving to a presumably valid value using a column
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
module Sequel
|
|
4
|
+
module Plugins
|
|
5
|
+
# The validate_associated_context plugin extends the validate_associated
|
|
6
|
+
# plugin to work with the validation_contexts plugin. It ensures associated
|
|
7
|
+
# objects are validated using the validation context of the current object.
|
|
8
|
+
#
|
|
9
|
+
# This plugin loads the validate_associated and validation_contexts plugins.
|
|
10
|
+
# The associated model must also use the validation_contexts plugin in order
|
|
11
|
+
# to access the validation context.
|
|
12
|
+
#
|
|
13
|
+
# class Album < Sequel::Model
|
|
14
|
+
# plugin :validate_associated_context
|
|
15
|
+
# many_to_one :artist
|
|
16
|
+
#
|
|
17
|
+
# def validate
|
|
18
|
+
# super
|
|
19
|
+
# validate_associated_object(model.association_reflection(:artist), artist) if artist
|
|
20
|
+
# end
|
|
21
|
+
# end
|
|
22
|
+
#
|
|
23
|
+
# class Artist < Sequel::Model
|
|
24
|
+
# plugin :validation_contexts
|
|
25
|
+
# def validate
|
|
26
|
+
# super
|
|
27
|
+
# errors.add(:name, 'not present') if name.nil? && validation_context == :publish
|
|
28
|
+
# end
|
|
29
|
+
# end
|
|
30
|
+
#
|
|
31
|
+
# album = Album.new(artist: Artist.new)
|
|
32
|
+
# album.valid? # => true
|
|
33
|
+
# album.valid?(validation_context: :publish) # => false
|
|
34
|
+
module ValidateAssociatedContext
|
|
35
|
+
# Depend on the validate_associated and validation_contexts plugins.
|
|
36
|
+
def self.apply(model)
|
|
37
|
+
model.plugin :validate_associated
|
|
38
|
+
model.plugin :validation_contexts
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
module InstanceMethods
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
# Whether the associated object is valid, using the validation context
|
|
45
|
+
# of the current object.
|
|
46
|
+
def associated_object_valid?(reflection, obj)
|
|
47
|
+
obj.valid?(:validation_context=>validation_context)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|