Class: HQ::GraphQL::PaginatedAssociationLoader
- Inherits:
-
GraphQL::Batch::Loader
- Object
- GraphQL::Batch::Loader
- HQ::GraphQL::PaginatedAssociationLoader
- Defined in:
- lib/hq/graphql/paginated_association_loader.rb
Class Method Summary collapse
Instance Method Summary collapse
- #cache_key(record) ⇒ Object
-
#initialize(model, association_name, internal_association: false, limit: nil, offset: nil, scope: nil, sort_by: nil, sort_order: nil) ⇒ PaginatedAssociationLoader
constructor
A new instance of PaginatedAssociationLoader.
- #load(record) ⇒ Object
- #perform(records) ⇒ Object
Constructor Details
#initialize(model, association_name, internal_association: false, limit: nil, offset: nil, scope: nil, sort_by: nil, sort_order: nil) ⇒ PaginatedAssociationLoader
Returns a new instance of PaginatedAssociationLoader.
19 20 21 22 23 24 25 26 27 28 29 30 |
# File 'lib/hq/graphql/paginated_association_loader.rb', line 19 def initialize(model, association_name, internal_association: false, limit: nil, offset: nil, scope: nil, sort_by: nil, sort_order: nil) @model = model @association_name = association_name @internal_association = internal_association @limit = [0, limit].max if limit @offset = [0, offset].max if offset @scope = scope @sort_by = sort_by || :updated_at @sort_order = normalize_sort_order(sort_order) validate! end |
Class Method Details
.for(*args, scope: nil, **kwargs) ⇒ Object
8 9 10 11 12 13 14 15 16 17 |
# File 'lib/hq/graphql/paginated_association_loader.rb', line 8 def self.for(*args, scope: nil, **kwargs) if scope raise TypeError, "scope must be an ActiveRecord::Relation" unless scope.is_a?(::ActiveRecord::Relation) executor = ::GraphQL::Batch::Executor.current loader_key = loader_key_for(*args, **kwargs, scope: scope.to_sql) executor.loader(loader_key) { new(*args, **kwargs, scope: scope) } else super end end |
Instance Method Details
#cache_key(record) ⇒ Object
37 38 39 |
# File 'lib/hq/graphql/paginated_association_loader.rb', line 37 def cache_key(record) record.send(primary_key) end |
#load(record) ⇒ Object
32 33 34 35 |
# File 'lib/hq/graphql/paginated_association_loader.rb', line 32 def load(record) raise TypeError, "#{@model} loader can't load association for #{record.class}" unless record.is_a?(@model) super end |
#perform(records) ⇒ Object
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
# File 'lib/hq/graphql/paginated_association_loader.rb', line 41 def perform(records) scope = if @limit || @offset # If a limit or offset is added, then we need to transform the query # into a lateral join so that we can limit on groups of data. # # > SELECT * FROM addresses WHERE addresses.user_id IN ($1, $2, ..., $N) ORDER BY addresses.created_at DESC; # ...becomes # > SELECT DISTINCT a_top.* # > FROM addresses # > INNER JOIN LATERAL ( # > SELECT inner.* # > FROM addresses inner # > WHERE inner.user_id = addresses.user_id # > ORDER BY inner.created_at DESC # > LIMIT 1 # > ) a_top ON TRUE # > WHERE addresses.user_id IN ($1, $2, ..., $N) # > ORDER BY a_top.created_at DESC inner_table = association_class.arel_table association_table = inner_table.alias("outer") inside_scope = default_scope. select(inner_table[::Arel.star]). from(inner_table). where(inner_table[association_key].eq(association_table[association_key])). reorder(arel_order(inner_table)). limit(@limit). offset(@offset) outside_table = ::Arel::Table.new("top") association_class. select(outside_table[::Arel.star]).distinct. from(association_table). joins("INNER JOIN LATERAL (#{inside_scope.to_sql}) #{outside_table.name} ON TRUE"). where(association_table[association_key].in(records.map { |r| join_value(r) })). reorder(arel_order(outside_table)) else default_scope. reorder(arel_order(association_class.arel_table)). where(association_key => records.map { |r| join_value(r) }) end results = scope.to_a records.each do |record| fulfill(record, association_value(record, results)) unless fulfilled?(record) end end |