graphiform 0.2.9 → 0.2.13

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 841f7ddfa6fd9f56cda166df64e77ec0d94fac684c872ce44b5fc024afe3d433
4
- data.tar.gz: 10c339a1f949bf05dfa2dcf94a8bf3332f3a1c468699c605ab8ac60966644fd0
3
+ metadata.gz: 24d0d05956c47d3c131958d9b273951c53d313f28dd622a5f841724ce18e1a4a
4
+ data.tar.gz: 82bd9b1ba24f07a5abc4cb164bd64ea8d217409d434613b543a2441edf5ba202
5
5
  SHA512:
6
- metadata.gz: e72009f747cf7bf8b6655940eb443900cf2c08e419cb25e1786aafc1b36347fb0f6916bc7d837a82681e46280a6bc5b6fe617b80ba081556f7acf319f01ed40b
7
- data.tar.gz: d13b40bf891ccad27f83e7a23c55b20b5c94c594bc83d28ee07b762aca7a5740030aeaec20789d2cccc590ca701a566e0257555d5e0c2ee67fe02608e61c25ec
6
+ metadata.gz: b5480858bde4de83a235a691ee1e7ec05f49f7348d44e0e8b3fd6e739ab17211f1f4ea7e0e651cd43edbe7b34b4227c429c7c87d542bea668a406cd679fff9b5
7
+ data.tar.gz: 96d29abd576caf4dfe334f10df9eddf89a32055c9677bcb600dccb07529a24d7531c5a2fb9e5a25595626164e9398bc900a0211b07537269a09472240480416a
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
@@ -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
@@ -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
 
@@ -153,7 +155,7 @@ module Graphiform
153
155
  def base_resolve(**args)
154
156
  @value = model.all
155
157
  apply_built_ins(**args)
156
- @value.first
158
+ @value.take
157
159
  end
158
160
  end
159
161
  end
@@ -173,18 +175,62 @@ module Graphiform
173
175
  end
174
176
  end
175
177
 
176
- 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], **)
177
179
  Class.new(graphql_base_resolver) do
178
180
  type resolver_type, null: null
179
181
 
180
182
  define_method :base_resolve do |**args|
181
183
  @value = object
182
184
 
183
- @value = instance_exec(@value, context, &read_resolve) if read_resolve
184
- @value = @value.public_send(method_name) if !read_resolve && @value.respond_to?(method_name)
185
- @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
186
187
 
187
- 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)
188
234
  end
189
235
  end
190
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
 
@@ -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(STDOUT)
8
+ @logger ||= Logger.new($stdout)
9
9
  @logger
10
10
  end
11
11
 
@@ -19,22 +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
- else
36
- active_record_type
37
- end
22
+ Graphiform.configuration[:scalar_mappings][active_record_type.to_sym] || active_record_type
38
23
  end
39
24
 
40
25
  def self.resolver?(val)
@@ -70,5 +55,19 @@ module Graphiform
70
55
  association_def.klass.send(method).respond_to?(:arguments) &&
71
56
  !association_def.klass.send(method).arguments.empty?
72
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
+ (
65
+ !association_def.scope ||
66
+ association_def.scope.arity.zero?
67
+ ) &&
68
+ !keys.is_a?(Array) &&
69
+ !dataloader.is_a?(GraphQL::Dataloader::NullDataloader)
70
+ )
71
+ end
73
72
  end
74
73
  end
@@ -1,3 +1,3 @@
1
1
  module Graphiform
2
- VERSION = '0.2.9'.freeze
2
+ VERSION = '0.2.13'.freeze
3
3
  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.9
4
+ version: 0.2.13
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-03-24 00:00:00.000000000 Z
11
+ date: 2021-08-03 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.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.7
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