sequel 5.83.0 → 5.106.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 (259) hide show
  1. checksums.yaml +4 -4
  2. data/MIT-LICENSE +1 -1
  3. data/lib/sequel/adapters/ado/access.rb +2 -2
  4. data/lib/sequel/adapters/ado.rb +2 -2
  5. data/lib/sequel/adapters/amalgalite.rb +16 -1
  6. data/lib/sequel/adapters/ibmdb.rb +2 -1
  7. data/lib/sequel/adapters/jdbc/db2.rb +2 -2
  8. data/lib/sequel/adapters/jdbc/derby.rb +4 -2
  9. data/lib/sequel/adapters/jdbc/h2.rb +4 -4
  10. data/lib/sequel/adapters/jdbc/hsqldb.rb +2 -2
  11. data/lib/sequel/adapters/jdbc/jtds.rb +2 -2
  12. data/lib/sequel/adapters/jdbc/mysql.rb +3 -3
  13. data/lib/sequel/adapters/jdbc/oracle.rb +6 -6
  14. data/lib/sequel/adapters/jdbc/postgresql.rb +5 -5
  15. data/lib/sequel/adapters/jdbc/sqlanywhere.rb +6 -6
  16. data/lib/sequel/adapters/jdbc/sqlite.rb +3 -3
  17. data/lib/sequel/adapters/jdbc/sqlserver.rb +3 -3
  18. data/lib/sequel/adapters/jdbc.rb +29 -15
  19. data/lib/sequel/adapters/mysql.rb +1 -1
  20. data/lib/sequel/adapters/mysql2.rb +10 -3
  21. data/lib/sequel/adapters/odbc.rb +1 -1
  22. data/lib/sequel/adapters/oracle.rb +16 -0
  23. data/lib/sequel/adapters/postgres.rb +2 -1
  24. data/lib/sequel/adapters/shared/access.rb +1 -0
  25. data/lib/sequel/adapters/shared/db2.rb +8 -3
  26. data/lib/sequel/adapters/shared/mssql.rb +9 -8
  27. data/lib/sequel/adapters/shared/mysql.rb +16 -11
  28. data/lib/sequel/adapters/shared/oracle.rb +1 -0
  29. data/lib/sequel/adapters/shared/postgres.rb +438 -47
  30. data/lib/sequel/adapters/shared/sqlite.rb +9 -7
  31. data/lib/sequel/adapters/sqlite.rb +20 -2
  32. data/lib/sequel/adapters/tinytds.rb +2 -2
  33. data/lib/sequel/adapters/trilogy.rb +2 -3
  34. data/lib/sequel/ast_transformer.rb +2 -0
  35. data/lib/sequel/connection_pool/sharded_timed_queue.rb +42 -11
  36. data/lib/sequel/connection_pool/timed_queue.rb +33 -10
  37. data/lib/sequel/connection_pool.rb +8 -2
  38. data/lib/sequel/core.rb +31 -2
  39. data/lib/sequel/database/connecting.rb +1 -1
  40. data/lib/sequel/database/dataset_defaults.rb +3 -3
  41. data/lib/sequel/database/misc.rb +29 -11
  42. data/lib/sequel/database/query.rb +12 -12
  43. data/lib/sequel/database/schema_generator.rb +117 -16
  44. data/lib/sequel/database/schema_methods.rb +85 -30
  45. data/lib/sequel/dataset/actions.rb +83 -11
  46. data/lib/sequel/dataset/deprecated_singleton_class_methods.rb +1 -1
  47. data/lib/sequel/dataset/placeholder_literalizer.rb +3 -0
  48. data/lib/sequel/dataset/prepared_statements.rb +76 -28
  49. data/lib/sequel/dataset/query.rb +26 -11
  50. data/lib/sequel/dataset/sql.rb +40 -17
  51. data/lib/sequel/extensions/async_thread_pool.rb +1 -1
  52. data/lib/sequel/extensions/caller_logging.rb +1 -3
  53. data/lib/sequel/extensions/connection_checkout_event_callback.rb +151 -0
  54. data/lib/sequel/extensions/connection_expiration.rb +44 -5
  55. data/lib/sequel/extensions/connection_validator.rb +15 -10
  56. data/lib/sequel/extensions/constraint_validations.rb +3 -3
  57. data/lib/sequel/extensions/dataset_run.rb +41 -0
  58. data/lib/sequel/extensions/date_arithmetic.rb +6 -6
  59. data/lib/sequel/extensions/empty_array_consider_nulls.rb +7 -0
  60. data/lib/sequel/extensions/eval_inspect.rb +3 -1
  61. data/lib/sequel/extensions/inflector.rb +2 -2
  62. data/lib/sequel/extensions/lit_require_frozen.rb +131 -0
  63. data/lib/sequel/extensions/looser_typecasting.rb +5 -12
  64. data/lib/sequel/extensions/migration.rb +38 -21
  65. data/lib/sequel/extensions/null_dataset.rb +2 -2
  66. data/lib/sequel/extensions/pg_array_ops.rb +41 -0
  67. data/lib/sequel/extensions/pg_auto_parameterize.rb +10 -3
  68. data/lib/sequel/extensions/pg_auto_parameterize_duplicate_query_detection.rb +191 -0
  69. data/lib/sequel/extensions/pg_auto_parameterize_in_array.rb +94 -10
  70. data/lib/sequel/extensions/pg_enum.rb +4 -4
  71. data/lib/sequel/extensions/pg_hstore.rb +1 -1
  72. data/lib/sequel/extensions/pg_hstore_ops.rb +10 -5
  73. data/lib/sequel/extensions/pg_json_ops.rb +674 -18
  74. data/lib/sequel/extensions/pg_multirange.rb +1 -1
  75. data/lib/sequel/extensions/pg_range.rb +14 -2
  76. data/lib/sequel/extensions/pg_row.rb +5 -3
  77. data/lib/sequel/extensions/pg_schema_caching.rb +90 -0
  78. data/lib/sequel/extensions/provenance.rb +1 -3
  79. data/lib/sequel/extensions/query_blocker.rb +172 -0
  80. data/lib/sequel/extensions/schema_caching.rb +24 -9
  81. data/lib/sequel/extensions/schema_dumper.rb +17 -5
  82. data/lib/sequel/extensions/set_literalizer.rb +20 -39
  83. data/lib/sequel/extensions/split_array_nil.rb +12 -2
  84. data/lib/sequel/extensions/sqlite_json_ops.rb +1 -1
  85. data/lib/sequel/extensions/string_agg.rb +2 -2
  86. data/lib/sequel/extensions/to_dot.rb +5 -0
  87. data/lib/sequel/extensions/virtual_row_method_block.rb +1 -0
  88. data/lib/sequel/model/associations.rb +215 -15
  89. data/lib/sequel/model/base.rb +198 -35
  90. data/lib/sequel/model/plugins.rb +12 -1
  91. data/lib/sequel/model.rb +1 -0
  92. data/lib/sequel/plugins/accessed_columns.rb +4 -0
  93. data/lib/sequel/plugins/active_model.rb +5 -6
  94. data/lib/sequel/plugins/association_pks.rb +2 -0
  95. data/lib/sequel/plugins/auto_validations.rb +2 -0
  96. data/lib/sequel/plugins/class_table_inheritance_constraint_validations.rb +82 -0
  97. data/lib/sequel/plugins/columns_updated.rb +4 -0
  98. data/lib/sequel/plugins/composition.rb +3 -1
  99. data/lib/sequel/plugins/constraint_validations.rb +15 -10
  100. data/lib/sequel/plugins/dataset_associations.rb +20 -1
  101. data/lib/sequel/plugins/deprecated_associations.rb +151 -0
  102. data/lib/sequel/plugins/detect_unnecessary_association_options.rb +164 -0
  103. data/lib/sequel/plugins/dirty.rb +9 -2
  104. data/lib/sequel/plugins/enum.rb +1 -1
  105. data/lib/sequel/plugins/forbid_lazy_load.rb +15 -1
  106. data/lib/sequel/plugins/insert_conflict.rb +4 -0
  107. data/lib/sequel/plugins/insert_returning_select.rb +10 -1
  108. data/lib/sequel/plugins/inspect_pk.rb +44 -0
  109. data/lib/sequel/plugins/instance_filters.rb +8 -1
  110. data/lib/sequel/plugins/instance_hooks.rb +4 -0
  111. data/lib/sequel/plugins/inverted_subsets.rb +1 -0
  112. data/lib/sequel/plugins/json_serializer.rb +6 -10
  113. data/lib/sequel/plugins/lazy_attributes.rb +1 -1
  114. data/lib/sequel/plugins/many_through_many.rb +21 -0
  115. data/lib/sequel/plugins/modification_detection.rb +2 -0
  116. data/lib/sequel/plugins/mssql_optimistic_locking.rb +1 -1
  117. data/lib/sequel/plugins/nested_attributes.rb +10 -5
  118. data/lib/sequel/plugins/paged_operations.rb +5 -2
  119. data/lib/sequel/plugins/pg_array_associations.rb +2 -2
  120. data/lib/sequel/plugins/pg_auto_constraint_validations.rb +6 -1
  121. data/lib/sequel/plugins/pg_auto_validate_enums.rb +88 -0
  122. data/lib/sequel/plugins/pg_eager_any_typed_array.rb +95 -0
  123. data/lib/sequel/plugins/pg_xmin_optimistic_locking.rb +1 -1
  124. data/lib/sequel/plugins/rcte_tree.rb +6 -6
  125. data/lib/sequel/plugins/serialization.rb +23 -6
  126. data/lib/sequel/plugins/serialization_modification_detection.rb +4 -0
  127. data/lib/sequel/plugins/single_statement_dataset_destroy.rb +49 -0
  128. data/lib/sequel/plugins/split_values.rb +12 -0
  129. data/lib/sequel/plugins/sql_comments.rb +7 -2
  130. data/lib/sequel/plugins/static_cache.rb +13 -0
  131. data/lib/sequel/plugins/static_cache_cache.rb +50 -13
  132. data/lib/sequel/plugins/subset_conditions.rb +85 -5
  133. data/lib/sequel/plugins/subset_static_cache.rb +278 -0
  134. data/lib/sequel/plugins/table_select.rb +7 -0
  135. data/lib/sequel/plugins/tactical_eager_loading.rb +4 -0
  136. data/lib/sequel/plugins/unused_associations.rb +11 -3
  137. data/lib/sequel/plugins/update_primary_key.rb +4 -0
  138. data/lib/sequel/plugins/validation_class_methods.rb +1 -1
  139. data/lib/sequel/plugins/validation_contexts.rb +4 -0
  140. data/lib/sequel/sql.rb +27 -12
  141. data/lib/sequel/version.rb +1 -1
  142. metadata +17 -240
  143. data/CHANGELOG +0 -1393
  144. data/README.rdoc +0 -936
  145. data/doc/advanced_associations.rdoc +0 -884
  146. data/doc/association_basics.rdoc +0 -1859
  147. data/doc/bin_sequel.rdoc +0 -146
  148. data/doc/cheat_sheet.rdoc +0 -255
  149. data/doc/code_order.rdoc +0 -104
  150. data/doc/core_extensions.rdoc +0 -405
  151. data/doc/dataset_basics.rdoc +0 -96
  152. data/doc/dataset_filtering.rdoc +0 -222
  153. data/doc/extensions.rdoc +0 -77
  154. data/doc/fork_safety.rdoc +0 -84
  155. data/doc/mass_assignment.rdoc +0 -98
  156. data/doc/migration.rdoc +0 -660
  157. data/doc/model_dataset_method_design.rdoc +0 -129
  158. data/doc/model_hooks.rdoc +0 -254
  159. data/doc/model_plugins.rdoc +0 -270
  160. data/doc/mssql_stored_procedures.rdoc +0 -43
  161. data/doc/object_model.rdoc +0 -563
  162. data/doc/opening_databases.rdoc +0 -439
  163. data/doc/postgresql.rdoc +0 -611
  164. data/doc/prepared_statements.rdoc +0 -144
  165. data/doc/querying.rdoc +0 -1070
  166. data/doc/reflection.rdoc +0 -120
  167. data/doc/release_notes/5.0.0.txt +0 -159
  168. data/doc/release_notes/5.1.0.txt +0 -31
  169. data/doc/release_notes/5.10.0.txt +0 -84
  170. data/doc/release_notes/5.11.0.txt +0 -83
  171. data/doc/release_notes/5.12.0.txt +0 -141
  172. data/doc/release_notes/5.13.0.txt +0 -27
  173. data/doc/release_notes/5.14.0.txt +0 -63
  174. data/doc/release_notes/5.15.0.txt +0 -39
  175. data/doc/release_notes/5.16.0.txt +0 -110
  176. data/doc/release_notes/5.17.0.txt +0 -31
  177. data/doc/release_notes/5.18.0.txt +0 -69
  178. data/doc/release_notes/5.19.0.txt +0 -28
  179. data/doc/release_notes/5.2.0.txt +0 -33
  180. data/doc/release_notes/5.20.0.txt +0 -89
  181. data/doc/release_notes/5.21.0.txt +0 -87
  182. data/doc/release_notes/5.22.0.txt +0 -48
  183. data/doc/release_notes/5.23.0.txt +0 -56
  184. data/doc/release_notes/5.24.0.txt +0 -56
  185. data/doc/release_notes/5.25.0.txt +0 -32
  186. data/doc/release_notes/5.26.0.txt +0 -35
  187. data/doc/release_notes/5.27.0.txt +0 -21
  188. data/doc/release_notes/5.28.0.txt +0 -16
  189. data/doc/release_notes/5.29.0.txt +0 -22
  190. data/doc/release_notes/5.3.0.txt +0 -121
  191. data/doc/release_notes/5.30.0.txt +0 -20
  192. data/doc/release_notes/5.31.0.txt +0 -148
  193. data/doc/release_notes/5.32.0.txt +0 -46
  194. data/doc/release_notes/5.33.0.txt +0 -24
  195. data/doc/release_notes/5.34.0.txt +0 -40
  196. data/doc/release_notes/5.35.0.txt +0 -56
  197. data/doc/release_notes/5.36.0.txt +0 -60
  198. data/doc/release_notes/5.37.0.txt +0 -30
  199. data/doc/release_notes/5.38.0.txt +0 -28
  200. data/doc/release_notes/5.39.0.txt +0 -19
  201. data/doc/release_notes/5.4.0.txt +0 -80
  202. data/doc/release_notes/5.40.0.txt +0 -40
  203. data/doc/release_notes/5.41.0.txt +0 -25
  204. data/doc/release_notes/5.42.0.txt +0 -136
  205. data/doc/release_notes/5.43.0.txt +0 -98
  206. data/doc/release_notes/5.44.0.txt +0 -32
  207. data/doc/release_notes/5.45.0.txt +0 -34
  208. data/doc/release_notes/5.46.0.txt +0 -87
  209. data/doc/release_notes/5.47.0.txt +0 -59
  210. data/doc/release_notes/5.48.0.txt +0 -14
  211. data/doc/release_notes/5.49.0.txt +0 -59
  212. data/doc/release_notes/5.5.0.txt +0 -61
  213. data/doc/release_notes/5.50.0.txt +0 -78
  214. data/doc/release_notes/5.51.0.txt +0 -47
  215. data/doc/release_notes/5.52.0.txt +0 -87
  216. data/doc/release_notes/5.53.0.txt +0 -23
  217. data/doc/release_notes/5.54.0.txt +0 -27
  218. data/doc/release_notes/5.55.0.txt +0 -21
  219. data/doc/release_notes/5.56.0.txt +0 -51
  220. data/doc/release_notes/5.57.0.txt +0 -23
  221. data/doc/release_notes/5.58.0.txt +0 -31
  222. data/doc/release_notes/5.59.0.txt +0 -73
  223. data/doc/release_notes/5.6.0.txt +0 -31
  224. data/doc/release_notes/5.60.0.txt +0 -22
  225. data/doc/release_notes/5.61.0.txt +0 -43
  226. data/doc/release_notes/5.62.0.txt +0 -132
  227. data/doc/release_notes/5.63.0.txt +0 -33
  228. data/doc/release_notes/5.64.0.txt +0 -50
  229. data/doc/release_notes/5.65.0.txt +0 -21
  230. data/doc/release_notes/5.66.0.txt +0 -24
  231. data/doc/release_notes/5.67.0.txt +0 -32
  232. data/doc/release_notes/5.68.0.txt +0 -61
  233. data/doc/release_notes/5.69.0.txt +0 -26
  234. data/doc/release_notes/5.7.0.txt +0 -108
  235. data/doc/release_notes/5.70.0.txt +0 -35
  236. data/doc/release_notes/5.71.0.txt +0 -21
  237. data/doc/release_notes/5.72.0.txt +0 -33
  238. data/doc/release_notes/5.73.0.txt +0 -66
  239. data/doc/release_notes/5.74.0.txt +0 -45
  240. data/doc/release_notes/5.75.0.txt +0 -35
  241. data/doc/release_notes/5.76.0.txt +0 -86
  242. data/doc/release_notes/5.77.0.txt +0 -63
  243. data/doc/release_notes/5.78.0.txt +0 -67
  244. data/doc/release_notes/5.79.0.txt +0 -28
  245. data/doc/release_notes/5.8.0.txt +0 -170
  246. data/doc/release_notes/5.80.0.txt +0 -40
  247. data/doc/release_notes/5.81.0.txt +0 -31
  248. data/doc/release_notes/5.82.0.txt +0 -61
  249. data/doc/release_notes/5.83.0.txt +0 -56
  250. data/doc/release_notes/5.9.0.txt +0 -99
  251. data/doc/schema_modification.rdoc +0 -679
  252. data/doc/security.rdoc +0 -443
  253. data/doc/sharding.rdoc +0 -286
  254. data/doc/sql.rdoc +0 -648
  255. data/doc/testing.rdoc +0 -204
  256. data/doc/thread_safety.rdoc +0 -15
  257. data/doc/transactions.rdoc +0 -250
  258. data/doc/validations.rdoc +0 -558
  259. data/doc/virtual_rows.rdoc +0 -265
