Skip to main content

A CLI tool to add idempotent statements to SQL files

Project description

SQL Idempotent Tool

A sophisticated CLI tool that analyzes SQL files and automatically transforms non-idempotent statements into idempotent ones. This tool helps ensure that SQL scripts can be run multiple times safely without causing errors or unintended side effects.

Features

🔍 Comprehensive SQL Statement Support

  • Views: CREATE VIEWCREATE OR REPLACE VIEW
  • Materialized Views: CREATE MATERIALIZED VIEWDROP IF EXISTS + CREATE
  • Triggers: CREATE TRIGGERDROP IF EXISTS + CREATE
  • Types: CREATE TYPEDROP IF EXISTS + CREATE
  • Indexes: CREATE INDEXCREATE INDEX IF NOT EXISTS
  • Functions: CREATE FUNCTIONCREATE OR REPLACE FUNCTION
  • Procedures: CREATE PROCEDUREDROP IF EXISTS + CREATE
  • Schemas: CREATE SCHEMACREATE SCHEMA IF NOT EXISTS
  • Policies: CREATE POLICYDROP IF EXISTS + CREATE
  • Sequences: CREATE SEQUENCEDROP IF EXISTS + CREATE
  • Domains: CREATE DOMAINDROP IF EXISTS + CREATE
  • Extensions: CREATE EXTENSIONCREATE EXTENSION IF NOT EXISTS
  • Roles: CREATE ROLEDROP IF EXISTS + CREATE
  • Users: CREATE USERDROP IF EXISTS + CREATE
  • Grants: GRANTREVOKE ALL + GRANT
  • Constraints: ALTER TABLE ADD CONSTRAINTDROP IF EXISTS + ADD

⚙️ Advanced Configuration System

  • TOML-based configuration with sensible defaults
  • Per-statement-type configuration (enable/disable, strategy selection)
  • Custom transformation templates
  • Parser settings (case sensitivity, comment handling)
  • Output formatting options

🛠️ Powerful CLI Interface

  • Analysis mode: Identify non-idempotent statements
  • Transformation mode: Convert statements to idempotent form
  • Validation mode: Check if files are already idempotent
  • Batch processing: Handle multiple files and directories
  • Configuration management: Initialize, view, and modify settings

🎯 Smart Parsing

  • Tree-sitter integration for accurate SQL parsing
  • Regex fallback for compatibility
  • Multi-line statement support
  • Comment preservation
  • Complex SQL construct handling (CTEs, subqueries, etc.)

Installation

# Clone the repository
git clone <repository-url>
cd sql-idempotent-tool

# Install with uv (recommended)
uv sync

# Or install with pip
pip install -e .

Quick Start

1. Analyze a SQL file

sql-idempotent analyze sample.sql

2. Transform a SQL file

sql-idempotent transform sample.sql --output sample_idempotent.sql

3. Validate a SQL file

sql-idempotent validate sample.sql

CLI Commands

analyze

Analyze a SQL file and identify non-idempotent statements.

sql-idempotent analyze [OPTIONS] FILE_PATH

Options:
  --config, -c PATH    Path to config file
  --verbose, -v        Show detailed output
  --help              Show this message and exit

Example:

sql-idempotent analyze complex_sample.sql --verbose

transform

Transform SQL statements to make them idempotent.

sql-idempotent transform [OPTIONS] FILE_PATH

Options:
  --output, -o PATH           Output file path
  --config, -c PATH           Path to config file
  --dry-run                   Show preview without making changes
  --verbose, -v               Show detailed output
  --safe-mode/--no-safe-mode  Use conditional blocks instead of DROP+CREATE (default: enabled)
  --format/--no-format        Format output SQL using SQLFluff (default: enabled)
  --help                      Show this message and exit

Examples:

# Transform and save to new file
sql-idempotent transform sample.sql --output sample_idempotent.sql

# Preview changes without saving
sql-idempotent transform sample.sql --dry-run

# Transform in place (overwrites original)
sql-idempotent transform sample.sql

# Use safe mode to preserve dependencies (default)
sql-idempotent transform sample.sql --safe-mode

# Use regular mode for more concise output
sql-idempotent transform sample.sql --no-safe-mode

# Format output with SQLFluff (default)
sql-idempotent transform sample.sql --format

# Skip formatting for faster processing
sql-idempotent transform sample.sql --no-format

Safe Mode vs Regular Mode

The tool offers two transformation strategies:

Safe Mode (--safe-mode, default):

  • Uses PostgreSQL DO blocks with conditional existence checks
  • Preserves database dependencies - never drops existing objects
  • Safer for production environments where objects may have dependencies
  • Example output:
DO $$
BEGIN
    IF NOT EXISTS (SELECT 1 FROM information_schema.views WHERE table_name = 'my_view') THEN
        EXECUTE 'CREATE VIEW my_view AS SELECT * FROM users';
    END IF;
END $$;

Regular Mode (--no-safe-mode):

  • Uses modern PostgreSQL syntax like CREATE OR REPLACE and IF NOT EXISTS
  • More concise and readable output
  • Faster execution but may break dependencies if objects are referenced elsewhere
  • Example output:
CREATE OR REPLACE VIEW my_view AS SELECT * FROM users;

When to use Safe Mode:

  • Production databases with complex dependencies
  • When you're unsure about object relationships
  • When preserving existing objects is critical
  • In CI/CD pipelines where safety is paramount

When to use Regular Mode:

  • Development environments
  • When you want cleaner, more readable SQL
  • When you're certain about dependencies
  • For better performance in simple scenarios

SQL Formatting

The tool includes automatic SQL formatting using SQLFluff, a popular SQL linter and formatter.

Features:

  • Automatic formatting - Formats transformed SQL for better readability
  • Configurable dialect - Supports PostgreSQL, MySQL, SQLite, and more
  • Custom rules - Use your own SQLFluff configuration file
  • Optional - Can be disabled for faster processing

Configuration:

[output]
format_sql = true                    # Enable/disable formatting
sqlfluff_dialect = "postgres"       # SQL dialect
sqlfluff_config_path = ".sqlfluff"  # Path to SQLFluff config (optional)

Benefits:

  • Consistent code style across your SQL files
  • Better readability of transformed statements
  • Follows SQL best practices and conventions
  • Integrates seamlessly with existing SQLFluff workflows

validate

Validate that a SQL file contains only idempotent statements.

sql-idempotent validate [OPTIONS] FILE_PATH

Options:
  --config, -c PATH    Path to config file
  --strict            Fail on any non-idempotent statements
  --help              Show this message and exit

Examples:

# Check if file is idempotent
sql-idempotent validate sample.sql

# Strict validation (exit code 1 if non-idempotent)
sql-idempotent validate sample.sql --strict

batch

Process multiple SQL files in a directory.

sql-idempotent batch [OPTIONS] DIRECTORY

Options:
  --pattern TEXT       File pattern to match (default: *.sql)
  --output-dir PATH    Output directory for transformed files
  --config, -c PATH    Path to config file
  --recursive, -r      Process subdirectories recursively
  --dry-run           Show preview without making changes
  --help              Show this message and exit

Examples:

# Process all SQL files in a directory
sql-idempotent batch ./sql-scripts --output-dir ./sql-scripts-idempotent

# Process recursively with custom pattern
sql-idempotent batch ./database --pattern "migration_*.sql" --recursive

Configuration Management

config-init

Initialize a new configuration file.

sql-idempotent config-init [OPTIONS]

Options:
  --config, -c PATH    Path to create config file
  --force, -f         Overwrite existing config file
  --help              Show this message and exit

config-show

Display current configuration settings.

sql-idempotent config-show [OPTIONS]

Options:
  --config, -c PATH    Path to config file
  --help              Show this message and exit

config-set

Set a configuration value.

sql-idempotent config-set [OPTIONS] KEY VALUE

Options:
  --config, -c PATH    Path to config file
  --help              Show this message and exit

Examples:

# Disable transformation for triggers
sql-idempotent config-set transformations.CREATE_TRIGGER.enabled false

# Change strategy for views
sql-idempotent config-set transformations.CREATE_VIEW.strategy drop_and_create

# Enable comment addition
sql-idempotent config-set output.add_comments true

Configuration File

The tool uses TOML configuration files. Here's an example:

# sql-idempotent.toml

[transformations.CREATE_VIEW]
enabled = true
strategy = "or_replace"

[transformations.CREATE_TRIGGER]
enabled = true
strategy = "drop_and_create"

[transformations.CREATE_INDEX]
enabled = true
strategy = "if_not_exists"

[parser]
case_sensitive = false
ignore_comments = true
excluded_statement_types = []

[output]
preserve_formatting = true
add_comments = true
comment_template = "-- Idempotent transformation applied by sql-idempotent-tool"

# Safety settings
require_confirmation = false
max_file_size_mb = 100
create_backups = true
backup_suffix = ".backup"

Configuration Locations

