sequel 5.31.0 → 5.36.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/CHANGELOG +90 -0
- data/README.rdoc +1 -1
- data/doc/advanced_associations.rdoc +4 -4
- data/doc/association_basics.rdoc +10 -5
- data/doc/code_order.rdoc +12 -2
- data/doc/dataset_filtering.rdoc +2 -2
- data/doc/model_dataset_method_design.rdoc +1 -1
- data/doc/model_plugins.rdoc +1 -1
- data/doc/release_notes/5.32.0.txt +46 -0
- data/doc/release_notes/5.33.0.txt +24 -0
- data/doc/release_notes/5.34.0.txt +40 -0
- data/doc/release_notes/5.35.0.txt +56 -0
- data/doc/release_notes/5.36.0.txt +60 -0
- data/doc/testing.rdoc +1 -0
- data/doc/validations.rdoc +1 -1
- data/lib/sequel/adapters/odbc.rb +4 -6
- data/lib/sequel/adapters/oracle.rb +2 -1
- data/lib/sequel/adapters/shared/access.rb +6 -6
- data/lib/sequel/adapters/shared/mssql.rb +19 -9
- data/lib/sequel/adapters/shared/mysql.rb +9 -9
- data/lib/sequel/adapters/shared/oracle.rb +28 -22
- data/lib/sequel/adapters/shared/postgres.rb +57 -9
- data/lib/sequel/adapters/shared/sqlanywhere.rb +9 -9
- data/lib/sequel/adapters/shared/sqlite.rb +14 -3
- data/lib/sequel/adapters/tinytds.rb +1 -0
- data/lib/sequel/adapters/utils/mysql_mysql2.rb +1 -0
- data/lib/sequel/connection_pool/sharded_single.rb +4 -1
- data/lib/sequel/connection_pool/sharded_threaded.rb +12 -12
- data/lib/sequel/connection_pool/single.rb +1 -1
- data/lib/sequel/connection_pool/threaded.rb +2 -2
- data/lib/sequel/core.rb +318 -314
- data/lib/sequel/database/connecting.rb +1 -1
- data/lib/sequel/database/misc.rb +16 -10
- data/lib/sequel/database/query.rb +3 -1
- data/lib/sequel/database/schema_generator.rb +0 -1
- data/lib/sequel/database/schema_methods.rb +15 -16
- data/lib/sequel/database/transactions.rb +8 -5
- data/lib/sequel/dataset/placeholder_literalizer.rb +3 -7
- data/lib/sequel/dataset/query.rb +5 -4
- data/lib/sequel/deprecated.rb +3 -1
- data/lib/sequel/exceptions.rb +2 -0
- data/lib/sequel/extensions/_pretty_table.rb +1 -2
- data/lib/sequel/extensions/columns_introspection.rb +1 -2
- data/lib/sequel/extensions/connection_expiration.rb +2 -2
- data/lib/sequel/extensions/connection_validator.rb +2 -2
- data/lib/sequel/extensions/core_refinements.rb +2 -0
- data/lib/sequel/extensions/duplicate_columns_handler.rb +2 -0
- data/lib/sequel/extensions/fiber_concurrency.rb +24 -0
- data/lib/sequel/extensions/index_caching.rb +9 -7
- data/lib/sequel/extensions/integer64.rb +2 -0
- data/lib/sequel/extensions/migration.rb +1 -1
- data/lib/sequel/extensions/pg_array_ops.rb +4 -0
- data/lib/sequel/extensions/pg_enum.rb +2 -0
- data/lib/sequel/extensions/pg_extended_date_support.rb +1 -1
- data/lib/sequel/extensions/pg_hstore_ops.rb +2 -0
- data/lib/sequel/extensions/pg_inet.rb +15 -5
- data/lib/sequel/extensions/pg_interval.rb +2 -0
- data/lib/sequel/extensions/pg_json_ops.rb +46 -2
- data/lib/sequel/extensions/pg_range.rb +5 -7
- data/lib/sequel/extensions/pg_range_ops.rb +2 -0
- data/lib/sequel/extensions/pg_row.rb +0 -1
- data/lib/sequel/extensions/pg_timestamptz.rb +2 -0
- data/lib/sequel/extensions/query.rb +1 -0
- data/lib/sequel/extensions/run_transaction_hooks.rb +72 -0
- data/lib/sequel/extensions/s.rb +2 -0
- data/lib/sequel/extensions/server_block.rb +3 -3
- data/lib/sequel/extensions/symbol_aref_refinement.rb +2 -0
- data/lib/sequel/extensions/symbol_as_refinement.rb +2 -0
- data/lib/sequel/extensions/to_dot.rb +9 -3
- data/lib/sequel/model.rb +3 -1
- data/lib/sequel/model/associations.rb +54 -25
- data/lib/sequel/model/base.rb +60 -51
- data/lib/sequel/model/plugins.rb +4 -3
- data/lib/sequel/plugins/association_lazy_eager_option.rb +2 -0
- data/lib/sequel/plugins/association_multi_add_remove.rb +2 -0
- data/lib/sequel/plugins/association_pks.rb +60 -18
- data/lib/sequel/plugins/association_proxies.rb +3 -0
- data/lib/sequel/plugins/blacklist_security.rb +1 -2
- data/lib/sequel/plugins/boolean_subsets.rb +4 -1
- data/lib/sequel/plugins/class_table_inheritance.rb +28 -28
- data/lib/sequel/plugins/csv_serializer.rb +2 -0
- data/lib/sequel/plugins/dirty.rb +13 -13
- data/lib/sequel/plugins/forbid_lazy_load.rb +2 -0
- data/lib/sequel/plugins/instance_specific_default.rb +113 -0
- data/lib/sequel/plugins/json_serializer.rb +3 -7
- data/lib/sequel/plugins/lazy_attributes.rb +1 -1
- data/lib/sequel/plugins/pg_array_associations.rb +2 -3
- data/lib/sequel/plugins/prepared_statements.rb +5 -11
- data/lib/sequel/plugins/prepared_statements_safe.rb +1 -3
- data/lib/sequel/plugins/rcte_tree.rb +10 -16
- data/lib/sequel/plugins/single_table_inheritance.rb +15 -15
- data/lib/sequel/plugins/string_stripper.rb +1 -1
- data/lib/sequel/plugins/subclasses.rb +2 -0
- data/lib/sequel/plugins/validation_class_methods.rb +5 -1
- data/lib/sequel/timezones.rb +6 -4
- data/lib/sequel/version.rb +1 -1
- metadata +15 -2
data/lib/sequel/model/base.rb
CHANGED
|
@@ -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
|
#
|
|
@@ -538,6 +491,11 @@ module Sequel
|
|
|
538
491
|
# the module using a the camelized plugin name under Sequel::Plugins.
|
|
539
492
|
def plugin(plugin, *args, &block)
|
|
540
493
|
m = plugin.is_a?(Module) ? plugin : plugin_module(plugin)
|
|
494
|
+
|
|
495
|
+
if !m.respond_to?(:apply) && !m.respond_to?(:configure) && (!args.empty? || block)
|
|
496
|
+
Deprecation.deprecate("Plugin #{plugin} accepts no arguments or block, and passing arguments/block to it", "Remove arguments and block when loading the plugin")
|
|
497
|
+
end
|
|
498
|
+
|
|
541
499
|
unless @plugins.include?(m)
|
|
542
500
|
@plugins << m
|
|
543
501
|
m.apply(self, *args, &block) if m.respond_to?(:apply)
|
|
@@ -547,8 +505,10 @@ module Sequel
|
|
|
547
505
|
dataset_extend(m::DatasetMethods, :create_class_methods=>false)
|
|
548
506
|
end
|
|
549
507
|
end
|
|
508
|
+
|
|
550
509
|
m.configure(self, *args, &block) if m.respond_to?(:configure)
|
|
551
510
|
end
|
|
511
|
+
ruby2_keywords(:plugin) if respond_to?(:ruby2_keywords, true)
|
|
552
512
|
|
|
553
513
|
# Returns primary key attribute hash. If using a composite primary key
|
|
554
514
|
# value such be an array with values for each primary key in the correct
|
|
@@ -640,7 +600,7 @@ module Sequel
|
|
|
640
600
|
@columns = superclass.instance_variable_get(:@columns)
|
|
641
601
|
@db_schema = superclass.instance_variable_get(:@db_schema)
|
|
642
602
|
else
|
|
643
|
-
@dataset = @dataset.with_extend(*@dataset_method_modules.reverse)
|
|
603
|
+
@dataset = @dataset.with_extend(*@dataset_method_modules.reverse)
|
|
644
604
|
@db_schema = get_db_schema
|
|
645
605
|
end
|
|
646
606
|
|
|
@@ -679,8 +639,7 @@ module Sequel
|
|
|
679
639
|
|
|
680
640
|
# Cache of setter methods to allow by default, in order to speed up mass assignment.
|
|
681
641
|
def setter_methods
|
|
682
|
-
|
|
683
|
-
@setter_methods = get_setter_methods
|
|
642
|
+
@setter_methods || (@setter_methods = get_setter_methods)
|
|
684
643
|
end
|
|
685
644
|
|
|
686
645
|
# Returns name of primary table for the dataset. If the table for the dataset
|
|
@@ -798,6 +757,7 @@ module Sequel
|
|
|
798
757
|
else
|
|
799
758
|
define_singleton_method(meth){|*args, &block| dataset.public_send(meth, *args, &block)}
|
|
800
759
|
end
|
|
760
|
+
singleton_class.send(:ruby2_keywords, meth) if respond_to?(:ruby2_keywords, true)
|
|
801
761
|
end
|
|
802
762
|
|
|
803
763
|
# Get the schema from the database, fall back on checking the columns
|
|
@@ -854,6 +814,46 @@ module Sequel
|
|
|
854
814
|
meths
|
|
855
815
|
end
|
|
856
816
|
|
|
817
|
+
# If possible, set the dataset for the model subclass as soon as it
|
|
818
|
+
# is created. Also, make sure the inherited class instance variables
|
|
819
|
+
# are copied into the subclass.
|
|
820
|
+
#
|
|
821
|
+
# Sequel queries the database to get schema information as soon as
|
|
822
|
+
# a model class is created:
|
|
823
|
+
#
|
|
824
|
+
# class Artist < Sequel::Model # Causes schema query
|
|
825
|
+
# end
|
|
826
|
+
def inherited(subclass)
|
|
827
|
+
super
|
|
828
|
+
ivs = subclass.instance_variables
|
|
829
|
+
inherited_instance_variables.each do |iv, dup|
|
|
830
|
+
if (sup_class_value = instance_variable_get(iv)) && dup
|
|
831
|
+
sup_class_value = case dup
|
|
832
|
+
when :dup
|
|
833
|
+
sup_class_value.dup
|
|
834
|
+
when :hash_dup
|
|
835
|
+
h = {}
|
|
836
|
+
sup_class_value.each{|k,v| h[k] = v.dup}
|
|
837
|
+
h
|
|
838
|
+
when Proc
|
|
839
|
+
dup.call(sup_class_value)
|
|
840
|
+
else
|
|
841
|
+
raise Error, "bad inherited instance variable type: #{dup.inspect}"
|
|
842
|
+
end
|
|
843
|
+
end
|
|
844
|
+
subclass.instance_variable_set(iv, sup_class_value)
|
|
845
|
+
end
|
|
846
|
+
|
|
847
|
+
unless ivs.include?(:@dataset)
|
|
848
|
+
if @dataset && self != Model
|
|
849
|
+
subclass.set_dataset(@dataset.clone, :inherited=>true)
|
|
850
|
+
elsif (n = subclass.name) && !n.to_s.empty?
|
|
851
|
+
db
|
|
852
|
+
subclass.set_dataset(subclass.implicit_table_name)
|
|
853
|
+
end
|
|
854
|
+
end
|
|
855
|
+
end
|
|
856
|
+
|
|
857
857
|
# A hash of instance variables to automatically set up in subclasses.
|
|
858
858
|
# Keys are instance variable symbols, values should be:
|
|
859
859
|
# nil :: Assign directly from superclass to subclass (frozen objects)
|
|
@@ -908,6 +908,12 @@ module Sequel
|
|
|
908
908
|
opts[:class_name] ||= '::' + ((name || '').split("::")[0..-2] + [camelize(default)]).join('::')
|
|
909
909
|
end
|
|
910
910
|
|
|
911
|
+
# Clear the setter_methods cache when a setter method is added.
|
|
912
|
+
def method_added(meth)
|
|
913
|
+
clear_setter_methods_cache if meth.to_s.end_with?('=')
|
|
914
|
+
super
|
|
915
|
+
end
|
|
916
|
+
|
|
911
917
|
# Module that the class includes that holds methods the class adds for column accessors and
|
|
912
918
|
# associations so that the methods can be overridden with +super+.
|
|
913
919
|
def overridable_methods_module
|
|
@@ -1116,7 +1122,7 @@ module Sequel
|
|
|
1116
1122
|
when nil
|
|
1117
1123
|
return false
|
|
1118
1124
|
when Array
|
|
1119
|
-
return false if
|
|
1125
|
+
return false if pkv.any?(&:nil?)
|
|
1120
1126
|
end
|
|
1121
1127
|
|
|
1122
1128
|
(obj.class == model) && (obj.pk == pkv)
|
|
@@ -1718,6 +1724,7 @@ module Sequel
|
|
|
1718
1724
|
|
|
1719
1725
|
# The values hash to use when inserting a new record.
|
|
1720
1726
|
alias _insert_values values
|
|
1727
|
+
private :_insert_values
|
|
1721
1728
|
|
|
1722
1729
|
# Refresh using a particular dataset, used inside save to make sure the same server
|
|
1723
1730
|
# is used for reading newly inserted values from the database
|
|
@@ -2231,7 +2238,9 @@ module Sequel
|
|
|
2231
2238
|
plugin self
|
|
2232
2239
|
|
|
2233
2240
|
singleton_class.send(:undef_method, :dup, :clone, :initialize_copy)
|
|
2241
|
+
# :nocov:
|
|
2234
2242
|
if RUBY_VERSION >= '1.9.3'
|
|
2243
|
+
# :nocov:
|
|
2235
2244
|
singleton_class.send(:undef_method, :initialize_clone, :initialize_dup)
|
|
2236
2245
|
end
|
|
2237
2246
|
end
|
data/lib/sequel/model/plugins.rb
CHANGED
|
@@ -31,6 +31,7 @@ module Sequel
|
|
|
31
31
|
def self.def_dataset_methods(mod, meths)
|
|
32
32
|
Array(meths).each do |meth|
|
|
33
33
|
mod.class_eval("def #{meth}(*args, &block); dataset.#{meth}(*args, &block) end", __FILE__, __LINE__)
|
|
34
|
+
mod.send(:ruby2_keywords, meth) if respond_to?(:ruby2_keywords, true)
|
|
34
35
|
end
|
|
35
36
|
end
|
|
36
37
|
|
|
@@ -40,6 +41,7 @@ module Sequel
|
|
|
40
41
|
mod.send(:define_method, :inherited_instance_variables) do ||
|
|
41
42
|
super().merge!(hash)
|
|
42
43
|
end
|
|
44
|
+
mod.send(:private, :inherited_instance_variables)
|
|
43
45
|
end
|
|
44
46
|
|
|
45
47
|
# Add method to +mod+ that overrides set_dataset to call the method afterward.
|
|
@@ -148,9 +150,8 @@ module Sequel
|
|
|
148
150
|
required_args = arity
|
|
149
151
|
arity -= 1 if keyword == :required
|
|
150
152
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
end
|
|
153
|
+
# callable currently is always a non-lambda Proc
|
|
154
|
+
optional_args -= arity
|
|
154
155
|
|
|
155
156
|
[required_args, optional_args, rest, keyword]
|
|
156
157
|
end
|
|
@@ -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)
|
|
@@ -2,13 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
module Sequel
|
|
4
4
|
module Plugins
|
|
5
|
-
# The association_pks plugin adds association_pks and
|
|
6
|
-
# instance methods to the model class for each
|
|
7
|
-
#
|
|
8
|
-
#
|
|
5
|
+
# The association_pks plugin adds association_pks, association_pks=, and
|
|
6
|
+
# association_pks_dataset instance methods to the model class for each
|
|
7
|
+
# one_to_many and many_to_many association added. These methods allow for
|
|
8
|
+
# easily returning the primary keys of the associated objects, and easily
|
|
9
|
+
# modifying which objects are associated:
|
|
9
10
|
#
|
|
10
11
|
# Artist.one_to_many :albums
|
|
11
12
|
# artist = Artist[1]
|
|
13
|
+
# artist.album_pks_dataset
|
|
14
|
+
# # SELECT id FROM albums WHERE (albums.artist_id = 1)
|
|
15
|
+
#
|
|
12
16
|
# artist.album_pks # [1, 2, 3]
|
|
13
17
|
# artist.album_pks = [2, 4]
|
|
14
18
|
# artist.album_pks # [2, 4]
|
|
@@ -22,11 +26,18 @@ module Sequel
|
|
|
22
26
|
# This plugin makes modifications directly to the underlying tables,
|
|
23
27
|
# it does not create or return any model objects, and therefore does
|
|
24
28
|
# not call any callbacks. If you have any association callbacks,
|
|
25
|
-
# you probably should not use the setter methods.
|
|
29
|
+
# you probably should not use the setter methods this plugin adds.
|
|
26
30
|
#
|
|
27
31
|
# By default, changes to the association will not happen until the object
|
|
28
|
-
# is saved. However, using the delay_pks: false option, you can have
|
|
29
|
-
# changes made immediately when the association_pks setter method is called.
|
|
32
|
+
# is saved. However, using the delay_pks: false association option, you can have
|
|
33
|
+
# the changes made immediately when the association_pks setter method is called.
|
|
34
|
+
#
|
|
35
|
+
# By default, repeated calls to the association_pks getter method will not be
|
|
36
|
+
# cached, unless the setter method has been used and the delay_pks: false
|
|
37
|
+
# association option is not used. You can set caching of repeated calls to the
|
|
38
|
+
# association_pks getter method using the :cache_pks association option. You can
|
|
39
|
+
# pass the :refresh option when calling the getter method to ignore any existing
|
|
40
|
+
# cached values, similar to how the :refresh option works with associations.
|
|
30
41
|
#
|
|
31
42
|
# By default, if you pass a nil value to the setter, an exception will be raised.
|
|
32
43
|
# You can change this behavior by using the :association_pks_nil association option.
|
|
@@ -60,9 +71,11 @@ module Sequel
|
|
|
60
71
|
|
|
61
72
|
# Define a association_pks method using the block for the association reflection
|
|
62
73
|
def def_association_pks_methods(opts)
|
|
74
|
+
association_module_def(opts[:pks_dataset_method], &opts[:pks_dataset])
|
|
75
|
+
|
|
63
76
|
opts[:pks_getter_method] = :"#{singularize(opts[:name])}_pks_getter"
|
|
64
77
|
association_module_def(opts[:pks_getter_method], &opts[:pks_getter])
|
|
65
|
-
association_module_def(:"#{singularize(opts[:name])}_pks", opts){_association_pks_getter(opts)}
|
|
78
|
+
association_module_def(:"#{singularize(opts[:name])}_pks", opts){|dynamic_opts=OPTS| _association_pks_getter(opts, dynamic_opts)}
|
|
66
79
|
|
|
67
80
|
if opts[:pks_setter]
|
|
68
81
|
opts[:pks_setter_method] = :"#{singularize(opts[:name])}_pks_setter"
|
|
@@ -84,7 +97,9 @@ module Sequel
|
|
|
84
97
|
clpk = lpk.is_a?(Array)
|
|
85
98
|
crk = rk.is_a?(Array)
|
|
86
99
|
|
|
87
|
-
opts[:
|
|
100
|
+
dataset_method = opts[:pks_dataset_method] = :"#{singularize(opts[:name])}_pks_dataset"
|
|
101
|
+
|
|
102
|
+
opts[:pks_dataset] = if join_associated_table = opts[:association_pks_use_associated_table]
|
|
88
103
|
tname = opts[:join_table]
|
|
89
104
|
lambda do
|
|
90
105
|
cond = if clpk
|
|
@@ -95,16 +110,26 @@ module Sequel
|
|
|
95
110
|
rpk = opts.associated_class.primary_key
|
|
96
111
|
opts.associated_dataset.
|
|
97
112
|
naked.where(cond).
|
|
98
|
-
|
|
113
|
+
select(*Sequel.public_send(rpk.is_a?(Array) ? :deep_qualify : :qualify, opts.associated_class.table_name, rpk))
|
|
99
114
|
end
|
|
100
115
|
elsif clpk
|
|
101
116
|
lambda do
|
|
102
117
|
cond = lk.zip(lpk).map{|k, pk| [k, get_column_value(pk)]}
|
|
103
|
-
_join_table_dataset(opts).where(cond).
|
|
118
|
+
_join_table_dataset(opts).where(cond).select(*rk)
|
|
119
|
+
end
|
|
120
|
+
else
|
|
121
|
+
lambda do
|
|
122
|
+
_join_table_dataset(opts).where(lk=>get_column_value(lpk)).select(*rk)
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
opts[:pks_getter] = if join_associated_table = opts[:association_pks_use_associated_table]
|
|
127
|
+
lambda do
|
|
128
|
+
public_send(dataset_method).map(opts.associated_class.primary_key)
|
|
104
129
|
end
|
|
105
130
|
else
|
|
106
131
|
lambda do
|
|
107
|
-
|
|
132
|
+
public_send(dataset_method).map(rk)
|
|
108
133
|
end
|
|
109
134
|
end
|
|
110
135
|
|
|
@@ -145,8 +170,14 @@ module Sequel
|
|
|
145
170
|
|
|
146
171
|
key = opts[:key]
|
|
147
172
|
|
|
173
|
+
dataset_method = opts[:pks_dataset_method] = :"#{singularize(opts[:name])}_pks_dataset"
|
|
174
|
+
|
|
175
|
+
opts[:pks_dataset] = lambda do
|
|
176
|
+
public_send(opts[:dataset_method]).select(*opts.associated_class.primary_key)
|
|
177
|
+
end
|
|
178
|
+
|
|
148
179
|
opts[:pks_getter] = lambda do
|
|
149
|
-
public_send(
|
|
180
|
+
public_send(dataset_method).map(opts.associated_class.primary_key)
|
|
150
181
|
end
|
|
151
182
|
|
|
152
183
|
unless opts[:read_only]
|
|
@@ -207,12 +238,22 @@ module Sequel
|
|
|
207
238
|
# Return the primary keys of the associated objects.
|
|
208
239
|
# If the receiver is a new object, return any saved
|
|
209
240
|
# pks, or an empty array if no pks have been saved.
|
|
210
|
-
def _association_pks_getter(opts)
|
|
241
|
+
def _association_pks_getter(opts, dynamic_opts=OPTS)
|
|
242
|
+
do_cache = opts[:cache_pks]
|
|
211
243
|
delay = opts.fetch(:delay_pks, true)
|
|
212
|
-
|
|
244
|
+
cache_or_delay = do_cache || delay
|
|
245
|
+
|
|
246
|
+
if dynamic_opts[:refresh] && @_association_pks
|
|
247
|
+
@_association_pks.delete(opts[:name])
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
if new? && cache_or_delay
|
|
213
251
|
(@_association_pks ||= {})[opts[:name]] ||= []
|
|
214
|
-
elsif
|
|
252
|
+
elsif cache_or_delay && @_association_pks && (objs = @_association_pks[opts[:name]])
|
|
215
253
|
objs
|
|
254
|
+
elsif do_cache
|
|
255
|
+
# pks_getter_method is private
|
|
256
|
+
(@_association_pks ||= {})[opts[:name]] = send(opts[:pks_getter_method])
|
|
216
257
|
else
|
|
217
258
|
# pks_getter_method is private
|
|
218
259
|
send(opts[:pks_getter_method])
|
|
@@ -254,9 +295,10 @@ module Sequel
|
|
|
254
295
|
|
|
255
296
|
if primary_key.is_a?(Array)
|
|
256
297
|
if (cols = sch.values_at(*klass.primary_key)).all? && (convs = cols.map{|c| c[:type] == :integer}).all?
|
|
298
|
+
db = model.db
|
|
257
299
|
pks.map do |cpk|
|
|
258
|
-
cpk.
|
|
259
|
-
|
|
300
|
+
cpk.map do |pk|
|
|
301
|
+
db.typecast_value(:integer, pk)
|
|
260
302
|
end
|
|
261
303
|
end
|
|
262
304
|
else
|
|
@@ -99,6 +99,7 @@ module Sequel
|
|
|
99
99
|
end
|
|
100
100
|
v.public_send(meth, *args, &block)
|
|
101
101
|
end
|
|
102
|
+
ruby2_keywords(:method_missing) if respond_to?(:ruby2_keywords, true)
|
|
102
103
|
end
|
|
103
104
|
|
|
104
105
|
module ClassMethods
|
|
@@ -109,6 +110,8 @@ module Sequel
|
|
|
109
110
|
|
|
110
111
|
Plugins.inherited_instance_variables(self, :@association_proxy_to_dataset=>nil)
|
|
111
112
|
|
|
113
|
+
private
|
|
114
|
+
|
|
112
115
|
# Changes the association method to return a proxy instead of the associated objects
|
|
113
116
|
# directly.
|
|
114
117
|
def def_association_method(opts)
|
|
@@ -58,8 +58,7 @@ module Sequel
|
|
|
58
58
|
# restricted_columns.
|
|
59
59
|
def get_setter_methods
|
|
60
60
|
meths = super
|
|
61
|
-
|
|
62
|
-
if (!defined?(::Sequel::Plugins::WhitelistSecurity) || !plugins.include?(::Sequel::Plugins::WhitelistSecurity) || !allowed_columns) && restricted_columns
|
|
61
|
+
if (!defined?(::Sequel::Plugins::WhitelistSecurity::ClassMethods) || !is_a?(::Sequel::Plugins::WhitelistSecurity::ClassMethods) || !allowed_columns) && restricted_columns
|
|
63
62
|
meths -= restricted_columns.map{|x| "#{x}="}
|
|
64
63
|
end
|
|
65
64
|
meths
|
|
@@ -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
|
-
|
|
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.last
|
|
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
|
|
|
@@ -289,7 +310,7 @@ module Sequel
|
|
|
289
310
|
# Set table if this is a class table inheritance
|
|
290
311
|
table = nil
|
|
291
312
|
columns = nil
|
|
292
|
-
if
|
|
313
|
+
if n = subclass.name
|
|
293
314
|
if table = cti_table_map[n.to_sym]
|
|
294
315
|
columns = db.schema(table).map(&:first)
|
|
295
316
|
else
|
|
@@ -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])
|
|
@@ -422,7 +417,7 @@ module Sequel
|
|
|
422
417
|
@values[primary_key] ||= nid
|
|
423
418
|
end
|
|
424
419
|
end
|
|
425
|
-
|
|
420
|
+
@values[primary_key]
|
|
426
421
|
end
|
|
427
422
|
|
|
428
423
|
# Update rows in all backing tables, using the columns in each table.
|
|
@@ -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
|