sequel 5.45.0 → 5.77.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (218) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +434 -0
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +59 -27
  5. data/bin/sequel +11 -3
  6. data/doc/advanced_associations.rdoc +16 -14
  7. data/doc/association_basics.rdoc +119 -24
  8. data/doc/cheat_sheet.rdoc +11 -3
  9. data/doc/mass_assignment.rdoc +1 -1
  10. data/doc/migration.rdoc +27 -6
  11. data/doc/model_hooks.rdoc +1 -1
  12. data/doc/object_model.rdoc +8 -8
  13. data/doc/opening_databases.rdoc +28 -12
  14. data/doc/postgresql.rdoc +16 -8
  15. data/doc/querying.rdoc +5 -3
  16. data/doc/release_notes/5.46.0.txt +87 -0
  17. data/doc/release_notes/5.47.0.txt +59 -0
  18. data/doc/release_notes/5.48.0.txt +14 -0
  19. data/doc/release_notes/5.49.0.txt +59 -0
  20. data/doc/release_notes/5.50.0.txt +78 -0
  21. data/doc/release_notes/5.51.0.txt +47 -0
  22. data/doc/release_notes/5.52.0.txt +87 -0
  23. data/doc/release_notes/5.53.0.txt +23 -0
  24. data/doc/release_notes/5.54.0.txt +27 -0
  25. data/doc/release_notes/5.55.0.txt +21 -0
  26. data/doc/release_notes/5.56.0.txt +51 -0
  27. data/doc/release_notes/5.57.0.txt +23 -0
  28. data/doc/release_notes/5.58.0.txt +31 -0
  29. data/doc/release_notes/5.59.0.txt +73 -0
  30. data/doc/release_notes/5.60.0.txt +22 -0
  31. data/doc/release_notes/5.61.0.txt +43 -0
  32. data/doc/release_notes/5.62.0.txt +132 -0
  33. data/doc/release_notes/5.63.0.txt +33 -0
  34. data/doc/release_notes/5.64.0.txt +50 -0
  35. data/doc/release_notes/5.65.0.txt +21 -0
  36. data/doc/release_notes/5.66.0.txt +24 -0
  37. data/doc/release_notes/5.67.0.txt +32 -0
  38. data/doc/release_notes/5.68.0.txt +61 -0
  39. data/doc/release_notes/5.69.0.txt +26 -0
  40. data/doc/release_notes/5.70.0.txt +35 -0
  41. data/doc/release_notes/5.71.0.txt +21 -0
  42. data/doc/release_notes/5.72.0.txt +33 -0
  43. data/doc/release_notes/5.73.0.txt +66 -0
  44. data/doc/release_notes/5.74.0.txt +45 -0
  45. data/doc/release_notes/5.75.0.txt +35 -0
  46. data/doc/release_notes/5.76.0.txt +86 -0
  47. data/doc/release_notes/5.77.0.txt +63 -0
  48. data/doc/schema_modification.rdoc +1 -1
  49. data/doc/security.rdoc +9 -9
  50. data/doc/sharding.rdoc +3 -1
  51. data/doc/sql.rdoc +27 -15
  52. data/doc/testing.rdoc +23 -13
  53. data/doc/transactions.rdoc +6 -6
  54. data/doc/virtual_rows.rdoc +1 -1
  55. data/lib/sequel/adapters/ado/access.rb +1 -1
  56. data/lib/sequel/adapters/ado.rb +1 -1
  57. data/lib/sequel/adapters/amalgalite.rb +3 -5
  58. data/lib/sequel/adapters/ibmdb.rb +3 -3
  59. data/lib/sequel/adapters/jdbc/derby.rb +8 -0
  60. data/lib/sequel/adapters/jdbc/h2.rb +63 -10
  61. data/lib/sequel/adapters/jdbc/hsqldb.rb +8 -0
  62. data/lib/sequel/adapters/jdbc/postgresql.rb +7 -4
  63. data/lib/sequel/adapters/jdbc/sqlanywhere.rb +15 -0
  64. data/lib/sequel/adapters/jdbc/sqlserver.rb +4 -0
  65. data/lib/sequel/adapters/jdbc.rb +24 -22
  66. data/lib/sequel/adapters/mysql.rb +92 -67
  67. data/lib/sequel/adapters/mysql2.rb +56 -51
  68. data/lib/sequel/adapters/odbc/mssql.rb +1 -1
  69. data/lib/sequel/adapters/odbc.rb +1 -1
  70. data/lib/sequel/adapters/oracle.rb +4 -3
  71. data/lib/sequel/adapters/postgres.rb +89 -45
  72. data/lib/sequel/adapters/shared/access.rb +11 -1
  73. data/lib/sequel/adapters/shared/db2.rb +42 -0
  74. data/lib/sequel/adapters/shared/mssql.rb +91 -10
  75. data/lib/sequel/adapters/shared/mysql.rb +78 -3
  76. data/lib/sequel/adapters/shared/oracle.rb +86 -7
  77. data/lib/sequel/adapters/shared/postgres.rb +576 -171
  78. data/lib/sequel/adapters/shared/sqlanywhere.rb +21 -5
  79. data/lib/sequel/adapters/shared/sqlite.rb +92 -8
  80. data/lib/sequel/adapters/sqlanywhere.rb +1 -1
  81. data/lib/sequel/adapters/sqlite.rb +99 -18
  82. data/lib/sequel/adapters/tinytds.rb +1 -1
  83. data/lib/sequel/adapters/trilogy.rb +117 -0
  84. data/lib/sequel/adapters/utils/columns_limit_1.rb +22 -0
  85. data/lib/sequel/adapters/utils/mysql_mysql2.rb +1 -1
  86. data/lib/sequel/ast_transformer.rb +6 -0
  87. data/lib/sequel/connection_pool/sharded_single.rb +5 -7
  88. data/lib/sequel/connection_pool/sharded_threaded.rb +16 -11
  89. data/lib/sequel/connection_pool/sharded_timed_queue.rb +374 -0
  90. data/lib/sequel/connection_pool/single.rb +6 -8
  91. data/lib/sequel/connection_pool/threaded.rb +14 -8
  92. data/lib/sequel/connection_pool/timed_queue.rb +270 -0
  93. data/lib/sequel/connection_pool.rb +57 -31
  94. data/lib/sequel/core.rb +17 -18
  95. data/lib/sequel/database/connecting.rb +27 -3
  96. data/lib/sequel/database/dataset.rb +16 -6
  97. data/lib/sequel/database/misc.rb +70 -14
  98. data/lib/sequel/database/query.rb +73 -2
  99. data/lib/sequel/database/schema_generator.rb +11 -6
  100. data/lib/sequel/database/schema_methods.rb +23 -4
  101. data/lib/sequel/database/transactions.rb +6 -0
  102. data/lib/sequel/dataset/actions.rb +111 -15
  103. data/lib/sequel/dataset/deprecated_singleton_class_methods.rb +42 -0
  104. data/lib/sequel/dataset/features.rb +20 -1
  105. data/lib/sequel/dataset/misc.rb +12 -2
  106. data/lib/sequel/dataset/placeholder_literalizer.rb +20 -9
  107. data/lib/sequel/dataset/query.rb +170 -41
  108. data/lib/sequel/dataset/sql.rb +190 -71
  109. data/lib/sequel/dataset.rb +4 -0
  110. data/lib/sequel/extensions/_model_pg_row.rb +0 -12
  111. data/lib/sequel/extensions/_pretty_table.rb +1 -1
  112. data/lib/sequel/extensions/any_not_empty.rb +2 -2
  113. data/lib/sequel/extensions/async_thread_pool.rb +14 -13
  114. data/lib/sequel/extensions/auto_cast_date_and_time.rb +94 -0
  115. data/lib/sequel/extensions/auto_literal_strings.rb +1 -1
  116. data/lib/sequel/extensions/connection_expiration.rb +15 -9
  117. data/lib/sequel/extensions/connection_validator.rb +16 -11
  118. data/lib/sequel/extensions/constraint_validations.rb +1 -1
  119. data/lib/sequel/extensions/core_refinements.rb +36 -11
  120. data/lib/sequel/extensions/date_arithmetic.rb +36 -8
  121. data/lib/sequel/extensions/date_parse_input_handler.rb +67 -0
  122. data/lib/sequel/extensions/datetime_parse_to_time.rb +5 -1
  123. data/lib/sequel/extensions/duplicate_columns_handler.rb +11 -10
  124. data/lib/sequel/extensions/index_caching.rb +5 -1
  125. data/lib/sequel/extensions/inflector.rb +1 -1
  126. data/lib/sequel/extensions/is_distinct_from.rb +141 -0
  127. data/lib/sequel/extensions/looser_typecasting.rb +3 -0
  128. data/lib/sequel/extensions/migration.rb +57 -15
  129. data/lib/sequel/extensions/named_timezones.rb +22 -6
  130. data/lib/sequel/extensions/pagination.rb +1 -1
  131. data/lib/sequel/extensions/pg_array.rb +33 -4
  132. data/lib/sequel/extensions/pg_array_ops.rb +2 -2
  133. data/lib/sequel/extensions/pg_auto_parameterize.rb +509 -0
  134. data/lib/sequel/extensions/pg_auto_parameterize_in_array.rb +110 -0
  135. data/lib/sequel/extensions/pg_enum.rb +1 -2
  136. data/lib/sequel/extensions/pg_extended_date_support.rb +39 -28
  137. data/lib/sequel/extensions/pg_extended_integer_support.rb +116 -0
  138. data/lib/sequel/extensions/pg_hstore.rb +6 -1
  139. data/lib/sequel/extensions/pg_hstore_ops.rb +53 -3
  140. data/lib/sequel/extensions/pg_inet.rb +10 -11
  141. data/lib/sequel/extensions/pg_inet_ops.rb +1 -1
  142. data/lib/sequel/extensions/pg_interval.rb +11 -11
  143. data/lib/sequel/extensions/pg_json.rb +13 -15
  144. data/lib/sequel/extensions/pg_json_ops.rb +125 -2
  145. data/lib/sequel/extensions/pg_multirange.rb +367 -0
  146. data/lib/sequel/extensions/pg_range.rb +13 -26
  147. data/lib/sequel/extensions/pg_range_ops.rb +37 -9
  148. data/lib/sequel/extensions/pg_row.rb +20 -19
  149. data/lib/sequel/extensions/pg_row_ops.rb +1 -1
  150. data/lib/sequel/extensions/pg_timestamptz.rb +27 -3
  151. data/lib/sequel/extensions/round_timestamps.rb +1 -1
  152. data/lib/sequel/extensions/s.rb +2 -1
  153. data/lib/sequel/extensions/schema_caching.rb +1 -1
  154. data/lib/sequel/extensions/schema_dumper.rb +45 -11
  155. data/lib/sequel/extensions/server_block.rb +10 -13
  156. data/lib/sequel/extensions/set_literalizer.rb +58 -0
  157. data/lib/sequel/extensions/sql_comments.rb +110 -3
  158. data/lib/sequel/extensions/sql_log_normalizer.rb +108 -0
  159. data/lib/sequel/extensions/sqlite_json_ops.rb +255 -0
  160. data/lib/sequel/extensions/string_agg.rb +1 -1
  161. data/lib/sequel/extensions/string_date_time.rb +19 -23
  162. data/lib/sequel/extensions/symbol_aref.rb +2 -0
  163. data/lib/sequel/extensions/transaction_connection_validator.rb +78 -0
  164. data/lib/sequel/model/associations.rb +286 -92
  165. data/lib/sequel/model/base.rb +53 -33
  166. data/lib/sequel/model/dataset_module.rb +3 -0
  167. data/lib/sequel/model/errors.rb +10 -1
  168. data/lib/sequel/model/exceptions.rb +15 -3
  169. data/lib/sequel/model/inflections.rb +1 -1
  170. data/lib/sequel/plugins/auto_restrict_eager_graph.rb +62 -0
  171. data/lib/sequel/plugins/auto_validations.rb +74 -16
  172. data/lib/sequel/plugins/class_table_inheritance.rb +2 -2
  173. data/lib/sequel/plugins/column_encryption.rb +29 -8
  174. data/lib/sequel/plugins/composition.rb +3 -2
  175. data/lib/sequel/plugins/concurrent_eager_loading.rb +4 -4
  176. data/lib/sequel/plugins/constraint_validations.rb +8 -5
  177. data/lib/sequel/plugins/defaults_setter.rb +16 -0
  178. data/lib/sequel/plugins/dirty.rb +1 -1
  179. data/lib/sequel/plugins/enum.rb +124 -0
  180. data/lib/sequel/plugins/finder.rb +4 -2
  181. data/lib/sequel/plugins/insert_conflict.rb +4 -0
  182. data/lib/sequel/plugins/instance_specific_default.rb +1 -1
  183. data/lib/sequel/plugins/json_serializer.rb +2 -2
  184. data/lib/sequel/plugins/lazy_attributes.rb +3 -0
  185. data/lib/sequel/plugins/list.rb +8 -3
  186. data/lib/sequel/plugins/many_through_many.rb +109 -10
  187. data/lib/sequel/plugins/mssql_optimistic_locking.rb +8 -38
  188. data/lib/sequel/plugins/nested_attributes.rb +4 -4
  189. data/lib/sequel/plugins/optimistic_locking.rb +9 -42
  190. data/lib/sequel/plugins/optimistic_locking_base.rb +55 -0
  191. data/lib/sequel/plugins/paged_operations.rb +181 -0
  192. data/lib/sequel/plugins/pg_array_associations.rb +46 -34
  193. data/lib/sequel/plugins/pg_auto_constraint_validations.rb +9 -3
  194. data/lib/sequel/plugins/pg_xmin_optimistic_locking.rb +109 -0
  195. data/lib/sequel/plugins/prepared_statements.rb +12 -2
  196. data/lib/sequel/plugins/prepared_statements_safe.rb +2 -1
  197. data/lib/sequel/plugins/primary_key_lookup_check_values.rb +154 -0
  198. data/lib/sequel/plugins/rcte_tree.rb +7 -4
  199. data/lib/sequel/plugins/require_valid_schema.rb +67 -0
  200. data/lib/sequel/plugins/serialization.rb +1 -0
  201. data/lib/sequel/plugins/serialization_modification_detection.rb +1 -0
  202. data/lib/sequel/plugins/single_table_inheritance.rb +8 -0
  203. data/lib/sequel/plugins/sql_comments.rb +189 -0
  204. data/lib/sequel/plugins/static_cache.rb +39 -1
  205. data/lib/sequel/plugins/static_cache_cache.rb +5 -1
  206. data/lib/sequel/plugins/subclasses.rb +28 -11
  207. data/lib/sequel/plugins/tactical_eager_loading.rb +23 -10
  208. data/lib/sequel/plugins/timestamps.rb +1 -1
  209. data/lib/sequel/plugins/unused_associations.rb +521 -0
  210. data/lib/sequel/plugins/update_or_create.rb +1 -1
  211. data/lib/sequel/plugins/validate_associated.rb +22 -12
  212. data/lib/sequel/plugins/validation_helpers.rb +41 -11
  213. data/lib/sequel/plugins/validation_helpers_generic_type_messages.rb +73 -0
  214. data/lib/sequel/plugins/xml_serializer.rb +1 -1
  215. data/lib/sequel/sql.rb +1 -1
  216. data/lib/sequel/timezones.rb +12 -14
  217. data/lib/sequel/version.rb +1 -1
  218. metadata +109 -19
