sequel 4.22.0 → 4.23.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (214) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +22 -0
  3. data/README.rdoc +6 -0
  4. data/Rakefile +59 -81
  5. data/doc/migration.rdoc +2 -0
  6. data/doc/release_notes/4.23.0.txt +65 -0
  7. data/doc/sharding.rdoc +16 -14
  8. data/doc/testing.rdoc +61 -77
  9. data/lib/sequel/adapters/jdbc.rb +1 -0
  10. data/lib/sequel/adapters/mock.rb +0 -1
  11. data/lib/sequel/adapters/postgres.rb +1 -0
  12. data/lib/sequel/adapters/postgresql.rb +1 -0
  13. data/lib/sequel/adapters/shared/postgres.rb +3 -3
  14. data/lib/sequel/connection_pool/sharded_threaded.rb +5 -0
  15. data/lib/sequel/connection_pool/threaded.rb +9 -1
  16. data/lib/sequel/database/connecting.rb +1 -1
  17. data/lib/sequel/database/transactions.rb +2 -1
  18. data/lib/sequel/dataset/prepared_statements.rb +1 -1
  19. data/lib/sequel/extensions/constraint_validations.rb +12 -12
  20. data/lib/sequel/extensions/date_arithmetic.rb +0 -4
  21. data/lib/sequel/extensions/pagination.rb +14 -2
  22. data/lib/sequel/extensions/pg_enum.rb +2 -2
  23. data/lib/sequel/extensions/pg_hstore.rb +1 -1
  24. data/lib/sequel/extensions/pg_json_ops.rb +2 -2
  25. data/lib/sequel/plugins/csv_serializer.rb +2 -0
  26. data/lib/sequel/plugins/delay_add_association.rb +50 -0
  27. data/lib/sequel/plugins/list.rb +2 -2
  28. data/lib/sequel/plugins/nested_attributes.rb +8 -28
  29. data/lib/sequel/plugins/update_refresh.rb +50 -0
  30. data/lib/sequel/plugins/validate_associated.rb +55 -0
  31. data/lib/sequel/version.rb +1 -1
  32. data/spec/adapters/db2_spec.rb +29 -29
  33. data/spec/adapters/firebird_spec.rb +97 -103
  34. data/spec/adapters/informix_spec.rb +25 -25
  35. data/spec/adapters/mssql_spec.rb +156 -172
  36. data/spec/adapters/mysql_spec.rb +334 -359
  37. data/spec/adapters/oracle_spec.rb +67 -69
  38. data/spec/adapters/postgres_spec.rb +1298 -1249
  39. data/spec/adapters/spec_helper.rb +2 -35
  40. data/spec/adapters/sqlanywhere_spec.rb +39 -39
  41. data/spec/adapters/sqlite_spec.rb +203 -200
  42. data/spec/bin_spec.rb +57 -59
  43. data/spec/core/connection_pool_spec.rb +402 -401
  44. data/spec/core/database_spec.rb +953 -944
  45. data/spec/core/dataset_spec.rb +2178 -2168
  46. data/spec/core/deprecated_spec.rb +19 -19
  47. data/spec/core/expression_filters_spec.rb +415 -415
  48. data/spec/core/mock_adapter_spec.rb +212 -212
  49. data/spec/core/object_graph_spec.rb +73 -73
  50. data/spec/core/placeholder_literalizer_spec.rb +71 -71
  51. data/spec/core/schema_generator_spec.rb +44 -44
  52. data/spec/core/schema_spec.rb +470 -472
  53. data/spec/core/spec_helper.rb +5 -20
  54. data/spec/core/version_spec.rb +2 -2
  55. data/spec/core_extensions_spec.rb +320 -320
  56. data/spec/extensions/accessed_columns_spec.rb +12 -12
  57. data/spec/extensions/active_model_spec.rb +3 -3
  58. data/spec/extensions/after_initialize_spec.rb +2 -2
  59. data/spec/extensions/arbitrary_servers_spec.rb +23 -23
  60. data/spec/extensions/association_dependencies_spec.rb +34 -34
  61. data/spec/extensions/association_pks_spec.rb +98 -98
  62. data/spec/extensions/association_proxies_spec.rb +33 -33
  63. data/spec/extensions/auto_validations_spec.rb +46 -46
  64. data/spec/extensions/blacklist_security_spec.rb +19 -18
  65. data/spec/extensions/blank_spec.rb +36 -36
  66. data/spec/extensions/boolean_readers_spec.rb +36 -36
  67. data/spec/extensions/caching_spec.rb +82 -82
  68. data/spec/extensions/class_table_inheritance_spec.rb +72 -72
  69. data/spec/extensions/column_conflicts_spec.rb +19 -14
  70. data/spec/extensions/column_select_spec.rb +19 -19
  71. data/spec/extensions/columns_introspection_spec.rb +43 -43
  72. data/spec/extensions/composition_spec.rb +64 -64
  73. data/spec/extensions/connection_validator_spec.rb +92 -90
  74. data/spec/extensions/constraint_validations_plugin_spec.rb +92 -92
  75. data/spec/extensions/constraint_validations_spec.rb +80 -80
  76. data/spec/extensions/core_refinements_spec.rb +220 -220
  77. data/spec/extensions/csv_serializer_spec.rb +44 -44
  78. data/spec/extensions/current_datetime_timestamp_spec.rb +8 -8
  79. data/spec/extensions/dataset_associations_spec.rb +65 -65
  80. data/spec/extensions/dataset_source_alias_spec.rb +16 -16
  81. data/spec/extensions/date_arithmetic_spec.rb +51 -58
  82. data/spec/extensions/defaults_setter_spec.rb +19 -19
  83. data/spec/extensions/delay_add_association_spec.rb +52 -0
  84. data/spec/extensions/dirty_spec.rb +51 -51
  85. data/spec/extensions/eager_each_spec.rb +8 -8
  86. data/spec/extensions/empty_array_ignore_nulls_spec.rb +10 -10
  87. data/spec/extensions/error_splitter_spec.rb +2 -2
  88. data/spec/extensions/error_sql_spec.rb +4 -4
  89. data/spec/extensions/eval_inspect_spec.rb +3 -3
  90. data/spec/extensions/filter_having_spec.rb +8 -8
  91. data/spec/extensions/force_encoding_spec.rb +30 -30
  92. data/spec/extensions/from_block_spec.rb +7 -7
  93. data/spec/extensions/graph_each_spec.rb +19 -19
  94. data/spec/extensions/hash_aliases_spec.rb +5 -5
  95. data/spec/extensions/hook_class_methods_spec.rb +100 -100
  96. data/spec/extensions/inflector_spec.rb +54 -54
  97. data/spec/extensions/input_transformer_spec.rb +10 -10
  98. data/spec/extensions/insert_returning_select_spec.rb +8 -8
  99. data/spec/extensions/instance_filters_spec.rb +26 -26
  100. data/spec/extensions/instance_hooks_spec.rb +85 -85
  101. data/spec/extensions/json_serializer_spec.rb +68 -68
  102. data/spec/extensions/lazy_attributes_spec.rb +49 -49
  103. data/spec/extensions/list_spec.rb +77 -75
  104. data/spec/extensions/looser_typecasting_spec.rb +16 -16
  105. data/spec/extensions/many_through_many_spec.rb +627 -627
  106. data/spec/extensions/meta_def_spec.rb +7 -7
  107. data/spec/extensions/migration_spec.rb +217 -217
  108. data/spec/extensions/modification_detection_spec.rb +20 -20
  109. data/spec/extensions/mssql_optimistic_locking_spec.rb +21 -21
  110. data/spec/extensions/named_timezones_spec.rb +18 -18
  111. data/spec/extensions/nested_attributes_spec.rb +107 -107
  112. data/spec/extensions/null_dataset_spec.rb +24 -24
  113. data/spec/extensions/optimistic_locking_spec.rb +21 -21
  114. data/spec/extensions/pagination_spec.rb +52 -52
  115. data/spec/extensions/pg_array_associations_spec.rb +273 -273
  116. data/spec/extensions/pg_array_ops_spec.rb +52 -52
  117. data/spec/extensions/pg_array_spec.rb +152 -152
  118. data/spec/extensions/pg_enum_spec.rb +13 -13
  119. data/spec/extensions/pg_hstore_ops_spec.rb +63 -63
  120. data/spec/extensions/pg_hstore_spec.rb +84 -84
  121. data/spec/extensions/pg_inet_spec.rb +15 -15
  122. data/spec/extensions/pg_interval_spec.rb +29 -29
  123. data/spec/extensions/pg_json_ops_spec.rb +86 -84
  124. data/spec/extensions/pg_json_spec.rb +104 -104
  125. data/spec/extensions/pg_loose_count_spec.rb +6 -6
  126. data/spec/extensions/pg_range_ops_spec.rb +24 -24
  127. data/spec/extensions/pg_range_spec.rb +143 -143
  128. data/spec/extensions/pg_row_ops_spec.rb +14 -14
  129. data/spec/extensions/pg_row_plugin_spec.rb +12 -12
  130. data/spec/extensions/pg_row_spec.rb +118 -118
  131. data/spec/extensions/pg_static_cache_updater_spec.rb +28 -28
  132. data/spec/extensions/pg_typecast_on_load_spec.rb +21 -21
  133. data/spec/extensions/prepared_statements_associations_spec.rb +42 -42
  134. data/spec/extensions/prepared_statements_safe_spec.rb +18 -18
  135. data/spec/extensions/prepared_statements_spec.rb +28 -28
  136. data/spec/extensions/prepared_statements_with_pk_spec.rb +11 -11
  137. data/spec/extensions/pretty_table_spec.rb +16 -16
  138. data/spec/extensions/query_literals_spec.rb +37 -37
  139. data/spec/extensions/query_spec.rb +32 -32
  140. data/spec/extensions/rcte_tree_spec.rb +141 -141
  141. data/spec/extensions/round_timestamps_spec.rb +21 -21
  142. data/spec/extensions/schema_caching_spec.rb +8 -8
  143. data/spec/extensions/schema_dumper_spec.rb +78 -78
  144. data/spec/extensions/schema_spec.rb +31 -27
  145. data/spec/extensions/scissors_spec.rb +3 -3
  146. data/spec/extensions/select_remove_spec.rb +14 -14
  147. data/spec/extensions/sequel_3_dataset_methods_spec.rb +28 -28
  148. data/spec/extensions/serialization_modification_detection_spec.rb +33 -33
  149. data/spec/extensions/serialization_spec.rb +79 -78
  150. data/spec/extensions/server_block_spec.rb +17 -17
  151. data/spec/extensions/set_overrides_spec.rb +30 -30
  152. data/spec/extensions/sharding_spec.rb +65 -65
  153. data/spec/extensions/shared_caching_spec.rb +29 -29
  154. data/spec/extensions/single_table_inheritance_spec.rb +79 -79
  155. data/spec/extensions/skip_create_refresh_spec.rb +3 -3
  156. data/spec/extensions/spec_helper.rb +4 -29
  157. data/spec/extensions/split_array_nil_spec.rb +9 -9
  158. data/spec/extensions/split_values_spec.rb +7 -7
  159. data/spec/extensions/sql_expr_spec.rb +32 -32
  160. data/spec/extensions/static_cache_spec.rb +123 -123
  161. data/spec/extensions/string_date_time_spec.rb +34 -34
  162. data/spec/extensions/string_stripper_spec.rb +15 -15
  163. data/spec/extensions/subclasses_spec.rb +31 -31
  164. data/spec/extensions/table_select_spec.rb +15 -15
  165. data/spec/extensions/tactical_eager_loading_spec.rb +23 -23
  166. data/spec/extensions/thread_local_timezones_spec.rb +13 -13
  167. data/spec/extensions/timestamps_spec.rb +40 -40
  168. data/spec/extensions/to_dot_spec.rb +34 -34
  169. data/spec/extensions/touch_spec.rb +52 -52
  170. data/spec/extensions/tree_spec.rb +72 -72
  171. data/spec/extensions/typecast_on_load_spec.rb +25 -25
  172. data/spec/extensions/unlimited_update_spec.rb +2 -2
  173. data/spec/extensions/update_or_create_spec.rb +36 -36
  174. data/spec/extensions/update_primary_key_spec.rb +35 -35
  175. data/spec/extensions/update_refresh_spec.rb +41 -0
  176. data/spec/extensions/validate_associated_spec.rb +52 -0
  177. data/spec/extensions/validation_class_methods_spec.rb +314 -317
  178. data/spec/extensions/validation_helpers_spec.rb +195 -195
  179. data/spec/extensions/xml_serializer_spec.rb +48 -48
  180. data/spec/guards_helper.rb +55 -0
  181. data/spec/integration/associations_test.rb +1089 -1088
  182. data/spec/integration/database_test.rb +29 -29
  183. data/spec/integration/dataset_test.rb +661 -661
  184. data/spec/integration/eager_loader_test.rb +147 -147
  185. data/spec/integration/migrator_test.rb +122 -122
  186. data/spec/integration/model_test.rb +70 -70
  187. data/spec/integration/plugin_test.rb +682 -640
  188. data/spec/integration/prepared_statement_test.rb +172 -172
  189. data/spec/integration/schema_test.rb +245 -245
  190. data/spec/integration/spec_helper.rb +1 -64
  191. data/spec/integration/timezone_test.rb +17 -17
  192. data/spec/integration/transaction_test.rb +87 -87
  193. data/spec/integration/type_test.rb +33 -33
  194. data/spec/model/association_reflection_spec.rb +130 -121
  195. data/spec/model/associations_spec.rb +1112 -1113
  196. data/spec/model/base_spec.rb +197 -196
  197. data/spec/model/class_dataset_methods_spec.rb +118 -118
  198. data/spec/model/dataset_methods_spec.rb +49 -49
  199. data/spec/model/eager_loading_spec.rb +705 -702
  200. data/spec/model/hooks_spec.rb +169 -168
  201. data/spec/model/inflector_spec.rb +5 -5
  202. data/spec/model/model_spec.rb +287 -297
  203. data/spec/model/plugins_spec.rb +47 -47
  204. data/spec/model/record_spec.rb +534 -535
  205. data/spec/model/spec_helper.rb +3 -21
  206. data/spec/model/validations_spec.rb +72 -70
  207. data/spec/spec_config.rb +8 -0
  208. metadata +41 -9
  209. data/lib/sequel/adapters/fdbsql.rb +0 -286
  210. data/lib/sequel/adapters/jdbc/fdbsql.rb +0 -66
  211. data/lib/sequel/adapters/openbase.rb +0 -54
  212. data/lib/sequel/adapters/shared/fdbsql.rb +0 -550
  213. data/spec/adapters/fdbsql_spec.rb +0 -429
  214. data/spec/rspec_helper.rb +0 -22
