Class: Smriti::MatViewDefinition

Inherits:
ApplicationRecord show all
Defined in:
app/models/smriti/mat_view_definition.rb

Overview

Represents a materialised view definition managed by the engine.

A definition stores the canonical name and SQL for a materialised view and drives lifecycle operations (create, refresh, delete) via background jobs and services. It also tracks operational history through associated run models.

Validations ensure a sane PostgreSQL identifier for name and that sql begins with SELECT (case-insensitive).

Examples:

Creating a definition

defn = Smriti::MatViewDefinition.create!(
  name: "mv_user_accounts",
  sql:  "SELECT users.id, accounts.id AS account_id FROM users JOIN accounts ON ..."
)

Enqueue a refresh

Smriti::RefreshViewJob.perform_later(defn.id, :estimated)

See Also:

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from SmritiPaginate

paginate

Methods included from SmritiI18n

hint_for, human_enum_name, human_enum_options, human_name, placeholder_for

Instance Attribute Details

#nameObject

validates :name that must be present, unique, and a valid identifier.



64
65
66
67
# File 'app/models/smriti/mat_view_definition.rb', line 64

validates :name,
presence: true,
uniqueness: true,
format: { with: /\A[a-zA-Z_][a-zA-Z0-9_]*\z/ }

#refresh_strategyString

Returns one of "regular", "concurrent", "swap".

Returns:

  • (String)

    one of "regular", "concurrent", "swap"



97
# File 'app/models/smriti/mat_view_definition.rb', line 97

enum :refresh_strategy, { regular: 0, concurrent: 1, swap: 2 }

#sqlObject

validates :sql that must be present and begin with SELECT.



72
73
74
# File 'app/models/smriti/mat_view_definition.rb', line 72

validates :sql,
presence: true,
format: { with: /\A\s*SELECT/i, message: :invalid }

#unique_index_columnsObject

validates :unique_index_columns to be non-empty when using refresh_strategy=concurrent.



79
80
81
# File 'app/models/smriti/mat_view_definition.rb', line 79

validates :unique_index_columns,
length: { minimum: 1, message: :at_least_one },
if: -> { refresh_strategy == 'concurrent' }

Class Method Details

.filter_options_for_nameArray<Array(String, String)>

Returns options for filters in admin UI datatable.

Returns:

  • (Array<Array(String, String)>)

    array of [label, value] pairs



219
220
221
# File 'app/models/smriti/mat_view_definition.rb', line 219

def filter_options_for_name
  order(:name).distinct.pluck(:name).map { |name| [name, name] }
end

.filter_options_for_refresh_strategyArray<Array(String, String)>

Returns options for filters in admin UI datatable.

Returns:

  • (Array<Array(String, String)>)

    array of [label, value] pairs



227
228
229
# File 'app/models/smriti/mat_view_definition.rb', line 227

def filter_options_for_refresh_strategy
  order(:refresh_strategy).distinct.pluck(:refresh_strategy).compact.map { |rs| [human_enum_name(:refresh_strategy, rs), rs] }
end

.filter_options_for_schedule_cronArray<Array(String, String)>

Returns options for filters in admin UI datatable.

Returns:

  • (Array<Array(String, String)>)

    array of [label, value] pairs



235
236
237
# File 'app/models/smriti/mat_view_definition.rb', line 235

def filter_options_for_schedule_cron
  order(:schedule_cron).distinct.pluck(:schedule_cron).compact.map { |sc| [sc, sc.tr(' ', '_')] }
end

Instance Method Details

#filtered_by_nameActiveRecord::Relation<Smriti::MatViewDefinition>

Scope filtered by name Filters by exact match on the name attribute.

Parameters:

  • name (String)

    filter value

Returns:



188
# File 'app/models/smriti/mat_view_definition.rb', line 188

scope :filtered_by_name, ->(name) { where(name:) }

#filtered_by_refresh_strategyActiveRecord::Relation<Smriti::MatViewDefinition>

Scope filtered by refresh_strategy Filters by exact match on the refresh_strategy attribute.

Parameters:

  • refresh_strategy (String)

    filter value, one of "regular", "concurrent", "swap"

Returns:



195
# File 'app/models/smriti/mat_view_definition.rb', line 195

scope :filtered_by_refresh_strategy, ->(refresh_strategy) { where(refresh_strategy:) }

#filtered_by_schedule_cronActiveRecord::Relation<Smriti::MatViewDefinition>

Scope filtered by schedule_cron Filters by exact match on the schedule_cron attribute, or NULL/empty.

Parameters:

  • schedule_cron (String)

    filter value, or "no_value" to match NULL/empty

Returns:



202
203
204
205
206
207
208
# File 'app/models/smriti/mat_view_definition.rb', line 202

scope :filtered_by_schedule_cron, lambda { |schedule_cron|
  if schedule_cron == 'no_value'
    where(schedule_cron: nil).or(where(schedule_cron: ''))
  else
    where('schedule_cron ILIKE ?', "%#{schedule_cron.tr('_', ' ')}%")
  end
}

