sequel 5.95.0 → 5.99.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 (44) hide show
  1. checksums.yaml +4 -4
  2. data/lib/sequel/adapters/amalgalite.rb +16 -1
  3. data/lib/sequel/adapters/postgres.rb +1 -0
  4. data/lib/sequel/adapters/shared/mssql.rb +1 -1
  5. data/lib/sequel/adapters/shared/mysql.rb +1 -1
  6. data/lib/sequel/adapters/shared/postgres.rb +50 -6
  7. data/lib/sequel/adapters/sqlite.rb +15 -1
  8. data/lib/sequel/ast_transformer.rb +2 -0
  9. data/lib/sequel/core.rb +15 -1
  10. data/lib/sequel/database/misc.rb +1 -1
  11. data/lib/sequel/database/schema_generator.rb +4 -0
  12. data/lib/sequel/dataset/actions.rb +65 -10
  13. data/lib/sequel/dataset/query.rb +1 -1
  14. data/lib/sequel/dataset/sql.rb +10 -2
  15. data/lib/sequel/extensions/constraint_validations.rb +3 -3
  16. data/lib/sequel/extensions/empty_array_consider_nulls.rb +7 -0
  17. data/lib/sequel/extensions/eval_inspect.rb +2 -0
  18. data/lib/sequel/extensions/looser_typecasting.rb +5 -12
  19. data/lib/sequel/extensions/pg_array_ops.rb +41 -0
  20. data/lib/sequel/extensions/pg_auto_parameterize.rb +4 -2
  21. data/lib/sequel/extensions/pg_auto_parameterize_duplicate_query_detection.rb +191 -0
  22. data/lib/sequel/extensions/pg_auto_parameterize_in_array.rb +2 -1
  23. data/lib/sequel/extensions/pg_hstore_ops.rb +10 -5
  24. data/lib/sequel/extensions/pg_json_ops.rb +32 -9
  25. data/lib/sequel/extensions/pg_multirange.rb +1 -1
  26. data/lib/sequel/extensions/pg_range.rb +13 -2
  27. data/lib/sequel/extensions/pg_row.rb +2 -2
  28. data/lib/sequel/extensions/set_literalizer.rb +20 -39
  29. data/lib/sequel/extensions/split_array_nil.rb +12 -2
  30. data/lib/sequel/extensions/to_dot.rb +5 -0
  31. data/lib/sequel/model/associations.rb +7 -7
  32. data/lib/sequel/model/base.rb +36 -9
  33. data/lib/sequel/plugins/deprecated_associations.rb +151 -0
  34. data/lib/sequel/plugins/insert_returning_select.rb +10 -1
  35. data/lib/sequel/plugins/json_serializer.rb +1 -7
  36. data/lib/sequel/plugins/pg_array_associations.rb +2 -2
  37. data/lib/sequel/plugins/rcte_tree.rb +5 -5
  38. data/lib/sequel/plugins/split_values.rb +10 -0
  39. data/lib/sequel/plugins/static_cache.rb +13 -0
  40. data/lib/sequel/plugins/subset_static_cache.rb +15 -0
  41. data/lib/sequel/plugins/table_select.rb +7 -0
  42. data/lib/sequel/sql.rb +1 -1
  43. data/lib/sequel/version.rb +1 -1
  44. metadata +3 -1
@@ -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
@@ -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
@@ -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.
@@ -541,7 +541,7 @@ module Sequel
541
541
  if (assoc_pks = obj.get_column_value(key)) && !assoc_pks.empty?
542
542
  Sequel[pk=>assoc_pks.to_a]
543
543
  end
544
- when Array
544
+ when Array, Set
545
545
  if (assoc_pks = obj.map{|o| o.get_column_value(key)}.flatten.compact.uniq) && !assoc_pks.empty?
546
546
  Sequel[pk=>assoc_pks]
547
547
  end
@@ -563,7 +563,7 @@ module Sequel
563
563
  if pkv = obj.get_column_value(ref.primary_key_method)
564
564
  Sequel.pg_array_op(key).contains(Sequel.pg_array([pkv], ref.array_type))
