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 +4 -4
- data/lib/sequel/database/schema_generator.rb +3 -1
- data/lib/sequel/database/schema_methods.rb +3 -1
- data/lib/sequel/dataset/actions.rb +9 -0
- data/lib/sequel/dataset/sql.rb +3 -4
- data/lib/sequel/extensions/pg_range.rb +1 -0
- data/lib/sequel/plugins/detect_unnecessary_association_options.rb +164 -0
- data/lib/sequel/plugins/single_statement_dataset_destroy.rb +49 -0
- data/lib/sequel/plugins/unused_associations.rb +7 -1
- data/lib/sequel/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9de2d20e1483de5f15a285b695d5eab98601c26f1e711e378de1a03331f197a1
|
|
4
|
+
data.tar.gz: 4d7df1811d7242dad22f6c9968fb43feecb5a86fd814aa2ba7434bdb44369cb8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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,
|
data/lib/sequel/dataset/sql.rb
CHANGED
|
@@ -638,12 +638,11 @@ module Sequel
|
|
|
638
638
|
if args.empty?
|
|
639
639
|
sql << str
|
|
640
640
|
else
|
|
641
|
-
re = /:(#{args.keys.map
|
|
642
|
-
|
|
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[
|
|
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)
|
|
@@ -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
|
|
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]
|
data/lib/sequel/version.rb
CHANGED
|
@@ -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 =
|
|
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.
|
|
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:
|
|
456
|
+
rubygems_version: 4.0.3
|
|
455
457
|
specification_version: 4
|
|
456
458
|
summary: The Database Toolkit for Ruby
|
|
457
459
|
test_files: []
|