Skip to main content

Run Snowflake SQL locally, powered by DuckDB - lightweight in-memory SQL engine for development and testing

Project description

โ„๏ธ๐Ÿฆ† SnowDuck

CI/CD Pipeline Python 3.11+ License: MIT Code style: ruff

Run Snowflake SQL locally, powered by DuckDB

SnowDuck is a lightweight, in-memory SQL engine that emulates Snowflake's behavior for development and testing. Write and test Snowflake SQL locally without cloud access or costs.

Why SnowDuck?

  • ๐Ÿš€ Fast Development - Test SQL queries instantly without waiting for cloud connections
  • ๐Ÿ’ฐ Zero Cloud Costs - Develop and test locally without Snowflake compute charges
  • ๐Ÿงช Easy Testing - Mock Snowflake databases for unit tests and CI/CD pipelines
  • โšก Lightning Fast - Powered by DuckDB's in-memory execution engine
  • ๐Ÿ”Œ Drop-in Compatible - Uses Snowflake's connector interface - just patch and go

Features

Core SQL Support

Category Functions
DDL Operations CREATE/DROP DATABASE, SCHEMA, TABLE
DML Operations INSERT, UPDATE, DELETE, MERGE
Advanced SQL CTEs, JOINs, subqueries, CASE, QUALIFY
Session Variables SET/SELECT $variable syntax
Information Schema Query metadata (databases, tables, columns)

Function Support

Category Functions
String CONCAT, CONCAT_WS, SPLIT, SPLIT_PART, CONTAINS, REPLACE, TRIM, LTRIM, RTRIM, LPAD, RPAD, SPACE, STRTOK, TRANSLATE, REVERSE, STARTSWITH, ENDSWITH, ASCII, CHR, INITCAP, SOUNDEX, UPPER, LOWER, LENGTH, LEN, SUBSTR, SUBSTRING, INSTR, POSITION
Date/Time DATEADD, DATEDIFF, TIMEDIFF, DATE_TRUNC, DATE_PART, EXTRACT, LAST_DAY, ADD_MONTHS, DATE_FROM_PARTS, TIME_FROM_PARTS, TIMESTAMP_FROM_PARTS, CONVERT_TIMEZONE, TO_DATE, TO_TIMESTAMP
Numeric ABS, CEIL, FLOOR, ROUND, MOD, SQRT, POWER, EXP, LN, LOG, SIGN, DIV0, DIV0NULL, WIDTH_BUCKET, TRUNCATE, CBRT, FACTORIAL, DEGREES, RADIANS, PI, RANDOM, GREATEST, LEAST
Aggregate COUNT, SUM, AVG, MIN, MAX, MEDIAN, LISTAGG, ANY_VALUE, KURTOSIS, SKEW, COVAR_POP, COVAR_SAMP
Window ROW_NUMBER, RANK, DENSE_RANK, LEAD, LAG, FIRST_VALUE, LAST_VALUE
JSON PARSE_JSON, OBJECT_CONSTRUCT, OBJECT_INSERT, GET_PATH, TRY_PARSE_JSON, OBJECT_KEYS, CHECK_JSON, TO_JSON
Array ARRAY_CONSTRUCT, ARRAY_SIZE, ARRAY_CONTAINS, FLATTEN, ARRAY_SLICE, ARRAY_CAT, ARRAY_APPEND, ARRAY_PREPEND, ARRAY_SORT, ARRAY_REVERSE, ARRAY_MIN, ARRAY_MAX, ARRAY_SUM, ARRAYS_OVERLAP, ARRAY_DISTINCT, ARRAY_INTERSECTION, ARRAY_EXCEPT
Conditional NVL, NVL2, DECODE, IFF, COALESCE, NULLIF, EQUAL_NULL, ZEROIFNULL, NULLIFZERO
Conversion TO_CHAR, TO_NUMBER, TO_BOOLEAN, TO_DATE, TRY_CAST, TRY_TO_NUMBER, TRY_TO_DATE, TRY_TO_TIMESTAMP, TRY_TO_BOOLEAN
Regex REGEXP_LIKE, REGEXP_SUBSTR, REGEXP_REPLACE, REGEXP_COUNT
Hash MD5, SHA1, SHA2, SHA256, HASH
Encoding BASE64_ENCODE, BASE64_DECODE_STRING, HEX_ENCODE, HEX_DECODE_STRING
Bitwise BITAND, BITOR, BITXOR, BITNOT, BITAND_AGG, BITOR_AGG, BITXOR_AGG
Boolean Agg BOOLAND_AGG, BOOLOR_AGG
Utility UUID_STRING, TYPEOF

Cursor Methods

SnowDuck supports all standard Snowflake cursor methods:

  • execute() - Execute SQL statements
  • fetchone() - Fetch a single row
  • fetchmany(size) - Fetch multiple rows
  • fetchall() - Fetch all rows
  • fetch_pandas_all() - Fetch all rows as pandas DataFrame
  • fetch_pandas_batches() - Fetch rows as iterator of DataFrames
  • get_result_batches() - Get Arrow record batches
  • describe() - Get result schema without execution

Note: SnowDuck is designed for development and testing. Use production Snowflake for production workloads.

Quick Start

Installation

