graphiform 0.1.2 → 0.2.2

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: d348d5da31c862403a9127ada31cbb135e892c21928ca48b8ccfb5eb2d64d047
4
- data.tar.gz: 73db372bee299b12a56e219218d04c4977436f3457379def8d0dd952a5e97aec
3
+ metadata.gz: 76a4ecba322d7e4c1f2486f621531307b184bf42f52827023ef5f11942b4bcbc
4
+ data.tar.gz: ed8815feff1a1eaba966dd44b5db53f1739fce88f0d0e9fb7a850dda522d74bc
5
5
  SHA512:
6
- metadata.gz: b22a9b8d9e6b612406ab06a1d8fc86e8ad9e6305a8f1d222d7dc36a08f72cf95d911445ab5e2c1d852714f565b8d8758b6f3c2b3a1ebb1e62199a11f1a4880cb
7
- data.tar.gz: c5766eb8d166b5311189ede79a26e21b5d55155199f24f995a763c9ddcc6540a5973bf360e1f5edb6ed75959085661f597e81946102a04b9022ad2ada48f5a61
6
+ metadata.gz: 412b372b015026737c993a1990031222c066272c5b9aec2563cd95e1474f5d2637d0a0ede3d3e589982ccb161b4b62d18c8380b117548e33221172689e1a5a41
7
+ data.tar.gz: b2c489a6c8f250f535657b5324aed7aa341365fa39540908ce2eabb6c403b793f71863cabfa63b6313ce60aab43731c94fc82492f7105e00d162a5eca0e1c96e
@@ -76,8 +76,38 @@ module Graphiform
76
76
  unless defined? @base_resolver
77
77
  @base_resolver = Helpers.get_const_or_create(demodulized_name, ::Resolvers) do
78
78
  Class.new(::Resolvers::BaseResolver) do
79
- # Default resolver just returns the object to prevent exceptions
80
- define_method :resolve do |**_args|
79
+ attr_reader :value
80
+
81
+ class << self
82
+ attr_accessor :addon_resolve_blocks
83
+ end
84
+
85
+ def self.addon_resolve(&block)
86
+ @addon_resolve_blocks ||= []
87
+ @addon_resolve_blocks << block
88
+ end
89
+
90
+ def resolve(**args)
91
+ @value = base_resolve(**args)
92
+
93
+ if self.class.addon_resolve_blocks.present? && !self.class.addon_resolve_blocks.empty?
94
+ self.class.addon_resolve_blocks.each do |addon_resolve_block|
95
+ @value = instance_exec(**args, &addon_resolve_block)
96
+ end
97
+ end
98
+
99
+ @value
100
+ end
101
+
102
+ def apply_built_ins(where: nil, sort: nil, **)
103
+ @value = @value.apply_filters(where.to_h) if where.present? && @value.respond_to?(:apply_filters)
104
+ @value = @value.apply_sorts(sort.to_h) if sort.present? && @value.respond_to?(:apply_sorts)
105
+
106
+ @value
107
+ end
108
+
109
+ # Default resolver - meant to be overridden
110
+ def base_resolve(**)
81
111
  object
82
112
  end
83
113
  end
@@ -86,7 +116,14 @@ module Graphiform
86
116
  local_graphql_filter = graphql_filter
87
117
  local_graphql_sort = graphql_sort
88
118
 
119
+ model = self
89
120
  @base_resolver.class_eval do
121
+ unless respond_to?(:model)
122
+ define_method :model do
123
+ model
124
+ end
125
+ end
126
+
90
127
  argument :where, local_graphql_filter, required: false
91
128
  argument :sort, local_graphql_sort, required: false unless local_graphql_sort.arguments.empty?
92
129
  end
@@ -97,16 +134,14 @@ module Graphiform
97
134
 
98
135
  def graphql_query
99
136
  Helpers.get_const_or_create(demodulized_name, ::Resolvers::Queries) do
100
- model = self
101
137
  local_graphql_type = graphql_type
102
138
  Class.new(graphql_base_resolver) do
103
139
  type local_graphql_type, null: false
104
140
 
105
- define_method :resolve do |where: nil|
106
- val = model.all
107
- val = val.apply_filters(where.to_h) if where.present? && val.respond_to?(:apply_filters)
108
-
109
- val.first
141
+ def base_resolve(**args)
142
+ @value = model.all
143
+ apply_built_ins(**args)
144
+ @value.first
110
145
  end
111
146
  end
112
147
  end
@@ -114,36 +149,30 @@ module Graphiform
114
149
 
115
150
  def graphql_connection_query
