graphiti_graphql 0.1.0 → 0.1.5

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: e0393f405900a890b0875cf64d93bb60a0f8a0c2ef52d3536a6faacb0f0d1ca0
4
- data.tar.gz: 878b11ef0e004c8b5559ee1c09dd2a325f464184cbd2d328f73b46bb1c92f968
3
+ metadata.gz: 432533feee410a6ea882ec0362ff202b1c79f1bad917c1e24eb01fc83e4de147
4
+ data.tar.gz: 2dda92eb996d6152538d4575fbe7c6e72c8afeff4a66e150a422e9c2c2cc131b
5
5
  SHA512:
6
- metadata.gz: 0752a653316c694d9382f0ba4c05e9a0421c8cb77e2fd536413efa9efd0add4e97593135cdb833e26a3e65b1faef41f51cedcc01517592a35e69cafb1ccde555
7
- data.tar.gz: f3be55e066cef1d8cd79e3d8711b4bc914fb911751f95564ea084ea2f00846d946d198bb5306e140e2f645a526848c984d9723b17d813ca743c732c5f328b5e4
6
+ metadata.gz: 29d66aab18e94862648b6e1385ccb74503b17c80c6a8c745abc2adfe4d394c93869b2b8fb272cad98f053613defff9d3c37730c51881126ae295c31fc811c023
7
+ data.tar.gz: badaf32c3b391fa21033fd0184b8785c607aa13837fbeeeef654f564f679267071e3a487d9dd1a1e8c7224b1f3b2b46006889456defa8cc6843abe470bb6586b
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
 
@@ -1,5 +1,7 @@
1
1
  require "active_support/core_ext/object/json"
2
2
 
3
+ require "graphql"
4
+ require "graphiti"
3
5
  require "graphiti_graphql/version"
4
6
  require "graphiti_graphql/graphiti_schema/wrapper"
5
7
  require "graphiti_graphql/graphiti_schema/sideload"
@@ -9,38 +11,58 @@ require "graphiti_graphql/schema"
9
11
  require "graphiti_graphql/runner"
10
12
  require "graphiti_graphql/util"
11
13
 
12
- Graphiti.class_eval do
13
- class << self
14
- attr_writer :graphql_schema
15
- end
14
+ module GraphitiGraphQL
15
+ class Configuration
16
+ attr_accessor :schema_reloading
16
17
 
17
- # TODO probably move these off of Graphiti
18
- def self.gql(query, variables)
19
- runner = ::GraphitiGraphQL::Runner.new
20
- runner.execute(query, variables, graphql_schema.schema)
21
- end
18
+ def initialize
19
+ self.schema_reloading = true
20
+ end
22
21
 
23
- def self.graphql_schema
24
- @graphql_schema ||= GraphitiGraphQL::Schema.generate
25
- end
22
+ def define_context(&blk)
23
+ @define_context = blk
24
+ end
26
25
 
27
- def self.graphql_schema?
28
- !!@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
29
34
  end
30
35
 
31
- def self.graphql_schema!(entrypoint_resources = nil)
32
- @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
33
41
  end
34
- end
35
42
 
36
- module GraphitiGraphQL
37
- class Error < StandardError; end
43
+ class SchemaProxy
44
+ def graphql
45
+ generated.schema
46
+ end
38
47
 
39
- class Configuration
40
- attr_accessor :schema_reloading
48
+ def graphiti
49
+ generated.graphiti_schema
50
+ end
41
51
 
42
- def initialize
43
- 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
44
66
  end
45
67
  end
46
68
 
@@ -52,20 +74,13 @@ module GraphitiGraphQL
52
74
  @config ||= Configuration.new
53
75
  end
54
76
 
55
- def self.define_context(&blk)
56
- @define_context = blk
57
- end
58
-
59
- def self.get_context
60
- obj = Graphiti.context[:object]
61
- if @define_context
62
- @define_context.call(obj)
63
- else
64
- {object: obj}
65
- end
77
+ def self.schemas
78
+ @schemas ||= SchemaProxy.new
66
79
  end
67
80
  end
68
81
 
82
+ Graphiti.extend(GraphitiGraphQL::Runnable)
83
+
69
84
  if defined?(::Rails)
70
85
  require "graphiti_graphql/engine"
71
86
  end
@@ -48,14 +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
- GraphitiGraphQL::Engine.reloader_class.after_class_unload do
55
- GraphitiGraphQL::Federation.clear!
56
- end
57
- end
58
-
59
51
  initializer "graphiti_graphql.schema_reloading" do |app|
60
52
  # Only reload the schema if we ask for it
61
53
  # Some may want to avoid the performance penalty
@@ -64,8 +56,8 @@ module GraphitiGraphQL
64
56
  # We want to reload the schema when classes change
65
57
  # But this way, you only pay the cost (time) when the GraphQL endpoint
66
58
  # is actually hit
67
- if Graphiti.graphql_schema?
68
- Graphiti.graphql_schema = nil
59
+ if GraphitiGraphQL.schemas.generated?
60
+ GraphitiGraphQL.schemas.clear!
69
61
  end
70
62
  end
71
63
  end
@@ -83,7 +75,9 @@ module GraphitiGraphQL
83
75
  end
84
76
 
85
77
  initializer "graphiti_graphql.federation" do
86
- GraphitiGraphQL::Federation.setup!
78
+ if defined?(GraphitiGraphQL::Federation)
79
+ GraphitiGraphQL::Federation.setup!
80
+ end
87
81
  end
88
82
  end
89
83
  end
@@ -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