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:, legacy_nulls:) ⇒ MutationFieldMap

Returns a new instance of MutationFieldMap.

Raises:

  • (ArgumentError)


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

def initialize(model_type, find_by:, null_behavior:, legacy_nulls:)
  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 %i[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
  @legacy_nulls = legacy_nulls

  @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



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

def association
  @association
end

#fieldsObject

Returns the value of attribute fields.



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

def fields
  @fields
end

#find_byObject

Returns the value of attribute find_by.



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

def find_by
  @find_by
end

#has_manyObject

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



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

def has_many
  @has_many
end

#legacy_nullsObject

Returns the value of attribute legacy_nulls.



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

def legacy_nulls
  @legacy_nulls
end

#model_typeObject

Returns the value of attribute model_type.



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

def model_type
  @model_type
end

#nameObject

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



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

def name
  @name
end

#nested_mapsObject

Returns the value of attribute nested_maps.



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

def nested_maps
  @nested_maps
end

#null_behaviorObject

Returns the value of attribute null_behavior.



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

def null_behavior
  @null_behavior
end

#pathObject

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



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

def path
  @path
end

#requiredObject

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



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

def required
  @required
end

Instance Method Details

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



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
61
62
# File 'lib/graphql/models/mutation_field_map.rb', line 29

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)


134
135
136
# File 'lib/graphql/models/mutation_field_map.rb', line 134

def leave_null_unchanged?
  null_behavior == :leave_unchanged
end

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



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
131
132
# File 'lib/graphql/models/mutation_field_map.rb', line 102

def nested(association, find_by: nil, null_behavior:, name: nil, &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, legacy_nulls: legacy_nulls)
  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



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
99
100
# File 'lib/graphql/models/mutation_field_map.rb', line 64

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

  reflection = model_type&.reflect_on_association(association)

  if reflection
    unless %i[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, legacy_nulls: legacy_nulls)
  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



25
26
27
# File 'lib/graphql/models/mutation_field_map.rb', line 25

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