116
151
  Helpers.get_const_or_create(demodulized_name, ::Resolvers::ConnectionQueries) do
117
- model = self
118
152
  connection_type = graphql_connection
119
153
  Class.new(graphql_base_resolver) do
120
154
  type connection_type, null: false
121
155
 
122
- define_method :resolve do |where: nil, sort: nil|
123
- val = model.all
124
- val = val.apply_filters(where.to_h) if where.present? && val.respond_to?(:apply_filters)
125
- val = val.apply_sorts(sort.to_h) if sort.present? && val.respond_to?(:apply_sorts)
126
-
127
- val
156
+ def base_resolve(**args)
157
+ @value = model.all
158
+ apply_built_ins(**args)
128
159
  end
129
160
  end
130
161
  end
131
162
  end
132
163
 
133
- def graphql_create_resolver(method_name, resolver_type = graphql_type)
164
+ def graphql_create_resolver(method_name, resolver_type = graphql_type, read_prepare: nil, read_resolve: nil, **)
134
165
  Class.new(graphql_base_resolver) do
135
166
  type resolver_type, null: false
136
167
 
137
- define_method :resolve do |where: nil, **args|
138
- where_hash = where.to_h
139
-
140
- val = super(**args)
141
-
142
- val = val.public_send(method_name) if val.respond_to? method_name
168
+ define_method :base_resolve do |**args|
169
+ @value = object
143
170
 
144
- return val.apply_filters(where_hash) if val.respond_to? :apply_filters
171
+ @value = instance_exec(@value, context, &read_resolve) if read_resolve
172
+ @value = @value.public_send(method_name) if !read_resolve && @value.respond_to?(method_name)
173
+ @value = instance_exec(@value, context, &read_prepare) if read_prepare
145
174
 
146
- val
175
+ apply_built_ins(**args)
147
176
  end
148
177
  end
149
178
  end
@@ -9,17 +9,18 @@ module Graphiform
9
9
  module ClassMethods
10
10
  def graphql_readable_field(
11
11
  name,
12
+ as: nil,
12
13
  **options
13
14
  )
14
- column_def = column(name)
15
- association_def = association(name)
15
+ column_def = column(as || name)
16
+ association_def = association(as || name)
16
17
 
17
- graphql_add_column_field(name, column_def, **options) if column_def.present?
18
- graphql_add_association_field(name, association_def, **options) if association_def.present?
19
- graphql_add_method_field(name, **options) unless column_def.present? || association_def.present?
18
+ graphql_add_column_field(name, column_def, as: as, **options) if column_def.present?
19
+ graphql_add_association_field(name, association_def, as: as, **options) if association_def.present?
20
+ graphql_add_method_field(name, as: as, **options) unless column_def.present? || association_def.present?
20
21
 
21
- graphql_add_scopes_to_filter(name)
22
- graphql_field_to_sort(name)
22
+ graphql_add_scopes_to_filter(name, as || name)
23
+ graphql_field_to_sort(name, as || name)
23
24
  end
24
25
 
25
26
  def graphql_writable_field(
@@ -31,25 +32,30 @@ module Graphiform
31
32
  description: nil,
32
33
  default_value: ::GraphQL::Schema::Argument::NO_DEFAULT,
33
34
  as: nil,
34
- **_options
35
+ **
35
36
  )
36
37
  name = name.to_sym
37
- argument_name = graphql_resolve_argument_name(name)
38
- argument_type = graphql_resolve_argument_type(name, type)
38
+ has_nested_attributes_method = instance_methods.include?("#{as || name}_attributes=".to_sym)
39
39
 
40
- return Helpers.logger.warn "Graphiform: Missing `type` for argument #{name}" if argument_type.nil?
40
+ argument_name = has_nested_attributes_method ? "#{name}_attributes".to_sym : name
41
+ argument_type = graphql_resolve_argument_type(as || name, type)
42
+ as = has_nested_attributes_method ? "#{as}_attributes".to_sym : as.to_sym if as
43
+
44
+ return Helpers.logger.warn "Graphiform: Missing `type` for argument `#{name}` in model `#{self.name}`" if argument_type.nil?
41
45
 
42
46
  prepare = write_prepare || prepare
43
47
 
44
48
  graphql_input.class_eval do
45
- argument \
49
+ argument(
46
50
  argument_name,
47
51
  argument_type,
48
52
  required: required,
49
53
  prepare: prepare,
50
54
  description: description,
51
55
  default_value: default_value,
52
- as: as
56
+ as: as,
57
+ method_access: false
58
+ )
53
59
  end
54
60
  end
