graphiti_graphql 0.1.1 → 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f3636c8634e8e8798b5faa86fed69735c02be79903ecca7f4fb09418786756f1
4
- data.tar.gz: 6ce1f38785202d1fb6972152731ef5f535fd4f3514f8996eb60f1abc13431ea0
3
+ metadata.gz: fc07d6560d9c73767aca102d08c8c9f6b31fe09b8f3bb6db266a6566d8c3b50d
4
+ data.tar.gz: c51c68edca23ae65f7b3c0a6e7f45d9546442d619fcc76f97682dc24e0b01644
5
5
  SHA512:
6
- metadata.gz: 45796a4cde424e1fcec4d8eef45238fb52d4fb4d0980c067dbd8321a9dd1b9e3f5d487a3125d9fe0b50bb0d2a452bf79520e5cee4438ee7f31da229c51b70e98
7
- data.tar.gz: c1f7707ea8591be326b7a371b797bd15a969cdf5c115e35892966c310dcb75be656d4a81b408b6c72d83a192a3d0dc69042b91a6006d3220b9fa31a8134eb004
6
+ metadata.gz: a9338e7a088054719c0f80147587dff04ebc9320c77ccec823798436a6fa671b616d6df8c9970d64bba332254ee8b08f46a7ef380aea0087889f9592446c0b9e
7
+ data.tar.gz: 5cae58a969a23d6dcb0ee8b80a56af8d42eee6a7b0e6c16a6bba8d7b9d009bc78663cdb9e5520572d95c384a91df3e38b7f756a247c3f8b36697e16022ab8fda
data/Gemfile CHANGED
@@ -1,6 +1,4 @@
1
1
  source "https://rubygems.org"
2
2
 
3
3
  # Specify your gem's dependencies in graphiti_graphql.gemspec
4
- gemspec
5
-
6
- gem "graphiti", path: "../graphiti"
4
+ gemspec
data/Gemfile.lock CHANGED
@@ -1,19 +1,9 @@
1
- PATH
2
- remote: ../graphiti
3
- specs:
4
- graphiti (1.2.31)
5
- activesupport (>= 4.1)
6
- concurrent-ruby (~> 1.0)
7
- dry-types (>= 0.15.0, < 2.0)
8
- graphiti_errors (~> 1.1.0)
9
- jsonapi-renderer (~> 0.2, >= 0.2.2)
10
- jsonapi-serializable (~> 0.3.0)
11
-
12
1
  PATH
13
2
  remote: .
14
3
  specs:
15
- graphiti_graphql (0.1.0)
4
+ graphiti_graphql (0.1.4)
16
5
  activesupport (>= 4.1)
6
+ graphiti (>= 1.2.36)
17
7
  graphql (~> 1.12)
18
8
 
19
9
  GEM
@@ -35,7 +25,7 @@ GEM
35
25
  coderay (1.1.3)
36
26
  concurrent-ruby (1.1.8)
37
27
  diff-lcs (1.4.4)
38
- dry-configurable (0.12.0)
28
+ dry-configurable (0.12.1)
39
29
  concurrent-ruby (~> 1.0)
40
30
  dry-core (~> 0.5, >= 0.5.0)
41
31
  dry-container (0.7.2)
@@ -47,13 +37,20 @@ GEM
47
37
  dry-logic (1.1.0)
48
38
  concurrent-ruby (~> 1.0)
49
39
  dry-core (~> 0.5, >= 0.5)
50
- dry-types (1.5.0)
40
+ dry-types (1.5.1)
51
41
  concurrent-ruby (~> 1.0)
52
42
  dry-container (~> 0.3)
53
43
  dry-core (~> 0.5, >= 0.5)
54
44
  dry-inflector (~> 0.1, >= 0.1.2)
55
45
  dry-logic (~> 1.0, >= 1.0.2)
56
46
  google-protobuf (3.15.2)
