Module: Quail::Resource::TypeBuilder::AssociationBuilder

Defined in:
lib/quail/resource/type_builder/association_builder.rb

Overview

Wires up association fields (belongs_to, has_one, has_many, polymorphic) on a GraphQL type.

Class Method Summary collapse

Class Method Details

.add_association_field(type_class, name, kind, assoc_type, ar_assoc) ⇒ Object



80
81
82
83
84
85
86
87
88
# File 'lib/quail/resource/type_builder/association_builder.rb', line 80

def self.add_association_field(type_class, name, kind, assoc_type, ar_assoc)
  case kind
  when :has_many
    type_class.field name, [assoc_type], null: false
  when :has_one, :belongs_to
    nullable = kind != :belongs_to || !ar_assoc || ar_assoc.options[:optional] != false
    type_class.field name, assoc_type, null: nullable
  end
end

.add_explicit_resource_field(type_class, model, name, config) ⇒ Object



35
36
37
38
39
40
41
42
# File 'lib/quail/resource/type_builder/association_builder.rb', line 35

def self.add_explicit_resource_field(type_class, model, name, config)
  resource_class = TypeBuilder.resolve_resource_ref(config[:resource])
  assoc_type = resource_class&.graphql_type
  return unless assoc_type

  ar_assoc = model.reflect_on_association(name)
  add_association_field(type_class, name, config[:kind], assoc_type, ar_assoc)
end

.add_fields(resource_class) ⇒ Object



9
10
11
12
13
14
15
16
17
18
# File 'lib/quail/resource/type_builder/association_builder.rb', line 9

def self.add_fields(resource_class)
  model = resource_class.model_class
  type_class = resource_class.graphql_type

  resource_class.association_definitions.each do |name, config|
    next if type_class.own_fields.key?(name.to_s)

    add_single(type_class, model, name, config)
  end
end

.add_polymorphic_field(type_class, name, config) ⇒ Object



30
31
32
33
# File 'lib/quail/resource/type_builder/association_builder.rb', line 30

def self.add_polymorphic_field(type_class, name, config)
  union_type = build_union_type(name, config)
  type_class.field name, union_type, null: true
end

.add_reflected_field(type_class, model, name, config) ⇒ Object



44
45
46
47
48
49
50
51
52
# File 'lib/quail/resource/type_builder/association_builder.rb', line 44

def self.add_reflected_field(type_class, model, name, config)
  ar_assoc = model.reflect_on_association(name)
  return unless ar_assoc

  assoc_type = Quail.resource_for(ar_assoc.klass)&.graphql_type
  return unless assoc_type

  add_association_field(type_class, name, config[:kind], assoc_type, ar_assoc)
end

.add_single(type_class, model, name, config) ⇒ Object



20
21
22
23
24
25
26
27
28
# File 'lib/quail/resource/type_builder/association_builder.rb', line 20

def self.add_single(type_class, model, name, config)
  if config[:polymorphic]
    add_polymorphic_field(type_class, name, config)
  elsif config[:resource]
    add_explicit_resource_field(type_class, model, name, config)
  else
    add_reflected_field(type_class, model, name, config)
  end
end

.build_union_type(name, config) ⇒ Object



54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/quail/resource/type_builder/association_builder.rb', line 54

def self.build_union_type(name, config)
  gql_name = config[:union_name] || "#{name.to_s.camelize}Union"
  resolved_types = resolve_polymorphic_types(config[:polymorphic_types])
  assoc_name = name

  Class.new(GraphQL::Schema::Union) do
    graphql_name gql_name
    description "Union type for polymorphic association #{assoc_name}"
    possible_types(*resolved_types)
    define_method(:resolve_type) { |obj, _ctx| TypeBuilder.resolve_polymorphic_type(obj, assoc_name) }
  end
end

.resolve_polymorphic_types(types) ⇒ Object



67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/quail/resource/type_builder/association_builder.rb', line 67

def self.resolve_polymorphic_types(types)
  types.map do |t|
    resource = TypeBuilder.resolve_resource_ref(t)
    gql_type = resource.graphql_type
    unless gql_type
      raise ArgumentError,
            "Polymorphic type #{t.inspect} resolved to #{resource.name} but its graphql_type is nil. " \
            "Ensure the resource is registered before building associations."
    end
    gql_type
  end
end