Class: HQ::GraphQL::PaginatedAssociationLoader
- Inherits:
-
GraphQL::Batch::Loader
- Object
- GraphQL::Batch::Loader
- HQ::GraphQL::PaginatedAssociationLoader
- Defined in:
- lib/hq/graphql/paginated_association_loader.rb
Instance Method Summary collapse
- #cache_key(record) ⇒ Object
-
#initialize(model, association_name, limit: nil, offset: 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, limit: nil, offset: nil, sort_by: nil, sort_order: nil) ⇒ PaginatedAssociationLoader
Returns a new instance of PaginatedAssociationLoader.
6 7 8 9 10 11 12 13 14 15 |
# File 'lib/hq/graphql/paginated_association_loader.rb', line 6 def initialize(model, association_name, limit: nil, offset: nil, sort_by: nil, sort_order: nil) @model = model @association_name = association_name @limit = [0, limit].max if limit @offset = [0, offset].max if offset @sort_by = sort_by || :updated_at @sort_order = normalize_sort_order(sort_order) validate! end |
Instance Method Details
#cache_key(record) ⇒ Object
22 23 24 |
# File 'lib/hq/graphql/paginated_association_loader.rb', line 22 def cache_key(record) record.send(primary_key) end |
#load(record) ⇒ Object
17 18 19 20 |
# File 'lib/hq/graphql/paginated_association_loader.rb', line 17 def load(record) raise TypeError, "#{@model} loader can't load association for #{record.class}" unless record.is_a?(@model) super end |
#perform(records) ⇒ Object
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 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 |
# File 'lib/hq/graphql/paginated_association_loader.rb', line 26 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 |