sequel 5.41.0 → 5.46.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 +46 -0
- data/README.rdoc +1 -2
- data/doc/association_basics.rdoc +22 -3
- 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/release_notes/5.46.0.txt +87 -0
- 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 +0 -12
- 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/date_arithmetic.rb +29 -16
- data/lib/sequel/extensions/pg_enum.rb +1 -1
- data/lib/sequel/extensions/pg_loose_count.rb +3 -1
- data/lib/sequel/model/associations.rb +146 -75
- data/lib/sequel/model/base.rb +2 -2
- data/lib/sequel/plugins/async_thread_pool.rb +39 -0
- 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 +52 -38
- 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/unused_associations.rb +500 -0
- data/lib/sequel/version.rb +1 -1
- metadata +19 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8202d77fff48270013e8d06b75c5ab51933ff9e3fda72f99139211c9cb00de65
|
4
|
+
data.tar.gz: 15393a6189c83eb324e243d81805da38deced274d3f3a1b64bbf3cee54a27fa6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 35aa602f835100be3a01bec05ecfb3a0d53555774d1dff520963c254d79c8123328f61e2252c8cb9c69b935f015de7c53f5cbeaec378d425666e7c96bcd0dba7
|
7
|
+
data.tar.gz: b52d0a0e2ea2fe6e388bd8fc694bac86d66f960cba0ed6c952213ba2414395862d3ba734b1763f13883ec7f7983cf69fe75a39a0f8e9406af46e2a2974f7210e
|
data/CHANGELOG
CHANGED
@@ -1,3 +1,49 @@
|
|
1
|
+
=== 5.46.0 (2021-07-01)
|
2
|
+
|
3
|
+
* Add unused_associations plugin, for determining which associations and association methods are not used (jeremyevans)
|
4
|
+
|
5
|
+
* Make nil :setter/:adder/:remover/:clearer association options not create related methods (jeremyevans)
|
6
|
+
|
7
|
+
=== 5.45.0 (2021-06-01)
|
8
|
+
|
9
|
+
* Fix handling of NULL values in boolean columns in the ODBC adapter (jeremyevans) (#1765)
|
10
|
+
|
11
|
+
* Add auto_validations_constraint_validations_presence_message plugin for auto_validations/constraint_validations presence message integration (jeremyevans)
|
12
|
+
|
13
|
+
* Support Dataset#with :materialized option on SQLite 3.35+ for [NOT] MATERIALIZED (jeremyevans)
|
14
|
+
|
15
|
+
* Use ALTER TABLE DROP COLUMN for dropping columns on SQLite 3.35+ (jeremyevans)
|
16
|
+
|
17
|
+
=== 5.44.0 (2021-05-01)
|
18
|
+
|
19
|
+
* Add concurrent_eager_loading plugin, for eager loading multiple associations concurrently using separate threads (jeremyevans)
|
20
|
+
|
21
|
+
* Support :weeks as a interval unit in the date_arithmetic extension (jeremyevans) (#1759)
|
22
|
+
|
23
|
+
* Raise an exception if an interval hash with an unsupported key is passed in the date_arithmetic extension (jeremyevans) (#1759)
|
24
|
+
|
25
|
+
* Support dropping non-composite unique constraints on SQLite (jeremyevans) (#1755)
|
26
|
+
|
27
|
+
=== 5.43.0 (2021-04-01)
|
28
|
+
|
29
|
+
* Add column_encryption plugin, for encrypting column values (jeremyevans)
|
30
|
+
|
31
|
+
=== 5.42.0 (2021-03-01)
|
32
|
+
|
33
|
+
* Make the ado timestamp conversion proc a normal conversion proc that can be overridden similar to other conversion procs (jeremyevans)
|
34
|
+
|
35
|
+
* Add :reject_nil option to the nested_attributes method, to ignore calls where nil is passed as the associated object data (jeremyevans)
|
36
|
+
|
37
|
+
* Add async_thread_pool plugin for easier async usage with model classes and support for async destroy, with_pk, and with_pk! methods (jeremyevans)
|
38
|
+
|
39
|
+
* Add async_thread_pool Database extension for executing queries asynchronously using a thread pool (jeremyevans)
|
40
|
+
|
41
|
+
* Fix possible thread safety issue in Database#extension that could allow Module#extended to be called twice with the same Database instance (jeremyevans)
|
42
|
+
|
43
|
+
* Support cases where validations make modifications beyond setting errors in Model#freeze (jeremyevans)
|
44
|
+
|
45
|
+
* Add Model#to_json_data to the json_serializer plugin, returning a JSON data structure (jeremyevans)
|
46
|
+
|
1
47
|
=== 5.41.0 (2021-02-01)
|
2
48
|
|
3
49
|
* Have explicit :text option for a String column take priority over :size option on PostgreSQL (jeremyevans) (#1750)
|
data/README.rdoc
CHANGED
@@ -22,10 +22,9 @@ RDoc Documentation :: http://sequel.jeremyevans.net/rdoc
|
|
22
22
|
Source Code :: https://github.com/jeremyevans/sequel
|
23
23
|
Bug tracking (GitHub Issues) :: http://github.com/jeremyevans/sequel/issues
|
24
24
|
Discussion Forum (sequel-talk Google Group) :: http://groups.google.com/group/sequel-talk
|
25
|
-
IRC Channel (#sequel) :: irc://irc.freenode.net/sequel
|
26
25
|
|
27
26
|
If you have questions about how to use Sequel, please ask on the
|
28
|
-
sequel-talk Google Group
|
27
|
+
sequel-talk Google Group. Only use the the bug tracker to report
|
29
28
|
bugs in Sequel, not to ask for help on using Sequel.
|
30
29
|
|
31
30
|
To check out the source code:
|
data/doc/association_basics.rdoc
CHANGED
@@ -826,6 +826,8 @@ you also wanted to handle the Artist#add_album method:
|
|
826
826
|
end)
|
827
827
|
end
|
828
828
|
|
829
|
+
You can set this to +nil+ to not create a add_<i>association</i> method.
|
830
|
+
|
829
831
|
=== :remover (\_remove_<i>association</i> method)
|
830
832
|
|
831
833
|
Continuing with the same example, here's how you would handle the same case if
|
@@ -837,6 +839,8 @@ you also wanted to handle the Artist#remove_album method:
|
|
837
839
|
end)
|
838
840
|
end
|
839
841
|
|
842
|
+
You can set this to +nil+ to not create a remove_<i>association</i> method.
|
843
|
+
|
840
844
|
=== :clearer (\_remove_all_<i>association</i> method)
|
841
845
|
|
842
846
|
Continuing with the same example, here's how you would handle the same case if
|
@@ -850,6 +854,22 @@ you also wanted to handle the Artist#remove_all_albums method:
|
|
850
854
|
end)
|
851
855
|
end
|
852
856
|
|
857
|
+
You can set this to +nil+ to not create a remove_all_<i>association</i> method.
|
858
|
+
|
859
|
+
=== :no_dataset_method
|
860
|
+
|
861
|
+
Setting this to true will not result in the <i>association</i>_dataset method
|
862
|
+
not being defined. This can save memory if you only use the <i>association</i>
|
863
|
+
method and do not call the <i>association</i>_dataset method directly or
|
864
|
+
indirectly.
|
865
|
+
|
866
|
+
=== :no_association_method
|
867
|
+
|
868
|
+
Setting this to true will not result in the <i>association</i> method
|
869
|
+
not being defined. This can save memory if you only use the
|
870
|
+
<i>association</i>_dataset method and do not call the <i>association</i> method
|
871
|
+
directly or indirectly.
|
872
|
+
|
853
873
|
== Association Options
|
854
874
|
|
855
875
|
Sequel's associations mostly share the same options. For ease of understanding,
|
@@ -1638,9 +1658,8 @@ For +many_to_one+ and +one_to_one+ associations, do not add a setter method.
|
|
1638
1658
|
For +one_to_many+ and +many_to_many+, do not add the add_<i>association</i>,
|
1639
1659
|
remove_<i>association</i>, or remove_all_<i>association</i> methods.
|
1640
1660
|
|
1641
|
-
If
|
1642
|
-
|
1643
|
-
want, it may be best to set this option to true.
|
1661
|
+
If you are not using the association modification methods, setting this
|
1662
|
+
value to true will save memory.
|
1644
1663
|
|
1645
1664
|
==== :validate
|
1646
1665
|
|
@@ -0,0 +1,136 @@
|
|
1
|
+
= New Features
|
2
|
+
|
3
|
+
* An async_thread_pool Database extension has been added, which
|
4
|
+
executes queries and processes results using a separate thread
|
5
|
+
pool. This allows you do do things like:
|
6
|
+
|
7
|
+
foos = DB[:foos].async.all
|
8
|
+
bars = DB[:bars].async.select_map(:name)
|
9
|
+
foo_bars = DB[:foo_bars].async.each{|x| p x}
|
10
|
+
|
11
|
+
and have the three method calls (all, select_map, and each)
|
12
|
+
execute concurrently. On Ruby implementations without a global
|
13
|
+
VM lock, such as JRuby, it will allow for parallel execution of
|
14
|
+
the method calls. On CRuby, the main benefit will be for cases
|
15
|
+
where query execution takes a long time or there is significant
|
16
|
+
latency between the application and the database.
|
17
|
+
|
18
|
+
When you call a method on foos, bars, or foo_bars, if the thread
|
19
|
+
pool hasn't finished processing the method, the calling code will
|
20
|
+
block until the method call has finished.
|
21
|
+
|
22
|
+
By default, for consistency, calling code will not preempt the
|
23
|
+
async thread pool. For example, if you do:
|
24
|
+
|
25
|
+
DB[:foos].async.all.size
|
26
|
+
|
27
|
+
The calling code will always wait for the async thread pool to
|
28
|
+
run the all method, and then the calling code will call size on
|
29
|
+
the result. This ensures that async queries will not use the
|
30
|
+
same connection as the the calling thread, even if calling thread
|
31
|
+
has a connection checked out.
|
32
|
+
|
33
|
+
In some cases, such as when the async thread pool is very busy,
|
34
|
+
preemption is desired for performance reasons. If you set the
|
35
|
+
:preempt_async_thread Database option before loading the
|
36
|
+
async_thread_pool extension, preemption will be allowed. With
|
37
|
+
preemption allowed, if the async thread pool has not started the
|
38
|
+
processing of the method at the time the calling code needs the
|
39
|
+
results of the method, the calling code will preempt the async
|
40
|
+
thread pool, and run the method on the current thread.
|
41
|
+
|
42
|
+
By default, the async thread pool uses the same number of threads as
|
43
|
+
the Database objects :max_connections attribute (the default for
|
44
|
+
that is 4). You can modify the number of async threads by setting
|
45
|
+
the :num_async_threads Database option before loading the Database
|
46
|
+
async_thread_pool extension.
|
47
|
+
|
48
|
+
Most Dataset methods that execute queries on the database and return
|
49
|
+
results will operate asynchronously if the the dataset is set to be
|
50
|
+
asynchronous via the Dataset#async method. This includes most
|
51
|
+
methods available due to the inclusion in Enumerable, even if not
|
52
|
+
defined by Dataset itself.
|
53
|
+
|
54
|
+
There are multiple caveats when using the async_thread_pool
|
55
|
+
extension:
|
56
|
+
|
57
|
+
* Asynchronous behavior is harder to understand and harder to
|
58
|
+
debug. It would be wise to only use this support in cases where
|
59
|
+
it provides is significant performance benefit.
|
60
|
+
|
61
|
+
* Dataset methods executed asynchronously will use a separate
|
62
|
+
database connection than the calling thread, so they will not
|
63
|
+
respect transactions in the calling thread, or other cases where
|
64
|
+
the calling thread checks out a connection directly using
|
65
|
+
Database#synchronize. They will also not respect the use of
|
66
|
+
Database#with_server (from the server_block extension) in the
|
67
|
+
calling thread.
|
68
|
+
|
69
|
+
* Dataset methods executed asynchronously should never ignore their
|
70
|
+
return value. Code such as:
|
71
|
+
|
72
|
+
DB[:table].async.insert(1)
|
73
|
+
|
74
|
+
is probablematic because without storing the return value, you
|
75
|
+
have no way to block until the insert has been completed.
|
76
|
+
|
77
|
+
* The returned object for Dataset methods executed asynchronously is
|
78
|
+
a proxy object (promise). So you should never do:
|
79
|
+
|
80
|
+
row = DB[:table].async.first
|
81
|
+
# ...
|
82
|
+
if row
|
83
|
+
end
|
84
|
+
|
85
|
+
# or:
|
86
|
+
|
87
|
+
bool = DB[:table].async.get(:boolean_column)
|
88
|
+
# ...
|
89
|
+
if bool
|
90
|
+
end
|
91
|
+
|
92
|
+
because the if branches will always be taken as row and bool will
|
93
|
+
never be nil or false. If you want to get the underlying value,
|
94
|
+
call itself on the proxy object (or __value if using Ruby <2.2).
|
95
|
+
|
96
|
+
For the same reason, you should not use the proxy objects directly
|
97
|
+
in case expressions or as arguments to Class#===. Use itself or
|
98
|
+
__value in those cases.
|
99
|
+
|
100
|
+
* Dataset methods executed asynchronously that include blocks have the
|
101
|
+
block executed asynchronously as well, assuming that the method
|
102
|
+
calls the block. Because these blocks are executed in a separate
|
103
|
+
thread, you cannot use control flow modifiers such as break or
|
104
|
+
return in them.
|
105
|
+
|
106
|
+
* An async_thread_pool model plugin has been added. This requires the
|
107
|
+
async_thread_pool extension has been loaded into the model's Database
|
108
|
+
object, and allows you to call Model.async instead of
|
109
|
+
Model.dataset.async. It also adds async support to the destroy,
|
110
|
+
with_pk, and with_pk! model dataset methods.
|
111
|
+
|
112
|
+
* Model#to_json_data has been added to the json_serializer plugin, for
|
113
|
+
returning a hash of data that can be converted to JSON, instead of
|
114
|
+
a JSON string.
|
115
|
+
|
116
|
+
* A :reject_nil option has been added to the nested_attributes method
|
117
|
+
in the nested_attributes plugin. This will ignore calls to the
|
118
|
+
nested attributes setter method where nil is passed as the setter
|
119
|
+
method argument.
|
120
|
+
|
121
|
+
= Other Improvements
|
122
|
+
|
123
|
+
* Model#freeze now works in case where model validation modifies the
|
124
|
+
object beyond adding errors.
|
125
|
+
|
126
|
+
* Model#freeze in the composition, serialization, and
|
127
|
+
serialization_modification_detection plugins now works in cases
|
128
|
+
where validation would end up loading the composed or
|
129
|
+
serialized values.
|
130
|
+
|
131
|
+
* Database#extension now avoids a possible thread safety issue that
|
132
|
+
could result in the extension being loaded into the Database twice.
|
133
|
+
|
134
|
+
* The ado adapter now supports overriding the timestamp conversion
|
135
|
+
proc. Previously, unlike other conversion procs, the timestamp
|
136
|
+
conversion proc was hard coded and could not be overridden.
|
@@ -0,0 +1,98 @@
|
|
1
|
+
= New Features
|
2
|
+
|
3
|
+
* A column_encryption plugin has been added to support encrypting the
|
4
|
+
content of individual columns in a table.
|
5
|
+
|
6
|
+
Column values are encrypted with AES-256-GCM using a per-value
|
7
|
+
cipher key derived from a key provided in the configuration using
|
8
|
+
HMAC-SHA256.
|
9
|
+
|
10
|
+
If you would like to support encryption of columns in more than one
|
11
|
+
model, you should probably load the plugin into the parent class of
|
12
|
+
your models and specify the keys:
|
13
|
+
|
14
|
+
Sequel::Model.plugin :column_encryption do |enc|
|
15
|
+
enc.key 0, ENV["SEQUEL_COLUMN_ENCRYPTION_KEY"]
|
16
|
+
end
|
17
|
+
|
18
|
+
This specifies a single master encryption key. Unless you are
|
19
|
+
actively rotating keys, it is best to use a single master key.
|
20
|
+
|
21
|
+
In the above call, 0 is the id of the key, and
|
22
|
+
ENV["SEQUEL_COLUMN_ENCRYPTION_KEY"] is the content of the key, which
|
23
|
+
must be a string with exactly 32 bytes. As indicated, this key
|
24
|
+
should not be hardcoded or otherwise committed to the source control
|
25
|
+
repository.
|
26
|
+
|
27
|
+
For models that need encrypted columns, you load the plugin again,
|
28
|
+
but specify the columns to encrypt:
|
29
|
+
|
30
|
+
ConfidentialModel.plugin :column_encryption do |enc|
|
31
|
+
enc.column :encrypted_column_name
|
32
|
+
enc.column :searchable_column_name, searchable: true
|
33
|
+
enc.column :ci_searchable_column_name, searchable: :case_insensitive
|
34
|
+
end
|
35
|
+
|
36
|
+
With this, all three specified columns (encrypted_column_name,
|
37
|
+
searchable_column_name, and ci_searchable_column_name) will be
|
38
|
+
marked as encrypted columns. When you run the following code:
|
39
|
+
|
40
|
+
ConfidentialModel.create(
|
41
|
+
encrypted_column_name: 'These',
|
42
|
+
searchable_column_name: 'will be',
|
43
|
+
ci_searchable_column_name: 'Encrypted'
|
44
|
+
)
|
45
|
+
|
46
|
+
It will save encrypted versions to the database.
|
47
|
+
encrypted_column_name will not be searchable, searchable_column_name
|
48
|
+
will be searchable with an exact match, and
|
49
|
+
ci_searchable_column_name will be searchable with a case insensitive
|
50
|
+
match.
|
51
|
+
|
52
|
+
To search searchable encrypted columns, use with_encrypted_value.
|
53
|
+
This example code will return the model instance created in the code
|
54
|
+
example in the previous section:
|
55
|
+
|
56
|
+
ConfidentialModel.
|
57
|
+
with_encrypted_value(:searchable_column_name, "will be")
|
58
|
+
with_encrypted_value(:ci_searchable_column_name, "encrypted").
|
59
|
+
first
|
60
|
+
|
61
|
+
To rotate encryption keys, add a new key above the existing key,
|
62
|
+
with a new key ID:
|
63
|
+
|
64
|
+
Sequel::Model.plugin :column_encryption do |enc|
|
65
|
+
enc.key 1, ENV["SEQUEL_COLUMN_ENCRYPTION_KEY"]
|
66
|
+
enc.key 0, ENV["SEQUEL_OLD_COLUMN_ENCRYPTION_KEY"]
|
67
|
+
end
|
68
|
+
|
69
|
+
Newly encrypted data will then use the new key. Records encrypted
|
70
|
+
with the older key will still be decrypted correctly.
|
71
|
+
|
72
|
+
To force reencryption for existing records that are using the older
|
73
|
+
key, you can use the needing_reencryption dataset method and the
|
74
|
+
reencrypt instance method. For a small number of records, you can
|
75
|
+
probably do:
|
76
|
+
|
77
|
+
ConfidentialModel.needing_reencryption.all(&:reencrypt)
|
78
|
+
|
79
|
+
With more than a small number of records, you'll want to do this in
|
80
|
+
batches. It's possible you could use an approach such as:
|
81
|
+
|
82
|
+
ds = ConfidentialModel.needing_reencryption.limit(100)
|
83
|
+
true until ds.all(&:reencrypt).empty?
|
84
|
+
|
85
|
+
After all values have been reencrypted for all models, and no models
|
86
|
+
use the older encryption key, you can remove it from the
|
87
|
+
configuration:
|
88
|
+
|
89
|
+
Sequel::Model.plugin :column_encryption do |enc|
|
90
|
+
enc.key 1, ENV["SEQUEL_COLUMN_ENCRYPTION_KEY"]
|
91
|
+
end
|
92
|
+
|
93
|
+
The column_encryption plugin supports encrypting serialized data,
|
94
|
+
as well as enforcing uniquenss of searchable encrypted columns
|
95
|
+
(in the absence of key rotation). By design, it does not support
|
96
|
+
compression, mixing encrypted and unencrypted data in the same
|
97
|
+
column, or support arbitrary encryption ciphers. See the plugin
|
98
|
+
documentation for more details.
|
@@ -0,0 +1,32 @@
|
|
1
|
+
= New Features
|
2
|
+
|
3
|
+
* A concurrent_eager_loading plugin has been added. This plugin
|
4
|
+
builds on top of the async_thread_pool Database extension and
|
5
|
+
allows eager loading multiple associations concurrently in
|
6
|
+
separate threads. With this plugin, you can mark datasets for
|
7
|
+
concurrent eager loading using eager_load_concurrently:
|
8
|
+
|
9
|
+
Album.eager_load_concurrently.eager(:artist, :genre, :tracks).all
|
10
|
+
|
11
|
+
Datasets that are marked for concurrent eager loading will use
|
12
|
+
concurrent eager loading if they are eager loading more than one
|
13
|
+
association. If you would like to make concurrent eager loading
|
14
|
+
the default, you can load the plugin with the :always option.
|
15
|
+
|
16
|
+
All of the association types that ship with Sequel now support
|
17
|
+
concurrent eager loading when using this plugin. For custom eager
|
18
|
+
loaders using the :eager_loader association option, please see the
|
19
|
+
documentation for the plugin for how to enable custom eager loading
|
20
|
+
for them.
|
21
|
+
|
22
|
+
= Other Improvements
|
23
|
+
|
24
|
+
* The date_arithmetic extension now handles ActiveSupport::Duration
|
25
|
+
values with weeks, as well as :weeks as a key in a hash value. Weeks
|
26
|
+
are converted into 7 days internally.
|
27
|
+
|
28
|
+
* The shared SQLite adapter now emulates the dropping of non-composite
|
29
|
+
unique constraints. Non-composite unique constraints are now
|
30
|
+
treated similarly to composite unique constraints, in that dropping
|
31
|
+
any unique constraints on a table will drop all unique constraints
|
32
|
+
on that table.
|
@@ -0,0 +1,34 @@
|
|
1
|
+
= New Features
|
2
|
+
|
3
|
+
* A auto_validations_constraint_validations_presence_message plugin
|
4
|
+
has been added that provides integration for the auto_validations
|
5
|
+
and constraint_validations plugin in the following conditions:
|
6
|
+
|
7
|
+
* The column has a NOT NULL constraint
|
8
|
+
* The column has a presence constraint validation with both
|
9
|
+
the :message and :allow_nil options used.
|
10
|
+
|
11
|
+
In this case, when saving a nil value in the column, the plugin
|
12
|
+
will make it so the more specific message from the presence
|
13
|
+
constraint validation is used, instead of the generic message
|
14
|
+
from auto_validations.
|
15
|
+
|
16
|
+
= Other Improvements
|
17
|
+
|
18
|
+
* On SQLite 3.35.0+, Sequel now uses ALTER TABLE DROP COLUMN for
|
19
|
+
dropping columns, instead of emulating the dropped column by
|
20
|
+
recreating the table.
|
21
|
+
|
22
|
+
* The Dataset#with :materialized option is now supported on SQLite
|
23
|
+
3.35.0+ for specifying whether common table expressions should be
|
24
|
+
materialized.
|
25
|
+
|
26
|
+
* The odbc adapter now correct handles boolean columns with NULL
|
27
|
+
values. Previously, such values were returned as false instead
|
28
|
+
of nil.
|
29
|
+
|
30
|
+
= Backwards Compatibility
|
31
|
+
|
32
|
+
* The change to use ALTER TABLE DROP COLUMN on SQLite 3.35.0+ can
|
33
|
+
cause backwards compatibility issues if SQLite 3.35.0+ does
|
34
|
+
not allow dropping the column.
|
@@ -0,0 +1,87 @@
|
|
1
|
+
= New Features
|
2
|
+
|
3
|
+
* An unused_associations plugin has been added, which allows you to
|
4
|
+
determine which associations and association methods are not used.
|
5
|
+
You can use this to avoid defining the unused associations and
|
6
|
+
association methods, which can save memory.
|
7
|
+
|
8
|
+
This plugin is supported on Ruby 2.5+, and uses method coverage to
|
9
|
+
determine if the plugin's methods are called. Because Sequel::Model
|
10
|
+
adds association methods to an anonymous module included in the
|
11
|
+
class, directly using the method coverage data to determine which
|
12
|
+
associations are used is challenging.
|
13
|
+
|
14
|
+
This plugin is mostly designed for reporting. You can have a
|
15
|
+
test suite that runs with method coverage enabled, and use the
|
16
|
+
coverage information to get data on unused associations:
|
17
|
+
|
18
|
+
# Calls Coverage.result
|
19
|
+
cov_data = Sequel::Model.update_associations_coverage
|
20
|
+
unused_associations_data = Sequel::Model.update_unused_associations_data(coverage_data: cov_data)
|
21
|
+
Sequel::Model.unused_associations(unused_associations_data: unused_associations_data)
|
22
|
+
# => [["Class1", "assoc1"], ...]
|
23
|
+
|
24
|
+
unused_associations returns an array of two element arrays, where
|
25
|
+
the first element is the class name and the second element is the
|
26
|
+
association name. The returned values will be associations where
|
27
|
+
all of the association methods are not used.
|
28
|
+
|
29
|
+
In addition to determining which associations are not used, you can
|
30
|
+
also use this to determine if you are defining association methods
|
31
|
+
that are not used:
|
32
|
+
|
33
|
+
Sequel::Model.unused_association_options(unused_associations_data: unused_associations_data)
|
34
|
+
# => [["Class2", "assoc2", {:read_only=>true}], ...]
|
35
|
+
|
36
|
+
unused_association_options is similar to unused_associations, but
|
37
|
+
returns an array of three element arrays, where the third element
|
38
|
+
is a hash of association options that should be used to avoid
|
39
|
+
defining the unused association methods. It's common in Sequel to
|
40
|
+
define associations and only use them for reading data and not for
|
41
|
+
modifications, and you can use this to easily see which associations
|
42
|
+
are only used for reading data.
|
43
|
+
|
44
|
+
As the determination of whether associations are used is based on
|
45
|
+
method coverage, this will report as unused any associations that are
|
46
|
+
used but where the association methods are not called. These cases
|
47
|
+
are rare, but can happen if you have libraries that use the
|
48
|
+
association reflection metadata without calling the association
|
49
|
+
methods, or use the association only in combination with another
|
50
|
+
plugin such as dataset_associations. You can set the :is_used
|
51
|
+
association option to explicitly mark an association as used, and
|
52
|
+
have this plugin avoid reporting it as unused.
|
53
|
+
|
54
|
+
In addition to just reporting on unused associations, you can also
|
55
|
+
directly use the unused associations metadata to automatically avoid
|
56
|
+
defining unused associations or unused associations methods. You
|
57
|
+
can set a :file option when loading the plugin:
|
58
|
+
|
59
|
+
Sequel::Model.plugin :unused_associations, file: 'unused_associations.json'
|
60
|
+
|
61
|
+
Then run the method coverage testing. This will save the unused
|
62
|
+
associations metadata to the file. Then you can use this metadata
|
63
|
+
automatically by also setting the :modify_associations option:
|
64
|
+
|
65
|
+
Sequel::Model.plugin :unused_associations, file: 'unused_associations.json',
|
66
|
+
modify_associations: true
|
67
|
+
|
68
|
+
With the :modify_associations option, unused associations are
|
69
|
+
skipped instead of being defined, and the options returned by
|
70
|
+
unused_association_options are automatically used. Note that using
|
71
|
+
the :modify_associations option is risky unless you have complete
|
72
|
+
coverage and do not have cases where the associations are used
|
73
|
+
without calling methods.
|
74
|
+
|
75
|
+
It is common to have multiple test suites where you need to combine
|
76
|
+
coverage. The plugin supports this by using a :coverage_file option:
|
77
|
+
|
78
|
+
Sequel::Model.plugin :unused_associations, coverage_file: 'unused_associations_coverage.json'
|
79
|
+
|
80
|
+
In this case, you would run update_associations_coverage after each
|
81
|
+
test suite, and update_unused_associations_data only after all test
|
82
|
+
suites have been run.
|
83
|
+
|
84
|
+
* Passing nil as the value of the :setter, :adder, :remover, or
|
85
|
+
:clearer association options will cause the related method to not be
|
86
|
+
defined, instead of using the default value. This allows you to
|
87
|
+
only define the methods you will actually be using.
|