47
+ graphiti (1.2.36)
48
+ activesupport (>= 4.1)
49
+ concurrent-ruby (~> 1.0)
50
+ dry-types (>= 0.15.0, < 2.0)
51
+ graphiti_errors (~> 1.1.0)
52
+ jsonapi-renderer (~> 0.2, >= 0.2.2)
53
+ jsonapi-serializable (~> 0.3.0)
57
54
  graphiti_errors (1.1.2)
58
55
  jsonapi-serializable (~> 0.1)
59
56
  graphiti_spec_helpers (1.0.5)
@@ -63,13 +60,13 @@ GEM
63
60
  graphql-batch (0.4.3)
64
61
  graphql (>= 1.3, < 2)
65
62
  promise.rb (~> 0.7.2)
66
- i18n (1.8.7)
63
+ i18n (1.8.9)
67
64
  concurrent-ruby (~> 1.0)
68
65
  jsonapi-renderer (0.2.2)
69
66
  jsonapi-serializable (0.3.1)
70
67
  jsonapi-renderer (~> 0.2.0)
71
68
  method_source (1.0.0)
72
- minitest (5.14.3)
69
+ minitest (5.14.4)
73
70
  parallel (1.20.1)
74
71
  parser (3.0.0.0)
75
72
  ast (~> 2.4.1)
@@ -129,7 +126,6 @@ DEPENDENCIES
129
126
  activemodel (>= 4.1)
130
127
  apollo-federation (~> 1.1)
131
128
  bundler (~> 2.0)
132
- graphiti!
133
129
  graphiti_graphql!
134
130
  graphiti_spec_helpers
135
131
  graphql (~> 1.12)
@@ -141,4 +137,4 @@ DEPENDENCIES
141
137
  standardrb
142
138
 
143
139
  BUNDLED WITH
144
- 2.0.2
140
+ 2.2.16
data/README.md CHANGED
@@ -1,35 +1,161 @@
1
1
  # GraphitiGraphql
2
2
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/graphiti_graphql`. To experiment with that code, run `bin/console` for an interactive prompt.
3
+ GraphQL (and Apollo Federation) support for Graphiti. Serve traditional Rails JSON, JSON:API or GraphQL with the same codebase.
4
4
 
5
- TODO: Delete this and the text above, and describe your gem
5
+ Currently read-only, but you can add your own Mutations [manually](#blending-with-graphql-ruby).
6
6
 
7
- ## Installation
7
+ Pre-alpha. Stay tuned.
8
8
 
9
- Add this line to your application's Gemfile:
9
+ ## Setup
10
+
11
+ Add to your `Gemfile`:
12
+
13
+ ```rb
14
+ gem 'graphiti', ">= 1.2.33"
15
+ gem "graphiti_graphql"
16
+ ```
17
+
18
+ Mount the engine:
10
19
 
11
20
  ```ruby