@@ -698,6 +698,7 @@ module Sequel
698
698
  sql = @sproc_name
699
699
  opts = Hash[opts]
700
700
  opts[:args] = @sproc_args
701
+ opts[:sproc] = true
701
702
  opts[:type] = :insert
702
703
  super
703
704
  end
@@ -37,7 +37,6 @@ module Sequel
37
37
  'cubrid'=>'Cubrid',
38
38
  'db2'=>'DB2',
39
39
  'firebird'=>'Firebird',
40
- 'fdbsql'=>'Fdbsql',
41
40
  'informix'=>'Informix',
42
41
  'mssql'=>'MSSQL',
43
42
  'mysql'=>'MySQL',
@@ -189,6 +189,7 @@ module Sequel
189
189
  INFINITE_TIMESTAMP_STRINGS = ['infinity'.freeze, '-infinity'.freeze].freeze
190
190
  INFINITE_DATETIME_VALUES = ([PLUS_INFINITY, MINUS_INFINITY] + INFINITE_TIMESTAMP_STRINGS).freeze
191
191
 
192
+ set_adapter_scheme :postgresql
192
193
  set_adapter_scheme :postgres
193
194
 
194
195
  # Whether infinite timestamps/dates should be converted on retrieval. By default, no
@@ -0,0 +1 @@
1
+ Sequel.require 'adapters/postgres'
@@ -706,7 +706,7 @@ module Sequel
706
706
  # Convert the hash of named conversion procs into a hash a oid conversion procs.
