graphql-rails-api 0.9.3 → 0.9.5

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: dfe867c4f64d230748b3d8a9d1aece95a16c6692d96491fd67298ad522ddd5ce
4
- data.tar.gz: 0a407e15eff08e02e8a202da0d47d3fe6116af42eb591421e3b5a914964f7a48
3
+ metadata.gz: 3613d8a2bc521ba1e8c8cdcc120b72ac56b5d6db12ac829c21d608605164aef4
4
+ data.tar.gz: 8365841223a6f4390e8fdbd870d5f3a48d1982b69dba3d1eb05b385dd54eb509
5
5
  SHA512:
6
- metadata.gz: e508676774b519da77b95483e1a0d28a91e1843925dc1669f674cb958d911ada161968923a385d86af51b86d47af56baecff3fe5a959cb1b727aed556834df6c
7
- data.tar.gz: 3e1aefb503057898ba28eb3008fd2e8b4c63f792fd530ac0a3bcfdf8754ed168a5b5f7f6c1dbaf76f96961494bd03da7f905fc57ba19ccaabd26af1eb8dddffc
6
+ metadata.gz: 3bb630bcffe4434a46f1e9eeba4ef1f601f6dc77bc0bd1df8089249141b4997e7afc5e8ea8bd018e415cf02ba1b9f1efbef9f86ffe20b4f70bfd9231767fc3f4
7
+ data.tar.gz: '09c3d6d3967e433b58746f125ec9071024fe18609f42d91cee150c88017ec63d0c15abd4d0102f19ab042ca3f812298f86482d9575139248dd5ce4b5fb0e3b4a'
@@ -8,13 +8,13 @@ class GraphqlAddFieldsGenerator < Rails::Generators::NamedBase
8
8
  end
9
9
 
10
10
  TYPES_MAPPING = {
11
- 'id' => 'types.String',
12
- 'uuid' => 'types.String',
13
- 'boolean' => 'types.Boolean',
14
- 'float' => 'types.Float',
15
- 'decimal' => 'types.Float',
16
- 'integer' => 'types.Int',
17
- 'bigint' => 'types.Int'
11
+ 'id' => 'String',
12
+ 'uuid' => 'String',
13
+ 'boolean' => 'Boolean',
14
+ 'float' => 'Float',
15
+ 'decimal' => 'Float',
16
+ 'integer' => 'Integer',
17
+ 'bigint' => 'Integer'
18
18
  }.freeze
19
19
 
20
20
  def create_graphql_files
@@ -35,30 +35,30 @@ class GraphqlAddFieldsGenerator < Rails::Generators::NamedBase
35
35
  add_has_many_to_models(@resource) if options.propagation?
36
36
  add_has_many_fields_to_types(@resource) if options.propagation?
37
37
 
38
- system('bundle exec rails db:migrate') if options.migrate?
38
+ # system('bundle exec rails db:migrate') if options.migrate?
39
39
  end
40
40
 
41
41
  private
42
42
 
43
43
  def types_mapping(type)
44
- TYPES_MAPPING[type] || 'types.String'
44
+ TYPES_MAPPING[type] || 'String'
45
45
  end
46
46
 
47
47
  def complete_graphql_input_type
48
48
  return if map_types(input_type: true).blank?
49
49
 
50
- write_at("#{@mutations_directory}/input_type.rb", 4, " #{map_types(input_type: true)}\n")
50
+ write_at("#{@mutations_directory}/input_type.rb", 7, " #{map_types(input_type: true)}\n")
51
51
  end
52
52
 
53
53
  def complete_graphql_type(resource)
54
54
  return if map_types(input_type: false).blank?
55
55
 
56
- write_at("#{graphql_resource_directory(resource)}/type.rb", 4, " #{map_types(input_type: false)}\n")
56
+ write_at("#{graphql_resource_directory(resource)}/type.rb", 6, " #{map_types(input_type: false)}\n")
57
57
  end
58
58
 
59
59
  def parse_args
60
60
  @id_db_type = 'uuid'
61
- @id_type = 'types.String'
61
+ @id_type = 'String'
62
62
 
63
63
  @resource = file_name.singularize
64
64
  @has_many = []
@@ -114,13 +114,8 @@ class GraphqlAddFieldsGenerator < Rails::Generators::NamedBase
114
114
  end
115
115
 
116
116
  write_at(
117
- file_name, 4,
118
- <<-STRING
119
- field :#{resource.singularize}_ids, types[#{@id_type}] do
120
- resolve CollectionIdsResolver
121
- end
122
- field :#{resource.pluralize}, types[#{resource.pluralize.camelize}::Type]
123
- STRING
117
+ file_name, 6,
118
+ " field :#{resource.pluralize}, [#{resource.pluralize.camelize}::Type], null: true\n"
124
119
  )
125
120
 
126
121
  input_type_file_name = "app/graphql/#{field.pluralize}/mutations/input_type.rb"
@@ -130,10 +125,8 @@ class GraphqlAddFieldsGenerator < Rails::Generators::NamedBase
130
125
  end
131
126
 
132
127
  write_at(
133
- input_type_file_name, 4,
134
- <<-STRING
135
- argument :#{resource.singularize}_ids, types[#{@id_type}]
136
- STRING
128
+ input_type_file_name, 7,
129
+ " argument :#{resource.singularize}_ids, [#{@id_type}], required: false\n"
137
130
  )
138
131
  end
139
132
 
@@ -145,11 +138,8 @@ class GraphqlAddFieldsGenerator < Rails::Generators::NamedBase
145
138
  end