The tool looks for configuration files in this order:

  1. --config parameter
  2. ./sql-idempotent.toml
  3. ./.sql-idempotent.toml
  4. ~/.config/sql-idempotent/config.toml
  5. ~/.sql-idempotent.toml

Transformation Strategies

or_replace

Uses CREATE OR REPLACE syntax where supported:

  • CREATE VIEWCREATE OR REPLACE VIEW
  • CREATE FUNCTIONCREATE OR REPLACE FUNCTION

if_not_exists

Uses IF NOT EXISTS syntax where supported:

  • CREATE SCHEMACREATE SCHEMA IF NOT EXISTS
  • CREATE INDEXCREATE INDEX IF NOT EXISTS
  • CREATE EXTENSIONCREATE EXTENSION IF NOT EXISTS

drop_and_create

Adds DROP IF EXISTS before the CREATE statement:

  • CREATE TRIGGERDROP TRIGGER IF EXISTS + CREATE TRIGGER
  • CREATE TYPEDROP TYPE IF EXISTS + CREATE TYPE

Examples

Basic Usage

-- Input: sample.sql
CREATE VIEW user_summary AS
SELECT id, name, email FROM users;

CREATE TRIGGER update_timestamp
BEFORE UPDATE ON users
FOR EACH ROW
EXECUTE FUNCTION update_modified_time();
sql-idempotent transform sample.sql --output sample_idempotent.sql
-- Output: sample_idempotent.sql
CREATE OR REPLACE VIEW user_summary AS
SELECT id, name, email FROM users;

DROP TRIGGER IF EXISTS update_timestamp;
CREATE TRIGGER update_timestamp
BEFORE UPDATE ON users
FOR EACH ROW
EXECUTE FUNCTION update_modified_time();

Complex Transformations

The tool handles complex SQL constructs including:

  • Multi-line statements with comments
  • CTEs (Common Table Expressions)
  • Complex constraint definitions
  • Role-based security policies
  • Grant statements with multiple objects

Batch Processing

# Process all migration files
sql-idempotent batch ./migrations --pattern "*.sql" --output-dir ./migrations-idempotent

# Validate all files in a directory
find ./sql-scripts -name "*.sql" -exec sql-idempotent validate {} \;

Development

Running Tests

# Run all tests
uv run pytest

# Run specific test file
uv run pytest tests/test_sql_parser.py

# Run with coverage
uv run pytest --cov=sql_idempotent_tool

Project Structure

sql-idempotent-tool/
├── sql_idempotent_tool/
│   ├── __init__.py
│   ├── cli.py              # CLI interface
│   ├── sql_parser.py       # Core parsing and transformation logic
│   └── config.py           # Configuration management
├── tests/
│   └── test_sql_parser.py  # Comprehensive test suite
├── pyproject.toml          # Project configuration
└── README.md              # This file

Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Add tests for new functionality
  4. Ensure all tests pass
  5. Submit a pull request

License

This project is licensed under the MIT License. See the LICENSE file for details.

Changelog

v1.0.0

  • Initial release with comprehensive SQL statement support
  • Configuration system with TOML files
  • Advanced CLI with multiple commands
  • Tree-sitter integration with regex fallback
  • Batch processing capabilities
  • Comprehensive test suite

Support

For issues, feature requests, or questions:

  • Open an issue on GitHub
  • Check the documentation
  • Review the test files for usage examples

Made with ❤️ for the SQL community

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

sql_idempotent_tool-0.1.0.tar.gz (42.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

sql_idempotent_tool-0.1.0-py3-none-any.whl (20.9 kB view details)

Uploaded Python 3

File details

Details for the file sql_idempotent_tool-0.1.0.tar.gz.

File metadata

  • Download URL: sql_idempotent_tool-0.1.0.tar.gz
  • Upload date:
  • Size: 42.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.11

File hashes

Hashes for sql_idempotent_tool-0.1.0.tar.gz
Algorithm Hash digest
SHA256 b4348da5be4a2be18e63ef9957ba0aca49a67842c752fae392e04c8d4d821c21
MD5 1adcff30ddf5cbf494e93dc1f9b87e34
BLAKE2b-256 7b6fa08145e1f8feae93f31d854e7d8191822420dc1e4fbc5f4d79be85bc844c

See more details on using hashes here.

File details

Details for the file sql_idempotent_tool-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for sql_idempotent_tool-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 417c229012b0734366d45d92ea609d060eabc291539160a9cbc600992c751945
MD5 cf56bde07918552f5772889b206eeda6
BLAKE2b-256 ab896f061e604f7ef92b462d619d6a20e000ea6e3095beaffbb52cf9c17b1add

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page