From bd5ac050f9b439bee3f1b9cf3392220c6585a52c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Giroux?= Date: Sat, 11 Feb 2017 13:57:01 -0500 Subject: [PATCH 1/3] Node Interface --- Gemfile | 2 +- Gemfile.lock | 4 +-- app/models/graph/schema.rb | 10 +++++++ app/models/graph/types/film.rb | 4 ++- app/models/graph/types/person.rb | 4 ++- app/models/graph/types/planet.rb | 4 ++- app/models/graph/types/query.rb | 4 +++ app/models/graph/types/species.rb | 4 ++- app/models/graph/types/starship.rb | 4 +-- app/models/graph/types/vehicle.rb | 4 +-- test/controllers/graphql_controller_test.rb | 32 +++++++++++++++++---- 11 files changed, 59 insertions(+), 17 deletions(-) diff --git a/Gemfile b/Gemfile index 421edab..e6a1c5d 100644 --- a/Gemfile +++ b/Gemfile @@ -12,7 +12,7 @@ gem 'sqlite3' # Use Puma as the app server gem 'puma', '~> 3.0' # Use GraphQL! -gem 'graphql', '~> 1.4.2' +gem 'graphql', '~> 1.4.3' # GraphiQL Interface gem 'graphiql-rails', '~> 1.4.1' diff --git a/Gemfile.lock b/Gemfile.lock index 09d1e6c..cbbe84c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -49,7 +49,7 @@ GEM activesupport (>= 4.1.0) graphiql-rails (1.4.1) rails - graphql (1.4.2) + graphql (1.4.3) i18n (0.8.0) listen (3.0.8) rb-fsevent (~> 0.9, >= 0.9.4) @@ -130,7 +130,7 @@ PLATFORMS DEPENDENCIES byebug graphiql-rails (~> 1.4.1) - graphql (~> 1.4.2) + graphql (~> 1.4.3) listen (~> 3.0.5) puma (~> 3.0) rails (~> 5.0.1) diff --git a/app/models/graph/schema.rb b/app/models/graph/schema.rb index d851cd8..2466c2d 100644 --- a/app/models/graph/schema.rb +++ b/app/models/graph/schema.rb @@ -1,8 +1,18 @@ module Graph Schema = GraphQL::Schema.define do query Graph::Types::Query + resolve_type ->(obj, ctx) do Graph::Schema.types.values.find { |type| type.name == obj.class.name } end + + id_from_object ->(object, type_definition, query_ctx) { + URI::GID.build(app: GlobalID.app, model_name: type_definition.name, model_id: object.id) + } + + object_from_id ->(id, query_ctx) { + gid = GlobalID.parse(id) + Object.const_get(gid.model_name).find(gid.model_id) + } end end diff --git a/app/models/graph/types/film.rb b/app/models/graph/types/film.rb index 4c19fa3..049d8c1 100644 --- a/app/models/graph/types/film.rb +++ b/app/models/graph/types/film.rb @@ -4,7 +4,9 @@ module Types name "Film" description "A single film." - field :id, types.ID, "The ID of the Film." + interfaces [GraphQL::Relay::Node.interface] + + global_id_field :id field :title, types.String, "The title of this film" field :episodeID, types.Int, "The episode number of this film.", property: :episode_id diff --git a/app/models/graph/types/person.rb b/app/models/graph/types/person.rb index dea1d21..aa1e5a4 100644 --- a/app/models/graph/types/person.rb +++ b/app/models/graph/types/person.rb @@ -4,7 +4,9 @@ module Types name "Person" description "An individual person or character within the Star Wars universe." - field :id, types.ID, "The ID of the person." + interfaces [GraphQL::Relay::Node.interface] + + global_id_field :id field :birthYear, types.String, "The birth year of the person, using the in-universe standard of BBY or ABY"\ diff --git a/app/models/graph/types/planet.rb b/app/models/graph/types/planet.rb index 13502f6..283aff6 100644 --- a/app/models/graph/types/planet.rb +++ b/app/models/graph/types/planet.rb @@ -4,7 +4,9 @@ module Types name "Planet" description "A large mass, planet or planetoid in the Star Wars Universe, at the time of 0 ABY." - field :id, types.ID, "The ID of the person." + interfaces [GraphQL::Relay::Node.interface] + + global_id_field :id field :name, types.String, "The name of this planet." field :diameter, types.Int, "The diameter of this planet in kilometers." diff --git a/app/models/graph/types/query.rb b/app/models/graph/types/query.rb index b282721..ae1ebd6 100644 --- a/app/models/graph/types/query.rb +++ b/app/models/graph/types/query.rb @@ -4,6 +4,10 @@ module Types name "Query" description "The query root of this schema" + # Relay + 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']) } diff --git a/app/models/graph/types/species.rb b/app/models/graph/types/species.rb index 3ecac64..ec6acad 100644 --- a/app/models/graph/types/species.rb +++ b/app/models/graph/types/species.rb @@ -4,7 +4,9 @@ module Types name "Species" description "A type of person or character within the Star Wars Universe." - field :id, types.ID, "The ID of this species." + interfaces [GraphQL::Relay::Node.interface] + + global_id_field :id field :name, types.String, "The name of this species." field :classification, types.String, "The classification of this species, such as \"mammal\" or \"reptile\"." diff --git a/app/models/graph/types/starship.rb b/app/models/graph/types/starship.rb index 0b96e3e..5486fde 100644 --- a/app/models/graph/types/starship.rb +++ b/app/models/graph/types/starship.rb @@ -4,9 +4,9 @@ module Types name "Starship" description "A single transport craft that has hyperdrive capability." - interfaces [Graph::Types::TransportInterface] + interfaces [GraphQL::Relay::Node.interface, Graph::Types::TransportInterface] - field :id, types.ID, "The ID of this starship." + global_id_field :id # Starship Specific Fields diff --git a/app/models/graph/types/vehicle.rb b/app/models/graph/types/vehicle.rb index 1557bb9..d03944c 100644 --- a/app/models/graph/types/vehicle.rb +++ b/app/models/graph/types/vehicle.rb @@ -4,9 +4,9 @@ module Types name "Vehicle" description "A single transport craft that has hyperdrive capability." - interfaces [Graph::Types::TransportInterface] + interfaces [GraphQL::Relay::Node.interface, Graph::Types::TransportInterface] - field :id, types.ID, "The ID of this vehicle." + global_id_field :id # Vehicle Specific Fields diff --git a/test/controllers/graphql_controller_test.rb b/test/controllers/graphql_controller_test.rb index a6e2cfc..4d81ed0 100644 --- a/test/controllers/graphql_controller_test.rb +++ b/test/controllers/graphql_controller_test.rb @@ -13,7 +13,7 @@ class GraphQLControllerTest < ActionDispatch::IntegrationTest "homeworld" => { "name" => "Tatooine" }, - "id" => "242320449", + "id" => "gid://swapi/Person/242320449", "mass" => 77, "name" => "Luke Skywalker", "skinColor" => "fair", @@ -21,7 +21,7 @@ class GraphQLControllerTest < ActionDispatch::IntegrationTest "film" => { "director" => "George Lucas", "episodeID" => 4, - "id" => "846649883", + "id" => "gid://swapi/Film/846649883", "producers" => ["Gary Kurtz", "Rick McCallum"], "releaseDate" => "1977-05-25", "title" => "A New Hope" @@ -30,7 +30,7 @@ class GraphQLControllerTest < ActionDispatch::IntegrationTest "climate" => "temperate", "diameter" => 12500, "gravity" => "1 standard", - "id" => "688730903", + "id" => "gid://swapi/Planet/688730903", "name" => "Alderaan", "orbitalPeriod" => 364, "population" => 2000.0, @@ -46,13 +46,13 @@ class GraphQLControllerTest < ActionDispatch::IntegrationTest "eyeColors" => ["yellow", "red"], "hairColors" => ["n/a"], "homeworld" => { "name" => "Nal Hutta" }, - "id" => "299344798", + "id" => "gid://swapi/Species/299344798", "language" => "Huttese", "name" => "Hutt", "skinColors" => ["green", "brown", "tan"], }, "starship" => { - "id" => "113504200", + "id" => "gid://swapi/Starship/113504200", "name" => "Millennium Falcon", "model" => "YT-1300 light freighter", "MGLT" => 75, @@ -79,7 +79,7 @@ class GraphQLControllerTest < ActionDispatch::IntegrationTest "starshipClass" => "Light freighter" }, "vehicle" => { - "id" => "82948950", + "id" => "gid://swapi/Vehicle/82948950", "name" => "Snowspeeder", "model" => "t-47 airspeeder", "cargoCapacity" => 10.0, @@ -105,6 +105,26 @@ class GraphQLControllerTest < ActionDispatch::IntegrationTest assert_equal expected, JSON.parse(response.body) end + test '#execute can execute node queries' do + starship = starships(:"millennium-falcon") + + query = " + query { + node(id: \"#{starship.to_global_id.to_s}\") { + ... on Starship { + name + } + } + } + " + + expected = { "data" => { "node" => { "name" => "Millennium Falcon" } } } + + post graphql_url, params: { query: query } + + assert_equal expected, JSON.parse(response.body) + end + private def full_graphql_query From a195236eb4a38896ca9ea65c5f62d4954e003c2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Giroux?= Date: Sat, 11 Feb 2017 14:25:29 -0500 Subject: [PATCH 2/3] policial :troll: --- app/models/graph/schema.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/models/graph/schema.rb b/app/models/graph/schema.rb index 2466c2d..a2c337e 100644 --- a/app/models/graph/schema.rb +++ b/app/models/graph/schema.rb @@ -6,13 +6,13 @@ module Graph Graph::Schema.types.values.find { |type| type.name == obj.class.name } end - id_from_object ->(object, type_definition, query_ctx) { + id_from_object ->(object, type_definition, query_ctx) do URI::GID.build(app: GlobalID.app, model_name: type_definition.name, model_id: object.id) - } + end - object_from_id ->(id, query_ctx) { + object_from_id ->(id, query_ctx) do gid = GlobalID.parse(id) Object.const_get(gid.model_name).find(gid.model_id) - } + end end end From 715401bbda0890e610b0fa85d51bc9a87d00b3b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Giroux?= Date: Sat, 11 Feb 2017 15:36:45 -0500 Subject: [PATCH 3/3] Check if possible type in object from id --- app/models/graph/schema.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/models/graph/schema.rb b/app/models/graph/schema.rb index a2c337e..80a672f 100644 --- a/app/models/graph/schema.rb +++ b/app/models/graph/schema.rb @@ -12,6 +12,11 @@ module Graph object_from_id ->(id, query_ctx) do gid = GlobalID.parse(id) + possible_types = query_ctx.warden.possible_types(GraphQL::Relay::Node.interface) + + return unless possible_types.map(&:name).include?(gid.model_name) + return unless gid.app == GlobalID.app + Object.const_get(gid.model_name).find(gid.model_id) end end