sequel 4.47.0 → 4.48.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
@@ -13,6 +13,16 @@ module Sequel
|
|
13
13
|
# album = Album.new(:a=>1, :b=>3)
|
14
14
|
# album.a # => 1
|
15
15
|
# album.b # => 3
|
16
|
+
#
|
17
|
+
# You can manually set default values as well:
|
18
|
+
#
|
19
|
+
# Album.default_values[:a] = 4
|
20
|
+
# Album.new.a # => 4
|
21
|
+
#
|
22
|
+
# You can also provide procs to set default values:
|
23
|
+
#
|
24
|
+
# Album.default_values[:a] = lambda{Date.today}
|
25
|
+
# Album.new.a # => Date.today
|
16
26
|
#
|
17
27
|
# Usage:
|
18
28
|
#
|
@@ -14,11 +14,11 @@ module Sequel
|
|
14
14
|
#
|
15
15
|
# Usage:
|
16
16
|
#
|
17
|
-
# # Force all strings to be
|
17
|
+
# # Force all strings to be UTF-8 encoded in a all model subclasses
|
18
18
|
# # (called before loading subclasses)
|
19
19
|
# Sequel::Model.plugin :force_encoding, 'UTF-8'
|
20
20
|
#
|
21
|
-
# # Force the encoding for the Album model to
|
21
|
+
# # Force the encoding for the Album model to UTF-8
|
22
22
|
# Album.plugin :force_encoding
|
23
23
|
# Album.forced_encoding = 'UTF-8'
|
24
24
|
module ForceEncoding
|
@@ -2,10 +2,10 @@
|
|
2
2
|
|
3
3
|
module Sequel
|
4
4
|
module Plugins
|
5
|
-
# Sequel's built-in
|
5
|
+
# Sequel's built-in hook_class_methods plugin is designed for backwards
|
6
6
|
# compatibility. Its use is not encouraged, it is recommended to use
|
7
|
-
# instance methods and super instead of this plugin.
|
8
|
-
#
|
7
|
+
# instance methods and super instead of this plugin. This plugin allows
|
8
|
+
# calling class methods with blocks to define hooks:
|
9
9
|
#
|
10
10
|
# # Block only, can cause duplicate hooks if code is reloaded
|
11
11
|
# before_save{self.created_at = Time.now}
|
@@ -15,17 +15,14 @@ module Sequel
|
|
15
15
|
# before_save(:set_created_at)
|
16
16
|
#
|
17
17
|
# Pretty much anything you can do with a hook class method, you can also
|
18
|
-
# do with an instance method instead
|
18
|
+
# do with an instance method instead (making sure to call super), which is
|
19
|
+
# the recommended way to add hooks in Sequel:
|
19
20
|
#
|
20
21
|
# def before_save
|
21
|
-
#
|
22
|
+
# super
|
22
23
|
# self.created_at = Time.now
|
23
24
|
# end
|
24
25
|
#
|
25
|
-
# Note that returning false in any before hook block will skip further
|
26
|
-
# before hooks and abort the action. So if a before_save hook block returns
|
27
|
-
# false, future before_save hook blocks are not called, and the save is aborted.
|
28
|
-
#
|
29
26
|
# Usage:
|
30
27
|
#
|
31
28
|
# # Allow use of hook class methods in all model subclasses (called before loading subclasses)
|
@@ -91,7 +88,6 @@ module Sequel
|
|
91
88
|
# arbitrary code execution.
|
92
89
|
def add_hook_type(*hooks)
|
93
90
|
Sequel::Deprecation.deprecate("Sequel::Model.add_hook_type", "You should add your own hook types manually")
|
94
|
-
Model::HOOKS.concat(hooks)
|
95
91
|
hooks.each do |hook|
|
96
92
|
@hooks[hook] = []
|
97
93
|
instance_eval("def #{hook}(method = nil, &block); add_hook(:#{hook}, method, &block) end", __FILE__, __LINE__)
|
@@ -141,7 +137,8 @@ module Sequel
|
|
141
137
|
end
|
142
138
|
|
143
139
|
module InstanceMethods
|
144
|
-
|
140
|
+
# SEQUEL5: Make :before_save, :before_destroy, :after_save, :after_destroy hooks use metaprogramming instead of specific definitions
|
141
|
+
[:before_create, :before_update, :before_validation].each do |h|
|
145
142
|
class_eval(<<-END, __FILE__, __LINE__+1)
|
146
143
|
def #{h}
|
147
144
|
model.hook_blocks(:#{h}) do |b|
|
@@ -154,7 +151,7 @@ module Sequel
|
|
154
151
|
end
|
155
152
|
END
|
156
153
|
end
|
157
|
-
|
154
|
+
[:after_create, :after_update, :after_validation].each{|h| class_eval("def #{h}; super; model.hook_blocks(:#{h}){|b| instance_eval(&b)}; end", __FILE__, __LINE__)}
|
158
155
|
|
159
156
|
def after_destroy
|
160
157
|
super
|
@@ -7,7 +7,9 @@ module Sequel
|
|
7
7
|
# where you would normally have to drop down to the dataset level
|
8
8
|
# to get the necessary control, because you only want to delete or
|
9
9
|
# update the rows in certain cases based on the current status of
|
10
|
-
# the row in the database.
|
10
|
+
# the row in the database. The main purpose of this plugin is to
|
11
|
+
# avoid race conditions by relying on the atomic properties of database
|
12
|
+
# transactions.
|
11
13
|
#
|
12
14
|
# class Item < Sequel::Model
|
13
15
|
# plugin :instance_filters
|
@@ -9,8 +9,7 @@ module Sequel
|
|
9
9
|
# All of the standard hooks are supported.
|
10
10
|
# Instance level before hooks are executed in reverse order of addition before
|
11
11
|
# calling super. Instance level after hooks are executed in order of addition
|
12
|
-
# after calling super.
|
13
|
-
# false, no more instance level before hooks are called and false is returned.
|
12
|
+
# after calling super.
|
14
13
|
#
|
15
14
|
# Instance level hooks for before and after are cleared after all related
|
16
15
|
# after level instance hooks have run. This means that if you add a before_create
|
@@ -29,9 +28,12 @@ module Sequel
|
|
29
28
|
# # Add the instance hook methods just to Album instances
|
30
29
|
# Album.plugin :instance_hooks
|
31
30
|
module InstanceHooks
|
32
|
-
BEFORE_HOOKS = Sequel::Model::
|
33
|
-
|
34
|
-
|
31
|
+
BEFORE_HOOKS, AFTER_HOOKS = Sequel::Model::HOOKS.partition{|l| l.to_s.start_with?('before')}
|
32
|
+
Sequel::Deprecation.deprecate_constant(self, :BEFORE_HOOKS)
|
33
|
+
Sequel::Deprecation.deprecate_constant(self, :AFTER_HOOKS)
|
34
|
+
HOOKS = Sequel::Model::HOOKS
|
35
|
+
Sequel::Deprecation.deprecate_constant(self, :HOOKS)
|
36
|
+
|
35
37
|
# SEQUEL5: Remove
|
36
38
|
DEPRECATION_REPLACEMENTS = {
|
37
39
|
:after_commit=>"Use obj.after_save_hook{obj.db.after_commit{}} instead",
|
@@ -41,7 +43,7 @@ module Sequel
|
|
41
43
|
}.freeze
|
42
44
|
|
43
45
|
module InstanceMethods
|
44
|
-
HOOKS.each{|h| class_eval(<<-END , __FILE__, __LINE__+1)}
|
46
|
+
Sequel::Model::HOOKS.each{|h| class_eval(<<-END , __FILE__, __LINE__+1)}
|
45
47
|
def #{h}_hook(&block)
|
46
48
|
#{"Sequel::Deprecation.deprecate('Sequel::Model##{h}_hook in the instance_hooks plugin', #{DEPRECATION_REPLACEMENTS[h].inspect})" if DEPRECATION_REPLACEMENTS[h]}
|
47
49
|
raise Sequel::Error, "can't add hooks to frozen object" if frozen?
|
@@ -50,8 +52,8 @@ module Sequel
|
|
50
52
|
end
|
51
53
|
END
|
52
54
|
|
53
|
-
|
54
|
-
|
55
|
+
[:before_create, :before_update, :before_validation].each{|h| class_eval("def #{h}; (@instance_hooks && run_before_instance_hooks(:#{h}) == false) ? false : super end", __FILE__, __LINE__)}
|
56
|
+
[:after_create, :after_update].each{|h| class_eval(<<-END, __FILE__, __LINE__ + 1)}
|
55
57
|
def #{h}
|
56
58
|
super
|
57
59
|
return unless @instance_hooks
|
@@ -65,6 +67,7 @@ module Sequel
|
|
65
67
|
def after_destroy
|
66
68
|
super
|
67
69
|
return unless @instance_hooks
|
70
|
+
# SEQUEL5: Remove commit/rollback
|
68
71
|
if ad = @instance_hooks[:after_destroy_commit]
|
69
72
|
db.after_commit{ad.each(&:call)}
|
70
73
|
end
|
@@ -86,6 +89,7 @@ module Sequel
|
|
86
89
|
def after_save
|
87
90
|
super
|
88
91
|
return unless @instance_hooks
|
92
|
+
# SEQUEL5: Remove commit/rollback
|
89
93
|
if (ac = @instance_hooks[:after_commit])
|
90
94
|
db.after_commit{ac.each(&:call)}
|
91
95
|
end
|
@@ -101,18 +105,22 @@ module Sequel
|
|
101
105
|
# Run before_destroy instance hooks.
|
102
106
|
def before_destroy
|
103
107
|
return super unless @instance_hooks
|
108
|
+
# SEQUEL5: Remove commit/rollback
|
104
109
|
if adr = @instance_hooks[:after_destroy_rollback]
|
105
110
|
db.after_rollback{adr.each(&:call)}
|
106
111
|
end
|
112
|
+
# SEQUEL5: No false checking
|
107
113
|
run_before_instance_hooks(:before_destroy) == false ? false : super
|
108
114
|
end
|
109
115
|
|
110
116
|
# Run before_save instance hooks.
|
111
117
|
def before_save
|
112
118
|
return super unless @instance_hooks
|
119
|
+
# SEQUEL5: Remove commit/rollback
|
113
120
|
if ar = @instance_hooks[:after_rollback]
|
114
121
|
db.after_rollback{ar.each(&:call)}
|
115
122
|
end
|
123
|
+
# SEQUEL5: No false checking
|
116
124
|
run_before_instance_hooks(:before_save) == false ? false : super
|
117
125
|
end
|
118
126
|
|
@@ -122,7 +130,7 @@ module Sequel
|
|
122
130
|
# the beginning of the instance hook's array. For after hooks, add it
|
123
131
|
# to the end.
|
124
132
|
def add_instance_hook(hook, &block)
|
125
|
-
instance_hooks(hook).send(
|
133
|
+
instance_hooks(hook).send(hook.to_s.start_with?('before') ? :unshift : :push, block)
|
126
134
|
end
|
127
135
|
|
128
136
|
# An array of instance level hook blocks for the given hook type.
|
@@ -62,6 +62,11 @@ module Sequel
|
|
62
62
|
#
|
63
63
|
# Album.to_json(:array=>[Album[1], Album[2]])
|
64
64
|
#
|
65
|
+
# All to_json methods take blocks, and if a block is given, it will yield
|
66
|
+
# the array or hash before serialization, and will serialize the value
|
67
|
+
# the block returns. This allows you to customize the resulting JSON format
|
68
|
+
# on a per-call basis.
|
69
|
+
#
|
65
70
|
# In addition to creating JSON, this plugin also enables Sequel::Model
|
66
71
|
# classes to create instances directly from JSON using the from_json class
|
67
72
|
# method:
|
@@ -126,9 +131,9 @@ module Sequel
|
|
126
131
|
module JsonSerializer
|
127
132
|
# Set up the column readers to do deserialization and the column writers
|
128
133
|
# to save the value in deserialized_values.
|
129
|
-
def self.configure(model, opts=
|
134
|
+
def self.configure(model, opts=OPTS)
|
130
135
|
model.instance_eval do
|
131
|
-
@json_serializer_opts = (@json_serializer_opts ||
|
136
|
+
@json_serializer_opts = (@json_serializer_opts || OPTS).merge(opts)
|
132
137
|
end
|
133
138
|
end
|
134
139
|
|
@@ -222,10 +227,10 @@ module Sequel
|
|
222
227
|
if assocs = opts[:associations]
|
223
228
|
assocs = case assocs
|
224
229
|
when Symbol
|
225
|
-
{assocs=>
|
230
|
+
{assocs=>OPTS}
|
226
231
|
when Array
|
227
232
|
assocs_tmp = {}
|
228
|
-
assocs.each{|v| assocs_tmp[v] =
|
233
|
+
assocs.each{|v| assocs_tmp[v] = OPTS}
|
229
234
|
assocs_tmp
|
230
235
|
when Hash
|
231
236
|
assocs
|
@@ -358,6 +363,7 @@ module Sequel
|
|
358
363
|
h = {root => h}
|
359
364
|
end
|
360
365
|
|
366
|
+
h = yield h if block_given?
|
361
367
|
Sequel.object_to_json(h, *a)
|
362
368
|
end
|
363
369
|
end
|
@@ -370,6 +376,8 @@ module Sequel
|
|
370
376
|
#
|
371
377
|
# :array :: An array of instances. If this is not provided,
|
372
378
|
# calls #all on the receiver to get the array.
|
379
|
+
# :instance_block :: A block to pass to #to_json for each
|
380
|
+
# value in the dataset (or :array option).
|
373
381
|
# :root :: If set to :collection, wraps the collection
|
374
382
|
# in a root object using the pluralized, underscored model
|
375
383
|
# name as the key. If set to :instance, only wraps
|
@@ -405,16 +413,15 @@ module Sequel
|
|
405
413
|
else
|
406
414
|
all
|
407
415
|
end
|
408
|
-
array.map{|obj| Literal.new(Sequel.object_to_json(obj, opts))}
|
416
|
+
array.map{|obj| Literal.new(Sequel.object_to_json(obj, opts, &opts[:instance_block]))}
|
409
417
|
else
|
410
418
|
all
|
411
419
|
end
|
412
420
|
|
413
|
-
if collection_root
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
end
|
421
|
+
res = {collection_root => res} if collection_root
|
422
|
+
res = yield res if block_given?
|
423
|
+
|
424
|
+
Sequel.object_to_json(res, *a)
|
418
425
|
end
|
419
426
|
end
|
420
427
|
end
|
@@ -92,9 +92,8 @@ module Sequel
|
|
92
92
|
# the attribute for just the current object. Return the value of
|
93
93
|
# the attribute for the current object.
|
94
94
|
def lazy_attribute_lookup(a, opts=OPTS)
|
95
|
-
|
96
|
-
|
97
|
-
end
|
95
|
+
table = opts[:table] || model.table_name
|
96
|
+
selection = Sequel.qualify(table, a)
|
98
97
|
|
99
98
|
if base_ds = opts[:dataset]
|
100
99
|
ds = base_ds.where(qualified_pk_hash(table))
|
@@ -103,10 +102,8 @@ module Sequel
|
|
103
102
|
ds = this
|
104
103
|
end
|
105
104
|
|
106
|
-
selection = Sequel.qualify(table, a)
|
107
|
-
|
108
105
|
if frozen?
|
109
|
-
return ds.
|
106
|
+
return ds.get(selection)
|
110
107
|
end
|
111
108
|
|
112
109
|
if retrieved_with
|
@@ -115,7 +112,11 @@ module Sequel
|
|
115
112
|
id_map = {}
|
116
113
|
retrieved_with.each{|o| id_map[o.pk] = o unless o.values.has_key?(a) || o.frozen?}
|
117
114
|
predicate_key = composite_pk ? primary_key.map{|k| Sequel.qualify(table, k)} : Sequel.qualify(table, primary_key)
|
118
|
-
base_ds.
|
115
|
+
base_ds.
|
116
|
+
select(*(Array(primary_key).map{|k| Sequel.qualify(table, k)} + [selection])).
|
117
|
+
where(predicate_key=>id_map.keys).
|
118
|
+
naked.
|
119
|
+
each do |row|
|
119
120
|
obj = id_map[composite_pk ? row.values_at(*primary_key) : row[primary_key]]
|
120
121
|
if obj && !obj.values.has_key?(a)
|
121
122
|
obj.values[a] = row[a]
|
@@ -17,6 +17,9 @@ module Sequel
|
|
17
17
|
# Note that for this plugin to work correctly, the column values must
|
18
18
|
# correctly implement the #hash method, returning the same value if
|
19
19
|
# the object is equal, and a different value if the object is not equal.
|
20
|
+
# As this solely uses hash values to check for modification, there may
|
21
|
+
# be cases where a modification is made and the hash value is the same,
|
22
|
+
# resulting in a false negative.
|
20
23
|
#
|
21
24
|
# Note that this plugin causes a performance hit for all retrieved
|
22
25
|
# objects, so it shouldn't be used in cases where performance is a
|
@@ -127,7 +127,11 @@ module Sequel
|
|
127
127
|
reflections = associations.map{|a| association_reflection(a) || raise(Error, "no association named #{a} for #{self}")}
|
128
128
|
reflections.each do |r|
|
129
129
|
r[:nested_attributes] = opts
|
130
|
-
r[:nested_attributes][:unmatched_pk] ||=
|
130
|
+
r[:nested_attributes][:unmatched_pk] ||= (
|
131
|
+
if opts.has_key?(:strict)
|
132
|
+
Sequel::Deprecation.deprecate("The nested_attributes :strict option", "Use the :unmatched_pk option instead")
|
133
|
+
end
|
134
|
+
opts.delete(:strict) == false ? :ignore : :raise)
|
131
135
|
r[:nested_attributes][:reject_if] ||= block
|
132
136
|
def_nested_attribute_method(r)
|
133
137
|
end
|
@@ -297,6 +297,11 @@ module Sequel
|
|
297
297
|
end
|
298
298
|
end
|
299
299
|
|
300
|
+
# Add the pg_array extension to the database
|
301
|
+
def self.apply(model)
|
302
|
+
model.db.extension(:pg_array)
|
303
|
+
end
|
304
|
+
|
300
305
|
module ClassMethods
|
301
306
|
# Create a many_to_pg_array association, for the case where the associated
|
302
307
|
# table contains the array with foreign keys pointing to the current table.
|
@@ -133,7 +133,7 @@ module Sequel
|
|
133
133
|
base_ds = model.where(prkey_array.zip(key_array.map{|k| get_column_value(k)}))
|
134
134
|
recursive_ds = model.join(t, key_array.zip(prkey_array))
|
135
135
|
if c = a[:conditions]
|
136
|
-
(base_ds, recursive_ds) = [base_ds, recursive_ds].
|
136
|
+
(base_ds, recursive_ds) = [base_ds, recursive_ds].map do |ds|
|
137
137
|
(c.is_a?(Array) && !Sequel.condition_specifier?(c)) ? ds.where(*c) : ds.where(c)
|
138
138
|
end
|
139
139
|
end
|
@@ -181,7 +181,7 @@ module Sequel
|
|
181
181
|
recursive_case = model.join(t, key_array.zip(prkey_array)).
|
182
182
|
select(*recursive_case_columns)
|
183
183
|
if c = r[:conditions]
|
184
|
-
(base_case, recursive_case) = [base_case, recursive_case].
|
184
|
+
(base_case, recursive_case) = [base_case, recursive_case].map do |ds|
|
185
185
|
(c.is_a?(Array) && !Sequel.condition_specifier?(c)) ? ds.where(*c) : ds.where(c)
|
186
186
|
end
|
187
187
|
end
|
@@ -228,7 +228,7 @@ module Sequel
|
|
228
228
|
base_ds = model.where(key_array.zip(prkey_array.map{|k| get_column_value(k)}))
|
229
229
|
recursive_ds = model.join(t, prkey_array.zip(key_array))
|
230
230
|
if c = d[:conditions]
|
231
|
-
(base_ds, recursive_ds) = [base_ds, recursive_ds].
|
231
|
+
(base_ds, recursive_ds) = [base_ds, recursive_ds].map do |ds|
|
232
232
|
(c.is_a?(Array) && !Sequel.condition_specifier?(c)) ? ds.where(*c) : ds.where(c)
|
233
233
|
end
|
234
234
|
end
|
@@ -279,7 +279,7 @@ module Sequel
|
|
279
279
|
recursive_case = model.join(t, prkey_array.zip(key_array)).
|
280
280
|
select(*recursive_case_columns)
|
281
281
|
if c = r[:conditions]
|
282
|
-
(base_case, recursive_case) = [base_case, recursive_case].
|
282
|
+
(base_case, recursive_case) = [base_case, recursive_case].map do |ds|
|
283
283
|
(c.is_a?(Array) && !Sequel.condition_specifier?(c)) ? ds.where(*c) : ds.where(c)
|
284
284
|
end
|
285
285
|
end
|
@@ -97,16 +97,9 @@ module Sequel
|
|
97
97
|
end
|
98
98
|
register_format(:marshal, lambda{|v| [Marshal.dump(v)].pack('m')},
|
99
99
|
lambda do |v|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
begin
|
104
|
-
# Backwards compatibility for unpacked marshal output.
|
105
|
-
Marshal.load(v)
|
106
|
-
rescue
|
107
|
-
raise e
|
108
|
-
end
|
109
|
-
end
|
100
|
+
# Handle unpacked marshalled data for backwards compat
|
101
|
+
v = v.unpack('m')[0] unless v[0..1] == "\x04\x08"
|
102
|
+
Marshal.load(v)
|
110
103
|
end)
|
111
104
|
register_format(:yaml, lambda(&:to_yaml), lambda{|v| YAML.load(v)})
|
112
105
|
register_format(:json, lambda{|v| Sequel.object_to_json(v)}, lambda{|v| Sequel.parse_json(v)})
|
@@ -95,7 +95,7 @@ module Sequel
|
|
95
95
|
end
|
96
96
|
end
|
97
97
|
km.each do |k,v|
|
98
|
-
h[k.to_s] = [
|
98
|
+
h[k.to_s] = [] unless h.key?(k.to_s)
|
99
99
|
h[k.to_s].push( *Array(v) )
|
100
100
|
end
|
101
101
|
h
|
@@ -111,7 +111,7 @@ module Sequel
|
|
111
111
|
end
|
112
112
|
end
|
113
113
|
sti_model_map.each do |k,v|
|
114
|
-
h[v.to_s] = [
|
114
|
+
h[v.to_s] = [] unless h.key?(v.to_s)
|
115
115
|
h[v.to_s] << k
|
116
116
|
end
|
117
117
|
h
|
@@ -57,11 +57,12 @@ module Sequel
|
|
57
57
|
# Check all entries in the values hash. If any of the keys are not columns,
|
58
58
|
# move the entry into the noncolumn_values hash.
|
59
59
|
def split_noncolumn_values
|
60
|
-
@values.keys
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
60
|
+
cols = (@values.keys - columns)
|
61
|
+
return self if cols.empty?
|
62
|
+
|
63
|
+
nc = @noncolumn_values ||= {}
|
64
|
+
vals = @values
|
65
|
+
cols.each{|k| nc[k] = vals.delete(k)}
|
65
66
|
self
|
66
67
|
end
|
67
68
|
end
|