sequel 5.39.0 → 5.66.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (191) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +336 -0
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +57 -25
  5. data/bin/sequel +11 -3
  6. data/doc/advanced_associations.rdoc +13 -13
  7. data/doc/association_basics.rdoc +119 -24
  8. data/doc/cheat_sheet.rdoc +11 -3
  9. data/doc/migration.rdoc +12 -6
  10. data/doc/model_hooks.rdoc +1 -1
  11. data/doc/object_model.rdoc +8 -8
  12. data/doc/opening_databases.rdoc +18 -11
  13. data/doc/postgresql.rdoc +16 -8
  14. data/doc/querying.rdoc +5 -3
  15. data/doc/release_notes/5.40.0.txt +40 -0
  16. data/doc/release_notes/5.41.0.txt +25 -0
  17. data/doc/release_notes/5.42.0.txt +136 -0
  18. data/doc/release_notes/5.43.0.txt +98 -0
  19. data/doc/release_notes/5.44.0.txt +32 -0
  20. data/doc/release_notes/5.45.0.txt +34 -0
  21. data/doc/release_notes/5.46.0.txt +87 -0
  22. data/doc/release_notes/5.47.0.txt +59 -0
  23. data/doc/release_notes/5.48.0.txt +14 -0
  24. data/doc/release_notes/5.49.0.txt +59 -0
  25. data/doc/release_notes/5.50.0.txt +78 -0
  26. data/doc/release_notes/5.51.0.txt +47 -0
  27. data/doc/release_notes/5.52.0.txt +87 -0
  28. data/doc/release_notes/5.53.0.txt +23 -0
  29. data/doc/release_notes/5.54.0.txt +27 -0
  30. data/doc/release_notes/5.55.0.txt +21 -0
  31. data/doc/release_notes/5.56.0.txt +51 -0
  32. data/doc/release_notes/5.57.0.txt +23 -0
  33. data/doc/release_notes/5.58.0.txt +31 -0
  34. data/doc/release_notes/5.59.0.txt +73 -0
  35. data/doc/release_notes/5.60.0.txt +22 -0
  36. data/doc/release_notes/5.61.0.txt +43 -0
  37. data/doc/release_notes/5.62.0.txt +132 -0
  38. data/doc/release_notes/5.63.0.txt +33 -0
  39. data/doc/release_notes/5.64.0.txt +50 -0
  40. data/doc/release_notes/5.65.0.txt +21 -0
  41. data/doc/release_notes/5.66.0.txt +24 -0
  42. data/doc/schema_modification.rdoc +1 -1
  43. data/doc/security.rdoc +9 -9
  44. data/doc/sql.rdoc +28 -16
  45. data/doc/testing.rdoc +22 -11
  46. data/doc/transactions.rdoc +6 -6
  47. data/doc/virtual_rows.rdoc +2 -2
  48. data/lib/sequel/adapters/ado/access.rb +1 -1
  49. data/lib/sequel/adapters/ado.rb +17 -17
  50. data/lib/sequel/adapters/amalgalite.rb +3 -5
  51. data/lib/sequel/adapters/ibmdb.rb +2 -2
  52. data/lib/sequel/adapters/jdbc/derby.rb +8 -0
  53. data/lib/sequel/adapters/jdbc/h2.rb +60 -10
  54. data/lib/sequel/adapters/jdbc/hsqldb.rb +6 -0
  55. data/lib/sequel/adapters/jdbc/postgresql.rb +4 -4
  56. data/lib/sequel/adapters/jdbc.rb +16 -18
  57. data/lib/sequel/adapters/mysql.rb +80 -67
  58. data/lib/sequel/adapters/mysql2.rb +54 -49
  59. data/lib/sequel/adapters/odbc.rb +6 -2
  60. data/lib/sequel/adapters/oracle.rb +4 -3
  61. data/lib/sequel/adapters/postgres.rb +83 -40
  62. data/lib/sequel/adapters/shared/access.rb +11 -1
  63. data/lib/sequel/adapters/shared/db2.rb +30 -0
  64. data/lib/sequel/adapters/shared/mssql.rb +83 -7
  65. data/lib/sequel/adapters/shared/mysql.rb +47 -2
  66. data/lib/sequel/adapters/shared/oracle.rb +82 -1
  67. data/lib/sequel/adapters/shared/postgres.rb +430 -174
  68. data/lib/sequel/adapters/shared/sqlanywhere.rb +11 -1
  69. data/lib/sequel/adapters/shared/sqlite.rb +116 -11
  70. data/lib/sequel/adapters/sqlanywhere.rb +1 -1
  71. data/lib/sequel/adapters/sqlite.rb +60 -18
  72. data/lib/sequel/adapters/tinytds.rb +1 -1
  73. data/lib/sequel/adapters/utils/columns_limit_1.rb +22 -0
  74. data/lib/sequel/adapters/utils/mysql_mysql2.rb +1 -1
  75. data/lib/sequel/ast_transformer.rb +6 -0
  76. data/lib/sequel/connection_pool/sharded_single.rb +5 -7
  77. data/lib/sequel/connection_pool/sharded_threaded.rb +5 -1
  78. data/lib/sequel/connection_pool/single.rb +6 -8
  79. data/lib/sequel/connection_pool/threaded.rb +8 -8
  80. data/lib/sequel/connection_pool/timed_queue.rb +257 -0
  81. data/lib/sequel/connection_pool.rb +47 -30
  82. data/lib/sequel/core.rb +28 -18
  83. data/lib/sequel/database/connecting.rb +26 -2
  84. data/lib/sequel/database/misc.rb +69 -14
  85. data/lib/sequel/database/query.rb +73 -2
  86. data/lib/sequel/database/schema_generator.rb +45 -52
  87. data/lib/sequel/database/schema_methods.rb +17 -1
  88. data/lib/sequel/dataset/actions.rb +108 -14
  89. data/lib/sequel/dataset/features.rb +20 -0
  90. data/lib/sequel/dataset/misc.rb +12 -2
  91. data/lib/sequel/dataset/placeholder_literalizer.rb +20 -9
  92. data/lib/sequel/dataset/prepared_statements.rb +2 -0
  93. data/lib/sequel/dataset/query.rb +118 -16
  94. data/lib/sequel/dataset/sql.rb +182 -47
  95. data/lib/sequel/extensions/_model_pg_row.rb +0 -12
  96. data/lib/sequel/extensions/_pretty_table.rb +1 -1
  97. data/lib/sequel/extensions/any_not_empty.rb +1 -1
  98. data/lib/sequel/extensions/async_thread_pool.rb +438 -0
  99. data/lib/sequel/extensions/auto_literal_strings.rb +1 -1
  100. data/lib/sequel/extensions/blank.rb +8 -0
  101. data/lib/sequel/extensions/constraint_validations.rb +1 -1
  102. data/lib/sequel/extensions/core_refinements.rb +36 -11
  103. data/lib/sequel/extensions/date_arithmetic.rb +71 -31
  104. data/lib/sequel/extensions/date_parse_input_handler.rb +67 -0
  105. data/lib/sequel/extensions/datetime_parse_to_time.rb +5 -1
  106. data/lib/sequel/extensions/duplicate_columns_handler.rb +1 -1
  107. data/lib/sequel/extensions/eval_inspect.rb +2 -0
  108. data/lib/sequel/extensions/inflector.rb +9 -1
  109. data/lib/sequel/extensions/is_distinct_from.rb +141 -0
  110. data/lib/sequel/extensions/looser_typecasting.rb +3 -0
  111. data/lib/sequel/extensions/migration.rb +7 -2
  112. data/lib/sequel/extensions/named_timezones.rb +26 -6
  113. data/lib/sequel/extensions/pagination.rb +1 -1
  114. data/lib/sequel/extensions/pg_array.rb +23 -3
  115. data/lib/sequel/extensions/pg_array_ops.rb +2 -2
  116. data/lib/sequel/extensions/pg_auto_parameterize.rb +509 -0
  117. data/lib/sequel/extensions/pg_enum.rb +1 -1
  118. data/lib/sequel/extensions/pg_extended_date_support.rb +28 -25
  119. data/lib/sequel/extensions/pg_extended_integer_support.rb +116 -0
  120. data/lib/sequel/extensions/pg_hstore.rb +6 -1
  121. data/lib/sequel/extensions/pg_hstore_ops.rb +53 -3
  122. data/lib/sequel/extensions/pg_inet.rb +10 -11
  123. data/lib/sequel/extensions/pg_inet_ops.rb +1 -1
  124. data/lib/sequel/extensions/pg_interval.rb +45 -19
  125. data/lib/sequel/extensions/pg_json.rb +13 -15
  126. data/lib/sequel/extensions/pg_json_ops.rb +73 -2
  127. data/lib/sequel/extensions/pg_loose_count.rb +3 -1
  128. data/lib/sequel/extensions/pg_multirange.rb +367 -0
  129. data/lib/sequel/extensions/pg_range.rb +10 -23
  130. data/lib/sequel/extensions/pg_range_ops.rb +37 -9
  131. data/lib/sequel/extensions/pg_row.rb +19 -13
  132. data/lib/sequel/extensions/pg_row_ops.rb +1 -1
  133. data/lib/sequel/extensions/query.rb +2 -0
  134. data/lib/sequel/extensions/s.rb +2 -1
  135. data/lib/sequel/extensions/schema_dumper.rb +13 -2
  136. data/lib/sequel/extensions/server_block.rb +8 -12
  137. data/lib/sequel/extensions/sql_comments.rb +110 -3
  138. data/lib/sequel/extensions/sql_log_normalizer.rb +108 -0
  139. data/lib/sequel/extensions/sqlite_json_ops.rb +255 -0
  140. data/lib/sequel/extensions/string_agg.rb +1 -1
  141. data/lib/sequel/extensions/string_date_time.rb +19 -23
  142. data/lib/sequel/extensions/symbol_aref.rb +2 -0
  143. data/lib/sequel/model/associations.rb +345 -101
  144. data/lib/sequel/model/base.rb +51 -27
  145. data/lib/sequel/model/errors.rb +10 -1
  146. data/lib/sequel/model/inflections.rb +1 -1
  147. data/lib/sequel/model/plugins.rb +5 -0
  148. data/lib/sequel/plugins/association_proxies.rb +2 -0
  149. data/lib/sequel/plugins/async_thread_pool.rb +39 -0
  150. data/lib/sequel/plugins/auto_restrict_eager_graph.rb +62 -0
  151. data/lib/sequel/plugins/auto_validations.rb +87 -15
  152. data/lib/sequel/plugins/auto_validations_constraint_validations_presence_message.rb +68 -0
  153. data/lib/sequel/plugins/class_table_inheritance.rb +2 -2
  154. data/lib/sequel/plugins/column_encryption.rb +728 -0
  155. data/lib/sequel/plugins/composition.rb +10 -4
  156. data/lib/sequel/plugins/concurrent_eager_loading.rb +174 -0
  157. data/lib/sequel/plugins/constraint_validations.rb +2 -1
  158. data/lib/sequel/plugins/dataset_associations.rb +4 -1
  159. data/lib/sequel/plugins/dirty.rb +1 -1
  160. data/lib/sequel/plugins/enum.rb +124 -0
  161. data/lib/sequel/plugins/finder.rb +4 -2
  162. data/lib/sequel/plugins/insert_conflict.rb +4 -0
  163. data/lib/sequel/plugins/instance_specific_default.rb +1 -1
  164. data/lib/sequel/plugins/json_serializer.rb +39 -24
  165. data/lib/sequel/plugins/lazy_attributes.rb +3 -0
  166. data/lib/sequel/plugins/list.rb +3 -1
  167. data/lib/sequel/plugins/many_through_many.rb +109 -10
  168. data/lib/sequel/plugins/nested_attributes.rb +12 -7
  169. data/lib/sequel/plugins/pg_array_associations.rb +56 -38
  170. data/lib/sequel/plugins/pg_auto_constraint_validations.rb +3 -1
  171. data/lib/sequel/plugins/prepared_statements.rb +10 -1
  172. data/lib/sequel/plugins/primary_key_lookup_check_values.rb +154 -0
  173. data/lib/sequel/plugins/rcte_tree.rb +27 -19
  174. data/lib/sequel/plugins/require_valid_schema.rb +67 -0
  175. data/lib/sequel/plugins/serialization.rb +9 -3
  176. data/lib/sequel/plugins/serialization_modification_detection.rb +2 -1
  177. data/lib/sequel/plugins/single_table_inheritance.rb +8 -0
  178. data/lib/sequel/plugins/sql_comments.rb +189 -0
  179. data/lib/sequel/plugins/static_cache.rb +1 -1
  180. data/lib/sequel/plugins/subclasses.rb +28 -11
  181. data/lib/sequel/plugins/tactical_eager_loading.rb +23 -10
  182. data/lib/sequel/plugins/timestamps.rb +1 -1
  183. data/lib/sequel/plugins/unused_associations.rb +521 -0
  184. data/lib/sequel/plugins/update_or_create.rb +1 -1
  185. data/lib/sequel/plugins/validate_associated.rb +22 -12
  186. data/lib/sequel/plugins/validation_helpers.rb +38 -11
  187. data/lib/sequel/plugins/xml_serializer.rb +1 -1
  188. data/lib/sequel/sql.rb +1 -1
  189. data/lib/sequel/timezones.rb +12 -14
  190. data/lib/sequel/version.rb +1 -1
  191. metadata +103 -43
