sequel 5.40.0 → 5.45.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 +52 -0
- data/MIT-LICENSE +1 -1
- data/doc/release_notes/5.41.0.txt +25 -0
- data/doc/release_notes/5.42.0.txt +136 -0
- data/doc/release_notes/5.43.0.txt +98 -0
- data/doc/release_notes/5.44.0.txt +32 -0
- data/doc/release_notes/5.45.0.txt +34 -0
- data/doc/sql.rdoc +1 -1
- data/doc/testing.rdoc +3 -0
- data/doc/virtual_rows.rdoc +1 -1
- data/lib/sequel/adapters/ado.rb +16 -16
- data/lib/sequel/adapters/odbc.rb +5 -1
- data/lib/sequel/adapters/shared/postgres.rb +4 -14
- data/lib/sequel/adapters/shared/sqlite.rb +8 -4
- data/lib/sequel/core.rb +11 -0
- data/lib/sequel/database/misc.rb +1 -2
- data/lib/sequel/database/schema_generator.rb +35 -47
- data/lib/sequel/database/schema_methods.rb +4 -0
- data/lib/sequel/dataset/query.rb +1 -3
- data/lib/sequel/dataset/sql.rb +7 -0
- data/lib/sequel/extensions/async_thread_pool.rb +438 -0
- data/lib/sequel/extensions/blank.rb +2 -0
- data/lib/sequel/extensions/date_arithmetic.rb +32 -23
- data/lib/sequel/extensions/inflector.rb +2 -0
- data/lib/sequel/extensions/named_timezones.rb +5 -1
- data/lib/sequel/extensions/pg_enum.rb +1 -1
- data/lib/sequel/extensions/pg_interval.rb +12 -2
- data/lib/sequel/extensions/pg_loose_count.rb +3 -1
- data/lib/sequel/model/associations.rb +70 -14
- data/lib/sequel/model/base.rb +2 -2
- data/lib/sequel/plugins/async_thread_pool.rb +39 -0
- data/lib/sequel/plugins/auto_validations.rb +15 -1
- data/lib/sequel/plugins/auto_validations_constraint_validations_presence_message.rb +68 -0
- data/lib/sequel/plugins/column_encryption.rb +728 -0
- data/lib/sequel/plugins/composition.rb +2 -1
- data/lib/sequel/plugins/concurrent_eager_loading.rb +174 -0
- data/lib/sequel/plugins/json_serializer.rb +37 -22
- data/lib/sequel/plugins/nested_attributes.rb +5 -2
- data/lib/sequel/plugins/pg_array_associations.rb +6 -4
- data/lib/sequel/plugins/rcte_tree.rb +27 -19
- data/lib/sequel/plugins/serialization.rb +8 -3
- data/lib/sequel/plugins/serialization_modification_detection.rb +1 -1
- data/lib/sequel/plugins/validation_helpers.rb +6 -2
- data/lib/sequel/version.rb +1 -1
- metadata +18 -3
@@ -8,9 +8,10 @@
|
|
8
8
|
# DB.extension :date_arithmetic
|
9
9
|
#
|
10
10
|
# Then you can use the Sequel.date_add and Sequel.date_sub methods
|
11
|
-
# to return Sequel expressions
|
11
|
+
# to return Sequel expressions (this example shows the only supported
|
12
|
+
# keys for the second argument):
|
12
13
|
#
|
13
|
-
# add = Sequel.date_add(:date_column, years: 1, months: 2, days:
|
14
|
+
# add = Sequel.date_add(:date_column, years: 1, months: 2, weeks: 2, days: 1)
|
14
15
|
# sub = Sequel.date_sub(:date_column, hours: 1, minutes: 2, seconds: 3)
|
15
16
|
#
|
16
17
|
# In addition to specifying the interval as a hash, there is also
|
@@ -52,14 +53,9 @@ module Sequel
|
|
52
53
|
if defined?(ActiveSupport::Duration) && interval.is_a?(ActiveSupport::Duration)
|
53
54
|
interval = interval.parts
|
54
55
|
end
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
h
|
59
|
-
else
|
60
|
-
-interval
|
61
|
-
end
|
62
|
-
DateAdd.new(expr, interval, opts)
|
56
|
+
parts = {}
|
57
|
+
interval.each{|k,v| parts[k] = -v unless v.nil?}
|
58
|
+
DateAdd.new(expr, parts, opts)
|
63
59
|
end
|
64
60
|
end
|
65
61
|
|
@@ -189,22 +185,35 @@ module Sequel
|
|
189
185
|
# ActiveSupport::Duration :: Converted to a hash using the interval's parts.
|
190
186
|
def initialize(expr, interval, opts=OPTS)
|
191
187
|
@expr = expr
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
188
|
+
|
189
|
+
h = Hash.new(0)
|
190
|
+
interval = interval.parts unless interval.is_a?(Hash)
|
191
|
+
interval.each do |unit, value|
|
192
|
+
# skip nil values
|
193
|
+
next unless value
|
194
|
+
|
195
|
+
# Convert weeks to days, as ActiveSupport::Duration can use weeks,
|
196
|
+
# but the database-specific literalizers only support days.
|
197
|
+
if unit == :weeks
|
198
|
+
unit = :days
|
199
|
+
value *= 7
|
200
|
+
end
|
201
|
+
|
202
|
+
unless DatasetMethods::DURATION_UNITS.include?(unit)
|
203
|
+
raise Sequel::Error, "Invalid key used in DateAdd interval hash: #{unit.inspect}"
|
204
|
+
end
|
205
|
+
|
206
|
+
# Attempt to prevent SQL injection by users who pass untrusted strings
|
207
|
+
# as interval values. It doesn't make sense to support literal strings,
|
208
|
+
# due to the numeric adding below.
|
209
|
+
if value.is_a?(String)
|
210
|
+
raise Sequel::InvalidValue, "cannot provide String value as interval part: #{value.inspect}"
|
199
211
|
end
|
200
|
-
|
201
|
-
|
202
|
-
h = Hash.new(0)
|
203
|
-
interval.parts.each{|unit, value| h[unit] += value}
|
204
|
-
Hash[h]
|
212
|
+
|
213
|
+
h[unit] += value
|
205
214
|
end
|
206
215
|
|
207
|
-
@interval.freeze
|
216
|
+
@interval = Hash[h].freeze
|
208
217
|
@cast_type = opts[:cast] if opts[:cast]
|
209
218
|
freeze
|
210
219
|
end
|
@@ -107,9 +107,11 @@ class String
|
|
107
107
|
end
|
108
108
|
|
109
109
|
%w'classify constantize dasherize demodulize foreign_key humanize pluralize singularize tableize underscore'.each do |m|
|
110
|
+
# :nocov:
|
110
111
|
if method_defined?(m)
|
111
112
|
alias_method(m, m)
|
112
113
|
end
|
114
|
+
# :nocov:
|
113
115
|
end
|
114
116
|
|
115
117
|
# By default, camelize converts the string to UpperCamelCase. If the argument to camelize
|
@@ -84,9 +84,9 @@ module Sequel
|
|
84
84
|
def convert_output_time_other(v, output_timezone)
|
85
85
|
Time.at(v.to_i, :in => output_timezone)
|
86
86
|
end
|
87
|
-
else
|
88
87
|
# :nodoc:
|
89
88
|
# :nocov:
|
89
|
+
else
|
90
90
|
def convert_input_time_other(v, input_timezone)
|
91
91
|
local_offset = input_timezone.period_for_local(v, &tzinfo_disambiguator_for(v)).utc_total_offset
|
92
92
|
Time.new(1970, 1, 1, 0, 0, 0, local_offset) + v.to_i
|
@@ -105,6 +105,8 @@ module Sequel
|
|
105
105
|
Time.new(1970, 1, 1, 0, 0, 0, local_offset) + v.to_i
|
106
106
|
end
|
107
107
|
end
|
108
|
+
# :nodoc:
|
109
|
+
# :nocov:
|
108
110
|
end
|
109
111
|
|
110
112
|
# Handle both TZInfo 1 and TZInfo 2
|
@@ -142,6 +144,8 @@ module Sequel
|
|
142
144
|
# Convert timezone offset from UTC to the offset for the output_timezone
|
143
145
|
(v - local_offset).new_offset(local_offset)
|
144
146
|
end
|
147
|
+
# :nodoc:
|
148
|
+
# :nocov:
|
145
149
|
end
|
146
150
|
|
147
151
|
# Returns TZInfo::Timezone instance if given a String.
|
@@ -71,6 +71,16 @@ module Sequel
|
|
71
71
|
# Whether ActiveSupport::Duration.new takes parts as array instead of hash
|
72
72
|
USE_PARTS_ARRAY = !defined?(ActiveSupport::VERSION::STRING) || ActiveSupport::VERSION::STRING < '5.1'
|
73
73
|
|
74
|
+
if defined?(ActiveSupport::Duration::SECONDS_PER_MONTH)
|
75
|
+
SECONDS_PER_MONTH = ActiveSupport::Duration::SECONDS_PER_MONTH
|
76
|
+
SECONDS_PER_YEAR = ActiveSupport::Duration::SECONDS_PER_YEAR
|
77
|
+
# :nocov:
|
78
|
+
else
|
79
|
+
SECONDS_PER_MONTH = 2592000
|
80
|
+
SECONDS_PER_YEAR = 31557600
|
81
|
+
# :nocov:
|
82
|
+
end
|
83
|
+
|
74
84
|
# Parse the interval input string into an ActiveSupport::Duration instance.
|
75
85
|
def call(string)
|
76
86
|
raise(InvalidValue, "invalid or unhandled interval format: #{string.inspect}") unless matches = /\A([+-]?\d+ years?\s?)?([+-]?\d+ mons?\s?)?([+-]?\d+ days?\s?)?(?:(?:([+-])?(\d{2,10}):(\d\d):(\d\d(\.\d+)?))|([+-]?\d+ hours?\s?)?([+-]?\d+ mins?\s?)?([+-]?\d+(\.\d+)? secs?\s?)?)?\z/.match(string)
|
@@ -80,12 +90,12 @@ module Sequel
|
|
80
90
|
|
81
91
|
if v = matches[1]
|
82
92
|
v = v.to_i
|
83
|
-
value +=
|
93
|
+
value += SECONDS_PER_YEAR * v
|
84
94
|
parts[:years] = v
|
85
95
|
end
|
86
96
|
if v = matches[2]
|
87
97
|
v = v.to_i
|
88
|
-
value +=
|
98
|
+
value += SECONDS_PER_MONTH * v
|
89
99
|
parts[:months] = v
|
90
100
|
end
|
91
101
|
if v = matches[3]
|
@@ -12,7 +12,9 @@
|
|
12
12
|
#
|
13
13
|
# How accurate this count is depends on the number of rows
|
14
14
|
# added/deleted from the table since the last time it was
|
15
|
-
# analyzed.
|
15
|
+
# analyzed. If the table has not been vacuumed or analyzed
|
16
|
+
# yet, this can return 0 or -1 depending on the PostgreSQL
|
17
|
+
# version in use.
|
16
18
|
#
|
17
19
|
# To load the extension into the database:
|
18
20
|
#
|
@@ -263,7 +263,9 @@ module Sequel
|
|
263
263
|
# yielding each row to the block.
|
264
264
|
def eager_load_results(eo, &block)
|
265
265
|
rows = eo[:rows]
|
266
|
-
|
266
|
+
unless eo[:initialize_rows] == false
|
267
|
+
Sequel.synchronize_with(eo[:mutex]){initialize_association_cache(rows)}
|
268
|
+
end
|
267
269
|
if eo[:id_map]
|
268
270
|
ids = eo[:id_map].keys
|
269
271
|
return ids if ids.empty?
|
@@ -311,7 +313,8 @@ module Sequel
|
|
311
313
|
objects = loader.all(ids)
|
312
314
|
end
|
313
315
|
|
314
|
-
objects.each(&block)
|
316
|
+
Sequel.synchronize_with(eo[:mutex]){objects.each(&block)}
|
317
|
+
|
315
318
|
if strategy == :ruby
|
316
319
|
apply_ruby_eager_limit_strategy(rows, eager_limit || limit_and_offset)
|
317
320
|
end
|
@@ -1929,8 +1932,22 @@ module Sequel
|
|
1929
1932
|
# can be easily overridden in the class itself while allowing for
|
1930
1933
|
# super to be called.
|
1931
1934
|
def association_module_def(name, opts=OPTS, &block)
|
1932
|
-
association_module(opts)
|
1933
|
-
|
1935
|
+
mod = association_module(opts)
|
1936
|
+
mod.send(:define_method, name, &block)
|
1937
|
+
mod.send(:alias_method, name, name)
|
1938
|
+
end
|
1939
|
+
|
1940
|
+
# Add a method to the module included in the class, so the method
|
1941
|
+
# can be easily overridden in the class itself while allowing for
|
1942
|
+
# super to be called. This method allows passing keywords through
|
1943
|
+
# the defined methods.
|
1944
|
+
def association_module_delegate_def(name, opts, &block)
|
1945
|
+
mod = association_module(opts)
|
1946
|
+
mod.send(:define_method, name, &block)
|
1947
|
+
# :nocov:
|
1948
|
+
mod.send(:ruby2_keywords, name) if mod.respond_to?(:ruby2_keywords, true)
|
1949
|
+
# :nocov:
|
1950
|
+
mod.send(:alias_method, name, name)
|
1934
1951
|
end
|
1935
1952
|
|
1936
1953
|
# Add a private method to the module included in the class.
|
@@ -1982,17 +1999,17 @@ module Sequel
|
|
1982
1999
|
|
1983
2000
|
if adder = opts[:adder]
|
1984
2001
|
association_module_private_def(opts[:_add_method], opts, &adder)
|
1985
|
-
|
2002
|
+
association_module_delegate_def(opts[:add_method], opts){|o,*args| add_associated_object(opts, o, *args)}
|
1986
2003
|
end
|
1987
2004
|
|
1988
2005
|
if remover = opts[:remover]
|
1989
2006
|
association_module_private_def(opts[:_remove_method], opts, &remover)
|
1990
|
-
|
2007
|
+
association_module_delegate_def(opts[:remove_method], opts){|o,*args| remove_associated_object(opts, o, *args)}
|
1991
2008
|
end
|
1992
2009
|
|
1993
2010
|
if clearer = opts[:clearer]
|
1994
2011
|
association_module_private_def(opts[:_remove_all_method], opts, &clearer)
|
1995
|
-
|
2012
|
+
association_module_delegate_def(opts[:remove_all_method], opts){|*args| remove_all_associated_objects(opts, *args)}
|
1996
2013
|
end
|
1997
2014
|
end
|
1998
2015
|
|
@@ -2424,6 +2441,9 @@ module Sequel
|
|
2424
2441
|
run_association_callbacks(opts, :after_add, o)
|
2425
2442
|
o
|
2426
2443
|
end
|
2444
|
+
# :nocov:
|
2445
|
+
ruby2_keywords(:add_associated_object) if respond_to?(:ruby2_keywords, true)
|
2446
|
+
# :nocov:
|
2427
2447
|
|
2428
2448
|
# Add/Set the current object to/as the given object's reciprocal association.
|
2429
2449
|
def add_reciprocal_object(opts, o)
|
@@ -2566,6 +2586,9 @@ module Sequel
|
|
2566
2586
|
associations[opts[:name]] = []
|
2567
2587
|
ret
|
2568
2588
|
end
|
2589
|
+
# :nocov:
|
2590
|
+
ruby2_keywords(:remove_all_associated_objects) if respond_to?(:ruby2_keywords, true)
|
2591
|
+
# :nocov:
|
2569
2592
|
|
2570
2593
|
# Remove the given associated object from the given association
|
2571
2594
|
def remove_associated_object(opts, o, *args)
|
@@ -2587,6 +2610,9 @@ module Sequel
|
|
2587
2610
|
run_association_callbacks(opts, :after_remove, o)
|
2588
2611
|
o
|
2589
2612
|
end
|
2613
|
+
# :nocov:
|
2614
|
+
ruby2_keywords(:remove_associated_object) if respond_to?(:ruby2_keywords, true)
|
2615
|
+
# :nocov:
|
2590
2616
|
|
2591
2617
|
# Check that the object from the associated table specified by the primary key
|
2592
2618
|
# is currently associated to the receiver. If it is associated, return the object, otherwise
|
@@ -2985,6 +3011,8 @@ module Sequel
|
|
2985
3011
|
# You can specify an custom alias and/or join type on a per-association basis by providing an
|
2986
3012
|
# Sequel::SQL::AliasedExpression object instead of an a Symbol for the association name.
|
2987
3013
|
#
|
3014
|
+
# You cannot mix calls to +eager_graph+ and +graph+ on the same dataset.
|
3015
|
+
#
|
2988
3016
|
# Examples:
|
2989
3017
|
#
|
2990
3018
|
# # For each album, eager_graph load the artist
|
@@ -3351,15 +3379,30 @@ module Sequel
|
|
3351
3379
|
egl.dup
|
3352
3380
|
end
|
3353
3381
|
|
3354
|
-
# Eagerly load all specified associations
|
3382
|
+
# Eagerly load all specified associations.
|
3355
3383
|
def eager_load(a, eager_assoc=@opts[:eager])
|
3356
3384
|
return if a.empty?
|
3385
|
+
|
3386
|
+
# Reflections for all associations to eager load
|
3387
|
+
reflections = eager_assoc.keys.map{|assoc| model.association_reflection(assoc) || (raise Sequel::UndefinedAssociation, "Model: #{self}, Association: #{assoc}")}
|
3388
|
+
|
3389
|
+
perform_eager_loads(prepare_eager_load(a, reflections, eager_assoc))
|
3390
|
+
|
3391
|
+
reflections.each do |r|
|
3392
|
+
a.each{|object| object.send(:run_association_callbacks, r, :after_load, object.associations[r[:name]])} if r[:after_load]
|
3393
|
+
end
|
3394
|
+
|
3395
|
+
nil
|
3396
|
+
end
|
3397
|
+
|
3398
|
+
# Prepare a hash loaders and eager options which will be used to implement the eager loading.
|
3399
|
+
def prepare_eager_load(a, reflections, eager_assoc)
|
3400
|
+
eager_load_data = {}
|
3401
|
+
|
3357
3402
|
# Key is foreign/primary key name symbol.
|
3358
3403
|
# Value is hash with keys being foreign/primary key values (generally integers)
|
3359
3404
|
# and values being an array of current model objects with that specific foreign/primary key
|
3360
3405
|
key_hash = {}
|
3361
|
-
# Reflections for all associations to eager load
|
3362
|
-
reflections = eager_assoc.keys.map{|assoc| model.association_reflection(assoc) || (raise Sequel::UndefinedAssociation, "Model: #{self}, Association: #{assoc}")}
|
3363
3406
|
|
3364
3407
|
# Populate the key_hash entry for each association being eagerly loaded
|
3365
3408
|
reflections.each do |r|
|
@@ -3390,7 +3433,6 @@ module Sequel
|
|
3390
3433
|
id_map = nil
|
3391
3434
|
end
|
3392
3435
|
|
3393
|
-
loader = r[:eager_loader]
|
3394
3436
|
associations = eager_assoc[r[:name]]
|
3395
3437
|
if associations.respond_to?(:call)
|
3396
3438
|
eager_block = associations
|
@@ -3398,9 +3440,23 @@ module Sequel
|
|
3398
3440
|
elsif associations.is_a?(Hash) && associations.length == 1 && (pr_assoc = associations.to_a.first) && pr_assoc.first.respond_to?(:call)
|
3399
3441
|
eager_block, associations = pr_assoc
|
3400
3442
|
end
|
3401
|
-
|
3402
|
-
|
3403
|
-
end
|
3443
|
+
|
3444
|
+
eager_load_data[r[:eager_loader]] = {:key_hash=>key_hash, :rows=>a, :associations=>associations, :self=>self, :eager_block=>eager_block, :id_map=>id_map}
|
3445
|
+
end
|
3446
|
+
|
3447
|
+
eager_load_data
|
3448
|
+
end
|
3449
|
+
|
3450
|
+
# Using the hash of loaders and eager options, perform the eager loading.
|
3451
|
+
def perform_eager_loads(eager_load_data)
|
3452
|
+
eager_load_data.map do |loader, eo|
|
3453
|
+
perform_eager_load(loader, eo)
|
3454
|
+
end
|
3455
|
+
end
|
3456
|
+
|
3457
|
+
# Perform eager loading for a single association using the loader and eager options.
|
3458
|
+
def perform_eager_load(loader, eo)
|
3459
|
+
loader.call(eo)
|
3404
3460
|
end
|
3405
3461
|
|
3406
3462
|
# Return a subquery expression for filering by a many_to_many association
|
data/lib/sequel/model/base.rb
CHANGED
@@ -1260,12 +1260,12 @@ module Sequel
|
|
1260
1260
|
# Once an object is frozen, you cannot modify it's values, changed_columns,
|
1261
1261
|
# errors, or dataset.
|
1262
1262
|
def freeze
|
1263
|
-
values.freeze
|
1264
|
-
_changed_columns.freeze
|
1265
1263
|
unless errors.frozen?
|
1266
1264
|
validate
|
1267
1265
|
errors.freeze
|
1268
1266
|
end
|
1267
|
+
values.freeze
|
1268
|
+
_changed_columns.freeze
|
1269
1269
|
this if !new? && model.primary_key
|
1270
1270
|
super
|
1271
1271
|
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
3
|
+
module Sequel
|
4
|
+
extension 'async_thread_pool'
|
5
|
+
|
6
|
+
module Plugins
|
7
|
+
# The async_thread_pool plugin makes it slightly easier to use the async_thread_pool
|
8
|
+
# Database extension with models. It makes Model.async return an async dataset for the
|
9
|
+
# model, and support async behavior for #destroy, #with_pk, and #with_pk! for model
|
10
|
+
# datasets:
|
11
|
+
#
|
12
|
+
# # Will load the artist with primary key 1 asynchronously
|
13
|
+
# artist = Artist.async.with_pk(1)
|
14
|
+
#
|
15
|
+
# You must load the async_thread_pool Database extension into the Database object the
|
16
|
+
# model class uses in order for async behavior to work.
|
17
|
+
#
|
18
|
+
# Usage:
|
19
|
+
#
|
20
|
+
# # Make all model subclass datasets support support async class methods and additional
|
21
|
+
# # async dataset methods
|
22
|
+
# Sequel::Model.plugin :async_thread_pool
|
23
|
+
#
|
24
|
+
# # Make the Album class support async class method and additional async dataset methods
|
25
|
+
# Album.plugin :async_thread_pool
|
26
|
+
module AsyncThreadPool
|
27
|
+
module ClassMethods
|
28
|
+
Plugins.def_dataset_methods(self, :async)
|
29
|
+
end
|
30
|
+
|
31
|
+
module DatasetMethods
|
32
|
+
[:destroy, :with_pk, :with_pk!].each do |meth|
|
33
|
+
::Sequel::Database::AsyncThreadPool::DatasetMethods.define_async_method(self, meth)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
@@ -14,7 +14,9 @@ module Sequel
|
|
14
14
|
# the plugin looks at the database schema for the model's table. To determine
|
15
15
|
# the unique validations, Sequel looks at the indexes on the table. In order
|
16
16
|
# for this plugin to be fully functional, the underlying database adapter needs
|
17
|
-
# to support both schema and index parsing.
|
17
|
+
# to support both schema and index parsing. Additionally, unique validations are
|
18
|
+
# only added for models that select from a simple table, they are not added for models
|
19
|
+
# that select from a subquery or joined dataset.
|
18
20
|
#
|
19
21
|
# This plugin uses the validation_helpers plugin underneath to implement the
|
20
22
|
# validations. It does not allow for any per-column validation message
|
@@ -51,6 +53,11 @@ module Sequel
|
|
51
53
|
# This works for unique_opts, max_length_opts, schema_types_opts,
|
52
54
|
# explicit_not_null_opts, and not_null_opts.
|
53
55
|
#
|
56
|
+
# If you only want auto_validations to add validations to columns that do not already
|
57
|
+
# have an error associated with them, you can use the skip_invalid option:
|
58
|
+
#
|
59
|
+
# Model.plugin :auto_validations, skip_invalid: true
|
60
|
+
#
|
54
61
|
# Usage:
|
55
62
|
#
|
56
63
|
# # Make all model subclass use auto validations (called before loading subclasses)
|
@@ -100,6 +107,13 @@ module Sequel
|
|
100
107
|
h[type] = h[type].merge(type_opts).freeze
|
101
108
|
end
|
102
109
|
end
|
110
|
+
|
111
|
+
if opts[:skip_invalid]
|
112
|
+
[:not_null, :explicit_not_null, :max_length, :schema_types].each do |type|
|
113
|
+
h[type] = h[type].merge(:skip_invalid=>true).freeze
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
103
117
|
@auto_validate_options = h.freeze
|
104
118
|
end
|
105
119
|
end
|