lighthouse-graphql 0.3.0 → 0.4.0

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.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +44 -1
  3. data/README.md +11 -3
  4. data/docs/best-practices.md +16 -6
  5. data/docs/configuration.md +7 -6
  6. data/docs/directives.md +31 -6
  7. data/docs/events.md +3 -1
  8. data/docs/federation.md +3 -2
  9. data/docs/getting-started.md +52 -14
  10. data/docs/motivation.md +3 -2
  11. data/docs/resolvers.md +93 -19
  12. data/docs/security.md +210 -0
  13. data/docs/subscriptions.md +60 -37
  14. data/lib/generators/lighthouse/base_classes.rb +87 -0
  15. data/lib/generators/lighthouse/class_generator.rb +19 -8
  16. data/lib/generators/lighthouse/install/install_generator.rb +23 -6
  17. data/lib/generators/lighthouse/install/templates/initializer.rb.tt +7 -6
  18. data/lib/generators/lighthouse/install/templates/schema.rb.tt +14 -2
  19. data/lib/generators/lighthouse/mutation_generator.rb +5 -4
  20. data/lib/generators/lighthouse/query_generator.rb +5 -4
  21. data/lib/generators/lighthouse/subscription_generator.rb +21 -16
  22. data/lib/lighthouse/complexity.rb +174 -0
  23. data/lib/lighthouse/complexity_analyzer.rb +56 -0
  24. data/lib/lighthouse/config.rb +4 -3
  25. data/lib/lighthouse/directive_resolvers/convention_resolver.rb +14 -4
  26. data/lib/lighthouse/directive_resolvers/convert_empty_strings_resolver.rb +1 -1
  27. data/lib/lighthouse/directive_resolvers/subscription_resolver.rb +12 -4
  28. data/lib/lighthouse/directives/registry.rb +1 -0
  29. data/lib/lighthouse/events/execution_trace.rb +2 -1
  30. data/lib/lighthouse/events/lifecycle.rb +3 -1
  31. data/lib/lighthouse/field_resolver_stack.rb +8 -7
  32. data/lib/lighthouse/graphql/version.rb +1 -1
  33. data/lib/lighthouse/rb_lighthouse.rb +3 -0
  34. data/lib/lighthouse/resolver_bases.rb +61 -0
  35. data/lib/lighthouse/schema_factory.rb +0 -1
  36. data/lib/lighthouse/schema_generator.rb +15 -7
  37. data/lib/lighthouse/sdl_loader.rb +0 -2
  38. data/lib/lighthouse/support/model_resolver.rb +1 -1
  39. data/sig/lighthouse/graphql.rbs +29 -0
  40. metadata +6 -1
@@ -30,7 +30,6 @@ module Lighthouse::GraphQL::SchemaFactory
30
30
  folder = sdl_folder || (Lighthouse::GraphQL::Config.sdl_folder if defined?(Lighthouse::GraphQL::Config))
31
31
  return Lighthouse::GraphQL::SDLLoader.load_from_folder(folder) if folder && Dir.exist?(folder)
32
32
 
33
- # fallback to apps/chatwoot/schema.graphql
34
33
  File.read(File.expand_path('../../schema.graphql', __dir__))
35
34
  end
36
35
  end
@@ -45,17 +45,21 @@ module Lighthouse::GraphQL::SchemaGenerator
45
45
  # and fresh (see SchemaCache), else built now.
46
46
  document = build_document(sdl_string)
47
47
  impl = default_implementation
48
+ # base_types' resolver / mutation / subscription are Lighthouse's, not graphql-ruby's.
49
+ bases = Lighthouse::GraphQL::ResolverBases.extract!(opts)
48
50
  schema = from_document(document, impl, opts)
49
51
 
50
52
  delegate_to_federation_sdl(schema)
51
53
  Lighthouse::GraphQL::GeneratedResolvers.install_dispatcher(schema)
52
54
  attach_schema(impl, schema)
53
- post_process(schema, impl, **opts)
55
+ post_process(schema, impl, bases: bases, **opts)
54
56
  schema.trace_with(Lighthouse::Events::ExecutionTrace)
