sequel 5.39.0 → 5.72.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (219) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +408 -0
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +59 -27
  5. data/bin/sequel +11 -3
  6. data/doc/advanced_associations.rdoc +16 -14
  7. data/doc/association_basics.rdoc +119 -24
  8. data/doc/cheat_sheet.rdoc +11 -3
  9. data/doc/mass_assignment.rdoc +1 -1
  10. data/doc/migration.rdoc +13 -6
  11. data/doc/model_hooks.rdoc +1 -1
  12. data/doc/object_model.rdoc +8 -8
  13. data/doc/opening_databases.rdoc +26 -12
  14. data/doc/postgresql.rdoc +16 -8
  15. data/doc/querying.rdoc +5 -3
  16. data/doc/release_notes/5.40.0.txt +40 -0
  17. data/doc/release_notes/5.41.0.txt +25 -0
  18. data/doc/release_notes/5.42.0.txt +136 -0
  19. data/doc/release_notes/5.43.0.txt +98 -0
  20. data/doc/release_notes/5.44.0.txt +32 -0
  21. data/doc/release_notes/5.45.0.txt +34 -0
  22. data/doc/release_notes/5.46.0.txt +87 -0
  23. data/doc/release_notes/5.47.0.txt +59 -0
  24. data/doc/release_notes/5.48.0.txt +14 -0
  25. data/doc/release_notes/5.49.0.txt +59 -0
  26. data/doc/release_notes/5.50.0.txt +78 -0
  27. data/doc/release_notes/5.51.0.txt +47 -0
  28. data/doc/release_notes/5.52.0.txt +87 -0
  29. data/doc/release_notes/5.53.0.txt +23 -0
  30. data/doc/release_notes/5.54.0.txt +27 -0
  31. data/doc/release_notes/5.55.0.txt +21 -0
  32. data/doc/release_notes/5.56.0.txt +51 -0
  33. data/doc/release_notes/5.57.0.txt +23 -0
  34. data/doc/release_notes/5.58.0.txt +31 -0
  35. data/doc/release_notes/5.59.0.txt +73 -0
  36. data/doc/release_notes/5.60.0.txt +22 -0
  37. data/doc/release_notes/5.61.0.txt +43 -0
  38. data/doc/release_notes/5.62.0.txt +132 -0
  39. data/doc/release_notes/5.63.0.txt +33 -0
  40. data/doc/release_notes/5.64.0.txt +50 -0
  41. data/doc/release_notes/5.65.0.txt +21 -0
  42. data/doc/release_notes/5.66.0.txt +24 -0
  43. data/doc/release_notes/5.67.0.txt +32 -0
  44. data/doc/release_notes/5.68.0.txt +61 -0
  45. data/doc/release_notes/5.69.0.txt +26 -0
  46. data/doc/release_notes/5.70.0.txt +35 -0
  47. data/doc/release_notes/5.71.0.txt +21 -0
  48. data/doc/release_notes/5.72.0.txt +33 -0
  49. data/doc/schema_modification.rdoc +1 -1
  50. data/doc/security.rdoc +9 -9
  51. data/doc/sharding.rdoc +3 -1
  52. data/doc/sql.rdoc +28 -16
  53. data/doc/testing.rdoc +22 -11
  54. data/doc/transactions.rdoc +6 -6
  55. data/doc/virtual_rows.rdoc +2 -2
  56. data/lib/sequel/adapters/ado/access.rb +1 -1
  57. data/lib/sequel/adapters/ado.rb +17 -17
  58. data/lib/sequel/adapters/amalgalite.rb +3 -5
  59. data/lib/sequel/adapters/ibmdb.rb +2 -2
  60. data/lib/sequel/adapters/jdbc/derby.rb +8 -0
  61. data/lib/sequel/adapters/jdbc/h2.rb +60 -10
  62. data/lib/sequel/adapters/jdbc/hsqldb.rb +6 -0
  63. data/lib/sequel/adapters/jdbc/postgresql.rb +7 -4
  64. data/lib/sequel/adapters/jdbc.rb +16 -18
  65. data/lib/sequel/adapters/mysql.rb +92 -67
  66. data/lib/sequel/adapters/mysql2.rb +54 -49
  67. data/lib/sequel/adapters/odbc.rb +6 -2
  68. data/lib/sequel/adapters/oracle.rb +4 -3
  69. data/lib/sequel/adapters/postgres.rb +83 -40
  70. data/lib/sequel/adapters/shared/access.rb +11 -1
  71. data/lib/sequel/adapters/shared/db2.rb +30 -0
  72. data/lib/sequel/adapters/shared/mssql.rb +90 -9
  73. data/lib/sequel/adapters/shared/mysql.rb +47 -2
  74. data/lib/sequel/adapters/shared/oracle.rb +82 -1
  75. data/lib/sequel/adapters/shared/postgres.rb +496 -178
  76. data/lib/sequel/adapters/shared/sqlanywhere.rb +11 -1
  77. data/lib/sequel/adapters/shared/sqlite.rb +116 -11
  78. data/lib/sequel/adapters/sqlanywhere.rb +1 -1
  79. data/lib/sequel/adapters/sqlite.rb +60 -18
  80. data/lib/sequel/adapters/tinytds.rb +1 -1
  81. data/lib/sequel/adapters/trilogy.rb +117 -0
  82. data/lib/sequel/adapters/utils/columns_limit_1.rb +22 -0
  83. data/lib/sequel/adapters/utils/mysql_mysql2.rb +1 -1
  84. data/lib/sequel/ast_transformer.rb +6 -0
  85. data/lib/sequel/connection_pool/sharded_single.rb +5 -7
  86. data/lib/sequel/connection_pool/sharded_threaded.rb +16 -11
  87. data/lib/sequel/connection_pool/sharded_timed_queue.rb +374 -0
  88. data/lib/sequel/connection_pool/single.rb +6 -8
  89. data/lib/sequel/connection_pool/threaded.rb +14 -8
  90. data/lib/sequel/connection_pool/timed_queue.rb +270 -0
  91. data/lib/sequel/connection_pool.rb +55 -31
  92. data/lib/sequel/core.rb +28 -18
  93. data/lib/sequel/database/connecting.rb +27 -3
  94. data/lib/sequel/database/dataset.rb +16 -6
  95. data/lib/sequel/database/misc.rb +69 -14
  96. data/lib/sequel/database/query.rb +73 -2
  97. data/lib/sequel/database/schema_generator.rb +46 -53
  98. data/lib/sequel/database/schema_methods.rb +18 -2
  99. data/lib/sequel/dataset/actions.rb +108 -14
  100. data/lib/sequel/dataset/deprecated_singleton_class_methods.rb +42 -0
  101. data/lib/sequel/dataset/features.rb +20 -0
  102. data/lib/sequel/dataset/misc.rb +12 -2
  103. data/lib/sequel/dataset/placeholder_literalizer.rb +20 -9
  104. data/lib/sequel/dataset/prepared_statements.rb +2 -0
  105. data/lib/sequel/dataset/query.rb +171 -44
  106. data/lib/sequel/dataset/sql.rb +182 -47
  107. data/lib/sequel/dataset.rb +4 -0
  108. data/lib/sequel/extensions/_model_pg_row.rb +0 -12
  109. data/lib/sequel/extensions/_pretty_table.rb +1 -1
  110. data/lib/sequel/extensions/any_not_empty.rb +1 -1
  111. data/lib/sequel/extensions/async_thread_pool.rb +439 -0
  112. data/lib/sequel/extensions/auto_literal_strings.rb +1 -1
  113. data/lib/sequel/extensions/blank.rb +8 -0
  114. data/lib/sequel/extensions/connection_expiration.rb +15 -9
  115. data/lib/sequel/extensions/connection_validator.rb +16 -11
  116. data/lib/sequel/extensions/constraint_validations.rb +1 -1
  117. data/lib/sequel/extensions/core_refinements.rb +36 -11
  118. data/lib/sequel/extensions/date_arithmetic.rb +71 -31
  119. data/lib/sequel/extensions/date_parse_input_handler.rb +67 -0
  120. data/lib/sequel/extensions/datetime_parse_to_time.rb +5 -1
  121. data/lib/sequel/extensions/duplicate_columns_handler.rb +1 -1
  122. data/lib/sequel/extensions/eval_inspect.rb +2 -0
  123. data/lib/sequel/extensions/index_caching.rb +5 -1
  124. data/lib/sequel/extensions/inflector.rb +9 -1
  125. data/lib/sequel/extensions/is_distinct_from.rb +141 -0
  126. data/lib/sequel/extensions/looser_typecasting.rb +3 -0
  127. data/lib/sequel/extensions/migration.rb +11 -2
  128. data/lib/sequel/extensions/named_timezones.rb +26 -6
  129. data/lib/sequel/extensions/pagination.rb +1 -1
  130. data/lib/sequel/extensions/pg_array.rb +32 -4
  131. data/lib/sequel/extensions/pg_array_ops.rb +2 -2
  132. data/lib/sequel/extensions/pg_auto_parameterize.rb +509 -0
  133. data/lib/sequel/extensions/pg_auto_parameterize_in_array.rb +110 -0
  134. data/lib/sequel/extensions/pg_enum.rb +2 -3
  135. data/lib/sequel/extensions/pg_extended_date_support.rb +38 -27
  136. data/lib/sequel/extensions/pg_extended_integer_support.rb +116 -0
  137. data/lib/sequel/extensions/pg_hstore.rb +6 -1
  138. data/lib/sequel/extensions/pg_hstore_ops.rb +53 -3
  139. data/lib/sequel/extensions/pg_inet.rb +10 -11
  140. data/lib/sequel/extensions/pg_inet_ops.rb +1 -1
  141. data/lib/sequel/extensions/pg_interval.rb +45 -19
  142. data/lib/sequel/extensions/pg_json.rb +13 -15
  143. data/lib/sequel/extensions/pg_json_ops.rb +73 -2
  144. data/lib/sequel/extensions/pg_loose_count.rb +3 -1
  145. data/lib/sequel/extensions/pg_multirange.rb +367 -0
  146. data/lib/sequel/extensions/pg_range.rb +11 -24
  147. data/lib/sequel/extensions/pg_range_ops.rb +37 -9
  148. data/lib/sequel/extensions/pg_row.rb +21 -19
  149. data/lib/sequel/extensions/pg_row_ops.rb +1 -1
  150. data/lib/sequel/extensions/query.rb +2 -0
  151. data/lib/sequel/extensions/s.rb +2 -1
  152. data/lib/sequel/extensions/schema_caching.rb +1 -1
  153. data/lib/sequel/extensions/schema_dumper.rb +45 -11
  154. data/lib/sequel/extensions/server_block.rb +10 -13
  155. data/lib/sequel/extensions/set_literalizer.rb +58 -0
  156. data/lib/sequel/extensions/sql_comments.rb +110 -3
  157. data/lib/sequel/extensions/sql_log_normalizer.rb +108 -0
  158. data/lib/sequel/extensions/sqlite_json_ops.rb +255 -0
  159. data/lib/sequel/extensions/string_agg.rb +1 -1
  160. data/lib/sequel/extensions/string_date_time.rb +19 -23
  161. data/lib/sequel/extensions/symbol_aref.rb +2 -0
  162. data/lib/sequel/model/associations.rb +345 -101
  163. data/lib/sequel/model/base.rb +51 -27
  164. data/lib/sequel/model/dataset_module.rb +3 -0
  165. data/lib/sequel/model/errors.rb +10 -1
  166. data/lib/sequel/model/inflections.rb +1 -1
  167. data/lib/sequel/model/plugins.rb +5 -0
  168. data/lib/sequel/plugins/association_proxies.rb +2 -0
  169. data/lib/sequel/plugins/async_thread_pool.rb +39 -0
  170. data/lib/sequel/plugins/auto_restrict_eager_graph.rb +62 -0
  171. data/lib/sequel/plugins/auto_validations.rb +87 -15
  172. data/lib/sequel/plugins/auto_validations_constraint_validations_presence_message.rb +68 -0
  173. data/lib/sequel/plugins/class_table_inheritance.rb +2 -2
  174. data/lib/sequel/plugins/column_encryption.rb +728 -0
  175. data/lib/sequel/plugins/composition.rb +10 -4
  176. data/lib/sequel/plugins/concurrent_eager_loading.rb +174 -0
  177. data/lib/sequel/plugins/constraint_validations.rb +10 -6
  178. data/lib/sequel/plugins/dataset_associations.rb +4 -1
  179. data/lib/sequel/plugins/defaults_setter.rb +16 -0
  180. data/lib/sequel/plugins/dirty.rb +1 -1
  181. data/lib/sequel/plugins/enum.rb +124 -0
  182. data/lib/sequel/plugins/finder.rb +4 -2
  183. data/lib/sequel/plugins/insert_conflict.rb +4 -0
  184. data/lib/sequel/plugins/instance_specific_default.rb +1 -1
  185. data/lib/sequel/plugins/json_serializer.rb +39 -24
  186. data/lib/sequel/plugins/lazy_attributes.rb +3 -0
  187. data/lib/sequel/plugins/list.rb +3 -1
  188. data/lib/sequel/plugins/many_through_many.rb +109 -10
  189. data/lib/sequel/plugins/mssql_optimistic_locking.rb +8 -38
  190. data/lib/sequel/plugins/nested_attributes.rb +12 -7
  191. data/lib/sequel/plugins/optimistic_locking.rb +9 -42
  192. data/lib/sequel/plugins/optimistic_locking_base.rb +55 -0
  193. data/lib/sequel/plugins/pg_array_associations.rb +56 -38
  194. data/lib/sequel/plugins/pg_auto_constraint_validations.rb +11 -3
  195. data/lib/sequel/plugins/pg_xmin_optimistic_locking.rb +109 -0
  196. data/lib/sequel/plugins/prepared_statements.rb +12 -2
  197. data/lib/sequel/plugins/prepared_statements_safe.rb +2 -1
  198. data/lib/sequel/plugins/primary_key_lookup_check_values.rb +154 -0
  199. data/lib/sequel/plugins/rcte_tree.rb +27 -19
  200. data/lib/sequel/plugins/require_valid_schema.rb +67 -0
  201. data/lib/sequel/plugins/serialization.rb +9 -3
  202. data/lib/sequel/plugins/serialization_modification_detection.rb +2 -1
  203. data/lib/sequel/plugins/single_table_inheritance.rb +8 -0
  204. data/lib/sequel/plugins/sql_comments.rb +189 -0
  205. data/lib/sequel/plugins/static_cache.rb +39 -1
  206. data/lib/sequel/plugins/static_cache_cache.rb +5 -1
  207. data/lib/sequel/plugins/subclasses.rb +28 -11
  208. data/lib/sequel/plugins/tactical_eager_loading.rb +23 -10
  209. data/lib/sequel/plugins/timestamps.rb +1 -1
  210. data/lib/sequel/plugins/unused_associations.rb +521 -0
  211. data/lib/sequel/plugins/update_or_create.rb +1 -1
  212. data/lib/sequel/plugins/validate_associated.rb +22 -12
  213. data/lib/sequel/plugins/validation_helpers.rb +46 -12
  214. data/lib/sequel/plugins/validation_helpers_generic_type_messages.rb +73 -0
  215. data/lib/sequel/plugins/xml_serializer.rb +1 -1
  216. data/lib/sequel/sql.rb +1 -1
  217. data/lib/sequel/timezones.rb +12 -14
  218. data/lib/sequel/version.rb +1 -1
  219. metadata +132 -38
