graphql-relay 0.3.6 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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