146
139
 
147
140
  write_at(
148
- file_name, 4,
149
- <<-STRING
150
- field :#{field.singularize}_id, #{@id_type}
151
- field :#{field.singularize}, #{field.pluralize.camelize}::Type
152
- STRING
141
+ file_name, 6,
142
+ " field :#{field.singularize}_id, #{@id_type}, null: false\n field :#{field.singularize}, #{field.pluralize.camelize}::Type, null: false\n"
153
143
  )
154
144
  input_type_file_name = "app/graphql/#{resource.pluralize}/mutations/input_type.rb"
155
145
  if File.read(input_type_file_name).include?("argument :#{field.singularize}_id") ||
@@ -158,10 +148,8 @@ class GraphqlAddFieldsGenerator < Rails::Generators::NamedBase
158
148
  end
159
149
 
160
150
  write_at(
161
- input_type_file_name, 4,
162
- <<-STRING
163
- argument :#{field.singularize}_id, #{@id_type}
164
- STRING
151
+ input_type_file_name, 7,
152
+ " argument :#{field.singularize}_id, #{@id_type}, required: false\n"
165
153
  )
166
154
  end
167
155
 
@@ -225,14 +213,14 @@ t.#{@id_db_type} :#{resource.underscore.singularize}_id
225
213
  result = args&.map do |k, v|
226
214
  field_name = k
227
215
  field_type = types_mapping(v)
228
- res = "#{input_type ? 'argument' : 'field'} :#{field_name}, #{field_type}"
216
+ res = "#{input_type ? 'argument' : 'field'} :#{field_name}, #{field_type}, #{input_type ? "required: false" : "null: true"}"
229
217
  if !input_type && field_name.ends_with?('_id') && @belongs_to_fields.key?(field_name)
230
- res += "\n field :#{field_name.gsub('_id', '')}, " \
218
+ res += "\n field :#{field_name.gsub('_id', '')}, " \
231
219
  "#{field_name.gsub('_id', '').pluralize.camelize}::Type"
232
220
  end
233
221
  res
234
- end&.join("\n ")
235
- input_type ? result.gsub("field :id, #{@id_type}\n", '') : result
222
+ end&.join("\n " + (" " if input_type).to_s)
223
+ input_type ? result.gsub("field :id, #{@id_type}, null: false\n", '') : result
236
224
  end
237
225
 
238
226
  # Helpers methods
@@ -248,13 +236,13 @@ t.#{@id_db_type} :#{resource.underscore.singularize}_id
248
236
  file = open(file_name)
249
237
  line_count = file.readlines.size
250
238
  line_nb = 0
251
- file.each do |l|
239
+ IO.readlines(file).each do |l|
252
240
  line_nb += 1
253
241
  break if l.include?('ApplicationRecord')
254
242
  end
255
243
  raise 'Your model must inherit from ApplicationRecord to make it work' if line_nb >= line_count
256
244
 
257
- write_at(file_name, line_nb + 2, " #{line}\n")
245
+ write_at(file_name, line_nb + 1, " #{line}\n")
258
246
  end
259
247
 
260
248
  def generate_has_many_migration(resource, has_many:)
@@ -1,5 +1,4 @@
1
1
  class GraphqlMutationsGenerator < Rails::Generators::NamedBase
2
-
3
2
  def generate
4
3
  resource = file_name.underscore.singularize
5
4
  dir = "app/graphql/#{resource.pluralize}/mutations"
@@ -7,55 +6,30 @@ class GraphqlMutationsGenerator < Rails::Generators::NamedBase
7
6
  generate_create_mutation(dir, resource)
8
7
  generate_update_mutation(dir, resource)
9
8
  generate_destroy_mutation(dir, resource)
10
- generate_bulk_create_mutation(dir, resource)
11
- generate_bulk_update_mutation(dir, resource)
12
9
  end
13
10
 
14
11
  private
15
12
 