data/doc/querying.rdoc CHANGED
@@ -357,7 +357,9 @@ For ranges, Sequel uses a pair of inequality statements:
357
357
  # SELECT * FROM artists WHERE ((id >= 1) AND (id < 5))
358
358
 
359
359
  Finally, for regexps, Sequel uses an SQL regular expression. Note that this
360
- is probably only supported on PostgreSQL and MySQL.
360
+ is only supported by default on PostgreSQL and MySQL. It can also be supported
361
+ on SQLite when using the sqlite adapter with the :setup_regexp_function
362
+ Database option.
361
363
 
362
364
  Artist.where(name: /JM$/)
363
365
  # SELECT * FROM artists WHERE (name ~ 'JM$')
@@ -498,7 +500,7 @@ filters:
498
500
  # SELECT * FROM artists WHERE (id != 5)
499
501
 
500
502
  Artist.where(id: 5).exclude{name > 'A'}
501
- # SELECT * FROM artists WHERE ((id = 5) OR (name <= 'A')
503
+ # SELECT * FROM artists WHERE ((id = 5) AND (name <= 'A')
502
504
 
503
505
  So to do a NOT IN with an array:
504
506
 
@@ -713,7 +715,7 @@ aggregation:
713
715
 
714
716
  Album.select_group(:artist_id).select_append{sum(num_tracks).as(tracks)}
