Skip to content

feat(Snowflake): Add Snowflake dialect#9

Open
khvn26 wants to merge 6 commits into
mainfrom
feat/snowflake-dialect
Open

feat(Snowflake): Add Snowflake dialect#9
khvn26 wants to merge 6 commits into
mainfrom
feat/snowflake-dialect

Conversation

@khvn26
Copy link
Copy Markdown
Member

@khvn26 khvn26 commented May 15, 2026

Contributes to Flagsmith/flagsmith#5663.

Initial scaffold for flagsmith-sql-flag-engine — sibling to flagsmith-flag-engine (Python) and flagsmith-rust-flag-engine (Rust). Translates SegmentContext predicate trees into SQL WHERE expressions.

The translator emits a predicate that runs against a single IDENTITIES table aliased i; trait-bound conditions become path-extractable lookups via the active Dialect. Snowflake reads from a VARIANT column, but the translator never assumes that storage shape. PERCENTAGE_SPLIT and :semver-marked comparators compile to inline pure-SQL.

Public API

from flag_engine.context.types import EvaluationContext, SegmentContext

from flagsmith_sql_flag_engine import TranslateContext, translate_segment
from flagsmith_sql_flag_engine.dialects import SnowflakeDialect

eval_context: EvaluationContext = {
    "environment": {"key": "n9fbf...3ngWhb", "name": "Production"},
}
ctx = TranslateContext(evaluation_context=eval_context, dialect=SnowflakeDialect())

segment: SegmentContext = ...  # your segment definition
where_expr = translate_segment(segment, ctx)

EnvironmentContext.key is used directly as the environment_id literal in emitted SQL — no separate integer PK. IDENTITIES holds a STRING environment_id column matching the engine's vocabulary.

What's included

  • uv-managed Python package, src/ layout, py.typed
  • Dialect protocol with SnowflakeDialect implementation; regex-flavour gating lives on the dialect via regex_supports, so future engines aren't forced into RE2's restricted feature set
  • engine-test-data as a git submodule pinned to v3.7.0
  • 55 unit tests (translator SQL-shape regression, no Snowflake required)
  • 599 + 3 xfailed engine-parity tests parametrised over engine-test-data and a per-dialect DialectTestHarness; new dialects extend by writing one harness module under tests/harnesses/
  • mypy strict across src/ and tests/
  • CI workflow: lint + typecheck + unit + engine-parity gated on SNOWFLAKE_* secrets; 100% line + branch coverage gate via Cobertura
  • Renovate config: CVEs only for deps, aggressive bumps on engine-test-data releases via the git-submodules manager (mirrors the Python engine's setup)
  • CODEOWNERS: * @flagsmith/flagsmith-back-end, mirroring the Python engine

Operator coverage

Operator Translatable Notes
EQUAL, NOT_EQUAL, IN yes
IS_SET, IS_NOT_SET yes traits:"<key>" IS NOT NULL / IS NULL
CONTAINS, NOT_CONTAINS yes
GREATER_THAN, LESS_THAN plus _INCLUSIVE yes
MODULO yes
PERCENTAGE_SPLIT yes inlined MD5-mod-9999; ~0.005% diverge on hash==9998
REGEX partial dialect-flavour gated; unsupported patterns → caller fallback
:semver-marked comparators yes major.minor.patch only; ignores prerelease

Performance

Measured on COMPUTE_WH X-Small, query result cache disabled, warehouse SUSPENDed before each timed query so reads come off remote storage rather than warehouse-local SSD:

identities simple, IN + IS_SET multi, 4 conditions pure %Split
10M 1.05s 1.16s 0.50s
100M 1.31s 1.43s 0.95s
870M 4.11s 4.27s 0.49s

The %Split row above hashes on the implicit $.identity.key subject and so doesn't read traits; a PERCENTAGE_SPLIT against a trait property pays the per-row trait-read cost on top of the hash. Warehouse-scaling is roughly linear in warehouse size — divide the X-Small numbers by the warehouse-size multiplier for an estimate.

khvn26 added 4 commits May 15, 2026 19:23
Adds the repo plumbing the rest of the branch builds on:

  - pyproject (uv build backend, mypy strict, 100% branch coverage gate,
    clickhouse-connect dev dep)
  - Makefile (install / lint / typecheck / test)
  - pre-commit (ruff, uv-lock, flagsmith-lint-tests, local mypy)
  - GitHub Actions CI: lint → typecheck → ClickHouse docker-compose →
    test → cobertura coverage gate
  - engine-test-data submodule pinned at v3.7.0
  - docker-compose for the ClickHouse parity harness
  - CODEOWNERS, renovate, .python-version, gitignore additions
  - py.typed marker and empty package skeleton

beep boop
beep boop
@khvn26 khvn26 requested a review from a team as a code owner May 15, 2026 19:06
@khvn26 khvn26 requested review from emyller and removed request for a team May 15, 2026 19:06
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 15, 2026

File Coverage Missing
All files 100%

Minimum allowed coverage is 100%

Generated by 🐒 cobertura-action against 67cc1ed

@khvn26 khvn26 force-pushed the feat/snowflake-dialect branch from 87fea78 to 67cc1ed Compare May 18, 2026 10:22
Base automatically changed from initial-scaffold to main May 19, 2026 17:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant