Skip to content

Commit 9789934

Browse files
authored
Merge pull request #433 from mk3008/feat/ztd-cli-zero-deps
Refactor ztd-cli to reduce dependencies and support named parameters
2 parents 49a2ba9 + c25a109 commit 9789934

File tree

99 files changed

+2989
-3693
lines changed

Some content is hidden

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

99 files changed

+2989
-3693
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
"@rawsql-ts/sql-contract": minor
3+
"@rawsql-ts/ztd-cli": patch
4+
---
5+
6+
Add a new public `timestampFromDriver(value, fieldName?)` helper in `@rawsql-ts/sql-contract` for fail-fast `Date | string` normalization of driver-returned timestamps.
7+
8+
Update `@rawsql-ts/ztd-cli` templates to normalize runtime timestamp fields through the shared sql-contract helper (via runtime coercion wiring), add strict guardrails against local timestamp re-implementation, and expand scaffold smoke validation tests for valid and invalid timestamp strings.

.changeset/sql-first-binder.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@rawsql-ts/ztd-cli": minor
3+
"@rawsql-ts/adapter-node-pg": patch
4+
---
5+
6+
Adopt SQL-first scaffolding with named-parameter SQL layout in the ZTD template, and compile named parameters to indexed placeholders in the pg adapter.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@rawsql-ts/ztd-cli": minor
3+
---
4+
5+
Redesign `ztd init` to produce a deterministic minimal scaffold with per-folder AGENTS.md guidance and option-specific DDL seeding only (pg_dump, empty, or demo DDL).
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@rawsql-ts/ztd-cli": minor
3+
---
4+
5+
Add the new default ZTD scaffold layout with view SQL under "src/sql/views", job SQL under "src/sql/jobs", and repositories split between "src/repositories/views" and "src/repositories/tables". The init command now supports "--yes" to overwrite existing scaffold files without prompts for non-interactive runs.

.github/workflows/pr-check.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,18 @@ jobs:
3232
pnpm --filter @rawsql-ts/testkit-core run build
3333
pnpm --filter @rawsql-ts/ztd-cli run build
3434
35+
- name: Detect deprecated playground
36+
id: playground
37+
run: |
38+
if [ -d "./playgrounds/ztd-playground" ]; then
39+
echo "exists=true" >> "$GITHUB_OUTPUT"
40+
else
41+
echo "exists=false" >> "$GITHUB_OUTPUT"
42+
echo "playgrounds/ztd-playground is removed; skipping playground artifact generation."
43+
fi
44+
3545
- name: Generate ZTD artifacts (playground)
46+
if: steps.playground.outputs.exists == 'true'
3647
working-directory: ./playgrounds/ztd-playground
3748
run: node ../../packages/ztd-cli/dist/index.js ztd-config
3849

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,3 +191,4 @@ docs/.vitepress/dist
191191
docs/.vitepress/cache
192192

193193
CONTINUITY.md
194+
playgrounds/ztd-playground/

AGENTS.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,8 @@ When changing schemas or search paths, update `ztd.config.json` accordingly.
106106
* Use `pnpm` and `pnpm --filter <package>` for scoped tasks.
107107
* All identifiers, comments, and documentation must be written in English.
108108
* Use `./tmp` for throwaway assets.
109+
* In tests, do not duplicate production normalization or sanitization rules; import shared helpers from source modules whenever those helpers are deterministic and side-effect free.
110+
* In docs, avoid directional wording like "below" when pointing to separate recipe files; use explicit Markdown links to the target document.
109111
* README and driver demos must exercise the rewrite and fixture helpers located at
110112
`packages/sql-contract/tests/readme/support/postgres-demo.ts`.
111113
* Remove console debugging statements before committing.
@@ -136,6 +138,12 @@ Run the following before opening or updating a PR:
136138

137139
---
138140

141+
## Validation tooling recipes
142+
143+
- Every ZTD project installs `@rawsql-ts/sql-contract` and a validator backend during `ztd init`, so `docs/recipes/sql-contract.md` is the canonical mapping reference.
144+
- When both `@rawsql-ts/sql-contract` and `zod` are declared, follow the Zod validator flow in `docs/recipes/validation-zod.md`. Installing `@rawsql-ts/sql-contract-zod` is optional sugar that adds `mapper.zod` and coercion helpers on top of the same base stack.
145+
- When `@rawsql-ts/sql-contract` is present without `zod` but `arktype` is declared, follow the ArkType recipe in `docs/recipes/validation-arktype.md`.
146+
139147
## Docs Demo Updates
140148

141149
* Rebuild the browser bundle when parser or formatter behavior changes:

