graphql-rails-api 0.5.0 → 0.6.0
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 +4 -4
- data/lib/generators/graphql_connections/graphql_all_connections_generator.rb +1 -2
- data/lib/generators/graphql_mutations/graphql_bulk_update_mutations_generator.rb +0 -13
- data/lib/generators/graphql_mutations/graphql_mutations_generator.rb +34 -0
- data/lib/generators/graphql_rails_api/install_generator.rb +129 -65
- data/lib/generators/graphql_resource/graphql_resource_generator.rb +40 -13
- data/lib/graphql/hydrate_query.rb +23 -6
- data/lib/graphql/rails/api/config.rb +1 -1
- data/lib/graphql/rails/api/version.rb +1 -1
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 066b640b12080a61dc163b4989543cb22cff0c0bc000d5c5f2881ef74a37656a
|
4
|
+
data.tar.gz: '08e978790a84b509ad77c8a0fb58c6d496d891c095092676289c1516fcb478d9'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 68ab8d0cc279ca2edebdc20bf3b490b73e8badf3a9f7f0284ef9c3f85c4a1c56ff8f29f8d69d1f16eb7b97e2035e3223308d2f3b093ab5692c40ad560a42cc35
|
7
|
+
data.tar.gz: 44ffdd02ea1cf52065c29db18df694c518ca7b08a9a3264ff25895d702308127265dbce8319ea6e7ce5844df2aeb50f6f3d9c5cdcc4ac0e574675064ab71e58a
|
@@ -7,14 +7,13 @@ class GraphqlAllConnectionsGenerator < Rails::Generators::NamedBase
|
|
7
7
|
end
|
8
8
|
end
|
9
9
|
|
10
|
-
private
|
11
|
-
|
12
10
|
def generate_connection(dir, resource)
|
13
11
|
File.write(
|
14
12
|
"#{dir}/connection.rb",
|
15
13
|
<<~STRING
|
16
14
|
#{resource.pluralize.camelize}::Connection = #{resource.pluralize.camelize}::Type.define_connection do
|
17
15
|
name '#{resource.camelize}Connection'
|
16
|
+
|
18
17
|
field :total_count, types.Int do
|
19
18
|
resolve ->(obj, _, _) { obj.nodes.count }
|
20
19
|
end
|
@@ -27,17 +27,4 @@ class GraphqlBulkUpdateMutationsGenerator < Rails::Generators::NamedBase
|
|
27
27
|
resource.pluralize.camelize
|
28
28
|
end
|
29
29
|
|
30
|
-
def write_at(file_name, line, data)
|
31
|
-
open(file_name, 'r+') do |f|
|
32
|
-
while (line -= 1).positive?
|
33
|
-
f.readline
|
34
|
-
end
|
35
|
-
pos = f.pos
|
36
|
-
rest = f.read
|
37
|
-
f.seek pos
|
38
|
-
f.write data
|
39
|
-
f.write rest
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
30
|
end
|
@@ -8,10 +8,44 @@ class GraphqlMutationsGenerator < Rails::Generators::NamedBase
|
|
8
8
|
generate_create_mutation(dir, resource)
|
9
9
|
generate_update_mutation(dir, resource)
|
10
10
|
generate_destroy_mutation(dir, resource)
|
11
|
+
generate_bulk_create_mutation(dir, resource)
|
12
|
+
generate_bulk_update_mutation(dir, resource)
|
11
13
|
end
|
12
14
|
|
13
15
|
private
|
14
16
|
|
17
|
+
def generate_bulk_create_mutation(dir, resource)
|
18
|
+
File.write(
|
19
|
+
"#{dir}/bulk_create.rb",
|
20
|
+
<<~STRING
|
21
|
+
#{resource_class(resource)}::Mutations::BulkCreate = GraphQL::Field.define do
|
22
|
+
description 'creates some #{resource_class(resource).pluralize}'
|
23
|
+
type types[#{resource_class(resource)}::Type]
|
24
|
+
|
25
|
+
argument :#{resource}, types[#{resource_class(resource)}::Mutations::InputType]
|
26
|
+
|
27
|
+
resolve ApplicationService.call(:#{resource}, :bulk_create)
|
28
|
+
end
|
29
|
+
STRING
|
30
|
+
)
|
31
|
+
end
|
32
|
+
|
33
|
+
def generate_bulk_update_mutation(dir, resource)
|
34
|
+
File.write(
|
35
|
+
"#{dir}/bulk_update.rb",
|
36
|
+
<<~STRING
|
37
|
+
#{resource_class(resource)}::Mutations::BulkUpdate = GraphQL::Field.define do
|
38
|
+
description 'Updates some #{resource_class(resource).pluralize}'
|
39
|
+
type types[#{resource_class(resource)}::Type]
|
40
|
+
|
41
|
+
argument :#{resource}, types[#{resource_class(resource)}::Mutations::InputType]
|
42
|
+
|
43
|
+
resolve ApplicationService.call(:#{resource}, :bulk_update)
|
44
|
+
end
|
45
|
+
STRING
|
46
|
+
)
|
47
|
+
end
|
48
|
+
|
15
49
|
def generate_create_mutation(dir, resource)
|
16
50
|
File.write(
|
17
51
|
"#{dir}/create.rb",
|
@@ -21,7 +21,7 @@ module GraphqlRailsApi
|
|
21
21
|
write_controller
|
22
22
|
if options.action_cable_subs?
|
23
23
|
write_websocket_connection
|
24
|
-
|
24
|
+
write_online_users_channel
|
25
25
|
end
|
26
26
|
write_initializer
|
27
27
|
write_require_application_rb
|
@@ -51,6 +51,7 @@ module GraphqlRailsApi
|
|
51
51
|
'app/models/application_record.rb',
|
52
52
|
lines_count,
|
53
53
|
<<-STRING
|
54
|
+
|
54
55
|
def self.visible_for(*)
|
55
56
|
all
|
56
57
|
end
|
@@ -59,6 +60,45 @@ module GraphqlRailsApi
|
|
59
60
|
all
|
60
61
|
end
|
61
62
|
|
63
|
+
STRING
|
64
|
+
)
|
65
|
+
return unless options.action_cable_subs?
|
66
|
+
|
67
|
+
lines_count = File.read('app/models/application_record.rb').lines.count
|
68
|
+
write_at(
|
69
|
+
'app/models/application_record.rb',
|
70
|
+
lines_count,
|
71
|
+
<<-STRING
|
72
|
+
after_commit :notify_online_users
|
73
|
+
|
74
|
+
def notify_online_users
|
75
|
+
Redis.current.keys('#{Rails.application.class.parent_name.underscore}_subscribed_query_*').each_with_object({}) do |key, hash|
|
76
|
+
hash[
|
77
|
+
key.gsub('#{Rails.application.class.parent_name.underscore}_subscribed_query_', '')
|
78
|
+
] = Redis.current.hgetall(key).each_with_object([]) do |(data, vars), array|
|
79
|
+
data = data.split('/////')
|
80
|
+
array << { query: data[0], store: data[1], variables: vars.blank? ? nil : JSON.parse(vars), scope: data[2] }
|
81
|
+
end
|
82
|
+
end.each do |user_id, user_queries_array|
|
83
|
+
user_queries_array.map { |user_hash| notify_user(user_id, user_hash) }
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def notify_user(user_id, user_hash)
|
88
|
+
model_name = self.class.to_s.underscore
|
89
|
+
if !user_hash[:query].include?(model_name.singularize + '(id: $id') &&
|
90
|
+
!user_hash[:query].include?(' ' + model_name.pluralize)
|
91
|
+
return
|
92
|
+
end
|
93
|
+
return if user_hash[:query].include?(model_name + '(id: $id') && user_hash[:variables]['id'] != id
|
94
|
+
|
95
|
+
u = User.find_by(id: user_id)
|
96
|
+
return unless u
|
97
|
+
|
98
|
+
result = #{Rails.application.class.parent_name}ApiSchema.execute(user_hash[:query], context: { current_user: u }, variables: user_hash[:variables])
|
99
|
+
OnlineUsersChannel.broadcast_to(u, store: user_hash[:store], scope: user_hash[:scope], result: result['data'])
|
100
|
+
end
|
101
|
+
|
62
102
|
STRING
|
63
103
|
)
|
64
104
|
end
|
@@ -98,9 +138,6 @@ module GraphqlRailsApi
|
|
98
138
|
config = Graphql::Rails::Api::Config.instance
|
99
139
|
|
100
140
|
config.id_type = #{options.pg_uuid? ? ':uuid' : ':id'} # :id or :uuid
|
101
|
-
|
102
|
-
# Possibilites are :create, :update or :destroy
|
103
|
-
config.basic_mutations = %i[create update destroy]
|
104
141
|
STRING
|
105
142
|
)
|
106
143
|
end
|
@@ -125,58 +162,45 @@ module GraphqlRailsApi
|
|
125
162
|
)
|
126
163
|
end
|
127
164
|
|
128
|
-
def
|
165
|
+
def write_online_users_channel
|
129
166
|
File.write(
|
130
|
-
'app/channels/
|
167
|
+
'app/channels/online_users_channel.rb',
|
131
168
|
<<~STRING
|
132
|
-
class
|
169
|
+
class OnlineUsersChannel < ApplicationCable::Channel
|
133
170
|
|
134
171
|
def subscribed
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
query, context, variables, operation_name = options_for_execute(data)
|
141
|
-
result = #{@app_name.camelize}Schema.execute(query: query, context: context,
|
142
|
-
variables: variables, operation_name: operation_name)
|
143
|
-
payload = { result: result.subscription? ? nil : result.to_h, more: result.subscription?,
|
144
|
-
errors: result ? result.to_h[:errors] : nil }
|
145
|
-
@subscription_ids << result.context[:subscription_id] if result.context[:subscription_id]
|
146
|
-
transmit(payload)
|
172
|
+
stream_for(current_user)
|
173
|
+
Redis.current.hset('#{Rails.application.class.parent_name.underscore}_online_users', current_user.id, '1')
|
174
|
+
User.online.each do |user|
|
175
|
+
OnlineUsersChannel.broadcast_to(user, User.online_user_ids)
|
176
|
+
end
|
147
177
|
end
|
148
178
|
|
149
|
-
def
|
150
|
-
|
151
|
-
#{
|
152
|
-
|
179
|
+
def subscribe_to_query(data)
|
180
|
+
Redis.current.hset(
|
181
|
+
'#{Rails.application.class.parent_name.underscore}_subscribed_query_' + current_user.id,
|
182
|
+
data['query'] + '/////' + data['store'] + '/////' + data['scope'],
|
183
|
+
data['variables']
|
184
|
+
)
|
153
185
|
end
|
154
186
|
|
155
|
-
def
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
merge(ensure_hash(data['context']).symbolize_keys). # ensure context is filled
|
161
|
-
merge(variables) # include variables in context too
|
162
|
-
[query, context, variables, operation_name]
|
187
|
+
def unsubscribe_to_query(data)
|
188
|
+
Redis.current.hdel(
|
189
|
+
'#{Rails.application.class.parent_name.underscore}_subscribed_query_' + current_user.id,
|
190
|
+
data['query'] + '/////' + data['store']
|
191
|
+
)
|
163
192
|
end
|
164
193
|
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
when Hash, ActionController::Parameters
|
171
|
-
ambiguous_param
|
172
|
-
when nil
|
173
|
-
{}
|
174
|
-
else
|
175
|
-
raise ArgumentError, 'Unexpected parameter: ' + ambiguous_param
|
194
|
+
def unsubscribed
|
195
|
+
Redis.current.hset('#{Rails.application.class.parent_name.underscore}_online_users', current_user.id, '0')
|
196
|
+
Redis.current.hdel('#{Rails.application.class.parent_name.underscore}_subscribed_query_' + current_user.id, current_user.id)
|
197
|
+
User.online.each do |user|
|
198
|
+
OnlineUsersChannel.broadcast_to(user, User.online_user_ids)
|
176
199
|
end
|
177
200
|
end
|
178
201
|
|
179
202
|
end
|
203
|
+
|
180
204
|
STRING
|
181
205
|
)
|
182
206
|
end
|
@@ -347,7 +371,7 @@ module GraphqlRailsApi
|
|
347
371
|
attr_accessor :params, :object, :fields, :user
|
348
372
|
|
349
373
|
def initialize(params: {}, object: nil, object_id: nil, user: nil, context: nil)
|
350
|
-
@params = params.to_h.symbolize_keys
|
374
|
+
@params = params.is_a?(Array) ? params.map { |p| p.to_h.symbolize_keys } : params.to_h.symbolize_keys
|
351
375
|
@context = context
|
352
376
|
@object = object || (object_id && model.visible_for(user: user).find_by(id: object_id))
|
353
377
|
@object_id = object_id
|
@@ -365,51 +389,76 @@ module GraphqlRailsApi
|
|
365
389
|
end
|
366
390
|
|
367
391
|
def index
|
368
|
-
|
392
|
+
HydrateQuery.new(
|
393
|
+
model.all,
|
394
|
+
@context,
|
395
|
+
order_by: params[:order_by],
|
396
|
+
filter: params[:filter],
|
397
|
+
user: user
|
398
|
+
).run
|
369
399
|
end
|
370
400
|
|
371
401
|
def show
|
372
|
-
|
373
|
-
|
374
|
-
object
|
402
|
+
return not_allowed if access_not_allowed
|
403
|
+
|
404
|
+
showed_resource = HydrateQuery.new(model.all, @context, user: user, id: object.id).run
|
405
|
+
|
406
|
+
return not_allowed if showed_resource.blank?
|
407
|
+
|
408
|
+
showed_resource
|
375
409
|
end
|
376
410
|
|
377
411
|
def create
|
378
|
-
|
379
|
-
|
380
|
-
|
412
|
+
if user&.action?("can_create_#{singular_resource}")
|
413
|
+
created_resource = model.new(params.select { |p| model.new.respond_to?(p) })
|
414
|
+
return not_allowed if not_allowed_to_create_resource(created_resource)
|
415
|
+
|
416
|
+
created_resource.save ? created_resource : graphql_error(created_resource.errors.full_messages.join(', '))
|
417
|
+
elsif user&.action?("can_create_#{singular_resource}_with_verif")
|
418
|
+
Verification.create(action: 'create', model: model.to_s, params: params, user_id: user.id)
|
419
|
+
graphql_error("Pending verification for a #{singular_resource} creation")
|
381
420
|
else
|
382
|
-
|
421
|
+
not_allowed
|
383
422
|
end
|
384
423
|
end
|
385
424
|
|
386
|
-
def
|
387
|
-
object = model.find_by(id: params[:id])
|
425
|
+
def update
|
388
426
|
return not_allowed if write_not_allowed
|
389
|
-
|
390
|
-
|
427
|
+
|
428
|
+
if user.action?("can_update_#{singular_resource}")
|
429
|
+
object.update_attributes(params) ? object : graphql_error(object.errors.full_messages.join(', '))
|
430
|
+
elsif user.action?("can_update_#{singular_resource}_with_verif")
|
431
|
+
create_update_verification
|
391
432
|
else
|
392
|
-
|
433
|
+
not_allowed
|
393
434
|
end
|
394
435
|
end
|
395
436
|
|
396
|
-
def
|
397
|
-
return not_allowed if write_not_allowed
|
398
|
-
|
399
|
-
|
400
|
-
else
|
401
|
-
graphql_error(object.errors.full_messages.join(', '))
|
402
|
-
end
|
437
|
+
def destroy
|
438
|
+
return not_allowed if write_not_allowed || !user.action?("can_delete_#{singular_resource}")
|
439
|
+
|
440
|
+
object.destroy ? object : graphql_error(object.errors.full_messages.join(', '))
|
403
441
|
end
|
404
442
|
|
405
443
|
private
|
406
444
|
|
445
|
+
def create_update_verification
|
446
|
+
Verification.create(
|
447
|
+
action: 'update', model: model.to_s, params: params.merge(id: object.id), user_id: user.id
|
448
|
+
)
|
449
|
+
graphql_error("Pending verification for a #{singular_resource} update")
|
450
|
+
end
|
451
|
+
|
407
452
|
def write_not_allowed
|
408
|
-
|
453
|
+
return true unless object
|
454
|
+
|
455
|
+
!model.writable_for(user: user).pluck(:id).include?(object.id)
|
409
456
|
end
|
410
457
|
|
411
458
|
def access_not_allowed
|
412
|
-
|
459
|
+
return true unless object
|
460
|
+
|
461
|
+
!model.visible_for(user: user).pluck(:id).include?(object.id)
|
413
462
|
end
|
414
463
|
|
415
464
|
def not_allowed
|
@@ -432,8 +481,23 @@ module GraphqlRailsApi
|
|
432
481
|
self.class.to_s.split(':').first.underscore
|
433
482
|
end
|
434
483
|
|
484
|
+
def not_allowed_to_create_resource(created_resource)
|
485
|
+
params.select { |k, _| k.to_s.end_with?('_id') }.each do |belongs_relation, rel_id|
|
486
|
+
klass = created_resource.class.reflect_on_association(belongs_relation.to_s.gsub('_id', '')).klass
|
487
|
+
return true if rel_id.present? && !klass.visible_for(user: user).pluck(:id).include?(rel_id)
|
488
|
+
end
|
489
|
+
|
490
|
+
params.select { |k, _| k.to_s.end_with?('_ids') }.each do |many_relation, rel_ids|
|
491
|
+
klass = created_resource.class.reflect_on_association(many_relation.to_s.gsub('_ids', '').pluralize).klass
|
492
|
+
ids = klass.visible_for(user: user).pluck(:id)
|
493
|
+
rel_ids.each { |id| return true if id.present? && !ids.include?(id) }
|
494
|
+
end
|
495
|
+
false
|
496
|
+
end
|
497
|
+
|
435
498
|
end
|
436
499
|
|
500
|
+
|
437
501
|
STRING
|
438
502
|
)
|
439
503
|
end
|
@@ -1,12 +1,15 @@
|
|
1
1
|
class GraphqlResourceGenerator < Rails::Generators::NamedBase
|
2
2
|
|
3
|
-
%i[
|
3
|
+
%i[
|
4
|
+
migration model mutations service graphql_input_type
|
5
|
+
graphql_type propagation connection migrate
|
6
|
+
].each do |opt|
|
4
7
|
class_option(opt, type: :boolean, default: true)
|
5
8
|
end
|
6
9
|
|
7
10
|
TYPES_MAPPING = {
|
8
|
-
'id' => '
|
9
|
-
'uuid' => '
|
11
|
+
'id' => 'types.ID',
|
12
|
+
'uuid' => 'types.String',
|
10
13
|
'boolean' => 'types.Boolean',
|
11
14
|
'float' => 'types.Float',
|
12
15
|
'decimal' => 'types.Float',
|
@@ -16,6 +19,7 @@ class GraphqlResourceGenerator < Rails::Generators::NamedBase
|
|
16
19
|
|
17
20
|
def create_graphql_files
|
18
21
|
return if args.blank?
|
22
|
+
|
19
23
|
parse_args
|
20
24
|
|
21
25
|
# Generate migration
|
@@ -27,6 +31,9 @@ class GraphqlResourceGenerator < Rails::Generators::NamedBase
|
|
27
31
|
# Graphql Type
|
28
32
|
generate_graphql_type(@resource) if options.graphql_type?
|
29
33
|
|
34
|
+
# Graphql Connection
|
35
|
+
generate_graphql_connection(@resource) if options.connection?
|
36
|
+
|
30
37
|
# Model
|
31
38
|
generate_model(@resource) if options.model?
|
32
39
|
|
@@ -44,16 +51,16 @@ class GraphqlResourceGenerator < Rails::Generators::NamedBase
|
|
44
51
|
private
|
45
52
|
|
46
53
|
def types_mapping(type)
|
47
|
-
TYPES_MAPPING[type] ||
|
54
|
+
TYPES_MAPPING[type] || 'types.String'
|
48
55
|
end
|
49
56
|
|
50
57
|
def parse_args
|
51
58
|
if Graphql::Rails::Api::Config.instance.id_type == :uuid
|
52
59
|
@id_db_type = 'uuid'
|
53
|
-
@id_type = '
|
60
|
+
@id_type = 'types.String'
|
54
61
|
else
|
55
62
|
@id_db_type = 'integer'
|
56
|
-
@id_type = '
|
63
|
+
@id_type = 'types.ID'
|
57
64
|
end
|
58
65
|
|
59
66
|
@resource = file_name.singularize
|
@@ -64,6 +71,7 @@ class GraphqlResourceGenerator < Rails::Generators::NamedBase
|
|
64
71
|
|
65
72
|
@args = args.each_with_object({}) do |f, hash|
|
66
73
|
next if f.split(':').count != 2
|
74
|
+
|
67
75
|
case f.split(':').first
|
68
76
|
when 'belongs_to' then
|
69
77
|
hash["#{f.split(':').last.singularize}_id"] = @id_db_type
|
@@ -110,6 +118,21 @@ class GraphqlResourceGenerator < Rails::Generators::NamedBase
|
|
110
118
|
generate_graphql_input_type(resource) if options.graphql_input_type?
|
111
119
|
end
|
112
120
|
|
121
|
+
def generate_graphql_connection(resource)
|
122
|
+
File.write(
|
123
|
+
"#{graphql_resource_directory(resource)}/connection.rb",
|
124
|
+
<<~STRING
|
125
|
+
#{resource_class(resource)}::Connection = #{resource.pluralize.camelize}::Type.define_connection do
|
126
|
+
name '#{resource.camelize}Connection'
|
127
|
+
|
128
|
+
field :total_count, types.Int do
|
129
|
+
resolve ->(obj, _, _) { obj.nodes.count }
|
130
|
+
end
|
131
|
+
end
|
132
|
+
STRING
|
133
|
+
)
|
134
|
+
end
|
135
|
+
|
113
136
|
def generate_graphql_input_type(resource)
|
114
137
|
system("mkdir -p #{@mutations_directory}")
|
115
138
|
File.write(
|
@@ -132,7 +155,7 @@ class GraphqlResourceGenerator < Rails::Generators::NamedBase
|
|
132
155
|
<<~STRING
|
133
156
|
#{resource_class(resource)}::Type = GraphQL::ObjectType.define do
|
134
157
|
name '#{resource_class(resource).singularize}'
|
135
|
-
field :id,
|
158
|
+
field :id, !#{@id_type}
|
136
159
|
field :created_at, types.String
|
137
160
|
field :updated_at, types.String
|
138
161
|
#{map_types(input_type: false)}
|
@@ -148,14 +171,16 @@ class GraphqlResourceGenerator < Rails::Generators::NamedBase
|
|
148
171
|
def add_has_many_fields_to_type(field, resource)
|
149
172
|
file_name = "app/graphql/#{field.pluralize}/type.rb"
|
150
173
|
if File.read(file_name).include?("field :#{resource.singularize}_ids") ||
|
151
|
-
File.read(file_name).include?("field :#{resource.pluralize}")
|
174
|
+
File.read(file_name).include?("field :#{resource.pluralize}") ||
|
175
|
+
File.read(file_name).include?("connection :#{resource.pluralize}_connection")
|
152
176
|
return
|
153
177
|
end
|
154
178
|
write_at(
|
155
179
|
file_name, 4,
|
156
180
|
<<-STRING
|
157
|
-
field :#{resource.singularize}_ids,
|
158
|
-
field :#{resource.pluralize},
|
181
|
+
field :#{resource.singularize}_ids, types[#{@id_type}]
|
182
|
+
field :#{resource.pluralize}, types[#{resource.pluralize.camelize}::Type]
|
183
|
+
connection :#{resource.pluralize}_connection, #{resource.pluralize.camelize}::Connection
|
159
184
|
STRING
|
160
185
|
)
|
161
186
|
|
@@ -167,7 +192,7 @@ class GraphqlResourceGenerator < Rails::Generators::NamedBase
|
|
167
192
|
write_at(
|
168
193
|
input_type_file_name, 4,
|
169
194
|
<<-STRING
|
170
|
-
argument :#{resource.singularize}_ids,
|
195
|
+
argument :#{resource.singularize}_ids, types[#{@id_type}]
|
171
196
|
STRING
|
172
197
|
)
|
173
198
|
|
@@ -179,11 +204,12 @@ class GraphqlResourceGenerator < Rails::Generators::NamedBase
|
|
179
204
|
File.read(file_name).include?("field :#{field.singularize}")
|
180
205
|
return
|
181
206
|
end
|
207
|
+
|
182
208
|
write_at(
|
183
209
|
file_name, 4,
|
184
210
|
<<-STRING
|
185
211
|
field :#{field.singularize}_id, #{@id_type}
|
186
|
-
field :#{field.singularize},
|
212
|
+
field :#{field.singularize}, #{field.pluralize.camelize}::Type
|
187
213
|
STRING
|
188
214
|
)
|
189
215
|
input_type_file_name = "app/graphql/#{resource.pluralize}/mutations/input_type.rb"
|
@@ -191,6 +217,7 @@ class GraphqlResourceGenerator < Rails::Generators::NamedBase
|
|
191
217
|
File.read(input_type_file_name).include?("argument :#{field.singularize}")
|
192
218
|
return
|
193
219
|
end
|
220
|
+
|
194
221
|
write_at(
|
195
222
|
input_type_file_name, 4,
|
196
223
|
<<-STRING
|
@@ -275,7 +302,7 @@ t.#{@id_db_type} :#{resource.underscore.singularize}_id
|
|
275
302
|
res = "#{input_type ? 'argument' : 'field'} :#{field_name}, #{field_type}"
|
276
303
|
if !input_type && field_name.ends_with?('_id') && @belongs_to_fields.key?(field_name)
|
277
304
|
res += "\n field :#{field_name.gsub('_id', '')}, " \
|
278
|
-
"
|
305
|
+
"#{field_name.gsub('_id', '').pluralize.camelize}::Type"
|
279
306
|
end
|
280
307
|
res
|
281
308
|
end&.join("\n ")
|
@@ -1,10 +1,13 @@
|
|
1
1
|
require 'deep_pluck'
|
2
|
+
require 'rkelly'
|
2
3
|
|
3
4
|
module Graphql
|
4
5
|
class HydrateQuery
|
5
6
|
|
6
|
-
def initialize(model, context, check_visibility: true, id: nil, user: nil)
|
7
|
-
@
|
7
|
+
def initialize(model, context, order_by: nil, filter: nil, check_visibility: true, id: nil, user: nil)
|
8
|
+
@context = context
|
9
|
+
@filter = filter
|
10
|
+
@order_by = order_by
|
8
11
|
@model = model
|
9
12
|
@models = [model_name.singularize.camelize]
|
10
13
|
@check_visibility = check_visibility
|
@@ -13,12 +16,19 @@ module Graphql
|
|
13
16
|
end
|
14
17
|
|
15
18
|
def run
|
19
|
+
@model = @model.where(transform_filter(@filter)) if @filter
|
20
|
+
@model = @model.order(@order_by) if @order_by
|
16
21
|
@model = @model.where(id: @id) if @id
|
17
|
-
plucked = @model.deep_pluck(*hash_to_array_of_hashes(
|
22
|
+
plucked = @model.deep_pluck(*hash_to_array_of_hashes(parse_fields(@context&.irep_node), @model))
|
18
23
|
result = plucked_attr_to_structs(plucked, model_name.singularize.camelize.constantize)&.compact
|
19
24
|
@id ? result.first : result
|
20
25
|
end
|
21
26
|
|
27
|
+
def transform_filter(filter)
|
28
|
+
parsed_filter = RKelly::Parser.new.parse(filter).to_ecma
|
29
|
+
parsed_filter.gsub('||', 'OR').gsub('&&', 'AND').gsub('===', '=').gsub('==', '=').delete(';')
|
30
|
+
end
|
31
|
+
|
22
32
|
def plucked_attr_to_structs(arr, parent_model)
|
23
33
|
arr.map { |e| hash_to_struct(e, parent_model) }
|
24
34
|
end
|
@@ -49,7 +59,7 @@ module Graphql
|
|
49
59
|
end
|
50
60
|
|
51
61
|
def hash_to_array_of_hashes(hash, parent_class)
|
52
|
-
return if parent_class.nil?
|
62
|
+
return if parent_class.nil? || hash.nil?
|
53
63
|
|
54
64
|
hash['id'] = nil if hash['id'].blank?
|
55
65
|
fetch_ids_from_relation(hash)
|
@@ -87,14 +97,21 @@ module Graphql
|
|
87
97
|
child_class_name = child.to_s.singularize.camelize
|
88
98
|
parent_class_name = parent.to_s.singularize.camelize
|
89
99
|
return child_class_name.constantize if activerecord_model?(child_class_name)
|
100
|
+
|
90
101
|
return unless activerecord_model?(parent_class_name)
|
91
102
|
|
92
103
|
parent_class_name.constantize.reflections[child.to_s.underscore]&.klass
|
93
104
|
end
|
94
105
|
|
95
|
-
def
|
106
|
+
def parse_fields(irep_node)
|
107
|
+
fields = irep_node&.scoped_children&.values&.first
|
108
|
+
if fields.key?('edges')
|
109
|
+
fields = fields['edges'].scoped_children.values.first['node']&.scoped_children&.values&.first
|
110
|
+
end
|
111
|
+
return if fields.blank?
|
112
|
+
|
96
113
|
fields.each_with_object({}) do |(k, v), h|
|
97
|
-
h[k] = v.scoped_children == {} ? nil :
|
114
|
+
h[k] = v.scoped_children == {} ? nil : parse_fields(v)
|
98
115
|
end
|
99
116
|
end
|
100
117
|
|
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.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- poilon
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-12-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: graphql
|
@@ -64,6 +64,20 @@ dependencies:
|
|
64
64
|
- - ">="
|
65
65
|
- !ruby/object:Gem::Version
|
66
66
|
version: 5.2.0
|
67
|
+
- !ruby/object:Gem::Dependency
|
68
|
+
name: rkelly-remix
|
69
|
+
requirement: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - "~>"
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: '0'
|
74
|
+
type: :runtime
|
75
|
+
prerelease: false
|
76
|
+
version_requirements: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - "~>"
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: '0'
|
67
81
|
description: This gem purpose is to make graphql easier to use in ruby. Mainly developed
|
68
82
|
for from-scratch app
|
69
83
|
email:
|