0.3.3 • Published 7 months ago

@magic-mustard/sqlsync v0.3.3

Weekly downloads
-
License
MIT
Repository
github
Last release
7 months ago

SQLSync

A modern SQL migration tool with declarative schema management

āš ļø ALPHA STATUS: SQLSync is currently in alpha testing. The API and features may change significantly between versions.

SQLSync simplifies database schema evolution by allowing a declarative approach to table management, reducing manual SQL migration writing and improving database change reliability.

Notice

Project is written in conjunction with AI. AI being the main developer.

Purpose & Approach

SQLSync addresses several key challenges in database schema evolution:

  1. Complements Existing Migration Tools: SQLSync is not designed to replace or directly migrate changes to a database. Instead, it works alongside existing migration tools (like Supabase migrations or Flyway) to generate migration files that these tools can execute.

  2. Tracks Changes Throughout Development: A common challenge with database development is losing track of incremental changes during the development lifecycle. SQLSync addresses this by breaking down the structure of your database using SQL, making it easy to see what changed and when.

  3. Leverages Non-Destructive SQL: Many SQL operations can be written to be non-destructive (e.g., CREATE INDEX IF NOT EXISTS). SQLSync takes advantage of this to generate safe migrations that won't disrupt existing data or structures.

  4. Simplifies Table Column Changes: Tracking alterations to table columns is particularly difficult with traditional approaches. SQLSync's declarative table feature lets you simply edit the CREATE TABLE statement, and any changes are automatically detected and translated into the appropriate ALTER TABLE statements in the migration file.

Key Features

šŸ”„ Declarative Table Management

Define your database tables once, with automatic migration generation when they change:

-- sqlsync: declarativeTable=true
CREATE TABLE users (
  id SERIAL PRIMARY KEY,
  username VARCHAR(50) NOT NULL,
  email VARCHAR(100) NOT NULL UNIQUE,
  created_at TIMESTAMP DEFAULT NOW()
);

SQLSync handles declarative tables with incremental schema changes:

  • For new tables: The initial migration includes the full CREATE TABLE statement
  • For existing tables: Any changes to columns will generate the appropriate ALTER TABLE statements:
    • Added columns → ALTER TABLE ADD COLUMN
    • Modified columns → ALTER TABLE ALTER COLUMN
    • Removed columns → ALTER TABLE DROP COLUMN

šŸ“ Statement Splitting for Data Migrations

-- sqlsync: splitStatements=true

-- Each statement is tracked individually
INSERT INTO categories (name) VALUES ('Electronics');
INSERT INTO categories (name) VALUES ('Books');
INSERT INTO categories (name) VALUES ('Clothing');

When you add new statements, only those new statements will be included in the migration. SQLSync will attempt to automatically detect the boundaries between statements, but for complex SQL (such as function definitions with embedded dollar quotes or complex syntax), you can explicitly mark statement boundaries:

-- sqlsync: splitStatements=true

-- sqlsync: startStatement
CREATE FUNCTION my_complex_function() RETURNS ...
$$ 
BEGIN
  -- Complex code with multiple $$ or nested statements
END;
$$ LANGUAGE plpgsql;
-- sqlsync: endStatement

-- Next statement follows...

When statement splitting is disabled (the default behavior), SQLSync treats the entire file as a single unit, and any change to the file will cause the entire file to be included in the migration.

šŸ—‚ļø Sophisticated Directory Structure Support

SQLSync supports complex nested directories with flexible configuration:

# sqlsync.yaml
sources:
  schema:  # This is a logical section, not necessarily a physical directory
    order:
      - schemas.sql  # Process this file first
      - functions    # Then process this directory
      - tables       # Then process this directory
    functions:
      order:
        - update_timestamp.sql  # Process specific files in this order
    tables:
      order:
        - users       # Process these subdirectories in this order
        - products
        - categories
      orderedSubdirectoryFileOrder:  # Process files in each subdirectory in this order
        - types.sql
        - table.sql
        - rls.sql
        - indexes.sql

