sequel 3.46.0 → 3.47.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +96 -0
- data/Rakefile +7 -1
- data/bin/sequel +6 -4
- data/doc/active_record.rdoc +1 -1
- data/doc/advanced_associations.rdoc +14 -35
- data/doc/association_basics.rdoc +66 -4
- data/doc/migration.rdoc +4 -0
- data/doc/opening_databases.rdoc +6 -0
- data/doc/postgresql.rdoc +302 -0
- data/doc/release_notes/3.47.0.txt +270 -0
- data/doc/security.rdoc +6 -0
- data/lib/sequel/adapters/ibmdb.rb +9 -9
- data/lib/sequel/adapters/jdbc.rb +22 -7
- data/lib/sequel/adapters/jdbc/postgresql.rb +7 -2
- data/lib/sequel/adapters/mock.rb +2 -0
- data/lib/sequel/adapters/postgres.rb +44 -13
- data/lib/sequel/adapters/shared/mssql.rb +1 -1
- data/lib/sequel/adapters/shared/mysql.rb +2 -2
- data/lib/sequel/adapters/shared/postgres.rb +94 -55
- data/lib/sequel/adapters/shared/sqlite.rb +3 -1
- data/lib/sequel/adapters/sqlite.rb +2 -2
- data/lib/sequel/adapters/utils/pg_types.rb +1 -14
- data/lib/sequel/adapters/utils/split_alter_table.rb +3 -3
- data/lib/sequel/connection_pool/threaded.rb +1 -1
- data/lib/sequel/core.rb +1 -1
- data/lib/sequel/database/connecting.rb +2 -2
- data/lib/sequel/database/features.rb +5 -0
- data/lib/sequel/database/misc.rb +47 -5
- data/lib/sequel/database/query.rb +2 -2
- data/lib/sequel/dataset/actions.rb +4 -2
- data/lib/sequel/dataset/misc.rb +1 -1
- data/lib/sequel/dataset/prepared_statements.rb +1 -1
- data/lib/sequel/dataset/query.rb +8 -6
- data/lib/sequel/dataset/sql.rb +8 -6
- data/lib/sequel/extensions/constraint_validations.rb +5 -2
- data/lib/sequel/extensions/migration.rb +10 -8
- data/lib/sequel/extensions/pagination.rb +3 -0
- data/lib/sequel/extensions/pg_array.rb +85 -25
- data/lib/sequel/extensions/pg_hstore.rb +8 -1
- data/lib/sequel/extensions/pg_hstore_ops.rb +4 -1
- data/lib/sequel/extensions/pg_inet.rb +16 -13
- data/lib/sequel/extensions/pg_interval.rb +6 -2
- data/lib/sequel/extensions/pg_json.rb +18 -11
- data/lib/sequel/extensions/pg_range.rb +17 -2
- data/lib/sequel/extensions/pg_range_ops.rb +7 -5
- data/lib/sequel/extensions/pg_row.rb +29 -12
- data/lib/sequel/extensions/pretty_table.rb +3 -0
- data/lib/sequel/extensions/query.rb +3 -0
- data/lib/sequel/extensions/schema_caching.rb +2 -0
- data/lib/sequel/extensions/schema_dumper.rb +3 -1
- data/lib/sequel/extensions/select_remove.rb +3 -0
- data/lib/sequel/model.rb +8 -2
- data/lib/sequel/model/associations.rb +39 -27
- data/lib/sequel/model/base.rb +99 -38
- data/lib/sequel/model/plugins.rb +25 -0
- data/lib/sequel/plugins/association_autoreloading.rb +27 -22
- data/lib/sequel/plugins/association_dependencies.rb +1 -7
- data/lib/sequel/plugins/auto_validations.rb +110 -0
- data/lib/sequel/plugins/boolean_readers.rb +1 -6
- data/lib/sequel/plugins/caching.rb +6 -13
- data/lib/sequel/plugins/class_table_inheritance.rb +1 -0
- data/lib/sequel/plugins/composition.rb +14 -7
- data/lib/sequel/plugins/constraint_validations.rb +2 -13
- data/lib/sequel/plugins/defaults_setter.rb +1 -6
- data/lib/sequel/plugins/dirty.rb +8 -0
- data/lib/sequel/plugins/error_splitter.rb +54 -0
- data/lib/sequel/plugins/force_encoding.rb +1 -5
- data/lib/sequel/plugins/hook_class_methods.rb +1 -6
- data/lib/sequel/plugins/input_transformer.rb +79 -0
- data/lib/sequel/plugins/instance_filters.rb +7 -1
- data/lib/sequel/plugins/instance_hooks.rb +7 -1
- data/lib/sequel/plugins/json_serializer.rb +5 -10
- data/lib/sequel/plugins/lazy_attributes.rb +20 -7
- data/lib/sequel/plugins/list.rb +1 -6
- data/lib/sequel/plugins/many_through_many.rb +1 -2
- data/lib/sequel/plugins/many_to_one_pk_lookup.rb +23 -39
- data/lib/sequel/plugins/optimistic_locking.rb +1 -5
- data/lib/sequel/plugins/pg_row.rb +4 -2
- data/lib/sequel/plugins/pg_typecast_on_load.rb +3 -7
- data/lib/sequel/plugins/prepared_statements.rb +1 -5
- data/lib/sequel/plugins/prepared_statements_safe.rb +2 -11
- data/lib/sequel/plugins/rcte_tree.rb +2 -2
- data/lib/sequel/plugins/serialization.rb +11 -13
- data/lib/sequel/plugins/serialization_modification_detection.rb +13 -1
- data/lib/sequel/plugins/single_table_inheritance.rb +4 -4
- data/lib/sequel/plugins/static_cache.rb +67 -19
- data/lib/sequel/plugins/string_stripper.rb +7 -27
- data/lib/sequel/plugins/subclasses.rb +3 -5
- data/lib/sequel/plugins/tactical_eager_loading.rb +2 -2
- data/lib/sequel/plugins/timestamps.rb +2 -7
- data/lib/sequel/plugins/touch.rb +5 -8
- data/lib/sequel/plugins/tree.rb +1 -6
- data/lib/sequel/plugins/typecast_on_load.rb +1 -5
- data/lib/sequel/plugins/update_primary_key.rb +26 -14
- data/lib/sequel/plugins/validation_class_methods.rb +31 -16
- data/lib/sequel/plugins/validation_helpers.rb +50 -26
- data/lib/sequel/plugins/xml_serializer.rb +3 -6
- data/lib/sequel/sql.rb +1 -1
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/postgres_spec.rb +131 -15
- data/spec/adapters/sqlite_spec.rb +1 -1
- data/spec/core/connection_pool_spec.rb +16 -17
- data/spec/core/database_spec.rb +111 -40
- data/spec/core/dataset_spec.rb +65 -74
- data/spec/core/expression_filters_spec.rb +6 -5
- data/spec/core/object_graph_spec.rb +0 -1
- data/spec/core/schema_spec.rb +23 -23
- data/spec/core/spec_helper.rb +5 -1
- data/spec/extensions/association_dependencies_spec.rb +1 -1
- data/spec/extensions/association_proxies_spec.rb +1 -1
- data/spec/extensions/auto_validations_spec.rb +90 -0
- data/spec/extensions/caching_spec.rb +6 -0
- data/spec/extensions/class_table_inheritance_spec.rb +8 -1
- data/spec/extensions/composition_spec.rb +12 -5
- data/spec/extensions/constraint_validations_spec.rb +4 -4
- data/spec/extensions/core_refinements_spec.rb +29 -79
- data/spec/extensions/dirty_spec.rb +14 -0
- data/spec/extensions/error_splitter_spec.rb +18 -0
- data/spec/extensions/identity_map_spec.rb +0 -1
- data/spec/extensions/input_transformer_spec.rb +54 -0
- data/spec/extensions/instance_filters_spec.rb +6 -0
- data/spec/extensions/instance_hooks_spec.rb +12 -1
- data/spec/extensions/json_serializer_spec.rb +0 -1
- data/spec/extensions/lazy_attributes_spec.rb +64 -55
- data/spec/extensions/looser_typecasting_spec.rb +1 -1
- data/spec/extensions/many_through_many_spec.rb +3 -4
- data/spec/extensions/many_to_one_pk_lookup_spec.rb +53 -15
- data/spec/extensions/migration_spec.rb +16 -0
- data/spec/extensions/null_dataset_spec.rb +1 -1
- data/spec/extensions/pg_array_spec.rb +48 -1
- data/spec/extensions/pg_hstore_ops_spec.rb +10 -2
- data/spec/extensions/pg_hstore_spec.rb +5 -0
- data/spec/extensions/pg_inet_spec.rb +5 -0
- data/spec/extensions/pg_interval_spec.rb +7 -3
- data/spec/extensions/pg_json_spec.rb +6 -1
- data/spec/extensions/pg_range_ops_spec.rb +4 -1
- data/spec/extensions/pg_range_spec.rb +5 -0
- data/spec/extensions/pg_row_plugin_spec.rb +13 -0
- data/spec/extensions/pg_row_spec.rb +28 -19
- data/spec/extensions/pg_typecast_on_load_spec.rb +6 -1
- data/spec/extensions/prepared_statements_associations_spec.rb +1 -1
- data/spec/extensions/query_literals_spec.rb +1 -1
- data/spec/extensions/rcte_tree_spec.rb +2 -2
- data/spec/extensions/schema_spec.rb +2 -2
- data/spec/extensions/serialization_modification_detection_spec.rb +8 -0
- data/spec/extensions/serialization_spec.rb +15 -1
- data/spec/extensions/sharding_spec.rb +1 -1
- data/spec/extensions/single_table_inheritance_spec.rb +1 -1
- data/spec/extensions/static_cache_spec.rb +59 -9
- data/spec/extensions/tactical_eager_loading_spec.rb +19 -4
- data/spec/extensions/update_primary_key_spec.rb +17 -1
- data/spec/extensions/validation_class_methods_spec.rb +25 -0
- data/spec/extensions/validation_helpers_spec.rb +59 -3
- data/spec/integration/associations_test.rb +5 -5
- data/spec/integration/eager_loader_test.rb +32 -63
- data/spec/integration/model_test.rb +2 -2
- data/spec/integration/plugin_test.rb +88 -56
- data/spec/integration/prepared_statement_test.rb +1 -1
- data/spec/integration/schema_test.rb +1 -1
- data/spec/integration/timezone_test.rb +0 -1
- data/spec/integration/transaction_test.rb +0 -1
- data/spec/model/association_reflection_spec.rb +1 -1
- data/spec/model/associations_spec.rb +106 -84
- data/spec/model/base_spec.rb +4 -4
- data/spec/model/eager_loading_spec.rb +8 -8
- data/spec/model/model_spec.rb +27 -9
- data/spec/model/plugins_spec.rb +71 -0
- data/spec/model/record_spec.rb +99 -13
- metadata +12 -2
@@ -190,7 +190,7 @@ module Sequel
|
|
190
190
|
opts[:eager_loader_key] = left_pk unless opts.has_key?(:eager_loader_key)
|
191
191
|
left_pks = opts[:left_primary_keys] = Array(left_pk)
|
192
192
|
lpkc = opts[:left_primary_key_column] ||= left_pk
|
193
|
-
|
193
|
+
opts[:left_primary_key_columns] ||= Array(lpkc)
|
194
194
|
opts[:dataset] ||= lambda do
|
195
195
|
ds = opts.associated_dataset
|
196
196
|
opts.reverse_edges.each{|t| ds = ds.join(t[:table], Array(t[:left]).zip(Array(t[:right])), :table_alias=>t[:alias], :qualify=>:deep)}
|
@@ -267,7 +267,6 @@ module Sequel
|
|
267
267
|
lpks = ref.qualify(model.table_name, lpks)
|
268
268
|
edges = ref.edges
|
269
269
|
first, rest = edges.first, edges[1..-1]
|
270
|
-
last = edges.last
|
271
270
|
ds = model.db[first[:table]].select(*Array(ref.qualify(first[:table], first[:right])))
|
272
271
|
rest.each{|e| ds = ds.join(e[:table], e.fetch(:only_conditions, (Array(e[:right]).zip(Array(e[:left])) + e[:conditions])), :table_alias=>ds.unused_table_alias(e[:table]), :qualify=>:deep, &e[:block])}
|
273
272
|
last_alias = if rest.empty?
|
@@ -1,26 +1,16 @@
|
|
1
1
|
module Sequel
|
2
2
|
module Plugins
|
3
|
-
#
|
3
|
+
# The ManyToOnePkLookup plugin that modifies the internal association loading logic
|
4
4
|
# for many_to_one associations to use a simple primary key lookup on the associated
|
5
5
|
# class, which is generally faster as it uses mostly static SQL. Additional, if the
|
6
6
|
# associated class is caching primary key lookups, you get the benefit of a cached
|
7
7
|
# lookup.
|
8
8
|
#
|
9
|
-
# This plugin is generally not as fast as the prepared_statements_associations plugin
|
10
|
-
# in the case where the model is not caching primary key lookups, however, it is
|
11
|
-
# probably significantly faster if the model is caching primary key lookups. If
|
12
|
-
# the prepared_statements_associations plugin has been loaded first, this
|
13
|
-
# plugin will only use the primary key lookup code if the associated model is
|
14
|
-
# caching primary key lookups.
|
15
|
-
#
|
16
9
|
# This plugin attempts to determine cases where the primary key lookup would have
|
17
|
-
# different results than the regular lookup, and use the regular lookup in that case
|
18
|
-
#
|
19
|
-
#
|
10
|
+
# different results than the regular lookup, and use the regular lookup in that case.
|
11
|
+
# If you want to explicitly force whether or not to use primary key lookups for
|
12
|
+
# a given association, set the :many_to_one_pk_lookup association option.
|
20
13
|
#
|
21
|
-
# You can disable primary key lookups on a per association basis with this
|
22
|
-
# plugin using the :many_to_one_pk_lookup=>false association option.
|
23
|
-
#
|
24
14
|
# Usage:
|
25
15
|
#
|
26
16
|
# # Make all model subclass instances use primary key lookups for many_to_one
|
@@ -30,37 +20,31 @@ module Sequel
|
|
30
20
|
# # Do so for just the album class.
|
31
21
|
# Album.plugin :many_to_one_pk_lookup
|
32
22
|
module ManyToOnePkLookup
|
23
|
+
module ClassMethods
|
24
|
+
# Disable primary key lookup in cases where it will result in a different
|
25
|
+
# query than the association query.
|
26
|
+
def def_many_to_one(opts)
|
27
|
+
if !opts.has_key?(:many_to_one_pk_lookup) &&
|
28
|
+
(opts[:dataset] || opts[:conditions] || opts[:block] || opts[:select] ||
|
29
|
+
(opts.has_key?(:key) && opts[:key] == nil))
|
30
|
+
opts[:many_to_one_pk_lookup] = false
|
31
|
+
end
|
32
|
+
super
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
33
36
|
module InstanceMethods
|
34
37
|
private
|
35
38
|
|
36
|
-
# If the current association is a
|
39
|
+
# If the current association is a simple many_to_one association, use
|
37
40
|
# a simple primary key lookup on the associated model, which can benefit from
|
38
41
|
# caching if the associated model is using caching.
|
39
|
-
def _load_associated_object(opts, dynamic_opts)
|
40
|
-
klass = opts.associated_class
|
41
|
-
cache_lookup = opts.send(:cached_fetch, :many_to_one_pk_lookup) do
|
42
|
-
opts[:type] == :many_to_one &&
|
43
|
-
opts[:key] &&
|
44
|
-
opts.primary_key == klass.primary_key
|
45
|
-
end
|
46
|
-
if cache_lookup &&
|
47
|
-
!dynamic_opts[:callback] &&
|
48
|
-
(o = klass.send(:primary_key_lookup, ((fk = opts[:key]).is_a?(Array) ? fk.map{|c| send(c)} : send(fk))))
|
49
|
-
o
|
50
|
-
else
|
51
|
-
super
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
# Deal with the situation where the prepared_statements_associations plugin is
|
56
|
-
# loaded first, by using a primary key lookup for many_to_one associations if
|
57
|
-
# the associated class is using caching, and using the default code otherwise.
|
58
|
-
# This is done because the prepared_statements_associations code is probably faster
|
59
|
-
# than the primary key lookup this plugin uses if the model is not caching lookups,
|
60
|
-
# but probably slower if the model is caching lookups.
|
61
42
|
def _load_associated_objects(opts, dynamic_opts={})
|
62
|
-
|
63
|
-
|
43
|
+
return super unless opts.can_have_associated_objects?(self) && opts[:type] == :many_to_one
|
44
|
+
klass = opts.associated_class
|
45
|
+
if !dynamic_opts[:callback] &&
|
46
|
+
opts.send(:cached_fetch, :many_to_one_pk_lookup){opts.primary_key == klass.primary_key}
|
47
|
+
klass.send(:primary_key_lookup, ((fk = opts[:key]).is_a?(Array) ? fk.map{|c| send(c)} : send(fk)))
|
64
48
|
else
|
65
49
|
super
|
66
50
|
end
|
@@ -38,11 +38,7 @@ module Sequel
|
|
38
38
|
# The column holding the version of the lock
|
39
39
|
attr_accessor :lock_column
|
40
40
|
|
41
|
-
|
42
|
-
def inherited(subclass)
|
43
|
-
super
|
44
|
-
subclass.lock_column = lock_column
|
45
|
-
end
|
41
|
+
Plugins.inherited_instance_variables(self, :@lock_column=>nil)
|
46
42
|
end
|
47
43
|
|
48
44
|
module InstanceMethods
|
@@ -100,7 +100,9 @@ module Sequel
|
|
100
100
|
module ClassMethods
|
101
101
|
# Register the model's row type with the database.
|
102
102
|
def register_row_type
|
103
|
-
|
103
|
+
table = dataset.first_source_table
|
104
|
+
db.register_row_type(table, :converter=>self, :typecaster=>method(:new))
|
105
|
+
db.instance_variable_get(:@schema_type_classes)[:"pg_row_#{table}"] = self
|
104
106
|
end
|
105
107
|
end
|
106
108
|
|
@@ -113,7 +115,7 @@ module Sequel
|
|
113
115
|
sql << ROW
|
114
116
|
ds.literal_append(sql, values.values_at(*columns))
|
115
117
|
sql << CAST
|
116
|
-
ds.quote_schema_table_append(sql, model.
|
118
|
+
ds.quote_schema_table_append(sql, model.dataset.first_source_table)
|
117
119
|
end
|
118
120
|
end
|
119
121
|
end
|
@@ -41,11 +41,7 @@ module Sequel
|
|
41
41
|
@pg_typecast_on_load_columns.concat(columns)
|
42
42
|
end
|
43
43
|
|
44
|
-
|
45
|
-
def inherited(subclass)
|
46
|
-
super
|
47
|
-
subclass.instance_variable_set(:@pg_typecast_on_load_columns, pg_typecast_on_load_columns.dup)
|
48
|
-
end
|
44
|
+
Plugins.inherited_instance_variables(self, :@pg_typecast_on_load_columns=>:dup)
|
49
45
|
end
|
50
46
|
|
51
47
|
module InstanceMethods
|
@@ -53,8 +49,8 @@ module Sequel
|
|
53
49
|
# object, and use it to convert the value.
|
54
50
|
def set_values(values)
|
55
51
|
model.pg_typecast_on_load_columns.each do |c|
|
56
|
-
if (v = values[c]).is_a?(String) && (oid = db_schema[c][:oid])
|
57
|
-
values[c] =
|
52
|
+
if (v = values[c]).is_a?(String) && (oid = db_schema[c][:oid]) && (pr = db.conversion_procs[oid])
|
53
|
+
values[c] = pr.call(v)
|
58
54
|
end
|
59
55
|
end
|
60
56
|
super
|
@@ -36,11 +36,7 @@ module Sequel
|
|
36
36
|
end
|
37
37
|
|
38
38
|
module ClassMethods
|
39
|
-
|
40
|
-
def inherited(subclass)
|
41
|
-
super
|
42
|
-
subclass.instance_variable_set(:@prepared_statements, :insert=>{}, :insert_select=>{}, :update=>{}, :lookup_sql=>{}, :fixed=>{})
|
43
|
-
end
|
39
|
+
Plugins.inherited_instance_variables(self, :@prepared_statements=>lambda{|v| {:insert=>{}, :insert_select=>{}, :update=>{}, :lookup_sql=>{}, :fixed=>{}}})
|
44
40
|
|
45
41
|
private
|
46
42
|
|
@@ -33,17 +33,8 @@ module Sequel
|
|
33
33
|
# that can be created is 2^N (where N is the number of free columns).
|
34
34
|
attr_reader :prepared_statements_column_defaults
|
35
35
|
|
36
|
-
|
37
|
-
|
38
|
-
subclass.instance_variable_set(:@prepared_statements_column_defaults, @prepared_statements_column_defaults) if @prepared_statements_column_defaults && !subclass.prepared_statements_column_defaults
|
39
|
-
end
|
40
|
-
|
41
|
-
# Set the column defaults to use when creating on the subclass.
|
42
|
-
def set_dataset(*)
|
43
|
-
x = super
|
44
|
-
set_prepared_statements_column_defaults
|
45
|
-
x
|
46
|
-
end
|
36
|
+
Plugins.inherited_instance_variables(self, :@prepared_statements_column_defaults=>:dup)
|
37
|
+
Plugins.after_set_dataset(self, :set_prepared_statements_column_defaults)
|
47
38
|
|
48
39
|
private
|
49
40
|
|
@@ -190,7 +190,7 @@ module Sequel
|
|
190
190
|
elds = elds.select_append(ka) unless elds.opts[:select] == nil
|
191
191
|
elds.all do |obj|
|
192
192
|
opk = obj[prkey]
|
193
|
-
if
|
193
|
+
if parent_map.has_key?(opk)
|
194
194
|
if idm_obj = parent_map[opk]
|
195
195
|
idm_obj.values[ka] = obj.values[ka]
|
196
196
|
obj = idm_obj
|
@@ -298,7 +298,7 @@ module Sequel
|
|
298
298
|
end
|
299
299
|
|
300
300
|
opk = obj[prkey]
|
301
|
-
if
|
301
|
+
if parent_map.has_key?(opk)
|
302
302
|
if idm_obj = parent_map[opk]
|
303
303
|
idm_obj.values[ka] = obj.values[ka]
|
304
304
|
obj = idm_obj
|
@@ -30,11 +30,11 @@ module Sequel
|
|
30
30
|
#
|
31
31
|
# == Example
|
32
32
|
#
|
33
|
-
# require
|
34
|
-
# # Require json, as the plugin doesn't require it for you.
|
33
|
+
# # Require json if you plan to use it, as the plugin doesn't require it for you.
|
35
34
|
# require 'json'
|
36
35
|
#
|
37
|
-
# # Register custom serializer/deserializer pair
|
36
|
+
# # Register custom serializer/deserializer pair, if desired
|
37
|
+
# require 'sequel/plugins/serialization'
|
38
38
|
# Sequel::Plugins::Serialization.register_format(:reverse,
|
39
39
|
# lambda{|v| v.reverse},
|
40
40
|
# lambda{|v| v.reverse})
|
@@ -111,16 +111,7 @@ module Sequel
|
|
111
111
|
# call be overridden and call super to get the serialization behavior
|
112
112
|
attr_accessor :serialization_module
|
113
113
|
|
114
|
-
|
115
|
-
def inherited(subclass)
|
116
|
-
super
|
117
|
-
sm = serialization_map.dup
|
118
|
-
dsm = deserialization_map.dup
|
119
|
-
subclass.instance_eval do
|
120
|
-
@deserialization_map = dsm
|
121
|
-
@serialization_map = sm
|
122
|
-
end
|
123
|
-
end
|
114
|
+
Plugins.inherited_instance_variables(self, :@deserialization_map=>:dup, :@serialization_map=>:dup)
|
124
115
|
|
125
116
|
# Create instance level reader that deserializes column values on request,
|
126
117
|
# and instance level writer that stores new deserialized values.
|
@@ -154,6 +145,8 @@ module Sequel
|
|
154
145
|
define_method(column) do
|
155
146
|
if deserialized_values.has_key?(column)
|
156
147
|
deserialized_values[column]
|
148
|
+
elsif frozen?
|
149
|
+
deserialize_value(column, super())
|
157
150
|
else
|
158
151
|
deserialized_values[column] = deserialize_value(column, super())
|
159
152
|
end
|
@@ -179,6 +172,11 @@ module Sequel
|
|
179
172
|
@deserialized_values ||= {}
|
180
173
|
end
|
181
174
|
|
175
|
+
def freeze
|
176
|
+
deserialized_values.freeze
|
177
|
+
super
|
178
|
+
end
|
179
|
+
|
182
180
|
# Initialization the deserialized values for objects retrieved from the database.
|
183
181
|
def set_values(hash)
|
184
182
|
@deserialized_values.clear if @deserialized_values
|
@@ -40,10 +40,18 @@ module Sequel
|
|
40
40
|
# Detect which serialized columns have changed.
|
41
41
|
def changed_columns
|
42
42
|
cc = super
|
43
|
+
cc = cc.dup if frozen?
|
43
44
|
deserialized_values.each{|c, v| cc << c if !cc.include?(c) && original_deserialized_value(c) != v}
|
44
45
|
cc
|
45
46
|
end
|
46
47
|
|
48
|
+
# Freeze the original deserialized values when freezing the instance.
|
49
|
+
def freeze
|
50
|
+
@original_deserialized_values ||= {}
|
51
|
+
@original_deserialized_values.freeze
|
52
|
+
super
|
53
|
+
end
|
54
|
+
|
47
55
|
private
|
48
56
|
|
49
57
|
# For new objects, serialize any existing deserialized values so that changes can
|
@@ -55,7 +63,11 @@ module Sequel
|
|
55
63
|
|
56
64
|
# Return the original deserialized value of the column, caching it to improve performance.
|
57
65
|
def original_deserialized_value(column)
|
58
|
-
|
66
|
+
if frozen?
|
67
|
+
@original_deserialized_values[column] || deserialize_value(column, self[column])
|
68
|
+
else
|
69
|
+
(@original_deserialized_values ||= {})[column] ||= deserialize_value(column, self[column])
|
70
|
+
end
|
59
71
|
end
|
60
72
|
end
|
61
73
|
end
|
@@ -77,9 +77,9 @@ module Sequel
|
|
77
77
|
@sti_model_map = opts[:model_map] || lambda{|v| v if v && v != ''}
|
78
78
|
@sti_key_map = if km = opts[:key_map]
|
79
79
|
if km.is_a?(Hash)
|
80
|
-
h = Hash.new do |
|
80
|
+
h = Hash.new do |h1,k|
|
81
81
|
unless k.is_a?(String)
|
82
|
-
|
82
|
+
h1[k.to_s]
|
83
83
|
else
|
84
84
|
[]
|
85
85
|
end
|
@@ -93,9 +93,9 @@ module Sequel
|
|
93
93
|
km
|
94
94
|
end
|
95
95
|
elsif sti_model_map.is_a?(Hash)
|
96
|
-
h = Hash.new do |
|
96
|
+
h = Hash.new do |h1,k|
|
97
97
|
unless k.is_a?(String)
|
98
|
-
|
98
|
+
h1[k.to_s]
|
99
99
|
else
|
100
100
|
[]
|
101
101
|
end
|
@@ -35,6 +35,15 @@ module Sequel
|
|
35
35
|
@all.dup
|
36
36
|
end
|
37
37
|
|
38
|
+
# Get the number of records in the cache, without issuing a database query.
|
39
|
+
def count(*a, &block)
|
40
|
+
if a.empty? && !block
|
41
|
+
@all.size
|
42
|
+
else
|
43
|
+
super
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
38
47
|
# Return the frozen object with the given pk, or nil if no such object exists
|
39
48
|
# in the cache, without issuing a database query.
|
40
49
|
def cache_get_pk(pk)
|
@@ -47,33 +56,72 @@ module Sequel
|
|
47
56
|
@all.each(&block)
|
48
57
|
end
|
49
58
|
|
50
|
-
#
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
59
|
+
# Use the cache instead of a query to get the results.
|
60
|
+
def map(column=nil, &block)
|
61
|
+
if column
|
62
|
+
raise(Error, "Cannot provide both column and block to map") if block
|
63
|
+
if column.is_a?(Array)
|
64
|
+
@all.map{|r| r.values.values_at(*column)}
|
65
|
+
else
|
66
|
+
@all.map{|r| r[column]}
|
67
|
+
end
|
56
68
|
else
|
57
|
-
|
69
|
+
@all.map(&(Proc.new if block_given?))
|
58
70
|
end
|
59
71
|
end
|
60
72
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
73
|
+
Plugins.after_set_dataset(self, :load_cache)
|
74
|
+
|
75
|
+
# Use the cache instead of a query to get the results.
|
76
|
+
def to_hash(key_column = nil, value_column = nil)
|
77
|
+
return cache.dup if key_column.nil? && value_column.nil?
|
78
|
+
|
79
|
+
h = {}
|
80
|
+
if value_column
|
81
|
+
if value_column.is_a?(Array)
|
82
|
+
if key_column.is_a?(Array)
|
83
|
+
each{|r| h[r.values.values_at(*key_column)] = r.values.values_at(*value_column)}
|
84
|
+
else
|
85
|
+
each{|r| h[r[key_column]] = r.values.values_at(*value_column)}
|
86
|
+
end
|
87
|
+
else
|
88
|
+
if key_column.is_a?(Array)
|
89
|
+
each{|r| h[r.values.values_at(*key_column)] = r[value_column]}
|
90
|
+
else
|
91
|
+
each{|r| h[r[key_column]] = r[value_column]}
|
92
|
+
end
|
93
|
+
end
|
94
|
+
elsif key_column.is_a?(Array)
|
95
|
+
each{|r| h[r.values.values_at(*key_column)] = r}
|
96
|
+
else
|
97
|
+
each{|r| h[r[key_column]] = r}
|
98
|
+
end
|
99
|
+
h
|
66
100
|
end
|
67
101
|
|
68
|
-
#
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
102
|
+
# Use the cache instead of a query to get the results
|
103
|
+
def to_hash_groups(key_column, value_column = nil)
|
104
|
+
h = {}
|
105
|
+
if value_column
|
106
|
+
if value_column.is_a?(Array)
|
107
|
+
if key_column.is_a?(Array)
|
108
|
+
each{|r| (h[r.values.values_at(*key_column)] ||= []) << r.values.values_at(*value_column)}
|
109
|
+
else
|
110
|
+
each{|r| (h[r[key_column]] ||= []) << r.values.values_at(*value_column)}
|
111
|
+
end
|
112
|
+
else
|
113
|
+
if key_column.is_a?(Array)
|
114
|
+
each{|r| (h[r.values.values_at(*key_column)] ||= []) << r[value_column]}
|
115
|
+
else
|
116
|
+
each{|r| (h[r[key_column]] ||= []) << r[value_column]}
|
117
|
+
end
|
118
|
+
end
|
119
|
+
elsif key_column.is_a?(Array)
|
120
|
+
each{|r| (h[r.values.values_at(*key_column)] ||= []) << r}
|
74
121
|
else
|
75
|
-
|
122
|
+
each{|r| (h[r[key_column]] ||= []) << r}
|
76
123
|
end
|
124
|
+
h
|
77
125
|
end
|
78
126
|
|
79
127
|
private
|
@@ -22,34 +22,24 @@ module Sequel
|
|
22
22
|
# # Make the Album class strip strings
|
23
23
|
# Album.plugin :string_stripper
|
24
24
|
module StringStripper
|
25
|
-
|
25
|
+
def self.apply(model)
|
26
|
+
model.plugin(:input_transformer, :string_stripper){|v| (v.is_a?(String) && !v.is_a?(SQL::Blob)) ? v.strip : v}
|
27
|
+
end
|
26
28
|
def self.configure(model)
|
27
|
-
model.
|
28
|
-
model.send(:set_skipped_string_stripping_columns)
|
29
|
+
model.instance_eval{set_skipped_string_stripping_columns if @dataset}
|
29
30
|
end
|
30
31
|
|
31
32
|
module ClassMethods
|
32
|
-
|
33
|
-
def inherited(subclass)
|
34
|
-
subclass.instance_variable_set(:@skipped_string_stripping_columns, @skipped_string_stripping_columns.dup)
|
35
|
-
super
|
36
|
-
end
|
37
|
-
|
38
|
-
# Set blob columns as skipping stripping when plugin is loaded.
|
39
|
-
def set_dataset(*)
|
40
|
-
res = super
|
41
|
-
set_skipped_string_stripping_columns
|
42
|
-
res
|
43
|
-
end
|
33
|
+
Plugins.after_set_dataset(self, :set_skipped_string_stripping_columns)
|
44
34
|
|
45
35
|
# Skip stripping for the given columns.
|
46
36
|
def skip_string_stripping(*columns)
|
47
|
-
|
37
|
+
skip_input_transformer(:string_stripper, *columns)
|
48
38
|
end
|
49
39
|
|
50
40
|
# Return true if the column should not have values stripped.
|
51
41
|
def skip_string_stripping?(column)
|
52
|
-
|
42
|
+
skip_input_transformer?(:string_stripper, column)
|
53
43
|
end
|
54
44
|
|
55
45
|
private
|
@@ -62,16 +52,6 @@ module Sequel
|
|
62
52
|
end
|
63
53
|
end
|
64
54
|
end
|
65
|
-
|
66
|
-
module InstanceMethods
|
67
|
-
# Strip value if it is a non-blob string and the model hasn't been set
|
68
|
-
# to skip stripping for the column, before attempting to assign
|
69
|
-
# it to the model's values.
|
70
|
-
def []=(k, v)
|
71
|
-
v = v.strip if v.is_a?(String) && !v.is_a?(SQL::Blob) && !model.skip_string_stripping?(k)
|
72
|
-
super(k, v)
|
73
|
-
end
|
74
|
-
end
|
75
55
|
end
|
76
56
|
end
|
77
57
|
end
|