707
707
  def convert_named_procs_to_procs(named_procs)
708
708
  h = {}
709
- from(:pg_type).where(:typtype=>'b', :typname=>named_procs.keys.map(&:to_s)).select_map([:oid, :typname]).each do |oid, name|
709
+ from(:pg_type).where(:typtype=>['b', 'e'], :typname=>named_procs.keys.map(&:to_s)).select_map([:oid, :typname]).each do |oid, name|
710
710
  h[oid.to_i] = named_procs[name.untaint.to_sym]
711
711
  end
712
712
  h
@@ -1294,9 +1294,9 @@ module Sequel
1294
1294
  # returned rows also include the exact phrase used.
1295
1295
  # :rank :: Set to true to order by the rank, so that closer matches are returned first.
1296
1296
  # :tsquery :: Specifies the terms argument is already a valid SQL expression returning a
1297
- # tsquery, and can be used directly in the query.
1297
+ # tsquery, and can be used directly in the query.
1298
1298
  # :tsvector :: Specifies the cols argument is already a valid SQL expression returning a
1299
- # tsvector, and can be used directly in the query.
1299
+ # tsvector, and can be used directly in the query.
1300
1300
  def full_text_search(cols, terms, opts = OPTS)
1301
1301
  lang = Sequel.cast(opts[:language] || 'simple', :regconfig)