@@ -113,7 +113,7 @@ module Sequel
113
113
  def parse_constraint_validations
114
114
  db.extension(:_model_constraint_validations)
115
115
 
116
- unless hash = Sequel.synchronize{db.constraint_validations}
116
+ unless Sequel.synchronize{db.constraint_validations}
117
117
  hash = {}
118
118
  db.from(constraint_validations_table).each do |r|
119
119
  (hash[r[:table]] ||= []) << r
@@ -121,14 +121,7 @@ module Sequel
121
121
  Sequel.synchronize{db.constraint_validations = hash}
122
122
  end
123
123
 
124
- if @dataset
125
- ds = @dataset.with_quote_identifiers(false)
126
- table_name = ds.literal(ds.first_source_table)
127
- reflections = {}
128
- allow_missing_columns = db_schema.select{|col, sch| sch[:allow_null] == false && nil != sch[:default]}.map(&:first)
129
- @constraint_validations = (Sequel.synchronize{hash[table_name]} || []).map{|r| constraint_validation_array(r, reflections, allow_missing_columns)}
130
- @constraint_validation_reflections = reflections
131
- end
124
+ parse_constraint_validations_dataset if @dataset
132
125
  end
133
126
 
134
127
  # Given a specific database constraint validation metadata row hash, transform