12
- gem 'graphiti_graphql'
21
+ # config/routes.rb
22
+ Rails.application.routes.draw do
23
+ scope path: ApplicationResource.endpoint_namespace, defaults: { format: :jsonapi } do
24
+ # ... normal graphiti stuff ...
25
+
26
+ mount GraphitiGraphQL::Engine, at: "/gql"
27
+ end
28
+ end
13
29
  ```
14
30
 
15
- And then execute:
31
+ For a default Graphiti app, you can now serve GraphQL by POSTing to `/api/v1/gql`.
32
+
33
+ That's it 🎉!
34
+
35
+ #### GraphiQL
36
+
37
+ You can add the GraphiQL editor to the project via [graphiql-rails](https://github.com/rmosolgo/graphiql-rails) as normal, but to save you the time here are the steps to make it work when Rails is running in API-only mode:
38
+
39
+ Add to the Gemfile:
16
40
 
17
- $ bundle
41
+ ```ruby
42
+ gem "graphiql-rails"
43
+ gem 'sprockets', '~> 3' # https://github.com/rmosolgo/graphiql-rails/issues/53
44
+ ```
18
45
 
19
- Or install it yourself as:
46
+ And then in `config/application.rb`:
20
47
 
21
- $ gem install graphiti_graphql
48
+ ```ruby
49
+ # *Uncomment* this line!
50
+ # require "sprockets/railtie"
51
+ ```
22
52
 
23
53
  ## Usage
24
54
 
25
- TODO: Write usage instructions here
55
+ #### Blending with graphql-ruby
56
+
57
+ Define your Schema and Type classes as normal. Then in an initializer:
58
+
59
+ ```ruby
60
+ # config/initializers/graphiti.rb
61
+ GraphitiGraphQL.schema_class = MySchema
62
+ ```
63
+
64
+ Any pre-existing GraphQL endpoint will continue working as normal. But the GQL endpoint you mounted in `config/routes.rb` will now serve BOTH your low-level `graphql-ruby` schema AND your Graphiti-specific schema. Note these cannot (currently) be served side-by-side under `query` within the *same request*.
65
+
66
+ By default the GraphQL context will be `Graphiti.context[:object]`, which is the controller being called. You might want to customize this so your existing graphql-ruby code continues to expect the same context:
67
+
68
+ ```ruby
69
+ GraphitiGraphQL.define_context do |controller|
70
+ { current_user: controller.current_user }
71
+ end
72
+ ```
73
+
74
+ #### Adding Federation Support
75
+
76
+ Add to the Gemfile
77
+
78
+ ```ruby
79
+ gem "apollo-federation"
80
+ gem "graphql-batch"
81
+ ```
82
+
83
+ And change the way we require `graphiti_graphql`:
84
+
85
+ ```ruby
86
+ gem "graphiti_graphql", require: "graphiti_graphql/federation"
87
+ ```
88
+
89
+ To create a federated relationship:
26
90
 
27
- ## Development
91
+ ```ruby
92
+ # PositionResource
93
+ federated_belongs_to :employee
94
+ ```
95
+
96
+ Or pass `type` and/or `foreign_key` to customize:
97
+
98
+ ```ruby
99
+ # type here is the GraphQL Type
100
+ federated_belongs_to :employee, type: "MyEmployee", foreign_key: :emp_id
101
+ ```
102
+
103
+ For `has_many` it's a slightly different syntax because we're adding the relationship to the ***remote*** type:
104
+
105
+ ```ruby
106
+ federated_type("Employee").has_many :positions # foreign_key: optional
107
+ ```
108
+
109
+ Finally, `has_many` accepts the traditional `params` block that works as normal:
110
+
111
+ ```ruby
112
+ federated_type("Employee").has_many :positions do
113
+ params do |hash|
114
+ hash[:filter][:active] = true
115
+ hash[:sort] = "-title"
116
+ end
117
+ end
118
+ ```
28
119
 
29
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
120
+ Remember that any time you make a change that affects the schema, you will have to bounce your federation gateway. This is how Apollo Federation works when not in "managed" mode and is unrelated to `graphiti_graphql`.
30
121
 
31
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
122
+ ## Configuration
32
123
 
33
- ## Contributing
124
+ #### Entrypoints
34
125
 
35
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/graphiti_graphql.
126
+ By default all Graphiti resources will expose their `index` and `show` functionality. IOW `EmployeeResource` now serves a list at `Query#employees` and a single employee at `Query#employee(id: 123)`. To limit the entrypoints:
127
+
128
+ ```ruby
129
+ GraphitiGraphQL::Schema.entrypoints = [
130
+ EmployeeResource
131
+ ]
132
+ ```
133
+
134
+ #### Schema Reloading
135
+
136
+ You may want to automatically regenerate the GQL schema when when Rails reloads your classes, or you may not want to pay that performance penalty. To turn off the automatic reloading:
137
+
138
+ ```ruby
139
+ # config/initializers/graphiti.rb
140
+ GraphitiGraphQL.config.schema_reloading = false
141
+ ```
142
+
143
+ #### `.graphql_entrypoint`
144
+
145
+ If the field you want on `Query` can't be inferred from the class name:
146
+
147
+ ```ruby
148
+ class EmployeeResource < ApplicationResource
149
+ self.graphql_entrypoint = :workers
150
+ end
151
+ ```
152
+
153
+ You can now
154
+
155
+ ```
156
+ query {
157
+ workers {
158
+ firstName
159
+ }
160
+ }
161
+ ```
@@ -27,6 +27,7 @@ Gem::Specification.new do |spec|
27
27
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
28
28
  spec.require_paths = ["lib"]