1302
1302
 
@@ -192,8 +192,13 @@ class Sequel::ShardedThreadedConnectionPool < Sequel::ThreadedConnectionPool
192
192
  deadline ||= time + @timeout
193
193
  current_time = Time.now
194
194
  raise(::Sequel::PoolTimeout, "timeout: #{@timeout}, elapsed: #{current_time - time}") if current_time > deadline
195
+ # :nocov:
196
+ # It's difficult to get to this point, it can only happen if there is a race condition
197
+ # where a connection cannot be acquired even after the thread is signalled by the condition
198
+ # variable that a connection is ready.
195
199
  @waiters[server].wait(@mutex, deadline - current_time)
196
200
  Thread.pass
201
+ # :nocov:
197
202
  end
198
203
 
199
204
  conn
@@ -4,7 +4,9 @@ class Sequel::ThreadedConnectionPool < Sequel::ConnectionPool
4
4
  # Whether or not a ConditionVariable should be used to wait for connections.
5
5
  # True except on ruby 1.8, where ConditionVariable#wait does not support a
6
6
  # timeout.
7
- USE_WAITER = RUBY_VERSION >= '1.9'
7
+ unless defined?(USE_WAITER)
8
+ USE_WAITER = RUBY_VERSION >= '1.9'
9
+ end
8
10
 
