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

Commit bc44dff

Browse files
authored
Merge pull request #27 from GraphQLAcademy/graphql-batch-associations
Batch load :homeworld associations
2 parents b06212f + 665d65d commit bc44dff

File tree

4 files changed

+61
-3
lines changed

4 files changed

+61
-3
lines changed

app/models/graph.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ def find_by_id_field(type, model)
77
resolve ->(_, args, _) do
88
gid = GlobalID.parse(args[:id])
99

10+
return unless gid
1011
return unless gid.model_name == type.name
1112

1213
Graph::FindLoader.for(model).load(gid.model_id.to_i)
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# From: https://github.com/Shopify/graphql-batch/issues/24#issuecomment-277331157
2+
class Graph::AssociationLoader < GraphQL::Batch::Loader
3+
def self.validate(model, association_name)
4+
new(model, association_name)
5+
nil
6+
end
7+
8+
def initialize(model, association_name)
9+
@model = model
10+
@association_name = association_name
11+
validate
12+
end
13+
14+
def load(record)
15+
raise TypeError, "#{@model} loader can't load association for #{record.class}" unless record.is_a?(@model)
16+
return Promise.resolve(read_association(record)) if association_loaded?(record)
17+
super
18+
end
19+
20+
# We want to load the associations on all records, even if they have the same id
21+
def cache_key(record)
22+
record.object_id
23+
end
24+
25+
def perform(records)
26+
preload_association(records)
27+
records.each { |record| fulfill(record, read_association(record)) }
28+
end
29+
30+
private
31+
32+
def validate
33+
unless @model.reflect_on_association(@association_name)
34+
raise ArgumentError, "No association #{@association_name} on #{@model}"
35+
end
36+
end
37+
38+
def preload_association(records)
39+
::ActiveRecord::Associations::Preloader.new.preload(records, @association_name)
40+
end
41+
42+
def read_association(record)
43+
record.public_send(@association_name)
44+
end
45+
46+
def association_loaded?(record)
47+
record.association(@association_name).loaded?
48+
end
49+
end

app/models/graph/types/person.rb

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,17 @@ module Types
2222
"The eye color of this person. Will be \"unknown\" if not known or \"n/a\" if the person does not have an eye.",
2323
property: :eye_color
2424

25-
field :gender, GenderEnum, "The gender of this person."
25+
field :gender, GenderEnum, "The gender of this person."
2626
field :hairColor, types.String,
2727
"The hair color of this person. Will be \"unknown\" if not known or \"n/a\" if the person does not have hair.",
2828
property: :hair_color
2929

3030
field :height, types.Int, "The height of the person in centimeters."
31-
field :homeworld, Planet, "A planet that this person was born on or inhabits."
31+
field :homeworld, Planet, "A planet that this person was born on or inhabits." do
32+
resolve -> (person, _, _) do
33+
Graph::AssociationLoader.for(::Person, :homeworld).load(person)
34+
end
35+
end
3236
field :mass, types.Int, "The mass of the person in kilograms."
3337
field :name, !types.String, "The name of this person."
3438
field :skinColor, types.String, "The skin color of this person.", property: :skin_color

app/models/graph/types/species.rb

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,11 @@ module Types
5050
end
5151

5252
field :language, types.String, "The language commonly spoken by this species."
53-
field :homeworld, Graph::Types::Planet, "A planet that this species originates from type."
53+
field :homeworld, Planet, "A planet that this species originates from type." do
54+
resolve -> (species, _, _) do
55+
Graph::AssociationLoader.for(::Species, :homeworld).load(species)
56+
end
57+
end
5458
end
5559
end
5660
end

0 commit comments

Comments
 (0)