data/bin/sequel CHANGED
@@ -194,7 +194,11 @@ begin
194
194
  TO_DB = connect_proc[db2]
195
195
  same_db = DB.database_type==TO_DB.database_type
196
196
  index_opts = {:same_db=>same_db}
197
+
198
+ # :nocov:
197
199
  index_opts[:index_names] = :namespace if !DB.global_index_namespace? && TO_DB.global_index_namespace?
200
+ # :nocov:
201
+
198
202
  if DB.database_type == :sqlite && !same_db
199
203
  # SQLite integer types allows 64-bit integers
200
204
  TO_DB.extension :integer64
@@ -212,18 +216,20 @@ begin
212
216
  puts "Begin copying data"
213
217
  DB.transaction do
214
218
  TO_DB.transaction do
219
+ all_status_lines = ENV['SEQUEL_BIN_STATUS_ALL_LINES']
220
+
215
221
  DB.tables.each do |table|
216
222
  puts "Begin copying records for table: #{table}"
217
223
  time = Time.now
218
224
  to_ds = TO_DB.from(table)
219
225
  j = 0
220
226
  DB.from(table).each do |record|
221
- if Time.now - time > 5
227
+ to_ds.insert(record)
228
+ j += 1
229
+ if Time.now - time > 5 || all_status_lines
222
230
  puts "Status: #{j} records copied"