55
57
 
56
58
  # @cacheControl hints become the response's Cache-Control header,
57
59
  # computed per query from the fields it selects.
58
60
  schema.query_analyzer(Lighthouse::GraphQL::CacheControl::Analyzer) if uses_cache_control
61
+ # The score graphql-ruby checks against max_complexity, for BuildExtensionsResponse.
62
+ schema.query_analyzer(Lighthouse::GraphQL::Complexity::Analyzer)
59
63
 
60
64
  schema
61
65
  end
@@ -124,7 +128,8 @@ module Lighthouse::GraphQL::SchemaGenerator
124
128
  augment_sdl_with_connections(inject_directive_definitions(sdl))
125
129
  end
126
130
 
127
- def post_process(schema, _impl, **_opts)
131
+ # `bases`: { root kind => the base class its fields' classes inherit from } (ResolverBases).
132
+ def post_process(schema, _impl, bases: {}, **_opts)
128
133
  root_kinds = root_kinds(schema)
129
134
 
130
135
  # Inspect types and fields for directives and attach generated resolvers
@@ -134,9 +139,12 @@ module Lighthouse::GraphQL::SchemaGenerator
134
139
  # Apply object-level federation directives to generated types so the
135
140
  # Apollo Federation helper can detect entities and add _entities.
136
141
  Lighthouse::GraphQL::FederationDirectives.apply(type)
137
- type.fields.each_value { |field_def| process_field(type, field_def, root_kinds[type.graphql_name]) }
142
+ type.fields.each_value { |field_def| process_field(type, field_def, root_kinds[type.graphql_name], bases) }
138
143
  end
139
144
 
145
+ # @complexity, and paginated fields, give graphql-ruby's complexity analysis their cost.
146
+ Lighthouse::GraphQL::Complexity.apply(schema, root_kinds)
147
+
140
148
  # @feature hides a field or type per query, through graphql-ruby's visibility.
141
149
  Lighthouse::GraphQL::FeatureDirective.apply(schema)
142
150
 
@@ -155,10 +163,10 @@ module Lighthouse::GraphQL::SchemaGenerator
155
163
 
156
164
  # A field's generated resolvers, then the runtime hooks that make
157
165
  # graphql-ruby reach them.
158
- def process_field(type, field_def, root_kind)
166
+ def process_field(type, field_def, root_kind, bases = {})
159
167
  return unless field_def.ast_node
160
168
 
161
- apply_field_resolvers(type, field_def, field_def.ast_node.directives || [], root_kind)
169
+ apply_field_resolvers(type, field_def, field_def.ast_node.directives || [], root_kind, bases)
162
170
  Lighthouse::GraphQL::GeneratedResolvers.route_runtime_resolver(type, field_def)
163
171
  ensure_connection_extension(field_def)
164
172
  end
@@ -180,8 +188,8 @@ module Lighthouse::GraphQL::SchemaGenerator
180
188
  end
181
189
 
182
190
  # A field's resolvers, installed in resolution order (see FieldResolverStack).
183
- def apply_field_resolvers(type, field_def, directives, root_kind)
184
- Lighthouse::GraphQL::FieldResolverStack.apply(type, field_def, directives, root_kind)
191
+ def apply_field_resolvers(type, field_def, directives, root_kind, bases = {})
192
+ Lighthouse::GraphQL::FieldResolverStack.apply(type, field_def, directives, root_kind, bases: bases)
185
193
  end
186
194
 
187
195
  # Scan SDL string for list-typed fields that carry relationship directives
@@ -6,8 +6,6 @@ module Lighthouse::GraphQL::SDLLoader
6
6
  def load_from_folder(folder)
7
7
  files = Dir[File.join(folder, '**', '*.graphql')]
8
8
  if files.empty?
9
- # fallback to the monolithic schema.graphql in apps/chatwoot
10
- # schema.graphql is located at apps/chatwoot/schema.graphql
11
9
  default = File.expand_path('../../..//schema.graphql', __dir__)
