Skip to main content

A SQLFluff templater compatible with schemachange, supporting macros, env_var, and config loading.

Project description

SQLFluff Templater for Schemachange

A custom SQLFluff templater that provides schemachange-compatible Jinja templating features. This templater reads schemachange-config.yml files and provides the same templating experience as schemachange without requiring schemachange as a dependency.

Note: This is a standalone implementation that replicates schemachange's templating behavior within SQLFluff. It does not import or depend on the schemachange package itself.

Features

  • Schemachange-Compatible Config: Reads schemachange-config.yml files using the same format and structure
  • Jinja2 Templating: Full SQLFluff JinjaTemplater support with additional schemachange-style functions
  • Variable Management: Supports complex nested variables exactly like schemachange
  • Environment Variables: Provides env_var() function matching schemachange's implementation
  • Modules Support: Load templates and macros from folders (schemachange modules-folder equivalent)
  • No External Dependencies: Pure SQLFluff + PyYAML implementation, no schemachange package required

Why Use This?

This templater is ideal when you want to:

  • Lint schemachange SQL files with SQLFluff's comprehensive rule set
  • Use existing schemachange configs without installing the full schemachange toolchain
  • Integrate SQL linting into CI/CD pipelines that use schemachange for deployments
  • Maintain consistency between your schemachange templates and SQLFluff linting

The templater replicates schemachange's Jinja environment and config parsing, so your templates work identically in both tools.

Installation

pip install sqlfluff-templater-schemachange

Or install from source:

git clone https://github.com/MACKAT05/sqlfluff-templater-schemachange
cd sqlfluff-templater-schemachange
pip install -e .

Configuration

Basic SQLFluff Configuration

Create a .sqlfluff file in your project root:

[sqlfluff]
templater = schemachange
dialect = snowflake

[sqlfluff:templater:schemachange]
# Path to schemachange config folder (optional, defaults to '.')
config_folder = .

# Schemachange config file name (optional, defaults to 'schemachange-config.yml')
config_file = schemachange-config.yml

# Modules folder for macro loading (optional)
modules_folder = modules

# Additional variables (merged with config file vars)
vars = {"environment": "dev", "schema_suffix": "_DEV"}

Schemachange Configuration

Create a schemachange-config.yml file:

config-version: 1

# Basic schemachange settings
root-folder: 'scripts'
modules-folder: 'modules'

# Database connection settings
snowflake-account: '{{ env_var("SNOWFLAKE_ACCOUNT") }}'
snowflake-user: '{{ env_var("SNOWFLAKE_USER") }}'
snowflake-role: 'TRANSFORMER'
snowflake-warehouse: 'COMPUTE_WH'
snowflake-database: 'MY_DATABASE'

# Variables for templating
vars:
  database_name: 'MY_DATABASE'
  schema_name: 'ANALYTICS'
  environment: 'production'
  table_prefix: 'fact_'

  # Nested variables
  sources:
    raw_database: 'RAW_DATA'
    staging_database: 'STAGING'

  # Secret variables (automatically filtered from logs)
  secrets:
    api_key: '{{ env_var("API_KEY") }}'
    encryption_key: '{{ env_var("ENCRYPTION_KEY") }}'

# Additional settings
create-change-history-table: false
autocommit: false
verbose: true

Usage Examples

Basic Variable Templating

SQL File (V1.0.1__create_tables.sql):

-- Create tables with dynamic names
CREATE TABLE {{ database_name }}.{{ schema_name }}.{{ table_prefix }}sales (
    id INTEGER,
    customer_id INTEGER,
    amount DECIMAL(10,2),
    created_at TIMESTAMP
);

CREATE TABLE {{ database_name }}.{{ schema_name }}.{{ table_prefix }}customers (
    id INTEGER,
    name VARCHAR(255),
    email VARCHAR(255)
);

Using Nested Variables

-- Reference nested configuration
CREATE SCHEMA IF NOT EXISTS {{ sources.staging_database }}.INTERMEDIATE;

-- Copy data from raw to staging
CREATE TABLE {{ sources.staging_database }}.INTERMEDIATE.cleaned_data AS
SELECT * FROM {{ sources.raw_database }}.PUBLIC.raw_data
WHERE created_at >= '{{ start_date }}';

