EdgeSQL

Reference

The public surface, the product IR, the error catalog, and the dialect rules. Public names are Query, Filter, FilterSet, Preview, AuditRecord, SqlCraftError, col, select, and param.

Parse Inspect Transforms Preview Builders Product IR Errors Dialects HTTP

Parse

CallResult
Query.parse(sql, *, dialect, schema=None, mode="library")A Query, or a SqlCraftError
query.to_sql(dialect=None, pretty=False)SQL text. A parsed query keeps its dialect.
query.to_tree()The product IR document

Parse runs the gates in order and stops at the first miss: known dialect, non-empty text, one parse result, exactly one statement, a SELECT or WITH root, the dialect rules, column resolution, then the optional pglast check on Postgres.

Inspect

CallResult
query.tables()Physical tables in scope order. CTE names are excluded.
query.ctes()CTE aliases
query.columns()ColumnRef items: table, name, via, tags
query.filters()A FilterSet. Each item has scope, clause, op, columns, values, negated, sql, and path.
query.filters().where(column=, table=, scope=, clause=, op=)A filtered FilterSet
query.filters().to_dicts()JSON-ready dictionaries
query.params()[{"param": name}] in source order

A filter reports one conjunct. An OR group is one item. The via list records each CTE or derived table on the path to the physical table.

Transforms

Each call returns a new Query and leaves the original unchanged.

CallEffect
cte(name)Focus later verbs inside cte:name
rename_column(old, new, *, table, keep_output_names=True)Rename a column. A search transform: zero matches blocks the preview.
and_where(predicate, *, scope=None)Add a conjunct
where(predicate)Alias for and_where
limit(value)Set LIMIT
remove_filter(filter)Remove one top-level conjunct
replace_filter(filter, predicate)Replace one top-level conjunct
with_cte(name, query)Add a CTE. A duplicate name raises DUPLICATE_CTE.
rename_cte(old, new)Rename the definition and every reference
drop_cte(name)Remove an unreferenced CTE. A live reference raises CTE_IN_USE.
set_params(patches)Lane A value patches
inline_cte(name), rewrite(fn)Raise NOT_IN_V1
migrate(target)A blocked preview with reason MIGRATE_STUB

Value patches

opparamsNode kind
set_comparisonvalueComparison
set_betweenlow, highBetween
set_in_listvaluesInList
set_limitvalueLimit

A patch that sends left, op, column, or children raises STRUCTURE_PATCH. An unknown node id raises UNKNOWN_NODE.

Preview

MemberContent
before_sql, after_sqlPretty SQL in the parse dialect
ast_diffThe sqlglot.diff edit script
semantic_difftables, filters_added, filters_removed, joins_changed, projection_changed, limit_changed
blocked, blocked_reasonsBlocked reasons: NO_MATCH, REPARSE_FAILED, TABLE_SET_CHANGED, DISALLOWED_STATEMENT, MIGRATE_STUB
collapsedTrue when the pretty SQL did not change
fingerprintFirst 16 hex characters of SHA-256 of canonical SQL
apply(actor=)A new Query, or BLOCKED. Sets last_audit and query.audit.

Builders

from edgesql import col, param, select

query = (
    select("sales.orders")
    .where(col("status").eq("paid"))
    .where(col("amount").gt(param("floor")))
    .limit(100)
)
print(query.to_sql("postgres"))    # ... amount > %(floor)s LIMIT 100
print(query.to_sql("databricks"))  # ... amount > :floor LIMIT 100

col(name) offers eq, ne, gt, gte, lt, and lte. param(name) makes a marker. select(table) starts a SELECT *. A built query has no parse dialect, so both dialects are available.

Product IR

schemaVersion is "0.1". The document has schemaVersion, dialect, rootId, and a flat nodes map. Every node has kind, children, and editable. An editable node adds editMode: "param_value".

{
  "schemaVersion": "0.1",
  "dialect": "postgres",
  "rootId": "n_select",
  "nodes": {
    "n_select": {"kind": "Select", "children": ["n_from", "n_where"], "editable": false},
    "n_from": {"kind": "From", "table": "sales.orders", "children": [], "editable": false},
    "n_where": {"kind": "Where", "children": ["n_cmp_cust_eq"], "editable": false},
    "n_cmp_cust_eq": {
      "kind": "Comparison",
      "editable": true,
      "editMode": "param_value",
      "children": [],
      "op": "=",
      "left": {"column": "cust_id"},
      "right": {"value": 42}
    }
  }
}

A comparison is editable only when its right side is a literal, a boolean, a NULL, a negative number, or a parameter marker. A comparison against a column or a function is read-only.

Errors

SqlCraftError carries phase, code, hint, line, col, and track_id (12 lowercase hex characters). display() returns [phase/code] message, plus Hint: when a hint exists. to_body() returns the HTTP object.

