sequel 4.47.0 → 4.48.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (177) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +134 -0
  3. data/Rakefile +1 -1
  4. data/doc/release_notes/4.48.0.txt +293 -0
  5. data/lib/sequel/adapters/ado/access.rb +2 -1
  6. data/lib/sequel/adapters/do/postgres.rb +5 -2
  7. data/lib/sequel/adapters/ibmdb.rb +24 -7
  8. data/lib/sequel/adapters/jdbc.rb +36 -22
  9. data/lib/sequel/adapters/jdbc/db2.rb +12 -3
  10. data/lib/sequel/adapters/jdbc/derby.rb +4 -5
  11. data/lib/sequel/adapters/jdbc/oracle.rb +16 -2
  12. data/lib/sequel/adapters/jdbc/postgresql.rb +43 -18
  13. data/lib/sequel/adapters/jdbc/sqlanywhere.rb +9 -7
  14. data/lib/sequel/adapters/jdbc/sqlserver.rb +11 -4
  15. data/lib/sequel/adapters/mock.rb +24 -19
  16. data/lib/sequel/adapters/mysql.rb +17 -16
  17. data/lib/sequel/adapters/mysql2.rb +4 -5
  18. data/lib/sequel/adapters/oracle.rb +5 -9
  19. data/lib/sequel/adapters/postgres.rb +89 -102
  20. data/lib/sequel/adapters/shared/db2.rb +22 -6
  21. data/lib/sequel/adapters/shared/mssql.rb +5 -4
  22. data/lib/sequel/adapters/shared/mysql.rb +75 -24
  23. data/lib/sequel/adapters/shared/postgres.rb +196 -94
  24. data/lib/sequel/adapters/shared/sqlanywhere.rb +23 -10
  25. data/lib/sequel/adapters/shared/sqlite.rb +72 -82
  26. data/lib/sequel/adapters/sqlanywhere.rb +4 -1
  27. data/lib/sequel/adapters/sqlite.rb +5 -3
  28. data/lib/sequel/adapters/swift/postgres.rb +5 -2
  29. data/lib/sequel/adapters/tinytds.rb +0 -5
  30. data/lib/sequel/adapters/utils/mysql_mysql2.rb +1 -1
  31. data/lib/sequel/adapters/utils/pg_types.rb +2 -76
  32. data/lib/sequel/core.rb +2 -2
  33. data/lib/sequel/database/connecting.rb +5 -5
  34. data/lib/sequel/database/dataset.rb +6 -3
  35. data/lib/sequel/database/misc.rb +1 -1
  36. data/lib/sequel/database/query.rb +3 -0
  37. data/lib/sequel/database/schema_methods.rb +1 -1
  38. data/lib/sequel/dataset/actions.rb +18 -10
  39. data/lib/sequel/dataset/graph.rb +1 -1
  40. data/lib/sequel/dataset/misc.rb +1 -0
  41. data/lib/sequel/dataset/prepared_statements.rb +3 -3
  42. data/lib/sequel/dataset/query.rb +19 -8
  43. data/lib/sequel/extensions/core_extensions.rb +4 -1
  44. data/lib/sequel/extensions/duplicate_columns_handler.rb +1 -1
  45. data/lib/sequel/extensions/empty_array_ignore_nulls.rb +3 -0
  46. data/lib/sequel/extensions/filter_having.rb +2 -0
  47. data/lib/sequel/extensions/freeze_datasets.rb +2 -0
  48. data/lib/sequel/extensions/from_block.rb +1 -1
  49. data/lib/sequel/extensions/graph_each.rb +2 -2
  50. data/lib/sequel/extensions/hash_aliases.rb +2 -0
  51. data/lib/sequel/extensions/identifier_mangling.rb +0 -7
  52. data/lib/sequel/extensions/meta_def.rb +2 -0
  53. data/lib/sequel/extensions/migration.rb +6 -6
  54. data/lib/sequel/extensions/no_auto_literal_strings.rb +1 -1
  55. data/lib/sequel/extensions/pagination.rb +1 -1
  56. data/lib/sequel/extensions/pg_array.rb +207 -130
  57. data/lib/sequel/extensions/pg_hstore.rb +38 -20
  58. data/lib/sequel/extensions/pg_inet.rb +18 -6
  59. data/lib/sequel/extensions/pg_interval.rb +19 -12
  60. data/lib/sequel/extensions/pg_json.rb +25 -14
  61. data/lib/sequel/extensions/pg_json_ops.rb +2 -2
  62. data/lib/sequel/extensions/pg_range.rb +133 -100
  63. data/lib/sequel/extensions/pg_range_ops.rb +4 -3
  64. data/lib/sequel/extensions/pg_row.rb +68 -39
  65. data/lib/sequel/extensions/pg_row_ops.rb +11 -5
  66. data/lib/sequel/extensions/query_literals.rb +2 -0
  67. data/lib/sequel/extensions/ruby18_symbol_extensions.rb +2 -0
  68. data/lib/sequel/extensions/s.rb +1 -1
  69. data/lib/sequel/extensions/schema_dumper.rb +24 -24
  70. data/lib/sequel/extensions/sequel_3_dataset_methods.rb +3 -1
  71. data/lib/sequel/extensions/sequel_4_dataset_methods.rb +83 -0
  72. data/lib/sequel/extensions/set_overrides.rb +2 -2
  73. data/lib/sequel/extensions/string_agg.rb +0 -1
  74. data/lib/sequel/extensions/symbol_aref.rb +0 -4
  75. data/lib/sequel/model.rb +25 -57
  76. data/lib/sequel/model/associations.rb +14 -5
  77. data/lib/sequel/model/base.rb +96 -32
  78. data/lib/sequel/plugins/association_pks.rb +73 -46
  79. data/lib/sequel/plugins/association_proxies.rb +1 -1
  80. data/lib/sequel/plugins/auto_validations.rb +6 -2
  81. data/lib/sequel/plugins/boolean_readers.rb +1 -1
  82. data/lib/sequel/plugins/caching.rb +19 -13
  83. data/lib/sequel/plugins/class_table_inheritance.rb +19 -10
  84. data/lib/sequel/plugins/column_conflicts.rb +7 -2
  85. data/lib/sequel/plugins/column_select.rb +1 -1
  86. data/lib/sequel/plugins/csv_serializer.rb +8 -8
  87. data/lib/sequel/plugins/defaults_setter.rb +10 -0
  88. data/lib/sequel/plugins/eager_each.rb +1 -1
  89. data/lib/sequel/plugins/force_encoding.rb +2 -2
  90. data/lib/sequel/plugins/hook_class_methods.rb +9 -12
  91. data/lib/sequel/plugins/identifier_columns.rb +2 -0
  92. data/lib/sequel/plugins/instance_filters.rb +3 -1
  93. data/lib/sequel/plugins/instance_hooks.rb +17 -9
  94. data/lib/sequel/plugins/json_serializer.rb +17 -10
  95. data/lib/sequel/plugins/lazy_attributes.rb +8 -7
  96. data/lib/sequel/plugins/modification_detection.rb +3 -0
  97. data/lib/sequel/plugins/nested_attributes.rb +5 -1
  98. data/lib/sequel/plugins/pg_array_associations.rb +5 -0
  99. data/lib/sequel/plugins/prepared_statements.rb +1 -0
  100. data/lib/sequel/plugins/rcte_tree.rb +4 -4
  101. data/lib/sequel/plugins/serialization.rb +3 -10
  102. data/lib/sequel/plugins/single_table_inheritance.rb +2 -2
  103. data/lib/sequel/plugins/split_values.rb +6 -5
  104. data/lib/sequel/plugins/static_cache.rb +31 -25
  105. data/lib/sequel/plugins/subset_conditions.rb +3 -1
  106. data/lib/sequel/plugins/table_select.rb +1 -1
  107. data/lib/sequel/plugins/touch.rb +2 -1
  108. data/lib/sequel/plugins/validation_class_methods.rb +5 -6
  109. data/lib/sequel/plugins/validation_helpers.rb +2 -4
  110. data/lib/sequel/plugins/xml_serializer.rb +4 -4
  111. data/lib/sequel/sql.rb +2 -2
  112. data/lib/sequel/version.rb +1 -1
  113. data/spec/adapters/db2_spec.rb +115 -14
  114. data/spec/adapters/mysql_spec.rb +78 -28
  115. data/spec/adapters/oracle_spec.rb +24 -24
  116. data/spec/adapters/postgres_spec.rb +38 -24
  117. data/spec/adapters/sqlanywhere_spec.rb +88 -86
  118. data/spec/adapters/sqlite_spec.rb +29 -24
  119. data/spec/core/connection_pool_spec.rb +17 -0
  120. data/spec/core/database_spec.rb +6 -0
  121. data/spec/core/dataset_spec.rb +46 -36
  122. data/spec/core/schema_spec.rb +16 -0
  123. data/spec/core/spec_helper.rb +1 -0
  124. data/spec/core_extensions_spec.rb +6 -2
  125. data/spec/extensions/active_model_spec.rb +1 -1
  126. data/spec/extensions/arbitrary_servers_spec.rb +1 -1
  127. data/spec/extensions/association_pks_spec.rb +34 -2
  128. data/spec/extensions/auto_literal_strings_spec.rb +5 -1
  129. data/spec/extensions/auto_validations_spec.rb +2 -0
  130. data/spec/extensions/boolean_readers_spec.rb +1 -1
  131. data/spec/extensions/boolean_subsets_spec.rb +1 -1
  132. data/spec/extensions/class_table_inheritance_spec.rb +48 -2
  133. data/spec/extensions/column_conflicts_spec.rb +11 -0
  134. data/spec/extensions/connection_validator_spec.rb +1 -1
  135. data/spec/extensions/dataset_associations_spec.rb +8 -8
  136. data/spec/extensions/defaults_setter_spec.rb +1 -1
  137. data/spec/extensions/filter_having_spec.rb +5 -3
  138. data/spec/extensions/hash_aliases_spec.rb +3 -1
  139. data/spec/extensions/identifier_columns_spec.rb +3 -1
  140. data/spec/extensions/implicit_subquery_spec.rb +4 -2
  141. data/spec/extensions/json_serializer_spec.rb +18 -0
  142. data/spec/extensions/lazy_attributes_spec.rb +3 -3
  143. data/spec/extensions/meta_def_spec.rb +9 -0
  144. data/spec/extensions/migration_spec.rb +3 -3
  145. data/spec/extensions/nested_attributes_spec.rb +14 -3
  146. data/spec/extensions/no_auto_literal_strings_spec.rb +8 -4
  147. data/spec/extensions/pg_array_associations_spec.rb +29 -18
  148. data/spec/extensions/pg_array_spec.rb +44 -25
  149. data/spec/extensions/pg_hstore_spec.rb +10 -0
  150. data/spec/extensions/pg_inet_spec.rb +26 -0
  151. data/spec/extensions/pg_interval_spec.rb +20 -0
  152. data/spec/extensions/pg_json_spec.rb +24 -0
  153. data/spec/extensions/pg_range_spec.rb +98 -14
  154. data/spec/extensions/pg_row_spec.rb +14 -4
  155. data/spec/extensions/prepared_statements_safe_spec.rb +1 -1
  156. data/spec/extensions/query_literals_spec.rb +3 -1
  157. data/spec/extensions/schema_dumper_spec.rb +96 -98
  158. data/spec/extensions/sequel_3_dataset_methods_spec.rb +10 -6
  159. data/spec/extensions/sequel_4_dataset_methods_spec.rb +121 -0
  160. data/spec/extensions/single_table_inheritance_spec.rb +1 -1
  161. data/spec/extensions/spec_helper.rb +7 -1
  162. data/spec/extensions/static_cache_spec.rb +75 -24
  163. data/spec/extensions/string_agg_spec.rb +1 -1
  164. data/spec/extensions/touch_spec.rb +9 -0
  165. data/spec/extensions/validation_helpers_spec.rb +9 -3
  166. data/spec/extensions/whitelist_security_spec.rb +26 -0
  167. data/spec/integration/dataset_test.rb +45 -44
  168. data/spec/integration/plugin_test.rb +20 -0
  169. data/spec/integration/prepared_statement_test.rb +3 -0
  170. data/spec/integration/schema_test.rb +21 -1
  171. data/spec/integration/transaction_test.rb +40 -40
  172. data/spec/model/class_dataset_methods_spec.rb +14 -4
  173. data/spec/model/dataset_methods_spec.rb +12 -3
  174. data/spec/model/model_spec.rb +8 -0
  175. metadata +6 -4
  176. data/spec/adapters/firebird_spec.rb +0 -405
  177. 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
  #
