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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 21069cf0c93c8778043e7e9c6fc4e4e1276ca551
4
- data.tar.gz: cda365ce7b19852d7d8639344fba45c3ed0b5503
3
+ metadata.gz: 4efd1cd2ad74d644082dec208d0f59fee5c43973
4
+ data.tar.gz: 2c31b7d7c3f3661e54ec02103e622328f5c25a51
5
5
  SHA512:
6
- metadata.gz: cb9fe462db0cc0f6754e5b6e671123c4d1f9306b145a560f977dfaa4d5680e83344ff12fd7a89ef8e0d774e7523a4dd1c81fe546ce481725fcc505915e3e1405
7
- data.tar.gz: fec3348a276e523294f19b269b55fcd9914f7170ecd6c8bbe22813fc12f2daee76f49e581db749b0eefb2d22e37def7dc208a9c7b69207a90d7b181d206a19bb
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 implement an object that responds to `#object_from_id(global_id)` & `#type_from_object(object)`, then pass it to `GraphQL::Relay::Node.create(implementation)`. [Example](https://github.com/rmosolgo/graphql-relay-ruby/blob/120b750cf86f1eb5c9997b588f022b2ef3a0012c/spec/support/star_wars_schema.rb#L4-L15)
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
- Then, you can add global id fields to your types with `global_id_field` definition helper.
29
- [Example](https://github.com/rmosolgo/graphql-relay-ruby/blob/master/spec/support/star_wars_schema.rb#L29)
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
- [Example 1](https://github.com/rmosolgo/graphql-relay-ruby/blob/master/spec/support/star_wars_schema.rb#L39-L51), [Example 2](https://github.com/rmosolgo/graphql-relay-ruby/blob/master/spec/support/star_wars_schema.rb#L52-L58)
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/120b750cf86f1eb5c9997b588f022b2ef3a0012c/spec/support/star_wars_schema.rb#L74-L93)
64
- - Mount on mutation type: [example](https://github.com/rmosolgo/graphql-relay-ruby/blob/120b750cf86f1eb5c9997b588f022b2ef3a0012c/spec/support/star_wars_schema.rb#L111)
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
- - [ ] Fix `Node.create` -- make it return one object which exposes useful info
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/node'
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
- Node.to_global_id(type_name, obj.public_send(property))
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
@@ -1,5 +1,5 @@
1
1
  module GraphQL
2
2
  module Relay
3
- VERSION = '0.3.6'
3
+ VERSION = '0.4.0'
4
4
  end
5
5
  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" => GraphQL::Relay::Node.to_global_id("Ship", "9"),
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
- # Taken from graphql-relay-js
1
+ # Adapted from graphql-relay-js
2
2
  # https://github.com/graphql/graphql-relay-js/blob/master/src/__tests__/starWarsSchema.js
3
3
 
4
- class NodeImplementation
5
- def object_from_id(id)
6
- type_name, id = GraphQL::Relay::Node.from_global_id(id)
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
- def type_from_object(object)
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 [NodeInterface]
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 [NodeInterface]
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 [NodeInterface]
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: NodeField
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.3.6
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-08-27 00:00:00.000000000 Z
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.6'
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.6'
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
@@ -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