@@ -0,0 +1,189 @@
1
+ # frozen-string-literal: true
2
+
3
+ module Sequel
4
+ module Plugins
5
+ # The sql_comments plugin will automatically use SQL comments on
6
+ # queries for the model it is loaded into. These comments will
7
+ # show the related model, what type of method was called, and
8
+ # the method name (or association name for queries to load
9
+ # associations):
10
+ #
11
+ # album = Album[1]
12
+ # # SELECT * FROM albums WHERE (id = 1) LIMIT 1
13
+ # # -- model:Album,method_type:class,method:[]
14
+ #
15
+ # album.update(name: 'A')
16
+ # # UPDATE albums SET name = 'baz' WHERE (id = 1)
17
+ # # -- model:Album,method_type:instance,method:update
18
+ #
19
+ # album.artist
20
+ # # SELECT * FROM artists WHERE (artists.id = 1)
21
+ # # -- model:Album,method_type:association_load,association:artist
22
+ #
23
+ # Album.eager(:artists).all
24
+ # # SELECT * FROM albums
25
+ # # SELECT * FROM artists WHERE (artists.id IN (1))
26
+ # # -- model:Album,method_type:association_eager_load,association:artist
27
+ #
28
+ # Album.where(id: 1).delete
29
+ # # DELETE FROM albums WHERE (id = 1)
30
+ # # -- model:Album,method_type:dataset,method:delete
31
+ #
32
+ # This plugin automatically supports the class, instance, and dataset
33
+ # methods are are supported by default in Sequel::Model. To support
34
+ # custom class, instance, and dataset methods, such as those added by
35
+ # other plugins, you can use the appropriate <tt>sql_comments_*_methods</tt>
36
+ # class method:
37
+ #
38
+ # Album.sql_comments_class_methods :first_by_name # example from finder plugin, with :mod option
39
+ # Album.sql_comments_instance_methods :lazy_attribute_lookup # lazy_attributes plugin
40
+ # Album.sql_comments_dataset_methods :to_csv # csv_serializer plugin
41
+ #
42
+ # In order for the sql_comments plugin to work, the sql_comments
43
+ # Database extension must be loaded into the model's database.
44
+ #
45
+ # Note that in order to make sure SQL comments are included, some
46
+ # optimizations are disabled if this plugin is loaded.
47
+ #
48
+ # Usage:
49
+ #
50
+ # # Make all model subclasses support automatic SQL comments
51
+ # # (called before loading subclasses)
52
+ # Sequel::Model.plugin :sql_comments
53
+ #
54
+ # # Make the Album class support automatic SQL comments
55
+ # Album.plugin :sql_comments
56
+ module SqlComments
57
+ # Define a method +meth+ on the given module +mod+ that will use automatic
58
+ # SQL comments with the given model, method_type, and method.
59
+ def self.def_sql_commend_method(mod, model, method_type, meth)
60
+ mod.send(:define_method, meth) do |*a, &block|
61
+ model.db.with_comments(:model=>model, :method_type=>method_type, :method=>meth) do
62
+ super(*a, &block)
63
+ end
64
+ end
65
+ # :nocov:
66
+ mod.send(:ruby2_keywords, meth) if mod.respond_to?(:ruby2_keywords, true)
67
+ # :nocov:
68
+ end
69
+
70
+ def self.configure(model)
71
+ model.send(:reset_fast_pk_lookup_sql)
72
+ end
73
+
74
+ module ClassMethods
75
+ # Use automatic SQL comments for the given class methods.
76
+ def sql_comments_class_methods(*meths)
77
+ _sql_comments_methods(singleton_class, :class, meths)
78
+ end
79
+
80
+ # Use automatic SQL comments for the given instance methods.
81
+ def sql_comments_instance_methods(*meths)
82
+ _sql_comments_methods(self, :instance, meths)
83
+ end
84
+
85
+ # Use automatic SQL comments for the given dataset methods.
86
+ def sql_comments_dataset_methods(*meths)
87
+ unless @_sql_comments_dataset_module
88
+ dataset_module(@_sql_comments_dataset_module = Module.new)
89
+ end
90
+ _sql_comments_methods(@_sql_comments_dataset_module, :dataset, meths)
91
+ end
92
+
93
+ [:[], :create, :find, :find_or_create, :with_pk, :with_pk!].each do |meth|
94
+ define_method(meth) do |*a, &block|
95
+ db.with_comments(:model=>self, :method_type=>:class, :method=>meth) do
96
+ super(*a, &block)
97
+ end
98
+ end
99
+ # :nocov:
100
+ ruby2_keywords(meth) if respond_to?(:ruby2_keywords, true)
101
+ # :nocov:
102
+ end
103
+
104
+ private
105
+
106
+ # Don't optimize the fast PK lookups, as it uses static SQL that
107
+ # won't support the SQL comments.
108
+ def reset_fast_pk_lookup_sql
109
+ @fast_pk_lookup_sql = @fast_instance_delete_sql = nil
110
+ end
111
+
112
+ # Define automatic SQL comment methods in +mod+ for each method in +meths+,
113
+ # with the given +method_type+.
114
+ def _sql_comments_methods(mod, method_type, meths)
115
+ meths.each do |meth|
116
+ SqlComments.def_sql_commend_method(mod, self, method_type, meth)
117
+ end
118
+ end
119
+ end
120
+
121
+ module InstanceMethods
122
+ [:delete, :destroy, :lock!, :refresh, :save, :save_changes, :update, :update_fields].each do |meth|
123
+ define_method(meth) do |*a, &block|
124
+ t = Sequel.current
125
+ return super(*a, &block) if (hash = Sequel.synchronize{db.comment_hashes[t]}) && hash[:model]
126
+
127
+ db.with_comments(:model=>model, :method_type=>:instance, :method=>meth) do
128
+ super(*a, &block)
129
+ end
130
+ end
131
+ # :nocov:
132
+ ruby2_keywords(meth) if respond_to?(:ruby2_keywords, true)
133
+ # :nocov:
134
+ end
135
+
136
+ private
137
+
138
+ # Do not use a placeholder loader for associations.
139
+ def _associated_object_loader(opts, dynamic_opts)
140
+ nil
141
+ end
142
+
143
+ # Use SQL comments on normal association load queries, showing they are association loads.
144
+ def _load_associated_objects(opts, dynamic_opts=OPTS)
145
+ db.with_comments(:model=>model, :method_type=>:association_load, :association=>opts[:name]) do
146
+ super
147
+ end
148
+ end
149
+ end
150
+
151
+ module DatasetMethods
152
+ Dataset::ACTION_METHODS.each do |meth|
153
+ define_method(meth) do |*a, &block|
154
+ t = Sequel.current
155
+ return super(*a, &block) if (hash = Sequel.synchronize{db.comment_hashes[t]}) && hash[:model]
156
+
157
+ db.with_comments(:model=>model, :method_type=>:dataset, :method=>meth) do
158
+ super(*a, &block)
159
+ end
160
+ end
161
+ # :nocov:
162
+ ruby2_keywords(meth) if respond_to?(:ruby2_keywords, true)
163
+ # :nocov:
164
+ end
165
+
166
+ private
167
+
168
+ # Add the association name as part of the eager load data, so
169
+ # perform_eager_load has access to it.
170
+ def prepare_eager_load(a, reflections, eager_assoc)
171
+ res = super
172
+
173
+ reflections.each do |r|
174
+ res[r[:eager_loader]][:association] = r[:name]
175
+ end
176
+
177
+ res
178
+ end
179
+
180
+ # Use SQL comments on eager load queries, showing they are eager loads.
181
+ def perform_eager_load(loader, eo)
182
+ db.with_comments(:model=>model, :method_type=>:association_eager_load, :method=>nil, :association=>eo[:association]) do
183
+ super
184
+ end
185
+ end
186
+ end
187
+ end
188
+ end
189
+ end
@@ -64,6 +64,9 @@ module Sequel
64
64
  def self.configure(model, opts=OPTS)
