Skip to content

Commit 40d8d5b

Browse files
committed
feat!: name built-in Rules SQLCLEAN and own the host contract
Built-in Rule codes are SQLCLEANnnn instead of SQCnnn, custom Rule codes start with XSQLCLEAN, and the parse error is SQLCLEAN999. The embedding API no longer carries SQLBuild names. Hosts write the SQLClean placeholder prefixes exported from constants, describe a test or macro wrapper with one fixture_harness request object instead of allows_ceremonial_select and allows_empty_fixture_star, and derive relation_keys themselves: DeclaredRelation and declared_relation_keys are removed. BREAKING CHANGE: SQC and XSQC codes are now SQLCLEAN and XSQLCLEAN, and the lint request replaces the two harness flags with fixture_harness.
1 parent ec34b41 commit 40d8d5b

82 files changed

Lines changed: 1168 additions & 1184 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.github/demos/check-fix.gif‎

4.82 KB
Loading

‎README.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ SQLClean in other configurations, on the same files:
6767

6868
| SQLClean command | Wall time |
6969
|---|---:|
70-
| `sqlclean check --select SQC` (every built-in Rule) | 1.33 s |
70+
| `sqlclean check --select SQLCLEAN` (every built-in Rule) | 1.33 s |
7171
| `sqlclean check` plus three custom Python Rules | 2.27 s |
7272
| `sqlclean check` rerun with nothing changed (result cache) | 0.23 s |
7373

@@ -114,7 +114,7 @@ def lowered(operand: ast.Expression) -> bool:
114114

115115

116116
@rule(
117-
code="XSQCTEAM001",
117+
code="XSQLCLEANTEAM001",
118118
message="Email comparisons must be case-insensitive",
119119
remediation="Compare LOWER(email) with LOWER(...) instead.",
120120
enabled_by_default=True,

‎benchmarks/linters/README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ and peak memory with `/usr/bin/time`, and every lint command writes JSON finding
3434
| Variant | Command |
3535
|---|---|
3636
| `sqlclean` | `sqlclean check --output-format json` (13 default Rules) |
37-
| `sqlclean_all` | `sqlclean check --select SQC --output-format json` (all 45 Rules) |
37+
| `sqlclean_all` | `sqlclean check --select SQLCLEAN --output-format json` (all 45 Rules) |
3838
| `sqlclean_custom` | `sqlclean check --config custom.toml --output-format json` (default Rules and the three Python Rules in `rules/`) |
3939
| `sqlclean_format` | `sqlclean format --check` |
4040
| `sqruff` | `sqruff lint -f json .` |

‎benchmarks/linters/bench.sh‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ trap 'rm -rf "$WORK"' EXIT
3434

3535
declare -A CMD
3636
CMD[sqlclean]="$SQLCLEAN check --output-format json"
37-
CMD[sqlclean_all]="$SQLCLEAN check --select SQC --output-format json"
37+
CMD[sqlclean_all]="$SQLCLEAN check --select SQLCLEAN --output-format json"
3838
# The default Rules plus the three Python Rules in rules/, copied into the work directory.
3939
CMD[sqlclean_custom]="$SQLCLEAN check --config custom.toml --output-format json"
4040
# sqruff's and SQLFluff's default rules include layout; SQLClean checks layout with its formatter.

‎benchmarks/linters/rules/layers.py‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99

1010
@rule(
11-
code="XSQCLAYER001",
11+
code="XSQLCLEANLAYER001",
1212
message="Mart reads a raw source",
1313
remediation="Read the staging model instead.",
1414
enabled_by_default=True,
@@ -26,7 +26,7 @@ def marts_read_staging(*, statement: Statement, ctx: RuleContext) -> list[Findin
2626

2727

2828
@rule(
29-
code="XSQCLAYER002",
29+
code="XSQLCLEANLAYER002",
3030
message="Staging model reads another model",
3131
remediation="Staging models read only raw sources and seeds.",
3232
enabled_by_default=True,
@@ -46,7 +46,7 @@ def staging_reads_sources(*, statement: Statement, ctx: RuleContext) -> list[Fin
4646

4747

4848
@rule(
49-
code="XSQCDET001",
49+
code="XSQLCLEANDET001",
5050
message="Model calls a nondeterministic function",
5151
remediation="Pass the time or seed in as a column so reruns give the same rows.",
5252
enabled_by_default=True,

‎benchmarks/linters/summarize.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ def count_findings(variant: str, out: str) -> tuple[int, int]:
4040
data = json.loads(out)
4141
if variant.startswith("sqlclean"):
4242
codes = [finding["code"] for finding in data["findings"]]
43-
return len(codes), codes.count("SQC999")
43+
return len(codes), codes.count("SQLCLEAN999")
4444
if variant == "sqruff":
4545
codes = [finding.get("code") for findings in data.values() for finding in findings]
4646
return len(codes), sum(1 for code in codes if code in (None, "PRS"))

‎crates/sqlclean-cli/skill/SKILL.md‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
name: sqlclean
3-
description: ALWAYS load this skill when linting, fixing or formatting SQL with SQLClean, editing sqlclean.toml, writing or testing custom Rules (Python @rule functions with XSQC codes), recording Rule exceptions, or reading SQLClean findings (SQC codes, SQC999 parse errors) in CI, JSON or SARIF output.
3+
description: ALWAYS load this skill when linting, fixing or formatting SQL with SQLClean, editing sqlclean.toml, writing or testing custom Rules (Python @rule functions with XSQLCLEAN codes), recording Rule exceptions, or reading SQLClean findings (SQLCLEAN codes, SQLCLEAN999 parse errors) in CI, JSON or SARIF output.
44
---
55
<!-- generated-by: sqlclean skills -->
66

@@ -17,7 +17,7 @@ engine extracts from each statement.
1717
`[rules]`). Paths in it are relative to its directory.
1818
2. **Check.** `sqlclean check [PATHS]` exits 0 when clean, 1 with findings, 2 on errors. Use
1919
`--output-format json` when you need to read findings programmatically.
20-
3. **Explain.** `sqlclean rules SQC001` shows a Rule's message, fix safety and remediation.
20+
3. **Explain.** `sqlclean rules SQLCLEAN001` shows a Rule's message, fix safety and remediation.
2121
4. **Fix.** `sqlclean fix --diff` previews safe fixes plus formatting; `sqlclean fix` writes them.
2222
Fixes marked unsafe can change query results, such as `= NULL` becoming `IS NULL`. Never pass
2323
`--unsafe-fixes` without the user's say-so.
@@ -31,16 +31,16 @@ engine extracts from each statement.
3131
`[[rules.rule_exceptions]]` entry with the Rule, path and a `reason`. Use
3232
`[[rules.rule_ignores]]` only for whole paths a Rule does not apply to.
3333
- An exception that no longer matches a finding is reported as stale; remove it.
34-
- `SQC999` is a parse error. It cannot be ignored: fix the SQL or set the right `dialect`,
34+
- `SQLCLEAN999` is a parse error. It cannot be ignored: fix the SQL or set the right `dialect`,
3535
globally or per path under `[[dialects]]`.
36-
- `--select` and `--ignore` take codes or prefixes such as `SQC001` or `SQC`.
36+
- `--select` and `--ignore` take codes or prefixes such as `SQLCLEAN001` or `SQLCLEAN`.
3737
- Results are cached in `.sqlclean/cache/`. Use `--no-cache` only when debugging a custom Rule
3838
that imports helpers from outside its `[rules] custom` paths.
3939

4040
## Custom Rules
4141

4242
- A custom Rule is a function decorated with `@rule` from `sqlclean`, in a file under a path
43-
listed in `[rules] custom`. Its code is `XSQC`, optional capital letters, then three digits.
43+
listed in `[rules] custom`. Its code is `XSQLCLEAN`, optional capital letters, then three digits.
4444
- The first keyword parameter names the subject: `statement: Statement`, `file: SqlFile` or
4545
`repository: Repository`. The second is `ctx: RuleContext`.
4646
- Return `ctx.finding(...)` values. Fixes are lists of `ctx.replace`, `ctx.insert_before`,

‎crates/sqlclean-cli/skill/references/docs/benchmarks.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ SQLFluff ran once.
1414
| Command | Wall time | CPU time | Peak memory | vs SQLClean defaults |
1515
|---|---:|---:|---:|---:|
1616
| `sqlclean check` (13 default Rules) | **0.81 s** | 2.5 s | 48 MiB | 1× |
17-
| `sqlclean check --select SQC` (all 45 Rules) | **1.33 s** | 3.8 s | 140 MiB | 1.6× |
17+
| `sqlclean check --select SQLCLEAN` (all 45 Rules) | **1.33 s** | 3.8 s | 140 MiB | 1.6× |
1818
| `sqlclean check` with three [custom Rules](#custom-rules) | **2.27 s** | 6.9 s | 182 MiB | 2.8× |
1919
| `sqlclean format --check` | **3.03 s** | 11.5 s | 49 MiB | 3.7× |
2020
| `sqruff lint` | 41.0 s | 114 s | 235 MiB | 51× |

‎crates/sqlclean-cli/skill/references/docs/cli/check.md‎

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ sqlclean check [OPTIONS] [PATHS]...
2929
```bash
3030
sqlclean check # every matching file under the configuration root
3131
sqlclean check models/orders.sql reports/ # only these files and directories
32-
sqlclean check --select SQC001,SQC004 # only these Rules
32+
sqlclean check --select SQLCLEAN001,SQLCLEAN004 # only these Rules
3333
sqlclean check --output-format sarif > sqlclean.sarif
3434
```
3535

@@ -50,28 +50,28 @@ when `include` does not match it, unless `exclude` does. See
5050
| `--config <PATH>` | Use this configuration file instead of the nearest `sqlclean.toml` |
5151

5252
`--select` and `--ignore` take a comma-separated list, or the flag repeated. A value is an exact
53-
code such as `SQC001` or a prefix such as `SQC` or `XSQCNAME`. A value that matches no Rule is an
53+
code such as `SQLCLEAN001` or a prefix such as `SQLCLEAN` or `XSQLCLEANNAME`. A value that matches no Rule is an
5454
error. See [Selecting Rules](../rules/overview.md#selecting-rules).
5555

5656
## Text output
5757

5858
```text
59-
error[SQC004]: Row selection is nondeterministic
59+
error[SQLCLEAN004]: Row selection is nondeterministic
6060
--> models/customers.sql:6:1
6161
|
6262
6 | LIMIT 10;
6363
| ^^^^^
6464
= help: Add ORDER BY with a deterministic tie-breaker before LIMIT or OFFSET.
6565
66-
error[SQC001]: Comparison with NULL is never true
66+
error[SQLCLEAN001]: Comparison with NULL is never true
6767
--> models/orders.sql:8:22
6868
|
6969
8 | WHERE o.cancelled_at = NULL
7070
| ^
7171
= help: Use IS NULL or IS NOT NULL when testing for NULL.
7272
= fix: available with `sqlclean fix --unsafe-fixes`
7373
74-
error: stale rule exception: SQC004 in models/orders.sql matches no finding; remove it from sqlclean.toml
74+
error: stale rule exception: SQLCLEAN004 in models/orders.sql matches no finding; remove it from sqlclean.toml
7575
7676
Found 3 problems (1 fixable with `sqlclean fix --unsafe-fixes`).
7777
```
@@ -92,7 +92,7 @@ and count characters, not bytes.
9292
{
9393
"findings": [
9494
{
95-
"code": "SQC004",
95+
"code": "SQLCLEAN004",
9696
"path": "models/customers.sql",
9797
"line": 6,
9898
"column": 1,
@@ -103,7 +103,7 @@ and count characters, not bytes.
103103
"fix": null
104104
},
105105
{
106-
"code": "SQC001",
106+
"code": "SQLCLEAN001",
107107
"path": "models/orders.sql",
108108
"line": 8,
109109
"column": 22,
@@ -116,7 +116,7 @@ and count characters, not bytes.
116116
],
117117
"stale_exceptions": [
118118
{
119-
"rule": "SQC004",
119+
"rule": "SQLCLEAN004",
120120
"path": "models/orders.sql",
121121
"relation": null
122122
}
@@ -140,7 +140,7 @@ text:
140140

141141
```json
142142
{
143-
"ruleId": "SQC001",
143+
"ruleId": "SQLCLEAN001",
144144
"level": "error",
145145
"message": {
146146
"text": "Comparison with NULL is never true. Use IS NULL or IS NOT NULL when testing for NULL."

‎crates/sqlclean-cli/skill/references/docs/cli/fix.md‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,14 @@ Files are chosen as for [`sqlclean check`](check.md).
3636
| `--no-cache` | Evaluate every file instead of reusing results for unchanged inputs |
3737
| `--config <PATH>` | Use this configuration file instead of the nearest `sqlclean.toml` |
3838

39-
Only fixes of selected Rules apply. `sqlclean fix --select SQC005` removes unused CTEs and
39+
Only fixes of selected Rules apply. `sqlclean fix --select SQLCLEAN005` removes unused CTEs and
4040
formats the files, and leaves every other finding alone.
4141

4242
## Output
4343

4444
```text
4545
Fixed 1 problem(s) and changed 1 file(s).
46-
error[SQC001]: Comparison with NULL is never true
46+
error[SQLCLEAN001]: Comparison with NULL is never true
4747
--> models/open_orders.sql:7:24
4848
|
4949
7 | WHERE cancelled_at = NULL
@@ -88,7 +88,7 @@ findings:
8888
formatter cannot format is reported as `<path>: could not format: <reason>` and keeps its fixes.
8989

9090
A file that does not parse gets no fixes and is reported as
91-
[`SQC999`](../rules/overview.md#parse-errors-sqc999).
91+
[`SQLCLEAN999`](../rules/overview.md#parse-errors-sqlclean999).
9292

9393
## Exit codes
9494

0 commit comments

Comments
 (0)