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