@@ -164,7 +157,7 @@ module Sequel
164
157
  arg = constraint_validation_int_range(arg)
165
158
  type = :includes
166
159
  when *OPERATOR_MAP.keys
167
- arg = arg.to_i if type.to_s =~ /\Aint_/
160
+ arg = arg.to_i if type.to_s.start_with?('int_')
168
161
  operator = OPERATOR_MAP[type]
169
162
  type = :operator
170
163
  end
@@ -236,6 +229,18 @@ module Sequel
236
229
  Regexp.new(arg)
237
230
  end
238
231
  end
232
+
233
+ # If this model has associated dataset, use the model's table name
234
+ # to get the validations for just this model.
235
+ def parse_constraint_validations_dataset
236
+ ds = @dataset.with_quote_identifiers(false)
237
+ table_name = ds.literal(ds.first_source_table)
238
+ reflections = {}
239
+ allow_missing_columns = db_schema.select{|col, sch| sch[:allow_null] == false && nil != sch[:default]}.map(&:first)
240
+ hash = Sequel.synchronize{db.constraint_validations}
241
+ @constraint_validations = (Sequel.synchronize{hash[table_name]} || []).map{|r| constraint_validation_array(r, reflections, allow_missing_columns)}
242
+ @constraint_validation_reflections = reflections
243
+ end
239
244
  end
