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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5bee75fe735608862a522a16be4a9ab31900b45af74ff48d4294d114227bd543
4
- data.tar.gz: ade635fd51be3820845bfccb79bd17c2b5bcff0c961a930910299dda6c90fad2
3
+ metadata.gz: 40128f0eaf0ad7859fa35c67bb73b2a2fccf51829bb3914877ce0c19730def91
4
+ data.tar.gz: 6f3fe80c618aaa093dd2daec4aa726621c32d2228bb92ddfdfd00f6a610490af
5
5
  SHA512:
6
- metadata.gz: e6720bf46431df3c5f5c2906fdf94aac13e4255cdfcdb2c2eb1fbd40d58bd2e28b231a9e2238d13e5ec7aaab9bd9ff60f86de9086972e90ec372bd12fe902978
7
- data.tar.gz: 0aff8b2e2459bd1c94b674dce2ce9e618f63c1b0dffc3fe49a1766c59b6aa692db2d14ca05d45747f990069d2bf39ee1ac3d9413732ba14c88ffeebbf20fa351
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.2)
4
+ graphiti_graphql (0.1.6)
5
5
  activesupport (>= 4.1)
6
- graphiti (>= 1.2.36)
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.7.2)
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.5.0)
34
+ dry-core (0.7.1)
35
35
  concurrent-ruby (~> 1.0)
36
- dry-inflector (0.2.0)
37
- dry-logic (1.1.0)
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.2.36)
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.0.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 || ">= 0.a"
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 ||= begin
64
+ @bundler_version ||=
65
65
  env_var_version || cli_arg_version ||
66
- lockfile_version || "#{Gem::Requirement.default}.a"
67
- end
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
- # must dup string for RG < 1.8 compatibility
74
- activate_bundler(bundler_version.dup)
86
+ activate_bundler
75
87
  end
76
88
 
77
- def activate_bundler(bundler_version)
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", bundler_version
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(bundler_version).satisfied_by?(Gem::Version.new(Bundler::VERSION))
89
- warn "Activating bundler (#{bundler_version}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_version}'`"
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
 
@@ -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", ">= 1.2.36"
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
 
@@ -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
- # rubocop:disable Lint/ConstantDefinitionInBlock(Standard)
68
- class GraphitiGraphQL::ExecutionController < ::ApplicationController
69
- register_exception Graphiti::Errors::UnreadableAttribute, message: true
70
- def execute
71
- params = request.params # avoid strong_parameters
72
- render json: Graphiti.gql(params[:query], params[:variables])
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
- {__typename: type, id: fk.to_s}
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.type_name)
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 add_federated_resource_type(klass_name)
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.type_name][:type],
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 arg.name == "page"
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].to_h
287
+ variable_hash[arg.value.name]
288
288
  else
289
- arg.value.to_h
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
@@ -1,3 +1,3 @@
1
1
  module GraphitiGraphQL
2
- VERSION = "0.1.4"
2
+ VERSION = "0.1.8"
3
3
  end
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
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-06-07 00:00:00.000000000 Z
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.2.36
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.2.36
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.0.3
277
+ rubygems_version: 3.2.22
278
278
  signing_key:
279
279
  specification_version: 4
280
280
  summary: GraphQL support for Graphiti