sequel 5.106.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.
Files changed (147) hide show
  1. checksums.yaml +4 -4
  2. data/bin/sequel +5 -5
  3. data/lib/sequel/adapters/ado.rb +1 -1
  4. data/lib/sequel/adapters/amalgalite.rb +34 -8
  5. data/lib/sequel/adapters/ibmdb.rb +2 -2
  6. data/lib/sequel/adapters/jdbc/hsqldb.rb +1 -1
  7. data/lib/sequel/adapters/jdbc/mssql.rb +28 -5
  8. data/lib/sequel/adapters/jdbc/mysql.rb +1 -1
  9. data/lib/sequel/adapters/jdbc/postgresql.rb +14 -3
  10. data/lib/sequel/adapters/jdbc.rb +4 -3
  11. data/lib/sequel/adapters/mock.rb +1 -1
  12. data/lib/sequel/adapters/mysql.rb +7 -2
  13. data/lib/sequel/adapters/mysql2.rb +5 -4
  14. data/lib/sequel/adapters/postgres.rb +42 -39
  15. data/lib/sequel/adapters/shared/db2.rb +5 -2
  16. data/lib/sequel/adapters/shared/mssql.rb +11 -5
  17. data/lib/sequel/adapters/shared/mysql.rb +2 -2
  18. data/lib/sequel/adapters/shared/postgres.rb +80 -92
  19. data/lib/sequel/adapters/shared/sqlanywhere.rb +0 -32
  20. data/lib/sequel/adapters/shared/sqlite.rb +8 -7
  21. data/lib/sequel/adapters/sqlite.rb +13 -9
  22. data/lib/sequel/adapters/trilogy.rb +2 -1
  23. data/lib/sequel/adapters/utils/emulate_offset_with_reverse_and_count.rb +1 -1
  24. data/lib/sequel/adapters/utils/mysql_mysql2.rb +11 -1
  25. data/lib/sequel/connection_pool/sharded_single.rb +1 -1
  26. data/lib/sequel/connection_pool/sharded_threaded.rb +7 -5
  27. data/lib/sequel/connection_pool/sharded_timed_queue.rb +3 -3
  28. data/lib/sequel/connection_pool/threaded.rb +9 -7
  29. data/lib/sequel/connection_pool/timed_queue.rb +2 -2
  30. data/lib/sequel/connection_pool.rb +3 -3
  31. data/lib/sequel/core.rb +44 -24
  32. data/lib/sequel/database/connecting.rb +1 -1
  33. data/lib/sequel/database/features.rb +1 -1
  34. data/lib/sequel/database/misc.rb +6 -11
  35. data/lib/sequel/database/query.rb +2 -2
  36. data/lib/sequel/database/schema_generator.rb +7 -5
  37. data/lib/sequel/database/schema_methods.rb +2 -2
  38. data/lib/sequel/database/transactions.rb +5 -7
  39. data/lib/sequel/dataset/actions.rb +2 -2
  40. data/lib/sequel/dataset/features.rb +4 -4
  41. data/lib/sequel/dataset/graph.rb +1 -1
  42. data/lib/sequel/dataset/misc.rb +3 -3
  43. data/lib/sequel/dataset/prepared_statements.rb +2 -2
  44. data/lib/sequel/dataset/query.rb +8 -8
  45. data/lib/sequel/dataset/sql.rb +32 -13
  46. data/lib/sequel/dataset.rb +2 -2
  47. data/lib/sequel/deprecated.rb +2 -2
  48. data/lib/sequel/exceptions.rb +2 -2
  49. data/lib/sequel/extensions/_pretty_table.rb +1 -1
  50. data/lib/sequel/extensions/async_thread_pool.rb +3 -3
  51. data/lib/sequel/extensions/auto_cast_date_and_time.rb +2 -2
  52. data/lib/sequel/extensions/blank.rb +2 -2
  53. data/lib/sequel/extensions/constraint_validations.rb +1 -1
  54. data/lib/sequel/extensions/core_refinements.rb +7 -10
  55. data/lib/sequel/extensions/date_arithmetic.rb +1 -1
  56. data/lib/sequel/extensions/datetime_parse_to_time.rb +2 -2
  57. data/lib/sequel/extensions/duplicate_columns_handler.rb +1 -3
  58. data/lib/sequel/extensions/graph_each.rb +1 -1
  59. data/lib/sequel/extensions/index_caching.rb +1 -1
  60. data/lib/sequel/extensions/inflector.rb +5 -5
  61. data/lib/sequel/extensions/is_distinct_from.rb +2 -2
  62. data/lib/sequel/extensions/lit_require_frozen.rb +20 -4
  63. data/lib/sequel/extensions/migration.rb +21 -7
  64. data/lib/sequel/extensions/named_timezones.rb +9 -9
  65. data/lib/sequel/extensions/pg_array.rb +10 -8
  66. data/lib/sequel/extensions/pg_array_ops.rb +69 -14
  67. data/lib/sequel/extensions/pg_auto_parameterize.rb +2 -2
  68. data/lib/sequel/extensions/pg_auto_parameterize_in_array.rb +3 -3
  69. data/lib/sequel/extensions/pg_enum.rb +2 -2
  70. data/lib/sequel/extensions/pg_extended_date_support.rb +5 -5
  71. data/lib/sequel/extensions/pg_extended_integer_support.rb +1 -1
  72. data/lib/sequel/extensions/pg_hstore.rb +2 -2
  73. data/lib/sequel/extensions/pg_hstore_ops.rb +5 -5
  74. data/lib/sequel/extensions/pg_inet.rb +2 -2
  75. data/lib/sequel/extensions/pg_inet_ops.rb +2 -2
  76. data/lib/sequel/extensions/pg_interval.rb +6 -6
  77. data/lib/sequel/extensions/pg_json.rb +4 -4
  78. data/lib/sequel/extensions/pg_json_ops.rb +15 -13
  79. data/lib/sequel/extensions/pg_range.rb +6 -6
  80. data/lib/sequel/extensions/pg_range_ops.rb +7 -7
  81. data/lib/sequel/extensions/pg_row.rb +4 -4
  82. data/lib/sequel/extensions/pg_row_ops.rb +6 -6
  83. data/lib/sequel/extensions/provenance.rb +2 -2
  84. data/lib/sequel/extensions/query.rb +2 -2
  85. data/lib/sequel/extensions/s.rb +6 -10
  86. data/lib/sequel/extensions/schema_dumper.rb +10 -6
  87. data/lib/sequel/extensions/sequel_4_dataset_methods.rb +2 -0
  88. data/lib/sequel/extensions/sql_comments.rb +1 -1
  89. data/lib/sequel/extensions/sql_log_normalizer.rb +1 -1
  90. data/lib/sequel/extensions/sqlite_json_ops.rb +2 -2
  91. data/lib/sequel/extensions/string_agg.rb +5 -5
  92. data/lib/sequel/extensions/symbol_aref.rb +12 -32
  93. data/lib/sequel/extensions/symbol_aref_refinement.rb +2 -5
  94. data/lib/sequel/extensions/symbol_as.rb +1 -2
  95. data/lib/sequel/extensions/symbol_as_refinement.rb +1 -5
  96. data/lib/sequel/extensions/transaction_connection_validator.rb +1 -1
  97. data/lib/sequel/model/associations.rb +17 -17
  98. data/lib/sequel/model/base.rb +18 -15
  99. data/lib/sequel/model/inflections.rb +1 -1
  100. data/lib/sequel/model/plugins.rb +2 -2
  101. data/lib/sequel/model.rb +2 -2
  102. data/lib/sequel/plugins/association_pks.rb +1 -1
  103. data/lib/sequel/plugins/association_proxies.rb +4 -4
  104. data/lib/sequel/plugins/auto_restrict_eager_graph.rb +2 -0
  105. data/lib/sequel/plugins/caching.rb +28 -3
  106. data/lib/sequel/plugins/class_table_inheritance.rb +1 -1
  107. data/lib/sequel/plugins/column_encryption.rb +10 -10
  108. data/lib/sequel/plugins/concurrent_eager_loading.rb +2 -2
  109. data/lib/sequel/plugins/csv_serializer.rb +9 -20
  110. data/lib/sequel/plugins/deprecated_associations.rb +2 -2
  111. data/lib/sequel/plugins/eager_each.rb +1 -1
  112. data/lib/sequel/plugins/finder.rb +1 -1
  113. data/lib/sequel/plugins/forbid_lazy_load.rb +3 -3
  114. data/lib/sequel/plugins/insert_conflict.rb +1 -1
  115. data/lib/sequel/plugins/insert_returning_select.rb +1 -1
  116. data/lib/sequel/plugins/instance_filters.rb +8 -0
  117. data/lib/sequel/plugins/instance_hooks.rb +19 -0
  118. data/lib/sequel/plugins/json_serializer.rb +4 -4
  119. data/lib/sequel/plugins/lazy_attributes.rb +1 -1
  120. data/lib/sequel/plugins/many_through_many.rb +1 -1
  121. data/lib/sequel/plugins/mssql_optimistic_locking.rb +9 -0
  122. data/lib/sequel/plugins/optimistic_locking.rb +12 -2
  123. data/lib/sequel/plugins/optimistic_locking_base.rb +14 -0
  124. data/lib/sequel/plugins/pg_array_associations.rb +4 -4
  125. data/lib/sequel/plugins/pg_auto_constraint_validations.rb +3 -3
  126. data/lib/sequel/plugins/pg_eager_any_typed_array.rb +2 -2
  127. data/lib/sequel/plugins/pg_xmin_optimistic_locking.rb +11 -2
  128. data/lib/sequel/plugins/prepared_statements.rb +2 -2
  129. data/lib/sequel/plugins/select_on_skipped_update.rb +63 -0
  130. data/lib/sequel/plugins/serialization.rb +1 -1
  131. data/lib/sequel/plugins/sharding.rb +1 -1
  132. data/lib/sequel/plugins/single_table_inheritance.rb +21 -3
  133. data/lib/sequel/plugins/skip_saving_columns.rb +2 -2
  134. data/lib/sequel/plugins/split_values.rb +1 -1
  135. data/lib/sequel/plugins/sql_comments.rb +8 -8
  136. data/lib/sequel/plugins/subclasses.rb +6 -6
  137. data/lib/sequel/plugins/subset_conditions.rb +5 -16
  138. data/lib/sequel/plugins/tactical_eager_loading.rb +1 -1
  139. data/lib/sequel/plugins/throw_failures.rb +3 -3
  140. data/lib/sequel/plugins/unused_associations.rb +5 -5
  141. data/lib/sequel/plugins/validate_associated.rb +7 -1
  142. data/lib/sequel/plugins/validate_associated_context.rb +52 -0
  143. data/lib/sequel/plugins/validation_helpers.rb +1 -1
  144. data/lib/sequel/plugins/xml_serializer.rb +2 -0
  145. data/lib/sequel/sql.rb +120 -116
  146. data/lib/sequel/version.rb +1 -1
  147. metadata +5 -3
