sequel 5.51.0 → 5.52.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 (40) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +28 -0
  3. data/README.rdoc +5 -0
  4. data/doc/opening_databases.rdoc +1 -1
  5. data/doc/release_notes/5.52.0.txt +87 -0
  6. data/doc/testing.rdoc +3 -1
  7. data/lib/sequel/adapters/amalgalite.rb +3 -5
  8. data/lib/sequel/adapters/jdbc.rb +7 -9
  9. data/lib/sequel/adapters/mysql.rb +80 -67
  10. data/lib/sequel/adapters/mysql2.rb +41 -43
  11. data/lib/sequel/adapters/postgres.rb +17 -21
  12. data/lib/sequel/adapters/shared/mysql.rb +3 -2
  13. data/lib/sequel/adapters/shared/postgres.rb +2 -2
  14. data/lib/sequel/adapters/sqlite.rb +16 -18
  15. data/lib/sequel/connection_pool/sharded_single.rb +5 -7
  16. data/lib/sequel/connection_pool/single.rb +6 -8
  17. data/lib/sequel/core.rb +17 -18
  18. data/lib/sequel/database/query.rb +1 -1
  19. data/lib/sequel/extensions/core_refinements.rb +36 -11
  20. data/lib/sequel/extensions/date_parse_input_handler.rb +67 -0
  21. data/lib/sequel/extensions/datetime_parse_to_time.rb +5 -1
  22. data/lib/sequel/extensions/pg_array_ops.rb +1 -1
  23. data/lib/sequel/extensions/pg_hstore_ops.rb +1 -1
  24. data/lib/sequel/extensions/pg_inet_ops.rb +1 -1
  25. data/lib/sequel/extensions/pg_interval.rb +1 -0
  26. data/lib/sequel/extensions/pg_json.rb +3 -5
  27. data/lib/sequel/extensions/pg_json_ops.rb +1 -1
  28. data/lib/sequel/extensions/pg_range_ops.rb +1 -1
  29. data/lib/sequel/extensions/pg_row_ops.rb +1 -1
  30. data/lib/sequel/extensions/s.rb +2 -1
  31. data/lib/sequel/extensions/server_block.rb +8 -12
  32. data/lib/sequel/extensions/sql_comments.rb +108 -3
  33. data/lib/sequel/extensions/string_date_time.rb +19 -23
  34. data/lib/sequel/model/base.rb +8 -12
  35. data/lib/sequel/plugins/sql_comments.rb +189 -0
  36. data/lib/sequel/plugins/subclasses.rb +28 -11
  37. data/lib/sequel/plugins/unused_associations.rb +2 -2
  38. data/lib/sequel/timezones.rb +12 -14
  39. data/lib/sequel/version.rb +1 -1
  40. metadata +7 -3
@@ -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
+ ruby2_keywords(meth) if respond_to?(:ruby2_keywords, false)
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, false)
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, false)
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, false)
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
@@ -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)
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
@@ -313,7 +313,7 @@ module Sequel
313
313
  {}
314
314
  end
315
315
 
316
- ([self] + descendents).each do |sc|
316
+ ([self] + descendants).each do |sc|
317
317
  next if sc.associations.empty? || !sc.name
318
318
  module_mapping[sc.send(:overridable_methods_module)] = sc
319
319
  cov_data = coverage_data[sc.name] ||= {''=>[]}
@@ -348,7 +348,7 @@ module Sequel
348
348
 
349
349
  unused_associations_data = {}
350
350
 
351
- ([self] + descendents).each do |sc|
351
+ ([self] + descendants).each do |sc|
352
352
  next unless cov_data = coverage_data[sc.name]
353
353
  reflection_data = cov_data[''] || []
354
354
 
@@ -82,22 +82,20 @@ module Sequel
82
82
  # +application_timezone+ using +convert_input_timestamp+ and
83
83
  # +convert_output_timestamp+.
84
84
  def convert_timestamp(v, input_timezone)