9
11
  # The maximum number of connections this pool will create (per shard/server
10
12
  # if sharding).
@@ -40,7 +42,9 @@ class Sequel::ThreadedConnectionPool < Sequel::ConnectionPool
40
42
  if USE_WAITER
41
43
  @waiter = ConditionVariable.new
42
44
  else
45
+ # :nocov:
43
46
  @sleep_time = Float(opts[:pool_sleep_time] || 0.001)
47
+ # :nocov:
44
48
  end
45
49
  end
46
50
 
@@ -155,8 +159,12 @@ class Sequel::ThreadedConnectionPool < Sequel::ConnectionPool
155
159
  deadline ||= time + @timeout
156
160
  current_time = Time.now
157
161
  raise(::Sequel::PoolTimeout, "timeout: #{@timeout}, elapsed: #{current_time - time}") if current_time > deadline
162
+ # :nocov:
163
+ # It's difficult to get to this point, it can only happen if there is a race condition
164
+ # where a connection cannot be acquired even after the thread is signalled by the condition
158
165
  @waiter.wait(@mutex, deadline - current_time)
159
166
  Thread.pass
167
+ # :nocov:
160
168
  end
161
169
 
162
170
  conn
@@ -6,7 +6,7 @@ module Sequel
6
6
  # ---------------------
7
7
 
8
8
  # Array of supported database adapters
9
- ADAPTERS = %w'ado amalgalite cubrid db2 dbi do fdbsql firebird ibmdb informix jdbc mock mysql mysql2 odbc openbase oracle postgres sqlanywhere sqlite swift tinytds'.collect(&:to_sym)
9
+ ADAPTERS = %w'ado amalgalite cubrid db2 dbi do firebird ibmdb informix jdbc mock mysql mysql2 odbc oracle postgres sqlanywhere sqlite swift tinytds'.collect(&:to_sym)
10
10
 
11
11
  @single_threaded = false
12
12
 
@@ -124,7 +124,7 @@ module Sequel
124
124
  begin_transaction(conn, opts)
125
125
  if rollback == :always
126
126
  begin
127
- yield(conn)
127
+ ret = yield(conn)
128
128
  rescue Exception => e1
129
129
  raise e1
130
130
  ensure
@@ -139,6 +139,7 @@ module Sequel
139
139
  rescue Exception
140
140
  end
141
141
  transaction_error(e, :conn=>conn, :rollback=>rollback)
142
+ ret
142
143
  ensure
143
144
  begin
144
145
  committed = commit_or_rollback_transaction(e, conn, opts)
@@ -30,7 +30,7 @@ module Sequel
30
30
  meths.each do |meth|
31
31
  module_eval("def #{meth}(sql, opts=Sequel::OPTS) #{code}; super end", __FILE__, __LINE__)
32
32
  end
