sequel 5.31.0 → 5.32.0

Sign up to get free protection for your applications and to get access to all the features.
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