565
565
  end
566
- when Array
566
+ when Array, Set
567
567
  if (pkvs = obj.map{|o| o.get_column_value(ref.primary_key_method)}.compact) && !pkvs.empty?
568
568
  Sequel.pg_array(key).overlaps(Sequel.pg_array(pkvs, ref.array_type))
569
569
  end
@@ -111,7 +111,7 @@ module Sequel
111
111
  ancestor_base_case_columns = prkey_array.zip(key_aliases).map{|k, ka_| SQL::AliasedExpression.new(k, ka_)} + c_all
112
112
  descendant_base_case_columns = key_array.zip(key_aliases).map{|k, ka_| SQL::AliasedExpression.new(k, ka_)} + c_all
113
113
  recursive_case_columns = prkey_array.zip(key_aliases).map{|k, ka_| SQL::QualifiedIdentifier.new(t, ka_)} + c_all
114
- extract_key_alias = lambda{|m| key_aliases.map{|ka_| bd_conv[m.values.delete(ka_)]}}
114
+ extract_key_alias = lambda{|m| key_aliases.map{|ka_| bd_conv[m.remove_key!(ka_)]}}
115
115
  else
116
116
  key_present = key_conv = lambda{|m| m[key]}
117
117
  prkey_conv = lambda{|m| m[prkey]}
@@ -119,7 +119,7 @@ module Sequel
119
119
  ancestor_base_case_columns = [SQL::AliasedExpression.new(prkey, ka)] + c_all
120
120
  descendant_base_case_columns = [SQL::AliasedExpression.new(key, ka)] + c_all
121
121
  recursive_case_columns = [SQL::QualifiedIdentifier.new(t, ka)] + c_all
122
- extract_key_alias = lambda{|m| bd_conv[m.values.delete(ka)]}
122
+ extract_key_alias = lambda{|m| bd_conv[m.remove_key!(ka)]}
123
123
  end
124
124
 
125
125
  parent = opts.merge(opts.fetch(:parent, OPTS)).fetch(:name, :parent)
@@ -200,7 +200,7 @@ module Sequel
200
200
  model.eager_load_results(r, eo.merge(:loader=>false, :initialize_rows=>false, :dataset=>ds, :id_map=>nil)) do |obj|
201
201
  opk = prkey_conv[obj]
202
202
  if idm_obj = parent_map[opk]
203
- key_aliases.each{|ka_| idm_obj.values[ka_] = obj.values[ka_]}
203
+ key_aliases.each{|ka_| idm_obj[ka_] = obj[ka_]}
204
204
  obj = idm_obj
205
205
  else
206
206
  obj.associations[parent] = nil
@@ -307,12 +307,12 @@ module Sequel
307
307
  ds = ds.select_append(ka) unless ds.opts[:select] == nil
308
308
  model.eager_load_results(r, eo.merge(:loader=>false, :initialize_rows=>false, :dataset=>ds, :id_map=>nil, :associations=>OPTS)) do |obj|
309
309
  if level
310
- no_cache = no_cache_level == obj.values.delete(la)
310
+ no_cache = no_cache_level == obj.remove_key!(la)
311
311
  end
312
312
 
313
313
  opk = prkey_conv[obj]
314
314
  if idm_obj = parent_map[opk]
315
- key_aliases.each{|ka_| idm_obj.values[ka_] = obj.values[ka_]}
315
+ key_aliases.each{|ka_| idm_obj[ka_] = obj[ka_]}
316
316
  obj = idm_obj
317
317
  else
318
318
  obj.associations[childrena] = [] unless no_cache
@@ -54,6 +54,16 @@ module Sequel
54
54
  end
55
55
  end
56
56
 
57
+ # Remove the key from noncolumn values if it is present there. If it is not
58
+ # present there, then use the default behavior of removing it from values.
59
+ def remove_key!(key)
60
+ if @noncolumn_values && @noncolumn_values.key?(key)
61
+ @noncolumn_values.delete(key)
62
+ else
63
+ super
64
+ end
65
+ end
66
+
57
67
  # Check all entries in the values hash. If any of the keys are not columns,
