sequel 5.99.0 → 5.101.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7e5d22a32d8c5f27e15e00203d0c2ce2a2fb3f5352d7b7c25c82389f4947882c
4
- data.tar.gz: 81909dc070cc8d48def396ae76e953a1f31dc478b45d3a5fa8b69646bc7df094
3
+ metadata.gz: 9de2d20e1483de5f15a285b695d5eab98601c26f1e711e378de1a03331f197a1
4
+ data.tar.gz: 4d7df1811d7242dad22f6c9968fb43feecb5a86fd814aa2ba7434bdb44369cb8
5
5
  SHA512:
6
- metadata.gz: c24ae48ece66511a09b2d8a5ad8b5b82e7486a4446bcb66108140b8afe449cd9c9e7645a29ca0bbe0c994d5c060a52f1ab4c41434dc068175751b1d6bd57b5dc
7
- data.tar.gz: e8acd2e5cb4272bd47aed87e3077018dfc5ba9673856b871c8222eec6b2de1be0843840969e046efc459b52902753e9e0f0e35b95dcdcf31914d98b5f487d78a
6
+ metadata.gz: a9aa7a3bd15f4f35457aace92b68b4734d367273996dc605d80adbe87bca1c945fc484571cad90149e69807980eea2f8b2a6a6fea85a4a0670c10a082a056a03
7
+ data.tar.gz: ca5c1eb34d71d16660a0b5eb2b9e5b4c784f06d6e4f89b036f00a62f31b57d564f071b8346bdcb9ebd9cced7bcfbe429e2c50bcda1b8b150d723b1e59105c474
@@ -657,9 +657,11 @@ module Sequel
657
657
  nil
658
658
  end
659
659
 
660
- # Modify the type of one of the table's column.
660
+ # Modify the type of one of the table's column. The given options are considered when
661
+ # determining the new type.
661
662
  #
662
663
  # set_column_type(:artist_name, 'char(10)') # ALTER COLUMN artist_name TYPE char(10)
664
+ # set_column_type(:artist_name, String, size: 10) # ALTER COLUMN artist_name TYPE varchar(10)
663
665
  #
664
666
  # PostgreSQL specific options:
665
667
  #
@@ -486,7 +486,9 @@ module Sequel
486
486
  end
487
487
 
488
488
  def alter_table_set_column_type_sql(table, op)
489
- "ALTER COLUMN #{quote_identifier(op[:name])} TYPE #{type_literal(op)}"
489
+ sql = "ALTER COLUMN #{quote_identifier(op[:name])} TYPE #{type_literal(op)}".dup
490
+ column_definition_collate_sql(sql, op)
491
+ sql
490
492
  end
491
493
 
492
494
  def alter_table_set_column_default_sql(table, op)
@@ -372,6 +372,15 @@ module Sequel
372
372
  # DB[:table].import([:x, :y], DB[:table2].select(:a, :b))
373
373
  # # INSERT INTO table (x, y) SELECT a, b FROM table2
374
374
  #
375
+ # The return value of this method is undefined and should not be used,
376
+ # except in two cases:
377
+ #
378
+ # * When the <tt>return: :primary_key</tt> option is used.
379
+ # * On PostgreSQL, when the dataset uses RETURNING. In this case, if
380
+ # a single value is returned per row, the return value is an array
381
+ # of those values. If multiple values are returned per row, the
382
+ # return value is an array of hashes.
383
+ #
375
384
  # Options:
376
385
  # :commit_every :: Open a new transaction for every given number of
377
386
  # records. For example, if you provide a value of 50,
@@ -638,12 +638,11 @@ module Sequel
638
638
  if args.empty?
639
639
  sql << str
640
640
  else
