lighthouse-graphql 0.5.0 → 0.6.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 +118 -1
- data/README.md +24 -16
- data/docs/caching.md +4 -3
- data/docs/configuration.md +1 -21
- data/docs/directives.md +14 -7
- data/docs/generators.md +41 -39
- data/docs/getting-started.md +88 -51
- data/docs/performance.md +2 -2
- data/docs/relationships.md +5 -4
- data/docs/relay.md +63 -0
- data/docs/resolvers.md +90 -37
- 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 +112 -91
- data/lib/generators/lighthouse/install/templates/initializer.rb.tt +3 -9
- data/lib/lighthouse/caching.rb +9 -3
- data/lib/lighthouse/config.rb +6 -23
- data/lib/lighthouse/controller.rb +28 -5
- data/lib/lighthouse/directive_resolvers/argument_transforms_resolver.rb +18 -18
- data/lib/lighthouse/directive_resolvers/cache_resolvers.rb +1 -1
- data/lib/lighthouse/directive_resolvers/global_id_resolver.rb +3 -1
- 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/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/rb_lighthouse.rb +1 -0
- 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_generator.rb +4 -3
- data/lib/lighthouse/upload.rb +4 -2
- data/lib/lighthouse/upload_store.rb +39 -14
- data/sig/lighthouse.rbs +0 -10
- metadata +3 -4
- 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
|
@@ -1,32 +1,57 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
#
|
|
6
|
-
# `
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
#
|
|
3
|
+
# Where @upload puts a file, as PHP Lighthouse's @upload puts it on one of the
|
|
4
|
+
# app's Laravel disks: an ActiveStorage blob on one of the app's services
|
|
5
|
+
# (config/storage.yml). `disk` names the service (config.active_storage.service
|
|
6
|
+
# without it), `path` prefixes the blob's key. ActiveStorage sets visibility per
|
|
7
|
+
# service (`public: true` in storage.yml), not per file, so `public` must agree
|
|
8
|
+
# with the service's: the schema never says a file is private that anyone can
|
|
9
|
+
# read, or public that no one can. The argument then holds the blob's signed id,
|
|
10
|
+
# which a has_one_attached / has_many_attached attribute attaches (where Laravel
|
|
11
|
+
# hands the stored path, for a model to keep). To store files elsewhere, declare
|
|
12
|
+
# an ActiveStorage service for it, as a Laravel app declares a disk.
|
|
10
13
|
module Lighthouse::GraphQL::UploadStore
|
|
11
14
|
module_function
|
|
12
15
|
|
|
13
|
-
def call(file, disk: nil, path: nil, public:
|
|
16
|
+
def call(file, argument:, disk: nil, path: nil, public: nil)
|
|
14
17
|
unless defined?(::ActiveStorage::Blob)
|
|
15
|
-
raise Lighthouse::DefinitionError,
|
|
16
|
-
|
|
18
|
+
raise Lighthouse::DefinitionError, '@upload stores files with ActiveStorage: install it (bin/rails active_storage:install).'
|
|
19
|
+
end
|
|
20
|
+
unless Lighthouse::GraphQL::Upload.file?(file)
|
|
21
|
+
raise Lighthouse::DefinitionError, "Expected argument `#{argument}` to be an uploaded file (Upload)."
|
|
17
22
|
end
|
|
18
23
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
::ActiveStorage::Blob.create_and_upload!(
|
|
24
|
+
service = service(argument, disk, public == true)
|
|
25
|
+
file.rewind if file.respond_to?(:rewind) # a @validator, or another argument the multipart map sent it to, may have read it
|
|
26
|
+
::ActiveStorage::Blob.create_and_upload!(
|
|
27
|
+
io: file, filename: filename(file), content_type: file.try(:content_type), key: key(path), service_name: service.name
|
|
28
|
+
).signed_id
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# The service `disk` names, or the default one, checked to be as public as asked.
|
|
32
|
+
def service(argument, disk, public)
|
|
33
|
+
service = disk ? ::ActiveStorage::Blob.services.fetch(disk) : ::ActiveStorage::Blob.service
|
|
34
|
+
return service if (service.public? == true) == public
|
|
35
|
+
|
|
36
|
+
raise Lighthouse::DefinitionError, visibility_mismatch(argument, service.name, public)
|
|
37
|
+
rescue KeyError => e
|
|
38
|
+
raise Lighthouse::DefinitionError, "@upload on `#{argument}`: #{e.message}"
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def visibility_mismatch(argument, service_name, public)
|
|
42
|
+
fix = public ? 'name a public one (public: true in config/storage.yml) with disk:' : 'pass public: true, or name a private one with disk:'
|
|
43
|
+
"@upload#{'(public: true)' if public} on `#{argument}` stores on the ActiveStorage service `#{service_name}`, " \
|
|
44
|
+
"which is #{'not ' if public}public: #{fix}."
|
|
22
45
|
end
|
|
23
46
|
|
|
24
47
|
def filename(file)
|
|
25
48
|
file.respond_to?(:original_filename) ? file.original_filename : File.basename(file.path)
|
|
26
49
|
end
|
|
27
50
|
|
|
51
|
+
# `path`'s directory, then a fresh token, as Laravel's `storeAs(path, hashName)`;
|
|
52
|
+
# under the root ("/", the default), ActiveStorage's own key.
|
|
28
53
|
def key(path)
|
|
29
54
|
prefix = path.to_s.delete_prefix('/').delete_suffix('/')
|
|
30
|
-
prefix.empty? ? nil : "#{prefix}/#{
|
|
55
|
+
prefix.empty? ? nil : "#{prefix}/#{::ActiveStorage::Blob.generate_unique_secure_token}"
|
|
31
56
|
end
|
|
32
57
|
end
|
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
|
|
@@ -112,8 +106,6 @@ module Lighthouse
|
|
|
112
106
|
def self.directive_map: () -> Hash[untyped, untyped]
|
|
113
107
|
|
|
114
108
|
# An ActiveSupport::Cache::Store; Rails.cache by default.
|
|
115
|
-
def self.cache_store: () -> untyped
|
|
116
|
-
def self.cache_store=: (untyped store) -> untyped
|
|
117
109
|
|
|
118
110
|
def self.transactional_mutations: () -> bool
|
|
119
111
|
def self.transactional_mutations=: (bool? enabled) -> bool?
|
|
@@ -147,8 +139,6 @@ module Lighthouse
|
|
|
147
139
|
def self.global_id: () -> _GlobalId
|
|
148
140
|
def self.global_id=: (_GlobalId? codec) -> _GlobalId?
|
|
149
141
|
|
|
150
|
-
def self.upload_store: () -> _UploadStore
|
|
151
|
-
def self.upload_store=: (_UploadStore? store) -> _UploadStore?
|
|
152
142
|
|
|
153
143
|
# Whether @broadcast triggers in an ActiveJob (Lighthouse::GraphQL::BroadcastJob)
|
|
154
144
|
# 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.6.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Vaz Innovation
|
|
@@ -78,14 +78,12 @@ files:
|
|
|
78
78
|
- lib/generators/lighthouse/base_classes.rb
|
|
79
79
|
- lib/generators/lighthouse/builder_generator.rb
|
|
80
80
|
- lib/generators/lighthouse/class_generator.rb
|
|
81
|
+
- lib/generators/lighthouse/install/graphql_ruby_install.rb
|
|
81
82
|
- lib/generators/lighthouse/install/install_generator.rb
|
|
82
83
|
- lib/generators/lighthouse/install/templates/graphql.config.yml.tt
|
|
83
84
|
- lib/generators/lighthouse/install/templates/graphql_controller.rb.tt
|
|
84
85
|
- lib/generators/lighthouse/install/templates/initializer.rb.tt
|
|
85
86
|
- 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
87
|
- lib/generators/lighthouse/subscription_generator.rb
|
|
90
88
|
- lib/generators/lighthouse/validator_generator.rb
|
|
91
89
|
- lib/lighthouse-graphql.rb
|
|
@@ -197,6 +195,7 @@ files:
|
|
|
197
195
|
- lib/lighthouse/resolve_info.rb
|
|
198
196
|
- lib/lighthouse/resolver_bases.rb
|
|
199
197
|
- lib/lighthouse/resolver_dispatch.rb
|
|
198
|
+
- lib/lighthouse/root_types.rb
|
|
200
199
|
- lib/lighthouse/scalar_coercion.rb
|
|
201
200
|
- lib/lighthouse/schema_cache.rb
|
|
202
201
|
- lib/lighthouse/schema_factory.rb
|
|
@@ -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
|