33
- private *meths
33
+ private(*meths)
34
34
  end
35
35
  end
36
36
  private_class_method :prepared_statements_module
@@ -224,6 +224,16 @@ module Sequel
224
224
  end
225
225
  end
226
226
 
227
+ # Modify the default create_table generator to include
228
+ # the constraint validation methods.
229
+ def create_table_generator(&block)
230
+ super do
231
+ extend CreateTableGeneratorMethods
232
+ @validations = []
233
+ instance_eval(&block) if block
234
+ end
235
+ end
236
+
227
237
  # Drop the constraint validations table.
228
238
  def drop_constraint_validations_table
229
239
  drop_table(constraint_validations_table)
@@ -262,8 +272,6 @@ module Sequel
262
272
  ds.delete
263
273
  end
264
274
 
265
- private
266
-
267
275
  # Modify the default alter_table generator to include
268
276
  # the constraint validation methods.
269
277
  def alter_table_generator(&block)
@@ -274,6 +282,8 @@ module Sequel
274
282
  end
275
283
  end
276
284
 
285
+ private
286
+
277
287
  # After running all of the table alteration statements,
278
288
  # if there were any constraint validations, run table alteration
279
289
  # statements to create related constraints. This is purposely
@@ -317,16 +327,6 @@ module Sequel
317
327
  super
318
328
  end
319
329
 
320
- # Modify the default create_table generator to include
321
- # the constraint validation methods.
322
- def create_table_generator(&block)
323
- super do
324
- extend CreateTableGeneratorMethods
325
- @validations = []
326
- instance_eval(&block) if block
327
- end
328
- end
329
-
330
330
  # For the given table, generator, and validations, add constraints
331
331
  # to the generator for each of the validations, as well as adding
332
332
  # validation metadata to the constraint validations table.
@@ -123,10 +123,6 @@ module Sequel
123
123
  expr = Sequel.+(expr, Sequel.lit(["", " "], value, sql_unit))
124
124
  end
125
125
  false
126
- when :fdbsql
127
- each_valid_interval_unit(h, FDBSQL_DURATION_UNITS) do |value, sql_unit|
128
- expr = Sequel.+(expr, Sequel.lit(["INTERVAL ", " "], value, sql_unit))
129
- end
130
126
  else
131
127
  raise Error, "date arithmetic is not implemented on #{db.database_type}"
132
128
  end
@@ -1,6 +1,18 @@
1
1
  # The pagination extension adds the Sequel::Dataset#paginate and #each_page methods,
2
- # which return paginated (limited and offset) datasets with some helpful methods
3
- # that make creating a paginated display easier.
2
+ # which return paginated (limited and offset) datasets with the following methods
3
+ # added that make creating a paginated display easier:
4
+ #
5
+ # * +page_size+
6
+ # * +page_count+
7
+ # * +page_range+
8
+ # * +current_page+
9
+ # * +next_page+
10
+ # * +prev_page+
11
+ # * +first_page?+
12
+ # * +last_page?+
13
+ # * +pagination_record_count+
14
+ # * +current_page_record_count+
15
+ # * +current_page_record_range+
4
16
  #
5
17
  # This extension uses Object#extend at runtime, which can hurt performance.
6
18
  #
@@ -18,7 +18,7 @@
18
18
  # Just like any user-created type, after creating the type, you
19
19
  # can create tables that have a column of that type:
20
20
  #
21
- # DB.create_table(:table_name)
21
+ # DB.create_table(:table_name) do
22
22
  # enum_type_name :column_name
23
23
  # end
24
24
  #
@@ -31,7 +31,7 @@
31
31
  # If the pg_array extension is used, arrays of enums are returned as a
32
32
  # PGArray:
33
33
  #
34
- # DB.create_table(:table_name)
34
+ # DB.create_table(:table_name) do
35
35
  # column :column_name, 'enum_type_name[]'
36
36
  # end
37
37
  # DB[:table_name].get(:column_name)
@@ -8,7 +8,7 @@
8
8
  # as instances of Sequel::Postgres::HStore. HStore is
9
9
  # a DelegateClass of Hash, so it mostly acts like a hash, but not
10
10
  # completely (is_a?(Hash) is false). If you want the actual hash,
11
- # you can call Hstore#to_hash. This is done so that Sequel does not
11
+ # you can call HStore#to_hash. This is done so that Sequel does not
12
12
  # treat a HStore like a Hash by default, which would cause issues.
13
13
  #