240
245
 
241
246
  module InstanceMethods
@@ -82,8 +82,27 @@ module Sequel
82
82
  # database supports window functions.
83
83
  def associated(name)
84
84
  raise Error, "unrecognized association name: #{name.inspect}" unless r = model.association_reflection(name)
85
- ds = r.associated_class.dataset
85
+ klass = r.associated_class
86
86
  sds = opts[:limit] ? self : unordered
87
+
88
+ if r.send(:filter_by_associations_limit_strategy) == :lateral_subquery
89
+ ds = r.send(:associated_eager_dataset)
90
+
91
+ case r[:type]
92
+ when :one_to_one, :one_to_many
93
+ sds = sds.select(*Array(r.qualified_primary_key))
94
+ else
95
+ sds = sds.select(*r[:left_primary_keys])
96
+ ds = ds.select_all(klass.table_name)
97
+ update_select = true
98
+ end
99
+
100
+ ds = r.send(:apply_lateral_subquery_eager_limit_strategy, ds, sds, r.limit_and_offset)
101
+ ds = ds.clone(:select=>ds.opts[:select][0,1]) if update_select
102
+ return ds.clone(:eager=>nil, :eager_graph=>nil)
103
+ end
104
+
105
+ ds = klass.dataset
87
106
  ds = case r[:type]
88
107
  when :many_to_one
89
108
  ds.where(r.qualified_primary_key=>sds.select(*Array(r[:qualified_key])))
