graphiform 0.2.8 → 0.2.12
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/graphiform.rb +8 -0
- data/lib/graphiform/association_source.rb +56 -0
- data/lib/graphiform/core.rb +64 -7
- data/lib/graphiform/fields.rb +46 -9
- data/lib/graphiform/helpers.rb +13 -1
- data/lib/graphiform/skeleton.rb +8 -0
- data/lib/graphiform/version.rb +1 -1
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 68647a1e2a4781554b98f3e34e4b8d517bdee49c76459aa8445dffb13dd59f07
|
4
|
+
data.tar.gz: b66dcc28e233bf23a4468a1af531d1c650c50bf3d3054687e43831ee6fd3826f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9d87c2c3723f8e643a3370bce93a86231466aa6f8d90ef264b308942cc6b7d832e1c4db4e9ab3a503d6f13804f3beedaef70106fd253c7fb67f9ad4863af01b4
|
7
|
+
data.tar.gz: 6f4c3e3784b7c70aea0044fff3bda3dd9c79780e5835ee2ea2593025be264da83798a6379ea0f9acbbe807e08fb237946f7e04910c746f17a480ad083247bc2b
|
data/lib/graphiform.rb
CHANGED
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Graphiform
|
4
|
+
class AssociationSource < GraphQL::Dataloader::Source
|
5
|
+
def initialize(model, attribute, **options)
|
6
|
+
super()
|
7
|
+
|
8
|
+
@model = model
|
9
|
+
@attribute = attribute
|
10
|
+
@options = options
|
11
|
+
end
|
12
|
+
|
13
|
+
def fetch(values)
|
14
|
+
normalized_values = normalize_values(values)
|
15
|
+
records = query(normalized_values.uniq).to_a
|
16
|
+
results(normalized_values, records)
|
17
|
+
end
|
18
|
+
|
19
|
+
def query(values)
|
20
|
+
query = @model.where(@attribute => values)
|
21
|
+
|
22
|
+
query = query.includes(@options[:includes]) if @options[:includes].present? && query.respond_to?(:includes)
|
23
|
+
query = query.apply_filters(@options[:where].to_h) if @options[:where].present? && query.respond_to?(:apply_filters)
|
24
|
+
query = query.apply_sorts(@options[:sort].to_h) if @options[:sort].present? && query.respond_to?(:apply_sorts)
|
25
|
+
|
26
|
+
query
|
27
|
+
end
|
28
|
+
|
29
|
+
def normalize_value(value)
|
30
|
+
value = value.downcase if !@options[:case_sensitive] && value.is_a?(String)
|
31
|
+
|
32
|
+
value
|
33
|
+
end
|
34
|
+
|
35
|
+
def normalize_values(values)
|
36
|
+
type_for_attribute = @model.type_for_attribute(@attribute) if @model.respond_to?(:type_for_attribute)
|
37
|
+
values.map do |value|
|
38
|
+
value = type_for_attribute.cast(value) if type_for_attribute.present?
|
39
|
+
normalize_value(value)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def results(values, records)
|
44
|
+
record_attributes = records.map { |record| normalize_value(record[@attribute]) }
|
45
|
+
values.map do |value|
|
46
|
+
if @options[:multi]
|
47
|
+
indexes = record_attributes.each_index.select { |index| record_attributes[index] == value }
|
48
|
+
indexes.map { |index| index && records[index] }
|
49
|
+
else
|
50
|
+
index = record_attributes.index(value)
|
51
|
+
index && records[index]
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
data/lib/graphiform/core.rb
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
require 'active_support/concern'
|
4
4
|
|
5
5
|
require 'graphiform/helpers'
|
6
|
+
require 'graphiform/association_source'
|
6
7
|
|
7
8
|
module Graphiform
|
8
9
|
module Core
|
@@ -37,6 +38,7 @@ module Graphiform
|
|
37
38
|
end
|
38
39
|
@filter.class_eval do
|
39
40
|
argument 'OR', [self], required: false
|
41
|
+
argument 'AND', [self], required: false
|
40
42
|
end
|
41
43
|
end
|
42
44
|
|
@@ -52,6 +54,15 @@ module Graphiform
|
|
52
54
|
end
|
53
55
|
end
|
54
56
|
|
57
|
+
def graphql_grouping
|
58
|
+
local_demodulized_name = demodulized_name
|
59
|
+
Helpers.get_const_or_create(local_demodulized_name, ::Inputs::Groupings) do
|
60
|
+
Class.new(::Inputs::Groupings::BaseGrouping) do
|
61
|
+
graphql_name "#{local_demodulized_name}Grouping"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
55
66
|
def graphql_edge
|
56
67
|
Helpers.get_const_or_create("#{demodulized_name}Edge", ::Types) do
|
57
68
|
node_type = graphql_type
|
@@ -99,9 +110,10 @@ module Graphiform
|
|
99
110
|
@value
|
100
111
|
end
|
101
112
|
|
102
|
-
def apply_built_ins(where: nil, sort: nil, **)
|
113
|
+
def apply_built_ins(where: nil, sort: nil, group: nil, **)
|
103
114
|
@value = @value.apply_filters(where.to_h) if where.present? && @value.respond_to?(:apply_filters)
|
104
115
|
@value = @value.apply_sorts(sort.to_h) if sort.present? && @value.respond_to?(:apply_sorts)
|
116
|
+
@value = @value.apply_groupings(group.to_h) if group.present? && @value.respond_to?(:apply_groupings)
|
105
117
|
|
106
118
|
@value
|
107
119
|
end
|
@@ -115,6 +127,7 @@ module Graphiform
|
|
115
127
|
|
116
128
|
local_graphql_filter = graphql_filter
|
117
129
|
local_graphql_sort = graphql_sort
|
130
|
+
local_graphql_grouping = graphql_grouping
|
118
131
|
|
119
132
|
model = self
|
120
133
|
@base_resolver.class_eval do
|
@@ -126,6 +139,7 @@ module Graphiform
|
|
126
139
|
|
127
140
|
argument :where, local_graphql_filter, required: false
|
128
141
|
argument :sort, local_graphql_sort, required: false unless local_graphql_sort.arguments.empty?
|
142
|
+
argument :group, local_graphql_grouping, required: false unless local_graphql_grouping.arguments.empty?
|
129
143
|
end
|
130
144
|
end
|
131
145
|
|
@@ -141,7 +155,7 @@ module Graphiform
|
|
141
155
|
def base_resolve(**args)
|
142
156
|
@value = model.all
|
143
157
|
apply_built_ins(**args)
|
144
|
-
@value.
|
158
|
+
@value.take
|
145
159
|
end
|
146
160
|
end
|
147
161
|
end
|
@@ -161,18 +175,61 @@ module Graphiform
|
|
161
175
|
end
|
162
176
|
end
|
163
177
|
|
164
|
-
def graphql_create_resolver(method_name, resolver_type = graphql_type, read_prepare: nil, read_resolve: nil, null: true, **)
|
178
|
+
def graphql_create_resolver(method_name, resolver_type = graphql_type, read_prepare: nil, read_resolve: nil, null: true, skip_dataloader: false, case_sensitive: Graphiform.configuration[:case_sensitive], **)
|
165
179
|
Class.new(graphql_base_resolver) do
|
166
180
|
type resolver_type, null: null
|
167
181
|
|
168
182
|
define_method :base_resolve do |**args|
|
169
183
|
@value = object
|
170
184
|
|
171
|
-
|
172
|
-
|
173
|
-
|
185
|
+
association_def = @value.association(method_name)&.reflection
|
186
|
+
join_keys = association_def&.join_keys
|
187
|
+
|
188
|
+
skip_dataloader ||=
|
189
|
+
!association_def ||
|
190
|
+
!Helpers.dataloader_support?(dataloader, association_def, join_keys.foreign_key) ||
|
191
|
+
read_resolve ||
|
192
|
+
read_prepare ||
|
193
|
+
args[:group]
|
194
|
+
|
195
|
+
if skip_dataloader
|
196
|
+
@value = instance_exec(@value, context, &read_resolve) if read_resolve
|
197
|
+
@value = @value.public_send(method_name) if !read_resolve && @value.respond_to?(method_name)
|
198
|
+
@value = instance_exec(@value, context, &read_prepare) if read_prepare
|
199
|
+
|
200
|
+
apply_built_ins(**args)
|
201
|
+
else
|
202
|
+
dataloader
|
203
|
+
.with(
|
204
|
+
AssociationSource,
|
205
|
+
association_def.klass,
|
206
|
+
join_keys.key,
|
207
|
+
where: args[:where],
|
208
|
+
sort: args[:sort],
|
209
|
+
multi: true,
|
210
|
+
case_sensitive: case_sensitive,
|
211
|
+
)
|
212
|
+
.load(
|
213
|
+
@value.public_send(join_keys.foreign_key)
|
214
|
+
)
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
def graphql_create_association_resolver(association_def, resolver_type, null: true, skip_dataloader: false, case_sensitive: nil, **)
|
221
|
+
Class.new(::Resolvers::BaseResolver) do
|
222
|
+
type resolver_type, null: null
|
223
|
+
|
224
|
+
define_method :resolve do |*|
|
225
|
+
join_keys = association_def.join_keys
|
226
|
+
|
227
|
+
skip_dataloader ||= !Helpers.dataloader_support?(dataloader, association_def, join_keys.foreign_key)
|
228
|
+
|
229
|
+
return object.public_send(association_def.name) if skip_dataloader
|
174
230
|
|
175
|
-
|
231
|
+
value = object.public_send(join_keys.foreign_key)
|
232
|
+
dataloader.with(AssociationSource, association_def.klass, join_keys.key, case_sensitive: case_sensitive).load(value)
|
176
233
|
end
|
177
234
|
end
|
178
235
|
end
|
data/lib/graphiform/fields.rb
CHANGED
@@ -12,15 +12,17 @@ module Graphiform
|
|
12
12
|
as: nil,
|
13
13
|
**options
|
14
14
|
)
|
15
|
-
|
16
|
-
|
15
|
+
identifier = as || name
|
16
|
+
column_def = column(identifier)
|
17
|
+
association_def = association(identifier)
|
17
18
|
|
18
19
|
graphql_add_column_field(name, column_def, as: as, **options) if column_def.present?
|
19
20
|
graphql_add_association_field(name, association_def, as: as, **options) if association_def.present?
|
20
21
|
graphql_add_method_field(name, as: as, **options) unless column_def.present? || association_def.present?
|
21
22
|
|
22
|
-
graphql_add_scopes_to_filter(name,
|
23
|
-
graphql_field_to_sort(name,
|
23
|
+
graphql_add_scopes_to_filter(name, identifier)
|
24
|
+
graphql_field_to_sort(name, identifier)
|
25
|
+
graphql_field_to_grouping(name, identifier)
|
24
26
|
end
|
25
27
|
|
26
28
|
def graphql_writable_field(
|
@@ -120,9 +122,11 @@ module Graphiform
|
|
120
122
|
type = association_def.klass.graphql_filter
|
121
123
|
end
|
122
124
|
|
123
|
-
|
125
|
+
filter_only_by_scopes = added_scopes.select do |scope_def|
|
126
|
+
!scope_def.options || scope_def.options[:type].blank? || scope_def.options[:type] == :enum
|
127
|
+
end
|
124
128
|
|
125
|
-
|
129
|
+
filter_only_by_scopes.each do |added_scope|
|
126
130
|
scope_argument_type = type || added_scope.options[:argument_type]
|
127
131
|
if added_scope.options[:type] == :enum
|
128
132
|
enum = graphql_create_enum(name)
|
@@ -175,6 +179,28 @@ module Graphiform
|
|
175
179
|
end
|
176
180
|
end
|
177
181
|
|
182
|
+
def graphql_field_to_grouping(name, as)
|
183
|
+
column_def = column(as || name)
|
184
|
+
association_def = association(as || name)
|
185
|
+
|
186
|
+
type = GraphQL::Types::Boolean if column_def.present?
|
187
|
+
type = association_def.klass.graphql_grouping if Helpers.association_arguments_valid?(association_def, :graphql_grouping)
|
188
|
+
|
189
|
+
return if type.blank?
|
190
|
+
|
191
|
+
local_graphql_grouping = graphql_grouping
|
192
|
+
|
193
|
+
local_graphql_grouping.class_eval do
|
194
|
+
argument(
|
195
|
+
name,
|
196
|
+
type,
|
197
|
+
required: false,
|
198
|
+
as: as,
|
199
|
+
method_access: false
|
200
|
+
)
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
178
204
|
def graphql_add_field_to_type(
|
179
205
|
field_name,
|
180
206
|
type,
|
@@ -241,6 +267,8 @@ module Graphiform
|
|
241
267
|
include_connection: true,
|
242
268
|
read_prepare: nil,
|
243
269
|
read_resolve: nil,
|
270
|
+
skip_dataloader: false,
|
271
|
+
case_sensitive: Graphiform.configuration[:case_sensitive],
|
244
272
|
**options
|
245
273
|
)
|
246
274
|
unless association_def.klass.respond_to?(:graphql_type)
|
@@ -266,7 +294,9 @@ module Graphiform
|
|
266
294
|
klass.graphql_connection,
|
267
295
|
read_prepare: read_prepare,
|
268
296
|
read_resolve: read_resolve,
|
269
|
-
null: false
|
297
|
+
null: false,
|
298
|
+
skip_dataloader: true,
|
299
|
+
case_sensitive: case_sensitive
|
270
300
|
),
|
271
301
|
false,
|
272
302
|
**options
|
@@ -281,10 +311,17 @@ module Graphiform
|
|
281
311
|
[klass.graphql_type],
|
282
312
|
read_prepare: read_prepare,
|
283
313
|
read_resolve: read_resolve,
|
284
|
-
null: false
|
314
|
+
null: false,
|
315
|
+
skip_dataloader: skip_dataloader,
|
316
|
+
case_sensitive: case_sensitive
|
285
317
|
)
|
286
318
|
else
|
287
|
-
klass.
|
319
|
+
klass.graphql_create_association_resolver(
|
320
|
+
association_def,
|
321
|
+
klass.graphql_type,
|
322
|
+
skip_dataloader: skip_dataloader,
|
323
|
+
case_sensitive: case_sensitive
|
324
|
+
)
|
288
325
|
end
|
289
326
|
)
|
290
327
|
|
data/lib/graphiform/helpers.rb
CHANGED
@@ -5,7 +5,7 @@ module Graphiform
|
|
5
5
|
def self.logger
|
6
6
|
return Rails.logger if Rails.logger.present?
|
7
7
|
|
8
|
-
@logger ||= Logger.new(
|
8
|
+
@logger ||= Logger.new($stdout)
|
9
9
|
@logger
|
10
10
|
end
|
11
11
|
|
@@ -32,6 +32,8 @@ module Graphiform
|
|
32
32
|
GraphQL::Types::Float
|
33
33
|
when :boolean
|
34
34
|
GraphQL::Types::Boolean
|
35
|
+
when :json, :jsonb
|
36
|
+
GraphQL::Types::JSON
|
35
37
|
else
|
36
38
|
active_record_type
|
37
39
|
end
|
@@ -70,5 +72,15 @@ module Graphiform
|
|
70
72
|
association_def.klass.send(method).respond_to?(:arguments) &&
|
71
73
|
!association_def.klass.send(method).arguments.empty?
|
72
74
|
end
|
75
|
+
|
76
|
+
def self.dataloader_support?(dataloader, association_def, keys)
|
77
|
+
(
|
78
|
+
association_def.present? &&
|
79
|
+
!association_def.polymorphic? &&
|
80
|
+
!association_def.through_reflection? &&
|
81
|
+
!keys.is_a?(Array) &&
|
82
|
+
!dataloader.is_a?(GraphQL::Dataloader::NullDataloader)
|
83
|
+
)
|
84
|
+
end
|
73
85
|
end
|
74
86
|
end
|
data/lib/graphiform/skeleton.rb
CHANGED
@@ -45,6 +45,14 @@ module Graphiform
|
|
45
45
|
Class.new(::GraphQL::Schema::InputObject)
|
46
46
|
end
|
47
47
|
|
48
|
+
Helpers.get_const_or_create('Groupings', ::Inputs) do
|
49
|
+
Module.new
|
50
|
+
end
|
51
|
+
|
52
|
+
Helpers.get_const_or_create('BaseGrouping', ::Inputs::Groupings) do
|
53
|
+
Class.new(::GraphQL::Schema::InputObject)
|
54
|
+
end
|
55
|
+
|
48
56
|
# Resolvers
|
49
57
|
Helpers.get_const_or_create('Resolvers') do
|
50
58
|
Module.new
|
data/lib/graphiform/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: graphiform
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.12
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- jayce.pulsipher
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-07-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -44,14 +44,14 @@ dependencies:
|
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: 0.2.
|
47
|
+
version: 0.2.9
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: 0.2.
|
54
|
+
version: 0.2.9
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: appraisal
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -120,6 +120,7 @@ files:
|
|
120
120
|
- Rakefile
|
121
121
|
- lib/graphiform.rb
|
122
122
|
- lib/graphiform/active_record_helpers.rb
|
123
|
+
- lib/graphiform/association_source.rb
|
123
124
|
- lib/graphiform/core.rb
|
124
125
|
- lib/graphiform/fields.rb
|
125
126
|
- lib/graphiform/helpers.rb
|