graphiform 0.2.11 → 0.2.15

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7ee58551bb7e16aeccf79e81c5665e74cfa9bd6750c517b02eaef9f28deefe24
4
- data.tar.gz: 1d37cf0e858774a84d88dd87e6bd67c00bfd5266c76ceb7aa656dc612019d275
3
+ metadata.gz: fab0dbed0f9bf83d6772ad4cbe9a173481a05588b4b39de92c4d5a4d7e378e49
4
+ data.tar.gz: ccec67f90ba334776a3bdba195d15d1969b684e369f3ccf250815904b864b66c
5
5
  SHA512:
6
- metadata.gz: 056d9d69dfe38e12fd40dae4b62a758f86dea1daddb8c1f140910a5ea86beb51f1ecbd19a38b624bf51ee654058d4a63f7177781e6dde548c33bd2543d92eecd
7
- data.tar.gz: 84db19af1351992f07456ba23197661e8fc3a5843496ec2e2c53641f94786cbc7b8d675fd20566211e8ca419356f5b7d923de1b4da1f2a9a02b080095e80a3b8
6
+ metadata.gz: cb326352bc1be1cd962167795cd437b28abb1d72bcad3ad9fad7e0104782c0f55cfb00038d121f5e59b9240ba6701dfcf5ed9bd7ed9eba47497dde9ebaea22cb
7
+ data.tar.gz: '085525d8620e9417edffab0a665e814c24fa19363b01fcd649afac138e93975c952d7efe7c24ff3c85edba187d989ca657f260712738f52295e487210661fdaa'
@@ -0,0 +1,58 @@
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
21
+ query = query.merge(@model.instance_exec(&@options[:scope])) if @options[:scope].present?
22
+ query = query.where(@attribute => values)
23
+
24
+ query = query.includes(@options[:includes]) if @options[:includes].present? && query.respond_to?(:includes)
25
+ query = query.apply_filters(@options[:where].to_h) if @options[:where].present? && query.respond_to?(:apply_filters)
26
+ query = query.apply_sorts(@options[:sort].to_h) if @options[:sort].present? && query.respond_to?(:apply_sorts)
27
+
28
+ query
29
+ end
30
+
31
+ def normalize_value(value)
32
+ value = value.downcase if !@options[:case_sensitive] && value.is_a?(String)
33
+
34
+ value
35
+ end
36
+
37
+ def normalize_values(values)
38
+ type_for_attribute = @model.type_for_attribute(@attribute) if @model.respond_to?(:type_for_attribute)
39
+ values.map do |value|
40
+ value = type_for_attribute.cast(value) if type_for_attribute.present?
41
+ normalize_value(value)
42
+ end
43
+ end
44
+
45
+ def results(values, records)
46
+ record_attributes = records.map { |record| normalize_value(record[@attribute]) }
47
+ values.map do |value|
48
+ if @options[:multi]
49
+ indexes = record_attributes.each_index.select { |index| record_attributes[index] == value }
50
+ indexes.map { |index| index && records[index] }
51
+ else
52
+ index = record_attributes.index(value)
53
+ index && records[index]
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -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
@@ -174,18 +175,62 @@ module Graphiform
174
175
  end
175
176
  end
176
177
 
177
- 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], **)
178
179
  Class.new(graphql_base_resolver) do
179
180
  type resolver_type, null: null
180
181
 
181
182
  define_method :base_resolve do |**args|
182
183
  @value = object
183
184
 
184
- @value = instance_exec(@value, context, &read_resolve) if read_resolve
185
- @value = @value.public_send(method_name) if !read_resolve && @value.respond_to?(method_name)
186
- @value = instance_exec(@value, context, &read_prepare) if read_prepare
185
+ association_def = @value.association(method_name)&.reflection
186
+ join_keys = association_def&.join_keys
187
187
 
188
- apply_built_ins(**args)
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
+ scope: association_def.scope,
208
+ where: args[:where],
209
+ sort: args[:sort],
210
+ multi: true,
211
+ case_sensitive: case_sensitive,
212
+ )
213
+ .load(
214
+ @value.public_send(join_keys.foreign_key)
215
+ )
216
+ end
217
+ end
218
+ end
219
+ end
220
+
221
+ def graphql_create_association_resolver(association_def, resolver_type, null: true, skip_dataloader: false, case_sensitive: nil, **)
222
+ Class.new(::Resolvers::BaseResolver) do
223
+ type resolver_type, null: null
224
+
225
+ define_method :resolve do |*|
226
+ join_keys = association_def.join_keys
227
+
228
+ skip_dataloader ||= !Helpers.dataloader_support?(dataloader, association_def, join_keys.foreign_key)
229
+
230
+ return object.public_send(association_def.name) if skip_dataloader
231
+
232
+ value = object.public_send(join_keys.foreign_key)
233
+ dataloader.with(AssociationSource, association_def.klass, join_keys.key, scope: association_def.scope, case_sensitive: case_sensitive).load(value)
189
234
  end
190
235
  end
191
236
  end
@@ -12,16 +12,17 @@ module Graphiform
12
12
  as: nil,
13
13
  **options
14
14
  )
15
- column_def = column(as || name)
16
- association_def = association(as || name)
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, as || name)
23
- graphql_field_to_sort(name, as || name)
24
- graphql_field_to_grouping(name, as || name)
23
+ graphql_add_scopes_to_filter(name, identifier)
24
+ graphql_field_to_sort(name, identifier)
25
+ graphql_field_to_grouping(name, identifier)
25
26
  end
