Class: GraphQL::Models::MutationFieldMap

Inherits:
Object
  • Object
show all
Defined in:
lib/graphql/models/mutation_field_map.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(model_type, find_by:, null_behavior:) ⇒ MutationFieldMap

Returns a new instance of MutationFieldMap.

Raises:

  • (ArgumentError)


9
10
11
12
13
14
15
16
17
18
19
20
21
# File 'lib/graphql/models/mutation_field_map.rb', line 9

def initialize(model_type, find_by:, null_behavior:)
  raise ArgumentError, "model_type must be a model" if model_type && !(model_type <= ActiveRecord::Base)
  raise ArgumentError, "null_behavior must be :set_null or :leave_unchanged" unless [:set_null, :leave_unchanged].include?(null_behavior)

  @fields = []
  @nested_maps = []
  @path = []
  @model_type = model_type
  @find_by = Array.wrap(find_by)
  @null_behavior = null_behavior

  @find_by.each { |f| attr(f) }
end

Instance Attribute Details

#associationObject

These are used when this is a proxy_to or a nested field map



7
8
9
# File 'lib/graphql/models/mutation_field_map.rb', line 7

def association
  @association
end

#fieldsObject

Returns the value of attribute fields.



4
5
6
# File 'lib/graphql/models/mutation_field_map.rb', line 4

def fields
  @fields
end

#find_byObject

Returns the value of attribute find_by.



4
5
6
# File 'lib/graphql/models/mutation_field_map.rb', line 4

def find_by
  @find_by
end

#has_manyObject

These are used when this is a proxy_to or a nested field map



7
8
9
# File 'lib/graphql/models/mutation_field_map.rb', line 7

def has_many
  @has_many
end

#model_typeObject

Returns the value of attribute model_type.



4
5
6
# File 'lib/graphql/models/mutation_field_map.rb', line 4

def model_type
  @model_type
end

#nameObject

These are used when this is a proxy_to or a nested field map



7
8
9
# File 'lib/graphql/models/mutation_field_map.rb', line 7

def name
  @name
end

#nested_mapsObject

Returns the value of attribute nested_maps.



4
5
6
# File 'lib/graphql/models/mutation_field_map.rb', line 4

def nested_maps
  @nested_maps
end

#null_behaviorObject

Returns the value of attribute null_behavior.



4
5
6
# File 'lib/graphql/models/mutation_field_map.rb', line 4

def null_behavior
  @null_behavior
end

#pathObject

These are used when this is a proxy_to or a nested field map



7
8
9
# File 'lib/graphql/models/mutation_field_map.rb', line 7

def path
  @path
end

#requiredObject

These are used when this is a proxy_to or a nested field map



7
8
9
# File 'lib/graphql/models/mutation_field_map.rb', line 7

def required
  @required
end

Instance Method Details

#attr(attribute, type: nil, name: nil, required: nil) ⇒ Object



27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/graphql/models/mutation_field_map.rb', line 27

def attr(attribute, type: nil, name: nil, required: nil)
  attribute = attribute.to_sym if attribute.is_a?(String)

  if type.nil? && !model_type
    raise ArgumentError, "You must specify a type for attribute #{name}, because its model type is not known until runtime."
  end

  if type.nil? && (attribute == :id || foreign_keys.include?(attribute))
    type = types.ID
  end

  if type.nil? && model_type
    type = Reflection.attribute_graphql_type(model_type, attribute).input
  end

  if required.nil?
    required = model_type ? Reflection.is_required(model_type, attribute) : false
  end

  name ||= attribute.to_s.camelize(:lower)
  name = name.to_s

  detect_field_conflict(name)

  # Delete the field, if it's already in the map
  fields.reject! { |fd| fd[:attribute] == attribute }

  fields << {
    name: name,
    attribute: attribute,
    type: type,
    required: required,
  }
end

#leave_null_unchanged?Boolean

Returns:

  • (Boolean)


132
133
134
# File 'lib/graphql/models/mutation_field_map.rb', line 132

def leave_null_unchanged?
  null_behavior == :leave_unchanged
end

#nested(association, find_by: nil, null_behavior:, name: nil, has_many: false, &block) ⇒ Object



100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/graphql/models/mutation_field_map.rb', line 100

def nested(association, find_by: nil, null_behavior:, name: nil, has_many: false, &block)
  unless model_type
    raise ArgumentError, "Cannot use `nested` unless the model type is known at build time."
  end

  association = association.to_sym if association.is_a?(String)
  reflection = model_type.reflect_on_association(association)

  unless reflection
    raise ArgumentError, "Could not find association #{association} on #{model_type.name}"
  end

  if reflection.polymorphic?
    raise ArgumentError, "Cannot used `nested` with polymorphic association #{association} on #{model_type.name}"
  end

  has_many = reflection.macro == :has_many
  required = Reflection.is_required(model_type, association)

  map = MutationFieldMap.new(reflection.klass, find_by: find_by, null_behavior: null_behavior)
  map.name = name || association.to_s.camelize(:lower)
  map.association = association.to_s
  map.has_many = has_many
  map.required = required

  detect_field_conflict(map.name)

  map.instance_exec(&block)

  nested_maps.push(map)
end

#proxy_to(association, &block) ⇒ Object



62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/graphql/models/mutation_field_map.rb', line 62

def proxy_to(association, &block)
  association = association.to_sym if association.is_a?(String)

  reflection = model_type&.reflect_on_association(association)

  if reflection
    unless [:belongs_to, :has_one].include?(reflection.macro)
      raise ArgumentError, "Cannot proxy to #{reflection.macro} association #{association} from #{model_type.name}"
    end

    klass = reflection.polymorphic? ? nil : reflection.klass
  else
    klass = nil
  end

  proxy = MutationFieldMap.new(klass, find_by: nil, null_behavior: null_behavior)
  proxy.association = association
  proxy.instance_exec(&block)

  proxy.fields.each { |f| detect_field_conflict(f[:name]) }
  proxy.nested_maps.each { |m| detect_field_conflict(m.name) }

  proxy.fields.each do |field|
    fields.push({
      name: field[:name],
      attribute: field[:attribute],
      type: field[:type],
      required: field[:required],
      path: [association] + Array.wrap(field[:path]),
    })
  end

  proxy.nested_maps.each do |m|
    m.path.unshift(association)
    nested_maps.push(m)
  end
end

#typesObject



23
24
25
# File 'lib/graphql/models/mutation_field_map.rb', line 23

def types
  GraphQL::Define::TypeDefiner.instance
end