graphql_model_mapper 0.0.6 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +273 -272
- data/lib/graphql_model_mapper.rb +22 -10
- data/lib/graphql_model_mapper/custom_type.rb +4 -0
- data/lib/graphql_model_mapper/mapper_type.rb +195 -187
- data/lib/graphql_model_mapper/mutation.rb +78 -35
- data/lib/graphql_model_mapper/query.rb +126 -22
- data/lib/graphql_model_mapper/resolve.rb +256 -210
- data/lib/graphql_model_mapper/schema.rb +98 -20
- data/lib/graphql_model_mapper/utility.rb +20 -2
- data/lib/graphql_model_mapper/version.rb +1 -1
- metadata +3 -2
@@ -4,8 +4,8 @@ module GraphqlModelMapper
|
|
4
4
|
resolver: nil)
|
5
5
|
|
6
6
|
|
7
|
-
input_type = GraphqlModelMapper::MapperType.get_ar_object_with_params(name,
|
8
|
-
output_type = GraphqlModelMapper::MapperType.get_ar_object_with_params(name,
|
7
|
+
input_type = GraphqlModelMapper::MapperType.get_ar_object_with_params(name, type_sub_key: :input_type)
|
8
|
+
output_type = GraphqlModelMapper::MapperType.get_ar_object_with_params(name, type_sub_key: :output_type)
|
9
9
|
|
10
10
|
self.get_mutation(name, description, "Update", resolver, input_type, output_type, name.downcase, "item")
|
11
11
|
end
|
@@ -15,21 +15,22 @@ module GraphqlModelMapper
|
|
15
15
|
arguments: [],
|
16
16
|
scope_methods: [])
|
17
17
|
|
18
|
-
input_type = GraphqlModelMapper::MapperType.get_ar_object_with_params(name,
|
19
|
-
output_type = GraphqlModelMapper::MapperType.get_ar_object_with_params(name,
|
18
|
+
input_type = GraphqlModelMapper::MapperType.get_ar_object_with_params(name, type_sub_key: :input_type)
|
19
|
+
output_type = GraphqlModelMapper::MapperType.get_ar_object_with_params(name, type_sub_key: :output_type).to_list_type
|
20
20
|
self.get_delete_mutation(name, description, "Delete", resolver, arguments, scope_methods, input_type, output_type)
|
21
21
|
end
|
22
22
|
|
23
23
|
def self.graphql_create(name: "", description:"",
|
24
24
|
resolver: nil)
|
25
25
|
|
26
|
-
input_type = GraphqlModelMapper::MapperType.get_ar_object_with_params(name,
|
27
|
-
output_type = GraphqlModelMapper::MapperType.get_ar_object_with_params(name,
|
26
|
+
input_type = GraphqlModelMapper::MapperType.get_ar_object_with_params(name, type_sub_key: :input_type)
|
27
|
+
output_type = GraphqlModelMapper::MapperType.get_ar_object_with_params(name, type_sub_key: :output_type)
|
28
28
|
|
29
29
|
self.get_mutation(name, description, "Create", resolver, input_type, output_type, name.downcase, "item")
|
30
30
|
end
|
31
31
|
|
32
32
|
def self.get_mutation(name, description, operation_name, resolver, input_type, output_type, input_name, output_name)
|
33
|
+
model = name.classify.constantize
|
33
34
|
mutation_type_name = GraphqlModelMapper.get_type_case("#{GraphqlModelMapper.get_type_name(name)}#{operation_name}")
|
34
35
|
return GraphqlModelMapper.get_constant(mutation_type_name) if GraphqlModelMapper.defined_constant?(mutation_type_name)
|
35
36
|
mutation_type = GraphQL::Relay::Mutation.define do
|
@@ -38,7 +39,7 @@ module GraphqlModelMapper
|
|
38
39
|
input_field input_name.to_sym, -> {input_type}
|
39
40
|
return_field output_name.to_sym, -> {output_type}
|
40
41
|
|
41
|
-
resolve resolver
|
42
|
+
resolve GraphqlModelMapper::Mutation.get_resolver(resolver, model, operation_name.downcase.to_sym)
|
42
43
|
end
|
43
44
|
|
44
45
|
GraphqlModelMapper.set_constant(mutation_type_name, mutation_type.field)
|
@@ -50,33 +51,50 @@ module GraphqlModelMapper
|
|
50
51
|
return GraphqlModelMapper.get_constant(query_type_name) if GraphqlModelMapper.defined_constant?(query_type_name)
|
51
52
|
|
52
53
|
model = name.classify.constantize
|
53
|
-
|
54
|
-
|
55
|
-
select_input_type_name = GraphqlModelMapper.get_type_case("#{GraphqlModelMapper.get_type_name(name)}SelectInput")
|
54
|
+
default_arguments = arguments ? (arguments.length > 0 ? arguments : self.get_default_select_arguments(model, scope_methods)) : []
|
55
|
+
|
56
|
+
select_input_type_name = GraphqlModelMapper.get_type_case("#{GraphqlModelMapper.get_type_name(name)}SelectInput")
|
56
57
|
if GraphqlModelMapper.defined_constant?(select_input_type_name)
|
57
|
-
|
58
|
+
query_input_object_type = GraphqlModelMapper.get_constant(select_input_type_name)
|
58
59
|
else
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
60
|
+
query_input_object_type = GraphQL::InputObjectType.define do
|
61
|
+
name select_input_type_name
|
62
|
+
default_arguments.each do |k|
|
63
|
+
argument k[:name].to_sym, k[:type], k[:description], default_value: k[:default] do
|
64
|
+
if k[:authorization] && GraphqlModelMapper.use_authorize
|
65
|
+
authorized ->(ctx, model_name, access_type) { GraphqlModelMapper.authorized?(ctx, model_name, access_type.to_sym) }
|
66
|
+
model_name name
|
67
|
+
access_type k[:authorization]
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
GraphqlModelMapper.set_constant(select_input_type_name, query_input_object_type)
|
66
73
|
end
|
67
74
|
|
75
|
+
total_result_type_name = GraphqlModelMapper.get_type_case("TotalResult")
|
76
|
+
if GraphqlModelMapper.defined_constant?(total_result_type_name)
|
77
|
+
total_result_type = GraphqlModelMapper.get_constant(total_result_type_name)
|
78
|
+
else
|
79
|
+
total_result_type = GraphQL::InterfaceType.define do
|
80
|
+
name total_result_type_name
|
81
|
+
field :total, -> {GraphQL::INT_TYPE} do
|
82
|
+
resolve -> (obj, args, ctx) {
|
83
|
+
obj.items.length
|
84
|
+
}
|
85
|
+
end
|
86
|
+
end
|
87
|
+
GraphqlModelMapper.set_constant(total_result_type_name, total_result_type)
|
88
|
+
end
|
89
|
+
|
68
90
|
|
69
91
|
ret_type = GraphQL::Relay::Mutation.define do
|
70
92
|
name query_type_name
|
71
|
-
#return_field :item, output_object_type
|
72
93
|
return_field :items, output_type
|
73
|
-
|
74
|
-
|
75
|
-
#description description
|
76
|
-
#input_field "input".to_sym, -> {input_object_type}
|
94
|
+
return_interfaces [total_result_type]
|
77
95
|
input_field :select, -> {!query_input_object_type}
|
78
|
-
|
79
|
-
resolve resolver
|
96
|
+
|
97
|
+
resolve GraphqlModelMapper::Mutation.get_resolver(resolver, model, :delete)
|
80
98
|
end
|
81
99
|
GraphqlModelMapper.set_constant(query_type_name, ret_type.field)
|
82
100
|
GraphqlModelMapper.get_constant(query_type_name)
|
@@ -84,19 +102,25 @@ module GraphqlModelMapper
|
|
84
102
|
|
85
103
|
def self.get_default_select_arguments(model, scope_methods)
|
86
104
|
default_arguments = [
|
87
|
-
{:name=>:
|
88
|
-
{:name=>:
|
89
|
-
{:name=>:ids, :type=>GraphQL::INT_TYPE.to_list_type, :default=>nil},
|
90
|
-
{:name=>:limit, :type=>GraphQL::INT_TYPE, :default=>50},
|
91
|
-
{:name=>:offset, :type=>GraphQL::INT_TYPE, :default=>nil},
|
92
|
-
{:name=>:order, :type=>GraphQL::STRING_TYPE, :default=>nil},
|
93
|
-
{:name=>:where, :type=>GraphQL::STRING_TYPE.to_list_type, :default=>nil}
|
105
|
+
{:name=>:id, :type=>GraphQL::ID_TYPE, :default=>nil},
|
106
|
+
{:name=>:ids, :type=>GraphQL::ID_TYPE.to_list_type, :default=>nil},
|
94
107
|
]
|
108
|
+
|
109
|
+
default_arguments = default_arguments + [
|
110
|
+
{:name=>:item_id, :type=>GraphQL::INT_TYPE, :default=>nil},
|
111
|
+
{:name=>:item_ids, :type=>GraphQL::INT_TYPE.to_list_type, :default=>nil}
|
112
|
+
] if GraphqlModelMapper::MapperType.get_type_params(model.name, type_sub_key: :input_type)[:primary_keys]
|
95
113
|
|
114
|
+
default_arguments = default_arguments + [
|
115
|
+
{:name=>:explain, :type=>GraphQL::BOOLEAN_TYPE, :default=>nil, :authorization=>:manage},
|
116
|
+
{:name=>:order, :type=>GraphQL::STRING_TYPE, :default=>nil, :authorization=>:manage},
|
117
|
+
{:name=>:where, :type=>GraphQL::STRING_TYPE.to_list_type, :default=>nil, :authorization=>:manage }
|
118
|
+
]
|
119
|
+
|
96
120
|
scope_methods = scope_methods.map(&:to_sym)
|
97
121
|
#.select{|m| model.method(m.to_sym).arity == 0}
|
98
122
|
if (model.public_methods - model.instance_methods - Object.methods - ActiveRecord::Base.methods).include?(:with_deleted)
|
99
|
-
default_arguments << {:name=>:with_deleted, :type=>GraphQL::BOOLEAN_TYPE, :default=>false}
|
123
|
+
default_arguments << {:name=>:with_deleted, :type=>GraphQL::BOOLEAN_TYPE, :default=>false, :authorization=>:manage}
|
100
124
|
end
|
101
125
|
allowed_scope_methods = []
|
102
126
|
if scope_methods.count > 0
|
@@ -116,10 +140,29 @@ module GraphqlModelMapper
|
|
116
140
|
end
|
117
141
|
GraphqlModelMapper.set_constant typename, enum_type
|
118
142
|
end
|
119
|
-
default_arguments << {:name=>:scope, :type=>GraphqlModelMapper.get_constant(typename), :default=>nil}
|
143
|
+
default_arguments << {:name=>:scope, :type=>GraphqlModelMapper.get_constant(typename), :default=>nil, :authorization=>:manage}
|
120
144
|
end
|
121
145
|
end
|
122
146
|
default_arguments
|
123
|
-
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def self.get_resolver(resolver, model, operation)
|
150
|
+
if model.public_methods.include?("graphql_#{operation}_resolver".to_sym)
|
151
|
+
case operation
|
152
|
+
when :create
|
153
|
+
resolver = -> (obj, args, ctx) {model.graphql_create_resolver(obj,args,ctx) } if model.public_methods.include?(:graphql_create_resolver)
|
154
|
+
when :delete
|
155
|
+
resolver = -> (obj, args, ctx) {model.graphql_delete_resolver(obj,args,ctx) } if model.public_methods.include?(:graphql_delete_resolver)
|
156
|
+
when :update
|
157
|
+
resolver = -> (obj, args, ctx) {model.graphql_update_resolver(obj,args,ctx) } if model.public_methods.include?(:graphql_update_resolver)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
if GraphqlModelMapper.mutation_resolve_wrapper && GraphqlModelMapper.mutation_resolve_wrapper < GraphqlModelMapper::Resolve::ResolveWrapper
|
161
|
+
return GraphqlModelMapper.mutation_resolve_wrapper.new(resolver)
|
162
|
+
else
|
163
|
+
return GraphqlModelMapper::Resolve::ResolveWrapper.new(resolver)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
124
167
|
end
|
125
168
|
end
|
@@ -7,26 +7,39 @@ module GraphqlModelMapper
|
|
7
7
|
scope_methods: []
|
8
8
|
)
|
9
9
|
|
10
|
-
input_type = GraphqlModelMapper::MapperType.get_ar_object_with_params(name,
|
11
|
-
output_type = GraphqlModelMapper::MapperType.get_ar_object_with_params(name,
|
10
|
+
input_type = GraphqlModelMapper::MapperType.get_ar_object_with_params(name, type_sub_key: :input_type)
|
11
|
+
output_type = GraphqlModelMapper::MapperType.get_ar_object_with_params(name, type_sub_key: :output_type)
|
12
12
|
self.get_query(name, description, "Query", resolver, arguments, scope_methods, input_type, output_type)
|
13
13
|
end
|
14
14
|
|
15
15
|
def self.get_default_select_arguments(model, scope_methods)
|
16
16
|
default_arguments = [
|
17
|
-
{:name=>:
|
18
|
-
{:name=>:
|
19
|
-
{:name=>:ids, :type=>GraphQL::INT_TYPE.to_list_type, :default=>nil},
|
20
|
-
{:name=>:limit, :type=>GraphQL::INT_TYPE, :default=>50},
|
21
|
-
{:name=>:offset, :type=>GraphQL::INT_TYPE, :default=>nil},
|
22
|
-
{:name=>:order, :type=>GraphQL::STRING_TYPE, :default=>nil},
|
23
|
-
{:name=>:where, :type=>GraphQL::STRING_TYPE.to_list_type, :default=>nil}
|
17
|
+
{:name=>:id, :type=>GraphQL::ID_TYPE, :default=>nil},
|
18
|
+
{:name=>:ids, :type=>GraphQL::ID_TYPE.to_list_type, :default=>nil},
|
24
19
|
]
|
25
|
-
|
20
|
+
|
21
|
+
default_arguments = default_arguments + [
|
22
|
+
{:name=>:item_id, :type=>GraphQL::INT_TYPE, :default=>nil},
|
23
|
+
{:name=>:item_ids, :type=>GraphQL::INT_TYPE.to_list_type, :default=>nil}
|
24
|
+
] if GraphqlModelMapper::MapperType.get_type_params(model.name, type_sub_key: :input_type)[:primary_keys]
|
25
|
+
|
26
|
+
|
27
|
+
default_arguments = default_arguments + [
|
28
|
+
{:name=>:explain, :type=>GraphQL::BOOLEAN_TYPE, :default=>nil, :authorization=>:manage},
|
29
|
+
{:name=>:order, :type=>GraphQL::STRING_TYPE, :default=>nil, :authorization=>:manage},
|
30
|
+
{:name=>:where, :type=>GraphQL::STRING_TYPE.to_list_type, :default=>nil, :authorization=>:manage }
|
31
|
+
]
|
32
|
+
=begin
|
33
|
+
default_arguments = default_arguments + [
|
34
|
+
# {:name=>:limit, :type=>GraphQL::INT_TYPE, :default=>GraphqlModelMapper.max_page_size},
|
35
|
+
{:name=>:first, :type=>GraphQL::INT_TYPE, :default=>nil},
|
36
|
+
{:name=>:last, :type=>GraphQL::INT_TYPE, :default=>nil},
|
37
|
+
{:name=>:offset, :type=>GraphQL::INT_TYPE, :default=>nil}] if ![:deep, :shallow].include?(GraphqlModelMapper.nesting_strategy)
|
38
|
+
=end
|
26
39
|
scope_methods = scope_methods.map(&:to_sym)
|
27
40
|
#.select{|m| model.method(m.to_sym).arity == 0}
|
28
41
|
if (model.public_methods - model.instance_methods - Object.methods - ActiveRecord::Base.methods).include?(:with_deleted)
|
29
|
-
default_arguments << {:name=>:with_deleted, :type=>GraphQL::BOOLEAN_TYPE, :default=>false}
|
42
|
+
default_arguments << {:name=>:with_deleted, :type=>GraphQL::BOOLEAN_TYPE, :default=>false, :authorization=>:manage}
|
30
43
|
end
|
31
44
|
allowed_scope_methods = []
|
32
45
|
if scope_methods.count > 0
|
@@ -46,7 +59,7 @@ module GraphqlModelMapper
|
|
46
59
|
end
|
47
60
|
GraphqlModelMapper.set_constant typename, enum_type
|
48
61
|
end
|
49
|
-
default_arguments << {:name=>:scope, :type=>GraphqlModelMapper.get_constant(typename), :default=>nil}
|
62
|
+
default_arguments << {:name=>:scope, :type=>GraphqlModelMapper.get_constant(typename), :default=>nil, :authorization=>:manage}
|
50
63
|
end
|
51
64
|
end
|
52
65
|
default_arguments
|
@@ -59,8 +72,12 @@ module GraphqlModelMapper
|
|
59
72
|
|
60
73
|
model = name.classify.constantize
|
61
74
|
|
62
|
-
default_arguments = self.get_default_select_arguments(model, scope_methods)
|
75
|
+
default_arguments = arguments ? (arguments.length > 0 ? arguments : self.get_default_select_arguments(model, scope_methods)) : []
|
76
|
+
|
77
|
+
|
78
|
+
=begin
|
63
79
|
select_input_type_name = "#{GraphqlModelMapper.get_type_case(GraphqlModelMapper.get_type_name(name))}QueryInput"
|
80
|
+
|
64
81
|
if GraphqlModelMapper.defined_constant?(select_input_type_name)
|
65
82
|
select_input_type = GraphqlModelMapper.get_constant(select_input_type_name)
|
66
83
|
else
|
@@ -72,7 +89,43 @@ module GraphqlModelMapper
|
|
72
89
|
end
|
73
90
|
GraphqlModelMapper.set_constant(select_input_type_name, select_input_type)
|
74
91
|
end
|
75
|
-
|
92
|
+
=end
|
93
|
+
=begin
|
94
|
+
page_info_type_name = "FlatPageInfo"
|
95
|
+
|
96
|
+
if GraphqlModelMapper.defined_constant?(page_info_type_name)
|
97
|
+
page_info_type = GraphqlModelMapper.get_constant(page_info_type_name)
|
98
|
+
else
|
99
|
+
page_info_type = GraphQL::ObjectType.define do
|
100
|
+
name("FlatPageInfo")
|
101
|
+
description("Information about pagination in a query.")
|
102
|
+
field :hasNextPage, !types.Boolean, "When paginating forwards, are there more items?", property: :has_next_page
|
103
|
+
field :hasPreviousPage, !types.Boolean, "When paginating backwards, are there more items?", property: :has_previous_page
|
104
|
+
field :startCursor, types.String, "When paginating backwards, the cursor to continue.", property: :start_cursor
|
105
|
+
field :endCursor, types.String, "When paginating forwards, the cursor to continue.", property: :end_cursor
|
106
|
+
end
|
107
|
+
GraphqlModelMapper.set_constant(page_info_type_name, page_info_type)
|
108
|
+
end
|
109
|
+
=end
|
110
|
+
|
111
|
+
if [:deep, :shallow].include?(GraphqlModelMapper.nesting_strategy)
|
112
|
+
connection_type_name = "#{GraphqlModelMapper.get_type_case(GraphqlModelMapper.get_type_name(name))}ConnectionType"
|
113
|
+
if GraphqlModelMapper.defined_constant?(connection_type_name)
|
114
|
+
connection_type = GraphqlModelMapper.get_constant(connection_type_name)
|
115
|
+
else
|
116
|
+
connection_type = output_type.define_connection do
|
117
|
+
name connection_type_name
|
118
|
+
field :total, hash_key: :total do
|
119
|
+
type types.Int
|
120
|
+
resolve ->(obj, args, ctx) {
|
121
|
+
obj.nodes.count
|
122
|
+
}
|
123
|
+
end
|
124
|
+
end
|
125
|
+
GraphqlModelMapper.set_constant(connection_type_name, connection_type)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
76
129
|
total_output_type_name = "#{GraphqlModelMapper.get_type_name(name)}QueryPayload"
|
77
130
|
if GraphqlModelMapper.defined_constant?(total_output_type_name)
|
78
131
|
total_output_type = GraphqlModelMapper.get_constant(total_output_type_name)
|
@@ -80,11 +133,46 @@ module GraphqlModelMapper
|
|
80
133
|
total_output_type = GraphQL::ObjectType.define do
|
81
134
|
name total_output_type_name
|
82
135
|
if [:deep, :shallow].include?(GraphqlModelMapper.nesting_strategy)
|
83
|
-
connection :items, -> {
|
136
|
+
connection :items, -> {connection_type}, max_page_size: GraphqlModelMapper.max_page_size do
|
137
|
+
resolve -> (obj, args, ctx) {
|
138
|
+
limit = GraphqlModelMapper.max_page_size
|
139
|
+
raise GraphQL::ExecutionError.new("you have exceeded the maximum requested page size #{limit}") if args[:first].to_i > limit || args[:last].to_i > limit
|
140
|
+
|
141
|
+
obj
|
142
|
+
}
|
143
|
+
end
|
84
144
|
else
|
85
|
-
field :items, -> {output_type.to_list_type}, hash_key: :items
|
145
|
+
field :items, -> {output_type.to_list_type}, hash_key: :items do
|
146
|
+
argument :per_page, GraphQL::INT_TYPE
|
147
|
+
argument :page, GraphQL::INT_TYPE
|
148
|
+
resolve->(obj, args, ctx){
|
149
|
+
first_rec = nil
|
150
|
+
last_rec = nil
|
151
|
+
limit = GraphqlModelMapper.max_page_size.to_i
|
152
|
+
|
153
|
+
if args[:per_page]
|
154
|
+
per_page = args[:per_page].to_i
|
155
|
+
raise GraphQL::ExecutionError.new("per_page must be greater than 0") if per_page < 1
|
156
|
+
raise GraphQL::ExecutionError.new("you have exceeded the maximum requested page size #{limit}") if per_page > limit
|
157
|
+
limit = [per_page,limit].min
|
158
|
+
end
|
159
|
+
if args[:page]
|
160
|
+
page = args[:page].to_i
|
161
|
+
raise GraphQL::ExecutionError.new("page must be greater than 0") if page < 1
|
162
|
+
max_page = (obj.count/per_page).floor + 1
|
163
|
+
raise GraphQL::ExecutionError.new("you requested page #{page} which is greater than the max number of pages #{max_page}") if page > max_page
|
164
|
+
obj = obj.offset((page-1)*limit)
|
165
|
+
end
|
166
|
+
obj = obj.limit(limit)
|
167
|
+
obj
|
168
|
+
}
|
169
|
+
end
|
170
|
+
field :total, -> {GraphQL::INT_TYPE}, hash_key: :total do
|
171
|
+
resolve->(obj,args, ctx){
|
172
|
+
obj.limit(nil).count
|
173
|
+
}
|
174
|
+
end
|
86
175
|
end
|
87
|
-
field :total, -> {GraphQL::INT_TYPE}, hash_key: :total
|
88
176
|
end
|
89
177
|
GraphqlModelMapper.set_constant(total_output_type_name, total_output_type)
|
90
178
|
end
|
@@ -93,15 +181,31 @@ module GraphqlModelMapper
|
|
93
181
|
ret_type = GraphQL::Field.define do
|
94
182
|
name query_type_name
|
95
183
|
type total_output_type
|
96
|
-
#argument :select, -> {!select_input_type}
|
97
184
|
default_arguments.each do |k|
|
98
|
-
argument k[:name].to_sym, k[:type], k[:description], default_value: k[:default]
|
185
|
+
argument k[:name].to_sym, k[:type], k[:description], default_value: k[:default] do
|
186
|
+
if k[:authorization] && GraphqlModelMapper.use_authorize
|
187
|
+
authorized ->(ctx, model_name, access_type) { GraphqlModelMapper.authorized?(ctx, model_name, access_type.to_sym) }
|
188
|
+
model_name name
|
189
|
+
access_type k[:authorization]
|
190
|
+
end
|
191
|
+
end
|
99
192
|
end
|
100
|
-
|
101
|
-
|
102
|
-
end
|
193
|
+
resolve GraphqlModelMapper::Query.get_resolver(resolver, model)
|
194
|
+
end
|
103
195
|
GraphqlModelMapper.set_constant(query_type_name, ret_type)
|
104
196
|
GraphqlModelMapper.get_constant(query_type_name)
|
105
197
|
end
|
198
|
+
|
199
|
+
|
200
|
+
def self.get_resolver(resolver, model)
|
201
|
+
|
202
|
+
resolver = -> (obj,args,ctx){ model.graphql_query_resolver(obj, args, ctx) } if model.public_methods.include?(:graphql_query_resolver)
|
203
|
+
|
204
|
+
if GraphqlModelMapper.query_resolve_wrapper && GraphqlModelMapper.query_resolve_wrapper < GraphqlModelMapper::Resolve::ResolveWrapper
|
205
|
+
return GraphqlModelMapper.query_resolve_wrapper.new(resolver)
|
206
|
+
else
|
207
|
+
return GraphqlModelMapper::Resolve::ResolveWrapper.new(resolver)
|
208
|
+
end
|
209
|
+
end
|
106
210
|
end
|
107
211
|
end
|
@@ -1,239 +1,285 @@
|
|
1
1
|
module GraphqlModelMapper
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
implied_includes = self.get_implied_includes(name.classify.constantize, ctx.ast_node)
|
2
|
+
module Resolve
|
3
|
+
def self.query_resolver(obj, args, ctx, name)
|
4
|
+
#binding.pry
|
5
|
+
obj_context = obj || name.classify.constantize
|
6
|
+
select_args = args[:select] || args
|
7
|
+
|
8
|
+
if !GraphqlModelMapper.authorized?(ctx, obj_context.name, :query)
|
9
|
+
raise GraphQL::ExecutionError.new("error: unauthorized access: #{:query} '#{obj_context.class_name.classify}'")
|
10
|
+
end
|
11
|
+
classmethods = []
|
12
|
+
scope_allowed = false
|
13
|
+
with_deleted_allowed = false
|
14
|
+
if select_args[:scope]
|
15
|
+
classmethods = obj_context.methods - Object.methods
|
16
|
+
scope_allowed = classmethods.include?(select_args[:scope].to_sym)
|
17
|
+
raise GraphQL::ExecutionError.new("error: invalid scope '#{select_args[:scope]}' specified, '#{select_args[:scope]}' method does not exist on '#{obj_context.class_name.classify}'") unless scope_allowed
|
18
|
+
end
|
19
|
+
if select_args[:with_deleted]
|
20
|
+
classmethods = obj_context.methods - Object.methods
|
21
|
+
with_deleted_allowed = classmethods.include?(:with_deleted)
|
22
|
+
raise GraphQL::ExecutionError.new("error: invalid usage of 'with_deleted', 'with_deleted' method does not exist on '#{obj_context.class_name.classify}'") unless with_deleted_allowed
|
23
|
+
end
|
25
24
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
if select_args[:ids]
|
33
|
-
obj_context = obj_context.where(["#{obj_context.model_name.plural}.id in (?)", select_args[:ids]])
|
34
|
-
end
|
35
|
-
if select_args[:id]
|
36
|
-
obj_context = obj_context.where(["#{obj_context.model_name.plural}.id = ?", select_args[:id].to_i])
|
37
|
-
end
|
38
|
-
if select_args[:where]
|
39
|
-
obj_context = obj_context.where(select_args[:where])
|
40
|
-
end
|
41
|
-
if with_deleted_allowed
|
42
|
-
obj_context = obj_context.with_deleted
|
43
|
-
end
|
44
|
-
if scope_allowed
|
45
|
-
obj_context = obj_context.send(select_args[:scope].to_sym)
|
46
|
-
end
|
47
|
-
if !select_args[:limit].nil? && select_args[:limit].to_f > 0
|
48
|
-
obj_context = obj_context.limit(select_args[:limit])
|
49
|
-
end
|
50
|
-
if select_args[:offset]
|
51
|
-
obj_context = obj_context.offset(select_args[:offset])
|
52
|
-
end
|
53
|
-
if select_args[:order]
|
54
|
-
obj_context = obj_context.order(select_args[:order])
|
55
|
-
end
|
56
|
-
if select_args[:explain]
|
57
|
-
obj_context = obj_context.eager_load(implied_includes)
|
58
|
-
raise GraphQL::ExecutionError.new(obj_context.explain.split("\n").first.sub("EXPLAIN for: ", ""))
|
59
|
-
end
|
60
|
-
obj_context
|
25
|
+
implied_includes = self.get_implied_includes(obj_context.name.classify.constantize, ctx.ast_node)
|
26
|
+
if !implied_includes.empty?
|
27
|
+
obj_context = obj_context.includes(implied_includes)
|
28
|
+
if Rails.version.split(".").first.to_i > 3
|
29
|
+
obj_context = obj_context.references(implied_includes)
|
30
|
+
end
|
61
31
|
end
|
32
|
+
if select_args[:id]
|
62
33
|
|
63
|
-
|
64
|
-
|
65
|
-
|
34
|
+
type_name, item_id = GraphQL::Schema::UniqueWithinType.decode(select_args[:id])
|
35
|
+
raise GraphQL::ExecutionError.new("incorrect global id: unable to resolve type for id:'#{select_args[:id]}'") if type_name.nil?
|
36
|
+
model_name = GraphqlModelMapper.get_constant(type_name.upcase).metadata[:model_name].to_s.classify
|
37
|
+
raise GraphQL::ExecutionError.new("incorrect global id '#{select_args[:id]}': expected global id for '#{name}', received global id for '#{model_name}'") if model_name != name
|
38
|
+
obj_context = obj_context.where(["#{obj_context.model_name.plural}.id = ?", item_id.to_i])
|
66
39
|
end
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
if
|
73
|
-
|
74
|
-
|
75
|
-
begin
|
76
|
-
deleted_items = model.delete(ids)
|
77
|
-
rescue => e
|
78
|
-
raise e #GraphQL::ExecutionError.new("error: delete")
|
40
|
+
if select_args[:ids]
|
41
|
+
finder_array = []
|
42
|
+
errors = []
|
43
|
+
select_args[:ids].each do |id|
|
44
|
+
type_name, item_id = GraphQL::Schema::UniqueWithinType.decode(id)
|
45
|
+
if type_name.nil?
|
46
|
+
errors << "incorrect global id: unable to resolve type for id:'#{id}'"
|
47
|
+
next
|
79
48
|
end
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
49
|
+
model_name = GraphqlModelMapper.get_constant(type_name.upcase).metadata[:model_name].to_s.classify
|
50
|
+
if model_name != name
|
51
|
+
errors << "incorrect global id '#{id}': expected global id for '#{name}', received global id for '#{model_name}'"
|
52
|
+
next
|
84
53
|
end
|
54
|
+
finder_array << item_id.to_i
|
55
|
+
end
|
56
|
+
if errors.length > 0
|
57
|
+
raise GraphQL::ExecutionError.new(errors.join(";"))
|
58
|
+
end
|
59
|
+
obj_context = obj_context.where(["`#{obj_context.model_name.plural}`.id in (?)", finder_array])
|
60
|
+
end
|
61
|
+
if select_args[:item_ids]
|
62
|
+
obj_context = obj_context.where(["`#{obj_context.model_name.plural}`.id in (?)", select_args[:item_ids]])
|
63
|
+
end
|
64
|
+
if select_args[:item_id]
|
65
|
+
obj_context = obj_context.where(["`#{obj_context.model_name.plural}`.id = ?", select_args[:item_id].to_i])
|
66
|
+
end
|
67
|
+
if select_args[:where]
|
68
|
+
obj_context = obj_context.where(select_args[:where])
|
69
|
+
end
|
70
|
+
if with_deleted_allowed
|
71
|
+
obj_context = obj_context.with_deleted
|
72
|
+
end
|
73
|
+
if scope_allowed
|
74
|
+
obj_context = obj_context.send(select_args[:scope].to_sym)
|
85
75
|
end
|
76
|
+
if select_args[:order]
|
77
|
+
obj_context = obj_context.order(select_args[:order])
|
78
|
+
end
|
79
|
+
if select_args[:explain]
|
80
|
+
obj_context = obj_context.limit(1)
|
81
|
+
obj_context = obj_context.eager_load(implied_includes)
|
82
|
+
raise GraphQL::ExecutionError.new(obj_context.explain.split("\n").first.sub("EXPLAIN for: ", "").sub(" LIMIT 1", !select_args[:limit].nil? && select_args[:limit].to_f > 0 ? "LIMIT #{select_args[:limit]}" : ""))
|
83
|
+
end
|
84
|
+
#if select_args[:limit].nil?
|
85
|
+
# obj_context = obj_context.limit(100)
|
86
|
+
#end
|
87
|
+
obj_context = obj_context.where("1=1")
|
88
|
+
obj_context
|
89
|
+
end
|
86
90
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
91
|
+
def self.update_resolver(obj, inputs, ctx, name)
|
92
|
+
item = GraphqlModelMapper::Resolve.nested_update(ctx, name, inputs)
|
93
|
+
item
|
94
|
+
end
|
95
|
+
|
96
|
+
def self.delete_resolver(obj, inputs, ctx, model_name)
|
97
|
+
model = model_name.classify.constantize
|
98
|
+
items = self.query_resolver(obj, inputs, ctx, model_name)
|
99
|
+
ids = items.collect(&:id)
|
100
|
+
if !GraphqlModelMapper.authorized?(ctx, model_name, :update)
|
101
|
+
raise GraphQL::ExecutionError.new("error: unauthorized access: delete '#{model_name.classify}', transaction cancelled")
|
102
|
+
end
|
103
|
+
begin
|
104
|
+
deleted_items = model.delete(ids)
|
105
|
+
rescue => e
|
106
|
+
raise e #GraphQL::ExecutionError.new("error: delete")
|
107
|
+
end
|
108
|
+
if model.methods.include?(:with_deleted)
|
109
|
+
items.with_deleted
|
110
|
+
else
|
111
|
+
items
|
102
112
|
end
|
113
|
+
end
|
103
114
|
|
104
|
-
|
105
|
-
|
115
|
+
def self.create_resolver(obj, inputs, ctx, model_name)
|
116
|
+
if !GraphqlModelMapper.authorized?(ctx, model_name, :create)
|
117
|
+
raise GraphQL::ExecutionError.new("error: unauthorized access: create '#{model_name.classify}'")
|
106
118
|
end
|
107
|
-
|
108
|
-
|
109
|
-
|
119
|
+
model = model_name.classify.constantize
|
120
|
+
item = model.new(inputs[model_name.downcase].to_h)
|
121
|
+
begin
|
122
|
+
if !item.valid?
|
123
|
+
raise GraphQL::ExecutionError.new(item.errors.full_messages.join("; "))
|
124
|
+
else
|
125
|
+
raise GraphQL::ExecutionError.new("error: WIP, item not saved but is a valid '#{model_name.classify}'")
|
126
|
+
#item.save!
|
127
|
+
end
|
110
128
|
end
|
129
|
+
item
|
130
|
+
end
|
131
|
+
|
132
|
+
def self.using_relay_pagination?(selection)
|
133
|
+
selection.name == 'edges'
|
134
|
+
end
|
135
|
+
|
136
|
+
def self.using_is_items_collection?(selection)
|
137
|
+
selection.name == 'items'
|
138
|
+
end
|
139
|
+
|
140
|
+
def self.using_nodes_pagination?(selection)
|
141
|
+
selection.name == 'nodes'
|
142
|
+
end
|
143
|
+
|
144
|
+
def self.has_reflection_with_name?(class_name, selection_name)
|
145
|
+
class_name.reflect_on_all_associations.select{|m|m.name == selection_name.to_sym}.present?
|
146
|
+
end
|
147
|
+
|
148
|
+
def self.map_relay_pagination_depencies(class_name, selection, dependencies)
|
149
|
+
node_selection = selection.selections.find { |sel| sel.name == 'node' }
|
150
|
+
|
151
|
+
if node_selection.present?
|
152
|
+
get_implied_includes(class_name, node_selection, dependencies)
|
153
|
+
else
|
154
|
+
dependencies
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def self.get_implied_includes(class_name, ast_node, dependencies={})
|
159
|
+
ast_node.selections.each do |selection|
|
160
|
+
name = selection.name
|
111
161
|
|
112
|
-
|
113
|
-
selection
|
162
|
+
if using_relay_pagination?(selection)
|
163
|
+
map_relay_pagination_depencies(class_name, selection, dependencies)
|
164
|
+
next
|
114
165
|
end
|
115
166
|
|
116
|
-
|
117
|
-
class_name
|
167
|
+
if using_nodes_pagination?(selection)
|
168
|
+
get_implied_includes(class_name, selection, dependencies)
|
169
|
+
next
|
118
170
|
end
|
119
171
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
if node_selection.present?
|
124
|
-
get_implied_includes(class_name, node_selection, dependencies)
|
125
|
-
else
|
126
|
-
dependencies
|
127
|
-
end
|
172
|
+
if using_is_items_collection?(selection)
|
173
|
+
get_implied_includes(class_name, selection, dependencies)
|
174
|
+
next
|
128
175
|
end
|
129
176
|
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
177
|
+
if has_reflection_with_name?(class_name, name)
|
178
|
+
begin
|
179
|
+
current_class_name = selection.name.singularize.classify.constantize
|
180
|
+
dependencies[name] = get_implied_includes(current_class_name, selection)
|
181
|
+
rescue NameError
|
182
|
+
selection_name = class_name.reflections.with_indifferent_access[selection.name].class_name
|
183
|
+
begin
|
184
|
+
current_class_name = selection_name.singularize.classify.constantize
|
185
|
+
dependencies[selection.name.to_sym] = get_implied_includes(current_class_name, selection)
|
186
|
+
rescue
|
187
|
+
# this will occur if the relation is polymorphic, since polymorphic associations do not have a class_name
|
188
|
+
GraphqlModelMapper.logger.info "implied_includes: #{class_name} could not resolve a class for relation #{selection.name}"
|
142
189
|
end
|
190
|
+
next
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
dependencies
|
195
|
+
end
|
143
196
|
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
197
|
+
|
198
|
+
def self.nested_update(ctx, model_name, inputs, child_name=nil, child_id=nil, parent_name=nil, parent_id=nil, klass_name=nil)
|
199
|
+
model = model_name.classify.constantize
|
200
|
+
|
201
|
+
if !child_name.nil? && !child_id.nil? # has_many && has_one
|
202
|
+
inputs_root = inputs
|
203
|
+
#puts "inputs_root[:item_id] #{inputs_root[:item_id]} #{inputs_root}"
|
204
|
+
if model.public_methods.include?(:with_deleted)
|
205
|
+
item = model.with_deleted.where("id = ? and #{child_name.downcase}_id = ?", inputs_root[:item_id], child_id).first
|
206
|
+
else
|
207
|
+
item = model.where("id = ? and #{child_name.downcase}_id = ?", inputs_root[:item_id], child_id).first
|
208
|
+
end
|
209
|
+
raise GraphQL::ExecutionError.new("error: #{model.name} record not found for #{model.name}.id = #{inputs_root[:item_id]} and #{model.name}.#{child_name.downcase}_id = #{child_id}") if item.nil?
|
210
|
+
elsif !parent_name.nil? && !parent_id.nil? # belongs_to
|
211
|
+
inputs_root = inputs
|
212
|
+
#puts "parent_id #{parent_id} parent_name #{parent_name} #{model_name} model.with_deleted.find(#{parent_id}).send(#{parent_name}.to_sym).id} inputs_root[:item_id] #{inputs_root[:item_id]} #{inputs_root}"
|
213
|
+
if model.public_methods.include?(:with_deleted)
|
214
|
+
item = model.with_deleted.find(parent_id).public_send(parent_name.to_sym) if model.with_deleted.find(parent_id).public_send(parent_name.to_sym) && model.with_deleted.find(parent_id).public_send(parent_name.to_sym).id == inputs_root[:item_id]
|
215
|
+
else
|
216
|
+
item = model.find(parent_id).public_send(parent_name.to_sym) if model.find(parent_id).public_send(parent_name.to_sym) && model.with_deleted.find(parent_id).public_send(parent_name.to_sym).id == inputs_root[:item_id]
|
217
|
+
end
|
218
|
+
raise GraphQL::ExecutionError.new("error: #{model.name}.#{parent_name} record not found for #{model.name}.with_deleted.find(#{parent_id}).#{parent_name}_id = #{inputs_root[:item_id]}") if item.nil?
|
219
|
+
model_name = klass_name
|
220
|
+
model = klass_name.classify.constantize
|
221
|
+
else #root query always single record, need to offeset property for object_input_type
|
222
|
+
inputs_root = inputs[model_name.downcase]
|
223
|
+
#puts "inputs_root[:item_id] #{inputs_root[:item_id]} #{inputs_root}"
|
224
|
+
if model.public_methods.include?(:with_deleted)
|
225
|
+
item = model.with_deleted.find(inputs_root[:item_id])
|
226
|
+
else
|
227
|
+
item = model.find(inputs_root[:item_id])
|
228
|
+
end
|
229
|
+
raise GraphQL::ExecutionError.new("error: #{model.name} record not found for #{model.name}.id=#{inputs[model_name.downcase][:item_id]}") if item.nil?
|
230
|
+
end
|
231
|
+
if !GraphqlModelMapper.authorized?(ctx, model.name, :update)
|
232
|
+
raise GraphQL::ExecutionError.new("error: unauthorized access: #{:update} '#{model}', transaction cancelled")
|
233
|
+
end
|
234
|
+
|
235
|
+
item_associations = model.reflect_on_all_associations.select{|t| begin t.klass rescue next end}.select{|t| !t.options[:polymorphic]}
|
236
|
+
item_association_names = item_associations.map{|m| m.name.to_s}
|
237
|
+
input_association_names = item_association_names & inputs_root.to_h.keys
|
238
|
+
|
239
|
+
item.transaction do
|
240
|
+
#puts "***********item.update_attributes(#{inputs_root.to_h.except('id').except!(*item_association_names)})"
|
241
|
+
#puts "***********ctx[current_user.to_sym].is_admin?(#{ctx[:current_user].is_admin?})"
|
242
|
+
item.update_attributes(inputs_root.to_h.except('id').except('item_id').except!(*item_association_names))
|
243
|
+
input_association_names.each do |ia|
|
244
|
+
lclinput = inputs_root[ia]
|
245
|
+
ass = item_associations.select{|a| a.name.to_s == ia}.first
|
246
|
+
klass = ass.klass
|
247
|
+
is_collection = ass.collection?
|
248
|
+
belongs_to = ass.belongs_to?
|
249
|
+
#puts "#{ass.name} #{ass.collection?} #{ass.belongs_to?}"
|
250
|
+
#puts "#{ass.association_foreign_key} #{ass.association_primary_key} #{ass.active_record_primary_key}"
|
251
|
+
|
252
|
+
if is_collection
|
253
|
+
#puts "is_collection"
|
254
|
+
lclinput.each do |i|
|
255
|
+
#puts "#{klass.name} #{i.to_h} #{model_name.downcase} #{inputs_root[:item_id]}"
|
256
|
+
GraphqlModelMapper::Resolve.nested_update(ctx, klass.name, i, model_name.downcase, inputs_root[:item_id])
|
159
257
|
end
|
258
|
+
elsif !is_collection && belongs_to
|
259
|
+
#puts "belongs_to"
|
260
|
+
#puts "self.nested_update(#{ctx}, #{model.name}, #{lclinput.to_h}, nil, nil, #{ass.name}, #{inputs_root[:item_id]}, #{klass.name})"
|
261
|
+
GraphqlModelMapper::Resolve.nested_update(ctx, model.name, lclinput, nil, nil, ass.name, inputs_root[:item_id], klass.name)
|
262
|
+
elsif !is_collection && !belongs_to #has_one
|
263
|
+
#puts "has_one"
|
264
|
+
#puts "self.nested_update(#{ctx}, #{klass.name}, #{lclinput.to_h}, #{model_name.downcase}, #{inputs_root[:item_id]})"
|
265
|
+
GraphqlModelMapper::Resolve.nested_update(ctx, model.name, lclinput, nil, nil, ass.name, inputs_root[:item_id], klass.name)
|
160
266
|
end
|
161
|
-
dependencies
|
162
267
|
end
|
268
|
+
end
|
269
|
+
item
|
270
|
+
end
|
163
271
|
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
item = model.with_deleted.where("id = ? and #{child_name.downcase}_id = ?", inputs_root[:id], child_id).first
|
173
|
-
else
|
174
|
-
item = model.where("id = ? and #{child_name.downcase}_id = ?", inputs_root[:id], child_id).first
|
175
|
-
end
|
176
|
-
raise GraphQL::ExecutionError.new("error: #{model.name} record not found for #{model.name}.id = #{inputs_root[:id]} and #{model.name}.#{child_name.downcase}_id = #{child_id}") if item.nil?
|
177
|
-
elsif !parent_name.nil? && !parent_id.nil? # belongs_to
|
178
|
-
inputs_root = inputs
|
179
|
-
#puts "parent_id #{parent_id} parent_name #{parent_name} #{model_name} model.with_deleted.find(#{parent_id}).send(#{parent_name}.to_sym).id} inputs_root[:id] #{inputs_root[:id]} #{inputs_root}"
|
180
|
-
if model.public_methods.include?(:with_deleted)
|
181
|
-
item = model.with_deleted.find(parent_id).public_send(parent_name.to_sym) if model.with_deleted.find(parent_id).public_send(parent_name.to_sym) && model.with_deleted.find(parent_id).public_send(parent_name.to_sym).id == inputs_root[:id]
|
182
|
-
else
|
183
|
-
item = model.find(parent_id).public_send(parent_name.to_sym) if model.find(parent_id).public_send(parent_name.to_sym) && model.with_deleted.find(parent_id).public_send(parent_name.to_sym).id == inputs_root[:id]
|
184
|
-
end
|
185
|
-
raise GraphQL::ExecutionError.new("error: #{model.name}.#{parent_name} record not found for #{model.name}.with_deleted.find(#{parent_id}).#{parent_name}_id = #{inputs_root[:id]}") if item.nil?
|
186
|
-
model_name = klass_name
|
187
|
-
model = klass_name.classify.constantize
|
188
|
-
else #root query always single record, need to offeset property for object_input_type
|
189
|
-
inputs_root = inputs[model_name.downcase]
|
190
|
-
#puts "inputs_root[:id] #{inputs_root[:id]} #{inputs_root}"
|
191
|
-
if model.public_methods.include?(:with_deleted)
|
192
|
-
item = model.with_deleted.find(inputs_root[:id])
|
193
|
-
else
|
194
|
-
item = model.find(inputs_root[:id])
|
195
|
-
end
|
196
|
-
raise GraphQL::ExecutionError.new("error: #{model.name} record not found for #{model.name}.id=#{inputs[model_name.downcase][:id]}") if item.nil?
|
197
|
-
end
|
198
|
-
if !GraphqlModelMapper.authorized?(ctx, model.name, :update)
|
199
|
-
raise GraphQL::ExecutionError.new("error: unauthorized access: #{:update} '#{model}', transaction cancelled")
|
200
|
-
end
|
272
|
+
class ResolveWrapper
|
273
|
+
def initialize(resolve_func)
|
274
|
+
@resolve_func = resolve_func
|
275
|
+
end
|
276
|
+
|
277
|
+
def call(obj, args, ctx)
|
278
|
+
begin
|
279
|
+
@resolve_func.call(obj, args, ctx)
|
201
280
|
|
202
|
-
|
203
|
-
|
204
|
-
input_association_names = item_association_names & inputs_root.to_h.keys
|
205
|
-
|
206
|
-
item.transaction do
|
207
|
-
#puts "***********item.update_attributes(#{inputs_root.to_h.except('id').except!(*item_association_names)})"
|
208
|
-
#puts "***********ctx[current_user.to_sym].is_admin?(#{ctx[:current_user].is_admin?})"
|
209
|
-
item.update_attributes(inputs_root.to_h.except('id').except!(*item_association_names))
|
210
|
-
input_association_names.each do |ia|
|
211
|
-
lclinput = inputs_root[ia]
|
212
|
-
ass = item_associations.select{|a| a.name.to_s == ia}.first
|
213
|
-
klass = ass.klass
|
214
|
-
is_collection = ass.collection?
|
215
|
-
belongs_to = ass.belongs_to?
|
216
|
-
#puts "#{ass.name} #{ass.collection?} #{ass.belongs_to?}"
|
217
|
-
#puts "#{ass.association_foreign_key} #{ass.association_primary_key} #{ass.active_record_primary_key}"
|
218
|
-
|
219
|
-
if is_collection
|
220
|
-
#puts "is_collection"
|
221
|
-
lclinput.each do |i|
|
222
|
-
#puts "#{klass.name} #{i.to_h} #{model_name.downcase} #{inputs_root[:id]}"
|
223
|
-
GraphqlModelMapper::Resolve.nested_update(ctx, klass.name, i, model_name.downcase, inputs_root[:id])
|
224
|
-
end
|
225
|
-
elsif !is_collection && belongs_to
|
226
|
-
#puts "belongs_to"
|
227
|
-
#puts "self.nested_update(#{ctx}, #{model.name}, #{lclinput.to_h}, nil, nil, #{ass.name}, #{inputs_root[:id]}, #{klass.name})"
|
228
|
-
GraphqlModelMapper::Resolve.nested_update(ctx, model.name, lclinput, nil, nil, ass.name, inputs_root[:id], klass.name)
|
229
|
-
elsif !is_collection && !belongs_to #has_one
|
230
|
-
#puts "has_one"
|
231
|
-
#puts "self.nested_update(#{ctx}, #{klass.name}, #{lclinput.to_h}, #{model_name.downcase}, #{inputs_root[:id]})"
|
232
|
-
GraphqlModelMapper::Resolve.nested_update(ctx, model.name, lclinput, nil, nil, ass.name, inputs_root[:id], klass.name)
|
233
|
-
end
|
234
|
-
end
|
235
|
-
end
|
236
|
-
item
|
237
|
-
end
|
281
|
+
end
|
282
|
+
end
|
238
283
|
end
|
284
|
+
end
|
239
285
|
end
|