Class: GraphQL::FancyLoader

Inherits:
Batch::Loader
  • Object
show all
Includes:
ActiveSupport::Configurable, DSL
Defined in:
lib/graphql/fancy_loader/version.rb,
lib/graphql/fancy_loader.rb,
lib/graphql/fancy_loader/dsl.rb,
lib/graphql/fancy_loader/type_generator.rb,
lib/graphql/fancy_loader/query_generator.rb,
lib/graphql/fancy_loader/pagination_filter.rb,
lib/graphql/fancy_loader/rank_query_generator.rb

Overview

HACK: This allows us to import the version number in the gemspec

Defined Under Namespace

Modules: DSL Classes: PaginationFilter, PunditMiddleware, QueryGenerator, RankQueryGenerator, TypeGenerator

Constant Summary collapse

VERSION =
'0.1.4'.freeze

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(find_by:, sort:, before: nil, after: 0, first: nil, last: nil, where: nil, context: {}) ⇒ FancyLoader

Initialize a FancyLoader. This takes all the keys which are used to batch, which is a lot of them. Thanks to the design of GraphQL, however, the frequently-called fields also tend to have the same parameters each time. This means that we can get away with this less-than-ideal batching and still have significant performance gains.

The pagination parameters have some odd interactions to be aware of! They are intersected, so if you pass before and after, you’re specifying after < row < before. That’s pretty logical, but first+last are weirder, because when combined they will return the middle, due to that intersection-driven logic. That is, given a set of 10 rows, first=6 & last=6 will return rows 4, 5, and 6 because they are the only ones in both sets. This isn’t a particularly useful behavior, but the Relay spec is pretty clear that you shouldn’t expect good results if you pass both first and last to the same field.

Parameters:

  • find_by (Symbol, String)

    the key to find by

  • before (Integer) (defaults to: nil)

    Filter by rows less than this

  • after (Integer) (defaults to: 0)

    Filter by rows greater than this

  • first (Integer) (defaults to: nil)

    Filter for first N rows

  • last (Integer) (defaults to: nil)

    Filter for last N rows

  • sort (Array<{:on, :direction => Symbol}>)

    The sorts to apply while loading



52
53
54
55
56
57
58
59
60
61
# File 'lib/graphql/fancy_loader.rb', line 52

def initialize(find_by:, sort:, before: nil, after: 0, first: nil, last: nil, where: nil, context: {})
  @find_by = find_by
  @sort = sort.map(&:to_h)
  @before = before
  @after = after
  @first = first
  @last = last
  @where = where
  @context = context
end

Class Method Details

.connection_for(args, key) ⇒ Object

Get a FancyConnection wrapping this Loader



29
30
31
# File 'lib/graphql/fancy_loader.rb', line 29

def self.connection_for(args, key)
  GraphQL::FancyConnection.new(self, args.except(:context), key, **args.slice(:context))
end

.sort_argumentObject

Get an autogenerated GraphQL type for an order input



24
25
26
# File 'lib/graphql/fancy_loader.rb', line 24

def self.sort_argument
  @sort_argument ||= GraphQL::FancyLoader::TypeGenerator.new(self).sorts_list
end

Instance Method Details

#perform(keys) ⇒ Object

Perform the loading. Uses QueryGenerator to build a query, then groups the results by the @find_by column, then fulfills all the Promises.



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/graphql/fancy_loader.rb', line 65

def perform(keys)
  query = QueryGenerator.new(
    model: model,
    find_by: @find_by,
    before: @before,
    after: @after,
    first: @first,
    last: @last,
    sort: sort,
    keys: keys,
    where: @where,
    context: @context,
    modify_query: modify_query_lambda
  ).query

  results = query.to_a.group_by { |rec| rec[@find_by] }
  keys.each do |key|
    fulfill(key, results[key] || [])
  end
end