65
65
  model.instance_exec do
66
66
  @static_cache_frozen = opts.fetch(:frozen, true)
67
+ if @static_cache_frozen && defined?(::Sequel::Plugins::ForbidLazyLoad::ClassMethods) && is_a?(::Sequel::Plugins::ForbidLazyLoad::ClassMethods)
68
+ extend ForbidLazyLoadClassMethods
69
+ end
67
70
  load_cache
68
71
  end
69
72
  end
@@ -87,7 +90,7 @@ module Sequel
87
90
  # array containing the number of instances specified (single integer
88
91
  # argument).
89
92
  def first(*args)
90
- if block_given? || args.length > 1 || (args.length == 1 && !args[0].is_a?(Integer))
93
+ if defined?(yield) || args.length > 1 || (args.length == 1 && !args[0].is_a?(Integer))
91
94
  super
92
95
  else
93
96
  @all.first(*args)
@@ -246,6 +249,41 @@ module Sequel
246
249
  end
247
250
  end
248
251
 
252
+ module ForbidLazyLoadClassMethods
253
+ # Do not forbid lazy loading for single object retrieval.
254
+ def cache_get_pk(pk)
255
+ primary_key_lookup(pk)
256
+ end
257
+
258
+ # Use static cache to return first arguments.
259
+ def first(*args)
260
+ if !defined?(yield) && args.empty?
261
+ if o = @all.first
262
+ _static_cache_frozen_copy(o)
263
+ end
264
+ else
265
+ super
266
+ end
267
+ end
268
+
269
+ private
270
+
271
+ # Return a frozen copy of the object that does not have lazy loading
272
+ # forbidden.
273
+ def _static_cache_frozen_copy(o)
274
+ o = call(Hash[o.values])
275
+ o.errors.freeze
276
+ o.freeze
277
+ end
278
+
279
+ # Do not forbid lazy loading for single object retrieval.
280
+ def primary_key_lookup(pk)
281
+ if o = cache[pk]
282
+ _static_cache_frozen_copy(o)
283
+ end
284
+ end
285
+ end
286
+
249
287
  module InstanceMethods
