hq-graphql 2.0.6 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +28 -0
- data/lib/hq-graphql.rb +0 -2
- data/lib/hq/graphql.rb +29 -20
- data/lib/hq/graphql/active_record_extensions.rb +23 -27
- data/lib/hq/graphql/association_loader.rb +49 -0
- data/lib/hq/graphql/comparator.rb +1 -6
- data/lib/hq/graphql/config.rb +17 -11
- data/lib/hq/graphql/engine.rb +0 -1
- data/lib/hq/graphql/enum.rb +78 -0
- data/lib/hq/graphql/enum/sort_by.rb +8 -0
- data/lib/hq/graphql/enum/sort_order.rb +8 -0
- data/lib/hq/graphql/field.rb +26 -6
- data/lib/hq/graphql/input_object.rb +8 -7
- data/lib/hq/graphql/inputs.rb +4 -3
- data/lib/hq/graphql/mutation.rb +0 -1
- data/lib/hq/graphql/object.rb +15 -4
- data/lib/hq/graphql/paginated_association_loader.rb +138 -0
- data/lib/hq/graphql/resource.rb +47 -156
- data/lib/hq/graphql/resource/auto_mutation.rb +159 -0
- data/lib/hq/graphql/root_mutation.rb +1 -2
- data/lib/hq/graphql/root_query.rb +0 -1
- data/lib/hq/graphql/scalars.rb +0 -1
- data/lib/hq/graphql/schema.rb +22 -0
- data/lib/hq/graphql/types.rb +19 -8
- data/lib/hq/graphql/types/object.rb +7 -11
- data/lib/hq/graphql/types/uuid.rb +7 -14
- data/lib/hq/graphql/version.rb +1 -2
- metadata +9 -39
- data/lib/hq/graphql/loaders.rb +0 -4
- data/lib/hq/graphql/loaders/association.rb +0 -52
- data/lib/hq/graphql/resource/mutation.rb +0 -39
@@ -0,0 +1,159 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module HQ
|
4
|
+
module GraphQL
|
5
|
+
module Resource
|
6
|
+
module AutoMutation
|
7
|
+
def build_create
|
8
|
+
scoped_self = self
|
9
|
+
|
10
|
+
build_mutation(action: :create) do
|
11
|
+
define_method(:resolve) do |**args|
|
12
|
+
resource = scoped_self.new_record(context)
|
13
|
+
resource.assign_attributes(args[:attributes].format_nested_attributes)
|
14
|
+
if resource.save
|
15
|
+
{
|
16
|
+
resource: resource,
|
17
|
+
errors: {},
|
18
|
+
}
|
19
|
+
else
|
20
|
+
{
|
21
|
+
resource: nil,
|
22
|
+
errors: errors_from_resource(resource)
|
23
|
+
}
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
lazy_load do
|
28
|
+
argument :attributes, ::HQ::GraphQL::Inputs[scoped_self.model_name], required: true
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def build_update
|
34
|
+
scoped_self = self
|
35
|
+
|
36
|
+
build_mutation(action: :update, require_primary_key: true) do
|
37
|
+
define_method(:resolve) do |**args|
|
38
|
+
resource = scoped_self.find_record(args, context)
|
39
|
+
|
40
|
+
if resource
|
41
|
+
resource.assign_attributes(args[:attributes].format_nested_attributes)
|
42
|
+
if resource.save
|
43
|
+
{
|
44
|
+
resource: resource,
|
45
|
+
errors: {},
|
46
|
+
}
|
47
|
+
else
|
48
|
+
{
|
49
|
+
resource: nil,
|
50
|
+
errors: errors_from_resource(resource)
|
51
|
+
}
|
52
|
+
end
|
53
|
+
else
|
54
|
+
{
|
55
|
+
resource: nil,
|
56
|
+
errors: { resource: "Unable to find #{self.class.graphql_name}" }
|
57
|
+
}
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
lazy_load do
|
62
|
+
argument :attributes, ::HQ::GraphQL::Inputs[scoped_self.model_name], required: true
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def build_copy
|
68
|
+
scoped_self = self
|
69
|
+
|
70
|
+
build_mutation(action: :copy, require_primary_key: true, nil_klass: true) do
|
71
|
+
define_method(:resolve) do |**args|
|
72
|
+
resource = scoped_self.find_record(args, context)
|
73
|
+
|
74
|
+
if resource
|
75
|
+
copy = resource.copy
|
76
|
+
if copy.save
|
77
|
+
{
|
78
|
+
resource: copy,
|
79
|
+
errors: {},
|
80
|
+
}
|
81
|
+
else
|
82
|
+
{
|
83
|
+
resource: copy,
|
84
|
+
errors: errors_from_resource(copy)
|
85
|
+
}
|
86
|
+
end
|
87
|
+
else
|
88
|
+
{
|
89
|
+
resource: nil,
|
90
|
+
errors: { resource: "Unable to find #{self.class.graphql_name}" }
|
91
|
+
}
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def build_destroy
|
98
|
+
scoped_self = self
|
99
|
+
|
100
|
+
build_mutation(action: :destroy, require_primary_key: true) do
|
101
|
+
define_method(:resolve) do |**attrs|
|
102
|
+
resource = scoped_self.find_record(attrs, context)
|
103
|
+
|
104
|
+
if resource
|
105
|
+
if resource.destroy
|
106
|
+
{
|
107
|
+
resource: resource,
|
108
|
+
errors: {},
|
109
|
+
}
|
110
|
+
else
|
111
|
+
{
|
112
|
+
resource: nil,
|
113
|
+
errors: errors_from_resource(resource)
|
114
|
+
}
|
115
|
+
end
|
116
|
+
else
|
117
|
+
{
|
118
|
+
resource: nil,
|
119
|
+
errors: { resource: "Unable to find #{self.class.graphql_name}" }
|
120
|
+
}
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def build_mutation(action:, require_primary_key: false, nil_klass: false, &block)
|
127
|
+
gql_name = "#{graphql_name}#{action.to_s.titleize}"
|
128
|
+
scoped_model_name = model_name
|
129
|
+
Class.new(::HQ::GraphQL::Mutation) do
|
130
|
+
graphql_name gql_name
|
131
|
+
|
132
|
+
define_method(:ready?) do |*args|
|
133
|
+
super(*args) && ::HQ::GraphQL.authorized?(action, scoped_model_name, context)
|
134
|
+
end
|
135
|
+
|
136
|
+
lazy_load do
|
137
|
+
field :errors, ::HQ::GraphQL::Types::Object, null: false
|
138
|
+
field :resource, ::HQ::GraphQL::Types[scoped_model_name, nil_klass], null: true
|
139
|
+
end
|
140
|
+
|
141
|
+
instance_eval(&block)
|
142
|
+
|
143
|
+
if require_primary_key
|
144
|
+
lazy_load do
|
145
|
+
klass = scoped_model_name.constantize
|
146
|
+
primary_key = klass.primary_key
|
147
|
+
argument primary_key, ::GraphQL::Types::ID, required: true
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def errors_from_resource(resource)
|
152
|
+
resource.errors.to_h.deep_transform_keys { |k| k.to_s.camelize(:lower) }
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
@@ -1,4 +1,3 @@
|
|
1
|
-
# typed: true
|
2
1
|
# frozen_string_literal: true
|
3
2
|
|
4
3
|
module HQ
|
@@ -8,7 +7,7 @@ module HQ
|
|
8
7
|
super
|
9
8
|
base.class_eval do
|
10
9
|
lazy_load do
|
11
|
-
::HQ::GraphQL.
|
10
|
+
::HQ::GraphQL.resources.each do |type|
|
12
11
|
type.mutation_klasses.each do |mutation_name, klass|
|
13
12
|
field mutation_name, mutation: klass
|
14
13
|
end
|
data/lib/hq/graphql/scalars.rb
CHANGED
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module HQ
|
4
|
+
module GraphQL
|
5
|
+
class Schema < ::GraphQL::Schema
|
6
|
+
class << self
|
7
|
+
def dump_directory(directory = Rails.root.join("app/graphql"))
|
8
|
+
@dump_directory ||= directory
|
9
|
+
end
|
10
|
+
|
11
|
+
def dump_filename(filename = "#{self.name.underscore}.graphql")
|
12
|
+
@dump_filename ||= filename
|
13
|
+
end
|
14
|
+
|
15
|
+
def dump
|
16
|
+
::FileUtils.mkdir_p(dump_directory)
|
17
|
+
::File.open(::File.join(dump_directory, dump_filename), "w") { |file| file.write(self.to_definition) }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/hq/graphql/types.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
# typed: true
|
2
1
|
# frozen_string_literal: true
|
3
2
|
|
4
3
|
module HQ
|
@@ -8,12 +7,23 @@ module HQ
|
|
8
7
|
MISSING_TYPE_MSG = "The GraphQL type for `%{klass}` is missing."
|
9
8
|
end
|
10
9
|
|
11
|
-
def self.
|
12
|
-
@
|
10
|
+
def self.registry
|
11
|
+
@registry ||= Hash.new do |hash, options|
|
13
12
|
klass, nil_klass = Array(options)
|
14
13
|
hash[klass] = nil_klass ? nil_query_klass(klass) : klass_for(klass)
|
15
14
|
end
|
16
|
-
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.register(k, v)
|
18
|
+
self[k] = v
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.[]=(key, is_nil = false, value)
|
22
|
+
registry[[key, is_nil]] = value
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.[](key, is_nil = false)
|
26
|
+
registry[[key, is_nil]]
|
17
27
|
end
|
18
28
|
|
19
29
|
def self.type_from_column(column)
|
@@ -38,7 +48,7 @@ module HQ
|
|
38
48
|
|
39
49
|
# Only being used in testing
|
40
50
|
def self.reset!
|
41
|
-
@
|
51
|
+
@registry = nil
|
42
52
|
end
|
43
53
|
|
44
54
|
class << self
|
@@ -54,9 +64,10 @@ module HQ
|
|
54
64
|
|
55
65
|
def find_klass(klass_or_string, method)
|
56
66
|
klass = klass_or_string.is_a?(String) ? klass_or_string.constantize : klass_or_string
|
57
|
-
::HQ::GraphQL.
|
58
|
-
|
59
|
-
|
67
|
+
resource = ::HQ::GraphQL.lookup_resource(klass)
|
68
|
+
|
69
|
+
raise(Error, Error::MISSING_TYPE_MSG % { klass: klass.name }) if !resource
|
70
|
+
resource.send(method)
|
60
71
|
end
|
61
72
|
end
|
62
73
|
end
|
@@ -1,4 +1,3 @@
|
|
1
|
-
# typed: true
|
2
1
|
# frozen_string_literal: true
|
3
2
|
|
4
3
|
module HQ
|
@@ -7,17 +6,15 @@ module HQ
|
|
7
6
|
class Object < ::GraphQL::Schema::Scalar
|
8
7
|
description "Object"
|
9
8
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
def coerce_input(value, _context)
|
14
|
-
validate_and_return_object(value)
|
15
|
-
end
|
9
|
+
def self.coerce_input(value, _context)
|
10
|
+
validate_and_return_object(value)
|
11
|
+
end
|
16
12
|
|
17
|
-
|
18
|
-
|
19
|
-
|
13
|
+
def self.coerce_result(value, _context)
|
14
|
+
validate_and_return_object(value)
|
15
|
+
end
|
20
16
|
|
17
|
+
class << self
|
21
18
|
private
|
22
19
|
|
23
20
|
def validate_and_return_object(value)
|
@@ -28,7 +25,6 @@ module HQ
|
|
28
25
|
end
|
29
26
|
end
|
30
27
|
|
31
|
-
sig { params(value: T.untyped).returns(T::Boolean) }
|
32
28
|
def validate_object(value)
|
33
29
|
value.is_a?(Hash)
|
34
30
|
end
|
@@ -1,4 +1,3 @@
|
|
1
|
-
# typed: strict
|
2
1
|
# frozen_string_literal: true
|
3
2
|
|
4
3
|
module HQ
|
@@ -7,22 +6,17 @@ module HQ
|
|
7
6
|
class UUID < ::GraphQL::Schema::Scalar
|
8
7
|
description "UUID"
|
9
8
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
sig { params(value: T.untyped, _context: T.untyped).returns(String) }
|
14
|
-
def coerce_input(value, _context)
|
15
|
-
validate_and_return_uuid(value)
|
16
|
-
end
|
9
|
+
def self.coerce_input(value, _context)
|
10
|
+
validate_and_return_uuid(value)
|
11
|
+
end
|
17
12
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
end
|
13
|
+
def self.coerce_result(value, _context)
|
14
|
+
validate_and_return_uuid(value)
|
15
|
+
end
|
22
16
|
|
17
|
+
class << self
|
23
18
|
private
|
24
19
|
|
25
|
-
sig { params(value: T.untyped).returns(String) }
|
26
20
|
def validate_and_return_uuid(value)
|
27
21
|
if validate_uuid(value)
|
28
22
|
value
|
@@ -31,7 +25,6 @@ module HQ
|
|
31
25
|
end
|
32
26
|
end
|
33
27
|
|
34
|
-
sig { params(value: T.untyped).returns(T::Boolean) }
|
35
28
|
def validate_uuid(value)
|
36
29
|
!!value.to_s.match(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/)
|
37
30
|
end
|
data/lib/hq/graphql/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hq-graphql
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0
|
4
|
+
version: 2.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Danny Jones
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-06-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -29,9 +29,6 @@ dependencies:
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: '1.0'
|
34
|
-
- - ">="
|
35
32
|
- !ruby/object:Gem::Version
|
36
33
|
version: 1.9.6
|
37
34
|
type: :runtime
|
@@ -39,9 +36,6 @@ dependencies:
|
|
39
36
|
version_requirements: !ruby/object:Gem::Requirement
|
40
37
|
requirements:
|
41
38
|
- - "~>"
|
42
|
-
- !ruby/object:Gem::Version
|
43
|
-
version: '1.0'
|
44
|
-
- - ">="
|
45
39
|
- !ruby/object:Gem::Version
|
46
40
|
version: 1.9.6
|
47
41
|
- !ruby/object:Gem::Dependency
|
@@ -86,20 +80,6 @@ dependencies:
|
|
86
80
|
- - "~>"
|
87
81
|
- !ruby/object:Gem::Version
|
88
82
|
version: '1.1'
|
89
|
-
- !ruby/object:Gem::Dependency
|
90
|
-
name: sorbet-runtime
|
91
|
-
requirement: !ruby/object:Gem::Requirement
|
92
|
-
requirements:
|
93
|
-
- - ">="
|
94
|
-
- !ruby/object:Gem::Version
|
95
|
-
version: '0'
|
96
|
-
type: :runtime
|
97
|
-
prerelease: false
|
98
|
-
version_requirements: !ruby/object:Gem::Requirement
|
99
|
-
requirements:
|
100
|
-
- - ">="
|
101
|
-
- !ruby/object:Gem::Version
|
102
|
-
version: '0'
|
103
83
|
- !ruby/object:Gem::Dependency
|
104
84
|
name: sprockets
|
105
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -254,20 +234,6 @@ dependencies:
|
|
254
234
|
- - "~>"
|
255
235
|
- !ruby/object:Gem::Version
|
256
236
|
version: '2.3'
|
257
|
-
- !ruby/object:Gem::Dependency
|
258
|
-
name: sorbet
|
259
|
-
requirement: !ruby/object:Gem::Requirement
|
260
|
-
requirements:
|
261
|
-
- - ">="
|
262
|
-
- !ruby/object:Gem::Version
|
263
|
-
version: '0'
|
264
|
-
type: :development
|
265
|
-
prerelease: false
|
266
|
-
version_requirements: !ruby/object:Gem::Requirement
|
267
|
-
requirements:
|
268
|
-
- - ">="
|
269
|
-
- !ruby/object:Gem::Version
|
270
|
-
version: '0'
|
271
237
|
description: OneHQ GraphQL Library
|
272
238
|
email:
|
273
239
|
- dpjones09@gmail.com
|
@@ -281,21 +247,25 @@ files:
|
|
281
247
|
- lib/hq-graphql.rb
|
282
248
|
- lib/hq/graphql.rb
|
283
249
|
- lib/hq/graphql/active_record_extensions.rb
|
250
|
+
- lib/hq/graphql/association_loader.rb
|
284
251
|
- lib/hq/graphql/comparator.rb
|
285
252
|
- lib/hq/graphql/config.rb
|
286
253
|
- lib/hq/graphql/engine.rb
|
254
|
+
- lib/hq/graphql/enum.rb
|
255
|
+
- lib/hq/graphql/enum/sort_by.rb
|
256
|
+
- lib/hq/graphql/enum/sort_order.rb
|
287
257
|
- lib/hq/graphql/field.rb
|
288
258
|
- lib/hq/graphql/input_object.rb
|
289
259
|
- lib/hq/graphql/inputs.rb
|
290
|
-
- lib/hq/graphql/loaders.rb
|
291
|
-
- lib/hq/graphql/loaders/association.rb
|
292
260
|
- lib/hq/graphql/mutation.rb
|
293
261
|
- lib/hq/graphql/object.rb
|
262
|
+
- lib/hq/graphql/paginated_association_loader.rb
|
294
263
|
- lib/hq/graphql/resource.rb
|
295
|
-
- lib/hq/graphql/resource/
|
264
|
+
- lib/hq/graphql/resource/auto_mutation.rb
|
296
265
|
- lib/hq/graphql/root_mutation.rb
|
297
266
|
- lib/hq/graphql/root_query.rb
|
298
267
|
- lib/hq/graphql/scalars.rb
|
268
|
+
- lib/hq/graphql/schema.rb
|
299
269
|
- lib/hq/graphql/types.rb
|
300
270
|
- lib/hq/graphql/types/object.rb
|
301
271
|
- lib/hq/graphql/types/uuid.rb
|