sequel 4.46.0 → 4.49.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.
Files changed (228) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +210 -0
  3. data/Rakefile +1 -1
  4. data/doc/advanced_associations.rdoc +1 -1
  5. data/doc/opening_databases.rdoc +3 -2
  6. data/doc/release_notes/4.47.0.txt +56 -0
  7. data/doc/release_notes/4.48.0.txt +293 -0
  8. data/doc/release_notes/4.49.0.txt +222 -0
  9. data/lib/sequel/adapters/ado/access.rb +2 -1
  10. data/lib/sequel/adapters/do/postgres.rb +5 -2
  11. data/lib/sequel/adapters/ibmdb.rb +30 -8
  12. data/lib/sequel/adapters/jdbc/as400.rb +1 -1
  13. data/lib/sequel/adapters/jdbc/db2.rb +12 -3
  14. data/lib/sequel/adapters/jdbc/derby.rb +4 -5
  15. data/lib/sequel/adapters/jdbc/h2.rb +10 -1
  16. data/lib/sequel/adapters/jdbc/oracle.rb +16 -2
  17. data/lib/sequel/adapters/jdbc/postgresql.rb +46 -20
  18. data/lib/sequel/adapters/jdbc/sqlanywhere.rb +9 -7
  19. data/lib/sequel/adapters/jdbc/sqlserver.rb +20 -6
  20. data/lib/sequel/adapters/jdbc.rb +39 -23
  21. data/lib/sequel/adapters/mock.rb +27 -19
  22. data/lib/sequel/adapters/mysql.rb +17 -16
  23. data/lib/sequel/adapters/mysql2.rb +5 -6
  24. data/lib/sequel/adapters/oracle.rb +5 -9
  25. data/lib/sequel/adapters/postgres.rb +91 -103
  26. data/lib/sequel/adapters/shared/db2.rb +22 -6
  27. data/lib/sequel/adapters/shared/mssql.rb +5 -4
  28. data/lib/sequel/adapters/shared/mysql.rb +79 -25
  29. data/lib/sequel/adapters/shared/oracle.rb +26 -3
  30. data/lib/sequel/adapters/shared/postgres.rb +199 -95
  31. data/lib/sequel/adapters/shared/sqlanywhere.rb +23 -10
  32. data/lib/sequel/adapters/shared/sqlite.rb +72 -82
  33. data/lib/sequel/adapters/sqlanywhere.rb +4 -1
  34. data/lib/sequel/adapters/sqlite.rb +5 -3
  35. data/lib/sequel/adapters/swift/postgres.rb +5 -2
  36. data/lib/sequel/adapters/tinytds.rb +0 -5
  37. data/lib/sequel/adapters/utils/mysql_mysql2.rb +1 -1
  38. data/lib/sequel/adapters/utils/pg_types.rb +2 -76
  39. data/lib/sequel/ast_transformer.rb +1 -1
  40. data/lib/sequel/connection_pool/sharded_single.rb +1 -1
  41. data/lib/sequel/connection_pool/sharded_threaded.rb +1 -1
  42. data/lib/sequel/connection_pool/single.rb +2 -2
  43. data/lib/sequel/connection_pool/threaded.rb +2 -2
  44. data/lib/sequel/connection_pool.rb +9 -2
  45. data/lib/sequel/core.rb +2 -2
  46. data/lib/sequel/database/connecting.rb +8 -8
  47. data/lib/sequel/database/dataset.rb +6 -3
  48. data/lib/sequel/database/dataset_defaults.rb +14 -1
  49. data/lib/sequel/database/misc.rb +1 -1
  50. data/lib/sequel/database/query.rb +3 -0
  51. data/lib/sequel/database/schema_methods.rb +1 -1
  52. data/lib/sequel/dataset/actions.rb +72 -10
  53. data/lib/sequel/dataset/dataset_module.rb +58 -0
  54. data/lib/sequel/dataset/graph.rb +1 -1
  55. data/lib/sequel/dataset/misc.rb +1 -0
  56. data/lib/sequel/dataset/prepared_statements.rb +3 -3
  57. data/lib/sequel/dataset/query.rb +22 -11
  58. data/lib/sequel/dataset.rb +1 -1
  59. data/lib/sequel/exceptions.rb +8 -0
  60. data/lib/sequel/extensions/_model_pg_row.rb +5 -2
  61. data/lib/sequel/extensions/core_extensions.rb +4 -1
  62. data/lib/sequel/extensions/current_datetime_timestamp.rb +2 -1
  63. data/lib/sequel/extensions/date_arithmetic.rb +1 -0
  64. data/lib/sequel/extensions/duplicate_columns_handler.rb +3 -3
  65. data/lib/sequel/extensions/empty_array_ignore_nulls.rb +3 -0
  66. data/lib/sequel/extensions/filter_having.rb +2 -0
  67. data/lib/sequel/extensions/freeze_datasets.rb +2 -0
  68. data/lib/sequel/extensions/from_block.rb +1 -1
  69. data/lib/sequel/extensions/graph_each.rb +2 -2
  70. data/lib/sequel/extensions/hash_aliases.rb +2 -0
  71. data/lib/sequel/extensions/identifier_mangling.rb +0 -7
  72. data/lib/sequel/extensions/meta_def.rb +2 -0
  73. data/lib/sequel/extensions/migration.rb +11 -8
  74. data/lib/sequel/extensions/no_auto_literal_strings.rb +1 -1
  75. data/lib/sequel/extensions/null_dataset.rb +1 -0
  76. data/lib/sequel/extensions/pagination.rb +1 -1
  77. data/lib/sequel/extensions/pg_array.rb +207 -130
  78. data/lib/sequel/extensions/pg_hstore.rb +38 -20
  79. data/lib/sequel/extensions/pg_inet.rb +18 -6
  80. data/lib/sequel/extensions/pg_interval.rb +19 -12
  81. data/lib/sequel/extensions/pg_json.rb +25 -14
  82. data/lib/sequel/extensions/pg_json_ops.rb +2 -2
  83. data/lib/sequel/extensions/pg_range.rb +133 -100
  84. data/lib/sequel/extensions/pg_range_ops.rb +4 -3
  85. data/lib/sequel/extensions/pg_row.rb +68 -39
  86. data/lib/sequel/extensions/pg_row_ops.rb +11 -5
  87. data/lib/sequel/extensions/query_literals.rb +2 -0
  88. data/lib/sequel/extensions/ruby18_symbol_extensions.rb +2 -0
  89. data/lib/sequel/extensions/s.rb +1 -1
  90. data/lib/sequel/extensions/schema_dumper.rb +29 -25
  91. data/lib/sequel/extensions/sequel_3_dataset_methods.rb +3 -1
  92. data/lib/sequel/extensions/sequel_4_dataset_methods.rb +83 -0
  93. data/lib/sequel/extensions/server_block.rb +32 -15
  94. data/lib/sequel/extensions/set_overrides.rb +2 -2
  95. data/lib/sequel/extensions/string_agg.rb +0 -1
  96. data/lib/sequel/extensions/symbol_aref.rb +0 -4
  97. data/lib/sequel/model/associations.rb +35 -7
  98. data/lib/sequel/model/base.rb +113 -87
  99. data/lib/sequel/model/dataset_module.rb +5 -43
  100. data/lib/sequel/model/errors.rb +2 -1
  101. data/lib/sequel/model/inflections.rb +17 -5
  102. data/lib/sequel/model.rb +26 -58
  103. data/lib/sequel/plugins/active_model.rb +2 -2
  104. data/lib/sequel/plugins/association_autoreloading.rb +2 -0
  105. data/lib/sequel/plugins/association_dependencies.rb +3 -3
  106. data/lib/sequel/plugins/association_pks.rb +73 -46
  107. data/lib/sequel/plugins/association_proxies.rb +1 -1
  108. data/lib/sequel/plugins/auto_validations.rb +6 -2
  109. data/lib/sequel/plugins/boolean_readers.rb +2 -2
  110. data/lib/sequel/plugins/boolean_subsets.rb +1 -1
  111. data/lib/sequel/plugins/caching.rb +19 -13
  112. data/lib/sequel/plugins/class_table_inheritance.rb +24 -13
  113. data/lib/sequel/plugins/column_conflicts.rb +7 -2
  114. data/lib/sequel/plugins/column_select.rb +3 -3
  115. data/lib/sequel/plugins/composition.rb +2 -2
  116. data/lib/sequel/plugins/csv_serializer.rb +8 -8
  117. data/lib/sequel/plugins/dataset_associations.rb +25 -13
  118. data/lib/sequel/plugins/defaults_setter.rb +13 -1
  119. data/lib/sequel/plugins/eager_each.rb +1 -1
  120. data/lib/sequel/plugins/force_encoding.rb +2 -2
  121. data/lib/sequel/plugins/hook_class_methods.rb +9 -12
  122. data/lib/sequel/plugins/identifier_columns.rb +2 -0
  123. data/lib/sequel/plugins/instance_filters.rb +3 -1
  124. data/lib/sequel/plugins/instance_hooks.rb +17 -9
  125. data/lib/sequel/plugins/json_serializer.rb +19 -12
  126. data/lib/sequel/plugins/lazy_attributes.rb +8 -7
  127. data/lib/sequel/plugins/many_to_one_pk_lookup.rb +2 -0
  128. data/lib/sequel/plugins/modification_detection.rb +3 -0
  129. data/lib/sequel/plugins/nested_attributes.rb +6 -2
  130. data/lib/sequel/plugins/pg_array_associations.rb +5 -0
  131. data/lib/sequel/plugins/pg_row.rb +4 -2
  132. data/lib/sequel/plugins/pg_typecast_on_load.rb +2 -0
  133. data/lib/sequel/plugins/prepared_statements.rb +1 -0
  134. data/lib/sequel/plugins/rcte_tree.rb +4 -24
  135. data/lib/sequel/plugins/serialization.rb +9 -15
  136. data/lib/sequel/plugins/single_table_inheritance.rb +8 -3
  137. data/lib/sequel/plugins/split_values.rb +6 -5
  138. data/lib/sequel/plugins/static_cache.rb +31 -25
  139. data/lib/sequel/plugins/subset_conditions.rb +3 -1
  140. data/lib/sequel/plugins/table_select.rb +1 -1
  141. data/lib/sequel/plugins/touch.rb +4 -2
  142. data/lib/sequel/plugins/validation_class_methods.rb +5 -6
  143. data/lib/sequel/plugins/validation_helpers.rb +14 -8
  144. data/lib/sequel/plugins/xml_serializer.rb +4 -4
  145. data/lib/sequel/sql.rb +18 -9
  146. data/lib/sequel/version.rb +1 -1
  147. data/spec/adapters/db2_spec.rb +115 -14
  148. data/spec/adapters/mssql_spec.rb +4 -4
  149. data/spec/adapters/mysql_spec.rb +83 -29
  150. data/spec/adapters/oracle_spec.rb +28 -24
  151. data/spec/adapters/postgres_spec.rb +40 -24
  152. data/spec/adapters/sqlanywhere_spec.rb +88 -86
  153. data/spec/adapters/sqlite_spec.rb +29 -24
  154. data/spec/bin_spec.rb +7 -1
  155. data/spec/core/connection_pool_spec.rb +45 -14
  156. data/spec/core/database_spec.rb +155 -0
  157. data/spec/core/dataset_spec.rb +219 -36
  158. data/spec/core/schema_spec.rb +16 -0
  159. data/spec/core/spec_helper.rb +1 -0
  160. data/spec/core_extensions_spec.rb +6 -2
  161. data/spec/extensions/active_model_spec.rb +1 -1
  162. data/spec/extensions/arbitrary_servers_spec.rb +1 -1
  163. data/spec/extensions/association_pks_spec.rb +34 -2
  164. data/spec/extensions/auto_literal_strings_spec.rb +5 -1
  165. data/spec/extensions/auto_validations_spec.rb +2 -0
  166. data/spec/extensions/boolean_readers_spec.rb +1 -1
  167. data/spec/extensions/boolean_subsets_spec.rb +1 -1
  168. data/spec/extensions/class_table_inheritance_spec.rb +106 -19
  169. data/spec/extensions/column_conflicts_spec.rb +11 -0
  170. data/spec/extensions/column_select_spec.rb +1 -0
  171. data/spec/extensions/composition_spec.rb +13 -0
  172. data/spec/extensions/connection_validator_spec.rb +1 -1
  173. data/spec/extensions/dataset_associations_spec.rb +20 -8
  174. data/spec/extensions/defaults_setter_spec.rb +15 -1
  175. data/spec/extensions/filter_having_spec.rb +5 -3
  176. data/spec/extensions/hash_aliases_spec.rb +3 -1
  177. data/spec/extensions/identifier_columns_spec.rb +3 -1
  178. data/spec/extensions/implicit_subquery_spec.rb +4 -2
  179. data/spec/extensions/json_serializer_spec.rb +18 -0
  180. data/spec/extensions/lazy_attributes_spec.rb +3 -3
  181. data/spec/extensions/many_through_many_spec.rb +4 -4
  182. data/spec/extensions/meta_def_spec.rb +9 -0
  183. data/spec/extensions/migration_spec.rb +3 -3
  184. data/spec/extensions/nested_attributes_spec.rb +14 -3
  185. data/spec/extensions/no_auto_literal_strings_spec.rb +8 -4
  186. data/spec/extensions/null_dataset_spec.rb +1 -1
  187. data/spec/extensions/pg_array_associations_spec.rb +29 -18
  188. data/spec/extensions/pg_array_spec.rb +44 -25
  189. data/spec/extensions/pg_hstore_spec.rb +10 -0
  190. data/spec/extensions/pg_inet_spec.rb +26 -0
  191. data/spec/extensions/pg_interval_spec.rb +20 -0
  192. data/spec/extensions/pg_json_spec.rb +24 -0
  193. data/spec/extensions/pg_range_spec.rb +98 -14
  194. data/spec/extensions/pg_row_spec.rb +14 -4
  195. data/spec/extensions/pg_typecast_on_load_spec.rb +11 -9
  196. data/spec/extensions/prepared_statements_safe_spec.rb +1 -1
  197. data/spec/extensions/query_literals_spec.rb +3 -1
  198. data/spec/extensions/schema_dumper_spec.rb +108 -94
  199. data/spec/extensions/sequel_3_dataset_methods_spec.rb +10 -6
  200. data/spec/extensions/sequel_4_dataset_methods_spec.rb +121 -0
  201. data/spec/extensions/serialization_spec.rb +1 -1
  202. data/spec/extensions/server_block_spec.rb +7 -0
  203. data/spec/extensions/single_table_inheritance_spec.rb +17 -1
  204. data/spec/extensions/spec_helper.rb +7 -1
  205. data/spec/extensions/static_cache_spec.rb +75 -24
  206. data/spec/extensions/string_agg_spec.rb +1 -1
  207. data/spec/extensions/touch_spec.rb +9 -0
  208. data/spec/extensions/validation_helpers_spec.rb +10 -5
  209. data/spec/extensions/whitelist_security_spec.rb +26 -0
  210. data/spec/integration/associations_test.rb +8 -0
  211. data/spec/integration/dataset_test.rb +45 -44
  212. data/spec/integration/model_test.rb +53 -4
  213. data/spec/integration/plugin_test.rb +28 -4
  214. data/spec/integration/prepared_statement_test.rb +3 -0
  215. data/spec/integration/schema_test.rb +21 -1
  216. data/spec/integration/transaction_test.rb +40 -40
  217. data/spec/model/association_reflection_spec.rb +43 -1
  218. data/spec/model/associations_spec.rb +29 -9
  219. data/spec/model/class_dataset_methods_spec.rb +20 -4
  220. data/spec/model/dataset_methods_spec.rb +12 -3
  221. data/spec/model/eager_loading_spec.rb +8 -8
  222. data/spec/model/model_spec.rb +45 -1
  223. data/spec/model/plugins_spec.rb +34 -0
  224. data/spec/model/record_spec.rb +1 -1
  225. data/spec/spec_config.rb +2 -0
  226. metadata +11 -4
  227. data/spec/adapters/firebird_spec.rb +0 -405
  228. data/spec/adapters/informix_spec.rb +0 -100
@@ -29,11 +29,16 @@ module Sequel
29
29
  # # Make the Album class handle column conflicts automatically
30
30
  # Album.plugin :column_conflicts
31
31
  module ColumnConflicts
32
- # Check for column conflicts on the current model if the model has a dataset.
33
- def self.configure(model)
32
+ def self.apply(model)
34
33
  model.instance_eval do
35
34
  @get_column_conflicts = {}
36
35
  @set_column_conflicts = {}
36
+ end
37
+ end
38
+
39
+ # Check for column conflicts on the current model if the model has a dataset.
40
+ def self.configure(model)
41
+ model.instance_eval do
37
42
  check_column_conflicts if @dataset
38
43
  end
39
44
  end
@@ -41,15 +41,15 @@ module Sequel
41
41
  # qualifying them with table's name.
42
42
  def convert_input_dataset(ds)
43
43
  ds = super
44
- if !ds.opts[:select] && (from = ds.opts[:from]) && from.length == 1 && !ds.opts[:join]
44
+ if !ds.opts[:select] && (from = ds.opts[:from]) && from.length == 1 && !ds.opts[:join] # SEQUE5: just !ds.opts[:select]
45
45
  if db.supports_schema_parsing?
46
- cols = check_non_connection_error{db.schema(ds)}
46
+ cols = check_non_connection_error(false){db.schema(ds)}
47
47
  if cols
48
48
  cols = cols.map{|c, _| c}
49
49
  end
50
50
  end
51
51
 
52
- if cols ||= check_non_connection_error{ds.columns}
52
+ if cols ||= check_non_connection_error(false){ds.columns}
53
53
  ds = ds.select(*cols.map{|c| Sequel.qualify(ds.first_source, Sequel.identifier(c))})
54
54
  end
55
55
  end
@@ -123,9 +123,9 @@ module Sequel
123
123
  setters = setter_meths.zip(cov_methods)
124
124
  opts[:decomposer] = proc do
125
125
  if (o = compositions[name]).nil?
126
- setter_meths.each{|sm| get_column_value(sm, nil)}
126
+ setter_meths.each{|sm| set_column_value(sm, nil)}
127
127
  else
128
- setters.each{|sm, cm| get_column_value(sm, o.send(cm))}
128
+ setters.each{|sm, cm| set_column_value(sm, o.send(cm))}
129
129
  end
130
130
  end
131
131
  end
@@ -76,9 +76,9 @@ module Sequel
76
76
 
77
77
  # Set up the column readers to do deserialization and the column writers
78
78
  # to save the value in deserialized_values
79
- def self.configure(model, opts = {})
79
+ def self.configure(model, opts = OPTS)
80
80
  model.instance_eval do
