Metadata-Version: 2.5
Name: localtools-sql-formatter
Version: 1.0.1
Summary: Lint, fix and transpile SQL in any major dialect with sqlfluff and sqlglot (localtools, offline)
Project-URL: Source, https://github.com/chayprabs/localtools
License-Expression: MIT
License-File: LICENSE
Requires-Python: >=3.10
Requires-Dist: multipart>=1.2
Requires-Dist: sqlfluff[rs]<5,>=4.4
Requires-Dist: sqlglot>=30
Description-Content-Type: text/markdown

# SQL Formatter (localtools)

Lint, auto-fix and format SQL in 28 dialects with **sqlfluff**, and transpile between dialects with **sqlglot**.
Runs on your machine: a one-page web UI on `http://127.0.0.1:47117`, plus a CLI for scripts and CI.

## Install

| OS | command |
|---|---|
| Windows (PowerShell) | `irm https://raw.githubusercontent.com/chayprabs/localtools/main/sql-formatter/install.ps1 \| iex` |
| macOS / Linux | `curl -fsSL https://raw.githubusercontent.com/chayprabs/localtools/main/sql-formatter/install.sh \| bash` |
| PyPI | `pipx install localtools-sql-formatter` |

The script installs a self-contained build (bundled Python) into `~/.localtools/sql-formatter` and adds a launcher.

## Use

`localtools-sql-formatter` opens the UI. Paste SQL or drop `.sql` files (several at once), pick the dialect, then:

- **Lint**: every violation with line:column, rule code (linked to the sqlfluff docs) and whether it can be auto-fixed. Download the report as JSON.
- **Fix**: the fixed SQL with a diff, Copy and Download, plus what still needs a human.
- **Transpile**: rewrite between dialects (e.g. T-SQL `TOP`/`ISNULL` to Postgres `LIMIT`/`COALESCE`), with notes on unsupported constructs.

Options: rule selection/exclusion (`LT01,CP01`, `core`, `layout`, names, legacy aliases and wildcards), templater (Raw, Jinja, or placeholders `:name`, `?`, `$1`, `$name`, `%(name)s`, `%s`), and an uploaded `.sqlfluff` / `setup.cfg` / `tox.ini` / `pyproject.toml`. Config/default uses SQLFluff's Jinja default unless the uploaded config chooses another templater. Unknown rule selectors and placeholder styles are rejected.

```sh
localtools-sql-formatter lint models/*.sql --dialect postgres --format json   # or human | sarif; exit 1 on violations
localtools-sql-formatter fix query.sql --dialect snowflake                     # fixed SQL to stdout
localtools-sql-formatter fix *.sql --in-place --config .sqlfluff              # rewrite files; exit 1 if anything is left
localtools-sql-formatter fix - --diff < query.sql                             # stdin, unified diff
localtools-sql-formatter transpile q.sql --read tsql --write duckdb
localtools-sql-formatter dialects | rules
```

API: `POST /api/lint`, `/api/fix`, `/api/transpile` (multipart: `sql` and/or `file`..., `dialect`, `rules`, `exclude_rules`,
`templater`, `config` file; transpile: `read`, `write`), `GET /api/meta`. `/api/lint` with `format=sarif` returns SARIF 2.1.0.

## Engine and why

- **sqlfluff 4** (with its Rust parser, sqlfluffrs) is the most complete open-source SQL linter: dialect-aware parsing,
  ~70 rules, real auto-fix, Jinja/placeholder templating. Results are identical to the `sqlfluff` CLI with the same config
  (tested on TPC-H, sqlfluff's dialect fixtures, dbt's jaffle_shop and GitLab's schema).
- `fix` repeats sqlfluff's fix pass until nothing changes, so running it twice gives the same SQL; when sqlfluff
  oscillates between two layouts (it happens), the tool settles on one of them deterministically.
- **sqlglot** transpiles (sqlfluff cannot): it parses into an AST and regenerates SQL for 31 dialects. Output equals the
  `python -m sqlglot --identify false` CLI. It reformats in its own style, which is why lint/fix stay with sqlfluff.

## Limits and safety

- The web UI/API takes up to 512 KB of SQL and about 2,000 statements per run, and each run has a 120 s deadline
  (sqlfluff is thorough but slow: a messy 20 KB file can take 10+ s). Every run is a separate worker process that is
  killed at the deadline, when the browser disconnects, or when the server exits; at most 1–4 run at once (else HTTP 503).
  On Linux each worker is capped at 2 GB of memory. The CLI has no size limit or deadline.
- Config files are parsed, never executed: `library_path`, macro/loader paths (any `*_path` / `*_dir` key), the python and
  dbt templaters and `processes` are ignored and listed in the result. sqlfluff's 20 KB "skip large file" default is off.
- Files that do not parse are not fixed (like the sqlfluff CLI); the parse error shows line and column.
- In-place fixes use an atomic replacement and retain the file mode, UTF-8 BOM and CRLF convention. Old crashed request folders are swept after one hour at startup; active owners and linked folders are preserved.

## Cut

- dbt templater (needs a dbt project, adapters and a database connection) and the python templater (runs code): use
  `jinja`, which provides dbt's `ref`/`source`/`config` builtins.
- Automatic discovery of `.sqlfluff` files next to the SQL: pass `--config` explicitly.
- winget/Homebrew/Scoop packages: Python-runtime tools ship through the install scripts and PyPI.

## Update / uninstall

`localtools-sql-formatter update` · `localtools-sql-formatter uninstall` (pipx: `pipx upgrade|uninstall localtools-sql-formatter`).

## License

MIT. Bundled components: see THIRD_PARTY_NOTICES.md.
