graphql-decorate 0.2.1 → 1.0.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 +4 -4
- data/.github/workflows/gem-push-on-release.yml +4 -3
- data/.github/workflows/ruby.yml +44 -0
- data/.rubocop.yml +14 -0
- data/Gemfile +4 -2
- data/README.md +51 -25
- data/Rakefile +5 -3
- data/bin/console +4 -3
- data/graphql-decorate.gemspec +25 -15
- data/lib/graphql/decorate.rb +6 -3
- data/lib/graphql/decorate/configuration.rb +4 -2
- data/lib/graphql/decorate/connection_wrapper.rb +68 -0
- data/lib/graphql/decorate/decoration.rb +34 -0
- data/lib/graphql/decorate/field_extension.rb +33 -11
- data/lib/graphql/decorate/field_integration.rb +4 -24
- data/lib/graphql/decorate/metadata.rb +29 -0
- data/lib/graphql/decorate/object_integration.rb +9 -19
- data/lib/graphql/decorate/type_attributes.rb +9 -3
- data/lib/graphql/decorate/undecorated_field.rb +102 -0
- data/lib/graphql/decorate/version.rb +3 -1
- metadata +65 -7
- data/.github/workflows/rspec.yml +0 -32
- data/lib/graphql/decorate/connection.rb +0 -52
- data/lib/graphql/decorate/field_context.rb +0 -18
- data/lib/graphql/decorate/object.rb +0 -71
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f51b30fb5841e235310b83ab3d9b697d86b420c1a807bb0500b73dcf231d295b
|
4
|
+
data.tar.gz: 4c02e6130d6955d6d9fbde06a9fe45352e1bd7f5dba7ec7e1d60c9bb846242c0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2aaa588eb463291941b8c4678daaaead6479b2526d9799998889186cccece07770cded6ec469108e2b92346317ab804fed0e7fd24acb80679251b2e0cb63dc43
|
7
|
+
data.tar.gz: 1c2a48487fd6b82739b501968578f039c89e7769db849daf955f152b72ec2e353b43790ea159400580f0e99f8b464c7a8f7cd98e11b7bd7a818ce42df7b2299f
|
@@ -11,10 +11,11 @@ jobs:
|
|
11
11
|
|
12
12
|
steps:
|
13
13
|
- uses: actions/checkout@v2
|
14
|
-
- name: Set up Ruby
|
15
|
-
uses:
|
14
|
+
- name: Set up Ruby
|
15
|
+
uses: ruby/setup-ruby@v1
|
16
16
|
with:
|
17
|
-
ruby-version: 2.6
|
17
|
+
ruby-version: 2.6
|
18
|
+
bundler-cache: true
|
18
19
|
|
19
20
|
- name: Verify version number matches
|
20
21
|
run: |
|
@@ -0,0 +1,44 @@
|
|
1
|
+
name: Ruby
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches: [ master ]
|
6
|
+
pull_request:
|
7
|
+
branches: [ master ]
|
8
|
+
|
9
|
+
jobs:
|
10
|
+
test:
|
11
|
+
runs-on: ubuntu-latest
|
12
|
+
strategy:
|
13
|
+
matrix:
|
14
|
+
ruby-version: ['2.6', '2.7', '3.0']
|
15
|
+
|
16
|
+
steps:
|
17
|
+
- uses: actions/checkout@v2
|
18
|
+
|
19
|
+
- name: Set up Ruby
|
20
|
+
uses: ruby/setup-ruby@v1
|
21
|
+
with:
|
22
|
+
ruby-version: ${{ matrix.ruby-version }}
|
23
|
+
bundler-cache: true
|
24
|
+
|
25
|
+
- name: Run tests
|
26
|
+
run: bundle exec rake
|
27
|
+
|
28
|
+
- name: Run RuboCop
|
29
|
+
run: bundle exec rubocop
|
30
|
+
|
31
|
+
- name: Upload coverage results
|
32
|
+
uses: actions/upload-artifact@master
|
33
|
+
with:
|
34
|
+
name: coverage-report
|
35
|
+
path: coverage
|
36
|
+
|
37
|
+
- name: Check documentation completion
|
38
|
+
run: |
|
39
|
+
completion_percentage=$(bundle exec yard | tee /dev/stdout | tail -1 | cut -d'%' -f1 | xargs)
|
40
|
+
echo $completion_percentage
|
41
|
+
if [[ $completion_percentage != "100.00" ]]; then
|
42
|
+
echo "YARD documentation must be at 100%"
|
43
|
+
exit 2;
|
44
|
+
fi
|
data/.rubocop.yml
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require:
|
2
|
+
rubocop-rspec
|
3
|
+
AllCops:
|
4
|
+
NewCops: enable
|
5
|
+
TargetRubyVersion: 2.6
|
6
|
+
SuggestExtensions: false
|
7
|
+
RSpec/FilePath:
|
8
|
+
CustomTransform:
|
9
|
+
GraphQL: graphql
|
10
|
+
Metrics/BlockLength:
|
11
|
+
Exclude:
|
12
|
+
- 'spec/**/*.rb'
|
13
|
+
RSpec/MessageSpies:
|
14
|
+
EnforcedStyle: receive
|
data/Gemfile
CHANGED
@@ -1,6 +1,8 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
source 'https://rubygems.org'
|
4
|
+
|
5
|
+
git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
|
4
6
|
|
5
7
|
# Specify your gem's dependencies in graphql-decorate.gemspec
|
6
8
|
gemspec
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# GraphQL Decorate
|
2
2
|
|
3
|
-
`graphql-decorate` adds an easy-to-use interface for decorating types in `graphql-ruby
|
3
|
+
`graphql-decorate` adds an easy-to-use interface for decorating types in [`graphql-ruby`](https://github.com/rmosolgo/graphql-ruby). It lets
|
4
4
|
you move logic out of your type files and keep them declarative.
|
5
5
|
|
6
6
|
## Installation
|
@@ -59,24 +59,28 @@ In this example, the `Rectangle` type is being decorated with a `RectangleDecora
|
|
59
59
|
`RectangleDecorator`. All of the methods on the decorator are accessible on the type.
|
60
60
|
|
61
61
|
### Decorators
|
62
|
-
By default, `graphql-decorate` is set up to work with
|
62
|
+
By default, `graphql-decorate` is set up to work with [`draper`](https://github.com/drapergem/draper) style decorators. These decorators
|
63
63
|
provide a `decorate` method that wraps the original object and returns an instance of the
|
64
|
-
decorator. They can also take in
|
64
|
+
decorator. They can also take in additional metadata.
|
65
65
|
```ruby
|
66
|
-
RectangleDecorator.decorate(rectangle, context)
|
66
|
+
RectangleDecorator.decorate(rectangle, context: metadata)
|
67
67
|
```
|
68
68
|
If you are using a different decorator pattern then you can override this default behavior in
|
69
69
|
the configuration.
|
70
70
|
```ruby
|
71
71
|
GraphQL::Decorate.configure do |config|
|
72
|
-
config.decorate do |decorator_class, object,
|
72
|
+
config.decorate do |decorator_class, object, _metadata|
|
73
73
|
decorator_class.decorate_differently(object)
|
74
74
|
end
|
75
75
|
end
|
76
76
|
```
|
77
77
|
|
78
78
|
### Types
|
79
|
-
|
79
|
+
Two methods are made available on your type classes: `decorate_with` and `decorate_metadata`.
|
80
|
+
Every method that yields the underlying object will also yield the current GraphQL `context`.
|
81
|
+
If decoration depends on some context in the current query then you can access it when the field
|
82
|
+
is resolved.
|
83
|
+
|
80
84
|
#### decorate_with
|
81
85
|
`decorate_with` accepts a decorator class that will decorate every instance of your type.
|
82
86
|
```ruby
|
@@ -85,12 +89,11 @@ class Rectangle < GraphQL::Schema::Object
|
|
85
89
|
end
|
86
90
|
```
|
87
91
|
|
88
|
-
|
89
|
-
`decorate_when` accepts a block which yields the underlying object. If you have multiple
|
92
|
+
`decorate_with` optionally accepts a block which yields the underlying object. If you have multiple
|
90
93
|
possible decorator classes you can return the one intended for the underling object.
|
91
94
|
```ruby
|
92
95
|
class Rectangle < GraphQL::Schema::Object
|
93
|
-
|
96
|
+
decorate_with do |object, _graphql_context|
|
94
97
|
if object.length == object.width
|
95
98
|
SquareDecorator
|
96
99
|
else
|
@@ -100,30 +103,50 @@ class Rectangle < GraphQL::Schema::Object
|
|
100
103
|
end
|
101
104
|
```
|
102
105
|
|
103
|
-
####
|
104
|
-
|
105
|
-
|
106
|
+
#### decorate_metadata
|
107
|
+
If your decorator pattern allows additional metadata to be passed into the decorators, you can
|
108
|
+
define it here. By default every metadata hash will contain `{ graphql: true }`. This is
|
109
|
+
useful if your decorator logic needs to diverge when used in a GraphQL context. Ideally your
|
110
|
+
decorators are agnostic to where they are being used, but it is available if needed.
|
111
|
+
|
112
|
+
`decorate_metadata` yields a `GraphQL::Decorate::Metadata` metadata instance. It responds to two
|
113
|
+
methods: `unscoped` and `scoped`. `unscoped` sets metadata for a resolved field. `scoped` sets
|
114
|
+
metadata for a resolved field and all of its child fields. `unscoped` and `scoped` are expected
|
115
|
+
to return `Hash`s.
|
116
|
+
|
106
117
|
```ruby
|
107
118
|
class Rectangle < GraphQL::Schema::Object
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
119
|
+
decorate_metadata do |metadata|
|
120
|
+
metadata.unscoped do |object, _graphql_context|
|
121
|
+
{
|
122
|
+
name: object.name
|
123
|
+
}
|
124
|
+
end
|
125
|
+
|
126
|
+
metadata.scoped do |object, _graphql_context|
|
127
|
+
{
|
128
|
+
inside_rectangle: true
|
129
|
+
}
|
130
|
+
end
|
112
131
|
end
|
113
132
|
end
|
114
133
|
```
|
115
|
-
`RectangleDecorator` will be initialized with
|
134
|
+
`RectangleDecorator` will be initialized with metadata `{ name: <object_name>,
|
135
|
+
inside_rectangle: true, graphql: true }`. All child fields of `Rectangle` will be initialized
|
136
|
+
with metadata `{ inside_rectangle: true, graphql: true }`.
|
116
137
|
|
117
138
|
#### Combinations
|
118
|
-
You can mix and match these methods to suit your needs. Note that if `
|
119
|
-
`
|
139
|
+
You can mix and match these methods to suit your needs. Note that if `unscoped` and
|
140
|
+
`scoped` are both provided for metadata that `scoped` will override any shared keys.
|
120
141
|
```ruby
|
121
142
|
class Rectangle < GraphQL::Schema::Object
|
122
143
|
decorate_with RectangleDecorator
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
144
|
+
decorate_metadata do |metadata|
|
145
|
+
metadata.scoped do |object, _graphql_context|
|
146
|
+
{
|
147
|
+
name: object.name
|
148
|
+
}
|
149
|
+
end
|
127
150
|
end
|
128
151
|
end
|
129
152
|
```
|
@@ -141,8 +164,11 @@ end
|
|
141
164
|
|
142
165
|
## Development
|
143
166
|
|
144
|
-
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to
|
167
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to
|
168
|
+
run the tests. You can also run `bin/console` for an interactive prompt that will allow you to
|
169
|
+
experiment.
|
145
170
|
|
146
171
|
## License
|
147
172
|
|
148
|
-
The gem is available as open source under the terms of the
|
173
|
+
The gem is available as open source under the terms of the
|
174
|
+
[MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
CHANGED
data/bin/console
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
|
-
require
|
4
|
-
require
|
4
|
+
require 'bundler/setup'
|
5
|
+
require 'graphql/decorate'
|
5
6
|
|
6
7
|
# You can add fixtures and/or initialization code here to make experimenting
|
7
8
|
# with your gem easier. You can also use a different console, if you like.
|
@@ -10,5 +11,5 @@ require "graphql/decorate"
|
|
10
11
|
# require "pry"
|
11
12
|
# Pry.start
|
12
13
|
|
13
|
-
require
|
14
|
+
require 'irb'
|
14
15
|
IRB.start(__FILE__)
|
data/graphql-decorate.gemspec
CHANGED
@@ -1,30 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
|
2
|
-
lib = File.expand_path(
|
3
|
+
lib = File.expand_path('lib', __dir__)
|
3
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
require
|
5
|
+
require 'graphql/decorate/version'
|
5
6
|
|
6
7
|
Gem::Specification.new do |spec|
|
7
|
-
spec.name =
|
8
|
+
spec.name = 'graphql-decorate'
|
8
9
|
spec.version = GraphQL::Decorate::VERSION
|
9
|
-
spec.authors = [
|
10
|
-
spec.email = [
|
10
|
+
spec.authors = ['Ben Brook']
|
11
|
+
spec.email = ['bbrook154@gmail.com']
|
11
12
|
|
12
13
|
spec.summary = 'A decorator integration for the GraphQL gem'
|
13
14
|
spec.homepage = 'https://www.github.com/TrueCar/graphql-decorate'
|
14
|
-
spec.license =
|
15
|
+
spec.license = 'MIT'
|
15
16
|
|
16
17
|
# Specify which files should be added to the gem when it is released.
|
17
|
-
# The `git ls-files -z` loads the files in the RubyGem that have been added
|
18
|
-
|
19
|
-
|
18
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added
|
19
|
+
# into git.
|
20
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
21
|
+
`git ls-files -z`.split("\x0").reject do |f|
|
22
|
+
f.match(%r{^(test|spec|features)/})
|
23
|
+
end
|
20
24
|
end
|
21
|
-
spec.bindir =
|
25
|
+
spec.bindir = 'exe'
|
22
26
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
23
|
-
spec.require_paths = [
|
27
|
+
spec.require_paths = ['lib']
|
24
28
|
|
25
|
-
spec.
|
29
|
+
spec.required_ruby_version = '>= 2.6.0'
|
26
30
|
|
27
|
-
spec.
|
28
|
-
|
29
|
-
spec.add_development_dependency
|
31
|
+
spec.add_runtime_dependency 'graphql', '>= 1.3', '< 2'
|
32
|
+
|
33
|
+
spec.add_development_dependency 'bundler', '>= 2'
|
34
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
35
|
+
spec.add_development_dependency 'rspec', '~> 3.0'
|
36
|
+
spec.add_development_dependency 'rubocop', ' >= 1.11.0 '
|
37
|
+
spec.add_development_dependency 'rubocop-rspec', '2.2.0'
|
38
|
+
spec.add_development_dependency 'simplecov', '~> 0.21.2'
|
39
|
+
spec.add_development_dependency 'yard', '~> 0.9.26'
|
30
40
|
end
|
data/lib/graphql/decorate.rb
CHANGED
@@ -1,13 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'graphql'
|
2
4
|
require_relative 'decorate/version'
|
3
5
|
require_relative 'decorate/configuration'
|
4
6
|
require_relative 'decorate/object_integration'
|
5
7
|
require_relative 'decorate/field_integration'
|
6
8
|
require_relative 'decorate/field_extension'
|
7
|
-
require_relative 'decorate/
|
9
|
+
require_relative 'decorate/decoration'
|
8
10
|
require_relative 'decorate/type_attributes'
|
9
|
-
require_relative 'decorate/
|
10
|
-
require_relative 'decorate/
|
11
|
+
require_relative 'decorate/undecorated_field'
|
12
|
+
require_relative 'decorate/connection_wrapper'
|
13
|
+
require_relative 'decorate/metadata'
|
11
14
|
|
12
15
|
# Matching the graphql-ruby namespace
|
13
16
|
module GraphQL
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module GraphQL
|
2
4
|
module Decorate
|
3
5
|
# Allows overriding default decoration and custom collection class behavior.
|
@@ -9,8 +11,8 @@ module GraphQL
|
|
9
11
|
attr_accessor :custom_collection_classes
|
10
12
|
|
11
13
|
def initialize
|
12
|
-
@evaluate_decorator = lambda do |decorator_class, object,
|
13
|
-
decorator_class.decorate(object, context:
|
14
|
+
@evaluate_decorator = lambda do |decorator_class, object, metadata|
|
15
|
+
decorator_class.decorate(object, context: metadata)
|
14
16
|
end
|
15
17
|
@custom_collection_classes = []
|
16
18
|
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GraphQL
|
4
|
+
module Decorate
|
5
|
+
# Wraps a GraphQL::Pagination::ConnectionWrapper object to decorate values after pagination is applied.
|
6
|
+
class ConnectionWrapper
|
7
|
+
# @param connection [GraphQL::Pagination::Connection] ConnectionWrapper being decorated
|
8
|
+
# @param node_type [GraphQL::Schema::Object] Type class of the connection's node
|
9
|
+
# @param context [GraphQL::Query::Context] Current query context
|
10
|
+
def self.wrap(connection, node_type, context)
|
11
|
+
@connection_class = connection.class
|
12
|
+
new(connection, node_type, context)
|
13
|
+
end
|
14
|
+
|
15
|
+
# @return [GraphQL::Pagination::Connection] ConnectionWrapper being decorated
|
16
|
+
attr_reader :connection
|
17
|
+
|
18
|
+
# @param connection [GraphQL::Pagination::Connection] ConnectionWrapper being decorated
|
19
|
+
# # @param node_type [GraphQL::Schema::Object] Type class of the connection's node
|
20
|
+
# @param context [GraphQL::Query::Context] Current query context
|
21
|
+
def initialize(connection, node_type, context)
|
22
|
+
@connection = connection
|
23
|
+
@node_type = node_type
|
24
|
+
@context = context
|
25
|
+
end
|
26
|
+
|
27
|
+
# @return [Array] Decorated nodes after pagination is applied
|
28
|
+
def nodes
|
29
|
+
nodes = @connection.nodes
|
30
|
+
nodes.map do |node|
|
31
|
+
unresolved_field = GraphQL::Decorate::UndecoratedField.new(node, node_type, connection.parent,
|
32
|
+
connection.field.owner, context)
|
33
|
+
GraphQL::Decorate::Decoration.decorate(unresolved_field)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# @see nodes
|
38
|
+
# @return [Array] Decorated nodes after pagination is applied
|
39
|
+
def edge_nodes
|
40
|
+
nodes
|
41
|
+
end
|
42
|
+
|
43
|
+
class << self
|
44
|
+
private
|
45
|
+
|
46
|
+
def method_missing(symbol, *args, &block)
|
47
|
+
@connection_class.send(symbol, *args, &block) || super
|
48
|
+
end
|
49
|
+
|
50
|
+
def respond_to_missing?(method, include_private = false)
|
51
|
+
@connection_class.respond_to?(method, include_private)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
attr_reader :node_type, :context
|
58
|
+
|
59
|
+
def method_missing(symbol, *args, &block)
|
60
|
+
@connection.send(symbol, *args, &block) || super
|
61
|
+
end
|
62
|
+
|
63
|
+
def respond_to_missing?(method, include_private = false)
|
64
|
+
@connection.respond_to?(method, include_private)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GraphQL
|
4
|
+
module Decorate
|
5
|
+
# Handles decorating an value at runtime given its current field.
|
6
|
+
class Decoration
|
7
|
+
# Resolve the undecorated_field.value with decoration.
|
8
|
+
# @param undecorated_field [GraphQL::Decorate::UndecoratedField]
|
9
|
+
# @return [Object] Decorated undecorated_field.value if possible, otherwise the original undecorated_field.value.
|
10
|
+
def self.decorate(undecorated_field)
|
11
|
+
new(undecorated_field).decorate
|
12
|
+
end
|
13
|
+
|
14
|
+
# @param undecorated_field [GraphQL::Decorate::UndecoratedField]
|
15
|
+
def initialize(undecorated_field)
|
16
|
+
@undecorated_field = undecorated_field
|
17
|
+
end
|
18
|
+
|
19
|
+
# @return [Object] Decorated undecorated_field.value if possible, otherwise the original undecorated_field.value.
|
20
|
+
def decorate
|
21
|
+
if undecorated_field.decorator_class
|
22
|
+
GraphQL::Decorate.configuration.evaluate_decorator.call(undecorated_field.decorator_class,
|
23
|
+
undecorated_field.value, undecorated_field.metadata)
|
24
|
+
else
|
25
|
+
undecorated_field.value
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
attr_reader :undecorated_field
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -1,26 +1,44 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module GraphQL
|
3
4
|
module Decorate
|
4
5
|
# Extension run after fields are resolved to decorate their value.
|
5
6
|
class FieldExtension < GraphQL::Schema::FieldExtension
|
6
7
|
# Extension to be called after lazy loading.
|
7
8
|
# @param context [GraphQL::Query::Context] The current GraphQL query context.
|
8
|
-
# @param value [Object, GraphQL::Schema::Object] The object being decorated. Can
|
9
|
-
#
|
10
|
-
|
9
|
+
# @param value [Object, GraphQL::Schema::Object, GraphQL::Pagination::Connection] The object being decorated. Can
|
10
|
+
# be a schema object if the field hasn't been resolved yet or a connection.
|
11
|
+
# @param object [Object] Object the field is being resolved on.
|
12
|
+
# @return [Object, GraphQL::Decorate::ConnectionWrapper] Decorated object.
|
13
|
+
def after_resolve(context:, value:, object:, **_rest)
|
11
14
|
return if value.nil?
|
12
15
|
|
13
|
-
|
16
|
+
resolve_decorated_value(value, object, context)
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def resolve_decorated_value(value, parent_object, context)
|
22
|
+
type = extract_type(context.to_h[:current_field].type)
|
14
23
|
if value.is_a?(GraphQL::Pagination::Connection)
|
15
|
-
GraphQL::Decorate::
|
16
|
-
elsif
|
17
|
-
value.map
|
24
|
+
GraphQL::Decorate::ConnectionWrapper.wrap(value, type, context)
|
25
|
+
elsif collection?(value)
|
26
|
+
value.map do |item|
|
27
|
+
decorate(item, type, parent_object.object, parent_object.class, context)
|
28
|
+
end
|
18
29
|
else
|
19
|
-
decorate(value,
|
30
|
+
decorate(value, type, parent_object.object, parent_object.class, context)
|
20
31
|
end
|
21
32
|
end
|
22
33
|
|
23
|
-
|
34
|
+
def decorate(value, type, parent_object, parent_type, context)
|
35
|
+
undecorated_field = GraphQL::Decorate::UndecoratedField.new(value, type, parent_object, parent_type, context)
|
36
|
+
GraphQL::Decorate::Decoration.decorate(undecorated_field)
|
37
|
+
end
|
38
|
+
|
39
|
+
def collection?(value)
|
40
|
+
collection_classes.any? { |c| value.is_a?(c) }
|
41
|
+
end
|
24
42
|
|
25
43
|
def collection_classes
|
26
44
|
klasses = [Array] + GraphQL::Decorate.configuration.custom_collection_classes
|
@@ -28,8 +46,12 @@ module GraphQL
|
|
28
46
|
klasses
|
29
47
|
end
|
30
48
|
|
31
|
-
def
|
32
|
-
|
49
|
+
def extract_type(field)
|
50
|
+
if field.respond_to?(:of_type)
|
51
|
+
extract_type(field.of_type)
|
52
|
+
else
|
53
|
+
field
|
54
|
+
end
|
33
55
|
end
|
34
56
|
end
|
35
57
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module GraphQL
|
2
4
|
module Decorate
|
3
5
|
# Extends default field behavior and adds extension to the field if it should be decorated.
|
@@ -8,30 +10,8 @@ module GraphQL
|
|
8
10
|
def initialize(type:, **rest, &block)
|
9
11
|
super
|
10
12
|
field_type = [type].flatten(1).first
|
11
|
-
|
12
|
-
|
13
|
-
end
|
14
|
-
|
15
|
-
private
|
16
|
-
|
17
|
-
def get_extension_options(type)
|
18
|
-
type_attributes = GraphQL::Decorate::TypeAttributes.new(type)
|
19
|
-
return unless type_attributes.decorator_class
|
20
|
-
|
21
|
-
{
|
22
|
-
decorator_class: type_attributes.decorator_class,
|
23
|
-
decorator_evaluator: type_attributes.decorator_evaluator,
|
24
|
-
decorator_context_evaluator: type_attributes.decorator_context_evaluator,
|
25
|
-
unresolved_type: type_attributes.unresolved_type
|
26
|
-
}
|
27
|
-
end
|
28
|
-
|
29
|
-
def extend_with_decorator(options)
|
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
|
13
|
+
type_attributes = GraphQL::Decorate::TypeAttributes.new(field_type)
|
14
|
+
extension(GraphQL::Decorate::FieldExtension) if type_attributes.decoratable?
|
35
15
|
end
|
36
16
|
end
|
37
17
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GraphQL
|
4
|
+
module Decorate
|
5
|
+
# Contains methods to evaluate different types of metadata
|
6
|
+
class Metadata
|
7
|
+
# @return [Proc]
|
8
|
+
attr_reader :unscoped_proc
|
9
|
+
|
10
|
+
# @return [Proc]
|
11
|
+
attr_reader :scoped_proc
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
@unscoped_proc = nil
|
15
|
+
@scoped_proc = nil
|
16
|
+
end
|
17
|
+
|
18
|
+
# @yield [object, graphql_context] Evaluate metadata for a single resolved field
|
19
|
+
def unscoped(&block)
|
20
|
+
@unscoped_proc = block
|
21
|
+
end
|
22
|
+
|
23
|
+
# @yield [object, graphql_context] Evaluate metadata for a resolved field and all child fields
|
24
|
+
def scoped(&block)
|
25
|
+
@scoped_proc = block
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -1,41 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module GraphQL
|
2
4
|
module Decorate
|
3
5
|
# Extends GraphQL::Schema::Object classes with methods to set the desired decorator class and context.
|
4
6
|
module ObjectIntegration
|
5
7
|
# Decorate the type with a decorator class.
|
6
8
|
# @param klass [Class] Class the object should be decorated with.
|
7
|
-
def decorate_with(klass)
|
9
|
+
def decorate_with(klass = nil, &block)
|
8
10
|
@decorator_class = klass
|
9
|
-
end
|
10
|
-
|
11
|
-
# Dynamically choose the decorator class based on the underlying object.
|
12
|
-
# @yield [object] Gives the underlying object to the block.
|
13
|
-
# @return [Proc] Proc to evaluate decorator class. Proc should return a decorator class.
|
14
|
-
def decorate_when(&block)
|
15
11
|
@decorator_evaluator = block
|
16
12
|
end
|
17
13
|
|
18
14
|
# Pass additional data to the decorator context (if supported).
|
19
15
|
# @yield [object] Gives the underlying object to the block.
|
20
16
|
# @return [Proc] Proc to evaluate decorator context. Proc should return Hash.
|
21
|
-
def
|
22
|
-
@
|
17
|
+
def decorate_metadata
|
18
|
+
@decorator_metadata ||= GraphQL::Decorate::Metadata.new
|
19
|
+
yield(@decorator_metadata)
|
23
20
|
end
|
24
21
|
|
25
22
|
# @return [Class, nil] Gets the currently set decorator class.
|
26
|
-
|
27
|
-
@decorator_class
|
28
|
-
end
|
23
|
+
attr_reader :decorator_class
|
29
24
|
|
30
25
|
# @return [Proc, nil] Gets the currently set decorator evaluator.
|
31
|
-
|
32
|
-
@decorator_evaluator
|
33
|
-
end
|
26
|
+
attr_reader :decorator_evaluator
|
34
27
|
|
35
|
-
|
36
|
-
def decorator_context_evaluator
|
37
|
-
@decorator_context_evaluator
|
38
|
-
end
|
28
|
+
attr_reader :decorator_metadata
|
39
29
|
end
|
40
30
|
end
|
41
31
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module GraphQL
|
3
4
|
module Decorate
|
4
5
|
# Extracts configured decorator attributes from a GraphQL::Schema::Object type.
|
@@ -11,6 +12,11 @@ module GraphQL
|
|
11
12
|
@type = type
|
12
13
|
end
|
13
14
|
|
15
|
+
# @return [Boolean] True if the type can be decorated, false otherwise
|
16
|
+
def decoratable?
|
17
|
+
!!(decorator_class || decorator_evaluator || unresolved_type?)
|
18
|
+
end
|
19
|
+
|
14
20
|
# @return [Class, nil] Decorator class for the type if available
|
15
21
|
def decorator_class
|
16
22
|
get_attribute(:decorator_class)
|
@@ -21,9 +27,9 @@ module GraphQL
|
|
21
27
|
get_attribute(:decorator_evaluator)
|
22
28
|
end
|
23
29
|
|
24
|
-
# @return [Proc, nil] Decorator
|
25
|
-
def
|
26
|
-
get_attribute(:
|
30
|
+
# @return [Proc, nil] Decorator metadata evaluator for the type if available
|
31
|
+
def decorator_metadata
|
32
|
+
get_attribute(:decorator_metadata)
|
27
33
|
end
|
28
34
|
|
29
35
|
# @return [GraphQL::Schema::Object, nil] Decorator evaluator for the type if available
|
@@ -0,0 +1,102 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GraphQL
|
4
|
+
module Decorate
|
5
|
+
# Wraps current value, parents, and graphql_context and extracts relevant decoration data to resolve the field.
|
6
|
+
class UndecoratedField
|
7
|
+
# @return [Object] Value to be decorated
|
8
|
+
attr_reader :value
|
9
|
+
|
10
|
+
# @param value [Object] Value to be decorated
|
11
|
+
# @param type [GraphQL::Schema::Object] Type class of value to be decorated
|
12
|
+
# @param parent_value [Object] Value of the parent field
|
13
|
+
# @param parent_type [GraphQL::Schema::Object] Type class of the parent field
|
14
|
+
# @param graphql_context [GraphQL::Query::Context] Current query graphql_context
|
15
|
+
def initialize(value, type, parent_value, parent_type, graphql_context)
|
16
|
+
@value = value
|
17
|
+
@type_attributes = GraphQL::Decorate::TypeAttributes.new(type)
|
18
|
+
@parent_value = parent_value
|
19
|
+
@parent_type = parent_type
|
20
|
+
@graphql_context = graphql_context
|
21
|
+
@default_metadata = { graphql: true }
|
22
|
+
end
|
23
|
+
|
24
|
+
# @return [Class] Decorator class for the current field
|
25
|
+
def decorator_class
|
26
|
+
resolved_class = type_attributes.decorator_class || resolve_decorator_class
|
27
|
+
return resolved_class if resolved_class
|
28
|
+
|
29
|
+
class_evaluator = type_attributes.decorator_evaluator || resolve_decorator_evaluator
|
30
|
+
class_evaluator&.call(value, graphql_context)
|
31
|
+
end
|
32
|
+
|
33
|
+
# @return [Hash] Metadata to be provided to a decorator for the current field
|
34
|
+
def metadata
|
35
|
+
default_metadata.merge(unscoped_metadata, scoped_metadata)
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
attr_reader :type_attributes, :graphql_context, :parent_value, :parent_type, :default_metadata
|
41
|
+
|
42
|
+
def unscoped_metadata
|
43
|
+
unscoped_metadata_proc&.call(value, graphql_context) || {}
|
44
|
+
end
|
45
|
+
|
46
|
+
def scoped_metadata
|
47
|
+
merged_scoped_metadata = existing_scoped_metadata.merge(new_scoped_metadata)
|
48
|
+
graphql_context.scoped_set!(:scoped_decorator_metadata, merged_scoped_metadata)
|
49
|
+
merged_scoped_metadata
|
50
|
+
end
|
51
|
+
|
52
|
+
def new_scoped_metadata
|
53
|
+
scoped_metadata = scoped_metadata_proc&.call(value, graphql_context) || {}
|
54
|
+
parent_scoped_metadata.merge(scoped_metadata)
|
55
|
+
end
|
56
|
+
|
57
|
+
def parent_scoped_metadata
|
58
|
+
parent_type_attributes.decorator_metadata&.scoped_proc&.call(parent_value, graphql_context) || {}
|
59
|
+
end
|
60
|
+
|
61
|
+
def parent_type_attributes
|
62
|
+
GraphQL::Decorate::TypeAttributes.new(parent_type)
|
63
|
+
end
|
64
|
+
|
65
|
+
def existing_scoped_metadata
|
66
|
+
graphql_context[:scoped_decorator_metadata] || {}
|
67
|
+
end
|
68
|
+
|
69
|
+
def unscoped_metadata_proc
|
70
|
+
type_attributes.decorator_metadata&.unscoped_proc || resolve_unscoped_proc
|
71
|
+
end
|
72
|
+
|
73
|
+
def scoped_metadata_proc
|
74
|
+
type_attributes.decorator_metadata&.scoped_proc || resolve_scoped_proc
|
75
|
+
end
|
76
|
+
|
77
|
+
def resolve_decorator_class
|
78
|
+
resolved_type_attributes&.decorator_class
|
79
|
+
end
|
80
|
+
|
81
|
+
def resolve_decorator_evaluator
|
82
|
+
resolved_type_attributes&.decorator_evaluator
|
83
|
+
end
|
84
|
+
|
85
|
+
def resolve_unscoped_proc
|
86
|
+
resolved_type_attributes&.decorator_metadata&.unscoped_proc
|
87
|
+
end
|
88
|
+
|
89
|
+
def resolve_scoped_proc
|
90
|
+
resolved_type_attributes&.decorator_metadata&.scoped_proc
|
91
|
+
end
|
92
|
+
|
93
|
+
def resolved_type_attributes
|
94
|
+
@resolved_type_attributes ||= begin
|
95
|
+
if type_attributes.unresolved_type?
|
96
|
+
GraphQL::Decorate::TypeAttributes.new(type_attributes.type.resolve_type(value, graphql_context))
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
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: 1.0.0
|
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-
|
11
|
+
date: 2021-03-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: graphql
|
@@ -72,6 +72,62 @@ dependencies:
|
|
72
72
|
- - "~>"
|
73
73
|
- !ruby/object:Gem::Version
|
74
74
|
version: '3.0'
|
75
|
+
- !ruby/object:Gem::Dependency
|
76
|
+
name: rubocop
|
77
|
+
requirement: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - ">="
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: 1.11.0
|
82
|
+
type: :development
|
83
|
+
prerelease: false
|
84
|
+
version_requirements: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: 1.11.0
|
89
|
+
- !ruby/object:Gem::Dependency
|
90
|
+
name: rubocop-rspec
|
91
|
+
requirement: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - '='
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: 2.2.0
|
96
|
+
type: :development
|
97
|
+
prerelease: false
|
98
|
+
version_requirements: !ruby/object:Gem::Requirement
|
99
|
+
requirements:
|
100
|
+
- - '='
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: 2.2.0
|
103
|
+
- !ruby/object:Gem::Dependency
|
104
|
+
name: simplecov
|
105
|
+
requirement: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - "~>"
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: 0.21.2
|
110
|
+
type: :development
|
111
|
+
prerelease: false
|
112
|
+
version_requirements: !ruby/object:Gem::Requirement
|
113
|
+
requirements:
|
114
|
+
- - "~>"
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: 0.21.2
|
117
|
+
- !ruby/object:Gem::Dependency
|
118
|
+
name: yard
|
119
|
+
requirement: !ruby/object:Gem::Requirement
|
120
|
+
requirements:
|
121
|
+
- - "~>"
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: 0.9.26
|
124
|
+
type: :development
|
125
|
+
prerelease: false
|
126
|
+
version_requirements: !ruby/object:Gem::Requirement
|
127
|
+
requirements:
|
128
|
+
- - "~>"
|
129
|
+
- !ruby/object:Gem::Version
|
130
|
+
version: 0.9.26
|
75
131
|
description:
|
76
132
|
email:
|
77
133
|
- bbrook154@gmail.com
|
@@ -80,8 +136,9 @@ extensions: []
|
|
80
136
|
extra_rdoc_files: []
|
81
137
|
files:
|
82
138
|
- ".github/workflows/gem-push-on-release.yml"
|
83
|
-
- ".github/workflows/
|
139
|
+
- ".github/workflows/ruby.yml"
|
84
140
|
- ".gitignore"
|
141
|
+
- ".rubocop.yml"
|
85
142
|
- Gemfile
|
86
143
|
- LICENSE.txt
|
87
144
|
- README.md
|
@@ -91,13 +148,14 @@ files:
|
|
91
148
|
- graphql-decorate.gemspec
|
92
149
|
- lib/graphql/decorate.rb
|
93
150
|
- lib/graphql/decorate/configuration.rb
|
94
|
-
- lib/graphql/decorate/
|
95
|
-
- lib/graphql/decorate/
|
151
|
+
- lib/graphql/decorate/connection_wrapper.rb
|
152
|
+
- lib/graphql/decorate/decoration.rb
|
96
153
|
- lib/graphql/decorate/field_extension.rb
|
97
154
|
- lib/graphql/decorate/field_integration.rb
|
98
|
-
- lib/graphql/decorate/
|
155
|
+
- lib/graphql/decorate/metadata.rb
|
99
156
|
- lib/graphql/decorate/object_integration.rb
|
100
157
|
- lib/graphql/decorate/type_attributes.rb
|
158
|
+
- lib/graphql/decorate/undecorated_field.rb
|
101
159
|
- lib/graphql/decorate/version.rb
|
102
160
|
homepage: https://www.github.com/TrueCar/graphql-decorate
|
103
161
|
licenses:
|
@@ -111,7 +169,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
111
169
|
requirements:
|
112
170
|
- - ">="
|
113
171
|
- !ruby/object:Gem::Version
|
114
|
-
version:
|
172
|
+
version: 2.6.0
|
115
173
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
116
174
|
requirements:
|
117
175
|
- - ">="
|
data/.github/workflows/rspec.yml
DELETED
@@ -1,32 +0,0 @@
|
|
1
|
-
# This workflow uses actions that are not certified by GitHub.
|
2
|
-
# They are provided by a third-party and are governed by
|
3
|
-
# separate terms of service, privacy policy, and support
|
4
|
-
# documentation.
|
5
|
-
# This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
|
6
|
-
# For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
|
7
|
-
|
8
|
-
name: Ruby
|
9
|
-
|
10
|
-
on:
|
11
|
-
push:
|
12
|
-
branches: [ master ]
|
13
|
-
pull_request:
|
14
|
-
branches: [ master ]
|
15
|
-
|
16
|
-
jobs:
|
17
|
-
test:
|
18
|
-
|
19
|
-
runs-on: ubuntu-latest
|
20
|
-
strategy:
|
21
|
-
matrix:
|
22
|
-
ruby-version: ['2.6', '2.7', '3.0']
|
23
|
-
|
24
|
-
steps:
|
25
|
-
- uses: actions/checkout@v2
|
26
|
-
- name: Set up Ruby
|
27
|
-
uses: ruby/setup-ruby@v1
|
28
|
-
with:
|
29
|
-
ruby-version: ${{ matrix.ruby-version }}
|
30
|
-
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
|
31
|
-
- name: Run tests
|
32
|
-
run: bundle exec rake
|
@@ -1,52 +0,0 @@
|
|
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
|
@@ -1,18 +0,0 @@
|
|
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,71 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
module GraphQL
|
3
|
-
module Decorate
|
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
|
-
@object = object
|
10
|
-
@field_context = field_context
|
11
|
-
@default_decorator_context = { graphql: true }
|
12
|
-
end
|
13
|
-
|
14
|
-
# Resolve the object with decoration.
|
15
|
-
# @return [Object] Decorated object if possible, otherwise the original object.
|
16
|
-
def decorate
|
17
|
-
if decorator_class
|
18
|
-
GraphQL::Decorate.configuration.evaluate_decorator.call(decorator_class, object, decorator_context)
|
19
|
-
else
|
20
|
-
object
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
private
|
25
|
-
|
26
|
-
attr_reader :object, :field_context, :default_decorator_context
|
27
|
-
|
28
|
-
def decorator_class
|
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)
|
33
|
-
else
|
34
|
-
resolve_decorator_class
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
def decorator_context_evaluator
|
39
|
-
field_context.options[:decorator_context_evaluator] || resolve_decorator_context_evaluator
|
40
|
-
end
|
41
|
-
|
42
|
-
private
|
43
|
-
|
44
|
-
def evaluate_decoration_context
|
45
|
-
decorator_context_evaluator ? decorator_context_evaluator.call(object) : {}
|
46
|
-
end
|
47
|
-
|
48
|
-
def decorator_context
|
49
|
-
evaluate_decoration_context.merge(default_decorator_context)
|
50
|
-
end
|
51
|
-
|
52
|
-
def resolve_decorator_class
|
53
|
-
type = resolve_type
|
54
|
-
if type.respond_to?(:decorator_class) && type.decorator_class
|
55
|
-
type.decorator_class
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
def resolve_decorator_context_evaluator
|
60
|
-
type = resolve_type
|
61
|
-
if type.respond_to?(:decorator_context_evaluator) && type.decorator_context_evaluator
|
62
|
-
type.decorator_context_evaluator
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
def resolve_type
|
67
|
-
field_context.options[:unresolved_type]&.resolve_type(object, field_context.context)
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|