223
231
  time = Time.now
224
232
  end
225
- to_ds.insert(record)
226
- j += 1
227
233
  end
228
234
  puts "Finished copying #{j} records for table: #{table}"
229
235
  end
@@ -260,8 +266,10 @@ if !ARGV.empty?
260
266
  ARGV.each{|v| load(v)}
261
267
  elsif !$stdin.isatty
262
268
  eval($stdin.read)
269
+ # :nocov:
263
270
  else
264
271
  require 'irb'
265
272
  puts "Your database is stored in DB..."
266
273
  IRB.start
267
274
  end
275
+ # :nocov:
@@ -115,7 +115,7 @@ These two approaches can also be nested, with +eager+ -> +eager_graph+ -> +eager
115
115
 
116
116
  Or with 2 separate +eager_graph+ queries:
117
117
 
118
- Artist.eager_graph(:albums).eager_graph_eager([:albums], :tracks=>proc{|ds| ds.eager_graph(:lyric)})
118
+ Artist.eager_graph(:albums).eager_graph_eager([:albums], tracks: proc{|ds| ds.eager_graph(:lyric)})
119
119
  # 2 Queries:
120
120
  # SELECT artists.id, artists.name, ...
121
121
  # albums.id AS albums_id, albums.name AS albums_name, ...
