Module: Reports::HasManyOptions

Defined in:
app/commands/reports/has_many_options.rb

Class Method Summary collapse

Class Method Details

.association_and_descendants(association) ⇒ Object



88
89
90
91
92
93
# File 'app/commands/reports/has_many_options.rb', line 88

def self.association_and_descendants(association)
  [
    [association.klass, association.name.to_s],
    *association.klass.descendants.map { |d| [d, format_descendent_name(d, association)] }
  ]
end

.build_resource_name(name) ⇒ Object



84
85
86
# File 'app/commands/reports/has_many_options.rb', line 84

def self.build_resource_name(name)
  Reports::Generator.build_option_name(name).delete(" ")
end

.flattener(klass) ⇒ Object



20
21
22
# File 'app/commands/reports/has_many_options.rb', line 20

def self.flattener(klass)
  Flattener.for(klass).pivot_or_self
end

.format_descendent_name(descendant, association) ⇒ Object

To avoid naming conflicts, suffix the descendant's name with the association unless the association's name matches the association's klass name



97
98
99
100
101
102
103
# File 'app/commands/reports/has_many_options.rb', line 97

def self.format_descendent_name(descendant, association)
  if association.name.to_s.classify == association.klass.name.demodulize
    descendant.name.tableize
  else
    "#{descendant.name.underscore}_#{association.name}"
  end
end

.generate_filter_options(klass, nested_as: nil, **_options) ⇒ Object



16
17
18
# File 'app/commands/reports/has_many_options.rb', line 16

def self.generate_filter_options(klass, nested_as: nil, **_options)
  generate_options(klass: klass, type: "Filter", nested_as: nested_as)
end

.generate_options(klass:, type:, nested_as: nil, **_options) ⇒ Object



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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'app/commands/reports/has_many_options.rb', line 34

def self.generate_options(klass:, type:, nested_as: nil, **_options)
  Enumerator.new do |yielder|
    # Yield a select option for each belongs to association
    has_many_associations(klass).each do |association|
      expansions = Array(association.expand_on)
      assoc_name = build_resource_name(association.name).singularize
      break if assoc_name == "Favorite"
      association_resource_id = Reports::ExternalGraphqlClient.
        query_resource_by_name(name: assoc_name)&.
        dig("data", "resourceName", "id")
      # to define the join resource, we need to define the join association on the flattener we let a commented example on projects
      join_resource_id =
        if association.join_resource.present?
          Reports::ExternalGraphqlClient.
            query_resource_by_name(name: build_resource_name(association.join_resource))&.
            dig("data", "resourceName", "id")
        end
      # join_name = join_resource.dig("data", "resourceName", "name")
      next if association_resource_id.blank?
      association_and_descendants(association).each do |_association_klass, association_name|
        expansions.each do |expansion|
          option = {
            name: ::Reports::Generator.build_option_name(*expansion, association_name),
            associationResourceId: association_resource_id.to_i,
            associationName: association_name,
            associationColumnName: [*nested_as, association.foreign_key].join("_"),
          }
          option[:joinResourceId] = join_resource_id if join_resource_id.present?
          option[:columnType] = "link" if type == "Select"
          option[:selectOptionType] = "HasMany" if type == "Select"
          option[:filterOptionType] = "HasMany" if type == "Filter"
          yielder << option
        end

        option = {
          name: ::Reports::Generator.build_option_name(association_name),
          associationResourceId: association_resource_id.to_i,
          associationName: association_name,
          associationColumnName: [*nested_as, association.foreign_key].join("_"),
        }
        option[:joinResourceId] = join_resource_id if join_resource_id.present?
        option[:columnType] = "link" if type == "Select"
        option[:selectOptionType] = "HasMany" if type == "Select"
        option[:filterOptionType] = "HasMany" if type == "Filter"
        yielder << option
      end
    end
  end
end

.generate_select_options(klass, nested_as: nil, **_options) ⇒ Object

Generate select options (attributes) for all associations with nested attributes for the given class.



8
9
10
11
12
13
14
# File 'app/commands/reports/has_many_options.rb', line 8

def self.generate_select_options(klass, nested_as: nil, **_options)
  generate_options(
    klass: klass,
    type: "Select",
    nested_as: nested_as
  )
end

.has_many_associations(klass) ⇒ Object

Returns a lazy enumerator which yields the belongs_to associations (only those available for reports) for the given class.



25
26
27
28
29
30
31
32
# File 'app/commands/reports/has_many_options.rb', line 25

def self.has_many_associations(klass)
  flattener(klass).associations.lazy.
    reject(&:is_constant?).
    reject(&:is_nested_attributes?).
    select { |association| association.macro == :has_many }.
    reject { |association| association.ar_association.through_reflection }.
    reject { |association| association.flattener.class.is_pivot? }
end