sequel 5.31.0 → 5.32.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/CHANGELOG +16 -0
  3. data/doc/advanced_associations.rdoc +4 -4
  4. data/doc/association_basics.rdoc +3 -3
  5. data/doc/code_order.rdoc +12 -2
  6. data/doc/model_dataset_method_design.rdoc +1 -1
  7. data/doc/release_notes/5.32.0.txt +46 -0
  8. data/doc/testing.rdoc +1 -0
  9. data/lib/sequel/adapters/shared/access.rb +6 -6
  10. data/lib/sequel/adapters/shared/mssql.rb +5 -5
  11. data/lib/sequel/adapters/shared/mysql.rb +9 -9
  12. data/lib/sequel/adapters/shared/oracle.rb +16 -16
  13. data/lib/sequel/adapters/shared/postgres.rb +18 -8
  14. data/lib/sequel/adapters/shared/sqlanywhere.rb +9 -9
  15. data/lib/sequel/adapters/shared/sqlite.rb +1 -0
  16. data/lib/sequel/connection_pool/sharded_threaded.rb +2 -2
  17. data/lib/sequel/connection_pool/threaded.rb +1 -1
  18. data/lib/sequel/core.rb +318 -314
  19. data/lib/sequel/database/query.rb +1 -1
  20. data/lib/sequel/extensions/connection_expiration.rb +2 -2
  21. data/lib/sequel/extensions/connection_validator.rb +2 -2
  22. data/lib/sequel/extensions/fiber_concurrency.rb +24 -0
  23. data/lib/sequel/extensions/index_caching.rb +9 -7
  24. data/lib/sequel/extensions/integer64.rb +2 -0
  25. data/lib/sequel/extensions/pg_inet.rb +13 -5
  26. data/lib/sequel/extensions/pg_interval.rb +2 -0
  27. data/lib/sequel/extensions/pg_range.rb +2 -0
  28. data/lib/sequel/extensions/pg_timestamptz.rb +2 -0
  29. data/lib/sequel/extensions/run_transaction_hooks.rb +72 -0
  30. data/lib/sequel/extensions/server_block.rb +3 -3
  31. data/lib/sequel/model/base.rb +48 -47
  32. data/lib/sequel/model/plugins.rb +1 -0
  33. data/lib/sequel/plugins/association_lazy_eager_option.rb +2 -0
  34. data/lib/sequel/plugins/association_multi_add_remove.rb +2 -0
  35. data/lib/sequel/plugins/association_proxies.rb +2 -0
  36. data/lib/sequel/plugins/boolean_subsets.rb +4 -1
  37. data/lib/sequel/plugins/class_table_inheritance.rb +26 -26
  38. data/lib/sequel/plugins/dirty.rb +13 -13
  39. data/lib/sequel/plugins/json_serializer.rb +3 -7
  40. data/lib/sequel/plugins/single_table_inheritance.rb +15 -15
  41. data/lib/sequel/plugins/subclasses.rb +2 -0
  42. data/lib/sequel/timezones.rb +6 -4
  43. data/lib/sequel/version.rb +1 -1
  44. metadata +6 -2
@@ -325,7 +325,7 @@ module Sequel
325
325
  :integer
326
326
  when /\Adate\z/io
327
327
  :date
328
- when /\A((small)?datetime|timestamp( with(out)? time zone)?)(\(\d+\))?\z/io
328
+ when /\A((small)?datetime|timestamp(\(\d\))?( with(out)? time zone)?)\z/io
329
329
  :datetime
330
330
  when /\Atime( with(out)? time zone)?\z/io
331
331
  :time
@@ -80,9 +80,9 @@ module Sequel
80
80
  Sequel.elapsed_seconds_since(cet[0]) > cet[1]
81
81
 
82
82
  if pool_type == :sharded_threaded
83
- sync{allocated(a.last).delete(Thread.current)}
83
+ sync{allocated(a.last).delete(Sequel.current)}
84
84
  else
85
- sync{@allocated.delete(Thread.current)}
85
+ sync{@allocated.delete(Sequel.current)}
86
86
  end
87
87
 
88
88
  disconnect_connection(conn)
@@ -104,9 +104,9 @@ module Sequel
104
104
  !db.valid_connection?(conn)
105
105
 
106
106
  if pool_type == :sharded_threaded
107
- sync{allocated(a.last).delete(Thread.current)}
107
+ sync{allocated(a.last).delete(Sequel.current)}
108
108
  else