This configuration provides several key benefits:

  • Logical Organization: Define logical sections that can map to physical directories
  • Processing Control: Specify the exact order for processing files and directories
  • Subdirectory File Ordering: Use orderedSubdirectoryFileOrder to process files in each subdirectory in the same consistent order
  • Optional Files: Files listed in orderedSubdirectoryFileOrder are optional - if they don't exist, SQLSync simply skips them
  • Standardized Structure: Apply the same file processing order to multiple similar directories (like table subdirectories)

šŸ‘„ Multi-Developer Collaboration

SQLSync supports multiple developers working simultaneously on the same database:

  • Independent Development: Developers can work independently on different aspects of the database schema
  • Migration Sharing: Developers can share migrations with teammates by committing them to version control
  • State Synchronization: The sync command updates the local state file to recognize migrations from other team members
  • Schema Comparison: SQLSync detects when the current schema differs from the locally applied migrations
  • Conflict Resolution: When conflicts occur (e.g., different developers modifying the same table differently), SQLSync helps identify discrepancies and generates appropriate ALTER statements to resolve them
# View current status compared to applied migrations
sqlsync status

# Recognize migrations from other developers
sqlsync sync

# Generate new migrations after resolving conflicts
sqlsync generate resolve-conflict

SQLSync uses color-coded output to make changes clear:

  • 🟢 Green for added items
  • 🟔 Yellow for modified items
  • šŸ”“ Red for deleted items

šŸ›”ļø Safety-First Migrations

  • āœ… Non-destructive changes (CREATE, ADD, ALTER) are automatically included
  • āš ļø Destructive operations require explicit user action
  • 🚨 Clear warnings highlight when manual intervention might be needed

šŸ”™ Migration Rollback Support

Roll back migrations when needed with built-in protection for critical changes:

# List available migrations for rollback
sqlsync rollback --list

# Roll back to a specific migration (that migration and all newer ones will be rolled back)
sqlsync rollback 20250401_add_users.sql

# Roll back and delete the rolled back migration files
sqlsync rollback 20250401_add_users.sql --delete-files

# Mark a migration to prevent accidental rollback
sqlsync rollback 20250401_add_users.sql --mark

# Unmark a previously protected migration
sqlsync rollback 20250401_add_users.sql --unmark

The system ensures state consistency after rollback, allowing development to continue smoothly.

šŸž Debug Support

SQLSync includes a powerful debug utility to help troubleshoot issues:

# Enable basic debugging information
sqlsync <command> --debug

# Enable verbose debugging with more detailed information
sqlsync <command> --debug verbose

Debug output can be controlled through:

  • Command-line flag: --debug [basic|verbose]
  • Environment variable: SQLSYNC_DEBUG=true
  • Development mode: Automatically enabled when NODE_ENV=development

šŸŽØ Enhanced CLI Experience

  • Color-coded output shows exactly what changed:
    • Green: Added items (tables, columns, statements)
    • Yellow: Modified items (column types, constraints)
    • Red: Deleted items (with warnings about manual intervention)

Installation

npm install -g sqlsync

Quick Start

  1. Create a configuration file sqlsync.yaml in your project root:
# sqlsync.yaml
config:
  migrations:
    outputDir: migrations  # Relative to this config file's location

sources:
  schema:
    order:
      - tables
      - functions
    tables:
      order:
        - users
        - products
      orderedSubdirectoryFileOrder:
        - table.sql
        - rls.sql
        - indexes.sql
    functions:
      order:
        - update_timestamp.sql  # Process specific files in this order
  1. Create your SQL files according to the directory structure defined in your configuration:
/project
ā”œā”€ā”€ sqlsync.yaml
ā”œā”€ā”€ migrations/
└── schema/
    ā”œā”€ā”€ tables/
    │   ā”œā”€ā”€ users/
    │   │   ā”œā”€ā”€ table.sql        # -- sqlsync: declarativeTable=true
    │   │   └── indexes.sql
    │   └── products/
    │       ā”œā”€ā”€ table.sql        # -- sqlsync: declarativeTable=true  
    │       └── data.sql         # -- sqlsync: splitStatements=true
    └── functions/
        └── user_functions.sql   # -- sqlsync: splitStatements=true
  1. Generate migrations after making changes to your SQL files:
sqlsync generate add_user_table
  1. Review the generated migration in the migrations directory and apply it using your preferred database migration tool.

Configuration Options

The sqlsync.yaml file supports:

config:
  migrations:
    outputDir: './migrations' # Where migrations are saved
    cli: # Optional external tool integration
      latest: 'npx sequelize-cli db:migrate'
      migrate: 'npx sequelize-cli db:migrate --name'
  maxRollbacks: 5 # Optional limit on how many migrations can be rolled back or marked
sources: # Sources of SQL files
  schema: # Source name
    order: # Processing order (files/directories)
      - 'schema/tables' # Directory path
      - 'schema/views'
  data:
    order:
      - 'data/seed'

SQL File Directives

Add these directives as comments in your SQL files:

DirectiveDescription
-- sqlsync: declarativeTable=trueTreats the file as a declarative table definition. Requires exactly one CREATE TABLE statement per file.
-- sqlsync: splitStatements=trueTracks each SQL statement in the file separately. Ideal for data files with multiple INSERT statements.
-- sqlsync: startStatementExplicitly marks the start of a statement when using statement splitting with complex SQL.
-- sqlsync: endStatementExplicitly marks the end of a statement when using statement splitting with complex SQL.

Commands

CommandDescription
sqlsync initCreates a default configuration
sqlsync generate <migration-name>Generates migration files based on changes
sqlsync generate <n> --no-mark-appliedGenerate without marking as locally applied
sqlsync statusShows current status of SQL files vs state
sqlsync syncSynchronizes with migrations from other developers
sqlsync rollback <migration-name>Rolls back to a specific migration (inclusive)
sqlsync rollback --listLists migrations available for rollback
sqlsync rollback <n> --markMarks a migration to prevent accidental rollback
sqlsync rollback <n> --unmarkUnmarks a previously protected migration
sqlsync rollback <n> --delete-filesDeletes the rolled back migration files
sqlsync rollback <n> --forceSkips confirmation prompts during rollback
sqlsync mark-applied <migration-name>Marks a migration as applied locally
sqlsync mark-applied allMarks all migrations as applied locally
sqlsync migrateRuns migrations (if external tool configured)
sqlsync --debug [level]Enables debug output (levels: basic, verbose)

Development

# Install dependencies
npm install

# Run tests
npm test

# Run specific test suite
npx jest tests/core/collaboration-manager.test.ts

# Run a specific test case
npx jest -t "should support multiple developers working simultaneously"

# Build
npm run build

Testing Architecture

SQLSync tests are organized into the following categories:

  • Core Tests: Validate the fundamental components

    • sql-processor.test.ts: Tests SQL parsing and validation logic
    • collaboration-manager.test.ts: Tests multi-developer workflows
    • declarative-tables.test.ts: Tests CREATE TABLE validation and ALTER detection
    • split-statements.test.ts: Tests statement-level tracking
  • Command Tests: Validate the CLI commands

    • generate.test.ts: Tests migration generation with color-coded output
    • sync.test.ts: Tests synchronization between multiple developers

When adding new features, please ensure all tests pass by running npm test.

License

MIT

0.3.3

7 months ago

0.3.2

7 months ago

0.3.1

7 months ago

0.3.0

7 months ago

0.2.2

8 months ago

0.2.1

8 months ago

0.2.0

8 months ago

0.1.2

9 months ago

0.1.1

9 months ago

0.1.0

9 months ago

0.0.1

9 months ago