81
- @csv_serializer_opts = (@csv_serializer_opts || {}).merge(opts)
81
+ @csv_serializer_opts = (@csv_serializer_opts || OPTS).merge(opts)
82
82
  end
83
83
  end
84
84
 
@@ -87,7 +87,7 @@ module Sequel
87
87
  attr_reader :csv_serializer_opts
88
88
 
89
89
  # Attempt to parse an array of instances from the given CSV string
90
- def array_from_csv(csv, opts = {})
90
+ def array_from_csv(csv, opts = OPTS)
91
91
  CSV.parse(csv, process_csv_serializer_opts(opts)).map do |row|
92
92
  row = row.to_hash
93
93
  row.delete(nil)
@@ -105,13 +105,13 @@ module Sequel
105
105
  end
106
106
 
107
107
  # Attempt to parse a single instance from the given CSV string
108
- def from_csv(csv, opts = {})
108
+ def from_csv(csv, opts = OPTS)
109
109
  new.from_csv(csv, opts)
110
110
  end
111
111
 
112
112
  # Convert the options hash to one that can be passed to CSV.
113
113
  def process_csv_serializer_opts(opts)
114
- opts = (csv_serializer_opts || {}).merge(opts)
114
+ opts = (csv_serializer_opts || OPTS).merge(opts)
115
115
  opts_cols = opts.delete(:columns)