250
288
  # Disallowing destroying the object unless the frozen: false option was used.
251
289
  def before_destroy
@@ -26,7 +26,11 @@ module Sequel
26
26
  module ClassMethods
27
27
  # Dump the in-memory cached rows to the cache file.
28
28
  def dump_static_cache_cache
29
- File.open(@static_cache_cache_file, 'wb'){|f| f.write(Marshal.dump(@static_cache_cache))}
29
+ static_cache_cache = {}
30
+ @static_cache_cache.sort.each do |k, v|
31
+ static_cache_cache[k] = v
32
+ end
33
+ File.open(@static_cache_cache_file, 'wb'){|f| f.write(Marshal.dump(static_cache_cache))}
30
34
  nil
31
35
  end
32
36
 
@@ -5,7 +5,7 @@ module Sequel
5
5
  # The subclasses plugin keeps track of all subclasses of the
6
6
  # current model class. Direct subclasses are available via the
7
7
  # subclasses method, and all descendent classes are available via the
8
- # descendents method:
8
+ # descendants method:
9
9
  #
10
10
  # c = Class.new(Sequel::Model)
11
11
  # c.plugin :subclasses
@@ -16,7 +16,7 @@ module Sequel
16
16
  # sc1.subclasses # [ssc1]
17
17
  # sc2.subclasses # []