12
10
  return File.read(default) if File.exist?(default)
13
11
 
@@ -25,7 +25,7 @@ module Lighthouse::Support::ModelResolver
25
25
 
26
26
  # `namespaces:` overrides the configured resolver_namespaces, e.g. with
27
27
  # Config.namespaces[:builders] to look a builder class up.
28
- # `fallback: false` skips the bare name, so `Queries::User` is never
28
+ # `fallback: false` skips the bare name, so `Resolvers::User` is never
29
29
  # mistaken for the `User` model.
30
30
  def constantize(name, namespaces: self.namespaces, fallback: true)
31
31
  return nil unless name
@@ -97,6 +97,35 @@ module Lighthouse
97
97
  def self?.apply: (untyped response, untyped result) -> String?
98
98
  end
99
99
 
100
+ # What fields cost in graphql-ruby's complexity analysis (@complexity, and
101
+ # paginated fields scaled by `first`).
102
+ module Complexity
103
+ DEFINITION: String
104
+ CONTEXT_KEY: Symbol
105
+
106
+ # Give the schema's fields their cost; `root_kinds` maps root type names to
107
+ # :queries / :mutations / :subscriptions.
108
+ def self?.apply: (untyped schema, ?Hash[String, Symbol] root_kinds) -> untyped
109
+ # A query's score, once scored for BuildExtensionsResponse; nil otherwise.
110
+ def self?.query_complexity: (untyped query) -> Integer?
111
+ end
112
+
113
+ # A concern for a GraphQL::Analysis::Analyzer that @complexity(resolver:)
114
+ # names (graphql-ruby ships no RBS, so the class it is included in is not
115
+ # declared): its `complexity` is the cost of the fields naming the class.
116
+ module ComplexityAnalyzer
117
+ # Only when the class has a `result` of its own.
118
+ def analyze?: () -> bool
119
+ def result: () -> nil
120
+
121
+ # The class methods the concern adds to its includer.
122
+ module ClassMethods
123
+ # A number (added to the selection's cost) or a proc of
124
+ # (context, args, child_complexity); nil when never set.
125
+ def complexity: (?(Numeric | ^(context, arguments, Integer) -> Integer)? new_complexity) -> (Numeric | ^(context, arguments, Integer) -> Integer)?
126
+ end
127
+ end
128
+
100
129
  # The opt-in cache of the manipulated schema document, in tmp/cache.
101
130
  module SchemaCache
102
131
  PREFIX: String
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lighthouse-graphql
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vaz Innovation
@@ -68,8 +68,10 @@ files:
68
68
  - docs/performance.md
69
69
  - docs/relationships.md
70
70
  - docs/resolvers.md
71
+ - docs/security.md
71
72
  - docs/subscriptions.md
72
73
  - docs/validation.md
74
+ - lib/generators/lighthouse/base_classes.rb
73
75
  - lib/generators/lighthouse/builder_generator.rb
74
76
  - lib/generators/lighthouse/class_generator.rb
75
77
  - lib/generators/lighthouse/install/install_generator.rb
@@ -87,6 +89,8 @@ files:
87
89
  - lib/lighthouse/broadcasting.rb
88
90
  - lib/lighthouse/cache_control.rb
89
91
  - lib/lighthouse/caching.rb
92
+ - lib/lighthouse/complexity.rb
93
+ - lib/lighthouse/complexity_analyzer.rb
90
94
  - lib/lighthouse/config.rb
91
95
  - lib/lighthouse/contracts/arg_builder.rb
92
96
  - lib/lighthouse/contracts/arg_manipulator.rb
@@ -161,6 +165,7 @@ files:
161
165
  - lib/lighthouse/rb_lighthouse.rb
162
166
  - lib/lighthouse/reference_resolver.rb
163
167
  - lib/lighthouse/relation_batch.rb
168
+ - lib/lighthouse/resolver_bases.rb
164
169
  - lib/lighthouse/resolver_dispatch.rb
165
170
  - lib/lighthouse/schema_cache.rb
166
171
  - lib/lighthouse/schema_factory.rb