graphiti_graphql 0.1.4 → 0.1.8
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/Gemfile.lock +8 -8
- data/bin/bundle +22 -13
- data/graphiti_graphql.gemspec +1 -1
- data/lib/graphiti_graphql.rb +5 -1
- data/lib/graphiti_graphql/engine.rb +9 -6
- data/lib/graphiti_graphql/federation/federated_resource.rb +12 -0
- data/lib/graphiti_graphql/federation/loaders/has_many.rb +13 -0
- data/lib/graphiti_graphql/federation/resource_dsl.rb +14 -2
- data/lib/graphiti_graphql/federation/schema_decorator.rb +23 -3
- data/lib/graphiti_graphql/runner.rb +22 -3
- data/lib/graphiti_graphql/schema.rb +39 -1
- data/lib/graphiti_graphql/version.rb +1 -1
- metadata +7 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 40128f0eaf0ad7859fa35c67bb73b2a2fccf51829bb3914877ce0c19730def91
|
4
|
+
data.tar.gz: 6f3fe80c618aaa093dd2daec4aa726621c32d2228bb92ddfdfd00f6a610490af
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f957bb6f2092f052d683c94008940823a29cb0a995d4741eaadbf2b87f0e3585268e01819a7fde057afd0a99c0f2b4dd14d2fc76903f3e44cc51c05724a0bd69
|
7
|
+
data.tar.gz: 30c3b26190d74c0559553458d05fdd36367fb9742b320322138d0f7a9ac503775d14edddb3a25b28276b5c099588186554f6ac686da0095175c557a921c1029e
|
data/Gemfile.lock
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
graphiti_graphql (0.1.
|
4
|
+
graphiti_graphql (0.1.6)
|
5
5
|
activesupport (>= 4.1)
|
6
|
-
graphiti (
|
6
|
+
graphiti (~> 1.3)
|
7
7
|
graphql (~> 1.12)
|
8
8
|
|
9
9
|
GEM
|
@@ -28,13 +28,13 @@ GEM
|
|
28
28
|
dry-configurable (0.12.1)
|
29
29
|
concurrent-ruby (~> 1.0)
|
30
30
|
dry-core (~> 0.5, >= 0.5.0)
|
31
|
-
dry-container (0.
|
31
|
+
dry-container (0.8.0)
|
32
32
|
concurrent-ruby (~> 1.0)
|
33
33
|
dry-configurable (~> 0.1, >= 0.1.3)
|
34
|
-
dry-core (0.
|
34
|
+
dry-core (0.7.1)
|
35
35
|
concurrent-ruby (~> 1.0)
|
36
|
-
dry-inflector (0.2.
|
37
|
-
dry-logic (1.
|
36
|
+
dry-inflector (0.2.1)
|
37
|
+
dry-logic (1.2.0)
|
38
38
|
concurrent-ruby (~> 1.0)
|
39
39
|
dry-core (~> 0.5, >= 0.5)
|
40
40
|
dry-types (1.5.1)
|
@@ -44,7 +44,7 @@ GEM
|
|
44
44
|
dry-inflector (~> 0.1, >= 0.1.2)
|
45
45
|
dry-logic (~> 1.0, >= 1.0.2)
|
46
46
|
google-protobuf (3.15.2)
|
47
|
-
graphiti (1.
|
47
|
+
graphiti (1.3.0)
|
48
48
|
activesupport (>= 4.1)
|
49
49
|
concurrent-ruby (~> 1.0)
|
50
50
|
dry-types (>= 0.15.0, < 2.0)
|
@@ -137,4 +137,4 @@ DEPENDENCIES
|
|
137
137
|
standardrb
|
138
138
|
|
139
139
|
BUNDLED WITH
|
140
|
-
2.
|
140
|
+
2.2.16
|
data/bin/bundle
CHANGED
@@ -31,7 +31,7 @@ m = Module.new do
|
|
31
31
|
bundler_version = a
|
32
32
|
end
|
33
33
|
next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/
|
34
|
-
bundler_version = $1
|
34
|
+
bundler_version = $1
|
35
35
|
update_index = i
|
36
36
|
end
|
37
37
|
bundler_version
|
@@ -61,32 +61,41 @@ m = Module.new do
|
|
61
61
|
end
|
62
62
|
|
63
63
|
def bundler_version
|
64
|
-
@bundler_version ||=
|
64
|
+
@bundler_version ||=
|
65
65
|
env_var_version || cli_arg_version ||
|
66
|
-
lockfile_version
|
67
|
-
|
66
|
+
lockfile_version
|
67
|
+
end
|
68
|
+
|
69
|
+
def bundler_requirement
|
70
|
+
return "#{Gem::Requirement.default}.a" unless bundler_version
|
71
|
+
|
72
|
+
bundler_gem_version = Gem::Version.new(bundler_version)
|
73
|
+
|
74
|
+
requirement = bundler_gem_version.approximate_recommendation
|
75
|
+
|
76
|
+
return requirement unless Gem::Version.new(Gem::VERSION) < Gem::Version.new("2.7.0")
|
77
|
+
|
78
|
+
requirement += ".a" if bundler_gem_version.prerelease?
|
79
|
+
|
80
|
+
requirement
|
68
81
|
end
|
69
82
|
|
70
83
|
def load_bundler!
|
71
84
|
ENV["BUNDLE_GEMFILE"] ||= gemfile
|
72
85
|
|
73
|
-
|
74
|
-
activate_bundler(bundler_version.dup)
|
86
|
+
activate_bundler
|
75
87
|
end
|
76
88
|
|
77
|
-
def activate_bundler
|
78
|
-
if Gem::Version.correct?(bundler_version) && Gem::Version.new(bundler_version).release < Gem::Version.new("2.0")
|
79
|
-
bundler_version = "< 2"
|
80
|
-
end
|
89
|
+
def activate_bundler
|
81
90
|
gem_error = activation_error_handling do
|
82
|
-
gem "bundler",
|
91
|
+
gem "bundler", bundler_requirement
|
83
92
|
end
|
84
93
|
return if gem_error.nil?
|
85
94
|
require_error = activation_error_handling do
|
86
95
|
require "bundler/version"
|
87
96
|
end
|
88
|
-
return if require_error.nil? && Gem::Requirement.new(
|
89
|
-
warn "Activating bundler (#{
|
97
|
+
return if require_error.nil? && Gem::Requirement.new(bundler_requirement).satisfied_by?(Gem::Version.new(Bundler::VERSION))
|
98
|
+
warn "Activating bundler (#{bundler_requirement}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_requirement}'`"
|
90
99
|
exit 42
|
91
100
|
end
|
92
101
|
|
data/graphiti_graphql.gemspec
CHANGED
@@ -27,7 +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", "
|
30
|
+
spec.add_dependency "graphiti", "~> 1.3"
|
31
31
|
spec.add_dependency "activesupport", ">= 4.1"
|
32
32
|
spec.add_dependency "graphql", "~> 1.12"
|
33
33
|
|
data/lib/graphiti_graphql.rb
CHANGED
@@ -13,7 +13,7 @@ require "graphiti_graphql/util"
|
|
13
13
|
|
14
14
|
module GraphitiGraphQL
|
15
15
|
class Configuration
|
16
|
-
attr_accessor :schema_reloading
|
16
|
+
attr_accessor :schema_reloading, :federation_application_controller
|
17
17
|
|
18
18
|
def initialize
|
19
19
|
self.schema_reloading = true
|
@@ -74,6 +74,10 @@ module GraphitiGraphQL
|
|
74
74
|
@config ||= Configuration.new
|
75
75
|
end
|
76
76
|
|
77
|
+
def self.configure
|
78
|
+
yield config
|
79
|
+
end
|
80
|
+
|
77
81
|
def self.schemas
|
78
82
|
@schemas ||= SchemaProxy.new
|
79
83
|
end
|
@@ -64,12 +64,15 @@ module GraphitiGraphQL
|
|
64
64
|
end
|
65
65
|
|
66
66
|
initializer "graphiti_graphql.define_controller" do
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
67
|
+
GraphitiGraphQL::Engine.reloader_class.to_prepare do
|
68
|
+
app_controller = GraphitiGraphQL.config.federation_application_controller || ::ApplicationController
|
69
|
+
# rubocop:disable Lint/ConstantDefinitionInBlock(Standard)
|
70
|
+
class GraphitiGraphQL::ExecutionController < app_controller
|
71
|
+
register_exception Graphiti::Errors::UnreadableAttribute, message: true
|
72
|
+
def execute
|
73
|
+
params = request.params # avoid strong_parameters
|
74
|
+
render json: Graphiti.gql(params[:query], params[:variables])
|
75
|
+
end
|
73
76
|
end
|
74
77
|
end
|
75
78
|
end
|
@@ -21,6 +21,18 @@ module GraphitiGraphQL
|
|
21
21
|
@relationships[name].instance_eval(&blk)
|
22
22
|
end
|
23
23
|
end
|
24
|
+
|
25
|
+
def polymorphic?
|
26
|
+
@type_name.is_a?(Hash)
|
27
|
+
end
|
28
|
+
|
29
|
+
def klass_name
|
30
|
+
if polymorphic?
|
31
|
+
"I#{@relationships.keys[0].to_s.camelize}"
|
32
|
+
else
|
33
|
+
@type_name
|
34
|
+
end
|
35
|
+
end
|
24
36
|
end
|
25
37
|
end
|
26
38
|
end
|
@@ -15,6 +15,19 @@ module GraphitiGraphQL
|
|
15
15
|
|
16
16
|
@federated_relationship.params_block&.call(@params)
|
17
17
|
|
18
|
+
if (first = @params.delete(:first))
|
19
|
+
@params[:page] ||= {}
|
20
|
+
@params[:page][:size] = first
|
21
|
+
end
|
22
|
+
if (after = @params.delete(:after))
|
23
|
+
@params[:page] ||= {}
|
24
|
+
@params[:page][:after] = after
|
25
|
+
end
|
26
|
+
if (before = @params.delete(:before))
|
27
|
+
@params[:page] ||= {}
|
28
|
+
@params[:page][:before] = before
|
29
|
+
end
|
30
|
+
|
18
31
|
if ids.length > 1 && @params[:page]
|
19
32
|
raise Graphiti::Errors::UnsupportedPagination
|
20
33
|
elsif !@params[:page]
|
@@ -64,18 +64,30 @@ module GraphitiGraphQL
|
|
64
64
|
# * Add to the list of external graphql-ruby types we need in schema
|
65
65
|
# * Add a gql-specific attribute to the serializer that gives apollo
|
66
66
|
# the representation it needs.
|
67
|
-
def federated_belongs_to(name, type: nil, foreign_key: nil)
|
67
|
+
def federated_belongs_to(name, type: nil, foreign_key: nil, foreign_type: nil)
|
68
68
|
type ||= name.to_s.camelize
|
69
69
|
foreign_key ||= :"#{name.to_s.underscore}_id"
|
70
70
|
resource = FederatedResource.new(type)
|
71
71
|
federated_resources << resource
|
72
72
|
resource.add_relationship(:belongs_to, name, self, foreign_key)
|
73
73
|
|
74
|
+
foreign_type ||= :"#{name.to_s.underscore}_type" if resource.polymorphic?
|
75
|
+
|
74
76
|
opts = {readable: :gql?, only: [:readable], schema: false}
|
75
77
|
attribute name, :hash, opts do
|
76
78
|
prc = self.class.attribute_blocks[foreign_key]
|
77
79
|
fk = prc ? instance_eval(&prc) : @object.send(foreign_key)
|
78
|
-
|
80
|
+
|
81
|
+
typename = type
|
82
|
+
if resource.polymorphic?
|
83
|
+
prc = self.class.attribute_blocks[foreign_type]
|
84
|
+
ft = prc ? instance_eval(&prc) : @object.send(foreign_type)
|
85
|
+
typename = type[ft]
|
86
|
+
end
|
87
|
+
|
88
|
+
if fk && typename.present?
|
89
|
+
{__typename: typename, id: fk.to_s}
|
90
|
+
end
|
79
91
|
end
|
80
92
|
end
|
81
93
|
end
|
@@ -66,19 +66,39 @@ module GraphitiGraphQL
|
|
66
66
|
pre_registered = !!type_registry[federated_resource.type_name]
|
67
67
|
type_class = if pre_registered
|
68
68
|
type_registry[federated_resource.type_name][:type]
|
69
|
+
elsif federated_resource.polymorphic?
|
70
|
+
add_federated_resource_interface(federated_resource)
|
69
71
|
else
|
70
|
-
add_federated_resource_type(federated_resource.
|
72
|
+
add_federated_resource_type(federated_resource.klass_name)
|
71
73
|
end
|
72
74
|
|
73
75
|
yield type_class, federated_resource
|
74
76
|
end
|
75
77
|
end
|
76
78
|
|
77
|
-
def
|
79
|
+
def add_federated_resource_interface(federated_resource)
|
80
|
+
interface = define_polymorphic_federated_resource_interface(federated_resource.klass_name)
|
81
|
+
federated_resource.type_name.values.each do |name|
|
82
|
+
add_federated_resource_type(name, interface: interface)
|
83
|
+
end
|
84
|
+
interface
|
85
|
+
end
|
86
|
+
|
87
|
+
def define_polymorphic_federated_resource_interface(klass_name)
|
88
|
+
interface = Module.new
|
89
|
+
interface.send(:include, @schema.class.base_interface)
|
90
|
+
interface.graphql_name(klass_name)
|
91
|
+
interface.field :id, String, null: false, external: true
|
92
|
+
type_registry[klass_name] = {type: interface, interface: true}
|
93
|
+
interface
|
94
|
+
end
|
95
|
+
|
96
|
+
def add_federated_resource_type(klass_name, interface: nil)
|
78
97
|
federated_type = Class.new(@schema.class.base_object)
|
79
98
|
federated_type.graphql_name klass_name
|
80
99
|
federated_type.key(fields: "id")
|
81
100
|
federated_type.extend_type
|
101
|
+
federated_type.implements(interface) if interface
|
82
102
|
federated_type.field :id, String, null: false, external: true
|
83
103
|
federated_type.class_eval do
|
84
104
|
def self.resolve_reference(reference, _context, _lookup)
|
@@ -161,7 +181,7 @@ module GraphitiGraphQL
|
|
161
181
|
|
162
182
|
local_types.each do |local|
|
163
183
|
local.field relationship.name,
|
164
|
-
type_registry[federated_resource.
|
184
|
+
type_registry[federated_resource.klass_name][:type],
|
165
185
|
null: true
|
166
186
|
end
|
167
187
|
end
|
@@ -282,11 +282,23 @@ module GraphitiGraphQL
|
|
282
282
|
def gather_pages(params, selection, variable_hash, chained_name = nil)
|
283
283
|
pages = {}.tap do |p|
|
284
284
|
selection.arguments.each do |arg|
|
285
|
-
if
|
285
|
+
if ["page", "first", "after", "before"].include?(arg.name)
|
286
286
|
value = if arg.value.respond_to?(:name) # is a variable
|
287
|
-
variable_hash[arg.value.name]
|
287
|
+
variable_hash[arg.value.name]
|
288
288
|
else
|
289
|
-
arg.value
|
289
|
+
arg.value
|
290
|
+
end
|
291
|
+
|
292
|
+
next unless value
|
293
|
+
|
294
|
+
value = if arg.name == "first"
|
295
|
+
{size: value}
|
296
|
+
elsif arg.name == "after"
|
297
|
+
{after: value}
|
298
|
+
elsif arg.name == "before"
|
299
|
+
{before: value}
|
300
|
+
else
|
301
|
+
value.to_h
|
290
302
|
end
|
291
303
|
|
292
304
|
if chained_name
|
@@ -304,6 +316,13 @@ module GraphitiGraphQL
|
|
304
316
|
params[:page] ||= {}
|
305
317
|
params[:page].merge!(pages)
|
306
318
|
end
|
319
|
+
|
320
|
+
(selection.try(:selections) || []).each do |sub|
|
321
|
+
if sub.try(:name) == "pageInfo"
|
322
|
+
params[:fields] ||= {}
|
323
|
+
params[:fields][:page_info] = sub.selections.map(&:name).map(&:underscore).join(",")
|
324
|
+
end
|
325
|
+
end
|
307
326
|
end
|
308
327
|
|
309
328
|
def gather_stats(params, selection, variable_hash, chained_name = nil)
|
@@ -93,6 +93,7 @@ module GraphitiGraphQL
|
|
93
93
|
query_class = Class.new(existing_query || self.class.base_object)
|
94
94
|
# NB MUST be Query or federation-ruby will break things
|
95
95
|
query_class.graphql_name "Query"
|
96
|
+
query_class.field_class BaseField
|
96
97
|
|
97
98
|
get_entrypoints(entrypoint_resources).each do |resource|
|
98
99
|
next if resource.remote?
|
@@ -145,22 +146,46 @@ module GraphitiGraphQL
|
|
145
146
|
[type],
|
146
147
|
"List #{resource.graphql_class_name(false).pluralize}",
|
147
148
|
null: false
|
149
|
+
|
150
|
+
# Stats currently only supported on top level
|
148
151
|
if top_level
|
152
|
+
klass.field :page_info, PageInfoType, null: false
|
149
153
|
klass.field :stats, generate_stat_class(resource), null: false
|
150
154
|
end
|
151
155
|
register(name, klass)
|
152
156
|
klass
|
153
157
|
end
|
154
158
|
|
159
|
+
# def edge_type(name, type)
|
160
|
+
# if (registered = type_registry[name])
|
161
|
+
# return registered[:type]
|
162
|
+
# end
|
163
|
+
|
164
|
+
# klass = Class.new(BaseObject) do
|
165
|
+
# graphql_name "#{name}Edge"
|
166
|
+
# field :cursor, String, null: false
|
167
|
+
# field :node, type, null: false
|
168
|
+
# end
|
169
|
+
# type_registry[name] = {type: klass}
|
170
|
+
# klass
|
171
|
+
# end
|
172
|
+
|
155
173
|
def add_index(query_class, resource)
|
156
174
|
field_name = resource.graphql_entrypoint.to_s.underscore.to_sym
|
157
175
|
field = query_class.field field_name,
|
158
176
|
generate_connection_type(resource, top_level: true),
|
159
|
-
null: false
|
177
|
+
null: false,
|
178
|
+
connection: false
|
160
179
|
@query_fields[field_name] = resource
|
161
180
|
define_arguments_for_sideload_field(field, resource)
|
162
181
|
end
|
163
182
|
|
183
|
+
def apply_connection_args(field)
|
184
|
+
field.argument :after, "String", "Cursor to paginate after", required: false
|
185
|
+
field.argument :before, "String", "Cursor to paginate before", required: false
|
186
|
+
field.argument :first, "Int", "Same as page.size", required: false
|
187
|
+
end
|
188
|
+
|
164
189
|
def add_show(query_class, resource)
|
165
190
|
field_name = resource.graphql_entrypoint.to_s.underscore.singularize.to_sym
|
166
191
|
field = query_class.field field_name,
|
@@ -222,6 +247,7 @@ module GraphitiGraphQL
|
|
222
247
|
field.argument :sort, [sort_type], required: false
|
223
248
|
end
|
224
249
|
field.argument :page, PageType, required: false
|
250
|
+
apply_connection_args(field)
|
225
251
|
|
226
252
|
unless resource.filters.empty?
|
227
253
|
filter_type = generate_filter_type(field, resource)
|
@@ -375,6 +401,8 @@ module GraphitiGraphQL
|
|
375
401
|
end
|
376
402
|
end
|
377
403
|
|
404
|
+
klass.field :_cursor, String, null: false
|
405
|
+
|
378
406
|
register(type_name, klass, resource, poly_parent)
|
379
407
|
|
380
408
|
resource.sideloads.each_pair do |name, sideload|
|
@@ -480,6 +508,16 @@ module GraphitiGraphQL
|
|
480
508
|
graphql_name "Page"
|
481
509
|
argument :size, Int, required: false
|
482
510
|
argument :number, Int, required: false
|
511
|
+
argument :after, String, required: false
|
512
|
+
argument :before, String, required: false
|
513
|
+
end
|
514
|
+
|
515
|
+
class PageInfoType < BaseObject
|
516
|
+
graphql_name "PageInfo"
|
517
|
+
field :has_next_page, Boolean, null: false
|
518
|
+
field :has_previous_page, Boolean, null: false
|
519
|
+
field :start_cursor, String, null: false
|
520
|
+
field :end_cursor, String, null: false
|
483
521
|
end
|
484
522
|
|
485
523
|
class SortDirType < GraphQL::Schema::Enum
|
metadata
CHANGED
@@ -1,29 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: graphiti_graphql
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lee Richmond
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-08-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: graphiti
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 1.
|
19
|
+
version: '1.3'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 1.
|
26
|
+
version: '1.3'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: activesupport
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -274,7 +274,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
274
274
|
- !ruby/object:Gem::Version
|
275
275
|
version: '0'
|
276
276
|
requirements: []
|
277
|
-
rubygems_version: 3.
|
277
|
+
rubygems_version: 3.2.22
|
278
278
|
signing_key:
|
279
279
|
specification_version: 4
|
280
280
|
summary: GraphQL support for Graphiti
|