GraphqlLazyLoad

Lazy executor for activerecord associations and graphql gem.

Installation

GraphqlLazyLoad requires ActiveRecord >= 4.1.16 and Graphql >= 1.3.0. To use add this line to your application's Gemfile:

gem 'graphql_lazy_load', '~> 0.3.0'

Then run bundle install.

Or install it yourself as:

$ gem install graphql_lazy_load

Usage

To use, first add the executor (GraphqlLazyLoad::ActiveRecordRelation and/or GraphqlLazyLoad::Custom) to graphqls schema:

class MySchema < GraphQL::Schema
  mutation(Types::MutationType)
  query(Types::QueryType)

  lazy_resolve(GraphqlLazyLoad::ActiveRecordRelation, :result)
  lazy_resolve(GraphqlLazyLoad::Custom, :result)
end

Now you can start using it!

The easiest thing to do is to extend the object helper method in the Types::BaseObject (or where you want to use the methods):

module Types
  class BaseObject < GraphQL::Schema::Object
    extend GraphqlLazyLoad::ObjectHelper
  end
end

ActiveRecordRelation Syntax

field :field_name, Types::AssociationType, null: false
lazy_load_association(:field_name)

If the association does not match the field name you can pass it lazy_load_association(:field_name, association: :association_name)

Custom Syntax

field :field_name, Types::AssociationType, null: false
lazy_load_custom(:field_name, :id) do |field_name_ids|
  # return hash of field_name_id => association_name, ...
  AssociationName.where(id: ids).reduce({}) do |acc, value|
    acc[value.id] = value
    acc
  end
end

Examples

If you have two models Team which can have many Players. To lazy load players from teams do the following:

ActiveRecordRelation

module Types
  class TeamType < Types::BaseObject
    # extend GraphqlLazyLoad::ObjectHelper # uncomment if not extended in Types::BaseObject
    ...
    field :players, [Types::PlayerType], null: false
    lazy_load_association(:players)
  end
end

And to lazy load teams from players do the following:

module Types
  class PlayerType < Types::BaseObject
    ...
    field :team, Types::TeamType, null: false
    lazy_load_association(:team)
  end
end

Custom

module Types
  class TeamType < Types::BaseObject
    ...
    field :players, [Types::PlayerType], null: false
    lazy_load_custom(:players, :id) do |team_ids|
      # return a hash with key team_id => [player,...]
      Player.where(team_id: team_ids).group_by(&:team_id)
    end
  end
end

And to lazy load teams from players do the following:

module Types
  class PlayerType < Types::BaseObject
    ...
    field :team, Types::TeamType, null: false
    lazy_load_custom(:field_name, :team_id) do |team_ids|
      # return a hash with key team_id => team
      Team.where(id: team_ids).each_with_object({}) do |team, acc|
        acc[team.id] = team
      end
    end
  end
end

Scoping

The great thing is you can pass params. So for the example above if you want to allow sorting (or query, paging, etc) on player do the following.

ActiveRecordRelation

module Types
  class PlayerType < Types::BaseObject
    ...
    field :players, [Types::PlayerType], null: false do
      argument :order, String, required: false
    end
    lazy_load_association(:players) do |order: nil|
      scope = Player.all
      scope = scope.sort(order.underscore) if order
      scope
    end
  end
end

Custom

module Types
  class PlayerType < Types::BaseObject
    ...
    field :players, [Types::PlayerType], null: false do
      argument :order, String, required: false
    end
    lazy_load_custom(:players, :id) do |team_ids, order: nil|
      # return a hash with key team_id => [player,...]
      query = Player.where(team_id: team_ids)
      query = query.order(params[:order].underscore) if params[:order]
      query.group_by(&:team_id)
    end
  end
end

To test this out try the example app at graph_test

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/jonathongardner/graphql_lazy_load. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.

License

The gem is available as open source under the terms of the MIT License.

Code of Conduct

Everyone interacting in the GraphqlLazyLoad project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.