sequel 5.30.0 → 5.35.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (97) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +86 -0
  3. data/README.rdoc +1 -1
  4. data/doc/advanced_associations.rdoc +4 -4
  5. data/doc/association_basics.rdoc +10 -5
  6. data/doc/code_order.rdoc +12 -2
  7. data/doc/dataset_filtering.rdoc +2 -2
  8. data/doc/model_dataset_method_design.rdoc +1 -1
  9. data/doc/postgresql.rdoc +71 -0
  10. data/doc/release_notes/5.31.0.txt +148 -0
  11. data/doc/release_notes/5.32.0.txt +46 -0
  12. data/doc/release_notes/5.33.0.txt +24 -0
  13. data/doc/release_notes/5.34.0.txt +40 -0
  14. data/doc/release_notes/5.35.0.txt +56 -0
  15. data/doc/testing.rdoc +1 -1
  16. data/lib/sequel/adapters/oracle.rb +2 -1
  17. data/lib/sequel/adapters/shared/access.rb +6 -6
  18. data/lib/sequel/adapters/shared/mssql.rb +5 -5
  19. data/lib/sequel/adapters/shared/mysql.rb +9 -9
  20. data/lib/sequel/adapters/shared/oracle.rb +16 -16
  21. data/lib/sequel/adapters/shared/postgres.rb +169 -14
  22. data/lib/sequel/adapters/shared/sqlanywhere.rb +9 -9
  23. data/lib/sequel/adapters/shared/sqlite.rb +33 -6
  24. data/lib/sequel/adapters/tinytds.rb +1 -0
  25. data/lib/sequel/connection_pool/sharded_single.rb +4 -1
  26. data/lib/sequel/connection_pool/sharded_threaded.rb +12 -12
  27. data/lib/sequel/connection_pool/single.rb +1 -1
  28. data/lib/sequel/connection_pool/threaded.rb +2 -2
  29. data/lib/sequel/core.rb +318 -314
  30. data/lib/sequel/database/connecting.rb +1 -1
  31. data/lib/sequel/database/misc.rb +16 -10
  32. data/lib/sequel/database/query.rb +3 -1
  33. data/lib/sequel/database/schema_generator.rb +0 -1
  34. data/lib/sequel/database/schema_methods.rb +15 -16
  35. data/lib/sequel/database/transactions.rb +7 -4
  36. data/lib/sequel/dataset/placeholder_literalizer.rb +3 -7
  37. data/lib/sequel/dataset/query.rb +5 -4
  38. data/lib/sequel/deprecated.rb +3 -1
  39. data/lib/sequel/exceptions.rb +2 -0
  40. data/lib/sequel/extensions/_pretty_table.rb +1 -2
  41. data/lib/sequel/extensions/columns_introspection.rb +1 -2
  42. data/lib/sequel/extensions/connection_expiration.rb +2 -2
  43. data/lib/sequel/extensions/connection_validator.rb +2 -2
  44. data/lib/sequel/extensions/core_refinements.rb +2 -0
  45. data/lib/sequel/extensions/duplicate_columns_handler.rb +2 -0
  46. data/lib/sequel/extensions/fiber_concurrency.rb +24 -0
  47. data/lib/sequel/extensions/index_caching.rb +9 -7
  48. data/lib/sequel/extensions/integer64.rb +2 -0
  49. data/lib/sequel/extensions/migration.rb +1 -2
  50. data/lib/sequel/extensions/pg_array_ops.rb +4 -0
  51. data/lib/sequel/extensions/pg_enum.rb +7 -2
  52. data/lib/sequel/extensions/pg_extended_date_support.rb +1 -1
  53. data/lib/sequel/extensions/pg_hstore.rb +6 -0
  54. data/lib/sequel/extensions/pg_hstore_ops.rb +2 -0
  55. data/lib/sequel/extensions/pg_inet.rb +15 -5
  56. data/lib/sequel/extensions/pg_interval.rb +2 -0
  57. data/lib/sequel/extensions/pg_json_ops.rb +2 -0
  58. data/lib/sequel/extensions/pg_range.rb +5 -7
  59. data/lib/sequel/extensions/pg_range_ops.rb +2 -0
  60. data/lib/sequel/extensions/pg_row.rb +0 -1
  61. data/lib/sequel/extensions/pg_timestamptz.rb +2 -0
  62. data/lib/sequel/extensions/run_transaction_hooks.rb +72 -0
  63. data/lib/sequel/extensions/s.rb +2 -0
  64. data/lib/sequel/extensions/schema_dumper.rb +10 -4
  65. data/lib/sequel/extensions/server_block.rb +3 -3
  66. data/lib/sequel/extensions/symbol_aref_refinement.rb +2 -0
  67. data/lib/sequel/extensions/symbol_as_refinement.rb +2 -0
  68. data/lib/sequel/extensions/to_dot.rb +9 -3
  69. data/lib/sequel/model.rb +2 -0
  70. data/lib/sequel/model/associations.rb +54 -25
  71. data/lib/sequel/model/base.rb +70 -57
  72. data/lib/sequel/model/plugins.rb +3 -3
  73. data/lib/sequel/plugins/association_lazy_eager_option.rb +66 -0
  74. data/lib/sequel/plugins/association_multi_add_remove.rb +2 -0
  75. data/lib/sequel/plugins/association_pks.rb +60 -18
  76. data/lib/sequel/plugins/association_proxies.rb +2 -0
  77. data/lib/sequel/plugins/blacklist_security.rb +1 -2
  78. data/lib/sequel/plugins/boolean_subsets.rb +4 -1
  79. data/lib/sequel/plugins/class_table_inheritance.rb +28 -28
  80. data/lib/sequel/plugins/csv_serializer.rb +2 -0
  81. data/lib/sequel/plugins/dirty.rb +13 -13
  82. data/lib/sequel/plugins/forbid_lazy_load.rb +216 -0
  83. data/lib/sequel/plugins/instance_specific_default.rb +113 -0
  84. data/lib/sequel/plugins/json_serializer.rb +3 -7
  85. data/lib/sequel/plugins/lazy_attributes.rb +1 -1
  86. data/lib/sequel/plugins/pg_array_associations.rb +2 -3
  87. data/lib/sequel/plugins/prepared_statements.rb +5 -11
  88. data/lib/sequel/plugins/prepared_statements_safe.rb +1 -3
  89. data/lib/sequel/plugins/rcte_tree.rb +10 -16
  90. data/lib/sequel/plugins/single_table_inheritance.rb +15 -15
  91. data/lib/sequel/plugins/skip_saving_columns.rb +108 -0
  92. data/lib/sequel/plugins/string_stripper.rb +1 -1
  93. data/lib/sequel/plugins/subclasses.rb +2 -0
  94. data/lib/sequel/plugins/validation_class_methods.rb +5 -1
  95. data/lib/sequel/timezones.rb +6 -4
  96. data/lib/sequel/version.rb +1 -1
  97. metadata +18 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 22c562c1227d83d1425ef6db9d8bd503595cd97e35036cca335aeb588a00f3df