14
14
  # In addition to the parsers, this extension comes with literalizers
@@ -210,9 +210,9 @@ module Sequel
210
210
  private
211
211
 
212
212
  # Return a placeholder literal with the given str and args, wrapped
213
- # in an JSONOp, used by operators that return json.
213
+ # in an JSONOp or JSONBOp, used by operators that return json or jsonb.
214
214
  def json_op(str, args)
215
- JSONOp.new(Sequel::SQL::PlaceholderLiteralString.new(str, [self, args]))
215
+ self.class.new(Sequel::SQL::PlaceholderLiteralString.new(str, [self, args]))
216
216
  end
217
217
 
218
218
  # Return a function with the given name, and the receiver as the first
@@ -1,5 +1,7 @@
1
1
  if RUBY_VERSION < "1.9"
2
+ # :nocov:
2
3
  require 'fastercsv'
4
+ # :nocov:
3
5
  else
4
6
  require 'csv'
5
7
  end
@@ -0,0 +1,50 @@
1
+ module Sequel
2
+ module Plugins
3
+ # The delay_add_association plugin delays the adding of
4
+ # associated objects to a new (unsaved) object until after the new
5
+ # object is saved. By default, if you attempt to add
6
+ # associated objects to a new object, Sequel will raise
7
+ # an error, because you need to have a primary key before
8
+ # saving the objects.
9
+ #
10
+ # When delaying the add of an associated object, the object
11
+ # will be immediately added to the cached association array.
12
+ # When saving the current object, it will also attempt to
13
+ # validate any associated objects, and if the associated objects
14
+ # are not valid, the current object will also be considered
15
+ # not valid.
16
+ #
17
+ # Usage:
18
+ #
19
+ # # Make all model subclass delay add_association for new objects
20
+ # Sequel::Model.plugin :delay_add_association
21
+ #
22
+ # # Make the Album class delay add_association for new objects
23
+ # Album.plugin :delay_add_association
24
+ module DelayAddAssociation
25
+ # Depend on the validate_associated plugin.
26
+ def self.apply(mod)
27
+ mod.plugin :validate_associated
28
+ end
29
+
30
+ module InstanceMethods
31
+ private
32
+
33
+ # Delay the addition of the associated object till after
34
+ # saving the current object, if the current object is new
35
+ # and the associated dataset requires a primary key on the
36
+ # current object.
37
+ def add_associated_object(opts, o, *args)
38
+ if opts.dataset_need_primary_key? && new?
39
+ delay_validate_associated_object(opts, o)
40
+ send(opts[:name]) << o
41
+ after_create_hook{super(opts, o, *args)}
42
+ o
43
+ else
44
+ super
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -129,11 +129,11 @@ module Sequel
129
129
  checked_transaction do
130
130
  ds = list_dataset
131
131
  op, ds = if target < current
132
- raise(Sequel::Error, "Moving too far up (target = #{target})") if target < 1
132
+ target = 1 if target < 1
133
133
  [:+, ds.filter(position_field=>target...current)]
134
134
  else
135
135
  lp ||= last_position
136
- raise(Sequel::Error, "Moving too far down (target = #{target}, last_position = #{lp})") if target > lp
136
+ target = lp if target > lp
137
137
  [:-, ds.filter(position_field=>(current + 1)..target)]
138
138
  end
139
139
  ds.update(position_field => Sequel::SQL::NumericExpression.new(op, position_field, 1))
@@ -37,14 +37,16 @@ module Sequel
37
37
  # of creating a new album.
38
38
  #
39
39
  # If you would like to delete the associated object instead of updating it, you add a _delete
40
- # entry to the hash:
40
+ # entry to the hash, and also pass the :destroy option when calling +nested_attributes+:
41
41
  #
42
+ # Artist.nested_attributes :albums, :destroy=>true
42
43
  # a.update(:albums_attributes => [{:id=>1, :_delete=>true}])
43
44
  #
44
45
  # This will delete the related associated object from the database. If you want to leave the
45
46
  # associated object in the database, but just remove it from the association, add a _remove
46
- # entry in the hash:
47
+ # entry in the hash, and also pass the :remove option when calling +nested_attributes+:
47
48
  #
49
+ # Artist.nested_attributes :albums, :remove=>true
48
50
  # a.update(:albums_attributes => [{:id=>1, :_remove=>true}])
49
51
  #
50
52
  # The above example was for a one_to_many association, but the plugin also works similarly
