sequel 5.70.0 → 5.71.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 +10 -0
- data/doc/migration.rdoc +1 -0
- data/doc/release_notes/5.71.0.txt +21 -0
- data/lib/sequel/adapters/jdbc/postgresql.rb +3 -0
- data/lib/sequel/adapters/shared/postgres.rb +0 -2
- data/lib/sequel/extensions/migration.rb +4 -0
- data/lib/sequel/plugins/mssql_optimistic_locking.rb +8 -38
- data/lib/sequel/plugins/optimistic_locking.rb +9 -42
- data/lib/sequel/plugins/optimistic_locking_base.rb +55 -0
- data/lib/sequel/plugins/pg_xmin_optimistic_locking.rb +109 -0
- data/lib/sequel/version.rb +1 -1
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 17fbd14a63974634d39c289194210ea773d5e2017ad24ac3f6a5c89cc6eb481d
|
4
|
+
data.tar.gz: 390a9c664bf0a7710bb341ef8699e53b0ed2ea4d4fd2c221f7e140393d52047e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0af7a0afdad27b270d69eb8248e734408c0c132d209c111f03957a14d1fc2ef44fc4a6da66eaa4986dadf1565f428a140dc9b807bb0215117b015b69057445a1
|
7
|
+
data.tar.gz: a2aade8559d69fe43306b6834069e976f57809170e1a9102501e4031d899dd046119de95f485712024e68aa5b077cf63cccc74b7a77b244e821a2c42b87a09a3
|
data/CHANGELOG
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
=== 5.71.0 (2023-08-01)
|
2
|
+
|
3
|
+
* Support ILIKE ANY on PostgreSQL by not forcing the use of ESCAPE for ILIKE (gilesbowkett) (#2066)
|
4
|
+
|
5
|
+
* Add pg_xmin_optimistic_locking plugin for optimistic locking for all models without database changes (jeremyevans)
|
6
|
+
|
7
|
+
* Recognize the xid PostgreSQL type as an integer type in the jdbc/postgresql adapter (jeremyevans)
|
8
|
+
|
9
|
+
* Make set_column_allow_null method reversible in migrations (enescakir) (#2060)
|
10
|
+
|
1
11
|
=== 5.70.0 (2023-07-01)
|
2
12
|
|
3
13
|
* Make static_cache plugin better handle cases where forbid_lazy_load plugin is already loaded (jeremyevans)
|
data/doc/migration.rdoc
CHANGED
@@ -0,0 +1,21 @@
|
|
1
|
+
= New Features
|
2
|
+
|
3
|
+
* A pg_xmin_optimistic_locking plugin has been added. This plugin
|
4
|
+
uses PostgreSQL's xmin system column to implement optimistic
|
5
|
+
locking. The xmin system column is automatically updated whenever
|
6
|
+
the database row is updated. You can load this plugin into a
|
7
|
+
base model and have all models that subclass from it use optimistic
|
8
|
+
locking, without needing any user-defined lock columns.
|
9
|
+
|
10
|
+
= Other Improvements
|
11
|
+
|
12
|
+
* set_column_allow_null is now a reversible migration method inside
|
13
|
+
alter_table blocks.
|
14
|
+
|
15
|
+
* The use of ILIKE no longer forces the ESCAPE clause on PostgreSQL,
|
16
|
+
which allows the use of ILIKE ANY and other constructions. There
|
17
|
+
is no need to use the ESCAPE clause with ILIKE, because the value
|
18
|
+
Sequel uses is PostgreSQL's default.
|
19
|
+
|
20
|
+
* The xid PostgreSQL type is now recognized as an integer type in the
|
21
|
+
jdbc/postgresql adapter.
|
@@ -199,6 +199,7 @@ module Sequel
|
|
199
199
|
v.strftime("'%H:%M:%S#{sprintf(".%03d", (v.usec/1000.0).round)}'")
|
200
200
|
end
|
201
201
|
|
202
|
+
INTEGER_TYPE = Java::JavaSQL::Types::INTEGER
|
202
203
|
STRING_TYPE = Java::JavaSQL::Types::VARCHAR
|
203
204
|
ARRAY_TYPE = Java::JavaSQL::Types::ARRAY
|
204
205
|
PG_SPECIFIC_TYPES = [Java::JavaSQL::Types::ARRAY, Java::JavaSQL::Types::OTHER, Java::JavaSQL::Types::STRUCT, Java::JavaSQL::Types::TIME_WITH_TIMEZONE, Java::JavaSQL::Types::TIME].freeze
|
@@ -219,6 +220,8 @@ module Sequel
|
|
219
220
|
oid = meta.getField(i).getOID
|
220
221
|
if pr = db.oid_convertor_proc(oid)
|
221
222
|
pr
|
223
|
+
elsif oid == 28 # XID (Transaction ID)
|
224
|
+
map[INTEGER_TYPE]
|
222
225
|
elsif oid == 2950 # UUID
|
223
226
|
map[STRING_TYPE]
|
224
227
|
elsif meta.getPGType(i) == 'hstore'
|
@@ -270,6 +270,10 @@ module Sequel
|
|
270
270
|
def rename_column(name, new_name)
|
271
271
|
@actions << [:rename_column, new_name, name]
|
272
272
|
end
|
273
|
+
|
274
|
+
def set_column_allow_null(name, allow_null=true)
|
275
|
+
@actions << [:set_column_allow_null, name, !allow_null]
|
276
|
+
end
|
273
277
|
end
|
274
278
|
|
275
279
|
# The preferred method for writing Sequel migrations, using a DSL:
|
@@ -26,57 +26,27 @@ module Sequel
|
|
26
26
|
module MssqlOptimisticLocking
|
27
27
|
# Load the instance_filters plugin into the model.
|
28
28
|
def self.apply(model, opts=OPTS)
|
29
|
-
model.plugin
|
29
|
+
model.plugin(:optimistic_locking_base)
|
30
30
|
end
|
31
31
|
|
32
|
-
# Set the
|
32
|
+
# Set the lock column
|
33
33
|
def self.configure(model, opts=OPTS)
|
34
|
-
model.lock_column = opts[:lock_column] || :timestamp
|
34
|
+
model.lock_column = opts[:lock_column] || model.lock_column || :timestamp
|
35
35
|
end
|
36
|
-
|
37
|
-
module ClassMethods
|
38
|
-
# The timestamp/rowversion column containing the version for the current row.
|
39
|
-
attr_accessor :lock_column
|
40
|
-
|
41
|
-
Plugins.inherited_instance_variables(self, :@lock_column=>nil)
|
42
|
-
end
|
43
|
-
|
36
|
+
|
44
37
|
module InstanceMethods
|
45
|
-
# Add the lock column instance filter to the object before destroying it.
|
46
|
-
def before_destroy
|
47
|
-
lock_column_instance_filter
|
48
|
-
super
|
49
|
-
end
|
50
|
-
|
51
|
-
# Add the lock column instance filter to the object before updating it.
|
52
|
-
def before_update
|
53
|
-
lock_column_instance_filter
|
54
|
-
super
|
55
|
-
end
|
56
|
-
|
57
38
|
private
|
58
39
|
|
59
|
-
#
|
60
|
-
def
|
61
|
-
|
62
|
-
instance_filter(lc=>Sequel.blob(get_column_value(lc)))
|
63
|
-
end
|
64
|
-
|
65
|
-
# Clear the instance filters when refreshing, so that attempting to
|
66
|
-
# refresh after a failed save removes the previous lock column filter
|
67
|
-
# (the new one will be added before updating).
|
68
|
-
def _refresh(ds)
|
69
|
-
clear_instance_filters
|
70
|
-
super
|
40
|
+
# Make the instance filter value a blob.
|
41
|
+
def lock_column_instance_filter_value
|
42
|
+
Sequel.blob(super)
|
71
43
|
end
|
72
44
|
|
73
45
|
# Remove the lock column from the columns to update.
|
74
46
|
# SQL Server automatically updates the lock column value, and does not like
|
75
47
|
# it to be assigned.
|
76
48
|
def _save_update_all_columns_hash
|
77
|
-
v =
|
78
|
-
cc = changed_columns
|
79
|
-
Array(primary_key).each{|x| v.delete(x) unless cc.include?(x)}
|
49
|
+
v = super
|
80
50
|
v.delete(model.lock_column)
|
81
51
|
v
|
82
52
|
end
|
@@ -12,64 +12,31 @@ module Sequel
|
|
12
12
|
# p1 = Person[1]
|
13
13
|
# p2 = Person[1]
|
14
14
|
# p1.update(name: 'Jim') # works
|
15
|
-
# p2.update(name: 'Bob') # raises Sequel::
|
15
|
+
# p2.update(name: 'Bob') # raises Sequel::NoExistingObject
|
16
16
|
#
|
17
17
|
# In order for this plugin to work, you need to make sure that the database
|
18
|
-
# table has a +lock_version+ column
|
19
|
-
#
|
18
|
+
# table has a +lock_version+ column that defaults to 0. To change the column
|
19
|
+
# used, provide a +:lock_column+ option when loading the plugin:
|
20
|
+
#
|
21
|
+
# plugin :optimistic_locking, lock_column: :version
|
20
22
|
#
|
21
23
|
# This plugin relies on the instance_filters plugin.
|
22
24
|
module OptimisticLocking
|
23
25
|
# Exception class raised when trying to update or destroy a stale object.
|
24
26
|
Error = Sequel::NoExistingObject
|
25
27
|
|
26
|
-
# Load the instance_filters plugin into the model.
|
27
28
|
def self.apply(model, opts=OPTS)
|
28
|
-
model.plugin
|
29
|
+
model.plugin(:optimistic_locking_base)
|
29
30
|
end
|
30
31
|
|
31
|
-
# Set the
|
32
|
-
# that option is not given.
|
32
|
+
# Set the lock column
|
33
33
|
def self.configure(model, opts=OPTS)
|
34
|
-
model.lock_column = opts[:lock_column] || :lock_version
|
34
|
+
model.lock_column = opts[:lock_column] || model.lock_column || :lock_version
|
35
35
|
end
|
36
|
-
|
37
|
-
module ClassMethods
|
38
|
-
# The column holding the version of the lock
|
39
|
-
attr_accessor :lock_column
|
40
|
-
|
41
|
-
Plugins.inherited_instance_variables(self, :@lock_column=>nil)
|
42
|
-
end
|
43
|
-
|
36
|
+
|
44
37
|
module InstanceMethods
|
45
|
-
# Add the lock column instance filter to the object before destroying it.
|
46
|
-
def before_destroy
|
47
|
-
lock_column_instance_filter
|
48
|
-
super
|
49
|
-
end
|
50
|
-
|
51
|
-
# Add the lock column instance filter to the object before updating it.
|
52
|
-
def before_update
|
53
|
-
lock_column_instance_filter
|
54
|
-
super
|
55
|
-
end
|
56
|
-
|
57
38
|
private
|
58
39
|
|
59
|
-
# Add the lock column instance filter to the object.
|
60
|
-
def lock_column_instance_filter
|
61
|
-
lc = model.lock_column
|
62
|
-
instance_filter(lc=>get_column_value(lc))
|
63
|
-
end
|
64
|
-
|
65
|
-
# Clear the instance filters when refreshing, so that attempting to
|
66
|
-
# refresh after a failed save removes the previous lock column filter
|
67
|
-
# (the new one will be added before updating).
|
68
|
-
def _refresh(ds)
|
69
|
-
clear_instance_filters
|
70
|
-
super
|
71
|
-
end
|
72
|
-
|
73
40
|
# Only update the row if it has the same lock version, and increment the
|
74
41
|
# lock version.
|
75
42
|
def _update_columns(columns)
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
3
|
+
module Sequel
|
4
|
+
module Plugins
|
5
|
+
# Base for other optimistic locking plugins
|
6
|
+
module OptimisticLockingBase
|
7
|
+
# Load the instance_filters plugin into the model.
|
8
|
+
def self.apply(model)
|
9
|
+
model.plugin :instance_filters
|
10
|
+
end
|
11
|
+
|
12
|
+
module ClassMethods
|
13
|
+
# The column holding the version of the lock
|
14
|
+
attr_accessor :lock_column
|
15
|
+
|
16
|
+
Plugins.inherited_instance_variables(self, :@lock_column=>nil)
|
17
|
+
end
|
18
|
+
|
19
|
+
module InstanceMethods
|
20
|
+
# Add the lock column instance filter to the object before destroying it.
|
21
|
+
def before_destroy
|
22
|
+
lock_column_instance_filter
|
23
|
+
super
|
24
|
+
end
|
25
|
+
|
26
|
+
# Add the lock column instance filter to the object before updating it.
|
27
|
+
def before_update
|
28
|
+
lock_column_instance_filter
|
29
|
+
super
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
# Add the lock column instance filter to the object.
|
35
|
+
def lock_column_instance_filter
|
36
|
+
instance_filter(model.lock_column=>lock_column_instance_filter_value)
|
37
|
+
end
|
38
|
+
|
39
|
+
# Use the current value of the lock column
|
40
|
+
def lock_column_instance_filter_value
|
41
|
+
public_send(model.lock_column)
|
42
|
+
end
|
43
|
+
|
44
|
+
# Clear the instance filters when refreshing, so that attempting to
|
45
|
+
# refresh after a failed save removes the previous lock column filter
|
46
|
+
# (the new one will be added before updating).
|
47
|
+
def _refresh(ds)
|
48
|
+
clear_instance_filters
|
49
|
+
super
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
@@ -0,0 +1,109 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
3
|
+
module Sequel
|
4
|
+
module Plugins
|
5
|
+
# This plugin implements optimistic locking mechanism on PostgreSQL based
|
6
|
+
# on the xmin of the row. The xmin system column is automatically set to
|
7
|
+
# the current transaction id whenever the row is inserted or updated:
|
8
|
+
#
|
9
|
+
# class Person < Sequel::Model
|
10
|
+
# plugin :pg_xmin_optimistic_locking
|
11
|
+
# end
|
12
|
+
# p1 = Person[1]
|
13
|
+
# p2 = Person[1]
|
14
|
+
# p1.update(name: 'Jim') # works
|
15
|
+
# p2.update(name: 'Bob') # raises Sequel::NoExistingObject
|
16
|
+
#
|
17
|
+
# The advantage of pg_xmin_optimistic_locking plugin compared to the
|
18
|
+
# regular optimistic_locking plugin as that it does not require any
|
19
|
+
# additional columns setup on the model. This allows it to be loaded
|
20
|
+
# in the base model and have all subclasses automatically use
|
21
|
+
# optimistic locking. The disadvantage is that testing can be
|
22
|
+
# more difficult if you are modifying the underlying row between
|
23
|
+
# when a model is retrieved and when it is saved.
|
24
|
+
#
|
25
|
+
# This plugin may not work with the class_table_inheritance plugin.
|
26
|
+
#
|
27
|
+
# This plugin relies on the instance_filters plugin.
|
28
|
+
module PgXminOptimisticLocking
|
29
|
+
WILDCARD = LiteralString.new('*').freeze
|
30
|
+
|
31
|
+
# Define the xmin column accessor
|
32
|
+
def self.apply(model)
|
33
|
+
model.instance_exec do
|
34
|
+
plugin(:optimistic_locking_base)
|
35
|
+
@lock_column = :xmin
|
36
|
+
def_column_accessor(:xmin)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Update the dataset to append the xmin column if it is usable
|
41
|
+
# and there is a dataset for the model.
|
42
|
+
def self.configure(model)
|
43
|
+
model.instance_exec do
|
44
|
+
set_dataset(@dataset) if @dataset
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
module ClassMethods
|
49
|
+
private
|
50
|
+
|
51
|
+
# Ensure the dataset selects the xmin column if doing so
|
52
|
+
def convert_input_dataset(ds)
|
53
|
+
append_xmin_column_if_usable(super)
|
54
|
+
end
|
55
|
+
|
56
|
+
# If the xmin column is not already selected, and selecting it does not
|
57
|
+
# raise an error, append it to the selections.
|
58
|
+
def append_xmin_column_if_usable(ds)
|
59
|
+
select = ds.opts[:select]
|
60
|
+
|
61
|
+
unless select && select.include?(:xmin)
|
62
|
+
xmin_ds = ds.select_append(:xmin)
|
63
|
+
begin
|
64
|
+
columns = xmin_ds.columns!
|
65
|
+
rescue Sequel::DatabaseConnectionError, Sequel::DatabaseDisconnectError
|
66
|
+
raise
|
67
|
+
rescue Sequel::DatabaseError
|
68
|
+
# ignore, could be view, subquery, table returning function, etc.
|
69
|
+
else
|
70
|
+
ds = xmin_ds if columns.include?(:xmin)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
ds
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
module InstanceMethods
|
79
|
+
private
|
80
|
+
|
81
|
+
# Only set the lock column instance filter if there is an xmin value.
|
82
|
+
def lock_column_instance_filter
|
83
|
+
super if @values[:xmin]
|
84
|
+
end
|
85
|
+
|
86
|
+
# Include xmin value when inserting initial row
|
87
|
+
def _insert_dataset
|
88
|
+
super.returning(WILDCARD, :xmin)
|
89
|
+
end
|
90
|
+
|
91
|
+
# Remove the xmin from the columns to update.
|
92
|
+
# PostgreSQL automatically updates the xmin value, and it cannot be assigned.
|
93
|
+
def _save_update_all_columns_hash
|
94
|
+
v = super
|
95
|
+
v.delete(:xmin)
|
96
|
+
v
|
97
|
+
end
|
98
|
+
|
99
|
+
# Add an RETURNING clause to fetch the updated xmin when updating the row.
|
100
|
+
def _update_without_checking(columns)
|
101
|
+
ds = _update_dataset
|
102
|
+
rows = ds.clone(ds.send(:default_server_opts, :sql=>ds.returning(:xmin).update_sql(columns))).all
|
103
|
+
values[:xmin] = rows.first[:xmin] unless rows.empty?
|
104
|
+
rows.length
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
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 = 71
|
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,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sequel
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.
|
4
|
+
version: 5.71.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeremy Evans
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-08-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: minitest
|
@@ -203,6 +203,7 @@ extra_rdoc_files:
|
|
203
203
|
- doc/release_notes/5.69.0.txt
|
204
204
|
- doc/release_notes/5.7.0.txt
|
205
205
|
- doc/release_notes/5.70.0.txt
|
206
|
+
- doc/release_notes/5.71.0.txt
|
206
207
|
- doc/release_notes/5.8.0.txt
|
207
208
|
- doc/release_notes/5.9.0.txt
|
208
209
|
files:
|
@@ -301,6 +302,7 @@ files:
|
|
301
302
|
- doc/release_notes/5.69.0.txt
|
302
303
|
- doc/release_notes/5.7.0.txt
|
303
304
|
- doc/release_notes/5.70.0.txt
|
305
|
+
- doc/release_notes/5.71.0.txt
|
304
306
|
- doc/release_notes/5.8.0.txt
|
305
307
|
- doc/release_notes/5.9.0.txt
|
306
308
|
- doc/schema_modification.rdoc
|
@@ -552,9 +554,11 @@ files:
|
|
552
554
|
- lib/sequel/plugins/mssql_optimistic_locking.rb
|
553
555
|
- lib/sequel/plugins/nested_attributes.rb
|
554
556
|
- lib/sequel/plugins/optimistic_locking.rb
|
557
|
+
- lib/sequel/plugins/optimistic_locking_base.rb
|
555
558
|
- lib/sequel/plugins/pg_array_associations.rb
|
556
559
|
- lib/sequel/plugins/pg_auto_constraint_validations.rb
|
557
560
|
- lib/sequel/plugins/pg_row.rb
|
561
|
+
- lib/sequel/plugins/pg_xmin_optimistic_locking.rb
|
558
562
|
- lib/sequel/plugins/prepared_statements.rb
|
559
563
|
- lib/sequel/plugins/prepared_statements_safe.rb
|
560
564
|
- lib/sequel/plugins/primary_key_lookup_check_values.rb
|