29
29
 
30
+ spec.add_dependency "graphiti", ">= 1.2.36"
30
31
  spec.add_dependency "activesupport", ">= 4.1"
31
32
  spec.add_dependency "graphql", "~> 1.12"
32
33
 
@@ -11,38 +11,58 @@ require "graphiti_graphql/schema"
11
11
  require "graphiti_graphql/runner"
12
12
  require "graphiti_graphql/util"
13
13
 
14
- Graphiti.class_eval do
15
- class << self
16
- attr_writer :graphql_schema
17
- end
14
+ module GraphitiGraphQL
15
+ class Configuration
16
+ attr_accessor :schema_reloading, :federation_application_controller
18
17
 
19
- # TODO probably move these off of Graphiti
20
- def self.gql(query, variables)
21
- runner = ::GraphitiGraphQL::Runner.new
22
- runner.execute(query, variables, graphql_schema.schema)
23
- end
18
+ def initialize
19
+ self.schema_reloading = true
20
+ end
24
21
 
25
- def self.graphql_schema
26
- @graphql_schema ||= GraphitiGraphQL::Schema.generate
27
- end
22
+ def define_context(&blk)
23
+ @define_context = blk
24
+ end
28
25
 
29
- def self.graphql_schema?
30
- !!@graphql_schema
26
+ def get_context
27
+ obj = Graphiti.context[:object]
28
+ if @define_context
29
+ @define_context.call(obj)
30
+ else
31
+ {object: obj}
32
+ end
33
+ end
31
34
  end
32
35
 
33
- def self.graphql_schema!(entrypoint_resources = nil)
34
- @graphql_schema = GraphitiGraphQL::Schema.generate(entrypoint_resources)
36
+ module Runnable
37
+ def gql(query, variables)
38
+ runner = ::GraphitiGraphQL::Runner.new
39
+ runner.execute(query, variables, GraphitiGraphQL.schemas.graphql)
40
+ end
35
41
  end
36
- end
37
42
 
38
- module GraphitiGraphQL
39
- class Error < StandardError; end
43
+ class SchemaProxy
44
+ def graphql
45
+ generated.schema
46
+ end
40
47
 
41
- class Configuration
42
- attr_accessor :schema_reloading
48
+ def graphiti
49
+ generated.graphiti_schema
50
+ end
43
51
 
44
- def initialize
45
- self.schema_reloading = true
52
+ def generated
53
+ @generated ||= GraphitiGraphQL::Schema.generate
54
+ end
55
+
56
+ def generate!(entrypoint_resources = nil)
57
+ @generated = GraphitiGraphQL::Schema.generate(entrypoint_resources)
58
+ end
59
+
60
+ def generated?
61
+ !!@generated
62
+ end
63
+
64
+ def clear!
65
+ @generated = nil
46
66
  end
47
67
  end
48
68
 
@@ -54,20 +74,17 @@ module GraphitiGraphQL
54
74
  @config ||= Configuration.new
55
75
  end
56
76
 
57
- def self.define_context(&blk)
58
- @define_context = blk
77
+ def self.configure
78
+ yield config
59
79
  end
60
80
 