@@ -71,9 +73,9 @@ module Sequel
71
73
  # To save changes to the artist, create the first album and associate it to the artist,
72
74
  # and update the other existing associated album.
73
75
  module NestedAttributes
74
- # Depend on the instance_hooks plugin.
76
+ # Depend on the validate_associated plugin.
75
77
  def self.apply(model)
76
- model.plugin(:instance_hooks)
78
+ model.plugin(:validate_associated)
77
79
  end
78
80
 
79
81
  module ClassMethods
@@ -166,7 +168,7 @@ module Sequel
166
168
  reflection = meta[:reflection]
167
169
  obj = reflection.associated_class.new
168
170
  nested_attributes_set_attributes(meta, obj, attributes)
169
- after_validation_hook{validate_associated_object(meta, obj)}
171
+ delay_validate_associated_object(reflection, obj)
170
172
  if reflection.returns_array?
171
173
  send(reflection[:name]) << obj
172
174
  after_save_hook{send(reflection.add_method, obj)}
@@ -282,7 +284,7 @@ module Sequel
282
284
  # Returns the object updated.
283
285
  def nested_attributes_update(meta, obj, attributes)
284
286
  nested_attributes_update_attributes(meta, obj, attributes)
285
- after_validation_hook{validate_associated_object(meta, obj)}
287
+ delay_validate_associated_object(meta[:reflection], obj)
286
288
  # Don't need to validate the object twice if :validate association option is not false
287
289
  # and don't want to validate it at all if it is false.
288
290
  after_save_hook{obj.save_changes(:validate=>false)}
@@ -295,28 +297,6 @@ module Sequel
295
297
  nested_attributes_set_attributes(meta, obj, attributes)
296
298
  end
297
299
  end
298
-
299
- # Validate the given associated object, adding any validation error messages from the
300
- # given object to the parent object.
301
- def validate_associated_object(meta, obj)
302
- reflection = meta[:reflection]
303
- return if reflection[:validate] == false
304
- association = reflection[:name]
305
- if (reflection[:type] == :one_to_many || reflection[:type] == :one_to_one) && (key = reflection[:key]).is_a?(Symbol) && !(pk_val = obj.values[key])
306
- # There could be a presence validation on the foreign key in the associated model,
307
- # which will fail if we validate before saving the current object. If there is
308
- # no value for the foreign key, set it to the current primary key value, or a dummy
309
- # value of 0 if we haven't saved the current object.
310
- p_key = pk unless pk.is_a?(Array)
311
- obj.values[key] = p_key || 0
312
- key = nil if p_key
313
- end
314
- obj.errors.full_messages.each{|m| errors.add(association, m)} unless obj.valid?
315
- if key && !pk_val
316
- # If we used a dummy value of 0, remove it so it doesn't accidently remain.
317
- obj.values.delete(key)
318
- end
319
- end
320
300
  end
321
301
  end
322
302
  end
@@ -0,0 +1,50 @@
1
+ module Sequel
2
+ module Plugins
3
+ # The update_refresh plugin makes the model class refresh
4
+ # the object after updating. By default, Sequel only
5
+ # refreshes automatically after inserting new rows, not
6
+ # after updating. However, if you are using triggers
7
+ # to modify the contents of updated rows, it can be
8
+ # helpful to immediately get the current data after
9
+ # updating.
10
+ #
11
+ # If the dataset supports UPDATE RETURNING, this
12
+ # plugin will use it so that it can retrieve the current
13
+ # data in the same query it uses for the update.
14
+ #
15
+ # Usage:
16
+ #
17
+ # # Make all model subclasses refresh after update
18
+ # Sequel::Model.plugin :update_refresh
19
+ #
20
+ # # Make the Album class refresh after update
21
+ # Album.plugin :update_refresh
22
+ module UpdateRefresh
23
+ module InstanceMethods
24
+ def after_update
25
+ super
26
+ unless this.supports_returning?(:update)
27
+ refresh
28
+ end
29
+ end
30
+
31
+ private
32
+
33
+ def _update_without_checking(columns)
34
+ ds = _update_dataset
35
+ if ds.supports_returning?(:update)
36
+ ds = ds.opts[:returning] ? ds : ds.returning
37
+ rows = ds.update(columns)
38
+ n = rows.length
39
+ if n == 1
40
+ @values.merge!(rows.first)
41
+ end
42
+ n
43
+ else
44
+ super
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end