Query Uses — Schema Impact Analysis
ztd query uses is a static analysis command that answers "which SQL queries are affected by this schema change?" without running a database.
The command-line UX is provided by @rawsql-ts/ztd-cli, and the reusable analysis engine behind it now lives in @rawsql-ts/sql-grep-core.
Prerequisites
ztd query uses scans the active QuerySpec set for the project. By default it discovers JSON or TypeScript specs recursively under the current project root, then follows each spec's sqlFile field and parses the referenced SQL for analysis.
Common project shapes:
project-root/
├── src/
│ └── features/
│ ├── users/
│ │ └── persistence/
│ │ ├── users.spec.ts
│ │ └── users.sql
│ └── orders/
│ └── persistence/
│ ├── orders.spec.ts
│ └── orders.sql- Spec files are required. Plain
.sqlfiles without a spec are not scanned. If you have not runztd inityet, start there. - Project-wide discovery is the default. QuerySpec files are discovered recursively under the project root unless you narrow the scan with
--scope-dir. - Feature-local specs are first-class. The preferred contract is a spec that keeps
sqlFilerelative to the spec itself, for example./users.sql. - Shared SQL roots still work. If your project intentionally keeps SQL in one shared tree, you can still use
--sql-rootas a fallback resolver. - No database connection is needed. The analysis is purely static. It parses SQL text, not a live schema.
Why not grep?
A naive grep "sale_items" on your SQL files will match table names, but it cannot distinguish:
- A table referenced in a
FROMclause vs. a comment or string literal - A column used in a
JOINcondition vs. an unrelated alias - Which specific statements (out of many in a project) actually depend on the target
ztd query uses parses each SQL statement into an AST and resolves table/column references with schema awareness. It tells you how each query uses the target, not just that the name appears somewhere in the file.
| Approach | Finds references | Schema-aware | Shows usage kind | Filters noise |
|---|---|---|---|---|
grep | Yes | No | No | No |
ztd query uses | Yes | Yes | Yes (join, select, ...) | Yes |
Two output formats: human and machine
Every command supports --format text (default) and --format json.
Text is designed for human review in the terminal:
npx ztd query uses table public.sale_lines --exclude-generatedmode: exact
view: impact
target: table public.sale_lines
catalogs: 5
statements: 5
matches: 2
fallback matches: 0
parse warnings: 0
unresolved sql files: 0
Affected queries:
- sales.byId sales.byId:1 high
sql_file: src/sql/sales/get-sale-by-id.sql
statement_fingerprint: 1dc4401557aa
source: ast
usageKinds: join=1
notes: (none)
- sales.list sales.list:1 high
sql_file: src/sql/sales/list-sales.sql
statement_fingerprint: 03249e9c4052
source: ast
usageKinds: join=1
notes: (none)JSON is designed for AI agents and CI pipelines. The same structured data is emitted as a single JSON object, making it easy to parse programmatically:
npx ztd query uses table public.sale_lines --exclude-generated --format jsonUse --out <path> to write the result to a file instead of stdout, which is useful for piping into downstream tools or archiving evidence.
If you need the same AST-based impact analysis in your own tooling, import @rawsql-ts/sql-grep-core directly and call the report builder without the rest of the CLI.
The command does not scan every .sql file in the repository blindly. It scans the SQL files referenced by the active QuerySpec set, so unregistered SQL stays outside the impact report until it has a spec.
When to use it
Before a table rename
"I want to rename
sale_itemstosale_lines. What breaks?"
npx ztd query uses table public.sale_items --exclude-generatedIf matches: 2, you know exactly which 2 queries need updating. After renaming, run the new name to confirm they moved over:
npx ztd query uses table public.sale_lines --exclude-generatedBefore a column rename
"I want to rename
products.nametoproducts.title. Which queries reference it?"
npx ztd query uses column public.products.name --exclude-generatedBefore a column type change
"I'm changing
sale_items.quantityfromintegertonumeric. Who uses it?"
npx ztd query uses column public.sale_items.quantity --exclude-generatedThe command does not judge type compatibility. It tells you every statement that still references the column so you can inspect each one.
Checking a new table/column is not yet referenced
"I just added
sale_discounts. Is anything using it yet?"
npx ztd query uses table public.sale_discountsmatches: 0
Affected queries:
(none)A clean zero confirms no query depends on it yet.
Detail view: edit-ready evidence
Add --view detail to get the exact snippet and file location for each match:
npx ztd query uses column public.products.title --view detail --exclude-generatedPrimary matches:
- sales.byId sales.byId:1 select high
sql_file: src/sql/sales/get-sale-by-id.sql
statement_fingerprint: b80eaec367cd
source: ast
snippet: p.title, ', ' order by si.line_no) as product_names
notes: (none)
exprHints: function, projection
location: 10:14-10:21 @ 262-269The location field gives you the line and column range, so you can jump straight to the code.
Learn more
- Impact Checks reference — full option reference, output field descriptions, scenario playbook, and troubleshooting