mat_views (engine)

Gem CI License

Rails engine that manages PostgreSQL materialized views with definitions, services, background jobs, and Rake tasks.


Quickstart (diagram)

flowchart LR
  A[Define MatViewDefinition] --> B[Create]
  B --> C[Unique Index for CONCURRENT]
  C --> D[Refresh: regular or concurrent or swap]
  D --> E[Read MV]
  D --> F[Track runs]

Install

bundle add mat_views
bin/rails g mat_views:install
bin/rails db:migrate
# config/initializers/mat_views.rb
MatViews.configure do |c|
  c.job_queue = :default
end

Define a view

defn = MatViews::MatViewDefinition.create!(
  name: 'mv_user_activity',
  sql: <<~SQL,
    SELECT u.id AS user_id,
           COUNT(a.*) AS accounts_count,
           COUNT(e.*) AS events_count,
           COUNT(s.*) AS sessions_count
    FROM users u
    LEFT JOIN accounts a ON a.user_id = u.id
    LEFT JOIN events   e ON e.user_id = u.id
    LEFT JOIN sessions s ON s.user_id = u.id
    GROUP BY u.id
  SQL
  refresh_strategy: :concurrent,
  unique_index_columns: ['user_id']
)

Services & Jobs

# Create
MatViews::Services::CreateView.new(defn, force: true).call
MatViews::CreateViewJob.perform_later(defn.id, force: true)

# Refresh
MatViews::Services::RegularRefresh.new(defn, row_count_strategy: :estimated).call
MatViews::RefreshViewJob.perform_later(defn.id, row_count_strategy: :exact)

# Delete
MatViews::Services::DeleteView.new(defn, cascade: false, if_exists: true).call
MatViews::DeleteViewJob.perform_later(defn.id, cascade: true)

Uniform response: status, meta, success? / error?.


Enqueue adapter

MatViews::Jobs::Adapter.enqueue(job_class, queue: :default, args: [...])
  • Uses your configured backend; no guessing.
  • Supports ActiveJob, Sidekiq, Resque.

Rake tasks

# Create
bundle exec rake mat_views:create_by_name\[VIEW_NAME,force,row_count_strategy,--yes]
bundle exec rake mat_views:create_by_id\[ID,force,row_count_strategy,--yes]
bundle exec rake mat_views:create_all\[force,row_count_strategy,--yes]

# Refresh
bundle exec rake mat_views:refresh_by_name\[VIEW_NAME,row_count_strategy,--yes]
bundle exec rake mat_views:refresh_by_id\[ID,row_count_strategy,--yes]
bundle exec rake mat_views:refresh_all\[row_count_strategy,--yes]

# Delete
bundle exec rake mat_views:delete_by_name\[VIEW_NAME,cascade,row_count_strategy,--yes]
bundle exec rake mat_views:delete_by_id\[ID,cascade,row_count_strategy,--yes]
bundle exec rake mat_views:delete_all\[cascade,row_count_strategy,--yes]

Docs & policies