sequel 4.31.0 → 4.32.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +24 -0
- data/Rakefile +17 -15
- data/doc/association_basics.rdoc +7 -3
- data/doc/opening_databases.rdoc +7 -0
- data/doc/release_notes/4.32.0.txt +132 -0
- data/doc/schema_modification.rdoc +1 -1
- data/doc/security.rdoc +70 -26
- data/doc/testing.rdoc +1 -0
- data/lib/sequel/adapters/jdbc.rb +2 -1
- data/lib/sequel/adapters/postgres.rb +3 -4
- data/lib/sequel/adapters/shared/mysql.rb +14 -1
- data/lib/sequel/adapters/shared/sqlite.rb +2 -2
- data/lib/sequel/extensions/_pretty_table.rb +2 -0
- data/lib/sequel/extensions/arbitrary_servers.rb +2 -0
- data/lib/sequel/extensions/columns_introspection.rb +2 -0
- data/lib/sequel/extensions/connection_validator.rb +2 -0
- data/lib/sequel/extensions/constraint_validations.rb +2 -0
- data/lib/sequel/extensions/core_extensions.rb +1 -5
- data/lib/sequel/extensions/current_datetime_timestamp.rb +2 -0
- data/lib/sequel/extensions/dataset_source_alias.rb +2 -0
- data/lib/sequel/extensions/date_arithmetic.rb +2 -0
- data/lib/sequel/extensions/empty_array_consider_nulls.rb +3 -1
- data/lib/sequel/extensions/error_sql.rb +2 -0
- data/lib/sequel/extensions/eval_inspect.rb +2 -0
- data/lib/sequel/extensions/filter_having.rb +2 -0
- data/lib/sequel/extensions/from_block.rb +2 -0
- data/lib/sequel/extensions/graph_each.rb +2 -0
- data/lib/sequel/extensions/hash_aliases.rb +2 -0
- data/lib/sequel/extensions/inflector.rb +2 -0
- data/lib/sequel/extensions/looser_typecasting.rb +3 -1
- data/lib/sequel/extensions/meta_def.rb +2 -0
- data/lib/sequel/extensions/migration.rb +4 -0
- data/lib/sequel/extensions/mssql_emulate_lateral_with_apply.rb +2 -0
- data/lib/sequel/extensions/named_timezones.rb +2 -0
- data/lib/sequel/extensions/no_auto_literal_strings.rb +84 -0
- data/lib/sequel/extensions/null_dataset.rb +2 -0
- data/lib/sequel/extensions/pagination.rb +2 -0
- data/lib/sequel/extensions/pg_array.rb +2 -4
- data/lib/sequel/extensions/pg_array_ops.rb +2 -0
- data/lib/sequel/extensions/pg_enum.rb +2 -0
- data/lib/sequel/extensions/pg_hstore.rb +2 -4
- data/lib/sequel/extensions/pg_hstore_ops.rb +2 -0
- data/lib/sequel/extensions/pg_inet.rb +2 -4
- data/lib/sequel/extensions/pg_inet_ops.rb +2 -0
- data/lib/sequel/extensions/pg_interval.rb +2 -4
- data/lib/sequel/extensions/pg_json.rb +4 -4
- data/lib/sequel/extensions/pg_json_ops.rb +3 -0
- data/lib/sequel/extensions/pg_loose_count.rb +2 -0
- data/lib/sequel/extensions/pg_range.rb +2 -4
- data/lib/sequel/extensions/pg_range_ops.rb +2 -0
- data/lib/sequel/extensions/pg_row.rb +2 -4
- data/lib/sequel/extensions/pg_row_ops.rb +2 -0
- data/lib/sequel/extensions/pg_static_cache_updater.rb +2 -0
- data/lib/sequel/extensions/pretty_table.rb +2 -0
- data/lib/sequel/extensions/query.rb +3 -0
- data/lib/sequel/extensions/query_literals.rb +7 -5
- data/lib/sequel/extensions/round_timestamps.rb +4 -3
- data/lib/sequel/extensions/schema_caching.rb +2 -0
- data/lib/sequel/extensions/schema_dumper.rb +2 -0
- data/lib/sequel/extensions/select_remove.rb +2 -0
- data/lib/sequel/extensions/sequel_3_dataset_methods.rb +2 -0
- data/lib/sequel/extensions/server_block.rb +3 -0
- data/lib/sequel/extensions/set_overrides.rb +2 -0
- data/lib/sequel/extensions/split_array_nil.rb +2 -0
- data/lib/sequel/extensions/thread_local_timezones.rb +2 -0
- data/lib/sequel/extensions/to_dot.rb +2 -0
- data/lib/sequel/model/associations.rb +95 -55
- data/lib/sequel/plugins/association_pks.rb +58 -33
- data/lib/sequel/plugins/eager_each.rb +22 -0
- data/lib/sequel/plugins/pg_typecast_on_load.rb +3 -2
- data/lib/sequel/plugins/tactical_eager_loading.rb +44 -3
- data/lib/sequel/version.rb +2 -2
- data/spec/adapters/mysql_spec.rb +34 -6
- data/spec/adapters/oracle_spec.rb +1 -1
- data/spec/bin_spec.rb +2 -2
- data/spec/core/dataset_spec.rb +7 -0
- data/spec/extensions/association_pks_spec.rb +38 -0
- data/spec/extensions/class_table_inheritance_spec.rb +24 -0
- data/spec/extensions/eager_each_spec.rb +25 -1
- data/spec/extensions/no_auto_literal_strings_spec.rb +65 -0
- data/spec/extensions/pg_range_spec.rb +1 -0
- data/spec/extensions/spec_helper.rb +5 -5
- data/spec/extensions/tactical_eager_loading_spec.rb +71 -17
- data/spec/integration/associations_test.rb +77 -62
- data/spec/integration/dataset_test.rb +3 -3
- data/spec/integration/plugin_test.rb +22 -0
- data/spec/integration/prepared_statement_test.rb +8 -8
- data/spec/integration/spec_helper.rb +4 -0
- data/spec/model/association_reflection_spec.rb +30 -0
- data/spec/model/associations_spec.rb +177 -16
- metadata +6 -2
@@ -80,11 +80,9 @@
|
|
80
80
|
# See the {schema modification guide}[rdoc-ref:doc/schema_modification.rdoc]
|
81
81
|
# for details on using hstore columns in CREATE/ALTER TABLE statements.
|
82
82
|
#
|
83
|
-
# If you are not using the native postgres or jdbc/postgresql adapters and are using hstore
|
84
|
-
# types as model column values you probably should use the
|
85
|
-
# pg_typecast_on_load plugin if the column values are returned as a string.
|
86
|
-
#
|
87
83
|
# This extension requires the delegate and strscan libraries.
|
84
|
+
#
|
85
|
+
# Related module: Sequel::Postgres::HStore
|
88
86
|
|
89
87
|
require 'delegate'
|
90
88
|
require 'strscan'
|
@@ -75,6 +75,8 @@
|
|
75
75
|
# pg_hstore extension is loaded. Methods representing expressions that return
|
76
76
|
# PostgreSQL arrays will have the returned expression automatically wrapped in a
|
77
77
|
# Postgres::ArrayOp if the pg_array_ops extension is loaded.
|
78
|
+
#
|
79
|
+
# Related module: Sequel::Postgres::HStoreOp
|
78
80
|
|
79
81
|
#
|
80
82
|
module Sequel
|
@@ -11,10 +11,6 @@
|
|
11
11
|
#
|
12
12
|
# DB.extension :pg_inet
|
13
13
|
#
|
14
|
-
# If you are not using the native postgres or jdbc/postgresql adapters and are using inet/cidr
|
15
|
-
# types as model column values you probably should use the
|
16
|
-
# pg_typecast_on_load plugin if the column values are returned as a string.
|
17
|
-
#
|
18
14
|
# This extension integrates with the pg_array extension. If you plan
|
19
15
|
# to use the inet[] or cidr[] types, load the pg_array extension before
|
20
16
|
# the pg_inet extension:
|
@@ -29,6 +25,8 @@
|
|
29
25
|
#
|
30
26
|
# See the {schema modification guide}[rdoc-ref:doc/schema_modification.rdoc]
|
31
27
|
# for details on using inet/cidr columns in CREATE/ALTER TABLE statements.
|
28
|
+
#
|
29
|
+
# Related module: Sequel::Postgres::InetDatabaseMethods
|
32
30
|
|
33
31
|
require 'ipaddr'
|
34
32
|
Sequel.require 'adapters/utils/pg_types'
|
@@ -17,10 +17,6 @@
|
|
17
17
|
#
|
18
18
|
# DB.extension :pg_interval
|
19
19
|
#
|
20
|
-
# If you are not using the native postgres or jdbc/postgresql adapters and are using interval
|
21
|
-
# types as model column values you probably should use the
|
22
|
-
# pg_typecast_on_load plugin if the column values are returned as a string.
|
23
|
-
#
|
24
20
|
# This extension integrates with the pg_array extension. If you plan
|
25
21
|
# to use arrays of interval types, load the pg_array extension before the
|
26
22
|
# pg_interval extension:
|
@@ -36,6 +32,8 @@
|
|
36
32
|
#
|
37
33
|
# See the {schema modification guide}[rdoc-ref:doc/schema_modification.rdoc]
|
38
34
|
# for details on using interval columns in CREATE/ALTER TABLE statements.
|
35
|
+
#
|
36
|
+
# Related module: Sequel::Postgres::IntervalDatabaseMethods
|
39
37
|
|
40
38
|
require 'active_support/duration'
|
41
39
|
Sequel.require 'adapters/utils/pg_types'
|
@@ -45,10 +45,6 @@
|
|
45
45
|
#
|
46
46
|
# DB.extension :pg_json
|
47
47
|
#
|
48
|
-
# If you are not using the native postgres adapter and are using json
|
49
|
-
# types as model column values you probably should use the
|
50
|
-
# pg_typecast_on_load plugin if the column values are returned as a string.
|
51
|
-
#
|
52
48
|
# See the {schema modification guide}[rdoc-ref:doc/schema_modification.rdoc]
|
53
49
|
# for details on using json columns in CREATE/ALTER TABLE statements.
|
54
50
|
#
|
@@ -62,6 +58,10 @@
|
|
62
58
|
# Attempting to use other values (such as symbols) will not work correctly.
|
63
59
|
#
|
64
60
|
# This extension requires both the json and delegate libraries.
|
61
|
+
#
|
62
|
+
# Related modules: Sequel::Postgres::JSONArrayBase, Sequel::Postgres::JSONArray,
|
63
|
+
# Sequel::Postgres::JSONArray, Sequel::Postgres::JSONBArray, Sequel::Postgres::JSONHashBase,
|
64
|
+
# Sequel::Postgres::JSONHash, Sequel::Postgres::JSONBHash, Sequel::Postgres::JSONDatabaseMethods
|
65
65
|
|
66
66
|
require 'delegate'
|
67
67
|
require 'json'
|
@@ -80,6 +80,9 @@
|
|
80
80
|
# In order to get the automatic conversion from a ruby array to a PostgreSQL array
|
81
81
|
# (as shown in the #[] and #get_text examples above), you need to load the pg_array
|
82
82
|
# extension.
|
83
|
+
#
|
84
|
+
# Related modules: Sequel::Postgres::JSONBaseOp, Sequel::Postgres::JSONOp,
|
85
|
+
# Sequel::Postgres::JSONBOp
|
83
86
|
|
84
87
|
#
|
85
88
|
module Sequel
|
@@ -47,10 +47,6 @@
|
|
47
47
|
#
|
48
48
|
# DB.extension :pg_range
|
49
49
|
#
|
50
|
-
# If you are not using the native postgres or jdbc/postgresql adapters and are using range
|
51
|
-
# types as model column values you probably should use the
|
52
|
-
# pg_typecast_on_load plugin if the column values are returned as a string.
|
53
|
-
#
|
54
50
|
# See the {schema modification guide}[rdoc-ref:doc/schema_modification.rdoc]
|
55
51
|
# for details on using range type columns in CREATE/ALTER TABLE statements.
|
56
52
|
#
|
@@ -59,6 +55,8 @@
|
|
59
55
|
# pg_range extension:
|
60
56
|
#
|
61
57
|
# DB.extension :pg_array, :pg_range
|
58
|
+
#
|
59
|
+
# Related module: Sequel::Postgres::PGRange
|
62
60
|
|
63
61
|
Sequel.require 'adapters/utils/pg_types'
|
64
62
|
|
@@ -53,6 +53,8 @@
|
|
53
53
|
# If you are also using the pg_range extension, you should load it before
|
54
54
|
# loading this extension. Doing so will allow you to use PGArray#op to get
|
55
55
|
# an RangeOp, allowing you to perform range operations on range literals.
|
56
|
+
#
|
57
|
+
# Related module: Sequel::Postgres::RangeOp
|
56
58
|
|
57
59
|
#
|
58
60
|
module Sequel
|
@@ -76,14 +76,12 @@
|
|
76
76
|
# DB.conversion_procs.select{|k,v| v.is_a?(Sequel::Postgres::PGRow::Parser) && \
|
77
77
|
# v.converter && (v.converter.name.nil? || v.converter.name == '') }.map{|k,v| v}
|
78
78
|
#
|
79
|
-
# If you are not using the native postgres or jdbc/postgresql adapters and are using composite types
|
80
|
-
# types as model column values you probably should use the
|
81
|
-
# pg_typecast_on_load plugin if the column values are returned as a string.
|
82
|
-
#
|
83
79
|
# See the {schema modification guide}[rdoc-ref:doc/schema_modification.rdoc]
|
84
80
|
# for details on using row type columns in CREATE/ALTER TABLE statements.
|
85
81
|
#
|
86
82
|
# This extension requires both the strscan and delegate libraries.
|
83
|
+
#
|
84
|
+
# Related module: Sequel::Postgres::PGRow
|
87
85
|
|
88
86
|
require 'delegate'
|
89
87
|
require 'strscan'
|
@@ -17,11 +17,11 @@
|
|
17
17
|
# SELECT a, b, 2, FROM table GROUP BY a, b ORDER BY c
|
18
18
|
#
|
19
19
|
# This extension makes select, group, and order methods operate
|
20
|
-
# like filter methods, which support the same interface.
|
21
|
-
#
|
22
|
-
#
|
23
|
-
#
|
24
|
-
#
|
20
|
+
# like filter methods, which support the same interface. Note
|
21
|
+
# that this extension can add SQL injection vulnerabilities to existing
|
22
|
+
# code if any of the strings passed to one of the supported
|
23
|
+
# methods is derived from user input. For that reason, it should
|
24
|
+
# be used with caution.
|
25
25
|
#
|
26
26
|
# You can load this extension into specific datasets:
|
27
27
|
#
|
@@ -32,6 +32,8 @@
|
|
32
32
|
# is probably the desired behavior if you are using this extension:
|
33
33
|
#
|
34
34
|
# DB.extension(:query_literals)
|
35
|
+
#
|
36
|
+
# Related module: Sequel::QueryLiterals
|
35
37
|
|
36
38
|
#
|
37
39
|
module Sequel
|
@@ -4,9 +4,8 @@
|
|
4
4
|
# values to the database's supported level of precision before literalizing
|
5
5
|
# them.
|
6
6
|
#
|
7
|
-
# For example, if the database supports
|
8
|
-
# it a Time value with
|
9
|
-
# appropriately:
|
7
|
+
# For example, if the database supports millisecond precision, and you give
|
8
|
+
# it a Time value with microsecond precision, it will round it appropriately:
|
10
9
|
#
|
11
10
|
# Time.at(1405341161.917999982833862)
|
12
11
|
# # default: 2014-07-14 14:32:41.917999
|
@@ -23,6 +22,8 @@
|
|
23
22
|
# To round timestamps for all datasets on a single database:
|
24
23
|
#
|
25
24
|
# DB.extension(:round_timestamps)
|
25
|
+
#
|
26
|
+
# Related module: Sequel::Dataset::RoundTimestamps
|
26
27
|
|
27
28
|
unless RUBY_VERSION >= '1.9'
|
28
29
|
# :nocov:
|
@@ -43,6 +43,8 @@
|
|
43
43
|
# The cached schema is dumped in Marshal format, since it is the fastest
|
44
44
|
# and it handles all ruby objects used in the schema hash. Because of this,
|
45
45
|
# you should not attempt to load the schema from a untrusted file.
|
46
|
+
#
|
47
|
+
# Related module: Sequel::SchemaCaching
|
46
48
|
|
47
49
|
#
|
48
50
|
module Sequel
|
@@ -14,6 +14,7 @@ module Sequel
|
|
14
14
|
@association_reflections = {}
|
15
15
|
@autoreloading_associations = {}
|
16
16
|
@cache_associations = true
|
17
|
+
@default_association_options = {}
|
17
18
|
end
|
18
19
|
end
|
19
20
|
|
@@ -489,40 +490,21 @@ module Sequel
|
|
489
490
|
|
490
491
|
private
|
491
492
|
|
492
|
-
|
493
|
-
#
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
Sequel.synchronize{return h[key] if h.has_key?(key)}
|
500
|
-
value = yield
|
501
|
-
Sequel.synchronize{h[key] = value}
|
502
|
-
end
|
503
|
-
end
|
504
|
-
|
505
|
-
# Cache the value at the given key, synchronizing access.
|
506
|
-
def cached_set(key, value)
|
507
|
-
return unless h = self[:cache]
|
493
|
+
# On non-GVL rubies, assume the need to synchronize access. Store the key
|
494
|
+
# in a special sub-hash that always uses this method to synchronize access.
|
495
|
+
def cached_fetch(key)
|
496
|
+
fetch(key) do
|
497
|
+
return yield unless h = self[:cache]
|
498
|
+
Sequel.synchronize{return h[key] if h.has_key?(key)}
|
499
|
+
value = yield
|
508
500
|
Sequel.synchronize{h[key] = value}
|
509
501
|
end
|
510
|
-
|
511
|
-
else
|
512
|
-
# On MRI, use a plain fetch, since the GVL will synchronize access.
|
513
|
-
def cached_fetch(key)
|
514
|
-
fetch(key) do
|
515
|
-
return yield unless h = self[:cache]
|
516
|
-
h.fetch(key){h[key] = yield}
|
517
|
-
end
|
518
|
-
end
|
502
|
+
end
|
519
503
|
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
h[key] = value
|
525
|
-
end
|
504
|
+
# Cache the value at the given key, synchronizing access.
|
505
|
+
def cached_set(key, value)
|
506
|
+
return unless h = self[:cache]
|
507
|
+
Sequel.synchronize{h[key] = value}
|
526
508
|
end
|
527
509
|
|
528
510
|
# The base dataset used for the association, before any order/conditions
|
@@ -1436,11 +1418,14 @@ module Sequel
|
|
1436
1418
|
attr_reader :autoreloading_associations
|
1437
1419
|
|
1438
1420
|
# Whether association metadata should be cached in the association reflection. If not cached, it will be computed
|
1439
|
-
# on demand. In general you only want to set this to
|
1421
|
+
# on demand. In general you only want to set this to false when using code reloading. When using code reloading,
|
1440
1422
|
# setting this will make sure that if an associated class is removed or modified, this class will not hang on to
|
1441
1423
|
# the previous class.
|
1442
1424
|
attr_accessor :cache_associations
|
1443
1425
|
|
1426
|
+
# The default options to use for all associations.
|
1427
|
+
attr_accessor :default_association_options
|
1428
|
+
|
1444
1429
|
# The default :eager_limit_strategy option to use for limited or offset associations (default: true, causing Sequel
|
1445
1430
|
# to use what it considers the most appropriate strategy).
|
1446
1431
|
attr_accessor :default_eager_limit_strategy
|
@@ -1674,7 +1659,7 @@ module Sequel
|
|
1674
1659
|
orig_opts = cloned_assoc[:orig_opts].merge(orig_opts)
|
1675
1660
|
end
|
1676
1661
|
|
1677
|
-
opts = orig_opts.merge(:type => type, :name => name, :cache=>({} if cache_associations), :model => self)
|
1662
|
+
opts = default_association_options.merge(orig_opts).merge(:type => type, :name => name, :cache=>({} if cache_associations), :model => self)
|
1678
1663
|
opts[:block] = block if block
|
1679
1664
|
if !opts.has_key?(:instance_specific) && (block || orig_opts[:block] || orig_opts[:dataset])
|
1680
1665
|
# It's possible the association is instance specific, in that it depends on
|
@@ -1757,7 +1742,7 @@ module Sequel
|
|
1757
1742
|
associate(:one_to_one, name, opts, &block)
|
1758
1743
|
end
|
1759
1744
|
|
1760
|
-
Plugins.inherited_instance_variables(self, :@association_reflections=>:dup, :@autoreloading_associations=>:hash_dup, :@cache_associations=>nil, :@default_eager_limit_strategy=>nil)
|
1745
|
+
Plugins.inherited_instance_variables(self, :@association_reflections=>:dup, :@autoreloading_associations=>:hash_dup, :@default_association_options=>:dup, :@cache_associations=>nil, :@default_eager_limit_strategy=>nil)
|
1761
1746
|
Plugins.def_dataset_methods(self, [:eager, :eager_graph, :eager_graph_with_options, :association_join, :association_full_join, :association_inner_join, :association_left_join, :association_right_join])
|
1762
1747
|
|
1763
1748
|
private
|
@@ -1818,7 +1803,6 @@ module Sequel
|
|
1818
1803
|
# Configures many_to_many and one_through_one association reflection and adds the related association methods
|
1819
1804
|
def def_many_to_many(opts)
|
1820
1805
|
one_through_one = opts[:type] == :one_through_one
|
1821
|
-
opts[:read_only] = true if one_through_one
|
1822
1806
|
left = (opts[:left_key] ||= opts.default_left_key)
|
1823
1807
|
lcks = opts[:left_keys] = Array(left)
|
1824
1808
|
right = (opts[:right_key] ||= opts.default_right_key)
|
@@ -1872,21 +1856,54 @@ module Sequel
|
|
1872
1856
|
end
|
1873
1857
|
end
|
1874
1858
|
|
1875
|
-
return if opts[:read_only]
|
1859
|
+
return if opts[:read_only]
|
1876
1860
|
|
1877
|
-
|
1878
|
-
|
1879
|
-
|
1880
|
-
|
1881
|
-
|
1882
|
-
end
|
1861
|
+
if one_through_one
|
1862
|
+
opts[:setter] ||= proc do |o|
|
1863
|
+
h = {}
|
1864
|
+
lh = lcks.zip(lcpks.map{|k| get_column_value(k)})
|
1865
|
+
jtds = _join_table_dataset(opts).where(lh)
|
1883
1866
|
|
1884
|
-
|
1885
|
-
|
1886
|
-
|
1867
|
+
checked_transaction do
|
1868
|
+
current = jtds.first
|
1869
|
+
|
1870
|
+
if o
|
1871
|
+
new_values = []
|
1872
|
+
rcks.zip(opts.right_primary_key_methods).each{|k, pk| new_values << (h[k] = o.get_column_value(pk))}
|
1873
|
+
end
|
1887
1874
|
|
1888
|
-
|
1889
|
-
|
1875
|
+
if current
|
1876
|
+
current_values = rcks.map{|k| current[k]}
|
1877
|
+
jtds = jtds.where(rcks.zip(current_values))
|
1878
|
+
if o
|
1879
|
+
if current_values != new_values
|
1880
|
+
jtds.update(h)
|
1881
|
+
end
|
1882
|
+
else
|
1883
|
+
jtds.delete
|
1884
|
+
end
|
1885
|
+
elsif o
|
1886
|
+
lh.each{|k,v| h[k] = v}
|
1887
|
+
jtds.insert(h)
|
1888
|
+
end
|
1889
|
+
end
|
1890
|
+
end
|
1891
|
+
opts[:_setter] = proc{|o| set_one_through_one_associated_object(opts, o)}
|
1892
|
+
else
|
1893
|
+
opts[:adder] ||= proc do |o|
|
1894
|
+
h = {}
|
1895
|
+
lcks.zip(lcpks).each{|k, pk| h[k] = get_column_value(pk)}
|
1896
|
+
rcks.zip(opts.right_primary_key_methods).each{|k, pk| h[k] = o.get_column_value(pk)}
|
1897
|
+
_join_table_dataset(opts).insert(h)
|
1898
|
+
end
|
1899
|
+
|
1900
|
+
opts[:remover] ||= proc do |o|
|
1901
|
+
_join_table_dataset(opts).where(lcks.zip(lcpks.map{|k| get_column_value(k)}) + rcks.zip(opts.right_primary_key_methods.map{|k| o.get_column_value(k)})).delete
|
1902
|
+
end
|
1903
|
+
|
1904
|
+
opts[:clearer] ||= proc do
|
1905
|
+
_join_table_dataset(opts).where(lcks.zip(lcpks.map{|k| get_column_value(k)})).delete
|
1906
|
+
end
|
1890
1907
|
end
|
1891
1908
|
end
|
1892
1909
|
|
@@ -2242,18 +2259,34 @@ module Sequel
|
|
2242
2259
|
self
|
2243
2260
|
end
|
2244
2261
|
|
2245
|
-
#
|
2246
|
-
|
2247
|
-
|
2248
|
-
|
2249
|
-
|
2250
|
-
|
2262
|
+
# Handle parsing of options when loading associations. For historical
|
2263
|
+
# reasons, you can pass true/false/nil or a callable argument to
|
2264
|
+
# associations. That will be going away in Sequel 5, but we'll still
|
2265
|
+
# support it until then.
|
2266
|
+
def load_association_objects_options(dynamic_opts, &block)
|
2267
|
+
dynamic_opts = case dynamic_opts
|
2268
|
+
when true, false, nil
|
2269
|
+
{:reload=>dynamic_opts}
|
2270
|
+
when Hash
|
2271
|
+
Hash[dynamic_opts]
|
2272
|
+
else
|
2273
|
+
if dynamic_opts.respond_to?(:call)
|
2274
|
+
{:callback=>dynamic_opts}
|
2275
|
+
end
|
2251
2276
|
end
|
2277
|
+
|
2252
2278
|
if block_given?
|
2253
|
-
dynamic_opts =
|
2279
|
+
dynamic_opts[:callback] = block
|
2254
2280
|
end
|
2281
|
+
|
2282
|
+
dynamic_opts
|
2283
|
+
end
|
2284
|
+
|
2285
|
+
# Load the associated objects using the dataset, handling callbacks, reciprocals, and caching.
|
2286
|
+
def load_associated_objects(opts, dynamic_opts=nil, &block)
|
2287
|
+
dynamic_opts = load_association_objects_options(dynamic_opts, &block)
|
2255
2288
|
name = opts[:name]
|
2256
|
-
if associations.include?(name)
|
2289
|
+
if associations.include?(name) && !dynamic_opts[:callback] && !dynamic_opts[:reload]
|
2257
2290
|
associations[name]
|
2258
2291
|
else
|
2259
2292
|
objs = _load_associated_objects(opts, dynamic_opts)
|
@@ -2386,6 +2419,13 @@ module Sequel
|
|
2386
2419
|
_set_associated_object(opts, o)
|
2387
2420
|
end
|
2388
2421
|
|
2422
|
+
# Set the given object as the associated object for the given one_through_one association reflection
|
2423
|
+
def set_one_through_one_associated_object(opts, o)
|
2424
|
+
raise(Error, "object #{inspect} does not have a primary key") unless pk
|
2425
|
+
raise(Error, "associated object #{o.inspect} does not have a primary key") if o && !o.pk
|
2426
|
+
_set_associated_object(opts, o)
|
2427
|
+
end
|
2428
|
+
|
2389
2429
|
# Set the given object as the associated object for the given one_to_one association reflection
|
2390
2430
|
def set_one_to_one_associated_object(opts, o)
|
2391
2431
|
raise(Error, "object #{inspect} does not have a primary key") unless pk
|