109
- sync{@allocated.delete(Thread.current)}
109
+ sync{@allocated.delete(Sequel.current)}
110
110
  end
111
111
 
112
112
  disconnect_connection(conn)
@@ -0,0 +1,24 @@
1
+ # frozen-string-literal: true
2
+ #
3
+ # The fiber_concurrency extension changes the default concurrency
4
+ # primitive in Sequel to be Fiber.current instead of Thread.current.
5
+ # This is the value used in various hash keys to implement safe
6
+ # concurrency (thread-safe concurrency by default, fiber-safe
7
+ # concurrency with this extension. It can be enabled via:
8
+ #
9
+ # Sequel.extension :fiber_concurrency
10
+ #
11
+ # Related module: Sequel::FiberConcurrency
12
+
13
+ require 'fiber'
14
+
15
+ module Sequel
16
+ module FiberConcurrency
17
+ # Make the current concurrency primitive be Fiber.current.
18
+ def current
19
+ Fiber.current
20
+ end
21
+ end
22
+
23
+ extend FiberConcurrency
24
+ end
@@ -54,13 +54,6 @@ module Sequel
54
54
  db.instance_variable_set(:@indexes, {})
55
55
  end
56
56
 
57
- # Remove the index cache for the given schema name
58
- def remove_cached_schema(table)
59
- k = quote_schema_table(table)
60
- Sequel.synchronize{@indexes.delete(k)}
61
- super
62
- end
63
-
64
57
  # Dump the index cache to the filename given in Marshal format.
65
58
  def dump_index_cache(file)
66
59
  File.open(file, 'wb'){|f| f.write(Marshal.dump(@indexes))}
@@ -101,6 +94,15 @@ module Sequel
101
94
  Sequel.synchronize{@indexes[quoted_name] = result}
102
95
  result
103
96
  end
97
+
98
+ private
99
+
100
+ # Remove the index cache for the given schema name
101
+ def remove_cached_schema(table)
102
+ k = quote_schema_table(table)
103
+ Sequel.synchronize{@indexes.delete(k)}
104
+ super
105
+ end
104
106
  end
105
107
 
106
108
  Database.register_extension(:index_caching, IndexCaching)
@@ -20,6 +20,8 @@
20
20
  #
21
21
  module Sequel
22
22
  module Integer64
23
+ private
24
+
23
25
  # Use same type as used for :Bignum by default for generic integer value.
24
26
  def type_literal_generic_integer(column)
25
27
  type_literal_generic_bignum_symbol(column)
@@ -40,12 +40,20 @@ module Sequel
40
40
  def self.extended(db)
41
41
  db.instance_exec do
42
42
  extend_datasets(InetDatasetMethods)
43
- meth = IPAddr.method(:new)
44
- add_conversion_proc(869, meth)
45
- add_conversion_proc(650, meth)
43
+
44
+ if !defined?(SEQUEL_PG_VERSION_INTEGER) || SEQUEL_PG_VERSION_INTEGER >= 11300
45
+ # sequel_pg 1.13.0+ will use inet/cidr conversion procs, but doing so is
46
+ # slower, so don't add the conversion procs if using sequel_pg 1.13.0+.
47
+ meth = IPAddr.method(:new)
48
+ add_conversion_proc(869, meth)
49
+ add_conversion_proc(650, meth)
50
+ if respond_to?(:register_array_type)
51
+ register_array_type('inet', :oid=>1041, :scalar_oid=>869)
52
+ register_array_type('cidr', :oid=>651, :scalar_oid=>650)
53
+ end
54
+ end
55
+
46
56
  if respond_to?(:register_array_type)
47
- register_array_type('inet', :oid=>1041, :scalar_oid=>869)
48
- register_array_type('cidr', :oid=>651, :scalar_oid=>650)
49
57
  register_array_type('macaddr', :oid=>1040, :scalar_oid=>829)
50
58
  end
51
59
  @schema_type_classes[:ipaddr] = IPAddr
@@ -178,6 +178,8 @@ module Sequel
178
178
  end
179
179
 
180
180
  module IntervalDatasetMethods
181
+ private
182
+
181
183
  # Handle literalization of ActiveSupport::Duration objects, treating them as
182
184
  # PostgreSQL intervals.
183
185
  def literal_other_append(sql, v)
@@ -304,6 +304,8 @@ module Sequel
304
304
  end
305
305
 
306
306
  module DatasetMethods
307
+ private
308
+
307
309
  # Handle literalization of ruby Range objects, treating them as
308
310
  # PostgreSQL ranges.
