Skip to content

Commit 645ebac

Browse files
docs: add ROADMAP and refresh Key Numbers post W013
ROADMAP.md sets v0.7 theme as Performance Rules Pack (extending W017 leading-wildcard-like, W018 or-across-columns, W019 count-distinct-unbounded). Lists five candidate rules for v0.7, tentative v0.8 dialect-aware coverage direction, and the always-out-of-scope set so drive-by PRs have a place to point. README Key Numbers refreshed to reflect main post W013 merge: 39 rules (10 errors, 24 warnings, 5 Python-source), 152 tests.
1 parent 6240050 commit 645ebac

2 files changed

Lines changed: 104 additions & 3 deletions

File tree

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
- [Download Stats](https://pypistats.org/packages/sql-sop)
1515
- Install: `pip install sql-sop`
1616
- [Profile](https://github.com/Pawansingh3889)
17-
- **Contributing:** [`CONTRIBUTING.md`](CONTRIBUTING.md) · [`GOVERNANCE.md`](GOVERNANCE.md) · [`CODE_OF_CONDUCT.md`](CODE_OF_CONDUCT.md) · [`SECURITY.md`](SECURITY.md) · [`NOTICE`](NOTICE)
17+
- **Contributing:** [`CONTRIBUTING.md`](CONTRIBUTING.md) · [`ROADMAP.md`](ROADMAP.md) · [`GOVERNANCE.md`](GOVERNANCE.md) · [`CODE_OF_CONDUCT.md`](CODE_OF_CONDUCT.md) · [`SECURITY.md`](SECURITY.md) · [`NOTICE`](NOTICE)
1818

1919
## Why Does This Exist?
2020

@@ -24,8 +24,8 @@ One bad SQL query can delete production data, expose customer records, or bring
2424

2525
| | |
2626
|---|---|
27-
| Rules | 38 (10 errors, 23 warnings, 5 Python-source) |
28-
| Tests | 149 |
27+
| Rules | 39 (10 errors, 24 warnings, 5 Python-source) |
28+
| Tests | 152 |
2929
| Coverage | 86% |
3030
| Scan speed | 0.08s across 200 files |
3131
| PyPI downloads | 500+/month |

ROADMAP.md

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
# sql-sop roadmap
2+
3+
This is the maintainer's working roadmap. It tells you what's likely to land in upcoming releases, what's deliberately out of scope, and where contributions are most welcome. It's a living document — open an issue to discuss anything that surprises you.
4+
5+
Last updated: 2026-04-27.
6+
7+
## Current release
8+
9+
**v0.6.x** is in maintenance. Headline features as of v0.6.1 on PyPI: 38 rules (33 SQL + 5 Python), T-SQL safety pack (T001-T005), migration guards, inline `-- sql-guard: disable=...` directives, `.sql-guard.yml` config, `--changed-only` flag, SARIF 2.1.0 output for GitHub Code Scanning, libCST scanner for Python source.
10+
11+
`main` is at 39 rules after [W013 window-without-partition](https://github.com/Pawansingh3889/sql-guard/pull/21) merged 2026-04-26. **v0.6.2 patch release pending** to ship W013 to PyPI users.
12+
13+
## v0.7 — Performance Rules Pack
14+
15+
**Theme:** catch SQL patterns that compile fine and run slowly. Builds on the v0.6 W017 / W018 / W019 trio (leading wildcard, OR across columns, count-distinct-unbounded).
16+
17+
The performance-traps angle is already in sql-sop's tagline and matches what real users hit in production. v0.7 doubles down with a coordinated set of new rules + sharper messaging on existing ones.
18+
19+
### In scope
20+
21+
New performance-flavoured warning rules. Each is a single rule mirroring the W019 shape (one regex or libCST visitor, fixture line, two tests, README entry, CHANGELOG bullet). Specific candidates:
22+
23+
- **cross-join-without-on** — flag explicit `CROSS JOIN` or implicit cartesian (comma-separated FROM with no WHERE binding the join) where the result is likely unintended.
24+
- **function-on-indexed-column**`WHERE UPPER(email) = 'x'` defeats a B-tree index. Flag function calls applied to columns inside WHERE or JOIN ON predicates, with an allowlist for cases that are actually fine (e.g. `LOWER(email)` against a functional index).
25+
- **scalar-udf-in-where** — scalar UDFs in WHERE force row-by-row evaluation in T-SQL. Initially T-SQL flavour; Postgres equivalent (`VOLATILE` functions in WHERE) as a follow-up.
26+
- **negate-of-equality**`WHERE NOT col = x` and `col != x` defeat range-based index access in many engines. Flag with rationale.
27+
- **select-star-in-view-or-cte**`SELECT *` inside a view or CTE freezes the column list and surprises downstream callers when the underlying table changes. Flag with suggestion to enumerate.
28+
29+
Also in scope:
30+
31+
- **Dialect-aware messaging on existing rules.** W019's bypass list already recognises `WHERE`, `GROUP BY`, `LIMIT`, `TOP`, `FETCH NEXT`. Other rules could similarly adjust suggestion text per dialect (Postgres advice for Postgres queries, T-SQL for T-SQL, etc.). Where the rule fires the same but the fix differs, the message should be specific.
32+
- **`--severity` threshold improvements.** Currently uppercases input; should accept comma-separated lists like `--severity error,warning` and reject typos with a clear error.
33+
- **Self-benchmark on every release.** Add a tiny perf gate to CI that asserts sql-sop stays under N ms per 1000 lines of SQL on a fixture corpus. Catches regressions caused by adding rules.
34+
35+
### Out of scope for v0.7
36+
37+
- LSP server / IDE integration (queued for v0.9+)
38+
- sqlglot-based AST detection (queued for v0.8 or later — major architecture change)
39+
- New output formats beyond SARIF (text, JSON, SARIF already cover the realistic CI matrix)
40+
- Auto-fix application (some rules already include suggestion text; actually applying fixes is a v1.0 candidate)
41+
- Plugin system for third-party rules (out of scope until the core rule API is stable)
42+
43+
### Contribution shape for v0.7
44+
45+
Each new rule follows the same pattern. See `sql_guard/rules/warnings.py:CountDistinctUnbounded` (W019) for the canonical example, and [PR #29](https://github.com/Pawansingh3889/sql-guard/pull/29) for the full review cycle.
46+
47+
PR checklist:
48+
49+
1. New rule class registered in `sql_guard/rules/__init__.py`
50+
2. Fixture line in `tests/fixtures/warnings.sql`
51+
3. "Fires on bad SQL" test in `tests/test_rules.py`
52+
4. "Does not fire on safe SQL" test
53+
5. README rule table + Key Numbers count updated
54+
6. CHANGELOG entry under `## [Unreleased]``### Added`
55+
7. Conventional commit style (`feat(rules): add Wxxx ...`)
56+
57+
The W019 mvanhorn PR ([#29](https://github.com/Pawansingh3889/sql-guard/pull/29)) and W013 Prabhu PR ([#21](https://github.com/Pawansingh3889/sql-guard/pull/21)) are good references for the full review cycle, including how rebases get handled when main moves.
58+
59+
## v0.8 — Dialect-Aware Coverage (tentative)
60+
61+
**Theme:** expand dialect-specific safety packs.
62+
63+
The T-SQL pack (T001-T005) already exists. v0.8 adds Postgres and Redshift packs, plus a dialect detection layer in the rule engine so individual rules don't have to invent their own detection.
64+
65+
### In scope (subject to v0.7 outcomes)
66+
67+
- **Postgres pack (P-prefix-Postgres rules, naming TBD).** Examples: `SERIAL` discouraged in favour of `GENERATED ALWAYS AS IDENTITY`, JSONB anti-patterns (`->>` chains where `jsonb_path_query` fits), `LATERAL` join misuse.
68+
- **Redshift pack.** `SORTKEY` / `DISTKEY` reminders, `IDENTITY(seed, step)` syntax checks, the bits where Redshift diverges from Postgres SQL.
69+
- **Dialect detection** from file path (`migrations/redshift/*.sql` infers Redshift), from `.sql-guard.yml` config (`dialect: postgres`), or from an inline comment marker (`-- sql-guard: dialect=postgres`).
70+
71+
### Out of scope for v0.8
72+
73+
- Snowflake or BigQuery packs (sqlfluff covers those well; sql-sop's wedge is T-SQL + migration safety + Python source scanning)
74+
75+
## v0.9 and beyond — directional, not committed
76+
77+
- **LSP server** for editor integration. Probably built on the existing libCST + rule engine, exposing diagnostics over the LSP protocol.
78+
- **VSCode extension** that wraps the LSP server.
79+
- **sqlglot-based AST detection** for rules where regex hits its ceiling. Big change; would involve a dual code path during transition.
80+
- **Plugin system** for third-party rule authors. Only after the core rule API has been stable for two minor versions.
81+
82+
## Always-welcome contributions
83+
84+
These don't need to wait for a milestone:
85+
86+
- Bug reports with minimal repro SQL and expected vs actual output
87+
- New test cases that exercise edge conditions in existing rules, especially dialect quirks
88+
- Documentation fixes (typos, clearer examples in README rule tables)
89+
- Performance improvements where benchmarked (don't optimise without data — `pytest --benchmark` numbers in the PR description)
90+
91+
## Always out of scope
92+
93+
- Generic Python linting (use [ruff](https://github.com/astral-sh/ruff))
94+
- Generic SQL formatting (use [sqlfluff](https://github.com/sqlfluff/sqlfluff))
95+
- Database connection or query execution. sql-sop is static analysis; runtime concerns belong elsewhere.
96+
- ORM-specific rules beyond Python + SQLAlchemy via libCST. Django ORM, Pandas, polars are not the focus.
97+
- Rules without a concrete bad-pattern + good-pattern example. Style preferences without measurable impact don't make the cut.
98+
99+
## How to read this document
100+
101+
The version themes are aspirational. A v0.7 PR that doesn't fit the performance theme but is a clear win still has a good chance of landing — the theme orients new contributions, it doesn't gate every merge. If you're not sure whether something belongs, open an issue and ask before writing the code.

0 commit comments

Comments
 (0)