Skip to content
This repository has been archived by the owner on Sep 24, 2019. It is now read-only.

Commit

Permalink
Use GraphQL Batch for find by id fields
Browse files Browse the repository at this point in the history
  • Loading branch information
cjoudrey committed Feb 12, 2017
1 parent 7e66c35 commit 1857ed2
Show file tree
Hide file tree
Showing 8 changed files with 56 additions and 41 deletions.
7 changes: 5 additions & 2 deletions Gemfile
Expand Up @@ -7,12 +7,11 @@ end

# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '~> 5.0.1'
# use PG in prod for heroku
gem 'pg'
# Use Puma as the app server
gem 'puma', '~> 3.0'
# Use GraphQL!
gem 'graphql', '~> 1.4.3'
gem 'graphql-batch'
# GraphiQL Interface
gem 'graphiql-rails', '~> 1.4.1'

Expand All @@ -24,6 +23,10 @@ group :development, :test do
gem 'sqlite3'
end

group :production do
gem 'pg'
end

group :development do
# Access an IRB console on exception pages or by using <%= console %> anywhere in the code.
gem 'web-console', '>= 3.3.0'
Expand Down
5 changes: 5 additions & 0 deletions Gemfile.lock
Expand Up @@ -51,6 +51,9 @@ GEM
graphiql-rails (1.4.1)
rails
graphql (1.4.3)
graphql-batch (0.3.1)
graphql (>= 0.8, < 2)
promise.rb (~> 0.7.2)
i18n (0.8.0)
json (2.0.2)
listen (3.0.8)
Expand All @@ -70,6 +73,7 @@ GEM
nokogiri (1.7.0.1)
mini_portile2 (~> 2.1.0)
pg (0.19.0)
promise.rb (0.7.2)
puma (3.7.0)
rack (2.0.1)
rack-test (0.6.3)
Expand Down Expand Up @@ -137,6 +141,7 @@ DEPENDENCIES
byebug
graphiql-rails (~> 1.4.1)
graphql (~> 1.4.3)
graphql-batch
listen (~> 3.0.5)
pg
puma (~> 3.0)
Expand Down
17 changes: 17 additions & 0 deletions app/models/graph.rb
@@ -0,0 +1,17 @@
module Graph
class << self
def find_by_id_field(type, model)
GraphQL::Field.define do
type type
argument :id, !types.ID
resolve ->(_, args, _) do
gid = GlobalID.parse(args[:id])

return unless gid.model_name == type.name

Graph::FindLoader.for(model).load(gid.model_id.to_i)
end
end
end
end
end
11 changes: 11 additions & 0 deletions app/models/graph/find_loader.rb
@@ -0,0 +1,11 @@
class Graph::FindLoader < GraphQL::Batch::Loader
def initialize(model)
@model = model
end

def perform(ids)
records = @model.where(id: ids.uniq)
records.each { |record| fulfill(record.id, record) }
ids.each { |id| fulfill(id, nil) unless fulfilled?(id) }
end
end
3 changes: 3 additions & 0 deletions app/models/graph/schema.rb
Expand Up @@ -19,5 +19,8 @@ module Graph

Object.const_get(gid.model_name).find(gid.model_id)
end

lazy_resolve(Promise, :sync)
instrument(:query, GraphQL::Batch::Setup)
end
end
36 changes: 6 additions & 30 deletions app/models/graph/types/query.rb
Expand Up @@ -8,56 +8,32 @@ module Types
field :node, GraphQL::Relay::Node.field
field :nodes, GraphQL::Relay::Node.plural_field

field :person, Graph::Types::Person do
argument :id, types.ID
resolve ->(_, args, _) { ::Person.find_by(id: args['id']) }
end

field :person, Graph.find_by_id_field(Graph::Types::Person, ::Person)
field :people, types[Graph::Types::Person] do
resolve ->(_, _, _) { ::Person.all }
end

field :planet, Graph::Types::Planet do
argument :id, types.ID
resolve ->(_, args, _) { ::Planet.find(args['id']) }
end

field :planet, Graph.find_by_id_field(Graph::Types::Planet, ::Planet)
field :planets, types[Graph::Types::Planet] do
resolve ->(_, _, _) { ::Planet.all }
end

field :film, Graph::Types::Film do
argument :id, types.ID
resolve ->(_, args, _) { ::Film.find(args['id']) }
end

field :film, Graph.find_by_id_field(Graph::Types::Film, ::Film)
field :films, types[Graph::Types::Film] do
resolve ->(_, _, _) { ::Film.all }
end

field :species, Graph::Types::Species do
argument :id, types.ID
resolve ->(_, args, _) { ::Species.find(args['id']) }
end

field :species, Graph.find_by_id_field(Graph::Types::Species, ::Species)
field :allSpecies, types[Graph::Types::Species] do
resolve ->(_, _, _) { ::Species.all }
end

field :starship, Graph::Types::Starship do
argument :id, types.ID
resolve ->(_, args, _) { ::Starship.find(args['id']) }
end

field :starship, Graph.find_by_id_field(Graph::Types::Starship, ::Starship)
field :starships, types[Graph::Types::Starship] do
resolve ->(_, _, _) { ::Starship.all }
end

field :vehicle, Graph::Types::Vehicle do
argument :id, types.ID
resolve ->(_, args, _) { ::Vehicle.find(args['id']) }
end

field :vehicle, Graph.find_by_id_field(Graph::Types::Vehicle, ::Vehicle)
field :vehicles, types[Graph::Types::Vehicle] do
resolve ->(_, _, _) { ::Vehicle.all }
end
Expand Down
4 changes: 2 additions & 2 deletions config/secrets.yml
@@ -1,8 +1,8 @@
development:
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
secret_key_base: secret-for-development-not-so-secret

test:
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
secret_key_base: secret-for-test-not-so-secret

production:
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
14 changes: 7 additions & 7 deletions test/controllers/graphql_controller_test.rb
Expand Up @@ -113,7 +113,7 @@ class GraphQLControllerTest < ActionDispatch::IntegrationTest

def full_graphql_query
"
query Full($personID: ID, $filmID: ID, $planetID: ID, $starshipID: ID, $speciesID: ID, $vehicleID: ID) {
query Full($personID: ID!, $filmID: ID!, $planetID: ID!, $starshipID: ID!, $speciesID: ID!, $vehicleID: ID!) {
person(id: $personID) {
birthYear
eyeColor
Expand Down Expand Up @@ -204,12 +204,12 @@ def default_variables
vehicle = vehicles(:snowspeeder)

{
"starshipID" => starship.id,
"personID" => person.id,
"filmID" => film.id,
"planetID" => planet.id,
"speciesID" => species.id,
"vehicleID" => vehicle.id
"starshipID" => starship.to_global_id,
"personID" => person.to_global_id,
"filmID" => film.to_global_id,
"planetID" => planet.to_global_id,
"speciesID" => species.to_global_id,
"vehicleID" => vehicle.to_global_id,
}
end
end

0 comments on commit 1857ed2

Please sign in to comment.