graphql-relay 0.3.6 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +14 -8
- data/lib/graphql/relay.rb +1 -1
- data/lib/graphql/relay/global_id_field.rb +1 -1
- data/lib/graphql/relay/global_node_identification.rb +86 -0
- data/lib/graphql/relay/monkey_patches/definition_config.rb +10 -0
- data/lib/graphql/relay/version.rb +1 -1
- data/spec/graphql/relay/global_node_identification_spec.rb +36 -0
- data/spec/graphql/relay/mutation_spec.rb +1 -1
- data/spec/support/star_wars_schema.rb +15 -11
- metadata +7 -7
- data/lib/graphql/relay/node.rb +0 -64
- data/spec/graphql/relay/node_spec.rb +0 -26
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4efd1cd2ad74d644082dec208d0f59fee5c43973
|
4
|
+
data.tar.gz: 2c31b7d7c3f3661e54ec02103e622328f5c25a51
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7475507b89ca0adf9a061be156f06ce2a8ff96dc6b09a78f23cd1c796c862e8490feed2a0afa1a60802ded7d3384b7aedafd2a2f48a13990baafe18edc5b350d
|
7
|
+
data.tar.gz: 9c38cc95c267429b0047b1ee140307cef4e08bde2abe832eff76cc29e3e867b7d6b5bffad51459671bebfcec0093dbc1e6cef3f99eaeeb27e0f1d194aeb37bd1
|
data/README.md
CHANGED
@@ -23,10 +23,11 @@ bundle install
|
|
23
23
|
|
24
24
|
Global Ids provide refetching & global identification for Relay.
|
25
25
|
|
26
|
-
You should
|
26
|
+
You should create `GraphQL::Relay::GlobalNodeIdentification` helper by defining `object_from_id(global_id)` & `type_from_object(object)`. The resulting object provides ID resultion methods, a find-by-global-id field and a node interface. [Example](https://github.com/rmosolgo/graphql-relay-ruby/blob/master/spec/support/star_wars_schema.rb#L9-L18)
|
27
27
|
|
28
|
-
|
29
|
-
|
28
|
+
ObjectTypes should implement that interface with the `global_id_field` helper: [Example](https://github.com/rmosolgo/graphql-relay-ruby/blob/master/spec/support/star_wars_schema.rb#L30-L31)
|
29
|
+
|
30
|
+
You should attach the field to your query type: [Example](https://github.com/rmosolgo/graphql-relay-ruby/blob/master/spec/support/star_wars_schema.rb#L121)
|
30
31
|
|
31
32
|
### Connections
|
32
33
|
|
@@ -35,9 +36,13 @@ Connections will provide arguments, pagination and `pageInfo` for `Array`s or `A
|
|
35
36
|
Then, implement the field. It's different than a normal field:
|
36
37
|
- use the `connection` helper to define it, instead of `field`
|
37
38
|
- Call `#connection_type` on an `ObjectType` for the field's return type (eg, `ShipType.connection_type`)
|
38
|
-
- implement `resolve` to return an Array or an ActiveRecord::Relation, depending on the connection type.
|
39
39
|
|
40
|
-
|
40
|
+
Examples:
|
41
|
+
|
42
|
+
- [Connection with custom arguments](https://github.com/rmosolgo/graphql-relay-ruby/blob/master/spec/support/star_wars_schema.rb#L51-L63)
|
43
|
+
- [Connection with a different name than the underlying property](https://github.com/rmosolgo/graphql-relay-ruby/blob/master/spec/support/star_wars_schema.rb#L77)
|
44
|
+
|
45
|
+
You can also add custom fields to connection objects: [Example](https://github.com/rmosolgo/graphql-relay-ruby/blob/master/spec/support/star_wars_schema.rb#L36-L43)
|
41
46
|
|
42
47
|
### Mutations
|
43
48
|
|
@@ -60,14 +65,15 @@ The resolve proc:
|
|
60
65
|
- Must return a hash with keys matching your defined `return_field`s
|
61
66
|
|
62
67
|
Examples:
|
63
|
-
- Definition: [example](https://github.com/rmosolgo/graphql-relay-ruby/blob/
|
64
|
-
- Mount on mutation type: [example](https://github.com/rmosolgo/graphql-relay-ruby/blob/
|
68
|
+
- Definition: [example](https://github.com/rmosolgo/graphql-relay-ruby/blob/master/spec/support/star_wars_schema.rb#L90)
|
69
|
+
- Mount on mutation type: [example](https://github.com/rmosolgo/graphql-relay-ruby/blob/master/spec/support/star_wars_schema.rb#L127)
|
65
70
|
|
66
71
|
## Todo
|
67
72
|
|
68
|
-
-
|
73
|
+
- Show how to replace default connection implementations with custom ones
|
69
74
|
|
70
75
|
## More Resources
|
71
76
|
|
77
|
+
- [GraphQL Slack](graphql-slack.herokuapp.com), come join us in the `#ruby` channel!
|
72
78
|
- [`graphql`](https://github.com/rmosolgo/graphql-ruby) Ruby gem
|
73
79
|
- [`graphql-relay-js`](https://github.com/graphql/graphql-relay-js) JavaScript helpers for GraphQL and Relay
|
data/lib/graphql/relay.rb
CHANGED
@@ -4,7 +4,7 @@ require 'graphql'
|
|
4
4
|
require 'graphql/relay/monkey_patches/definition_config'
|
5
5
|
require 'graphql/relay/monkey_patches/object_type'
|
6
6
|
|
7
|
-
require 'graphql/relay/
|
7
|
+
require 'graphql/relay/global_node_identification'
|
8
8
|
require 'graphql/relay/page_info'
|
9
9
|
require 'graphql/relay/edge'
|
10
10
|
require 'graphql/relay/base_connection'
|
@@ -10,7 +10,7 @@ module GraphQL
|
|
10
10
|
self.arguments = {}
|
11
11
|
self.type = !GraphQL::ID_TYPE
|
12
12
|
self.resolve = -> (obj, args, ctx) {
|
13
|
-
|
13
|
+
GraphQL::Relay::GlobalNodeIdentification.to_global_id(type_name, obj.public_send(property))
|
14
14
|
}
|
15
15
|
end
|
16
16
|
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
module GraphQL
|
3
|
+
module Relay
|
4
|
+
# This object provides helpers for working with global IDs.
|
5
|
+
# It's assumed you'll only have 1!
|
6
|
+
# GlobalIdField depends on that, since it calls class methods
|
7
|
+
# which delegate to the singleton instance.
|
8
|
+
class GlobalNodeIdentification
|
9
|
+
include GraphQL::DefinitionHelpers::DefinedByConfig
|
10
|
+
defined_by_config :object_from_id_proc, :type_from_object_proc
|
11
|
+
attr_accessor :object_from_id_proc, :type_from_object_proc
|
12
|
+
|
13
|
+
class << self
|
14
|
+
def new(*args, &block)
|
15
|
+
if @instance.nil?
|
16
|
+
@instance = super
|
17
|
+
else
|
18
|
+
raise("Can't make a second global identifier!")
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def instance
|
23
|
+
@instance
|
24
|
+
end
|
25
|
+
|
26
|
+
def from_global_id(id)
|
27
|
+
@instance.from_global_id(id)
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_global_id(type_name, id)
|
31
|
+
@instance.to_global_id(type_name, id)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Returns `NodeInterface`, which all Relay types must implement
|
36
|
+
def interface
|
37
|
+
@interface ||= begin
|
38
|
+
ident = self
|
39
|
+
GraphQL::InterfaceType.define do
|
40
|
+
name "Node"
|
41
|
+
field :id, !types.ID
|
42
|
+
resolve_type -> (obj) {
|
43
|
+
ident.type_from_object(obj)
|
44
|
+
}
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Returns a field for finding objects from a global ID, which Relay needs
|
50
|
+
def field
|
51
|
+
ident = self
|
52
|
+
GraphQL::Field.define do
|
53
|
+
type(ident.interface)
|
54
|
+
argument :id, !types.ID
|
55
|
+
resolve -> (obj, args, ctx) {
|
56
|
+
ident.object_from_id(args[:id])
|
57
|
+
}
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Create a global ID for type-name & ID
|
62
|
+
# (This is an opaque transform)
|
63
|
+
def to_global_id(type_name, id)
|
64
|
+
Base64.strict_encode64("#{type_name}-#{id}")
|
65
|
+
end
|
66
|
+
|
67
|
+
# Get type-name & ID from global ID
|
68
|
+
# (This reverts the opaque transform)
|
69
|
+
def from_global_id(global_id)
|
70
|
+
Base64.decode64(global_id).split("-")
|
71
|
+
end
|
72
|
+
|
73
|
+
# Use the provided config to
|
74
|
+
# get a type for a given object
|
75
|
+
def type_from_object(object)
|
76
|
+
@type_from_object_proc.call(object)
|
77
|
+
end
|
78
|
+
|
79
|
+
# Use the provided config to
|
80
|
+
# get an object from a UUID
|
81
|
+
def object_from_id(id)
|
82
|
+
@object_from_id_proc.call(id)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -38,4 +38,14 @@ class GraphQL::DefinitionHelpers::DefinedByConfig::DefinitionConfig
|
|
38
38
|
name || raise("You must define the type's name before creating a GlobalIdField")
|
39
39
|
field(field_name, field: GraphQL::Relay::GlobalIdField.new(name))
|
40
40
|
end
|
41
|
+
|
42
|
+
# Support GlobalNodeIdentification
|
43
|
+
attr_accessor :object_from_id_proc, :type_from_object_proc
|
44
|
+
def object_from_id(proc)
|
45
|
+
@object_from_id_proc = proc
|
46
|
+
end
|
47
|
+
|
48
|
+
def type_from_object(proc)
|
49
|
+
@type_from_object_proc = proc
|
50
|
+
end
|
41
51
|
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe GraphQL::Relay::GlobalNodeIdentification do
|
4
|
+
let(:node_identification) { NodeIdentification }
|
5
|
+
describe 'NodeField' do
|
6
|
+
it 'finds objects by id' do
|
7
|
+
global_id = node_identification.to_global_id("Ship", "1")
|
8
|
+
result = query(%|{node(id: "#{global_id}") { id, ... on Ship { name } }}|)
|
9
|
+
expected = {"data" => {
|
10
|
+
"node" => {
|
11
|
+
"id" => global_id,
|
12
|
+
"name" => "X-Wing"
|
13
|
+
}
|
14
|
+
}}
|
15
|
+
assert_equal(expected, result)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe 'to_global_id / from_global_id ' do
|
20
|
+
it 'Converts typename and ID to and from ID' do
|
21
|
+
global_id = node_identification.to_global_id("SomeType", "123")
|
22
|
+
type_name, id = node_identification.from_global_id(global_id)
|
23
|
+
assert_equal("SomeType", type_name)
|
24
|
+
assert_equal("123", id)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe 'making a second instance' do
|
29
|
+
it 'raises an error' do
|
30
|
+
err = assert_raises(RuntimeError) do
|
31
|
+
GraphQL::Relay::GlobalNodeIdentification.define {}
|
32
|
+
end
|
33
|
+
assert_includes(err.message, "Can't make a second")
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -25,7 +25,7 @@ describe GraphQL::Relay::Mutation do
|
|
25
25
|
"clientMutationId" => "1234",
|
26
26
|
"ship" => {
|
27
27
|
"name" => "Bagel",
|
28
|
-
"id" =>
|
28
|
+
"id" => NodeIdentification.to_global_id("Ship", "9"),
|
29
29
|
},
|
30
30
|
"faction" => {"name" => STAR_WARS_DATA["Faction"]["1"].name }
|
31
31
|
}
|
@@ -1,29 +1,33 @@
|
|
1
|
-
#
|
1
|
+
# Adapted from graphql-relay-js
|
2
2
|
# https://github.com/graphql/graphql-relay-js/blob/master/src/__tests__/starWarsSchema.js
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
# This object exposes helpers for working with global IDs:
|
5
|
+
# - global id creation & "decrypting"
|
6
|
+
# - a find-object-by-global ID field
|
7
|
+
# - an interface for Relay ObjectTypes to implement
|
8
|
+
# See global_node_identification.rb for the full API.
|
9
|
+
NodeIdentification = GraphQL::Relay::GlobalNodeIdentification.define do
|
10
|
+
object_from_id -> (id) do
|
11
|
+
type_name, id = NodeIdentification.from_global_id(id)
|
7
12
|
STAR_WARS_DATA[type_name][id]
|
8
13
|
end
|
9
14
|
|
10
|
-
|
15
|
+
type_from_object -> (object) do
|
11
16
|
STAR_WARS_DATA["Faction"].values.include?(object) ? Faction : Ship
|
12
17
|
end
|
13
18
|
end
|
14
19
|
|
15
|
-
NodeInterface, NodeField = GraphQL::Relay::Node.create(NodeImplementation.new)
|
16
|
-
|
17
20
|
Ship = GraphQL::ObjectType.define do
|
18
21
|
name "Ship"
|
19
|
-
interfaces [
|
22
|
+
interfaces [NodeIdentification.interface]
|
23
|
+
# Explict alternative to `global_id_field` helper:
|
20
24
|
field :id, field: GraphQL::Relay::GlobalIdField.new("Ship")
|
21
25
|
field :name, types.String
|
22
26
|
end
|
23
27
|
|
24
28
|
BaseType = GraphQL::ObjectType.define do
|
25
29
|
name "Base"
|
26
|
-
interfaces [
|
30
|
+
interfaces [NodeIdentification.interface]
|
27
31
|
global_id_field :id
|
28
32
|
field :name, types.String
|
29
33
|
field :planet, types.String
|
@@ -41,7 +45,7 @@ end
|
|
41
45
|
|
42
46
|
Faction = GraphQL::ObjectType.define do
|
43
47
|
name "Faction"
|
44
|
-
interfaces [
|
48
|
+
interfaces [NodeIdentification.interface]
|
45
49
|
field :id, field: GraphQL::Relay::GlobalIdField.new("Faction")
|
46
50
|
field :name, types.String
|
47
51
|
connection :ships, Ship.connection_type do
|
@@ -114,7 +118,7 @@ QueryType = GraphQL::ObjectType.define do
|
|
114
118
|
resolve -> (obj, args, ctx) { STAR_WARS_DATA["Faction"]["2"]}
|
115
119
|
end
|
116
120
|
|
117
|
-
field :node, field:
|
121
|
+
field :node, field: NodeIdentification.field
|
118
122
|
end
|
119
123
|
|
120
124
|
MutationType = GraphQL::ObjectType.define do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: graphql-relay
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Robert Mosolgo
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-09-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: graphql
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '0.
|
19
|
+
version: '0.8'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '0.
|
26
|
+
version: '0.8'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: activerecord
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -192,16 +192,16 @@ files:
|
|
192
192
|
- lib/graphql/relay/base_connection.rb
|
193
193
|
- lib/graphql/relay/edge.rb
|
194
194
|
- lib/graphql/relay/global_id_field.rb
|
195
|
+
- lib/graphql/relay/global_node_identification.rb
|
195
196
|
- lib/graphql/relay/monkey_patches/definition_config.rb
|
196
197
|
- lib/graphql/relay/monkey_patches/object_type.rb
|
197
198
|
- lib/graphql/relay/mutation.rb
|
198
|
-
- lib/graphql/relay/node.rb
|
199
199
|
- lib/graphql/relay/page_info.rb
|
200
200
|
- lib/graphql/relay/relation_connection.rb
|
201
201
|
- lib/graphql/relay/version.rb
|
202
202
|
- spec/graphql/relay/array_connection_spec.rb
|
203
|
+
- spec/graphql/relay/global_node_identification_spec.rb
|
203
204
|
- spec/graphql/relay/mutation_spec.rb
|
204
|
-
- spec/graphql/relay/node_spec.rb
|
205
205
|
- spec/graphql/relay/relation_connection_spec.rb
|
206
206
|
- spec/spec_helper.rb
|
207
207
|
- spec/support/star_wars_data.rb
|
@@ -232,8 +232,8 @@ specification_version: 4
|
|
232
232
|
summary: Relay helpers for GraphQL
|
233
233
|
test_files:
|
234
234
|
- spec/graphql/relay/array_connection_spec.rb
|
235
|
+
- spec/graphql/relay/global_node_identification_spec.rb
|
235
236
|
- spec/graphql/relay/mutation_spec.rb
|
236
|
-
- spec/graphql/relay/node_spec.rb
|
237
237
|
- spec/graphql/relay/relation_connection_spec.rb
|
238
238
|
- spec/spec_helper.rb
|
239
239
|
- spec/support/star_wars_data.rb
|
data/lib/graphql/relay/node.rb
DELETED
@@ -1,64 +0,0 @@
|
|
1
|
-
require 'singleton'
|
2
|
-
module GraphQL
|
3
|
-
module Relay
|
4
|
-
# To get a `NodeField` and `NodeInterface`,
|
5
|
-
# define an object that responds to:
|
6
|
-
# - object_from_id
|
7
|
-
# - type_from_object
|
8
|
-
# and pass it to `Node.create`
|
9
|
-
#
|
10
|
-
class Node
|
11
|
-
include Singleton
|
12
|
-
|
13
|
-
# Allows you to call methods on the class
|
14
|
-
def self.method_missing(method_name, *args, &block)
|
15
|
-
if instance.respond_to?(method_name)
|
16
|
-
instance.send(method_name, *args, &block)
|
17
|
-
else
|
18
|
-
super
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
# Return interface and field using implementation
|
23
|
-
def create(implementation)
|
24
|
-
interface = create_interface(implementation)
|
25
|
-
field = create_field(implementation, interface)
|
26
|
-
[interface, field]
|
27
|
-
end
|
28
|
-
|
29
|
-
# Create a global ID for type-name & ID
|
30
|
-
# (This is an opaque transform)
|
31
|
-
def to_global_id(type_name, id)
|
32
|
-
Base64.strict_encode64("#{type_name}-#{id}")
|
33
|
-
end
|
34
|
-
|
35
|
-
# Get type-name & ID from global ID
|
36
|
-
# (This reverts the opaque transform)
|
37
|
-
def from_global_id(global_id)
|
38
|
-
Base64.decode64(global_id).split("-")
|
39
|
-
end
|
40
|
-
|
41
|
-
private
|
42
|
-
|
43
|
-
def create_interface(implementation)
|
44
|
-
GraphQL::InterfaceType.define do
|
45
|
-
name "Node"
|
46
|
-
field :id, !types.ID
|
47
|
-
resolve_type -> (obj) {
|
48
|
-
implementation.type_from_object(obj)
|
49
|
-
}
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
def create_field(implementation, interface)
|
54
|
-
GraphQL::Field.define do
|
55
|
-
type(interface)
|
56
|
-
argument :id, !types.ID
|
57
|
-
resolve -> (obj, args, ctx) {
|
58
|
-
implementation.object_from_id(args[:id])
|
59
|
-
}
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|
@@ -1,26 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe GraphQL::Relay::Node do
|
4
|
-
describe 'NodeField' do
|
5
|
-
it 'finds objects by id' do
|
6
|
-
global_id = GraphQL::Relay::Node.to_global_id("Ship", "1")
|
7
|
-
result = query(%|{node(id: "#{global_id}") { id, ... on Ship { name } }}|)
|
8
|
-
expected = {"data" => {
|
9
|
-
"node" => {
|
10
|
-
"id" => global_id,
|
11
|
-
"name" => "X-Wing"
|
12
|
-
}
|
13
|
-
}}
|
14
|
-
assert_equal(expected, result)
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
describe 'to_global_id / from_global_id ' do
|
19
|
-
it 'Converts typename and ID to and from ID' do
|
20
|
-
global_id = GraphQL::Relay::Node.to_global_id("SomeType", "123")
|
21
|
-
type_name, id = GraphQL::Relay::Node.from_global_id(global_id)
|
22
|
-
assert_equal("SomeType", type_name)
|
23
|
-
assert_equal("123", id)
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|