116
116
  opts_include = opts.delete(:include)
117
117
  opts_except = opts.delete(:except)
@@ -136,7 +136,7 @@ module Sequel
136
136
  #
137
137
  # :headers :: The headers to use for the CSV line. Use nil for a header
138
138
  # to specify the column should be ignored.
139
- def from_csv(csv, opts = {})
139
+ def from_csv(csv, opts = OPTS)
140
140
  row = CSV.parse_line(csv, model.process_csv_serializer_opts(opts)).to_hash
141
141
  row.delete(nil)
142
142
  set(row)
@@ -151,7 +151,7 @@ module Sequel
151
151
  # output, ignoring all other columns
152
152
  # :include :: Symbol or Array of Symbols specifying non-column
153
153
  # attributes to include in the CSV output.
154
- def to_csv(opts = {})
154
+ def to_csv(opts = OPTS)
155
155
  opts = model.process_csv_serializer_opts(opts)
156
156
 
157
157
  CSV.generate(opts) do |csv|
@@ -168,7 +168,7 @@ module Sequel
168
168
  #
169
169
  # :array :: An array of instances. If this is not provided, calls #all
170
170
  # on the receiver to get the array.
171
- def to_csv(opts = {})
171
+ def to_csv(opts = OPTS)
172
172
  opts = model.process_csv_serializer_opts({:columns=>columns}.merge!(opts))