@@ -0,0 +1,151 @@
1
+ # frozen-string-literal: true
2
+
3
+ module Sequel
4
+ module Plugins
5
+ # The deprecated_associations plugin adds support for
6
+ # deprecating associations. Attempts to use association
7
+ # methods and access association metadata for deprecated
8
+ # associations results in a warning.
9
+ #
10
+ # Album.plugin :deprecated_associations
11
+ # Album.many_to_one :artist, deprecated: true
12
+ # album = Album[1]
13
+ #
14
+ # # Warnings for all of the following calls
15
+ # album.artist
16
+ # album.artist_dataset
17
+ # album.artist = Artist[2]
18
+ # Album.association_reflection(:artist)
19
+ # Album.eager(:artist)
20
+ # Album.eager_graph(:artist)
21
+ # Album.where(artist: Artist[1]).all
22
+ #
23
+ # By default, the plugin issues a single warning per
24
+ # association method or association reflection. See
25
+ # DeprecatedAssociations.configure for options to make
26
+ # deprecated association issue warnings for every access,
27
+ # to include backtraces in warnings, or to raise an
28
+ # exception instead of warning.
29
+ #
30
+ # Note that Model.association_reflections and
31
+ # Model.all_association_reflections will include deprecated
32
+ # associations, and accessing the metadata for deprecated
33
+ # associations through these interfaces not issue warnings.
34
+ #
35
+ # Usage:
36
+ #
37
+ # # Make all models support deprecated associations
38
+ # # (called before loading subclasses)
39
+ # Sequel::Model.plugin :deprecated_associations
40
+ #
41
+ # # Make Album class support deprecated associations
42
+ # Album.plugin :deprecated_associations
43
+ module DeprecatedAssociations
44
+ # Exception class used for deprecated association use when
45
+ # raising exceptions instead of emitting warnings.
46
+ class Access < Sequel::Error; end
47
+
48
+ # Configure the deprecated associations plugin. Options:
49
+ #
50
+ # backtrace: Print backtrace with warning
51
+ # deduplicate: Set to false to emit warnings for every
52
+ # deprecated association method call/access
53
+ # (when not caching associations, this is always false)
54
+ # raise: Raise Sequel::Plugin::DeprecatedAssociations::Access
55
+ # instead of warning
56
+ def self.configure(model, opts = OPTS)
57
+ model.instance_exec do
58
+ (@deprecated_associations_config ||= {}).merge!(opts)
59
+ end
60
+ end
61
+
62
+ module ClassMethods
63
+ # Issue a deprecation warning if the association is deprecated.
64
+ def association_reflection(assoc)
65
+ ref = super
66
+ if ref && ref[:deprecated]
67
+ emit_deprecated_association_warning(ref, nil) do
68
+ "Access of association reflection for deprecated association: class:#{name} association:#{assoc}"
69
+ end
70
+ end
71
+ ref
72
+ end
73
+
74
+ private
75
+
76
+ # Issue a deprecation warning when the defined method is called if the
77
+ # association is deprecated and the method name does not start with the
78
+ # underscore (to avoid not warning twice, once for the public association
79
+ # method and once for the private association method).
80
+ def association_module_def(name, opts=OPTS, &block)
81
+ super
82
+ if opts[:deprecated] && name[0] != "_"
83
+ deprecated_associations_module.module_exec do
84
+ define_method(name) do |*a, &b|
85
+ self.class.send(:emit_deprecated_association_warning, opts, name) do
86
+ "Calling deprecated association method: class:#{self.class.name} association:#{opts[:name]} method:#{name}"
87
+ end
88
+ super(*a, &b)
89
+ end
90
+ alias_method name, name
91
+ end
92
+ end
93
+ nil
94
+ end
95
+
96
+ # Issue a deprecation warning when the defined method is called if the
97
+ # association is deprecated.
98
+ def association_module_delegate_def(name, opts, &block)
99
+ super
100
+ if opts[:deprecated]
101
+ deprecated_associations_module.module_exec do
102
+ define_method(name) do |*a, &b|
103
+ self.class.send(:emit_deprecated_association_warning, opts, name) do
104
+ "Calling deprecated association method: class:#{self.class.name} association:#{opts[:name]} method:#{name}"
105
+ end
106
+ super(*a, &b)
107
+ end
108
+ # :nocov:
109
+ ruby2_keywords(name) if respond_to?(:ruby2_keywords, true)
110
+ # :nocov:
111
+ alias_method(name, name)
112
+ end
113
+ end
114
+ nil
115
+ end
116
+
117
+ # A module to add deprecated association methods to. These methods
118
+ # handle issuing the deprecation warnings, and call super to get the
119
+ # default behavior.
120
+ def deprecated_associations_module
121
+ return @deprecated_associations_module if defined?(@deprecated_associations_module)
122
+ @deprecated_associations_module = Module.new
123
+ include(@deprecated_associations_module)
124
+ @deprecated_associations_module
125
+ end
126
+
127
+ # Emit a deprecation warning, or raise an exception if the :raise
128
+ # plugin option was used.
129
+ def emit_deprecated_association_warning(ref, method)
130
+ config = @deprecated_associations_config
131
+
132
+ raise Access, yield if config[:raise]
133
+
134
+ unless config[:deduplicate] == false
135
+ emit = false
136
+ ref.send(:cached_fetch, [:deprecated_associations, method]) do
137
+ emit = true
138
+ end
139
+ return unless emit
140
+ end
141
+
142
+ if config[:backtrace]
143
+ warn yield, caller(2)
144
+ else
145
+ warn yield, :uplevel => 2
146
+ end
147
+ end
148
+ end
149
+ end
150
+ end
151
+ end
@@ -0,0 +1,164 @@
1
+ # frozen-string-literal: true
2
+
3
+ module Sequel
4
+ module Plugins
5
+ # The detect_unnecessary_association_options plugin can detect unnecessary
6
+ # association options, and either warn or raise if they are detected.
7
+ # This allows you to find and remove the unnecessary options.
8
+ # Association options are considered unnecessary if they specify the same
9
+ # value as Sequel's defaults.
10
+ #
11
+ # To detect unnecessary association options, you should load the plugin
12
+ # into your model base class (e.g. Sequel::Model) before loading your model
13
+ # classes. Then, after all models have been loaded, you can call the
14
+ # detect_unnecessary_association_options on each to check for unnecessary
15
+ # association options. Additionally, if you are calling finalize_associations,
16
+ # it will automatically check for unnecessary association options.
17
+ #
18
+ # A typical usage would be to combine this with the subclasses plugin:
19
+ #
20
+ # Sequel::Model.plugin :detect_unnecessary_association_options
21
+ # Sequel::Model.plugin :subclasses
22
+ # # load model classes
23
+ #
24
+ # # implicitly check all subclasses when freezing descendants
25
+ # Sequel::Model.freeze_descendants
26
+ #
27
+ # # or, if not freezing all descendants
28
+ # Sequel::Model.descendants.each(&:detect_unnecessary_association_options)
29
+ #
30
+ # By default, the plugin warns for every unnecessary association option.
31
+ # To raise an error instead, you can pass the <tt>action: :raise</tt> option when loading the
32
+ # plugin:
33
+ #
34
+ # Sequel::Model.plugin :detect_unnecessary_association_options, action: :raise
35
+ #
36
+ # This plugin only detects the most common unnecessary association options, such as:
37
+ #
38
+ # * :class (all associations)
39
+ # * :key and :primary_key (associations without join tables)
40
+ # * :join_table, :left_key, :right_key, :left_primary_key, :right_primary_key (single join table associations)
41
+ # * :left_primary_key, :right_primary_key (*_through_many associations)
42
+ #
43
+ # Only association types supported by default or supported by a plugin that
44
+ # ships with Sequel are supported by this plugin. Other association types are
45
+ # ignored.
46
+ module DetectUnnecessaryAssociationOptions
47
+ def self.configure(model, opts={})
48
+ model.instance_variable_set(:@detect_unnecessary_association_options_action, opts[:action] || :warn)
49
+ end
50
+
51
+ # Raised if the plugin action is to raise and an unnecessary association option
52
+ # is detected.
53
+ class UnnecessaryAssociationOption < Sequel::Error
54
+ end
55
+
56
+ module ClassMethods
57
+ Plugins.inherited_instance_variables(self, :@detect_unnecessary_association_options_action => nil)
58
+
59
+ # Implicitly check for unnecessary association options when finalizing associations.
60
+ def finalize_associations
61
+ res = super
62
+ detect_unnecessary_association_options
63
+ res
64
+ end
65
+
66
+ # Check for unnecessary association options.
67
+ def detect_unnecessary_association_options
68
+ @association_reflections.each_value do |ref|
69
+ meth = "detect_unnecessary_association_options_#{ref[:type]}"
70
+ # Expected to call private methods.
71
+ # Ignore unrecognized association types.
72
+ # External association types can define the appropriate method to
73
+ # support their own unnecessary association option checks.
74
+ if respond_to?(meth, true)
75
+ # All recognized association types need same class check
76
+ _detect_unnecessary_association_options_class(ref)
77
+ send(meth, ref)
78
+ end
79
+ end
80
+
81
+ nil
82
+ end
83
+
84
+ private
85
+
86
+ # Action to take if an unnecessary association option is detected.
87
+ def unnecessary_association_options_detected(ref, key)
88
+ if @detect_unnecessary_association_options_action == :raise
89
+ raise UnnecessaryAssociationOption, "#{ref.inspect} :#{key} option unnecessary"
90
+ else
91
+ warn "#{ref.inspect} :#{key} option unnecessary"
92
+ end
93
+ end
94
+
95
+ # Detect unnecessary :class option.
96
+ def _detect_unnecessary_association_options_class(ref)
97
+ return unless ref[:orig_class]
98
+
99
+ h = {}
100
+ name = ref[:name]
101
+ late_binding_class_option(h, ref.returns_array? ? singularize(name) : name)
102
+
103
+ begin
104
+ default_association_class = constantize(h[:class_name])
105
+ actual_association_class = ref.associated_class
106
+ rescue NameError
107
+ # Do not warn. For the default association class to not be a valid
108
+ # constant is expected. For the actual association class to not be
109
+ # a valid constant is not expected and a bug in the association, but
110
+ # the job of this plugin is not to detect invalid options, only
111
+ # unnecessary options.
112
+ else
113
+ if default_association_class.equal?(actual_association_class)
114
+ unnecessary_association_options_detected(ref, "class")
115
+ end
116
+ end
117
+ end
118
+
119
+ # Detect other unnecessary options. An option is considered unnecessary
120
+ # if the key was submitted as an association option and the value for
121
+ # the option is the same as the given value.
122
+ def _detect_unnecessary_association_options_key_value(ref, key, value)
123
+ if ref[:orig_opts].has_key?(key) && ref[:orig_opts][key] == value
124
+ unnecessary_association_options_detected(ref, key)
125
+ end
126
+ end
127
+
128
+ # Same as _detect_unnecessary_association_options_key_value, but calls
129
+ # the default_* method on the association reflection to get the default value.
130
+ def _detect_unnecessary_association_options_key(ref, key)
131
+ _detect_unnecessary_association_options_key_value(ref, key, ref.send(:"default_#{key}"))
132
+ end
133
+
134
+ def detect_unnecessary_association_options_many_to_one(ref)
135
+ _detect_unnecessary_association_options_key(ref, :key)
136
+ _detect_unnecessary_association_options_key_value(ref, :primary_key, ref.associated_class.primary_key)
137
+ end
138
+ alias detect_unnecessary_association_options_pg_array_to_many detect_unnecessary_association_options_many_to_one
139
+
140
+ def detect_unnecessary_association_options_one_to_many(ref)
141
+ _detect_unnecessary_association_options_key(ref, :key)
142
+ _detect_unnecessary_association_options_key_value(ref, :primary_key, primary_key)
143
+ end
144
+ alias detect_unnecessary_association_options_one_to_one detect_unnecessary_association_options_one_to_many
145
+ alias detect_unnecessary_association_options_many_to_pg_array detect_unnecessary_association_options_one_to_many
146
+
147
+ def detect_unnecessary_association_options_many_to_many(ref)
148
+ [:join_table, :left_key, :right_key].each do |key|
149
+ _detect_unnecessary_association_options_key(ref, key)
150
+ end
151
+ _detect_unnecessary_association_options_key_value(ref, :left_primary_key, primary_key)
152
+ _detect_unnecessary_association_options_key_value(ref, :right_primary_key, ref.associated_class.primary_key)
153
+ end
154
+ alias detect_unnecessary_association_options_one_through_one detect_unnecessary_association_options_many_to_many
155
+
156
+ def detect_unnecessary_association_options_many_through_many(ref)
157
+ _detect_unnecessary_association_options_key_value(ref, :left_primary_key, primary_key)
158
+ _detect_unnecessary_association_options_key_value(ref, :right_primary_key, ref.associated_class.primary_key)
159
+ end
160
+ alias detect_unnecessary_association_options_one_through_many detect_unnecessary_association_options_many_through_many
161
+ end
162
+ end
163
+ end
164
+ end
@@ -63,6 +63,10 @@ module Sequel
63
63
  # # Make the Album class record previous values
