Skip to content
Jacob-9909Public

About

Fold a wide physical schema into a few wide logical models an LLM can read in one shot, then expand the SQL back.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

tablefold

English | 한국어

CI License: MIT

Fold a wide physical schema into a few wide logical models an LLM can read in one shot, then expand the LLM's logical SQL back into executable physical SQL.

53 physical tables  ──fold──▶  7 logical models (~3k tokens)
                    ◀─expand──  executable SQL

Text-to-SQL often fails on real databases because of long DDL and complex joins. tablefold groups related tables into wide models such as orders and products, so the LLM does not have to reason about joins.

Install

uv sync
uv sync --extra postgres   # to read the schema directly from PostgreSQL

Usage

# Fold the physical schema into logical models
tablefold fold --ddl fixtures/retail_50.sql

# Print schema context for an LLM prompt
tablefold context --ddl fixtures/retail_50.sql --field-budget 120

# Expand logical SQL into physical SQL
tablefold expand "SELECT customer_tier_label, SUM(grand_total) FROM orders GROUP BY 1" \
    --ddl fixtures/retail_50.sql

Python API:

from tablefold.introspect.ddl import DDLIntrospector
from tablefold.pipeline import fold
from tablefold.expand import expand

schema = DDLIntrospector.from_path("schema.sql").introspect()
result = fold(schema)

print(expand("SELECT SUM(grand_total) FROM orders", result.layer, result.graph).sql)

How It Works

  1. Introspect: Reads tables, columns, and keys from a DDL file or PostgreSQL.
  2. FK recovery: Infers missing foreign keys from naming rules such as customer_id → customers.id.
  3. Anchor selection: Scores fact tables and uses greedy set cover to reach maximum coverage with the fewest models. With --llm, an LLM refines model names and domain decisions.
  4. Synthesis: N:1 relations are flattened in. 1:N child tables are pre-aggregated with GROUP BY to prevent row fan-out.
  5. Expand: Keeps only the joins needed for the fields the query actually uses and builds physical CTE SQL.

Without the LLM option, the whole process is deterministic. See docs/pipeline_architecture.md (Korean) for the full design.

Fold Options

Option Default Description
--coverage 0.90 Target table coverage
--min-gain 2 Minimum number of new tables one model must cover
--max-cost 10 Allowed fields per new table
--llm off Use an LLM to refine anchor selection and model names

Development

uv run pytest tests/
uv run ruff check src tests

License

MIT

About

Fold a wide physical schema into a few wide logical models an LLM can read in one shot, then expand the SQL back.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages