sequel 5.45.0 → 5.77.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
@@ -274,7 +274,9 @@ module Sequel
|
|
274
274
|
cascade = eo[:associations]
|
275
275
|
eager_limit = nil
|
276
276
|
|
277
|
-
if eo[:
|
277
|
+
if eo[:no_results]
|
278
|
+
no_results = true
|
279
|
+
elsif eo[:eager_block] || eo[:loader] == false || !use_placeholder_loader?
|
278
280
|
ds = eager_loading_dataset(eo)
|
279
281
|
|
280
282
|
strategy = ds.opts[:eager_limit_strategy] || strategy
|
@@ -297,13 +299,28 @@ module Sequel
|
|
297
299
|
strategy = :ruby if strategy == :correlated_subquery
|
298
300
|
strategy = nil if strategy == :ruby && assign_singular?
|
299
301
|
objects = apply_eager_limit_strategy(ds, strategy, eager_limit).all
|
302
|
+
|
303
|
+
if strategy == :window_function
|
304
|
+
delete_rn = ds.row_number_column
|
305
|
+
objects.each{|obj| obj.values.delete(delete_rn)}
|
306
|
+
end
|
300
307
|
elsif strategy == :union
|
301
308
|
objects = []
|
302
309
|
ds = associated_dataset
|
303
310
|
loader = union_eager_loader
|
304
311
|
joiner = " UNION ALL "
|
305
312
|
ids.each_slice(subqueries_per_union).each do |slice|
|
306
|
-
|
313
|
+
sql = loader.send(:sql_origin)
|
314
|
+
join = false
|
315
|
+
slice.each do |k|
|
316
|
+
if join
|
317
|
+
sql << joiner
|
318
|
+
else
|
319
|
+
join = true
|
320
|
+
end
|
321
|
+
loader.append_sql(sql, *k)
|
322
|
+
end
|
323
|
+
objects.concat(ds.with_sql(sql).to_a)
|
307
324
|
end
|
308
325
|
ds = ds.eager(cascade) if cascade
|
309
326
|
ds.send(:post_load, objects)
|
@@ -313,7 +330,7 @@ module Sequel
|
|
313
330
|
objects = loader.all(ids)
|
314
331
|
end
|
315
332
|
|
316
|
-
Sequel.synchronize_with(eo[:mutex]){objects.each(&block)}
|
333
|
+
Sequel.synchronize_with(eo[:mutex]){objects.each(&block)} unless no_results
|
317
334
|
|
318
335
|
if strategy == :ruby
|
319
336
|
apply_ruby_eager_limit_strategy(rows, eager_limit || limit_and_offset)
|
@@ -439,7 +456,7 @@ module Sequel
|
|
439
456
|
def placeholder_loader
|
440
457
|
if use_placeholder_loader?
|
441
458
|
cached_fetch(:placeholder_loader) do
|
442
|
-
|
459
|
+
associated_dataset.placeholder_literalizer_loader do |pl, ds|
|
443
460
|
ds = ds.where(Sequel.&(*predicate_keys.map{|k| SQL::BooleanExpression.new(:'=', k, pl.arg)}))
|
444
461
|
if self[:block]
|
445
462
|
ds = self[:block].call(ds)
|
@@ -638,9 +655,7 @@ module Sequel
|
|
638
655
|
# given the hash passed to the eager loader.
|
639
656
|
def eager_loading_dataset(eo=OPTS)
|
640
657
|
ds = eo[:dataset] || associated_eager_dataset
|
641
|
-
|
642
|
-
ds = ds.where(eager_loading_predicate_condition(id_map.keys))
|
643
|
-
end
|
658
|
+
ds = eager_loading_set_predicate_condition(ds, eo)
|
644
659
|
if associations = eo[:associations]
|
645
660
|
ds = ds.eager(associations)
|
646
661
|
end
|
@@ -667,6 +682,15 @@ module Sequel
|
|
667
682
|
self[:model].default_eager_limit_strategy || :ruby
|
668
683
|
end
|
669
684
|
|
685
|
+
# Set the predicate condition for the eager loading dataset based on the id map
|
686
|
+
# in the eager loading options.
|
687
|
+
def eager_loading_set_predicate_condition(ds, eo)
|
688
|
+
if id_map = eo[:id_map]
|
689
|
+
ds = ds.where(eager_loading_predicate_condition(id_map.keys))
|
690
|
+
end
|
691
|
+
ds
|
692
|
+
end
|
693
|
+
|
670
694
|
# The predicate condition to use for the eager_loader.
|
671
695
|
def eager_loading_predicate_condition(keys)
|
672
696
|
{predicate_key=>keys}
|
@@ -734,8 +758,8 @@ module Sequel
|
|
734
758
|
# A placeholder literalizer used to speed up eager loading.
|
735
759
|
def placeholder_eager_loader
|
736
760
|
cached_fetch(:placeholder_eager_loader) do
|
737
|
-
|
738
|
-
apply_eager_limit_strategy(
|
761
|
+
eager_loading_dataset.placeholder_literalizer_loader do |pl, ds|
|
762
|
+
apply_eager_limit_strategy(ds.where(predicate_key=>pl.arg), eager_limit_strategy)
|
739
763
|
end
|
740
764
|
end
|
741
765
|
end
|
@@ -794,7 +818,7 @@ module Sequel
|
|
794
818
|
# loading a limited association.
|
795
819
|
def union_eager_loader
|
796
820
|
cached_fetch(:union_eager_loader) do
|
797
|
-
|
821
|
+
associated_dataset.placeholder_literalizer_loader do |pl, ds|
|
798
822
|
ds = self[:eager_block].call(ds) if self[:eager_block]
|
799
823
|
keys = predicate_keys
|
800
824
|
ds = ds.where(keys.map{pl.arg}.zip(keys))
|
@@ -808,7 +832,7 @@ module Sequel
|
|
808
832
|
|
809
833
|
# Whether the placeholder loader can be used to load the association.
|
810
834
|
def use_placeholder_loader?
|
811
|
-
self[:use_placeholder_loader]
|
835
|
+
self[:use_placeholder_loader] && _associated_dataset.supports_placeholder_literalizer?
|
812
836
|
end
|
813
837
|
end
|
814
838
|
|
@@ -1318,7 +1342,7 @@ module Sequel
|
|
1318
1342
|
|
1319
1343
|
# many_to_many associations need to select a key in an associated table to eagerly load
|
1320
1344
|
def eager_loading_use_associated_key?
|
1321
|
-
|
1345
|
+
!separate_query_per_table?
|
1322
1346
|
end
|
1323
1347
|
|
1324
1348
|
# The source of the join table. This is the join table itself, unless it
|
@@ -1375,10 +1399,30 @@ module Sequel
|
|
1375
1399
|
cached_fetch(:select){default_select}
|
1376
1400
|
end
|
1377
1401
|
|
1402
|
+
# Whether a separate query should be used for the join table.
|
1403
|
+
def separate_query_per_table?
|
1404
|
+
self[:join_table_db]
|
1405
|
+
end
|
1406
|
+
|
1378
1407
|
private
|
1379
1408
|
|
1409
|
+
# Join to the the join table, unless using a separate query per table.
|
1380
1410
|
def _associated_dataset
|
1381
|
-
|
1411
|
+
if separate_query_per_table?
|
1412
|
+
super
|
1413
|
+
else
|
1414
|
+
super.inner_join(self[:join_table], self[:right_keys].zip(right_primary_keys), :qualify=>:deep)
|
1415
|
+
end
|
1416
|
+
end
|
1417
|
+
|
1418
|
+
# Use the right_keys from the eager loading options if
|
1419
|
+
# using a separate query per table.
|
1420
|
+
def eager_loading_set_predicate_condition(ds, eo)
|
1421
|
+
if separate_query_per_table?
|
1422
|
+
ds.where(right_primary_key=>eo[:right_keys])
|
1423
|
+
else
|
1424
|
+
super
|
1425
|
+
end
|
1382
1426
|
end
|
1383
1427
|
|
1384
1428
|
# The default selection for associations that require joins. These do not use the default
|
@@ -1595,6 +1639,7 @@ module Sequel
|
|
1595
1639
|
# === Multiple Types
|
1596
1640
|
# :adder :: Proc used to define the private _add_* method for doing the database work
|
1597
1641
|
# to associate the given object to the current object (*_to_many assocations).
|
1642
|
+
# Set to nil to not define a add_* method for the association.
|
1598
1643
|
# :after_add :: Symbol, Proc, or array of both/either specifying a callback to call
|
1599
1644
|
# after a new item is added to the association.
|
1600
1645
|
# :after_load :: Symbol, Proc, or array of both/either specifying a callback to call
|
@@ -1605,6 +1650,8 @@ module Sequel
|
|
1605
1650
|
# after an item is set using the association setter method.
|
1606
1651
|
# :allow_eager :: If set to false, you cannot load the association eagerly
|
1607
1652
|
# via eager or eager_graph
|
1653
|
+
# :allow_eager_graph :: If set to false, you cannot load the association eagerly via eager_graph.
|
1654
|
+
# :allow_filtering_by :: If set to false, you cannot use the association when filtering
|
1608
1655
|
# :before_add :: Symbol, Proc, or array of both/either specifying a callback to call
|
1609
1656
|
# before a new item is added to the association.
|
1610
1657
|
# :before_remove :: Symbol, Proc, or array of both/either specifying a callback to call
|
@@ -1623,6 +1670,7 @@ module Sequel
|
|
1623
1670
|
# the class. <tt>class: 'Foo', class_namespace: 'Bar'</tt> looks for <tt>::Bar::Foo</tt>.)
|
1624
1671
|
# :clearer :: Proc used to define the private _remove_all_* method for doing the database work
|
1625
1672
|
# to remove all objects associated to the current object (*_to_many assocations).
|
1673
|
+
# Set to nil to not define a remove_all_* method for the association.
|
1626
1674
|
# :clone :: Merge the current options and block into the options and block used in defining
|
1627
1675
|
# the given association. Can be used to DRY up a bunch of similar associations that
|
1628
1676
|
# all share the same options such as :class and :key, while changing the order and block used.
|
@@ -1677,18 +1725,26 @@ module Sequel
|
|
1677
1725
|
# :graph_only_conditions :: The conditions to use on the SQL join when eagerly loading
|
1678
1726
|
# the association via +eager_graph+, instead of the default conditions specified by the
|
1679
1727
|
# foreign/primary keys. This option causes the :graph_conditions option to be ignored.
|
1680
|
-
# :graph_order ::
|
1728
|
+
# :graph_order :: the order to use when using eager_graph, instead of the default order. This should be used
|
1681
1729
|
# in the case where :order contains an identifier qualified by the table's name, which may not match
|
1682
1730
|
# the alias used when eager graphing. By setting this to the unqualified identifier, it will be
|
1683
1731
|
# automatically qualified when using eager_graph.
|
1684
1732
|
# :graph_select :: A column or array of columns to select from the associated table
|
1685
1733
|
# when eagerly loading the association via +eager_graph+. Defaults to all
|
1686
1734
|
# columns in the associated table.
|
1735
|
+
# :graph_use_association_block :: Makes eager_graph consider the association block. Without this, eager_graph
|
1736
|
+
# ignores the bock and only use the :graph_* options.
|
1737
|
+
# :instance_specific :: Marks the association as instance specific. Should be used if the association block
|
1738
|
+
# uses instance specific state, or transient state (accessing current date/time, etc.).
|
1687
1739
|
# :limit :: Limit the number of records to the provided value. Use
|
1688
1740
|
# an array with two elements for the value to specify a
|
1689
1741
|
# limit (first element) and an offset (second element).
|
1690
1742
|
# :methods_module :: The module that methods the association creates will be placed into. Defaults
|
1691
1743
|
# to the module containing the model's columns.
|
1744
|
+
# :no_association_method :: Do not add a method for the association. This can save memory if the association
|
1745
|
+
# method is never used.
|
1746
|
+
# :no_dataset_method :: Do not add a method for the association dataset. This can save memory if the dataset
|
1747
|
+
# method is never used.
|
1692
1748
|
# :order :: the column(s) by which to order the association dataset. Can be a
|
1693
1749
|
# singular column symbol or an array of column symbols.
|
1694
1750
|
# :order_eager_graph :: Whether to add the association's order to the graphed dataset's order when graphing
|
@@ -1701,6 +1757,7 @@ module Sequel
|
|
1701
1757
|
# the current association's key(s). Set to nil to not use a reciprocal.
|
1702
1758
|
# :remover :: Proc used to define the private _remove_* method for doing the database work
|
1703
1759
|
# to remove the association between the given object and the current object (*_to_many assocations).
|
1760
|
+
# Set to nil to not define a remove_* method for the association.
|
1704
1761
|
# :select :: the columns to select. Defaults to the associated class's table_name.* in an association
|
1705
1762
|
# that uses joins, which means it doesn't include the attributes from the
|
1706
1763
|
# join table. If you want to include the join table attributes, you can
|
@@ -1709,6 +1766,7 @@ module Sequel
|
|
1709
1766
|
# the same name in both the join table and the associated table.
|
1710
1767
|
# :setter :: Proc used to define the private _*= method for doing the work to setup the assocation
|
1711
1768
|
# between the given object and the current object (*_to_one associations).
|
1769
|
+
# Set to nil to not define a setter method for the association.
|
1712
1770
|
# :subqueries_per_union :: The number of subqueries to use in each UNION query, for eager
|
1713
1771
|
# loading limited associations using the default :union strategy.
|
1714
1772
|
# :validate :: Set to false to not validate when implicitly saving any associated object.
|
@@ -1765,6 +1823,9 @@ module Sequel
|
|
1765
1823
|
# underscored, sorted, and joined with '_'.
|
1766
1824
|
# :join_table_block :: proc that can be used to modify the dataset used in the add/remove/remove_all
|
1767
1825
|
# methods. Should accept a dataset argument and return a modified dataset if present.
|
1826
|
+
# :join_table_db :: When retrieving records when using lazy loading or eager loading via +eager+, instead of
|
1827
|
+
# a join between to the join table and the associated table, use a separate query for the
|
1828
|
+
# join table using the given Database object.
|
1768
1829
|
# :left_key :: foreign key in join table that points to current model's
|
1769
1830
|
# primary key, as a symbol. Defaults to :"#{self.name.underscore}_id".
|
1770
1831
|
# Can use an array of symbols for a composite key association.
|
@@ -1794,7 +1855,9 @@ module Sequel
|
|
1794
1855
|
|
1795
1856
|
if opts[:clone]
|
1796
1857
|
cloned_assoc = association_reflection(opts[:clone])
|
1858
|
+
remove_class_name = orig_opts[:class] && !orig_opts[:class_name]
|
1797
1859
|
orig_opts = cloned_assoc[:orig_opts].merge(orig_opts)
|
1860
|
+
orig_opts.delete(:class_name) if remove_class_name
|
1798
1861
|
end
|
1799
1862
|
|
1800
1863
|
opts = Hash[default_association_options]
|
@@ -1812,6 +1875,16 @@ module Sequel
|
|
1812
1875
|
# in certain places to disable optimizations.
|
1813
1876
|
opts[:instance_specific] = _association_instance_specific_default(name)
|
1814
1877
|
end
|
1878
|
+
if (orig_opts[:instance_specific] || orig_opts[:dataset]) && !opts.has_key?(:allow_eager) && !opts[:eager_loader]
|
1879
|
+
# For associations explicitly marked as instance specific, or that use the
|
1880
|
+
# :dataset option, where :allow_eager is not set, and no :eager_loader is
|
1881
|
+
# provided, disallow eager loading. In these cases, eager loading is
|
1882
|
+
# unlikely to work. This is not done for implicit setting of :instance_specific,
|
1883
|
+
# because implicit use is done by default for all associations with blocks,
|
1884
|
+
# and the vast majority of associations with blocks use the block for filtering
|
1885
|
+
# in a manner compatible with eager loading.
|
1886
|
+
opts[:allow_eager] = false
|
1887
|
+
end
|
1815
1888
|
opts = assoc_class.new.merge!(opts)
|
1816
1889
|
|
1817
1890
|
if opts[:clone] && !opts.cloneable?(cloned_assoc)
|
@@ -1841,8 +1914,7 @@ module Sequel
|
|
1841
1914
|
# Remove :class entry if it exists and is nil, to work with cached_fetch
|
1842
1915
|
opts.delete(:class) unless opts[:class]
|
1843
1916
|
|
1844
|
-
|
1845
|
-
def_association_instance_methods(opts)
|
1917
|
+
def_association(opts)
|
1846
1918
|
|
1847
1919
|
orig_opts.delete(:clone)
|
1848
1920
|
opts[:orig_class] = orig_opts[:class] || orig_opts[:class_name]
|
@@ -1956,6 +2028,13 @@ module Sequel
|
|
1956
2028
|
association_module(opts).send(:private, name)
|
1957
2029
|
end
|
1958
2030
|
|
2031
|
+
# Delegate to the type-specific association method to setup the
|
2032
|
+
# association, and define the association instance methods.
|
2033
|
+
def def_association(opts)
|
2034
|
+
send(:"def_#{opts[:type]}", opts)
|
2035
|
+
def_association_instance_methods(opts)
|
2036
|
+
end
|
2037
|
+
|
1959
2038
|
# Adds the association method to the association methods module.
|
1960
2039
|
def def_association_method(opts)
|
1961
2040
|
association_module_def(opts.association_method, opts) do |dynamic_opts=OPTS, &block|
|
@@ -1981,13 +2060,13 @@ module Sequel
|
|
1981
2060
|
opts[:setter_method] = :"#{opts[:name]}="
|
1982
2061
|
end
|
1983
2062
|
|
1984
|
-
association_module_def(opts.dataset_method, opts){_dataset(opts)}
|
2063
|
+
association_module_def(opts.dataset_method, opts){_dataset(opts)} unless opts[:no_dataset_method]
|
1985
2064
|
if opts[:block]
|
1986
2065
|
opts[:block_method] = Plugins.def_sequel_method(association_module(opts), "#{opts[:name]}_block", 1, &opts[:block])
|
1987
2066
|
end
|
1988
2067
|
opts[:dataset_opt_arity] = opts[:dataset].arity == 0 ? 0 : 1
|
1989
2068
|
opts[:dataset_opt_method] = Plugins.def_sequel_method(association_module(opts), "#{opts[:name]}_dataset_opt", opts[:dataset_opt_arity], &opts[:dataset])
|
1990
|
-
def_association_method(opts)
|
2069
|
+
def_association_method(opts) unless opts[:no_association_method]
|
1991
2070
|
|
1992
2071
|
return if opts[:read_only]
|
1993
2072
|
|
@@ -2031,7 +2110,7 @@ module Sequel
|
|
2031
2110
|
raise(Error, "mismatched number of right keys: #{rcks.inspect} vs #{rcpks.inspect}") unless rcks.length == rcpks.length
|
2032
2111
|
end
|
2033
2112
|
opts[:uses_left_composite_keys] = lcks.length > 1
|
2034
|
-
opts[:uses_right_composite_keys] = rcks.length > 1
|
2113
|
+
uses_rcks = opts[:uses_right_composite_keys] = rcks.length > 1
|
2035
2114
|
opts[:cartesian_product_number] ||= one_through_one ? 0 : 1
|
2036
2115
|
join_table = (opts[:join_table] ||= opts.default_join_table)
|
2037
2116
|
opts[:left_key_alias] ||= opts.default_associated_key_alias
|
@@ -2040,8 +2119,75 @@ module Sequel
|
|
2040
2119
|
opts[:after_load] ||= []
|
2041
2120
|
opts[:after_load].unshift(:array_uniq!)
|
2042
2121
|
end
|
2043
|
-
opts[:
|
2044
|
-
|
2122
|
+
if join_table_db = opts[:join_table_db]
|
2123
|
+
opts[:use_placeholder_loader] = false
|
2124
|
+
opts[:allow_eager_graph] = false
|
2125
|
+
opts[:allow_filtering_by] = false
|
2126
|
+
opts[:eager_limit_strategy] = nil
|
2127
|
+
join_table_ds = join_table_db.from(join_table)
|
2128
|
+
opts[:dataset] ||= proc do |r|
|
2129
|
+
vals = join_table_ds.where(lcks.zip(lcpks.map{|k| get_column_value(k)})).select_map(right)
|
2130
|
+
ds = r.associated_dataset.where(opts.right_primary_key => vals)
|
2131
|
+
if uses_rcks
|
2132
|
+
vals.delete_if{|v| v.any?(&:nil?)}
|
2133
|
+
else
|
2134
|
+
vals.delete(nil)
|
2135
|
+
end
|
2136
|
+
ds = ds.clone(:no_results=>true) if vals.empty?
|
2137
|
+
ds
|
2138
|
+
end
|
2139
|
+
opts[:eager_loader] ||= proc do |eo|
|
2140
|
+
h = eo[:id_map]
|
2141
|
+
assign_singular = opts.assign_singular?
|
2142
|
+
rpk = opts.right_primary_key
|
2143
|
+
name = opts[:name]
|
2144
|
+
|
2145
|
+
join_map = join_table_ds.where(left=>h.keys).select_hash_groups(right, left)
|
2146
|
+
|
2147
|
+
if uses_rcks
|
2148
|
+
join_map.delete_if{|v,| v.any?(&:nil?)}
|
2149
|
+
else
|
2150
|
+
join_map.delete(nil)
|
2151
|
+
end
|
2152
|
+
|
2153
|
+
eo = Hash[eo]
|
2154
|
+
|
2155
|
+
if join_map.empty?
|
2156
|
+
eo[:no_results] = true
|
2157
|
+
else
|
2158
|
+
join_map.each_value do |vs|
|
2159
|
+
vs.replace(vs.flat_map{|v| h[v]})
|
2160
|
+
vs.uniq!
|
2161
|
+
end
|
2162
|
+
|
2163
|
+
eo[:loader] = false
|
2164
|
+
eo[:right_keys] = join_map.keys
|
2165
|
+
end
|
2166
|
+
|
2167
|
+
opts[:model].eager_load_results(opts, eo) do |assoc_record|
|
2168
|
+
rpkv = if uses_rcks
|
2169
|
+
assoc_record.values.values_at(*rpk)
|
2170
|
+
else
|
2171
|
+
assoc_record.values[rpk]
|
2172
|
+
end
|
2173
|
+
|
2174
|
+
objects = join_map[rpkv]
|
2175
|
+
|
2176
|
+
if assign_singular
|
2177
|
+
objects.each do |object|
|
2178
|
+
object.associations[name] ||= assoc_record
|
2179
|
+
end
|
2180
|
+
else
|
2181
|
+
objects.each do |object|
|
2182
|
+
object.associations[name].push(assoc_record)
|
2183
|
+
end
|
2184
|
+
end
|
2185
|
+
end
|
2186
|
+
end
|
2187
|
+
else
|
2188
|
+
opts[:dataset] ||= opts.association_dataset_proc
|
2189
|
+
opts[:eager_loader] ||= opts.method(:default_eager_loader)
|
2190
|
+
end
|
2045
2191
|
|
2046
2192
|
join_type = opts[:graph_join_type]
|
2047
2193
|
select = opts[:graph_select]
|
@@ -2075,50 +2221,60 @@ module Sequel
|
|
2075
2221
|
return if opts[:read_only]
|
2076
2222
|
|
2077
2223
|
if one_through_one
|
2078
|
-
opts
|
2079
|
-
|
2080
|
-
|
2081
|
-
|
2224
|
+
unless opts.has_key?(:setter)
|
2225
|
+
opts[:setter] = proc do |o|
|
2226
|
+
h = {}
|
2227
|
+
lh = lcks.zip(lcpks.map{|k| get_column_value(k)})
|
2228
|
+
jtds = _join_table_dataset(opts).where(lh)
|
2082
2229
|
|
2083
|
-
|
2084
|
-
|
2085
|
-
|
2086
|
-
if o
|
2087
|
-
new_values = []
|
2088
|
-
rcks.zip(opts.right_primary_key_methods).each{|k, pk| new_values << (h[k] = o.get_column_value(pk))}
|
2089
|
-
end
|
2230
|
+
checked_transaction do
|
2231
|
+
current = jtds.first
|
2090
2232
|
|
2091
|
-
if current
|
2092
|
-
current_values = rcks.map{|k| current[k]}
|
2093
|
-
jtds = jtds.where(rcks.zip(current_values))
|
2094
2233
|
if o
|
2095
|
-
|
2096
|
-
|
2234
|
+
new_values = []
|
2235
|
+
rcks.zip(opts.right_primary_key_methods).each{|k, pk| new_values << (h[k] = o.get_column_value(pk))}
|
2236
|
+
end
|
2237
|
+
|
2238
|
+
if current
|
2239
|
+
current_values = rcks.map{|k| current[k]}
|
2240
|
+
jtds = jtds.where(rcks.zip(current_values))
|
2241
|
+
if o
|
2242
|
+
if current_values != new_values
|
2243
|
+
jtds.update(h)
|
2244
|
+
end
|
2245
|
+
else
|
2246
|
+
jtds.delete
|
2097
2247
|
end
|
2098
|
-
|
2099
|
-
|
2248
|
+
elsif o
|
2249
|
+
lh.each{|k,v| h[k] = v}
|
2250
|
+
jtds.insert(h)
|
2100
2251
|
end
|
2101
|
-
elsif o
|
2102
|
-
lh.each{|k,v| h[k] = v}
|
2103
|
-
jtds.insert(h)
|
2104
2252
|
end
|
2105
2253
|
end
|
2106
2254
|
end
|
2107
|
-
opts
|
2255
|
+
if opts.fetch(:setter, true)
|
2256
|
+
opts[:_setter] = proc{|o| set_one_through_one_associated_object(opts, o)}
|
2257
|
+
end
|
2108
2258
|
else
|
2109
|
-
opts
|
2110
|
-
|
2111
|
-
|
2112
|
-
|
2113
|
-
|
2259
|
+
unless opts.has_key?(:adder)
|
2260
|
+
opts[:adder] = proc do |o|
|
2261
|
+
h = {}
|
2262
|
+
lcks.zip(lcpks).each{|k, pk| h[k] = get_column_value(pk)}
|
2263
|
+
rcks.zip(opts.right_primary_key_methods).each{|k, pk| h[k] = o.get_column_value(pk)}
|
2264
|
+
_join_table_dataset(opts).insert(h)
|
2265
|
+
end
|
2114
2266
|
end
|
2115
2267
|
|
2116
|
-
opts
|
2117
|
-
|
2268
|
+
unless opts.has_key?(:remover)
|
2269
|
+
opts[:remover] = proc do |o|
|
2270
|
+
_join_table_dataset(opts).where(lcks.zip(lcpks.map{|k| get_column_value(k)}) + rcks.zip(opts.right_primary_key_methods.map{|k| o.get_column_value(k)})).delete
|
2271
|
+
end
|
2118
2272
|
end
|
2119
2273
|
|
2120
|
-
opts
|
2121
|
-
|
2274
|
+
unless opts.has_key?(:clearer)
|
2275
|
+
opts[:clearer] = proc do
|
2276
|
+
_join_table_dataset(opts).where(lcks.zip(lcpks.map{|k| get_column_value(k)})).delete
|
2277
|
+
end
|
2122
2278
|
end
|
2123
2279
|
end
|
2124
2280
|
end
|
@@ -2175,8 +2331,12 @@ module Sequel
|
|
2175
2331
|
|
2176
2332
|
return if opts[:read_only]
|
2177
2333
|
|
2178
|
-
|
2179
|
-
|
2334
|
+
unless opts.has_key?(:setter)
|
2335
|
+
opts[:setter] = proc{|o| cks.zip(opts.primary_key_methods).each{|k, pk| set_column_value(:"#{k}=", (o.get_column_value(pk) if o))}}
|
2336
|
+
end
|
2337
|
+
if opts.fetch(:setter, true)
|
2338
|
+
opts[:_setter] = proc{|o| set_associated_object(opts, o)}
|
2339
|
+
end
|
2180
2340
|
end
|
2181
2341
|
|
2182
2342
|
# Configures one_to_many and one_to_one association reflections and adds the related association methods
|
@@ -2243,49 +2403,59 @@ module Sequel
|
|
2243
2403
|
cks.each{|k| ck_nil_hash[k] = nil}
|
2244
2404
|
|
2245
2405
|
if one_to_one
|
2246
|
-
opts
|
2247
|
-
|
2406
|
+
unless opts.has_key?(:setter)
|
2407
|
+
opts[:setter] = proc do |o|
|
2408
|
+
up_ds = _apply_association_options(opts, opts.associated_dataset.where(cks.zip(cpks.map{|k| get_column_value(k)})))
|
2248
2409
|
|
2249
|
-
|
2250
|
-
|
2251
|
-
|
2410
|
+
if (froms = up_ds.opts[:from]) && (from = froms[0]) && (from.is_a?(Sequel::Dataset) || (from.is_a?(Sequel::SQL::AliasedExpression) && from.expression.is_a?(Sequel::Dataset)))
|
2411
|
+
if old = up_ds.first
|
2412
|
+
cks.each{|k| old.set_column_value(:"#{k}=", nil)}
|
2413
|
+
end
|
2414
|
+
save_old = true
|
2252
2415
|
end
|
2253
|
-
save_old = true
|
2254
|
-
end
|
2255
2416
|
|
2256
|
-
|
2257
|
-
|
2258
|
-
|
2417
|
+
if o
|
2418
|
+
if !o.new? && !save_old
|
2419
|
+
up_ds = up_ds.exclude(o.pk_hash)
|
2420
|
+
end
|
2421
|
+
cks.zip(cpks).each{|k, pk| o.set_column_value(:"#{k}=", get_column_value(pk))}
|
2259
2422
|
end
|
2260
|
-
cks.zip(cpks).each{|k, pk| o.set_column_value(:"#{k}=", get_column_value(pk))}
|
2261
|
-
end
|
2262
2423
|
|
2263
|
-
|
2264
|
-
|
2265
|
-
|
2266
|
-
|
2267
|
-
|
2268
|
-
|
2424
|
+
checked_transaction do
|
2425
|
+
if save_old
|
2426
|
+
old.save(save_opts) || raise(Sequel::Error, "invalid previously associated object, cannot save") if old
|
2427
|
+
else
|
2428
|
+
up_ds.skip_limit_check.update(ck_nil_hash)
|
2429
|
+
end
|
2269
2430
|
|
2270
|
-
|
2431
|
+
o.save(save_opts) || raise(Sequel::Error, "invalid associated object, cannot save") if o
|
2432
|
+
end
|
2271
2433
|
end
|
2272
2434
|
end
|
2273
|
-
opts
|
2435
|
+
if opts.fetch(:setter, true)
|
2436
|
+
opts[:_setter] = proc{|o| set_one_to_one_associated_object(opts, o)}
|
2437
|
+
end
|
2274
2438
|
else
|
2275
2439
|
save_opts[:raise_on_failure] = opts[:raise_on_save_failure] != false
|
2276
2440
|
|
2277
|
-
opts
|
2278
|
-
|
2279
|
-
|
2441
|
+
unless opts.has_key?(:adder)
|
2442
|
+
opts[:adder] = proc do |o|
|
2443
|
+
cks.zip(cpks).each{|k, pk| o.set_column_value(:"#{k}=", get_column_value(pk))}
|
2444
|
+
o.save(save_opts)
|
2445
|
+
end
|
2280
2446
|
end
|
2281
2447
|
|
2282
|
-
opts
|
2283
|
-
|
2284
|
-
|
2448
|
+
unless opts.has_key?(:remover)
|
2449
|
+
opts[:remover] = proc do |o|
|
2450
|
+
cks.each{|k| o.set_column_value(:"#{k}=", nil)}
|
2451
|
+
o.save(save_opts)
|
2452
|
+
end
|
2285
2453
|
end
|
2286
2454
|
|
2287
|
-
opts
|
2288
|
-
|
2455
|
+
unless opts.has_key?(:clearer)
|
2456
|
+
opts[:clearer] = proc do
|
2457
|
+
_apply_association_options(opts, opts.associated_dataset.where(cks.zip(cpks.map{|k| get_column_value(k)}))).update(ck_nil_hash)
|
2458
|
+
end
|
2289
2459
|
end
|
2290
2460
|
end
|
2291
2461
|
end
|
@@ -2303,6 +2473,9 @@ module Sequel
|
|
2303
2473
|
# Return dataset to graph into given the association reflection, applying the :callback option if set.
|
2304
2474
|
def eager_graph_dataset(opts, eager_options)
|
2305
2475
|
ds = opts.associated_class.dataset
|
2476
|
+
if opts[:graph_use_association_block] && (b = opts[:block])
|
2477
|
+
ds = b.call(ds)
|
2478
|
+
end
|
2306
2479
|
if cb = eager_options[:callback]
|
2307
2480
|
ds = cb.call(ds)
|
2308
2481
|
end
|
@@ -2379,7 +2552,7 @@ module Sequel
|
|
2379
2552
|
|
2380
2553
|
# Dataset for the join table of the given many to many association reflection
|
2381
2554
|
def _join_table_dataset(opts)
|
2382
|
-
ds = model.db.from(opts.join_table_source)
|
2555
|
+
ds = (opts[:join_table_db] || model.db).from(opts.join_table_source)
|
2383
2556
|
opts[:join_table_block] ? opts[:join_table_block].call(ds) : ds
|
2384
2557
|
end
|
2385
2558
|
|
@@ -2400,7 +2573,12 @@ module Sequel
|
|
2400
2573
|
if loader = _associated_object_loader(opts, dynamic_opts)
|
2401
2574
|
loader.all(*opts.predicate_key_values(self))
|
2402
2575
|
else
|
2403
|
-
_associated_dataset(opts, dynamic_opts)
|
2576
|
+
ds = _associated_dataset(opts, dynamic_opts)
|
2577
|
+
if ds.opts[:no_results]
|
2578
|
+
[]
|
2579
|
+
else
|
2580
|
+
ds.all
|
2581
|
+
end
|
2404
2582
|
end
|
2405
2583
|
end
|
2406
2584
|
|
@@ -2861,6 +3039,8 @@ module Sequel
|
|
2861
3039
|
(multiple = ((op == :IN || op == :'NOT IN') && ((is_ds = r.is_a?(Sequel::Dataset)) || (r.respond_to?(:all?) && r.all?{|x| x.is_a?(Sequel::Model)})))))
|
2862
3040
|
l = args[0]
|
2863
3041
|
if ar = model.association_reflections[l]
|
3042
|
+
raise Error, "filtering by associations is not allowed for #{ar.inspect}" if ar[:allow_filtering_by] == false
|
3043
|
+
|
2864
3044
|
if multiple
|
2865
3045
|
klass = ar.associated_class
|
2866
3046
|
if is_ds
|
@@ -2982,7 +3162,7 @@ module Sequel
|
|
2982
3162
|
|
2983
3163
|
# The secondary eager loading method. Loads all associations in a single query. This
|
2984
3164
|
# method should only be used if you need to filter or order based on columns in associated tables,
|
2985
|
-
# or if you have done comparative benchmarking
|
3165
|
+
# or if you have done comparative benchmarking and determined it is faster.
|
2986
3166
|
#
|
2987
3167
|
# This method uses <tt>Dataset#graph</tt> to create appropriate aliases for columns in all the
|
2988
3168
|
# tables. Then it uses the graph's metadata to build the associations from the single hash, and
|
@@ -3207,8 +3387,15 @@ module Sequel
|
|
3207
3387
|
local_opts = ds.opts[:eager_graph][:local]
|
3208
3388
|
limit_strategy = r.eager_graph_limit_strategy(local_opts[:limit_strategy])
|
3209
3389
|
|
3210
|
-
|
3211
|
-
|
3390
|
+
# SEQUEL6: remove and integrate the auto_restrict_eager_graph plugin
|
3391
|
+
if !r[:orig_opts].has_key?(:graph_conditions) && !r[:orig_opts].has_key?(:graph_only_conditions) && !r.has_key?(:graph_block) && !r[:allow_eager_graph]
|
3392
|
+
if r[:conditions] && !Sequel.condition_specifier?(r[:conditions])
|
3393
|
+
raise Error, "Cannot eager_graph association when :conditions specified and not a hash or an array of pairs. Specify :graph_conditions, :graph_only_conditions, or :graph_block for the association. Model: #{r[:model]}, association: #{r[:name]}"
|
3394
|
+
end
|
3395
|
+
|
3396
|
+
if r[:block] && !r[:graph_use_association_block]
|
3397
|
+
warn "eager_graph used for association when association given a block without graph options. The block is ignored in this case. This will result in an exception starting in Sequel 6. Model: #{r[:model]}, association: #{r[:name]}"
|
3398
|
+
end
|
3212
3399
|
end
|
3213
3400
|
|
3214
3401
|
ds = loader.call(:self=>ds, :table_alias=>assoc_table_alias, :implicit_qualifier=>(ta == ds.opts[:eager_graph][:master]) ? first_source : qualifier_from_alias_symbol(ta, first_source), :callback=>callback, :join_type=>join_type || local_opts[:join_type], :join_only=>local_opts[:join_only], :limit_strategy=>limit_strategy, :from_self_alias=>ds.opts[:eager_graph][:master])
|
@@ -3356,7 +3543,7 @@ module Sequel
|
|
3356
3543
|
# Allow associations that are eagerly graphed to be specified as an SQL::AliasedExpression, for
|
3357
3544
|
# per-call determining of the alias base.
|
3358
3545
|
def eager_graph_check_association(model, association)
|
3359
|
-
if association.is_a?(SQL::AliasedExpression)
|
3546
|
+
reflection = if association.is_a?(SQL::AliasedExpression)
|
3360
3547
|
expr = association.expression
|
3361
3548
|
if expr.is_a?(SQL::Identifier)
|
3362
3549
|
expr = expr.value
|
@@ -3365,10 +3552,17 @@ module Sequel
|
|
3365
3552
|
end
|
3366
3553
|
end
|
3367
3554
|
|
3368
|
-
|
3555
|
+
check_reflection = check_association(model, expr)
|
3556
|
+
SQL::AliasedExpression.new(check_reflection, association.alias || expr, association.columns)
|
3369
3557
|
else
|
3370
|
-
check_association(model, association)
|
3558
|
+
check_reflection = check_association(model, association)
|
3559
|
+
end
|
3560
|
+
|
3561
|
+
if check_reflection && check_reflection[:allow_eager_graph] == false
|
3562
|
+
raise Error, "eager_graph not allowed for #{reflection.inspect}"
|
3371
3563
|
end
|
3564
|
+
|
3565
|
+
reflection
|
3372
3566
|
end
|
3373
3567
|
|
3374
3568
|
# The EagerGraphLoader instance used for converting eager_graph results.
|
@@ -3380,11 +3574,11 @@ module Sequel
|
|
3380
3574
|
end
|
3381
3575
|
|
3382
3576
|
# Eagerly load all specified associations.
|
3383
|
-
def eager_load(a, eager_assoc=@opts[:eager])
|
3577
|
+
def eager_load(a, eager_assoc=@opts[:eager], m=model)
|
3384
3578
|
return if a.empty?
|
3385
3579
|
|
3386
3580
|
# Reflections for all associations to eager load
|
3387
|
-
reflections = eager_assoc.keys.map{|assoc|
|
3581
|
+
reflections = eager_assoc.keys.map{|assoc| m.association_reflection(assoc) || (raise Sequel::UndefinedAssociation, "Model: #{self}, Association: #{assoc}")}
|
3388
3582
|
|
3389
3583
|
perform_eager_loads(prepare_eager_load(a, reflections, eager_assoc))
|
3390
3584
|
|