309
311
  def literal_other_append(sql, v)
@@ -15,6 +15,8 @@
15
15
  module Sequel
16
16
  module Postgres
17
17
  module Timestamptz
18
+ private
19
+
18
20
  # Use timestamptz by default for generic timestamp value.
19
21
  def type_literal_generic_datetime(column)
20
22
  :timestamptz
@@ -0,0 +1,72 @@
1
+ # frozen-string-literal: true
2
+ #
3
+ # The run_transaction_hooks extension allows for running after_commit or
4
+ # after_rollback extensions before commit or rollback. It then removes
5
+ # the hook after running it, so it will not be run twice.
6
+ #
7
+ # This extension should only be used in transactional tests where the
8
+ # transaction always rolls back, to test the behavior of the after_commit
9
+ # and after_rollback hooks. Any other usage is probably a bad idea.
10
+ #
11
+ # Example:
12
+ #
13
+ # DB.extension :run_transaction_hooks
14
+ # x = 1
15
+ # DB.transaction(rollback: :always) do
16
+ # DB.after_rollback{x = 3}
17
+ # DB.after_commit{x = 2}
18
+ #
19
+ # x # => 1
20
+ # DB.run_after_rollback_hooks
21
+ # x # => 3
22
+ # DB.run_after_commit_hooks
23
+ # x # => 2
24
+ # end
25
+ # x # => 2
26
+
27
+ #
28
+ class Sequel::Database
29
+ module RunTransactionHooks
30
+ # Run all savepoint and transaction after_commit hooks for the current transaction,
31
+ # and remove the hooks after running them.
32
+ # Options:
33
+ # :server :: The server/shard to use.
34
+ def run_after_commit_hooks(opts=OPTS)
35
+ _run_transaction_hooks(:after_commit, opts)
36
+ end
37
+
38
+ # Run all savepoint and transaction after_rollback hooks for the current transaction,
39
+ # and remove the hooks after running them.
40
+ # Options:
41
+ # :server :: The server/shard to use.
42
+ def run_after_rollback_hooks(opts=OPTS)
43
+ _run_transaction_hooks(:after_rollback, opts)
44
+ end
45
+
46
+ private
47
+
48
+ def _run_transaction_hooks(type, opts)
49
+ synchronize(opts[:server]) do |conn|
50
+ unless h = _trans(conn)
51
+ raise Error, "Cannot call run_#{type}_hooks outside of a transaction"
52
+ end
53
+
54
+ if hooks = h[type]
55
+ hooks.each(&:call)
56
+ hooks.clear
57
+ end
58
+
59
+ if (savepoints = h[:savepoints])
60
+ savepoints.each do |savepoint|
61
+ if hooks = savepoint[type]
62
+ hooks.each(&:call)
63
+ hooks.clear
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
70
+
71
+ register_extension(:run_transaction_hooks, RunTransactionHooks)
72
+ end
@@ -143,13 +143,13 @@ module Sequel
143
143
 
144
144
  # Make the given server the new default server for the current thread.
145
145
  def set_default_server(default_server, read_only_server=default_server)
146
- sync{(@default_servers[Thread.current] ||= [])} << [default_server, read_only_server]
146
+ sync{(@default_servers[Sequel.current] ||= [])} << [default_server, read_only_server]
147
147
  end
148
148
 
149
149
  # Remove the current default server for the current thread, restoring the
150
150
  # previous default server.
151
151
  def clear_default_server
152
- t = Thread.current
152
+ t = Sequel.current
153
153
  a = sync{@default_servers[t]}
154
154
  a.pop
155
155
  sync{@default_servers.delete(t)} if a.empty?
@@ -157,7 +157,7 @@ module Sequel
157
157
 
158
158
  # Use the server given to with_server for the given thread, if appropriate.
159
159
  def pick_server(server)
160
- a = sync{@default_servers[Thread.current]}
160
+ a = sync{@default_servers[Sequel.current]}
161
161
  if !a || a.empty?
162
162
  super
163
163
  else
@@ -460,47 +460,6 @@ module Sequel
460
460
  super
461
461
  end
462
462
 
