Skip to content

Commit

Permalink
fix: Support lazy objects (#17)
Browse files Browse the repository at this point in the history
* fix: Support lazy objects

- Adds field extension that supports lazy object resolution and type assignment
- Adds field extension to _entities field

* test: Scope lazy class

- Scopes lazy object class within let block
- Resolves other rubocop issues
  • Loading branch information
cmschuetz authored and noaelad committed Oct 12, 2019
1 parent 858d092 commit 68b0b9a
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 7 deletions.
10 changes: 3 additions & 7 deletions lib/apollo-federation/entities_field.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

require 'graphql'
require 'apollo-federation/any'
require 'apollo-federation/entity_type_resolution_extension'

module ApolloFederation
module EntitiesField
Expand All @@ -15,6 +16,7 @@ module ClassMethods
def define_entities_field(entity_type)
field(:_entities, [entity_type, null: true], null: false) do
argument :representations, [Any], required: true
extension(EntityTypeResolutionExtension)
end
end
end
Expand All @@ -38,13 +40,7 @@ def _entities(representations:)
result = reference
end

# TODO: This isn't 100% correct: if (for some reason) 2 different resolve_reference calls
# return the same object, it might not have the right type
# Right now, apollo-federation just adds a __typename property to the result,
# but I don't really like the idea of modifying the resolved object
context[result] = type
# TODO: Handle lazy objects?
result
[type, result]
end
end
end
Expand Down
18 changes: 18 additions & 0 deletions lib/apollo-federation/entity_type_resolution_extension.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# frozen_string_literal: true

class EntityTypeResolutionExtension < GraphQL::Schema::FieldExtension
def after_resolve(value:, context:, **_rest)
synced_value =
value.map do |type, result|
[type, context.query.schema.sync_lazy(result)]
end

# TODO: This isn't 100% correct: if (for some reason) 2 different resolve_reference calls
# return the same object, it might not have the right type
# Right now, apollo-federation just adds a __typename property to the result,
# but I don't really like the idea of modifying the resolved object
synced_value.each { |type, result| context[result] = type }

synced_value.map { |_, result| result }
end
end
43 changes: 43 additions & 0 deletions spec/apollo-federation/entities_field_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,49 @@ def self.resolve_reference(reference, _context)

it { is_expected.to match_array [{ 'id' => id.to_s, 'otherField' => 'more data' }] }
it { expect(errors).to be_nil }

context 'when resolve_reference returns a lazy object' do
let(:lazy_entity) do
Class.new do
def initialize(data)
@data = data
end

def load_entity
@data
end
end
end

let(:schema) do
lazy_entity_class = lazy_entity
type_with_key_class = type_with_key
Class.new(base_schema) do
lazy_resolve(lazy_entity_class, :load_entity)

orphan_types type_with_key_class
end
end

let(:type_with_key) do
lazy_entity_class = lazy_entity
Class.new(base_object) do
graphql_name 'TypeWithKey'
key fields: 'id'
field :id, 'ID', null: false
field :other_field, 'String', null: false

define_singleton_method :resolve_reference do |reference, _context|
if reference[:id] == 123
lazy_entity_class.new(id: 123, other_field: 'more data')
end
end
end
end

it { is_expected.to match_array [{ 'id' => id.to_s, 'otherField' => 'more data' }] }
it { expect(errors).to be_nil }
end
end
end
end
Expand Down

0 comments on commit 68b0b9a

Please sign in to comment.