18
18
  # ssc1.subclasses # []
19
- # c.descendents # [sc1, ssc1, sc2]
19
+ # c.descendants # [sc1, ssc1, sc2]
20
20
  #
21
21
  # You can also finalize the associations and then freeze the classes
22
22
  # in all descendent classes. Doing so is a recommended practice after
@@ -35,9 +35,14 @@ module Sequel
35
35
  # class B < Sequel::Model; end
36
36
  # a # => [A, B]
37
37
  module Subclasses
38
+ NEED_SUBCLASSES = !Object.respond_to?(:subclasses) || Object.method(:subclasses).source_location
39
+ private_constant :NEED_SUBCLASSES
40
+
38
41
  # Initialize the subclasses instance variable for the model.
39
42
  def self.apply(model, &block)
40
- model.instance_variable_set(:@subclasses, [])
43
+ # :nocov:
44
+ model.instance_variable_set(:@subclasses, []) if NEED_SUBCLASSES
45
+ # :nocov:
41
46
  model.instance_variable_set(:@on_subclass, block)
42
47
  end
43
48
 
@@ -46,21 +51,31 @@ module Sequel
46
51
  # class created.
47
52
  attr_reader :on_subclass
48
53
 
49
- # All subclasses for the current model. Does not
50
- # include the model itself.
51
- attr_reader :subclasses
54
+ # :nocov:
55
+ if NEED_SUBCLASSES
56
+ # All subclasses for the current model. Does not
57
+ # include the model itself.
58
+ attr_reader :subclasses
59
+ end
60
+ # :nocov:
52
61
 