@@ -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 acessor methods to the serialization_module
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 retreived from.
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 sti_kep_map entry for the class.
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
- constantize(v) rescue self
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 skip_saving_columms plugin allows skipping specific columns when
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 _save_update_changed_colums_hash
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 retreived from the
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
- # :nocov:
66
+ # simplecov:disable
67
67
  mod.send(:ruby2_keywords, meth) if mod.respond_to?(:ruby2_keywords, true)
68
- # :nocov:
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
- # :nocov:
104
+ # simplecov:disable
105
105
  ruby2_keywords(meth) if respond_to?(:ruby2_keywords, true)
106
- # :nocov:
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
- # :nocov:
136
+ # simplecov:disable
137
137
  ruby2_keywords(meth) if respond_to?(:ruby2_keywords, true)
138
- # :nocov:
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
- # :nocov:
166
+ # simplecov:disable
167
167
  ruby2_keywords(meth) if respond_to?(:ruby2_keywords, true)
168
- # :nocov:
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
- # :nocov:
43
+ # simplecov:disable
44
44
  model.instance_variable_set(:@subclasses, []) if NEED_SUBCLASSES
45
- # :nocov:
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
- # :nocov:
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
- # :nocov:
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
- # :nocov:
88
+ # simplecov:disable
89
89
  Sequel.synchronize{subclasses << subclass} if NEED_SUBCLASSES
90
- # :nocov:
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
- if RUBY_VERSION >= '2'
109
- # Backbone of #where_any and #where_all
110
- def _where_any_all(meth, name, args)
111
- ds = model.dataset
112
- # #bind used here because the dataset module may not yet be included in the model's dataset
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 alreayd have the association loaded,
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
- # :nocov:
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
- # :nocov:
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
- # :nocov:
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 eliminiated.
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 assocations or add options to prevent the
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 ot call methods such as
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
- # :nocov:
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.valid?
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
@@ -39,7 +39,7 @@ module Sequel
39
39
  # :skip_invalid :: Do not try to validate columns that are already invalid.
40
40
  #
41
41
  # The default validation options for all models can be modified by
42
- # overridding the Model#default_validation_helpers_options private method.
42
+ # overriding the Model#default_validation_helpers_options private method.
43
43
  # By changing the default options, you can setup internationalization of the
44
44
  # error messages. For example, you would modify the default options:
45
45
  #
@@ -1,5 +1,7 @@
1
1
  # frozen-string-literal: true
2
2
 
3
+ # SEQUEL6: Remove
4
+
3
5
  require 'nokogiri'
4
6
 
5
7
  module Sequel