@@ -39,7 +39,7 @@ module Sequel
39
39
  end
40
40
 
41
41
  # Call #all instead of #each if eager loading,
42
- # uless #each is being called by #all.
42
+ # unless #each is being called by #all.
43
43
  def each(&block)
44
44
  if use_eager_all?
45
45
  all(&block)
@@ -14,11 +14,11 @@ module Sequel
14
14
  #
15
15
  # Usage:
16
16
  #
17
- # # Force all strings to be UTF8 encoded in a all model subclasses
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 UTF8
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 hook class methods plugin is designed for backwards
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. What this plugin
8
- # allows you to do is, for example:
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
- # return false if super == false
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
- (Model::BEFORE_HOOKS - [:before_save, :before_destroy]).each do |h|
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
- (Model::AFTER_HOOKS - [:after_save, :after_destroy, :after_commit, :after_rollback, :after_destroy_commit, :after_destroy_rollback]).each{|h| class_eval("def #{h}; super; model.hook_blocks(:#{h}){|b| instance_eval(&b)}; end", __FILE__, __LINE__)}
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
@@ -1,5 +1,7 @@
1
1
  # frozen-string-literal: true
2
2
 
3
+ Sequel::Deprecation.deprecate("The identifier_columns plugin", "Set Sequel.split_symbols = false instead")
4
+
3
5
  module Sequel