# Using uv (recommended)
uv pip install snowduck

# Or using pip
pip install snowduck

Basic Usage

import snowflake.connector
from snowduck import start_patch_snowflake

# Patch the Snowflake connector to use DuckDB
start_patch_snowflake()

# Use Snowflake connector as normal - it's now backed by DuckDB!
with snowflake.connector.connect() as conn:
    cursor = conn.cursor()
    
    cursor.execute("CREATE DATABASE my_database")
    cursor.execute("USE DATABASE my_database")
    
    cursor.execute("""
        CREATE TABLE employees (id INTEGER, name VARCHAR, salary INTEGER)
    """)
    
    cursor.execute("""
        INSERT INTO employees VALUES
        (1, 'Alice', 95000),
        (2, 'Bob', 75000),
        (3, 'Carol', 105000)
    """)
    
    cursor.execute("""
        SELECT name, salary, RANK() OVER (ORDER BY salary DESC) as rank
        FROM employees
    """)
    
    for row in cursor.fetchall():
        print(f"{row[0]}: \${row[1]:,} (Rank: {row[2]})")

Data Persistence

# In-memory (default) - fast, isolated
start_patch_snowflake()

# File-based - persistent across restarts
start_patch_snowflake(db_file='my_data.duckdb')

# Fresh start - reset existing data
start_patch_snowflake(db_file='my_data.duckdb', reset=True)

Test Data Seeding

from snowduck import seed_table

with snowflake.connector.connect() as conn:
    # From dict
    seed_table(conn, 'customers', {
        'id': [1, 2, 3],
        'name': ['Acme', 'TechStart', 'DataCo']
    })
    
    # From pandas DataFrame
    seed_table(conn, 'orders', df)

Testing

Using the Decorator

from snowduck import mock_snowflake

@mock_snowflake
def test_query():
    conn = snowflake.connector.connect()
    cursor = conn.cursor()
    cursor.execute("SELECT 1")
    assert cursor.fetchone()[0] == 1

Using the Context Manager

from snowduck import patch_snowflake

def test_with_fixture():
    with patch_snowflake():
        conn = snowflake.connector.connect()
        # Test code here

pytest Fixture

import pytest
from snowduck import patch_snowflake

@pytest.fixture
def conn():
    with patch_snowflake():
        yield snowflake.connector.connect()

def test_feature(conn):
    cursor = conn.cursor()
    cursor.execute("SELECT 1")

REST API Server

# Install with server extras
uv pip install snowduck[server]

# Start the server
uvicorn snowduck.server:app --reload

The server provides:

  • Execute SQL queries via REST API
  • Arrow IPC format responses
  • Multi-session support

Architecture

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  Your Application   โ”‚
โ”‚  (Snowflake code)   โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
           โ”‚
           โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  SnowDuck Patch     โ”‚  โ† Intercepts connector calls
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
           โ”‚
           โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  SQL Translator     โ”‚  โ† Snowflake โ†’ DuckDB dialect
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
           โ”‚
           โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚   DuckDB Engine     โ”‚  โ† Fast in-memory execution
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Examples

See the examples/ directory for Jupyter notebooks demonstrating:

  • Basic operations and queries
  • String, date, and numeric functions
  • JSON and array operations
  • Window functions
  • Advanced SQL patterns

Development

git clone https://github.com/hupe1980/snowduck.git
cd snowduck
uv sync
just test
just check

Contributing

Contributions welcome! See issues for areas where help is needed.

License

MIT License - see LICENSE for details.

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

snowduck-0.0.5.tar.gz (293.9 kB view details)

Uploaded Source

Built Distribution

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

snowduck-0.0.5-py3-none-any.whl (82.3 kB view details)

Uploaded Python 3

File details

Details for the file snowduck-0.0.5.tar.gz.

File metadata

  • Download URL: snowduck-0.0.5.tar.gz
  • Upload date:
  • Size: 293.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for snowduck-0.0.5.tar.gz
Algorithm Hash digest
SHA256 b84d7b11f55e12263e3cfbe2ba78e31bd950e0aa538373216de98eb6bcc41b9c
MD5 6cb613b39d365e55be0824513de8ccae
BLAKE2b-256 6a55accac2536a477a75f3655f2998db30fb8f459f5e331520f45e79d5a3d03b

See more details on using hashes here.

Provenance

The following attestation bundles were made for snowduck-0.0.5.tar.gz:

Publisher: release.yml on hupe1980/snowduck

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

File details

Details for the file snowduck-0.0.5-py3-none-any.whl.

File metadata

  • Download URL: snowduck-0.0.5-py3-none-any.whl
  • Upload date:
  • Size: 82.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for snowduck-0.0.5-py3-none-any.whl
Algorithm Hash digest
SHA256 350170d7ce8bc2025648a9a3c8f3aebb8c6242298f2ade55f33080ec1c279516
MD5 af5e88936aea7fa503a1627e75839310
BLAKE2b-256 94facb26de0c7885e063347081a8af926cdebaf3d0a25e867ca95ff20018e392

See more details on using hashes here.

Provenance

The following attestation bundles were made for snowduck-0.0.5-py3-none-any.whl:

Publisher: release.yml on hupe1980/snowduck

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