463
- # If possible, set the dataset for the model subclass as soon as it
464
- # is created. Also, make sure the inherited class instance variables
465
- # are copied into the subclass.
466
- #
467
- # Sequel queries the database to get schema information as soon as
468
- # a model class is created:
469
- #
470
- # class Artist < Sequel::Model # Causes schema query
471
- # end
472
- def inherited(subclass)
473
- super
474
- ivs = subclass.instance_variables
475
- inherited_instance_variables.each do |iv, dup|
476
- next if ivs.include?(iv)
477
- if (sup_class_value = instance_variable_get(iv)) && dup
478
- sup_class_value = case dup
479
- when :dup
480
- sup_class_value.dup
481
- when :hash_dup
482
- h = {}
483
- sup_class_value.each{|k,v| h[k] = v.dup}
484
- h
485
- when Proc
486
- dup.call(sup_class_value)
487
- else
488
- raise Error, "bad inherited instance variable type: #{dup.inspect}"
489
- end
490
- end
491
- subclass.instance_variable_set(iv, sup_class_value)
492
- end
493
-
494
- unless ivs.include?(:@dataset)
495
- if @dataset && self != Model
496
- subclass.set_dataset(@dataset.clone, :inherited=>true)
497
- elsif (n = subclass.name) && !n.to_s.empty?
498
- db
499
- subclass.set_dataset(subclass.implicit_table_name)
500
- end
501
- end
502
- end
503
-
504
463
  # Returns the implicit table name for the model class, which is the demodulized,
505
464
  # underscored, pluralized name of the class.
506
465
  #
@@ -515,12 +474,6 @@ module Sequel
515
474
  call(values)
516
475
  end
517
476
 
518
- # Clear the setter_methods cache when a setter method is added.
519
- def method_added(meth)
520
- clear_setter_methods_cache if meth.to_s.end_with?('=')
521
- super
522
- end
523
-
524
477
  # Mark the model as not having a primary key. Not having a primary key
525
478
  # can cause issues, among which is that you won't be able to update records.
526
479
  #
@@ -854,6 +807,47 @@ module Sequel
854
807
  meths
855
808
  end
856
809
 
810
+ # If possible, set the dataset for the model subclass as soon as it
811
+ # is created. Also, make sure the inherited class instance variables
812
+ # are copied into the subclass.
813
+ #
814
+ # Sequel queries the database to get schema information as soon as
815
+ # a model class is created:
816
+ #
817
+ # class Artist < Sequel::Model # Causes schema query
818
+ # end
819
+ def inherited(subclass)
820
+ super
821
+ ivs = subclass.instance_variables
822
+ inherited_instance_variables.each do |iv, dup|
823
+ next if ivs.include?(iv)
824
+ if (sup_class_value = instance_variable_get(iv)) && dup
825
+ sup_class_value = case dup
826
+ when :dup
827
+ sup_class_value.dup
828
+ when :hash_dup
829
+ h = {}
830
+ sup_class_value.each{|k,v| h[k] = v.dup}
831
+ h
832
+ when Proc
833
+ dup.call(sup_class_value)
834
+ else
835
+ raise Error, "bad inherited instance variable type: #{dup.inspect}"
836
+ end
837
+ end
838
+ subclass.instance_variable_set(iv, sup_class_value)
839
+ end
840
+
841
+ unless ivs.include?(:@dataset)
842
+ if @dataset && self != Model
843
+ subclass.set_dataset(@dataset.clone, :inherited=>true)
844
+ elsif (n = subclass.name) && !n.to_s.empty?
845
+ db
846
+ subclass.set_dataset(subclass.implicit_table_name)
847
+ end
848
+ end
849
+ end
850
+
857
851
  # A hash of instance variables to automatically set up in subclasses.
858
852
  # Keys are instance variable symbols, values should be:
859
853
  # nil :: Assign directly from superclass to subclass (frozen objects)
@@ -908,6 +902,12 @@ module Sequel
908
902
  opts[:class_name] ||= '::' + ((name || '').split("::")[0..-2] + [camelize(default)]).join('::')
909
903
  end
910
904
 
905
+ # Clear the setter_methods cache when a setter method is added.
906
+ def method_added(meth)
907
+ clear_setter_methods_cache if meth.to_s.end_with?('=')
908
+ super
909
+ end
910
+
911
911
  # Module that the class includes that holds methods the class adds for column accessors and
912
912
  # associations so that the methods can be overridden with +super+.
913
913
  def overridable_methods_module
@@ -1718,6 +1718,7 @@ module Sequel
1718
1718
 
1719
1719
  # The values hash to use when inserting a new record.
1720
1720
  alias _insert_values values
1721
+ private :_insert_values
1721
1722
 
1722
1723
  # Refresh using a particular dataset, used inside save to make sure the same server
1723
1724
  # is used for reading newly inserted values from the database
@@ -40,6 +40,7 @@ module Sequel
40
40
  mod.send(:define_method, :inherited_instance_variables) do ||
41
41
  super().merge!(hash)
42
42
  end
43
+ mod.send(:private, :inherited_instance_variables)
43
44
  end
44
45
 
45
46
  # Add method to +mod+ that overrides set_dataset to call the method afterward.
@@ -36,6 +36,8 @@ module Sequel
36
36
  # Album.plugin :association_lazy_eager_option
37
37
  module AssociationLazyEagerOption
38
38
  module InstanceMethods
39
+ private
40
+
39
41
  # Return a dataset for the association after applying any dynamic callback.
40
42
  def _associated_dataset(opts, dynamic_opts)
41
43
  ds = super
@@ -39,6 +39,8 @@ module Sequel
39
39
  # Album.plugin :association_multi_add_remove
40
40
  module AssociationMultiAddRemove
41
41
  module ClassMethods
42
+ private
43
+
42
44
  # Define the methods use to add/remove/set multiple associated objects
43
45
  # in a single method call.
44
46
  def def_association_instance_methods(opts)
@@ -109,6 +109,8 @@ module Sequel
109
109
 
110
110
  Plugins.inherited_instance_variables(self, :@association_proxy_to_dataset=>nil)
111
111
 
112
+ private
113
+
112
114
  # Changes the association method to return a proxy instead of the associated objects
113
115
  # directly.
114
116
  def def_association_method(opts)
@@ -31,7 +31,10 @@ module Sequel
31
31
  # Create boolean subset methods for each boolean column.
32
32
  def self.configure(model, &block)
33
33
  model.instance_exec do
34
- define_singleton_method(:boolean_subset_args, &block) if block
34
+ if block
35
+ define_singleton_method(:boolean_subset_args, &block)
36
+ singleton_class.send(:private, :boolean_subset_args)
37
+ end
35
38
  create_boolean_subsets if @dataset
36
39
  end
37
40
  end
@@ -278,6 +278,27 @@ module Sequel
278
278
 
279
279
  Plugins.inherited_instance_variables(self, :@cti_models=>nil, :@cti_tables=>nil, :@cti_table_columns=>nil, :@cti_instance_dataset=>nil, :@cti_table_map=>nil, :@cti_alias=>nil, :@cti_ignore_subclass_columns=>nil, :@cti_qualify_tables=>nil)
280
280
 
281
+ # The table name for the current model class's main table.
282
+ def table_name
283
+ if cti_tables && cti_tables.length > 1
284
+ @cti_alias
285
+ else
286
+ super
287
+ end
288
+ end
289
+
290
+ # The name of the most recently joined table.
291
+ def cti_table_name
292
+ cti_tables ? cti_tables.last : dataset.first_source_alias
293
+ end
294
+
295
+ # The model class for the given key value.
296
+ def sti_class_from_key(key)
297
+ sti_class(sti_model_map[key])
298
+ end
299
+
300
+ private
301
+
281
302
  def inherited(subclass)
282
303
  ds = sti_dataset
283
304
 
@@ -340,27 +361,6 @@ module Sequel
340
361
  end
341
362
  end
342
363
 
343
- # The table name for the current model class's main table.
344
- def table_name
345
- if cti_tables && cti_tables.length > 1
346
- @cti_alias
347
- else
348
- super
349
- end
350
- end
351
-
352
- # The name of the most recently joined table.
353
- def cti_table_name
354
- cti_tables ? cti_tables.last : dataset.first_source_alias
355
- end
356
-
357
- # The model class for the given key value.
358
- def sti_class_from_key(key)
359
- sti_class(sti_model_map[key])
360
- end
361
-
362
- private
363
-
364
364
  # If using a subquery for class table inheritance, also use a subquery
365
365
  # when setting subclass dataset.
366
366
  def sti_subclass_dataset(key)
@@ -383,11 +383,6 @@ module Sequel
383
383
  self
384
384
  end
385
385
 
386
- # Don't allow use of prepared statements.
387
- def use_prepared_statements_for?(type)
388
- false
389
- end
390
-
391
386
  # Set the sti_key column based on the sti_key_map.
392
387
  def before_validation
393
388
  if new? && (set = self[model.sti_key])
@@ -438,6 +433,11 @@ module Sequel
438
433
  end
439
434
  end
440
435
  end
436
+
437
+ # Don't allow use of prepared statements.
438
+ def use_prepared_statements_for?(type)
439
+ false
440
+ end
441
441
  end
442
442
  end
443
443
  end