graphql_model_mapper 0.0.6 → 0.1.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.
@@ -1,5 +1,6 @@
1
1
  require "graphql"
2
2
  require "graphql_model_mapper/mapper_type"
3
+ require "graphql_model_mapper/custom_type"
3
4
  require "graphql_model_mapper/mutation"
4
5
  require "graphql_model_mapper/query"
5
6
  require "graphql_model_mapper/resolve"
@@ -9,14 +10,30 @@ require "graphql_model_mapper/version"
9
10
  require 'graphql_model_mapper/railtie' if defined?(Rails)
10
11
 
11
12
  module GraphqlModelMapper
13
+ mattr_accessor :query_resolve_wrapper
14
+ mattr_accessor :mutation_resolve_wrapper
15
+ mattr_accessor :resolve_wrapper
12
16
  mattr_accessor :type_case
13
17
  mattr_accessor :nesting_strategy
14
18
  mattr_accessor :use_authorize
19
+ mattr_accessor :max_page_size
20
+ mattr_accessor :scan_for_polymorphic_associations
21
+ mattr_accessor :default_nodes_field
22
+ mattr_accessor :bidirectional_pagination
23
+
15
24
 
16
25
  @@type_case = :camelize
17
26
  @@nesting_strategy = :shallow
18
27
  @@use_authorize = false
28
+ @@max_page_size = 100
29
+ @@scan_for_polymorphic_associations = false
30
+ @@query_resolve_wrapper = nil
31
+ @@mutation_resolve_wrapper = nil
32
+ @@default_nodes_field = false
33
+ @@bidirectional_pagination = false
19
34
 
35
+
36
+
20
37
  class << self
21
38
  attr_writer :logger
22
39
 
@@ -36,15 +53,15 @@ module GraphqlModelMapper
36
53
 
37
54
  protected
38
55
 
39
- def graphql_types(query: {}, update: {}, delete: {}, create: {})
56
+ def graphql_types(input_type:{}, output_type:{})
40
57
  name = self.name
41
58
  define_singleton_method(:graphql_types) do
42
- GraphqlModelMapper::MapperType.graphql_types(name: name, query: query, update: update, delete: delete, create: create)
59
+ GraphqlModelMapper::MapperType.graphql_types(name: name, input_type: input_type, output_type: output_type)
43
60
  end
44
61
  end
45
62
 
