Moose Stack

Moose OLAP

Applying Migrations

Applying Migrations

Viewing:

Overview

Moose automatically manages database migrations by comparing your code with your database schema. Migrations are applied automatically when:

  • Development: Changes are detected during moose dev
  • Production: Changes are applied during deployment

When Migrations Happen

Migration Triggers

Adding new columns

New fields in your TypeScript interfaces or Python models

Removing columns

Deleted fields from your data models

Changing column types

Modified data types (e.g., string to number)

Adding new tables

New OlapTable instances in your code

Adding materialized views

New MaterializedView instances in your code

Development Workflow

Starting the Runtime

Use moose dev to start the Moose runtime with automatic migration detection:

moose dev
 
 Starting local infrastructure
  Successfully started containers
     Validated clickhousedb-1 docker container
     Validated redpanda-1 docker container
  Successfully validated red panda cluster
     Validated temporal docker container
  Successfully ran local infrastructure

Automatic Migration Detection

Moose continuously monitors your code changes and applies migrations automatically. All changes are applied to your local database only.

app/tables/events.ts
interface Event {
  id: Key<string>;
  name: string;
  createdAt: Date;
  status: string; // New field - will trigger migration
}
 
export const events = new OlapTable<Event>("events")

Migration Logs

When you save changes, you’ll see detailed migration logs showing what’s being applied:

 Processing Infrastructure changes from file watcher
             ~ Topic: events - Version: 0.0 - Retention Period: 604800s - Partition Count: 1
             ~ Table events with column changes: [Added(Column { name: "status", data_type: String, required: true, unique: false, primary_key: false, default: None })] and order by changes: OrderByChange { before: [], after: [] }
             ~ Topic to Table Sync Process: events_0_0 -> events
             ~ API Endpoint: events - Version: 0.0 - Path: ingest/events - Method: POST - Format: Some(Json)

MooseTip:

Migration Safety: In development, migrations are applied immediately. In production, migrations are applied during deployment with additional safety checks.

Production Workflow

Deployment Process

When you deploy your code to production, Moose follows this migration process:

  1. Schema Comparison: Moose compares the final code in your repository with the state of your production database schema
  2. Migration Plan: A migration plan is generated showing what changes will be applied
  3. Manual Review: Before applying migrations, you will be prompted to review the plan and confirm the changes. You can make changes to the plan before applying it.
  4. Application: Changes are applied to the production database during deployment

Migration Types

Adding New Tables or Materialized Views

index.ts
import { newTable, newMaterializedView } from "./path/to/your/newObjects"
 
// Export the new table and materialized view to apply changes
export {
  newTable, // New table
  newMaterializedView // New materialized view
}

Column Additions

Adding new fields to your data models:

Before
interface AddedColumn {
  id: Key<string>;
  another_column: string;
  some_column: string;
}
After
interface AddedColumn {
  id: Key<string>;
  another_column: string;
  some_column: string;
  new_column: number; // New field - migration applied
}

Column Removals

Removing fields from your data models:

Before
interface RemovedColumn {
  id: Key<string>;
  another_column: string;
  some_column: string;
  old_column: number;
}
After
interface RemovedColumn {
  id: Key<string>;
  another_column: string;
  some_column: string;
  // old_column field removed - migration applied
}

Type Changes

Changing data types (use with caution):

Before
interface ChangedType {
  id: Key<string>;
  some_column: string; // String type - migration applied
}
After
interface ChangedType {
  id: Key<string>;
  some_column: number; // Number type - migration applied
}

Materialized View Changes

Modifying the SELECT statement of a materialized view:

Before.ts
export const userStats = new MaterializedView<UserStats>("user_stats", {
  selectStatement: `
    SELECT 
      userId,
      COUNT(*) as event_count,
      MAX(createdAt) as last_event
    FROM users
    GROUP BY userId
  `
  // other MV config properties...
});
After.ts
export const userStats = new MaterializedView<UserStats>("user_stats", {
  selectStatement: `
    SELECT 
      userId,
      COUNT(*) as event_count,
      MAX(createdAt) as last_event,
      AVG(value) as avg_value  // New column added
    FROM users
    GROUP BY userId
  `
  // other MV config properties...
});

When you modify a materialized view’s SELECT statement, Moose will:

  1. Detect the change in your code
  2. Drop the existing view in the database
  3. Recreate the view with the new SELECT statement
  4. Repopulate the data using the new query

Warning:

Materialized View Migration: Changing a materialized view’s SELECT statement will recreate the entire view and repopulate all data. This can be time-consuming for large datasets.

Migration Best Practices

Migration Guidelines

Test migrations locally first

Always test schema changes in development before deploying

Use additive changes when possible

Adding columns is safer than removing or changing existing ones

Review migration logs

Check the migration output to ensure changes are applied correctly

Backup before major changes

Create database backups before significant schema changes

Deploy during low-traffic periods

Schedule migrations during periods of low database activity

Troubleshooting Migrations

Common Issues

Migration Issues

  • Migration conflicts: Restart moose dev to resolve schema conflicts
  • Type mismatches: Ensure data types are compatible with existing data
  • Missing exports: Verify all tables are exported from your main file
  • Network issues: Check database connectivity if migrations fail