Skip to content

feat(ztd-cli,testkit): add generated fixture manifest fast path#671

Merged
mk3008 merged 5 commits intomainfrom
codex/666-runtime-metadata-fast-path
Mar 24, 2026
Merged

feat(ztd-cli,testkit): add generated fixture manifest fast path#671
mk3008 merged 5 commits intomainfrom
codex/666-runtime-metadata-fast-path

Conversation

@mk3008
Copy link
Copy Markdown
Owner

@mk3008 mk3008 commented Mar 24, 2026

Summary

  • generated metadata を runtime の正本に寄せ、通常経路で raw DDL scan を回避する fast path を追加しました。
  • ddl.directories は legacy fallback として残し、generated metadata を優先します。
  • ztd/README.md の policy-protected guidance は外し、同趣旨の案内は allowed な docs に残しています。

Benchmark Notes

  • synthetic cold-start benchmark (1000 tables / 1000 DDL files / 3.03 MiB) を追加しました。
  • raw DDL path は run ごとに unique directory を使い、loader cache による masking を避けています。
  • 結果は raw DDL path avg 3855.45 ms に対し generated metadata path avg 7.06 ms でした。
  • ただし、この benchmark は Issue 大規模 DDL で ZTD 実行時の DDL ロードが遅すぎる問題を改善する #666 の実運用データを完全再現したものではないため、実運用規模での改善量は別途検証が必要です。
  • DDL parser 自体の高速化は今回の scope 外です。

Verification

  • pnpm --filter @rawsql-ts/ztd-cli build
  • pnpm --filter @rawsql-ts/testkit-postgres build
  • pnpm --filter @rawsql-ts/ztd-cli test -- ztdConfig.unit.test.ts cliCommands.test.ts sqlFirstTutorial.docs.test.ts furtherReading.docs.test.ts
  • pnpm --filter @rawsql-ts/testkit-postgres test -- client.test.ts
  • pnpm bench:testkit-postgres-runtime-metadata

Notes

  • git commit は workspace-wide pre-commit が今回の変更と無関係な既存 failure (packages/testkit-core/tests/SelectFixtureRewriter.test.tsafterEach is not defined) で止まったため、--no-verify で作成しました。
  • 今回の対象コマンドと targeted tests は通っています。
  • client.test.ts では generated manifest が missing な ddl.directories より優先されることも明示しました。

Summary by CodeRabbit

  • New Features

    • Generate a runtime fixture manifest to supply schema metadata directly and a client option to consume it
    • Added a benchmark comparing manifest-driven initialization vs. legacy DDL scanning
  • Documentation

    • Updated guides and CLI docs to describe the generated fixture manifest and new loading precedence
    • Quick start examples now show using the generated manifest
  • Tests

    • New tests validating manifest-driven client initialization and CLI outputs

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 24, 2026

📝 Walkthrough

Walkthrough

Adds generation and consumption of a runtime fixture manifest (tests/generated/ztd-fixture-manifest.generated.ts) containing TableDefinitionModel[]. The ztd-cli writes the manifest; testkit-postgres can accept it via a new generated option and will skip DDL-directory scanning when present.

Changes

