sequel 5.45.0 → 5.77.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +434 -0
- data/MIT-LICENSE +1 -1
- data/README.rdoc +59 -27
- data/bin/sequel +11 -3
- data/doc/advanced_associations.rdoc +16 -14
- data/doc/association_basics.rdoc +119 -24
- data/doc/cheat_sheet.rdoc +11 -3
- data/doc/mass_assignment.rdoc +1 -1
- data/doc/migration.rdoc +27 -6
- data/doc/model_hooks.rdoc +1 -1
- data/doc/object_model.rdoc +8 -8
- data/doc/opening_databases.rdoc +28 -12
- data/doc/postgresql.rdoc +16 -8
- data/doc/querying.rdoc +5 -3
- data/doc/release_notes/5.46.0.txt +87 -0
- data/doc/release_notes/5.47.0.txt +59 -0
- data/doc/release_notes/5.48.0.txt +14 -0
- data/doc/release_notes/5.49.0.txt +59 -0
- data/doc/release_notes/5.50.0.txt +78 -0
- data/doc/release_notes/5.51.0.txt +47 -0
- data/doc/release_notes/5.52.0.txt +87 -0
- data/doc/release_notes/5.53.0.txt +23 -0
- data/doc/release_notes/5.54.0.txt +27 -0
- data/doc/release_notes/5.55.0.txt +21 -0
- data/doc/release_notes/5.56.0.txt +51 -0
- data/doc/release_notes/5.57.0.txt +23 -0
- data/doc/release_notes/5.58.0.txt +31 -0
- data/doc/release_notes/5.59.0.txt +73 -0
- data/doc/release_notes/5.60.0.txt +22 -0
- data/doc/release_notes/5.61.0.txt +43 -0
- data/doc/release_notes/5.62.0.txt +132 -0
- data/doc/release_notes/5.63.0.txt +33 -0
- data/doc/release_notes/5.64.0.txt +50 -0
- data/doc/release_notes/5.65.0.txt +21 -0
- data/doc/release_notes/5.66.0.txt +24 -0
- data/doc/release_notes/5.67.0.txt +32 -0
- data/doc/release_notes/5.68.0.txt +61 -0
- data/doc/release_notes/5.69.0.txt +26 -0
- data/doc/release_notes/5.70.0.txt +35 -0
- data/doc/release_notes/5.71.0.txt +21 -0
- data/doc/release_notes/5.72.0.txt +33 -0
- data/doc/release_notes/5.73.0.txt +66 -0
- data/doc/release_notes/5.74.0.txt +45 -0
- data/doc/release_notes/5.75.0.txt +35 -0
- data/doc/release_notes/5.76.0.txt +86 -0
- data/doc/release_notes/5.77.0.txt +63 -0
- data/doc/schema_modification.rdoc +1 -1
- data/doc/security.rdoc +9 -9
- data/doc/sharding.rdoc +3 -1
- data/doc/sql.rdoc +27 -15
- data/doc/testing.rdoc +23 -13
- data/doc/transactions.rdoc +6 -6
- data/doc/virtual_rows.rdoc +1 -1
- data/lib/sequel/adapters/ado/access.rb +1 -1
- data/lib/sequel/adapters/ado.rb +1 -1
- data/lib/sequel/adapters/amalgalite.rb +3 -5
- data/lib/sequel/adapters/ibmdb.rb +3 -3
- data/lib/sequel/adapters/jdbc/derby.rb +8 -0
- data/lib/sequel/adapters/jdbc/h2.rb +63 -10
- data/lib/sequel/adapters/jdbc/hsqldb.rb +8 -0
- data/lib/sequel/adapters/jdbc/postgresql.rb +7 -4
- data/lib/sequel/adapters/jdbc/sqlanywhere.rb +15 -0
- data/lib/sequel/adapters/jdbc/sqlserver.rb +4 -0
- data/lib/sequel/adapters/jdbc.rb +24 -22
- data/lib/sequel/adapters/mysql.rb +92 -67
- data/lib/sequel/adapters/mysql2.rb +56 -51
- data/lib/sequel/adapters/odbc/mssql.rb +1 -1
- data/lib/sequel/adapters/odbc.rb +1 -1
- data/lib/sequel/adapters/oracle.rb +4 -3
- data/lib/sequel/adapters/postgres.rb +89 -45
- data/lib/sequel/adapters/shared/access.rb +11 -1
- data/lib/sequel/adapters/shared/db2.rb +42 -0
- data/lib/sequel/adapters/shared/mssql.rb +91 -10
- data/lib/sequel/adapters/shared/mysql.rb +78 -3
- data/lib/sequel/adapters/shared/oracle.rb +86 -7
- data/lib/sequel/adapters/shared/postgres.rb +576 -171
- data/lib/sequel/adapters/shared/sqlanywhere.rb +21 -5
- data/lib/sequel/adapters/shared/sqlite.rb +92 -8
- data/lib/sequel/adapters/sqlanywhere.rb +1 -1
- data/lib/sequel/adapters/sqlite.rb +99 -18
- data/lib/sequel/adapters/tinytds.rb +1 -1
- data/lib/sequel/adapters/trilogy.rb +117 -0
- data/lib/sequel/adapters/utils/columns_limit_1.rb +22 -0
- data/lib/sequel/adapters/utils/mysql_mysql2.rb +1 -1
- data/lib/sequel/ast_transformer.rb +6 -0
- data/lib/sequel/connection_pool/sharded_single.rb +5 -7
- data/lib/sequel/connection_pool/sharded_threaded.rb +16 -11
- data/lib/sequel/connection_pool/sharded_timed_queue.rb +374 -0
- data/lib/sequel/connection_pool/single.rb +6 -8
- data/lib/sequel/connection_pool/threaded.rb +14 -8
- data/lib/sequel/connection_pool/timed_queue.rb +270 -0
- data/lib/sequel/connection_pool.rb +57 -31
- data/lib/sequel/core.rb +17 -18
- data/lib/sequel/database/connecting.rb +27 -3
- data/lib/sequel/database/dataset.rb +16 -6
- data/lib/sequel/database/misc.rb +70 -14
- data/lib/sequel/database/query.rb +73 -2
- data/lib/sequel/database/schema_generator.rb +11 -6
- data/lib/sequel/database/schema_methods.rb +23 -4
- data/lib/sequel/database/transactions.rb +6 -0
- data/lib/sequel/dataset/actions.rb +111 -15
- data/lib/sequel/dataset/deprecated_singleton_class_methods.rb +42 -0
- data/lib/sequel/dataset/features.rb +20 -1
- data/lib/sequel/dataset/misc.rb +12 -2
- data/lib/sequel/dataset/placeholder_literalizer.rb +20 -9
- data/lib/sequel/dataset/query.rb +170 -41
- data/lib/sequel/dataset/sql.rb +190 -71
- data/lib/sequel/dataset.rb +4 -0
- data/lib/sequel/extensions/_model_pg_row.rb +0 -12
- data/lib/sequel/extensions/_pretty_table.rb +1 -1
- data/lib/sequel/extensions/any_not_empty.rb +2 -2
- data/lib/sequel/extensions/async_thread_pool.rb +14 -13
- data/lib/sequel/extensions/auto_cast_date_and_time.rb +94 -0
- data/lib/sequel/extensions/auto_literal_strings.rb +1 -1
- data/lib/sequel/extensions/connection_expiration.rb +15 -9
- data/lib/sequel/extensions/connection_validator.rb +16 -11
- data/lib/sequel/extensions/constraint_validations.rb +1 -1
- data/lib/sequel/extensions/core_refinements.rb +36 -11
- data/lib/sequel/extensions/date_arithmetic.rb +36 -8
- data/lib/sequel/extensions/date_parse_input_handler.rb +67 -0
- data/lib/sequel/extensions/datetime_parse_to_time.rb +5 -1
- data/lib/sequel/extensions/duplicate_columns_handler.rb +11 -10
- data/lib/sequel/extensions/index_caching.rb +5 -1
- data/lib/sequel/extensions/inflector.rb +1 -1
- data/lib/sequel/extensions/is_distinct_from.rb +141 -0
- data/lib/sequel/extensions/looser_typecasting.rb +3 -0
- data/lib/sequel/extensions/migration.rb +57 -15
- data/lib/sequel/extensions/named_timezones.rb +22 -6
- data/lib/sequel/extensions/pagination.rb +1 -1
- data/lib/sequel/extensions/pg_array.rb +33 -4
- data/lib/sequel/extensions/pg_array_ops.rb +2 -2
- data/lib/sequel/extensions/pg_auto_parameterize.rb +509 -0
- data/lib/sequel/extensions/pg_auto_parameterize_in_array.rb +110 -0
- data/lib/sequel/extensions/pg_enum.rb +1 -2
- data/lib/sequel/extensions/pg_extended_date_support.rb +39 -28
- data/lib/sequel/extensions/pg_extended_integer_support.rb +116 -0
- data/lib/sequel/extensions/pg_hstore.rb +6 -1
- data/lib/sequel/extensions/pg_hstore_ops.rb +53 -3
- data/lib/sequel/extensions/pg_inet.rb +10 -11
- data/lib/sequel/extensions/pg_inet_ops.rb +1 -1
- data/lib/sequel/extensions/pg_interval.rb +11 -11
- data/lib/sequel/extensions/pg_json.rb +13 -15
- data/lib/sequel/extensions/pg_json_ops.rb +125 -2
- data/lib/sequel/extensions/pg_multirange.rb +367 -0
- data/lib/sequel/extensions/pg_range.rb +13 -26
- data/lib/sequel/extensions/pg_range_ops.rb +37 -9
- data/lib/sequel/extensions/pg_row.rb +20 -19
- data/lib/sequel/extensions/pg_row_ops.rb +1 -1
- data/lib/sequel/extensions/pg_timestamptz.rb +27 -3
- data/lib/sequel/extensions/round_timestamps.rb +1 -1
- data/lib/sequel/extensions/s.rb +2 -1
- data/lib/sequel/extensions/schema_caching.rb +1 -1
- data/lib/sequel/extensions/schema_dumper.rb +45 -11
- data/lib/sequel/extensions/server_block.rb +10 -13
- data/lib/sequel/extensions/set_literalizer.rb +58 -0
- data/lib/sequel/extensions/sql_comments.rb +110 -3
- data/lib/sequel/extensions/sql_log_normalizer.rb +108 -0
- data/lib/sequel/extensions/sqlite_json_ops.rb +255 -0
- data/lib/sequel/extensions/string_agg.rb +1 -1
- data/lib/sequel/extensions/string_date_time.rb +19 -23
- data/lib/sequel/extensions/symbol_aref.rb +2 -0
- data/lib/sequel/extensions/transaction_connection_validator.rb +78 -0
- data/lib/sequel/model/associations.rb +286 -92
- data/lib/sequel/model/base.rb +53 -33
- data/lib/sequel/model/dataset_module.rb +3 -0
- data/lib/sequel/model/errors.rb +10 -1
- data/lib/sequel/model/exceptions.rb +15 -3
- data/lib/sequel/model/inflections.rb +1 -1
- data/lib/sequel/plugins/auto_restrict_eager_graph.rb +62 -0
- data/lib/sequel/plugins/auto_validations.rb +74 -16
- data/lib/sequel/plugins/class_table_inheritance.rb +2 -2
- data/lib/sequel/plugins/column_encryption.rb +29 -8
- data/lib/sequel/plugins/composition.rb +3 -2
- data/lib/sequel/plugins/concurrent_eager_loading.rb +4 -4
- data/lib/sequel/plugins/constraint_validations.rb +8 -5
- data/lib/sequel/plugins/defaults_setter.rb +16 -0
- data/lib/sequel/plugins/dirty.rb +1 -1
- data/lib/sequel/plugins/enum.rb +124 -0
- data/lib/sequel/plugins/finder.rb +4 -2
- data/lib/sequel/plugins/insert_conflict.rb +4 -0
- data/lib/sequel/plugins/instance_specific_default.rb +1 -1
- data/lib/sequel/plugins/json_serializer.rb +2 -2
- data/lib/sequel/plugins/lazy_attributes.rb +3 -0
- data/lib/sequel/plugins/list.rb +8 -3
- data/lib/sequel/plugins/many_through_many.rb +109 -10
- data/lib/sequel/plugins/mssql_optimistic_locking.rb +8 -38
- data/lib/sequel/plugins/nested_attributes.rb +4 -4
- data/lib/sequel/plugins/optimistic_locking.rb +9 -42
- data/lib/sequel/plugins/optimistic_locking_base.rb +55 -0
- data/lib/sequel/plugins/paged_operations.rb +181 -0
- data/lib/sequel/plugins/pg_array_associations.rb +46 -34
- data/lib/sequel/plugins/pg_auto_constraint_validations.rb +9 -3
- data/lib/sequel/plugins/pg_xmin_optimistic_locking.rb +109 -0
- data/lib/sequel/plugins/prepared_statements.rb +12 -2
- data/lib/sequel/plugins/prepared_statements_safe.rb +2 -1
- data/lib/sequel/plugins/primary_key_lookup_check_values.rb +154 -0
- data/lib/sequel/plugins/rcte_tree.rb +7 -4
- data/lib/sequel/plugins/require_valid_schema.rb +67 -0
- data/lib/sequel/plugins/serialization.rb +1 -0
- data/lib/sequel/plugins/serialization_modification_detection.rb +1 -0
- data/lib/sequel/plugins/single_table_inheritance.rb +8 -0
- data/lib/sequel/plugins/sql_comments.rb +189 -0
- data/lib/sequel/plugins/static_cache.rb +39 -1
- data/lib/sequel/plugins/static_cache_cache.rb +5 -1
- data/lib/sequel/plugins/subclasses.rb +28 -11
- data/lib/sequel/plugins/tactical_eager_loading.rb +23 -10
- data/lib/sequel/plugins/timestamps.rb +1 -1
- data/lib/sequel/plugins/unused_associations.rb +521 -0
- data/lib/sequel/plugins/update_or_create.rb +1 -1
- data/lib/sequel/plugins/validate_associated.rb +22 -12
- data/lib/sequel/plugins/validation_helpers.rb +41 -11
- data/lib/sequel/plugins/validation_helpers_generic_type_messages.rb +73 -0
- data/lib/sequel/plugins/xml_serializer.rb +1 -1
- data/lib/sequel/sql.rb +1 -1
- data/lib/sequel/timezones.rb +12 -14
- data/lib/sequel/version.rb +1 -1
- 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
|
-
|
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], :
|
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(:
|
242
|
-
album2 = Album.create(:
|
243
|
-
album3 = Album.create(:
|
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(:
|
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(:
|
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, :
|
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(:
|
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, :
|
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(:
|
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(:
|
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, :
|
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(:
|
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).
|
data/doc/association_basics.rdoc
CHANGED
@@ -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
|
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
|
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
|
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 :
|
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(:
|
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
|
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, :
|
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, :
|
542
|
-
String :name, :
|
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, :
|
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(:
|
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, :
|
595
|
-
foreign_key :artist_id, :artists, :
|
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
|
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: {:
|
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
|
-
|
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, :
|
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
|
-
:
|
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
|
1642
|
-
|
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)
|
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(:
|
58
|
-
dataset.where(:active).update(:
|
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, :
|
177
|
+
DateTime :created_at, default: Sequel::CURRENT_TIMESTAMP, index: true
|
170
178
|
|
171
179
|
index [:category_id, :active]
|
172
180
|
end
|
data/doc/mass_assignment.rdoc
CHANGED
@@ -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
|
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
data/doc/object_model.rdoc
CHANGED
@@ -36,7 +36,7 @@ schema modification,
|
|
36
36
|
and transactions:
|
37
37
|
|
38
38
|
DB.transaction do
|
39
|
-
DB[:table].insert(:
|
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(:
|
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, :
|
486
|
-
Sequel::SQL::OrderedExpression.new(:a, false, :
|
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, :
|
493
|
-
Sequel.desc(:a, :
|
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(:
|
498
|
-
:a.desc(:
|
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
|
|