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