@rawsql-ts/ztd-cli 0.15.0 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -12
- package/dist/commands/init.js +19 -10
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/lint.d.ts +1 -1
- package/dist/commands/lint.js +3 -3
- package/dist/commands/lint.js.map +1 -1
- package/package.json +7 -6
- package/templates/AGENTS.md +58 -45
- package/templates/README.md +45 -67
- package/templates/dist/drivers/pg-testkit/src/driver/PgTestkitClient.d.ts +38 -0
- package/templates/dist/drivers/pg-testkit/src/driver/PgTestkitClient.js +117 -0
- package/templates/dist/drivers/pg-testkit/src/driver/PgTestkitClient.js.map +1 -0
- package/templates/dist/drivers/pg-testkit/src/driver/createPgTestkitPool.d.ts +4 -0
- package/templates/dist/drivers/pg-testkit/src/driver/createPgTestkitPool.js +71 -0
- package/templates/dist/drivers/pg-testkit/src/driver/createPgTestkitPool.js.map +1 -0
- package/templates/dist/drivers/pg-testkit/src/index.d.ts +5 -0
- package/templates/dist/drivers/pg-testkit/src/index.js +11 -0
- package/templates/dist/drivers/pg-testkit/src/index.js.map +1 -0
- package/templates/dist/drivers/pg-testkit/src/proxy/wrapPgClient.d.ts +3 -0
- package/templates/dist/drivers/pg-testkit/src/proxy/wrapPgClient.js +79 -0
- package/templates/dist/drivers/pg-testkit/src/proxy/wrapPgClient.js.map +1 -0
- package/templates/dist/drivers/pg-testkit/src/types.d.ts +69 -0
- package/templates/dist/drivers/pg-testkit/src/types.js +3 -0
- package/templates/dist/drivers/pg-testkit/src/types.js.map +1 -0
- package/templates/dist/drivers/pg-testkit/src/utils/fixtureState.d.ts +15 -0
- package/templates/dist/drivers/pg-testkit/src/utils/fixtureState.js +34 -0
- package/templates/dist/drivers/pg-testkit/src/utils/fixtureState.js.map +1 -0
- package/templates/dist/drivers/pg-testkit/src/utils/fixtureValidation.d.ts +12 -0
- package/templates/dist/drivers/pg-testkit/src/utils/fixtureValidation.js +53 -0
- package/templates/dist/drivers/pg-testkit/src/utils/fixtureValidation.js.map +1 -0
- package/templates/dist/mapper-core/src/index.d.ts +160 -0
- package/templates/dist/mapper-core/src/index.js +637 -0
- package/templates/dist/mapper-core/src/index.js.map +1 -0
- package/templates/dist/testkit-core/src/errors/index.d.ts +49 -0
- package/templates/dist/testkit-core/src/errors/index.js +111 -0
- package/templates/dist/testkit-core/src/errors/index.js.map +1 -0
- package/templates/dist/testkit-core/src/fixtures/ColumnAffinity.d.ts +5 -0
- package/templates/dist/testkit-core/src/fixtures/ColumnAffinity.js +29 -0
- package/templates/dist/testkit-core/src/fixtures/ColumnAffinity.js.map +1 -0
- package/templates/dist/testkit-core/src/fixtures/DdlFixtureLoader.d.ts +37 -0
- package/templates/dist/testkit-core/src/fixtures/DdlFixtureLoader.js +182 -0
- package/templates/dist/testkit-core/src/fixtures/DdlFixtureLoader.js.map +1 -0
- package/templates/dist/testkit-core/src/fixtures/FixtureProvider.d.ts +20 -0
- package/templates/dist/testkit-core/src/fixtures/FixtureProvider.js +121 -0
- package/templates/dist/testkit-core/src/fixtures/FixtureProvider.js.map +1 -0
- package/templates/dist/testkit-core/src/fixtures/FixtureStore.d.ts +51 -0
- package/templates/dist/testkit-core/src/fixtures/FixtureStore.js +199 -0
- package/templates/dist/testkit-core/src/fixtures/FixtureStore.js.map +1 -0
- package/templates/dist/testkit-core/src/fixtures/TableDefinitionSchemaRegistry.d.ts +10 -0
- package/templates/dist/testkit-core/src/fixtures/TableDefinitionSchemaRegistry.js +28 -0
- package/templates/dist/testkit-core/src/fixtures/TableDefinitionSchemaRegistry.js.map +1 -0
- package/templates/dist/testkit-core/src/fixtures/TableNameResolver.d.ts +18 -0
- package/templates/dist/testkit-core/src/fixtures/TableNameResolver.js +80 -0
- package/templates/dist/testkit-core/src/fixtures/TableNameResolver.js.map +1 -0
- package/templates/dist/testkit-core/src/fixtures/ddlLint.d.ts +59 -0
- package/templates/dist/testkit-core/src/fixtures/ddlLint.js +489 -0
- package/templates/dist/testkit-core/src/fixtures/ddlLint.js.map +1 -0
- package/templates/dist/testkit-core/src/fixtures/naming.d.ts +1 -0
- package/templates/dist/testkit-core/src/fixtures/naming.js +6 -0
- package/templates/dist/testkit-core/src/fixtures/naming.js.map +1 -0
- package/templates/dist/testkit-core/src/index.d.ts +17 -0
- package/templates/dist/testkit-core/src/index.js +47 -0
- package/templates/dist/testkit-core/src/index.js.map +1 -0
- package/templates/dist/testkit-core/src/logger/NoopLogger.d.ts +8 -0
- package/templates/dist/testkit-core/src/logger/NoopLogger.js +16 -0
- package/templates/dist/testkit-core/src/logger/NoopLogger.js.map +1 -0
- package/templates/dist/testkit-core/src/provider/TestkitProvider.d.ts +57 -0
- package/templates/dist/testkit-core/src/provider/TestkitProvider.js +149 -0
- package/templates/dist/testkit-core/src/provider/TestkitProvider.js.map +1 -0
- package/templates/dist/testkit-core/src/rewriter/ResultSelectRewriter.d.ts +43 -0
- package/templates/dist/testkit-core/src/rewriter/ResultSelectRewriter.js +473 -0
- package/templates/dist/testkit-core/src/rewriter/ResultSelectRewriter.js.map +1 -0
- package/templates/dist/testkit-core/src/rewriter/SelectAnalyzer.d.ts +9 -0
- package/templates/dist/testkit-core/src/rewriter/SelectAnalyzer.js +38 -0
- package/templates/dist/testkit-core/src/rewriter/SelectAnalyzer.js.map +1 -0
- package/templates/dist/testkit-core/src/rewriter/SelectFixtureRewriter.d.ts +42 -0
- package/templates/dist/testkit-core/src/rewriter/SelectFixtureRewriter.js +298 -0
- package/templates/dist/testkit-core/src/rewriter/SelectFixtureRewriter.js.map +1 -0
- package/templates/dist/testkit-core/src/sql/SqliteValuesBuilder.d.ts +12 -0
- package/templates/dist/testkit-core/src/sql/SqliteValuesBuilder.js +63 -0
- package/templates/dist/testkit-core/src/sql/SqliteValuesBuilder.js.map +1 -0
- package/templates/dist/testkit-core/src/types/index.d.ts +69 -0
- package/templates/dist/testkit-core/src/types/index.js +3 -0
- package/templates/dist/testkit-core/src/types/index.js.map +1 -0
- package/templates/dist/testkit-core/src/utils/queryHelpers.d.ts +28 -0
- package/templates/dist/testkit-core/src/utils/queryHelpers.js +81 -0
- package/templates/dist/testkit-core/src/utils/queryHelpers.js.map +1 -0
- package/templates/dist/writer-core/src/index.d.ts +34 -0
- package/templates/dist/writer-core/src/index.js +115 -0
- package/templates/dist/writer-core/src/index.js.map +1 -0
- package/templates/dist/ztd-cli/templates/src/db/sql-client.d.ts +20 -0
- package/templates/dist/ztd-cli/templates/src/db/sql-client.js +3 -0
- package/templates/dist/ztd-cli/templates/src/db/sql-client.js.map +1 -0
- package/templates/dist/ztd-cli/templates/src/repositories/user-accounts.d.ts +36 -0
- package/templates/dist/ztd-cli/templates/src/repositories/user-accounts.js +85 -0
- package/templates/dist/ztd-cli/templates/src/repositories/user-accounts.js.map +1 -0
- package/templates/dist/ztd-cli/templates/tests/generated/ztd-row-map.generated.d.ts +20 -0
- package/templates/dist/ztd-cli/templates/tests/generated/ztd-row-map.generated.js +33 -0
- package/templates/dist/ztd-cli/templates/tests/generated/ztd-row-map.generated.js.map +1 -0
- package/templates/dist/ztd-cli/templates/tests/support/global-setup.d.ts +10 -0
- package/templates/dist/ztd-cli/templates/tests/support/global-setup.js +29 -0
- package/templates/dist/ztd-cli/templates/tests/support/global-setup.js.map +1 -0
- package/templates/dist/ztd-cli/templates/tests/support/testkit-client.d.ts +66 -0
- package/templates/dist/ztd-cli/templates/tests/support/testkit-client.js +552 -0
- package/templates/dist/ztd-cli/templates/tests/support/testkit-client.js.map +1 -0
- package/templates/dist/ztd-cli/templates/tests/user-profiles.test.d.ts +1 -0
- package/templates/dist/ztd-cli/templates/tests/user-profiles.test.js +82 -0
- package/templates/dist/ztd-cli/templates/tests/user-profiles.test.js.map +1 -0
- package/templates/dist/ztd-cli/templates/tests/writer-constraints.test.d.ts +1 -0
- package/templates/dist/ztd-cli/templates/tests/writer-constraints.test.js +29 -0
- package/templates/dist/ztd-cli/templates/tests/writer-constraints.test.js.map +1 -0
- package/templates/dist/ztd-cli/templates/tests/ztd-layout.generated.d.ts +7 -0
- package/templates/dist/ztd-cli/templates/tests/ztd-layout.generated.js +10 -0
- package/templates/dist/ztd-cli/templates/tests/ztd-layout.generated.js.map +1 -0
- package/templates/src/db/sql-client.ts +1 -1
- package/templates/src/repositories/user-accounts.ts +179 -0
- package/templates/tests/AGENTS.md +23 -2
- package/templates/tests/support/global-setup.ts +1 -1
- package/templates/tests/support/testkit-client.ts +4 -4
- package/templates/tests/user-profiles.test.ts +161 -0
- package/templates/tests/writer-constraints.test.ts +32 -0
- package/templates/tests/ztd-layout.generated.ts +0 -2
- package/templates/tsconfig.json +1 -2
- package/templates/ztd/AGENTS.md +10 -85
- package/templates/ztd/README.md +10 -79
package/templates/AGENTS.md
CHANGED
|
@@ -4,7 +4,7 @@ This application uses **Zero Table Dependency (ZTD)** as an internal development
|
|
|
4
4
|
ZTD is not part of the application's runtime behavior; rather, it provides a framework for:
|
|
5
5
|
|
|
6
6
|
- Maintaining consistent SQL across the project
|
|
7
|
-
- Keeping schema
|
|
7
|
+
- Keeping schema metadata and generated artifacts synchronized
|
|
8
8
|
- Ensuring deterministic SQL unit tests
|
|
9
9
|
- Enabling structured collaboration between humans and AI
|
|
10
10
|
|
|
@@ -36,6 +36,7 @@ After any code change, TypeScript type checking **must** be performed and must p
|
|
|
36
36
|
- If generated files are involved, run generators first, then re-run typecheck.
|
|
37
37
|
- If typecheck fails, fix errors by root cause, not only the first reported error.
|
|
38
38
|
- A change is not considered complete unless typecheck is green.
|
|
39
|
+
CI pipelines SHOULD run `npx ztd ztd-config` before typecheck and tests (recommended).
|
|
39
40
|
|
|
40
41
|
Rationale:
|
|
41
42
|
In ZTD-based development, many schema or SQL inconsistencies surface first as TypeScript errors via generated row maps and DTOs.
|
|
@@ -47,6 +48,13 @@ Type checking is a primary correctness signal, not an optional step.
|
|
|
47
48
|
|
|
48
49
|
The `src/` directory should contain pure TypeScript logic that operates on the row interfaces generated by `tests/generated/ztd-row-map.generated.ts`. Tests should import the row map, repositories should import DTOs, and fixtures must stay under `tests/`. Keep production code decoupled from the generated row map to preserve the distinction between implementation and test scaffolding.
|
|
49
50
|
|
|
51
|
+
### Runtime dependency boundaries (important)
|
|
52
|
+
|
|
53
|
+
- Code under `src/` MUST NOT import anything from `tests/` or `tests/generated/`.
|
|
54
|
+
- Generated row-maps are test-only artifacts and MUST NEVER influence runtime behavior.
|
|
55
|
+
- Mapper and writer runtime utilities MUST NOT depend on ZTD internals or generated helpers.
|
|
56
|
+
- All schema compatibility checks (column existence, enum coverage, forbidden columns, etc.) MUST be enforced in tests, never in production code.
|
|
57
|
+
|
|
50
58
|
### Repository Classes: What to Care About
|
|
51
59
|
|
|
52
60
|
#### Scope and Responsibility
|
|
@@ -63,15 +71,19 @@ Rules:
|
|
|
63
71
|
- Tests must call repository methods, not raw SQL files or SQL strings.
|
|
64
72
|
- ZTD fixtures are the only allowed source of database state in tests.
|
|
65
73
|
- A repository change without tests is considered incomplete.
|
|
74
|
+
- Every repository or test modification must be followed by `pnpm --filter <package> test` (replace `<package>` with the template package name).
|
|
75
|
+
- `tests/support/global-setup.ts` already uses `@testcontainers/postgresql`, so the suite stands up a Postgres container automatically whenever `DATABASE_URL` is absent.
|
|
76
|
+
- If the suite fails, fix the root cause and rerun the command until it passes before considering the repository change complete.
|
|
66
77
|
|
|
67
78
|
Rationale:
|
|
68
79
|
ZTD derives much of its value from deterministic, repository-level tests.
|
|
69
80
|
Without tests, schema drift and SQL inconsistencies cannot be detected.
|
|
70
81
|
|
|
71
82
|
#### SQL Management
|
|
72
|
-
-
|
|
73
|
-
-
|
|
74
|
-
-
|
|
83
|
+
- Keep every SELECT statement in a dedicated `.sql` file under `src/sql/` (match the repository name, e.g. `src/sql/user-accounts.sql`).
|
|
84
|
+
- Load the SQL via `fs.readFileSync` or similar helpers so the repository never embeds long SQL strings inline.
|
|
85
|
+
- Inline SQL is forbidden unless a human explicitly requests an override; follow the `.sql` file convention by default.
|
|
86
|
+
- Repository classes should reference those SQL files; the file name should match the repository class or the query method to keep the code/spec alignment clear.
|
|
75
87
|
|
|
76
88
|
#### Specifications and Documentation
|
|
77
89
|
- If a markdown file with the same base name as the repository or SQL exists, read it before implementation.
|
|
@@ -97,6 +109,32 @@ Without tests, schema drift and SQL inconsistencies cannot be detected.
|
|
|
97
109
|
- Do not introduce intermediate `*Row` types when SQL already returns DTO-compatible shapes.
|
|
98
110
|
- Define separate Row types only when SQL intentionally returns database-shaped (snake_case) rows, and always convert them explicitly.
|
|
99
111
|
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
### Mapper + writer guardrails (template-specific)
|
|
115
|
+
|
|
116
|
+
- In this project, `src/repositories/user-accounts.ts` is the authoritative mapper for the columns defined by the DDL; it MUST enumerate those columns explicitly so downstream logic never infers metadata at runtime.
|
|
117
|
+
- Writer helpers in the same module MUST emit SQL for `public.user_account` only and MUST remain limited to the explicit insert/update/delete helpers shown there; DO NOT introduce ad-hoc schema discovery.
|
|
118
|
+
- `tests/writer-constraints.test.ts` MUST consume `userAccountWriterColumnSets` together with `tests/generated/ztd-row-map.generated.ts` so CUD callers only reference columns that exist on `public.user_account`.
|
|
119
|
+
- When the schema of `public.user_account` changes, update `src/repositories/user-accounts.ts` column metadata, keep `tests/writer-constraints.test.ts` expectations aligned, and re-run `npx ztd ztd-config` so the generated row map stays synchronized with the tests.
|
|
120
|
+
|
|
121
|
+
#### Writer safety contract (important)
|
|
122
|
+
|
|
123
|
+
- Allowed:
|
|
124
|
+
- Insert, update, and delete helpers tied to a single table with explicitly enumerated column sets.
|
|
125
|
+
- Explicit `RETURNING` clauses that list permitted columns.
|
|
126
|
+
- Patch-style updates that only touch writable columns listed in `userAccountWriterColumnSets`.
|
|
127
|
+
- Forbidden:
|
|
128
|
+
- Generic writers that accept arbitrary table or column names.
|
|
129
|
+
- Runtime schema or enum discovery (e.g., querying `information_schema`) to drive writer column lists.
|
|
130
|
+
- Writers that embed joins or subqueries beyond simple `RETURNING` clauses.
|
|
131
|
+
If these constraints are insufficient, write the SQL manually.
|
|
132
|
+
|
|
133
|
+
#### Mapper strictness policy
|
|
134
|
+
|
|
135
|
+
- Mapping is strict by default: SQL must return exactly the DTO-shaped results that `src/repositories/user-accounts.ts` exposes; missing or mismatched columns are bugs that tests MUST surface.
|
|
136
|
+
- Non-strict behaviors (coercions, key transforms, etc.) MUST be enabled explicitly via named presets or configuration; relying on implicit or silent defaults is prohibited.
|
|
137
|
+
|
|
100
138
|
### Sequence / identity column policy (important)
|
|
101
139
|
|
|
102
140
|
- Sequence / identity columns (auto-generated IDs) are infrastructure concerns.
|
|
@@ -133,19 +171,15 @@ Testing under ZTD follows dedicated, directory-scoped rules.
|
|
|
133
171
|
/ddl
|
|
134
172
|
*.sql <- physical schema definitions
|
|
135
173
|
|
|
136
|
-
/domain-specs
|
|
137
|
-
*.md <- one behavioral SELECT per file (one SQL block)
|
|
138
|
-
|
|
139
|
-
/enums
|
|
140
|
-
*.md <- one enum definition per file (one SQL block)
|
|
141
|
-
|
|
142
174
|
README.md <- documentation for the layout
|
|
143
|
-
AGENTS.md <- combined guidance for DDL
|
|
175
|
+
AGENTS.md <- combined guidance for DDL
|
|
144
176
|
|
|
145
177
|
/src <- application & repository logic
|
|
146
178
|
/tests <- ZTD tests, fixtures, row-maps
|
|
147
179
|
```
|
|
148
180
|
|
|
181
|
+
Only `ztd/ddl` is part of the template contract. Do not create or assume any other `ztd` subdirectories unless the project explicitly adds them.
|
|
182
|
+
|
|
149
183
|
The file `tests/generated/ztd-layout.generated.ts` ensures ZTD CLI always points to the correct directories.
|
|
150
184
|
|
|
151
185
|
---
|
|
@@ -153,8 +187,7 @@ The file `tests/generated/ztd-layout.generated.ts` ensures ZTD CLI always points
|
|
|
153
187
|
# Protected directories and edit ownership (important)
|
|
154
188
|
|
|
155
189
|
- DDL editing is human-led: `ztd/ddl/`
|
|
156
|
-
-
|
|
157
|
-
- Enums editing is human-led: `ztd/enums/`
|
|
190
|
+
- `ztd/ddl` is the sole human-owned directory inside `/ztd`; other directories must not be assumed or created without explicit instructions.
|
|
158
191
|
- Application code is shared ownership: `src/`
|
|
159
192
|
- Tests are shared ownership: `tests/`
|
|
160
193
|
- Detailed test constraints live in `templates/tests/AGENTS.md`.
|
|
@@ -169,21 +202,17 @@ Additionally:
|
|
|
169
202
|
|
|
170
203
|
### 1. Humans own the definitions
|
|
171
204
|
- Physical schema (DDL)
|
|
172
|
-
- Domain semantics (domain-specs)
|
|
173
|
-
- Enumerations (enums)
|
|
174
205
|
- Repository interfaces
|
|
175
206
|
|
|
176
207
|
### 2. AI assists with implementation
|
|
177
208
|
- Generating repository SQL
|
|
178
209
|
- Updating fixtures
|
|
179
210
|
- Producing intermediate TypeScript structures
|
|
180
|
-
- Ensuring SQL adheres to DDL
|
|
211
|
+
- Ensuring SQL adheres to DDL
|
|
181
212
|
|
|
182
213
|
### 3. ZTD enforces consistency
|
|
183
214
|
ZTD tests verify that:
|
|
184
215
|
- SQL logic matches DDL shapes
|
|
185
|
-
- SQL semantics match domain-specs
|
|
186
|
-
- SQL values match enumerations
|
|
187
216
|
|
|
188
217
|
If anything diverges, ZTD failures surface immediately and deterministically.
|
|
189
218
|
|
|
@@ -213,11 +242,11 @@ Changing method signatures, adding new repository methods, etc.
|
|
|
213
242
|
|
|
214
243
|
1. Modify the repository interface or implementation in `/src`.
|
|
215
244
|
2. Use AI assistance to generate or update the SQL implementation.
|
|
216
|
-
3. If the generated SQL conflicts with
|
|
245
|
+
3. If the generated SQL conflicts with DDL or other human-maintained references, update the authoritative source first.
|
|
217
246
|
4. Run ZTD tests.
|
|
218
247
|
5. Regenerate config if SQL output shape changed.
|
|
219
248
|
|
|
220
|
-
Flow: Interface to SQL to
|
|
249
|
+
Flow: Interface to SQL to Tests
|
|
221
250
|
|
|
222
251
|
---
|
|
223
252
|
|
|
@@ -226,31 +255,19 @@ Bug fixes, refactoring, rewriting queries.
|
|
|
226
255
|
|
|
227
256
|
1. Edit SQL inside the repository.
|
|
228
257
|
2. Run ZTD tests.
|
|
229
|
-
3. If intended behavior changes,
|
|
258
|
+
3. If intended behavior changes, coordinate any necessary DDL updates before adjusting dependent code.
|
|
230
259
|
4. Update fixtures as needed.
|
|
231
260
|
5. Regenerate config if result shape changed.
|
|
232
261
|
|
|
233
|
-
Flow: SQL to
|
|
234
|
-
|
|
235
|
-
---
|
|
236
|
-
|
|
237
|
-
# Workflow D - Starting From Enum or Domain Specification Changes
|
|
238
|
-
Business rule changes or conceptual model updates.
|
|
239
|
-
|
|
240
|
-
Flow: Specs or Enums to SQL to Tests to (DDL if required)
|
|
262
|
+
Flow: SQL to Tests
|
|
241
263
|
|
|
242
264
|
---
|
|
243
265
|
|
|
244
266
|
# Combined Real-World Examples
|
|
245
267
|
|
|
246
|
-
- Adding a new contract state:
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
- Adding a new table:
|
|
250
|
-
DDL to config to SQL to fixtures to tests
|
|
251
|
-
|
|
252
|
-
- Fixing business logic:
|
|
253
|
-
SQL to domain-spec to tests
|
|
268
|
+
- Adding a new contract state: DDL to SQL to config to tests
|
|
269
|
+
- Adding a new table: DDL to SQL to fixtures/tests
|
|
270
|
+
- Fixing business logic: SQL to tests
|
|
254
271
|
|
|
255
272
|
ZTD ensures the development always converges into a consistent, validated workflow.
|
|
256
273
|
|
|
@@ -261,8 +278,6 @@ ZTD ensures the development always converges into a consistent, validated workfl
|
|
|
261
278
|
Humans maintain:
|
|
262
279
|
|
|
263
280
|
- Schema definitions (`ztd/ddl`)
|
|
264
|
-
- Domain logic definitions (`ztd/domain-specs`)
|
|
265
|
-
- Domain enumerations (`ztd/enums`)
|
|
266
281
|
- Repository interfaces and architectural decisions
|
|
267
282
|
- Acceptance and review of AI-generated patches
|
|
268
283
|
|
|
@@ -274,12 +289,10 @@ Humans decide what is correct.
|
|
|
274
289
|
|
|
275
290
|
AI must:
|
|
276
291
|
|
|
277
|
-
- Use
|
|
278
|
-
-
|
|
279
|
-
-
|
|
280
|
-
-
|
|
281
|
-
- Update fixtures when needed
|
|
282
|
-
- Never modify `ztd/AGENTS.md` or `ztd/README.md` without explicit instruction
|
|
292
|
+
- Use DDL as the physical structure constraint and never assume any additional `ztd` directories exist unless explicitly added.
|
|
293
|
+
- Generate SQL consistent with DDL.
|
|
294
|
+
- Update fixtures when needed.
|
|
295
|
+
- Never modify `ztd/AGENTS.md` or `ztd/README.md` without explicit instruction.
|
|
283
296
|
|
|
284
297
|
AI decides how to implement, but not what is correct.
|
|
285
298
|
|
package/templates/README.md
CHANGED
|
@@ -5,31 +5,28 @@ This project organizes all SQL‑related artifacts under the `ztd/` directory, s
|
|
|
5
5
|
```
|
|
6
6
|
/ztd
|
|
7
7
|
/ddl
|
|
8
|
-
*.sql <- schema definitions
|
|
9
|
-
/domain-specs
|
|
10
|
-
*.md <- one behavior per file (one SQL block)
|
|
11
|
-
/enums
|
|
12
|
-
*.md <- one enum per file (one SQL block)
|
|
8
|
+
*.sql <- schema definitions (required)
|
|
13
9
|
README.md <- documentation for the layout
|
|
14
|
-
AGENTS.md <- combined guidance for
|
|
10
|
+
AGENTS.md <- combined guidance for DDL
|
|
15
11
|
|
|
16
12
|
/src <- application & repository code
|
|
17
13
|
/tests <- ZTD tests, fixtures, generated maps
|
|
18
14
|
```
|
|
19
15
|
|
|
16
|
+
Only `ztd/ddl` is part of the template contract. Do not create or assume other `ztd` subdirectories unless the project explicitly adds them.
|
|
17
|
+
|
|
20
18
|
## Generated files (important)
|
|
21
19
|
|
|
22
20
|
`tests/generated/` is auto-generated and must never be committed to git.
|
|
23
|
-
|
|
24
|
-
After cloning the repository (or in a clean environment), run:
|
|
21
|
+
After cloning the repository (or in a clean environment), run (strongly recommended):
|
|
25
22
|
|
|
26
23
|
```bash
|
|
27
24
|
npx ztd ztd-config
|
|
28
25
|
```
|
|
29
26
|
|
|
30
|
-
If TypeScript reports missing modules or type errors because `tests/generated/` is missing,
|
|
27
|
+
If TypeScript reports missing modules or type errors because `tests/generated/` is missing, rerun `npx ztd ztd-config`.
|
|
31
28
|
|
|
32
|
-
`tests/generated/ztd-layout.generated.ts` declares the directories above so the CLI and your tests always point at the
|
|
29
|
+
`tests/generated/ztd-layout.generated.ts` declares the directories above so the CLI and your tests always point at the intended files. The authoritative directory remains `ztd/ddl/`; do not read or assume additional `ztd` subdirectories.
|
|
33
30
|
|
|
34
31
|
---
|
|
35
32
|
|
|
@@ -60,12 +57,21 @@ export function getSqlClient(): SqlClient {
|
|
|
60
57
|
|
|
61
58
|
---
|
|
62
59
|
|
|
60
|
+
# Mapper + writer sample
|
|
61
|
+
|
|
62
|
+
- This scaffold already exposes `src/repositories/user-accounts.ts`, which maps `public.user_account` rows together with optional `public.user_profile` data through `@rawsql-ts/sql-contract/mapper` and emits insert/update/remove helpers via `@rawsql-ts/sql-contract/writer`.
|
|
63
|
+
- The SQL used here is defined in `src/repositories/user-accounts.ts`; the template tests exercise that implementation and `ztd/ddl` is the authoritative source for every column and constraint.
|
|
64
|
+
- Two template tests demonstrate how to run the stitch:
|
|
65
|
+
- `tests/user-profiles.test.ts` seeds fixtures, executes the query through the mapper, and verifies the DTO shape.
|
|
66
|
+
- `tests/writer-constraints.test.ts` reads `userAccountWriterColumnSets` plus `tests/generated/ztd-row-map.generated.ts` so writer callers stay within the approved column set when referencing `public.user_account`.
|
|
67
|
+
- Regenerate `tests/generated/ztd-row-map.generated.ts` (`npx ztd ztd-config`) before running the example tests so the row map reflects any schema changes.
|
|
68
|
+
- The example tests require a real PostgreSQL connection via `DATABASE_URL`; they automatically skip when the variable is missing so local tooling stays fast.
|
|
69
|
+
|
|
63
70
|
# Principles
|
|
64
71
|
|
|
65
72
|
### 1. Humans own the *definitions*
|
|
66
73
|
- DDL (physical schema)
|
|
67
|
-
|
|
68
|
-
- Enums (canonical domain values)
|
|
74
|
+
Only `ztd/ddl` is part of the template contract; other subdirectories should not be assumed.
|
|
69
75
|
|
|
70
76
|
### 2. AI owns the *implementation*
|
|
71
77
|
- Repository SQL generation
|
|
@@ -75,9 +81,8 @@ export function getSqlClient(): SqlClient {
|
|
|
75
81
|
|
|
76
82
|
### 3. ZTD ensures these stay in sync
|
|
77
83
|
ZTD acts as the consistency layer ensuring:
|
|
78
|
-
- DDL
|
|
79
|
-
-
|
|
80
|
-
- enums ↔ code‑level constants consistency
|
|
84
|
+
- DDL → SQL shape consistency
|
|
85
|
+
- Do not rely on other directories unless the project explicitly adds them.
|
|
81
86
|
|
|
82
87
|
If any part diverges, ZTD tests fail deterministically.
|
|
83
88
|
|
|
@@ -115,22 +120,22 @@ Different tasks start from different entry points. Choose the workflow that matc
|
|
|
115
120
|
|
|
116
121
|
1. Modify the repository interface or class in `/src`.
|
|
117
122
|
2. Allow AI to generate the SQL needed to satisfy the interface.
|
|
118
|
-
3. If the query contradicts
|
|
123
|
+
3. If the query contradicts DDL, reconcile the authoritative definition before continuing.
|
|
119
124
|
4. Run ZTD tests to confirm logic is consistent.
|
|
120
125
|
5. Regenerate ZTD config if result shapes changed.
|
|
121
126
|
|
|
122
127
|
**Flow:**
|
|
123
|
-
**repository interface -> SQL ->
|
|
128
|
+
**repository interface -> SQL -> tests**
|
|
124
129
|
|
|
125
130
|
---
|
|
126
131
|
|
|
127
|
-
# Workflow C — Starting From
|
|
132
|
+
# Workflow C — Starting From Repository SQL Logic Changes
|
|
128
133
|
(Fixing a bug, optimizing logic, rewriting a query)
|
|
129
134
|
|
|
130
135
|
1. Edit SQL inside the repository.
|
|
131
|
-
2. Run
|
|
132
|
-
3. If the intended behavior changes, update
|
|
133
|
-
4. Update fixtures
|
|
136
|
+
2. Run ZTD tests.
|
|
137
|
+
3. If the intended behavior changes, update the DDL before adjusting dependent logic and keep documentation aligned with the confirmed schema.
|
|
138
|
+
4. Update fixtures as necessary.
|
|
134
139
|
5. If SQL result shape changed, run:
|
|
135
140
|
|
|
136
141
|
```bash
|
|
@@ -138,62 +143,30 @@ Different tasks start from different entry points. Choose the workflow that matc
|
|
|
138
143
|
```
|
|
139
144
|
|
|
140
145
|
**Flow:**
|
|
141
|
-
**SQL ->
|
|
142
|
-
|
|
143
|
-
---
|
|
144
|
-
|
|
145
|
-
# Workflow D — Starting From *Enums or Domain Spec Changes*
|
|
146
|
-
(Business rules change, new status added, new definition created)
|
|
147
|
-
|
|
148
|
-
## For enums:
|
|
149
|
-
|
|
150
|
-
1. Update the relevant `.md` file under `ztd/enums/`.
|
|
151
|
-
2. Regenerate row-map:
|
|
152
|
-
|
|
153
|
-
```bash
|
|
154
|
-
npx ztd ztd-config
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
3. Update SQL referencing enum values.
|
|
158
|
-
4. Update domain-specs or repository SQL if behaviors change.
|
|
159
|
-
5. Update fixtures and tests.
|
|
160
|
-
|
|
161
|
-
## For domain-specs:
|
|
162
|
-
|
|
163
|
-
1. Modify the `.md` spec in `ztd/domain-specs/`.
|
|
164
|
-
2. Update SQL in `/src` to follow the new semantics.
|
|
165
|
-
3. Update tests and fixtures.
|
|
166
|
-
4. Update DDL only if the new behavior requires schema changes.
|
|
167
|
-
|
|
168
|
-
**Flow:**
|
|
169
|
-
**spec/enums -> SQL -> tests -> (DDL if required)**
|
|
146
|
+
**SQL -> fixtures/tests**
|
|
170
147
|
|
|
171
148
|
---
|
|
172
149
|
|
|
173
150
|
# Combined Real‑World Flow Examples
|
|
174
151
|
|
|
175
152
|
- **Add a new contract status**
|
|
176
|
-
|
|
153
|
+
DDL -> SQL -> config -> tests
|
|
177
154
|
|
|
178
155
|
- **Add a new table**
|
|
179
156
|
DDL -> config -> SQL -> fixtures -> tests
|
|
180
157
|
|
|
181
158
|
- **Fix business logic**
|
|
182
|
-
SQL ->
|
|
183
|
-
|
|
184
|
-
ZTD ensures all changes converge into the same consistency pipeline.
|
|
159
|
+
SQL -> tests
|
|
185
160
|
|
|
161
|
+
ZTD ensures all changes converge into a consistent, validated workflow.
|
|
186
162
|
---
|
|
187
163
|
|
|
188
164
|
# Human Responsibilities
|
|
189
165
|
|
|
190
|
-
Humans maintain:
|
|
191
|
-
|
|
192
|
-
-
|
|
193
|
-
-
|
|
194
|
-
- Domain vocabularies (`enums`)
|
|
195
|
-
- High‑level repository interfaces
|
|
196
|
-
- Acceptance of AI-generated changes
|
|
166
|
+
- Humans maintain:
|
|
167
|
+
- Physical schema (`ddl`)
|
|
168
|
+
- High‑level repository interfaces
|
|
169
|
+
- Acceptance of AI-generated changes
|
|
197
170
|
|
|
198
171
|
Humans decide “what is correct.”
|
|
199
172
|
|
|
@@ -203,12 +176,11 @@ Humans decide “what is correct.”
|
|
|
203
176
|
|
|
204
177
|
AI must:
|
|
205
178
|
|
|
206
|
-
- Use
|
|
207
|
-
-
|
|
208
|
-
-
|
|
209
|
-
-
|
|
210
|
-
-
|
|
211
|
-
- Never modify `ztd/AGENTS.md` or `ztd/README.md` unless explicitly asked
|
|
179
|
+
- Use DDL as the **physical shape constraint** and primary source of truth.
|
|
180
|
+
- Do not assume any additional `ztd` directories exist unless a human explicitly creates them.
|
|
181
|
+
- Generate repository SQL consistent with DDL and the documented behavior.
|
|
182
|
+
- Regenerate fixtures and tests as instructed.
|
|
183
|
+
- Never modify `ztd/AGENTS.md` or `ztd/README.md` unless explicitly asked.
|
|
212
184
|
|
|
213
185
|
AI decides “how to implement” within those constraints.
|
|
214
186
|
|
|
@@ -237,3 +209,9 @@ ZTD is the verification engine guaranteeing correctness.
|
|
|
237
209
|
ZTD enables a workflow where **humans define meaning**, **AI writes implementation**, and **tests guarantee correctness**.
|
|
238
210
|
|
|
239
211
|
The project layout and workflows above ensure long-term maintainability, clarity, and full reproducibility of SQL logic independent of physical database state.
|
|
212
|
+
|
|
213
|
+
## Recommended local verification
|
|
214
|
+
|
|
215
|
+
- `npx ztd ztd-config` (Recommended)
|
|
216
|
+
- `pnpm -C packages/ztd-cli test` (Recommended)
|
|
217
|
+
- `templates/tests/user-profiles.test.ts` runs only when `DATABASE_URL` is configured; otherwise it skips automatically.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { QueryResult, QueryResultRow } from 'pg';
|
|
2
|
+
import type { CreatePgTestkitClientOptions, PgQueryInput, PgQueryable, TableRowsFixture } from '../types';
|
|
3
|
+
/**
|
|
4
|
+
* Lightweight client that rewrites CRUD/SELECT statements into fixture-backed SELECTs
|
|
5
|
+
* and delegates execution to a real `pg` connection.
|
|
6
|
+
*
|
|
7
|
+
* Consumers can use this in place of `pg.Client` during tests; production code can stay
|
|
8
|
+
* unaware of pg-testkit as long as it relies on the standard `query` API.
|
|
9
|
+
*/
|
|
10
|
+
export declare class PgTestkitClient {
|
|
11
|
+
private readonly options;
|
|
12
|
+
private readonly scopedRows?;
|
|
13
|
+
private connection?;
|
|
14
|
+
private readonly rewriter;
|
|
15
|
+
private readonly tableNameResolver;
|
|
16
|
+
constructor(options: CreatePgTestkitClientOptions, scopedRows?: TableRowsFixture[] | undefined, seedConnection?: PgQueryable);
|
|
17
|
+
/**
|
|
18
|
+
* Executes SQL after rewriting it to use fixture-backed CTEs. CRUD statements are converted
|
|
19
|
+
* to result-producing SELECTs; unsupported DDL is ignored.
|
|
20
|
+
*
|
|
21
|
+
* @param textOrConfig SQL text or pg QueryConfig
|
|
22
|
+
* @param values Optional positional parameters
|
|
23
|
+
* @returns pg-style QueryResult with rows simulated from fixtures
|
|
24
|
+
*/
|
|
25
|
+
query<T extends QueryResultRow = QueryResultRow>(textOrConfig: PgQueryInput, values?: unknown[]): Promise<QueryResult<T>>;
|
|
26
|
+
/**
|
|
27
|
+
* Derives a scoped client that overlays additional fixtures while reusing the same connection.
|
|
28
|
+
*/
|
|
29
|
+
withFixtures(fixtures: TableRowsFixture[]): PgTestkitClient;
|
|
30
|
+
/**
|
|
31
|
+
* Disposes the underlying connection or returns it to the pool if `release` is available.
|
|
32
|
+
*/
|
|
33
|
+
close(): Promise<void>;
|
|
34
|
+
private getConnection;
|
|
35
|
+
private buildEmptyResult;
|
|
36
|
+
}
|
|
37
|
+
/** Factory that instantiates a `PgTestkitClient` with the provided fixture-driven options. */
|
|
38
|
+
export declare const createPgTestkitClient: (options: CreatePgTestkitClientOptions) => PgTestkitClient;
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createPgTestkitClient = exports.PgTestkitClient = void 0;
|
|
4
|
+
const testkit_core_1 = require("@rawsql-ts/testkit-core");
|
|
5
|
+
const fixtureValidation_1 = require("../utils/fixtureValidation");
|
|
6
|
+
const fixtureState_1 = require("../utils/fixtureState");
|
|
7
|
+
/**
|
|
8
|
+
* Lightweight client that rewrites CRUD/SELECT statements into fixture-backed SELECTs
|
|
9
|
+
* and delegates execution to a real `pg` connection.
|
|
10
|
+
*
|
|
11
|
+
* Consumers can use this in place of `pg.Client` during tests; production code can stay
|
|
12
|
+
* unaware of pg-testkit as long as it relies on the standard `query` API.
|
|
13
|
+
*/
|
|
14
|
+
class PgTestkitClient {
|
|
15
|
+
constructor(options, scopedRows, seedConnection) {
|
|
16
|
+
var _a, _b;
|
|
17
|
+
this.options = options;
|
|
18
|
+
this.scopedRows = scopedRows;
|
|
19
|
+
// Keep a resolver around so every fixture/DDL lookup uses the same schema rules.
|
|
20
|
+
this.tableNameResolver = new testkit_core_1.TableNameResolver({
|
|
21
|
+
defaultSchema: options.defaultSchema,
|
|
22
|
+
searchPath: options.searchPath,
|
|
23
|
+
});
|
|
24
|
+
// Align DDL metadata and explicit overrides under the shared resolver rules.
|
|
25
|
+
const fixturesState = (0, fixtureState_1.resolveFixtureState)({
|
|
26
|
+
ddl: options.ddl,
|
|
27
|
+
tableDefinitions: options.tableDefinitions,
|
|
28
|
+
tableRows: options.tableRows,
|
|
29
|
+
}, this.tableNameResolver);
|
|
30
|
+
// Combine the base and scoped fixtures so they are validated exactly once through the resolver.
|
|
31
|
+
const mergedTableRows = [...((_a = options.tableRows) !== null && _a !== void 0 ? _a : []), ...(scopedRows !== null && scopedRows !== void 0 ? scopedRows : [])];
|
|
32
|
+
(0, fixtureValidation_1.validateFixtureRowsAgainstTableDefinitions)(mergedTableRows, fixturesState.tableDefinitions, 'tableRows', this.tableNameResolver);
|
|
33
|
+
const fixtureStore = new testkit_core_1.DefaultFixtureProvider(fixturesState.tableDefinitions, fixturesState.tableRows, this.tableNameResolver);
|
|
34
|
+
this.rewriter = new testkit_core_1.ResultSelectRewriter(fixtureStore, (_b = options.missingFixtureStrategy) !== null && _b !== void 0 ? _b : 'error', options.formatterOptions, this.tableNameResolver);
|
|
35
|
+
this.connection = seedConnection;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Executes SQL after rewriting it to use fixture-backed CTEs. CRUD statements are converted
|
|
39
|
+
* to result-producing SELECTs; unsupported DDL is ignored.
|
|
40
|
+
*
|
|
41
|
+
* @param textOrConfig SQL text or pg QueryConfig
|
|
42
|
+
* @param values Optional positional parameters
|
|
43
|
+
* @returns pg-style QueryResult with rows simulated from fixtures
|
|
44
|
+
*/
|
|
45
|
+
async query(textOrConfig, values) {
|
|
46
|
+
var _a, _b, _c;
|
|
47
|
+
const sql = typeof textOrConfig === 'string' ? textOrConfig : textOrConfig.text;
|
|
48
|
+
if (!sql) {
|
|
49
|
+
throw new Error('Query text is required for pg-testkit execution.');
|
|
50
|
+
}
|
|
51
|
+
// Rewrite CRUD and SELECT statements into fixture-backed SELECT queries.
|
|
52
|
+
const rewritten = this.rewriter.rewrite(sql, this.scopedRows);
|
|
53
|
+
if (!rewritten.sql) {
|
|
54
|
+
return this.buildEmptyResult('NOOP');
|
|
55
|
+
}
|
|
56
|
+
// Align caller-supplied parameters with the rewritten placeholders to keep numbering contiguous.
|
|
57
|
+
const incomingParams = typeof textOrConfig === 'string'
|
|
58
|
+
? values
|
|
59
|
+
: (_a = values !== null && values !== void 0 ? values : textOrConfig.values) !== null && _a !== void 0 ? _a : textOrConfig.params;
|
|
60
|
+
const normalizeResult = (0, testkit_core_1.alignRewrittenParameters)(rewritten.sql, incomingParams);
|
|
61
|
+
const payload = typeof textOrConfig === 'string'
|
|
62
|
+
? normalizeResult.sql
|
|
63
|
+
: { ...textOrConfig, text: normalizeResult.sql, values: normalizeResult.params };
|
|
64
|
+
const connection = await this.getConnection();
|
|
65
|
+
(_c = (_b = this.options).onExecute) === null || _c === void 0 ? void 0 : _c.call(_b, normalizeResult.sql, normalizeResult.params, rewritten.fixturesApplied);
|
|
66
|
+
const rawResult = typeof payload === 'string'
|
|
67
|
+
? await connection.query(payload, normalizeResult.params)
|
|
68
|
+
: await connection.query(payload);
|
|
69
|
+
return (0, testkit_core_1.applyCountWrapper)(rawResult, rewritten.sourceCommand, rewritten.isCountWrapper);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Derives a scoped client that overlays additional fixtures while reusing the same connection.
|
|
73
|
+
*/
|
|
74
|
+
withFixtures(fixtures) {
|
|
75
|
+
return new PgTestkitClient(this.options, fixtures, this.connection);
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Disposes the underlying connection or returns it to the pool if `release` is available.
|
|
79
|
+
*/
|
|
80
|
+
async close() {
|
|
81
|
+
if (!this.connection) {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
const closable = this.connection;
|
|
85
|
+
this.connection = undefined;
|
|
86
|
+
if (typeof closable.release === 'function') {
|
|
87
|
+
closable.release();
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
if (typeof closable.end === 'function') {
|
|
91
|
+
await closable.end();
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
async getConnection() {
|
|
95
|
+
if (this.connection) {
|
|
96
|
+
return this.connection;
|
|
97
|
+
}
|
|
98
|
+
this.connection = await this.options.connectionFactory();
|
|
99
|
+
return this.connection;
|
|
100
|
+
}
|
|
101
|
+
buildEmptyResult(command) {
|
|
102
|
+
return {
|
|
103
|
+
command,
|
|
104
|
+
rowCount: 0,
|
|
105
|
+
oid: 0,
|
|
106
|
+
rows: [],
|
|
107
|
+
fields: [],
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
exports.PgTestkitClient = PgTestkitClient;
|
|
112
|
+
/** Factory that instantiates a `PgTestkitClient` with the provided fixture-driven options. */
|
|
113
|
+
const createPgTestkitClient = (options) => {
|
|
114
|
+
return new PgTestkitClient(options);
|
|
115
|
+
};
|
|
116
|
+
exports.createPgTestkitClient = createPgTestkitClient;
|
|
117
|
+
//# sourceMappingURL=PgTestkitClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PgTestkitClient.js","sourceRoot":"","sources":["../../../../../../../drivers/pg-testkit/src/driver/PgTestkitClient.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { Pool } from 'pg';
|
|
2
|
+
import type { CreatePgTestkitPoolOptions, TableRowsFixture } from '../types';
|
|
3
|
+
/** Builds a pool whose clients rewrite CRUD traffic through pg-testkit while leaving transactions alone. */
|
|
4
|
+
export declare const createPgTestkitPool: (connectionString: string, ...fixturesOrOptions: Array<TableRowsFixture | CreatePgTestkitPoolOptions>) => Pool;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createPgTestkitPool = void 0;
|
|
4
|
+
const pg_1 = require("pg");
|
|
5
|
+
const PgTestkitClient_1 = require("./PgTestkitClient");
|
|
6
|
+
const TRANSACTION_COMMAND_RE = /^\s*(BEGIN|COMMIT|ROLLBACK|SAVEPOINT|RELEASE)/i;
|
|
7
|
+
const isPoolOptions = (value) => {
|
|
8
|
+
return (typeof value === 'object' &&
|
|
9
|
+
value !== null &&
|
|
10
|
+
('ddl' in value || 'tableRows' in value || 'tableDefinitions' in value));
|
|
11
|
+
};
|
|
12
|
+
/** Builds a pool whose clients rewrite CRUD traffic through pg-testkit while leaving transactions alone. */
|
|
13
|
+
const createPgTestkitPool = (connectionString, ...fixturesOrOptions) => {
|
|
14
|
+
var _a;
|
|
15
|
+
const hasOptions = fixturesOrOptions.length > 0 && isPoolOptions(fixturesOrOptions[fixturesOrOptions.length - 1]);
|
|
16
|
+
const poolOptions = hasOptions
|
|
17
|
+
? fixturesOrOptions[fixturesOrOptions.length - 1]
|
|
18
|
+
: undefined;
|
|
19
|
+
const baseFixtures = hasOptions
|
|
20
|
+
? fixturesOrOptions.slice(0, -1)
|
|
21
|
+
: fixturesOrOptions;
|
|
22
|
+
// Combine ad-hoc rows with option-provided ones so callers can mix styles.
|
|
23
|
+
const combinedFixtures = [...baseFixtures, ...((_a = poolOptions === null || poolOptions === void 0 ? void 0 : poolOptions.tableRows) !== null && _a !== void 0 ? _a : [])];
|
|
24
|
+
class TestkitClient extends pg_1.Client {
|
|
25
|
+
constructor() {
|
|
26
|
+
super(...arguments);
|
|
27
|
+
this.testkit = (0, PgTestkitClient_1.createPgTestkitClient)({
|
|
28
|
+
connectionFactory: async () => this.buildRawConnection(),
|
|
29
|
+
tableRows: combinedFixtures,
|
|
30
|
+
ddl: poolOptions === null || poolOptions === void 0 ? void 0 : poolOptions.ddl,
|
|
31
|
+
tableDefinitions: poolOptions === null || poolOptions === void 0 ? void 0 : poolOptions.tableDefinitions,
|
|
32
|
+
defaultSchema: poolOptions === null || poolOptions === void 0 ? void 0 : poolOptions.defaultSchema,
|
|
33
|
+
searchPath: poolOptions === null || poolOptions === void 0 ? void 0 : poolOptions.searchPath,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
buildRawConnection() {
|
|
37
|
+
const baseQuery = pg_1.Client.prototype.query;
|
|
38
|
+
// Forward rewritten SQL to the original pg client so transactional commands stay bound to the pool.
|
|
39
|
+
const rawConnection = {
|
|
40
|
+
query: (queryTextOrConfig, values) => baseQuery.call(this, queryTextOrConfig, values),
|
|
41
|
+
};
|
|
42
|
+
return rawConnection;
|
|
43
|
+
}
|
|
44
|
+
query(...args) {
|
|
45
|
+
var _a;
|
|
46
|
+
const [queryTextOrConfig, valuesOrCallback, callbackOrUndefined] = args;
|
|
47
|
+
const callback = typeof valuesOrCallback === 'function' ? valuesOrCallback : callbackOrUndefined;
|
|
48
|
+
const values = typeof valuesOrCallback === 'function' ? undefined : valuesOrCallback;
|
|
49
|
+
const sqlText = typeof queryTextOrConfig === 'string' ? queryTextOrConfig : queryTextOrConfig.text;
|
|
50
|
+
const configPayload = typeof queryTextOrConfig === 'string' ? undefined : queryTextOrConfig;
|
|
51
|
+
const normalizedValues = (_a = values !== null && values !== void 0 ? values : configPayload === null || configPayload === void 0 ? void 0 : configPayload.values) !== null && _a !== void 0 ? _a : configPayload === null || configPayload === void 0 ? void 0 : configPayload.params;
|
|
52
|
+
// Allow explicit transaction control to reach Pg without interference.
|
|
53
|
+
if (sqlText && TRANSACTION_COMMAND_RE.test(sqlText)) {
|
|
54
|
+
return pg_1.Client.prototype.query.apply(this, args);
|
|
55
|
+
}
|
|
56
|
+
const execution = this.testkit.query(queryTextOrConfig, normalizedValues);
|
|
57
|
+
// Surface callback behavior when the caller provided the older pg query signature.
|
|
58
|
+
if (typeof callback === 'function') {
|
|
59
|
+
execution
|
|
60
|
+
.then((result) => callback(null, result))
|
|
61
|
+
.catch((error) => callback(error, undefined));
|
|
62
|
+
return undefined;
|
|
63
|
+
}
|
|
64
|
+
return execution;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
const poolConfig = { connectionString, Client: TestkitClient };
|
|
68
|
+
return new pg_1.Pool(poolConfig);
|
|
69
|
+
};
|
|
70
|
+
exports.createPgTestkitPool = createPgTestkitPool;
|
|
71
|
+
//# sourceMappingURL=createPgTestkitPool.js.map
|