715
717
  # SELECT artist_id, sum(num_tracks) AS tracks FROM albums GROUP BY artist_id
716
-
718
+
717
719
  == Having
718
720
 
719
721
  The SQL HAVING clause is similar to the WHERE clause, except that
@@ -0,0 +1,40 @@
1
+ = New Features
2
+
3
+ * On SQLite 3.33.0+, the UPDATE FROM syntax is now supported. This
4
+ allows you to update one table based on a join to another table.
5
+ The SQLite syntax is based on the PostgreSQL syntax, and the
6
+ Sequel API is the same for both. You need to pass multiple tables
7
+ to Dataset#from. The first table is the table to update, and the
8
+ remaining tables are used to construct the UPDATE FROM clause:
9
+
10
+ DB[:a, :b].where{{a[:c]=>b[:d]}}.update(:e=>'f')
11
+ # UPDATE a SET e = 'f' FROM b WHERE (a.c = b.d)
12
+
13
+ Unlike PostgreSQL, SQLite does not support the deletion of joined
14
+ datasets. Related to this, the following methods for testing
15
+ database support for modifying joined datasets have been added:
16
+
17
+ * supports_updating_joins?
18
+ * supports_deleting_joins?
19
+
20
+ = Other Improvements
21
+
22
+ * The pg_interval and date_arithmetic extensions now support
23
+ ActiveSupport 6.1.
24
+
25
+ * Sequel no longer issues method redefinition warnings in verbose
26
+ mode. As Ruby 3 has dropped uninitialized instance variable
27
+ warnings, Sequel is now verbose warning free on Ruby 3.
28
+
29
+ = Backwards Compatibility
30
+
31
+ * Trying to truncate or insert into a joined dataset now correctly
32
+ raises an exception even if the joined dataset supports updates.
33
+
34
+ * The private Dataset#check_modification_allowed! method is now
35
+ deprecated, and users (custom adapters) should now switch to one
36
+ of the more specific methods introduced in this version:
37
+
38
+ * check_insert_allowed!
39
+ * check_update_allowed!
40
+ * check_delete_allowed!
@@ -0,0 +1,25 @@
1
+ = New Features
2
+
3
+ * The validation methods added by the validation_helpers plugin now
4
+ support the :skip_invalid option, which will not add a validation
5
+ error on a column if it already has a validation error. This can
6
+ be useful if you want to avoid having duplicate errors.
7
+
8
+ * The auto_validations plugin now supports a :skip_invalid plugin
9
+ option, which will pass the :skip_invalid option when calling
10
+ validation methods.
11
+
12
+ = Other Improvements
13
+
14
+ * The :adder, :remover, and :clearer association options now
15
+ support keyword arguments in Ruby 2.7+.
16
+
17
+ * In the pg_interval extension, Sequel now uses the same number of
18
+ seconds per month and seconds per year as active_support. It
19
+ originally used the same number, but active_support changed the
20
+ values in active_support 5.1. Sequel now uses the active_support
21
+ values if they are available.
22
+
23
+ * When adding a String column on PostgreSQL, an explicit text: true
24
+ option now takes precedence over an explicit :size option, as it
25
+ does in Sequel's default behavior.
@@ -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.
@@ -0,0 +1,59 @@
1
+ = New Features
2
+
3
+ * Sequel now supports using separate queries for each table for both
4
+ lazy and eager loading of the following associations:
5
+
6
+ * many_to_many
7
+ * one_through_one
8
+ * many_through_many # many_through_many plugin
9
+ * one_through_many # many_through_many plugin
10
+
11
+ For many_to_many/one_through_one, you specify the :join_table_db
12
+ association option, which should be a Sequel::Database instance
13
+ containing the join table. It is possible for the current table,
14
+ join table, and associated table all to be in separate databases:
15
+
16
+ JOIN_TABLE_DB = Sequel.connect('...')
17
+ Album.many_to_many :artists, join_table_db: JOIN_TABLE_DB
18
+
19
+ For many_through_many/one_through_many, you can use the :db option
20
+ in each join table specification. All join tables can be in
21
+ separate databases:
22
+
23
+ JTDB1 = Sequel.connect('...')
24
+ JTDB2 = Sequel.connect('...')
25
+ # Tracks on all albums this artist appears on
26
+ Artist.many_through_many :album_tracks, [
27
+ {table: :albums_artists, left: :artist_id, right: :album_id, db: JTDB1},
28
+ {table: :artists, left: :id, right: :id, db: JTDB2}
29
+ ],
30
+ class: :Track, right_primary_key: :album_id
31
+
32
+ * The :allow_eager_graph association option has been added. Setting
33
+ this option to false will disallow eager loading via #eager_graph.
34
+ This is useful if you can eager load the association via #eager,
35
+ but not with #eager_graph.
36
+
37
+ * The :allow_filtering_by association option has been added. Setting
38
+ this option to false will disallow the use of filtering by
39
+ associations for the association.
40
+
41
+ * Dataset#returning is now supported on SQLite 3.35.0+. To work around
42
+ bugs in the SQLite implementation, identifiers used in the RETURNING
43
+ clause are automatically aliased. Additionally, prepared statements
44
+ that use the RETURNING clause on SQLite seem to have issues, so the
45
+ prepared_statements plugin does not automatically use prepared
46
+ statements on SQLite for queries that use the RETURNING clause.
47
+
48
+ * Database#rename_tables has been added on MySQL to support renaming
49
+ multiple tables in the same query.
50
+
51
+ = Other Improvements
52
+
53
+ * The unused_associations plugin now tracks access to the association
54
+ reflection for associations, so it will no longer show an
55
+ association as completely unused if something is accessing the
56
+ association reflection for it. This eliminates most of the false
57
+ positives, where the plugin would show an association as unused
58
+ even though something was using it without calling the association
59
+ methods.
@@ -0,0 +1,14 @@
1
+ = New Features
2
+
3
+ * A Sequel::Database#like_without_collate accessor has been added on
4
+ Microsoft SQL Server, which avoids using the COLLATE clause for
5
+ LIKE expressions. This can speed up query performance significantly.
6
+
7
+ * A private Sequel::Model::Errors#full_message method has been added
8
+ to make it easier to support internationalization for Sequel::Model
9
+ error messages.
10
+
11
+ = Other Improvements
12
+
13
+ * The association reflection tracking in the unused_associations
14
+ plugin now works correctly when combining coverage runs.
@@ -0,0 +1,59 @@
1
+ = New Features
2
+
3
+ * Model#validates_no_null_byte has been added to the
4
+ validation_helpers. It checks that the value being validated does
5
+ not contain an ASCII NUL ('\0') byte. Some databases will return an
6
+ error if a string contains a NUL byte.
7
+
8
+ The auto_validations plugin will now automatically add no_null_byte
9
+ validations for all string columns in the model's table. This will
10
+ change exceptions raised by NUL bytes from database errors to
11
+ validation failures.
12
+
13
+ If you are using auto_validations and would like to have a table
14
+ accept NUL bytes in string columns, use the following code inside
15
+ the model:
16
+
17
+ skip_auto_validations(:no_null_byte)
18
+
19
+ * JSONB subscripts are now supported on PostgreSQL 14+ when using the
20
+ pg_json_ops extension. You can use JSONB subscripts to more easily
21
+ update part of a JSONB column:
22
+
23
+ DB[:table].update(Sequel.pg_jsonb_op(:column)['key'] => 'value')
24
+ UPDATE "table" SET "column"['key'] = 'value'
25
+
26
+ * hstore subscripts are now supported on PostgreSQL 14+ when using the
27
+ pg_hstore_ops extension. You can use hstore subscripts to more
28
+ easily update part of an hstore column:
29
+
30
+ DB[:table].update(Sequel.hstore_op(:column)['key'] => 'value')
31
+ UPDATE "table" SET "column"['key'] = 'value'
32
+
33
+ * Sequel now supports table aliases for JOIN USING columns on
34
+ PostgreSQL 14+. These allow you to reference the USING columns in
35
+ the query using a qualified identifier. To use this support, pass an
36
+ SQL::AliasedExpression as the expression to join on:
37
+
38
+ DB[:t1].join(:t2, Sequel.as([:c1, :c2], :alias))
39
+ # SELECT * FROM "t1" INNER JOIN "t2" USING ("c1", "c2") AS "alias"
40
+
41
+ * Database#create_trigger on PostgreSQL now supports a :replace option
42
+ for CREATE OR REPLACE TRIGGER (supported in PostgreSQL 14+).
43
+
44
+ * SQL::Expression#sequel_ast_transform has been added to support
45
+ AST transforms of custom expression classes.
46
+
47
+ = Other Improvements
48
+
49
+ * Sequel now supports calling PostgreSQL procedures without arguments
50
+ when using Database#call_procedure. Previously, attempts to call
51
+ procuredures without arguments would call the procedure with a
52
+ single NULL argument.
53
+
54
+ * Sequel now uses defined?(yield) instead of block_given? internally
55
+ for better performance on CRuby. defined?(yield) is faster as it is
56
+ built into the VM, while block_given? is a regular method and has
57
+ the overhead of calling a regular method. Note that defined?(yield)
58
+ is not implemented correctly on JRuby before 9.0.0.0, so this
59
+ release of Sequel drops support for JRuby versions before 9.0.0.0.