Back to catalog

database-migration-helper

Manage SQLite database schema migrations, generate migration scripts, and maintain data integrity during schema changes

  • Category: discovered
  • Tags: github, community
  • Version: 1.0.0
  • Author: walid
  • Downloads: 0
  • Updated: 2025-11-22

Download the latest version (v1.0.0) from this page.

SKILL.md

---
description: Manage SQLite database schema migrations, generate migration scripts, and maintain data integrity during schema changes
---

# Database Migration Helper

Manage SQLite database schema migrations, generate migration scripts, and maintain data integrity during schema changes.

## Capabilities

1. **Schema Analysis**
   - Analyze current SQLite schema from code (TableRepresentable types)
   - Detect schema changes between versions
   - Compare database file schema vs code definitions
   - Identify missing tables, columns, or indexes

2. **Migration Generation**
   - Auto-generate migration SQL for schema changes
   - Create versioned migration files
   - Generate rollback scripts
   - Support for complex migrations (data transformations)

3. **Migration Execution**
   - Apply migrations safely with transactions
   - Verify migration success
   - Handle migration failures and rollbacks
   - Track applied migrations

4. **Data Preservation**
   - Generate data migration scripts for schema changes
   - Create backup strategies
   - Transform data during migrations
   - Validate data after migration

5. **Model Code Generation**
   - Generate Swift TableRepresentable types from existing database
   - Update existing models when schema changes
   - Create test fixtures from database data
   - Generate documentation for database schema

## Workflow

When invoked, this skill will:

1. **Analyze**: Scan TableRepresentable types and database files
2. **Compare**: Detect differences between code and database
3. **Plan**: Generate migration strategy
4. **Execute**: Apply migrations safely
5. **Verify**: Confirm schema and data integrity

## Usage Instructions

When the user invokes this skill:

1. Identify the task:
   - Create new migration
   - Apply pending migrations
   - Generate models from database
   - Analyze schema differences
   - Rollback migrations

2. For **creating migrations**:
   - Analyze current TableRepresentable types
   - Compare with previous version (git history)
   - Generate migration SQL
   - Create migration file with version number
   - Generate rollback script

3. For **applying migrations**:
   - Check migration history table
   - Identify unapplied migrations
   - Apply in order within transactions
   - Update migration history
   - Verify schema matches code

4. For **model generation**:
   - Read SQLite schema from database file
   - Generate Swift structs conforming to TableRepresentable
   - Include proper CodingKeys
   - Add convenience methods

## Project-Specific Integration

### Your CodableSQLiteNonThread Framework

Based on your project structure:

```swift
// Example TableRepresentable type from your project
struct Layer: TableRepresentable {
    static var tableName: String { "Layer" }
    static var primaryKey: String? { "id" }

    let id: UUID
    let name: String
    let layerType: Int
    // ... other properties
}
```

The skill understands:
- `TableRepresentable` protocol requirements
- `QueryProtocol` for SQL generation
- `Bindable` types for parameter binding
- SQLiteInterface for database operations

## Migration File Format

### Migration Naming Convention
```
YYYYMMDD_HHMM_description.sql
```

Example: `20250125_1430_add_datasets_table.sql`

### Migration File Structure
```sql
-- Migration: Add datasets table
-- Version: 20250125_1430
-- Description: Creates the datasets table with foreign key to layers

BEGIN TRANSACTION;

-- Up Migration
CREATE TABLE IF NOT EXISTS DataSet (
    id TEXT PRIMARY KEY,
    layerId TEXT NOT NULL,
    name TEXT NOT NULL,
    dataType INTEGER NOT NULL,
    createdAt REAL NOT NULL,
    FOREIGN KEY (layerId) REFERENCES Layer(id) ON DELETE CASCADE
);

CREATE INDEX idx_dataset_layer ON DataSet(layerId);

-- Record migration
INSERT INTO schema_migrations (version, applied_at)
VALUES ('20250125_1430', datetime('now'));

COMMIT;

-- Down Migration (for rollback)
-- BEGIN TRANSACTION;
-- DROP TABLE IF EXISTS DataSet;
-- DELETE FROM schema_migrations WHERE version = '20250125_1430';
-- COMMIT;
```

## Common Migration Scenarios

### 1. Adding a Column
```sql
-- Add optional column (safe)
ALTER TABLE Layer ADD COLUMN color TEXT;

-- Add non-null column (requires default or data migration)
ALTER TABLE Layer ADD COLUMN orderIndex INTEGER NOT NULL DEFAULT 0;
```

### 2. Renaming a Column
SQLite doesn't support RENAME COLUMN directly (before 3.25.0), so we use table recreation:

```sql
-- Create new table with correct schema
CREATE TABLE Layer_new (
    id TEXT PRIMARY KEY,
    name TEXT NOT NULL,
    displayName TEXT NOT NULL, -- renamed from 'title'
    layerType INTEGER NOT NULL
);

-- Copy data
INSERT INTO Layer_new (id, name, displayName, layerType)
SELECT id, name, title, layerType FROM Layer;

-- Drop old table and rename new one
DROP TABLE Layer;
ALTER TABLE Layer_new RENAME TO Layer;
```