@@ -238,9 +238,9 @@ have the following associations
238
238
 
239
239
  and the following three albums in the database:
240
240
 
241
- album1 = Album.create(:artist_id=>3) # id: 1
242
- album2 = Album.create(:artist_id=>3) # id: 2
243
- album3 = Album.create(:artist_id=>2) # id: 3
241
+ album1 = Album.create(artist_id: 3) # id: 1
242
+ album2 = Album.create(artist_id: 3) # id: 2
243
+ album3 = Album.create(artist_id: 2) # id: 3
244
244
 
245
245
  If you try to eager load this dataset:
246
246
 
@@ -256,7 +256,7 @@ the are both in the array related to that key. album3 has a different
256
256
  artist_id, so it is in a different array. Eager loading of artists is
257
257
  done by looking for any artist having one of the keys in the hash:
258
258
 
259
- artists = Artist.where(:id=>id_map.keys).all
259
+ artists = Artist.where(id: id_map.keys).all
260
260
 
261
261
  When the artists are retrieved, you can iterate over them, find entries
262
262
  with matching keys, and manually associate them to the albums:
@@ -281,7 +281,7 @@ case each array only has a single object, because id is the primary key). So wh
281
281
  looking for tracks to eagerly load, you only need to look for ones that have an
282
282
  album_id with one of the keys in the hash:
283
283
 
284
- tracks = Track.where(:album_id=>id_map.keys).all
284
+ tracks = Track.where(album_id: id_map.keys).all
285
285
 
286
286
  When the tracks are retrieved, you can iterate over them, find entries with matching
287
287
  keys, and manually associate them to the albums:
@@ -314,10 +314,10 @@ artist or tracks method on the album will not do another database lookup.
314
314
 
315
315
  So putting everything together, the artist eager loader looks like:
316
316
 