85
- begin
86
- if v.is_a?(Date) && !v.is_a?(DateTime)
87
- # Dates handled specially as they are assumed to already be in the application_timezone
88
- if datetime_class == DateTime
89
- DateTime.civil(v.year, v.month, v.day, 0, 0, 0, application_timezone == :local ? Rational(Time.local(v.year, v.month, v.day).utc_offset, 86400) : 0)
90
- else
91
- Time.public_send(application_timezone == :utc ? :utc : :local, v.year, v.month, v.day)
92
- end
85
+ if v.is_a?(Date) && !v.is_a?(DateTime)
86
+ # Dates handled specially as they are assumed to already be in the application_timezone
87
+ if datetime_class == DateTime
88
+ DateTime.civil(v.year, v.month, v.day, 0, 0, 0, application_timezone == :local ? Rational(Time.local(v.year, v.month, v.day).utc_offset, 86400) : 0)
93
89
  else
94
- convert_output_timestamp(convert_input_timestamp(v, input_timezone), application_timezone)
90
+ Time.public_send(application_timezone == :utc ? :utc : :local, v.year, v.month, v.day)
95
91
  end
96
- rescue InvalidValue
97
- raise
98
- rescue => e
99
- raise convert_exception_class(e, InvalidValue)
92
+ else
93
+ convert_output_timestamp(convert_input_timestamp(v, input_timezone), application_timezone)
100
94
  end
95
+ rescue InvalidValue
96
+ raise
97
+ rescue => e
98
+ raise convert_exception_class(e, InvalidValue)
101
99
  end
102
100
 
103
101
  # Convert the given object into an object of <tt>Sequel.datetime_class</tt> in the
@@ -158,7 +156,7 @@ module Sequel
158
156
  case v
159
157
  when String
160
158
  v2 = Sequel.string_to_datetime(v)
161
- if !input_timezone || Date._parse(v).has_key?(:offset)
159
+ if !input_timezone || _date_parse(v).has_key?(:offset)
162
160
  v2
163
161
  else
164
162
  # Correct for potentially wrong offset if string doesn't include offset
@@ -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 = 51
9
+ MINOR = 52
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,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sequel
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.51.0
4
+ version: 5.52.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeremy Evans
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-12-01 00:00:00.000000000 Z
11
+ date: 2022-01-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest
@@ -196,6 +196,7 @@ extra_rdoc_files:
196
196
  - doc/release_notes/5.5.0.txt
197
197
  - doc/release_notes/5.50.0.txt
198
198
  - doc/release_notes/5.51.0.txt
199
+ - doc/release_notes/5.52.0.txt
199
200
  - doc/release_notes/5.6.0.txt
200
201
  - doc/release_notes/5.7.0.txt
201
202
  - doc/release_notes/5.8.0.txt
@@ -275,6 +276,7 @@ files:
275
276
  - doc/release_notes/5.5.0.txt
276
277
  - doc/release_notes/5.50.0.txt
277
278
  - doc/release_notes/5.51.0.txt
279
+ - doc/release_notes/5.52.0.txt
278
280
  - doc/release_notes/5.6.0.txt
279
281
  - doc/release_notes/5.7.0.txt
280
282
  - doc/release_notes/5.8.0.txt
@@ -387,6 +389,7 @@ files:
387
389
  - lib/sequel/extensions/current_datetime_timestamp.rb
388
390
  - lib/sequel/extensions/dataset_source_alias.rb
389
391
  - lib/sequel/extensions/date_arithmetic.rb
392
+ - lib/sequel/extensions/date_parse_input_handler.rb
390
393
  - lib/sequel/extensions/datetime_parse_to_time.rb
391
394
  - lib/sequel/extensions/duplicate_columns_handler.rb
392
395
  - lib/sequel/extensions/empty_array_consider_nulls.rb
@@ -530,6 +533,7 @@ files:
530
533
  - lib/sequel/plugins/skip_create_refresh.rb
531
534
  - lib/sequel/plugins/skip_saving_columns.rb
532
535
  - lib/sequel/plugins/split_values.rb
536
+ - lib/sequel/plugins/sql_comments.rb
533
537
  - lib/sequel/plugins/static_cache.rb
534
538
  - lib/sequel/plugins/static_cache_cache.rb
535
539
  - lib/sequel/plugins/string_stripper.rb
@@ -588,7 +592,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
588
592
  - !ruby/object:Gem::Version
589
593
  version: '0'
590
594
  requirements: []
591
- rubygems_version: 3.2.32
595
+ rubygems_version: 3.3.3
592
596
  signing_key:
593
597
  specification_version: 4
594
598
  summary: The Database Toolkit for Ruby