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