PhaseCodes
parseUNKNOWN_DIALECT, EMPTY_SQL, PARSE_FAILED, MULTI_STATEMENT, UNSUPPORTED_STATEMENT, DIALECT_NODE, MIXED_MARKERS
resolveAMBIGUOUS_COLUMN, UNKNOWN_SOURCE, UNKNOWN_COLUMN
transformUNKNOWN_SCOPE, UNSUPPORTED_REMOVE, UNSUPPORTED_NODE, DUPLICATE_CTE, CTE_IN_USE, RECURSIVE_PROJECTION, STRUCTURE_PATCH, UNKNOWN_NODE, NOT_IN_V1
applyBLOCKED
renderCROSS_DIALECT
httpSTALE_FINGERPRINT, DRAFT_NOT_FOUND, CSRF_REQUIRED, DIALECT_MISMATCH

Dialects

TopicPostgresDatabricks
Quotes"name"`name`
Markers$1, %(name)s:name, ?
QUALIFYrefusedaccepted
SEMI and ANTI joinsrefusedaccepted
DISTINCT ONacceptedrefused
FETCHacceptedrefused
MAX RECURSION LEVELrefusedkept
Recursive CTEUNION or UNION ALLUNION ALL only
Mixed markersnot applicableMIXED_MARKERS

HTTP

RouteResult
GET /The HTML screen, with a session cookie and a CSRF token
GET /healthz{"ok": true}
GET /v1/examplesThe example gallery
POST /v1/queries201 with draft_id, dialect, and fingerprint
GET /v1/queries/{id}/treeThe product IR
PATCH /v1/queries/{id}/paramsA patch, guarded by If-Match
POST /v1/queries/{id}/previewBefore, after, diff, reasons, preview_fingerprint, and filter_values
POST /v1/queries/{id}/applyA new draft and the audit record
POST /v1/queries/{id}/to_sqlSQL in the draft dialect
SituationStatusCode
Created201none
Read, preview, or SQL200none
Bad SQL or bad patch422catalog code
Stale fingerprint409STALE_FINGERPRINT
Unknown draft404DRAFT_NOT_FOUND
Missing CSRF403CSRF_REQUIRED

Credits and license

Copyright 2026 Raphael Mansuy. Licensed under the Apache License, Version 2.0. SQLGlot supplies the parser and the printer and keeps its own MIT license. The Postgres regression fixtures keep the PostgreSQL license, and the Databricks examples come from the Databricks documentation. See the notice for the full list.

Headshot of Raphael Mansuy, author of EdgeSQL.

Raphael Mansuy

Author of EdgeSQL

Raphael is a data engineering and AI strategist with more than 20 years of global technology leadership experience. He works on democratizing data management and AI, and helps organizations build scalable data platforms. His work covers resilient data infrastructure, machine learning models, and coaching teams on practice. He leads a startup studio in Hong Kong.

EdgeSQL started from one observation: changing SQL with string replacement breaks as soon as two edits touch the same name. A typed tree with a preview gate is the smallest honest fix, so he built it and tested it against the official Postgres and Databricks statements.

Recognition

Favikon ranks Raphael at 12 in Top 20 AI Experts in France in 2026, with a Favikon Authority Score of 7,012 points. The list covers the most visible AI practitioners in France. The entry cites his 20 years of data and AI leadership, his work on scalable data platforms, and the startup studio he leads in Hong Kong.

Source: Favikon, Top 20 AI Experts in France in 2026.

Cover of The Definitive Guide to Data Integration, with Raphael Mansuy as a co-author.

The Definitive Guide to Data Integration

Packt, 2024

Unlock the power of data integration to efficiently manage, transform, and analyze data. Raphael is a co-author with Pierre-Yves Bonnefoy, Emeric Chaize, Mehdi Tazi, and Stephane Heckel.

Read it on O'Reilly

Other projects by Raphael

EdgeQuake knowledge graph view: 200 nodes and 840 edges over an AI research corpus.

EdgeQuake

Graph-RAG in Rust: one binary, one Postgres, any LLM. It reads PDFs and text, builds a knowledge graph in PostgreSQL, and answers questions with sources. Six retrieval modes: naive, local, global, hybrid, mix, and bypass. Apache 2.0.

EdgeCrab illustration: a comic battle between EdgeCrab and OpenClaw.

EdgeCrab

A personal and coding SuperAgent in one native Rust binary, with a ratatui terminal UI and a ReAct tool loop. It supports 24 LLM providers and 17 messaging gateways. Install with npm install -g edgecrab-cli, pip install edgecrab-cli, or cargo install edgecrab-cli.

EdgeWhisper banner: voice dictation, on-device AI for macOS.

EdgeWhisper

Voice dictation for macOS, powered by Voxtral from Mistral AI. It runs fully on the device, with no cloud and no data collection. It supports 13 languages, an Apple Silicon Mac, and macOS 14 or later.

Building something with SQL? Tell Raphael about it.

Connect on LinkedIn