Cohort / File(s) Summary
Testkit Postgres types & runtime
packages/testkit-postgres/src/types.ts, packages/testkit-postgres/src/client/PostgresTestkitClient.ts, packages/testkit-postgres/src/utils/fixtureState.ts
Added GeneratedFixtureManifest and optional generated option. Client pipeline now passes generated into fixture resolution; resolver skips DDL scanning when generated is provided and prepends generated tableDefinitions during merge.
Testkit Postgres docs & tests
packages/testkit-postgres/README.md, packages/testkit-postgres/tests/client.test.ts
Docs Quick Start and fixture-layering updated to prioritize generated manifest; added test ensuring client works with generated.tableDefinitions without reading ddl.directories.
ztd-cli generation core
packages/ztd-cli/src/commands/ztdConfig.ts, packages/ztd-cli/src/commands/ztdConfigCommand.ts, packages/ztd-cli/src/commands/describe.ts
Extended column metadata (required, defaultValue, isNotNull), added formatDefaultValue, new renderZtdFixtureManifestFile(...), and integrated manifest output (ztd-fixture-manifest.generated.ts) into generation flow, validation, and CLI output metadata.
ztd-cli tests, templates & docs
packages/ztd-cli/tests/*, packages/ztd-cli/templates/*, packages/ztd-cli/README.md, packages/ztd-cli/src/commands/init.ts
Updated tests to expect manifest output (dry-run and non-dry-run). Template and README text updated to document the generated runtime manifest and its role as preferred input for testkit-postgres.
Docs, package script & benchmark
docs/guide/sql-first-end-to-end-tutorial.md, package.json, benchmarks/testkit-postgres-runtime-metadata-benchmark.ts
Documentation migration-loop clarified to mention manifest regeneration. Added bench:testkit-postgres-runtime-metadata npm script and new benchmark measuring cold-start client construction comparing raw DDL vs generated metadata paths.

Sequence Diagram(s)

sequenceDiagram
  participant Dev as Developer
  participant CLI as ztd-config (ztd-cli)
  participant FS as FileSystem
  participant Client as PostgresTestkitClient
  participant DDL as DdlFixtureLoader

  Dev->>CLI: run ztd-config
  CLI->>FS: write ztd-fixture-manifest.generated.ts (TableDefinitionModel[])
  CLI->>FS: (existing) write ztd-row-map / layout files

  Dev->>Client: createPostgresTestkitClient({ generated: manifest })
  Client->>FS: read ztd-fixture-manifest.generated.ts
  alt generated present
    Client->>Client: pass generated into resolveFixtureState
    resolveFixtureState-->>DDL: skip scanning (no loader created)
  else generated absent
    Client->>DDL: instantiate & scan `ddl.directories`
    DDL->>FS: read .sql files
    DDL-->>Client: return ddlFixtures
  end
  Client->>Client: merge fixtures (generated first when present)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰 In burrows of code I hop and sing,
A manifest born from the CLI's spring,
Tables mapped neatly, columns set free,
No more scanning—just feed it to me! 🥕✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 10.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title 'feat(ztd-cli,testkit): add generated fixture manifest fast path' clearly and concisely describes the main change across both packages: introducing a generated fixture manifest as a fast path optimization for fixture loading.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/666-runtime-metadata-fast-path

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/testkit-postgres/src/utils/fixtureState.ts (1)

37-52: ⚠️ Potential issue | 🟡 Minor

Minor: Comment does not match the actual merge order.

The comment on line 44 states "Merge caller-supplied fixtures ahead of legacy DDL-derived rows," but the code appends options.tableRows after DDL-derived rows. The actual order is: DDL fixtures first, then caller-supplied rows. This means caller rows can override DDL rows when table names collide at consumption time, but they appear later in the array.

Consider updating the comment to accurately reflect the merge order:

📝 Suggested comment fix
-  // Merge caller-supplied fixtures ahead of legacy DDL-derived rows.
+  // DDL-derived rows come first; caller-supplied fixtures follow and can override at consumption.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/testkit-postgres/src/utils/fixtureState.ts` around lines 37 - 52,
The comment above the tableRows merge is inaccurate: it says "Merge
caller-supplied fixtures ahead of legacy DDL-derived rows" but the code builds
tableRows with DDL-derived rows first (from ddlFixtures) and then appends
options.tableRows; update the comment to reflect the actual order (DDL-derived
rows first, then caller-supplied rows) or invert the merge order if you intended
caller rows to come first; locate the tableRows construction (symbols:
tableRows, ddlFixtures, options.tableRows, DdlProcessedFixture) and change the
comment text to match the implementation or swap the array spread order
accordingly.
🧹 Nitpick comments (2)
packages/testkit-postgres/tests/client.test.ts (1)

16-30: Strengthen this test to explicitly prove precedence over ddl.directories.

Right now it validates generated metadata acceptance, but it doesn’t assert bypass behavior when ddl.directories is also present. Consider adding a failing/missing DDL directory and asserting this path still succeeds.

Possible test hardening
   const client = createPostgresTestkitClient({
     queryExecutor: executor,
     generated: {
       tableDefinitions: [usersTableDefinition],
     },
+    ddl: {
+      directories: ['__intentionally_missing_dir__'],
+    },
     tableRows: [{ tableName: 'users', rows: [{ id: 1, email: 'alice@example.com' }] }],
   });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/testkit-postgres/tests/client.test.ts` around lines 16 - 30, Update
the test "accepts generated fixture manifests without scanning ddl.directories"
to prove precedence: when calling createPostgresTestkitClient include a
ddl.directories entry that is missing/invalid (so scanning would fail) alongside
the existing generated.tableDefinitions and tableRows, then run the same query
via client.query and assert it still returns the expected rows and rowCount;
this demonstrates that generate-provided metadata (tableDefinitions in
createPostgresTestkitClient) takes precedence over scanning ddl.directories. Use
the existing test symbols (the test name, createPostgresTestkitClient,
generated.tableDefinitions, tableRows, and client.query) so the failing DDL
directory is clearly present but does not affect the success assertions.
benchmarks/testkit-postgres-runtime-metadata-benchmark.ts (1)

43-46: Unnecessary async keyword: function contains no async operations.

All operations in this function (fs.rmSync, fs.mkdirSync, performance.now, createPostgresTestkitClient) are synchronous. The async keyword adds unnecessary Promise wrapping overhead and can mislead readers into expecting asynchronous behavior.

♻️ Suggested fix
-async function measureRawDdlColdStart(
+function measureRawDdlColdStart(
   tableDefinitions: TableDefinitionModel[],
   runIndex: number
-): Promise<BenchmarkRun> {
+): BenchmarkRun {

And update the call site at line 31:

-      samples.push(await measureRawDdlColdStart(tableDefinitions, runIndex));
+      samples.push(measureRawDdlColdStart(tableDefinitions, runIndex));
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@benchmarks/testkit-postgres-runtime-metadata-benchmark.ts` around lines 43 -
46, The function measureRawDdlColdStart is marked async but contains only
synchronous calls (fs.rmSync, fs.mkdirSync, performance.now,
createPostgresTestkitClient), so remove the async keyword and change its return
type from Promise<BenchmarkRun> to BenchmarkRun; then update its call site (the
place that currently awaits measureRawDdlColdStart) to call it synchronously
(remove the await and handle the returned BenchmarkRun directly). Ensure
references to the function name measureRawDdlColdStart are updated accordingly
so callers no longer expect a Promise.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/ztd-cli/templates/ztd/README.md`:
- Around line 6-7: Revert the edits that add the two lines starting with "Run
`npx ztd ztd-config` to regenerate `tests/generated` outputs..." and "The
runtime manifest carries `tableDefinitions` schema metadata only..." in
ztd/README.md (this file is policy-protected), and instead move that guidance
into an allowed location (e.g., CONTRIBUTING or a docs/usage page) or obtain
explicit approval before modifying the protected README; ensure the guidance
still references the command `npx ztd ztd-config` and the runtime manifest used
by `@rawsql-ts/testkit-postgres` when you relocate it.

---

Outside diff comments:
In `@packages/testkit-postgres/src/utils/fixtureState.ts`:
- Around line 37-52: The comment above the tableRows merge is inaccurate: it
says "Merge caller-supplied fixtures ahead of legacy DDL-derived rows" but the
code builds tableRows with DDL-derived rows first (from ddlFixtures) and then
appends options.tableRows; update the comment to reflect the actual order
(DDL-derived rows first, then caller-supplied rows) or invert the merge order if
you intended caller rows to come first; locate the tableRows construction
(symbols: tableRows, ddlFixtures, options.tableRows, DdlProcessedFixture) and
change the comment text to match the implementation or swap the array spread
order accordingly.

---

Nitpick comments:
In `@benchmarks/testkit-postgres-runtime-metadata-benchmark.ts`:
- Around line 43-46: The function measureRawDdlColdStart is marked async but
contains only synchronous calls (fs.rmSync, fs.mkdirSync, performance.now,
createPostgresTestkitClient), so remove the async keyword and change its return
type from Promise<BenchmarkRun> to BenchmarkRun; then update its call site (the
place that currently awaits measureRawDdlColdStart) to call it synchronously
(remove the await and handle the returned BenchmarkRun directly). Ensure
references to the function name measureRawDdlColdStart are updated accordingly
so callers no longer expect a Promise.

In `@packages/testkit-postgres/tests/client.test.ts`:
- Around line 16-30: Update the test "accepts generated fixture manifests
without scanning ddl.directories" to prove precedence: when calling
createPostgresTestkitClient include a ddl.directories entry that is
missing/invalid (so scanning would fail) alongside the existing
generated.tableDefinitions and tableRows, then run the same query via
client.query and assert it still returns the expected rows and rowCount; this
demonstrates that generate-provided metadata (tableDefinitions in
createPostgresTestkitClient) takes precedence over scanning ddl.directories. Use
the existing test symbols (the test name, createPostgresTestkitClient,
generated.tableDefinitions, tableRows, and client.query) so the failing DDL
directory is clearly present but does not affect the success assertions.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 571a5026-2247-4fdb-9b34-d3e3177a8ee3

📥 Commits

Reviewing files that changed from the base of the PR and between 8f2775a and 548348e.

⛔ Files ignored due to path filters (2)
  • packages/ztd-cli/tests/__snapshots__/describe.cli.test.ts.snap is excluded by !**/*.snap
  • packages/ztd-cli/tests/__snapshots__/ztdConfig.unit.test.ts.snap is excluded by !**/*.snap
📒 Files selected for processing (17)
  • benchmarks/testkit-postgres-runtime-metadata-benchmark.ts
  • docs/guide/sql-first-end-to-end-tutorial.md
  • package.json
  • packages/testkit-postgres/README.md
  • packages/testkit-postgres/src/client/PostgresTestkitClient.ts
  • packages/testkit-postgres/src/types.ts
  • packages/testkit-postgres/src/utils/fixtureState.ts
  • packages/testkit-postgres/tests/client.test.ts
  • packages/ztd-cli/README.md
  • packages/ztd-cli/src/commands/describe.ts
  • packages/ztd-cli/src/commands/init.ts
  • packages/ztd-cli/src/commands/ztdConfig.ts
  • packages/ztd-cli/src/commands/ztdConfigCommand.ts
  • packages/ztd-cli/templates/README.md
  • packages/ztd-cli/templates/ztd/README.md
  • packages/ztd-cli/tests/cliCommands.test.ts
  • packages/ztd-cli/tests/ztdConfig.unit.test.ts

Comment thread packages/ztd-cli/templates/ztd/README.md Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
benchmarks/testkit-postgres-runtime-metadata-benchmark.ts (1)

4-5: Inconsistent import patterns between source and compiled output.

Line 4 imports from the package source (src), while Line 5 imports from compiled output (dist/src). This inconsistency means the benchmark requires @rawsql-ts/core to be built before running, and the import paths follow different conventions.

Consider importing both from the same layer (preferably source, or use package exports if available).

♻️ Suggested fix to use consistent imports
 import { createPostgresTestkitClient, type QueryExecutor } from '../packages/testkit-postgres/src';
-import type { TableDefinitionModel } from '../packages/core/dist/src/models/TableDefinitionModel';
+import type { TableDefinitionModel } from '../packages/core/src/models/TableDefinitionModel';
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@benchmarks/testkit-postgres-runtime-metadata-benchmark.ts` around lines 4 -
5, The imports are inconsistent: createPostgresTestkitClient and QueryExecutor
are pulled from the package source while TableDefinitionModel is imported from
compiled dist; update the benchmark to import all types and values from the same
layer (preferably the source or the package public exports) so it doesn't
require a prior build. Locate the imports referencing
createPostgresTestkitClient, QueryExecutor and TableDefinitionModel and change
the TableDefinitionModel import to the same module path pattern as the others
(or switch all imports to the package's public export entry) to ensure uniform
import resolution.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@benchmarks/testkit-postgres-runtime-metadata-benchmark.ts`:
- Around line 4-5: The imports are inconsistent: createPostgresTestkitClient and
QueryExecutor are pulled from the package source while TableDefinitionModel is
imported from compiled dist; update the benchmark to import all types and values
from the same layer (preferably the source or the package public exports) so it
doesn't require a prior build. Locate the imports referencing
createPostgresTestkitClient, QueryExecutor and TableDefinitionModel and change
the TableDefinitionModel import to the same module path pattern as the others
(or switch all imports to the package's public export entry) to ensure uniform
import resolution.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 8597c756-cc87-4156-8dda-8221541fbf96

📥 Commits

Reviewing files that changed from the base of the PR and between 548348e and 8afaecd.

📒 Files selected for processing (4)
  • benchmarks/testkit-postgres-runtime-metadata-benchmark.ts
  • packages/testkit-postgres/src/utils/fixtureState.ts
  • packages/testkit-postgres/tests/client.test.ts
  • packages/ztd-cli/templates/ztd/README.md
💤 Files with no reviewable changes (1)
  • packages/ztd-cli/templates/ztd/README.md
✅ Files skipped from review due to trivial changes (1)
  • packages/testkit-postgres/tests/client.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/testkit-postgres/src/utils/fixtureState.ts

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant