hq-graphql 2.0.10 → 2.1.3
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/lib/hq/graphql.rb +17 -7
- data/lib/hq/graphql/active_record_extensions.rb +1 -1
- data/lib/hq/graphql/association_loader.rb +49 -0
- data/lib/hq/graphql/config.rb +2 -0
- data/lib/hq/graphql/enum.rb +2 -0
- data/lib/hq/graphql/enum/sort_by.rb +10 -0
- data/lib/hq/graphql/enum/sort_order.rb +10 -0
- data/lib/hq/graphql/field.rb +12 -10
- data/lib/hq/graphql/field_extension/association_loader_extension.rb +15 -0
- data/lib/hq/graphql/field_extension/paginated_arguments.rb +22 -0
- data/lib/hq/graphql/field_extension/paginated_loader.rb +45 -0
- data/lib/hq/graphql/input_object.rb +4 -0
- data/lib/hq/graphql/inputs.rb +3 -7
- data/lib/hq/graphql/object.rb +37 -9
- data/lib/hq/graphql/object_association.rb +67 -0
- data/lib/hq/graphql/paginated_association_loader.rb +193 -0
- data/lib/hq/graphql/resource.rb +63 -155
- data/lib/hq/graphql/resource/auto_mutation.rb +163 -0
- data/lib/hq/graphql/root_mutation.rb +1 -1
- data/lib/hq/graphql/types.rb +14 -13
- data/lib/hq/graphql/version.rb +1 -1
- metadata +11 -5
- data/lib/hq/graphql/loaders.rb +0 -3
- data/lib/hq/graphql/loaders/association.rb +0 -51
- data/lib/hq/graphql/resource/mutation.rb +0 -38
@@ -0,0 +1,163 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "hq/graphql/inputs"
|
4
|
+
require "hq/graphql/mutation"
|
5
|
+
require "hq/graphql/types"
|
6
|
+
|
7
|
+
module HQ
|
8
|
+
module GraphQL
|
9
|
+
module Resource
|
10
|
+
module AutoMutation
|
11
|
+
def build_create
|
12
|
+
scoped_self = self
|
13
|
+
|
14
|
+
build_mutation(action: :create) do
|
15
|
+
define_method(:resolve) do |**args|
|
16
|
+
resource = scoped_self.new_record(context)
|
17
|
+
resource.assign_attributes(args[:attributes].format_nested_attributes)
|
18
|
+
if resource.save
|
19
|
+
{
|
20
|
+
resource: resource,
|
21
|
+
errors: {},
|
22
|
+
}
|
23
|
+
else
|
24
|
+
{
|
25
|
+
resource: nil,
|
26
|
+
errors: errors_from_resource(resource)
|
27
|
+
}
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
lazy_load do
|
32
|
+
argument :attributes, ::HQ::GraphQL::Inputs[scoped_self.model_name], required: true
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def build_update
|
38
|
+
scoped_self = self
|
39
|
+
|
40
|
+
build_mutation(action: :update, require_primary_key: true) do
|
41
|
+
define_method(:resolve) do |**args|
|
42
|
+
resource = scoped_self.find_record(args, context)
|
43
|
+
|
44
|
+
if resource
|
45
|
+
resource.assign_attributes(args[:attributes].format_nested_attributes)
|
46
|
+
if resource.save
|
47
|
+
{
|
48
|
+
resource: resource,
|
49
|
+
errors: {},
|
50
|
+
}
|
51
|
+
else
|
52
|
+
{
|
53
|
+
resource: nil,
|
54
|
+
errors: errors_from_resource(resource)
|
55
|
+
}
|
56
|
+
end
|
57
|
+
else
|
58
|
+
{
|
59
|
+
resource: nil,
|
60
|
+
errors: { resource: "Unable to find #{self.class.graphql_name}" }
|
61
|
+
}
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
lazy_load do
|
66
|
+
argument :attributes, ::HQ::GraphQL::Inputs[scoped_self.model_name], required: true
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def build_copy
|
72
|
+
scoped_self = self
|
73
|
+
|
74
|
+
build_mutation(action: :copy, require_primary_key: true, nil_klass: true) do
|
75
|
+
define_method(:resolve) do |**args|
|
76
|
+
resource = scoped_self.find_record(args, context)
|
77
|
+
|
78
|
+
if resource
|
79
|
+
copy = resource.copy
|
80
|
+
if copy.save
|
81
|
+
{
|
82
|
+
resource: copy,
|
83
|
+
errors: {},
|
84
|
+
}
|
85
|
+
else
|
86
|
+
{
|
87
|
+
resource: copy,
|
88
|
+
errors: errors_from_resource(copy)
|
89
|
+
}
|
90
|
+
end
|
91
|
+
else
|
92
|
+
{
|
93
|
+
resource: nil,
|
94
|
+
errors: { resource: "Unable to find #{self.class.graphql_name}" }
|
95
|
+
}
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def build_destroy
|
102
|
+
scoped_self = self
|
103
|
+
|
104
|
+
build_mutation(action: :destroy, require_primary_key: true) do
|
105
|
+
define_method(:resolve) do |**attrs|
|
106
|
+
resource = scoped_self.find_record(attrs, context)
|
107
|
+
|
108
|
+
if resource
|
109
|
+
if resource.destroy
|
110
|
+
{
|
111
|
+
resource: resource,
|
112
|
+
errors: {},
|
113
|
+
}
|
114
|
+
else
|
115
|
+
{
|
116
|
+
resource: nil,
|
117
|
+
errors: errors_from_resource(resource)
|
118
|
+
}
|
119
|
+
end
|
120
|
+
else
|
121
|
+
{
|
122
|
+
resource: nil,
|
123
|
+
errors: { resource: "Unable to find #{self.class.graphql_name}" }
|
124
|
+
}
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def build_mutation(action:, require_primary_key: false, nil_klass: false, &block)
|
131
|
+
gql_name = "#{graphql_name}#{action.to_s.titleize}"
|
132
|
+
scoped_model_name = model_name
|
133
|
+
Class.new(::HQ::GraphQL::Mutation) do
|
134
|
+
graphql_name gql_name
|
135
|
+
|
136
|
+
define_method(:ready?) do |*args|
|
137
|
+
super(*args) && ::HQ::GraphQL.authorized?(action, scoped_model_name, context)
|
138
|
+
end
|
139
|
+
|
140
|
+
lazy_load do
|
141
|
+
field :errors, ::HQ::GraphQL::Types::Object, null: false
|
142
|
+
field :resource, ::HQ::GraphQL::Types[scoped_model_name, nil_klass], null: true
|
143
|
+
end
|
144
|
+
|
145
|
+
instance_eval(&block)
|
146
|
+
|
147
|
+
if require_primary_key
|
148
|
+
lazy_load do
|
149
|
+
klass = scoped_model_name.constantize
|
150
|
+
primary_key = klass.primary_key
|
151
|
+
argument primary_key, ::GraphQL::Types::ID, required: true
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
def errors_from_resource(resource)
|
156
|
+
resource.errors.to_h.deep_transform_keys { |k| k.to_s.camelize(:lower) }
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
data/lib/hq/graphql/types.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "hq/graphql/types/object"
|
4
|
+
require "hq/graphql/types/uuid"
|
5
|
+
|
3
6
|
module HQ
|
4
7
|
module GraphQL
|
5
8
|
module Types
|
@@ -10,7 +13,7 @@ module HQ
|
|
10
13
|
def self.registry
|
11
14
|
@registry ||= Hash.new do |hash, options|
|
12
15
|
klass, nil_klass = Array(options)
|
13
|
-
hash[
|
16
|
+
hash[options] = nil_klass ? nil_query_object(klass) : klass_for(klass)
|
14
17
|
end
|
15
18
|
end
|
16
19
|
|
@@ -39,6 +42,10 @@ module HQ
|
|
39
42
|
::GraphQL::Types::Float
|
40
43
|
when :boolean
|
41
44
|
::GraphQL::Types::Boolean
|
45
|
+
when :date
|
46
|
+
::GraphQL::Types::ISO8601Date
|
47
|
+
when :datetime
|
48
|
+
::GraphQL::Types::ISO8601DateTime
|
42
49
|
else
|
43
50
|
::GraphQL::Types::String
|
44
51
|
end
|
@@ -54,26 +61,20 @@ module HQ
|
|
54
61
|
class << self
|
55
62
|
private
|
56
63
|
|
57
|
-
def
|
58
|
-
find_klass(klass_or_string, :
|
64
|
+
def nil_query_object(klass_or_string)
|
65
|
+
find_klass(klass_or_string, :nil_query_object)
|
59
66
|
end
|
60
67
|
|
61
68
|
def klass_for(klass_or_string)
|
62
|
-
find_klass(klass_or_string, :
|
69
|
+
find_klass(klass_or_string, :query_object)
|
63
70
|
end
|
64
71
|
|
65
72
|
def find_klass(klass_or_string, method)
|
66
73
|
klass = klass_or_string.is_a?(String) ? klass_or_string.constantize : klass_or_string
|
67
|
-
|
68
|
-
type ||= find_type(klass.base_class)
|
69
|
-
type ||= find_type(klass.superclass)
|
70
|
-
|
71
|
-
raise(Error, Error::MISSING_TYPE_MSG % { klass: klass.name }) if !type
|
72
|
-
type.send(method)
|
73
|
-
end
|
74
|
+
resource = ::HQ::GraphQL.lookup_resource(klass)
|
74
75
|
|
75
|
-
|
76
|
-
|
76
|
+
raise(Error, Error::MISSING_TYPE_MSG % { klass: klass.name }) if !resource
|
77
|
+
resource.send(method)
|
77
78
|
end
|
78
79
|
end
|
79
80
|
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.
|
4
|
+
version: 2.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Danny Jones
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-06-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -247,19 +247,25 @@ files:
|
|
247
247
|
- lib/hq-graphql.rb
|
248
248
|
- lib/hq/graphql.rb
|
249
249
|
- lib/hq/graphql/active_record_extensions.rb
|
250
|
+
- lib/hq/graphql/association_loader.rb
|
250
251
|
- lib/hq/graphql/comparator.rb
|
251
252
|
- lib/hq/graphql/config.rb
|
252
253
|
- lib/hq/graphql/engine.rb
|
253
254
|
- lib/hq/graphql/enum.rb
|
255
|
+
- lib/hq/graphql/enum/sort_by.rb
|
256
|
+
- lib/hq/graphql/enum/sort_order.rb
|
254
257
|
- lib/hq/graphql/field.rb
|
258
|
+
- lib/hq/graphql/field_extension/association_loader_extension.rb
|
259
|
+
- lib/hq/graphql/field_extension/paginated_arguments.rb
|
260
|
+
- lib/hq/graphql/field_extension/paginated_loader.rb
|
255
261
|
- lib/hq/graphql/input_object.rb
|
256
262
|
- lib/hq/graphql/inputs.rb
|
257
|
-
- lib/hq/graphql/loaders.rb
|
258
|
-
- lib/hq/graphql/loaders/association.rb
|
259
263
|
- lib/hq/graphql/mutation.rb
|
260
264
|
- lib/hq/graphql/object.rb
|
265
|
+
- lib/hq/graphql/object_association.rb
|
266
|
+
- lib/hq/graphql/paginated_association_loader.rb
|
261
267
|
- lib/hq/graphql/resource.rb
|
262
|
-
- lib/hq/graphql/resource/
|
268
|
+
- lib/hq/graphql/resource/auto_mutation.rb
|
263
269
|
- lib/hq/graphql/root_mutation.rb
|
264
270
|
- lib/hq/graphql/root_query.rb
|
265
271
|
- lib/hq/graphql/scalars.rb
|
data/lib/hq/graphql/loaders.rb
DELETED
@@ -1,51 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module HQ
|
4
|
-
module GraphQL
|
5
|
-
module Loaders
|
6
|
-
class Association < ::GraphQL::Batch::Loader
|
7
|
-
def initialize(model, association_name)
|
8
|
-
@model = model
|
9
|
-
@association_name = association_name
|
10
|
-
validate
|
11
|
-
end
|
12
|
-
|
13
|
-
def load(record)
|
14
|
-
raise TypeError, "#{@model} loader can't load association for #{record.class}" unless record.is_a?(@model)
|
15
|
-
return Promise.resolve(read_association(record)) if association_loaded?(record)
|
16
|
-
super
|
17
|
-
end
|
18
|
-
|
19
|
-
# We want to load the associations on all records, even if they have the same id
|
20
|
-
def cache_key(record)
|
21
|
-
record.object_id
|
22
|
-
end
|
23
|
-
|
24
|
-
def perform(records)
|
25
|
-
preload_association(records)
|
26
|
-
records.each { |record| fulfill(record, read_association(record)) }
|
27
|
-
end
|
28
|
-
|
29
|
-
private
|
30
|
-
|
31
|
-
def validate
|
32
|
-
unless @model.reflect_on_association(@association_name)
|
33
|
-
raise ArgumentError, "No association #{@association_name} on #{@model}"
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
def preload_association(records)
|
38
|
-
::ActiveRecord::Associations::Preloader.new.preload(records, @association_name)
|
39
|
-
end
|
40
|
-
|
41
|
-
def read_association(record)
|
42
|
-
record.public_send(@association_name)
|
43
|
-
end
|
44
|
-
|
45
|
-
def association_loaded?(record)
|
46
|
-
record.association(@association_name).loaded?
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
@@ -1,38 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module HQ
|
4
|
-
module GraphQL
|
5
|
-
module Resource
|
6
|
-
module Mutation
|
7
|
-
def self.build(model_name, action:, graphql_name:, require_primary_key: false, nil_klass: false, &block)
|
8
|
-
Class.new(::HQ::GraphQL::Mutation) do
|
9
|
-
graphql_name graphql_name
|
10
|
-
|
11
|
-
define_method(:ready?) do |*args|
|
12
|
-
super(*args) && ::HQ::GraphQL.authorized?(action, model_name, context)
|
13
|
-
end
|
14
|
-
|
15
|
-
lazy_load do
|
16
|
-
field :errors, ::HQ::GraphQL::Types::Object, null: false
|
17
|
-
field :resource, ::HQ::GraphQL::Types[model_name, nil_klass], null: true
|
18
|
-
end
|
19
|
-
|
20
|
-
instance_eval(&block)
|
21
|
-
|
22
|
-
if require_primary_key
|
23
|
-
lazy_load do
|
24
|
-
klass = model_name.constantize
|
25
|
-
primary_key = klass.primary_key
|
26
|
-
argument primary_key, ::GraphQL::Types::ID, required: true
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
def errors_from_resource(resource)
|
31
|
-
resource.errors.to_h.deep_transform_keys { |k| k.to_s.camelize(:lower) }
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|