As of writing, no UI is provided; all operations are via service objects, background jobs, and rake tasks.

Define a materialized view

Definition is managed via the MatViews::MatViewDefinition model. You can create definitions in Rails console, seeds, or migrations.

# create a new definition
definition = MatViews::MatViewDefinition.create!(
  name: 'my_mat_view',
  sql: <<-SQL.squish,
    SELECT id, name, created_at
    FROM users
    WHERE active = true
  SQL
  refresh_strategy: :concurrent, # :regular (default), :concurrent (needs unique index), :swap
  unique_index_columns: ['id'],  # required for :concurrent and :swap strategies
  dependencies: []                # optional, array of other MatViewDefinition names
)

Create the materialized view

You can create the materialized view directly via the service object or enqueue a background job or use the Rake tasks.

Direct service call

Use this for logic that needs direct control, or for scripts/migrations where background jobs aren’t suitable.

# Direct service call
result = MatViews::Services::CreateView.call(definition.id, force: true)
if result.success?
  puts "Materialized view created successfully."
else
  puts "Error creating materialized view: #{result.error_message}"
end

Enqueue background job

Use this in application code where you want to offload the creation to a background job.

# Enqueue background job
MatViews::Jobs::Adapter.enqueue(
  MatViews::CreateViewJob,
  queue: MatViews.configuration.job_queue,
  args:  [definition.id, true] # force: true
)

Use Rake task

You can also use the provided Rake tasks to create materialized views by name, id, or all at once.

  • All tasks require confirmation unless you pass the --yes flag.
  • force flag will drop existing views before creating.
  • All tasks enqueue background jobs, using Job adapter and queue from configuration.
# Create by name
bundle exec rake mat_views:create_by_name\[my_mat_view,force,--yes]
# Create by id
bundle exec rake mat_views:create_by_id\[1,force,--yes]
# Create all
bundle exec rake mat_views:create_all\[force,--yes]

Refresh the materialized view

You can refresh the materialized view directly via the service object or enqueue a background job or use the Rake tasks.

Direct service call

Use this for logic that needs direct control, or for scripts/migrations where background jobs aren’t suitable. It supports two strategies: :estimated (default) and :full.

:estimated uses PostgreSQL’s query planner to estimate the number of rows to refresh, which is faster for large datasets. :full perform proper count of rows, which is more accurate but slower. In most cases, :estimated is sufficient.

# Direct service call
result = MatViews::Services::RefreshView.call(definition.id, :estimated)
if result.success?
  puts "Materialized view refreshed successfully."
else
  puts "Error refreshing materialized view: #{result.error_message}"
end

Enqueue background job

Use this in application code where you want to offload the refresh to a background job. It supports two strategies: :estimated (default) and :full.

# Enqueue background job
MatViews::Jobs::Adapter.enqueue(
  MatViews::RefreshViewJob,
  queue: MatViews.configuration.job_queue,
  args:  [definition.id, :estimated] # or :full
)

Use Rake task

You can also use the provided Rake tasks to refresh materialized views by name, id, or all at once.

  • All tasks require confirmation unless you pass the --yes flag.
  • row_count_strategy can be :estimated (default) or :full.
  • All tasks enqueue background jobs, using Job adapter and queue from configuration.
# Refresh by name
bundle exec rake mat_views:refresh_by_name\[my_mat_view,estimated,--yes]
# Refresh by id
bundle exec rake mat_views:refresh_by_id\[1,full,--yes]
# Refresh all
bundle exec rake mat_views:refresh_all\[estimated,--yes]

Delete the materialized view

You can delete the materialized view directly via the service object or enqueue a background job or use the Rake tasks.

  • cascade flag will also delete dependent views.
  • Deleting a view does not delete its definition; you can recreate it later.
  • All tasks enqueue background jobs, using Job adapter and queue from configuration.

Direct service call

Use this for logic that needs direct control, or for scripts/migrations where background jobs aren’t suitable.

# Direct service call
result = MatViews::Services::DeleteView.call(definition.id, cascade: true)
if result.success?
  puts "Materialized view deleted successfully."
else
  puts "Error deleting materialized view: #{result.error_message}"
end

Enqueue background job

Use this in application code where you want to offload the deletion to a background job.

# Enqueue background job
MatViews::Jobs::Adapter.enqueue(
  MatViews::DeleteViewJob,
  queue: MatViews.configuration.job_queue,
  args:  [definition.id, true] # cascade: true
)

Use Rake task

You can also use the provided Rake tasks to delete materialized views by name, id, or all at once.

  • All tasks require confirmation unless you pass the --yes flag.
  • cascade flag will also delete dependent views.
  • All tasks enqueue background jobs, using Job adapter and queue from configuration.
# Delete by name
bundle exec rake mat_views:delete_by_name\[my_mat_view,cascade,--yes]
# Delete by id
bundle exec rake mat_views:delete_by_id\[1,cascade,--yes]
# Delete all
bundle exec rake mat_views:delete_all\[cascade,--yes]