@rawsql-ts/ztd-cli 0.15.0 → 0.17.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 +38 -25
- package/dist/commands/init.d.ts +13 -0
- package/dist/commands/init.js +372 -118
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/lint.d.ts +4 -4
- package/dist/commands/lint.js +60 -40
- package/dist/commands/lint.js.map +1 -1
- package/dist/commands/ztdConfig.d.ts +2 -2
- package/dist/commands/ztdConfig.js +26 -12
- package/dist/commands/ztdConfig.js.map +1 -1
- package/dist/utils/optionalDependencies.d.ts +35 -0
- package/dist/utils/optionalDependencies.js +96 -0
- package/dist/utils/optionalDependencies.js.map +1 -0
- package/package.json +18 -10
- package/templates/AGENTS.md +36 -296
- package/templates/README.md +12 -237
- 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/db/sql-client.ts +24 -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/AGENTS.md +26 -0
- package/templates/src/catalog/AGENTS.md +37 -0
- package/templates/src/catalog/runtime/AGENTS.md +75 -0
- package/templates/src/catalog/runtime/_coercions.ts +1 -0
- package/templates/src/catalog/runtime/_smoke.runtime.ts +21 -0
- package/templates/src/catalog/specs/AGENTS.md +48 -0
- package/templates/src/catalog/specs/_smoke.spec.arktype.ts +21 -0
- package/templates/src/catalog/specs/_smoke.spec.zod.ts +20 -0
- package/templates/src/db/sql-client.ts +5 -5
- package/templates/src/jobs/AGENTS.md +26 -0
- package/templates/src/jobs/README.md +3 -0
- package/templates/src/repositories/AGENTS.md +118 -0
- package/templates/src/repositories/tables/AGENTS.md +94 -0
- package/templates/src/repositories/tables/README.md +3 -0
- package/templates/src/repositories/views/AGENTS.md +25 -0
- package/templates/src/repositories/views/README.md +3 -0
- package/templates/src/sql/AGENTS.md +77 -0
- package/templates/src/sql/README.md +6 -0
- package/templates/tests/AGENTS.md +43 -129
- package/templates/tests/generated/AGENTS.md +16 -0
- package/templates/tests/smoke.test.ts +5 -0
- package/templates/tests/smoke.validation.test.ts +34 -0
- package/templates/tests/support/AGENTS.md +26 -0
- package/templates/tests/support/global-setup.ts +8 -23
- package/templates/tests/support/testkit-client.ts +13 -741
- package/templates/tests/ztd-layout.generated.ts +0 -2
- package/templates/tsconfig.json +9 -3
- package/templates/ztd/AGENTS.md +11 -142
- package/templates/ztd/README.md +4 -82
- package/templates/ztd/ddl/AGENTS.md +34 -0
- package/templates/ztd/ddl/demo.sql +74 -0
package/templates/README.md
CHANGED
|
@@ -1,239 +1,14 @@
|
|
|
1
1
|
# Zero Table Dependency Project
|
|
2
2
|
|
|
3
|
-
This project
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
/
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
/src <- application & repository code
|
|
17
|
-
/tests <- ZTD tests, fixtures, generated maps
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
## Generated files (important)
|
|
21
|
-
|
|
22
|
-
`tests/generated/` is auto-generated and must never be committed to git.
|
|
23
|
-
|
|
24
|
-
After cloning the repository (or in a clean environment), run:
|
|
25
|
-
|
|
26
|
-
```bash
|
|
27
|
-
npx ztd ztd-config
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
If TypeScript reports missing modules or type errors because `tests/generated/` is missing, run `npx ztd ztd-config`.
|
|
31
|
-
|
|
32
|
-
`tests/generated/ztd-layout.generated.ts` declares the directories above so the CLI and your tests always point at the correct files.
|
|
33
|
-
|
|
34
|
-
---
|
|
35
|
-
|
|
36
|
-
# Optional SqlClient seam
|
|
37
|
-
|
|
38
|
-
If this project was initialized with `npx ztd init --with-sqlclient`, you'll also have `src/db/sql-client.ts`.
|
|
39
|
-
It defines a minimal `SqlClient` interface that repositories can depend on:
|
|
40
|
-
|
|
41
|
-
- Use it for tutorials and greenfield projects to keep repository SQL decoupled from drivers.
|
|
42
|
-
- Skip it when you already have a database abstraction (Prisma, Drizzle, Kysely, custom adapters).
|
|
43
|
-
- For `pg`, adapt `client.query(...)` so it returns a plain `T[]` row array that matches the interface.
|
|
44
|
-
- Prefer a shared client per worker process so tests and scripts do not reconnect on every query.
|
|
45
|
-
- Do not share a live connection across parallel workers; each worker should own its own shared client.
|
|
46
|
-
|
|
47
|
-
Example (driver-agnostic):
|
|
48
|
-
|
|
49
|
-
```ts
|
|
50
|
-
let sharedClient: SqlClient | undefined;
|
|
51
|
-
|
|
52
|
-
export function getSqlClient(): SqlClient {
|
|
53
|
-
if (!sharedClient) {
|
|
54
|
-
// Create the client once using your chosen driver (pg, mysql, etc.).
|
|
55
|
-
sharedClient = createSqlClientOnce();
|
|
56
|
-
}
|
|
57
|
-
return sharedClient;
|
|
58
|
-
}
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
---
|
|
62
|
-
|
|
63
|
-
# Principles
|
|
64
|
-
|
|
65
|
-
### 1. Humans own the *definitions*
|
|
66
|
-
- DDL (physical schema)
|
|
67
|
-
- Domain specifications (business logic -> SQL semantics)
|
|
68
|
-
- Enums (canonical domain values)
|
|
69
|
-
|
|
70
|
-
### 2. AI owns the *implementation*
|
|
71
|
-
- Repository SQL generation
|
|
72
|
-
- Test fixture updates
|
|
73
|
-
- Intermediate TypeScript structures
|
|
74
|
-
- SQL rewriting, parameter binding, shape resolution
|
|
75
|
-
|
|
76
|
-
### 3. ZTD ensures these stay in sync
|
|
77
|
-
ZTD acts as the consistency layer ensuring:
|
|
78
|
-
- DDL ↔ SQL shape consistency
|
|
79
|
-
- domain-specs ↔ query logic consistency
|
|
80
|
-
- enums ↔ code‑level constants consistency
|
|
81
|
-
|
|
82
|
-
If any part diverges, ZTD tests fail deterministically.
|
|
83
|
-
|
|
84
|
-
---
|
|
85
|
-
|
|
86
|
-
# Workflow Overview
|
|
87
|
-
|
|
88
|
-
Different tasks start from different entry points. Choose the workflow that matches what you want to change.
|
|
89
|
-
|
|
90
|
-
---
|
|
91
|
-
|
|
92
|
-
# Workflow A — Starting From *DDL Changes*
|
|
93
|
-
(Adding tables/columns, changing constraints)
|
|
94
|
-
|
|
95
|
-
1. Edit files under `ztd/ddl/`.
|
|
96
|
-
2. Run:
|
|
97
|
-
|
|
98
|
-
```bash
|
|
99
|
-
npx ztd ztd-config
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
This regenerates `tests/generated/ztd-row-map.generated.ts` from the new schema.
|
|
103
|
-
|
|
104
|
-
3. Update repository SQL so it matches the new schema.
|
|
105
|
-
4. Update fixtures if shapes changed.
|
|
106
|
-
5. Run tests. Any schema mismatch will fail fast.
|
|
107
|
-
|
|
108
|
-
**Flow:**
|
|
109
|
-
**DDL -> repository SQL -> fixtures/tests -> application**
|
|
110
|
-
|
|
111
|
-
---
|
|
112
|
-
|
|
113
|
-
# Workflow B — Starting From *Repository Interface Changes*
|
|
114
|
-
(Adding a method, changing return types, etc.)
|
|
115
|
-
|
|
116
|
-
1. Modify the repository interface or class in `/src`.
|
|
117
|
-
2. Allow AI to generate the SQL needed to satisfy the interface.
|
|
118
|
-
3. If the query contradicts domain-specs or enums, update specs first.
|
|
119
|
-
4. Run ZTD tests to confirm logic is consistent.
|
|
120
|
-
5. Regenerate ZTD config if result shapes changed.
|
|
121
|
-
|
|
122
|
-
**Flow:**
|
|
123
|
-
**repository interface -> SQL -> (update specs if needed) -> tests**
|
|
124
|
-
|
|
125
|
-
---
|
|
126
|
-
|
|
127
|
-
# Workflow C — Starting From *Repository SQL Logic Changes*
|
|
128
|
-
(Fixing a bug, optimizing logic, rewriting a query)
|
|
129
|
-
|
|
130
|
-
1. Edit SQL inside the repository.
|
|
131
|
-
2. Run existing ZTD tests.
|
|
132
|
-
3. If the intended behavior changes, update `ztd/domain-specs/`.
|
|
133
|
-
4. Update fixtures if necessary.
|
|
134
|
-
5. If SQL result shape changed, run:
|
|
135
|
-
|
|
136
|
-
```bash
|
|
137
|
-
npx ztd ztd-config
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
**Flow:**
|
|
141
|
-
**SQL -> domain-specs (if needed) -> fixtures/tests**
|
|
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)**
|
|
170
|
-
|
|
171
|
-
---
|
|
172
|
-
|
|
173
|
-
# Combined Real‑World Flow Examples
|
|
174
|
-
|
|
175
|
-
- **Add a new contract status**
|
|
176
|
-
enums -> domain-spec -> SQL -> config -> tests
|
|
177
|
-
|
|
178
|
-
- **Add a new table**
|
|
179
|
-
DDL -> config -> SQL -> fixtures -> tests
|
|
180
|
-
|
|
181
|
-
- **Fix business logic**
|
|
182
|
-
SQL -> domain-spec -> tests
|
|
183
|
-
|
|
184
|
-
ZTD ensures all changes converge into the same consistency pipeline.
|
|
185
|
-
|
|
186
|
-
---
|
|
187
|
-
|
|
188
|
-
# Human Responsibilities
|
|
189
|
-
|
|
190
|
-
Humans maintain:
|
|
191
|
-
|
|
192
|
-
- Business logic definitions (`domain-specs`)
|
|
193
|
-
- Physical schema (`ddl`)
|
|
194
|
-
- Domain vocabularies (`enums`)
|
|
195
|
-
- High‑level repository interfaces
|
|
196
|
-
- Acceptance of AI-generated changes
|
|
197
|
-
|
|
198
|
-
Humans decide “what is correct.”
|
|
199
|
-
|
|
200
|
-
---
|
|
201
|
-
|
|
202
|
-
# AI Responsibilities
|
|
203
|
-
|
|
204
|
-
AI must:
|
|
205
|
-
|
|
206
|
-
- Use domain-specs as the **semantic source of truth**
|
|
207
|
-
- Use enums as the **canonical vocabulary source**
|
|
208
|
-
- Use DDL as the **physical shape constraint**
|
|
209
|
-
- Generate repository SQL consistent with all three
|
|
210
|
-
- Regenerate fixtures and tests as instructed
|
|
211
|
-
- Never modify `ztd/AGENTS.md` or `ztd/README.md` unless explicitly asked
|
|
212
|
-
|
|
213
|
-
AI decides “how to implement” within those constraints.
|
|
214
|
-
|
|
215
|
-
---
|
|
216
|
-
|
|
217
|
-
# ZTD CLI Responsibilities
|
|
218
|
-
|
|
219
|
-
ZTD CLI:
|
|
220
|
-
|
|
221
|
-
- Parses DDL files to build accurate table/column shapes
|
|
222
|
-
- Rewrites SQL with fixture-based CTE shadowing (via testkit adapters)
|
|
223
|
-
- Generates `ztd-row-map.generated.ts`
|
|
224
|
-
- Produces deterministic, parallelizable tests
|
|
225
|
-
|
|
226
|
-
ZTD is the verification engine guaranteeing correctness.
|
|
227
|
-
|
|
228
|
-
## Traditional execution mode
|
|
229
|
-
|
|
230
|
-
- Set `ZTD_EXECUTION_MODE=traditional` or pass `{ mode: 'traditional', traditional: { isolation: 'schema', cleanup: 'drop_schema' } }` when you need to run the tests against a real Postgres schema (locking, isolation, constraints). The helper still applies the DDL inside `ztd/ddl/`, loads the fixture rows into the schema, optionally executes `setupSql`, and carries out the chosen cleanup strategy (`drop_schema`, `custom_sql`, or `none`).
|
|
231
|
-
- Use `isolation: 'none'` if you need to target a schema that is already defined or if your SQL embeds schema qualifiers explicitly.
|
|
232
|
-
|
|
233
|
-
---
|
|
234
|
-
|
|
235
|
-
# Summary
|
|
236
|
-
|
|
237
|
-
ZTD enables a workflow where **humans define meaning**, **AI writes implementation**, and **tests guarantee correctness**.
|
|
238
|
-
|
|
239
|
-
The project layout and workflows above ensure long-term maintainability, clarity, and full reproducibility of SQL logic independent of physical database state.
|
|
3
|
+
This project uses Zero Table Dependency (ZTD) to keep SQL, DDL, and tests aligned.
|
|
4
|
+
|
|
5
|
+
Key folders:
|
|
6
|
+
- ztd/ddl: schema files (source of truth)
|
|
7
|
+
- src: application SQL and repositories
|
|
8
|
+
- tests: ZTD tests and support
|
|
9
|
+
|
|
10
|
+
Next steps:
|
|
11
|
+
1. Update `ztd/ddl/<schema>.sql` if needed.
|
|
12
|
+
2. Run `npx ztd ztd-config`.
|
|
13
|
+
3. Provide a SqlClient implementation.
|
|
14
|
+
4. Run tests (`pnpm test` or `npx vitest run`).
|
|
@@ -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
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createPgTestkitPool.js","sourceRoot":"","sources":["../../../../../../../drivers/pg-testkit/src/driver/createPgTestkitPool.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export type { CreatePgTestkitClientOptions, CreatePgTestkitPoolOptions, PgQueryInput, PgQueryable, WrapPgClientOptions, WrappedPgClient, } from './types';
|
|
2
|
+
export type { TableRowsFixture } from '@rawsql-ts/testkit-core';
|
|
3
|
+
export { createPgTestkitClient, PgTestkitClient } from './driver/PgTestkitClient';
|
|
4
|
+
export { createPgTestkitPool } from './driver/createPgTestkitPool';
|
|
5
|
+
export { wrapPgClient } from './proxy/wrapPgClient';
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.wrapPgClient = exports.createPgTestkitPool = exports.PgTestkitClient = exports.createPgTestkitClient = void 0;
|
|
4
|
+
var PgTestkitClient_1 = require("./driver/PgTestkitClient");
|
|
5
|
+
Object.defineProperty(exports, "createPgTestkitClient", { enumerable: true, get: function () { return PgTestkitClient_1.createPgTestkitClient; } });
|
|
6
|
+
Object.defineProperty(exports, "PgTestkitClient", { enumerable: true, get: function () { return PgTestkitClient_1.PgTestkitClient; } });
|
|
7
|
+
var createPgTestkitPool_1 = require("./driver/createPgTestkitPool");
|
|
8
|
+
Object.defineProperty(exports, "createPgTestkitPool", { enumerable: true, get: function () { return createPgTestkitPool_1.createPgTestkitPool; } });
|
|
9
|
+
var wrapPgClient_1 = require("./proxy/wrapPgClient");
|
|
10
|
+
Object.defineProperty(exports, "wrapPgClient", { enumerable: true, get: function () { return wrapPgClient_1.wrapPgClient; } });
|
|
11
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../drivers/pg-testkit/src/index.ts"],"names":[],"mappings":";;;AASA,4DAAkF;AAAzE,wHAAA,qBAAqB,OAAA;AAAE,kHAAA,eAAe,OAAA;AAC/C,oEAAmE;AAA1D,0HAAA,mBAAmB,OAAA;AAC5B,qDAAoD;AAA3C,4GAAA,YAAY,OAAA"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { PgQueryable, WrapPgClientOptions, WrappedPgClient } from '../types';
|
|
2
|
+
/** Wraps an existing Postgres client with fixture-aware query rewriting. */
|
|
3
|
+
export declare const wrapPgClient: <T extends PgQueryable>(client: T, options: WrapPgClientOptions) => WrappedPgClient<T>;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.wrapPgClient = 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
|
+
const buildEmptyResult = (command = 'NOOP') => ({
|
|
8
|
+
command,
|
|
9
|
+
rowCount: 0,
|
|
10
|
+
oid: 0,
|
|
11
|
+
rows: [],
|
|
12
|
+
fields: [],
|
|
13
|
+
});
|
|
14
|
+
/** Wraps an existing Postgres client with fixture-aware query rewriting. */
|
|
15
|
+
const wrapPgClient = (client, options) => {
|
|
16
|
+
var _a;
|
|
17
|
+
// Keep resolver configuration in sync with the pg-testkit options.
|
|
18
|
+
const tableNameResolver = new testkit_core_1.TableNameResolver({
|
|
19
|
+
defaultSchema: options.defaultSchema,
|
|
20
|
+
searchPath: options.searchPath,
|
|
21
|
+
});
|
|
22
|
+
// Align shared fixtures with the resolver so every consumer sees the same schema snapshot.
|
|
23
|
+
const fixtureState = (0, fixtureState_1.resolveFixtureState)({
|
|
24
|
+
ddl: options.ddl,
|
|
25
|
+
tableDefinitions: options.tableDefinitions,
|
|
26
|
+
tableRows: options.tableRows,
|
|
27
|
+
}, tableNameResolver);
|
|
28
|
+
// Ensure the provided fixtures align with the shared definitions before creating the fixture store.
|
|
29
|
+
(0, fixtureValidation_1.validateFixtureRowsAgainstTableDefinitions)(options.tableRows, fixtureState.tableDefinitions, 'wrap tableRows', tableNameResolver);
|
|
30
|
+
const fixtureStore = new testkit_core_1.DefaultFixtureProvider(fixtureState.tableDefinitions, fixtureState.tableRows, tableNameResolver);
|
|
31
|
+
const rewriter = new testkit_core_1.ResultSelectRewriter(fixtureStore, (_a = options.missingFixtureStrategy) !== null && _a !== void 0 ? _a : 'error', options.formatterOptions, tableNameResolver);
|
|
32
|
+
const buildProxy = (scopedFixtures) => {
|
|
33
|
+
return new Proxy(client, {
|
|
34
|
+
get(target, prop, receiver) {
|
|
35
|
+
if (prop === 'withFixtures') {
|
|
36
|
+
return (fixtures) => {
|
|
37
|
+
// Confirm each overlay matches the resolved definitions before reusing the proxy.
|
|
38
|
+
(0, fixtureValidation_1.validateFixtureRowsAgainstTableDefinitions)(fixtures, fixtureState.tableDefinitions, 'scoped fixtures', tableNameResolver);
|
|
39
|
+
return buildProxy(fixtures);
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
const value = Reflect.get(target, prop, receiver);
|
|
43
|
+
if (prop === 'query' && typeof value === 'function') {
|
|
44
|
+
return async (textOrConfig, values) => {
|
|
45
|
+
var _a, _b;
|
|
46
|
+
const sql = typeof textOrConfig === 'string' ? textOrConfig : textOrConfig.text;
|
|
47
|
+
if (!sql) {
|
|
48
|
+
return value.apply(target, [textOrConfig, values]);
|
|
49
|
+
}
|
|
50
|
+
// Inject fixture-backed CTEs into CRUD/SELECT statements and skip unsupported DDL.
|
|
51
|
+
const rewritten = rewriter.rewrite(sql, scopedFixtures);
|
|
52
|
+
if (!rewritten.sql) {
|
|
53
|
+
return buildEmptyResult();
|
|
54
|
+
}
|
|
55
|
+
// Align caller parameters with the rewritten SQL so placeholders stay contiguous.
|
|
56
|
+
const incomingParams = typeof textOrConfig === 'string'
|
|
57
|
+
? values
|
|
58
|
+
: (_a = values !== null && values !== void 0 ? values : textOrConfig.values) !== null && _a !== void 0 ? _a : textOrConfig.params;
|
|
59
|
+
const normalized = (0, testkit_core_1.alignRewrittenParameters)(rewritten.sql, incomingParams);
|
|
60
|
+
const payload = typeof textOrConfig === 'string'
|
|
61
|
+
? normalized.sql
|
|
62
|
+
: { ...textOrConfig, text: normalized.sql, values: normalized.params };
|
|
63
|
+
let result = typeof payload === 'string'
|
|
64
|
+
? await value.call(target, payload, normalized.params)
|
|
65
|
+
: await value.call(target, payload);
|
|
66
|
+
(_b = options.onExecute) === null || _b === void 0 ? void 0 : _b.call(options, normalized.sql, normalized.params, rewritten.fixturesApplied);
|
|
67
|
+
// Normalize rowCount/command only when the rewriter produced a count-wrapper SELECT.
|
|
68
|
+
result = (0, testkit_core_1.applyCountWrapper)(result, rewritten.sourceCommand, rewritten.isCountWrapper);
|
|
69
|
+
return result;
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
return typeof value === 'function' ? value.bind(target) : value;
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
};
|
|
76
|
+
return buildProxy();
|
|
77
|
+
};
|
|
78
|
+
exports.wrapPgClient = wrapPgClient;
|
|
79
|
+
//# sourceMappingURL=wrapPgClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wrapPgClient.js","sourceRoot":"","sources":["../../../../../../../drivers/pg-testkit/src/proxy/wrapPgClient.ts"],"names":[],"mappings":"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"}
|