641
- re = /:(#{args.keys.map{|k| Regexp.escape(k.to_s)}.join('|')})\b/
642
- while true
641
+ re = /:(#{Regexp.union(args.keys.map(&:to_s))})\b/
642
+ until str.empty?
643
643
  previous, q, str = str.partition(re)
644
644
  sql << previous
645
- literal_append(sql, args[($1||q[1..-1].to_s).to_sym]) unless q.empty?
646
- break if str.empty?
645
+ literal_append(sql, args[$1.to_sym]) unless q.empty?
647
646
  end
648
647
  end
649
648
  elsif str.is_a?(Array)
@@ -431,6 +431,7 @@ module Sequel
431
431
 
432
432
  "#<#{self.class.name} #{range}#{"::#{@db_type}" if @db_type}>"
433
433
  end
434
+ alias to_s inspect
434
435
 
435
436
  # Append a literalize version of the receiver to the sql.
436
437
  def sql_literal_append(ds, sql)
@@ -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
@@ -0,0 +1,49 @@
1
+ # frozen-string-literal: true
2
+
3
+ module Sequel
4
+ module Plugins
5
+ # The single_statement_dataset_destroy plugin makes the
6
+ # model dataset.destroy method delete all rows in a
7
+ # single DELETE statement. It runs all before_destroy
8
+ # hooks before the DELETE, and all after_destroy hooks
9
+ # after the delete.
10
+ #
11
+ # This is not compatible with around_destroy hooks,
12
+ # so if the model is using custom around_destroy hooks,
13
+ # dataset.destroy falls back to a separate DELETE statement
14
+ # per row.
15
+ #
16
+ # Usage:
17
+ #
18
+ # # Make all model subclasses use a single DELETE
19
+ # # statement for dataset.destroy
20
+ # Sequel::Model.plugin :single_statement_dataset_destroy
21
+ #
22
+ # # Make the Album class use a single DELETE
23
+ # # statement for dataset.destroy
24
+ # Album.plugin :single_statement_dataset_destroy
25
+ module SingleStatementDatasetDestroy
26
+ module DatasetMethods
27
+ # Destroy all rows in a single DELETE statement. Run the before_destroy
28
+ # hooks for all rows before the DELETE, and all after_destroy hooks
29
+ # for all rows after the DELETE. If the model uses an around_destroy
30
+ # hook, fallback to using a separate DELETE statement per row.
31
+ def destroy
32
+ return super unless model.instance_method(:around_destroy).owner == Sequel::Model::InstanceMethods
33
+
34
+ db.transaction do
35
+ rows = all
36
+ rows.each(&:before_destroy)
37
+ expected_rows = rows.length
38
+ n = delete
39
+ unless n == expected_rows
40
+ raise Error, "dataset changed during destroy, expected rows: #{expected_rows}, actual rows: #{n}"
41
+ end
42
+ rows.each(&:after_destroy)
43
+ n
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -198,7 +198,8 @@ module Sequel
198
198
  #
199
199
  # Since this plugin is based on coverage information, if you do
200
200
  # not have tests that cover all usage of associations in your
201
- # application, you can end up with coverage that shows the
201
+ # application, or you are mocking the related association methods
202
+ # and not calling them, you can end up with coverage that shows the
202
203
  # association is not used, when it is used in code that is not
203
204
  # covered. The output of plugin can still be useful in such cases,
204
205
  # as long as you are manually checking it. However, you should
@@ -208,6 +209,8 @@ module Sequel
208
209
  # option for any association that you know is used. If an
209
210
  # association uses the :is_used association option, this plugin
210
211
  # will not modify it if the :modify_associations option is used.
212
+ # It will also not report the association as unused if the :is_used
213
+ # association option is present.
211
214
  #
212
215
  # This plugin does not handle anonymous classes. Any unused
213
216
  # associations defined in anonymous classes will not be
@@ -362,6 +365,9 @@ module Sequel
362
365
  # looks in the class's overridable_methods_module
363
366
  next if ref[:methods_module]
364
367
 
368
+ # Do not report associations if they are explicitly marked as used.
369
+ next if ref[:is_used]
370
+
365
371
  info = {}
366
372
  if reflection_data.include?(assoc.to_s)
367
373
  info[:used] = [:reflection]
@@ -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 = 99
9
+ MINOR = 101
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.99.0
4
+ version: 5.101.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeremy Evans
@@ -344,6 +344,7 @@ files:
344
344
  - lib/sequel/plugins/defaults_setter.rb
345
345
  - lib/sequel/plugins/delay_add_association.rb
346
346
  - lib/sequel/plugins/deprecated_associations.rb
347
+ - lib/sequel/plugins/detect_unnecessary_association_options.rb
347
348
  - lib/sequel/plugins/dirty.rb
348
349
  - lib/sequel/plugins/eager_each.rb
349
350
  - lib/sequel/plugins/eager_graph_eager.rb
@@ -386,6 +387,7 @@ files:
386
387
  - lib/sequel/plugins/serialization.rb
387
388
  - lib/sequel/plugins/serialization_modification_detection.rb
388
389
  - lib/sequel/plugins/sharding.rb
390
+ - lib/sequel/plugins/single_statement_dataset_destroy.rb
389
391
  - lib/sequel/plugins/single_table_inheritance.rb
390
392
  - lib/sequel/plugins/singular_table_names.rb
391
393
  - lib/sequel/plugins/skip_create_refresh.rb
@@ -451,7 +453,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
451
453
  - !ruby/object:Gem::Version
452
454
  version: '0'
453
455
  requirements: []
454
- rubygems_version: 3.6.9
456
+ rubygems_version: 4.0.3
455
457
  specification_version: 4
456
458
  summary: The Database Toolkit for Ruby
457
459
  test_files: []