#last_runSmriti::MatViewRun?

Returns the most recent run associated with this definition.

Returns:



250
251
252
# File 'app/models/smriti/mat_view_definition.rb', line 250

def last_run
  mat_view_runs.order(created_at: :desc).first
end

#mat_view_runsActiveRecord::Relation<Smriti::MatViewRun>

Historical create runs linked to this definition.

Returns:



53
54
55
# File 'app/models/smriti/mat_view_definition.rb', line 53

has_many :mat_view_runs,
dependent: :destroy,
class_name: 'Smriti::MatViewRun'

#ordered_by_last_run_atActiveRecord::Relation<Smriti::MatViewDefinition>

Scope ordered by last_run_at Orders by the timestamp of the most recent associated run's started_at, NULLs last.

Parameters:

  • dir (Symbol, String)

    :asc or :desc

Returns:



131
132
133
134
135
136
137
138
139
140
141
# File 'app/models/smriti/mat_view_definition.rb', line 131

scope :ordered_by_last_run_at, lambda { |dir|
  dir = dir.to_s.casecmp('asc').zero? ? 'ASC' : 'DESC'

  order(Arel.sql(<<~SQL.squish))
    (
      SELECT MAX(r.created_at)
      FROM mat_view_runs r
      WHERE r.mat_view_definition_id = mat_view_definitions.id
    ) #{dir} NULLS LAST
  SQL
}

#ordered_by_nameActiveRecord::Relation<Smriti::MatViewDefinition>

Scope ordered by name Orders by the name attribute.

Parameters:

  • dir (Symbol, String)

    :asc or :desc

Returns:



109
# File 'app/models/smriti/mat_view_definition.rb', line 109

scope :ordered_by_name, ->(dir) { order("name #{dir.to_s.upcase}") }

#ordered_by_refresh_strategyActiveRecord::Relation<Smriti::MatViewDefinition>

Scope ordered by refresh_strategy Orders by the refresh_strategy attribute, using humanized enum labels.

Parameters:

  • dir (Symbol, String)

    :asc or :desc

Returns:



117
# File 'app/models/smriti/mat_view_definition.rb', line 117

scope :ordered_by_refresh_strategy, ->(dir) { ordered_by_enum(enum_values: refresh_strategies, enum_name: :refresh_strategy, direction: dir) }

#ordered_by_schedule_cronActiveRecord::Relation<Smriti::MatViewDefinition>

Scope ordered by schedule_cron Orders by the schedule_cron attribute, NULLs last.

Parameters:

  • dir (Symbol, String)

    :asc or :desc

Returns:



124
# File 'app/models/smriti/mat_view_definition.rb', line 124

scope :ordered_by_schedule_cron, ->(dir) { order("schedule_cron #{dir.to_s.upcase} NULLS LAST") }

#search_by_last_run_atActiveRecord::Relation<Smriti::MatViewDefinition>

Scope search by last_run_at Searches the timestamp of the most recent associated run's started_at using ILIKE

Parameters:

  • term (String)

    search term

Returns:



169
170
171
172
173
174
175
176
177
178
179
180
181
# File 'app/models/smriti/mat_view_definition.rb', line 169

scope :search_by_last_run_at, lambda { |term|
  where(<<~SQL, like: "%#{term}%")
    EXISTS (
      SELECT 1
      FROM (
        SELECT MAX(r.started_at) AS last_run_at
        FROM mat_view_runs r
        WHERE r.mat_view_definition_id = mat_view_definitions.id
      ) m
      WHERE CAST(m.last_run_at AS TEXT) ILIKE :like
    )
  SQL
}

#search_by_nameActiveRecord::Relation<Smriti::MatViewDefinition>

Scope search by name Searches the name attribute using ILIKE.

Parameters:

  • term (String)

    search term

Returns:



148
# File 'app/models/smriti/mat_view_definition.rb', line 148

scope :search_by_name, ->(term) { where('name ILIKE ?', "%#{term}%") }

#search_by_refresh_strategyActiveRecord::Relation<Smriti::MatViewDefinition>

Scope search by refresh_strategy Searches the refresh_strategy attribute using humanized enum labels.

Parameters:

  • term (String)

    search term

Returns:



155
# File 'app/models/smriti/mat_view_definition.rb', line 155

scope :search_by_refresh_strategy, ->(term) { search_by_enum(enum_values: refresh_strategies, enum_name: :refresh_strategy, term: term) }

#search_by_schedule_cronActiveRecord::Relation<Smriti::MatViewDefinition>

Scope search by schedule_cron Searches the schedule_cron attribute using ILIKE.

Parameters:

  • term (String)

    search term

Returns:



162
# File 'app/models/smriti/mat_view_definition.rb', line 162

scope :search_by_schedule_cron, ->(term) { where('schedule_cron ILIKE ?', "%#{term}%") }