173
173
  items = opts.delete(:array) || self
174
174
 
@@ -93,22 +93,34 @@ module Sequel
93
93
  where(r.qualify(r.join_table_alias, r[:left_keys])=>sds.select(*r.qualify(model.table_name, r[:left_primary_key_columns])))
94
94
  ds.where(r.qualified_right_primary_key=>r.send(:apply_filter_by_associations_limit_strategy, mds))
95
95
  when :many_through_many, :one_through_many
96
- fe, *edges = r.edges
97
- edges << r.final_edge
98
- if fre = r.reverse_edges.first
99
- table = fre[:table]
100
- left = fre[:left]
101
- mds = model.join(fe[:table], Array(fe[:right]).zip(Array(fe[:left])), :implicit_qualifier=>model.table_name)
102
- else
103
- table = fe[:table]
104
- left = edges.first[:left]
105
- edges = []
96
+ if r.reverse_edges.empty?
106
97
  mds = r.associated_dataset
98
+ fe = r.edges.first
99
+ selection = Array(r.qualify(fe[:table], r.final_edge[:left]))
100
+ predicate_key = r.qualify(fe[:table], fe[:right])
101
+ else
102
+ mds = model.dataset
103
+ iq = model.table_name
104
+ edges = r.edges.map(&:dup)
105
+ edges << r.final_edge.dup
106
+ edges.each do |e|
107
+ alias_expr = e[:table]
108
+ aliaz = mds.unused_table_alias(e[:table])
109
+ unless aliaz == alias_expr
110
+ alias_expr = Sequel.as(e[:table], aliaz)
111
+ end
112
+ e[:alias] = aliaz
113
+ mds = mds.join(alias_expr, Array(e[:right]).zip(Array(e[:left])), :implicit_qualifier=>iq)
114
+ iq = nil
115
+ end
116
+ fe, f1e, f2e = edges.values_at(0, -1, -2)
117
+ selection = Array(r.qualify(f2e[:alias], f1e[:left]))
118
+ predicate_key = r.qualify(fe[:alias], fe[:right])
107
119
  end
120
+
108
121
  mds = mds.
109
- select(*Array(r.qualify(table, left))).
110
- where(r.qualify(fe[:table], fe[:right])=>sds.select(*r.qualify(model.table_name, r[:left_primary_key_columns])))
111
- edges.each{|e| mds = mds.join(e[:table], Array(e[:right]).zip(Array(e[:left])))}
122
+ select(*selection).
123
+ where(predicate_key=>sds.select(*r.qualify(model.table_name, r[:left_primary_key_columns])))
112
124
  ds.where(r.qualified_right_primary_key=>r.send(:apply_filter_by_associations_limit_strategy, mds))
113
125
  when :pg_array_to_many