docs/recipes/sql-contract.md

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
---
2+
title: SQL catalog & mapping recipe
3+
---
4+
5+
# SQL catalog & mapping recipe
6+
7+
When `ztd init` enables runtime validation, it always installs `@rawsql-ts/sql-contract` so you can map raw SQL rows into DTOs without duplicating column metadata.
8+
9+
## Install
10+
11+
```bash
12+
pnpm add -D @rawsql-ts/sql-contract
13+
```
14+
15+
## What to wire
16+
17+
- Use `createReader` (and `createWriter` when you need CUD helpers) to wrap the executor that appears in `tests/support/testkit-client.ts`.
18+
- Bind domain-specific `rowMapping` definitions to the reader so DTO shapes stay explicit and reusable.
19+
- Refer to `tests/generated/ztd-row-map.generated.ts` for authoritative row types and `src/repositories/*` for repository contracts.
20+
21+
### Example (`tests/support/testkit-client.ts`)
22+
23+
```ts
24+
import type { SqlClient } from '../../src/db/sql-client';
25+
import { createReader } from '@rawsql-ts/sql-contract/mapper';
26+
import { rowMapping } from '@rawsql-ts/sql-contract/mapper';
27+
import { getSqlClient } from '../support/sql-client-factory';
28+
29+
const executor = async (sql: string, params: readonly unknown[]) => {
30+
const client: SqlClient = await getSqlClient();
31+
const rows = await client.query(sql, params);
32+
return rows;
33+
};
34+
35+
const userMapping = rowMapping({
36+
name: 'UserProfile',
37+
key: 'userAccountId',
38+
columnMap: {
39+
userAccountId: 'user_account_id',
40+
displayName: 'display_name',
41+
},
42+
});
43+
44+
const reader = createReader(executor);
45+
46+
export async function listUserProfiles() {
47+
return reader.bind(userMapping).list(
48+
'SELECT user_account_id, display_name FROM public.user_account',
49+
[]
50+
);
51+
}
52+
```
53+
54+
The reader above can be used directly in tests or shared helpers so the same SQL, mapping, and fixtures power every suite.
55+
56+
## What’s next
57+
58+
- Wire runtime validation by following the [Zod](./validation-zod.md) or [ArkType](./validation-arktype.md) recipe. Validation is required for every ZTD project, so keep your chosen validator aligned with the reader/writer wiring.

docs/recipes/validation-arktype.md

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
---
2+
title: Validation recipe (ArkType)
3+
---
4+
5+
# Validation recipe (ArkType)
6+
7+
Selecting ArkType as the runtime validator installs `arktype` so you can validate every DTO using its expressive schema syntax while still executing SQL through `@rawsql-ts/sql-contract`. The runtime hook uses `reader.validator(...)`, so no additional helper package is required beyond `arktype`.
8+
9+
## Install
10+
11+
```bash
12+
pnpm add -D @rawsql-ts/sql-contract arktype
13+
```
14+
15+
## Example snippet
16+
17+
```ts
18+
import { type } from 'arktype';
19+
import { createReader } from '@rawsql-ts/sql-contract/mapper';
20+
import { getSqlClient } from '../support/sql-client-factory';
21+
22+
const executor = async (sql: string, params: readonly unknown[]) => {
23+
const client = await getSqlClient();
24+
return client.query(sql, params);
25+
};
26+
27+
const reader = createReader(executor);
28+
29+
const CustomerSchema = type({
30+
customerId: 'number',
31+
customerName: 'string',
32+
});
33+
34+
type Customer = ReturnType<typeof CustomerSchema>;
35+
36+
export async function listCustomers(): Promise<Customer[]> {
37+
return reader
38+
.validator((value) => {
39+
CustomerSchema.assert(value);
40+
return value as Customer;
41+
})
42+
.list('SELECT customer_id, customer_name FROM public.user_account', []);
43+
}
44+
```
45+
46+
This validator wraps the ArkType schema, asserts the DTO shape, and returns the typed value so the mapper pipeline remains untouched.
47+
48+
## Related recipes
49+
50+
- Use the SQL contract recipe for the base reader/writer wiring (`docs/recipes/sql-contract.md`).
51+
- The Zod recipe describes the alternate runtime validator (`docs/recipes/validation-zod.md`).

docs/recipes/validation-zod.md

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
---
2+
title: Validation recipe (Zod)
3+
---
4+
5+
# Validation recipe (Zod)
6+
7+
ZTD init always selects a validator backend. When Zod is chosen, you can wire schemas through `@rawsql-ts/sql-contract` without additional helpers.
8+
9+
## Install
10+
11+
```bash
12+
pnpm add -D @rawsql-ts/sql-contract zod
13+
```
14+
15+
`@rawsql-ts/sql-contract` exposes `reader.validator`, which accepts Zod schemas because they implement `parse(value)` (see `ReaderValidatorInput`). For convenience you can still install `@rawsql-ts/sql-contract-zod` if you want the `reader.zod` helper and numeric coercion helpers described in its README, but the base stack only requires `zod`.
16+
17+
## Example snippet
18+
19+
```ts
20+
import { z } from 'zod';
21+
import { createReader } from '@rawsql-ts/sql-contract/mapper';
22+
import { getSqlClient } from '../support/sql-client-factory';
23+
24+
const executor = async (sql: string, params: readonly unknown[]) => {
25+
const client = await getSqlClient();
26+
return client.query(sql, params);
27+
};
28+
29+
const reader = createReader(executor);
30+
31+
const CustomerSchema = z.object({
32+
customerId: z.number(),
33+
customerName: z.string(),
34+
});
35+
36+
export async function listCustomers() {
37+
return reader.validator(CustomerSchema).list(
38+
'SELECT customer_id, customer_name FROM public.user_account',
39+
[]
40+
);
41+
}
42+
```
43+
44+
Zod validation runs after the mapper binds every row to the DTO, so schema errors surface before tests rely on the result shape.
45+
46+
## Optional helper: @rawsql-ts/sql-contract-zod
47+
48+
`@rawsql-ts/sql-contract-zod` depends on the core mapper and adds the `mapper.zod` helper plus Zod-aware coercion helpers such as `zNumberFromString`. Install it only if you prefer those dedicated APIs; `@rawsql-ts/sql-contract` plus `zod` covers the required validator flow.

0 commit comments

Comments
 (0)