sequel 5.108.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/lib/sequel/adapters/amalgalite.rb +34 -8
- data/lib/sequel/adapters/jdbc/mssql.rb +28 -5
- data/lib/sequel/adapters/jdbc/postgresql.rb +14 -3
- data/lib/sequel/adapters/jdbc.rb +2 -1
- data/lib/sequel/adapters/postgres.rb +5 -2
- data/lib/sequel/adapters/shared/db2.rb +3 -0
- data/lib/sequel/adapters/shared/mssql.rb +7 -1
- data/lib/sequel/adapters/shared/postgres.rb +19 -990
- data/lib/sequel/adapters/shared/sqlanywhere.rb +0 -32
- data/lib/sequel/adapters/sqlite.rb +13 -9
- data/lib/sequel/adapters/trilogy.rb +2 -1
- data/lib/sequel/core.rb +14 -2
- data/lib/sequel/database/misc.rb +1 -6
- data/lib/sequel/database/transactions.rb +1 -3
- data/lib/sequel/dataset/actions.rb +1 -1
- data/lib/sequel/dataset/sql.rb +14 -3
- data/lib/sequel/extensions/core_refinements.rb +1 -4
- data/lib/sequel/extensions/duplicate_columns_handler.rb +1 -3
- data/lib/sequel/extensions/lit_require_frozen.rb +17 -1
- data/lib/sequel/extensions/named_timezones.rb +1 -1
- data/lib/sequel/extensions/pg_array.rb +1 -0
- data/lib/sequel/extensions/pg_json_ops.rb +4 -2
- data/lib/sequel/extensions/s.rb +4 -8
- data/lib/sequel/extensions/schema_dumper.rb +6 -2
- data/lib/sequel/extensions/symbol_aref.rb +11 -31
- data/lib/sequel/extensions/symbol_aref_refinement.rb +1 -4
- data/lib/sequel/extensions/symbol_as.rb +1 -2
- data/lib/sequel/extensions/symbol_as_refinement.rb +1 -5
- data/lib/sequel/model/base.rb +1 -6
- data/lib/sequel/plugins/caching.rb +27 -2
- data/lib/sequel/plugins/csv_serializer.rb +9 -20
- data/lib/sequel/plugins/instance_filters.rb +8 -0
- data/lib/sequel/plugins/instance_hooks.rb +19 -0
- 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_xmin_optimistic_locking.rb +11 -2
- data/lib/sequel/plugins/select_on_skipped_update.rb +63 -0
- data/lib/sequel/plugins/single_table_inheritance.rb +20 -2
- data/lib/sequel/plugins/subset_conditions.rb +5 -16
- data/lib/sequel/plugins/throw_failures.rb +1 -1
- data/lib/sequel/plugins/validate_associated.rb +7 -1
- data/lib/sequel/plugins/validate_associated_context.rb +52 -0
- data/lib/sequel/sql.rb +109 -105
- data/lib/sequel/version.rb +1 -1
- metadata +5 -3
|
@@ -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
|
|
@@ -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
|
|
|
@@ -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
|
|
@@ -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
|
|
@@ -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
|
|
@@ -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
|
-
# simplecov:disable
|
|
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
|
-
# simplecov:enable
|
|
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
|
|
@@ -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)
|
|
@@ -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
|
data/lib/sequel/sql.rb
CHANGED
|
@@ -1060,123 +1060,127 @@ module Sequel
|
|
|
1060
1060
|
# in a boolean value in SQL.
|
|
1061
1061
|
class BooleanExpression < ComplexExpression
|
|
1062
1062
|
include BooleanMethods
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
if
|
|
1102
|
-
|
|
1063
|
+
|
|
1064
|
+
module ClassMethods
|
|
1065
|
+
# Take pairs of values (e.g. a hash or array of two element arrays)
|
|
1066
|
+
# and converts it to a +BooleanExpression+. The operator and args
|
|
1067
|
+
# used depends on the case of the right (2nd) argument:
|
|
1068
|
+
#
|
|
1069
|
+
# 0..10 :: left >= 0 AND left <= 10
|
|
1070
|
+
# [1,2] :: left IN (1,2)
|
|
1071
|
+
# nil :: left IS NULL
|
|
1072
|
+
# true :: left IS TRUE
|
|
1073
|
+
# false :: left IS FALSE
|
|
1074
|
+
# /as/ :: left ~ 'as'
|
|
1075
|
+
# :blah :: left = blah
|
|
1076
|
+
# 'blah' :: left = 'blah'
|
|
1077
|
+
#
|
|
1078
|
+
# If multiple arguments are given, they are joined with the op given (AND
|
|
1079
|
+
# by default, OR possible). If negate is set to true,
|
|
1080
|
+
# all subexpressions are inverted before used. Therefore, the following
|
|
1081
|
+
# expressions are equivalent:
|
|
1082
|
+
#
|
|
1083
|
+
# ~from_value_pairs(hash)
|
|
1084
|
+
# from_value_pairs(hash, :OR, true)
|
|
1085
|
+
def from_value_pairs(pairs, op=:AND, negate=false)
|
|
1086
|
+
pairs = pairs.map{|l,r| from_value_pair(l, r)}
|
|
1087
|
+
pairs.map!{|ce| invert(ce)} if negate
|
|
1088
|
+
pairs.length == 1 ? pairs[0] : new(op, *pairs)
|
|
1089
|
+
end
|
|
1090
|
+
|
|
1091
|
+
# Return a BooleanExpression based on the right side of the pair.
|
|
1092
|
+
def from_value_pair(l, r)
|
|
1093
|
+
case r
|
|
1094
|
+
when Range
|
|
1095
|
+
unless r.begin.nil?
|
|
1096
|
+
begin_expr = new(:>=, l, r.begin)
|
|
1097
|
+
end
|
|
1098
|
+
unless r.end.nil?
|
|
1099
|
+
end_expr = new(r.exclude_end? ? :< : :<=, l, r.end)
|
|
1100
|
+
end
|
|
1101
|
+
if begin_expr
|
|
1102
|
+
if end_expr
|
|
1103
|
+
new(:AND, begin_expr, end_expr)
|
|
1104
|
+
else
|
|
1105
|
+
begin_expr
|
|
1106
|
+
end
|
|
1107
|
+
elsif end_expr
|
|
1108
|
+
end_expr
|
|
1103
1109
|
else
|
|
1104
|
-
|
|
1110
|
+
new(:'=', 1, 1)
|
|
1105
1111
|
end
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
r.transform do |v|
|
|
1132
|
-
if prev_transform
|
|
1133
|
-
v = prev_transform.call(v)
|
|
1112
|
+
when ::Array, ::Set
|
|
1113
|
+
r = r.dup.freeze unless r.frozen?
|
|
1114
|
+
new(:IN, l, r)
|
|
1115
|
+
when ::String
|
|
1116
|
+
r = r.dup.freeze unless r.frozen?
|
|
1117
|
+
new(:'=', l, r)
|
|
1118
|
+
when ::Sequel::Dataset
|
|
1119
|
+
new(:IN, l, r)
|
|
1120
|
+
when NegativeBooleanConstant
|
|
1121
|
+
new(:"IS NOT", l, r.constant)
|
|
1122
|
+
when BooleanConstant
|
|
1123
|
+
new(:IS, l, r.constant)
|
|
1124
|
+
when NilClass, TrueClass, FalseClass
|
|
1125
|
+
new(:IS, l, r)
|
|
1126
|
+
when Regexp
|
|
1127
|
+
StringExpression.like(l, r)
|
|
1128
|
+
when DelayedEvaluation
|
|
1129
|
+
Sequel.delay{|ds| from_value_pair(l, r.call(ds))}
|
|
1130
|
+
when Dataset::PlaceholderLiteralizer::Argument
|
|
1131
|
+
prev_transform = r.instance_variable_get(:@transformer)
|
|
1132
|
+
r.transform do |v|
|
|
1133
|
+
if prev_transform
|
|
1134
|
+
v = prev_transform.call(v)
|
|
1135
|
+
end
|
|
1136
|
+
from_value_pair(l, v)
|
|
1134
1137
|
end
|
|
1135
|
-
|
|
1138
|
+
else
|
|
1139
|
+
new(:'=', l, r)
|
|
1136
1140
|
end
|
|
1137
|
-
else
|
|
1138
|
-
new(:'=', l, r)
|
|
1139
1141
|
end
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1142
|
+
private :from_value_pair
|
|
1143
|
+
|
|
1144
|
+
# Invert the expression, if possible. If the expression cannot
|
|
1145
|
+
# be inverted, raise an error. An inverted expression should match everything that the
|
|
1146
|
+
# uninverted expression did not match, and vice-versa, except for possible issues with
|
|
1147
|
+
# SQL NULL (i.e. 1 == NULL is NULL and 1 != NULL is also NULL).
|
|
1148
|
+
#
|
|
1149
|
+
# BooleanExpression.invert(:a) # NOT "a"
|
|
1150
|
+
def invert(ce)
|
|
1151
|
+
case ce
|
|
1152
|
+
when BooleanExpression
|
|
1153
|
+
case op = ce.op
|
|
1154
|
+
when :AND, :OR
|
|
1155
|
+
BooleanExpression.new(ComplexExpression::OPERATOR_INVERSIONS[op], *ce.args.map{|a| BooleanExpression.invert(a)})
|
|
1156
|
+
when :IN, :"NOT IN"
|
|
1157
|
+
BooleanExpression.new(ComplexExpression::OPERATOR_INVERSIONS[op], *ce.args.dup)
|
|
1158
|
+
else
|
|
1159
|
+
if ce.args.length == 2
|
|
1160
|
+
case ce.args[1]
|
|
1161
|
+
when Function, LiteralString, PlaceholderLiteralString
|
|
1162
|
+
# Special behavior to not push down inversion in this case because doing so
|
|
1163
|
+
# can result in incorrect behavior for ANY/SOME/ALL operators.
|
|
1164
|
+
BooleanExpression.new(:NOT, ce)
|
|
1165
|
+
else
|
|
1166
|
+
BooleanExpression.new(ComplexExpression::OPERATOR_INVERSIONS[op], *ce.args.dup)
|
|
1167
|
+
end
|
|
1164
1168
|
else
|
|
1165
|
-
BooleanExpression.new(OPERATOR_INVERSIONS[op], *ce.args.dup)
|
|
1169
|
+
BooleanExpression.new(ComplexExpression::OPERATOR_INVERSIONS[op], *ce.args.dup)
|
|
1166
1170
|
end
|
|
1167
|
-
else
|
|
1168
|
-
BooleanExpression.new(OPERATOR_INVERSIONS[op], *ce.args.dup)
|
|
1169
1171
|
end
|
|
1172
|
+
when StringExpression, NumericExpression
|
|
1173
|
+
raise(Sequel::Error, "cannot invert #{ce.inspect}")
|
|
1174
|
+
when Constant
|
|
1175
|
+
ComplexExpression::CONSTANT_INVERSIONS[ce] || raise(Sequel::Error, "cannot invert #{ce.inspect}")
|
|
1176
|
+
else
|
|
1177
|
+
BooleanExpression.new(:NOT, ce)
|
|
1170
1178
|
end
|
|
1171
|
-
when StringExpression, NumericExpression
|
|
1172
|
-
raise(Sequel::Error, "cannot invert #{ce.inspect}")
|
|
1173
|
-
when Constant
|
|
1174
|
-
CONSTANT_INVERSIONS[ce] || raise(Sequel::Error, "cannot invert #{ce.inspect}")
|
|
1175
|
-
else
|
|
1176
|
-
BooleanExpression.new(:NOT, ce)
|
|
1177
1179
|
end
|
|
1178
1180
|
end
|
|
1179
1181
|
|
|
1182
|
+
extend ClassMethods
|
|
1183
|
+
|
|
1180
1184
|
# Always use an AND operator for & on BooleanExpressions
|
|
1181
1185
|
def &(ce)
|
|
1182
1186
|
BooleanExpression.new(:AND, self, ce)
|
data/lib/sequel/version.rb
CHANGED
|
@@ -6,7 +6,7 @@ module Sequel
|
|
|
6
6
|
|
|
7
7
|
# The minor version of Sequel. Bumped for every non-patch level
|
|
8
8
|
# release, generally around once a month.
|
|
9
|
-
MINOR =
|
|
9
|
+
MINOR = 109
|
|
10
10
|
|
|
11
11
|
# The tiny version of Sequel. Usually 0, only bumped for bugfix
|
|
12
12
|
# releases that fix regressions from previous versions.
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: sequel
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 5.
|
|
4
|
+
version: 5.109.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Jeremy Evans
|
|
@@ -386,6 +386,7 @@ files:
|
|
|
386
386
|
- lib/sequel/plugins/primary_key_lookup_check_values.rb
|
|
387
387
|
- lib/sequel/plugins/rcte_tree.rb
|
|
388
388
|
- lib/sequel/plugins/require_valid_schema.rb
|
|
389
|
+
- lib/sequel/plugins/select_on_skipped_update.rb
|
|
389
390
|
- lib/sequel/plugins/serialization.rb
|
|
390
391
|
- lib/sequel/plugins/serialization_modification_detection.rb
|
|
391
392
|
- lib/sequel/plugins/sharding.rb
|
|
@@ -416,6 +417,7 @@ files:
|
|
|
416
417
|
- lib/sequel/plugins/update_refresh.rb
|
|
417
418
|
- lib/sequel/plugins/uuid.rb
|
|
418
419
|
- lib/sequel/plugins/validate_associated.rb
|
|
420
|
+
- lib/sequel/plugins/validate_associated_context.rb
|
|
419
421
|
- lib/sequel/plugins/validation_class_methods.rb
|
|
420
422
|
- lib/sequel/plugins/validation_contexts.rb
|
|
421
423
|
- lib/sequel/plugins/validation_helpers.rb
|
|
@@ -448,14 +450,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
448
450
|
requirements:
|
|
449
451
|
- - ">="
|
|
450
452
|
- !ruby/object:Gem::Version
|
|
451
|
-
version:
|
|
453
|
+
version: '2.0'
|
|
452
454
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
453
455
|
requirements:
|
|
454
456
|
- - ">="
|
|
455
457
|
- !ruby/object:Gem::Version
|
|
456
458
|
version: '0'
|
|
457
459
|
requirements: []
|
|
458
|
-
rubygems_version: 4.0.
|
|
460
|
+
rubygems_version: 4.0.20
|
|
459
461
|
specification_version: 4
|
|
460
462
|
summary: The Database Toolkit for Ruby
|
|
461
463
|
test_files: []
|