64
64
  # Album.plugin :dirty
65
65
  module Dirty
66
+ module ClassMethods
67
+ Plugins.model_instance_variables(self, :@previous_changes, :@initial_values, :@missing_initial_values)
68
+ end
69
+
66
70
  module InstanceMethods
67
71
  # A hash of previous changes before the object was
68
72
  # saved, in the same format as #column_changes.
@@ -234,8 +238,11 @@ module Sequel
234
238
  iv.delete(column)
235
239
  end
236
240
  else
237
- check_missing_initial_value(column)
238
- iv[column] = get_column_value(column)
241
+ if db_schema[column]
242
+ check_missing_initial_value(column)
243
+ iv[column] = get_column_value(column)
244
+ end
245
+
239
246
  super
240
247
  end
241
248
  end
@@ -80,7 +80,7 @@ module Sequel
80
80
  inverted = values.invert.freeze
81
81
 
82
82
  unless @enum_methods
83
- @enum_methods = Module.new
83
+ @enum_methods = Sequel.set_temp_name(Module.new){"#{name}::@enum_methods"}
84
84
  include @enum_methods
85
85
  end
86
86
 
@@ -39,6 +39,9 @@ module Sequel
39
39
  #
40
40
  # Album.first.artist # no error
41
41
  #
42
+ # This behavior of enabling +forbid_lazy_load+ automatically from dataset
43
+ # methods can be disabled using the plugin's +:allow_by_default+ option.
44
+ #
42
45
  # You can allow lazy loading associations for an instance that it