16
- def generate_bulk_create_mutation(dir, resource)
17
- File.write(
18
- "#{dir}/bulk_create.rb",
19
- <<~STRING
20
- #{resource_class(resource)}::Mutations::BulkCreate = GraphQL::Field.define do
21
- description 'creates some #{resource_class(resource).pluralize}'
22
- type types[#{resource_class(resource)}::Type]
23
-
24
- argument :#{resource}, !types[#{resource_class(resource)}::Mutations::InputType]
25
-
26
- resolve ApplicationService.call(:#{resource}, :bulk_create)
27
- end
28
- STRING
29
- )
30
- end
31
-
32
- def generate_bulk_update_mutation(dir, resource)
33
- File.write(
34
- "#{dir}/bulk_update.rb",
35
- <<~STRING
36
- #{resource_class(resource)}::Mutations::BulkUpdate = GraphQL::Field.define do
37
- description 'Updates some #{resource_class(resource).pluralize}'
38
- type types[#{resource_class(resource)}::Type]
39
-
40
- argument :#{resource}, !types[#{resource_class(resource)}::Mutations::InputType]
41
-
42
- resolve ApplicationService.call(:#{resource}, :bulk_update)
43
- end
44
- STRING
45
- )
46
- end
47
-
48
13
  def generate_create_mutation(dir, resource)
49
14
  File.write(
50
15
  "#{dir}/create.rb",
51
16
  <<~STRING
52
- #{resource_class(resource)}::Mutations::Create = GraphQL::Field.define do
53
- description 'Creates a #{resource_class(resource).singularize}'
54
- type #{resource_class(resource)}::Type
55
-
56
- argument :#{resource}, !#{resource_class(resource)}::Mutations::InputType
57
-
58
- resolve ApplicationService.call(:#{resource}, :create)
17
+ module #{resource_class(resource)}
18
+ module Mutations
19
+ class Create < GraphQL::Schema::Mutation
20
+ graphql_name "Create#{resource_class(resource)}"
21
+ description "Create a #{resource_class(resource).singularize}"
22
+
23
+ field :errors, [String], null: true
24
+ field :#{resource}, #{resource_class(resource)}::Type, null: true
25
+
26
+ argument :attributes, #{resource_class(resource)}::Mutations::InputType, required: false
27
+
28
+ def resolve(attributes:)
29
+ ApplicationService.call(:#{resource}, :create, context, attributes)
30
+ end
31
+ end
32
+ end
59
33
  end
60
34
  STRING
61
35
  )
@@ -65,14 +39,23 @@ class GraphqlMutationsGenerator < Rails::Generators::NamedBase
65
39
  File.write(
66
40
  "#{dir}/update.rb",
67
41
  <<~STRING
68
- #{resource_class(resource)}::Mutations::Update = GraphQL::Field.define do
69
- description 'Updates a #{resource_class(resource).singularize}'
70
- type #{resource_class(resource)}::Type
71
-
72
- argument :id, types.String
73
- argument :#{resource}, !#{resource_class(resource)}::Mutations::InputType
74
-
75
- resolve ApplicationService.call(:#{resource}, :update)
42
+ module #{resource_class(resource)}
43
+ module Mutations
44
+ class Update < GraphQL::Schema::Mutation
45
+ graphql_name "Update#{resource_class(resource)}"
46
+ description "Update a #{resource_class(resource).singularize}"
47
+
48
+ field :errors, [String], null: true
49
+ field :#{resource}, #{resource_class(resource)}::Type, null: true
50
+
51
+ argument :id, String, required: true
52
+ argument :attributes, #{resource_class(resource)}::Mutations::InputType, required: false
53
+
54
+ def resolve(id:, attributes:)
55
+ ApplicationService.call(:#{resource}, :update, context, id, attributes)
56
+ end
57
+ end
58
+ end
76
59
  end
77
60
  STRING
78
61
  )
@@ -82,13 +65,22 @@ class GraphqlMutationsGenerator < Rails::Generators::NamedBase
82
65
  File.write(
83
66
  "#{dir}/destroy.rb",
84
67
  <<~STRING
85
- #{resource_class(resource)}::Mutations::Destroy = GraphQL::Field.define do
86
- description 'Destroys a #{resource_class(resource).singularize}'
87
- type #{resource_class(resource)}::Type
88
-
89
- argument :id, !types.String
90
-
91
- resolve ApplicationService.call(:#{resource}, :destroy)
68
+ module #{resource_class(resource)}
69
+ module Mutations
70
+ class Destroy < GraphQL::Schema::Mutation
71
+ graphql_name "Destroy#{resource_class(resource)}"
72
+ description "Destroy a #{resource_class(resource).singularize}"
73
+
74
+ field :errors, [String], null: true
75
+ field :#{resource}, #{resource_class(resource)}::Type, null: true
76
+
77
+ argument :id, String, required: true
78
+
79
+ def resolve(id:)
80
+ ApplicationService.call(:#{resource}, :destroy, context, id)
81
+ end
82
+ end
83
+ end
92
84
  end
93
85
  STRING
94
86
  )
@@ -97,5 +89,4 @@ class GraphqlMutationsGenerator < Rails::Generators::NamedBase
97
89
  def resource_class(resource)
98
90
  @resource_class ||= resource.pluralize.camelize
99
91
  end
100
-
101
92
  end
@@ -3,7 +3,6 @@ require 'graphql/rails/api/config'
3
3
  module GraphqlRailsApi
4
4
  class InstallGenerator < Rails::Generators::Base
5
5
 
6
- class_option('apollo_compatibility', type: :boolean, default: true)
7
6
  class_option('generate_graphql_route', type: :boolean, default: true)
8
7
 
9
8
  def generate_files
@@ -165,18 +164,18 @@ end
165
164
  File.write(
166
165
  'app/graphql/mutation_type.rb',
167
166
  <<~'STRING'
168
- MutationType = GraphQL::ObjectType.define do
169
- name 'Mutation'
167
+ class MutationType < GraphQL::Schema::Object
168
+ graphql_name "Mutation"
169
+ description "The mutation root of this schema"
170
170
 
171
171
  Graphql::Rails::Api::Config.mutation_resources.each do |methd, resources|
172
172
  resources.each do |resource|
173
173
  field(
174
174
  "#{methd}_#{resource.singularize}".to_sym,
175
- "#{resource.camelize}::Mutations::#{methd.camelize}".constantize
175
+ mutation: "#{resource.camelize}::Mutations::#{methd.camelize}".constantize
176
176
  )
177
177
  end
178
178
  end
179
-
180
179
  end
181
180
  STRING
182
181
  )
@@ -186,59 +185,71 @@ end
186
185
  File.write(
187
186
  'app/graphql/query_type.rb',
188
187
  <<~'STRING'
189
- QueryType = GraphQL::ObjectType.define do
190
- name 'Query'
188
+ class QueryType < GraphQL::Schema::Object
189
+ description "The query root of this schema"
191
190
 
192
191
  Graphql::Rails::Api::Config.query_resources.each do |resource|
193
- field resource.singularize do
194
- description "Returns a #{resource.classify}"
195
- type !"#{resource.camelize}::Type".constantize
196
- argument :id, !types.String
197
- resolve ApplicationService.call(resource, :show)
192
+ klass = Class.new(GraphQL::Schema::Object) do
193
+ graphql_name "Paginated#{resource.classify}"
194
+
195
+ field :total_count, Integer, null: false
196
+ field :page, Integer, null: false
197
+ field :per_page, Integer, null: false
198
+ field :data, ["#{resource.pluralize.camelize}::Type".constantize], null: false
198
199
  end
199
200
 
200
- field resource.pluralize do
201
- description "Returns a #{resource.classify}"
202
- type !types[!"#{resource.camelize}::Type".constantize]
203
- argument :page, types.Int
204
- argument :per_page, types.Int
205
- argument :filter, types.String
206
- argument :order_by, types.String
207
- resolve ApplicationService.call(resource, :index)
201
+ resource.pluralize.camelize.constantize.const_set(
202
+ :PaginatedType,
203
+ klass
204
+ )
205
+
206
+ field "paginated_#{resource.pluralize}", "#{resource.camelize}::PaginatedType".constantize, null: false do
207
+ description "Return paginated #{resource.classify}"
208
+ argument :page, Integer, required: true
209
+ argument :per_page, Integer, required: true
210
+ argument :filter, String, required: false
211
+ argument :order_by, type: String, required: false
208
212
  end
209
213
 
210
- end
214
+ define_method("paginated_#{resource.pluralize}") do |page:, per_page:, filter: nil, order_by: nil|
215
+ arguments = {
216
+ page: page,
217
+ per_page: per_page,
218
+ filter: filter,
219
+ order_by: order_by
220
+ }
221
+ ApplicationService.call(resource, :paginated_index, context, arguments)
222
+ end
211
223
 
212
- field :me, Users::Type do
213
- description 'Returns the current user'
214
- resolve ->(_, _, ctx) { ctx[:current_user] }
215
- end
224
+ field resource.pluralize.to_sym, ["#{resource.camelize}::Type".constantize], null: false do
225
+ description "All #{resource.pluralize}"
226
+ argument :page, Integer, required: false
227
+ argument :per_page, Integer, required: false
228
+ argument :filter, String, required: false
229
+ argument :order_by, String, required: false
230
+ end
216
231
 
232
+ define_method(resource.pluralize) do |page: nil, per_page: nil, filter: nil, order_by: nil|
233
+ arguments = {page: page, per_page: per_page, filter: filter, order_by: order_by}
234
+ ApplicationService.call(resource, :index, context, arguments)
235
+ end
236
+
237
+ field resource.singularize.to_sym, "#{resource.camelize}::Type".constantize, null: false do
238
+ description "A #{resource.singularize}"
239
+ argument :id, String, required: true
240
+ end
241
+
242
+ define_method(resource.singularize) do |id:|
243
+ arguments = {id: id}
244
+ ApplicationService.call(resource, :show, context, arguments)
245
+ end
246
+ end
217
247
  end
248
+
218
249
  STRING
219
250
  )
220
251
  end
221
252
 
222
- def apollo_compat
223
- <<~'STRING'
224
- # /!\ do not remove /!\
225
- # Apollo Data compat.
226
- ClientDirective = GraphQL::Directive.define do
227
- name 'client'
228
- locations([GraphQL::Directive::FIELD])
229
- default_directive true
230
- end
231
- ConnectionDirective = GraphQL::Directive.define do
232
- name 'connection'
233
- locations([GraphQL::Directive::FIELD])
234
- argument :key, GraphQL::STRING_TYPE
235
- argument :filter, GraphQL::STRING_TYPE.to_list_type
236
- default_directive true
237
- end
238
- # end of Apollo Data compat.
239
- STRING
240
- end
241
-
242
253
  def write_schema
243
254
  logger = <<~'STRING'
244
255
  type_error_logger = Logger.new("#{Rails.root}/log/graphql_type_errors.log")
@@ -252,18 +263,20 @@ end
252
263
  File.write(
253
264
  "app/graphql/#{@app_name}_schema.rb",
254
265
  <<~STRING
255
- #{logger}
256
- #{apollo_compat if options.apollo_compatibility?}
257
- # Schema definition
258
- #{@app_name.camelize}Schema = GraphQL::Schema.define do
259
- mutation(MutationType)
260
- query(QueryType)
261
- #{'directives [ConnectionDirective, ClientDirective]' if options.apollo_compatibility?}
262
- type_error lambda { |err, query_ctx|
263
- #{error_handler}
264
- }
266
+ class #{@app_name.camelize}Schema < GraphQL::Schema
267
+ query QueryType
268
+ mutation MutationType
269
+ max_depth 15
270
+
271
+ def self.type_error(err, query_ctx)
272
+ type_error_logger = Logger.new("#{Rails.root}/log/graphql_type_errors.log")
273
+
274
+ type_error_logger.error(
275
+ "#{err} for #{query_ctx.query.query_string} with #{query_ctx.query.provided_variables}"
276
+ )
277
+ end
265
278
  end
266
- STRING
279
+ <<~STRING
267
280
  )
268
281
  end
269
282
 
@@ -317,41 +330,17 @@ end
317
330
  return not_allowed if not_allowed_to_create_resource(object)
318
331
 
319
332
  if object.save
320
- object
333
+ { singular_resource => Graphql::HydrateQuery.new(model.all, @context, user: user, id: object.id).run }
321
334
  else
322
335
  graphql_error(object.errors.full_messages.join(', '))
323
336
  end
324
337
  end
325
338
 
326
- def bulk_create
327
- result = model.import(params.map { |p| p.select { |param| model.new.respond_to?(param) } })
328
- result.each { |e| e.run_callbacks(:save) }
329
- hyd = Graphql::HydrateQuery.new(model.where(id: result.ids), @context).run.compact + result.failed_instances.map do |i|
330
- graphql_error(i.errors.full_messages)
331
- end
332
- return hyd.first if hyd.all? { |e| e.is_a?(GraphQL::ExecutionError) }
333
-
334
- hyd
335
- end
336
-
337
- def bulk_update
338
- visible_ids = model.where(id: params.map { |p| p[:id] }).pluck(:id)
339
- return not_allowed if (model.visible_for(user: user).pluck(:id) & visible_ids).size < visible_ids.size
340
-
341
- hash = params.each_with_object({}) { |p, h| h[p.delete(:id)] = p }
342
- failed_instances = []
343
- result = model.update(hash.keys, hash.values).map { |e| e.errors.blank? ? e : (failed_instances << e && nil) }
344
- hyd = Graphql::HydrateQuery.new(model.where(id: result.compact.map(&:id)), @context).run.compact + failed_instances.map do |i|
345
- graphql_error(i.errors.full_messages)
346
- end
347
- hyd.all? { |e| e.is_a?(GraphQL::ExecutionError) } ? hyd.first : hyd
348
- end
349
-
350
339
  def update
351
340
  return not_allowed if write_not_allowed
352
341
 
353
342
  if object.update_attributes(params)
354
- object
343
+ { singular_resource => Graphql::HydrateQuery.new(model.all, @context, user: user, id: object.id).run }
355
344
  else
356
345
  graphql_error(object.errors.full_messages.join(', '))
357
346
  end
@@ -362,7 +351,7 @@ end
362
351
  return not_allowed if write_not_allowed
363
352
 
364
353
  if object.destroy
365
- object
354
+ { singular_resource => object.attributes }
366
355
  else
367
356
  graphql_error(object.errors.full_messages.join(', '))
368
357
  end
@@ -1,20 +1,19 @@
1
1
  class GraphqlResourceGenerator < Rails::Generators::NamedBase
2
-
3
2
  %i[
4
3
  migration model mutations service graphql_input_type
5
- graphql_type propagation connection migrate
4
+ graphql_type propagation migrate
6
5
  ].each do |opt|
7
6
  class_option(opt, type: :boolean, default: true)
8
7
  end
9
8
 
10
9
  TYPES_MAPPING = {
11
- 'id' => 'types.String',
12
- 'uuid' => 'types.String',
13
- 'boolean' => 'types.Boolean',
14
- 'float' => 'types.Float',
15
- 'decimal' => 'types.Float',
16
- 'integer' => 'types.Int',
17
- 'bigint' => 'types.Int'
10
+ "id" => "String",
11
+ "uuid" => "String",
12
+ "boolean" => "Boolean",
13
+ "float" => "Float",
14
+ "decimal" => "Float",
15
+ "integer" => "Integer",
16
+ "bigint" => "Integer"
18
17
  }.freeze
19
18
 
20
19
  def create_graphql_files
@@ -42,18 +41,18 @@ class GraphqlResourceGenerator < Rails::Generators::NamedBase
42
41
  add_has_many_to_models(@resource) if options.propagation?
43
42
  add_has_many_fields_to_types(@resource) if options.propagation?
44
43
 
45
- system('bundle exec rails db:migrate') if options.migrate?
44
+ # system("bundle exec rails db:migrate") if options.migrate?
46
45
  end
47
46
 
48
47
  private
49
48
 
50
49
  def types_mapping(type)
51
- TYPES_MAPPING[type] || 'types.String'
50
+ TYPES_MAPPING[type] || "String"
52
51
  end
53
52
 
54
53
  def parse_args
55
- @id_db_type = 'uuid'
56
- @id_type = 'types.String'
54
+ @id_db_type = "uuid"
55
+ @id_type = "String"
57
56
 
58
57
  @resource = file_name.singularize
59
58
  @has_many = []
@@ -62,21 +61,21 @@ class GraphqlResourceGenerator < Rails::Generators::NamedBase
62
61
  @belongs_to_fields = {}
63
62
 
64
63
  @args = args.each_with_object({}) do |f, hash|
65
- next if f.split(':').count != 2
66
-
67
- case f.split(':').first
68
- when 'belongs_to' then
69
- hash["#{f.split(':').last.singularize}_id"] = @id_db_type
70
- @belongs_to_fields["#{f.split(':').last.singularize}_id"] = @id_db_type
71
- when 'has_many' then @has_many << f.split(':').last.pluralize
72
- when 'many_to_many' then @many_to_many << f.split(':').last.pluralize
64
+ next if f.split(":").count != 2
65
+
66
+ case f.split(":").first
67
+ when "belongs_to"
68
+ hash["#{f.split(":").last.singularize}_id"] = @id_db_type
69
+ @belongs_to_fields["#{f.split(":").last.singularize}_id"] = @id_db_type
70
+ when "has_many" then @has_many << f.split(":").last.pluralize
71
+ when "many_to_many" then @many_to_many << f.split(":").last.pluralize
73
72
  else
74
- hash[f.split(':').first] = f.split(':').last
73
+ hash[f.split(":").first] = f.split(":").last
75
74
  end
76
75
  end
77
76
 
78
77
  @fields_to_migration = @args.map do |f|
79
- "t.#{f.reverse.join(' :')}"
78
+ "t.#{f.reverse.join(" :")}"
80
79
  end.join("\n ")
81
80
  end
82
81
 
@@ -90,7 +89,7 @@ class GraphqlResourceGenerator < Rails::Generators::NamedBase
90
89
  File.write(
91
90
  migration_file,
92
91
  <<~STRING
93
- class Create#{resource.camelize} < ActiveRecord::Migration[5.2]
92
+ class Create#{resource.camelize} < ActiveRecord::Migration[7.0]
94
93
  def change
95
94
  create_table :#{resource.pluralize}, id: :uuid do |t|
96
95
  #{fields}
@@ -110,33 +109,20 @@ class GraphqlResourceGenerator < Rails::Generators::NamedBase
110
109
  generate_graphql_input_type(resource) if options.graphql_input_type?
111
110
  end
112
111
 
113
- def generate_graphql_connection(resource)
114
- File.write(
115
- "#{graphql_resource_directory(resource)}/connection.rb",
116
- <<~STRING
117
- #{resource_class(resource)}::Connection = #{resource.pluralize.camelize}::Type.define_connection do
118
- name '#{resource.camelize}Connection'
119
-
120
- field :total_count, types.Int do
121
- resolve ->(obj, _, _) { obj.nodes.count }
122
- end
123
- end
124
- STRING
125
- )
126
- end
127
-
128
112
  def generate_graphql_input_type(resource)
129
113
  FileUtils.mkdir_p(@mutations_directory) unless File.directory?(@mutations_directory)
130
114
 
131
115
  File.write(
132
116
  "#{@mutations_directory}/input_type.rb",
133
117
  <<~STRING
134
- #{resource_class(resource)}::Mutations::InputType = GraphQL::InputObjectType.define do
135
- name '#{resource_class(resource).singularize}InputType'
136
- description 'Properties for updating a #{resource_class(resource).singularize}'
137
-
138
- #{map_types(input_type: true)}
139
-
118
+ module #{resource_class(resource)}
119
+ module Mutations
120
+ class InputType < GraphQL::Schema::InputObject
121
+ graphql_name "#{resource.camelize}InputType"
122
+ description "Attributes for creating or updating a #{resource}"
123
+ #{map_types(input_type: true)}
124
+ end
125
+ end
140
126
  end
141
127
  STRING
142
128
  )
@@ -146,12 +132,16 @@ class GraphqlResourceGenerator < Rails::Generators::NamedBase
146
132
  File.write(
147
133
  "#{graphql_resource_directory(resource)}/type.rb",
148
134
  <<~STRING
149
- #{resource_class(resource)}::Type = GraphQL::ObjectType.define do
150
- name '#{resource_class(resource).singularize}'
151
- field :id, !#{@id_type}
152
- field :created_at, types.String
153
- field :updated_at, types.String
154
- #{map_types(input_type: false)}
135
+ module #{resource_class(resource)}
136
+ class Type < GraphQL::Schema::Object
137
+ graphql_name "#{resource.camelize}"
138
+ description "A #{resource}"
139
+
140
+ field :id, #{@id_type}, null: false
141
+ field :created_at, String, null: false
142
+ field :updated_at, String, null: false
143
+ #{map_types(input_type: false)}
144
+ end
155
145
  end
156
146
  STRING
157
147
  )
@@ -168,13 +158,7 @@ class GraphqlResourceGenerator < Rails::Generators::NamedBase
168
158
  return
169
159
  end
170
160
  write_at(
171
- file_name, 4,
172
- <<-STRING
173
- field :#{resource.singularize}_ids, types[#{@id_type}] do
174
- resolve CollectionIdsResolver
175
- end
176
- field :#{resource.pluralize}, types[#{resource.pluralize.camelize}::Type]
177
- STRING
161
+ file_name, 6," field :#{resource.pluralize}, [#{resource.pluralize.camelize}::Type], null: true\n"
178
162
  )
179
163
 
180
164
  input_type_file_name = "app/graphql/#{field.pluralize}/mutations/input_type.rb"
@@ -183,10 +167,8 @@ class GraphqlResourceGenerator < Rails::Generators::NamedBase
183
167
  return
184
168
  end
185
169
  write_at(
186
- input_type_file_name, 4,
187
- <<-STRING
188
- argument :#{resource.singularize}_ids, types[#{@id_type}]
189
- STRING
170
+ input_type_file_name, 7,
171
+ " argument :#{resource.singularize}_ids, [#{@id_type}], required: false\n"
190
172
  )
191
173
 
192
174
  end
@@ -199,11 +181,8 @@ class GraphqlResourceGenerator < Rails::Generators::NamedBase
199
181
  end
200
182
 
201
183
  write_at(
202
- file_name, 4,
203
- <<-STRING
204
- field :#{field.singularize}_id, #{@id_type}
205
- field :#{field.singularize}, #{field.pluralize.camelize}::Type
206
- STRING
184
+ file_name, 6,
185
+ " field :#{field.singularize}_id, #{@id_type}, null: false\n field :#{field.singularize}, #{field.pluralize.camelize}::Type, null: false\n"
207
186
  )
208
187
  input_type_file_name = "app/graphql/#{resource.pluralize}/mutations/input_type.rb"
209
188
  if File.read(input_type_file_name).include?("argument :#{field.singularize}_id") ||
@@ -212,10 +191,8 @@ class GraphqlResourceGenerator < Rails::Generators::NamedBase
212
191
  end
213
192
 
214
193
  write_at(
215
- input_type_file_name, 4,
216
- <<-STRING
217
- argument :#{field.singularize}_id, #{@id_type}
218
- STRING
194
+ input_type_file_name, 7,
195
+ " argument :#{field.singularize}_id, #{@id_type}, required: false\n"
219
196
  )
220
197
  end
221
198
 
@@ -225,8 +202,8 @@ class GraphqlResourceGenerator < Rails::Generators::NamedBase
225
202
  add_belongs_to_field_to_type(resource, f)
226
203
  end
227
204
  @belongs_to_fields.each do |f, _|
228
- add_has_many_fields_to_type(f.gsub('_id', ''), resource)
229
- add_belongs_to_field_to_type(f.gsub('_id', ''), resource)
205
+ add_has_many_fields_to_type(f.gsub("_id", ""), resource)
206
+ add_belongs_to_field_to_type(f.gsub("_id", ""), resource)
230
207
  end
231
208
  end
232
209
 
@@ -242,9 +219,8 @@ class GraphqlResourceGenerator < Rails::Generators::NamedBase
242
219
  end
243
220
 
244
221
  def generate_service(resource)
245
-
246
222
  FileUtils.mkdir_p("app/graphql/#{resource.pluralize}/") unless File.directory?("app/graphql/#{resource.pluralize}/")
247
-
223
+
248
224
  File.write(
249
225
  "app/graphql/#{resource.pluralize}/service.rb",
250
226
  <<~STRING
@@ -261,9 +237,9 @@ class GraphqlResourceGenerator < Rails::Generators::NamedBase
261
237
  @many_to_many.each do |field|
262
238
  generate_create_migration(
263
239
  "#{resource}_#{field}",
264
- <<-STRING
265
- t.#{@id_db_type} :#{resource.underscore.singularize}_id
266
- t.#{@id_db_type} :#{field.underscore.singularize}_id
240
+ <<~STRING
241
+ t.#{@id_db_type} :#{resource.underscore.singularize}_id
242
+ t.#{@id_db_type} :#{field.underscore.singularize}_id
267
243
  STRING
268
244
  )
269
245
  generate_empty_model("#{resource}_#{field.singularize}")
@@ -285,7 +261,7 @@ t.#{@id_db_type} :#{resource.underscore.singularize}_id
285
261
  add_to_model(field, "belongs_to :#{resource.singularize}")
286
262
  end
287
263
  @belongs_to_fields.each do |k, _|
288
- field = k.gsub('_id', '')
264
+ field = k.gsub("_id", "")
289
265
  add_to_model(field, "has_many :#{resource.pluralize}")
290
266
  add_to_model(resource, "belongs_to :#{field.singularize}")
291
267
  end
@@ -295,14 +271,15 @@ t.#{@id_db_type} :#{resource.underscore.singularize}_id
295
271
  result = args&.map do |k, v|
296
272
  field_name = k
297
273
  field_type = types_mapping(v)
298
- res = "#{input_type ? 'argument' : 'field'} :#{field_name}, #{field_type}"
299
- if !input_type && field_name.ends_with?('_id') && @belongs_to_fields.key?(field_name)
300
- res += "\n field :#{field_name.gsub('_id', '')}, " \
301
- "#{field_name.gsub('_id', '').pluralize.camelize}::Type"
274
+ res = "#{input_type ? "argument" : "field"} :#{field_name}, #{field_type}, #{input_type ? "required: false" : "null: true"}"
275
+
276
+ if !input_type && field_name.ends_with?("_id") && @belongs_to_fields.key?(field_name)
277
+ res += "\n field :#{field_name.gsub("_id", "")}, " \
278
+ "#{field_name.gsub("_id", "").pluralize.camelize}::Type, null: false"
302
279
  end
303
280
  res
304
- end&.join("\n ")
305
- input_type ? result.gsub("field :id, #{@id_type}\n", '') : result
281
+ end&.join("\n " + (" " if input_type).to_s)
282
+ input_type ? result.gsub("field :id, #{@id_type}, null: false\n", "") : result
306
283
  end
307
284
 
308
285
  # Helpers methods
@@ -312,19 +289,19 @@ t.#{@id_db_type} :#{resource.underscore.singularize}_id
312
289
  end
313
290
 
314
291
  def add_to_model(model, line)
315
- file_name = File.join("app","models","#{model.underscore.singularize}.rb")
292
+ file_name = File.join("app", "models", "#{model.underscore.singularize}.rb")
316
293
  return if !File.exist?(file_name) || File.read(file_name).include?(line)
317
294
 
318
295
  file = open(file_name)
319
296
  line_count = file.readlines.size
320
297
  line_nb = 0
321
- file.each do |l|
298
+ IO.readlines(file).each do |l|
322
299
  line_nb += 1
323
- break if l.include?('ApplicationRecord')
300
+ break if l.include?("ApplicationRecord")
324
301
  end
325
- raise 'Your model must inherit from ApplicationRecord to make it work' if line_nb >= line_count
302
+ raise "Your model must inherit from ApplicationRecord to make it work" if line_nb >= line_count
326
303
 
327
- write_at(file_name, line_nb + 2, " #{line}\n")
304
+ write_at(file_name, line_nb + 1, " #{line}\n")
328
305
  end
329
306
 
330
307
  def generate_has_many_migration(resource, has_many:)
@@ -335,7 +312,7 @@ t.#{@id_db_type} :#{resource.underscore.singularize}_id
335
312
  File.write(
336
313
  migration_file,
337
314
  <<~STRING
338
- class Add#{resource.singularize.camelize}IdTo#{has_many.camelize} < ActiveRecord::Migration[5.2]
315
+ class Add#{resource.singularize.camelize}IdTo#{has_many.camelize} < ActiveRecord::Migration[7.0]
339
316
  def change
340
317
  add_column :#{has_many.pluralize}, :#{resource.singularize}_id, :#{@id_db_type}
341
318
  end
@@ -349,7 +326,7 @@ t.#{@id_db_type} :#{resource.underscore.singularize}_id
349
326
  end
350
327
 
351
328
  def write_at(file_name, line, data)
352
- open(file_name, 'r+') do |f|
329
+ open(file_name, "r+") do |f|
353
330
  while (line -= 1).positive?
354
331
  f.readline
355
332
  end
@@ -360,5 +337,4 @@ t.#{@id_db_type} :#{resource.underscore.singularize}_id
360
337
  f.write(rest)
361
338
  end
362
339
  end
363
-
364
340
  end
@@ -24,7 +24,7 @@ module Graphql
24
24
  def run
25
25
  if @id
26
26
  @model = @model.where(id: @id)
27
- deep_pluck_to_structs(@context&.irep_node).first
27
+ deep_pluck_to_structs(irep_node(model_name.singularize)).first
28
28
  else
29
29
  @model = @model.limit(@per_page)
30
30
  @model = @model.offset(@per_page * (@page - 1))
@@ -32,7 +32,7 @@ module Graphql
32
32
  transform_filter if @filter.present?
33
33
  transform_order if @order_by.present?
34
34
 
35
- deep_pluck_to_structs(@context&.irep_node)
35
+ deep_pluck_to_structs(irep_node(model_name.pluralize))
36
36
  end
37
37
  end
38
38
 
@@ -45,7 +45,7 @@ module Graphql
45
45
  @model = @model.offset(@per_page * (@page - 1))
46
46
 
47
47
  OpenStruct.new(
48
- data: deep_pluck_to_structs(@context&.irep_node&.typed_children&.values&.first.try(:[], "data")),
48
+ data: deep_pluck_to_structs(irep_node(model_name.pluralize, paginated: true)),
49
49
  total_count: @total,
50
50
  per_page: @per_page,
51
51
  page: @page
@@ -371,13 +371,29 @@ module Graphql
371
371
  parent_class_name.constantize.reflections[child.to_s.underscore]&.klass
372
372
  end
373
373
 
374
- def parse_fields(irep_node)
375
- fields = irep_node&.scoped_children&.values&.first
376
- fields = fields["edges"].scoped_children.values.first["node"]&.scoped_children&.values&.first if fields&.key?("edges")
374
+ def irep_node(name, paginated: false)
375
+ child = @context.query.lookahead.ast_nodes.first.children[@context[:query_index]]
376
+ result = if paginated
377
+ child.children.find { |n| n.name == "data" }.children
378
+ else
379
+ child.children
380
+ end
381
+ @context[:query_index] += 1
382
+ result
383
+ end
384
+
385
+ def parse_fields(global_fields)
386
+ return if global_fields.blank?
387
+
388
+ fields = global_fields.map do |field|
389
+ next if field.class != GraphQL::Language::Nodes::Field
390
+ field
391
+ end.compact
392
+
377
393
  return if fields.blank?
378
394
 
379
- fields.each_with_object({}) do |(k, v), h|
380
- h[k] = v.scoped_children == {} ? v.definition.name : parse_fields(v)
395
+ fields.each_with_object({}) do |node, h|
396
+ h[node.name.underscore] = node.children.blank? ? nil : parse_fields(node.children)
381
397
  end
382
398
  end
383
399
 
@@ -385,4 +401,5 @@ module Graphql
385
401
  @model.class.to_s.split("::").first.underscore.pluralize
386
402
  end
387
403
  end
404
+
388
405
  end
@@ -1,7 +1,7 @@
1
1
  module Graphql
2
2
  module Rails
3
3
  module Api
4
- VERSION = "0.9.3".freeze
4
+ VERSION = "0.9.5".freeze
5
5
  end
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: graphql-rails-api
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.3
4
+ version: 0.9.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - poilon
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-09-06 00:00:00.000000000 Z
11
+ date: 2022-11-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: graphql
@@ -16,20 +16,20 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.12'
19
+ version: 2.0.15
20
20
  - - "<="
21
21
  - !ruby/object:Gem::Version
22
- version: 1.12.13
22
+ version: 2.0.15
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
26
26
  requirements:
27
27
  - - "~>"
28
28
  - !ruby/object:Gem::Version
29
- version: '1.12'
29
+ version: 2.0.15
30
30
  - - "<="
31
31
  - !ruby/object:Gem::Version
32
- version: 1.12.13
32
+ version: 2.0.15
33
33
  - !ruby/object:Gem::Dependency
34
34
  name: deep_pluck_with_authorization
35
35
  requirement: !ruby/object:Gem::Requirement
@@ -50,14 +50,14 @@ dependencies:
50
50
  requirements:
51
51
  - - ">="
52
52
  - !ruby/object:Gem::Version
53
- version: 5.1.4
53
+ version: '0'
54
54
  type: :runtime
55
55
  prerelease: false
56
56
  version_requirements: !ruby/object:Gem::Requirement
57
57
  requirements:
58
58
  - - ">="
59
59
  - !ruby/object:Gem::Version
60
- version: 5.1.4
60
+ version: '0'
61
61
  - !ruby/object:Gem::Dependency
62
62
  name: rkelly-remix
63
63
  requirement: !ruby/object:Gem::Requirement