sequel 5.8.0 → 5.9.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 +30 -0
- data/doc/release_notes/5.9.0.txt +99 -0
- data/doc/testing.rdoc +10 -10
- data/lib/sequel/adapters/ado.rb +1 -1
- data/lib/sequel/adapters/amalgalite.rb +1 -1
- data/lib/sequel/adapters/jdbc.rb +19 -7
- data/lib/sequel/adapters/jdbc/oracle.rb +1 -1
- data/lib/sequel/adapters/jdbc/postgresql.rb +0 -5
- data/lib/sequel/adapters/postgres.rb +3 -3
- data/lib/sequel/adapters/shared/access.rb +5 -6
- data/lib/sequel/adapters/shared/mysql.rb +28 -2
- data/lib/sequel/adapters/shared/postgres.rb +16 -6
- data/lib/sequel/adapters/shared/sqlite.rb +1 -1
- data/lib/sequel/adapters/sqlanywhere.rb +1 -1
- data/lib/sequel/adapters/sqlite.rb +2 -2
- data/lib/sequel/connection_pool.rb +2 -1
- data/lib/sequel/connection_pool/sharded_threaded.rb +12 -4
- data/lib/sequel/connection_pool/threaded.rb +19 -7
- data/lib/sequel/core.rb +1 -1
- data/lib/sequel/database/connecting.rb +6 -6
- data/lib/sequel/database/misc.rb +3 -3
- data/lib/sequel/database/query.rb +2 -2
- data/lib/sequel/database/schema_generator.rb +9 -3
- data/lib/sequel/database/schema_methods.rb +12 -5
- data/lib/sequel/dataset/features.rb +5 -0
- data/lib/sequel/dataset/misc.rb +1 -1
- data/lib/sequel/dataset/prepared_statements.rb +4 -4
- data/lib/sequel/dataset/query.rb +5 -0
- data/lib/sequel/dataset/sql.rb +8 -6
- data/lib/sequel/extensions/escaped_like.rb +100 -0
- data/lib/sequel/extensions/eval_inspect.rb +3 -1
- data/lib/sequel/extensions/looser_typecasting.rb +3 -3
- data/lib/sequel/extensions/pg_extended_date_support.rb +23 -10
- data/lib/sequel/model/associations.rb +18 -4
- data/lib/sequel/model/base.rb +9 -2
- data/lib/sequel/plugins/defaults_setter.rb +1 -1
- data/lib/sequel/plugins/many_through_many.rb +1 -1
- data/lib/sequel/plugins/nested_attributes.rb +2 -2
- data/lib/sequel/plugins/pg_auto_constraint_validations.rb +2 -2
- data/lib/sequel/plugins/rcte_tree.rb +5 -7
- data/lib/sequel/plugins/sharding.rb +2 -2
- data/lib/sequel/plugins/tactical_eager_loading.rb +1 -1
- data/lib/sequel/plugins/tree.rb +2 -2
- data/lib/sequel/plugins/validation_class_methods.rb +1 -1
- data/lib/sequel/sql.rb +2 -2
- data/lib/sequel/version.rb +4 -1
- data/spec/adapters/mysql_spec.rb +24 -0
- data/spec/adapters/postgres_spec.rb +9 -9
- data/spec/adapters/sqlite_spec.rb +10 -10
- data/spec/core/connection_pool_spec.rb +22 -0
- data/spec/core/database_spec.rb +6 -6
- data/spec/core/dataset_spec.rb +16 -5
- data/spec/core/expression_filters_spec.rb +1 -1
- data/spec/core/schema_spec.rb +1 -1
- data/spec/core/version_spec.rb +7 -0
- data/spec/extensions/connection_expiration_spec.rb +20 -2
- data/spec/extensions/connection_validator_spec.rb +20 -3
- data/spec/extensions/escaped_like_spec.rb +40 -0
- data/spec/extensions/eval_inspect_spec.rb +1 -1
- data/spec/extensions/nested_attributes_spec.rb +6 -0
- data/spec/extensions/pg_array_spec.rb +13 -13
- data/spec/extensions/pg_auto_constraint_validations_spec.rb +0 -1
- data/spec/extensions/pg_range_spec.rb +1 -1
- data/spec/extensions/schema_dumper_spec.rb +2 -2
- data/spec/extensions/sql_expr_spec.rb +1 -1
- data/spec/extensions/string_agg_spec.rb +1 -1
- data/spec/extensions/timestamps_spec.rb +2 -2
- data/spec/extensions/validation_helpers_spec.rb +1 -1
- data/spec/integration/associations_test.rb +12 -0
- data/spec/integration/dataset_test.rb +21 -0
- data/spec/integration/type_test.rb +4 -4
- data/spec/model/base_spec.rb +9 -0
- data/spec/model/eager_loading_spec.rb +25 -0
- data/spec/model/record_spec.rb +1 -1
- metadata +6 -2
data/lib/sequel/dataset/query.rb
CHANGED
@@ -113,6 +113,11 @@ module Sequel
|
|
113
113
|
# DB[:items].distinct # SQL: SELECT DISTINCT * FROM items
|
114
114
|
# DB[:items].order(:id).distinct(:id) # SQL: SELECT DISTINCT ON (id) * FROM items ORDER BY id
|
115
115
|
# DB[:items].order(:id).distinct{func(:id)} # SQL: SELECT DISTINCT ON (func(id)) * FROM items ORDER BY id
|
116
|
+
#
|
117
|
+
# There is support for emualting the DISTINCT ON support in MySQL, but it
|
118
|
+
# does not support the ORDER of the dataset, and also doesn't work in many
|
119
|
+
# cases if the ONLY_FULL_GROUP_BY sql_mode is used, which is the default on
|
120
|
+
# MySQL 5.7.5+.
|
116
121
|
def distinct(*args, &block)
|
117
122
|
virtual_row_columns(args, block)
|
118
123
|
if args.empty?
|
data/lib/sequel/dataset/sql.rb
CHANGED
@@ -28,7 +28,7 @@ module Sequel
|
|
28
28
|
|
29
29
|
case values.size
|
30
30
|
when 0
|
31
|
-
return insert_sql(
|
31
|
+
return insert_sql(OPTS)
|
32
32
|
when 1
|
33
33
|
case vals = values[0]
|
34
34
|
when Hash
|
@@ -389,8 +389,10 @@ module Sequel
|
|
389
389
|
literal_append(sql, args[0])
|
390
390
|
sql << ' ' << op.to_s << ' '
|
391
391
|
literal_append(sql, args[1])
|
392
|
-
|
393
|
-
|
392
|
+
if requires_like_escape?
|
393
|
+
sql << " ESCAPE "
|
394
|
+
literal_append(sql, "\\")
|
395
|
+
end
|
394
396
|
sql << ')'
|
395
397
|
when :ILIKE, :'NOT ILIKE'
|
396
398
|
complex_expression_sql_append(sql, (op == :ILIKE ? :LIKE : :"NOT LIKE"), args.map{|v| Sequel.function(:UPPER, v)})
|
@@ -577,7 +579,7 @@ module Sequel
|
|
577
579
|
sql << str
|
578
580
|
else
|
579
581
|
re = /:(#{args.keys.map{|k| Regexp.escape(k.to_s)}.join('|')})\b/
|
580
|
-
|
582
|
+
while true
|
581
583
|
previous, q, str = str.partition(re)
|
582
584
|
sql << previous
|
583
585
|
literal_append(sql, args[($1||q[1..-1].to_s).to_sym]) unless q.empty?
|
@@ -596,13 +598,13 @@ module Sequel
|
|
596
598
|
else
|
597
599
|
i = -1
|
598
600
|
match_len = args.length - 1
|
599
|
-
|
601
|
+
while true
|
600
602
|
previous, q, str = str.partition('?')
|
601
603
|
sql << previous
|
602
604
|
literal_append(sql, args.at(i+=1)) unless q.empty?
|
603
605
|
if str.empty?
|
604
606
|
unless i == match_len
|
605
|
-
raise Error, "Mismatched number of placeholders (#{i+1}) and placeholder arguments (#{args.length}) when using placeholder
|
607
|
+
raise Error, "Mismatched number of placeholders (#{i+1}) and placeholder arguments (#{args.length}) when using placeholder string"
|
606
608
|
end
|
607
609
|
break
|
608
610
|
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
#
|
3
|
+
# The escaped_like extension adds +escaped_like+ and +escaped_ilike+
|
4
|
+
# methods to Sequel::SQL::StringMethods, which allow them to be easily
|
5
|
+
# used with most of Sequel's expression objects. Example:
|
6
|
+
#
|
7
|
+
# DB[:table].where{string_column.escaped_like('?%', user_input)}
|
8
|
+
# # user_input is 'foo':
|
9
|
+
# # SELECT * FROM table WHERE string_column LIKE 'foo%' ESCAPE '\'
|
10
|
+
# # user_input is '%foo':
|
11
|
+
# # SELECT * FROM table WHERE string_column LIKE '\%foo%' ESCAPE '\'
|
12
|
+
#
|
13
|
+
# To load the extension:
|
14
|
+
#
|
15
|
+
# Sequel.extension :escaped_like
|
16
|
+
#
|
17
|
+
# Related modules: Sequel::SQL::StringMethods, Sequel::SQL::EscapedLikeExpression
|
18
|
+
|
19
|
+
#
|
20
|
+
module Sequel
|
21
|
+
module SQL
|
22
|
+
# Represents an pattern match SQL expression, where the pattern can depend
|
23
|
+
# upon interpolated values in a database-dependent manner.
|
24
|
+
class EscapedLikeExpression < Expression
|
25
|
+
include AliasMethods
|
26
|
+
include BooleanMethods
|
27
|
+
include CastMethods
|
28
|
+
include OrderMethods
|
29
|
+
|
30
|
+
# Initialize the expression. Arguments:
|
31
|
+
# expr :: Right hand site of LIKE/ILIKE operator, what you are matching against the pattern
|
32
|
+
# case_insensitive :: Whether the match is case sensitive
|
33
|
+
# placeholder_pattern :: The pattern to match against, with +?+ for the placeholders
|
34
|
+
# placeholder_values :: The string values for each +?+ in the placeholder pattern. Should be an
|
35
|
+
# array of strings, though it can be a single string if there is only
|
36
|
+
# a single placeholder.
|
37
|
+
def initialize(expr, case_sensitive, placeholder_pattern, placeholder_values)
|
38
|
+
@expr = expr
|
39
|
+
@method = case_sensitive ? :like : :ilike
|
40
|
+
@pattern = placeholder_pattern
|
41
|
+
unless placeholder_values.is_a?(Array)
|
42
|
+
placeholder_values = [placeholder_values].freeze
|
43
|
+
end
|
44
|
+
@values = placeholder_values
|
45
|
+
freeze
|
46
|
+
end
|
47
|
+
|
48
|
+
# Interpolate the pattern values into the placeholder pattern to get the final pattern,
|
49
|
+
# now that we have access to the dataset. Use the expression and final pattern and
|
50
|
+
# add an appropriate LIKE/ILIKE expression to the SQL being built.
|
51
|
+
def to_s_append(ds, sql)
|
52
|
+
i = -1
|
53
|
+
match_len = @values.length - 1
|
54
|
+
like_pattern = String.new
|
55
|
+
pattern = @pattern
|
56
|
+
while true
|
57
|
+
previous, q, pattern = pattern.partition('?')
|
58
|
+
like_pattern << previous
|
59
|
+
|
60
|
+
unless q.empty?
|
61
|
+
if i == match_len
|
62
|
+
raise Error, "Mismatched number of placeholders (#{i+1}) and placeholder arguments (#{@values.length}) for escaped like expression: #{@pattern.inspect}"
|
63
|
+
end
|
64
|
+
like_pattern << ds.escape_like(@values.at(i+=1))
|
65
|
+
end
|
66
|
+
|
67
|
+
if pattern.empty?
|
68
|
+
unless i == match_len
|
69
|
+
raise Error, "Mismatched number of placeholders (#{i+1}) and placeholder arguments (#{@values.length}) for escaped like expression: #{@pattern.inspect}"
|
70
|
+
end
|
71
|
+
break
|
72
|
+
end
|
73
|
+
end
|
74
|
+
ds.literal_append(sql, Sequel.send(@method, @expr, like_pattern))
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
module StringMethods
|
79
|
+
# Create a +EscapedLikeExpression+ case insensitive pattern match of the receiver
|
80
|
+
# with the patterns, interpolated escaped values for each +?+ placeholder in the
|
81
|
+
# pattern.
|
82
|
+
#
|
83
|
+
# Sequel[:a].escaped_ilike('?%', 'A') # "a" ILIKE 'A%' ESCAPE '\'
|
84
|
+
# Sequel[:a].escaped_ilike('?%', '%A') # "a" ILIKE '\%A%' ESCAPE '\'
|
85
|
+
def escaped_ilike(placeholder_pattern, placeholder_values)
|
86
|
+
EscapedLikeExpression.new(self, false, placeholder_pattern, placeholder_values)
|
87
|
+
end
|
88
|
+
|
89
|
+
# Create a +EscapedLikeExpression+ case sensitive pattern match of the receiver
|
90
|
+
# with the patterns, interpolated escaped values for each +?+ placeholder in the
|
91
|
+
# pattern.
|
92
|
+
#
|
93
|
+
# Sequel[:a].escaped_like('?%', 'A') # "a" LIKE 'A%' ESCAPE '\'
|
94
|
+
# Sequel[:a].escaped_like('?%', '%A') # "a" LIKE '\%A%' ESCAPE '\'
|
95
|
+
def escaped_like(placeholder_pattern, placeholder_values)
|
96
|
+
EscapedLikeExpression.new(self, true, placeholder_pattern, placeholder_values)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -26,7 +26,9 @@ module Sequel
|
|
26
26
|
# for eval.
|
27
27
|
def eval_inspect(obj)
|
28
28
|
case obj
|
29
|
-
when
|
29
|
+
when BigDecimal
|
30
|
+
"BigDecimal(#{obj.to_s.inspect})"
|
31
|
+
when Sequel::SQL::Blob, Sequel::LiteralString
|
30
32
|
"#{obj.class}.new(#{obj.to_s.inspect})"
|
31
33
|
when Sequel::SQL::ValueList
|
32
34
|
"#{obj.class}.new(#{obj.to_a.inspect})"
|
@@ -36,14 +36,14 @@ module Sequel
|
|
36
36
|
|
37
37
|
if RUBY_VERSION >= '2.4'
|
38
38
|
def _typecast_value_string_to_decimal(value)
|
39
|
-
BigDecimal
|
39
|
+
BigDecimal(value)
|
40
40
|
rescue
|
41
|
-
BigDecimal
|
41
|
+
BigDecimal('0.0')
|
42
42
|
end
|
43
43
|
else
|
44
44
|
# :nocov:
|
45
45
|
def _typecast_value_string_to_decimal(value)
|
46
|
-
BigDecimal
|
46
|
+
BigDecimal(value)
|
47
47
|
end
|
48
48
|
# :nocov:
|
49
49
|
end
|
@@ -86,9 +86,19 @@ module Sequel
|
|
86
86
|
if value.is_a?(String) && (m = value.match(/(?:(?:[-+]\d\d:\d\d)(:\d\d)?)?( BC)?\z/)) && (m[1] || m[2])
|
87
87
|
if m[2]
|
88
88
|
value = value.sub(' BC', '').sub(' ', ' BC ')
|
89
|
+
conv = defined?(JRUBY_VERSION) && JRUBY_VERSION == '9.2.0.0'
|
89
90
|
end
|
90
|
-
if m[1]
|
91
|
+
if m[1] || conv
|
91
92
|
dt = DateTime.parse(value)
|
93
|
+
if conv
|
94
|
+
# :nocov:
|
95
|
+
if Sequel.datetime_class == DateTime
|
96
|
+
dt >>= 12
|
97
|
+
else
|
98
|
+
dt >>= 24
|
99
|
+
end
|
100
|
+
# :nocov:
|
101
|
+
end
|
92
102
|
dt = dt.to_time unless Sequel.datetime_class == DateTime
|
93
103
|
Sequel.convert_output_timestamp(dt, Sequel.application_timezone)
|
94
104
|
else
|
@@ -191,15 +201,6 @@ module Sequel
|
|
191
201
|
if RUBY_ENGINE == 'jruby'
|
192
202
|
# :nocov:
|
193
203
|
|
194
|
-
# Work around JRuby bug #4822 in Time#to_datetime for times before date of calendar reform
|
195
|
-
def literal_time(time)
|
196
|
-
if time < TIME_YEAR_1
|
197
|
-
literal_datetime(DateTime.parse(super))
|
198
|
-
else
|
199
|
-
super
|
200
|
-
end
|
201
|
-
end
|
202
|
-
|
203
204
|
ExtendedDateSupport::CONVERT_TYPES = [Java::JavaSQL::Types::DATE, Java::JavaSQL::Types::TIMESTAMP]
|
204
205
|
|
205
206
|
# Use non-JDBC parsing as JDBC parsing doesn't work for BC dates/timestamps.
|
@@ -211,6 +212,18 @@ module Sequel
|
|
211
212
|
super
|
212
213
|
end
|
213
214
|
end
|
215
|
+
|
216
|
+
# Work around JRuby bug #4822 in Time#to_datetime for times before date of calendar reform
|
217
|
+
def literal_time(time)
|
218
|
+
if time < TIME_YEAR_1
|
219
|
+
dt = DateTime.parse(super)
|
220
|
+
# Work around JRuby bug #5191
|
221
|
+
dt >>= 12 if JRUBY_VERSION == '9.2.0.0'
|
222
|
+
literal_datetime(dt)
|
223
|
+
else
|
224
|
+
super
|
225
|
+
end
|
226
|
+
end
|
214
227
|
# :nocov:
|
215
228
|
else
|
216
229
|
# Handle BC Time objects.
|
@@ -2751,7 +2751,7 @@ module Sequel
|
|
2751
2751
|
opts = @opts[:eager]
|
2752
2752
|
association_opts = eager_options_for_associations(associations)
|
2753
2753
|
opts = opts ? Hash[opts].merge!(association_opts) : association_opts
|
2754
|
-
clone(:eager=>opts)
|
2754
|
+
clone(:eager=>opts.freeze)
|
2755
2755
|
end
|
2756
2756
|
|
2757
2757
|
# The secondary eager loading method. Loads all associations in a single query. This
|
@@ -2800,8 +2800,9 @@ module Sequel
|
|
2800
2800
|
# significantly slower in some cases (perhaps even the majority of cases), so you should
|
2801
2801
|
# only use this if you have benchmarked that it is faster for your use cases.
|
2802
2802
|
def eager_graph_with_options(associations, opts=OPTS)
|
2803
|
+
opts = opts.dup unless opts.frozen?
|
2803
2804
|
associations = [associations] unless associations.is_a?(Array)
|
2804
|
-
if eg = @opts[:eager_graph]
|
2805
|
+
ds = if eg = @opts[:eager_graph]
|
2805
2806
|
eg = eg.dup
|
2806
2807
|
[:requirements, :reflections, :reciprocals, :limits].each{|k| eg[k] = eg[k].dup}
|
2807
2808
|
eg[:local] = opts
|
@@ -2815,8 +2816,12 @@ module Sequel
|
|
2815
2816
|
# :limits :: Any limit/offset array slicing that need to be handled in ruby land after loading
|
2816
2817
|
opts = {:requirements=>{}, :master=>alias_symbol(first_source), :reflections=>{}, :reciprocals=>{}, :limits=>{}, :local=>opts, :cartesian_product_number=>0, :row_proc=>row_proc}
|
2817
2818
|
ds = clone(:eager_graph=>opts)
|
2818
|
-
ds.eager_graph_associations(ds, model, ds.opts[:eager_graph][:master], [], *associations).naked
|
2819
|
+
ds = ds.eager_graph_associations(ds, model, ds.opts[:eager_graph][:master], [], *associations).naked
|
2819
2820
|
end
|
2821
|
+
|
2822
|
+
ds.opts[:eager_graph].freeze
|
2823
|
+
ds.opts[:eager_graph].each_value{|v| v.freeze if v.is_a?(Hash)}
|
2824
|
+
ds
|
2820
2825
|
end
|
2821
2826
|
|
2822
2827
|
# If the dataset is being eagerly loaded, default to calling all
|
@@ -3081,7 +3086,7 @@ module Sequel
|
|
3081
3086
|
associations = eager_assoc[r[:name]]
|
3082
3087
|
if associations.respond_to?(:call)
|
3083
3088
|
eager_block = associations
|
3084
|
-
associations =
|
3089
|
+
associations = OPTS
|
3085
3090
|
elsif associations.is_a?(Hash) && associations.length == 1 && (pr_assoc = associations.to_a.first) && pr_assoc.first.respond_to?(:call)
|
3086
3091
|
eager_block, associations = pr_assoc
|
3087
3092
|
end
|
@@ -3353,6 +3358,15 @@ module Sequel
|
|
3353
3358
|
key = hkey(ta_h)
|
3354
3359
|
end
|
3355
3360
|
rm, rp, assoc_name, tm, rcm = @ta_map[ta]
|
3361
|
+
|
3362
|
+
# Check type map for all dependencies, and use a unique
|
3363
|
+
# object if any are dependencies for multiple objects,
|
3364
|
+
# to prevent duplicate objects from showing up in the case
|
3365
|
+
# the normal duplicate removal code is not being used.
|
3366
|
+
if !@unique && !deps.empty? && deps.any?{|dep_key,_| @ta_map[dep_key][3]}
|
3367
|
+
key = [current.object_id, key]
|
3368
|
+
end
|
3369
|
+
|
3356
3370
|
unless rec = rm[key]
|
3357
3371
|
rec = rm[key] = rp.call(hfor(ta, h))
|
3358
3372
|
end
|
data/lib/sequel/model/base.rb
CHANGED
@@ -250,7 +250,7 @@ module Sequel
|
|
250
250
|
# Artist.create do |a|
|
251
251
|
# a.name = 'Jim'
|
252
252
|
# end # INSERT INTO artists (name) VALUES ('Jim')
|
253
|
-
def create(values =
|
253
|
+
def create(values = OPTS, &block)
|
254
254
|
new(values, &block).save
|
255
255
|
end
|
256
256
|
|
@@ -446,6 +446,13 @@ module Sequel
|
|
446
446
|
super
|
447
447
|
end
|
448
448
|
|
449
|
+
# Whether the model has a dataset. True for most model classes,
|
450
|
+
# but can be false if the model class is an abstract model class
|
451
|
+
# designed for subclassing, such as Sequel::Model itself.
|
452
|
+
def has_dataset?
|
453
|
+
!@dataset.nil?
|
454
|
+
end
|
455
|
+
|
449
456
|
# Clear the setter_methods cache when a module is included, as it
|
450
457
|
# may contain setter methods.
|
451
458
|
def include(*mods)
|
@@ -1055,7 +1062,7 @@ module Sequel
|
|
1055
1062
|
# Artist.new do |a|
|
1056
1063
|
# a.name = 'Bob'
|
1057
1064
|
# end
|
1058
|
-
def initialize(values =
|
1065
|
+
def initialize(values = OPTS)
|
1059
1066
|
@values = {}
|
1060
1067
|
@new = true
|
1061
1068
|
@modified = true
|
@@ -95,7 +95,7 @@ module Sequel
|
|
95
95
|
end
|
96
96
|
end
|
97
97
|
end
|
98
|
-
@default_values = h.merge!(@default_values ||
|
98
|
+
@default_values = h.merge!(@default_values || OPTS)
|
99
99
|
end
|
100
100
|
|
101
101
|
# Handle the CURRENT_DATE and CURRENT_TIMESTAMP values specially by returning an appropriate Date or
|
@@ -114,10 +114,10 @@ module Sequel
|
|
114
114
|
# If a block is provided, it is used to set the :reject_if option.
|
115
115
|
def nested_attributes(*associations, &block)
|
116
116
|
include(@nested_attributes_module ||= Module.new) unless @nested_attributes_module
|
117
|
-
opts = associations.last.is_a?(Hash) ? associations.pop :
|
117
|
+
opts = associations.last.is_a?(Hash) ? associations.pop : OPTS
|
118
118
|
reflections = associations.map{|a| association_reflection(a) || raise(Error, "no association named #{a} for #{self}")}
|
119
119
|
reflections.each do |r|
|
120
|
-
r[:nested_attributes] = opts
|
120
|
+
r[:nested_attributes] = opts.dup
|
121
121
|
r[:nested_attributes][:unmatched_pk] ||= :raise
|
122
122
|
r[:nested_attributes][:reject_if] ||= block
|
123
123
|
def_nested_attribute_method(r)
|
@@ -64,7 +64,7 @@ module Sequel
|
|
64
64
|
def self.configure(model, opts=OPTS)
|
65
65
|
model.instance_exec do
|
66
66
|
setup_pg_auto_constraint_validations
|
67
|
-
@pg_auto_constraint_validations_messages = (@pg_auto_constraint_validations_messages || DEFAULT_ERROR_MESSAGES).merge(opts[:messages] ||
|
67
|
+
@pg_auto_constraint_validations_messages = (@pg_auto_constraint_validations_messages || DEFAULT_ERROR_MESSAGES).merge(opts[:messages] || OPTS).freeze
|
68
68
|
end
|
69
69
|
end
|
70
70
|
|
@@ -195,7 +195,7 @@ module Sequel
|
|
195
195
|
end
|
196
196
|
end
|
197
197
|
end
|
198
|
-
rescue
|
198
|
+
rescue
|
199
199
|
# If there is an error trying to conver the constraint violation
|
200
200
|
# into a validation failure, it's best to just raise the constraint
|
201
201
|
# violation. This can make debugging the above block of code more
|
@@ -105,7 +105,6 @@ module Sequel
|
|
105
105
|
key_present = lambda{|m| key_conv[m].all?}
|
106
106
|
prkey_conv = lambda{|m| prkey_array.map{|k| m[k]}}
|
107
107
|
key_aliases = (0...key_array.length).map{|i| :"#{ka}_#{i}"}
|
108
|
-
ka_conv = lambda{|m| key_aliases.map{|k| m[k]}}
|
109
108
|
ancestor_base_case_columns = prkey_array.zip(key_aliases).map{|k, ka_| SQL::AliasedExpression.new(k, ka_)} + c_all
|
110
109
|
descendant_base_case_columns = key_array.zip(key_aliases).map{|k, ka_| SQL::AliasedExpression.new(k, ka_)} + c_all
|
111
110
|
recursive_case_columns = prkey_array.zip(key_aliases).map{|k, ka_| SQL::QualifiedIdentifier.new(t, ka_)} + c_all
|
@@ -114,18 +113,17 @@ module Sequel
|
|
114
113
|
key_present = key_conv = lambda{|m| m[key]}
|
115
114
|
prkey_conv = lambda{|m| m[prkey]}
|
116
115
|
key_aliases = [ka]
|
117
|
-
ka_conv = lambda{|m| m[ka]}
|
118
116
|
ancestor_base_case_columns = [SQL::AliasedExpression.new(prkey, ka)] + c_all
|
119
117
|
descendant_base_case_columns = [SQL::AliasedExpression.new(key, ka)] + c_all
|
120
118
|
recursive_case_columns = [SQL::QualifiedIdentifier.new(t, ka)] + c_all
|
121
119
|
extract_key_alias = lambda{|m| bd_conv[m.values.delete(ka)]}
|
122
120
|
end
|
123
121
|
|
124
|
-
parent = opts.merge(opts.fetch(:parent,
|
125
|
-
childrena = opts.merge(opts.fetch(:children,
|
122
|
+
parent = opts.merge(opts.fetch(:parent, OPTS)).fetch(:name, :parent)
|
123
|
+
childrena = opts.merge(opts.fetch(:children, OPTS)).fetch(:name, :children)
|
126
124
|
|
127
125
|
opts[:reciprocal] = nil
|
128
|
-
a = opts.merge(opts.fetch(:ancestors,
|
126
|
+
a = opts.merge(opts.fetch(:ancestors, OPTS))
|
129
127
|
ancestors = a.fetch(:name, :ancestors)
|
130
128
|
a[:read_only] = true unless a.has_key?(:read_only)
|
131
129
|
a[:eager_loader_key] = key
|
@@ -220,7 +218,7 @@ module Sequel
|
|
220
218
|
end
|
221
219
|
model.one_to_many ancestors, a
|
222
220
|
|
223
|
-
d = opts.merge(opts.fetch(:descendants,
|
221
|
+
d = opts.merge(opts.fetch(:descendants, OPTS))
|
224
222
|
descendants = d.fetch(:name, :descendants)
|
225
223
|
d[:read_only] = true unless d.has_key?(:read_only)
|
226
224
|
la = d[:level_alias] ||= :x_level_x
|
@@ -296,7 +294,7 @@ module Sequel
|
|
296
294
|
:args=>((key_aliases + col_aliases + (level ? [la] : [])) if col_aliases))
|
297
295
|
ds = r.apply_eager_dataset_changes(ds)
|
298
296
|
ds = ds.select_append(ka) unless ds.opts[:select] == nil
|
299
|
-
model.eager_load_results(r, eo.merge(:loader=>false, :initalize_rows=>false, :dataset=>ds, :id_map=>nil, :associations=>
|
297
|
+
model.eager_load_results(r, eo.merge(:loader=>false, :initalize_rows=>false, :dataset=>ds, :id_map=>nil, :associations=>OPTS)) do |obj|
|
300
298
|
if level
|
301
299
|
no_cache = no_cache_level == obj.values.delete(la)
|
302
300
|
end
|
@@ -21,7 +21,7 @@ module Sequel
|
|
21
21
|
module Sharding
|
22
22
|
module ClassMethods
|
23
23
|
# Create a new object on the given shard s.
|
24
|
-
def create_using_server(s, values=
|
24
|
+
def create_using_server(s, values=OPTS, &block)
|
25
25
|
new_using_server(s, values, &block).save
|
26
26
|
end
|
27
27
|
|
@@ -45,7 +45,7 @@ module Sequel
|
|
45
45
|
# Return a newly instantiated object that is tied to the given
|
46
46
|
# shard s. When the object is saved, a record will be inserted
|
47
47
|
# on shard s.
|
48
|
-
def new_using_server(s, values=
|
48
|
+
def new_using_server(s, values=OPTS, &block)
|
49
49
|
new(values, &block).set_server(s)
|
50
50
|
end
|
51
51
|
|