Module: Optic::Rails

Defined in:
lib/optic/rails.rb,
lib/optic/rails/railtie.rb,
lib/optic/rails/version.rb

Defined Under Namespace

Classes: Railtie

Constant Summary collapse

VERSION =
"1.3.0"

Class Method Summary collapse

Class Method Details

.entitiesObject



8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/optic/rails.rb', line 8

def entities
  with_connection do
    {
      schema_version: ActiveRecord::Migrator.current_version,
      entities: active_record_klasses.map do |klass|
        {
          name: klass.name,
          table_name: klass.table_name,
          entity_attribute_names: klass.attribute_names,
          table_exists: klass.table_exists?,
          associations: klass.reflect_on_all_associations.map do |reflection|
            {
              name: reflection.name,
              macro: reflection.macro,
              options: reflection.options.map { |k, v| [k, v.to_s] }.to_h,
              klass_name: reflection.options[:polymorphic] ? nil : reflection.klass.name,
            }
          end
        }
      end
    }
  end
end

.metrics(instructions) ⇒ Object



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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/optic/rails.rb', line 32

def metrics(instructions)
  with_connection do |connection|
    instructions.map do |instruction|
      name = instruction["entity"]
      entity = name.constantize.unscoped

      query =
        if pivot_name = instruction["pivot"]
          # TODO this is a terrible hack to extract zero-valued pivot
          # instances. The right thing to do is select from the pivot
          # table and LEFT OUTER JOIN to the entity table, which results
          # in a much simpler query, but it means we have to rewrite the
          # pathfinding logic in the server to find paths using has_many
          # associations instead of belongs_to associations, which might
          # be less accurate for a bunch of reasons. For now, we're doing
          # an INNER JOIN selecting from the entity table and then
          # selecting every possible pivot value as a UNION, throwing out
          # the duplicates.
          pivot = pivot_name.constantize
          join_path = instruction["join_path"]
          joins = join_path.reverse.map(&:to_sym).inject { |acc, elt| { elt => acc } }

          columns = [
            %Q|#{qualified_primary_key(pivot)} AS "primary_key"|,
            %Q|#{qualified_column(pivot, instruction["pivot_attribute_name"])} AS "pivot_attribute_name"|,
          ]

          join_select = entity
                        .joins(joins)
                        .group(qualified_primary_key(pivot))
                        .select(*columns, 'COUNT(*) AS "count"')
                        .to_sql

          instance_select = pivot
                            .select(*columns, '0 AS "count"')
                            .to_sql

          union_sql = <<~"SQL"
                        SELECT "pivot_values"."primary_key", "pivot_values"."pivot_attribute_name", MAX("pivot_values"."count") AS "count"
                          FROM (#{join_select} UNION ALL #{instance_select}) AS "pivot_values"
                          GROUP BY "pivot_values"."primary_key", "pivot_values"."pivot_attribute_name"
                      SQL
        else
          entity.select("COUNT(*)").to_sql
        end

      { metric_configuration_id: instruction["metric_configuration_id"], result: connection.execute(query).to_a }
    end
  end
end