graphql-decorate 0.1.1 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +2 -1
- data/graphql-decorate.gemspec +2 -2
- data/lib/graphql/decorate.rb +5 -1
- data/lib/graphql/decorate/configuration.rb +1 -0
- data/lib/graphql/decorate/connection.rb +52 -0
- data/lib/graphql/decorate/field_context.rb +18 -0
- data/lib/graphql/decorate/field_extension.rb +10 -7
- data/lib/graphql/decorate/field_integration.rb +8 -4
- data/lib/graphql/decorate/{resolution.rb → object.rb} +14 -15
- data/lib/graphql/decorate/object_integration.rb +1 -0
- data/lib/graphql/decorate/type_attributes.rb +11 -1
- data/lib/graphql/decorate/version.rb +2 -1
- metadata +7 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e23e910653e03c46982bf8916ab3f15cde1be96a6436cabbf0271c40a11f1b4d
|
4
|
+
data.tar.gz: d71940ac1feabb05b64228812ad1768f8f4f288e2ff105a619ee8cd02b00ce8a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 457e1cd6d2c62e5f463ccfacd8fa62f3e444c4b980d5e1d0b24b7b59aa960bcbf3c38cb0013055c793bafb3af86a5c0c2a68ae687b0c6af66de0b5b24b96d811
|
7
|
+
data.tar.gz: 678fb9bd85a0de6e6f0d336f2e812f91e1a326c7e3bff426159ff2bf2a83af5bc93bdf1b4ff490650f3a851f8d42b0370955d552bf57d22a47f183e8c2335462
|
data/README.md
CHANGED
@@ -131,7 +131,8 @@ end
|
|
131
131
|
### Collections
|
132
132
|
By default `graphql-decorate` recognizes `Array` and `ActiveRecord::Relation` object types and
|
133
133
|
decorates every element in the collection. If you have other collection types that should have
|
134
|
-
their elements decorated, you can add them in the configuration.
|
134
|
+
their elements decorated, you can add them in the configuration. Custom collection classes must
|
135
|
+
respond to `#map`.
|
135
136
|
```ruby
|
136
137
|
GraphQL::Decorate.configure do |config|
|
137
138
|
config.custom_collection_classes = [Mongoid::Relations::Targets::Enumerable]
|
data/graphql-decorate.gemspec
CHANGED
@@ -7,10 +7,10 @@ Gem::Specification.new do |spec|
|
|
7
7
|
spec.name = "graphql-decorate"
|
8
8
|
spec.version = GraphQL::Decorate::VERSION
|
9
9
|
spec.authors = ["Ben Brook"]
|
10
|
-
spec.email = ["
|
10
|
+
spec.email = ["bbrook154@gmail.com"]
|
11
11
|
|
12
12
|
spec.summary = 'A decorator integration for the GraphQL gem'
|
13
|
-
spec.homepage = 'https://
|
13
|
+
spec.homepage = 'https://www.github.com/TrueCar/graphql-decorate'
|
14
14
|
spec.license = "MIT"
|
15
15
|
|
16
16
|
# Specify which files should be added to the gem when it is released.
|
data/lib/graphql/decorate.rb
CHANGED
@@ -4,10 +4,14 @@ require_relative 'decorate/configuration'
|
|
4
4
|
require_relative 'decorate/object_integration'
|
5
5
|
require_relative 'decorate/field_integration'
|
6
6
|
require_relative 'decorate/field_extension'
|
7
|
-
require_relative 'decorate/
|
7
|
+
require_relative 'decorate/object'
|
8
8
|
require_relative 'decorate/type_attributes'
|
9
|
+
require_relative 'decorate/field_context'
|
10
|
+
require_relative 'decorate/connection'
|
9
11
|
|
12
|
+
# Matching the graphql-ruby namespace
|
10
13
|
module GraphQL
|
14
|
+
# Entry point for graphql-decorate. Handles configuration.
|
11
15
|
module Decorate
|
12
16
|
# @return [Configuration] Returns a new instance of GraphQL::Decorate::Configuration.
|
13
17
|
def self.configuration
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module GraphQL
|
3
|
+
module Decorate
|
4
|
+
# Wraps a GraphQL::Pagination::Connection object to decorate values after pagination is applied.
|
5
|
+
class Connection
|
6
|
+
# @return [GraphQL::Pagination::Connection] Connection being decorated
|
7
|
+
attr_reader :connection
|
8
|
+
|
9
|
+
# @return [GraphQL::Decorate::FieldContext] Current field context
|
10
|
+
attr_reader :field_context
|
11
|
+
|
12
|
+
def initialize(connection, field_context)
|
13
|
+
@connection = connection
|
14
|
+
@field_context = field_context
|
15
|
+
end
|
16
|
+
|
17
|
+
# @return [Array] Decorated nodes after pagination is applied
|
18
|
+
def nodes
|
19
|
+
nodes = @connection.nodes
|
20
|
+
nodes.map { |node| GraphQL::Decorate::Object.new(node, field_context).decorate }
|
21
|
+
end
|
22
|
+
|
23
|
+
# @see nodes
|
24
|
+
# @return [Array] Decorated nodes after pagination is applied
|
25
|
+
def edge_nodes
|
26
|
+
nodes
|
27
|
+
end
|
28
|
+
|
29
|
+
class << self
|
30
|
+
private
|
31
|
+
|
32
|
+
def method_missing(symbol, *args, &block)
|
33
|
+
@connection.class.send(symbol, *args, &block)
|
34
|
+
end
|
35
|
+
|
36
|
+
def respond_to_missing?(method, include_private = false)
|
37
|
+
@connection.class.respond_to_missing(method, include_private)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def method_missing(symbol, *args, &block)
|
44
|
+
@connection.send(symbol, *args, &block)
|
45
|
+
end
|
46
|
+
|
47
|
+
def respond_to_missing?(method, include_private = false)
|
48
|
+
@connection.respond_to_missing(method, include_private)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module GraphQL
|
3
|
+
module Decorate
|
4
|
+
# Wraps current GraphQL::Query::Context and options provided to a field for portability.
|
5
|
+
class FieldContext
|
6
|
+
# @return [GraphQL::Query::Context] Current GraphQL query context
|
7
|
+
attr_reader :context
|
8
|
+
|
9
|
+
# @return [Hash] Options provided to the field being decorated
|
10
|
+
attr_reader :options
|
11
|
+
|
12
|
+
def initialize(context, options)
|
13
|
+
@context = context
|
14
|
+
@options = options
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -1,19 +1,22 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
module GraphQL
|
3
3
|
module Decorate
|
4
|
+
# Extension run after fields are resolved to decorate their value.
|
4
5
|
class FieldExtension < GraphQL::Schema::FieldExtension
|
5
6
|
# Extension to be called after lazy loading.
|
6
7
|
# @param context [GraphQL::Query::Context] The current GraphQL query context.
|
7
8
|
# @param value [Object, GraphQL::Schema::Object] The object being decorated. Can be a schema object if the field hasn't been resolved yet.
|
8
|
-
# @return [Object] Decorated object.
|
9
|
+
# @return [::Object, GraphQL::Decorate::Connection] Decorated object.
|
9
10
|
def after_resolve(context:, value:, **_rest)
|
10
11
|
return if value.nil?
|
11
12
|
|
12
|
-
|
13
|
-
if
|
14
|
-
|
13
|
+
field_context = GraphQL::Decorate::FieldContext.new(context, options)
|
14
|
+
if value.is_a?(GraphQL::Pagination::Connection)
|
15
|
+
GraphQL::Decorate::Connection.new(value, field_context)
|
16
|
+
elsif collection_classes.any? { |c| value.is_a?(c) }
|
17
|
+
value.map { |item| decorate(item, field_context) }
|
15
18
|
else
|
16
|
-
decorate(value,
|
19
|
+
decorate(value, field_context)
|
17
20
|
end
|
18
21
|
end
|
19
22
|
|
@@ -25,8 +28,8 @@ module GraphQL
|
|
25
28
|
klasses
|
26
29
|
end
|
27
30
|
|
28
|
-
def decorate(object,
|
29
|
-
GraphQL::Decorate::
|
31
|
+
def decorate(object, field_context)
|
32
|
+
GraphQL::Decorate::Object.new(object, field_context).decorate
|
30
33
|
end
|
31
34
|
end
|
32
35
|
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
module GraphQL
|
2
2
|
module Decorate
|
3
|
+
# Extends default field behavior and adds extension to the field if it should be decorated.
|
3
4
|
module FieldIntegration
|
4
5
|
# Overridden field initializer
|
5
6
|
# @param type [GraphQL::Schema::Object] The type to add the extension to.
|
@@ -15,6 +16,8 @@ module GraphQL
|
|
15
16
|
|
16
17
|
def get_extension_options(type)
|
17
18
|
type_attributes = GraphQL::Decorate::TypeAttributes.new(type)
|
19
|
+
return unless type_attributes.decorator_class
|
20
|
+
|
18
21
|
{
|
19
22
|
decorator_class: type_attributes.decorator_class,
|
20
23
|
decorator_evaluator: type_attributes.decorator_evaluator,
|
@@ -24,10 +27,11 @@ module GraphQL
|
|
24
27
|
end
|
25
28
|
|
26
29
|
def extend_with_decorator(options)
|
27
|
-
|
28
|
-
|
29
|
-
@extensions.
|
30
|
-
@extensions.
|
30
|
+
extension(GraphQL::Decorate::FieldExtension, options)
|
31
|
+
# ext = GraphQL::Decorate::FieldExtension.new(field: self, options: options)
|
32
|
+
# @extensions = @extensions.dup
|
33
|
+
# @extensions.unshift(ext)
|
34
|
+
# @extensions.freeze
|
31
35
|
end
|
32
36
|
end
|
33
37
|
end
|
@@ -1,20 +1,19 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
module GraphQL
|
3
3
|
module Decorate
|
4
|
-
|
5
|
-
|
6
|
-
# @param
|
7
|
-
# @param
|
8
|
-
def initialize(object,
|
4
|
+
# Handles decorating an object given its current field context.
|
5
|
+
class Object
|
6
|
+
# @param object [Object] Object being decorated.
|
7
|
+
# @param field_context [GraphQL::Decorate::FieldContext] Current GraphQL field context and options.
|
8
|
+
def initialize(object, field_context)
|
9
9
|
@object = object
|
10
|
-
@
|
11
|
-
@extension_options = extension_options
|
10
|
+
@field_context = field_context
|
12
11
|
@default_decorator_context = { graphql: true }
|
13
12
|
end
|
14
13
|
|
15
14
|
# Resolve the object with decoration.
|
16
15
|
# @return [Object] Decorated object if possible, otherwise the original object.
|
17
|
-
def
|
16
|
+
def decorate
|
18
17
|
if decorator_class
|
19
18
|
GraphQL::Decorate.configuration.evaluate_decorator.call(decorator_class, object, decorator_context)
|
20
19
|
else
|
@@ -24,20 +23,20 @@ module GraphQL
|
|
24
23
|
|
25
24
|
private
|
26
25
|
|
27
|
-
attr_reader :object, :
|
26
|
+
attr_reader :object, :field_context, :default_decorator_context
|
28
27
|
|
29
28
|
def decorator_class
|
30
|
-
if
|
31
|
-
|
32
|
-
elsif
|
33
|
-
|
29
|
+
if field_context.options[:decorator_class]
|
30
|
+
field_context.options[:decorator_class]
|
31
|
+
elsif field_context.options[:decorator_evaluator]
|
32
|
+
field_context.options[:decorator_evaluator].call(object)
|
34
33
|
else
|
35
34
|
resolve_decorator_class
|
36
35
|
end
|
37
36
|
end
|
38
37
|
|
39
38
|
def decorator_context_evaluator
|
40
|
-
|
39
|
+
field_context.options[:decorator_context_evaluator] || resolve_decorator_context_evaluator
|
41
40
|
end
|
42
41
|
|
43
42
|
private
|
@@ -65,7 +64,7 @@ module GraphQL
|
|
65
64
|
end
|
66
65
|
|
67
66
|
def resolve_type
|
68
|
-
|
67
|
+
field_context.options[:unresolved_type]&.resolve_type(object, field_context.context)
|
69
68
|
end
|
70
69
|
end
|
71
70
|
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
module GraphQL
|
2
2
|
module Decorate
|
3
|
+
# Extends GraphQL::Schema::Object classes with methods to set the desired decorator class and context.
|
3
4
|
module ObjectIntegration
|
4
5
|
# Decorate the type with a decorator class.
|
5
6
|
# @param klass [Class] Class the object should be decorated with.
|
@@ -1,37 +1,47 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
module GraphQL
|
3
3
|
module Decorate
|
4
|
+
# Extracts configured decorator attributes from a GraphQL::Schema::Object type.
|
4
5
|
class TypeAttributes
|
6
|
+
# @return [GraphQL::Schema::Object] type to extract decorator attributes from
|
5
7
|
attr_reader :type
|
6
8
|
|
9
|
+
# @param [GraphQL::Schema::Object] type to extract decorator attributes from
|
7
10
|
def initialize(type)
|
8
11
|
@type = type
|
9
12
|
end
|
10
13
|
|
14
|
+
# @return [Class, nil] Decorator class for the type if available
|
11
15
|
def decorator_class
|
12
16
|
get_attribute(:decorator_class)
|
13
17
|
end
|
14
18
|
|
19
|
+
# @return [Proc, nil] Decorator evaluator for the type if available
|
15
20
|
def decorator_evaluator
|
16
21
|
get_attribute(:decorator_evaluator)
|
17
22
|
end
|
18
23
|
|
24
|
+
# @return [Proc, nil] Decorator context evaluator for the type if available
|
19
25
|
def decorator_context_evaluator
|
20
26
|
get_attribute(:decorator_context_evaluator)
|
21
27
|
end
|
22
28
|
|
29
|
+
# @return [GraphQL::Schema::Object, nil] Decorator evaluator for the type if available
|
23
30
|
def unresolved_type
|
24
31
|
unresolved_type? ? type : nil
|
25
32
|
end
|
26
33
|
|
34
|
+
# @return [Boolean] True if type is not yet resolved, false if it is resolved
|
27
35
|
def unresolved_type?
|
28
36
|
type.respond_to?(:resolve_type)
|
29
37
|
end
|
30
38
|
|
39
|
+
# @return [Boolean] True if type is resolved, false if it is not resolved
|
31
40
|
def resolved_type?
|
32
41
|
!unresolved_type?
|
33
42
|
end
|
34
43
|
|
44
|
+
# @return [Boolean] True if type is a connection, false if it is resolved
|
35
45
|
def connection?
|
36
46
|
resolved_type? && type.respond_to?(:node_type)
|
37
47
|
end
|
@@ -42,7 +52,7 @@ module GraphQL
|
|
42
52
|
if connection?
|
43
53
|
type.node_type.respond_to?(name) && type.node_type.public_send(name)
|
44
54
|
elsif resolved_type?
|
45
|
-
type.respond_to?(name)
|
55
|
+
type.respond_to?(name) ? type.public_send(name) : nil
|
46
56
|
end
|
47
57
|
end
|
48
58
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: graphql-decorate
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ben Brook
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-02-
|
11
|
+
date: 2021-02-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: graphql
|
@@ -74,7 +74,7 @@ dependencies:
|
|
74
74
|
version: '3.0'
|
75
75
|
description:
|
76
76
|
email:
|
77
|
-
-
|
77
|
+
- bbrook154@gmail.com
|
78
78
|
executables: []
|
79
79
|
extensions: []
|
80
80
|
extra_rdoc_files: []
|
@@ -91,13 +91,15 @@ files:
|
|
91
91
|
- graphql-decorate.gemspec
|
92
92
|
- lib/graphql/decorate.rb
|
93
93
|
- lib/graphql/decorate/configuration.rb
|
94
|
+
- lib/graphql/decorate/connection.rb
|
95
|
+
- lib/graphql/decorate/field_context.rb
|
94
96
|
- lib/graphql/decorate/field_extension.rb
|
95
97
|
- lib/graphql/decorate/field_integration.rb
|
98
|
+
- lib/graphql/decorate/object.rb
|
96
99
|
- lib/graphql/decorate/object_integration.rb
|
97
|
-
- lib/graphql/decorate/resolution.rb
|
98
100
|
- lib/graphql/decorate/type_attributes.rb
|
99
101
|
- lib/graphql/decorate/version.rb
|
100
|
-
homepage: https://
|
102
|
+
homepage: https://www.github.com/TrueCar/graphql-decorate
|
101
103
|
licenses:
|
102
104
|
- MIT
|
103
105
|
metadata: {}
|