61
- def self.get_context
62
- obj = Graphiti.context[:object]
63
- if @define_context
64
- @define_context.call(obj)
65
- else
66
- {object: obj}
67
- end
81
+ def self.schemas
82
+ @schemas ||= SchemaProxy.new
68
83
  end
69
84
  end
70
85
 
86
+ Graphiti.extend(GraphitiGraphQL::Runnable)
87
+
71
88
  if defined?(::Rails)
72
89
  require "graphiti_graphql/engine"
73
90
  end
@@ -48,16 +48,6 @@ module GraphitiGraphQL
48
48
  end
49
49
  end
50
50
 
51
- # We store a list of all federated relationships
52
- # Clear that list when classes are cleared so we don't keep appending
53
- initializer "graphiti_graphql.clear_federation" do |app|
54
- if defined?(GraphitiGraphQL::Federation)
55
- GraphitiGraphQL::Engine.reloader_class.after_class_unload do
56
- GraphitiGraphQL::Federation.clear!
57
- end
58
- end
59
- end
60
-
61
51
  initializer "graphiti_graphql.schema_reloading" do |app|
62
52
  # Only reload the schema if we ask for it
63
53
  # Some may want to avoid the performance penalty
@@ -66,16 +56,17 @@ module GraphitiGraphQL
66
56
  # We want to reload the schema when classes change
67
57
  # But this way, you only pay the cost (time) when the GraphQL endpoint
68
58
  # is actually hit
69
- if Graphiti.graphql_schema?
70
- Graphiti.graphql_schema = nil
59
+ if GraphitiGraphQL.schemas.generated?
60
+ GraphitiGraphQL.schemas.clear!
71
61
  end
72
62
  end
73
63
  end
74
64
  end
75
65
 
76
66
  initializer "graphiti_graphql.define_controller" do
67
+ app_controller = GraphitiGraphQL.config.federation_application_controller || ::ApplicationController
77
68
  # rubocop:disable Lint/ConstantDefinitionInBlock(Standard)
78
- class GraphitiGraphQL::ExecutionController < ::ApplicationController
69
+ class GraphitiGraphQL::ExecutionController < app_controller
79
70
  register_exception Graphiti::Errors::UnreadableAttribute, message: true
80
71
  def execute
81
72
  params = request.params # avoid strong_parameters
@@ -12,27 +12,28 @@ end
12
12
 
13
13
  # We don't want to add these as dependencies,
14
14
  # but do need to check things don't break
15
- if Gem::Version.new(ApolloFederation::VERSION) >= Gem::Version.new('2.0.0')
15
+ if Gem::Version.new(ApolloFederation::VERSION) >= Gem::Version.new("2.0.0")
16
16
  raise "graphiti_graphql federation is incompatible with apollo-federation >= 2"
17
17
  end
18
18
 
19
- if Gem::Version.new(GraphQL::Batch::VERSION) >= Gem::Version.new('1.0.0')
19
+ if Gem::Version.new(GraphQL::Batch::VERSION) >= Gem::Version.new("1.0.0")
20
20
  raise "graphiti_graphql federation is incompatible with graphql-batch >= 1"
21
21
  end
22
22
 
23
23
  require "graphiti_graphql"
24
+ require "graphiti_graphql/federation/loaders/has_many"
25
+ require "graphiti_graphql/federation/loaders/belongs_to"
26
+ require "graphiti_graphql/federation/federated_resource"
27
+ require "graphiti_graphql/federation/federated_relationship"
28
+ require "graphiti_graphql/federation/resource_dsl"
29
+ require "graphiti_graphql/federation/apollo_federation_override"
30
+ require "graphiti_graphql/federation/schema_decorator"
24
31
 
25
32
  module GraphitiGraphQL
26
33
  module Federation
27
-
28
- def self.external_resources
29
- @external_resources ||= {}
30
- end
31
-
32
- def self.clear!
33
- @external_resources = {}
34
- end
35
-
34
+ # * Extend Graphiti::Resource with federated_* macros
35
+ # * Add apollo-federation modules to graphql-ruby base types
36
+ # * Mark federation = true for checks down the line
36
37
  def self.setup!