53
62
  # All descendent classes of this model.
54
- def descendents
55
- Sequel.synchronize{subclasses.dup}.map{|x| [x] + x.send(:descendents)}.flatten
63
+ def descendants
64
+ Sequel.synchronize{subclasses.dup}.map{|x| [x] + x.send(:descendants)}.flatten
56
65
  end
57
66
 
67
+ # SEQUEL6: Remove
68
+ alias descendents descendants
69
+
58
70
  # Freeze all descendent classes. This also finalizes the associations for those
59
71
  # classes before freezing.
60
- def freeze_descendents
61
- descendents.each(&:finalize_associations).each(&:freeze)
72
+ def freeze_descendants
73
+ descendants.each(&:finalize_associations).each(&:freeze)
62
74
  end
63
75
 
76
+ # SEQUEL6: Remove
77
+ alias freeze_descendents freeze_descendants
78
+
64
79
  Plugins.inherited_instance_variables(self, :@subclasses=>lambda{|v| []}, :@on_subclass=>nil)
65
80
 
66
81
  private
@@ -70,7 +85,9 @@ module Sequel
70
85
  # in the subclass.
71
86
  def inherited(subclass)
72
87
  super
73
- Sequel.synchronize{subclasses << subclass}
88
+ # :nocov:
89
+ Sequel.synchronize{subclasses << subclass} if NEED_SUBCLASSES
90
+ # :nocov:
74
91
  on_subclass.call(subclass) if on_subclass