43
46
  # was previously forbidden for:
44
47
  #
@@ -98,13 +101,24 @@ module Sequel
98
101
  #
99
102
  # # Make the Album class support forbidding lazy load
100
103
  # Album.plugin :forbid_lazy_load
104
+ #
105
+ # # Let lazy loading be forbidden by object, but not automatically for any
106
+ # # object loaded via dataset.
107
+ # Album.plugin :forbid_lazy_load, allow_by_default: true
101
108
  module ForbidLazyLoad
109
+ def self.apply(model, opts=OPTS)
110
+ unless opts[:allow_by_default]
111
+ model.send(:dataset_extend, ForbidByDefault, :create_class_methods=>false)
112
+ end
113
+ end
114
+
102
115
  # Error raised when attempting to lazy load an association when
103
116
  # lazy loading has been forbidden.
104
117
  class Error < StandardError
105
118
  end
106
119
 
107
120
  module ClassMethods
121
+ Plugins.model_instance_variables(self, :@forbid_lazy_load)
108
122
  Plugins.def_dataset_methods(self, :forbid_lazy_load)
109
123
 
110
124
  # If the static_cache plugin is used by the associated class for
@@ -179,7 +193,7 @@ module Sequel
179
193
  end
180
194
  end
181
195
 
182
- module DatasetMethods
196
+ module ForbidByDefault
183
197
  # Mark model instances retrieved in this call as forbidding lazy loading.
184
198
  def each
185
199
  if row_proc
@@ -42,6 +42,10 @@ module Sequel
42
42
  end
43
43
  end
44
44
 
45
+ module ClassMethods
46
+ Plugins.model_instance_variables(self, :@insert_conflict_opts)
47
+ end
48
+
45
49
  module InstanceMethods
46
50
  # Set the insert_conflict options to pass to the dataset when inserting.
47
51
  def insert_conflict(opts=OPTS)
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Sequel
4
4
  module Plugins
5
- # If the model's dataset selects explicit columns and the
5
+ # If the model's dataset selects explicit columns (or table.*) and the
6
6
  # database supports it, the insert_returning_select plugin will
7
7
  # automatically set the RETURNING clause on the dataset used to
8
8
  # insert rows to the columns selected, which allows the default model
@@ -45,6 +45,9 @@ module Sequel
45
45
  ret
46
46
  end
47
47
 
48
+ RETURN_ALL = [Sequel::Dataset::WILDCARD].freeze
49
+ private_constant :RETURN_ALL
50
+
48
51
  # Determine the columns to use for the returning clause, or return nil
49
52
  # if they can't be determined and a returning clause should not be
50
53
  # added automatically.
@@ -52,6 +55,12 @@ module Sequel
52
55
  return unless ds.supports_returning?(:insert)
53
56
  return unless values = ds.opts[:select]
54
57
 