37
38
  Graphiti::Resource.send(:include, ResourceDSL)
38
39
  schema = GraphitiGraphQL::Schema
@@ -50,214 +51,5 @@ module GraphitiGraphQL
50
51
  schema.base_interface.field_class(schema.base_field)
51
52
  GraphitiGraphQL::Schema.federation = true
52
53
  end
53
-
54
- class HasManyLoader < GraphQL::Batch::Loader
55
- def initialize(resource_class, params, foreign_key)
56
- @resource_class = resource_class
57
- @params = params
58
- @foreign_key = foreign_key
59
- end
60
-
61
- def perform(ids)
62
- @params[:filter] ||= {}
63
- @params[:filter].merge!(@foreign_key => { eq: ids.join(",") })
64
-
65
- if ids.length > 1 && @params[:page]
66
- raise Graphiti::Errors::UnsupportedPagination
67
- elsif !@params[:page]
68
- @params[:page] = { size: 999 }
69
- end
70
-
71
- Util.with_gql_context do
72
- records = @resource_class.all(@params).as_json[:data]
73
- fk = ->(record) { record[@foreign_key].to_s }
74
- map = records.group_by(&fk)
75
- ids.each do |id|
76
- fulfill(id, (map[id] || []))
77
- end
78
- end
79
- end
80
- end
81
-
82
- class BelongsToLoader < GraphQL::Batch::Loader
83
- def initialize(resource_class, fields)
84
- @resource_class = resource_class
85
- @fields = fields
86
- end
87
-
88
- def perform(ids)
89
- Util.with_gql_context do
90
- params = { filter: { id: { eq: ids.join(",") } } }
91
- params[:fields] = { @resource_class.type => @fields.join(",") }
92
- records = @resource_class.all(params).as_json[:data]
93
- pk = ->(record) { record[:id].to_s }
94
- map = records.index_by(&pk)
95
- ids.each { |id| fulfill(id, map[id]) }
96
- end
97
- end
98
- end
99
-
100
- class ExternalRelationship
101
- attr_reader :name, :local_resource_class, :foreign_key
102
-
103
- def initialize(kind, name, local_resource_class, foreign_key)
104
- @kind = kind
105
- @name = name
106
- @local_resource_class = local_resource_class
107
- @foreign_key = foreign_key
108
- end
109
-
110
- def has_many?
111
- @kind == :has_many
112
- end
113
-
114
- def belongs_to?
115
- @kind == :belongs_to
116
- end
117
- end
118
-
119
- class ExternalResource
120
- attr_reader :type_name, :relationships
121
-
122
- def initialize(type_name)
123
- @type_name = type_name
124
- @relationships = {}
125
- end
126
-
127
- def add_relationship(
128
- kind,
129
- name,
130
- local_resource_class,
131
- foreign_key
132
- )
133
- @relationships[name] = ExternalRelationship
134
- .new(kind, name, local_resource_class, foreign_key)
135
- end
136
- end
137
-
138
- class TypeProxy
139
- def initialize(caller, type_name)
140
- @caller = caller
141
- @type_name = type_name
142
- end
143
-
144
- def has_many(relationship_name, foreign_key: nil)
145
- @caller.federated_has_many relationship_name,
146
- type: @type_name,
147
- foreign_key: foreign_key
148
- end
149
- end
150
-
151
- module ResourceDSL
152
- extend ActiveSupport::Concern
153
-
154
- class_methods do
155
- def federated_type(type_name)
156
- TypeProxy.new(self, type_name)
157
- end
158
-
159
- # TODO: raise error if belongs_to doesn't have corresponding filter (on schema gen)
160
- # TODO: hang these on the resource classes themselves
161
- def federated_has_many(name, type:, foreign_key: nil)
162
- foreign_key ||= :"#{type.underscore}_id"
163
- resource = GraphitiGraphQL::Federation.external_resources[type] ||=
164
- ExternalResource.new(type)
165
- resource.add_relationship(:has_many, name, self, foreign_key)
166
-
167
- attribute = attributes.find do |name, config|
168
- name.to_sym == foreign_key && !!config[:readable] && !!config[:filterable]
169
- end
170
- has_filter = filters.key?(foreign_key)
171
- if !attribute && !has_filter
172
- attribute foreign_key, :integer,
173
- only: [:readable, :filterable],
174
- schema: false,
175
- readable: :gql?,
176
- filterable: :gql?
177
- elsif has_filter && !attribute
178
- prior = filters[foreign_key]
179
- attribute foreign_key, prior[:type],
180
- only: [:readable, :filterable],
181
- schema: false,
182
- readable: :gql?
183
- filters[foreign_key] = prior
184
- elsif attribute && !has_filter
185
- filter foreign_key, attribute[:type]
186
- end
187
- end
188
-
189
- def federated_belongs_to(name, type: nil, foreign_key: nil)
190
- type ||= name.to_s.camelize
191
- foreign_key ||= :"#{name.to_s.underscore}_id"
192
- resource = GraphitiGraphQL::Federation.external_resources[type] ||=
193
- ExternalResource.new(type)
194
- resource.add_relationship(:belongs_to, name, self, foreign_key)
195
-
196
- attribute name, :hash, readable: :gql?, only: [:readable], schema: false do
197
- fk = if prc = self.class.attribute_blocks[foreign_key]
198
- instance_eval(&prc)
199
- else
200
- @object.send(foreign_key)
201
- end
202
- {
203
- __typename: type,
204
- id: fk.to_s
205
- }
206
- end
207
- end
208
- end
209
-
210
- def gql?
211
- Graphiti.context[:graphql]
212
- end
213
- end
214
- end
215
- end
216
-
217
- # Hacky sack!
218
- # All we're doing here is adding extras: [:lookahead] to the _entities field
219
- # And passing to to the .resolve_reference method when arity is 3
220
- # This way we can request only fields the user wants when resolving the reference
221
- # Important because we blow up when a field is guarded, and the guard fails
222
- ApolloFederation::EntitiesField::ClassMethods.module_eval do
223
- alias_method :define_entities_field_without_override, :define_entities_field
224
- def define_entities_field(*args)
225
- result = define_entities_field_without_override(*args)
226
- extras = fields["_entities"].extras
227
- extras |= [:lookahead]
228
- fields["_entities"].instance_variable_set(:@extras, extras)
229
- result
230
- end
231
- end
232
-
233
- module EntitiesFieldOverride
234
- def _entities(representations:, lookahead:) # accept the lookahead as argument
235
- representations.map do |reference|
236
- typename = reference[:__typename]
237
- type = context.warden.get_type(typename)
238
- if type.nil? || type.kind != GraphQL::TypeKinds::OBJECT
239
- raise "The _entities resolver tried to load an entity for type \"#{typename}\"," \
240
- ' but no object type of that name was found in the schema'
241
- end
242
-
243
- type_class = type.is_a?(GraphQL::ObjectType) ? type.metadata[:type_class] : type
244
- if type_class.respond_to?(:resolve_reference)
245
- meth = type_class.method(:resolve_reference)
246
- # ** THIS IS OUR EDIT **
247
- result = if meth.arity == 3
248
- type_class.resolve_reference(reference, context, lookahead)
249
- else
250
- type_class.resolve_reference(reference, context)
251
- end
252
- else
253
- result = reference
254
- end
255
-
256
- context.schema.after_lazy(result) do |resolved_value|
257
- context[resolved_value] = type
258
- resolved_value
259
- end
260
- end
261
54
  end
262
55
  end
263
- ApolloFederation::EntitiesField.send :prepend, EntitiesFieldOverride