Using Jinja Macros

Macro file (modules/common_macros.sql):

{% macro create_audit_columns() %}
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    created_by VARCHAR(255) DEFAULT CURRENT_USER()
{% endmacro %}

{% macro generate_schema_name(custom_schema_name=none, node=none) %}
    {% if custom_schema_name is none %}
        {{ target.schema }}
    {% else %}
        {{ target.schema }}_{{ custom_schema_name | trim }}
    {% endif %}
{% endmacro %}

SQL file using macros:

CREATE TABLE {{ database_name }}.{{ generate_schema_name('analytics') }}.user_events (
    event_id INTEGER,
    user_id INTEGER,
    event_type VARCHAR(50),
    {{ create_audit_columns() }}
);

Environment Variable Integration

Access environment variables using the env_var() function:

-- Use environment variables with defaults
USE WAREHOUSE {{ env_var('SNOWFLAKE_WAREHOUSE', 'DEFAULT_WH') }};
USE DATABASE {{ env_var('DATABASE_NAME', database_name) }};

-- Connect to environment-specific database
USE DATABASE {{ database_name }}_{{ env_var('ENVIRONMENT', 'dev') | upper }};

-- Use secrets from environment
CREATE OR REPLACE EXTERNAL FUNCTION get_data(...)
RETURNS VARIANT
LANGUAGE PYTHON
HANDLER='main'
API_INTEGRATION = {{ env_var('API_INTEGRATION_NAME') }};

Conditional Logic

CREATE TABLE {{ database_name }}.{{ schema_name }}.events (
    event_id INTEGER,
    user_id INTEGER,
    event_data JSON,

    {% if environment == 'production' %}
    -- Only add PII columns in production
    user_email VARCHAR(255),
    user_phone VARCHAR(20),
    {% endif %}

    created_at TIMESTAMP
);

{% if environment != 'production' %}
-- Add test data in non-production environments
INSERT INTO {{ database_name }}.{{ schema_name }}.events
VALUES (1, 100, '{"test": true}', CURRENT_TIMESTAMP);
{% endif %}

Template Inheritance

Base template (modules/base_table.sql):

{% block table_definition %}
CREATE TABLE {{ database_name }}.{{ schema_name }}.{{ table_name }} (
    {% block columns %}{% endblock %}
    {% block audit_columns %}
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
    {% endblock %}
);
{% endblock %}

{% block post_create %}
-- Default post-creation steps
{% endblock %}

Specific table (V1.0.2__create_products.sql):

{% extends "base_table.sql" %}
{% set table_name = "products" %}

{% block columns %}
    product_id INTEGER PRIMARY KEY,
    name VARCHAR(255) NOT NULL,
    price DECIMAL(10,2),
    category VARCHAR(100),
{% endblock %}

{% block post_create %}
-- Add specific indexes
CREATE INDEX idx_products_category ON {{ database_name }}.{{ schema_name }}.{{ table_name }} (category);
{% endblock %}

Running SQLFluff

Once configured, run SQLFluff as usual:

# Lint all SQL files
sqlfluff lint

# Lint specific files
sqlfluff lint scripts/versioned/

# Fix auto-fixable issues
sqlfluff fix

# Check specific file with verbose output
sqlfluff lint --verbose V1.0.1__create_tables.sql

Advanced Configuration

Multiple Environment Support

You can have different configurations for different environments:

.sqlfluff (development):

[sqlfluff:templater:schemachange]
config_folder = configs
config_file = dev-config.yml
vars = {"environment": "dev"}

configs/dev-config.yml:

config-version: 1
vars:
  database_name: 'DEV_DATABASE'
  environment: 'dev'
  debug_mode: true

configs/prod-config.yml:

config-version: 1
vars:
  database_name: 'PROD_DATABASE'
  environment: 'prod'
  debug_mode: false

Macro Loading

Configure macro loading from a modules folder:

[sqlfluff:templater:schemachange]
modules_folder = templates/macros

This allows you to use {% include %} and {% import %} statements to load macros from the specified folder.

Integration with CI/CD

GitHub Actions example:

name: SQL Linting
on: [push, pull_request]

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2

      - name: Set up Python
        uses: actions/setup-python@v2
        with:
          python-version: '3.9'

      - name: Install dependencies
        run: |
          pip install sqlfluff sqlfluff-templater-schemachange

      - name: Lint SQL files
        env:
          SNOWFLAKE_ACCOUNT: ${{ secrets.SNOWFLAKE_ACCOUNT }}
          SNOWFLAKE_USER: ${{ secrets.SNOWFLAKE_USER }}
        run: |
          sqlfluff lint scripts/

Secret Handling

The templater automatically identifies and filters secrets from logs based on:

  1. Variable names containing "secret" (case-insensitive)
  2. Variables nested under a "secrets" key
vars:
  api_key_secret: "sensitive_value"  # Filtered
  database_password: "password123"   # Not filtered

  secrets:
    oauth_token: "token123"          # Filtered
    encryption_key: "key456"         # Filtered

Troubleshooting

Common Issues

  1. Template not found: Ensure your modules-folder is correctly configured
  2. Undefined variable: Check your schemachange-config.yml and CLI vars
  3. Permission errors: Verify file paths and permissions for config and template files

Debug Mode

Enable verbose logging to see what's happening:

sqlfluff lint --verbose --debug

Environment Variables

Use environment variables for sensitive configuration:

export SNOWFLAKE_ACCOUNT="your-account"
export SNOWFLAKE_USER="your-user"
sqlfluff lint

Contributing

Development Setup

The project uses static tests for easy debugging and CI integration:

# Clone the repository
git clone https://github.com/MACKAT05/sqlfluff-templater-schemachange
cd sqlfluff-templater-schemachange

# Install in development mode
pip install -e .

# Install development dependencies
pip install -r requirements.txt

# Install pre-commit
pip install pre-commit
pre-commit install

The project includes static test files in the tests/ directory for easy debugging and CI integration.

Testing

The project includes static test files for easy debugging:

# Run all tests
python tests/run_tests.py

# Run individual tests
python tests/test_basic.py
python tests/test_modules.py
python tests/test_env_vars.py
python tests/test_conditional.py

Development Workflow

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Test your changes:
    # Run all tests
    python tests/run_tests.py
    
    # Test SQLFluff integration
    cd tests/basic && sqlfluff render test.sql
    
  5. Pre-commit hooks will run automatically on git commit
  6. Submit a pull request

Note on Pre-commit

The pre-commit configuration uses local SQLFluff hooks that require the development package to be installed first. This avoids the chicken-and-egg problem of trying to install the package from PyPI before it's published.

License

MIT License - see LICENSE file for details.

Related Projects

  • SQLFluff - The SQL linter this plugin extends
  • schemachange - Database change management tool this integrates with
  • Snowflake - Cloud data platform

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

sqlfluff_templater_schemachange-0.1.1.tar.gz (16.9 kB view details)

Uploaded Source

Built Distribution

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

File details

Details for the file sqlfluff_templater_schemachange-0.1.1.tar.gz.

File metadata

File hashes

Hashes for sqlfluff_templater_schemachange-0.1.1.tar.gz
Algorithm Hash digest
SHA256 532776b300a7b3d5a6bda2a82fadb019b94b6c6ff0412ac2e277d632ec1b9e2d
MD5 2f30a7c7b317acee670ad141c54bd716
BLAKE2b-256 4fbc14db7a8744c217532c3e46526b3b64b68356cbba1d707c15b12349c99504

See more details on using hashes here.

Provenance

The following attestation bundles were made for sqlfluff_templater_schemachange-0.1.1.tar.gz:

Publisher: python-publish.yml on MACKAT05/sqlfluff-templater-schemachange

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file sqlfluff_templater_schemachange-0.1.1-py3-none-any.whl.

File metadata

File hashes

Hashes for sqlfluff_templater_schemachange-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 c1e366c43c73d9b817af70120ead710e661db7a2d2b48bfa3d3908c60f9915ba
MD5 426e43f99b187f2c4f74fe5f1c705901
BLAKE2b-256 f9763d377a9e6f524b900b89e3a6f8f1feaaafad9d2072537543e172c32a4176

See more details on using hashes here.

Provenance

The following attestation bundles were made for sqlfluff_templater_schemachange-0.1.1-py3-none-any.whl:

Publisher: python-publish.yml on MACKAT05/sqlfluff-templater-schemachange

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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