75
92
  end
76
93
  end
@@ -109,6 +109,13 @@ module Sequel
109
109
  # to eagerly set the associated objects, and having separate threads
110
110
  # modify the same model instance is not thread-safe.
111
111
  #
112
+ # Because this plugin will automatically use eager loading for
113
+ # performance, it can break code that defines associations that
114
+ # do not support eager loading, without marking that they do not
115
+ # support eager loading via the <tt>allow_eager: false</tt> option.
116
+ # Make sure to set <tt>allow_eager: false</tt> on any association
117
+ # used with this plugin if the association doesn't support eager loading.
118
+ #
112
119
  # Usage:
113
120
  #
114
121
  # # Make all model subclass instances use tactical eager loading (called before loading subclasses)
@@ -143,19 +150,25 @@ module Sequel
143
150
  def load_associated_objects(opts, dynamic_opts=OPTS, &block)
144
151
  dynamic_opts = load_association_objects_options(dynamic_opts, &block)
145
152
  name = opts[:name]
146
- if (!associations.include?(name) || dynamic_opts[:eager_reload]) && opts[:allow_eager] != false && retrieved_by && !frozen? && !dynamic_opts[:callback] && !dynamic_opts[:reload]
147
- begin
148
- retrieved_by.send(:eager_load, retrieved_with.reject(&:frozen?), name=>dynamic_opts[:eager] || OPTS)
149
- rescue Sequel::UndefinedAssociation
150
- # This can happen if class table inheritance is used and the association
151
- # is only defined in a subclass. This particular instance can use the
152
- # association, but it can't be eagerly loaded as the parent class doesn't
153
- # have access to the association, and that's the class doing the eager loading.
154
- nil
155
- end
153
+ eager_reload = dynamic_opts[:eager_reload]
154
+ if (!associations.include?(name) || eager_reload) && opts[:allow_eager] != false && retrieved_by && !frozen? && !dynamic_opts[:callback] && !dynamic_opts[:reload]
155
+ retrieved_by.send(:eager_load, _filter_tactical_eager_load_objects(:eager_reload=>eager_reload, :name=>name), {name=>dynamic_opts[:eager] || OPTS}, model)
156
156
  end
157
157
  super
158
158
  end
159
+
160
+ # Filter the objects used when tactical eager loading.
161
+ # By default, this removes frozen objects and objects that alreayd have the association loaded
162
+ def _filter_tactical_eager_load_objects(opts)
163
+ objects = defined?(super) ? super : retrieved_with.dup
164
+ if opts[:eager_reload]
165
+ objects.reject!(&:frozen?)
166
+ else
167
+ name = opts[:name]
168
+ objects.reject!{|x| x.frozen? || x.associations.include?(name)}
169
+ end
170
+ objects
171
+ end
159
172
  end
160
173
 
161
174
  module DatasetMethods
@@ -19,7 +19,7 @@ module Sequel
19
19
  #
20
20
  # # Timestamp Artist instances, forcing an overwrite of the create
21
21
  # # timestamp, and setting the update timestamp when creating
22
- # Album.plugin :timestamps, force: true, update_on_create: true
22
+ # Artist.plugin :timestamps, force: true, update_on_create: true
23
23
  module Timestamps
24
24
  # Configure the plugin by setting the available options. Note that
25
25
  # if this method is run more than once, previous settings are ignored,