46
63
  def graphql_update(description:"", resolver: -> (obj, inputs, ctx){
47
- item = GraphqlModelMapper::Resolve.update_resolver(obj, inputs, ctx, name)
64
+ item = GraphqlModelMapper::Resolve.update_resolver(obj, inputs, ctx, name)
48
65
  {
49
66
  item: item
50
67
  }
@@ -58,7 +75,6 @@ module GraphqlModelMapper
58
75
  def graphql_delete(description:"", resolver: -> (obj, inputs, ctx){
59
76
  items = GraphqlModelMapper::Resolve.delete_resolver(obj, inputs, ctx, name)
60
77
  {
61
- total: items.length,
62
78
  items: items
63
79
  }
64
80
  }, arguments: [], scope_methods: [])
@@ -69,7 +85,7 @@ module GraphqlModelMapper
69
85
  end
70
86
 
71
87
  def graphql_create(description:"", resolver: -> (obj, args, ctx){
72
- item = GraphqlModelMapper::Resolve.create_resolver(obj, args, ctx, name)
88
+ item = GraphqlModelMapper::Resolve.create_resolver(obj, args, ctx, name)
73
89
  {
74
90
  item: item
75
91
  }
@@ -82,14 +98,10 @@ module GraphqlModelMapper
82
98
 
83
99
  def graphql_query(description: "", resolver: -> (obj, args, ctx) {
84
100
  items = GraphqlModelMapper::Resolve.query_resolver(obj, args, ctx, name)
85
- {
86
- items: items,
87
- total: items.length
88
- }
89
101
  }, arguments: [], scope_methods: [])
90
102
  name = self.name
91
103
  define_singleton_method(:graphql_query) do
92
- GraphqlModelMapper::Query.graphql_query(name: name, description: description, resolver: resolver, scope_methods: scope_methods)
104
+ GraphqlModelMapper::Query.graphql_query(name: name, description: description, resolver: resolver, scope_methods: scope_methods, arguments: arguments)
93
105
  end
94
106
  end
95
107
  end
@@ -0,0 +1,4 @@
1
+ module GraphqlModelMapper
2
+ module CustomType
3
+ end
4
+ end
@@ -2,29 +2,32 @@ module GraphqlModelMapper
2
2
  module MapperType
3
3
  def self.graphql_types(
4
4
  name: self.name,
5
- query: {},
6
- update: {},
7
- delete: {},
8
- create: {}
5
+ input_type: {},
6
+ output_type: {}
9
7
  )
10
- #typesuffix = method(__method__).parameters.map { |arg| eval arg[1].to_s }.hash.abs.to_i.to_s
11
- GraphqlModelMapper.logger.info("#{name.upcase}") if GraphqlModelMapper.const_defined?("#{name.upcase}_GRAPHQL_DEFAULT_TYPES")
12
- return GraphqlModelMapper.get_constant("#{name.upcase}_GRAPHQL_DEFAULT_TYPES") if GraphqlModelMapper.const_defined?("#{name.upcase}_GRAPHQL_DEFAULT_TYPES")
13
- #GraphqlModelMapper.logger.info "#{name.upcase}_GRAPHQL_DEFAULT_TYPES"
8
+ return GraphqlModelMapper::CustomType.const_get("#{name.upcase}_GRAPHQL_DEFAULT_TYPES") if GraphqlModelMapper::CustomType.const_defined?("#{name.upcase}_GRAPHQL_DEFAULT_TYPES")
14
9
  graphql_type = {}
15
- graphql_type[:query] = query
16
- graphql_type[:update] = update
17
- graphql_type[:delete] = delete
18
- graphql_type[:create] = create
10
+ graphql_type[:input_type] = input_type
11
+ graphql_type[:input_type][:type_sub_key] = :input_type
12
+ graphql_type[:output_type] = output_type
13
+ graphql_type[:output_type][:type_sub_key] = :output_type
19
14
  merged_graphql_type = self.graphql_default_types.deep_merge(graphql_type)
20
- GraphqlModelMapper.set_constant("#{name.upcase}_GRAPHQL_DEFAULT_TYPES", merged_graphql_type)
15
+ GraphqlModelMapper::CustomType.const_set("#{name.upcase}_GRAPHQL_DEFAULT_TYPES", merged_graphql_type)
21
16
 
22
17
  merged_graphql_type
23
18
  end
24
19
 
25
20
 
26
- def self.get_ar_object_with_params(name, type_key: nil, type_sub_key: nil)
27
- self.get_ar_object(name, self.get_type_params(name, type_key: type_key, type_sub_key: type_sub_key))
21
+ def self.graph_object(name)
22
+ if GraphqlModelMapper.implementations.map(&:to_s).include?(name.classify)
23
+ self.get_ar_object_with_params(name)
24
+ else
25
+ name.classify.constantize
26
+ end
27
+ end
28
+
29
+ def self.get_ar_object_with_params(name, type_sub_key: :output_type)
30
+ self.get_ar_object(name, self.get_type_params(name, type_sub_key: type_sub_key))
28
31
  end
29
32
 
30
33
  def self.get_ar_object(name,
@@ -36,12 +39,13 @@ module GraphqlModelMapper
36
39
  validation_keys: false,
37
40
  association_macro: nil,
38
41
  source_nulls: true,
39
- type_key: nil,
40
42
  type_sub_key: nil)
41
43
 
42
44
 
43
45
  #typesuffix = method(__method__).parameters.map { |arg| eval arg[1].to_s }.hash.abs.to_i.to_s
44
- typesuffix = "#{type_key.to_s.classify}#{GraphqlModelMapper.underscore(type_sub_key.to_s)}".camelize
46
+ #typesuffix = "#{type_key.to_s.classify}#{GraphqlModelMapper.underscore(type_sub_key.to_s)}".camelize
47
+ typesuffix = "#{GraphqlModelMapper.underscore(type_sub_key.to_s).sub("_Type", "")}".camelize
48
+ #typesuffix = "#{type_sub_key == :input_type ? '_i' : '_o'}"
45
49
  typename = "#{GraphqlModelMapper.get_type_name(name)}#{typesuffix}"
46
50
 
47
51
  return GraphqlModelMapper.get_constant(typename) if GraphqlModelMapper.defined_constant?(typename)
@@ -55,83 +59,102 @@ module GraphqlModelMapper
55
59
  # figure out which association fields we are exposing
56
60
  association_includes = (model.reflect_on_all_associations(association_macro).map(&:name)).map(&:to_sym) - excluded_attributes
57
61
 
58
- # find all relations for this model, skip ones where the association klass is invalid, as well as polymorphic associations, be cognizant of include/exclude arrays similar to dbfields
59
- associations = model.reflect_on_all_associations(association_macro).select{|t| begin t.klass rescue next end}.select{|t| !t.options[:polymorphic] && association_includes.include?(t.name.to_sym) }
62
+ # find all relations for this model, skip ones where the association klass is invalid, be cognizant of include/exclude arrays similar to dbfields
63
+ associations = model.reflect_on_all_associations(association_macro).select{|t| begin t.klass rescue next end}.select{|t| association_includes.include?(t.name.to_sym) }
64
+ # now include polymorphic relations whose association klass is invalid, but is correct
65
+ associations = associations + model.reflect_on_all_associations(association_macro).select{|t| t.options[:polymorphic]}.select{|t| association_includes.include?(t.name.to_sym) }
60
66
  # never show foreign keys for defined associations
61
- db_fields_never = foreign_keys ? [] : ( associations.map(&:association_foreign_key) + associations.map(&:options).select{|v| v.key?(:foreign_key) }.map {|x| x[:foreign_key]} ).uniq.map(&:to_sym)
67
+ db_fields_never = foreign_keys ? [] : ( model.reflect_on_all_associations.map(&:association_foreign_key) + model.reflect_on_all_associations.map(&:options).select{|v| v.key?(:foreign_key) }.map {|x| x[:foreign_key]} ).uniq.map(&:to_sym)
62
68
 
63
69
  # figure out which database fields we are exposing
64
70
  allowed_attributes = allowed_attributes.count > 0 ? allowed_attributes.map(&:to_sym) : associations.map(&:name) + columns.keys.map(&:to_sym)
65
71
  allowed_associations = (associations.map(&:name) - excluded_attributes - db_fields_never) & allowed_attributes
66
72
  db_fields = (columns.keys.map(&:to_sym) - excluded_attributes - db_fields_never) & allowed_attributes
67
73
  associations = associations.select{|m| allowed_associations.include?(m.name)}
68
-
74
+ enums = (Rails.version.split(".").first.to_i >= 4 && Rails.version.split(".").second.to_i >= 1) || (Rails.version.split(".").first.to_i >= 5) ? model.defined_enums.keys : []
75
+ enum_values = (Rails.version.split(".").first.to_i >= 4 && Rails.version.split(".").second.to_i >= 1) || (Rails.version.split(".").first.to_i >= 5) ? model.defined_enums : []
76
+
69
77
  ret_type = GraphQL::InputObjectType.define do
70
78
  #ensure type name is unique so it does not collide with known types
71
79
  name typename
72
80
  description "an input interface for the #{name} ActiveRecord model"
73
- # create GraphQL fields for each exposed database field
74
- db_fields.select{|s| (primary_keys && s.to_sym == :id)}.each do |f|
75
- argument f.to_sym, -> {GraphqlModelMapper::MapperType.convert_type(columns[f.to_s].type, columns[f.to_s].sql_type, (source_nulls ? columns[f.to_s].null : true))}
76
- end
77
- db_fields.select{|s| required_attributes.include?(s)}.each do |f|
78
- argument f.to_sym, -> {GraphqlModelMapper.convert_type(columns[f.to_s].type, columns[f.to_s].sql_type, false)}
79
- end
80
81
  # create GraphQL fields for each association
81
82
  associations.sort_by(&:name).each do |reflection|
82
83
  begin
83
- klass = reflection.klass
84
+ klass = reflection.klass if !reflection.options[:polymorphic]
84
85
  rescue
85
- GraphqlModelMapper.logger.warning("invalid relation #{reflection.name} specified on the #{name} model, the relation class does not exist")
86
+ GraphqlModelMapper.logger.info("invalid relation #{reflection.name} specified on the #{name} model, the relation class does not exist")
86
87
  next # most likely an invalid association without a class name, skip if other errors are encountered
87
88
  end
88
89
  if reflection.macro == :has_many
89
- argument reflection.name.to_sym, -> {GraphqlModelMapper::MapperType.get_ar_object_with_params(klass.name, type_key: type_key, type_sub_key: type_sub_key).to_list_type} do
90
+ argument reflection.name.to_sym, -> {GraphqlModelMapper::MapperType.get_ar_object_with_params(klass.name, type_sub_key: type_sub_key).to_list_type} do
90
91
  if GraphqlModelMapper.use_authorize
91
92
  authorized ->(ctx, model_name, access_type) { GraphqlModelMapper.authorized?(ctx, model_name, access_type.to_sym) }
92
93
  model_name klass.name
93
- access_type type_key.to_s
94
+ access_type :read
94
95
  end
95
96
  end
96
97
  else
97
- argument reflection.name.to_sym, -> {GraphqlModelMapper::MapperType.get_ar_object_with_params(klass.name, type_key: type_key, type_sub_key: type_sub_key)} do
98
- if GraphqlModelMapper.use_authorize
99
- authorized ->(ctx, model_name, access_type) { GraphqlModelMapper.authorized?(ctx, model_name, access_type.to_sym) }
100
- model_name klass.name
101
- access_type type_key.to_s
102
- end
103
- end
98
+ if reflection.options[:polymorphic] #not currently supported as an input type
99
+ #if GraphqlModelMapper.scan_for_polymorphic_associations
100
+ # argument reflection.name.to_sym, -> {GraphqlModelMapper::MapperType.get_polymorphic_type(reflection, name, type_sub_key: type_sub_key)}
101
+ #end
102
+ else
103
+ argument reflection.name.to_sym, -> {GraphqlModelMapper::MapperType.get_ar_object_with_params(klass.name, type_sub_key: type_sub_key)} do
104
+ if GraphqlModelMapper.use_authorize
105
+ authorized ->(ctx, model_name, access_type) { GraphqlModelMapper.authorized?(ctx, model_name, access_type.to_sym) }
106
+ model_name klass.name
107
+ access_type :read
108
+ end
109
+ end
110
+ end
104
111
  end
105
112
  end
106
113
 
107
- db_fields.reject{|s| (primary_keys && s.to_sym == :id) || required_attributes.include?(s)}.sort.each do |f|
108
- argument f.to_sym, -> {GraphqlModelMapper::MapperType.convert_type(columns[f.to_s].type, columns[f.to_s].sql_type, (source_nulls ? columns[f.to_s].null : true))}
114
+ # create GraphQL fields for each exposed database field
115
+ #if primary keys were requested
116
+ db_fields.select{|s| (primary_keys && s.to_sym == :id)}.each do |f|
117
+ argument "item_id".to_sym, -> {GraphqlModelMapper::MapperType.convert_type(columns[f.to_s].type, columns[f.to_s].sql_type, (source_nulls ? columns[f.to_s].null : true))}
118
+ end
119
+ argument :id, GraphQL::ID_TYPE
120
+ # force required_attributes to be non-null
121
+ db_fields.select{|s| required_attributes.include?(s)}.each do |f|
122
+ argument f.to_sym, -> {GraphqlModelMapper.convert_type(columns[f.to_s].type, columns[f.to_s].sql_type, false)}
123
+ end
124
+ #get the rest of the fields that are not primary keys or required fields
125
+ db_fields.reject{|s| (s.to_sym == :id) || required_attributes.include?(s)}.sort.each do |f|
126
+ custom_type_name = "#{name.classify}#{f.to_s.classify}AttributeInput"
127
+ if GraphqlModelMapper::CustomType.const_defined?(custom_type_name)
128
+ argument f.to_sym, GraphqlModelMapper::CustomType.const_get(custom_type_name)
129
+ else
130
+ if enums.include?(f.to_s)
131
+ argument f.to_sym, -> {GraphqlModelMapper::MapperType.get_enum_object(name, enum_values[f.to_s], f.to_s)}
132
+ else
133
+ argument f.to_sym, -> {GraphqlModelMapper::MapperType.convert_type(columns[f.to_s].type, columns[f.to_s].sql_type, (source_nulls ? columns[f.to_s].null : true))}
134
+ end
135
+ end
109
136
  end
110
137
  end if type_sub_key == :input_type
111
138
 
112
139
  ret_type = GraphQL::ObjectType.define do
113
140
  #ensure type name is unique so it does not collide with known types
114
141
  name typename
142
+ model_name name
143
+ authorized ->(ctx, model_name, access_type) { GraphqlModelMapper.authorized?(ctx, model_name, access_type.to_sym) }
144
+ access_type :read.to_s
145
+
115
146
  description "an output interface for the #{name} ActiveRecord model"
116
- # create GraphQL fields for each exposed database field
117
- db_fields.select{|s| (primary_keys && s.to_sym == :id)}.each do |f|
118
- #puts "source null #{f} #{source_nulls ? columns[f.to_s].null : true}"
119
- field f.to_sym, -> {GraphqlModelMapper::MapperType.convert_type(columns[f.to_s].type, columns[f.to_s].sql_type, (source_nulls ? columns[f.to_s].null : true))}
120
- end
121
- db_fields.select{|s| required_attributes.include?(s)}.sort.each do |f|
122
- field f.to_sym, -> {GraphqlModelMapper::MapperType.convert_type(columns[f.to_s].type, columns[f.to_s].sql_type, false)}
123
- end
124
- # create GraphQL fields for each association
147
+ # create GraphQL fields for each association
125
148
  associations.sort_by(&:name).each do |reflection|
126
149
  begin
127
- klass = reflection.klass
150
+ klass = reflection.klass if !reflection.options[:polymorphic]
128
151
  rescue
129
- GraphqlModelMapper.logger.warning("invalid relation #{reflection.name} specified on the #{name} model, the relation class does not exist")
152
+ GraphqlModelMapper.logger.info("invalid relation #{reflection.name} specified on the #{name} model, the relation class does not exist")
130
153
  next # most likely an invalid association without a class name, skip if other errors are encountered
131
154
  end
132
155
  if reflection.macro == :has_many
133
- if [:deep].include?(GraphqlModelMapper.nesting_strategy) && type_key == :query
134
- connection reflection.name.to_sym, -> {GraphqlModelMapper::MapperType.get_ar_object_with_params(klass.name, type_key: type_key, type_sub_key: type_sub_key).connection_type} do
156
+ if [:deep].include?(GraphqlModelMapper.nesting_strategy)
157
+ connection reflection.name.to_sym, -> {GraphqlModelMapper::MapperType.get_ar_object_with_params(klass.name, type_sub_key: type_sub_key).connection_type}, property: reflection.name.to_sym, max_page_size: GraphqlModelMapper.max_page_size do
135
158
  if GraphqlModelMapper.use_authorize
136
159
  authorized ->(ctx, model_name, access_type) { GraphqlModelMapper.authorized?(ctx, model_name, access_type.to_sym) }
137
160
  model_name klass.name
@@ -139,7 +162,7 @@ module GraphqlModelMapper
139
162
  end
140
163
  end
141
164
  else
142
- field reflection.name.to_sym, -> {GraphqlModelMapper::MapperType.get_ar_object_with_params(klass.name, type_key: type_key, type_sub_key: type_sub_key).to_list_type} do
165
+ field reflection.name.to_sym, -> {GraphqlModelMapper::MapperType.get_ar_object_with_params(klass.name, type_sub_key: type_sub_key).to_list_type}, property: reflection.name.to_sym do
143
166
  if GraphqlModelMapper.use_authorize
144
167
  authorized ->(ctx, model_name, access_type) { GraphqlModelMapper.authorized?(ctx, model_name, access_type.to_sym) }
145
168
  model_name klass.name
@@ -148,163 +171,134 @@ module GraphqlModelMapper
148
171
  end
149
172
  end
150
173
  else
151
- field reflection.name.to_sym, -> {GraphqlModelMapper::MapperType.get_ar_object_with_params(klass.name, type_key: type_key, type_sub_key: type_sub_key)} do
152
- if GraphqlModelMapper.use_authorize
153
- authorized ->(ctx, model_name, access_type) { GraphqlModelMapper.authorized?(ctx, model_name, access_type.to_sym) }
154
- model_name klass.name
155
- access_type :read.to_s
156
- end
157
- end
174
+ if reflection.options[:polymorphic]
175
+ # if a union type is defined in custom types use it, otherwise generate a union type from the association definition (requires a table scan)
176
+ custom_type_name = "#{name.classify}#{reflection.name.to_s.classify}Union"
177
+ if GraphqlModelMapper::CustomType.const_defined?(custom_type_name)
178
+ field reflection.name.to_sym, -> {GraphqlModelMapper::CustomType.const_get(custom_type_name)}, property: reflection.name.to_sym
179
+ elsif GraphqlModelMapper.scan_for_polymorphic_associations
180
+ field reflection.name.to_sym, -> {GraphqlModelMapper::MapperType.get_polymorphic_type(reflection, name)}, property: reflection.name.to_sym
181
+ end
182
+ else
183
+ field reflection.name.to_sym, -> {GraphqlModelMapper::MapperType.get_ar_object_with_params(klass.name, type_sub_key: type_sub_key)}, property: reflection.name.to_sym do
184
+ if GraphqlModelMapper.use_authorize
185
+ authorized ->(ctx, model_name, access_type) { GraphqlModelMapper.authorized?(ctx, model_name, access_type.to_sym) }
186
+ model_name klass.name
187
+ access_type :read.to_s
188
+ end
189
+ end
190
+ end
158
191
  end
159
192
  end
160
- db_fields.reject{|s| (primary_keys && s.to_sym == :id) || required_attributes.include?(s)}.sort.each do |f|
161
- #puts "source null #{f} #{source_nulls ? columns[f.to_s].null : true}"
162
- field f.to_sym, -> {GraphqlModelMapper::MapperType.convert_type(columns[f.to_s].type, columns[f.to_s].sql_type, (source_nulls ? columns[f.to_s].null : true))}
193
+ # create GraphQL fields for each exposed database field
194
+ # get primary keys if requested
195
+ implements GraphQL::Relay::Node.interface
196
+ global_id_field :id
197
+ db_fields.select{|s| (primary_keys && s.to_sym == :id)}.each do |f|
198
+ field "item_id".to_sym, -> {GraphqlModelMapper::MapperType.convert_type(columns[f.to_s].type, columns[f.to_s].sql_type, (source_nulls ? columns[f.to_s].null : true))}, property: :id do
199
+ resolve -> (obj, args, ctx) {
200
+ obj[:id]
201
+ }
202
+ end
203
+ end
204
+ # force required attributes to be non-null
205
+ db_fields.select{|s| required_attributes.include?(s)}.sort.each do |f|
206
+ field f.to_sym, -> {GraphqlModelMapper::MapperType.convert_type(columns[f.to_s].type, columns[f.to_s].sql_type, false)}, property: f.to_sym
207
+ end
208
+ # get the remaining fields and apply custom type if defined
209
+ db_fields.reject{|s| (s.to_sym == :id) || required_attributes.include?(s)}.sort.each do |f|
210
+ custom_type_name = "#{name.classify}#{f.to_s.classify}AttributeOutput"
211
+ if GraphqlModelMapper::CustomType.const_defined?(custom_type_name)
212
+ field f.to_sym, GraphqlModelMapper::CustomType.const_get(custom_type_name), property: f.to_sym
213
+ else
214
+ if enums.include?(f.to_s)
215
+ field f.to_sym, -> {GraphqlModelMapper::MapperType.get_enum_object(name, enum_values[f.to_s], f.to_s)}, property: f.to_sym
216
+ else
217
+ field f.to_sym, -> {GraphqlModelMapper::MapperType.convert_type(columns[f.to_s].type, columns[f.to_s].sql_type, (source_nulls ? columns[f.to_s].null : true))}, property: f.to_sym
218
+ end
219
+ end
163
220
  end
164
221
  end if type_sub_key == :output_type
165
222
  GraphqlModelMapper.set_constant(typename, ret_type) if !GraphqlModelMapper.defined_constant?(typename)
166
223
  ret_type
167
224
  end
168
225
 
169
- def self.get_type_params(name, type_key: nil, type_sub_key: nil)
226
+
227
+ def self.get_polymorphic_type(reflection, model_name)
228
+ type_name = "#{model_name}#{reflection.name.to_s.classify}UnionOutput"
229
+
230
+ return GraphqlModelMapper.get_constant(type_name) if GraphqlModelMapper.defined_constant?(type_name)
231
+
232
+ model = model_name.classify.constantize
233
+ has_with_deleted = model.public_methods.include?(:with_deleted)
234
+ parent_name = "#{reflection.name}_type"
235
+ parent_classes = has_with_deleted ? model.with_deleted.select("distinct #{parent_name}").map{|m| m.send("#{parent_name}".to_sym)} : model.select("distinct #{parent_name}").map{|m| m.send("#{parent_name}".to_sym)}
236
+ types = []
237
+ parent_classes.each do |p|
238
+ types << self.get_ar_object_with_params(p, type_sub_key: type_sub_key)
239
+ end
240
+
241
+ ret_type = GraphQL::UnionType.define do
242
+ name type_name
243
+ description "UnionType for polymorphic association #{reflection.name} on #{model_name}"
244
+ possible_types types
245
+ resolve_type ->(obj, ctx) {
246
+ GraphqlModelMapper::MapperType.get_ar_object_with_params(obj.class.name)
247
+ }
248
+ end
249
+ GraphqlModelMapper.set_constant(type_name, ret_type)
250
+ GraphqlModelMapper.get_constant(type_name)
251
+ end
252
+
253
+ def self.get_type_params(name, type_sub_key: :output_type)
170
254
  model = name.classify.constantize
171
255
  if model.public_methods.include?(:graphql_types)
172
256
  params = model.graphql_types
173
257
  else
174
258
  params = self.graphql_default_types
175
259
  end
176
- #puts params
177
- if !type_key.nil?
178
- if params.keys.include?(type_key.to_sym)
179
- params = params[type_key.to_sym]
180
- if !type_sub_key.nil?
181
- if params.keys.include?(type_sub_key.to_sym)
260
+ if !type_sub_key.nil?
261
+ if params.keys.include?(type_sub_key.to_sym)
182
262
  params = params[type_sub_key.to_sym]
183
- else
263
+ else
184
264
  params = nil
185
- end
186
265
  end
187
- else
266
+ else
188
267
  params = nil
189
- end
190
268
  end
269
+ params[:type_sub_key] = type_sub_key
191
270
  params
192
271
  end
193
272
 
194
273
  def self.graphql_default_types(
195
- query: {
196
- input_type: {
197
- required_attributes: [],
198
- excluded_attributes: [],
199
- allowed_attributes: [],
200
- foreign_keys: true,
201
- primary_keys: true,
202
- validation_keys: false,
203
- association_macro: nil,
204
- source_nulls: false,
205
- type_key: :query,
206
- type_sub_key: :input_type
207
- },
208
- output_type: {
209
- required_attributes: [],
210
- excluded_attributes: [],
211
- allowed_attributes: [],
212
- foreign_keys: true,
213
- primary_keys: true,
214
- validation_keys: false,
215
- association_macro: nil,
216
- source_nulls: false,
217
- type_key: :query,
218
- type_sub_key: :output_type
219
- }
220
- },
221
- update: {
222
- input_type: {
223
- required_attributes: [],
224
- excluded_attributes: [],
225
- allowed_attributes: [],
226
- foreign_keys: true,
227
- primary_keys: true,
228
- validation_keys: false,
229
- association_macro: nil,
230
- source_nulls: false,
231
- type_key: :update,
232
- type_sub_key: :input_type
233
- },
234
- output_type: {
235
- required_attributes: [],
236
- excluded_attributes: [],
237
- allowed_attributes: [],
238
- foreign_keys: true,
239
- primary_keys: true,
240
- validation_keys: false,
241
- association_macro: nil,
242
- source_nulls: true,
243
- type_key: :update,
244
- type_sub_key: :output_type
245
- }
246
- },
247
- delete: {
248
- input_type: {
249
- required_attributes: [:id],
250
- excluded_attributes: [],
251
- allowed_attributes: [:id],
252
- foreign_keys: false,
253
- primary_keys: true,
254
- validation_keys: false,
255
- association_macro: nil,
256
- source_nulls: false,
257
- type_key: :delete,
258
- type_sub_key: :input_type
259
- },
260
- output_type: {
261
- required_attributes: [],
262
- excluded_attributes: [],
263
- allowed_attributes: [],
264
- foreign_keys: false,
265
- primary_keys: true,
266
- validation_keys: false,
267
- association_macro: nil,
268
- source_nulls: true,
269
- type_key: :delete,
270
- type_sub_key: :output_type
271
- }
272
- },
273
- create: {
274
- input_type: {
275
- required_attributes: [],
276
- excluded_attributes: [],
277
- allowed_attributes: [],
278
- foreign_keys: true,
279
- primary_keys: false,
280
- validation_keys: false,
281
- association_macro: :has_many,
282
- source_nulls: false,
283
- type_key: :create,
284
- type_sub_key: :input_type
285
- },
286
- output_type: {
287
- required_attributes: [],
288
- excluded_attributes: [],
289
- allowed_attributes: [],
290
- foreign_keys: true,
291
- primary_keys: true,
292
- validation_keys: false,
293
- association_macro: nil,
294
- source_nulls: true,
295
- type_key: :create,
296
- type_sub_key: :output_type
297
- }
298
- })
299
- return GraphqlModelMapper.get_constant("GRAPHQL_DEFAULT_TYPES") if GraphqlModelMapper.const_defined?("GRAPHQL_DEFAULT_TYPES")
274
+ input_type: {
275
+ required_attributes: [],
276
+ excluded_attributes: [],
277
+ allowed_attributes: [],
278
+ foreign_keys: true,
279
+ primary_keys: true,
280
+ validation_keys: false,
281
+ association_macro: nil,
282
+ source_nulls: false
283
+ },
284
+ output_type: {
285
+ required_attributes: [],
286
+ excluded_attributes: [],
287
+ allowed_attributes: [],
288
+ foreign_keys: true,
289
+ primary_keys: true,
290
+ validation_keys: false,
291
+ association_macro: nil,
292
+ source_nulls: false
293
+ }
294
+ )
295
+ return GraphqlModelMapper::CustomType.const_get("GRAPHQL_DEFAULT_TYPES") if GraphqlModelMapper::CustomType.const_defined?("GRAPHQL_DEFAULT_TYPES")
300
296
 
301
297
  graphql_type = {}
302
- graphql_type[:query] = query
303
- graphql_type[:update] = update
304
- graphql_type[:delete] = delete
305
- graphql_type[:create] = create
306
-
307
- GraphqlModelMapper.set_constant("GRAPHQL_DEFAULT_TYPES", graphql_type)
298
+ graphql_type[:input_type] = input_type
299
+ graphql_type[:output_type] = output_type
300
+
301
+ GraphqlModelMapper::CustomType.const_set("GRAPHQL_DEFAULT_TYPES", graphql_type)
308
302
  graphql_type
309
303
  end
310
304
 
@@ -314,6 +308,20 @@ module GraphqlModelMapper
314
308
  model.reflect_on_all_associations.select{|p| validation_attributes.include?(p.name) }.map(&:foreign_key).map(&:to_sym) | validation_attributes & model.columns_hash.keys.map(&:to_sym)
315
309
  end
316
310
 
311
+ def self.get_enum_object(model_name, enum, enum_name)
312
+ enum_values = enum.keys
313
+ type_name = "#{model_name.classify}#{enum_name.classify}Enum"
314
+ return GraphqlModelMapper.get_constant(type_name) if GraphqlModelMapper.defined_constant?(type_name)
315
+ ret_type = GraphQL::EnumType.define do
316
+ name type_name
317
+ description "generated GraphQL enum for ActiveRecord enum #{enum_name} on model #{model_name}"
318
+ enum_values.each do |v|
319
+ value(v.classify, "", value: v)
320
+ end
321
+ end
322
+ GraphqlModelMapper.set_constant(type_name, ret_type)
323
+ GraphqlModelMapper.get_constant(type_name)
324
+ end
317
325
  # convert a database type to a GraphQL type
318
326
  # @param db_type [Symbol] the type returned by columns_hash[column_name].type
319
327
  # @param db_sql_type [String] the sql_type returned by columns_hash[column_name].sql_type