### 3. Adding Foreign Key Constraints
```sql
-- Create new table with FK
CREATE TABLE DataSet_new (
    id TEXT PRIMARY KEY,
    layerId TEXT NOT NULL,
    name TEXT NOT NULL,
    FOREIGN KEY (layerId) REFERENCES Layer(id) ON DELETE CASCADE
);

-- Copy data
INSERT INTO DataSet_new SELECT * FROM DataSet;

-- Swap tables
DROP TABLE DataSet;
ALTER TABLE DataSet_new RENAME TO DataSet;

-- Enable FK enforcement
PRAGMA foreign_keys = ON;
```

### 4. Data Transformation Migration
```sql
-- Example: Migrate color from Int to hex string
BEGIN TRANSACTION;

ALTER TABLE Layer ADD COLUMN colorHex TEXT;

UPDATE Layer SET colorHex =
    CASE
        WHEN colorInt = 0 THEN '#FF0000'
        WHEN colorInt = 1 THEN '#00FF00'
        WHEN colorInt = 2 THEN '#0000FF'
        ELSE '#000000'
    END;

-- After verification, can drop old column via table recreation

COMMIT;
```

## Swift Model Update Workflow

When schema changes:

1. **Update TableRepresentable Model**
```swift
struct Layer: TableRepresentable {
    static var tableName: String { "Layer" }
    static var primaryKey: String? { "id" }

    let id: UUID
    let name: String
    let displayName: String // Changed from 'title'
    let layerType: Int
    let colorHex: String? // New optional column

    enum CodingKeys: String, CodingKey {
        case id
        case name
        case displayName
        case layerType
        case colorHex
    }
}
```

2. **Generate Migration SQL**
3. **Update Tests** to use new schema
4. **Verify** with integration tests

## Migration Tracking

### Schema Migrations Table
```sql
CREATE TABLE IF NOT EXISTS schema_migrations (
    version TEXT PRIMARY KEY,
    applied_at TEXT NOT NULL,
    description TEXT
);
```

### Migration Manager (Swift)
```swift
struct MigrationManager {
    let db: SQLiteInterface

    func pendingMigrations() throws -> [Migration] {
        // Read migration files
        // Query schema_migrations table
        // Return unapplied migrations
    }

    func applyMigration(_ migration: Migration) throws {
        try db.execute("""
            BEGIN TRANSACTION;
            \(migration.sql)
            INSERT INTO schema_migrations (version, applied_at, description)
            VALUES (?, datetime('now'), ?);
            COMMIT;
        """, bindings: [migration.version, migration.description])
    }

    func rollback(to version: String) throws {
        // Apply down migrations in reverse order
    }
}
```

## Schema Inspection Queries

### List All Tables
```sql
SELECT name FROM sqlite_master
WHERE type='table'
ORDER BY name;
```

### Get Table Schema
```sql
PRAGMA table_info(Layer);
```

### Get Foreign Keys
```sql
PRAGMA foreign_key_list(DataSet);
```

### Get Indexes
```sql
PRAGMA index_list(Layer);
```

## Best Practices

1. **Always Use Transactions**
   - Wrap migrations in BEGIN/COMMIT
   - Automatic rollback on failure

2. **Versioned Migrations**
   - Never modify applied migrations
   - Create new migration for changes
   - Keep migrations in version control

3. **Data Safety**
   - Test migrations on copy of production data
   - Generate rollback scripts
   - Backup before migration

4. **Schema Evolution**
   - Add columns as nullable first
   - Migrate data, then add constraints
   - Use default values when possible

5. **Testing**
   - Test both up and down migrations
   - Verify data integrity after migration
   - Test on various schema versions

## Integration with Your Project

### Current Database Models

Based on your git status and code:
- `Layer` - Base layer type
- `LayerCore`, `LayerData`, `LayerGrid`, `LayerLineArrow`, `LayerText` - Layer subtypes
- `DataSet` - Dataset storage (you're on branch 43-DatasetsTable)
- `Geometry`, `Color`, `Encoding` - Supporting types
- `WindowControllerSize` - UI state

### Migration Use Cases

1. **Adding DataSet Table** (current branch work)
   - Generate create table migration
   - Add foreign keys to Layer
   - Create indexes for performance

2. **Refactoring Layer Hierarchy**
   - Migrate from inheritance to composition
   - Update foreign key relationships
   - Transform layer type data

3. **Performance Optimizations**
   - Add indexes based on query patterns
   - Denormalize frequently joined data
   - Add computed columns

## Configuration

Store migration settings in `.database-migration.json`:
```json
{
  "migrationsPath": "./Migrations",
  "databasePath": "./testfile.sqlite",
  "trackingTable": "schema_migrations",
  "backupBeforeMigration": true,
  "autoBackup": {
    "enabled": true,
    "path": "./Backups"
  }
}
```

## Commands Reference

### Generate New Migration
```bash
# Analyze changes and create migration file
claude-skill database-migration-helper generate "add datasets table"
```

### Apply Pending Migrations
```bash
# Apply all unapplied migrations
claude-skill database-migration-helper migrate
```

### Rollback Last Migration
```bash
# Rollback the most recent migration
claude-skill database-migration-helper rollback
```

### Generate Models from Database
```bash
# Create Swift models from existing database
claude-skill database-migration-helper generate-models --from testfile.sqlite
```

### Schema Diff
```bash
# Compare code models vs database schema
claude-skill database-migration-helper diff
```