4
6
  module Plugins
5
7
  # The identifier_columns plugin makes Sequel automatically
@@ -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. If any of the instance level before hook blocks return
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::BEFORE_HOOKS
33
- AFTER_HOOKS = Sequel::Model::AFTER_HOOKS
34
- HOOKS = BEFORE_HOOKS + AFTER_HOOKS
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
- (BEFORE_HOOKS - [:before_destroy, :before_save]).each{|h| class_eval("def #{h}; (@instance_hooks && run_before_instance_hooks(:#{h}) == false) ? false : super end", __FILE__, __LINE__)}
54
- (AFTER_HOOKS - [:after_validation, :after_save, :after_destroy, :after_commit, :after_destroy_commit, :after_destroy_rollback, :after_rollback]).each{|h| class_eval(<<-END, __FILE__, __LINE__ + 1)}
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(BEFORE_HOOKS.include?(hook) ? :unshift : :push, block)
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 || {}).merge(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
- Sequel.object_to_json({collection_root => res}, *a)
415
- else
416
- Sequel.object_to_json(res, *a)
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
- unless table = opts[:table]
96
- table = model.table_name
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.dup.get(selection)
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.select(*(Array(primary_key).map{|k| Sequel.qualify(table, k)} + [selection])).where(predicate_key=>id_map.keys).naked.each do |row|
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] ||= opts.delete(:strict) == false ? :ignore : :raise
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.
@@ -225,6 +225,7 @@ module Sequel
225
225
  case type
226
226
  when :insert, :insert_select, :update
227
227
  true
228
+ # SEQUEL5: Remove :delete/:refresh
228
229
  when :delete
229
230
  return true unless model.fast_instance_delete_sql
230
231
 
@@ -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].collect do |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].collect do |ds|
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].collect do |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].collect do |ds|
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
- begin
101
- Marshal.load(v.unpack('m')[0])
102
- rescue => e
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] = [ ] unless h.key?(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] = [ ] unless h.key?(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.each do |k|
61
- unless columns.include?(k)
62
- (@noncolumn_values ||= {})[k] = @values.delete(k)
63
- end
64
- end
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