graphiform 0.1.2 → 0.2.2

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: 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