graphql-decorate 0.2.1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|