Socket
Book a DemoInstallSign in
Socket

graphql-sources

Package Overview
Dependencies
Maintainers
1
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

graphql-sources

1.5.4
bundlerRubygems
Version published
Maintainers
1
Created
Source

GraphQL::Sources

LICENSE RubyGems GitHub Yard CircleCI Maintainability Test Coverage

GraphQL::Sources is a set of predefined dataloader classes build to avoid common n-plus-one issues in a GraphQL schema with Ruby. It supports loading has_one, has_many, belongs_to, has_and_belongs_to_many, has_one_attached and has_many_attached associations.

Recent versions of graphql-ruby include built-in support for loading records and associations via the dataload_record and dataload_association methods. These serve as a suitable alternative to some of the methods of loading provided by this library.

Installation

Install the gem and add to the application's Gemfile by executing:

$ bundle add graphql-sources

If bundler is not being used to manage dependencies, install the gem by executing:

$ gem install graphql-sources

The GraphQL::Dataloader plugin must be installed in the schema:

class AppSchema < GraphQL::Schema
  use GraphQL::Dataloader
  # ...
end

Usage

Loading belongs_to / has_many Associations

class Purchase < ActiveRecord::Base
  belongs_to :customer
end
class Customer < ActiveRecord::Base
  has_many :purchases
end
class PurchaseType < GraphQL::Schema::Object
  field :customer, CustomerType, null: false

  # @return [Customer]
  def customer
    # SELECT * FROM "customers" WHERE "customers"."id" IN (...)
    dataloader
      .with(GraphQL::Sources::ActiveRecordAssociation, :customer)
      .load(object)
  end
end
class CustomerType < GraphQL::Schema::Object
  field :purchases, [PurchaseType], null: false

  def purchases
    # SELECT * FROM "customers" WHERE "customers"."id" IN (...)
    dataloader
      .with(GraphQL::Sources::ActiveRecordAssociation, :purchases)
      .load(object)
  end
end

Loading belongs_to / has_one Associations

class Profile < ActiveRecord::Base
  belongs_to :user
end
class User < ActiveRecord::Base
  has_one :profile
end
class ProfileType < GraphQL::Schema::Object
  field :user, [UserType], null: false

  # @return [User]
  def user
    # SELECT * FROM "users" WHERE "users"."id" IN (...)
    dataloader
      .with(GraphQL::Sources::ActiveRecordAssociation, :user)
      .load(object)
  end
end
class UserType < GraphQL::Schema::Object
  field :profile, [ProfileType], null: false

  # @return [Profile]
  def profile
      # SELECT * FROM "profiles" WHERE "profiles"."id" IN (...)
    dataloader
      .with(GraphQL::Sources::ActiveRecordAssociation, :profile)
      .load(object)
  end
end

Loading has_and_belongs_to_many Associations

class Student
  has_and_belongs_to_many :courses
end
class Course
  has_and_belongs_to_many :students
end
class StudentType < GraphQL::Schema::Object
  field :courses, [CourseType], null: false

  # @return [Array<Course>]
  def courses
    # SELECT * FROM "courses_students" WHERE "courses_students"."student_id" = IN (...)
    # SELECT * FROM "courses" WHERE "courses"."id" IN (...)
    dataloader
      .with(GraphQL::Sources::ActiveRecordAssociation, :courses)
      .load(object)
  end
end
class CourseType < GraphQL::Schema::Object
  field :students, [StudentType], null: false

  # @return [Array<Student>]
  def students
    # SELECT * FROM "courses_students" WHERE "courses_students"."course_id" = IN (...)
    # SELECT * FROM "students" WHERE "students"."id" IN (...)
    dataloader
      .with(GraphQL::Sources::ActiveRecordAssociation, :students)
      .load(object)
  end
end

Loading has_one_attached Associations

class User
  has_one_attached :photo
end
class UserType < GraphQL::Schema::Object
  field :avatar, AttachedType, null: false

  # @return [ActiveStorage::Attachment]
  def avatar
    # SELECT "active_storage_attachments".*
    # FROM "active_storage_attachments"
    # WHERE "active_storage_attachments"."name" = 'avatar'
    #   AND "active_storage_attachments"."record_type" = 'User'
    #   AND "active_storage_attachments"."record_id" IN (...)
    dataloader
      .with(GraphQL::Sources::ActiveStorageHasOneAttached, :avatar)
      .load(object)
  end
end

Loading has_many_attached Associations

class User
  has_many_attached :photos
end
class UserType < GraphQL::Schema::Object
  field :photos, [AttachedType], null: false

  # @return [Array<ActiveStorage::Attachment>]
  def photos
    # SELECT "active_storage_attachments".*
    # FROM "active_storage_attachments"
    # WHERE "active_storage_attachments"."name" = 'photos'
    #   AND "active_storage_attachments"."record_type" = 'User'
    #   AND "active_storage_attachments"."record_id" IN (...)
    dataloader
      .with(GraphQL::Sources::ActiveStorageHasManyAttached, :photos)
      .load(object)
  end
end

Loading ActiveRecord Object / ActiveRecord Collection

class Event < ActiveRecord::Base
  belongs_to :device
end
class Device < ActiveRecord::Base
  has_many :events
end
class EventType < GraphQL::Schema::Object
  field :device, DeviceType, null: false

  # @return [Device]
  def device
    # SELECT * FROM "devices" WHERE "devices"."id" IN (...)
    dataloader
      .with(GraphQL::Sources::ActiveRecordObject, ::Device, key: :id)
      .load(object.device_id)
  end
end
class DeviceType < GraphQL::Schema::Object
  field :events, [EventType], null: false

  def events
    # SELECT * FROM "events" WHERE "events"."device_id" IN (...)
    dataloader
      .with(GraphQL::Sources::ActiveRecordCollection, ::Event, key: :device_id)
      .load(object)
  end
end

Loading Counts

class Like
  belongs_to :post
end
class Post
  has_many :likes
end
class PostType < GraphQL::Schema::Object
  field :likes, Integer, null: false

  def likes
    dataloader
      .with(GraphQL::Sources::ActiveRecordCount, ::Like, key: :post_id)
      .load(object.id)
  end
end
SELECT "likes"."post_id", COUNT(*)
FROM "likes"
WHERE "likes"."post_id" IN (1, 2, 3, ...)
GROUP BY "likes"."post_id"

Loading Exists

class User
  has_many :purchases
end
class Purchase
  belongs_to :product
  belongs_to :user
end
class Product
  has_many :purchases
end
class ProductType
  field :purchased, Boolean, null: false

  def purchased
    dataloader
      .with(GraphQL::Sources::ActiveRecordExists, ::Purchase.where(user: context.user), key: :product_id)
      .load(object.id)
  end
end

Loading with Rails.cache

class UserType < GraphQL::Schema::Object
  field :location, String, null: false

  def location
    dataloader
      .with(GraphQL::Sources::RailsCache)
      .load(key: "geocode:#{object.latest_ip}", fallback: -> { Geocode.for(object.latest_ip) })
  end
end

License

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

FAQs

Package last updated on 09 Jun 2025

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

About

Packages

Stay in touch

Get open source security insights delivered straight into your inbox.

  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc

U.S. Patent No. 12,346,443 & 12,314,394. Other pending.