Class: Skadi::Schema

Inherits:
Object
  • Object
show all
Defined in:
app/models/skadi/schema.rb

Constant Summary collapse

ALLOWED_FRONTEND_DATASET_KEYS =
[ :fields, :belongs_to, :counts ].freeze

Class Method Summary collapse

Class Method Details

.database_schemaObject

A hash where the key represents a dataset name and the value is its configuration



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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
61
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
99
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# File 'app/models/skadi/schema.rb', line 9

def database_schema
  return @_database_schema if defined?(@_database_schema)

  @_database_schema ||= {
    # A hash with the following keys:
    # model: The model for this dataset
    # counts: A hash describing how this table can be counted, e.g. visitors: { sql: "COUNT(DISTINCT skadi_visits.tracking_token)" }
    #         If the name of the count matches the table, the specified count overwrites the default of `COUNT(*)`
    # belongs_to: A hash describing belongs_to relationships, e.g. {visits: {key: :visit_id}}
    # fields: A hash where the key represents a field and the value is its configuration
    visits: {
      model: Skadi::Visit,
      counts: {
        visitors: { sql: "COUNT(DISTINCT skadi_visits.tracking_token)" },
      },
      # If the table has a date field, the fields Hash expects a value for :date
      fields: {
        # A hash with the following keys:
        # label: The label to show in the front end
        # type: The datatype, one of :one_of, :date, :string, :number, :boolean. Defaults to :string.
        # select: True if this field can be selected by the table chart
        # filter: True if this field can be filtered
        # split: True if this field can be split
        # sql: The SQL expression used to get this value for derived fields
        # options: A list of possible values
        # description: used in the front end as help text for this field
        id: {
          select: true,
        },
        date: {
          type: :date,
          select: true,
          filter: true,
          sql: "skadi_visits.created_at",
        },
        verified: {
          **SELECT_FILTER_AND_SPLIT,
          type: :boolean,
        },
        tracked: {
          **SELECT_FILTER_AND_SPLIT,
          type: :boolean,
          sql: "(skadi_visits.tracking_token IS NOT NULL)",
          description: "Whether the visit is tracked across multiple views and events using a cookie or anonymity set.",
        },
        cookies_enabled: {
          **SELECT_FILTER_AND_SPLIT,
          type: :boolean,
          description: "Whether this visit is tracked across multiple days using cookies.",
        },
        landing_page: SELECT_FILTER_AND_SPLIT,
        referrer_domain: {
          **SELECT_FILTER_AND_SPLIT,
          sql: Helpers::Sql.string_before_separator(Skadi::Visit, "referrer", "/"),
        },
        utm_source: SELECT_FILTER_AND_SPLIT,
        utm_medium: SELECT_FILTER_AND_SPLIT,
        utm_term: SELECT_FILTER_AND_SPLIT,
        utm_content: SELECT_FILTER_AND_SPLIT,
        utm_campaign: SELECT_FILTER_AND_SPLIT,
      },
    },
    views: {
      model: Skadi::View,
      belongs_to: { visits: { key: :visit_id } },
      fields: {
        id: {
          select: true,
        },
        date: {
          type: :date,
          select: true,
          filter: true,
          sql: "skadi_views.created_at",
        },
        verified: {
          **SELECT_FILTER_AND_SPLIT,
          type: :boolean,
        },
        controller: SELECT_FILTER_AND_SPLIT,
        action: {
          select: true,
          filter: true,
        },
        controller_and_action: {
          split: true,
          sql: "CONCAT(skadi_views.controller, '::', skadi_views.action)",
        },
        path: SELECT_FILTER_AND_SPLIT,
        verb: {
          **SELECT_FILTER_AND_SPLIT,
          type: :one_of,
          description: "Typically, GET requests are page views, and POST, PUT, PATCH and DELETE are form submissions.",
          options: %w[GET POST PUT PATCH DELETE],
        },
        version: SELECT_FILTER_AND_SPLIT,
        exit_page: SELECT_FILTER_AND_SPLIT,
      },
    },
    events: {
      model: Skadi::Event,
      belongs_to: { visits: { key: :visit_id }, views: { key: :view_id } },
      fields: {
        id: {
          select: true,
        },
        date: {
          type: :date,
          select: true,
          filter: true,
          sql: "skadi_events.created_at",
        },
        name: SELECT_FILTER_AND_SPLIT,
        **(Skadi.configuration.dashboard_custom_event_fields || {}),
      },
    },
    demographics: {
      model: Demographic,
      counts: {
        demographics: { label: "Count", sql: "COALESCE(SUM(skadi_demographics.count), 0)" },
      },
      fields: {
        date: {
          type: :date,
          select: true,
          filter: true,
          sql: "skadi_demographics.recorded_on",
        },
        uri: SELECT_FILTER_AND_SPLIT,
        name: SELECT_FILTER_AND_SPLIT,
        value: SELECT_FILTER_AND_SPLIT,
        count: {
          **SELECT_FILTER_AND_SPLIT,
          type: :number,
        },
      },
    },
    **(Skadi.configuration.dashboard_custom_schema || {}),
  }
end

.frontend_schemaObject



152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
# File 'app/models/skadi/schema.rb', line 152

def frontend_schema
  return @_frontend_schema if defined?(@_frontend_schema)

  # Redact the SQL from the dashboard schema
  schema = database_schema.deep_dup
  schema.each_value do |dataset|
    dataset[:belongs_to] = dataset[:belongs_to].keys if dataset.key?(:belongs_to)

    dataset.keys.each do |key|
      dataset.delete(key) unless ALLOWED_FRONTEND_DATASET_KEYS.include?(key)
    end

    dataset[:counts]&.each_value { |field| field.delete(:sql) }
    dataset[:fields].each_value { |field| field.delete(:sql) }
  end

  @_frontend_schema = schema
end