Skip to content

Commit 692b624

Browse files
authored
core: analyze every dialect through the new analysis core (#4538)
1 parent 982c26b commit 692b624

96 files changed

Lines changed: 8218 additions & 51743 deletions

Some content is hidden

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

CLAUDE.md

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -89,18 +89,23 @@ go test -v ./internal/config -run TestConfig
8989
go test -race ./internal/config
9090
```
9191

92-
## Test Types
92+
## Testing Strategy
9393

94-
### 1. Unit Tests
94+
**Cover new work with end-to-end tests, not unit tests.** A change to the
95+
compiler, an engine, the analysis core or codegen is exercised by running sqlc
96+
the way a user does — a schema, a query file and a committed golden output —
97+
so the test says what sqlc produces rather than what an internal function
98+
returns. Internal APIs move around; the SQL that goes in and the output that
99+
comes out is the contract worth pinning down.
95100

96-
- **Location:** Throughout the codebase as `*_test.go` files
97-
- **Run without:** Database or external dependencies
98-
- **Examples:**
99-
- `/internal/config/config_test.go` - Configuration parsing
100-
- `/internal/compiler/selector_test.go` - Compiler logic
101-
- `/internal/metadata/metadata_test.go` - Query metadata parsing
101+
Adding coverage means adding a directory under `/internal/endtoend/testdata/`,
102+
not a `*_test.go` next to the code. Reach for a unit test only when the
103+
behavior genuinely cannot be reached through the CLI, and say why in the test.
102104

103-
### 2. End-to-End Tests
105+
Some `*_test.go` files predate this and remain; they are not a precedent for
106+
new ones.
107+
108+
### End-to-End Tests
104109

105110
- **Location:** `/internal/endtoend/`
106111
- **Requirements:** `--tags=examples` flag and running databases
@@ -111,7 +116,15 @@ go test -race ./internal/config
111116
- `TestJsonSchema` - JSON schema validation
112117
- `TestExamplesVet` - Static analysis tests
113118

114-
### 3. Example Tests
119+
A case is a directory holding the inputs and the expected output. `exec.json`
120+
names the command and its arguments — omit it and the case runs `generate`,
121+
comparing the generated files against the ones committed alongside; give it
122+
`{"command": "analyze", "args": [...]}` and the case compares the command's
123+
stdout against `stdout.txt`. A case that is expected to fail commits its
124+
`stderr.txt`. Regenerate a golden by running the command in its directory and
125+
writing the output back over the committed file.
126+
127+
### Example Tests
115128

116129
- **Location:** `/examples/` directory
117130
- **Requirements:** Tagged with "examples", requires live databases
@@ -183,6 +196,9 @@ MYSQL_SERVER_URI="root:mysecretpassword@tcp(127.0.0.1:3306)/mysql?multiStatement
183196
- `/postgresql/` - PostgreSQL parser and converter
184197
- `/dolphin/` - MySQL parser (uses TiDB parser)
185198
- `/sqlite/` - SQLite parser
199+
- `<engine>/dialect/` - The engine's type system and standard library, as
200+
JSONL read by `/internal/core/seed`
201+
- `/internal/core/` - The analysis core: catalog, analyzer and dialect seeds
186202
- `/internal/compiler/` - Query compilation logic
187203
- `/internal/codegen/` - Code generation for different languages
188204
- `/internal/config/` - Configuration file parsing
@@ -232,9 +248,10 @@ go run ./cmd/sqlc-test-setup start
232248
## Tips for Contributors
233249

234250
1. **Run tests before committing:** `go test --tags=examples -timeout 20m ./...`
235-
2. **Check for race conditions:** Use `-race` flag when testing concurrent code
236-
3. **Use specific package tests:** Faster iteration during development
237-
4. **Read existing tests:** Good examples in `/internal/engine/postgresql/*_test.go`
251+
2. **Cover new behavior end to end:** Add a case under `/internal/endtoend/testdata/`
252+
3. **Check for race conditions:** Use `-race` flag when testing concurrent code
253+
4. **Iterate on one case:** `go test ./internal/endtoend -run 'TestReplay/base/<case>'`
254+
5. **Read existing cases:** `/internal/endtoend/testdata/` has one per feature
238255

239256
## Git Workflow
240257

docs/howto/analyze.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,13 @@ Unlike [`generate`](generate.md), this command does not require a configuration
77
file and does not connect to a database. It uses sqlc's native static analysis
88
to infer types directly from the provided schema.
99

10+
Every dialect is analyzed by the same engine-neutral analysis core: the schema
11+
is loaded into a catalog seeded with the dialect's types, operators and
12+
functions, and each query is resolved against it. `generate` still uses each
13+
engine's own analysis path, so the two can report a type differently — most
14+
visibly, `analyze` reports type names as the catalog stores them, in lower
15+
case.
16+
1017
## Usage
1118

1219
```sh

internal/cache/cas.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,19 @@ func (c *CAS) path(d Digest) string {
4141
return filepath.Join("cas", d.Hash[:2], d.Hash)
4242
}
4343

44+
// Filename returns the path of a stored blob, for a consumer that needs the
45+
// file rather than its bytes — SQLite, for one, opens a database by name. A
46+
// blob is named after the hash of its contents, so the file at this path never
47+
// changes and any number of processes may read it at once.
48+
//
49+
// It reports false when the blob is not stored.
50+
func (c *CAS) Filename(d Digest) (string, bool) {
51+
if !c.Contains(d) {
52+
return "", false
53+
}
54+
return filepath.Join(c.root.Name(), c.path(d)), true
55+
}
56+
4457
// createTemp creates a staging file under tmp/ in the cache root, returning
4558
// the open file and its root-relative name.
4659
func (c *CAS) createTemp(prefix string) (*os.File, string, error) {

internal/cmd/analyze.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ Examples:
130130
parserOpts := opts.Parser{}
131131

132132
ctx := cmd.Context()
133-
c, err := compiler.NewCompiler(sql, combo, parserOpts)
133+
c, err := compiler.NewCompiler(sql, combo, parserOpts, compiler.WithCoreAnalysis())
134134
if err != nil {
135135
return fmt.Errorf("error creating compiler: %w", err)
136136
}

0 commit comments

Comments
 (0)