114
126
  ds.where(Sequel[r.primary_key=>sds.select{Sequel.pg_array_op(r.qualify(r[:model].table_name, r[:key])).unnest}])
@@ -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
  #
@@ -36,6 +46,8 @@ module Sequel
36
46
 
37
47
  Plugins.after_set_dataset(self, :set_default_values)
38
48
 
49
+ Plugins.inherited_instance_variables(self, :@default_values=>:dup)
50
+
39
51
  # Freeze default values when freezing model class
40
52
  def freeze
41
53
  @default_values.freeze
@@ -48,7 +60,7 @@ module Sequel
48
60
  def set_default_values
49
61
  h = {}
50
62
  @db_schema.each{|k, v| h[k] = convert_default_value(v[:ruby_default]) unless v[:ruby_default].nil?} if @db_schema
51
- @default_values = h
63
+ @default_values = h.merge!(@default_values || {})
52
64
  end
53
65
 
54
66
  # Handle the CURRENT_DATE and CURRENT_TIMESTAMP values specially by returning an appropriate Date or
@@ -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
@@ -316,7 +321,7 @@ module Sequel
316
321
  if inc.is_a?(Hash)
317
322
  inc.each do |k, v|
318
323
  if k.is_a?(Sequel::SQL::AliasedExpression)
319
- key_name = k.aliaz.to_s
324
+ key_name = k.alias.to_s
320
325
  k = k.expression
321
326
  else
322
327
  key_name = k.to_s
@@ -341,7 +346,7 @@ module Sequel
341
346
  else
342
347
  Array(inc).each do |c|
343
348
  if c.is_a?(Sequel::SQL::AliasedExpression)
344
- key_name = c.aliaz.to_s
349
+ key_name = c.alias.to_s
345
350
  c = c.expression
346
351
  else
347
352
  key_name = c.to_s
@@ -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]
@@ -1,5 +1,7 @@
1
1
  # frozen-string-literal: true
2
2
 
3
+ Sequel::Deprecation.deprecate("The many_to_one_pk_lookup plugin", "This plugin was integrated into the default model behavior in Sequel 4.0, and no longer has an effect")
4
+
3
5
  module Sequel
4
6
  module Plugins
5
7
  # Empty plugin module for backwards compatibility
@@ -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
@@ -70,7 +70,7 @@ module Sequel
70
70
  #
71
71
  # Then you can do:
72
72
  #
73
- # artist.update(params[:artist])
73
+ # artist.update_fields(params[:artist], [:name, :albums_artists])
74
74
  #
75
75
  # To save changes to the artist, create the first album and associate it to the artist,
76
76
  # and update the other existing associated album.
@@ -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.
@@ -53,7 +53,9 @@ module Sequel
53
53
  # Address.load(:street=>'123 Foo St', :city=>'Bar Town', :zip=>'12345'))
54
54
  module PgRow
55
55
  ROW = 'ROW'.freeze
56
+ Sequel::Deprecation.deprecate_constant(self, :ROW)
56
57
  CAST = '::'.freeze
58
+ Sequel::Deprecation.deprecate_constant(self, :CAST)
57
59
 
58
60
  # When loading the extension, make sure the database has the pg_row extension
59
61
  # loaded, load the custom database extensions, and automatically register the
@@ -75,9 +77,9 @@ module Sequel
75
77
  module InstanceMethods
76
78
  # Literalize the model instance and append it to the sql.
77
79
  def sql_literal_append(ds, sql)
78
- sql << ROW
80
+ sql << 'ROW'
79
81
  ds.literal_append(sql, values.values_at(*columns))
80
- sql << CAST
82
+ sql << '::'
81
83
  ds.quote_schema_table_append(sql, model.dataset.first_source_table)
82
84
  end
83
85
  end
@@ -1,5 +1,7 @@
1
1
  # frozen-string-literal: true
2
2
 
3
+ Sequel::Deprecation.deprecate("The pg_typecast_on_load plugin", "This plugin is only useful on the deprecated do and switch adapters")
4
+
3
5
  module Sequel
4
6
  module Plugins
5
7
  # The PgTypecastOnLoad plugin exists because when you connect to PostgreSQL
@@ -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