lighthouse-graphql 0.5.0 → 0.7.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +212 -1
- data/README.md +38 -22
- data/docs/best-practices.md +6 -4
- data/docs/caching.md +4 -3
- data/docs/configuration.md +20 -26
- data/docs/custom-directives.md +2 -1
- data/docs/directives.md +79 -14
- data/docs/federation.md +1 -1
- data/docs/filtering-and-ordering.md +330 -30
- data/docs/generators.md +42 -40
- data/docs/getting-started.md +128 -58
- data/docs/motivation.md +3 -2
- data/docs/performance.md +5 -4
- data/docs/relationships.md +7 -5
- data/docs/relay.md +63 -0
- data/docs/resolvers.md +92 -39
- data/docs/schema-organisation.md +177 -0
- data/docs/security.md +64 -16
- data/docs/subscriptions.md +16 -9
- data/docs/types.md +16 -17
- data/docs/uploads.md +41 -14
- data/lib/generators/lighthouse/base_classes.rb +9 -14
- data/lib/generators/lighthouse/install/graphql_ruby_install.rb +113 -0
- data/lib/generators/lighthouse/install/install_generator.rb +125 -99
- data/lib/generators/lighthouse/install/templates/graphql.config.yml.tt +2 -1
- data/lib/generators/lighthouse/install/templates/initializer.rb.tt +14 -13
- data/lib/lighthouse/ast_builder.rb +124 -0
- data/lib/lighthouse/caching.rb +9 -3
- data/lib/lighthouse/config.rb +27 -25
- data/lib/lighthouse/contracts/arg_manipulator.rb +9 -5
- data/lib/lighthouse/contracts/field_builder.rb +13 -0
- data/lib/lighthouse/controller.rb +28 -5
- data/lib/lighthouse/directive_resolvers/aggregate_resolver.rb +1 -2
- data/lib/lighthouse/directive_resolvers/all_resolver.rb +0 -2
- data/lib/lighthouse/directive_resolvers/argument_transforms_resolver.rb +18 -18
- data/lib/lighthouse/directive_resolvers/association_resolvers.rb +9 -6
- data/lib/lighthouse/directive_resolvers/base.rb +6 -37
- data/lib/lighthouse/directive_resolvers/builder_applier.rb +21 -6
- data/lib/lighthouse/directive_resolvers/cache_resolvers.rb +1 -1
- data/lib/lighthouse/directive_resolvers/count_resolver.rb +0 -1
- data/lib/lighthouse/directive_resolvers/first_resolver.rb +0 -2
- data/lib/lighthouse/directive_resolvers/global_id_resolver.rb +3 -1
- data/lib/lighthouse/directive_resolvers/paginate_resolver.rb +2 -3
- data/lib/lighthouse/directive_resolvers/throttle_resolver.rb +85 -26
- data/lib/lighthouse/directive_resolvers/type_method_resolver.rb +12 -6
- data/lib/lighthouse/directives/arguments/more_filters.rb +1 -1
- data/lib/lighthouse/directives/arguments/order_by.rb +190 -26
- data/lib/lighthouse/directives/arguments/where_conditions.rb +25 -0
- data/lib/lighthouse/directives/arguments/where_conditions_base.rb +84 -0
- data/lib/lighthouse/directives/arguments/where_has_conditions.rb +56 -0
- data/lib/lighthouse/directives/definitions.rb +0 -1
- data/lib/lighthouse/directives/generated_types.rb +103 -0
- data/lib/lighthouse/directives/registry.rb +39 -10
- data/lib/lighthouse/document_ast.rb +111 -0
- data/lib/lighthouse/field_resolver_stack.rb +9 -6
- data/lib/lighthouse/global_id.rb +29 -3
- data/lib/lighthouse/graphql/version.rb +1 -1
- data/lib/lighthouse/graphql_ruby_patches.rb +45 -0
- data/lib/lighthouse/ide_helper.rb +80 -23
- data/lib/lighthouse/namespaces.rb +1 -0
- data/lib/lighthouse/order_by/types.rb +137 -0
- data/lib/lighthouse/railtie.rb +9 -2
- data/lib/lighthouse/rb_lighthouse.rb +16 -5
- data/lib/lighthouse/resolve_info.rb +5 -5
- data/lib/lighthouse/resolver_bases.rb +18 -4
- data/lib/lighthouse/resolver_dispatch.rb +16 -1
- data/lib/lighthouse/root_types.rb +117 -0
- data/lib/lighthouse/schema_cache.rb +8 -4
- data/lib/lighthouse/schema_factory.rb +6 -9
- data/lib/lighthouse/schema_generator.rb +8 -18
- data/lib/lighthouse/schema_stitcher.rb +64 -0
- data/lib/lighthouse/support/naming.rb +0 -12
- data/lib/lighthouse/upload.rb +4 -2
- data/lib/lighthouse/upload_store.rb +39 -14
- data/lib/lighthouse/where_conditions/columns.rb +36 -0
- data/lib/lighthouse/where_conditions/handler.rb +152 -0
- data/lib/lighthouse/where_conditions/json_column.rb +99 -0
- data/lib/lighthouse/where_conditions/operator_map.rb +1 -4
- data/lib/lighthouse/where_conditions/types.rb +110 -0
- data/sig/lighthouse/directives.rbs +16 -3
- data/sig/lighthouse/graphql.rbs +48 -4
- data/sig/lighthouse.rbs +8 -12
- metadata +17 -7
- data/lib/generators/lighthouse/install/templates/schema.rb.tt +0 -29
- data/lib/generators/lighthouse/mutation_generator.rb +0 -31
- data/lib/generators/lighthouse/query_generator.rb +0 -30
- data/lib/lighthouse/directive_resolvers/where_conditions_applier.rb +0 -170
- data/lib/lighthouse/directives/where_conditions_directive.rb +0 -244
- data/lib/lighthouse/sdl_loader.rb +0 -22
|
@@ -36,9 +36,17 @@ module Lighthouse
|
|
|
36
36
|
include Directive
|
|
37
37
|
end
|
|
38
38
|
|
|
39
|
+
# Its instances, built with (arg_node, directive_node), answer
|
|
40
|
+
# `manipulate_arg_definition(document_ast, field_node, type_node)` with the argument node.
|
|
39
41
|
module ArgManipulator
|
|
40
42
|
include Directive
|
|
41
43
|
end
|
|
44
|
+
|
|
45
|
+
# Its instances, built with (field_node, directive_node), answer
|
|
46
|
+
# `handle_field_builder(relation)` with the constrained relation.
|
|
47
|
+
module FieldBuilder
|
|
48
|
+
include Directive
|
|
49
|
+
end
|
|
42
50
|
end
|
|
43
51
|
|
|
44
52
|
class DirectiveRegistry
|
|
@@ -67,6 +75,9 @@ module Lighthouse
|
|
|
67
75
|
def resolution_names: () -> Array[String]
|
|
68
76
|
def arg_builder_class: (String | Symbol name) -> Class?
|
|
69
77
|
def arg_builder_names: () -> Array[String]
|
|
78
|
+
def arg_manipulator_class: (String | Symbol name) -> Class?
|
|
79
|
+
def arg_manipulator_classes: () -> Array[Class]
|
|
80
|
+
def field_builder_class: (String | Symbol name) -> Class?
|
|
70
81
|
|
|
71
82
|
# { "name" => "directive @name(...) on ..." }
|
|
72
83
|
def directive_definitions: () -> Hash[String, String]
|
|
@@ -83,9 +94,11 @@ module Lighthouse
|
|
|
83
94
|
PROGRAMMATIC_TYPES_FILE: String
|
|
84
95
|
|
|
85
96
|
# Writes both files into `output_dir` and returns their paths.
|
|
86
|
-
def self?.write: (output_dir: path, ?
|
|
97
|
+
def self?.write: (output_dir: path, ?schema_path: path?, ?registry: DirectiveRegistry) -> Array[String]
|
|
98
|
+
# Config.ide_helper's rewrite, on boot and every reload.
|
|
99
|
+
def self?.refresh: (?output_dir: path) -> Array[String]
|
|
87
100
|
def self?.directives_sdl: (?String sdl, ?registry: DirectiveRegistry) -> String
|
|
88
|
-
def self?.programmatic_types_sdl: (String sdl, ?registry: DirectiveRegistry) -> String
|
|
101
|
+
def self?.programmatic_types_sdl: (String sdl, ?registry: DirectiveRegistry, ?directives: String) -> String
|
|
89
102
|
end
|
|
90
103
|
|
|
91
104
|
module GraphQL
|
|
@@ -107,7 +120,7 @@ module Lighthouse
|
|
|
107
120
|
# `ctx`: the query's context, which @builder on an argument receives.
|
|
108
121
|
def apply_where_filters: (relation relation, untyped args, ?context? ctx) -> relation
|
|
109
122
|
def apply_arg_builders: (relation relation, arguments args_h, ?context? ctx) -> relation
|
|
110
|
-
def
|
|
123
|
+
def apply_field_builders: (relation relation, ?arguments args_h, ?context? ctx) -> relation
|
|
111
124
|
def constantize_model: (String? name) -> Class?
|
|
112
125
|
def apply_scopes: (relation relation) -> relation
|
|
113
126
|
|
data/sig/lighthouse/graphql.rbs
CHANGED
|
@@ -9,16 +9,60 @@ module Lighthouse
|
|
|
9
9
|
type schema = untyped
|
|
10
10
|
|
|
11
11
|
module RbLightHouse
|
|
12
|
-
# The schema built from the SDL
|
|
12
|
+
# The schema built from the SDL `schema_path` (default: Config.schema_path) and its imports.
|
|
13
13
|
# `options` takes :base_types, :base_schema and the schema's own options.
|
|
14
|
-
def self.get_schema: (?
|
|
14
|
+
def self.get_schema: (?schema_path: path?, ?options: Hash[Symbol, untyped]) -> schema
|
|
15
15
|
def self.configure: () ?{ (singleton(Lighthouse::Config) config) -> void } -> void
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
module SchemaFactory
|
|
19
|
-
def self?.build_base_schema: (?
|
|
19
|
+
def self?.build_base_schema: (?schema_path: path?, ?sdl: String?, ?base_types: Hash[untyped, untyped],
|
|
20
20
|
?schema_options: Hash[Symbol, untyped], **untyped extra_options) -> schema
|
|
21
|
-
def self?.load_sdl: (path?
|
|
21
|
+
def self?.load_sdl: (?path? schema_path) -> String
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Reads the schema from its entrypoint, pasting in what it #imports.
|
|
25
|
+
class SchemaStitcher
|
|
26
|
+
IMPORT: String
|
|
27
|
+
|
|
28
|
+
attr_reader root_schema_path: String
|
|
29
|
+
|
|
30
|
+
def initialize: (path root_schema_path) -> void
|
|
31
|
+
def schema_string: () -> String
|
|
32
|
+
# Every file the schema is read from, the entrypoint first.
|
|
33
|
+
def files: () -> Array[String]
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# The schema document the manipulation phase works on: each type defined once.
|
|
37
|
+
class DocumentAST
|
|
38
|
+
KEYWORDS: Hash[Class, String]
|
|
39
|
+
EXTENSIONS: Array[Class]
|
|
40
|
+
|
|
41
|
+
attr_reader types: Hash[String, untyped]
|
|
42
|
+
attr_reader type_extensions: Hash[String, Array[untyped]]
|
|
43
|
+
attr_reader directives: Hash[String, untyped]
|
|
44
|
+
attr_reader schema_definitions: Array[untyped]
|
|
45
|
+
|
|
46
|
+
def self.from_source: (String sdl) -> DocumentAST
|
|
47
|
+
def self.from_document: (untyped document) -> DocumentAST
|
|
48
|
+
|
|
49
|
+
def initialize: () -> void
|
|
50
|
+
def add: (untyped definition) -> untyped
|
|
51
|
+
# Adds a type, or replaces the one of the same name.
|
|
52
|
+
def put_type: (untyped definition) -> self
|
|
53
|
+
# Adds the type parsed from the SDL (or the block's), unless one of the name exists.
|
|
54
|
+
def define_type: (String name, ?String? sdl) ?{ () -> String } -> untyped
|
|
55
|
+
def type?: (String name) -> bool
|
|
56
|
+
def type_names: () -> Array[String]
|
|
57
|
+
def to_document: () -> untyped
|
|
58
|
+
def to_sdl: () -> String
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# The manipulation phase: extensions merged, then the type, field and argument manipulators.
|
|
62
|
+
module ASTBuilder
|
|
63
|
+
ROOT_TYPES: Array[String]
|
|
64
|
+
|
|
65
|
+
def self?.build: (String sdl, ?registry: DirectiveRegistry) -> String
|
|
22
66
|
end
|
|
23
67
|
|
|
24
68
|
# Apollo's Automatic Persisted Queries, and a manifest of trusted operations.
|
data/sig/lighthouse.rbs
CHANGED
|
@@ -45,12 +45,6 @@ module Lighthouse
|
|
|
45
45
|
def decode: (String global_id) -> Array[String]
|
|
46
46
|
end
|
|
47
47
|
|
|
48
|
-
# Config.upload_store: stores the file an @upload argument carries, and returns
|
|
49
|
-
# what the argument holds instead (an ActiveStorage blob's signed id by default).
|
|
50
|
-
interface _UploadStore
|
|
51
|
-
def call: (untyped file, ?disk: String?, ?path: String?, ?public: bool?) -> untyped
|
|
52
|
-
end
|
|
53
|
-
|
|
54
48
|
# Config.authenticated_user and Config.policy_user: the user of a request.
|
|
55
49
|
interface _UserReader
|
|
56
50
|
def call: (context? context) -> untyped
|
|
@@ -98,8 +92,14 @@ module Lighthouse
|
|
|
98
92
|
def self.[]: (Symbol | String key) -> untyped
|
|
99
93
|
def self.reset!: () -> void
|
|
100
94
|
|
|
101
|
-
|
|
102
|
-
def self.
|
|
95
|
+
# The schema's entrypoint, which imports the other files (SchemaStitcher).
|
|
96
|
+
def self.schema_path: () -> path?
|
|
97
|
+
def self.schema_path=: (path? path) -> path?
|
|
98
|
+
def self.schema_directory: () -> String?
|
|
99
|
+
|
|
100
|
+
# Rewrite the IDE helper files on boot and every reload; nil: in development with a graphql.config.yml.
|
|
101
|
+
def self.ide_helper: () -> bool?
|
|
102
|
+
def self.ide_helper=: (bool? enabled) -> bool?
|
|
103
103
|
|
|
104
104
|
# { queries:, mutations:, subscriptions:, builders:, validators:, events: } => [namespace, ...].
|
|
105
105
|
# Assigning a partial hash overrides only the kinds it names.
|
|
@@ -112,8 +112,6 @@ module Lighthouse
|
|
|
112
112
|
def self.directive_map: () -> Hash[untyped, untyped]
|
|
113
113
|
|
|
114
114
|
# An ActiveSupport::Cache::Store; Rails.cache by default.
|
|
115
|
-
def self.cache_store: () -> untyped
|
|
116
|
-
def self.cache_store=: (untyped store) -> untyped
|
|
117
115
|
|
|
118
116
|
def self.transactional_mutations: () -> bool
|
|
119
117
|
def self.transactional_mutations=: (bool? enabled) -> bool?
|
|
@@ -147,8 +145,6 @@ module Lighthouse
|
|
|
147
145
|
def self.global_id: () -> _GlobalId
|
|
148
146
|
def self.global_id=: (_GlobalId? codec) -> _GlobalId?
|
|
149
147
|
|
|
150
|
-
def self.upload_store: () -> _UploadStore
|
|
151
|
-
def self.upload_store=: (_UploadStore? store) -> _UploadStore?
|
|
152
148
|
|
|
153
149
|
# Whether @broadcast triggers in an ActiveJob (Lighthouse::GraphQL::BroadcastJob)
|
|
154
150
|
# unless the directive says shouldQueue; and the job's queue (nil: ActiveJob's default).
|
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.
|
|
4
|
+
version: 0.7.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Vaz Innovation
|
|
@@ -70,6 +70,7 @@ files:
|
|
|
70
70
|
- docs/relationships.md
|
|
71
71
|
- docs/relay.md
|
|
72
72
|
- docs/resolvers.md
|
|
73
|
+
- docs/schema-organisation.md
|
|
73
74
|
- docs/security.md
|
|
74
75
|
- docs/subscriptions.md
|
|
75
76
|
- docs/types.md
|
|
@@ -78,17 +79,16 @@ files:
|
|
|
78
79
|
- lib/generators/lighthouse/base_classes.rb
|
|
79
80
|
- lib/generators/lighthouse/builder_generator.rb
|
|
80
81
|
- lib/generators/lighthouse/class_generator.rb
|
|
82
|
+
- lib/generators/lighthouse/install/graphql_ruby_install.rb
|
|
81
83
|
- lib/generators/lighthouse/install/install_generator.rb
|
|
82
84
|
- lib/generators/lighthouse/install/templates/graphql.config.yml.tt
|
|
83
85
|
- lib/generators/lighthouse/install/templates/graphql_controller.rb.tt
|
|
84
86
|
- lib/generators/lighthouse/install/templates/initializer.rb.tt
|
|
85
87
|
- lib/generators/lighthouse/install/templates/schema.graphql.tt
|
|
86
|
-
- lib/generators/lighthouse/install/templates/schema.rb.tt
|
|
87
|
-
- lib/generators/lighthouse/mutation_generator.rb
|
|
88
|
-
- lib/generators/lighthouse/query_generator.rb
|
|
89
88
|
- lib/generators/lighthouse/subscription_generator.rb
|
|
90
89
|
- lib/generators/lighthouse/validator_generator.rb
|
|
91
90
|
- lib/lighthouse-graphql.rb
|
|
91
|
+
- lib/lighthouse/ast_builder.rb
|
|
92
92
|
- lib/lighthouse/async_mutation_job.rb
|
|
93
93
|
- lib/lighthouse/broadcast_job.rb
|
|
94
94
|
- lib/lighthouse/broadcasting.rb
|
|
@@ -100,6 +100,7 @@ files:
|
|
|
100
100
|
- lib/lighthouse/contracts/arg_builder.rb
|
|
101
101
|
- lib/lighthouse/contracts/arg_manipulator.rb
|
|
102
102
|
- lib/lighthouse/contracts/directive.rb
|
|
103
|
+
- lib/lighthouse/contracts/field_builder.rb
|
|
103
104
|
- lib/lighthouse/contracts/field_manipulator.rb
|
|
104
105
|
- lib/lighthouse/contracts/field_middleware.rb
|
|
105
106
|
- lib/lighthouse/contracts/field_resolver.rb
|
|
@@ -145,7 +146,6 @@ files:
|
|
|
145
146
|
- lib/lighthouse/directive_resolvers/throttle_resolver.rb
|
|
146
147
|
- lib/lighthouse/directive_resolvers/type_method_resolver.rb
|
|
147
148
|
- lib/lighthouse/directive_resolvers/validator_resolver.rb
|
|
148
|
-
- lib/lighthouse/directive_resolvers/where_conditions_applier.rb
|
|
149
149
|
- lib/lighthouse/directive_resolvers/with_count_resolver.rb
|
|
150
150
|
- lib/lighthouse/directive_resolvers/with_resolver.rb
|
|
151
151
|
- lib/lighthouse/directives/arguments/base.rb
|
|
@@ -153,7 +153,11 @@ files:
|
|
|
153
153
|
- lib/lighthouse/directives/arguments/more_filters.rb
|
|
154
154
|
- lib/lighthouse/directives/arguments/order_by.rb
|
|
155
155
|
- lib/lighthouse/directives/arguments/soft_deletes.rb
|
|
156
|
+
- lib/lighthouse/directives/arguments/where_conditions.rb
|
|
157
|
+
- lib/lighthouse/directives/arguments/where_conditions_base.rb
|
|
158
|
+
- lib/lighthouse/directives/arguments/where_has_conditions.rb
|
|
156
159
|
- lib/lighthouse/directives/definitions.rb
|
|
160
|
+
- lib/lighthouse/directives/generated_types.rb
|
|
157
161
|
- lib/lighthouse/directives/model_directive.rb
|
|
158
162
|
- lib/lighthouse/directives/node_directive.rb
|
|
159
163
|
- lib/lighthouse/directives/pagination_info_types.rb
|
|
@@ -161,7 +165,7 @@ files:
|
|
|
161
165
|
- lib/lighthouse/directives/registry.rb
|
|
162
166
|
- lib/lighthouse/directives/soft_deletes_directive.rb
|
|
163
167
|
- lib/lighthouse/directives/visibility_directive.rb
|
|
164
|
-
- lib/lighthouse/
|
|
168
|
+
- lib/lighthouse/document_ast.rb
|
|
165
169
|
- lib/lighthouse/enum_directive.rb
|
|
166
170
|
- lib/lighthouse/errors.rb
|
|
167
171
|
- lib/lighthouse/events.rb
|
|
@@ -186,6 +190,7 @@ files:
|
|
|
186
190
|
- lib/lighthouse/nested_mutations/many_to_many_operations.rb
|
|
187
191
|
- lib/lighthouse/nested_mutations/partitioner.rb
|
|
188
192
|
- lib/lighthouse/node_registry.rb
|
|
193
|
+
- lib/lighthouse/order_by/types.rb
|
|
189
194
|
- lib/lighthouse/pagination.rb
|
|
190
195
|
- lib/lighthouse/persisted_queries.rb
|
|
191
196
|
- lib/lighthouse/persisted_queries/batch.rb
|
|
@@ -197,12 +202,13 @@ files:
|
|
|
197
202
|
- lib/lighthouse/resolve_info.rb
|
|
198
203
|
- lib/lighthouse/resolver_bases.rb
|
|
199
204
|
- lib/lighthouse/resolver_dispatch.rb
|
|
205
|
+
- lib/lighthouse/root_types.rb
|
|
200
206
|
- lib/lighthouse/scalar_coercion.rb
|
|
201
207
|
- lib/lighthouse/schema_cache.rb
|
|
202
208
|
- lib/lighthouse/schema_factory.rb
|
|
203
209
|
- lib/lighthouse/schema_generator.rb
|
|
204
210
|
- lib/lighthouse/schema_implementation.rb
|
|
205
|
-
- lib/lighthouse/
|
|
211
|
+
- lib/lighthouse/schema_stitcher.rb
|
|
206
212
|
- lib/lighthouse/subscription.rb
|
|
207
213
|
- lib/lighthouse/support/arguments.rb
|
|
208
214
|
- lib/lighthouse/support/authorization.rb
|
|
@@ -218,7 +224,11 @@ files:
|
|
|
218
224
|
- lib/lighthouse/type_resolution.rb
|
|
219
225
|
- lib/lighthouse/upload.rb
|
|
220
226
|
- lib/lighthouse/upload_store.rb
|
|
227
|
+
- lib/lighthouse/where_conditions/columns.rb
|
|
228
|
+
- lib/lighthouse/where_conditions/handler.rb
|
|
229
|
+
- lib/lighthouse/where_conditions/json_column.rb
|
|
221
230
|
- lib/lighthouse/where_conditions/operator_map.rb
|
|
231
|
+
- lib/lighthouse/where_conditions/types.rb
|
|
222
232
|
- sig/lighthouse.rbs
|
|
223
233
|
- sig/lighthouse/controller.rbs
|
|
224
234
|
- sig/lighthouse/directives.rbs
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
# Executable schema built by Lighthouse from the SDL in <%= sdl_folder %>/. The
|
|
4
|
-
# Dataloader batches relationship loads (@hasMany, @belongsTo, ...) to avoid N+1.
|
|
5
|
-
# base_types names the base classes: every class a Query, Mutation or Subscription
|
|
6
|
-
# field resolves to must inherit from its kind's, and a Subscription field with no
|
|
7
|
-
# class of its own resolves with the subscription one. graphql-ruby builds the
|
|
8
|
-
# SDL's types from the others (written by `rails g graphql:install`), and type
|
|
9
|
-
# classes (Types::PostType, Types::DateTimeType, ...) inherit from them.
|
|
10
|
-
<%= schema_name %> = Lighthouse::GraphQL::RbLightHouse.get_schema(
|
|
11
|
-
options: {
|
|
12
|
-
using: { GraphQL::Dataloader => {} },
|
|
13
|
-
base_types: {
|
|
14
|
-
resolver: <%= base_class_constant(:queries) %>,
|
|
15
|
-
mutation: <%= base_class_constant(:mutations) %>,
|
|
16
|
-
subscription: <%= base_class_constant(:subscriptions) %>,
|
|
17
|
-
object: Types::BaseObject,
|
|
18
|
-
interface: Types::BaseInterface,
|
|
19
|
-
union: Types::BaseUnion,
|
|
20
|
-
scalar: Types::BaseScalar,
|
|
21
|
-
enum: Types::BaseEnum,
|
|
22
|
-
input_object: Types::BaseInputObject
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
)
|
|
26
|
-
|
|
27
|
-
# Refuse expensive queries before they run (see the gem's docs/security.md):
|
|
28
|
-
# <%= schema_name %>.max_complexity(300)
|
|
29
|
-
# <%= schema_name %>.max_depth(12)
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative 'class_generator'
|
|
4
|
-
|
|
5
|
-
# `rails generate lighthouse:mutation PublishPost` — the class (a
|
|
6
|
-
# Mutations::BaseMutation, so a GraphQL::Schema::Mutation) that `Mutation.publishPost`
|
|
7
|
-
# resolves to by convention.
|
|
8
|
-
class Lighthouse::Generators::MutationGenerator < Lighthouse::Generators::ClassGenerator
|
|
9
|
-
desc 'Generate the class of a Mutation field (a Mutations::BaseMutation) in app/graphql/mutations.'
|
|
10
|
-
|
|
11
|
-
private
|
|
12
|
-
|
|
13
|
-
def kind = :mutations
|
|
14
|
-
|
|
15
|
-
def body
|
|
16
|
-
<<~RUBY
|
|
17
|
-
# Resolves Mutation.#{class_basename.camelize(:lower)}. Keyword arguments are the field's
|
|
18
|
-
# arguments in snake_case; `object` and `context` are available. Raise
|
|
19
|
-
# GraphQL::ExecutionError for failures the client should see.
|
|
20
|
-
class #{class_basename} < #{superclass_name}
|
|
21
|
-
def resolve(**args)
|
|
22
|
-
raise NotImplementedError
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
RUBY
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
def usage
|
|
29
|
-
"Mutation.#{class_basename.camelize(:lower)} resolves to #{full_class_name} — add the field to your SDL without a resolving directive."
|
|
30
|
-
end
|
|
31
|
-
end
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative 'class_generator'
|
|
4
|
-
|
|
5
|
-
# `rails generate lighthouse:query LatestPosts` — the resolver (a
|
|
6
|
-
# Resolvers::BaseResolver, so a GraphQL::Schema::Resolver) that `Query.latestPosts`
|
|
7
|
-
# resolves to by convention.
|
|
8
|
-
class Lighthouse::Generators::QueryGenerator < Lighthouse::Generators::ClassGenerator
|
|
9
|
-
desc 'Generate the resolver of a Query field (a Resolvers::BaseResolver) in app/graphql/resolvers.'
|
|
10
|
-
|
|
11
|
-
private
|
|
12
|
-
|
|
13
|
-
def kind = :queries
|
|
14
|
-
|
|
15
|
-
def body
|
|
16
|
-
<<~RUBY
|
|
17
|
-
# Resolves Query.#{class_basename.camelize(:lower)}. Keyword arguments are the field's
|
|
18
|
-
# arguments in snake_case; `object` and `context` are available.
|
|
19
|
-
class #{class_basename} < #{superclass_name}
|
|
20
|
-
def resolve(**args)
|
|
21
|
-
raise NotImplementedError
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
RUBY
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def usage
|
|
28
|
-
"Query.#{class_basename.camelize(:lower)} resolves to #{full_class_name} — add the field to your SDL without a resolving directive."
|
|
29
|
-
end
|
|
30
|
-
end
|
|
@@ -1,170 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
class Lighthouse::GraphQL::DirectiveResolvers::WhereConditionsApplier
|
|
4
|
-
# Operator semantics live in Lighthouse::WhereConditions::OperatorMap so
|
|
5
|
-
# they can be shared with the simple argument-filter directives.
|
|
6
|
-
SUPPORTED_OPERATORS = Lighthouse::WhereConditions::OperatorMap::OPERATORS
|
|
7
|
-
# graphql-ruby hands input objects over with Ruby-style keys, so the
|
|
8
|
-
# generated input's AND/OR/HAS fields arrive as :and/:or/:has.
|
|
9
|
-
LOGICAL_KEYS = { and: :AND, or: :OR, has: :HAS }.freeze
|
|
10
|
-
|
|
11
|
-
class << self
|
|
12
|
-
def apply(relation, value)
|
|
13
|
-
return relation unless relation.respond_to?(:where)
|
|
14
|
-
|
|
15
|
-
condition = normalize_condition(value)
|
|
16
|
-
return relation unless condition
|
|
17
|
-
|
|
18
|
-
# AND narrows the incoming scope step by step; each OR branch starts
|
|
19
|
-
# from the incoming scope, and their union replaces it.
|
|
20
|
-
result = apply_all(relation, condition[:AND])
|
|
21
|
-
result = apply_any(relation, condition[:OR]) || result
|
|
22
|
-
result = apply_has_condition(result, condition[:HAS])
|
|
23
|
-
result = apply_single_condition(result, condition) if condition.key?(:column)
|
|
24
|
-
result
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def apply_has(relation, has_cond)
|
|
28
|
-
relation_name = has_cond[:relation].to_s
|
|
29
|
-
return relation if relation_name.blank?
|
|
30
|
-
|
|
31
|
-
resolved_relation_name = resolve_relation_name(relation, relation_name)
|
|
32
|
-
return relation if resolved_relation_name.blank?
|
|
33
|
-
|
|
34
|
-
reflection = reflection_for(relation, resolved_relation_name)
|
|
35
|
-
return relation unless reflection&.klass
|
|
36
|
-
|
|
37
|
-
joined = relation.joins(resolved_relation_name.to_sym)
|
|
38
|
-
return joined.distinct if has_cond[:condition].blank?
|
|
39
|
-
|
|
40
|
-
# Use an EXISTS-style filter to safely apply conditions from the related model.
|
|
41
|
-
child_scope = apply(reflection.klass.all, has_cond[:condition])
|
|
42
|
-
joined.where(reflection.klass.table_name => { id: child_scope.select(:id) }).distinct
|
|
43
|
-
rescue StandardError
|
|
44
|
-
relation
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
def resolve_relation_name(relation, relation_name)
|
|
48
|
-
candidate_names = [relation_name.to_s, relation_name.to_s.singularize, relation_name.to_s.pluralize].uniq
|
|
49
|
-
|
|
50
|
-
candidate_names.each do |candidate|
|
|
51
|
-
next if candidate.blank?
|
|
52
|
-
return candidate if association_exists?(relation, candidate)
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
nil
|
|
56
|
-
rescue StandardError
|
|
57
|
-
nil
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
def association_exists?(relation, name)
|
|
61
|
-
reflection_for(relation, name).present?
|
|
62
|
-
rescue StandardError
|
|
63
|
-
false
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
def apply_has_argument(relation, arg_name, arg_value, relation_name = nil)
|
|
67
|
-
relation_name ||= derive_relation_name(arg_name)
|
|
68
|
-
return relation unless relation_name.present? && arg_value.present?
|
|
69
|
-
|
|
70
|
-
condition = arg_value.is_a?(Hash) ? arg_value : symbolized(arg_value)
|
|
71
|
-
has_payload = { relation: relation_name, condition: condition }
|
|
72
|
-
apply_has(relation, has_payload)
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
private
|
|
76
|
-
|
|
77
|
-
# The condition as a symbol-keyed Hash, or nil when there is none.
|
|
78
|
-
def normalize_condition(value)
|
|
79
|
-
return nil if value.nil?
|
|
80
|
-
|
|
81
|
-
condition = value.is_a?(Hash) ? value.deep_symbolize_keys : symbolized(value)
|
|
82
|
-
condition.transform_keys { |key| LOGICAL_KEYS.fetch(key, key) } if condition.is_a?(Hash)
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
def apply_all(relation, conditions)
|
|
86
|
-
Array(conditions).reduce(relation) { |acc, sub| apply(acc, sub) }
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
# The union of the branches, or nil when there are none.
|
|
90
|
-
def apply_any(relation, conditions)
|
|
91
|
-
Array(conditions).map { |sub| apply(relation, sub) }.reduce { |acc, sub_scope| acc.or(sub_scope) }
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
def apply_has_condition(relation, has_cond)
|
|
95
|
-
return relation unless has_cond.is_a?(Hash) && has_cond[:relation]
|
|
96
|
-
|
|
97
|
-
apply_has(relation, has_cond)
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
def reflection_for(relation, name)
|
|
101
|
-
klass = relation.respond_to?(:klass) ? relation.klass : relation
|
|
102
|
-
klass.reflect_on_association(name.to_sym) if klass.respond_to?(:reflect_on_association)
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
def derive_relation_name(arg_name)
|
|
106
|
-
Lighthouse::Support::Naming.derive_relation_name(arg_name)
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
def apply_single_condition(relation, condition)
|
|
110
|
-
return relation if condition[:column].blank? || !relation.respond_to?(:where)
|
|
111
|
-
|
|
112
|
-
column_name = resolve_column_name(condition[:column])
|
|
113
|
-
return relation if column_name.blank?
|
|
114
|
-
|
|
115
|
-
apply_operator(relation, column_name, operator_of(condition), condition[:value])
|
|
116
|
-
rescue StandardError
|
|
117
|
-
relation
|
|
118
|
-
end
|
|
119
|
-
|
|
120
|
-
def operator_of(condition)
|
|
121
|
-
condition[:operator]&.to_s&.upcase || 'EQ'
|
|
122
|
-
end
|
|
123
|
-
|
|
124
|
-
# Null and set operators are plain hash conditions; the rest need Arel.
|
|
125
|
-
def apply_operator(relation, column_name, operator, value)
|
|
126
|
-
case operator
|
|
127
|
-
when 'IS_NULL' then relation.where(column_name => nil)
|
|
128
|
-
when 'IS_NOT_NULL' then relation.where.not(column_name => nil)
|
|
129
|
-
when 'IN' then relation.where(column_name => Array(value))
|
|
130
|
-
when 'NIN' then relation.where.not(column_name => Array(value))
|
|
131
|
-
else apply_arel_operator(relation, column_name, operator, value)
|
|
132
|
-
end
|
|
133
|
-
end
|
|
134
|
-
|
|
135
|
-
# An unknown operator falls back to equality rather than failing the query.
|
|
136
|
-
def apply_arel_operator(relation, column_name, operator, value)
|
|
137
|
-
pattern = like_pattern(operator, value)
|
|
138
|
-
return relation.where(arel_table(relation)[column_name].matches(pattern)) if pattern
|
|
139
|
-
|
|
140
|
-
predicate = SUPPORTED_OPERATORS[operator]
|
|
141
|
-
return relation.where(column_name => value) unless predicate
|
|
142
|
-
|
|
143
|
-
relation.where(arel_table(relation)[column_name].public_send(predicate, value))
|
|
144
|
-
end
|
|
145
|
-
|
|
146
|
-
def like_pattern(operator, value)
|
|
147
|
-
case operator
|
|
148
|
-
when 'CONTAINS' then "%#{value}%"
|
|
149
|
-
when 'STARTS_WITH' then "#{value}%"
|
|
150
|
-
when 'ENDS_WITH' then "%#{value}"
|
|
151
|
-
end
|
|
152
|
-
end
|
|
153
|
-
|
|
154
|
-
def resolve_column_name(column)
|
|
155
|
-
Lighthouse::Support::Naming.column(column)
|
|
156
|
-
end
|
|
157
|
-
|
|
158
|
-
def arel_table(relation)
|
|
159
|
-
relation.klass.arel_table
|
|
160
|
-
end
|
|
161
|
-
|
|
162
|
-
def symbolized(obj)
|
|
163
|
-
if obj.respond_to?(:to_h)
|
|
164
|
-
obj.to_h.deep_symbolize_keys
|
|
165
|
-
else
|
|
166
|
-
{}
|
|
167
|
-
end
|
|
168
|
-
end
|
|
169
|
-
end
|
|
170
|
-
end
|