smriti (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 smriti
bin/rails g smriti:install
bin/rails db:migrate
# config/initializers/smriti.rb
Smriti.configure do |c|
  c.job_queue = :default
end

Define a view

defn = Smriti::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
Smriti::Services::CreateView.new(defn, force: true).call
Smriti::CreateViewJob.perform_later(defn.id, force: true)

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

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

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


Enqueue adapter

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

Rake tasks

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

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

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

Rails version matrix

Use the pinned Gemfiles in gemfiles/ to exercise the engine against specific Rails releases:

# Rails 7.2.x
bundle install --gemfile gemfiles/rails_7_2.gemfile
BUNDLE_GEMFILE=gemfiles/rails_7_2.gemfile bundle exec bin/rspec-unit
BUNDLE_GEMFILE=gemfiles/rails_7_2.gemfile bundle exec bin/rspec-e2e

# Rails 8.0.x
bundle install --gemfile gemfiles/rails_8_0.gemfile
BUNDLE_GEMFILE=gemfiles/rails_8_0.gemfile bundle exec bin/rspec-unit
BUNDLE_GEMFILE=gemfiles/rails_8_0.gemfile bundle exec bin/rspec-e2e

# Rails 8.1.x
bundle install --gemfile gemfiles/rails_8_1.gemfile
BUNDLE_GEMFILE=gemfiles/rails_8_1.gemfile bundle exec bin/rspec-unit
BUNDLE_GEMFILE=gemfiles/rails_8_1.gemfile bundle exec bin/rspec-e2e

# Rails main branch
bundle install --gemfile gemfiles/rails_edge.gemfile
BUNDLE_GEMFILE=gemfiles/rails_edge.gemfile bundle exec bin/rspec-unit
BUNDLE_GEMFILE=gemfiles/rails_edge.gemfile bundle exec bin/rspec-e2e

The CI workflow consumes the same Gemfiles to run the unit suite across the compatibility matrix.


Screenshots

The end-to-end tests generate screenshots for visual verification. They are uploaded as artifacts in the GitHub Actions workflow runs. After creating a pull request, apply the e2e-screenshots label to trigger screenshot generation.

You can trigger screenshot in your local setup as well:

# 'en' is the desired locale
SCREENSHOT_LANG=en bin/rspec-app-screenshot

# OR

# runs for all configured locales (this may take long time)
bin/rspec-app-screenshots

Docs & policies