@rawsql-ts/ztd-cli 0.16.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 +33 -20
- package/dist/commands/init.d.ts +13 -0
- package/dist/commands/init.js +372 -127
- 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 +16 -9
- package/templates/AGENTS.md +36 -309
- package/templates/README.md +12 -215
- package/templates/dist/ztd-cli/templates/src/db/sql-client.ts +24 -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 -150
- 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/tsconfig.json +8 -1
- package/templates/ztd/AGENTS.md +11 -67
- package/templates/ztd/README.md +4 -13
- package/templates/ztd/ddl/AGENTS.md +34 -0
- package/templates/ztd/ddl/demo.sql +74 -0
- package/templates/src/repositories/user-accounts.ts +0 -179
- package/templates/tests/user-profiles.test.ts +0 -161
- package/templates/tests/writer-constraints.test.ts +0 -32
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.clearOptionalDependencyCache = clearOptionalDependencyCache;
|
|
40
|
+
exports.ensureTestkitCoreModule = ensureTestkitCoreModule;
|
|
41
|
+
exports.ensureAdapterNodePgModule = ensureAdapterNodePgModule;
|
|
42
|
+
exports.ensurePgModule = ensurePgModule;
|
|
43
|
+
exports.ensurePostgresContainerModule = ensurePostgresContainerModule;
|
|
44
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
45
|
+
const node_module_1 = require("node:module");
|
|
46
|
+
const node_url_1 = require("node:url");
|
|
47
|
+
const moduleCache = new Map();
|
|
48
|
+
async function loadOptionalModule(cacheKey, loader, description, installHint) {
|
|
49
|
+
if (moduleCache.has(cacheKey)) {
|
|
50
|
+
return moduleCache.get(cacheKey);
|
|
51
|
+
}
|
|
52
|
+
const moduleLoader = loader()
|
|
53
|
+
.catch((error) => {
|
|
54
|
+
moduleCache.delete(cacheKey);
|
|
55
|
+
const installNote = installHint ? ` Install it via \`${installHint}\`.` : '';
|
|
56
|
+
const original = error instanceof Error ? ` (${error.message})` : '';
|
|
57
|
+
throw new Error(`${description}${installNote}${original}`);
|
|
58
|
+
});
|
|
59
|
+
moduleCache.set(cacheKey, moduleLoader);
|
|
60
|
+
return moduleLoader;
|
|
61
|
+
}
|
|
62
|
+
function clearOptionalDependencyCache() {
|
|
63
|
+
moduleCache.clear();
|
|
64
|
+
}
|
|
65
|
+
function requireFromWorkspace(specifier) {
|
|
66
|
+
const require = (0, node_module_1.createRequire)(node_path_1.default.resolve(process.cwd(), 'package.json'));
|
|
67
|
+
return require(specifier);
|
|
68
|
+
}
|
|
69
|
+
async function loadAdapterNodePgModule() {
|
|
70
|
+
try {
|
|
71
|
+
return requireFromWorkspace('@rawsql-ts/adapter-node-pg');
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
// Workspace tests can run before adapter build output exists, so use source entrypoint.
|
|
75
|
+
const workspaceAdapterSrc = node_path_1.default.resolve(process.cwd(), 'packages/adapters/adapter-node-pg/src/index.ts');
|
|
76
|
+
try {
|
|
77
|
+
return (await Promise.resolve(`${(0, node_url_1.pathToFileURL)(workspaceAdapterSrc).href}`).then(s => __importStar(require(s))));
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
throw error;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
async function ensureTestkitCoreModule() {
|
|
85
|
+
return loadOptionalModule('@rawsql-ts/testkit-core', () => Promise.resolve().then(() => __importStar(require('@rawsql-ts/testkit-core'))), 'This command requires @rawsql-ts/testkit-core so fixtures and schema metadata are available.', 'pnpm add -D @rawsql-ts/testkit-core');
|
|
86
|
+
}
|
|
87
|
+
async function ensureAdapterNodePgModule() {
|
|
88
|
+
return loadOptionalModule('@rawsql-ts/adapter-node-pg', loadAdapterNodePgModule, 'A database adapter (for example @rawsql-ts/adapter-node-pg) is required to execute the rewritten SQL.', 'pnpm add -D @rawsql-ts/adapter-node-pg');
|
|
89
|
+
}
|
|
90
|
+
async function ensurePgModule() {
|
|
91
|
+
return loadOptionalModule('pg', () => Promise.resolve().then(() => __importStar(require('pg'))), 'The SQL lint command needs a PostgreSQL driver such as pg.', 'pnpm add -D pg');
|
|
92
|
+
}
|
|
93
|
+
async function ensurePostgresContainerModule() {
|
|
94
|
+
return loadOptionalModule('@testcontainers/postgresql', () => Promise.resolve().then(() => __importStar(require('@testcontainers/postgresql'))), 'ztd lint wants to spin up a disposable Postgres container via @testcontainers/postgresql.', 'pnpm add -D @testcontainers/postgresql');
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=optionalDependencies.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"optionalDependencies.js","sourceRoot":"","sources":["../../src/utils/optionalDependencies.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgEA,oEAEC;AAwBD,0DAOC;AAED,8DAOC;AAED,wCAOC;AAED,sEAOC;AA5HD,0DAA6B;AAC7B,6CAA4C;AAC5C,uCAAyC;AAEzC,MAAM,WAAW,GAAG,IAAI,GAAG,EAA4B,CAAC;AAExD,KAAK,UAAU,kBAAkB,CAC/B,QAAgB,EAChB,MAAwB,EACxB,WAAmB,EACnB,WAAmB;IAEnB,IAAI,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC9B,OAAO,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAe,CAAC;IACjD,CAAC;IAED,MAAM,YAAY,GAAG,MAAM,EAAE;SAC1B,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;QACf,WAAW,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC7B,MAAM,WAAW,GAAG,WAAW,CAAC,CAAC,CAAC,qBAAqB,WAAW,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7E,MAAM,QAAQ,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QACrE,MAAM,IAAI,KAAK,CAAC,GAAG,WAAW,GAAG,WAAW,GAAG,QAAQ,EAAE,CAAC,CAAC;IAC7D,CAAC,CAAC,CAAC;IAEL,WAAW,CAAC,GAAG,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;IACxC,OAAO,YAAY,CAAC;AACtB,CAAC;AAsCD,SAAgB,4BAA4B;IAC1C,WAAW,CAAC,KAAK,EAAE,CAAC;AACtB,CAAC;AAED,SAAS,oBAAoB,CAAI,SAAiB;IAChD,MAAM,OAAO,GAAG,IAAA,2BAAa,EAAC,mBAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,cAAc,CAAC,CAAC,CAAC;IAC3E,OAAO,OAAO,CAAC,SAAS,CAAM,CAAC;AACjC,CAAC;AAED,KAAK,UAAU,uBAAuB;IACpC,IAAI,CAAC;QACH,OAAO,oBAAoB,CAAsB,4BAA4B,CAAC,CAAC;IACjF,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,wFAAwF;QACxF,MAAM,mBAAmB,GAAG,mBAAI,CAAC,OAAO,CACtC,OAAO,CAAC,GAAG,EAAE,EACb,gDAAgD,CACjD,CAAC;QACF,IAAI,CAAC;YACH,OAAO,CAAC,yBAAa,IAAA,wBAAa,EAAC,mBAAmB,CAAC,CAAC,IAAI,uCAAC,CAAwB,CAAC;QACxF,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;AACH,CAAC;AAEM,KAAK,UAAU,uBAAuB;IAC3C,OAAO,kBAAkB,CACvB,yBAAyB,EACzB,GAAG,EAAE,mDAAQ,yBAAyB,GAAC,EACvC,8FAA8F,EAC9F,qCAAqC,CACtC,CAAC;AACJ,CAAC;AAEM,KAAK,UAAU,yBAAyB;IAC7C,OAAO,kBAAkB,CACvB,4BAA4B,EAC5B,uBAAuB,EACvB,uGAAuG,EACvG,wCAAwC,CACzC,CAAC;AACJ,CAAC;AAEM,KAAK,UAAU,cAAc;IAClC,OAAO,kBAAkB,CACvB,IAAI,EACJ,GAAG,EAAE,mDAAQ,IAAI,GAAC,EAClB,4DAA4D,EAC5D,gBAAgB,CACjB,CAAC;AACJ,CAAC;AAEM,KAAK,UAAU,6BAA6B;IACjD,OAAO,kBAAkB,CACvB,4BAA4B,EAC5B,GAAG,EAAE,mDAAQ,4BAA4B,GAAC,EAC1C,2FAA2F,EAC3F,wCAAwC,CACzC,CAAC;AACJ,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rawsql-ts/ztd-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.0",
|
|
4
4
|
"description": "DB-agnostic scaffolding and DDL helpers for Zero Table Dependency projects",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -22,23 +22,31 @@
|
|
|
22
22
|
"node": ">=20"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@testcontainers/postgresql": "^10.28.0",
|
|
26
25
|
"chokidar": "^5.0.0",
|
|
27
26
|
"commander": "^12.0.0",
|
|
28
27
|
"diff": "^8.0.3",
|
|
29
28
|
"fast-glob": "^3.3.3",
|
|
30
|
-
"pg": "^8.11.1",
|
|
31
|
-
"testcontainers": "^10.28.0",
|
|
32
|
-
"@rawsql-ts/adapter-node-pg": "^0.15.1",
|
|
33
|
-
"@rawsql-ts/testkit-postgres": "^0.15.1",
|
|
34
|
-
"@rawsql-ts/testkit-core": "^0.15.1",
|
|
35
29
|
"rawsql-ts": "^0.16.0"
|
|
36
30
|
},
|
|
31
|
+
"peerDependencies": {
|
|
32
|
+
"@rawsql-ts/adapter-node-pg": "^0.15.2"
|
|
33
|
+
},
|
|
34
|
+
"peerDependenciesMeta": {
|
|
35
|
+
"@rawsql-ts/adapter-node-pg": {
|
|
36
|
+
"optional": true
|
|
37
|
+
}
|
|
38
|
+
},
|
|
37
39
|
"devDependencies": {
|
|
40
|
+
"@testcontainers/postgresql": "^10.28.0",
|
|
38
41
|
"@types/diff": "^5.0.1",
|
|
39
42
|
"@types/node": "^22.13.10",
|
|
43
|
+
"pg": "^8.11.1",
|
|
44
|
+
"testcontainers": "^10.28.0",
|
|
40
45
|
"typescript": "^5.8.2",
|
|
41
|
-
"vitest": "^4.0.7"
|
|
46
|
+
"vitest": "^4.0.7",
|
|
47
|
+
"@rawsql-ts/adapter-node-pg": "^0.15.2",
|
|
48
|
+
"@rawsql-ts/testkit-core": "^0.15.1",
|
|
49
|
+
"@rawsql-ts/testkit-postgres": "^0.15.1"
|
|
42
50
|
},
|
|
43
51
|
"files": [
|
|
44
52
|
"dist",
|
|
@@ -47,7 +55,6 @@
|
|
|
47
55
|
"README.md"
|
|
48
56
|
],
|
|
49
57
|
"scripts": {
|
|
50
|
-
"prebuild": "pnpm --filter @rawsql-ts/testkit-core build && pnpm --filter @rawsql-ts/testkit-postgres build && pnpm --filter @rawsql-ts/adapter-node-pg build",
|
|
51
58
|
"build": "tsc -p tsconfig.json",
|
|
52
59
|
"test": "vitest run",
|
|
53
60
|
"lint": "eslint src --ext .ts",
|
package/templates/AGENTS.md
CHANGED
|
@@ -1,325 +1,52 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Workspace AGENTS
|
|
2
2
|
|
|
3
|
-
This
|
|
4
|
-
|
|
3
|
+
This repository uses directory-scoped AGENTS.
|
|
4
|
+
Rules live close to where the work happens.
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
- Keeping schema metadata and generated artifacts synchronized
|
|
8
|
-
- Ensuring deterministic SQL unit tests
|
|
9
|
-
- Enabling structured collaboration between humans and AI
|
|
6
|
+
## Rule precedence
|
|
10
7
|
|
|
11
|
-
|
|
8
|
+
- The closest "AGENTS.md" to the file being edited has the highest priority.
|
|
9
|
+
- Parent directories provide shared rules.
|
|
10
|
+
- Child directories should only describe deltas.
|
|
12
11
|
|
|
13
|
-
|
|
12
|
+
## Global non-negotiables
|
|
14
13
|
|
|
15
|
-
|
|
14
|
+
- Do not guess. If something is unknown, state "Not observed" and propose the next check.
|
|
15
|
+
- Do not edit generated artifacts unless explicitly instructed.
|
|
16
|
+
- Respect ownership boundaries: human-owned contracts must not be changed without explicit instruction.
|
|
16
17
|
|
|
17
|
-
|
|
18
|
-
- ZTD is assumed unless explicitly stated otherwise.
|
|
19
|
-
- Detailed rules about test execution modes are defined in `templates/tests/AGENTS.md`.
|
|
18
|
+
## Runtime vs non-runtime
|
|
20
19
|
|
|
21
|
-
|
|
20
|
+
- Runtime assets live under "src/": executed/loaded by the application.
|
|
21
|
+
- Non-runtime assets live under "ztd/" and parts of "tests/": used for verification and generation.
|
|
22
22
|
|
|
23
|
-
##
|
|
23
|
+
## Human-owned vs AI-assisted (important)
|
|
24
24
|
|
|
25
|
-
-
|
|
26
|
-
-
|
|
27
|
-
-
|
|
25
|
+
Human-owned (do not change without explicit instruction):
|
|
26
|
+
- "ztd/ddl" (physical schema / DDL)
|
|
27
|
+
- "src/catalog/specs" (query contracts: params + DTO + semantics)
|
|
28
|
+
- "src/sql" (SQL assets; AI may propose patches, but do not rewrite intent)
|
|
28
29
|
|
|
29
|
-
|
|
30
|
+
AI-assisted (implementation and verification):
|
|
31
|
+
- "src/repositories"
|
|
32
|
+
- "src/catalog/runtime"
|
|
33
|
+
- "tests" (except "tests/generated")
|
|
30
34
|
|
|
31
|
-
|
|
35
|
+
Never touch by hand:
|
|
36
|
+
- "tests/generated"
|
|
32
37
|
|
|
33
|
-
|
|
38
|
+
## Where to read next
|
|
34
39
|
|
|
35
|
-
-
|
|
36
|
-
-
|
|
37
|
-
-
|
|
38
|
-
-
|
|
39
|
-
|
|
40
|
+
- "src/catalog/AGENTS.md": catalog layout and contract boundaries
|
|
41
|
+
- "src/repositories/AGENTS.md": repository responsibilities and restrictions
|
|
42
|
+
- "src/sql/AGENTS.md": SQL asset rules
|
|
43
|
+
- "tests/AGENTS.md": ZTD testing rules
|
|
44
|
+
- "ztd/ddl/AGENTS.md": DDL authoring rules
|
|
40
45
|
|
|
41
|
-
|
|
42
|
-
In ZTD-based development, many schema or SQL inconsistencies surface first as TypeScript errors via generated row maps and DTOs.
|
|
43
|
-
Type checking is a primary correctness signal, not an optional step.
|
|
46
|
+
## Test environment guarantee (important)
|
|
44
47
|
|
|
45
|
-
|
|
48
|
+
- This workspace MUST be test-runnable immediately after initialization.
|
|
49
|
+
- `pnpm test` (or equivalent) must not fail due to missing configuration.
|
|
50
|
+
- Test runner configuration (e.g. vitest.config.ts) is considered part of the template contract.
|
|
46
51
|
|
|
47
|
-
|
|
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.
|
|
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
|
-
|
|
58
|
-
### Repository Classes: What to Care About
|
|
59
|
-
|
|
60
|
-
#### Scope and Responsibility
|
|
61
|
-
- Repository classes are responsible for executing SQL and returning query results.
|
|
62
|
-
- Avoid embedding business logic, thresholds, or data reshaping inside repositories.
|
|
63
|
-
- Treat repositories as thin adapters over SQL.
|
|
64
|
-
|
|
65
|
-
#### Mandatory testing rule (important)
|
|
66
|
-
|
|
67
|
-
Whenever a repository class is created or modified, corresponding tests **must** be created or updated.
|
|
68
|
-
|
|
69
|
-
Rules:
|
|
70
|
-
- Every public repository method must be covered by tests.
|
|
71
|
-
- Tests must call repository methods, not raw SQL files or SQL strings.
|
|
72
|
-
- ZTD fixtures are the only allowed source of database state in tests.
|
|
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.
|
|
77
|
-
|
|
78
|
-
Rationale:
|
|
79
|
-
ZTD derives much of its value from deterministic, repository-level tests.
|
|
80
|
-
Without tests, schema drift and SQL inconsistencies cannot be detected.
|
|
81
|
-
|
|
82
|
-
#### SQL Management
|
|
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.
|
|
87
|
-
|
|
88
|
-
#### Specifications and Documentation
|
|
89
|
-
- If a markdown file with the same base name as the repository or SQL exists, read it before implementation.
|
|
90
|
-
- Such files may contain repository-local specifications (e.g. decision tables, thresholds, request/response notes).
|
|
91
|
-
- Naming should be aligned (e.g. `FooRepository.ts`, `foo.sql`, `foo.md`).
|
|
92
|
-
|
|
93
|
-
#### Request and Response Contracts
|
|
94
|
-
- Be explicit about request parameters (types, nullability, constraints).
|
|
95
|
-
- Be explicit about response shape (columns, ordering, cardinality).
|
|
96
|
-
- Prefer documenting contracts in the repository-local markdown file rather than code comments when they are non-trivial.
|
|
97
|
-
|
|
98
|
-
### SqlClient lifecycle policy (important)
|
|
99
|
-
|
|
100
|
-
- When using `src/db/sql-client.ts`, prefer a shared `SqlClient` per worker process (singleton).
|
|
101
|
-
- Avoid creating a new database connection for every query or test case.
|
|
102
|
-
- Do not share a live connection across parallel workers; each worker should own its own shared client or pool.
|
|
103
|
-
- If you need strict isolation, create a dedicated client for that scope and close it explicitly.
|
|
104
|
-
|
|
105
|
-
### Repository SQL and DTO policy (important)
|
|
106
|
-
|
|
107
|
-
- Repository SQL must return application-facing DTO shapes.
|
|
108
|
-
- SQL SELECT statements should alias columns to camelCase and match the repository return types.
|
|
109
|
-
- Do not introduce intermediate `*Row` types when SQL already returns DTO-compatible shapes.
|
|
110
|
-
- Define separate Row types only when SQL intentionally returns database-shaped (snake_case) rows, and always convert them explicitly.
|
|
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
|
-
|
|
138
|
-
### Sequence / identity column policy (important)
|
|
139
|
-
|
|
140
|
-
- Sequence / identity columns (auto-generated IDs) are infrastructure concerns.
|
|
141
|
-
- Do not explicitly assign values to sequence / identity columns in `INSERT` statements unless explicitly instructed.
|
|
142
|
-
- Repository method inputs should omit sequence / identity columns by default.
|
|
143
|
-
- Only treat an ID as input data when it represents a business rule (e.g. natural keys, externally assigned IDs).
|
|
144
|
-
|
|
145
|
-
### No test-driven fallbacks in production code (important)
|
|
146
|
-
|
|
147
|
-
- Do not add fallbacks in `src/` that exist only to accommodate ZTD/testkit/rewriter limitations.
|
|
148
|
-
- If a query fails to be rewritten into ZTD form, do not change runtime behavior to compensate.
|
|
149
|
-
- Report tooling issues with minimal reproduction and expected behavior.
|
|
150
|
-
|
|
151
|
-
Rationale:
|
|
152
|
-
Production code must not diverge from intended SQL semantics due to tooling constraints.
|
|
153
|
-
|
|
154
|
-
---
|
|
155
|
-
|
|
156
|
-
## ZTD Test Guide (tests/)
|
|
157
|
-
|
|
158
|
-
Testing under ZTD follows dedicated, directory-scoped rules.
|
|
159
|
-
|
|
160
|
-
- Test design, execution mode selection, and constraints are defined in:
|
|
161
|
-
- `templates/tests/AGENTS.md`
|
|
162
|
-
- Tests validate repository behavior and returned DTOs.
|
|
163
|
-
- Raw SQL files or SQL strings must not be tested directly.
|
|
164
|
-
|
|
165
|
-
---
|
|
166
|
-
|
|
167
|
-
# ZTD Directory Layout
|
|
168
|
-
|
|
169
|
-
```
|
|
170
|
-
/ztd
|
|
171
|
-
/ddl
|
|
172
|
-
*.sql <- physical schema definitions
|
|
173
|
-
|
|
174
|
-
README.md <- documentation for the layout
|
|
175
|
-
AGENTS.md <- combined guidance for DDL
|
|
176
|
-
|
|
177
|
-
/src <- application & repository logic
|
|
178
|
-
/tests <- ZTD tests, fixtures, row-maps
|
|
179
|
-
```
|
|
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
|
-
|
|
183
|
-
The file `tests/generated/ztd-layout.generated.ts` ensures ZTD CLI always points to the correct directories.
|
|
184
|
-
|
|
185
|
-
---
|
|
186
|
-
|
|
187
|
-
# Protected directories and edit ownership (important)
|
|
188
|
-
|
|
189
|
-
- DDL editing is human-led: `ztd/ddl/`
|
|
190
|
-
- `ztd/ddl` is the sole human-owned directory inside `/ztd`; other directories must not be assumed or created without explicit instructions.
|
|
191
|
-
- Application code is shared ownership: `src/`
|
|
192
|
-
- Tests are shared ownership: `tests/`
|
|
193
|
-
- Detailed test constraints live in `templates/tests/AGENTS.md`.
|
|
194
|
-
|
|
195
|
-
Additionally:
|
|
196
|
-
- Never modify `ztd/AGENTS.md` or `ztd/README.md` without explicit instruction.
|
|
197
|
-
- When changes are required in human-led directories, prefer proposing a patch and explaining the impact before applying it.
|
|
198
|
-
|
|
199
|
-
---
|
|
200
|
-
|
|
201
|
-
# Principles of ZTD in This Repository
|
|
202
|
-
|
|
203
|
-
### 1. Humans own the definitions
|
|
204
|
-
- Physical schema (DDL)
|
|
205
|
-
- Repository interfaces
|
|
206
|
-
|
|
207
|
-
### 2. AI assists with implementation
|
|
208
|
-
- Generating repository SQL
|
|
209
|
-
- Updating fixtures
|
|
210
|
-
- Producing intermediate TypeScript structures
|
|
211
|
-
- Ensuring SQL adheres to DDL
|
|
212
|
-
|
|
213
|
-
### 3. ZTD enforces consistency
|
|
214
|
-
ZTD tests verify that:
|
|
215
|
-
- SQL logic matches DDL shapes
|
|
216
|
-
|
|
217
|
-
If anything diverges, ZTD failures surface immediately and deterministically.
|
|
218
|
-
|
|
219
|
-
---
|
|
220
|
-
|
|
221
|
-
# Development Workflows
|
|
222
|
-
|
|
223
|
-
Different types of changes start from different entry points. Use the workflow appropriate for your situation.
|
|
224
|
-
|
|
225
|
-
---
|
|
226
|
-
|
|
227
|
-
# Workflow A - Starting From DDL Changes
|
|
228
|
-
Modifying tables, columns, constraints, indexes.
|
|
229
|
-
|
|
230
|
-
1. Edit DDL files in `ztd/ddl/`.
|
|
231
|
-
2. Run `npx ztd ztd-config`.
|
|
232
|
-
3. Update repository SQL to match the new schema.
|
|
233
|
-
4. Update fixtures if result shapes changed.
|
|
234
|
-
5. Run tests.
|
|
235
|
-
|
|
236
|
-
Flow: DDL to Repository SQL to Fixtures and Tests to Application
|
|
237
|
-
|
|
238
|
-
---
|
|
239
|
-
|
|
240
|
-
# Workflow B - Starting From Repository Interface Changes
|
|
241
|
-
Changing method signatures, adding new repository methods, etc.
|
|
242
|
-
|
|
243
|
-
1. Modify the repository interface or implementation in `/src`.
|
|
244
|
-
2. Use AI assistance to generate or update the SQL implementation.
|
|
245
|
-
3. If the generated SQL conflicts with DDL or other human-maintained references, update the authoritative source first.
|
|
246
|
-
4. Run ZTD tests.
|
|
247
|
-
5. Regenerate config if SQL output shape changed.
|
|
248
|
-
|
|
249
|
-
Flow: Interface to SQL to Tests
|
|
250
|
-
|
|
251
|
-
---
|
|
252
|
-
|
|
253
|
-
# Workflow C - Starting From Repository SQL Logic Changes
|
|
254
|
-
Bug fixes, refactoring, rewriting queries.
|
|
255
|
-
|
|
256
|
-
1. Edit SQL inside the repository.
|
|
257
|
-
2. Run ZTD tests.
|
|
258
|
-
3. If intended behavior changes, coordinate any necessary DDL updates before adjusting dependent code.
|
|
259
|
-
4. Update fixtures as needed.
|
|
260
|
-
5. Regenerate config if result shape changed.
|
|
261
|
-
|
|
262
|
-
Flow: SQL to Tests
|
|
263
|
-
|
|
264
|
-
---
|
|
265
|
-
|
|
266
|
-
# Combined Real-World Examples
|
|
267
|
-
|
|
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
|
|
271
|
-
|
|
272
|
-
ZTD ensures the development always converges into a consistent, validated workflow.
|
|
273
|
-
|
|
274
|
-
---
|
|
275
|
-
|
|
276
|
-
# Human Responsibilities
|
|
277
|
-
|
|
278
|
-
Humans maintain:
|
|
279
|
-
|
|
280
|
-
- Schema definitions (`ztd/ddl`)
|
|
281
|
-
- Repository interfaces and architectural decisions
|
|
282
|
-
- Acceptance and review of AI-generated patches
|
|
283
|
-
|
|
284
|
-
Humans decide what is correct.
|
|
285
|
-
|
|
286
|
-
---
|
|
287
|
-
|
|
288
|
-
# AI Responsibilities
|
|
289
|
-
|
|
290
|
-
AI must:
|
|
291
|
-
|
|
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.
|
|
296
|
-
|
|
297
|
-
AI decides how to implement, but not what is correct.
|
|
298
|
-
|
|
299
|
-
---
|
|
300
|
-
|
|
301
|
-
# ZTD CLI Responsibilities
|
|
302
|
-
|
|
303
|
-
ZTD CLI:
|
|
304
|
-
|
|
305
|
-
- Parses DDL to compute schema shapes
|
|
306
|
-
- Rewrites SQL via CTE shadowing for testing
|
|
307
|
-
- Generates `ztd-row-map.generated.ts`
|
|
308
|
-
- Enables deterministic, parallel SQL unit tests
|
|
309
|
-
|
|
310
|
-
ZTD is the verification engine that validates correctness beyond static typing.
|
|
311
|
-
|
|
312
|
-
---
|
|
313
|
-
|
|
314
|
-
# Summary
|
|
315
|
-
|
|
316
|
-
This appendix documents how ZTD is used strictly as an internal implementation and maintenance guide.
|
|
317
|
-
It does not affect the runtime behavior of the application.
|
|
318
|
-
Its purpose is ensuring:
|
|
319
|
-
|
|
320
|
-
- Schema integrity
|
|
321
|
-
- SQL correctness
|
|
322
|
-
- Domain consistency
|
|
323
|
-
- Reliable AI-assisted development
|
|
324
|
-
|
|
325
|
-
With ZTD, humans define the meaning, AI writes the implementation, and tests guarantee correctness.
|
|
52
|
+
If tests fail due to missing config, this is a template defect, not a user error.
|