58
+ # SELECT table.* -> RETURNING *
59
+ if values.length == 1 && values[0].is_a?(Sequel::SQL::ColumnAll)
60
+ return RETURN_ALL
61
+ end
62
+
63
+ # SELECT column1, table.column2, ... -> RETURNING column1, column2, ...
55
64
  values = values.map{|v| ds.unqualified_column_for(v)}
56
65
  if values.all?
57
66
  values
@@ -0,0 +1,44 @@
1
+ # frozen-string-literal: true
2
+
3
+ module Sequel
4
+ module Plugins
5
+ # The inspect_pk plugin includes the pk right next to the
6
+ # model name in inspect, allowing for easily copying and
7
+ # pasting to retrieve a copy of the object:
8
+ #
9
+ # Album.with_pk(1).inspect
10
+ # # default: #<Album @values={...}>
11
+ # # with inspect_pk: #<Album[1] @values={...}>
12
+ #
13
+ # Usage:
14
+ #
15
+ # # Make all model instances include pk in inspect output
16
+ # Sequel::Model.plugin :inspect_pk
17
+ #
18
+ # # Make Album instances include pk in inspect output
19
+ # Album.plugin :inspect_pk
20
+ module InspectPk
21
+ module InstanceMethods
22
+ private
23
+
24
+ # The primary key value to include in the inspect output, if any.
25
+ # For composite primary keys, this only includes a value if all
26
+ # fields are present.
27
+ def inspect_pk
28
+ if primary_key && (pk = self.pk) && (!(Array === pk) || pk.all?)
29
+ pk
30
+ end
31
+ end
32
+
33
+ # Include the instance's primary key in the output.
34
+ def inspect_prefix
35
+ if v = inspect_pk
36
+ "#{super}[#{v.inspect}]"
37
+ else
38
+ super
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -50,6 +50,10 @@ module Sequel
50
50
  model.require_modification = true
51
51
  end
52
52
 
53
+ module ClassMethods
54
+ Plugins.model_instance_variables(self, :@instance_filters)
55
+ end
56
+
53
57
  module InstanceMethods
54
58
  # Clear the instance filters after successfully destroying the object.
55
59
  def after_destroy
@@ -102,7 +106,10 @@ module Sequel
102
106
 
103
107
  # Apply the instance filters to the given dataset
104
108
  def apply_instance_filters(ds)
105
- instance_filters.inject(ds){|ds1, i| ds1.where(*i[0], &i[1])}
109
+ instance_filters.inject(ds) do |ds1, i|
110
+ block = i[1]
111
+ ds1.where(*i[0], &block)
112
+ end
106
113
  end
107
114
 
108
115
  # Clear the instance filters.
@@ -28,6 +28,10 @@ module Sequel
28
28
  # # Add the instance hook methods just to Album instances
29
29
  # Album.plugin :instance_hooks
30
30
  module InstanceHooks
31
+ module ClassMethods
32
+ Plugins.model_instance_variables(self, :@instance_hooks)
33
+ end
34
+
31
35
  module InstanceMethods
32
36
  Sequel::Model::HOOKS.each{|h| class_eval(<<-END , __FILE__, __LINE__+1)}
33
37
  def #{h}_hook(&block)
@@ -32,6 +32,7 @@ module Sequel
32
32
  def self.apply(model, &block)
33
33
  model.instance_exec do
34
34
  @dataset_module_class = Class.new(@dataset_module_class) do
35
+ Sequel.set_temp_name(self){"#{model.name}::@dataset_module_class(InvertedSubsets)"}
35
36
  include DatasetModuleMethods
36
37
  if block
37
38
  define_method(:inverted_subset_name, &block)
@@ -106,13 +106,7 @@ module Sequel
106
106
  # and breaks some aspects of the json_serializer plugin. You can undo the damage
107
107
  # done by active_support/json by doing:
108
108
  #
109
- # module ActiveSupportBrokenJSONFix
110
- # def to_json(options = {})
111
- # JSON.generate(self)
112
- # end
113
- # end
114
- # Array.send(:prepend, ActiveSupportBrokenJSONFix)
115
- # Hash.send(:prepend, ActiveSupportBrokenJSONFix)
109
+ # ActiveSupport::ToJsonWithActiveSupportEncoder.send(:remove_method, :to_json)
116
110
  #
117
111
  # Note that this will probably cause active_support/json to no longer work
118
112
  # correctly in some cases.
@@ -168,6 +162,8 @@ module Sequel
168
162
  end
169
163
 
170
164
  module ClassMethods
165
+ Plugins.model_instance_variables(self, :@json_serializer_opts)
166
+
171
167
  # The default opts to use when serializing model objects to JSON.
172
168
  attr_reader :json_serializer_opts
173
169
 
@@ -370,9 +366,9 @@ module Sequel
370
366
  end
371
367
 
372
368
  # Convert the receiver to a JSON data structure using the given arguments.
373
- def to_json_data(*args, &block)
374
- if block
375
- to_json(*args){|x| return block.call(x)}
369
+ def to_json_data(*args)
370
+ if defined?(yield)
371
+ to_json(*args){|x| return yield(x)}
376
372
  else
377
373
  to_json(*args){|x| return x}
378
374
  end
@@ -64,7 +64,7 @@ module Sequel
64
64
  # :dataset :: The base dataset to use for the lazy attribute lookup
65
65
  # :table :: The table name to use to qualify the attribute and primary key columns.
66
66
  def define_lazy_attribute_getter(a, opts=OPTS)
67
- include(@lazy_attributes_module ||= Module.new) unless @lazy_attributes_module
67
+ include(@lazy_attributes_module ||= Sequel.set_temp_name(Module.new){"#{name}::@lazy_attributes_module"}) unless @lazy_attributes_module
68
68
  @lazy_attributes_module.class_eval do
69
69
  define_method(a) do
70
70
  if !values.has_key?(a) && !new?