sequel 4.47.0 → 4.48.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 +134 -0
- data/Rakefile +1 -1
- data/doc/release_notes/4.48.0.txt +293 -0
- data/lib/sequel/adapters/ado/access.rb +2 -1
- data/lib/sequel/adapters/do/postgres.rb +5 -2
- data/lib/sequel/adapters/ibmdb.rb +24 -7
- data/lib/sequel/adapters/jdbc.rb +36 -22
- data/lib/sequel/adapters/jdbc/db2.rb +12 -3
- data/lib/sequel/adapters/jdbc/derby.rb +4 -5
- data/lib/sequel/adapters/jdbc/oracle.rb +16 -2
- data/lib/sequel/adapters/jdbc/postgresql.rb +43 -18
- data/lib/sequel/adapters/jdbc/sqlanywhere.rb +9 -7
- data/lib/sequel/adapters/jdbc/sqlserver.rb +11 -4
- data/lib/sequel/adapters/mock.rb +24 -19
- data/lib/sequel/adapters/mysql.rb +17 -16
- data/lib/sequel/adapters/mysql2.rb +4 -5
- data/lib/sequel/adapters/oracle.rb +5 -9
- data/lib/sequel/adapters/postgres.rb +89 -102
- data/lib/sequel/adapters/shared/db2.rb +22 -6
- data/lib/sequel/adapters/shared/mssql.rb +5 -4
- data/lib/sequel/adapters/shared/mysql.rb +75 -24
- data/lib/sequel/adapters/shared/postgres.rb +196 -94
- data/lib/sequel/adapters/shared/sqlanywhere.rb +23 -10
- data/lib/sequel/adapters/shared/sqlite.rb +72 -82
- data/lib/sequel/adapters/sqlanywhere.rb +4 -1
- data/lib/sequel/adapters/sqlite.rb +5 -3
- data/lib/sequel/adapters/swift/postgres.rb +5 -2
- data/lib/sequel/adapters/tinytds.rb +0 -5
- data/lib/sequel/adapters/utils/mysql_mysql2.rb +1 -1
- data/lib/sequel/adapters/utils/pg_types.rb +2 -76
- data/lib/sequel/core.rb +2 -2
- data/lib/sequel/database/connecting.rb +5 -5
- data/lib/sequel/database/dataset.rb +6 -3
- data/lib/sequel/database/misc.rb +1 -1
- data/lib/sequel/database/query.rb +3 -0
- data/lib/sequel/database/schema_methods.rb +1 -1
- data/lib/sequel/dataset/actions.rb +18 -10
- data/lib/sequel/dataset/graph.rb +1 -1
- data/lib/sequel/dataset/misc.rb +1 -0
- data/lib/sequel/dataset/prepared_statements.rb +3 -3
- data/lib/sequel/dataset/query.rb +19 -8
- data/lib/sequel/extensions/core_extensions.rb +4 -1
- data/lib/sequel/extensions/duplicate_columns_handler.rb +1 -1
- data/lib/sequel/extensions/empty_array_ignore_nulls.rb +3 -0
- data/lib/sequel/extensions/filter_having.rb +2 -0
- data/lib/sequel/extensions/freeze_datasets.rb +2 -0
- data/lib/sequel/extensions/from_block.rb +1 -1
- data/lib/sequel/extensions/graph_each.rb +2 -2
- data/lib/sequel/extensions/hash_aliases.rb +2 -0
- data/lib/sequel/extensions/identifier_mangling.rb +0 -7
- data/lib/sequel/extensions/meta_def.rb +2 -0
- data/lib/sequel/extensions/migration.rb +6 -6
- data/lib/sequel/extensions/no_auto_literal_strings.rb +1 -1
- data/lib/sequel/extensions/pagination.rb +1 -1
- data/lib/sequel/extensions/pg_array.rb +207 -130
- data/lib/sequel/extensions/pg_hstore.rb +38 -20
- data/lib/sequel/extensions/pg_inet.rb +18 -6
- data/lib/sequel/extensions/pg_interval.rb +19 -12
- data/lib/sequel/extensions/pg_json.rb +25 -14
- data/lib/sequel/extensions/pg_json_ops.rb +2 -2
- data/lib/sequel/extensions/pg_range.rb +133 -100
- data/lib/sequel/extensions/pg_range_ops.rb +4 -3
- data/lib/sequel/extensions/pg_row.rb +68 -39
- data/lib/sequel/extensions/pg_row_ops.rb +11 -5
- data/lib/sequel/extensions/query_literals.rb +2 -0
- data/lib/sequel/extensions/ruby18_symbol_extensions.rb +2 -0
- data/lib/sequel/extensions/s.rb +1 -1
- data/lib/sequel/extensions/schema_dumper.rb +24 -24
- data/lib/sequel/extensions/sequel_3_dataset_methods.rb +3 -1
- data/lib/sequel/extensions/sequel_4_dataset_methods.rb +83 -0
- data/lib/sequel/extensions/set_overrides.rb +2 -2
- data/lib/sequel/extensions/string_agg.rb +0 -1
- data/lib/sequel/extensions/symbol_aref.rb +0 -4
- data/lib/sequel/model.rb +25 -57
- data/lib/sequel/model/associations.rb +14 -5
- data/lib/sequel/model/base.rb +96 -32
- data/lib/sequel/plugins/association_pks.rb +73 -46
- data/lib/sequel/plugins/association_proxies.rb +1 -1
- data/lib/sequel/plugins/auto_validations.rb +6 -2
- data/lib/sequel/plugins/boolean_readers.rb +1 -1
- data/lib/sequel/plugins/caching.rb +19 -13
- data/lib/sequel/plugins/class_table_inheritance.rb +19 -10
- data/lib/sequel/plugins/column_conflicts.rb +7 -2
- data/lib/sequel/plugins/column_select.rb +1 -1
- data/lib/sequel/plugins/csv_serializer.rb +8 -8
- data/lib/sequel/plugins/defaults_setter.rb +10 -0
- data/lib/sequel/plugins/eager_each.rb +1 -1
- data/lib/sequel/plugins/force_encoding.rb +2 -2
- data/lib/sequel/plugins/hook_class_methods.rb +9 -12
- data/lib/sequel/plugins/identifier_columns.rb +2 -0
- data/lib/sequel/plugins/instance_filters.rb +3 -1
- data/lib/sequel/plugins/instance_hooks.rb +17 -9
- data/lib/sequel/plugins/json_serializer.rb +17 -10
- data/lib/sequel/plugins/lazy_attributes.rb +8 -7
- data/lib/sequel/plugins/modification_detection.rb +3 -0
- data/lib/sequel/plugins/nested_attributes.rb +5 -1
- data/lib/sequel/plugins/pg_array_associations.rb +5 -0
- data/lib/sequel/plugins/prepared_statements.rb +1 -0
- data/lib/sequel/plugins/rcte_tree.rb +4 -4
- data/lib/sequel/plugins/serialization.rb +3 -10
- data/lib/sequel/plugins/single_table_inheritance.rb +2 -2
- data/lib/sequel/plugins/split_values.rb +6 -5
- data/lib/sequel/plugins/static_cache.rb +31 -25
- data/lib/sequel/plugins/subset_conditions.rb +3 -1
- data/lib/sequel/plugins/table_select.rb +1 -1
- data/lib/sequel/plugins/touch.rb +2 -1
- data/lib/sequel/plugins/validation_class_methods.rb +5 -6
- data/lib/sequel/plugins/validation_helpers.rb +2 -4
- data/lib/sequel/plugins/xml_serializer.rb +4 -4
- data/lib/sequel/sql.rb +2 -2
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/db2_spec.rb +115 -14
- data/spec/adapters/mysql_spec.rb +78 -28
- data/spec/adapters/oracle_spec.rb +24 -24
- data/spec/adapters/postgres_spec.rb +38 -24
- data/spec/adapters/sqlanywhere_spec.rb +88 -86
- data/spec/adapters/sqlite_spec.rb +29 -24
- data/spec/core/connection_pool_spec.rb +17 -0
- data/spec/core/database_spec.rb +6 -0
- data/spec/core/dataset_spec.rb +46 -36
- data/spec/core/schema_spec.rb +16 -0
- data/spec/core/spec_helper.rb +1 -0
- data/spec/core_extensions_spec.rb +6 -2
- data/spec/extensions/active_model_spec.rb +1 -1
- data/spec/extensions/arbitrary_servers_spec.rb +1 -1
- data/spec/extensions/association_pks_spec.rb +34 -2
- data/spec/extensions/auto_literal_strings_spec.rb +5 -1
- data/spec/extensions/auto_validations_spec.rb +2 -0
- data/spec/extensions/boolean_readers_spec.rb +1 -1
- data/spec/extensions/boolean_subsets_spec.rb +1 -1
- data/spec/extensions/class_table_inheritance_spec.rb +48 -2
- data/spec/extensions/column_conflicts_spec.rb +11 -0
- data/spec/extensions/connection_validator_spec.rb +1 -1
- data/spec/extensions/dataset_associations_spec.rb +8 -8
- data/spec/extensions/defaults_setter_spec.rb +1 -1
- data/spec/extensions/filter_having_spec.rb +5 -3
- data/spec/extensions/hash_aliases_spec.rb +3 -1
- data/spec/extensions/identifier_columns_spec.rb +3 -1
- data/spec/extensions/implicit_subquery_spec.rb +4 -2
- data/spec/extensions/json_serializer_spec.rb +18 -0
- data/spec/extensions/lazy_attributes_spec.rb +3 -3
- data/spec/extensions/meta_def_spec.rb +9 -0
- data/spec/extensions/migration_spec.rb +3 -3
- data/spec/extensions/nested_attributes_spec.rb +14 -3
- data/spec/extensions/no_auto_literal_strings_spec.rb +8 -4
- data/spec/extensions/pg_array_associations_spec.rb +29 -18
- data/spec/extensions/pg_array_spec.rb +44 -25
- data/spec/extensions/pg_hstore_spec.rb +10 -0
- data/spec/extensions/pg_inet_spec.rb +26 -0
- data/spec/extensions/pg_interval_spec.rb +20 -0
- data/spec/extensions/pg_json_spec.rb +24 -0
- data/spec/extensions/pg_range_spec.rb +98 -14
- data/spec/extensions/pg_row_spec.rb +14 -4
- data/spec/extensions/prepared_statements_safe_spec.rb +1 -1
- data/spec/extensions/query_literals_spec.rb +3 -1
- data/spec/extensions/schema_dumper_spec.rb +96 -98
- data/spec/extensions/sequel_3_dataset_methods_spec.rb +10 -6
- data/spec/extensions/sequel_4_dataset_methods_spec.rb +121 -0
- data/spec/extensions/single_table_inheritance_spec.rb +1 -1
- data/spec/extensions/spec_helper.rb +7 -1
- data/spec/extensions/static_cache_spec.rb +75 -24
- data/spec/extensions/string_agg_spec.rb +1 -1
- data/spec/extensions/touch_spec.rb +9 -0
- data/spec/extensions/validation_helpers_spec.rb +9 -3
- data/spec/extensions/whitelist_security_spec.rb +26 -0
- data/spec/integration/dataset_test.rb +45 -44
- data/spec/integration/plugin_test.rb +20 -0
- data/spec/integration/prepared_statement_test.rb +3 -0
- data/spec/integration/schema_test.rb +21 -1
- data/spec/integration/transaction_test.rb +40 -40
- data/spec/model/class_dataset_methods_spec.rb +14 -4
- data/spec/model/dataset_methods_spec.rb +12 -3
- data/spec/model/model_spec.rb +8 -0
- metadata +6 -4
- data/spec/adapters/firebird_spec.rb +0 -405
- data/spec/adapters/informix_spec.rb +0 -100
|
@@ -41,6 +41,17 @@ module Sequel
|
|
|
41
41
|
# If set to :remove, the setter will treat the nil as an empty array, removing
|
|
42
42
|
# the association all currently associated values.
|
|
43
43
|
#
|
|
44
|
+
# For many_to_many associations, association_pks assumes the related pks can be
|
|
45
|
+
# accessed directly from the join table. This works in most cases, but in cases
|
|
46
|
+
# where the :right_primary_key association option is used to specify a different
|
|
47
|
+
# primary key in the associated table, association_pks will return the value of
|
|
48
|
+
# the association primary keys (foreign key values to associated table in the join
|
|
49
|
+
# table), not the associated model primary keys. If you would like to use the
|
|
50
|
+
# associated model primary keys, you need to use the
|
|
51
|
+
# :association_pks_use_associated_table association option. If the
|
|
52
|
+
# :association_pks_use_associated_table association option is used, no setter
|
|
53
|
+
# method will be added.
|
|
54
|
+
#
|
|
44
55
|
# Usage:
|
|
45
56
|
#
|
|
46
57
|
# # Make all model subclass *_to_many associations have association_pks
|
|
@@ -57,7 +68,7 @@ module Sequel
|
|
|
57
68
|
# Define a association_pks method using the block for the association reflection
|
|
58
69
|
def def_association_pks_methods(opts)
|
|
59
70
|
association_module_def(:"#{singularize(opts[:name])}_pks", opts){_association_pks_getter(opts)}
|
|
60
|
-
association_module_def(:"#{singularize(opts[:name])}_pks=", opts){|pks| _association_pks_setter(opts, pks)}
|
|
71
|
+
association_module_def(:"#{singularize(opts[:name])}_pks=", opts){|pks| _association_pks_setter(opts, pks)} if opts[:pks_setter]
|
|
61
72
|
end
|
|
62
73
|
|
|
63
74
|
# Add a getter that checks the join table for matching records and
|
|
@@ -73,11 +84,23 @@ module Sequel
|
|
|
73
84
|
clpk = lpk.is_a?(Array)
|
|
74
85
|
crk = rk.is_a?(Array)
|
|
75
86
|
|
|
76
|
-
opts[:pks_getter] = if
|
|
87
|
+
opts[:pks_getter] = if join_associated_table = opts[:association_pks_use_associated_table]
|
|
88
|
+
tname = opts[:join_table]
|
|
89
|
+
lambda do
|
|
90
|
+
cond = if clpk
|
|
91
|
+
lk.zip(lpk).map{|k, pk| [Sequel.qualify(tname, k), get_column_value(pk)]}
|
|
92
|
+
else
|
|
93
|
+
{Sequel.qualify(tname, lk) => get_column_value(lpk)}
|
|
94
|
+
end
|
|
95
|
+
rpk = opts.associated_class.primary_key
|
|
96
|
+
opts.associated_dataset.
|
|
97
|
+
naked.where(cond).
|
|
98
|
+
select_map(Sequel.send(rpk.is_a?(Array) ? :deep_qualify : :qualify, opts.associated_class.table_name, rpk))
|
|
99
|
+
end
|
|
100
|
+
elsif clpk
|
|
77
101
|
lambda do
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
_join_table_dataset(opts).where(h).select_map(rk)
|
|
102
|
+
cond = lk.zip(lpk).map{|k, pk| [k, get_column_value(pk)]}
|
|
103
|
+
_join_table_dataset(opts).where(cond).select_map(rk)
|
|
81
104
|
end
|
|
82
105
|
else
|
|
83
106
|
lambda do
|
|
@@ -85,25 +108,27 @@ module Sequel
|
|
|
85
108
|
end
|
|
86
109
|
end
|
|
87
110
|
|
|
88
|
-
opts[:
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
111
|
+
if !opts[:read_only] && !join_associated_table
|
|
112
|
+
opts[:pks_setter] = lambda do |pks|
|
|
113
|
+
if pks.empty?
|
|
114
|
+
send(opts.remove_all_method)
|
|
115
|
+
else
|
|
116
|
+
checked_transaction do
|
|
117
|
+
if clpk
|
|
118
|
+
lpkv = lpk.map{|k| get_column_value(k)}
|
|
119
|
+
cond = lk.zip(lpkv)
|
|
120
|
+
else
|
|
121
|
+
lpkv = get_column_value(lpk)
|
|
122
|
+
cond = {lk=>lpkv}
|
|
123
|
+
end
|
|
124
|
+
ds = _join_table_dataset(opts).where(cond)
|
|
125
|
+
ds.exclude(rk=>pks).delete
|
|
126
|
+
pks -= ds.select_map(rk)
|
|
127
|
+
lpkv = Array(lpkv)
|
|
128
|
+
key_array = crk ? pks.map{|pk| lpkv + pk} : pks.map{|pk| lpkv + [pk]}
|
|
129
|
+
key_columns = Array(lk) + Array(rk)
|
|
130
|
+
ds.import(key_columns, key_array)
|
|
99
131
|
end
|
|
100
|
-
ds = _join_table_dataset(opts).where(cond)
|
|
101
|
-
ds.exclude(rk=>pks).delete
|
|
102
|
-
pks -= ds.select_map(rk)
|
|
103
|
-
lpkv = Array(lpkv)
|
|
104
|
-
key_array = crk ? pks.map{|pk| lpkv + pk} : pks.map{|pk| lpkv + [pk]}
|
|
105
|
-
key_columns = Array(lk) + Array(rk)
|
|
106
|
-
ds.import(key_columns, key_array)
|
|
107
132
|
end
|
|
108
133
|
end
|
|
109
134
|
end
|
|
@@ -124,29 +149,31 @@ module Sequel
|
|
|
124
149
|
send(opts.dataset_method).select_map(opts.associated_class.primary_key)
|
|
125
150
|
end
|
|
126
151
|
|
|
127
|
-
opts[:
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
primary_key = opts.associated_class.primary_key
|
|
132
|
-
pkh = {primary_key=>pks}
|
|
133
|
-
|
|
134
|
-
if key.is_a?(Array)
|
|
135
|
-
h = {}
|
|
136
|
-
nh = {}
|
|
137
|
-
key.zip(pk).each do|k, v|
|
|
138
|
-
h[k] = v
|
|
139
|
-
nh[k] = nil
|
|
140
|
-
end
|
|
152
|
+
unless opts[:read_only]
|
|
153
|
+
opts[:pks_setter] = lambda do |pks|
|
|
154
|
+
if pks.empty?
|
|
155
|
+
send(opts.remove_all_method)
|
|
141
156
|
else
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
end
|
|
157
|
+
primary_key = opts.associated_class.primary_key
|
|
158
|
+
pkh = {primary_key=>pks}
|
|
145
159
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
160
|
+
if key.is_a?(Array)
|
|
161
|
+
h = {}
|
|
162
|
+
nh = {}
|
|
163
|
+
key.zip(pk).each do|k, v|
|
|
164
|
+
h[k] = v
|
|
165
|
+
nh[k] = nil
|
|
166
|
+
end
|
|
167
|
+
else
|
|
168
|
+
h = {key=>pk}
|
|
169
|
+
nh = {key=>nil}
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
checked_transaction do
|
|
173
|
+
ds = send(opts.dataset_method)
|
|
174
|
+
ds.unfiltered.where(pkh).update(h)
|
|
175
|
+
ds.exclude(pkh).update(nh)
|
|
176
|
+
end
|
|
150
177
|
end
|
|
151
178
|
end
|
|
152
179
|
end
|
|
@@ -208,7 +235,7 @@ module Sequel
|
|
|
208
235
|
pks = convert_pk_array(opts, pks)
|
|
209
236
|
|
|
210
237
|
delay = opts.fetch(:delay_pks) do
|
|
211
|
-
Sequel::Deprecation.deprecate("association_pks will default to assuming the :delay_pks=>:always association option starting in Sequel 5. Explicitly set :delay_pks=>false option for the association if you want changes to take effect immediately instead of being delayed until the object is saved (association: #{opts.inspect})
|
|
238
|
+
Sequel::Deprecation.deprecate("association_pks will default to assuming the :delay_pks=>:always association option starting in Sequel 5. Explicitly set :delay_pks=>false option for the association if you want changes to take effect immediately instead of being delayed until the object is saved (association: #{opts.inspect})")
|
|
212
239
|
false
|
|
213
240
|
end
|
|
214
241
|
if (new? && delay) || (delay == :always)
|
|
@@ -216,7 +243,7 @@ module Sequel
|
|
|
216
243
|
(@_association_pks ||= {})[opts[:name]] = pks
|
|
217
244
|
else
|
|
218
245
|
if !new? && delay && delay != :always
|
|
219
|
-
Sequel::Deprecation.deprecate("association_pks with the :delay_pks=>true association option will also delay setting of associated values for existing objects in Sequel 5 (currently it just delays setting of associated values for new objects). Please change to using :delay_pks=>:always to avoid this message. Sequel 5 will not support the existing :delay_pks=>true behavior for only delaying for new objects and not for existing objects
|
|
246
|
+
Sequel::Deprecation.deprecate("association_pks with the :delay_pks=>true association option will also delay setting of associated values for existing objects in Sequel 5 (currently it just delays setting of associated values for new objects). Please change to using :delay_pks=>:always to avoid this message. Sequel 5 will not support the existing :delay_pks=>true behavior for only delaying for new objects and not for existing objects")
|
|
220
247
|
end
|
|
221
248
|
instance_exec(pks, &opts[:pks_setter])
|
|
222
249
|
end
|
|
@@ -101,7 +101,7 @@ module Sequel
|
|
|
101
101
|
def def_association_method(opts)
|
|
102
102
|
if opts.returns_array?
|
|
103
103
|
association_module_def(opts.association_method, opts) do |*dynamic_opts, &block|
|
|
104
|
-
Sequel::Deprecation.deprecate("Passing multiple arguments to ##{opts.association_method}", "Additional arguments are currently ignored
|
|
104
|
+
Sequel::Deprecation.deprecate("Passing multiple arguments to ##{opts.association_method}", "Additional arguments are currently ignored") if dynamic_opts.length > 1
|
|
105
105
|
AssociationProxy.new(self, opts, dynamic_opts.length == 0 ? OPTS : dynamic_opts[0], &block)
|
|
106
106
|
end
|
|
107
107
|
else
|
|
@@ -140,9 +140,13 @@ module Sequel
|
|
|
140
140
|
# Skip automatic validations for the given validation type (:not_null, :types, :unique).
|
|
141
141
|
# If :all is given as the type, skip all auto validations.
|
|
142
142
|
def skip_auto_validations(type)
|
|
143
|
-
|
|
143
|
+
case type
|
|
144
|
+
when :all
|
|
144
145
|
[:not_null, :types, :unique, :max_length].each{|v| skip_auto_validations(v)}
|
|
145
|
-
|
|
146
|
+
when :not_null
|
|
147
|
+
auto_validate_not_null_columns.clear
|
|
148
|
+
auto_validate_explicit_not_null_columns.clear
|
|
149
|
+
when :types
|
|
146
150
|
@auto_validate_types = false
|
|
147
151
|
else
|
|
148
152
|
send("auto_validate_#{type}_columns").clear
|
|
@@ -48,7 +48,7 @@ module Sequel
|
|
|
48
48
|
|
|
49
49
|
# Add attribute? methods for all of the boolean attributes for this model.
|
|
50
50
|
def create_boolean_readers
|
|
51
|
-
im = instance_methods.
|
|
51
|
+
im = instance_methods.map(&:to_s)
|
|
52
52
|
if cs = check_non_connection_error(false){columns}
|
|
53
53
|
cs.each{|c| create_boolean_reader(c) if boolean_attribute?(c) && !im.include?("#{c}?")}
|
|
54
54
|
end
|
|
@@ -19,8 +19,13 @@ module Sequel
|
|
|
19
19
|
# raise an exception for a missing record, so if you use memcached, you will
|
|
20
20
|
# want to use this option.
|
|
21
21
|
#
|
|
22
|
-
# Note that only
|
|
23
|
-
#
|
|
22
|
+
# Note that only lookups by primary key are cached using this plugin. The following
|
|
23
|
+
# methods use a lookup by primary key:
|
|
24
|
+
#
|
|
25
|
+
# * Model.with_pk
|
|
26
|
+
# * Model.with_pk!
|
|
27
|
+
# * Model.[] # when argument is not hash or nil
|
|
28
|
+
# * many_to_one association method # without dynamic callback, when primary key matches
|
|
24
29
|
#
|
|
25
30
|
# Usage:
|
|
26
31
|
#
|
|
@@ -68,7 +73,7 @@ module Sequel
|
|
|
68
73
|
|
|
69
74
|
# Returns the prefix used to namespace this class in the cache.
|
|
70
75
|
def cache_key_prefix
|
|
71
|
-
|
|
76
|
+
to_s
|
|
72
77
|
end
|
|
73
78
|
|
|
74
79
|
# Return a key string for the given primary key.
|
|
@@ -86,26 +91,27 @@ module Sequel
|
|
|
86
91
|
|
|
87
92
|
private
|
|
88
93
|
|
|
89
|
-
#
|
|
90
|
-
def
|
|
94
|
+
# Access the cache using the given method and key, rescuing exceptions if necessary.
|
|
95
|
+
def cache_op(meth, ck)
|
|
91
96
|
if @cache_ignore_exceptions
|
|
92
|
-
@cache_store.
|
|
97
|
+
@cache_store.send(meth, ck) rescue nil
|
|
93
98
|
else
|
|
94
|
-
@cache_store.
|
|
99
|
+
@cache_store.send(meth, ck)
|
|
95
100
|
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Delete the entry with the matching key from the cache
|
|
104
|
+
def cache_delete(ck)
|
|
105
|
+
cache_op(:delete, ck)
|
|
96
106
|
nil
|
|
97
107
|
end
|
|
98
108
|
|
|
99
109
|
# Returned the cached object, or nil if the object was not
|
|
100
110
|
# in the cached
|
|
101
111
|
def cache_get(ck)
|
|
102
|
-
|
|
103
|
-
@cache_store.get(ck) rescue nil
|
|
104
|
-
else
|
|
105
|
-
@cache_store.get(ck)
|
|
106
|
-
end
|
|
112
|
+
cache_op(:get, ck)
|
|
107
113
|
end
|
|
108
|
-
|
|
114
|
+
|
|
109
115
|
# Set the object in the cache_store with the given key for cache_ttl seconds.
|
|
110
116
|
def cache_set(ck, obj)
|
|
111
117
|
@cache_store.set(ck, obj, @cache_ttl)
|
|
@@ -203,7 +203,7 @@ module Sequel
|
|
|
203
203
|
@cti_instance_dataset = @instance_dataset
|
|
204
204
|
@cti_table_columns = columns
|
|
205
205
|
@cti_table_map = opts[:table_map] || {}
|
|
206
|
-
@cti_alias = opts[:alias]
|
|
206
|
+
@cti_alias = opts[:alias] # || table_name # SEQUEL5
|
|
207
207
|
end
|
|
208
208
|
end
|
|
209
209
|
|
|
@@ -216,6 +216,7 @@ module Sequel
|
|
|
216
216
|
# This is the only model in the hierarchy that loads the
|
|
217
217
|
# class_table_inheritance plugin. For backwards compatibility.
|
|
218
218
|
def cti_base_model
|
|
219
|
+
Sequel::Deprecation.deprecate("#{self}.cti_base_model", "Use #{self}.cti_models.first instead")
|
|
219
220
|
@cti_models.first
|
|
220
221
|
end
|
|
221
222
|
|
|
@@ -228,12 +229,12 @@ module Sequel
|
|
|
228
229
|
attr_reader :cti_instance_dataset
|
|
229
230
|
|
|
230
231
|
# An array of table symbols that back this model. The first is
|
|
231
|
-
#
|
|
232
|
+
# table symbol for the base model, and the last is the current model
|
|
232
233
|
# table symbol.
|
|
233
234
|
attr_reader :cti_tables
|
|
234
235
|
|
|
235
236
|
# A hash with class name symbol keys and table name symbol values.
|
|
236
|
-
# Specified with the :table_map option to the plugin, and used if
|
|
237
|
+
# Specified with the :table_map option to the plugin, and should be used if
|
|
237
238
|
# the implicit naming is incorrect.
|
|
238
239
|
attr_reader :cti_table_map
|
|
239
240
|
|
|
@@ -247,10 +248,16 @@ module Sequel
|
|
|
247
248
|
end
|
|
248
249
|
|
|
249
250
|
# Alias to sti_key, for backwards compatibility.
|
|
250
|
-
def cti_key
|
|
251
|
+
def cti_key
|
|
252
|
+
Sequel::Deprecation.deprecate("#{self}.cti_key", "Use #{self}.sti_key instead")
|
|
253
|
+
sti_key
|
|
254
|
+
end
|
|
251
255
|
|
|
252
256
|
# Alias to sti_model_map, for backwards compatibility.
|
|
253
|
-
def cti_model_map
|
|
257
|
+
def cti_model_map
|
|
258
|
+
Sequel::Deprecation.deprecate("#{self}.cti_model_map", "Use #{self}.sti_model_map instead")
|
|
259
|
+
sti_model_map
|
|
260
|
+
end
|
|
254
261
|
|
|
255
262
|
# Freeze CTI information when freezing model class.
|
|
256
263
|
def freeze
|
|
@@ -297,19 +304,20 @@ module Sequel
|
|
|
297
304
|
cols = columns - [pk]
|
|
298
305
|
dup_cols = cols & ds.columns
|
|
299
306
|
unless dup_cols.empty?
|
|
307
|
+
# raise Error, "class_table_inheritance with duplicate column names (other than the primary key column) is not supported, make sure tables have unique column names"
|
|
300
308
|
Sequel::Deprecation.deprecate("Using class_table_inheritance with duplicate column names (#{n} => #{dup_cols}) in subclass tables (other than the primary key column)', 'Make sure all tables used have unique column names, or implement support for handling duplicate column names in the class_table_inheritance plugin")
|
|
301
309
|
end
|
|
302
310
|
sel_app = cols.map{|cc| Sequel.qualify(table, Sequel.identifier(cc))}
|
|
303
311
|
@sti_dataset = ds = ds.join(table, pk=>pk).select_append(*sel_app)
|
|
304
312
|
|
|
305
|
-
if @cti_alias
|
|
313
|
+
if @cti_alias # SEQUEL5: remove if
|
|
306
314
|
ds = ds.from_self(:alias=>@cti_alias)
|
|
307
315
|
end
|
|
308
316
|
|
|
309
317
|
set_dataset(ds)
|
|
310
318
|
set_columns(self.columns)
|
|
311
319
|
@dataset = @dataset.with_row_proc(lambda{|r| subclass.sti_load(r)})
|
|
312
|
-
cols.each{|a| define_lazy_attribute_getter(a, :dataset=>dataset, :table=>@cti_alias||table)}
|
|
320
|
+
cols.each{|a| define_lazy_attribute_getter(a, :dataset=>dataset, :table=>@cti_alias||table)} # SEQUEL5: remove ||table
|
|
313
321
|
|
|
314
322
|
@cti_models += [self]
|
|
315
323
|
@cti_tables += [table]
|
|
@@ -325,7 +333,7 @@ module Sequel
|
|
|
325
333
|
# The table name for the current model class's main table.
|
|
326
334
|
def table_name
|
|
327
335
|
if cti_tables
|
|
328
|
-
if @cti_alias
|
|
336
|
+
if @cti_alias # SEQUEL5: remove if
|
|
329
337
|
@cti_alias
|
|
330
338
|
else
|
|
331
339
|
cti_tables.last
|
|
@@ -340,6 +348,7 @@ module Sequel
|
|
|
340
348
|
cti_tables ? cti_tables.last : dataset.first_source_alias
|
|
341
349
|
end
|
|
342
350
|
|
|
351
|
+
# The model class for the given key value.
|
|
343
352
|
def sti_class_from_key(key)
|
|
344
353
|
sti_class(sti_model_map[key])
|
|
345
354
|
end
|
|
@@ -350,7 +359,7 @@ module Sequel
|
|
|
350
359
|
# when setting subclass dataset.
|
|
351
360
|
def sti_subclass_dataset(key)
|
|
352
361
|
ds = super
|
|
353
|
-
if @cti_alias
|
|
362
|
+
if @cti_alias && cti_models[0] != self # SEQUEL5: remove @cti_alias
|
|
354
363
|
ds = ds.from_self(:alias=>@cti_alias)
|
|
355
364
|
end
|
|
356
365
|
ds
|
|
@@ -395,7 +404,7 @@ module Sequel
|
|
|
395
404
|
# Insert rows into all backing tables, using the columns
|
|
396
405
|
# in each table.
|
|
397
406
|
def _insert
|
|
398
|
-
return super if model.
|
|
407
|
+
return super if model.cti_models[0] == model
|
|
399
408
|
model.cti_models.each do |m|
|
|
400
409
|
v = {}
|
|
401
410
|
m.cti_table_columns.each{|c| v[c] = @values[c] if @values.include?(c)}
|
|
@@ -29,11 +29,16 @@ module Sequel
|
|
|
29
29
|
# # Make the Album class handle column conflicts automatically
|
|
30
30
|
# Album.plugin :column_conflicts
|
|
31
31
|
module ColumnConflicts
|
|
32
|
-
|
|
33
|
-
def self.configure(model)
|
|
32
|
+
def self.apply(model)
|
|
34
33
|
model.instance_eval do
|
|
35
34
|
@get_column_conflicts = {}
|
|
36
35
|
@set_column_conflicts = {}
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Check for column conflicts on the current model if the model has a dataset.
|
|
40
|
+
def self.configure(model)
|
|
41
|
+
model.instance_eval do
|
|
37
42
|
check_column_conflicts if @dataset
|
|
38
43
|
end
|
|
39
44
|
end
|
|
@@ -41,7 +41,7 @@ module Sequel
|
|
|
41
41
|
# qualifying them with table's name.
|
|
42
42
|
def convert_input_dataset(ds)
|
|
43
43
|
ds = super
|
|
44
|
-
if !ds.opts[:select] && (from = ds.opts[:from]) && from.length == 1 && !ds.opts[:join]
|
|
44
|
+
if !ds.opts[:select] && (from = ds.opts[:from]) && from.length == 1 && !ds.opts[:join] # SEQUE5: just !ds.opts[:select]
|
|
45
45
|
if db.supports_schema_parsing?
|
|
46
46
|
cols = check_non_connection_error(false){db.schema(ds)}
|
|
47
47
|
if cols
|
|
@@ -76,9 +76,9 @@ module Sequel
|
|
|
76
76
|
|
|
77
77
|
# Set up the column readers to do deserialization and the column writers
|
|
78
78
|
# to save the value in deserialized_values
|
|
79
|
-
def self.configure(model, opts =
|
|
79
|
+
def self.configure(model, opts = OPTS)
|
|
80
80
|
model.instance_eval do
|
|
81
|
-
@csv_serializer_opts = (@csv_serializer_opts ||
|
|
81
|
+
@csv_serializer_opts = (@csv_serializer_opts || OPTS).merge(opts)
|
|
82
82
|
end
|
|
83
83
|
end
|
|
84
84
|
|
|
@@ -87,7 +87,7 @@ module Sequel
|
|
|
87
87
|
attr_reader :csv_serializer_opts
|
|
88
88
|
|
|
89
89
|
# Attempt to parse an array of instances from the given CSV string
|
|
90
|
-
def array_from_csv(csv, opts =
|
|
90
|
+
def array_from_csv(csv, opts = OPTS)
|
|
91
91
|
CSV.parse(csv, process_csv_serializer_opts(opts)).map do |row|
|
|
92
92
|
row = row.to_hash
|
|
93
93
|
row.delete(nil)
|
|
@@ -105,13 +105,13 @@ module Sequel
|
|
|
105
105
|
end
|
|
106
106
|
|
|
107
107
|
# Attempt to parse a single instance from the given CSV string
|
|
108
|
-
def from_csv(csv, opts =
|
|
108
|
+
def from_csv(csv, opts = OPTS)
|
|
109
109
|
new.from_csv(csv, opts)
|
|
110
110
|
end
|
|
111
111
|
|
|
112
112
|
# Convert the options hash to one that can be passed to CSV.
|
|
113
113
|
def process_csv_serializer_opts(opts)
|
|
114
|
-
opts = (csv_serializer_opts ||
|
|
114
|
+
opts = (csv_serializer_opts || OPTS).merge(opts)
|
|
115
115
|
opts_cols = opts.delete(:columns)
|
|
116
116
|
opts_include = opts.delete(:include)
|
|
117
117
|
opts_except = opts.delete(:except)
|
|
@@ -136,7 +136,7 @@ module Sequel
|
|
|
136
136
|
#
|
|
137
137
|
# :headers :: The headers to use for the CSV line. Use nil for a header
|
|
138
138
|
# to specify the column should be ignored.
|
|
139
|
-
def from_csv(csv, opts =
|
|
139
|
+
def from_csv(csv, opts = OPTS)
|
|
140
140
|
row = CSV.parse_line(csv, model.process_csv_serializer_opts(opts)).to_hash
|
|
141
141
|
row.delete(nil)
|
|
142
142
|
set(row)
|
|
@@ -151,7 +151,7 @@ module Sequel
|
|
|
151
151
|
# output, ignoring all other columns
|
|
152
152
|
# :include :: Symbol or Array of Symbols specifying non-column
|
|
153
153
|
# attributes to include in the CSV output.
|
|
154
|
-
def to_csv(opts =
|
|
154
|
+
def to_csv(opts = OPTS)
|
|
155
155
|
opts = model.process_csv_serializer_opts(opts)
|
|
156
156
|
|
|
157
157
|
CSV.generate(opts) do |csv|
|
|
@@ -168,7 +168,7 @@ module Sequel
|
|
|
168
168
|
#
|
|
169
169
|
# :array :: An array of instances. If this is not provided, calls #all
|
|
170
170
|
# on the receiver to get the array.
|
|
171
|
-
def to_csv(opts =
|
|
171
|
+
def to_csv(opts = OPTS)
|
|
172
172
|
opts = model.process_csv_serializer_opts({:columns=>columns}.merge!(opts))
|
|
173
173
|
items = opts.delete(:array) || self
|
|
174
174
|
|