55
61
 
@@ -84,15 +90,9 @@ module Graphiform
84
90
 
85
91
  private
86
92
 
87
- def graphql_resolve_argument_name(name)
88
- attributes_name = "#{name}_attributes"
89
-
90
- return attributes_name.to_sym if instance_methods.include?("#{attributes_name}=".to_sym)
91
-
92
- name
93
- end
94
-
95
93
  def graphql_resolve_argument_type(name, type)
94
+ type = graphql_create_enum(name) if type.blank? && enum_attribute?(name)
95
+
96
96
  return Helpers.graphql_type(type) if type.present?
97
97
 
98
98
  column_def = column(name)
@@ -107,12 +107,12 @@ module Graphiform
107
107
  has_many ? [association_def.klass.graphql_input] : association_def.klass.graphql_input
108
108
  end
109
109
 
110
- def graphql_add_scopes_to_filter(name)
111
- added_scopes = auto_scopes_by_attribute(name)
110
+ def graphql_add_scopes_to_filter(name, as)
111
+ added_scopes = auto_scopes_by_attribute(as)
112
112
 
113
113
  return if added_scopes.empty?
114
114
 
115
- association_def = association(name)
115
+ association_def = association(as)
116
116
 
117
117
  if association_def.present?
118
118
  return unless Helpers.association_arguments_valid?(association_def, :graphql_filter)
@@ -128,19 +128,18 @@ module Graphiform
128
128
  enum = graphql_create_enum(name)
129
129
  scope_argument_type = scope_argument_type.is_a?(Array) ? [enum] : enum
130
130
  end
131
- add_scope_def_to_filter(added_scope, scope_argument_type)
131
+ add_scope_def_to_filter(name, added_scope, scope_argument_type)
132
132
  end
133
133
  end
134
134
 
135
- def add_scope_def_to_filter(scope_def, argument_type)
135
+ def add_scope_def_to_filter(name, scope_def, argument_type)
136
136
  return unless argument_type
137
137
 
138
138
  argument_type = Helpers.graphql_type(argument_type)
139
- camelized_attribute = scope_def.attribute.to_s.camelize(:lower)
139
+ argument_attribute = name
140
140
  argument_prefix = scope_def.prefix
141
- argument_suffix = scope_def.suffix
142
- argument_suffix = argument_suffix == '_is' ? '' : argument_suffix
143
- argument_name = "#{argument_prefix}#{camelized_attribute}#{argument_suffix}"
141
+ argument_suffix = scope_def.suffix == '_is' ? '' : scope_def.suffix
142
+ argument_name = "#{argument_prefix}#{argument_attribute}#{argument_suffix}".underscore
144
143
  scope_name = scope_def.name
145
144
 
146
145
  graphql_filter.class_eval do
@@ -148,15 +147,15 @@ module Graphiform
148
147
  argument_name,
149
148
  argument_type,
150
149
  required: false,
151
- camelize: false,
152
- as: scope_name
150
+ as: scope_name,
151
+ method_access: false
153
152
  )
154
153
  end
155
154
  end
156
155
 
157
- def graphql_field_to_sort(name)
158
- column_def = column(name)
159
- association_def = association(name)
156
+ def graphql_field_to_sort(name, as)
157
+ column_def = column(as || name)
158
+ association_def = association(as || name)
160
159
 
161
160
  type = ::Enums::Sort if column_def.present?
162
161
  type = association_def.klass.graphql_sort if Helpers.association_arguments_valid?(association_def, :graphql_sort)
@@ -169,7 +168,9 @@ module Graphiform
169
168
  argument(
170
169
  name,
171
170
  type,
172
- required: false
171
+ required: false,
172
+ as: as,
173
+ method_access: false
173
174
  )
174
175
  end
175
176
  end
@@ -181,18 +182,21 @@ module Graphiform
181
182
  description: nil,
182
183
  deprecation_reason: nil,
183
184
  method: nil,
185
+ as: nil,
184
186
  read_prepare: nil,
185
- **_options
187
+ read_resolve: nil,
188
+ **
186
189
  )
190
+ type = Helpers.graphql_type(type)
191
+ is_resolver = Helpers.resolver?(type)
192
+
187
193
  field_name = field_name.to_sym
188
194
  field_options = {
189
195
  description: description,
190
196
  deprecation_reason: deprecation_reason,
191
- method: method,
197
+ method: is_resolver ? nil : method || as,
192
198
  }
193
199
 
194
- type = Helpers.graphql_type(type)
195
-
196
200
  if Helpers.resolver?(type)
197
201
  field_options[:resolver] = type
