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
@@ -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
|
|