58
68
  # move the entry into the noncolumn_values hash.
59
69
  def split_noncolumn_values
@@ -176,6 +176,19 @@ module Sequel
176
176
  h
177
177
  end
178
178
 
179
+ # Use the cache instead of a query to get the results.
180
+ def as_set(column)
181
+ set = Set.new
182
+
183
+ if column.is_a?(Array)
184
+ @all.each{|r| set.add(r.values.values_at(*column))}
185
+ else
186
+ @all.each{|r| set.add(r[column])}
187
+ end
188
+
189
+ set
190
+ end
191
+
179
192
  # Alias of as_hash for backwards compatibility.
180
193
  def to_hash(*a)
181
194
  as_hash(*a)
@@ -226,6 +226,21 @@ module Sequel
226
226
  h
227
227
  end
228
228
 
229
+ # Use the cache instead of a query to get the results.
230
+ def as_set(column)
231
+ return super unless all = @cache[:subset_static_cache_all]
232
+
233
+ set = Set.new
234
+
235
+ if column.is_a?(Array)
236
+ all.each{|r| set.add(r.values.values_at(*column))}
237
+ else
238
+ all.each{|r| set.add(r[column])}
239
+ end
240
+
241
+ set
242
+ end
243
+
229
244
  # Alias of as_hash for backwards compatibility.
230
245
  def to_hash(*a)
231
246
  as_hash(*a)
@@ -9,6 +9,13 @@ module Sequel
9
9
  # in the result sets (and possibly overwrite columns in the
10
10
  # current model with the same name).
11
11
  #
12
+ # Note that by default on databases that supporting RETURNING,
13
+ # using this plugin will cause instance creations
14
+ # to use two queries (insert and refresh) instead of a single
15
+ # query using RETURNING. You can use the insert_returning_select
16
+ # plugin to automatically use RETURNING for instance creations
17
+ # for models using this plugin.
18
+ #
12
19
  # Usage:
13
20
  #
14
21
  # # Make all model subclasses select table.*
data/lib/sequel/sql.rb CHANGED
@@ -1108,7 +1108,7 @@ module Sequel
1108
1108
  else
1109
1109
  new(:'=', 1, 1)
1110
1110
  end
1111
- when ::Array
1111
+ when ::Array, ::Set
1112
1112
  r = r.dup.freeze unless r.frozen?
1113
1113
  new(:IN, l, r)
1114
1114
  when ::String
@@ -6,7 +6,7 @@ module Sequel
6
6
 
7
7
  # The minor version of Sequel. Bumped for every non-patch level
8
8
  # release, generally around once a month.
9
- MINOR = 95
9
+ MINOR = 99
10
10
 
11
11
  # The tiny version of Sequel. Usually 0, only bumped for bugfix
12
12
  # releases that fix regressions from previous versions.
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sequel
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.95.0
4
+ version: 5.99.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeremy Evans
@@ -250,6 +250,7 @@ files:
250
250
  - lib/sequel/extensions/pg_array.rb
251
251
  - lib/sequel/extensions/pg_array_ops.rb
252
252
  - lib/sequel/extensions/pg_auto_parameterize.rb
253
+ - lib/sequel/extensions/pg_auto_parameterize_duplicate_query_detection.rb
253
254
  - lib/sequel/extensions/pg_auto_parameterize_in_array.rb
254
255
  - lib/sequel/extensions/pg_enum.rb
255
256
  - lib/sequel/extensions/pg_extended_date_support.rb
@@ -342,6 +343,7 @@ files:
342
343
  - lib/sequel/plugins/def_dataset_method.rb
343
344
  - lib/sequel/plugins/defaults_setter.rb
344
345
  - lib/sequel/plugins/delay_add_association.rb
346
+ - lib/sequel/plugins/deprecated_associations.rb
345
347
  - lib/sequel/plugins/dirty.rb
346
348
  - lib/sequel/plugins/eager_each.rb
347
349
  - lib/sequel/plugins/eager_graph_eager.rb