sequel 3.46.0 → 3.47.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 +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
|
@@ -33,12 +33,7 @@ module Sequel
|
|
|
33
33
|
end
|
|
34
34
|
|
|
35
35
|
module ClassMethods
|
|
36
|
-
|
|
37
|
-
def set_dataset(*args)
|
|
38
|
-
super
|
|
39
|
-
create_boolean_readers
|
|
40
|
-
self
|
|
41
|
-
end
|
|
36
|
+
Plugins.after_set_dataset(self, :create_boolean_readers)
|
|
42
37
|
|
|
43
38
|
private
|
|
44
39
|
|
|
@@ -70,18 +70,7 @@ module Sequel
|
|
|
70
70
|
"#{self}:#{Array(pk).join(',')}"
|
|
71
71
|
end
|
|
72
72
|
|
|
73
|
-
|
|
74
|
-
def inherited(subclass)
|
|
75
|
-
super
|
|
76
|
-
store = @cache_store
|
|
77
|
-
ttl = @cache_ttl
|
|
78
|
-
cache_ignore_exceptions = @cache_ignore_exceptions
|
|
79
|
-
subclass.instance_eval do
|
|
80
|
-
@cache_store = store
|
|
81
|
-
@cache_ttl = ttl
|
|
82
|
-
@cache_ignore_exceptions = cache_ignore_exceptions
|
|
83
|
-
end
|
|
84
|
-
end
|
|
73
|
+
Plugins.inherited_instance_variables(self, :@cache_store=>nil, :@cache_ttl=>nil, :@cache_ignore_exceptions=>nil)
|
|
85
74
|
|
|
86
75
|
# Set the time to live for the cache store, in seconds (default is 3600, # so 1 hour).
|
|
87
76
|
def set_cache_ttl(ttl)
|
|
@@ -92,7 +81,11 @@ module Sequel
|
|
|
92
81
|
|
|
93
82
|
# Delete the entry with the matching key from the cache
|
|
94
83
|
def cache_delete(ck)
|
|
95
|
-
@
|
|
84
|
+
if @cache_ignore_exceptions
|
|
85
|
+
@cache_store.delete(ck) rescue nil
|
|
86
|
+
else
|
|
87
|
+
@cache_store.delete(ck)
|
|
88
|
+
end
|
|
96
89
|
nil
|
|
97
90
|
end
|
|
98
91
|
|
|
@@ -187,6 +187,7 @@ module Sequel
|
|
|
187
187
|
# Delete the row from all backing tables, starting from the
|
|
188
188
|
# most recent table and going through all superclasses.
|
|
189
189
|
def delete
|
|
190
|
+
raise Sequel::Error, "can't delete frozen object" if frozen?
|
|
190
191
|
m = model
|
|
191
192
|
m.cti_tables.reverse.each do |table|
|
|
192
193
|
m.db.from(table).filter(m.primary_key=>pk).delete
|
|
@@ -124,12 +124,7 @@ module Sequel
|
|
|
124
124
|
define_composition_accessor(name, opts)
|
|
125
125
|
end
|
|
126
126
|
|
|
127
|
-
|
|
128
|
-
def inherited(subclass)
|
|
129
|
-
super
|
|
130
|
-
c = compositions.dup
|
|
131
|
-
subclass.instance_eval{@compositions = c}
|
|
132
|
-
end
|
|
127
|
+
Plugins.inherited_instance_variables(self, :@compositions=>:dup)
|
|
133
128
|
|
|
134
129
|
# Define getter and setter methods for the composition object.
|
|
135
130
|
def define_composition_accessor(name, opts={})
|
|
@@ -137,7 +132,13 @@ module Sequel
|
|
|
137
132
|
composer = opts[:composer]
|
|
138
133
|
composition_module.class_eval do
|
|
139
134
|
define_method(name) do
|
|
140
|
-
compositions.
|
|
135
|
+
if compositions.has_key?(name)
|
|
136
|
+
compositions[name]
|
|
137
|
+
elsif frozen?
|
|
138
|
+
instance_eval(&composer)
|
|
139
|
+
else
|
|
140
|
+
compositions[name] = instance_eval(&composer)
|
|
141
|
+
end
|
|
141
142
|
end
|
|
142
143
|
define_method("#{name}=") do |v|
|
|
143
144
|
modified!
|
|
@@ -165,6 +166,12 @@ module Sequel
|
|
|
165
166
|
def compositions
|
|
166
167
|
@compositions ||= {}
|
|
167
168
|
end
|
|
169
|
+
|
|
170
|
+
# Freeze compositions hash when freezing model instance.
|
|
171
|
+
def freeze
|
|
172
|
+
compositions.freeze
|
|
173
|
+
super
|
|
174
|
+
end
|
|
168
175
|
end
|
|
169
176
|
end
|
|
170
177
|
end
|
|
@@ -61,19 +61,8 @@ module Sequel
|
|
|
61
61
|
# The name of the table containing the constraint validations metadata.
|
|
62
62
|
attr_reader :constraint_validations_table
|
|
63
63
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
super
|
|
67
|
-
subclass.instance_variable_set(:@constraint_validations_table, @constraint_validations_table)
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
# Parse the constraint validations from the database whenever the dataset
|
|
71
|
-
# changes.
|
|
72
|
-
def set_dataset(*)
|
|
73
|
-
r = super
|
|
74
|
-
parse_constraint_validations
|
|
75
|
-
r
|
|
76
|
-
end
|
|
64
|
+
Plugins.inherited_instance_variables(self, :@constraint_validations_table=>nil)
|
|
65
|
+
Plugins.after_set_dataset(self, :parse_constraint_validations)
|
|
77
66
|
|
|
78
67
|
private
|
|
79
68
|
|
|
@@ -28,12 +28,7 @@ module Sequel
|
|
|
28
28
|
# this hash to set specific default values, by default the ones will be parsed from the database.
|
|
29
29
|
attr_reader :default_values
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
def set_dataset(*)
|
|
33
|
-
x = super
|
|
34
|
-
set_default_values
|
|
35
|
-
x
|
|
36
|
-
end
|
|
31
|
+
Plugins.after_set_dataset(self, :set_default_values)
|
|
37
32
|
|
|
38
33
|
private
|
|
39
34
|
|
data/lib/sequel/plugins/dirty.rb
CHANGED
|
@@ -101,6 +101,14 @@ module Sequel
|
|
|
101
101
|
@initial_values ||= {}
|
|
102
102
|
end
|
|
103
103
|
|
|
104
|
+
# Freeze internal data structures
|
|
105
|
+
def freeze
|
|
106
|
+
initial_values.freeze
|
|
107
|
+
missing_initial_values.freeze
|
|
108
|
+
@previous_changes.freeze if @previous_changes
|
|
109
|
+
super
|
|
110
|
+
end
|
|
111
|
+
|
|
104
112
|
# Reset the column to its initial value. If the column was not set
|
|
105
113
|
# initial, removes it from the values.
|
|
106
114
|
#
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
module Sequel
|
|
2
|
+
module Plugins
|
|
3
|
+
# The error_splitter plugin automatically splits errors entries related to
|
|
4
|
+
# multiple columns to have separate error entries, one per column. For example,
|
|
5
|
+
# a multiple column uniqueness entry:
|
|
6
|
+
#
|
|
7
|
+
# validates_unique([:artist_id, :name])
|
|
8
|
+
#
|
|
9
|
+
# would by default result in errors entries such as:
|
|
10
|
+
#
|
|
11
|
+
# {[:artist_id, :name]=>'is already taken'}
|
|
12
|
+
#
|
|
13
|
+
# This plugin transforms those errors into:
|
|
14
|
+
#
|
|
15
|
+
# {:artist_id=>'is already taken', :name=>'is already taken'}
|
|
16
|
+
#
|
|
17
|
+
# The main reason to split errors is if you have a list of fields that you
|
|
18
|
+
# are checking for validation errors. If you don't split the errors, then:
|
|
19
|
+
#
|
|
20
|
+
# errors.on(:artist_id)
|
|
21
|
+
#
|
|
22
|
+
# would not return the uniqueness error.
|
|
23
|
+
#
|
|
24
|
+
# Usage:
|
|
25
|
+
#
|
|
26
|
+
# # Make all model subclass instances split errors (called before loading subclasses)
|
|
27
|
+
# Sequel::Model.plugin :error_splitter
|
|
28
|
+
#
|
|
29
|
+
# # Make the Album class split errors
|
|
30
|
+
# Album.plugin :error_splitter
|
|
31
|
+
module ErrorSplitter
|
|
32
|
+
module InstanceMethods
|
|
33
|
+
# If the model instance is not valid, go through all of the errors entries. For
|
|
34
|
+
# any that apply to multiple columns, remove them and add separate error entries,
|
|
35
|
+
# one per column.
|
|
36
|
+
def _valid?(*)
|
|
37
|
+
v = super
|
|
38
|
+
unless v
|
|
39
|
+
errors.keys.select{|k| k.is_a?(Array)}.each do |ks|
|
|
40
|
+
msgs = errors.delete(ks)
|
|
41
|
+
ks.each do |k|
|
|
42
|
+
msgs.each do |msg|
|
|
43
|
+
errors.add(k, msg)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
v
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
@@ -32,11 +32,7 @@ module Sequel
|
|
|
32
32
|
# The string encoding to force on a column string values
|
|
33
33
|
attr_accessor :forced_encoding
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
def inherited(subclass)
|
|
37
|
-
super
|
|
38
|
-
subclass.forced_encoding = forced_encoding
|
|
39
|
-
end
|
|
35
|
+
Plugins.inherited_instance_variables(self, :@forced_encoding=>nil)
|
|
40
36
|
end
|
|
41
37
|
|
|
42
38
|
module InstanceMethods
|
|
@@ -91,12 +91,7 @@ module Sequel
|
|
|
91
91
|
@hooks[hook].each{|k,v| yield v}
|
|
92
92
|
end
|
|
93
93
|
|
|
94
|
-
|
|
95
|
-
def inherited(subclass)
|
|
96
|
-
hooks = subclass.instance_variable_set(:@hooks, {})
|
|
97
|
-
instance_variable_get(:@hooks).each{|k,v| hooks[k] = v.dup}
|
|
98
|
-
super
|
|
99
|
-
end
|
|
94
|
+
Plugins.inherited_instance_variables(self, :@hooks=>:hash_dup)
|
|
100
95
|
|
|
101
96
|
private
|
|
102
97
|
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
module Sequel
|
|
2
|
+
module Plugins
|
|
3
|
+
# InputTransformer is a plugin that allows generic transformations
|
|
4
|
+
# of input values in model column setters. Example:
|
|
5
|
+
#
|
|
6
|
+
# Album.plugin :input_transformer
|
|
7
|
+
# Album.add_input_transformer(:reverser){|v| v.is_a?(String) ? v.reverse : v}
|
|
8
|
+
# album = Album.new(:name=>'foo')
|
|
9
|
+
# album.name # => 'oof'
|
|
10
|
+
#
|
|
11
|
+
# You can specifically set some columns to skip some input
|
|
12
|
+
# input transformers:
|
|
13
|
+
#
|
|
14
|
+
# Album.skip_input_transformer(:reverser, :foo)
|
|
15
|
+
# Album.new(:foo=>'bar').foo # => 'bar'
|
|
16
|
+
#
|
|
17
|
+
# Usage:
|
|
18
|
+
#
|
|
19
|
+
# # Make all model subclass instances support input transformers (called before loading subclasses)
|
|
20
|
+
# Sequel::Model.plugin :input_transformer
|
|
21
|
+
#
|
|
22
|
+
# # Make the Album class support input transformers
|
|
23
|
+
# Album.plugin :input_transformer
|
|
24
|
+
module InputTransformer
|
|
25
|
+
def self.apply(model, *)
|
|
26
|
+
model.instance_eval do
|
|
27
|
+
@input_transformers = {}
|
|
28
|
+
@input_transformer_order = []
|
|
29
|
+
@skip_input_transformer_columns = {}
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# If an input transformer is given in the plugin call,
|
|
34
|
+
# add it as a transformer
|
|
35
|
+
def self.configure(model, transformer_name=nil, &block)
|
|
36
|
+
model.add_input_transformer(transformer_name, &block) if transformer_name || block
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
module ClassMethods
|
|
40
|
+
# Hash of input transformer name symbols to transformer callables.
|
|
41
|
+
attr_reader :input_transformers
|
|
42
|
+
|
|
43
|
+
# The order in which to call the input transformers.
|
|
44
|
+
attr_reader :input_transformer_order
|
|
45
|
+
|
|
46
|
+
Plugins.inherited_instance_variables(self, :@skip_input_transformer_columns=>:hash_dup, :@input_transformers=>:dup, :@input_transformer_order=>:dup)
|
|
47
|
+
|
|
48
|
+
# Add an input transformer to this model.
|
|
49
|
+
def add_input_transformer(transformer_name, &block)
|
|
50
|
+
raise(Error, 'must provide both transformer name and block when adding input transformer') unless transformer_name && block
|
|
51
|
+
@input_transformers[transformer_name] = block
|
|
52
|
+
@input_transformer_order.unshift(transformer_name)
|
|
53
|
+
@skip_input_transformer_columns[transformer_name] = []
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Set columns that the transformer should skip.
|
|
57
|
+
def skip_input_transformer(transformer_name, *columns)
|
|
58
|
+
@skip_input_transformer_columns[transformer_name].concat(columns).uniq!
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Return true if the transformer should not be called for the given column.
|
|
62
|
+
def skip_input_transformer?(transformer_name, column)
|
|
63
|
+
@skip_input_transformer_columns[transformer_name].include?(column)
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
module InstanceMethods
|
|
68
|
+
# Transform the input using all of the transformers, except those explicitly
|
|
69
|
+
# skipped, before setting the value in the model object.
|
|
70
|
+
def []=(k, v)
|
|
71
|
+
model.input_transformer_order.each do |transformer_name|
|
|
72
|
+
v = model.input_transformers[transformer_name].call(v) unless model.skip_input_transformer?(transformer_name, k)
|
|
73
|
+
end
|
|
74
|
+
super
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
@@ -58,6 +58,12 @@ module Sequel
|
|
|
58
58
|
super
|
|
59
59
|
clear_instance_filters
|
|
60
60
|
end
|
|
61
|
+
|
|
62
|
+
# Freeze the instance filters when freezing the object
|
|
63
|
+
def freeze
|
|
64
|
+
instance_filters.freeze
|
|
65
|
+
super
|
|
66
|
+
end
|
|
61
67
|
|
|
62
68
|
# Add an instance filter to the array of instance filters
|
|
63
69
|
# Both the arguments given and the block are passed to the
|
|
@@ -85,7 +91,7 @@ module Sequel
|
|
|
85
91
|
|
|
86
92
|
# Apply the instance filters to the given dataset
|
|
87
93
|
def apply_instance_filters(ds)
|
|
88
|
-
instance_filters.inject(ds){|
|
|
94
|
+
instance_filters.inject(ds){|ds1, i| ds1.filter(*i[0], &i[1])}
|
|
89
95
|
end
|
|
90
96
|
|
|
91
97
|
# Clear the instance filters.
|
|
@@ -29,7 +29,13 @@ module Sequel
|
|
|
29
29
|
BEFORE_HOOKS = Sequel::Model::BEFORE_HOOKS
|
|
30
30
|
AFTER_HOOKS = Sequel::Model::AFTER_HOOKS - [:after_initialize]
|
|
31
31
|
HOOKS = BEFORE_HOOKS + AFTER_HOOKS
|
|
32
|
-
HOOKS.each{|h| class_eval(
|
|
32
|
+
HOOKS.each{|h| class_eval(<<-END , __FILE__, __LINE__+1)}
|
|
33
|
+
def #{h}_hook(&block)
|
|
34
|
+
raise Sequel::Error, "can't add hooks to frozen object" if frozen?
|
|
35
|
+
add_instance_hook(:#{h}, &block)
|
|
36
|
+
self
|
|
37
|
+
end
|
|
38
|
+
END
|
|
33
39
|
|
|
34
40
|
BEFORE_HOOKS.each{|h| class_eval("def #{h}; run_before_instance_hooks(:#{h}) == false ? false : super end", __FILE__, __LINE__)}
|
|
35
41
|
AFTER_HOOKS.each{|h| class_eval(<<-END, __FILE__, __LINE__ + 1)}
|
|
@@ -175,18 +175,13 @@ module Sequel
|
|
|
175
175
|
new.from_json_node(hash, {:all_columns=>true, :all_associations=>true}.merge(opts))
|
|
176
176
|
end
|
|
177
177
|
|
|
178
|
-
|
|
179
|
-
def to_json(*a)
|
|
180
|
-
dataset.to_json(*a)
|
|
181
|
-
end
|
|
182
|
-
|
|
183
|
-
# Copy the current model object's default json options into the subclass.
|
|
184
|
-
def inherited(subclass)
|
|
185
|
-
super
|
|
178
|
+
Plugins.inherited_instance_variables(self, :@json_serializer_opts=>lambda do |json_serializer_opts|
|
|
186
179
|
opts = {}
|
|
187
180
|
json_serializer_opts.each{|k, v| opts[k] = (v.is_a?(Array) || v.is_a?(Hash)) ? v.dup : v}
|
|
188
|
-
|
|
189
|
-
end
|
|
181
|
+
opts
|
|
182
|
+
end)
|
|
183
|
+
|
|
184
|
+
Plugins.def_dataset_methods(self, :to_json)
|
|
190
185
|
end
|
|
191
186
|
|
|
192
187
|
module InstanceMethods
|
|
@@ -5,7 +5,7 @@ module Sequel
|
|
|
5
5
|
# is needed after the instance has been retrieved, a database query is made to
|
|
6
6
|
# retreive the value of the attribute.
|
|
7
7
|
#
|
|
8
|
-
# This plugin depends on the
|
|
8
|
+
# This plugin depends on the tactical_eager_loading plugin, and allows you to
|
|
9
9
|
# eagerly load lazy attributes for all objects retrieved with the current object.
|
|
10
10
|
# So the following code should issue one query to get the albums and one query to
|
|
11
11
|
# get the reviews for all of those albums:
|
|
@@ -20,9 +20,8 @@ module Sequel
|
|
|
20
20
|
# # You can specify multiple columns to lazily load:
|
|
21
21
|
# Album.plugin :lazy_attributes, :review, :tracklist
|
|
22
22
|
module LazyAttributes
|
|
23
|
-
# Lazy attributes requires the
|
|
23
|
+
# Lazy attributes requires the tactical_eager_loading plugin
|
|
24
24
|
def self.apply(model, *attrs)
|
|
25
|
-
model.plugin :identity_map
|
|
26
25
|
model.plugin :tactical_eager_loading
|
|
27
26
|
end
|
|
28
27
|
|
|
@@ -51,7 +50,7 @@ module Sequel
|
|
|
51
50
|
include(self.lazy_attributes_module ||= Module.new) unless lazy_attributes_module
|
|
52
51
|
lazy_attributes_module.class_eval do
|
|
53
52
|
define_method(a) do
|
|
54
|
-
if !values.
|
|
53
|
+
if !values.has_key?(a) && !new?
|
|
55
54
|
lazy_attribute_lookup(a)
|
|
56
55
|
else
|
|
57
56
|
super()
|
|
@@ -69,9 +68,23 @@ module Sequel
|
|
|
69
68
|
# the attribute for just the current object. Return the value of
|
|
70
69
|
# the attribute for the current object.
|
|
71
70
|
def lazy_attribute_lookup(a)
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
71
|
+
if frozen?
|
|
72
|
+
return this.dup.select(a).get(a)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
if retrieved_with
|
|
76
|
+
raise(Error, "Invalid primary key column for #{model}: #{pkc.inspect}") unless primary_key = model.primary_key
|
|
77
|
+
composite_pk = true if primary_key.is_a?(Array)
|
|
78
|
+
id_map = {}
|
|
79
|
+
retrieved_with.each{|o| id_map[o.pk] = o unless o.values.has_key?(a) || o.frozen?}
|
|
80
|
+
model.select(*(Array(primary_key) + [a])).filter(primary_key=>id_map.keys).naked.each do |row|
|
|
81
|
+
obj = id_map[composite_pk ? row.values_at(*primary_key) : row[primary_key]]
|
|
82
|
+
if obj && !obj.values.has_key?(a)
|
|
83
|
+
obj.values[a] = row[a]
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
values[a] = this.select(a).get(a) unless values.has_key?(a)
|
|
75
88
|
values[a]
|
|
76
89
|
end
|
|
77
90
|
end
|
data/lib/sequel/plugins/list.rb
CHANGED
|
@@ -78,12 +78,7 @@ module Sequel
|
|
|
78
78
|
# proc should accept an instance and return a dataset representing the list.
|
|
79
79
|
attr_accessor :scope_proc
|
|
80
80
|
|
|
81
|
-
|
|
82
|
-
def inherited(subclass)
|
|
83
|
-
super
|
|
84
|
-
subclass.position_field = position_field
|
|
85
|
-
subclass.scope_proc = scope_proc
|
|
86
|
-
end
|
|
81
|
+
Plugins.inherited_instance_variables(self, :@position_field=>nil, :@scope_proc=>nil)
|
|
87
82
|
end
|
|
88
83
|
|
|
89
84
|
module InstanceMethods
|