26
27
 
27
28
  def graphql_writable_field(
@@ -266,6 +267,8 @@ module Graphiform
266
267
  include_connection: true,
267
268
  read_prepare: nil,
268
269
  read_resolve: nil,
270
+ skip_dataloader: false,
271
+ case_sensitive: Graphiform.configuration[:case_sensitive],
269
272
  **options
270
273
  )
271
274
  unless association_def.klass.respond_to?(:graphql_type)
@@ -291,7 +294,9 @@ module Graphiform
291
294
  klass.graphql_connection,
292
295
  read_prepare: read_prepare,
293
296
  read_resolve: read_resolve,
294
- null: false
297
+ null: false,
298
+ skip_dataloader: true,
299
+ case_sensitive: case_sensitive
295
300
  ),
296
301
  false,
297
302
  **options
@@ -306,10 +311,17 @@ module Graphiform
306
311
  [klass.graphql_type],
307
312
  read_prepare: read_prepare,
308
313
  read_resolve: read_resolve,
309
- null: false
314
+ null: false,
315
+ skip_dataloader: skip_dataloader,
316
+ case_sensitive: case_sensitive
310
317
  )
311
318
  else
312
- klass.graphql_type
319
+ klass.graphql_create_association_resolver(
320
+ association_def,
321
+ klass.graphql_type,
322
+ skip_dataloader: skip_dataloader,
323
+ case_sensitive: case_sensitive
324
+ )
313
325
  end
314
326
  )
315
327
 
@@ -19,24 +19,7 @@ module Graphiform
19
19
  def self.graphql_type_single(active_record_type)
20
20
  return active_record_type unless active_record_type.respond_to?(:to_sym)
21
21
 
22
- case active_record_type.to_sym
23
- when :string, :text
24
- GraphQL::Types::String
25
- when :date
26
- GraphQL::Types::ISO8601Date
27
- when :time, :datetime, :timestamp
28
- GraphQL::Types::ISO8601DateTime
29
- when :integer
30
- GraphQL::Types::Int
31
- when :float, :decimal
32
- GraphQL::Types::Float
33
- when :boolean
34
- GraphQL::Types::Boolean
35
- when :json, :jsonb
36
- GraphQL::Types::JSON
37
- else
38
- active_record_type
39
- end
22
+ Graphiform.configuration[:scalar_mappings][active_record_type.to_sym] || active_record_type
40
23
  end
41
24
 
42
25
  def self.resolver?(val)
@@ -72,5 +55,20 @@ module Graphiform
72
55
  association_def.klass.send(method).respond_to?(:arguments) &&
73
56
  !association_def.klass.send(method).arguments.empty?
74
57
  end
58
+
59
+ def self.dataloader_support?(dataloader, association_def, keys)
60
+ (
61
+ association_def.present? &&
62
+ !association_def.polymorphic? &&
63
+ !association_def.through_reflection? &&
64
+ !association_def.inverse_of&.polymorphic? &&
65
+ (
66
+ !association_def.scope ||
67
+ association_def.scope.arity.zero?
68
+ ) &&
69
+ !keys.is_a?(Array) &&
70
+ !dataloader.is_a?(GraphQL::Dataloader::NullDataloader)
71
+ )
72
+ end
75
73
  end
76
74
  end
@@ -1,3 +1,3 @@
1
1
  module Graphiform
2
- VERSION = '0.2.11'.freeze
2
+ VERSION = '0.2.15'.freeze
3
3
  end
data/lib/graphiform.rb CHANGED
@@ -19,4 +19,34 @@ module Graphiform
19
19
  include Graphiform::Fields
20
20
  end
21
21
  end
22
+
23
+ def self.configuration
24
+ @configuration ||= {
25
+ scalar_mappings: {
26
+ string: GraphQL::Types::String,
27
+ text: GraphQL::Types::String,
28
+ # nchar: GraphQL::Types::String,
29
+
30
+ date: GraphQL::Types::ISO8601Date,
31
+
32
+ time: GraphQL::Types::ISO8601DateTime,
33
+ datetime: GraphQL::Types::ISO8601DateTime,
34
+ timestamp: GraphQL::Types::ISO8601DateTime,
35
+
36
+ integer: GraphQL::Types::Int,
37
+
38
+ float: GraphQL::Types::Float,
39
+ decimal: GraphQL::Types::Float,
40
+
41
+ boolean: GraphQL::Types::Boolean,
42
+
43
+ json: GraphQL::Types::JSON,
44
+ jsonb: GraphQL::Types::JSON,
45
+ },
46
+ }
47
+ end
48
+
49
+ def self.configure
50
+ yield(configuration)
51
+ end
22
52
  end
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.11
4
+ version: 0.2.15
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-07-12 00:00:00.000000000 Z
11
+ date: 2021-11-22 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.7
47
+ version: 0.2.10
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.7
54
+ version: 0.2.10
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
@@ -146,8 +147,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
146
147
  - !ruby/object:Gem::Version
147
148
  version: '0'
148
149
  requirements: []
149
- rubyforge_project:
150
- rubygems_version: 2.7.7
150
+ rubygems_version: 3.1.2
151
151
  signing_key:
152
152
  specification_version: 4
153
153
  summary: Generate GraphQL types, inputs, resolvers, queries, and connections based