class Sequel::Model::Associations::AssociationReflection
AssociationReflection is a Hash subclass that keeps information on Sequel::Model associations. It provides methods to reduce internal code duplication. It should not be instantiated by the user.
Constants
- ASSOCIATION_DATASET_PROC
- FINALIZE_SETTINGS
-
Map of methods to cache keys used for finalizing associations.
Public Instance Methods
Source
# File lib/sequel/model/associations.rb 36 def _add_method 37 self[:_add_method] 38 end
Name symbol for the _add internal association method
Source
# File lib/sequel/model/associations.rb 41 def _remove_all_method 42 self[:_remove_all_method] 43 end
Name symbol for the _remove_all internal association method
Source
# File lib/sequel/model/associations.rb 46 def _remove_method 47 self[:_remove_method] 48 end
Name symbol for the _remove internal association method
Source
# File lib/sequel/model/associations.rb 51 def _setter_method 52 self[:_setter_method] 53 end
Name symbol for the _setter association method
Source
# File lib/sequel/model/associations.rb 56 def add_method 57 self[:add_method] 58 end
Name symbol for the add association method
Source
# File lib/sequel/model/associations.rb 84 def apply_dataset_changes(ds) 85 ds = ds.with_extend(AssociationDatasetMethods).clone(:association_reflection => self) 86 if exts = self[:reverse_extend] 87 ds = ds.with_extend(*exts) 88 end 89 ds = ds.select(*select) if select 90 if c = self[:conditions] 91 ds = (c.is_a?(Array) && !Sequel.condition_specifier?(c)) ? ds.where(*c) : ds.where(c) 92 end 93 ds = ds.order(*self[:order]) if self[:order] 94 ds = ds.limit(*self[:limit]) if self[:limit] 95 ds = ds.limit(1).skip_limit_check if limit_to_single_row? 96 ds = ds.eager(self[:eager]) if self[:eager] 97 ds = ds.distinct if self[:distinct] 98 ds 99 end
Apply all non-instance specific changes to the given dataset and return it.
Source
# File lib/sequel/model/associations.rb 140 def apply_distinct_on_eager_limit_strategy(ds) 141 keys = predicate_key 142 ds.distinct(*keys).order_prepend(*keys) 143 end
Use DISTINCT ON and ORDER BY clauses to limit the results to the first record with matching keys.
Source
# File lib/sequel/model/associations.rb 103 def apply_eager_dataset_changes(ds) 104 ds = apply_dataset_changes(ds) 105 if block = self[:eager_block] 106 ds = block.call(ds) 107 end 108 ds 109 end
Apply all non-instance specific changes and the eager_block option to the given dataset and return it.
Source
# File lib/sequel/model/associations.rb 113 def apply_eager_graph_limit_strategy(strategy, ds) 114 case strategy 115 when :lateral_subquery 116 apply_lateral_subquery_eager_graph_limit_strategy(ds) 117 when :distinct_on 118 apply_distinct_on_eager_limit_strategy(ds.order_prepend(*self[:order])) 119 when :window_function 120 apply_window_function_eager_limit_strategy(ds.order_prepend(*self[:order])).select(*ds.columns) 121 else 122 ds 123 end 124 end
Apply the eager graph limit strategy to the dataset to graph into the current dataset, or return the dataset unmodified if no SQL limit strategy is needed.
Source
# File lib/sequel/model/associations.rb 128 def apply_eager_limit_strategy(ds, strategy=eager_limit_strategy, limit_and_offset=limit_and_offset()) 129 case strategy 130 when :distinct_on 131 apply_distinct_on_eager_limit_strategy(ds) 132 when :window_function 133 apply_window_function_eager_limit_strategy(ds, limit_and_offset) 134 else 135 ds 136 end 137 end
Apply an eager limit strategy to the dataset, or return the dataset unmodified if it doesn’t need an eager limit strategy.
Source
# File lib/sequel/model/associations.rb 167 def apply_ruby_eager_limit_strategy(rows, limit_and_offset = limit_and_offset()) 168 name = self[:name] 169 return unless range = slice_range(limit_and_offset) 170 if returns_array? 171 rows.each{|o| o.associations[name] = o.associations[name][range] || []} 172 else 173 offset = range.begin 174 rows.each{|o| o.associations[name] = o.associations[name][offset]} 175 end 176 end
If the ruby eager limit strategy is being used, slice the array using the slice range to return the object(s) at the correct offset/limit.
Source
# File lib/sequel/model/associations.rb 146 def apply_window_function_eager_limit_strategy(ds, limit_and_offset=limit_and_offset()) 147 rn = ds.row_number_column 148 limit, offset = limit_and_offset 149 ds = ds.unordered.select_append{|o| o.row_number.function.over(:partition=>predicate_key, :order=>ds.opts[:order]).as(rn)}.from_self 150 ds = ds.order(rn) if ds.db.database_type == :mysql 151 ds = if !returns_array? 152 ds.where(rn => offset ? offset+1 : 1) 153 elsif offset 154 offset += 1 155 if limit 156 ds.where(rn => (offset...(offset+limit))) 157 else 158 ds.where{SQL::Identifier.new(rn) >= offset} 159 end 160 else 161 ds.where{SQL::Identifier.new(rn) <= limit} 162 end 163 end
Use a window function to limit the results of the eager loading dataset.
Source
# File lib/sequel/model/associations.rb 180 def assign_singular? 181 !returns_array? 182 end
Whether the associations cache should use an array when storing the associated records during eager loading.
Source
# File lib/sequel/model/associations.rb 66 def associated_class 67 cached_fetch(:class) do 68 begin 69 constantize(self[:class_name]) 70 rescue NameError => e 71 raise NameError, "#{e.message} (this happened when attempting to find the associated class for #{inspect})", e.backtrace 72 end 73 end 74 end
The class associated to the current model class via this association
Source
# File lib/sequel/model/associations.rb 79 def associated_dataset 80 cached_fetch(:_dataset){apply_dataset_changes(_associated_dataset)} 81 end
The dataset associated via this association, with the non-instance specific changes already applied. This will be a joined dataset if the association requires joining tables.
Source
# File lib/sequel/model/associations.rb 217 def association_dataset_for(object) 218 condition = if can_have_associated_objects?(object) 219 predicate_keys.zip(predicate_key_values(object)) 220 else 221 false 222 end 223 224 associated_dataset.where(condition) 225 end
Return an dataset that will load the appropriate associated objects for the given object using this association.
Source
# File lib/sequel/model/associations.rb 229 def association_dataset_proc 230 ASSOCIATION_DATASET_PROC 231 end
Proc used to create the association dataset method.
Source
# File lib/sequel/model/associations.rb 61 def association_method 62 self[:name] 63 end
Name symbol for association method, the same as the name of the association.
Source
# File lib/sequel/model/associations.rb 187 def can_have_associated_objects?(obj) 188 true 189 end
Whether this association can have associated objects, given the current object. Should be false if obj cannot have associated objects because the necessary key columns are NULL.
Source
# File lib/sequel/model/associations.rb 193 def cloneable?(ref) 194 ref[:type] == self[:type] 195 end
Whether you are able to clone from the given association type to the current association type, true by default only if the types match.
Source
# File lib/sequel/model/associations.rb 198 def dataset_method 199 self[:dataset_method] 200 end
Name symbol for the dataset association method
Source
# File lib/sequel/model/associations.rb 203 def dataset_need_primary_key? 204 true 205 end
Whether the dataset needs a primary key to function, true by default.
Source
# File lib/sequel/model/associations.rb 209 def delete_row_number_column(ds=associated_dataset) 210 if eager_limit_strategy == :window_function 211 ds.row_number_column 212 end 213 end
Return the symbol used for the row number column if the window function eager limit strategy is being used, or nil otherwise.
Source
# File lib/sequel/model/associations.rb 361 def eager_graph_lazy_dataset? 362 true 363 end
Whether to eagerly graph a lazy dataset, true by default. If this is false, the association won’t respect the :eager_graph option when loading the association for a single record.
Source
# File lib/sequel/model/associations.rb 234 def eager_graph_limit_strategy(strategy) 235 if self[:limit] || !returns_array? 236 strategy = strategy[self[:name]] if strategy.is_a?(Hash) 237 case strategy 238 when true 239 true_eager_graph_limit_strategy 240 when Symbol 241 strategy 242 else 243 if returns_array? || offset 244 :ruby 245 end 246 end 247 end 248 end
The eager_graph limit strategy to use for this dataset
Source
# File lib/sequel/model/associations.rb 251 def eager_limit_strategy 252 cached_fetch(:_eager_limit_strategy) do 253 if self[:limit] || !returns_array? 254 case s = cached_fetch(:eager_limit_strategy){default_eager_limit_strategy} 255 when true 256 true_eager_limit_strategy 257 else 258 s 259 end 260 end 261 end 262 end
The eager limit strategy to use for this dataset.
Source
# File lib/sequel/model/associations.rb 266 def eager_load_results(eo, &block) 267 rows = eo[:rows] 268 unless eo[:initialize_rows] == false 269 Sequel.synchronize_with(eo[:mutex]){initialize_association_cache(rows)} 270 end 271 if eo[:id_map] 272 ids = eo[:id_map].keys 273 return ids if ids.empty? 274 end 275 strategy = eager_limit_strategy 276 cascade = eo[:associations] 277 eager_limit = nil 278 279 if eo[:no_results] 280 no_results = true 281 elsif eo[:eager_block] || eo[:loader] == false || !use_placeholder_loader? 282 ds = eager_loading_dataset(eo) 283 284 strategy = ds.opts[:eager_limit_strategy] || strategy 285 286 eager_limit = 287 if el = ds.opts[:eager_limit] 288 raise Error, "The :eager_limit dataset option is not supported for associations returning a single record" unless returns_array? 289 strategy ||= true_eager_graph_limit_strategy 290 if el.is_a?(Array) 291 el 292 else 293 [el, nil] 294 end 295 else 296 limit_and_offset 297 end 298 299 strategy = true_eager_graph_limit_strategy if strategy == :union 300 # Correlated subqueries are not supported for regular eager loading 301 strategy = :ruby if strategy == :correlated_subquery 302 strategy = nil if strategy == :ruby && assign_singular? 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 309 310 if strategy == :window_function 311 delete_rn = ds.row_number_column 312 objects.each{|obj| obj.remove_key!(delete_rn)} 313 end 314 elsif strategy == :union 315 objects = [] 316 ds = associated_dataset 317 loader = union_eager_loader 318 joiner = " UNION ALL " 319 ids.each_slice(subqueries_per_union).each do |slice| 320 sql = loader.send(:sql_origin) 321 join = false 322 slice.each do |k| 323 if join 324 sql << joiner 325 else 326 join = true 327 end 328 loader.append_sql(sql, *k) 329 end 330 objects.concat(ds.with_sql(sql.freeze).to_a) 331 end 332 ds = ds.eager(cascade) if cascade 333 ds.send(:post_load, objects) 334 else 335 loader = placeholder_eager_loader 336 loader = loader.with_dataset{|dataset| dataset.eager(cascade)} if cascade 337 objects = loader.all(ids) 338 end 339 340 Sequel.synchronize_with(eo[:mutex]){objects.each(&block)} unless no_results 341 342 if strategy == :ruby 343 apply_ruby_eager_limit_strategy(rows, eager_limit || limit_and_offset) 344 end 345 end
Eager load the associated objects using the hash of eager options, yielding each row to the block.
Source
# File lib/sequel/model/associations.rb 348 def eager_loader_key 349 self[:eager_loader_key] 350 end
The key to use for the key hash when eager loading
Source
# File lib/sequel/model/associations.rb 354 def eager_loading_use_associated_key? 355 false 356 end
By default associations do not need to select a key in an associated table to eagerly load.
Source
# File lib/sequel/model/associations.rb 367 def filter_by_associations_add_conditions? 368 self[:conditions] || self[:eager_block] || self[:limit] 369 end
Whether additional conditions should be added when using the filter by associations support.
Source
# File lib/sequel/model/associations.rb 375 def filter_by_associations_conditions_expression(obj) 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 382 {filter_by_associations_conditions_key=>ds} 383 end
The expression to use for the additional conditions to be added for the filter by association support, when the association itself is filtered. Works by using a subquery to test that the objects passed also meet the association filter criteria.
Source
# File lib/sequel/model/associations.rb 388 def finalize 389 return unless cache = self[:cache] 390 391 finalizer = proc do |meth, key| 392 next if has_key?(key) 393 394 # Allow calling private methods to make sure caching is done appropriately 395 send(meth) 396 self[key] = cache.delete(key) if cache.has_key?(key) 397 end 398 399 finalize_settings.each(&finalizer) 400 401 unless self[:instance_specific] 402 finalizer.call(:associated_eager_dataset, :associated_eager_dataset) 403 finalizer.call(:filter_by_associations_conditions_dataset, :filter_by_associations_conditions_dataset) 404 end 405 406 nil 407 end
Finalize the association by first attempting to populate the thread-safe cache, and then transfering the thread-safe cache value to the association itself, so that a mutex is not needed to get the value.
Source
# File lib/sequel/model/associations.rb 419 def finalize_settings 420 FINALIZE_SETTINGS 421 end
Source
# File lib/sequel/model/associations.rb 425 def handle_silent_modification_failure? 426 false 427 end
Whether to handle silent modification failure when adding/removing associated records, false by default.
Source
# File lib/sequel/model/associations.rb 431 def hash 432 self[:_hash] 433 end
Hash value for the association reflection. This is precomputed to avoid concurrency issues at runtime.
Source
# File lib/sequel/model/associations.rb 436 def initialize_association_cache(objects) 437 name = self[:name] 438 if assign_singular? 439 objects.each{|object| object.associations[name] = nil} 440 else 441 objects.each{|object| object.associations[name] = []} 442 end 443 end
Initialize the associations cache for the current association for the given objects.
Source
# File lib/sequel/model/associations.rb 447 def inspect 448 o = self[:orig_opts].dup 449 o.delete(:class) 450 o.delete(:class_name) 451 o.delete(:block) unless o[:block] 452 o[:class] = self[:orig_class] if self[:orig_class] 453 454 "#<#{self.class} #{self[:model]}.#{self[:type]} #{self[:name].inspect}#{", #{o.inspect[1...-1]}" unless o.empty?}>" 455 end
Show which type of reflection this is, and a guess at what code was used to create the association.
Source
# File lib/sequel/model/associations.rb 458 def limit_and_offset 459 if (v = self[:limit]).is_a?(Array) 460 v 461 else 462 [v, nil] 463 end 464 end
The limit and offset for this association (returned as a two element array).
Source
# File lib/sequel/model/associations.rb 468 def need_associated_primary_key? 469 false 470 end
Whether the associated object needs a primary key to be added/removed, false by default.
Source
# File lib/sequel/model/associations.rb 474 def placeholder_loader 475 if use_placeholder_loader? 476 cached_fetch(:placeholder_loader) do 477 associated_dataset.placeholder_literalizer_loader do |pl, ds| 478 ds = ds.where(Sequel.&(*predicate_keys.map{|k| SQL::BooleanExpression.new(:'=', k, pl.arg)})) 479 if self[:block] 480 ds = self[:block].call(ds) 481 end 482 ds 483 end 484 end 485 end 486 end
A placeholder literalizer that can be used to lazily load the association. If one can’t be used, returns nil.
Source
# File lib/sequel/model/associations.rb 494 def predicate_key_values(object) 495 predicate_key_methods.map{|k| object.get_column_value(k)} 496 end
The values that predicate_keys should match for objects to be associated.
Source
# File lib/sequel/model/associations.rb 489 def predicate_keys 490 cached_fetch(:predicate_keys){Array(predicate_key)} 491 end
The keys to use for loading of the regular dataset, as an array.
Source
# File lib/sequel/model/associations.rb 499 def qualify(table, col) 500 transform(col) do |k| 501 case k 502 when Symbol, SQL::Identifier 503 SQL::QualifiedIdentifier.new(table, k) 504 else 505 Sequel::Qualifier.new(table).transform(k) 506 end 507 end 508 end
Qualify col with the given table name.
Source
# File lib/sequel/model/associations.rb 511 def qualify_assoc(col) 512 qualify(associated_class.table_name, col) 513 end
Qualify col with the associated model’s table name.
Source
# File lib/sequel/model/associations.rb 516 def qualify_cur(col) 517 qualify(self[:model].table_name, col) 518 end
Qualify col with the current model’s table name.
Source
# File lib/sequel/model/associations.rb 526 def reciprocal 527 cached_fetch(:reciprocal) do 528 possible_recips = [] 529 530 associated_class.all_association_reflections.each do |assoc_reflect| 531 if reciprocal_association?(assoc_reflect) 532 possible_recips << assoc_reflect 533 end 534 end 535 536 if possible_recips.length == 1 537 cached_set(:reciprocal_type, possible_recips.first[:type]) if ambiguous_reciprocal_type? 538 possible_recips.first[:name] 539 end 540 end 541 end
Returns the reciprocal association variable, if one exists. The reciprocal association is the association in the associated class that is the opposite of the current association. For example, Album.many_to_one :artist and Artist.one_to_many :albums are reciprocal associations. This information is to populate reciprocal associations. For example, when you do this_artist.add_album(album) it sets album.artist to this_artist.
Source
# File lib/sequel/model/associations.rb 545 def reciprocal_array? 546 true 547 end
Whether the reciprocal of this association returns an array of objects instead of a single object, true by default.
Source
# File lib/sequel/model/associations.rb 550 def remove_all_method 551 self[:remove_all_method] 552 end
Name symbol for the remove_all_ association method
Source
# File lib/sequel/model/associations.rb 556 def remove_before_destroy? 557 true 558 end
Whether associated objects need to be removed from the association before being destroyed in order to preserve referential integrity.
Source
# File lib/sequel/model/associations.rb 561 def remove_method 562 self[:remove_method] 563 end
Name symbol for the remove_ association method
Source
# File lib/sequel/model/associations.rb 566 def remove_should_check_existing? 567 false 568 end
Whether to check that an object to be disassociated is already associated to this object, false by default.
Source
# File lib/sequel/model/associations.rb 572 def returns_array? 573 true 574 end
Whether this association returns an array of objects instead of a single object, true by default.
Source
# File lib/sequel/model/associations.rb 577 def select 578 self[:select] 579 end
The columns to select when loading the association.
Source
# File lib/sequel/model/associations.rb 583 def set_reciprocal_to_self? 584 false 585 end
Whether to set the reciprocal association to self when loading associated records, false by default.
Source
# File lib/sequel/model/associations.rb 588 def setter_method 589 self[:setter_method] 590 end
Name symbol for the setter association method
Source
# File lib/sequel/model/associations.rb 593 def slice_range(limit_and_offset = limit_and_offset()) 594 limit, offset = limit_and_offset 595 if limit || offset 596 (offset||0)..(limit ? (offset||0)+limit-1 : -1) 597 end 598 end
The range used for slicing when using the :ruby eager limit strategy.
Private Instance Methods
Source
# File lib/sequel/model/associations.rb 623 def _associated_dataset 624 associated_class.dataset 625 end
The base dataset used for the association, before any order/conditions options have been applied.
Source
# File lib/sequel/model/associations.rb 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
Return an expression to filter the filter by associations dataset to only rows related to given objects.
Source
# File lib/sequel/model/associations.rb 629 def ambiguous_reciprocal_type? 630 false 631 end
Whether for the reciprocal type for the given association cannot be known in advantage, false by default.
Source
# File lib/sequel/model/associations.rb 649 def apply_filter_by_associations_distinct_on_limit_strategy(ds) 650 k = filter_by_associations_limit_key 651 ds.where(k=>apply_distinct_on_eager_limit_strategy(associated_eager_dataset.select(*k))) 652 end
Apply a distinct on eager limit strategy using IN with a subquery that uses DISTINCT ON to ensure only the first matching record for each key is included.
Source
# File lib/sequel/model/associations.rb 635 def apply_filter_by_associations_limit_strategy(ds) 636 case filter_by_associations_limit_strategy 637 when :distinct_on 638 apply_filter_by_associations_distinct_on_limit_strategy(ds) 639 when :window_function 640 apply_filter_by_associations_window_function_limit_strategy(ds) 641 else 642 ds 643 end 644 end
Apply a limit strategy to the given dataset so that filter by associations works with a limited dataset.
Source
# File lib/sequel/model/associations.rb 657 def apply_filter_by_associations_window_function_limit_strategy(ds) 658 ds.where(filter_by_associations_limit_key=>apply_window_function_eager_limit_strategy(associated_eager_dataset.select(*filter_by_associations_limit_alias_key)).select(*filter_by_associations_limit_aliases)) 659 end
Apply a distinct on eager limit strategy using IN with a subquery that uses a filter on the row_number window function to ensure that only rows inside the limit are returned.
Source
# File lib/sequel/model/associations.rb 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
Source
# File lib/sequel/model/associations.rb 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
Source
# File lib/sequel/model/associations.rb 662 def associated_eager_dataset 663 cached_fetch(:associated_eager_dataset) do 664 ds = associated_dataset.unlimited 665 if block = self[:eager_block] 666 ds = block.call(ds) 667 end 668 ds 669 end 670 end
The associated_dataset with the eager_block callback already applied.
Source
# File lib/sequel/model/associations.rb 606 def cached_fetch(key) 607 fetch(key) do 608 return yield unless h = self[:cache] 609 Sequel.synchronize{return h[key] if h.has_key?(key)} 610 value = yield 611 Sequel.synchronize{h[key] = value} 612 end 613 end
If the key exists in the reflection hash, return it. If the key doesn’t exist and association reflections are uncached, then yield to get the value. If the key doesn’t exist and association reflection are cached, check the cache and return the value if present, or yield to get the value, cache the value, and return it.
Source
# File lib/sequel/model/associations.rb 616 def cached_set(key, value) 617 return unless h = self[:cache] 618 Sequel.synchronize{h[key] = value} 619 end
Cache the value at the given key if caching.
Source
# File lib/sequel/model/associations.rb 699 def default_eager_limit_strategy 700 self[:model].default_eager_limit_strategy || :ruby 701 end
The default eager limit strategy to use for this association
Source
# File lib/sequel/model/associations.rb 674 def eager_loading_dataset(eo=OPTS) 675 ds = eo[:dataset] || associated_eager_dataset 676 ds = eager_loading_set_predicate_condition(ds, eo) 677 if associations = eo[:associations] 678 ds = ds.eager(associations) 679 end 680 if block = eo[:eager_block] 681 orig_ds = ds 682 ds = block.call(ds) 683 end 684 if eager_loading_use_associated_key? 685 ds = if ds.opts[:eager_graph] && !orig_ds.opts[:eager_graph] 686 block.call(orig_ds.select_append(*associated_key_array)) 687 else 688 ds.select_append(*associated_key_array) 689 end 690 end 691 if self[:eager_graph] 692 raise(Error, "cannot eagerly load a #{self[:type]} association that uses :eager_graph") if eager_loading_use_associated_key? 693 ds = ds.eager_graph(self[:eager_graph]) 694 end 695 ds 696 end
The dataset to use for eager loading associated objects for multiple current objects, given the hash passed to the eager loader.
Source
# File lib/sequel/model/associations.rb 713 def eager_loading_predicate_condition(keys) 714 if transform = self[:eager_loading_predicate_transform] 715 keys = transform.call(keys, self) 716 end 717 {predicate_key=>keys} 718 end
The predicate condition to use for the eager_loader.
Source
# File lib/sequel/model/associations.rb 705 def eager_loading_set_predicate_condition(ds, eo) 706 if id_map = eo[:id_map] 707 ds = ds.where(eager_loading_predicate_condition(id_map.keys)) 708 end 709 ds 710 end
Set the predicate condition for the eager loading dataset based on the id map in the eager loading options.
Source
# File lib/sequel/model/associations.rb 722 def filter_by_associations_add_conditions_dataset_filter(ds) 723 k = filter_by_associations_conditions_associated_keys 724 ds.select(*k).where(Sequel.negate(k.zip([]))) 725 end
Add conditions to the dataset to not include NULL values for the associated keys, and select those keys.
Source
# File lib/sequel/model/associations.rb 745 def filter_by_associations_conditions_dataset 746 cached_fetch(:filter_by_associations_conditions_dataset) do 747 ds = associated_eager_dataset.unordered 748 ds = filter_by_associations_add_conditions_dataset_filter(ds) 749 ds = apply_filter_by_associations_limit_strategy(ds) 750 ds 751 end 752 end
The base dataset to use for the filter by associations conditions subquery, regardless of the objects that are passed in as filter values.
Source
# File lib/sequel/model/associations.rb 730 def filter_by_associations_conditions_subquery_conditions(obj) 731 key = qualify(associated_class.table_name, associated_class.primary_key) 732 case obj 733 when Array 734 {key=>obj.map(&:pk)} 735 when Sequel::Dataset 736 {key=>obj.select(*Array(qualify(associated_class.table_name, associated_class.primary_key)))} 737 else 738 Array(key).zip(Array(obj.pk)) 739 end 740 end
The conditions to add to the filter by associations conditions subquery to restrict it to to the object(s) that was used as the filter value.
Source
# File lib/sequel/model/associations.rb 755 def filter_by_associations_limit_strategy 756 v = fetch(:filter_limit_strategy, self[:eager_limit_strategy]) 757 if v || self[:limit] || !returns_array? 758 case v ||= self[:model].default_eager_limit_strategy 759 when true, :union, :ruby 760 # Can't use a union or ruby-based strategy for filtering by associations, switch to default eager graph limit 761 # strategy. 762 true_eager_graph_limit_strategy 763 when Symbol 764 v 765 end 766 end 767 end
The strategy to use to filter by a limited association
Source
# File lib/sequel/model/associations.rb 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
Source
# File lib/sequel/model/associations.rb 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
Source
# File lib/sequel/model/associations.rb 825 def limit_to_single_row? 826 !returns_array? 827 end
Whether to limit the associated dataset to a single row.
Source
# File lib/sequel/model/associations.rb 830 def offset 831 limit_and_offset.last 832 end
Any offset to use for this association (or nil if there is no offset).
Source
# File lib/sequel/model/associations.rb 835 def placeholder_eager_loader 836 cached_fetch(:placeholder_eager_loader) do 837 eager_loading_dataset.placeholder_literalizer_loader do |pl, ds| 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 852 end 853 end 854 end
A placeholder literalizer used to speed up eager loading.
Source
# File lib/sequel/model/associations.rb 858 def possible_reciprocal_types 859 [reciprocal_type] 860 end
The reciprocal type as an array, should be overridden in reflection subclasses that have ambiguous reciprocal types.
Source
# File lib/sequel/model/associations.rb 864 def reciprocal_association?(assoc_reflect) 865 possible_reciprocal_types.include?(assoc_reflect[:type]) && 866 (begin; assoc_reflect.associated_class; rescue NameError; end) == self[:model] && 867 assoc_reflect[:conditions].nil? && 868 assoc_reflect[:block].nil? 869 end
Whether the given association reflection is possible reciprocal association for the current association reflection.
Source
# File lib/sequel/model/associations.rb 874 def subqueries_per_union 875 self[:subqueries_per_union] || 40 876 end
The number of subqueries to use in each union query, used to eagerly load limited associations. Defaults to 40, the optimal number depends on the latency between the database and the application.
Source
# File lib/sequel/model/associations.rb 880 def transform(s, &block) 881 s.is_a?(Array) ? s.map(&block) : (yield s) 882 end
If s is an array, map s over the block. Otherwise, just call the block with s.
Source
# File lib/sequel/model/associations.rb 898 def true_eager_graph_limit_strategy 899 if associated_class.dataset.supports_window_functions? 900 :window_function 901 else 902 :ruby 903 end 904 end
The eager_graph limit strategy used when true is given as the value, choosing the best strategy based on what the database supports.
Source
# File lib/sequel/model/associations.rb 886 def true_eager_limit_strategy 887 if self[:eager_graph] || (offset && !associated_dataset.supports_offsets_in_correlated_subqueries?) 888 # An SQL-based approach won't work if you are also eager graphing, 889 # so use a ruby based approach in that case. 890 :ruby 891 else 892 :union 893 end 894 end
What eager limit strategy should be used when true is given as the value, defaults to UNION as that is the fastest strategy if the appropriate keys are indexed.
Source
# File lib/sequel/model/associations.rb 908 def union_eager_loader 909 cached_fetch(:union_eager_loader) do 910 associated_dataset.placeholder_literalizer_loader do |pl, ds| 911 ds = self[:eager_block].call(ds) if self[:eager_block] 912 keys = predicate_keys 913 ds = ds.where(keys.map{pl.arg}.zip(keys)) 914 if eager_loading_use_associated_key? 915 ds = ds.select_append(*associated_key_array) 916 end 917 ds.from_self 918 end 919 end 920 end
A placeholder literalizer used to speed up the creation of union queries when eager loading a limited association.
Source
# File lib/sequel/model/associations.rb 923 def use_placeholder_loader? 924 self[:use_placeholder_loader] && _associated_dataset.supports_placeholder_literalizer? 925 end
Whether the placeholder loader can be used to load the association.