sequel 5.83.0 → 5.106.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/MIT-LICENSE +1 -1
- data/lib/sequel/adapters/ado/access.rb +2 -2
- data/lib/sequel/adapters/ado.rb +2 -2
- data/lib/sequel/adapters/amalgalite.rb +16 -1
- data/lib/sequel/adapters/ibmdb.rb +2 -1
- data/lib/sequel/adapters/jdbc/db2.rb +2 -2
- data/lib/sequel/adapters/jdbc/derby.rb +4 -2
- data/lib/sequel/adapters/jdbc/h2.rb +4 -4
- data/lib/sequel/adapters/jdbc/hsqldb.rb +2 -2
- data/lib/sequel/adapters/jdbc/jtds.rb +2 -2
- data/lib/sequel/adapters/jdbc/mysql.rb +3 -3
- data/lib/sequel/adapters/jdbc/oracle.rb +6 -6
- data/lib/sequel/adapters/jdbc/postgresql.rb +5 -5
- data/lib/sequel/adapters/jdbc/sqlanywhere.rb +6 -6
- data/lib/sequel/adapters/jdbc/sqlite.rb +3 -3
- data/lib/sequel/adapters/jdbc/sqlserver.rb +3 -3
- data/lib/sequel/adapters/jdbc.rb +29 -15
- data/lib/sequel/adapters/mysql.rb +1 -1
- data/lib/sequel/adapters/mysql2.rb +10 -3
- data/lib/sequel/adapters/odbc.rb +1 -1
- data/lib/sequel/adapters/oracle.rb +16 -0
- data/lib/sequel/adapters/postgres.rb +2 -1
- data/lib/sequel/adapters/shared/access.rb +1 -0
- data/lib/sequel/adapters/shared/db2.rb +8 -3
- data/lib/sequel/adapters/shared/mssql.rb +9 -8
- data/lib/sequel/adapters/shared/mysql.rb +16 -11
- data/lib/sequel/adapters/shared/oracle.rb +1 -0
- data/lib/sequel/adapters/shared/postgres.rb +438 -47
- data/lib/sequel/adapters/shared/sqlite.rb +9 -7
- data/lib/sequel/adapters/sqlite.rb +20 -2
- data/lib/sequel/adapters/tinytds.rb +2 -2
- data/lib/sequel/adapters/trilogy.rb +2 -3
- data/lib/sequel/ast_transformer.rb +2 -0
- data/lib/sequel/connection_pool/sharded_timed_queue.rb +42 -11
- data/lib/sequel/connection_pool/timed_queue.rb +33 -10
- data/lib/sequel/connection_pool.rb +8 -2
- data/lib/sequel/core.rb +31 -2
- data/lib/sequel/database/connecting.rb +1 -1
- data/lib/sequel/database/dataset_defaults.rb +3 -3
- data/lib/sequel/database/misc.rb +29 -11
- data/lib/sequel/database/query.rb +12 -12
- data/lib/sequel/database/schema_generator.rb +117 -16
- data/lib/sequel/database/schema_methods.rb +85 -30
- data/lib/sequel/dataset/actions.rb +83 -11
- data/lib/sequel/dataset/deprecated_singleton_class_methods.rb +1 -1
- data/lib/sequel/dataset/placeholder_literalizer.rb +3 -0
- data/lib/sequel/dataset/prepared_statements.rb +76 -28
- data/lib/sequel/dataset/query.rb +26 -11
- data/lib/sequel/dataset/sql.rb +40 -17
- data/lib/sequel/extensions/async_thread_pool.rb +1 -1
- data/lib/sequel/extensions/caller_logging.rb +1 -3
- data/lib/sequel/extensions/connection_checkout_event_callback.rb +151 -0
- data/lib/sequel/extensions/connection_expiration.rb +44 -5
- data/lib/sequel/extensions/connection_validator.rb +15 -10
- data/lib/sequel/extensions/constraint_validations.rb +3 -3
- data/lib/sequel/extensions/dataset_run.rb +41 -0
- data/lib/sequel/extensions/date_arithmetic.rb +6 -6
- data/lib/sequel/extensions/empty_array_consider_nulls.rb +7 -0
- data/lib/sequel/extensions/eval_inspect.rb +3 -1
- data/lib/sequel/extensions/inflector.rb +2 -2
- data/lib/sequel/extensions/lit_require_frozen.rb +131 -0
- data/lib/sequel/extensions/looser_typecasting.rb +5 -12
- data/lib/sequel/extensions/migration.rb +38 -21
- data/lib/sequel/extensions/null_dataset.rb +2 -2
- data/lib/sequel/extensions/pg_array_ops.rb +41 -0
- data/lib/sequel/extensions/pg_auto_parameterize.rb +10 -3
- data/lib/sequel/extensions/pg_auto_parameterize_duplicate_query_detection.rb +191 -0
- data/lib/sequel/extensions/pg_auto_parameterize_in_array.rb +94 -10
- data/lib/sequel/extensions/pg_enum.rb +4 -4
- data/lib/sequel/extensions/pg_hstore.rb +1 -1
- data/lib/sequel/extensions/pg_hstore_ops.rb +10 -5
- data/lib/sequel/extensions/pg_json_ops.rb +674 -18
- data/lib/sequel/extensions/pg_multirange.rb +1 -1
- data/lib/sequel/extensions/pg_range.rb +14 -2
- data/lib/sequel/extensions/pg_row.rb +5 -3
- data/lib/sequel/extensions/pg_schema_caching.rb +90 -0
- data/lib/sequel/extensions/provenance.rb +1 -3
- data/lib/sequel/extensions/query_blocker.rb +172 -0
- data/lib/sequel/extensions/schema_caching.rb +24 -9
- data/lib/sequel/extensions/schema_dumper.rb +17 -5
- data/lib/sequel/extensions/set_literalizer.rb +20 -39
- data/lib/sequel/extensions/split_array_nil.rb +12 -2
- data/lib/sequel/extensions/sqlite_json_ops.rb +1 -1
- data/lib/sequel/extensions/string_agg.rb +2 -2
- data/lib/sequel/extensions/to_dot.rb +5 -0
- data/lib/sequel/extensions/virtual_row_method_block.rb +1 -0
- data/lib/sequel/model/associations.rb +215 -15
- data/lib/sequel/model/base.rb +198 -35
- data/lib/sequel/model/plugins.rb +12 -1
- data/lib/sequel/model.rb +1 -0
- data/lib/sequel/plugins/accessed_columns.rb +4 -0
- data/lib/sequel/plugins/active_model.rb +5 -6
- data/lib/sequel/plugins/association_pks.rb +2 -0
- data/lib/sequel/plugins/auto_validations.rb +2 -0
- data/lib/sequel/plugins/class_table_inheritance_constraint_validations.rb +82 -0
- data/lib/sequel/plugins/columns_updated.rb +4 -0
- data/lib/sequel/plugins/composition.rb +3 -1
- data/lib/sequel/plugins/constraint_validations.rb +15 -10
- data/lib/sequel/plugins/dataset_associations.rb +20 -1
- data/lib/sequel/plugins/deprecated_associations.rb +151 -0
- data/lib/sequel/plugins/detect_unnecessary_association_options.rb +164 -0
- data/lib/sequel/plugins/dirty.rb +9 -2
- data/lib/sequel/plugins/enum.rb +1 -1
- data/lib/sequel/plugins/forbid_lazy_load.rb +15 -1
- data/lib/sequel/plugins/insert_conflict.rb +4 -0
- data/lib/sequel/plugins/insert_returning_select.rb +10 -1
- data/lib/sequel/plugins/inspect_pk.rb +44 -0
- data/lib/sequel/plugins/instance_filters.rb +8 -1
- data/lib/sequel/plugins/instance_hooks.rb +4 -0
- data/lib/sequel/plugins/inverted_subsets.rb +1 -0
- data/lib/sequel/plugins/json_serializer.rb +6 -10
- data/lib/sequel/plugins/lazy_attributes.rb +1 -1
- data/lib/sequel/plugins/many_through_many.rb +21 -0
- data/lib/sequel/plugins/modification_detection.rb +2 -0
- data/lib/sequel/plugins/mssql_optimistic_locking.rb +1 -1
- data/lib/sequel/plugins/nested_attributes.rb +10 -5
- data/lib/sequel/plugins/paged_operations.rb +5 -2
- data/lib/sequel/plugins/pg_array_associations.rb +2 -2
- data/lib/sequel/plugins/pg_auto_constraint_validations.rb +6 -1
- data/lib/sequel/plugins/pg_auto_validate_enums.rb +88 -0
- data/lib/sequel/plugins/pg_eager_any_typed_array.rb +95 -0
- data/lib/sequel/plugins/pg_xmin_optimistic_locking.rb +1 -1
- data/lib/sequel/plugins/rcte_tree.rb +6 -6
- data/lib/sequel/plugins/serialization.rb +23 -6
- data/lib/sequel/plugins/serialization_modification_detection.rb +4 -0
- data/lib/sequel/plugins/single_statement_dataset_destroy.rb +49 -0
- data/lib/sequel/plugins/split_values.rb +12 -0
- data/lib/sequel/plugins/sql_comments.rb +7 -2
- data/lib/sequel/plugins/static_cache.rb +13 -0
- data/lib/sequel/plugins/static_cache_cache.rb +50 -13
- data/lib/sequel/plugins/subset_conditions.rb +85 -5
- data/lib/sequel/plugins/subset_static_cache.rb +278 -0
- data/lib/sequel/plugins/table_select.rb +7 -0
- data/lib/sequel/plugins/tactical_eager_loading.rb +4 -0
- data/lib/sequel/plugins/unused_associations.rb +11 -3
- data/lib/sequel/plugins/update_primary_key.rb +4 -0
- data/lib/sequel/plugins/validation_class_methods.rb +1 -1
- data/lib/sequel/plugins/validation_contexts.rb +4 -0
- data/lib/sequel/sql.rb +27 -12
- data/lib/sequel/version.rb +1 -1
- metadata +17 -240
- data/CHANGELOG +0 -1393
- data/README.rdoc +0 -936
- data/doc/advanced_associations.rdoc +0 -884
- data/doc/association_basics.rdoc +0 -1859
- data/doc/bin_sequel.rdoc +0 -146
- data/doc/cheat_sheet.rdoc +0 -255
- data/doc/code_order.rdoc +0 -104
- data/doc/core_extensions.rdoc +0 -405
- data/doc/dataset_basics.rdoc +0 -96
- data/doc/dataset_filtering.rdoc +0 -222
- data/doc/extensions.rdoc +0 -77
- data/doc/fork_safety.rdoc +0 -84
- data/doc/mass_assignment.rdoc +0 -98
- data/doc/migration.rdoc +0 -660
- data/doc/model_dataset_method_design.rdoc +0 -129
- data/doc/model_hooks.rdoc +0 -254
- data/doc/model_plugins.rdoc +0 -270
- data/doc/mssql_stored_procedures.rdoc +0 -43
- data/doc/object_model.rdoc +0 -563
- data/doc/opening_databases.rdoc +0 -439
- data/doc/postgresql.rdoc +0 -611
- data/doc/prepared_statements.rdoc +0 -144
- data/doc/querying.rdoc +0 -1070
- data/doc/reflection.rdoc +0 -120
- data/doc/release_notes/5.0.0.txt +0 -159
- data/doc/release_notes/5.1.0.txt +0 -31
- data/doc/release_notes/5.10.0.txt +0 -84
- data/doc/release_notes/5.11.0.txt +0 -83
- data/doc/release_notes/5.12.0.txt +0 -141
- data/doc/release_notes/5.13.0.txt +0 -27
- data/doc/release_notes/5.14.0.txt +0 -63
- data/doc/release_notes/5.15.0.txt +0 -39
- data/doc/release_notes/5.16.0.txt +0 -110
- data/doc/release_notes/5.17.0.txt +0 -31
- data/doc/release_notes/5.18.0.txt +0 -69
- data/doc/release_notes/5.19.0.txt +0 -28
- data/doc/release_notes/5.2.0.txt +0 -33
- data/doc/release_notes/5.20.0.txt +0 -89
- data/doc/release_notes/5.21.0.txt +0 -87
- data/doc/release_notes/5.22.0.txt +0 -48
- data/doc/release_notes/5.23.0.txt +0 -56
- data/doc/release_notes/5.24.0.txt +0 -56
- data/doc/release_notes/5.25.0.txt +0 -32
- data/doc/release_notes/5.26.0.txt +0 -35
- data/doc/release_notes/5.27.0.txt +0 -21
- data/doc/release_notes/5.28.0.txt +0 -16
- data/doc/release_notes/5.29.0.txt +0 -22
- data/doc/release_notes/5.3.0.txt +0 -121
- data/doc/release_notes/5.30.0.txt +0 -20
- data/doc/release_notes/5.31.0.txt +0 -148
- data/doc/release_notes/5.32.0.txt +0 -46
- data/doc/release_notes/5.33.0.txt +0 -24
- data/doc/release_notes/5.34.0.txt +0 -40
- data/doc/release_notes/5.35.0.txt +0 -56
- data/doc/release_notes/5.36.0.txt +0 -60
- data/doc/release_notes/5.37.0.txt +0 -30
- data/doc/release_notes/5.38.0.txt +0 -28
- data/doc/release_notes/5.39.0.txt +0 -19
- data/doc/release_notes/5.4.0.txt +0 -80
- data/doc/release_notes/5.40.0.txt +0 -40
- data/doc/release_notes/5.41.0.txt +0 -25
- data/doc/release_notes/5.42.0.txt +0 -136
- data/doc/release_notes/5.43.0.txt +0 -98
- data/doc/release_notes/5.44.0.txt +0 -32
- data/doc/release_notes/5.45.0.txt +0 -34
- data/doc/release_notes/5.46.0.txt +0 -87
- data/doc/release_notes/5.47.0.txt +0 -59
- data/doc/release_notes/5.48.0.txt +0 -14
- data/doc/release_notes/5.49.0.txt +0 -59
- data/doc/release_notes/5.5.0.txt +0 -61
- data/doc/release_notes/5.50.0.txt +0 -78
- data/doc/release_notes/5.51.0.txt +0 -47
- data/doc/release_notes/5.52.0.txt +0 -87
- data/doc/release_notes/5.53.0.txt +0 -23
- data/doc/release_notes/5.54.0.txt +0 -27
- data/doc/release_notes/5.55.0.txt +0 -21
- data/doc/release_notes/5.56.0.txt +0 -51
- data/doc/release_notes/5.57.0.txt +0 -23
- data/doc/release_notes/5.58.0.txt +0 -31
- data/doc/release_notes/5.59.0.txt +0 -73
- data/doc/release_notes/5.6.0.txt +0 -31
- data/doc/release_notes/5.60.0.txt +0 -22
- data/doc/release_notes/5.61.0.txt +0 -43
- data/doc/release_notes/5.62.0.txt +0 -132
- data/doc/release_notes/5.63.0.txt +0 -33
- data/doc/release_notes/5.64.0.txt +0 -50
- data/doc/release_notes/5.65.0.txt +0 -21
- data/doc/release_notes/5.66.0.txt +0 -24
- data/doc/release_notes/5.67.0.txt +0 -32
- data/doc/release_notes/5.68.0.txt +0 -61
- data/doc/release_notes/5.69.0.txt +0 -26
- data/doc/release_notes/5.7.0.txt +0 -108
- data/doc/release_notes/5.70.0.txt +0 -35
- data/doc/release_notes/5.71.0.txt +0 -21
- data/doc/release_notes/5.72.0.txt +0 -33
- data/doc/release_notes/5.73.0.txt +0 -66
- data/doc/release_notes/5.74.0.txt +0 -45
- data/doc/release_notes/5.75.0.txt +0 -35
- data/doc/release_notes/5.76.0.txt +0 -86
- data/doc/release_notes/5.77.0.txt +0 -63
- data/doc/release_notes/5.78.0.txt +0 -67
- data/doc/release_notes/5.79.0.txt +0 -28
- data/doc/release_notes/5.8.0.txt +0 -170
- data/doc/release_notes/5.80.0.txt +0 -40
- data/doc/release_notes/5.81.0.txt +0 -31
- data/doc/release_notes/5.82.0.txt +0 -61
- data/doc/release_notes/5.83.0.txt +0 -56
- data/doc/release_notes/5.9.0.txt +0 -99
- data/doc/schema_modification.rdoc +0 -679
- data/doc/security.rdoc +0 -443
- data/doc/sharding.rdoc +0 -286
- data/doc/sql.rdoc +0 -648
- data/doc/testing.rdoc +0 -204
- data/doc/thread_safety.rdoc +0 -15
- data/doc/transactions.rdoc +0 -250
- data/doc/validations.rdoc +0 -558
- data/doc/virtual_rows.rdoc +0 -265
|
@@ -112,6 +112,8 @@ module Sequel
|
|
|
112
112
|
# the dataset unmodified if no SQL limit strategy is needed.
|
|
113
113
|
def apply_eager_graph_limit_strategy(strategy, ds)
|
|
114
114
|
case strategy
|
|
115
|
+
when :lateral_subquery
|
|
116
|
+
apply_lateral_subquery_eager_graph_limit_strategy(ds)
|
|
115
117
|
when :distinct_on
|
|
116
118
|
apply_distinct_on_eager_limit_strategy(ds.order_prepend(*self[:order]))
|
|
117
119
|
when :window_function
|
|
@@ -298,11 +300,16 @@ module Sequel
|
|
|
298
300
|
# Correlated subqueries are not supported for regular eager loading
|
|
299
301
|
strategy = :ruby if strategy == :correlated_subquery
|
|
300
302
|
strategy = nil if strategy == :ruby && assign_singular?
|
|
301
|
-
|
|
303
|
+
|
|
304
|
+
objects = if strategy == :lateral_subquery
|
|
305
|
+
apply_lateral_subquery_eager_limit_strategy(ds, ids, eager_limit).all
|
|
306
|
+
else
|
|
307
|
+
apply_eager_limit_strategy(ds, strategy, eager_limit).all
|
|
308
|
+
end
|
|
302
309
|
|
|
303
310
|
if strategy == :window_function
|
|
304
311
|
delete_rn = ds.row_number_column
|
|
305
|
-
objects.each{|obj| obj.
|
|
312
|
+
objects.each{|obj| obj.remove_key!(delete_rn)}
|
|
306
313
|
end
|
|
307
314
|
elsif strategy == :union
|
|
308
315
|
objects = []
|
|
@@ -320,7 +327,7 @@ module Sequel
|
|
|
320
327
|
end
|
|
321
328
|
loader.append_sql(sql, *k)
|
|
322
329
|
end
|
|
323
|
-
objects.concat(ds.with_sql(sql).to_a)
|
|
330
|
+
objects.concat(ds.with_sql(sql.freeze).to_a)
|
|
324
331
|
end
|
|
325
332
|
ds = ds.eager(cascade) if cascade
|
|
326
333
|
ds.send(:post_load, objects)
|
|
@@ -366,7 +373,12 @@ module Sequel
|
|
|
366
373
|
# filtered. Works by using a subquery to test that the objects passed
|
|
367
374
|
# also meet the association filter criteria.
|
|
368
375
|
def filter_by_associations_conditions_expression(obj)
|
|
369
|
-
ds =
|
|
376
|
+
ds = if filter_by_associations_limit_strategy == :lateral_subquery
|
|
377
|
+
apply_lateral_subquery_filter_limit_strategy(associated_eager_dataset, obj)
|
|
378
|
+
else
|
|
379
|
+
filter_by_associations_conditions_dataset.where(filter_by_associations_conditions_subquery_conditions(obj))
|
|
380
|
+
end
|
|
381
|
+
|
|
370
382
|
{filter_by_associations_conditions_key=>ds}
|
|
371
383
|
end
|
|
372
384
|
|
|
@@ -414,6 +426,12 @@ module Sequel
|
|
|
414
426
|
false
|
|
415
427
|
end
|
|
416
428
|
|
|
429
|
+
# Hash value for the association reflection. This is precomputed to avoid
|
|
430
|
+
# concurrency issues at runtime.
|
|
431
|
+
def hash
|
|
432
|
+
self[:_hash]
|
|
433
|
+
end
|
|
434
|
+
|
|
417
435
|
# Initialize the associations cache for the current association for the given objects.
|
|
418
436
|
def initialize_association_cache(objects)
|
|
419
437
|
name = self[:name]
|
|
@@ -693,6 +711,9 @@ module Sequel
|
|
|
693
711
|
|
|
694
712
|
# The predicate condition to use for the eager_loader.
|
|
695
713
|
def eager_loading_predicate_condition(keys)
|
|
714
|
+
if transform = self[:eager_loading_predicate_transform]
|
|
715
|
+
keys = transform.call(keys, self)
|
|
716
|
+
end
|
|
696
717
|
{predicate_key=>keys}
|
|
697
718
|
end
|
|
698
719
|
|
|
@@ -745,6 +766,61 @@ module Sequel
|
|
|
745
766
|
end
|
|
746
767
|
end
|
|
747
768
|
|
|
769
|
+
def lateral_subquery_eager_limit_strategy_lateral_dataset(ds, limit_and_offset)
|
|
770
|
+
ds.
|
|
771
|
+
where(Array(filter_by_associations_conditions_key).zip(Array(filter_by_associations_conditions_associated_keys))).
|
|
772
|
+
limit(*limit_and_offset).
|
|
773
|
+
lateral
|
|
774
|
+
end
|
|
775
|
+
|
|
776
|
+
def apply_lateral_subquery_eager_limit_strategy(ds, ids, limit_and_offset)
|
|
777
|
+
table_name = self[:model].table_name
|
|
778
|
+
associated_table_name = associated_class.table_name
|
|
779
|
+
|
|
780
|
+
associated_class.
|
|
781
|
+
from(table_name).
|
|
782
|
+
select_all(associated_table_name).
|
|
783
|
+
join(lateral_subquery_eager_limit_strategy_lateral_dataset(ds, limit_and_offset).as(associated_table_name), true).
|
|
784
|
+
order(*self[:order])
|
|
785
|
+
end
|
|
786
|
+
|
|
787
|
+
# Return an expression to filter the filter by associations dataset to only
|
|
788
|
+
# rows related to given objects.
|
|
789
|
+
def _lateral_subquery_filter_limit_strategy_conditions(obj, key, value_method, value_column)
|
|
790
|
+
value = case obj
|
|
791
|
+
when Array
|
|
792
|
+
if key.is_a?(Array)
|
|
793
|
+
key_methods = Array(value_method)
|
|
794
|
+
obj.map{|o| key_methods.map{|meth| o.send(meth)}}
|
|
795
|
+
else
|
|
796
|
+
obj.map{|o| o.send(value_method)}
|
|
797
|
+
end
|
|
798
|
+
when Sequel::Dataset
|
|
799
|
+
obj.select(*Array(qualify(associated_class.table_name, value_column)))
|
|
800
|
+
else
|
|
801
|
+
if key.is_a?(Array)
|
|
802
|
+
return Array(key).zip(Array(value_method).map{|meth| obj.send(meth)})
|
|
803
|
+
else
|
|
804
|
+
obj.send(value_method)
|
|
805
|
+
end
|
|
806
|
+
end
|
|
807
|
+
|
|
808
|
+
{key => value}
|
|
809
|
+
end
|
|
810
|
+
|
|
811
|
+
def lateral_subquery_filter_limit_strategy_lateral_dataset(ds, obj)
|
|
812
|
+
lateral_subquery_filter_limit_strategy_filter_lateral_dataset(ds.
|
|
813
|
+
select(*qualify(associated_class.table_name, associated_class.primary_key)).
|
|
814
|
+
limit(*limit_and_offset).
|
|
815
|
+
lateral)
|
|
816
|
+
end
|
|
817
|
+
|
|
818
|
+
def apply_lateral_subquery_filter_limit_strategy(ds, obj)
|
|
819
|
+
lateral_subquery_filter_limit_strategy_filter_dataset(self[:model].
|
|
820
|
+
select(*lateral_subquery_filter_limit_strategy_lateral_dataset_select).
|
|
821
|
+
join(lateral_subquery_filter_limit_strategy_lateral_dataset(ds, obj).as(associated_class.table_name), filter_by_associations_conditions_subquery_conditions(obj)), obj)
|
|
822
|
+
end
|
|
823
|
+
|
|
748
824
|
# Whether to limit the associated dataset to a single row.
|
|
749
825
|
def limit_to_single_row?
|
|
750
826
|
!returns_array?
|
|
@@ -759,7 +835,20 @@ module Sequel
|
|
|
759
835
|
def placeholder_eager_loader
|
|
760
836
|
cached_fetch(:placeholder_eager_loader) do
|
|
761
837
|
eager_loading_dataset.placeholder_literalizer_loader do |pl, ds|
|
|
762
|
-
|
|
838
|
+
arg = pl.arg
|
|
839
|
+
|
|
840
|
+
if transform = self[:eager_loading_predicate_transform]
|
|
841
|
+
arg = arg.transform do |v|
|
|
842
|
+
transform.call(v, self)
|
|
843
|
+
end
|
|
844
|
+
end
|
|
845
|
+
|
|
846
|
+
strategy = eager_limit_strategy
|
|
847
|
+
if strategy == :lateral_subquery
|
|
848
|
+
apply_lateral_subquery_eager_limit_strategy(ds, arg, limit_and_offset)
|
|
849
|
+
else
|
|
850
|
+
apply_eager_limit_strategy(ds.where(predicate_key=>arg), strategy)
|
|
851
|
+
end
|
|
763
852
|
end
|
|
764
853
|
end
|
|
765
854
|
end
|
|
@@ -1001,7 +1090,7 @@ module Sequel
|
|
|
1001
1090
|
class OneToManyAssociationReflection < AssociationReflection
|
|
1002
1091
|
ASSOCIATION_TYPES[:one_to_many] = self
|
|
1003
1092
|
|
|
1004
|
-
# Support a
|
|
1093
|
+
# Support a lateral_subquery and correlated_subquery limit strategy when using eager_graph.
|
|
1005
1094
|
def apply_eager_graph_limit_strategy(strategy, ds)
|
|
1006
1095
|
case strategy
|
|
1007
1096
|
when :correlated_subquery
|
|
@@ -1101,6 +1190,54 @@ module Sequel
|
|
|
1101
1190
|
ds.where(qualify(table_alias, primary_key)=>cs)
|
|
1102
1191
|
end
|
|
1103
1192
|
|
|
1193
|
+
# Use a LATERAL subquery to limit the dataset. Note that this will not
|
|
1194
|
+
# work correctly if the associated dataset uses qualified identifers in the WHERE clause,
|
|
1195
|
+
# as they would reference the containing query instead of the subquery.
|
|
1196
|
+
#
|
|
1197
|
+
# This does not contain the conditions that are necessary to join to the
|
|
1198
|
+
# query, since the necessary qualifier is not passed as an argument.
|
|
1199
|
+
def apply_lateral_subquery_eager_graph_limit_strategy(ds)
|
|
1200
|
+
table_name = ds.first_source_alias
|
|
1201
|
+
qualifier = ds.opts[:eager_options][:implicit_qualifier]
|
|
1202
|
+
graph_conditions = self[:_graph_conditions]
|
|
1203
|
+
|
|
1204
|
+
unless Sequel.condition_specifier?(graph_conditions)
|
|
1205
|
+
raise Error, "lateral_subquery eager graph limit strategy only supported when graph conditions are a hash or array of pairs"
|
|
1206
|
+
end
|
|
1207
|
+
|
|
1208
|
+
ds.
|
|
1209
|
+
limit(*limit_and_offset).
|
|
1210
|
+
order(*self[:order]).
|
|
1211
|
+
where(graph_conditions.map{|k, v| [qualify(table_name, k), qualify(qualifier, v)]}).
|
|
1212
|
+
lateral
|
|
1213
|
+
end
|
|
1214
|
+
|
|
1215
|
+
# Avoid setting duplicate predicate condition when using the lateral subquery
|
|
1216
|
+
# eager limit strategy.
|
|
1217
|
+
def eager_loading_set_predicate_condition(ds, eo)
|
|
1218
|
+
eager_limit_strategy == :lateral_subquery ? ds : super
|
|
1219
|
+
end
|
|
1220
|
+
|
|
1221
|
+
def apply_lateral_subquery_eager_limit_strategy(ds, ids, limit_and_offset)
|
|
1222
|
+
super.where(qualify(self[:model].table_name, self[:primary_key]) => ids)
|
|
1223
|
+
end
|
|
1224
|
+
|
|
1225
|
+
def lateral_subquery_filter_limit_strategy_conditions(obj)
|
|
1226
|
+
_lateral_subquery_filter_limit_strategy_conditions(obj, filter_by_associations_conditions_key, self[:key_method], self[:key])
|
|
1227
|
+
end
|
|
1228
|
+
|
|
1229
|
+
def lateral_subquery_filter_limit_strategy_filter_lateral_dataset(ds)
|
|
1230
|
+
ds.where(Array(filter_by_associations_conditions_key).zip(Array(filter_by_associations_conditions_associated_keys)))
|
|
1231
|
+
end
|
|
1232
|
+
|
|
1233
|
+
def lateral_subquery_filter_limit_strategy_filter_dataset(ds, obj)
|
|
1234
|
+
ds.where(lateral_subquery_filter_limit_strategy_conditions(obj))
|
|
1235
|
+
end
|
|
1236
|
+
|
|
1237
|
+
def lateral_subquery_filter_limit_strategy_lateral_dataset_select
|
|
1238
|
+
qualified_primary_key
|
|
1239
|
+
end
|
|
1240
|
+
|
|
1104
1241
|
# Support correlated subquery strategy when filtering by limited associations.
|
|
1105
1242
|
def apply_filter_by_associations_limit_strategy(ds)
|
|
1106
1243
|
case filter_by_associations_limit_strategy
|
|
@@ -1274,11 +1411,11 @@ module Sequel
|
|
|
1274
1411
|
name = self[:name]
|
|
1275
1412
|
|
|
1276
1413
|
self[:model].eager_load_results(self, eo) do |assoc_record|
|
|
1277
|
-
assoc_record.
|
|
1414
|
+
assoc_record.remove_key!(delete_rn) if delete_rn
|
|
1278
1415
|
hash_key = if uses_lcks
|
|
1279
|
-
left_key_alias.map{|k| assoc_record.
|
|
1416
|
+
left_key_alias.map{|k| assoc_record.remove_key!(k)}
|
|
1280
1417
|
else
|
|
1281
|
-
assoc_record.
|
|
1418
|
+
assoc_record.remove_key!(left_key_alias)
|
|
1282
1419
|
end
|
|
1283
1420
|
|
|
1284
1421
|
objects = h[hash_key]
|
|
@@ -1415,6 +1552,52 @@ module Sequel
|
|
|
1415
1552
|
end
|
|
1416
1553
|
end
|
|
1417
1554
|
|
|
1555
|
+
def lateral_subquery_filter_limit_strategy_conditions(obj)
|
|
1556
|
+
_lateral_subquery_filter_limit_strategy_conditions(obj, lateral_subquery_filter_limit_strategy_conditions_key, right_primary_key_method, right_primary_key)
|
|
1557
|
+
end
|
|
1558
|
+
|
|
1559
|
+
def lateral_subquery_filter_limit_strategy_conditions_key
|
|
1560
|
+
self[:right_key]
|
|
1561
|
+
end
|
|
1562
|
+
|
|
1563
|
+
def lateral_subquery_filter_limit_strategy_filter_lateral_dataset(ds)
|
|
1564
|
+
ds.where(Array(filter_by_associations_conditions_key).zip(Array(filter_by_associations_conditions_associated_keys)))
|
|
1565
|
+
end
|
|
1566
|
+
|
|
1567
|
+
def lateral_subquery_filter_limit_strategy_filter_dataset(ds, obj)
|
|
1568
|
+
ds.where(filter_by_associations_conditions_key => ds.db.from(self[:join_table]).
|
|
1569
|
+
select(*self[:left_key]).
|
|
1570
|
+
where(lateral_subquery_filter_limit_strategy_conditions(obj)))
|
|
1571
|
+
end
|
|
1572
|
+
|
|
1573
|
+
def lateral_subquery_filter_limit_strategy_lateral_dataset_select
|
|
1574
|
+
qualify(self[:model].table_name, self[:left_primary_key])
|
|
1575
|
+
end
|
|
1576
|
+
|
|
1577
|
+
def lateral_subquery_eager_limit_strategy_lateral_dataset(ds, limit_and_offset)
|
|
1578
|
+
ds = super
|
|
1579
|
+
select = ds.opts[:select].dup
|
|
1580
|
+
left_key_alias = self[:left_key_alias]
|
|
1581
|
+
select.pop while (s = select.last).is_a?(Sequel::SQL::AliasedExpression) && (left_key_alias.is_a?(Array) ? left_key_alias.include?(s.alias) : s.alias == left_key_alias)
|
|
1582
|
+
ds = ds.clone(:select=>select)
|
|
1583
|
+
end
|
|
1584
|
+
|
|
1585
|
+
def apply_lateral_subquery_eager_limit_strategy(ds, ids, limit_and_offset)
|
|
1586
|
+
table_name = self[:model].table_name
|
|
1587
|
+
super.
|
|
1588
|
+
select_all(associated_class.table_name).
|
|
1589
|
+
select_append(*qualify(table_name, self[:left_primary_keys]).zip(Array(self[:left_key_alias])).map{|id, aliaz| Sequel.as(id, aliaz)}).
|
|
1590
|
+
where(qualify(table_name, self[:left_primary_key]) => ids)
|
|
1591
|
+
end
|
|
1592
|
+
|
|
1593
|
+
def apply_lateral_subquery_eager_graph_limit_strategy(ds)
|
|
1594
|
+
ds.
|
|
1595
|
+
limit(*limit_and_offset).
|
|
1596
|
+
where(qualify(join_table_alias, self[:left_keys]).zip(qualify(ds.opts[:eager_options][:implicit_qualifier], self[:left_primary_key_columns]))).
|
|
1597
|
+
order(*self[:order]).
|
|
1598
|
+
lateral
|
|
1599
|
+
end
|
|
1600
|
+
|
|
1418
1601
|
# Use the right_keys from the eager loading options if
|
|
1419
1602
|
# using a separate query per table.
|
|
1420
1603
|
def eager_loading_set_predicate_condition(ds, eo)
|
|
@@ -1707,6 +1890,9 @@ module Sequel
|
|
|
1707
1890
|
# record should be populated.
|
|
1708
1891
|
# :eager_loader_key :: A symbol for the key column to use to populate the key_hash
|
|
1709
1892
|
# for the eager loader. Can be set to nil to not populate the key_hash.
|
|
1893
|
+
# :eager_loading_predicate_transform :: A callable object with which to transform the predicate key values used
|
|
1894
|
+
# when eager loading. Called with two arguments, the array of predicate key
|
|
1895
|
+
# values, and a the reflection for the association being eager loaded.
|
|
1710
1896
|
# :extend :: A module or array of modules to extend the dataset with.
|
|
1711
1897
|
# :filter_limit_strategy :: Determines the strategy used for enforcing limits and offsets when filtering by
|
|
1712
1898
|
# limited associations. Possible options are :window_function, :distinct_on, or
|
|
@@ -1769,6 +1955,9 @@ module Sequel
|
|
|
1769
1955
|
# Set to nil to not define a setter method for the association.
|
|
1770
1956
|
# :subqueries_per_union :: The number of subqueries to use in each UNION query, for eager
|
|
1771
1957
|
# loading limited associations using the default :union strategy.
|
|
1958
|
+
# :use_placeholder_loader :: Whether to use a placeholder loader when eager loading the
|
|
1959
|
+
# association. Can be set to false to disable the use of a placeholder
|
|
1960
|
+
# loader if one would be used by default.
|
|
1772
1961
|
# :validate :: Set to false to not validate when implicitly saving any associated object.
|
|
1773
1962
|
# === :many_to_one
|
|
1774
1963
|
# :key :: foreign key in current model's table that references
|
|
@@ -1891,7 +2080,7 @@ module Sequel
|
|
|
1891
2080
|
raise(Error, "cannot clone an association to an association of different type (association #{name} with type #{type} cloning #{opts[:clone]} with type #{cloned_assoc[:type]})")
|
|
1892
2081
|
end
|
|
1893
2082
|
|
|
1894
|
-
opts[:use_placeholder_loader] = !opts[:instance_specific] && !opts[:eager_graph]
|
|
2083
|
+
opts[:use_placeholder_loader] = !opts[:instance_specific] && !opts[:eager_graph] unless opts.include?(:use_placeholder_loader)
|
|
1895
2084
|
opts[:eager_block] = opts[:block] unless opts.include?(:eager_block)
|
|
1896
2085
|
opts[:graph_join_type] ||= :left_outer
|
|
1897
2086
|
opts[:order_eager_graph] = true unless opts.include?(:order_eager_graph)
|
|
@@ -1914,6 +2103,8 @@ module Sequel
|
|
|
1914
2103
|
# Remove :class entry if it exists and is nil, to work with cached_fetch
|
|
1915
2104
|
opts.delete(:class) unless opts[:class]
|
|
1916
2105
|
|
|
2106
|
+
opts[:_hash] = [self, name].hash
|
|
2107
|
+
|
|
1917
2108
|
def_association(opts)
|
|
1918
2109
|
|
|
1919
2110
|
orig_opts.delete(:clone)
|
|
@@ -1983,6 +2174,7 @@ module Sequel
|
|
|
1983
2174
|
associate(:one_to_one, name, opts, &block)
|
|
1984
2175
|
end
|
|
1985
2176
|
|
|
2177
|
+
Plugins.model_instance_variables(self, :@associations, :@set_associated_object_if_same)
|
|
1986
2178
|
Plugins.inherited_instance_variables(self, :@association_reflections=>:dup, :@autoreloading_associations=>:hash_dup, :@default_association_options=>:dup, :@default_association_type_options=>:hash_dup, :@cache_associations=>nil, :@default_eager_limit_strategy=>nil)
|
|
1987
2179
|
Plugins.def_dataset_methods(self, [:eager, :eager_graph, :eager_graph_with_options, :association_join, :association_full_join, :association_inner_join, :association_left_join, :association_right_join])
|
|
1988
2180
|
|
|
@@ -2362,7 +2554,7 @@ module Sequel
|
|
|
2362
2554
|
delete_rn = opts.delete_row_number_column
|
|
2363
2555
|
|
|
2364
2556
|
eager_load_results(opts, eo) do |assoc_record|
|
|
2365
|
-
assoc_record.
|
|
2557
|
+
assoc_record.remove_key!(delete_rn) if delete_rn
|
|
2366
2558
|
hash_key = uses_cks ? km.map{|k| assoc_record.get_column_value(k)} : assoc_record.get_column_value(km)
|
|
2367
2559
|
objects = h[hash_key]
|
|
2368
2560
|
if assign_singular
|
|
@@ -2388,9 +2580,14 @@ module Sequel
|
|
|
2388
2580
|
conditions = opts[:graph_conditions]
|
|
2389
2581
|
opts[:cartesian_product_number] ||= one_to_one ? 0 : 1
|
|
2390
2582
|
graph_block = opts[:graph_block]
|
|
2583
|
+
graph_conditions = opts[:_graph_conditions] = use_only_conditions ? only_conditions : cks.zip(pkcs) + conditions
|
|
2391
2584
|
opts[:eager_grapher] ||= proc do |eo|
|
|
2392
2585
|
ds = eo[:self]
|
|
2393
|
-
|
|
2586
|
+
graph_limit_strategy = eo[:limit_strategy]
|
|
2587
|
+
egds = opts.apply_eager_graph_limit_strategy(graph_limit_strategy, eager_graph_dataset(opts, eo))
|
|
2588
|
+
graph_conditions_true = true if graph_limit_strategy == :lateral_subquery
|
|
2589
|
+
|
|
2590
|
+
ds = ds.graph(egds, graph_conditions_true || graph_conditions, eo.merge(:select=>select, :join_type=>eo[:join_type]||join_type, :qualify=>:deep), &graph_block)
|
|
2394
2591
|
# We only load reciprocals for one_to_many associations, as other reciprocals don't make sense
|
|
2395
2592
|
ds.opts[:eager_graph][:reciprocals][eo[:table_alias]] = opts.reciprocal
|
|
2396
2593
|
ds
|
|
@@ -2473,6 +2670,9 @@ module Sequel
|
|
|
2473
2670
|
# Return dataset to graph into given the association reflection, applying the :callback option if set.
|
|
2474
2671
|
def eager_graph_dataset(opts, eager_options)
|
|
2475
2672
|
ds = opts.associated_class.dataset
|
|
2673
|
+
if eager_options[:limit_strategy] == :lateral_subquery
|
|
2674
|
+
ds = ds.clone(:eager_options=>eager_options)
|
|
2675
|
+
end
|
|
2476
2676
|
if opts[:graph_use_association_block] && (b = opts[:block])
|
|
2477
2677
|
ds = b.call(ds)
|
|
2478
2678
|
end
|
|
@@ -3038,7 +3238,7 @@ module Sequel
|
|
|
3038
3238
|
if (((op == :'=' || op == :'!=') && r.is_a?(Sequel::Model)) ||
|
|
3039
3239
|
(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)})))))
|
|
3040
3240
|
l = args[0]
|
|
3041
|
-
if ar = model.
|
|
3241
|
+
if ar = model.association_reflection(l)
|
|
3042
3242
|
raise Error, "filtering by associations is not allowed for #{ar.inspect}" if ar[:allow_filtering_by] == false
|
|
3043
3243
|
|
|
3044
3244
|
if multiple
|
|
@@ -3519,7 +3719,7 @@ module Sequel
|
|
|
3519
3719
|
else
|
|
3520
3720
|
vals = Array(obj).reject{|o| !meths.all?{|m| o.get_column_value(m)}}
|
|
3521
3721
|
return SQL::Constants::FALSE if vals.empty?
|
|
3522
|
-
if obj.is_a?(Array)
|
|
3722
|
+
if obj.is_a?(Array) || obj.is_a?(Set)
|
|
3523
3723
|
if keys.length == 1
|
|
3524
3724
|
meth = meths.first
|
|
3525
3725
|
{keys.first=>vals.map{|o| o.get_column_value(meth)}}
|
|
@@ -3591,7 +3791,7 @@ module Sequel
|
|
|
3591
3791
|
|
|
3592
3792
|
# Prepare a hash loaders and eager options which will be used to implement the eager loading.
|
|
3593
3793
|
def prepare_eager_load(a, reflections, eager_assoc)
|
|
3594
|
-
eager_load_data = {}
|
|
3794
|
+
eager_load_data = {}.compare_by_identity
|
|
3595
3795
|
|
|
3596
3796
|
# Key is foreign/primary key name symbol.
|
|
3597
3797
|
# Value is hash with keys being foreign/primary key values (generally integers)
|