4
- data.tar.gz: 18c96ea22fe23f65b6f85c6efc17ce9b17e783fc8bfaefa498edb7ada25499aa
3
+ metadata.gz: 7ac0d24707f9029714f4e5258c484148d7dc10a733c0c33865d252141cd4cc2e
4
+ data.tar.gz: cdabb1bb51fdfe7b7a22df0a6a9102dd15366bbdd98100907b2e3d74db4e5878
5
5
  SHA512:
6
- metadata.gz: 890ae35cd097875a8cab776d7db7760ccb8b21fa0317dd26011a5a49996d378bdd5db68c299967c47c7b066718aca642fb7b606979753a1ac9833ac2d004b02d
7
- data.tar.gz: bb685f30c7c4db37441f38cc1e6a729e5d87db86996474bbcb18dd551310ff7751e2abc56db146483e319197bb6381cbf12c6e4e2e6a2079da82ff74ae4aadc9
6
+ metadata.gz: d87a7d026c51d8897c964cca01ad30384b853bdbbda42811ee7245ef669ac23c1093e572a0e414db5daeb84b8f417e63c14c3ac13aa0b12ac9eb8f801ea6e6c2
7
+ data.tar.gz: 3e788cabe74d01035b930ca699b5ebc763a6a34410c1b8a3a5075d5a276c5155355d9476303b6b606d1b0a74d6a535ca4fdca696cdc0b83e32658be45c8f946e
data/CHANGELOG CHANGED
@@ -1,3 +1,89 @@
1
+ === 5.35.0 (2020-08-01)
2
+
3
+ * Recognize another disconnect error in the oracle adapter (sterlzbd) (#1705)
4
+
5
+ * Consider all associations with :dataset options as instance-specific associations (jeremyevans)
6
+
7
+ * Make Model.finalize_associations not break with instance-specific associations (jeremyevans)
8
+
9
+ * Make association placeholder loader consider block if instance_specific: false association option is used (jeremyevans)
10
+
11
+ * Copy composite unique constraints when emulating alter table operations on SQLite (jeremyevans) (#1704)
12
+
13
+ * Add instance_specific_default plugin for setting default association :instance_specific value, or warning/raising for cases where it is not specified (jeremyevans)
14
+
15
+ * Make Model.plugin issue deprecation warning if loading plugin with arguments and block if plugin does not accept arguments/block (jeremyevans)
16
+
17
+ * Make validation_class_methods consider all :if, :allow_missing, :allow_nil, and :allow_blank settings, instead of just the first (jeremyevans)
18
+
19
+ * Include hash entries with nil keys in Dataset#to_dot output in to_dot extension (jeremyevans)
20
+
21
+ * Remove unneeded conditionals from plugins and extensions (jeremyevans)
22
+
23
+ * Fix exception class in run_transaction_hooks extension if calling run_after_{commit,rollback}_hooks outside of a transaction (jeremyevans)
24
+
25
+ === 5.34.0 (2020-07-01)
26
+
27
+ * Make eager_graph work correctly if called with no associations (jeremyevans)
28
+
29
+ * Make :ruby eager limit strategy handle cases where there is no limit or offset (jeremyevans)
30
+
31
+ * Do not keep a reference to a Sequel::Database instance that raises an exception during initialization (jeremyevans)
32
+
33
+ * Make Database#pool.all_connections not yield for a single connection pool in disconnected state (jeremyevans)
34
+
35
+ * Raise an exception if trying to disconnect a server that doesn't exist in the sharded connection pools (jeremyevans)
36
+
37
+ * Support :refresh option when calling *_pks getter method in the association_pks plugin (jeremyevans)
38
+
39
+ * Support caching of repeated calls to *_pks getter method in the association_pks plugin using :cache_pks association option (jeremyevans)
40
+
41
+ * Add *_pks_dataset methods for one_to_many and many_to_many associations when using the association_pks plugin (jeremyevans)
42
+
43
+ === 5.33.0 (2020-06-01)
44
+
45
+ * Support custom join types on a per-association basis when using eager_graph/association_join (jeremyevans)
46
+
47
+ * Support primary_key with type: :smallserial on PostgreSQL (j-a-m-l) (#1698)
48
+
49
+ * Add Database#current_timestamp_utc accessor on SQLite to keep CURRENT_* in UTC instead of converting to localtime (jeremyevans)
50
+
51
+ === 5.32.0 (2020-05-01)
52
+
53
+ * Allow Database#create_table? work with :partition_of option on PostgreSQL (jeremyevans) (#1690)
54
+
55
+ * Add fiber_concurrency extension, for using Fiber.current instead of Thread.current for checking out connections (jeremyevans)
56
+
57
+ * Move most Sequel singleton methods into a module that extends Sequel for easier overriding (jeremyevans)
58
+
59
+ * Fix method visibility issues in model, plugin, extension, and adapter code (jeremyevans)
60
+
61
+ * Avoid defining conversion procs for PostgreSQL inet/cidr types in pg_inet extension when using sequel_pg 1.13.0+ (jeremyevans)
62
+
63
+ * Add run_transaction_hooks Database extension, allowing for running the transaction hooks before commit/rollback, for use with transactional testing (jeremyevans)
64
+
65
+ * Recognize timestamp(N) with time zone type (isc) (#1684)
66
+
67
+ === 5.31.0 (2020-04-01)
68
+
69
+ * Fix alter_table drop_constraint :primary_key option on SQLite for non-integer primary keys (jeremyevans)
70
+
71
+ * Add skip_saving_columns plugin, which supports columns to skip when saving, and skips generated columns by default (joeosburn, jeremyevans) (#1681, #1682)
72
+
73
+ * Add support for creating partitioned tables in PostgreSQL 10+ using :partition_by and :partition_of options (jeremyevans)
74
+
75
+ * Dump generated columns as generated columns when using the schema_dumper with :same_db option on PostgreSQL 12+ (jeremyevans) (#1680)
76
+
77
+ * Ignore defaults for generated columns by default when using the schema dumper (jeremyevans) (#1680)
78
+
79
+ * Include generated columns in schema on SQLite 3.31+ (jeremyevans)
80
+
81
+ * Add :generated schema entry on PostgreSQL 12+ and SQLite 3.31+ for whether the columns is generated (jeremyevans)
82
+
83
+ * Add association_lazy_eager_option plugin for supporting :eager option for association method (jeremyevans)
84
+
85
+ * Add forbid_lazy_load plugin for forbidding lazy loading of associations, to help find N+1 issues (jeremyevans)
86
+
1
87
  === 5.30.0 (2020-03-01)
2
88
 
3
89
  * Remove specs and old release notes from the gem to reduce gem size by over 40% (jeremyevans)
@@ -894,7 +894,7 @@ in the most current release.
894
894
 
895
895
  Sequel fully supports the currently supported versions of Ruby (MRI) and JRuby. It may
896
896
  support unsupported versions of Ruby or JRuby, but such support may be dropped in any
897
- minor version of keeping it becomes a support issue. The minimum Ruby version
897
+ minor version if keeping it becomes a support issue. The minimum Ruby version
898
898
  required to run the current version of Sequel is 1.9.2.
899
899
 
900
900
  == Maintainer
@@ -731,7 +731,7 @@ associations:
731
731
  one_to_one :tracks, key: [:disc_number, :number, :album_id], primary_key: [:disc_number, :number, :album_id]
732
732
  end
733
733
 
734
- === Tree - All Ancestors and Descendents
734
+ === Tree - All Ancestors and Descendants
735
735
 
736
736
  Let's say you want to store a tree relationship in your database, it's pretty
737
737
  simple:
@@ -749,7 +749,7 @@ node.children. You can even eager load the relationship up to a certain depth:
749
749
  # Load parents and grandparents for a group of nodes
750
750
  Node.where{id < 10}.eager(parent: :parent).all
751
751
 
752
- What if you want to get all ancestors up to the root node, or all descendents,
752
+ What if you want to get all ancestors up to the root node, or all descendants,
753
753
  without knowing the depth of the tree?
754
754
 
755
755
  class Node < Sequel::Model
@@ -770,7 +770,7 @@ without knowing the depth of the tree?
770
770
  id_map = {}
771
771
  # Create an map of parent_ids to nodes that have that parent id
772
772
  non_root_nodes.each{|n| (id_map[n.parent_id] ||= []) << n}
773
- # Doesn't cause an infinte loop, because when only the root node
773
+ # Doesn't cause an infinite loop, because when only the root node
774
774
  # is left, this is not called.
775
775
  Node.where(id: id_map.keys).eager(:ancestors).all do |node|
776
776
  # Populate the parent association for each node
@@ -879,4 +879,4 @@ associated tickets.
879
879
  end
880
880
 
881
881
  Note that it is often better to use a sum cache instead of this approach. You can implement
882
- a sum cache using +after_create+, +after_update+, and +after_delete+ hooks, or preferrably using a database trigger.
882
+ a sum cache using +after_create+, +after_update+, and +after_delete+ hooks, or preferably using a database trigger.
@@ -113,7 +113,7 @@ many rows in the current table, by using a join table to associate the two table
113
113
  The one_through_one association can be thought of as a subset of the many_to_many
114
114
  association, but where there can only be 0 or 1 records in the associated table.
115
115
  This is useful if there is a unique constraint on the foreign key in the join table
116
- that refrences the current table. It's also useful if you want to impose an order
116
+ that references the current table. It's also useful if you want to impose an order
117
117
  on the association and just want the first record returned. The one_through_one
118
118
  association is so named because it sets up a one-to-one association through a
119
119
  single join table.
@@ -781,7 +781,7 @@ Sequel is designed to be very flexible. If the default behavior of the
781
781
  association modification methods isn't what you desire, you can override
782
782
  the methods in your classes. However, you should be aware that for each
783
783
  of the association modification methods described, there is a private
784
- method that is preceeded by an underscore that does the actual
784
+ method that is preceded by an underscore that does the actual
785
785
  modification. The public method without the underscore handles caching
786
786
  and callbacks, and shouldn't be overridden by the user.
787
787
 
@@ -1069,7 +1069,7 @@ option of the first association, it doesn't attempt to merge them.
1069
1069
  In addition to the options hash, the :clone option will copy a block argument
1070
1070
  from the existing situation. If you want a cloned association to not have the
1071
1071
  same block as the association you are cloning from, specify the block: nil option
1072
- in additon to the :clone option.
1072
+ in addition to the :clone option.
1073
1073
 
1074
1074
  ==== :dataset
1075
1075
 
@@ -1676,11 +1676,16 @@ instances.
1676
1676
  ==== :instance_specific
1677
1677
 
1678
1678
  This allows you to override the setting of whether the dataset contains instance
1679
- specific code. For example, if you are passing a block to the association,
1679
+ specific code. If you are passing a block to the association,
1680
1680
  Sequel sets this to true by default, which disables some optimizations that
1681
1681
  would be invalid if the association is instance specific. If you know that the
1682
1682
  block does not contain instance specific code, you can set this to false to
1683
- reenable the optimizations.
1683
+ reenable the optimizations. Instance specific code is mostly commonly calling
1684
+ model instance methods inside an association block, but also
1685
+ includes cases where the association block can return different values based
1686
+ on the runtime environment, such as calls to <tt>Time.now</tt> in the block.
1687
+ Associations that use the :dataset option are always considered instance specific,
1688
+ even if explicitly specified otherwise.
1684
1689
 
1685
1690
  ==== :cartesian_product_number
1686
1691
 
@@ -7,7 +7,7 @@ this guide will be specific about which are strictly necessary.
7
7
 
8
8
  == Require Sequel
9
9
 
10
- This is sort of a no brainer, but you need to require the library
10
+ This is sort of a no-brainer, but you need to require the library
11
11
  first. This is a strict requirement, none of the other code can
12
12
  be executed unless the library has been required first. Example:
13
13
 
@@ -70,7 +70,7 @@ copied into the subclass when model subclasses are created. Example:
70
70
  == Load Model Classes
71
71
 
72
72
  After you have established a database connection, and configured your
73
- global model configration and global plugins, you can load your model
73
+ global model configuration and global plugins, you can load your model
74
74
  classes. It's recommended to have a separate file for each model class,
75
75
  unless the model classes are very simple. Example:
76
76
 
@@ -91,6 +91,16 @@ unsafe runtime modification of the configuration:
91
91
  model_classes.each(&:freeze)
92
92
  DB.freeze
93
93
 
94
+ The `subclasses` plugin can be used to keep track of all model classes
95
+ that have been setup in your application. Finalizing their associations
96
+ and freezing them can easily be achieved through the plugin:
97
+
98
+ # Register the plugin before setting up the models
99
+ Sequel::Model.plugin :subclasses
100
+ # ... setup models
101
+ # Now finalize associations & freeze models by calling the plugin:
102
+ Sequel::Model.freeze_descendents
103
+
94
104
  == Disconnect If Using Forking Webserver with Code Preloading
95
105
 
96
106
  If you are using a forking webserver such as unicorn or passenger, with
@@ -36,8 +36,8 @@ Ranges (both inclusive and exclusive) can also be used:
36
36
 
37
37
  If you need to select multiple items from a dataset, you can supply an array:
38
38
 
39
- items.where(id: [1, 38, 47, 99]).sql
40
- # "SELECT * FROM items WHERE (id IN (1, 38, 47, 99))"
39
+ items.where(id: [1, 38, 47, 99]).sql
40
+ # "SELECT * FROM items WHERE (id IN (1, 38, 47, 99))"
41
41
 
42
42
  == Filtering using expressions
43
43
 
@@ -4,7 +4,7 @@ How you design your model dataset methods can significantly affect the flexibili
4
4
 
5
5
  == Flexibility: Use Single Method Per Task
6
6
 
7
- In general, it is recommended that you have a single method per task for maximum flexibilty. For example, let's say you need to retrieve all albums released in a given year, ordered by number of units sold descending, and only care about the id, name and number of units sold. One way to do this is in your application code (outside the model), you can
7
+ In general, it is recommended that you have a single method per task for maximum flexibility. For example, let's say you need to retrieve all albums released in a given year, ordered by number of units sold descending, and only care about the id, name and number of units sold. One way to do this is in your application code (outside the model), you can
8
8
  call the dataset methods directly:
9
9
 
10
10
  Album.
@@ -139,6 +139,77 @@ conversion via a USING clause, and Sequel supports this using the <tt>:using</tt
139
139
  # ALTER TABLE "table" ALTER COLUMN "unix_time" TYPE timestamp
140
140
  # USING (CAST('epoch' AS timestamp) + (CAST('1 second' AS interval) * "unix_time"))
141
141
 
142
+ === Creating Partitioned Tables
143
+
144
+ PostgreSQL allows marking tables as partitioned tables, and adding partitions to such tables. Sequel
145
+ offers support for this. You can create a partitioned table using the +:partition_by+ option and
146
+ +:partition_type+ options (the default partition type is range partitioning):
147
+
148
+ DB.create_table(:table1, partition_by: :column, partition_type: :range) do
149
+ Integer :id
150
+ Date :column
151
+ end
152
+
153
+ DB.create_table(:table2, partition_by: :column, partition_type: :list) do
154
+ Integer :id
155
+ String :column
156
+ end
157
+
158
+ DB.create_table(:table3, partition_by: :column, partition_type: :hash) do
159
+ Integer :id
160
+ Integer :column
161
+ end
162
+
163
+ To add partitions of other tables, you use the +:partition_of+ option. This option will use
164
+ a custom DSL specific to partitioning other tables. For range partitioning, you can use the
165
+ +from+ and +to+ methods to specify the inclusive beginning and exclusive ending of the
166
+ range of the partition. You can call the +minvalue+ and +maxvalue+ methods to get the minimum
167
+ and maximum values for the column(s) in the range, useful as arguments to +from+ and +to+:
168
+
169
+ DB.create_table(:table1a, partition_of: :table1) do
170
+ from minvalue
171
+ to 0
172
+ end
173
+ DB.create_table(:table1b, partition_of: :table1) do
174
+ from 0
175
+ to 100
176
+ end
177
+ DB.create_table(:table1c, partition_of: :table1) do
178
+ from 100
179
+ to maxvalue
180
+ end
181
+
182
+ For list partitioning, you use the +values_in+ method. You can also use the +default+ method
183
+ to mark a partition as the default partition:
184
+
185
+ DB.create_table(:table2a, partition_of: :table2) do
186
+ values_in 1, 2, 3
187
+ end
188
+ DB.create_table(:table2b, partition_of: :table2) do
189
+ values_in 4, 5, 6
190
+ end
191
+ DB.create_table(:table2c, partition_of: :table2) do
192
+ default
193
+ end
194
+
195
+ For hash partitioning, you use the +modulus+ and +remainder+ methods:
196
+
197
+ DB.create_table(:table3a, partition_of: :table3) do
198
+ modulus 3
199
+ remainder 0
200
+ end
201
+ DB.create_table(:table3b, partition_of: :table3) do
202
+ modulus 3
203
+ remainder 1
204
+ end
205
+ DB.create_table(:table3c, partition_of: :table3) do
206
+ modulus 3
207
+ remainder 2
208
+ end
209
+
210
+ There is currently no support for using custom column or table constraints in partitions of
211
+ other tables. Support may be added in the future.
212
+
142
213
  === Creating Unlogged Tables
143
214
 
144
215
  PostgreSQL allows users to create unlogged tables, which are faster but not crash safe. Sequel
@@ -0,0 +1,148 @@
1
+ = New Features
2
+
3
+ * A forbid_lazy_load plugin has been added to forbid the lazy loading
4
+ of model associations if the current object was retreived with other
5
+ objects. This plugin helps detect N+1 query issues. This plugin
6
+ will raise an error if a lazy load is detected in such cases:
7
+
8
+ Album.plugin :forbid_lazy_load
9
+ Album.one_to_many :tracks
10
+
11
+ Album.each do |album|
12
+ album.tracks
13
+ # Could be N+1, raises Sequel::Plugins::ForbidLazyLoad::Error
14
+ end
15
+
16
+ Album.first.tracks
17
+ # Could not be N+1, no error raised
18
+
19
+ The forbid_lazy_load plugin is designed to be loaded into the base
20
+ model class (generally Sequel::Model), and can be loaded only in
21
+ test mode, or only in certain test mode configurations, so that it
22
+ does not have any production performance impact.
23
+
24
+ Note that an alternative approach that Sequel has supported for many
25
+ years is the tactical_eager_loading plugin, which automatically
26
+ eager loads when an N+1 query issue is detected.
27
+
28
+ * An association_lazy_eager_option plugin has been added which supports
29
+ the :eager option for the association method. If the association has
30
+ not been loaded, this eagerly loads the associations specified by the
31
+ :eager option when loading the association. If the association has
32
+ already been loaded, this option is ignored, with the assumption that
33
+ whatever loaded the association already used the correct eager
34
+ loading. Example:
35
+
36
+ Album.plugin :association_lazy_eager_option
37
+ Album.one_to_many :tracks
38
+ Track.many_to_one :artist
39
+
40
+ album = Album.first
41
+ album.tracks(:eager=>:artist)
42
+ # Loads tracks for album, then artist for each track (2 queries)
43
+
44
+ album.tracks(:eager=>:artist)
45
+ # No query issued as association is cached
46
+
47
+ You could previously have similar behavior for uncached associations
48
+ by passing a block to the association method and calling eager on
49
+ the yielded dataset. However, that would ignore any cached
50
+ association, causing redundant loading of the association in such
51
+ cases.
52
+
53
+ * On PostgreSQL 10+, creating partitioned tables and partitions of
54
+ other tables is now supported.
55
+
56
+ To create a partitioned table, use the :partition_by option:
57
+
58
+ DB.create_table(:table1, partition_by: :date_column,
59
+ partition_type: :range) do
60
+ Integer :id
61
+ Date :date_column
62
+ end
63
+
64
+ DB.create_table(:table2, partition_by: :string_column,
65
+ partition_type: :list) do
66
+ Integer :id
67
+ String :string_column
68
+ end
69
+
70
+ DB.create_table(:table3, partition_by: :int_column,
71
+ partition_type: :hash) do
72
+ Integer :id
73
+ Integer :int_column
74
+ end
75
+
76
+ To add partitions of other tables, use the :partition_of option.
77
+ This option will use a custom DSL specific to partitions of other
78
+ tables.
79
+
80
+ For range partitioning, you can use the from and to methods to
81
+ specify the inclusive beginning and exclusive ending of the range
82
+ of the partition. You can call the minvalue and maxvalue methods
83
+ to get the minimum and maximum values for the column(s) in the
84
+ range, useful as arguments to from and to:
85
+
86
+ DB.create_table(:table1a, partition_of: :table1) do
87
+ from minvalue
88
+ to 0
89
+ end
90
+ DB.create_table(:table1b, partition_of: :table1) do
91
+ from 0
92
+ to 100
93
+ end
94
+ DB.create_table(:table1c, partition_of: :table1) do
95
+ from 100
96
+ to maxvalue
97
+ end
98
+
99
+ For list partitioning, you use the values_in method. You can also
100
+ use the default method to mark a partition as the default partition:
101
+
102
+ DB.create_table(:table2a, partition_of: :table2) do
103
+ values_in 1, 2, 3
104
+ end
105
+ DB.create_table(:table2b, partition_of: :table2) do
106
+ values_in 4, 5, 6
107
+ end
108
+ DB.create_table(:table2c, partition_of: :table2) do
109
+ default
110
+ end
111
+
112
+ For hash partitioning, you use the modulus and remainder methods:
113
+
114
+ DB.create_table(:table3a, partition_of: :table3) do
115
+ modulus 3
116
+ remainder 0
117
+ end
118
+ DB.create_table(:table3b, partition_of: :table3) do
119
+ modulus 3
120
+ remainder 1
121
+ end
122
+ DB.create_table(:table3c, partition_of: :table3) do
123
+ modulus 3
124
+ remainder 2
125
+ end
126
+
127
+ * On PostgreSQL 12+ and SQLite 3.31+, column schema hashes now have
128
+ a :generated entry for whether the column is a generated column.
129
+
130
+ * The schema_dumper extension now dumps generated columns correctly
131
+ when using the :same_db option on PostgreSQL 12+.
132
+
133
+ * A skip_saving_columns plugin has been added. This allows skipping
134
+ saving of specific columns for the model. By default, it skips
135
+ saving of generated columns, but you can customize the columns
136
+ that it skips:
137
+
138
+ Album.plugin :skip_saving_columns
139
+ Album.skip_saving_columns = [:some_column]
140
+
141
+ = Other Improvements
142
+
143
+ * The alter_table drop_constraint :primary_key option on SQLite now
144
+ works correctly for non-integer primary keys.
145
+
146
+ * When an error is raised due to an irreversible migration, the error
147
+ message now includes the file containing the migration for easier
148
+ debugging.