198
202
  else
@@ -203,19 +207,40 @@ module Graphiform
203
207
  graphql_type.class_eval do
204
208
  added_field = field(field_name, **field_options)
205
209
 
206
- define_method(added_field.method_sym, -> { read_prepare.call(object.public_send(added_field.method_sym)) }) if read_prepare
210
+ if read_prepare || read_resolve
211
+ define_method(
212
+ added_field.method_sym,
213
+ lambda do
214
+ value = read_resolve ? instance_exec(object, context, &read_resolve) : object.public_send(added_field.method_sym)
215
+ instance_exec(value, context, &read_prepare) if read_prepare
216
+ end
217
+ )
218
+ end
207
219
  end
208
220
  end
209
221
 
210
- def graphql_add_column_field(field_name, column_def, type: nil, null: nil, **options)
211
- type = :string if type.blank? && enum_attribute?(field_name)
222
+ def graphql_add_column_field(field_name, column_def, type: nil, null: nil, as: nil, **options)
223
+ is_enum = type.blank? && enum_attribute?(as || field_name)
224
+ if is_enum
225
+ enum = graphql_create_enum(as || field_name)
226
+ type = enum
227
+ end
212
228
  type ||= column_def.type
213
229
  null = column_def.null if null.nil?
214
230
 
215
- graphql_add_field_to_type(field_name, type, null, **options)
231
+ graphql_add_field_to_type(field_name, type, null, as: as, **options)
216
232
  end
217
233
 
218
- def graphql_add_association_field(field_name, association_def, type: nil, null: nil, **options)
234
+ def graphql_add_association_field(
235
+ field_name,
236
+ association_def,
237
+ type: nil,
238
+ null: nil,
239
+ include_connection: true,
240
+ read_prepare: nil,
241
+ read_resolve: nil,
242
+ **options
243
+ )
219
244
  unless association_def.klass.respond_to?(:graphql_type)
220
245
  return Helpers.logger.warn(
221
246
  "Graphiform: `#{name}` trying to add association `#{field_name}` - `#{association_def.klass.name}` does not include Graphiform"
@@ -231,22 +256,46 @@ module Graphiform
231
256
  has_many = association_def.macro == :has_many
232
257
  klass = association_def.klass
233
258
 
234
- if has_many
259
+ if include_connection && has_many
235
260
  graphql_add_field_to_type(
236
261
  "#{field_name}_connection",
237
- klass.graphql_create_resolver(association_def.name, graphql_connection),
262
+ klass.graphql_create_resolver(
263
+ association_def.name,
264
+ klass.graphql_connection,
265
+ read_prepare: read_prepare,
266
+ read_resolve: read_resolve
267
+ ),
238
268
  false,
239
269
  **options
240
270
  )
241
271
  end
242
272
 
243
- type = has_many ? klass.graphql_create_resolver(association_def.name, [klass.graphql_type]) : klass.graphql_type if type.nil?
273
+ if type.nil?
274
+ type = (
275
+ if has_many
276
+ klass.graphql_create_resolver(
277
+ association_def.name,
278
+ [klass.graphql_type],
279
+ read_prepare: read_prepare,
280
+ read_resolve: read_resolve
281
+ )
282
+ else
283
+ klass.graphql_type
284
+ end
285
+ )
286
+
287
+ if has_many
288
+ read_prepare = nil
289
+ read_resolve = nil
290
+ end
291
+ end
292
+
244
293
  null = association_def.macro != :has_many if null.nil?
245
294
 
246
- graphql_add_field_to_type(field_name, type, null, **options)
295
+ graphql_add_field_to_type(field_name, type, null, read_prepare: read_prepare, read_resolve: read_resolve, **options)
247
296
  end
248
297
 
249
- def graphql_add_method_field(field_name, type:, null: true, **options)
298
+ def graphql_add_method_field(field_name, type: nil, null: true, **options)
250
299
  return Helpers.logger.warn "Graphiform: Missing `type` for field `#{field_name}` in model `#{name}`" if type.nil?
251
300
 
252
301
  graphql_add_field_to_type(field_name, type, null, **options)
@@ -1,3 +1,3 @@
1
1
  module Graphiform
2
- VERSION = '0.1.2'.freeze
2
+ VERSION = '0.2.2'.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.1.2
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - jayce.pulsipher
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-03-18 00:00:00.000000000 Z
11
+ date: 2020-05-28 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.0
47
+ version: 0.2.2
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.0
54
+ version: 0.2.2
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: appraisal
57
57
  requirement: !ruby/object:Gem::Requirement