317
- Album.many_to_one :artist, :eager_loader=>(proc do |eo_opts|
317
+ Album.many_to_one :artist, eager_loader: (proc do |eo_opts|
318
318
  eo_opts[:rows].each{|album| album.associations[:artist] = nil}
319
319
  id_map = eo_opts[:id_map]
320
- Artist.where(:id=>id_map.keys).all do |artist|
320
+ Artist.where(id: id_map.keys).all do |artist|
321
321
  if albums = id_map[artist.id]
322
322
  albums.each do |album|
323
323
  album.associations[:artist] = artist
@@ -328,10 +328,10 @@ So putting everything together, the artist eager loader looks like:
328
328
 
329
329
  and the tracks eager loader looks like:
330
330
 
331
- Album.one_to_many :tracks, :eager_loader=>(proc do |eo_opts|
331
+ Album.one_to_many :tracks, eager_loader: (proc do |eo_opts|
332
332
  eo_opts[:rows].each{|album| album.associations[:tracks] = []}
333
333
  id_map = eo_opts[:id_map]
334
- Track.where(:album_id=>id_map.keys).all do |track|
334
+ Track.where(album_id: id_map.keys).all do |track|
335
335
  if albums = id_map[track.album_id]
336
336
  albums.each do |album|
337
337
  album.associations[:tracks] << track
@@ -405,7 +405,7 @@ the window function strategy:
405
405
 
406
406
  Artist.one_to_many :first_10_albums, class: :Album, order: :release_date, limit: 10,
407
407
  eager_limit_strategy: :window_function
408
- Artist.where(:id=>[1,2]).eager(:first_10_albums).all
408
+ Artist.where(id: [1,2]).eager(:first_10_albums).all
409
409
  # SELECT * FROM (
410
410
  # SELECT *, row_number() OVER (PARTITION BY albums.artist_id ORDER BY release_date) AS x_sequel_row_number_x
411
411
  # FROM albums
@@ -483,7 +483,7 @@ function:
483
483
  The :correlated_subquery approach JOINs to a nested subquery using a correlated
484
484
  subquery:
485
485
 
486
- Artist.eager_graph_with_options(:first_10_albums, :limit_strategy=>:correlated_subquery).all
486
+ Artist.eager_graph_with_options(:first_10_albums, limit_strategy: :correlated_subquery).all
487
487
  # SELECT artists.id, artists.name, first_10_albums.id AS first_10_albums_id,
488
488
  # first_10_albums.name AS first_10_albums_name, first_10_albums.artist_id,
489
489
  # first_10_albums.release_date
@@ -670,8 +670,10 @@ polymorphic associations in Sequel about as easy as it is in ActiveRecord. Howe
670
670
  here's how they can be done using Sequel's custom associations (the sequel_polymorphic
671
671
  external plugin is just a generic version of this code):
672
672
 
673
+ Sequel.extension :inflector # for attachable_type.constantize
674
+
673
675
  class Asset < Sequel::Model
674
- many_to_one :attachable, reciprocal: :assets,
676
+ many_to_one :attachable, reciprocal: :assets, reciprocal_type: :one_to_many,
675
677
  setter: (lambda do |attachable|
676
678
  self[:attachable_id] = (attachable.pk if attachable)
677
679
  self[:attachable_type] = (attachable.class.name if attachable)
@@ -853,7 +855,7 @@ associated tickets.
853
855
  class Project < Sequel::Model
854
856
  one_to_many :tickets
855
857
  many_to_one :ticket_hours, read_only: true, key: :id,
856
- dataset: proc{Ticket.where(:project_id=>id).select{sum(hours).as(hours)}},
858
+ dataset: proc{Ticket.where(project_id: id).select{sum(hours).as(hours)}},
857
859
  eager_loader: (lambda do |eo|
858
860
  eo[:rows].each{|p| p.associations[:ticket_hours] = nil}
859
861
  Ticket.where(project_id: eo[:id_map].keys).
@@ -41,7 +41,7 @@ As is the code to add a related album to an artist:
41
41
 
42
42
  @artist.add_album(name: 'RF')
43
43
 
44
- It also makes it easier to creating queries that use joins based on the association:
44
+ It also makes it easier to create queries that use joins based on the association:
45
45
 
46
46
  Artist.association_join(:albums)
47
47
  # SELECT * FROM artists
@@ -63,8 +63,8 @@ It ships with additional association types via plugins.
63
63
 
64
64
  The many_to_one association is used when the table for the current class
65
65
  contains a foreign key that references the primary key in the table for the
66
- associated class. It is named because there can be many rows in the current
67
- table for each row in the associated table.
66
+ associated class. It is named 'many_to_one' because there can be many rows
67
+ in the current table for each row in the associated table.
68
68
 
69
69
  # Database schema:
70
70
  # albums artists
@@ -81,8 +81,8 @@ table for each row in the associated table.
81
81
 
82
82
  The one_to_many association is used when the table for the associated class
83
83
  contains a foreign key that references the primary key in the table for the
84
- current class. It is named because for each row in the current table there
85
- can be many rows in the associated table:
84
+ current class. It is named 'one_to_many' because for each row in the
85
+ current table there can be many rows in the associated table:
86
86
 
87
87
  The one_to_one association can be thought of as a subset of the one_to_many association,
88
88
  but where there can only be either 0 or 1 records in the associated table. This is
@@ -320,11 +320,11 @@ Associations are cached after being retrieved:
320
320
  @album.artists # Cached - No Database Query
321
321
 
322
322
  You can choose to ignore the cached versions and do a database query to
323
- retrieve results by passing a :reload=>true option to the association method:
323
+ retrieve results by passing a <tt>reload: true</tt> option to the association method:
324
324
 
325
325
  @album.artists # Not cached - Database Query
326
326
  @album.artists # Cached - No Database Query
327
- @album.artists(:reload=>true) # Ignore cache - Database Query
327
+ @album.artists(reload: true) # Ignore cache - Database Query
328
328
 
329
329
  If you reload/refresh the object, it will automatically clear the
330
330
  associations cache for the object:
@@ -342,9 +342,15 @@ instance method:
342
342
  @album.artists # [<Artist ...>, ...]
343
343
  @album.associations[:artists] # [<Artist ...>, ...]
344
344
 
345
+ === Code Reloading
346
+
347
+ When declaring associations, Sequel caches association metadata in the association reflection. If you're doing any code reloading that doesn't involve restarting the related process, you should disable caching of the association reflection, to avoid stale model classes still being referenced after reloading:
348
+
349
+ Sequel::Model.cache_associations = false
350
+
345
351
  == Dataset Method
346
352
 
347
- In addition to the above methods, associations also add a instance method
353
+ In addition to the above methods, associations also add an instance method
348
354
  ending in +_dataset+ that returns a dataset representing the objects in the associated table:
349
355
 
350
356
  @album.artist_id
@@ -532,14 +538,14 @@ Which could be created using the following Sequel code:
532
538
  DB.create_table(:artists) do
533
539
  # Primary key must be set explicitly
534
540
  primary_key :id
535
- String :name, :null=>false, :unique=>true
541
+ String :name, null: false, unique: true
536
542
  end
537
543
  DB.create_table(:albums) do
538
544
  primary_key :id
539
545
  # Table that foreign key references needs to be set explicitly
540
546
  # for a database foreign key reference to be created.
541
- foreign_key :artist_id, :artists, :null=>false
542
- String :name, :null=>false, :unique=>true
547
+ foreign_key :artist_id, :artists, null: false
548
+ String :name, null: false, unique: true
543
549
  end
544
550
 
545
551
  If you already had a schema such as:
@@ -552,7 +558,7 @@ If you already had a schema such as:
552
558
  Then you just need to add the column:
553
559
 
554
560
  DB.alter_table(:albums) do
555
- add_foreign_key :artist_id, :artists, :null=>false
561
+ add_foreign_key :artist_id, :artists, null: false
556
562
  end
557
563
 
558
564
  === many_to_many
@@ -588,11 +594,11 @@ wanted to add an albums_artists join table to create the following schema:
588
594
 
589
595
  You could use the following Sequel code:
590
596
 
591
- DB.create_join_table(:album_id=>:albums, :artist_id=>:artists)
597
+ DB.create_join_table(album_id: :albums, artist_id: :artists)
592
598
  # or
593
599
  DB.create_table(:albums_artists) do
594
- foreign_key :album_id, :albums, :null=>false
595
- foreign_key :artist_id, :artists, :null=>false
600
+ foreign_key :album_id, :albums, null: false
601
+ foreign_key :artist_id, :artists, null: false
596
602
  primary_key [:album_id, :artist_id]
597
603
  index [:artist_id, :album_id]
598
604
  end
@@ -713,7 +719,7 @@ saving the passed in (or newly created) object. However, to avoid
713
719
  silent failures of these methods, they explicitly raise exceptions
714
720
  even when raise_on_save_failure is false for the associated model.
715
721
  You can disable this behavior (i.e. return nil instead of raising
716
- exceptions on a save failure) by setting the <tt>:raise_on_save_failure=>false</tt>
722
+ exceptions on a save failure) by setting the <tt>raise_on_save_failure: false</tt>
717
723
  option for the association.
718
724
 
719
725
  === remove_<i>association</i>(object_to_disassociate) (e.g. remove_album) [+one_to_many+ and +many_to_many+]
@@ -826,6 +832,8 @@ you also wanted to handle the Artist#add_album method:
826
832
  end)
827
833
  end
828
834
 
835
+ You can set this to +nil+ to not create a add_<i>association</i> method.
836
+
829
837
  === :remover (\_remove_<i>association</i> method)
830
838
 
831
839
  Continuing with the same example, here's how you would handle the same case if
@@ -837,6 +845,8 @@ you also wanted to handle the Artist#remove_album method:
837
845
  end)
838
846
  end
839
847
 
848
+ You can set this to +nil+ to not create a remove_<i>association</i> method.
849
+
840
850
  === :clearer (\_remove_all_<i>association</i> method)
841
851
 
842
852
  Continuing with the same example, here's how you would handle the same case if
@@ -850,6 +860,22 @@ you also wanted to handle the Artist#remove_all_albums method:
850
860
  end)
851
861
  end
852
862
 
863
+ You can set this to +nil+ to not create a remove_all_<i>association</i> method.
864
+
865
+ === :no_dataset_method
866
+
867
+ Setting this to true will result in the <i>association</i>_dataset method
868
+ not being defined. This can save memory if you only use the <i>association</i>
869
+ method and do not call the <i>association</i>_dataset method directly or
870
+ indirectly.
871
+
872
+ === :no_association_method
873
+
874
+ Setting this to true will result in the <i>association</i> method
875
+ not being defined. This can save memory if you only use the
876
+ <i>association</i>_dataset method and do not call the <i>association</i> method
877
+ directly or indirectly.
878
+
853
879
  == Association Options
854
880
 
855
881
  Sequel's associations mostly share the same options. For ease of understanding,
@@ -961,7 +987,7 @@ If you do not use a hash or array of two element arrays, you should use the
961
987
  :graph_conditions, :graph_only_conditions, or :graph_block option or you will not
962
988
  be able to use eager_graph or association_join with the association.
963
989
 
964
- Artist.one_to_many :good_albums, class: :Album, conditions: {:good=>true}
990
+ Artist.one_to_many :good_albums, class: :Album, conditions: {good: true}
965
991
  @artist.good_albums
966
992
  # SELECT * FROM albums WHERE ((artist_id = 1) AND (good IS TRUE))
967
993
 
@@ -1087,7 +1113,7 @@ already applied, and the proc should return a modified copy of this dataset.
1087
1113
  Here's an example of an association of songs to artists through lyrics, where
1088
1114
  the artist can perform any one of four tasks for the lyric:
1089
1115
 
1090
- Album.one_to_many :songs, dataset: (lambda do |r|
1116
+ Artist.one_to_many :songs, dataset: (lambda do |r|
1091
1117
  r.associated_dataset.select_all(:songs).
1092
1118
  join(:lyrics, id: :lyricid, id=>[:composer_id, :arranger_id, :vocalist_id, :lyricist_id])
1093
1119
  end)
@@ -1142,10 +1168,27 @@ join of the join table and the associated table, whereas this option just
1142
1168
  applies to the join table. It can be used to make sure that filters are used
1143
1169
  when deleting.
1144
1170
 
1145
- Artist.many_to_many :lead_guitar_albums, class: :Album, :join_table_block=>(lambda do |ds|
1171
+ Artist.many_to_many :lead_guitar_albums, class: :Album, join_table_block: (lambda do |ds|
1146
1172
  ds.where(instrument_id: 5)
1147
1173
  end)
1148
1174
 
1175
+ ==== :join_table_db [+many_to_many+, +one_through_one+]
1176
+
1177
+ A Sequel::Database to use for the join table. Specifying this option switches the
1178
+ loading to use a separate query for the join table. This is useful if the
1179
+ join table is not located in the same database as the associated table, or
1180
+ if the database account with access to the associated table doesn't have
1181
+ access to the join table.
1182
+
1183
+ For example, if the Album class uses a different Sequel::Database than the Artist
1184
+ class, and the join table is in the database that the Artist class uses:
1185
+
1186
+ Artist.many_to_many :lead_guitar_albums, class: :Album, join_table_db: Artist.db
1187
+
1188
+ This option also affects the add/remove/remove_all methods, by changing
1189
+ which database is used for inserts/deletes from the join table (add/remove/remove_all
1190
+ defaults to use the current model's database instead of the associated model's database).
1191
+
1149
1192
  === Callback Options
1150
1193
 
1151
1194
  All callbacks can be specified as a Symbol, Proc, or array of both/either
@@ -1433,7 +1476,7 @@ at least the following keys:
1433
1476
  Example:
1434
1477
 
1435
1478
  Artist.one_to_many :self_title_albums, class: :Album,
1436
- :eager_grapher=>(lambda do |eo|
1479
+ eager_grapher: (lambda do |eo|
1437
1480
  eo[:self].graph(:albums, {artist_id: :id, name: :name},
1438
1481
  table_alias: eo[:table_alias], implicit_qualifier: eo[:implicit_qualifier])
1439
1482
  end)
@@ -1455,6 +1498,36 @@ as the qualifiers may not match the aliases automatically used by eager_graph.
1455
1498
  This should contain unqualified identifiers, and eager_graph will automatically
1456
1499
  qualify them with the appropriate alias.
1457
1500
 
1501
+ ==== :graph_use_association_block
1502
+
1503
+ Setting this to true makes eager_graph apply the association block to the
1504
+ associated dataset before graphing the associated dataset into the receiver.
1505
+ In most cases when this option is used and the association has a block, the
1506
+ dataset returned by eager_graph will contain a JOIN to a subquery.
1507
+
1508
+ By default (when this option is not used), the association block will be ignored
1509
+ when using eager_graph:
1510
+
1511
+ Artist.one_to_many :tracks do |ds|
1512
+ ds.where(foo: 3)
1513
+ end
1514
+ Artist.eager_graph(:tracks)
1515
+ # SELECT albums.id, tracks.id AS tracks_id, tracks.album_id
1516
+ # FROM albums
1517
+ # LEFT OUTER JOIN tracks
1518
+ # ON (tracks.album_id = albums.id)
1519
+
1520
+ When this option is used, the block will be respected:
1521
+
1522
+ Artist.one_to_many :tracks, graph_use_association_block: true do |ds|
1523
+ ds.where(foo: 3)
1524
+ end
1525
+ Artist.eager_graph(:tracks)
1526
+ # SELECT albums.id, tracks.id AS tracks_id, tracks.album_id
1527
+ # FROM albums
1528
+ # LEFT OUTER JOIN (SELECT * FROM tracks WHERE (foo = 3)) AS tracks
1529
+ # ON (tracks.album_id = albums.id)
1530
+
1458
1531
  ==== :graph_join_table_conditions [+many_to_many+, +one_through_one+]
1459
1532
 
1460
1533
  The additional conditions to use on the SQL join for the join table when
@@ -1638,9 +1711,8 @@ For +many_to_one+ and +one_to_one+ associations, do not add a setter method.
1638
1711
  For +one_to_many+ and +many_to_many+, do not add the add_<i>association</i>,
1639
1712
  remove_<i>association</i>, or remove_all_<i>association</i> methods.
1640
1713
 
1641
- If the default modification methods would not do what you want, and you
1642
- don't plan on overriding the internal modification methods to do what you
1643
- want, it may be best to set this option to true.
1714
+ If you are not using the association modification methods, setting this
1715
+ value to true will save memory.
1644
1716
 
1645
1717
  ==== :validate
1646
1718
 
@@ -1667,12 +1739,35 @@ If set to false, you cannot load the association eagerly via eager or
1667
1739
  eager_graph.
1668
1740
 
1669
1741
  Artist.one_to_many :albums, allow_eager: false
1670
- Artist.eager(:albums) # Raises Sequel::Error
1742
+ Artist.eager(:albums) # Raises Sequel::Error
1743
+ Artist.eager_graph(:albums) # Raises Sequel::Error
1671
1744
 
1672
1745
  This is usually used if the association dataset depends on specific values in
1673
1746
  model instance that would not be valid when eager loading for multiple
1674
1747
  instances.
1675
1748
 
1749
+ ==== :allow_eager_graph
1750
+
1751
+ If set to false, you cannot load the association eagerly via eager_graph.
1752
+
1753
+ Artist.one_to_many :albums, allow_eager_graph: false
1754
+ Artist.eager(:albums) # Allowed
1755
+ Artist.eager_graph(:albums) # Raises Sequel::Error
1756
+
1757
+ This is useful if you still want to allow loading via eager, but do not want
1758
+ to allow loading via eager graph, possibly because the association does not
1759
+ support joins.
1760
+
1761
+ ==== :allow_filtering_by
1762
+
1763
+ If set to false, you cannot use the association when filtering.
1764
+
1765
+ Artist.one_to_many :albums, allow_filtering_by: false
1766
+ Artist.where(albums: Album.where(name: 'A')).all # Raises Sequel::Error
1767
+
1768
+ This is useful if such filtering cannot work, such as when a subquery cannot
1769
+ be used because the necessary tables are not in the same database.
1770
+
1676
1771
  ==== :instance_specific
1677
1772
 
1678
1773
  This allows you to override the setting of whether the dataset contains instance
data/doc/cheat_sheet.rdoc CHANGED
@@ -54,8 +54,16 @@ Without a filename argument, the sqlite adapter will setup a new sqlite database
54
54
  == Update/Delete rows
55
55
 
56
56
  dataset.exclude(:active).delete
57
- dataset.where{price < 100}.update(:active => true)
58
- dataset.where(:active).update(:price => Sequel[:price] * 0.90)
57
+ dataset.where{price < 100}.update(active: true)
58
+ dataset.where(:active).update(price: Sequel[:price] * 0.90)
59
+
60
+ = Merge rows
61
+
62
+ dataset.
63
+ merge_using(:table, col1: :col2).
64
+ merge_insert(col3: :col4).
65
+ merge_delete{col5 > 30}.
66
+ merge_update(col3: Sequel[:col3] + :col4)
59
67
 
60
68
  == Datasets are Enumerable
61
69
 
@@ -166,7 +174,7 @@ Without a filename argument, the sqlite adapter will setup a new sqlite database
166
174
  String :name, unique: true, null: false
167
175
  TrueClass :active, default: true
168
176
  foreign_key :category_id, :categories
169
- DateTime :created_at, default: Sequel::CURRENT_TIMESTAMP, :index=>true
177
+ DateTime :created_at, default: Sequel::CURRENT_TIMESTAMP, index: true
170
178
 
171
179
  index [:category_id, :active]
172
180
  end
@@ -48,7 +48,7 @@ If you want to change mass assignment so it ignores attempts to access restricte
48
48
  Since mass assignment by default allows modification of all column values except for primary key columns, it can be a security risk in some cases.
49
49
  If you are dealing with untrusted input, you are generally going to want to restrict what should be updated.
50
50
 
51
- Sequel has <tt>Model#set_fields</tt> and <tt>Model#update_fields</tt> methods, which are designed to be used with untrused input.
51
+ Sequel has <tt>Model#set_fields</tt> and <tt>Model#update_fields</tt> methods, which are designed to be used with untrusted input.
52
52
  These methods take two arguments, the untrusted hash as the first argument, and a trusted array of field names as the second argument:
53
53
 
54
54
  post.set_fields({title: 'T', body: 'B'}, [:title, :body])
data/doc/migration.rdoc CHANGED
@@ -86,9 +86,24 @@ the following methods:
86
86
  * +add_full_text_index+
87
87
  * +add_spatial_index+
88
88
  * +rename_column+
89
+ * +set_column_allow_null+
89
90
 
90
91
  If you use any other methods, you should create your own +down+ block.
91
92
 
93
+ To revert a migration created with +change+, you can copy the migration to a new file, and
94
+ replace +change+ with +revert+. For example, if you no longer need the artists table, you
95
+ can use the following migration. This will drop the artists table when migrating up, and
96
+ recreate it when migrating down:
97
+
98
+ Sequel.migration do
99
+ revert do
100
+ create_table(:artists) do
101
+ primary_key :id
102
+ String :name, null: false
103
+ end
104
+ end
105
+ end
106
+
92
107
  In normal usage, when Sequel's migrator runs, it runs the +up+ blocks for all
93
108
  migrations that have not yet been applied. However, you can use the <tt>-M</tt>
94
109
  switch to specify the version to which to migrate, and if it is lower than the
@@ -352,7 +367,7 @@ you should give it some thought before using it.
352
367
 
353
368
  == Ignoring missing migrations
354
369
 
355
- In some cases, you may want to allow a migration in the database that does not exist in the filesystem (deploying to an older version of code without running a down migration when deploy auto-migrates, for example). If required, you can pass <tt>allow_missing_migration_files: true</tt> as an option. This will stop errors from being raised if there are migrations in the database that do not exist in the filesystem.
370
+ In some cases, you may want to allow a migration in the database that does not exist in the filesystem (deploying to an older version of code without running a down migration when deploy auto-migrates, for example). If required, you can pass <tt>allow_missing_migration_files: true</tt> as an option. This will stop errors from being raised if there are migrations in the database that do not exist in the filesystem. Note that the migrations themselves can still raise an error when using this option, if the database schema isn't in the state the migrations expect it to be in. In general, the <tt>allow_missing_migration_files: true</tt> option is very risky to use, and should only be used if it is absolutely necessary.
356
371
 
357
372
  == Modifying existing migrations
358
373
 
@@ -543,16 +558,22 @@ The main difference between the two is that <tt>-d</tt> will use the type method
543
558
  with the database independent ruby class types, while <tt>-D</tt> will use
544
559
  the +column+ method with string types.
545
560
 
546
- Note that Sequel cannot dump constraints other than primary key and possibly
547
- foreign key constraints. If you are using database features such
548
- as constraints or triggers, you should use your database's dump and restore
549
- programs instead of Sequel's schema dumper.
550
-
551
561
  You can take the migration created by the schema dumper to another computer
552
562
  with an empty database, and attempt to recreate the schema using:
553
563
 
554
564
  sequel -m db/migrations postgres://host/database
555
565
 
566
+ The schema_dumper extension is quite limited in what types of
567
+ database objects it supports. In general, it only supports
568
+ dumping tables, columns, primary key and foreign key constraints,
569
+ and some indexes. It does not support most table options, CHECK
570
+ constraints, partial indexes, database functions, triggers,
571
+ security grants/revokes, and a wide variety of other useful
572
+ database properties. Be aware of the limitations when using the
573
+ schema_dumper extension. If you are dumping the schema to restore
574
+ to the same database type, it is recommended to use your database's
575
+ dump and restore programs instead of the schema_dumper extension.
576
+
556
577
  == Checking for Current Migrations
557
578
 
558
579
  In your application code, you may want to check that you are up to date in
data/doc/model_hooks.rdoc CHANGED
@@ -199,7 +199,7 @@ While it's not enforced anywhere, it's a good idea to make +super+ the last expr
199
199
 
200
200
  def after_save
201
201
  super
202
- AuditLog.create(:log=>"Album #{name} created")
202
+ AuditLog.create(log: "Album #{name} created")
203
203
  end
204
204
  end
205
205
 
@@ -36,7 +36,7 @@ schema modification,
36
36
  and transactions:
37
37
 
38
38
  DB.transaction do
39
- DB[:table].insert(:column=>value)
39
+ DB[:table].insert(column: value)
40
40
  end
41
41
 
42
42
  Sequel::Database#literal can be used to take any object that Sequel handles
@@ -468,7 +468,7 @@ objects:
468
468
  Sequel.lit(['', ' = '], :a, 1)
469
469
 
470
470
  '? = ?'.lit(:a, 1) # core_extensions extension
471
- ':b = :v'.lit(:b=>:a, :v=>1) # core_extensions extension
471
+ ':b = :v'.lit(b: :a, v: 1) # core_extensions extension
472
472
 
473
473
  === Sequel::SQL::OrderedExpression
474
474
 
@@ -482,20 +482,20 @@ it ascending or descending:
482
482
  Additionally, they take an options hash, which can be used to specify how nulls
483
483
  can be sorted:
484
484
 
485
- Sequel::SQL::OrderedExpression.new(:a, true, :nulls=>:first) # "a" DESC NULLS FIRST
486
- Sequel::SQL::OrderedExpression.new(:a, false, :nulls=>:last) # "a" ASC NULLS LAST
485
+ Sequel::SQL::OrderedExpression.new(:a, true, nulls: :first) # "a" DESC NULLS FIRST
486
+ Sequel::SQL::OrderedExpression.new(:a, false, nulls: :last) # "a" ASC NULLS LAST
487
487
 
488
488
  The following shortcuts exist for creating Sequel::SQL::OrderedExpression objects:
489
489
 
490
490
  Sequel.asc(:a)
491
491
  Sequel.desc(:a)
492
- Sequel.asc(:a, :nulls=>:first)
493
- Sequel.desc(:a, :nulls=>:last)
492
+ Sequel.asc(:a, nulls: :first)
493
+ Sequel.desc(:a, nulls: :last)
494
494
 
495
495
  :a.asc # core_extensions extension
496
496
  :a.desc # core_extensions extension
497
- :a.asc(:nulls=>:first) # core_extensions extension
498
- :a.desc(:nulls=>:last) # core_extensions extension
497
+ :a.asc(nulls: :first) # core_extensions extension
498
+ :a.desc(nulls: :last) # core_extensions extension
499
499
 
500
500
  === Sequel::SQL::Subscript
501
501