From 6d3aecf0ddad56f623ebc7982ba44120db54f6ef Mon Sep 17 00:00:00 2001 From: Andrew Zolotukhin Date: Mon, 21 Sep 2026 12:06:30 +0000 Subject: [PATCH 01/41] feat: add composable typed queries and exact cursor pagination --- .changeset/composable-typed-queries.md | 9 + .github/workflows/ci.yml | 29 + libs/knex-schema/COMPOSABLE_QUERIES.md | 153 +++++ libs/knex-schema/README.md | 5 + libs/knex-schema/integration/queries.test.ts | 646 ++++++++++++++++++ libs/knex-schema/src/SchemaQueryBuilder.ts | 148 +++- libs/knex-schema/src/aliased-query.ts | 365 ++++++++++ .../src/composable-query.test-d.ts | 109 +++ libs/knex-schema/src/composable-query.test.ts | 182 +++++ libs/knex-schema/src/expressions.ts | 234 +++++++ libs/knex-schema/src/index.ts | 19 +- libs/knex-schema/src/operations/aggregate.ts | 136 ++++ .../src/operations/composite-cursor.ts | 255 +++++++ libs/knex-schema/src/operations/helpers.ts | 64 +- .../src/operations/ordering.test.ts | 39 ++ libs/knex-schema/src/operations/ordering.ts | 71 ++ libs/knex-schema/src/operations/select.ts | 19 +- libs/knex-schema/src/operations/state.ts | 4 + libs/knex-schema/src/types.ts | 10 +- libs/knex-schema/tsconfig.build.json | 2 +- libs/knex-schema/tsconfig.typecheck.json | 6 + libs/knex-schema/vitest.config.mts | 12 + libs/orm/README.md | 32 +- libs/orm/src/dbset.ts | 44 +- libs/orm/src/index.ts | 1 + libs/orm/src/query-types.test-d.ts | 36 + libs/orm/src/result-types.ts | 6 + libs/orm/tsconfig.build.json | 2 +- libs/orm/tsconfig.typecheck.json | 6 + libs/orm/vitest.config.mts | 12 + package.json | 1 + vitest.queries.config.mts | 9 + websites/docs/app/knex-schema/page.tsx | 62 ++ websites/docs/app/orm/page.tsx | 17 + 34 files changed, 2715 insertions(+), 30 deletions(-) create mode 100644 .changeset/composable-typed-queries.md create mode 100644 libs/knex-schema/COMPOSABLE_QUERIES.md create mode 100644 libs/knex-schema/integration/queries.test.ts create mode 100644 libs/knex-schema/src/aliased-query.ts create mode 100644 libs/knex-schema/src/composable-query.test-d.ts create mode 100644 libs/knex-schema/src/composable-query.test.ts create mode 100644 libs/knex-schema/src/expressions.ts create mode 100644 libs/knex-schema/src/operations/aggregate.ts create mode 100644 libs/knex-schema/src/operations/composite-cursor.ts create mode 100644 libs/knex-schema/src/operations/ordering.test.ts create mode 100644 libs/knex-schema/src/operations/ordering.ts create mode 100644 libs/knex-schema/tsconfig.typecheck.json create mode 100644 libs/knex-schema/vitest.config.mts create mode 100644 libs/orm/src/query-types.test-d.ts create mode 100644 libs/orm/tsconfig.typecheck.json create mode 100644 libs/orm/vitest.config.mts create mode 100644 vitest.queries.config.mts diff --git a/.changeset/composable-typed-queries.md b/.changeset/composable-typed-queries.md new file mode 100644 index 00000000..119ef3d5 --- /dev/null +++ b/.changeset/composable-typed-queries.md @@ -0,0 +1,9 @@ +--- +'@cleverbrush/knex-schema': minor +'@cleverbrush/orm': minor +--- + +Add typed flat joined projections, aggregate expressions and scalar helpers +with optional output schemas, and composite keyset pagination. Preserve parent +ordering during eager loading and infer related-query customization types. +Existing aggregate and single-column cursor APIs remain available unchanged. diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5c9af5d0..54d00131 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -43,3 +43,32 @@ jobs: - name: Test & Typecheck run: npm run test + + query-integration: + name: PostgreSQL Query Integration + runs-on: ubuntu-latest + services: + postgres: + image: postgres:16-alpine + env: + POSTGRES_DB: framework_queries + POSTGRES_USER: framework_test + POSTGRES_PASSWORD: framework_test + ports: + - 5432:5432 + options: >- + --health-cmd "pg_isready -U framework_test -d framework_queries" + --health-interval 5s + --health-timeout 5s + --health-retries 10 + env: + QUERY_TEST_DATABASE_URL: postgres://framework_test:framework_test@127.0.0.1:5432/framework_queries + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 24 + cache: npm + - run: npm ci + - run: npm run build + - run: npm run test:queries:integration diff --git a/libs/knex-schema/COMPOSABLE_QUERIES.md b/libs/knex-schema/COMPOSABLE_QUERIES.md new file mode 100644 index 00000000..72facc3f --- /dev/null +++ b/libs/knex-schema/COMPOSABLE_QUERIES.md @@ -0,0 +1,153 @@ +# Composable read queries + +These APIs are additive. Existing single-schema selectors, nested eager loading, +legacy aggregate methods, and single-column cursor calls remain available. + +## Typed flat joins + +```ts +import { alias, eq, query } from '@cleverbrush/knex-schema'; + +const task = alias(TaskSchema, 'task'); +const owner = alias(UserSchema, 'owner'); +const rows = await query(knex, task) + .leftJoin(owner, t => eq(t.task.ownerId, t.owner.id)) + .where(t => t.task.projectId, projectId) + .orderBy(t => t.task.id, 'desc') + .select(t => ({ id: t.task.id, ownerName: t.owner.name })); +// ownerName includes null because owner is left-joined. +``` + +Aliases do not mutate schemas. Each source retains default scopes and soft-delete +filters; filtering the right-hand source does not turn a left join into an inner +join. `createQuery(knex)` also accepts aliased schemas. `eq`, `and`, and `or` +compose column-based join conditions. Duplicate aliases are errors. + +The read-only aliased builder requires an explicit, non-empty projection and +supports `where`, `whereIn`, `whereNull`, `whereNotNull`, `orderBy`, `orderByRaw`, +`groupBy`, `having`, `limit`, `offset`, `first`, `execute`, `transacting`, and +awaiting the query. `apply`/`toKnexQuery` remain raw escape hatches whose effects +on result shape/cardinality are the caller's responsibility. Values remain bound +and identifiers quoted. Flat collection joins can repeat parents; they do not +deduplicate or fetch one related row at a time. Choose ORM eager loading for +nested related objects instead. + +## Aggregates with optional output schemas + +```ts +import { aggregate, number } from '@cleverbrush/knex-schema'; + +const count = await query(knex, TaskSchema).countValue(); // number +const total = await query(knex, TaskSchema) + .sumValue(t => t.estimate); // string | null + +const grouped = await query(knex, TaskSchema) + .groupBy(t => t.ownerId) + .select(t => ({ + ownerId: t.ownerId, + count: aggregate.count(), + total: aggregate.sum(t.estimate) + })); + +// Explicit floating-point conversion when appropriate for your domain. +const average = await query(knex, TaskSchema) + .avgValue(t => t.estimate, { + output: number().isFloat().coerce().nullable() + }); // number | null +``` + +| API | Default result | +| --- | --- | +| `countValue(options?)`, `countValue(column, options?)` | Safe number; counts rows or non-null values | +| `countDistinctValue(column, options?)` | Safe number | +| `sumValue(column, options?)`, `avgValue(column, options?)` | Database numeric text, or null | +| `minValue(column, options?)`, `maxValue(column, options?)` | Column's database representation, or null | + +The corresponding `aggregate.count/countDistinct/sum/avg/min/max` expressions +work in ordinary and aliased object projections. Expression options are the +second argument: `aggregate.count(undefined, { output: schema })` customizes +`COUNT(*)`. Aliased `having` also accepts aggregate expressions; its comparisons +use native SQL values, not decoded/text-formatted values. + +Counts reject malformed results and integers outside JavaScript's safe range. +Sum/average preserve PostgreSQL's result as text without changing global driver +parsers. This does not make floating-point source columns exact. Numeric/decimal/ +bigint extrema retain strings; because existing SQL overrides are not fully +represented in schema types, numeric extrema are conservatively typed as +`number | string | null`. Date extrema return `Date | null`. + +An optional **output schema replaces the default decoder**. Its synchronous +`parse` receives the raw driver value, including null, before default conversion. +Its schema output type determines the result, including nullable/optional +modifiers. PostgreSQL counts normally reach it as strings, so a number schema +needs explicit coercion. Validation failures reject the query. Custom parsers +may return bigint/domain decimal types; JSON serialization remains application +code. With custom parsers, the application owns their conversion/precision policy. + +Scalar helpers clone the source, ignore its limit/offset/order, and retain +filters, semantic joins, scopes, and transactions. They reject grouped, HAVING, +distinct, and already aggregated queries; use aggregate projections for those. +An empty scalar count is zero; other empty/all-null aggregates are null. An +empty grouped query returns no rows. Legacy `.count()`, `.sum()`, etc. keep their +existing behavior and signatures. + +## Eager-loading order + +```ts +const tasks = await query(knex, TaskSchema) + .orderBy(t => t.createdAt, 'desc') + .orderBy(t => t.id, 'desc') + .joinMany({ + foreignSchema: NoteSchema, + localColumn: t => t.id, + foreignColumn: t => t.taskId, + as: 'notes' + }) + .limit(20); +``` + +The final SELECT retains parent order, including bound raw ordering expressions. +Limits/offsets select parents, not expanded child rows. Internal fields are +removed from mapped results. Parent ordering, child ordering, and relation +filtering are separate operations. Add a unique tie-breaker for deterministic +ordering of tied parents. + +## Composite cursors + +```ts +const page = await query(knex, TaskSchema) + .where(t => t.projectId, projectId) + .select(t => ({ id: t.id, title: t.title })) + .paginateAfter({ + cursor: previousPage?.nextCursor, + limit: 50, + orderBy: [ + { column: t => t.createdAt, direction: 'desc' }, + { column: t => t.id, direction: 'desc' } + ] + }); +// { data, nextCursor: string | null, hasMore: boolean } +``` + +The opt-in `orderBy` form controls the full sort, replacing earlier ordering. +Mixed directions, projections, and eager loading are supported. Sort fields must +be non-null scalar columns and include a schema-declared primary/unique key. +Required eager relations filter parents before the cursor page limit is applied. +Offsets, flat joins, distinct/grouped/aggregate queries, malformed cursors, and +cursors from a different table/order are rejected. The source builder is not +mutated. The original `column`/`direction` form is unchanged. + +Cursors are versioned opaque strings preserving database timestamp precision +and numeric values without Date/number round-trips. Clients must not parse them. +Reapply access filters on every request and discard cursors when filters change: +they are positions, not authorization. They do not provide snapshot isolation; +sort-key updates can move records across the cursor. Sequential paging does not +support arbitrary page-number jumps; counts remain separate queries. Indexes +and representative query-plan measurements remain application work. + +## Integration verification + +From the repository root, run `npm run test:queries:integration` with +`QUERY_TEST_DATABASE_URL` pointing to a dedicated PostgreSQL test database. +The suite creates/drops only its randomly named fixture tables and fails if the +URL is missing. CI runs PostgreSQL 16 integration tests alongside unit/type tests. diff --git a/libs/knex-schema/README.md b/libs/knex-schema/README.md index 594e6958..0b5421de 100644 --- a/libs/knex-schema/README.md +++ b/libs/knex-schema/README.md @@ -464,6 +464,11 @@ The schema's `hasColumnName()` metadata is used to map `firstName` → `first_na ## API Reference +See [Composable read queries](./COMPOSABLE_QUERIES.md) for typed flat joins with +`alias`, all aggregate families with optional output schemas, preserved eager-load +ordering, and multi-column cursor pagination. These APIs preserve existing calls +and include runtime, type, and PostgreSQL integration coverage. + ### `query(knex, schema, baseQuery?)` Creates a `SchemaQueryBuilder`. `schema` must have `.hasTableName()` set. diff --git a/libs/knex-schema/integration/queries.test.ts b/libs/knex-schema/integration/queries.test.ts new file mode 100644 index 00000000..597dc2fd --- /dev/null +++ b/libs/knex-schema/integration/queries.test.ts @@ -0,0 +1,646 @@ +import { randomUUID } from 'node:crypto'; +import { + aggregate, + alias, + array, + boolean, + createDb, + date, + defineEntity, + eq, + number, + object, + query, + string +} from '@cleverbrush/orm'; +import Knex from 'knex'; +import { afterAll, beforeAll, describe, expect, it } from 'vitest'; + +const connection = process.env.QUERY_TEST_DATABASE_URL; +if (!connection) + throw new Error( + 'QUERY_TEST_DATABASE_URL is required; integration tests must not silently skip' + ); +const knex = Knex({ client: 'pg', connection, pool: { min: 0, max: 4 } }); +const prefix = `cb_query_${randomUUID().replaceAll('-', '')}`; +const tables = { + users: `${prefix}_users`, + tasks: `${prefix}_tasks`, + notes: `${prefix}_notes` +}; + +const User = object({ + id: number().primaryKey(), + name: string().hasColumnName('display_name'), + enabled: boolean(), + deletedAt: date().optional().hasColumnName('deleted_at') +}) + .hasTableName(tables.users) + .softDelete() + .defaultScope((q: any) => q.where('enabled', true)); +const Note = object({ + id: number().primaryKey(), + taskId: number().hasColumnName('task_id'), + body: string() +}).hasTableName(tables.notes); +const Task = object({ + id: number().primaryKey(), + ownerId: number().hasColumnName('owner_id'), + projectId: number().hasColumnName('project_id'), + title: string(), + amount: number().decimal(24, 6).optional(), + createdAt: date().hasColumnName('created_at'), + deletedAt: date().optional().hasColumnName('deleted_at'), + owner: User.optional(), + notes: array(Note).optional() +}) + .hasTableName(tables.tasks) + .softDelete(); +const taskEntity = defineEntity(Task) + .belongsTo( + t => t.owner, + t => t.ownerId, + t => t.id + ) + .hasMany( + t => t.notes, + t => t.id, + t => t.taskId + ); +const db = createDb(knex, { tasks: taskEntity }); +const orderBy = [ + { column: (t: any) => t.createdAt, direction: 'desc' as const }, + { column: (t: any) => t.id, direction: 'desc' as const } +]; + +beforeAll(async () => { + await knex.schema.createTable(tables.users, t => { + t.integer('id').primary(); + t.text('display_name').notNullable(); + t.boolean('enabled').notNullable(); + t.timestamp('deleted_at').nullable(); + }); + await knex.schema.createTable(tables.tasks, t => { + t.integer('id').primary(); + t.integer('owner_id').notNullable(); + t.integer('project_id').notNullable(); + t.text('title').notNullable(); + t.decimal('amount', 24, 6).nullable(); + t.specificType('created_at', 'timestamp(6)').notNullable(); + t.timestamp('deleted_at').nullable(); + }); + await knex.schema.createTable(tables.notes, t => { + t.integer('id').primary(); + t.integer('task_id').notNullable(); + t.text('body').notNullable(); + }); + await knex(tables.users).insert([ + { id: 1, display_name: 'Alice', enabled: true }, + { id: 2, display_name: 'Bob', enabled: false }, + { + id: 3, + display_name: 'Deleted', + enabled: true, + deleted_at: '2026-01-01' + } + ]); + await knex(tables.tasks).insert([ + { + id: 105, + owner_id: 1, + project_id: 1, + title: 'B', + amount: '0.100000', + created_at: '2026-01-01 10:00:00.000002' + }, + { + id: 104, + owner_id: 2, + project_id: 1, + title: 'A', + amount: '0.200000', + created_at: '2026-01-01 10:00:00.000002' + }, + { + id: 103, + owner_id: 3, + project_id: 1, + title: 'A', + amount: null, + created_at: '2026-01-01 10:00:00.000002' + }, + { + id: 102, + owner_id: 1, + project_id: 1, + title: 'C', + amount: '9007199254740993.000001', + created_at: '2026-01-01 10:00:00.000001' + }, + { + id: 101, + owner_id: 1, + project_id: 2, + title: 'Other project', + amount: '99', + created_at: '2026-01-01 09:59:00' + }, + { + id: 100, + owner_id: 1, + project_id: 1, + title: 'Deleted task', + amount: '1000', + created_at: '2026-01-01 09:58:00', + deleted_at: '2026-01-01' + } + ]); + await knex(tables.notes).insert([ + { id: 1, task_id: 104, body: 'one' }, + { id: 2, task_id: 104, body: 'two' }, + { id: 3, task_id: 103, body: 'three' } + ]); +}); + +afterAll(async () => { + // Only this suite's randomly named fixtures in its explicitly supplied test DB. + for (const table of [tables.notes, tables.tasks, tables.users]) + await knex.schema.dropTableIfExists(table); + await knex.destroy(); +}); + +describe('flat joins', () => { + it('preserves left joins when the right-hand schema has scopes and soft deletion', async () => { + const rows = await query(knex, alias(Task, 'task')) + .leftJoin(alias(User, 'owner'), t => eq(t.task.ownerId, t.owner.id)) + .where(t => t.task.projectId, 1) + .orderBy(t => t.task.id, 'desc') + .select(t => ({ id: t.task.id, owner: t.owner.name })); + expect(rows).toEqual([ + { id: 105, owner: 'Alice' }, + { id: 104, owner: null }, + { id: 103, owner: null }, + { id: 102, owner: 'Alice' } + ]); + }); + + it('groups joined rows with exact aggregates and numeric HAVING', async () => { + const rows = await query(knex, alias(Task, 'task')) + .join(alias(User, 'owner'), t => eq(t.task.ownerId, t.owner.id)) + .where(t => t.task.projectId, 1) + .groupBy(t => t.owner.name) + .having(() => aggregate.count(), '>', 1) + .select(t => ({ + owner: t.owner.name, + count: aggregate.count(), + total: aggregate.sum(t.task.amount) + })); + expect(rows).toEqual([ + { owner: 'Alice', count: 2, total: '9007199254740993.100001' } + ]); + }); +}); + +describe('eager ordering', () => { + it('keeps tied parent order and page size with one-to-many and one-to-one includes', async () => { + const rows = await db.tasks + .where(t => t.projectId, 1) + .orderBy(t => t.title) + .orderBy(t => t.id, 'desc') + .include(t => t.notes) + .include(t => t.owner) + .limit(2); + expect(rows.map(row => row.id)).toEqual([104, 103]); + expect(rows[0].notes).toHaveLength(2); + expect(rows[1].notes).toHaveLength(1); + expect(Object.keys(rows[0]).some(key => key.startsWith('__cb_'))).toBe( + false + ); + }); + + it('handles projected-away sort/FK fields, mapped aliases, raw bindings, offset and transactions', async () => { + await knex.transaction(async trx => { + const rows = await query(knex, Task) + .where(t => t.projectId, 1) + .orderByRaw('case when ?? = ? then 0 else 1 end, ?? desc', [ + 'id', + 102, + 'id' + ]) + .select(t => ({ taskId: t.id })) + .joinOne({ + foreignSchema: User, + localColumn: t => t.ownerId, + foreignColumn: t => t.id, + as: 'user', + required: false + }) + .offset(1) + .limit(2) + .transacting(trx); + expect(rows.map(row => row.taskId)).toEqual([105, 104]); + expect(Object.keys(rows[0]).sort()).toEqual(['taskId', 'user']); + }); + }); + + it('retains distinct/grouped parent cardinality', async () => { + for (const distinct of [true, false]) { + let q = query(knex, Task) + .where(t => t.projectId, 1) + .select(t => ({ owner_id: t.ownerId })) + .orderBy(t => t.ownerId); + q = distinct ? q.distinct() : q.groupBy(t => t.ownerId); + const rows = await q.joinOne({ + foreignSchema: User, + localColumn: t => t.ownerId, + foreignColumn: t => t.id, + as: 'user', + required: false + }); + expect(rows.map(row => row.owner_id)).toEqual([1, 2, 3]); + } + }); + + it.each([ + '"taskId" desc', + '1 desc' + ])('retains ordering by a projected alias or position: %s', async order => { + const rows = await query(knex, Task) + .where(t => t.projectId, 1) + .select(t => ({ taskId: t.id })) + .orderByRaw(order) + .joinMany({ + foreignSchema: Note, + localColumn: t => t.id, + foreignColumn: t => t.taskId, + as: 'notes' + }) + .limit(2); + expect(rows.map(row => row.taskId)).toEqual([105, 104]); + }); +}); + +describe('aggregate results', () => { + const tasks = () => db.tasks.where(t => t.projectId, 1); + it('counts rows, non-null values and distinct values without retaining page limits', async () => { + expect(await tasks().limit(1).offset(10).countValue()).toBe(4); + expect(await tasks().countValue(t => t.amount)).toBe(3); + expect(await tasks().countDistinctValue(t => t.ownerId)).toBe(3); + expect(await tasks().countValue({ output: string() })).toBe('4'); + }); + + it('counts parent rows through required relations and collection includes', async () => { + expect( + await tasks() + .include(t => t.notes) + .countValue() + ).toBe(4); + const visibleOwner = query(knex, Task) + .where(t => t.projectId, 1) + .joinOne({ + foreignSchema: User, + foreignQuery: query(knex, User), + localColumn: t => t.ownerId, + foreignColumn: t => t.id, + as: 'owner', + required: true + }); + expect(await visibleOwner.countValue()).toBe(2); + expect(await visibleOwner.sumValue(t => t.amount)).toBe( + '9007199254740993.100001' + ); + }); + + it('retains default-scope filters while ignoring default-scope pagination', async () => { + const Scoped = object({ id: number().primaryKey() }) + .hasTableName(tables.tasks) + .defaultScope((q: any) => + q + .where('project_id', 1) + .whereNull('deleted_at') + .limit(1) + .offset(1) + ); + expect(await query(knex, Scoped).countValue()).toBe(4); + const Grouped = Scoped.defaultScope((q: any) => q.groupBy('id')); + await expect(query(knex, Grouped).countValue()).rejects.toThrow( + 'ungrouped' + ); + }); + + it('preserves sum/average/decimal extrema and returns date/string extrema', async () => { + expect(await tasks().sumValue(t => t.amount)).toBe( + '9007199254740993.300001' + ); + const native = await knex(tables.tasks) + .where({ project_id: 1 }) + .whereNull('deleted_at') + .avg({ value: 'amount' }) + .first(); + expect(await tasks().avgValue(t => t.amount)).toBe(native!.value); + expect(await tasks().minValue(t => t.amount)).toBe('0.100000'); + expect(await tasks().maxValue(t => t.amount)).toBe( + '9007199254740993.000001' + ); + expect(await tasks().minValue(t => t.title)).toBe('A'); + expect(await tasks().maxValue(t => t.createdAt)).toBeInstanceOf(Date); + }); + + it('handles empty/all-null inputs and caller-supplied parsers', async () => { + const empty = () => query(knex, Task).where(t => t.id, -1); + expect(await empty().countValue()).toBe(0); + for (const method of [ + 'sumValue', + 'avgValue', + 'minValue', + 'maxValue' + ] as const) { + expect(await empty()[method]('amount')).toBe(null); + } + expect( + await query(knex, Task) + .where(t => t.id, 103) + .sumValue(t => t.amount) + ).toBe(null); + expect( + await query(knex, Task) + .where(t => t.id, 105) + .sumValue(t => t.amount, { + output: number().isFloat().coerce() + }) + ).toBe(0.1); + await expect( + empty().sumValue(t => t.amount, { output: string() }) + ).rejects.toThrow(); + }); + + it('decodes every grouped aggregate without treating rows as entities', async () => { + const rows = await query(knex, Task) + .where(t => t.projectId, 1) + .groupBy(t => t.ownerId) + .orderBy(t => t.ownerId) + .select(t => ({ + owner: t.ownerId, + count: aggregate.count(), + distinct: aggregate.countDistinct(t.id), + sum: aggregate.sum(t.amount), + avg: aggregate.avg(t.amount), + min: aggregate.min(t.title), + max: aggregate.max(t.title) + })); + expect(rows.map(row => [row.owner, row.count, row.distinct])).toEqual([ + [1, 2, 2], + [2, 1, 1], + [3, 1, 1] + ]); + expect(rows[2]).toEqual({ + owner: 3, + count: 1, + distinct: 1, + sum: null, + avg: null, + min: 'A', + max: 'A' + }); + await expect( + query(knex, Task) + .groupBy(t => t.ownerId) + .countValue() + ).rejects.toThrow('ungrouped'); + }); + + it('retains source state and transaction visibility', async () => { + const base = query(knex, Task) + .where(t => t.projectId, 1) + .select(t => ({ id: t.id })) + .limit(1); + const before = base.toQuery(); + expect(await base.countValue()).toBe(4); + expect(base.toQuery()).toBe(before); + await expect( + knex.transaction(async trx => { + await trx(tables.tasks).insert({ + id: 999, + owner_id: 1, + project_id: 1, + title: 'temporary', + amount: 1, + created_at: '2026-01-01' + }); + expect( + await db + .withTransaction(trx) + .tasks.where(t => t.projectId, 1) + .countValue() + ).toBe(5); + const rows = await query(knex, alias(Task, 'task')) + .where(t => t.task.id, 999) + .select(t => ({ id: t.task.id })) + .transacting(trx); + expect(rows).toEqual([{ id: 999 }]); + throw new Error('test rollback'); + }) + ).rejects.toThrow('test rollback'); + expect(await tasks().countValue()).toBe(4); + }); + + it('does not attach aggregate DTOs to the tracked entity identity map', async () => { + const tracked = createDb( + knex, + { tasks: taskEntity }, + { tracking: true } + ); + const original = await tracked.tasks.find(105); + const rows = await tracked.tasks + .where(t => t.id, 105) + .groupBy(t => t.id) + .select(t => ({ id: t.id, title: aggregate.count() })) + .execute(); + expect(rows).toEqual([{ id: 105, title: 1 }]); + const scalarObject = await tracked.tasks + .where(t => t.id, 105) + .countValue({ + output: { parse: value => ({ id: 105, title: value }) } + }); + expect(scalarObject).toEqual({ id: 105, title: '1' }); + expect(original!.title).toBe('B'); + expect(await tracked.tasks.find(105)).toBe(original); + }); +}); + +describe('composite cursor pages', () => { + it('applies required relation filters before testing whether another page exists', async () => { + const base = () => + query(knex, Task) + .where(t => t.projectId, 1) + .joinOne({ + foreignSchema: User, + foreignQuery: query(knex, User), + localColumn: t => t.ownerId, + foreignColumn: t => t.id, + as: 'owner', + required: true + }); + const first = await base().paginateAfter({ limit: 1, orderBy }); + expect(first.data.map(t => t.id)).toEqual([105]); + expect(first.hasMore).toBe(true); + const last = await base().paginateAfter({ + limit: 1, + orderBy, + cursor: first.nextCursor + }); + expect(last.data.map(t => t.id)).toEqual([102]); + expect(last.hasMore).toBe(false); + }); + + it('does not skip tied timestamps and retains microsecond precision with projections and includes', async () => { + const base = () => + query(knex, Task) + .where(t => t.projectId, 1) + .select(t => ({ taskId: t.id })) + .joinMany({ + foreignSchema: Note, + localColumn: t => t.id, + foreignColumn: t => t.taskId, + as: 'notes' + }); + const first = await base().paginateAfter({ limit: 2, orderBy }); + expect(first.data.map(t => t.taskId)).toEqual([105, 104]); + const second = await base().paginateAfter({ + limit: 2, + orderBy, + cursor: first.nextCursor + }); + expect(second.data.map(t => t.taskId)).toEqual([103, 102]); + expect(second.hasMore).toBe(false); + expect(second.nextCursor).toBe(null); + expect(Object.keys(first.data[0]).sort()).toEqual(['notes', 'taskId']); + expect( + Buffer.from(first.nextCursor!, 'base64url').toString() + ).toContain('000002'); + }); + + it('supports mixed directions, empty pages and ordinary projections', async () => { + const mixed = [ + { column: (t: any) => t.createdAt, direction: 'desc' as const }, + { column: (t: any) => t.id, direction: 'asc' as const } + ]; + const base = () => db.tasks.where(t => t.projectId, 1); + const first = await base().paginateAfter({ limit: 2, orderBy: mixed }); + const second = await base().paginateAfter({ + limit: 2, + orderBy: mixed, + cursor: first.nextCursor + }); + expect([...first.data, ...second.data].map(t => t.id)).toEqual([ + 103, 104, 105, 102 + ]); + const empty = await db.tasks + .where(t => t.projectId, -1) + .paginateAfter({ limit: 1, orderBy }); + expect(empty).toEqual({ data: [], hasMore: false, nextCursor: null }); + const projected = await query(knex, Task) + .where(t => t.projectId, 1) + .select(t => t.id) + .paginateAfter({ limit: 2, orderBy }); + expect(Object.keys(projected.data[0])).toEqual(['id']); + }); + + it('rejects a cursor from a different sort and preserves authorization scope', async () => { + const first = await db.tasks + .where(t => t.projectId, 1) + .paginateAfter({ limit: 2, orderBy }); + await expect( + db.tasks.paginateAfter({ + limit: 2, + cursor: first.nextCursor, + orderBy: [{ column: t => t.id, direction: 'asc' }] + }) + ).rejects.toThrow('incompatible'); + const anotherProject = await db.tasks + .where(t => t.projectId, 2) + .paginateAfter({ limit: 2, cursor: first.nextCursor, orderBy }); + expect(anotherProject.data.map(t => t.id)).toEqual([101]); + }); + + it('keeps the existing single-column cursor API operational', async () => { + const page = await db.tasks + .where(t => t.projectId, 1) + .paginateAfter({ limit: 2, column: t => t.id, direction: 'desc' }); + expect(page.data.map(t => t.id)).toEqual([105, 104]); + expect(page.nextCursor).toBe('104'); + }); + + it('groups an existing OR filter before applying continuation predicates', async () => { + const base = () => + query(knex, Task) + .where(t => t.id, 105) + .orWhere(t => t.id, 104); + const first = await base().paginateAfter({ limit: 1, orderBy }); + const second = await base().paginateAfter({ + limit: 1, + orderBy, + cursor: first.nextCursor + }); + expect(first.data.map(t => t.id)).toEqual([105]); + expect(second.data.map(t => t.id)).toEqual([104]); + }); + + it('supports composite primary and unique keys without assuming an id field', async () => { + const Keyed = object({ + ownerId: number().hasColumnName('owner_id'), + id: number() + }) + .hasTableName(tables.tasks) + .hasPrimaryKey(['ownerId', 'id']); + const page = await query(knex, Keyed) + .where(t => t.ownerId, 1) + .paginateAfter({ + limit: 1, + orderBy: [ + { column: t => t.ownerId, direction: 'asc' }, + { column: t => t.id, direction: 'desc' } + ] + }); + expect(page.data[0].id).toBe(105); + const Unique = object({ id: number().unique() }).hasTableName( + tables.tasks + ); + expect( + ( + await query(knex, Unique).paginateAfter({ + limit: 1, + orderBy: [{ column: t => t.id, direction: 'desc' }] + }) + ).data[0].id + ).toBe(105); + }); + + it('retains numeric cursor precision beyond the safe integer range', async () => { + // Cursor metadata retains the exact numeric independently of the + // public projection, which does not even include the sort column. + const Exact = object({ + id: number().primaryKey(), + amount: number().decimal(24, 6) + }).hasTableName(tables.tasks); + const orderBy = [ + { column: 'amount' as const, direction: 'desc' as const }, + { column: 'id' as const, direction: 'desc' as const } + ]; + const base = () => + query(knex, Exact) + .whereIn(t => t.id, [102, 104, 105]) + .select(t => ({ id: t.id })); + const first = await base().paginateAfter({ limit: 1, orderBy }); + const second = await base().paginateAfter({ + limit: 2, + orderBy, + cursor: first.nextCursor + }); + expect(first.data).toEqual([{ id: 102 }]); + expect(second.data).toEqual([{ id: 104 }, { id: 105 }]); + expect( + Buffer.from(first.nextCursor!, 'base64url').toString() + ).toContain('9007199254740993.000001'); + }); +}); diff --git a/libs/knex-schema/src/SchemaQueryBuilder.ts b/libs/knex-schema/src/SchemaQueryBuilder.ts index 81e6fd08..a6a4d0b5 100644 --- a/libs/knex-schema/src/SchemaQueryBuilder.ts +++ b/libs/knex-schema/src/SchemaQueryBuilder.ts @@ -7,8 +7,26 @@ import { type ObjectSchemaBuilder } from '@cleverbrush/schema'; import type { Knex } from 'knex'; +import { + AliasedQueryBuilder, + type AliasTables, + isTableAlias, + type TableAlias +} from './aliased-query.js'; import { buildColumnMap } from './columns.js'; +import type { + AggregateOptions, + AggregateResult, + ExtremumResult, + ExtremumValue, + OutputSchema +} from './expressions.js'; import { getTableName, POLYMORPHIC_TYPE_BRAND } from './extension.js'; +import { scalarAggregate } from './operations/aggregate.js'; +import { + type CompositeCursorOptions, + compositeCursor +} from './operations/composite-cursor.js'; // Operations import { avgImpl, @@ -166,6 +184,9 @@ export class SchemaQueryBuilder< explicitSelects: null, selectionMode: null, appliedProjection: null, + projectionColumns: null, + projectionDecoders: {}, + hiddenColumns: new Set(), includeDeleted: false, onlyDeleted: false, skipDefaultScope: false, @@ -217,6 +238,89 @@ export class SchemaQueryBuilder< return (avgImpl as any)(this, column); } + /** Count the unpaginated matching source, rejecting unsafe integer results. */ + countValue | undefined = undefined>( + options?: AggregateOptions + ): Promise>; + countValue | undefined = undefined>( + column: ColumnRef, + options?: AggregateOptions + ): Promise>; + countValue( + columnOrOptions?: ColumnRef | AggregateOptions, + options?: AggregateOptions + ): Promise { + const hasColumn = + typeof columnOrOptions === 'string' || + typeof columnOrOptions === 'function'; + return scalarAggregate( + this, + 'count', + hasColumn ? columnOrOptions : undefined, + hasColumn ? options : columnOrOptions + ); + } + + countDistinctValue | undefined = undefined>( + column: ColumnRef, + options?: AggregateOptions + ): Promise> { + return scalarAggregate(this, 'countDistinct', column, options); + } + + /** Exact database numeric text (or null), unless an output schema is supplied. */ + sumValue | undefined = undefined>( + column: ColumnRef, + options?: AggregateOptions + ): Promise> { + return scalarAggregate(this, 'sum', column, options); + } + + avgValue | undefined = undefined>( + column: ColumnRef, + options?: AggregateOptions + ): Promise> { + return scalarAggregate(this, 'avg', column, options); + } + + minValue< + C extends ColumnRef, + S extends OutputSchema | undefined = undefined + >( + column: C, + options?: AggregateOptions + ): Promise< + AggregateResult< + S, + C extends (...args: any[]) => infer D + ? ExtremumValue + : C extends keyof InferType + ? ExtremumResult[C]> + : unknown + > + > { + return scalarAggregate(this, 'min', column, options); + } + + maxValue< + C extends ColumnRef, + S extends OutputSchema | undefined = undefined + >( + column: C, + options?: AggregateOptions + ): Promise< + AggregateResult< + S, + C extends (...args: any[]) => infer D + ? ExtremumValue + : C extends keyof InferType + ? ExtremumResult[C]> + : unknown + > + > { + return scalarAggregate(this, 'max', column, options); + } + selectRaw(sql: string, bindings?: any[]): this { return selectRawImpl(this as any, sql, bindings); } @@ -438,12 +542,17 @@ export class SchemaQueryBuilder< >; } - async paginateAfter(opts: { + paginateAfter( + opts: CompositeCursorOptions + ): Promise>; + paginateAfter(opts: { cursor?: any; limit: number; column?: ColumnRef; direction?: 'asc' | 'desc'; - }): Promise> { + }): Promise>; + async paginateAfter(opts: any): Promise> { + if ('orderBy' in opts) return compositeCursor(this as any, opts); return (paginateAfterImpl as any)(this, opts) as Promise< CursorPaginationResult >; @@ -709,6 +818,11 @@ export class SchemaQueryBuilder< : null; builderState.selectionMode = state.selectionMode; builderState.appliedProjection = state.appliedProjection; + builderState.projectionColumns = state.projectionColumns + ? { ...state.projectionColumns } + : null; + builderState.projectionDecoders = { ...state.projectionDecoders }; + builderState.hiddenColumns = new Set(state.hiddenColumns); builderState.includeDeleted = state.includeDeleted; builderState.onlyDeleted = state.onlyDeleted; builderState.skipDefaultScope = state.skipDefaultScope; @@ -732,6 +846,11 @@ export class SchemaQueryBuilder< return getQuery(this).toQuery(); } + /** @internal ORM tracking must never attach aggregate or DTO rows as entities. */ + get returnsEntityRows(): boolean { + return getState(this).selectionMode === null; + } + toKnexQuery(): Knex.QueryBuilder { return getQuery(this); } @@ -781,6 +900,10 @@ registerSchemaQueryBuilder(SchemaQueryBuilder); // query() — main entry point // --------------------------------------------------------------------------- +export function query< + S extends ObjectSchemaBuilder, + N extends string +>(knex: Knex, schema: TableAlias): AliasedQueryBuilder>; export function query< TLocalSchema extends ObjectSchemaBuilder >( @@ -796,18 +919,13 @@ export function query< baseQuery: Knex.QueryBuilder ): SchemaQueryBuilder>; -export function query< - TLocalSchema extends ObjectSchemaBuilder ->( +export function query( knex: Knex, - schema: TLocalSchema, + schema: any, baseQuery?: Knex.QueryBuilder -): SchemaQueryBuilder> { - return new SchemaQueryBuilder>( - knex, - schema, - baseQuery - ); +): any { + if (isTableAlias(schema)) return new AliasedQueryBuilder(knex, schema); + return new SchemaQueryBuilder(knex, schema, baseQuery); } // --------------------------------------------------------------------------- @@ -815,6 +933,12 @@ export function query< // --------------------------------------------------------------------------- export interface BoundQuery { + < + S extends ObjectSchemaBuilder, + N extends string + >( + schema: TableAlias + ): AliasedQueryBuilder>; < TLocalSchema extends ObjectSchemaBuilder< any, diff --git a/libs/knex-schema/src/aliased-query.ts b/libs/knex-schema/src/aliased-query.ts new file mode 100644 index 00000000..c8a37977 --- /dev/null +++ b/libs/knex-schema/src/aliased-query.ts @@ -0,0 +1,365 @@ +import type { InferType, ObjectSchemaBuilder } from '@cleverbrush/schema'; +import type { Knex } from 'knex'; +import { buildColumnMap } from './columns.js'; +import { + type AggregateExpression, + type AliasedColumn, + COLUMN, + compileAggregate, + isAggregate +} from './expressions.js'; +import { + ALLOWED_OPS, + getEffectiveBaseQuery, + getSchemaQueryBuilderCtor +} from './operations/helpers.js'; + +type TableSchema = ObjectSchemaBuilder; +const ALIAS = Symbol('table-alias'); +const PREDICATE = Symbol('join-predicate'); + +/** Immutable table identity; does not mutate the schema's column metadata. */ +export interface TableAlias { + readonly [ALIAS]: true; + readonly schema: S; + readonly name: N; +} + +export function alias( + schema: S, + name: N +): TableAlias { + if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name)) { + throw new Error('Table aliases must be non-empty SQL identifier names'); + } + return Object.freeze({ [ALIAS]: true as const, schema, name }); +} + +export function isTableAlias( + value: unknown +): value is TableAlias { + return !!value && typeof value === 'object' && ALIAS in value; +} + +type Columns = { + [K in keyof InferType]-?: AliasedColumn< + | Exclude[K], undefined> + | (undefined extends InferType[K] ? null : never) + | (Nullable extends true ? null : never) + >; +}; + +export type AliasTables< + S extends TableSchema, + N extends string, + Nullable extends boolean = false +> = Record>; +type Selection = Record | AggregateExpression>; +export type JoinedProjection = { + [K in keyof S]: S[K] extends AggregateExpression + ? T + : S[K] extends AliasedColumn + ? T + : never; +}; + +export interface JoinPredicate { + readonly [PREDICATE]: + | { op: 'eq'; left: AliasedColumn; right: AliasedColumn } + | { op: 'and' | 'or'; items: readonly JoinPredicate[] }; +} + +/** Equality between two schema-backed columns, never interpolated SQL strings. */ +export function eq( + left: AliasedColumn, + right: AliasedColumn +): JoinPredicate { + return { [PREDICATE]: { op: 'eq', left, right } }; +} + +export function and(...items: JoinPredicate[]): JoinPredicate { + if (!items.length) throw new Error('and() requires at least one predicate'); + return { [PREDICATE]: { op: 'and', items } }; +} + +export function or(...items: JoinPredicate[]): JoinPredicate { + if (!items.length) throw new Error('or() requires at least one predicate'); + return { [PREDICATE]: { op: 'or', items } }; +} + +/** Read-only flat query builder. Explicit projections avoid ambiguous SELECT *. */ +export class AliasedQueryBuilder { + private sql: Knex.QueryBuilder; + private tables = new Map(); + private selected = false; + private decoders: Record unknown> = {}; + + constructor( + private knex: Knex, + source: TableAlias + ) { + this.tables.set(source.name, source.schema); + this.sql = knex.from(this.source(source)); + } + + private source(table: TableAlias): Knex.QueryBuilder { + const Constructor = getSchemaQueryBuilderCtor(); + return getEffectiveBaseQuery(new Constructor(this.knex, table.schema)) + .clone() + .as(table.name); + } + + private tree(): TTables { + return Object.fromEntries( + [...this.tables].map(([name, schema]) => { + const { propToCol } = buildColumnMap(schema); + const properties = schema.introspect().properties; + return [ + name, + Object.fromEntries( + [...propToCol].map(([key, column]) => [ + key, + { + [COLUMN]: { + alias: name, + column, + schema: properties[key] + } + } + ]) + ) + ]; + }) + ) as TTables; + } + + private column(value: AliasedColumn): string { + if (!value || !(COLUMN in value)) + throw new TypeError('Expected an aliased column'); + const column = value[COLUMN]; + const schema = this.tables.get(column.alias); + if ( + !schema || + ![...buildColumnMap(schema).propToCol.values()].includes( + column.column + ) + ) { + throw new Error('Column does not belong to this query'); + } + return `${column.alias}.${column.column}`; + } + + private predicate(value: JoinPredicate): Knex.Raw { + if (!value || !(PREDICATE in value)) + throw new TypeError('Expected a join predicate'); + const node = value[PREDICATE]; + if (node.op === 'eq') { + return this.knex.raw('?? = ??', [ + this.column(node.left), + this.column(node.right) + ]); + } + return this.knex.raw( + `(${node.items.map(() => '?').join(` ${node.op} `)})`, + node.items.map(item => this.predicate(item)) + ); + } + + join( + table: N extends keyof TTables ? never : TableAlias, + on: (tables: TTables & AliasTables) => JoinPredicate + ): AliasedQueryBuilder, TResult> { + this.addJoin(table, on as any, false); + return this as any; + } + + leftJoin( + table: N extends keyof TTables ? never : TableAlias, + on: (tables: TTables & AliasTables) => JoinPredicate + ): AliasedQueryBuilder, TResult> { + this.addJoin(table, on as any, true); + return this as any; + } + + private addJoin( + table: TableAlias, + on: (tables: TTables) => JoinPredicate, + left: boolean + ): void { + if (this.tables.has(table.name)) + throw new Error(`Duplicate table alias: ${table.name}`); + this.tables.set(table.name, table.schema); + try { + const predicate = this.predicate(on(this.tree())); + this.sql[left ? 'leftJoin' : 'join'](this.source(table), predicate); + } catch (error) { + this.tables.delete(table.name); + throw error; + } + } + + where( + column: (tables: TTables) => AliasedColumn, + value: unknown + ): this; + where( + column: (tables: TTables) => AliasedColumn, + operator: string, + value: unknown + ): this; + where( + column: (tables: TTables) => AliasedColumn, + ...args: [value: unknown] | [operator: string, value: unknown] + ): this { + const operator = args.length === 1 ? '=' : args[0].toLowerCase(); + if (!ALLOWED_OPS.has(operator)) + throw new Error(`Unsupported operator: ${operator}`); + this.sql.where( + this.column(column(this.tree())), + operator, + (args.length === 1 ? args[0] : args[1]) as any + ); + return this; + } + + whereIn( + column: (tables: TTables) => AliasedColumn, + values: readonly unknown[] + ): this { + this.sql.whereIn(this.column(column(this.tree())), values as any[]); + return this; + } + + whereNull(column: (tables: TTables) => AliasedColumn): this { + this.sql.whereNull(this.column(column(this.tree()))); + return this; + } + + whereNotNull(column: (tables: TTables) => AliasedColumn): this { + this.sql.whereNotNull(this.column(column(this.tree()))); + return this; + } + + orderBy( + column: (tables: TTables) => AliasedColumn, + direction: 'asc' | 'desc' = 'asc' + ): this { + this.sql.orderBy(this.column(column(this.tree())), direction); + return this; + } + + orderByRaw(sql: string, bindings: readonly Knex.RawBinding[] = []): this { + this.sql.orderByRaw(sql, bindings); + return this; + } + + groupBy(...columns: Array<(tables: TTables) => AliasedColumn>): this { + this.sql.groupBy( + columns.map(column => this.column(column(this.tree()))) + ); + return this; + } + + having( + value: ( + tables: TTables + ) => AggregateExpression | AliasedColumn, + operator: string, + right: unknown + ): this { + if (!ALLOWED_OPS.has(operator.toLowerCase())) + throw new Error('Unsupported HAVING operator'); + const expression = value(this.tree()); + const left = isAggregate(expression) + ? compileAggregate(this.knex, expression, c => + this.column(c as AliasedColumn) + ).native + : this.knex.raw('??', [this.column(expression)]); + this.sql.havingRaw(`? ${operator} ?`, [left, right as any]); + return this; + } + + select( + selector: (tables: TTables) => S + ): AliasedQueryBuilder> { + if (this.selected) + throw new Error('Only one object projection per query'); + const columns: Record = {}; + for (const [key, value] of Object.entries(selector(this.tree()))) { + if (isAggregate(value)) { + const compiled = compileAggregate(this.knex, value, c => + this.column(c as AliasedColumn) + ); + columns[key] = compiled.sql; + this.decoders[key] = compiled.decode; + } else columns[key] = this.column(value); + } + if (!Object.keys(columns).length) + throw new Error('A non-empty projection is required'); + this.sql.select(columns); + this.selected = true; + return this as any; + } + + limit(limit: number): this { + this.sql.limit(limit); + return this; + } + offset(offset: number): this { + this.sql.offset(offset); + return this; + } + + /** Raw escape hatch; callers own any effects on result shape or cardinality. */ + apply(callback: (query: Knex.QueryBuilder) => void): this { + callback(this.sql); + return this; + } + + transacting(trx: Knex.Transaction): AliasedQueryBuilder { + const [name, schema] = this.tables.entries().next().value!; + const copy = new AliasedQueryBuilder( + trx as unknown as Knex, + alias(schema, name) + ); + copy.sql = this.sql.clone().transacting(trx); + copy.tables = new Map(this.tables); + copy.selected = this.selected; + copy.decoders = { ...this.decoders }; + return copy; + } + + toKnexQuery(): Knex.QueryBuilder { + if (!this.selected) + throw new Error( + 'Aliased queries require an explicit select projection' + ); + return this.sql.clone(); + } + toQuery(): string { + return this.toKnexQuery().toQuery(); + } + + private decode(row: Record): TResult { + const result = { ...row }; + for (const [key, decode] of Object.entries(this.decoders)) + result[key] = decode(row[key]); + return result as TResult; + } + async execute(): Promise { + return (await this.toKnexQuery()).map((row: Record) => + this.decode(row) + ); + } + async first(): Promise { + const row = await this.toKnexQuery().first(); + return row === undefined ? undefined : this.decode(row); + } + // biome-ignore lint/suspicious/noThenProperty: intentional query thenable + then( + resolve?: ((rows: TResult[]) => T | PromiseLike) | null, + reject?: ((error: any) => E | PromiseLike) | null + ): Promise { + return this.execute().then(resolve, reject); + } +} diff --git a/libs/knex-schema/src/composable-query.test-d.ts b/libs/knex-schema/src/composable-query.test-d.ts new file mode 100644 index 00000000..5f8433e6 --- /dev/null +++ b/libs/knex-schema/src/composable-query.test-d.ts @@ -0,0 +1,109 @@ +import Knex from 'knex'; +import { expectTypeOf, test } from 'vitest'; +import { + aggregate, + alias, + createQuery, + date, + eq, + number, + object, + query, + string +} from './index.js'; + +const db = Knex({ client: 'pg' }); +const User = object({ id: number().primaryKey(), name: string() }).hasTableName( + 'users' +); +const Task = object({ + id: number().primaryKey(), + ownerId: number(), + amount: number(), + createdAt: date() +}).hasTableName('tasks'); + +test('flat join projection inference and nullable right-hand fields', async () => { + const task = alias(Task, 'task'); + const owner = alias(User, 'owner'); + const result = await query(db, task) + .leftJoin(owner, t => eq(t.task.ownerId, t.owner.id)) + .select(t => ({ id: t.task.id, owner: t.owner.name })); + expectTypeOf(result).toEqualTypeOf< + { id: number; owner: string | null }[] + >(); + // @ts-expect-error unselected property + result[0].amount; + // @ts-expect-error wrong table property + query(db, task).select(t => ({ name: t.task.name })); + // @ts-expect-error duplicate alias + query(db, task).join(task, t => eq(t.task.id, t.task.id)); + const bound = createQuery(db); + expectTypeOf( + await bound(owner).select(t => ({ name: t.owner.name })) + ).toEqualTypeOf<{ name: string }[]>(); +}); + +test('aggregate defaults and supplied output schemas infer accurately', async () => { + expectTypeOf(await query(db, Task).countValue()).toEqualTypeOf(); + expectTypeOf(await query(db, Task).sumValue(t => t.amount)).toEqualTypeOf< + string | null + >(); + expectTypeOf( + await query(db, Task).maxValue(t => t.createdAt) + ).toEqualTypeOf(); + expectTypeOf( + await query(db, Task).maxValue('createdAt') + ).toEqualTypeOf(); + expectTypeOf(await query(db, Task).minValue('amount')).toEqualTypeOf< + number | string | null + >(); + expectTypeOf(await query(db, Task).minValue(t => t.amount)).toEqualTypeOf< + number | string | null + >(); + expectTypeOf( + await query(db, Task).countValue({ output: string() }) + ).toEqualTypeOf(); + const results = await query(db, Task) + .groupBy(t => t.ownerId) + .select(t => ({ + ownerId: t.ownerId, + count: aggregate.count(), + sum: aggregate.sum(t.amount), + avg: aggregate.avg(t.amount, { + output: number().coerce().nullable() + }), + min: aggregate.min(t.createdAt) + })); + expectTypeOf(results).toEqualTypeOf< + { + ownerId: number; + count: number; + sum: string | null; + avg: number | null; + min: Date | null; + }[] + >(); +}); + +test('both cursor call shapes remain typed', async () => { + const queryBuilder = query(db, Task).select(t => ({ id: t.id })); + const page = await queryBuilder.paginateAfter({ + limit: 5, + orderBy: [ + { column: t => t.createdAt, direction: 'desc' }, + { column: t => t.id, direction: 'asc' } + ] + }); + expectTypeOf(page.data).toEqualTypeOf<{ id: number }[]>(); + await queryBuilder.paginateAfter({ + limit: 5, + column: t => t.id, + cursor: '5' + }); + await queryBuilder.paginateAfter({ + limit: 5, + // @ts-expect-error invalid cursor column + orderBy: [{ column: t => t.missing, direction: 'asc' }] + }); +}); diff --git a/libs/knex-schema/src/composable-query.test.ts b/libs/knex-schema/src/composable-query.test.ts new file mode 100644 index 00000000..fcc8ad76 --- /dev/null +++ b/libs/knex-schema/src/composable-query.test.ts @@ -0,0 +1,182 @@ +import Knex from 'knex'; +import { afterAll, describe, expect, it } from 'vitest'; +import { compileAggregate } from './expressions.js'; +import { + aggregate, + alias, + and, + date, + eq, + number, + object, + or, + query, + string +} from './index.js'; + +const db = Knex({ client: 'pg' }); +afterAll(() => db.destroy()); +const User = object({ + id: number().primaryKey(), + name: string().hasColumnName('display_name') +}).hasTableName('users'); +const Task = object({ + id: number().primaryKey(), + ownerId: number().hasColumnName('owner_id'), + amount: number().decimal(20, 4), + createdAt: date().hasColumnName('created_at') +}).hasTableName('tasks'); + +describe('typed aliases and aggregate SQL', () => { + it('quotes columns and binds values without modifying schema metadata', () => { + const before = Task.introspect(); + const compiled = query(db, alias(Task, 'task')) + .join(alias(User, 'owner'), t => + and( + eq(t.task.ownerId, t.owner.id), + or(eq(t.task.ownerId, t.owner.id)) + ) + ) + .where(t => t.owner.name, "O'Reilly") + .orderBy(t => t.task.id, 'desc') + .select(t => ({ id: t.task.id, name: t.owner.name })) + .toKnexQuery() + .toSQL(); + expect(compiled.sql).toContain('"owner"."display_name" as "name"'); + expect(compiled.sql).toContain('"task"."owner_id" = "owner"."id"'); + expect(compiled.bindings).toEqual(["O'Reilly"]); + expect(Task.introspect()).toEqual(before); + }); + + it('supports two aliases of one schema and rejects duplicate aliases', () => { + const users = query(db, alias(User, 'first')); + const result = users.leftJoin(alias(User, 'second'), t => + eq(t.first.id, t.second.id) + ); + expect( + result + .select(t => ({ a: t.first.name, b: t.second.name })) + .toQuery() + ).toContain('left join'); + expect(() => + (users as any).join(alias(User, 'first'), () => null) + ).toThrow('Duplicate'); + expect(() => query(db, alias(User, 'u')).toKnexQuery()).toThrow( + 'explicit select' + ); + }); + + it('supports grouped aggregate aliases and SQL-native HAVING comparisons', () => { + const compiled = query(db, alias(Task, 'task')) + .groupBy(t => t.task.ownerId) + .having(t => aggregate.sum(t.task.amount), '>', 10) + .select(t => ({ + owner: t.task.ownerId, + total: aggregate.sum(t.task.amount), + count: aggregate.count() + })) + .toKnexQuery() + .toSQL(); + expect(compiled.sql).toContain( + 'cast(sum("task"."amount") as text) as "total"' + ); + expect(compiled.sql).toContain('having sum("task"."amount") > ?'); + expect(compiled.bindings).toEqual([10]); + }); + + it('adds aggregate expressions to existing object selectors', () => { + const sql = query(db, Task) + .groupBy(t => t.ownerId) + .select(t => ({ + owner: t.ownerId, + total: aggregate.sum(t.amount), + count: aggregate.countDistinct(t.id) + })) + .toQuery(); + expect(sql).toContain('count(distinct "id")'); + expect(sql).toContain('group by "owner_id"'); + }); +}); + +describe('aggregate decoders', () => { + const count = compileAggregate(db, aggregate.count(), () => '').decode; + it.each([ + '0', + '3', + 5, + 12n, + String(Number.MAX_SAFE_INTEGER) + ])('decodes safe count %s', value => { + expect(count(value)).toBe(Number(value)); + }); + it.each([ + '9007199254740993', + -1, + '1.5', + '', + null, + NaN, + {}, + Infinity + ])('rejects unsafe/malformed count %s', value => { + expect(() => count(value)).toThrow(); + }); + it('lets output schemas replace default decoding, including overflow policy', () => { + const compiled = compileAggregate( + db, + aggregate.count(undefined, { output: string() }), + () => '' + ); + expect(compiled.decode('9007199254740993')).toBe('9007199254740993'); + expect(() => compiled.decode(null)).toThrow(); + }); +}); + +describe('composite cursor guards', () => { + it('rejects non-unique, nullable, grouped and malformed requests before querying', async () => { + const Nullable = object({ + id: number().primaryKey().nullable() + }).hasTableName('nullable_keys'); + await expect( + query(db, Nullable).paginateAfter({ + limit: 2, + orderBy: [{ column: t => t.id, direction: 'asc' }] + }) + ).rejects.toThrow('non-null'); + await expect( + query(db, Task).paginateAfter({ + limit: 2, + orderBy: [{ column: t => t.createdAt, direction: 'asc' }] + }) + ).rejects.toThrow('unique key'); + await expect( + query(db, Task).paginateAfter({ + limit: 0, + orderBy: [{ column: t => t.id, direction: 'asc' }] + }) + ).rejects.toThrow('limit'); + await expect( + query(db, Task) + .offset(2) + .paginateAfter({ + limit: 2, + orderBy: [{ column: t => t.id, direction: 'asc' }] + }) + ).rejects.toThrow('offsets'); + await expect( + query(db, Task) + .groupBy(t => t.id) + .paginateAfter({ + limit: 2, + orderBy: [{ column: t => t.id, direction: 'asc' }] + }) + ).rejects.toThrow('grouped'); + await expect( + query(db, Task).paginateAfter({ + cursor: 'not-a-cursor', + limit: 2, + orderBy: [{ column: t => t.id, direction: 'asc' }] + }) + ).rejects.toThrow('Invalid cursor'); + }); +}); diff --git a/libs/knex-schema/src/expressions.ts b/libs/knex-schema/src/expressions.ts new file mode 100644 index 00000000..11fa41de --- /dev/null +++ b/libs/knex-schema/src/expressions.ts @@ -0,0 +1,234 @@ +import { + type InferType, + type PropertyDescriptor, + type SchemaTypeBrand, + SYMBOL_SCHEMA_PROPERTY_DESCRIPTOR +} from '@cleverbrush/schema'; +import type { Knex } from 'knex'; + +/** A synchronous schema parser. Framework schemas implement this interface. */ +export interface OutputSchema { + parse(value: unknown): T; +} + +/** A supplied schema replaces default decoding and receives the raw SQL value. */ +export interface AggregateOptions< + S extends OutputSchema | undefined = undefined +> { + output?: S; +} + +/** Schema brands retain nullable/optional output modifiers unlike parse() alone. */ +export type AggregateResult = + S extends OutputSchema + ? S extends { readonly [K in SchemaTypeBrand]: unknown } + ? InferType + : ReturnType + : Fallback; + +export const COLUMN = Symbol('query-column'); +export const EXPRESSION = Symbol('query-expression'); + +/** A schema-backed SQL column belonging to one explicit table alias. */ +export interface AliasedColumn { + readonly [COLUMN]: { + alias: string; + column: string; + schema: any; + }; + readonly __value?: T; +} + +export type SelectableColumn = + | PropertyDescriptor + | AliasedColumn; + +export type ColumnValue = + C extends AliasedColumn + ? T + : C extends PropertyDescriptor + ? InferType + : never; + +/** Numeric SQL overrides can return exact strings rather than JS numbers. */ +export type ExtremumValue = ExtremumResult>; + +/** Widen numeric extrema for SQL overrides; all other columns retain their type. */ +export type ExtremumResult = + | (NonNullable extends number ? number | string : NonNullable) + | null; + +export type AggregateKind = + | 'count' + | 'countDistinct' + | 'sum' + | 'avg' + | 'min' + | 'max'; + +/** An aggregate description; evaluated by SQL, never once per application row. */ +export interface AggregateExpression { + readonly [EXPRESSION]: { + kind: AggregateKind; + column?: SelectableColumn; + output?: OutputSchema; + }; + readonly __result?: T; +} + +export function isAggregate(value: unknown): value is AggregateExpression { + return !!value && typeof value === 'object' && EXPRESSION in value; +} + +export function isColumn(value: unknown): value is SelectableColumn { + return ( + !!value && + typeof value === 'object' && + (COLUMN in value || SYMBOL_SCHEMA_PROPERTY_DESCRIPTOR in value) + ); +} + +export function createAggregate( + kind: AggregateKind, + column?: SelectableColumn, + options?: AggregateOptions +): AggregateExpression { + if (column !== undefined && !isColumn(column)) { + throw new TypeError(`${kind}: expected a schema property descriptor`); + } + if (kind !== 'count' && !column) { + throw new TypeError(`${kind}: a column is required`); + } + return Object.freeze({ + [EXPRESSION]: { kind, column, output: options?.output } + }); +} + +/** Typed aggregate expressions for scalar or grouped object projections. */ +export const aggregate = { + count | undefined = undefined>( + column?: SelectableColumn, + options?: AggregateOptions + ) { + return createAggregate>( + 'count', + column, + options + ); + }, + countDistinct | undefined = undefined>( + column: SelectableColumn, + options?: AggregateOptions + ) { + return createAggregate>( + 'countDistinct', + column, + options + ); + }, + sum | undefined = undefined>( + column: SelectableColumn, + options?: AggregateOptions + ) { + return createAggregate>( + 'sum', + column, + options + ); + }, + avg | undefined = undefined>( + column: SelectableColumn, + options?: AggregateOptions + ) { + return createAggregate>( + 'avg', + column, + options + ); + }, + min< + C extends SelectableColumn, + S extends OutputSchema | undefined = undefined + >(column: C, options?: AggregateOptions) { + return createAggregate>>( + 'min', + column, + options + ); + }, + max< + C extends SelectableColumn, + S extends OutputSchema | undefined = undefined + >(column: C, options?: AggregateOptions) { + return createAggregate>>( + 'max', + column, + options + ); + } +}; + +export function columnSchema(column: SelectableColumn): any { + return COLUMN in column + ? column[COLUMN].schema + : column[SYMBOL_SCHEMA_PROPERTY_DESCRIPTOR].getSchema(); +} + +export function compileAggregate( + knex: Knex, + value: AggregateExpression, + resolve: (column: SelectableColumn) => string | Knex.Raw +): { sql: Knex.Raw; native: Knex.Raw; decode: (value: unknown) => unknown } { + const { kind, column, output } = value[EXPRESSION]; + const argument = column ? knex.raw('??', [resolve(column)]) : knex.raw('*'); + const call = + kind === 'countDistinct' + ? knex.raw('count(distinct ?)', [argument]) + : knex.raw(`${kind}(?)`, [argument]); + // PostgreSQL numeric/int8 results stay exact even with custom pg parsers. + const schema = column ? columnSchema(column).introspect() : undefined; + const sqlType: string = schema?.extensions?.columnType ?? ''; + const exactExtremum = + /^(numeric|decimal|bigint|int8|bigserial)(\b|\()/i.test(sqlType); + const textResult = + !output && + (kind === 'sum' || + kind === 'avg' || + kind === 'count' || + kind === 'countDistinct' || + exactExtremum); + return { + native: call, + sql: textResult ? knex.raw('cast(? as text)', [call]) : call, + decode(raw) { + if (output) return output.parse(raw); + if (kind === 'count' || kind === 'countDistinct') { + if ( + (typeof raw !== 'string' && + typeof raw !== 'number' && + typeof raw !== 'bigint') || + !/^\d+$/.test(String(raw)) + ) { + throw new TypeError('Invalid SQL count result'); + } + const count = Number(raw); + if (!Number.isSafeInteger(count) || count < 0) { + throw new RangeError( + 'SQL count exceeds the safe integer range; supply an output schema' + ); + } + return count; + } + if (raw === null) return null; + if (textResult) return String(raw); + if (schema?.type === 'date') { + const date = + raw instanceof Date ? raw : new Date(raw as string); + if (!Number.isFinite(date.getTime())) + throw new TypeError('Invalid SQL date result'); + return date; + } + return raw; + } + }; +} diff --git a/libs/knex-schema/src/index.ts b/libs/knex-schema/src/index.ts index 2f2387ee..bfc8e56c 100644 --- a/libs/knex-schema/src/index.ts +++ b/libs/knex-schema/src/index.ts @@ -1,5 +1,13 @@ // @cleverbrush/knex-schema — Type-safe schema-driven query builder for Knex +export type { + AliasTables, + JoinedProjection, + JoinPredicate, + TableAlias +} from './aliased-query.js'; +// Types +export { AliasedQueryBuilder, alias, and, eq, or } from './aliased-query.js'; export type { PrimaryKeyColumns, RowVersionColumn, @@ -33,6 +41,14 @@ export type { } from './entity.js'; // Entity wrapper export { defineEntity, Entity } from './entity.js'; +export type { + AggregateExpression, + AggregateOptions, + AggregateResult, + AliasedColumn, + OutputSchema +} from './expressions.js'; +export { aggregate } from './expressions.js'; // Schema extension (hasColumnName / hasTableName + DDL/ORM) export { any, @@ -73,6 +89,7 @@ export { tableExistsInDb, validateEntitiesAgainstDatabase } from './migration.js'; +export type { CompositeCursorOptions } from './operations/composite-cursor.js'; // Raw query execution export { rawQuery } from './raw.js'; export type { BoundQuery } from './SchemaQueryBuilder.js'; @@ -88,8 +105,6 @@ export { loadSnapshot, writeSnapshot } from './snapshot.js'; - -// Types export type { AddColumnDiff, AddForeignKeyDiff, diff --git a/libs/knex-schema/src/operations/aggregate.ts b/libs/knex-schema/src/operations/aggregate.ts new file mode 100644 index 00000000..063ee36c --- /dev/null +++ b/libs/knex-schema/src/operations/aggregate.ts @@ -0,0 +1,136 @@ +import { ObjectSchemaBuilder } from '@cleverbrush/schema'; +import type { Knex } from 'knex'; +import { resolveColumnRef } from '../columns.js'; +import { + type AggregateKind, + type AggregateOptions, + compileAggregate, + createAggregate, + type SelectableColumn +} from '../expressions.js'; +import type { SchemaQueryBuilder } from '../SchemaQueryBuilder.js'; +import type { ColumnRef } from '../types.js'; +import { + buildQuery, + getEffectiveBaseQuery, + getSchemaQueryBuilderCtor +} from './helpers.js'; +import { getState } from './state.js'; + +/** Clone Framework metadata as well as Knex state; terminal helpers never mutate the source. */ +export function cloneQuery( + builder: SchemaQueryBuilder +): SchemaQueryBuilder { + const state = getState(builder); + const Constructor = getSchemaQueryBuilderCtor(); + const copy = new Constructor( + state.knex, + state.localSchema, + state.baseQuery.clone() + ); + Object.assign(getState(copy), state, { + baseQuery: state.baseQuery.clone(), + specs: state.specs.map(spec => ({ + ...spec, + foreignQuery: spec.foreignQuery.clone() + })), + explicitSelects: state.explicitSelects + ? [...state.explicitSelects] + : null, + projectionColumns: state.projectionColumns + ? { ...state.projectionColumns } + : null, + projectionDecoders: { ...state.projectionDecoders }, + hiddenColumns: new Set(state.hiddenColumns), + variantWhereFilters: [...state.variantWhereFilters], + variantRelationIncludes: [...state.variantRelationIncludes], + enabledVariants: state.enabledVariants + ? new Set(state.enabledVariants) + : null, + cachedBuiltQuery: null + }); + return copy; +} + +/** Knex clause inspection is isolated here and covered by SQL regression tests. */ +export function statements(query: Knex.QueryBuilder): any[] { + return (query as any)._statements; +} + +export function assertScalarSource(query: Knex.QueryBuilder): void { + if ( + statements(query).some( + s => + s.grouping === 'group' || + s.grouping === 'having' || + s.distinct || + s.distinctOn || + s.type === 'aggregate' || + s.type === 'aggregateRaw' + ) + ) { + throw new Error( + 'Scalar aggregates require an ungrouped, non-distinct source; use aggregate expressions for grouped results' + ); + } +} + +export async function scalarAggregate< + S extends ObjectSchemaBuilder +>( + builder: SchemaQueryBuilder, + kind: AggregateKind, + column?: ColumnRef, + options?: AggregateOptions +): Promise { + const copy = cloneQuery(builder); + const state = getState(copy); + // Materialize scopes before checking query shape/removing paging. A default + // scope may itself supply pagination, selection, or grouping clauses. + state.baseQuery = getEffectiveBaseQuery(copy).clone(); + state.skipDefaultScope = true; + state.includeDeleted = true; + state.onlyDeleted = false; + assertScalarSource(state.baseQuery); + if (Object.keys(state.projectionDecoders).length) { + throw new Error( + 'Cannot apply a scalar aggregate to an aggregate projection' + ); + } + const tree = ObjectSchemaBuilder.getPropertiesFor(state.localSchema); + const descriptor: SelectableColumn | undefined = + column === undefined + ? undefined + : typeof column === 'function' + ? column(tree as any) + : tree[column]; + if (column !== undefined && !descriptor) + throw new Error('Unknown aggregate column'); + const value = createAggregate(kind, descriptor, options); + const compiled = compileAggregate(state.knex, value, () => { + const resolved = resolveColumnRef( + column as ColumnRef, + state.localSchema, + kind, + state.knex + ); + return resolved; + }); + // Preserve filtering joins (including required eager joins), but aggregate + // the parent source rather than multiplying it by included collections. + state.baseQuery + .clearSelect() + .clearOrder() + .clear('limit') + .clear('offset') + .select(`${state.tableName}.*`); + state.explicitSelects = null; + state.projectionColumns = null; + state.selectionMode = null; + const source = buildQuery(copy).clearOrder().as('__cb_aggregate_source'); + const row = await state.knex + .from(source) + .select({ value: compiled.sql }) + .first(); + return compiled.decode(row.value); +} diff --git a/libs/knex-schema/src/operations/composite-cursor.ts b/libs/knex-schema/src/operations/composite-cursor.ts new file mode 100644 index 00000000..7265fbb8 --- /dev/null +++ b/libs/knex-schema/src/operations/composite-cursor.ts @@ -0,0 +1,255 @@ +import { Buffer } from 'node:buffer'; +import type { ObjectSchemaBuilder } from '@cleverbrush/schema'; +import { + buildColumnMap, + getPrimaryKeyColumns, + resolvePropertyKey +} from '../columns.js'; +import type { SchemaQueryBuilder } from '../SchemaQueryBuilder.js'; +import type { ColumnRef, CursorPaginationResult } from '../types.js'; +import { cloneQuery, statements } from './aggregate.js'; +import { cleanAndMapRow, getEffectiveBaseQuery, getQuery } from './helpers.js'; +import { privateColumn } from './ordering.js'; +import { getState } from './state.js'; + +/** Opt-in, non-null, uniquely ordered keyset pagination. */ +export interface CompositeCursorOptions< + S extends ObjectSchemaBuilder +> { + cursor?: string | null; + limit: number; + orderBy: readonly { column: ColumnRef; direction: 'asc' | 'desc' }[]; +} + +export async function compositeCursor( + builder: SchemaQueryBuilder, + options: CompositeCursorOptions +): Promise> { + if ( + !Number.isSafeInteger(options.limit) || + options.limit < 1 || + options.limit >= Number.MAX_SAFE_INTEGER + ) { + throw new Error('Cursor limit must be a positive safe integer'); + } + if (!Array.isArray(options.orderBy) || !options.orderBy.length) { + throw new Error('Composite cursors require a non-empty orderBy'); + } + const copy = cloneQuery(builder); + const state = getState(copy); + state.baseQuery = getEffectiveBaseQuery(copy).clone(); + state.skipDefaultScope = true; + state.includeDeleted = true; + state.onlyDeleted = false; + const sql = state.baseQuery; + if ( + (sql as any)._single.offset != null || + Object.keys(state.projectionDecoders).length || + statements(sql).some( + s => + ['join', 'group', 'having', 'union'].includes(s.grouping) || + s.distinct || + s.distinctOn || + s.type === 'aggregate' || + s.type === 'aggregateRaw' + ) + ) { + throw new Error( + 'Composite cursors do not support offsets, flat joins, distinct, grouped or aggregate queries' + ); + } + const { properties, extensions } = state.localSchema.introspect() as any; + const { propToCol, colToProp } = buildColumnMap(state.localSchema); + const order = options.orderBy.map(item => { + if (item.direction !== 'asc' && item.direction !== 'desc') + throw new Error('Invalid cursor direction'); + const key = resolvePropertyKey( + item.column, + state.localSchema, + 'cursor' + ); + const property = properties[key]; + const info = property?.introspect(); + if ( + !info || + !['number', 'string', 'date', 'boolean'].includes(info.type) || + !info.isRequired || + info.isNullable + ) { + throw new Error( + 'Cursor columns must be declared non-null scalar fields' + ); + } + return { + key, + column: propToCol.get(key)!, + direction: item.direction, + type: info.type + }; + }); + if (new Set(order.map(item => item.column)).size !== order.length) + throw new Error('Duplicate cursor columns'); + const normalize = (keys: string[]) => + keys.map(key => propToCol.get(key) ?? key); + const uniqueKeys: string[][] = [ + [...getPrimaryKeyColumns(state.localSchema).columnNames], + ...Object.entries(properties) + .filter(([, p]: [string, any]) => p.getExtension('unique')) + .map(([key]) => [propToCol.get(key)!]), + ...(extensions?.uniques ?? []).map((entry: any) => + normalize(entry.columns) + ), + ...(extensions?.indexes ?? []) + .filter((entry: any) => entry.unique) + .map((entry: any) => normalize(entry.columns)) + ].filter(keys => keys.length); + if ( + !uniqueKeys.some(keys => + keys.every(key => order.some(item => item.column === key)) + ) + ) { + throw new Error( + 'Cursor order must contain a schema-declared primary or unique key' + ); + } + const identity = JSON.stringify([ + state.tableName, + order.map(({ column, direction, type }) => [column, direction, type]) + ]); + let values: string[] | undefined; + if (options.cursor != null) { + try { + if ( + typeof options.cursor !== 'string' || + !/^[A-Za-z0-9_-]+$/.test(options.cursor) + ) + throw new Error(); + const payload = JSON.parse( + Buffer.from(options.cursor, 'base64url').toString('utf8') + ); + if ( + payload.v !== 1 || + payload.order !== identity || + !Array.isArray(payload.values) || + payload.values.length !== order.length || + payload.values.some((v: unknown) => typeof v !== 'string') + ) + throw new Error(); + values = payload.values; + for (let i = 0; i < order.length; i++) { + const value = values![i]; + if ( + (order[i].type === 'number' && + !/^[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?$/i.test( + value + )) || + (order[i].type === 'boolean' && + !['true', 'false'].includes(value)) || + (order[i].type === 'date' && + !Number.isFinite(Date.parse(value))) + ) + throw new Error(); + } + } catch { + throw new Error('Invalid cursor or incompatible cursor ordering'); + } + } + const requiredRelations = state.specs.filter( + spec => spec.type === 'one' && spec.required + ); + if (values || requiredRelations.length) { + const filters = statements(sql).filter(s => s.grouping === 'where'); + sql.clear('where'); + if (filters.length) + sql.where(function () { + (this as any)._statements.push(...filters); + }); + } + // Required eager relations filter parents. Apply that existence condition + // before limit+1 so an unmatched parent cannot truncate the cursor stream. + const requiredAlias = privateColumn([state.tableName], 'required'); + for (const spec of requiredRelations) { + sql.whereExists( + state.knex + .from(spec.foreignQuery.clone().as(requiredAlias)) + .select(state.knex.raw('1')) + .whereRaw('?? = ??', [ + `${requiredAlias}.${spec.foreignColumn}`, + `${state.tableName}.${spec.localColumn}` + ]) + ); + } + if (values) { + const cursorValues = values; + sql.where(function () { + order.forEach((item, index) => { + this.orWhere(function () { + for (let before = 0; before < index; before++) { + this.where(order[before].column, cursorValues[before]); + } + this.where( + item.column, + item.direction === 'desc' ? '<' : '>', + cursorValues[index] + ); + }); + }); + }); + } + sql.clearOrder().clear('limit'); + const hidden: string[] = []; + if (!statements(sql).some(s => s.grouping === 'columns')) + sql.select(`${state.tableName}.*`); + for (const item of order) { + sql.orderBy(item.column, item.direction); + const key = privateColumn( + [ + ...colToProp.keys(), + ...Object.keys(state.projectionColumns ?? {}), + ...hidden, + ...state.hiddenColumns + ], + 'cursor' + ); + const value = state.knex.raw('cast(?? as text)', [item.column]); + sql.select({ [key]: value }); + state.explicitSelects?.push(key); + // Object projections must carry hidden cursor values through eager wrapping. + if (state.projectionColumns) state.projectionColumns[key] = value; + hidden.push(key); + state.hiddenColumns.add(key); + } + sql.limit(options.limit + 1); + const rows: Record[] = await getQuery(copy); + for (const row of rows) { + if (hidden.some(key => typeof row[key] !== 'string')) { + throw new Error( + 'Cursor sort value is null or not losslessly encoded' + ); + } + } + const hasMore = rows.length > options.limit; + const page = rows.slice(0, options.limit); + const last = page.at(-1); + const nextCursor = + hasMore && last + ? Buffer.from( + JSON.stringify({ + v: 1, + order: identity, + values: hidden.map(key => { + if (typeof last[key] !== 'string') + throw new Error( + 'Cursor sort value is null or not losslessly encoded' + ); + return last[key]; + }) + }) + ).toString('base64url') + : null; + return { + data: page.map(row => cleanAndMapRow(copy, row)), + nextCursor, + hasMore + }; +} diff --git a/libs/knex-schema/src/operations/helpers.ts b/libs/knex-schema/src/operations/helpers.ts index cbaf6b9e..f47c5ad9 100644 --- a/libs/knex-schema/src/operations/helpers.ts +++ b/libs/knex-schema/src/operations/helpers.ts @@ -26,6 +26,7 @@ import type { ResolvedVariantRelationSpec, ValidatedSpec } from '../types.js'; +import { compileOrder, privateColumn } from './ordering.js'; import { getState } from './state.js'; // --------------------------------------------------------------------------- @@ -751,32 +752,74 @@ export function buildQuery( if (state.specs.length === 0) { return queryBase; } + if (Object.keys(state.projectionDecoders).length) { + throw new Error( + 'Aggregate projections cannot include entity relations; use a flat grouped query' + ); + } const knex = state.knex; const specs = state.specs; const requiredLocalColumns = [...new Set(specs.map(s => s.localColumn))]; - let cteQuery = queryBase; + const cteQuery = queryBase.clone(); let extraColumns: string[] = []; if (state.explicitSelects !== null) { - const selectedSet = new Set(state.explicitSelects); + const selectedSet = new Set( + state.projectionColumns + ? Object.keys(state.projectionColumns) + : state.explicitSelects + ); extraColumns = requiredLocalColumns.filter( col => !selectedSet.has(col) ); if (extraColumns.length > 0) { - cteQuery = queryBase.clone(); for (const col of extraColumns) { cteQuery.column(col); } } } + const order = compileOrder( + knex, + queryBase, + state.projectionColumns, + state.explicitSelects + ); + const ordinal = privateColumn( + [ + ...buildColumnMap(state.localSchema).colToProp.keys(), + ...Object.keys(state.projectionColumns ?? {}), + ...state.hiddenColumns + ], + 'order' + ); + if (order) { + // DENSE_RANK, unlike ROW_NUMBER, does not turn equal DISTINCT rows + // into different rows. The outer join cannot discard the requested order. + if ( + !(cteQuery as any)._statements.some( + (s: any) => s.grouping === 'columns' + ) + ) { + cteQuery.select(`${state.tableName}.*`); + } + cteQuery.select( + knex.raw('dense_rank() over (?) as ??', [order, ordinal]) + ); + state.hiddenColumns.add(ordinal); + } const resultQuery = knex.queryBuilder().with('originalQuery', cteQuery); - if (extraColumns.length > 0 && state.explicitSelects !== null) { - for (const col of state.explicitSelects) { + if ( + state.projectionColumns || + (extraColumns.length > 0 && state.explicitSelects !== null) + ) { + for (const col of state.projectionColumns + ? Object.keys(state.projectionColumns) + : state.explicitSelects!) { resultQuery.select( knex.raw(':originalQuery:.:col: as :col:', { originalQuery: 'originalQuery', @@ -805,6 +848,8 @@ export function buildQuery( } } + if (order) resultQuery.orderBy(`originalQuery.${ordinal}`, 'asc'); + return resultQuery; } @@ -856,8 +901,13 @@ export function cleanAndMapRow( const manySpecs = state.specs.filter( (s): s is ValidatedSpec & { type: 'many' } => s.type === 'many' ); - const cleaned = clearRow(row, oneSpecs, manySpecs); - return mapRow(builder, cleaned); + const cleaned = clearRow({ ...row }, oneSpecs, manySpecs); + for (const key of state.hiddenColumns) delete cleaned[key]; + for (const [key, decode] of Object.entries(state.projectionDecoders)) { + if (Object.hasOwn(cleaned, key)) cleaned[key] = decode(cleaned[key]); + } + // An explicit DTO alias is already the public property name. + return state.projectionColumns ? cleaned : mapRow(builder, cleaned); } export function mapObjectToColumns( diff --git a/libs/knex-schema/src/operations/ordering.test.ts b/libs/knex-schema/src/operations/ordering.test.ts new file mode 100644 index 00000000..ba8a4060 --- /dev/null +++ b/libs/knex-schema/src/operations/ordering.test.ts @@ -0,0 +1,39 @@ +import Knex from 'knex'; +import { afterAll, describe, expect, it } from 'vitest'; +import { compileOrder } from './ordering.js'; + +const knex = Knex({ client: 'pg' }); +afterAll(() => knex.destroy()); + +describe('eager ordering compilation', () => { + it('expands output aliases/positions while retaining raw SQL bindings', () => { + const source = knex('tasks').orderByRaw( + 'coalesce(??, ?), ?? desc nulls last, 1 asc', + ['title', 'a,b', 'taskId'] + ); + const compiled = compileOrder(knex, source, { taskId: 'id' })!.toSQL(); + expect(compiled.sql).toBe( + 'order by coalesce("title", ?), "id" desc nulls last, "id" asc' + ); + expect(compiled.bindings).toEqual(['a,b']); + }); + + it('does not rewrite commas/alias text inside literals or qualified columns', () => { + const source = knex('tasks').orderByRaw( + 'coalesce("title", \', taskId\'), length($tag$, taskId$tag$), tasks."taskId", "taskId" desc' + ); + expect(compileOrder(knex, source, { taskId: 'id' })!.toSQL().sql).toBe( + 'order by coalesce("title", \', taskId\'), length($tag$, taskId$tag$), tasks."taskId", "id" desc' + ); + }); + + it('resolves positions in ordinary selections and leaves unsorted queries alone', () => { + expect(compileOrder(knex, knex('tasks'))).toBe(null); + expect( + compileOrder(knex, knex('tasks').orderByRaw('2 desc'), null, [ + 'title', + 'id' + ])!.toSQL().sql + ).toBe('order by "id" desc'); + }); +}); diff --git a/libs/knex-schema/src/operations/ordering.ts b/libs/knex-schema/src/operations/ordering.ts new file mode 100644 index 00000000..d9253183 --- /dev/null +++ b/libs/knex-schema/src/operations/ordering.ts @@ -0,0 +1,71 @@ +import type { Knex } from 'knex'; +import { statements } from './aggregate.js'; + +/** Compile only ORDER BY, retaining Knex's identifier quoting and value bindings. */ +export function compileOrder( + knex: Knex, + source: Knex.QueryBuilder, + projection: Record | null = null, + selected: readonly string[] | null = null +): Knex.Raw | null { + const order = statements(source).filter(s => s.grouping === 'order'); + if (!order.length) return null; + const isolated = knex.queryBuilder(); + (isolated as any)._statements = order; + const compiled = isolated.toSQL(); + const prefix = 'select * '; + if (!compiled.sql.startsWith(prefix)) + throw new Error('Unsupported Knex ordering compiler'); + // SELECT aliases and positional references are visible to a query's ORDER + // BY, but not a window's ORDER BY. Expand known projection references to + // physical columns without touching expressions, literals or bindings. + const columns = projection ? Object.values(projection) : selected; + const clause = compiled.sql.slice(`${prefix}order by `.length); + const terms = splitOrderTerms(clause).map(term => { + const match = + /^("(?:[^"]|"")+"|[A-Za-z_][A-Za-z0-9_]*|\d+)(\s+(?:asc|desc))?(\s+nulls\s+(?:first|last))?$/i.exec( + term.trim() + ); + if (!match) return term; + const name = match[1].startsWith('"') + ? match[1].slice(1, -1).replaceAll('""', '"') + : match[1].toLowerCase(); + const column = /^\d+$/.test(match[1]) + ? columns?.[Number(match[1]) - 1] + : projection && Object.hasOwn(projection, name) + ? projection[name] + : undefined; + if (typeof column !== 'string') return term; + return `${knex.ref(column).toSQL().sql}${match[2] ?? ''}${match[3] ?? ''}`; + }); + return knex.raw(`order by ${terms.join(', ')}`, compiled.bindings as any[]); +} + +/** Split only top-level SQL commas; quoted SQL fragments are opaque. */ +function splitOrderTerms(sql: string): string[] { + const tokens = + /\$(\w*)\$[\s\S]*?\$\1\$|'(?:''|\\.|[^'])*'|"(?:""|[^"])*"|--[^\n]*|\/\*[\s\S]*?\*\/|[(),]/g; + const terms: string[] = []; + let depth = 0; + let start = 0; + for (const token of sql.matchAll(tokens)) { + if (token[0] === '(') depth++; + else if (token[0] === ')') depth--; + else if (token[0] === ',' && depth === 0) { + terms.push(sql.slice(start, token.index)); + start = token.index + 1; + } + } + terms.push(sql.slice(start)); + return terms; +} + +export function privateColumn( + existing: Iterable, + label: string +): string { + const used = new Set(existing); + let index = 0; + while (used.has(`__cb_${label}_${index}`)) index++; + return `__cb_${label}_${index}`; +} diff --git a/libs/knex-schema/src/operations/select.ts b/libs/knex-schema/src/operations/select.ts index 8896b2d9..223631bc 100644 --- a/libs/knex-schema/src/operations/select.ts +++ b/libs/knex-schema/src/operations/select.ts @@ -6,6 +6,7 @@ import { } from '@cleverbrush/schema'; import type { Knex } from 'knex'; import { buildColumnMap } from '../columns.js'; +import { compileAggregate, isAggregate } from '../expressions.js'; import { getProjections } from '../extension.js'; import type { SchemaQueryBuilder } from '../SchemaQueryBuilder.js'; import type { ColumnRef } from '../types.js'; @@ -40,11 +41,26 @@ export function selectImpl( state.selectionMode = 'projection'; state.appliedProjection = ''; - const aliasMap: Record = {}; + const aliasMap: Record = {}; state.explicitSelects ??= []; for (const [alias, descriptor] of Object.entries( result as Record )) { + if (isAggregate(descriptor)) { + const compiled = compileAggregate( + state.knex, + descriptor, + column => + resolveColumn( + builder, + () => column, + `select(selector).${alias}` + ) + ); + aliasMap[alias] = compiled.sql; + state.projectionDecoders[alias] = compiled.decode; + continue; + } if ( !descriptor || typeof descriptor !== 'object' || @@ -65,6 +81,7 @@ export function selectImpl( aliasMap[alias] = col as string; state.explicitSelects.push(col as string); } + state.projectionColumns = aliasMap; state.baseQuery.select(aliasMap); return builder; } diff --git a/libs/knex-schema/src/operations/state.ts b/libs/knex-schema/src/operations/state.ts index c257aa10..18d18c57 100644 --- a/libs/knex-schema/src/operations/state.ts +++ b/libs/knex-schema/src/operations/state.ts @@ -24,6 +24,10 @@ export interface QueryBuilderState { /** Name of the projection currently applied, for error messages. */ appliedProjection: string | null; + /** Output aliases and decoders for typed object projections. */ + projectionColumns: Record | null; + projectionDecoders: Record unknown>; + hiddenColumns: Set; /** When true, soft-delete filter is NOT applied. */ includeDeleted: boolean; diff --git a/libs/knex-schema/src/types.ts b/libs/knex-schema/src/types.ts index cf2cdc7e..ee96f00e 100644 --- a/libs/knex-schema/src/types.ts +++ b/libs/knex-schema/src/types.ts @@ -7,6 +7,7 @@ import type { PropertyDescriptorTree } from '@cleverbrush/schema'; import type { Knex } from 'knex'; +import type { AggregateExpression } from './expressions.js'; // --------------------------------------------------------------------------- // Utility: extract string keys from an ObjectSchemaBuilder's inferred type @@ -351,7 +352,9 @@ type DescriptorPropertySchema = * @public */ export type SelectProjection> = { - [K in keyof R]: InferType>; + [K in keyof R]: R[K] extends AggregateExpression + ? T + : InferType>; }; /** @@ -365,7 +368,10 @@ export type SelectSelector< T extends ObjectSchemaBuilder > = ( tree: PropertyDescriptorTree, SchemaBase> -) => Record>; +) => Record< + string, + PropertyDescriptor | AggregateExpression +>; // --------------------------------------------------------------------------- // Pagination result types diff --git a/libs/knex-schema/tsconfig.build.json b/libs/knex-schema/tsconfig.build.json index 7954e377..2082ba2d 100644 --- a/libs/knex-schema/tsconfig.build.json +++ b/libs/knex-schema/tsconfig.build.json @@ -12,5 +12,5 @@ "declarationMap": false }, "include": ["src/**/*.ts"], - "exclude": ["src/**/*.test.ts"] + "exclude": ["src/**/*.test.ts", "src/**/*.test-d.ts"] } diff --git a/libs/knex-schema/tsconfig.typecheck.json b/libs/knex-schema/tsconfig.typecheck.json new file mode 100644 index 00000000..c24a9fd6 --- /dev/null +++ b/libs/knex-schema/tsconfig.typecheck.json @@ -0,0 +1,6 @@ +{ + "extends": "./tsconfig.build.json", + "compilerOptions": { "noEmit": true, "strict": true }, + "include": ["src/**/*.test-d.ts"], + "exclude": [] +} diff --git a/libs/knex-schema/vitest.config.mts b/libs/knex-schema/vitest.config.mts new file mode 100644 index 00000000..c2329925 --- /dev/null +++ b/libs/knex-schema/vitest.config.mts @@ -0,0 +1,12 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + include: ['src/**/*.test.ts'], + typecheck: { + enabled: true, + include: ['src/**/*.test-d.ts'], + tsconfig: './tsconfig.typecheck.json' + } + } +}); diff --git a/libs/orm/README.md b/libs/orm/README.md index 568115e2..35226880 100644 --- a/libs/orm/README.md +++ b/libs/orm/README.md @@ -344,7 +344,37 @@ npx cb-orm validate --- -## See also +## Composable queries + +ORM re-exports `alias`, `eq`, `and`, `or`, and `aggregate`. Use +`query(db.knex, alias(TaskSchema, 'task'))` for flat DTO joins and `include` for +nested relations. Transaction-bound contexts expose their transaction as `db.knex`. + +`countValue`, `countDistinctValue`, `sumValue`, `avgValue`, `minValue`, and +`maxValue` are available on entity queries. An optional `{ output: schema }` +replaces default decoding and controls the inferred output, including nulls. +Aggregate/DTO projections are not attached as entities in tracked contexts. + +```ts +const tasks = await db.tasks + .orderBy(t => t.createdAt, 'desc') + .orderBy(t => t.id, 'desc') + .include(t => t.owner, owners => { + owners.where(t => t.name, 'Alice'); // foreign schema, not any + }) + .limit(20); +``` + +Eager loading retains parent order and page size. Filtering an included relation +does not necessarily filter parents. Callback types infer the declared foreign +schema, including variant queries when the relation schema is known. + +`paginateAfter({ limit, cursor, orderBy: [...] })` supports non-null scalar sorts +with a declared unique tie-breaker; single-column cursor calls are unchanged. +See the [complete query guide](../knex-schema/COMPOSABLE_QUERIES.md) for defaults, +precision policy, grouped aggregates, cursor restrictions, and migration examples. + +## Related packages - [`@cleverbrush/knex-schema`](../knex-schema) — the underlying schema DSL and query builder diff --git a/libs/orm/src/dbset.ts b/libs/orm/src/dbset.ts index 5364b0f8..8541a289 100644 --- a/libs/orm/src/dbset.ts +++ b/libs/orm/src/dbset.ts @@ -26,8 +26,10 @@ import { import type { Knex } from 'knex'; import { EntityNotFoundError } from './errors.js'; + import type { EntityResult, + RelatedSchema, RelKeyTree, SaveGraph, VariantInsertPayload, @@ -43,6 +45,15 @@ import { updateVariant as _updateVariant } from './variant-write.js'; +const scalarAggregateMethods = new Set([ + 'countValue', + 'countDistinctValue', + 'sumValue', + 'avgValue', + 'minValue', + 'maxValue' +]); + // --------------------------------------------------------------------------- // EntityQuery — public typed query handle // --------------------------------------------------------------------------- @@ -70,7 +81,14 @@ export interface EntityQuery, TResult> */ include & string>( sel: (t: RelKeyTree) => K, - customize?: (q: SchemaQueryBuilder) => void + customize?: ( + q: SchemaQueryBuilder< + RelatedSchema, + import('@cleverbrush/schema').InferType< + RelatedSchema + > + > + ) => void ): EntityQuery>; /** @@ -83,7 +101,16 @@ export interface EntityQuery, TResult> includeVariant( variantKey: TVariant, relationName: TRel, - customize?: (q: SchemaQueryBuilder) => void + customize?: ( + q: TRel extends keyof EntityRelations + ? SchemaQueryBuilder< + RelatedSchema, + import('@cleverbrush/schema').InferType< + RelatedSchema + > + > + : SchemaQueryBuilder + ) => void ): EntityQuery< TEntity, TRel extends keyof EntityRelations & string @@ -248,7 +275,14 @@ export interface VariantDbSet< */ include & string>( sel: (t: RelKeyTree) => R, - customize?: (q: SchemaQueryBuilder) => void + customize?: ( + q: SchemaQueryBuilder< + RelatedSchema, + import('@cleverbrush/schema').InferType< + RelatedSchema + > + > + ) => void ): VariantDbSet; /** Look up a single row by PK, typed to this variant. */ @@ -417,6 +451,8 @@ function wrapQuery, TResult>( // Wrap Promise results to auto-attach tracked entities. if ( onResults != null && + sqb.returnsEntityRows && + !scalarAggregateMethods.has(prop) && result != null && typeof (result as any).then === 'function' ) { @@ -910,6 +946,8 @@ function wrapVariantQuery< if (result === sqb) return proxy; if ( onResults != null && + sqb.returnsEntityRows && + !scalarAggregateMethods.has(prop) && result != null && typeof (result as any).then === 'function' ) { diff --git a/libs/orm/src/index.ts b/libs/orm/src/index.ts index a26814f1..e58fda81 100644 --- a/libs/orm/src/index.ts +++ b/libs/orm/src/index.ts @@ -30,6 +30,7 @@ export type { EntityResultByVariant, ExtractBranch, HasVariants, + RelatedSchema, RelKeyTree, ResolvedRel, SaveGraph, diff --git a/libs/orm/src/query-types.test-d.ts b/libs/orm/src/query-types.test-d.ts new file mode 100644 index 00000000..e4926c7e --- /dev/null +++ b/libs/orm/src/query-types.test-d.ts @@ -0,0 +1,36 @@ +import Knex from 'knex'; +import { expectTypeOf, test } from 'vitest'; +import { createDb, defineEntity, number, object, string } from './index.js'; + +const User = object({ id: number().primaryKey(), name: string() }).hasTableName( + 'users' +); +const Task = object({ + id: number().primaryKey(), + ownerId: number(), + owner: User.optional() +}).hasTableName('tasks'); +const tasks = defineEntity(Task).belongsTo( + t => t.owner, + t => t.ownerId, + t => t.id +); +const db = createDb(Knex({ client: 'pg' }), { tasks }); + +test('include customizers know their relation schema', () => { + db.tasks.include( + t => t.owner, + owners => { + owners.where(t => t.name, 'Alice'); + // @ts-expect-error field belongs to tasks, not users + owners.where(t => t.ownerId, 1); + } + ); +}); + +test('new terminal helpers propagate through ORM', async () => { + expectTypeOf(await db.tasks.countValue()).toEqualTypeOf(); + expectTypeOf( + await db.tasks.countValue({ output: string() }) + ).toEqualTypeOf(); +}); diff --git a/libs/orm/src/result-types.ts b/libs/orm/src/result-types.ts index 825351e0..7029d7a3 100644 --- a/libs/orm/src/result-types.ts +++ b/libs/orm/src/result-types.ts @@ -74,6 +74,12 @@ export type RelKeyTree> = { readonly [K in keyof EntityRelations & string]: K; }; +/** Schema of an entity's declared navigation property. */ +export type RelatedSchema< + TEntity extends Entity, + K extends keyof EntityRelations +> = EntityRelations[K] extends RelationInfo ? S : never; + /** * Result type after `.include('rel')` is applied. * diff --git a/libs/orm/tsconfig.build.json b/libs/orm/tsconfig.build.json index 7954e377..2082ba2d 100644 --- a/libs/orm/tsconfig.build.json +++ b/libs/orm/tsconfig.build.json @@ -12,5 +12,5 @@ "declarationMap": false }, "include": ["src/**/*.ts"], - "exclude": ["src/**/*.test.ts"] + "exclude": ["src/**/*.test.ts", "src/**/*.test-d.ts"] } diff --git a/libs/orm/tsconfig.typecheck.json b/libs/orm/tsconfig.typecheck.json new file mode 100644 index 00000000..c24a9fd6 --- /dev/null +++ b/libs/orm/tsconfig.typecheck.json @@ -0,0 +1,6 @@ +{ + "extends": "./tsconfig.build.json", + "compilerOptions": { "noEmit": true, "strict": true }, + "include": ["src/**/*.test-d.ts"], + "exclude": [] +} diff --git a/libs/orm/vitest.config.mts b/libs/orm/vitest.config.mts new file mode 100644 index 00000000..c2329925 --- /dev/null +++ b/libs/orm/vitest.config.mts @@ -0,0 +1,12 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + include: ['src/**/*.test.ts'], + typecheck: { + enabled: true, + include: ['src/**/*.test-d.ts'], + tsconfig: './tsconfig.typecheck.json' + } + } +}); diff --git a/package.json b/package.json index 45d76c1a..8edf3da8 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "publish:beta": "npm run clean && npm run build && changeset version --snapshot beta && changeset publish --tag beta --no-git-tag", "run_scheduler": "node ./libs/scheduler/dist/index.js", "test": "vitest --run --typecheck", + "test:queries:integration": "vitest run --config vitest.queries.config.mts", "test:coverage": "vitest --run --coverage && node scripts/update-coverage-badges.js", "bench": "vitest bench --run", "bench:json": "BENCH_JSON=bench-results.json vitest bench --run --project benchmarks && node scripts/relativize-bench-paths.js bench-results.json", diff --git a/vitest.queries.config.mts b/vitest.queries.config.mts new file mode 100644 index 00000000..6339951b --- /dev/null +++ b/vitest.queries.config.mts @@ -0,0 +1,9 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + include: ['libs/knex-schema/integration/**/*.test.ts'], + testTimeout: 15000, + hookTimeout: 30000 + } +}); diff --git a/websites/docs/app/knex-schema/page.tsx b/websites/docs/app/knex-schema/page.tsx index 04668be9..9a3b6fe9 100644 --- a/websites/docs/app/knex-schema/page.tsx +++ b/websites/docs/app/knex-schema/page.tsx @@ -90,6 +90,68 @@ export default function KnexSchemaPage() { +
+

Composable read queries

+

+ Use alias(schema, name) with typed flat + joins and object projections for DTOs. Left-joined + fields include null; source scopes and soft deletion are + retained. +

+
 eq(t.task.ownerId, t.owner.id))
+    .select(t => ({ id: t.task.id, ownerName: t.owner.name }));`)
+                        }}
+                    />
+                    

Aggregates and optional output schemas

+

+ Count helpers return checked numbers; sum and average + preserve database numeric text or null. Min/max follow + the column representation. Optional output schemas + replace decoding and receive raw driver values, + including null. Typed aggregate expressions support + grouped results. +

+
 t.estimate, {
+    output: number().isFloat().coerce().nullable()
+});`)
+                        }}
+                    />
+                    

Ordering and composite cursors

+

+ Eager loading preserves final parent order and page + size. Composite cursors retain timestamp precision and + require non-null scalar columns with a declared unique + tie-breaker. Reapply access filters; cursors are not + authorization. +

+
 t.createdAt, direction: 'desc' },
+        { column: t => t.id, direction: 'desc' }
+    ]
+});`)
+                        }}
+                    />
+                    

+ Existing APIs remain unchanged. Read the{' '} + + complete query guide + {' '} + for examples, precision policy, and restrictions. +

+
+ {/* ── Quick Start ──────────────────────────────────── */}

Quick Start

diff --git a/websites/docs/app/orm/page.tsx b/websites/docs/app/orm/page.tsx index 5ae24a9f..e52c1e89 100644 --- a/websites/docs/app/orm/page.tsx +++ b/websites/docs/app/orm/page.tsx @@ -504,6 +504,23 @@ npx cb-orm db push`
{/* ── See Also ─────────────────────────────────────── */} +
+

Reliable query composition

+

+ Eager loading retains parent ordering and page size. + Relation customization callbacks infer the foreign + schema. Scalar aggregate helpers accept optional output + schemas; typed projections support grouped aggregates. + DTOs are not tracked as entities. +

+

+ ORM re-exports flat-join aliases and aggregate + expressions. Composite cursors support non-null scalar + sort fields with a declared unique tie-breaker. Read the{' '} + query guide for examples and + compatibility details. +

+

See Also

    From cdfad72c8b0ea1b18008d82de09aa501e9fc04b0 Mon Sep 17 00:00:00 2001 From: Andrew Zolotukhin Date: Mon, 21 Sep 2026 12:10:29 +0000 Subject: [PATCH 02/41] docs: include composable query guide in the npm package --- libs/knex-schema/package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libs/knex-schema/package.json b/libs/knex-schema/package.json index d7bb3a5a..e65e3c6f 100644 --- a/libs/knex-schema/package.json +++ b/libs/knex-schema/package.json @@ -12,7 +12,8 @@ }, "description": "Type-safe schema-driven query builder for Knex using @cleverbrush/schema — strongly typed CRUD, eager loading, and column mapping for PostgreSQL", "files": [ - "dist" + "dist", + "COMPOSABLE_QUERIES.md" ], "homepage": "https://docs.cleverbrush.com/knex-schema", "keywords": [ From dbca5c287e8df5827306c4d1321f93cef0bffc65 Mon Sep 17 00:00:00 2001 From: Andrew Zolotukhin Date: Mon, 21 Sep 2026 13:09:42 +0000 Subject: [PATCH 03/41] fix: address typed query API review feedback --- .changeset/composable-typed-queries.md | 2 + libs/knex-schema/COMPOSABLE_QUERIES.md | 35 + libs/knex-schema/integration/queries.test.ts | 58 ++ libs/knex-schema/src/SchemaQueryBuilder.ts | 628 +++++++++++++++++- libs/knex-schema/src/aliased-query.ts | 135 +++- libs/knex-schema/src/columns.ts | 11 + .../src/composable-query.test-d.ts | 57 ++ libs/knex-schema/src/composable-query.test.ts | 33 +- libs/knex-schema/src/entity.ts | 17 +- libs/knex-schema/src/expressions.ts | 44 ++ libs/knex-schema/src/extension.ts | 27 + libs/knex-schema/src/index.ts | 1 + .../src/operations/composite-cursor.ts | 10 +- libs/knex-schema/src/operations/insert.ts | 29 + libs/knex-schema/src/public-api-docs.test.ts | 145 ++++ libs/knex-schema/src/sql-identifiers.test.ts | 46 ++ libs/knex-schema/src/sql-identifiers.ts | 18 + libs/knex-schema/src/types.ts | 207 ++++++ libs/orm/src/dbcontext.ts | 8 + libs/orm/src/dbset.ts | 31 +- libs/orm/src/errors.ts | 27 + libs/orm/src/query-types.test-d.ts | 28 +- 22 files changed, 1557 insertions(+), 40 deletions(-) create mode 100644 libs/knex-schema/src/public-api-docs.test.ts create mode 100644 libs/knex-schema/src/sql-identifiers.test.ts create mode 100644 libs/knex-schema/src/sql-identifiers.ts diff --git a/.changeset/composable-typed-queries.md b/.changeset/composable-typed-queries.md index 119ef3d5..1b396dd7 100644 --- a/.changeset/composable-typed-queries.md +++ b/.changeset/composable-typed-queries.md @@ -7,3 +7,5 @@ Add typed flat joined projections, aggregate expressions and scalar helpers with optional output schemas, and composite keyset pagination. Preserve parent ordering during eager loading and infer related-query customization types. Existing aggregate and single-column cursor APIs remain available unchanged. +Export reusable SQL identifier validation, preserve schema inference throughout +bound query factories, and document the public query/ORM APIs for IDE tooltips. diff --git a/libs/knex-schema/COMPOSABLE_QUERIES.md b/libs/knex-schema/COMPOSABLE_QUERIES.md index 72facc3f..e86394bb 100644 --- a/libs/knex-schema/COMPOSABLE_QUERIES.md +++ b/libs/knex-schema/COMPOSABLE_QUERIES.md @@ -23,6 +23,36 @@ filters; filtering the right-hand source does not turn a left join into an inner join. `createQuery(knex)` also accepts aliased schemas. `eq`, `and`, and `or` compose column-based join conditions. Duplicate aliases are errors. +Both `and` and `or` accept multiple predicates and can be nested. Each group +becomes a parenthesized SQL expression, preserving the intended precedence: + +```ts +import { alias, and, eq, or, query } from '@cleverbrush/knex-schema'; + +const rows = await query(knex, alias(TaskSchema, 'task')) + .join(alias(UserSchema, 'owner'), t => or( + eq(t.task.ownerId, t.owner.id), + and( + eq(t.task.approverId, t.owner.id), + or( + eq(t.task.teamId, t.owner.teamId), + eq(t.task.creatorId, t.owner.id) + ) + ) + )) + .select(t => ({ id: t.task.id, ownerName: t.owner.name })); +``` + +This example assumes the illustrated ID properties exist on the schemas. +Empty `and()`/`or()` groups are rejected. Predicates describe SQL; they do not +execute a JavaScript callback for each returned row. + +`isSqlIdentifier(value)` is an exported type guard used by `alias()`. It accepts +one ASCII identifier (`task_owner2`), not qualified names (`public.tasks`), quoted +names, whitespace or non-string values. This deliberately conservative format +does not describe every valid PostgreSQL identifier and does not replace Knex +identifier quoting. Existing table/column metadata APIs are not restricted by it. + The read-only aliased builder requires an explicit, non-empty projection and supports `where`, `whereIn`, `whereNull`, `whereNotNull`, `orderBy`, `orderByRaw`, `groupBy`, `having`, `limit`, `offset`, `first`, `execute`, `transacting`, and @@ -32,6 +62,11 @@ and identifiers quoted. Flat collection joins can repeat parents; they do not deduplicate or fetch one related row at a time. Choose ORM eager loading for nested related objects instead. +For reusable connection/transaction handling, ordinary and aliased schemas retain +the same inference through `createQuery(knex)`, `withTransaction(trx)`, and +`transaction(callback)`. Only ordinary-schema calls accept a custom Knex base +query. These APIs and their JSDoc are also available through `@cleverbrush/orm`. + ## Aggregates with optional output schemas ```ts diff --git a/libs/knex-schema/integration/queries.test.ts b/libs/knex-schema/integration/queries.test.ts index 597dc2fd..dcc6ea59 100644 --- a/libs/knex-schema/integration/queries.test.ts +++ b/libs/knex-schema/integration/queries.test.ts @@ -2,14 +2,17 @@ import { randomUUID } from 'node:crypto'; import { aggregate, alias, + and, array, boolean, createDb, + createQuery, date, defineEntity, eq, number, object, + or, query, string } from '@cleverbrush/orm'; @@ -170,6 +173,55 @@ afterAll(async () => { }); describe('flat joins', () => { + it('executes ordinary and aliased queries through a bound transaction callback', async () => { + const result = await createQuery(knex).transaction(async tx => ({ + ordinary: await tx(Task) + .where(t => t.id, 105) + .select(t => ({ id: t.id })) + .first(), + joined: await tx(alias(Task, 'task')) + .leftJoin(alias(User, 'owner'), t => + eq(t.task.ownerId, t.owner.id) + ) + .where(t => t.task.id, 105) + .select(t => ({ id: t.task.id, ownerName: t.owner.name })) + .first() + })); + expect(result).toEqual({ + ordinary: { id: 105 }, + joined: { id: 105, ownerName: 'Alice' } + }); + }); + it('executes nested AND/OR predicates with their explicit grouping', async () => { + const rows = await query(knex, alias(Task, 'task')) + .join(alias(Task, 'peer'), t => + and( + or( + eq(t.task.ownerId, t.peer.ownerId), + eq(t.task.projectId, t.peer.projectId) + ), + or( + eq(t.task.id, t.peer.id), + and( + eq(t.task.ownerId, t.peer.projectId), + eq(t.task.projectId, t.peer.ownerId) + ) + ) + ) + ) + .where(t => t.task.projectId, 1) + .orderBy(t => t.task.id, 'desc') + .orderBy(t => t.peer.id, 'desc') + .select(t => ({ task: t.task.id, peer: t.peer.id })); + expect(rows).toEqual([ + { task: 105, peer: 105 }, + { task: 105, peer: 102 }, + { task: 104, peer: 104 }, + { task: 103, peer: 103 }, + { task: 102, peer: 105 }, + { task: 102, peer: 102 } + ]); + }); it('preserves left joins when the right-hand schema has scopes and soft deletion', async () => { const rows = await query(knex, alias(Task, 'task')) .leftJoin(alias(User, 'owner'), t => eq(t.task.ownerId, t.owner.id)) @@ -438,6 +490,12 @@ describe('aggregate results', () => { .select(t => ({ id: t.task.id })) .transacting(trx); expect(rows).toEqual([{ id: 999 }]); + const bound = createQuery(knex).withTransaction(trx); + expect( + await bound(alias(Task, 'task')) + .where(t => t.task.id, 999) + .select(t => ({ id: t.task.id })) + ).toEqual([{ id: 999 }]); throw new Error('test rollback'); }) ).rejects.toThrow('test rollback'); diff --git a/libs/knex-schema/src/SchemaQueryBuilder.ts b/libs/knex-schema/src/SchemaQueryBuilder.ts index a6a4d0b5..cc7b97c4 100644 --- a/libs/knex-schema/src/SchemaQueryBuilder.ts +++ b/libs/knex-schema/src/SchemaQueryBuilder.ts @@ -165,10 +165,22 @@ type QueryResultType = TLocalSchema extends { // SchemaQueryBuilder // --------------------------------------------------------------------------- +/** + * Build schema-aware SQL with mapped columns, projections and eager relations. + * Fluent configuration methods mutate this builder; create a fresh query for each + * independent operation. Await the builder or call execute() to obtain mapped rows. + * Use query() to infer both the schema and result types automatically. + */ export class SchemaQueryBuilder< TLocalSchema extends ObjectSchemaBuilder, TResult > { + /** + * Create a query over the schema's configured table. + * @param knex - Database connection or transaction used to execute the query. + * @param localSchema - Schema containing property/column and relation metadata. + * @param baseQuery - Optional existing Knex query to configure; it is not cloned. + */ constructor( knex: Knex, localSchema: TLocalSchema, @@ -202,50 +214,120 @@ export class SchemaQueryBuilder< // SELECT / DISTINCT / AGGREGATES // ======================================================================= + /** + * Choose columns, or use an object selector to infer a flat result shape. + * Object values can be schema descriptors or aggregate expressions. Column-list + * selection retains the existing result type; raw SQL cannot infer a new shape. + * @returns This builder, narrowed to the object projection when one is supplied. + */ select(...columns: (ColumnRef | Knex.Raw)[]): this; + /** + * Choose columns, or use an object selector to infer a flat result shape. + * Object values can be schema descriptors or aggregate expressions. Column-list + * selection retains the existing result type; raw SQL cannot infer a new shape. + * @returns This builder, narrowed to the object projection when one is supplied. + */ select>( selector: TSel ): SchemaQueryBuilder>>; + /** + * Choose columns, or use an object selector to infer a flat result shape. + * Object values can be schema descriptors or aggregate expressions. Column-list + * selection retains the existing result type; raw SQL cannot infer a new shape. + * @returns This builder, narrowed to the object projection when one is supplied. + */ select(...args: unknown[]): any { return selectImpl(this as any, ...args); } + /** + * Apply SQL DISTINCT to the selected columns, optionally adding columns. + * Property selectors are mapped to database names; SQL decides row equality. + */ distinct(...columns: (ColumnRef | Knex.Raw)[]): this { return (distinctImpl as any)(this, ...columns); } + /** + * Append a legacy SQL COUNT selection without executing the query. + * The driver controls the result shape/value type. Prefer countValue() for a + * checked scalar number, or aggregate.count() in a typed object projection. + */ count(column?: ColumnRef | Knex.Raw): this { return (countImpl as any)(this, column); } + /** + * Append a legacy COUNT(DISTINCT column) selection. + * Prefer countDistinctValue() for a checked scalar or aggregate.countDistinct() + * for an inferred grouped result; this legacy method retains the builder type. + */ countDistinct(column?: ColumnRef | Knex.Raw): this { return (countDistinctImpl as any)(this, column); } + /** + * Append a legacy MIN selection without changing the result type. + * Use minValue() for a scalar with explicit decoding, or aggregate.min() in a + * typed projection. SQL returns null for an empty/all-null input. + */ min(column: ColumnRef | Knex.Raw): this { return (minImpl as any)(this, column); } + /** + * Append a legacy MAX selection without changing the result type. + * Use maxValue() for a scalar with explicit decoding, or aggregate.max() in a + * typed projection. SQL returns null for an empty/all-null input. + */ max(column: ColumnRef | Knex.Raw): this { return (maxImpl as any)(this, column); } + /** + * Append a legacy SUM selection, leaving numeric conversion to the driver. + * Prefer sumValue() or aggregate.sum() to preserve exact numeric text by default. + */ sum(column: ColumnRef | Knex.Raw): this { return (sumImpl as any)(this, column); } + /** + * Append a legacy AVG selection, leaving numeric conversion to the driver. + * Prefer avgValue() or aggregate.avg() for a typed, precision-preserving result. + */ avg(column: ColumnRef | Knex.Raw): this { return (avgImpl as any)(this, column); } - /** Count the unpaginated matching source, rejecting unsafe integer results. */ + /** + * Count matching rows, or non-null column values, without mutating this query. + * Ignores source ordering/limits/offsets while retaining filters and transactions. + * @param options - Optional output parser; receives the raw driver value. + * @returns A safe integer by default, including zero for an empty source. + * @throws If the default count overflows, the source is grouped/distinct, or parsing fails. + */ countValue | undefined = undefined>( options?: AggregateOptions ): Promise>; + /** + * Count non-null column values without mutating the source query. + * Source paging/order is ignored; filters, scopes and transactions remain. + * @param column - Mapped schema property to count. + * @param options - Optional parser replacing safe-integer decoding. + * @throws If the default result overflows or the source is grouped/distinct. + */ countValue | undefined = undefined>( column: ColumnRef, options?: AggregateOptions ): Promise>; + /** + * Count matching rows, or non-null column values, without mutating this query. + * Ignores source ordering/limits/offsets while retaining filters and transactions. + * @param options - Optional output parser; receives the raw driver value. + * @returns A safe integer by default, including zero for an empty source. + * @throws If the default count overflows, the source is grouped/distinct, or parsing fails. + */ countValue( columnOrOptions?: ColumnRef | AggregateOptions, options?: AggregateOptions @@ -261,6 +343,13 @@ export class SchemaQueryBuilder< ); } + /** + * Count distinct non-null values in an unpaginated clone of this query. + * @param column - Schema property to count; SQL nulls do not contribute. + * @param options - Optional parser replacing default safe-integer conversion. + * @returns A safe integer, or the parser's inferred output type. + * @throws If the count is unsafe, the source is grouped/distinct, or parsing fails. + */ countDistinctValue | undefined = undefined>( column: ColumnRef, options?: AggregateOptions @@ -268,7 +357,13 @@ export class SchemaQueryBuilder< return scalarAggregate(this, 'countDistinct', column, options); } - /** Exact database numeric text (or null), unless an output schema is supplied. */ + /** + * Sum non-null values in an unpaginated clone, preserving numeric precision. + * @param column - Numeric schema property to sum. + * @param options - Optional parser receiving the raw driver value, including null. + * @returns Database numeric text, or null for empty/all-null input by default. + * An output parser replaces default decoding and controls the result type. + */ sumValue | undefined = undefined>( column: ColumnRef, options?: AggregateOptions @@ -276,6 +371,13 @@ export class SchemaQueryBuilder< return scalarAggregate(this, 'sum', column, options); } + /** + * Average non-null values in an unpaginated clone of this query. + * @param column - Numeric schema property to aggregate. + * @param options - Optional parser receiving the raw driver result, including null. + * @returns Exact database numeric text or null by default; a parser overrides this. + * @remarks Text preserves database precision, not precision already lost in floating-point storage. + */ avgValue | undefined = undefined>( column: ColumnRef, options?: AggregateOptions @@ -283,6 +385,13 @@ export class SchemaQueryBuilder< return scalarAggregate(this, 'avg', column, options); } + /** + * Find the smallest non-null column value without retaining source paging. + * @param column - Schema property to aggregate. + * @param options - Optional parser replacing default decoding, including null handling. + * @returns Null for empty/all-null input; otherwise the column representation. + * Dates return Date; numeric SQL overrides may return exact strings. + */ minValue< C extends ColumnRef, S extends OutputSchema | undefined = undefined @@ -302,6 +411,13 @@ export class SchemaQueryBuilder< return scalarAggregate(this, 'min', column, options); } + /** + * Find the largest non-null column value without retaining source paging. + * @param column - Schema property to aggregate. + * @param options - Optional parser replacing default decoding, including null handling. + * @returns Null for empty/all-null input; otherwise the column representation. + * Dates return Date; numeric SQL overrides may return exact strings. + */ maxValue< C extends ColumnRef, S extends OutputSchema | undefined = undefined @@ -321,10 +437,19 @@ export class SchemaQueryBuilder< return scalarAggregate(this, 'max', column, options); } + /** + * Append a raw SELECT expression with optional Knex value/identifier bindings. + * The caller owns its SQL and result shape; this does not infer a new result type. + */ selectRaw(sql: string, bindings?: any[]): this { return selectRawImpl(this as any, sql, bindings); } + /** + * Apply a named schema projection and narrow the selected property type. + * @param name - Projection registered with the schema's projection() extension. + * @throws If the projection is unknown or conflicts with a prior selection. + */ projected & string>( name: K ): SchemaQueryBuilder< @@ -334,10 +459,19 @@ export class SchemaQueryBuilder< return projectedImpl(this as any, name); } + /** + * Apply a named schema scope to this query. + * @param name - Scope registered with the schema's scope() extension. + * @throws If the requested scope is not registered. + */ scoped>(name: K): this { return scopedImpl(this as any, name as string); } + /** + * Disable the default read scope and include soft-deleted rows. + * Explicit filters already added to this builder remain in place. + */ unscoped(): this { return unscopedImpl(this as any); } @@ -346,55 +480,173 @@ export class SchemaQueryBuilder< // WHERE // ======================================================================= + /** + * Add an AND filter using mapped schema columns, a record, or raw Knex SQL. + * Selector/key and record forms map property names to database columns. Grouped + * callbacks receive a Knex builder and therefore use database column names. + * Values are bound; use the operator form for comparisons other than equality. + */ where(column: ColumnRef, operator: string, value: any): this; + /** + * Add an AND filter using mapped schema columns, a record, or raw Knex SQL. + * Selector/key and record forms map property names to database columns. Grouped + * callbacks receive a Knex builder and therefore use database column names. + * Values are bound; use the operator form for comparisons other than equality. + */ where(column: ColumnRef, value: any): this; + /** + * Add an AND filter using mapped schema columns, a record, or raw Knex SQL. + * Selector/key and record forms map property names to database columns. Grouped + * callbacks receive a Knex builder and therefore use database column names. + * Values are bound; use the operator form for comparisons other than equality. + */ where(raw: Knex.Raw, operator: string, value: any): this; + /** + * Add an AND filter using mapped schema columns, a record, or raw Knex SQL. + * Selector/key and record forms map property names to database columns. Grouped + * callbacks receive a Knex builder and therefore use database column names. + * Values are bound; use the operator form for comparisons other than equality. + */ where(callback: (builder: Knex.QueryBuilder) => void): this; + /** + * Add an AND filter using mapped schema columns, a record, or raw Knex SQL. + * Selector/key and record forms map property names to database columns. Grouped + * callbacks receive a Knex builder and therefore use database column names. + * Values are bound; use the operator form for comparisons other than equality. + */ where(record: Record): this; + /** + * Add an AND filter using mapped schema columns, a record, or raw Knex SQL. + * Selector/key and record forms map property names to database columns. Grouped + * callbacks receive a Knex builder and therefore use database column names. + * Values are bound; use the operator form for comparisons other than equality. + */ where(raw: Knex.Raw): this; + /** + * Add an AND filter using mapped schema columns, a record, or raw Knex SQL. + * Selector/key and record forms map property names to database columns. Grouped + * callbacks receive a Knex builder and therefore use database column names. + * Values are bound; use the operator form for comparisons other than equality. + */ where(columnOrRaw: any, ...args: any[]): this { return whereImpl(this as any, columnOrRaw, ...args); } + /** + * Add an AND condition; an explicit synonym for where(). + * Property references and record keys are mapped; raw callbacks use Knex columns. + */ andWhere( column: ColumnRef, operator: string, value: any ): this; + /** + * Add an AND condition; an explicit synonym for where(). + * Property references and record keys are mapped; raw callbacks use Knex columns. + */ andWhere(column: ColumnRef, value: any): this; + /** + * Add an AND condition; an explicit synonym for where(). + * Property references and record keys are mapped; raw callbacks use Knex columns. + */ andWhere(record: Record): this; + /** + * Add an AND condition; an explicit synonym for where(). + * Property references and record keys are mapped; raw callbacks use Knex columns. + */ andWhere(callback: (builder: Knex.QueryBuilder) => void): this; + /** + * Add an AND condition; an explicit synonym for where(). + * Property references and record keys are mapped; raw callbacks use Knex columns. + */ andWhere(raw: Knex.Raw): this; + /** + * Add an AND condition; an explicit synonym for where(). + * Property references and record keys are mapped; raw callbacks use Knex columns. + */ andWhere(columnOrRaw: any, ...args: any[]): this { return andWhereImpl(this as any, columnOrRaw, ...args); } + /** + * Add an OR condition using a mapped property, record, raw SQL or Knex group. + * Group mixed AND/OR conditions explicitly when SQL precedence would change intent. + */ orWhere( column: ColumnRef, operator: string, value: any ): this; + /** + * Add an OR condition using a mapped property, record, raw SQL or Knex group. + * Group mixed AND/OR conditions explicitly when SQL precedence would change intent. + */ orWhere(column: ColumnRef, value: any): this; + /** + * Add an OR condition using a mapped property, record, raw SQL or Knex group. + * Group mixed AND/OR conditions explicitly when SQL precedence would change intent. + */ orWhere(record: Record): this; + /** + * Add an OR condition using a mapped property, record, raw SQL or Knex group. + * Group mixed AND/OR conditions explicitly when SQL precedence would change intent. + */ orWhere(callback: (builder: Knex.QueryBuilder) => void): this; + /** + * Add an OR condition using a mapped property, record, raw SQL or Knex group. + * Group mixed AND/OR conditions explicitly when SQL precedence would change intent. + */ orWhere(raw: Knex.Raw): this; + /** + * Add an OR condition using a mapped property, record, raw SQL or Knex group. + * Group mixed AND/OR conditions explicitly when SQL precedence would change intent. + */ orWhere(columnOrRaw: any, ...args: any[]): this { return orWhereImpl(this as any, columnOrRaw, ...args); } + /** + * Add a negated condition using a mapped property, record or Knex group. + * Use whereNotIn()/whereNotBetween() for their dedicated SQL operators. + */ whereNot( column: ColumnRef, operator: string, value: any ): this; + /** + * Add a negated condition using a mapped property, record or Knex group. + * Use whereNotIn()/whereNotBetween() for their dedicated SQL operators. + */ whereNot(column: ColumnRef, value: any): this; + /** + * Add a negated condition using a mapped property, record or Knex group. + * Use whereNotIn()/whereNotBetween() for their dedicated SQL operators. + */ whereNot(record: Record): this; + /** + * Add a negated condition using a mapped property, record or Knex group. + * Use whereNotIn()/whereNotBetween() for their dedicated SQL operators. + */ whereNot(callback: (builder: Knex.QueryBuilder) => void): this; + /** + * Add a negated condition using a mapped property, record or Knex group. + * Use whereNotIn()/whereNotBetween() for their dedicated SQL operators. + */ whereNot(raw: Knex.Raw): this; + /** + * Add a negated condition using a mapped property, record or Knex group. + * Use whereNotIn()/whereNotBetween() for their dedicated SQL operators. + */ whereNot(columnOrRaw: any, ...args: any[]): this { return whereNotImpl(this as any, columnOrRaw, ...args); } + /** + * Require the mapped column to match a value list or a single-column subquery. + * An empty list matches no rows. Subqueries use Knex's database column names. + */ whereIn( column: ColumnRef, values: readonly any[] | Knex.QueryBuilder @@ -402,6 +654,10 @@ export class SchemaQueryBuilder< return (whereInImpl as any)(this, column, values); } + /** + * Exclude values returned by a list or single-column subquery. + * SQL null semantics apply; a null in the set is not equivalent to a missing value. + */ whereNotIn( column: ColumnRef, values: readonly any[] | Knex.QueryBuilder @@ -409,6 +665,9 @@ export class SchemaQueryBuilder< return (whereNotInImpl as any)(this, column, values); } + /** + * Add an OR membership condition against a list or single-column subquery. + */ orWhereIn( column: ColumnRef, values: readonly any[] | Knex.QueryBuilder @@ -416,6 +675,9 @@ export class SchemaQueryBuilder< return (orWhereInImpl as any)(this, column, values); } + /** + * Add an OR non-membership condition; SQL NOT IN null semantics apply. + */ orWhereNotIn( column: ColumnRef, values: readonly any[] | Knex.QueryBuilder @@ -423,22 +685,37 @@ export class SchemaQueryBuilder< return (orWhereNotInImpl as any)(this, column, values); } + /** + * Add an AND IS NULL condition for a mapped schema property. + */ whereNull(column: ColumnRef): this { return (whereNullImpl as any)(this, column); } + /** + * Add an AND IS NOT NULL condition for a mapped schema property. + */ whereNotNull(column: ColumnRef): this { return (whereNotNullImpl as any)(this, column); } + /** + * Add an OR IS NULL condition for a mapped schema property. + */ orWhereNull(column: ColumnRef): this { return (orWhereNullImpl as any)(this, column); } + /** + * Add an OR IS NOT NULL condition for a mapped schema property. + */ orWhereNotNull(column: ColumnRef): this { return (orWhereNotNullImpl as any)(this, column); } + /** + * Require the mapped column to lie within an inclusive [lower, upper] range. + */ whereBetween( column: ColumnRef, range: readonly [any, any] @@ -446,6 +723,9 @@ export class SchemaQueryBuilder< return (whereBetweenImpl as any)(this, column, range); } + /** + * Exclude the inclusive [lower, upper] range from a mapped column. + */ whereNotBetween( column: ColumnRef, range: readonly [any, any] @@ -453,26 +733,51 @@ export class SchemaQueryBuilder< return (whereNotBetweenImpl as any)(this, column, range); } + /** + * Match a mapped column against a SQL LIKE pattern. + * Percent and underscore remain wildcards; values are bound, not wildcard-escaped. + */ whereLike(column: ColumnRef, value: string): this { return (whereLikeImpl as any)(this, column, value); } + /** + * Match a mapped column using PostgreSQL's case-insensitive ILIKE operator. + * Percent and underscore remain pattern wildcards. + */ whereILike(column: ColumnRef, value: string): this { return (whereILikeImpl as any)(this, column, value); } + /** + * Append raw WHERE SQL with Knex bindings. Never interpolate untrusted values. + * Raw SQL uses database names and is outside schema-level result/type checking. + */ whereRaw(sql: string, ...bindings: any[]): this { return (whereRawImpl as any)(this, sql, ...bindings); } + /** + * Add an EXISTS filter from a Knex subquery or query-building callback. + * Use qualified database columns to correlate it with the parent query. + */ whereExists(callback: Knex.QueryCallback | Knex.QueryBuilder): this { return (whereExistsImpl as any)(this, callback); } + /** + * Add a NOT EXISTS filter from a Knex subquery or query-building callback. + */ whereNotExists(callback: Knex.QueryCallback | Knex.QueryBuilder): this { return (whereNotExistsImpl as any)(this, callback); } + /** + * Compare a JSON-path value inside a mapped JSON column. + * @param path - JSON path understood by the Knex database dialect. + * @param operator - SQL comparison operator forwarded to Knex. + * @param value - Bound comparison value. + */ whereJsonPath( column: ColumnRef, path: string, @@ -486,6 +791,10 @@ export class SchemaQueryBuilder< // ORDER BY // ======================================================================= + /** + * Append ordering by a mapped property or raw expression (ascending by default). + * Add a unique tie-breaker for stable pages. Eager loading retains parent order. + */ orderBy( column: ColumnRef | Knex.Raw, direction?: 'asc' | 'desc' @@ -493,6 +802,10 @@ export class SchemaQueryBuilder< return (orderByImpl as any)(this, column, direction); } + /** + * Append a raw ORDER BY expression with Knex bindings. + * Use database column names; parent ordering is retained during eager loading. + */ orderByRaw(sql: string, ...bindings: any[]): this { return (orderByRawImpl as any)(this, sql, ...bindings); } @@ -501,14 +814,24 @@ export class SchemaQueryBuilder< // GROUP BY / HAVING // ======================================================================= + /** + * Group rows by mapped schema properties or raw expressions. + * Combine with aggregate expressions in select() to infer grouped DTO results. + */ groupBy(...columns: (ColumnRef | Knex.Raw)[]): this { return (groupByImpl as any)(this, ...columns); } + /** + * Append raw GROUP BY SQL with optional Knex bindings. + */ groupByRaw(sql: string, ...bindings: any[]): this { return (groupByRawImpl as any)(this, sql, ...bindings); } + /** + * Filter SQL groups by a mapped column/raw expression, operator and bound value. + */ having( column: ColumnRef | Knex.Raw, operator: string, @@ -517,6 +840,9 @@ export class SchemaQueryBuilder< return (havingImpl as any)(this, column, operator, value); } + /** + * Append raw HAVING SQL with Knex bindings, for example aggregate comparisons. + */ havingRaw(sql: string, ...bindings: any[]): this { return havingRawImpl(this as any, sql, ...bindings); } @@ -525,16 +851,31 @@ export class SchemaQueryBuilder< // PAGINATION // ======================================================================= + /** + * Set the maximum number of parent rows to select; mutates this query. + * Included collections do not consume the parent limit. + */ limit(n: number): this { return limitImpl(this as any, n); } + /** + * Skip this many parent rows before applying the limit; mutates this query. + * Use deterministic ordering when navigating offset-based pages. + */ offset(n: number): this { return offsetImpl(this as any, n); } + /** + * Execute a one-based offset page and a separate matching-source count query. + * Mutates this builder's limit/offset and returns mapped rows plus page metadata. + * The count and page are separate reads, not a snapshot unless your transaction provides one. + */ async paginate(opts: { + /** One-based page number. */ page: number; + /** Maximum parent rows in a page. */ pageSize: number; }): Promise> { return paginateImpl(this as any, opts) as Promise< @@ -542,15 +883,46 @@ export class SchemaQueryBuilder< >; } + /** + * Read a cursor page without running a total-count query. + * The orderBy form clones the source and preserves exact composite sort values; + * its non-null sort must contain a declared unique key. The legacy column form + * mutates this builder and defaults to id descending. Reapply access filters on + * every request: cursors are positions, not authorization or snapshots. + * @returns Mapped data, hasMore, and a nextCursor that is null on the last page. + * @throws For invalid composite cursors or unsupported composite query shapes. + */ paginateAfter( opts: CompositeCursorOptions ): Promise>; + /** + * Read a cursor page without running a total-count query. + * The orderBy form clones the source and preserves exact composite sort values; + * its non-null sort must contain a declared unique key. The legacy column form + * mutates this builder and defaults to id descending. Reapply access filters on + * every request: cursors are positions, not authorization or snapshots. + * @returns Mapped data, hasMore, and a nextCursor that is null on the last page. + * @throws For invalid composite cursors or unsupported composite query shapes. + */ paginateAfter(opts: { + /** Previous raw single-column position; omit for the first page. */ cursor?: any; + /** Maximum parent rows to return; one extra row determines hasMore. */ limit: number; + /** Unique sort property; defaults to id in the legacy API. */ column?: ColumnRef; + /** Sort/continuation direction; defaults to descending. */ direction?: 'asc' | 'desc'; }): Promise>; + /** + * Read a cursor page without running a total-count query. + * The orderBy form clones the source and preserves exact composite sort values; + * its non-null sort must contain a declared unique key. The legacy column form + * mutates this builder and defaults to id descending. Reapply access filters on + * every request: cursors are positions, not authorization or snapshots. + * @returns Mapped data, hasMore, and a nextCursor that is null on the last page. + * @throws For invalid composite cursors or unsupported composite query shapes. + */ async paginateAfter(opts: any): Promise> { if ('orderBy' in opts) return compositeCursor(this as any, opts); return (paginateAfterImpl as any)(this, opts) as Promise< @@ -562,14 +934,26 @@ export class SchemaQueryBuilder< // WRITE OPERATIONS // ======================================================================= + /** + * Insert one schema-shaped row and return its mapped database representation. + * Applies configured insert hooks, column mappings and timestamp defaults. + */ async insert(data: InsertType): Promise { return insertImpl(this as any, data) as Promise; } + /** + * Insert an array of schema-shaped rows and return their mapped representations. + * Returns an empty array for empty input; use bulkInsert() to control chunking. + */ async insertMany(data: InsertType[]): Promise { return insertManyImpl(this as any, data) as Promise; } + /** + * Configure an upsert conflict target using mapped properties. + * Call merge() or ignore() on the returned builder to insert the row. + */ onConflict( ...conflictColumns: ColumnRef[] ): import('./operations/insert.js').OnConflictBuilder< @@ -579,31 +963,53 @@ export class SchemaQueryBuilder< return (onConflictImpl as any)(this, ...conflictColumns); } + /** + * Insert one row or update it when the chosen conflict target already exists. + * @param opts - Conflict properties and optional subset of properties to update. + * @returns The inserted or updated row mapped to schema property names. + */ async upsert( data: InsertType, opts: { + /** Properties identifying an existing row on conflict. */ conflictColumns: ColumnRef[]; + /** Properties to update on conflict; omit to merge insert values. */ updateColumns?: ColumnRef[]; } ): Promise { return (upsertImpl as any)(this, data, opts); } + /** + * Insert rows in chunks, optionally ignoring or merging conflicts. + * @param opts - Chunk size (default 500), conflict policy and conflict properties. + * @returns Mapped rows returned by PostgreSQL; ignored conflicts produce no row. + */ async bulkInsert( rows: InsertType[], opts?: { + /** Requested rows per statement, capped by parameter limits; default 500. */ chunkSize?: number; + /** Optional PostgreSQL conflict policy applied to each chunk. */ onConflict?: 'ignore' | 'merge'; + /** Conflict target properties when a conflict policy is supplied. */ conflictColumns?: ColumnRef[]; } ): Promise { return (bulkInsertImpl as any)(this, rows, opts); } + /** + * Insert/update rows in chunks using the specified conflict properties. + * @param opts - Required conflict target and optional chunk size (default 500). + * @returns The database rows produced by each chunk, mapped to schema properties. + */ async bulkUpsert( rows: InsertType[], opts: { + /** Properties identifying an existing row on conflict. */ conflictColumns: ColumnRef[]; + /** Requested rows per statement, capped by parameter limits; default 500. */ chunkSize?: number; } ): Promise { @@ -614,13 +1020,24 @@ export class SchemaQueryBuilder< // UPDATE // ======================================================================= + /** + * Update rows matching this query's explicit filters and return mapped rows. + * Applies update hooks and timestamp metadata. Add a WHERE clause to avoid a + * table-wide update; this method does not track entity identity. + */ async update(data: Partial>): Promise { return updateImpl(this as any, data) as Promise; } + /** + * Apply per-row where/set pairs and return the total affected-row count. + * Maps both filter and update property names and applies configured update hooks. + */ async bulkUpdate( updates: ReadonlyArray<{ + /** Equality filters identifying the rows for this update. */ where: Partial>; + /** Schema properties to assign to those rows. */ set: Partial>; }> ): Promise { @@ -631,22 +1048,42 @@ export class SchemaQueryBuilder< // DELETE / SOFT DELETE // ======================================================================= + /** + * Delete rows matching explicit filters and return the affected-row count. + * Runs beforeDelete hooks; with soft-delete metadata it sets the deletion timestamp + * instead of removing rows. Add filters to avoid a table-wide write. + */ async delete(): Promise { return deleteImpl(this as any); } + /** + * Include soft-deleted rows in read results without removing explicit filters. + */ withDeleted(): this { return withDeletedImpl(this as any); } + /** + * Restrict reads to rows whose configured soft-delete column is non-null. + */ onlyDeleted(): this { return onlyDeletedImpl(this as any); } + /** + * Permanently delete rows matching explicit filters, even on a soft-delete schema. + * Runs beforeDelete hooks and returns the affected count. This cannot be undone + * without a transaction rollback or backup. + */ async hardDelete(): Promise { return hardDeleteImpl(this as any); } + /** + * Clear the deletion timestamp on rows matching explicit filters and return them. + * @throws If the schema has no soft-delete configuration. + */ async restore(): Promise { return restoreImpl(this as any) as Promise; } @@ -655,6 +1092,11 @@ export class SchemaQueryBuilder< // EAGER LOADING (JOIN) // ======================================================================= + /** + * Eager-load a related object under spec.as using mapped join columns. + * Required joins remove unmatched parents; optional joins return null. Unlike a + * flat join, related fields remain nested and are mapped with the foreign schema. + */ joinOne< TForeignSchema extends ObjectSchemaBuilder< any, @@ -681,6 +1123,10 @@ export class SchemaQueryBuilder< return joinOneImpl(this as any, spec); } + /** + * Eager-load a nested array without multiplying parent rows. + * The relation's own order/limit/offset controls children separately from parent paging. + */ joinMany< TForeignSchema extends ObjectSchemaBuilder< any, @@ -701,6 +1147,11 @@ export class SchemaQueryBuilder< return joinManyImpl(this as any, spec); } + /** + * Eager-load a relation registered on the schema by name. + * @param customize - Optional callback configuring the related query. + * Use an ORM DbSet when you need typed relation names and customization fields. + */ include( relationName: string, customize?: (q: SchemaQueryBuilder) => void @@ -708,6 +1159,11 @@ export class SchemaQueryBuilder< return includeImpl(this as any, relationName, customize); } + /** + * Eager-load a relation declared for one polymorphic discriminator value. + * Other variants are not populated with this relation. Use ORM entity declarations + * to retain known relation customization types. + */ includeVariant( variantKey: string, relationName: string, @@ -725,6 +1181,11 @@ export class SchemaQueryBuilder< // POLYMORPHIC VARIANTS // ======================================================================= + /** + * Add a filter applying only to the named polymorphic branch. + * Other discriminator values remain eligible. Maps the variant property to its + * CTI/STI storage column; throws for unknown variants or unsupported operators. + */ whereVariant( key: string, column: string, @@ -770,6 +1231,11 @@ export class SchemaQueryBuilder< return this; } + /** + * Choose which polymorphic variant bodies are loaded. + * This controls variant joins/selection, not a discriminator filter on base rows. + * @throws If the schema is not polymorphic. + */ selectVariants(keys: string[]): this { const state = getState(this); if (!getVariantConfig(this)) { @@ -786,6 +1252,11 @@ export class SchemaQueryBuilder< // ESCAPE HATCH // ======================================================================= + /** + * Configure the underlying mutable Knex query as an escape hatch. + * Raw changes do not infer a new result type; the caller owns column names, + * result shape and cardinality introduced by the callback. + */ apply(fn: (builder: Knex.QueryBuilder) => void): this { const state = getState(this); invalidateCache(this); @@ -797,6 +1268,10 @@ export class SchemaQueryBuilder< // TRANSACTION // ======================================================================= + /** + * Clone this query and its eager-relation queries onto an existing transaction. + * The source builder is unchanged; transaction commit/rollback stays with the caller. + */ transacting( trx: Knex.Transaction ): SchemaQueryBuilder { @@ -842,6 +1317,10 @@ export class SchemaQueryBuilder< // EXECUTION // ======================================================================= + /** + * Render SQL for debugging without executing it. + * Bindings may appear as literal values; avoid logging sensitive inputs. + */ toQuery(): string { return getQuery(this).toQuery(); } @@ -851,18 +1330,35 @@ export class SchemaQueryBuilder< return getState(this).selectionMode === null; } + /** + * Expose the built Knex query without executing Framework row mapping. + * Direct execution returns raw database rows, potentially including internal fields. + * Treat mutations as an escape hatch rather than typed Framework configuration. + */ toKnexQuery(): Knex.QueryBuilder { return getQuery(this); } + /** + * Render the query as a debugging SQL string; equivalent to toQuery(). + */ toString(): string { return getQuery(this).toString(); } + /** + * Execute SQL and map all rows, including eager relations and aggregate decoders. + * @returns An empty array when no rows match. + * @throws Database errors and output-parser validation failures. + */ async execute(): Promise { return executeImpl(this) as Promise; } + /** + * Execute this query for its first mapped row, or undefined if none matches. + * Set ordering when the choice of first row matters. + */ async first(): Promise { const query = getQuery(this).first(); const row = await query; @@ -871,6 +1367,10 @@ export class SchemaQueryBuilder< return cleanAndMapRow(this, row) as TResult; } + /** + * Execute a selection and collect one mapped column's values into an array. + * @param column - Schema property whose database column should be read. + */ async pluck( column: ColumnRef ): Promise { @@ -882,6 +1382,10 @@ export class SchemaQueryBuilder< ) as TResult[K][]; } + /** + * Promise-compatible execution hook enabling await query(...). + * Runs execute() and forwards fulfillment/rejection; repeated awaits may execute again. + */ // biome-ignore lint/suspicious/noThenProperty: intentional thenable then( onfulfilled?: @@ -900,10 +1404,26 @@ registerSchemaQueryBuilder(SchemaQueryBuilder); // query() — main entry point // --------------------------------------------------------------------------- +/** + * Create a schema-aware query while preserving its schema and inferred row type. + * Pass a table alias for a flat multi-table query requiring an explicit projection; + * pass an ordinary schema for nested eager loading and schema-aware writes. + * @param knex - Knex connection or transaction. + * @param schema - Table schema or immutable alias(schema, name). + * @returns The appropriately typed, unexecuted query builder. + */ export function query< S extends ObjectSchemaBuilder, N extends string >(knex: Knex, schema: TableAlias): AliasedQueryBuilder>; +/** + * Create a schema-aware query while preserving its schema and inferred row type. + * Pass a table alias for a flat multi-table query requiring an explicit projection; + * pass an ordinary schema for nested eager loading and schema-aware writes. + * @param knex - Knex connection or transaction. + * @param schema - Table schema or immutable alias(schema, name). + * @returns The appropriately typed, unexecuted query builder. + */ export function query< TLocalSchema extends ObjectSchemaBuilder >( @@ -911,6 +1431,14 @@ export function query< schema: TLocalSchema ): SchemaQueryBuilder>; +/** + * Create a schema-aware query while preserving its schema and inferred row type. + * Pass a table alias for a flat multi-table query requiring an explicit projection; + * pass an ordinary schema for nested eager loading and schema-aware writes. + * @param knex - Knex connection or transaction. + * @param schema - Table schema or immutable alias(schema, name). + * @returns The appropriately typed, unexecuted query builder. + */ export function query< TLocalSchema extends ObjectSchemaBuilder >( @@ -919,26 +1447,57 @@ export function query< baseQuery: Knex.QueryBuilder ): SchemaQueryBuilder>; -export function query( +/** + * Create a schema-aware query while preserving its schema and inferred row type. + * Pass a table alias for a flat multi-table query requiring an explicit projection; + * pass an ordinary schema for nested eager loading and schema-aware writes. + * @param knex - Knex connection or transaction. + * @param schema - Table schema or immutable alias(schema, name). + * @returns The appropriately typed, unexecuted query builder. + */ +export function query< + S extends ObjectSchemaBuilder, + N extends string +>( knex: Knex, - schema: any, + schema: S | TableAlias, baseQuery?: Knex.QueryBuilder -): any { - if (isTableAlias(schema)) return new AliasedQueryBuilder(knex, schema); - return new SchemaQueryBuilder(knex, schema, baseQuery); +): + | SchemaQueryBuilder> + | AliasedQueryBuilder> { + if (isTableAlias(schema)) + return new AliasedQueryBuilder>(knex, schema); + return new SchemaQueryBuilder>( + knex, + schema, + baseQuery + ); } // --------------------------------------------------------------------------- // createQuery() — knex-bound factory // --------------------------------------------------------------------------- +/** + * A query factory bound to a connection or transaction. + * Ordinary schemas retain schema/result inference; aliases retain the table context. + * Use withTransaction() to reuse a transaction or transaction() to create one. + */ export interface BoundQuery { + /** + * Start a typed query on the bound connection using a schema or table alias. + * Only ordinary schema calls accept an existing Knex base query. + */ < S extends ObjectSchemaBuilder, N extends string >( schema: TableAlias ): AliasedQueryBuilder>; + /** + * Start a typed query on the bound connection using a schema or table alias. + * Only ordinary schema calls accept an existing Knex base query. + */ < TLocalSchema extends ObjectSchemaBuilder< any, @@ -952,6 +1511,10 @@ export interface BoundQuery { >( schema: TLocalSchema ): SchemaQueryBuilder>; + /** + * Start a typed query on the bound connection using a schema or table alias. + * Only ordinary schema calls accept an existing Knex base query. + */ < TLocalSchema extends ObjectSchemaBuilder< any, @@ -966,11 +1529,30 @@ export interface BoundQuery { schema: TLocalSchema, baseQuery: Knex.QueryBuilder ): SchemaQueryBuilder>; + /** + * Create a factory bound to an existing transaction without committing it. + */ withTransaction(trx: Knex.Transaction): BoundQuery; + /** + * Run a callback with a transaction-bound factory. + * Resolves to the callback result on commit; rejects and rolls back on failure. + */ transaction(callback: (db: BoundQuery) => Promise): Promise; } +/** + * Bind query() to a connection, retaining all schema/alias overloads. + * @param knexInstance - Connection or existing transaction to bind. + * @returns A callable factory with transaction helpers. + * @example + * const db = createQuery(knex); + * const rows = await db(TaskSchema).select(t => ({ id: t.id })); + */ export function createQuery(knexInstance: Knex): BoundQuery { + function boundQuery< + S extends ObjectSchemaBuilder, + N extends string + >(schema: TableAlias): AliasedQueryBuilder>; function boundQuery< TLocalSchema extends ObjectSchemaBuilder< any, @@ -984,22 +1566,28 @@ export function createQuery(knexInstance: Knex): BoundQuery { >( schema: TLocalSchema, baseQuery?: Knex.QueryBuilder - ): SchemaQueryBuilder> { + ): SchemaQueryBuilder>; + function boundQuery< + S extends ObjectSchemaBuilder, + N extends string + >( + schema: S | TableAlias, + baseQuery?: Knex.QueryBuilder + ): + | SchemaQueryBuilder> + | AliasedQueryBuilder> { + if (isTableAlias(schema)) return query(knexInstance, schema); return baseQuery ? query(knexInstance, schema, baseQuery) : query(knexInstance, schema); } - (boundQuery as BoundQuery).withTransaction = ( - trx: Knex.Transaction - ): BoundQuery => createQuery(trx as unknown as Knex); - - (boundQuery as BoundQuery).transaction = ( - callback: (db: BoundQuery) => Promise - ): Promise => - knexInstance.transaction(trx => - callback(createQuery(trx as unknown as Knex)) - ); - - return boundQuery as BoundQuery; + return Object.assign(boundQuery, { + withTransaction(trx: Knex.Transaction): BoundQuery { + return createQuery(trx); + }, + transaction(callback: (db: BoundQuery) => Promise): Promise { + return knexInstance.transaction(trx => callback(createQuery(trx))); + } + }) satisfies BoundQuery; } diff --git a/libs/knex-schema/src/aliased-query.ts b/libs/knex-schema/src/aliased-query.ts index c8a37977..5ac2979f 100644 --- a/libs/knex-schema/src/aliased-query.ts +++ b/libs/knex-schema/src/aliased-query.ts @@ -13,6 +13,7 @@ import { getEffectiveBaseQuery, getSchemaQueryBuilderCtor } from './operations/helpers.js'; +import { isSqlIdentifier } from './sql-identifiers.js'; type TableSchema = ObjectSchemaBuilder; const ALIAS = Symbol('table-alias'); @@ -21,23 +22,43 @@ const PREDICATE = Symbol('join-predicate'); /** Immutable table identity; does not mutate the schema's column metadata. */ export interface TableAlias { readonly [ALIAS]: true; + /** + * The original immutable schema used to resolve columns and read scopes. + */ readonly schema: S; + /** + * Literal SQL alias exposed as a key in joined selector callbacks. + */ readonly name: N; } +/** + * Create an immutable table identity for typed flat joins and projections. + * The schema is not modified, so it can be joined repeatedly under different names. + * @param schema - Source table schema, including mapped columns and read scopes. + * @param name - Unique identifier within the query, checked by isSqlIdentifier(). + * @throws If name is not a supported single SQL identifier. + * @example + * const owner = alias(UserSchema, 'owner'); + */ export function alias( schema: S, name: N ): TableAlias { - if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name)) { + if (!isSqlIdentifier(name)) { throw new Error('Table aliases must be non-empty SQL identifier names'); } return Object.freeze({ [ALIAS]: true as const, schema, name }); } +/** @internal Narrow a query source without losing its schema or alias literal. */ +export function isTableAlias( + value: S | TableAlias +): value is TableAlias; export function isTableAlias( value: unknown -): value is TableAlias { +): value is TableAlias; +export function isTableAlias(value: unknown): boolean { return !!value && typeof value === 'object' && ALIAS in value; } @@ -49,12 +70,18 @@ type Columns = { >; }; +/** + * Map a literal alias to its schema columns; optional/left-joined fields include SQL null. + */ export type AliasTables< S extends TableSchema, N extends string, Nullable extends boolean = false > = Record>; type Selection = Record | AggregateExpression>; +/** + * Infer the exact selected DTO fields from aliased columns and aggregate expressions. + */ export type JoinedProjection = { [K in keyof S]: S[K] extends AggregateExpression ? T @@ -63,6 +90,9 @@ export type JoinedProjection = { : never; }; +/** + * An opaque SQL condition composed with eq(), and() and or(); never evaluated per row in JavaScript. + */ export interface JoinPredicate { readonly [PREDICATE]: | { op: 'eq'; left: AliasedColumn; right: AliasedColumn } @@ -77,11 +107,25 @@ export function eq( return { [PREDICATE]: { op: 'eq', left, right } }; } +/** + * Combine one or more predicates into a parenthesized SQL AND group. + * Groups may contain nested and()/or() calls at any depth. + * @throws If no predicates are supplied. + * @example + * and(eq(t.task.ownerId, t.owner.id), or(eq(t.task.id, t.owner.id), eq(t.task.ownerId, t.owner.managerId))) + */ export function and(...items: JoinPredicate[]): JoinPredicate { if (!items.length) throw new Error('and() requires at least one predicate'); return { [PREDICATE]: { op: 'and', items } }; } +/** + * Combine one or more predicates into a parenthesized SQL OR group. + * Nesting preserves explicit grouping independently of SQL operator precedence. + * @throws If no predicates are supplied. + * @example + * or(eq(t.task.ownerId, t.owner.id), eq(t.task.approverId, t.owner.id)) + */ export function or(...items: JoinPredicate[]): JoinPredicate { if (!items.length) throw new Error('or() requires at least one predicate'); return { [PREDICATE]: { op: 'or', items } }; @@ -94,6 +138,11 @@ export class AliasedQueryBuilder { private selected = false; private decoders: Record unknown> = {}; + /** + * Create a read-only query for one aliased schema. + * Prefer query(knex, alias(schema, name)) so the table-context type is inferred. + * The source retains its schema's default scope and soft-delete filters. + */ constructor( private knex: Knex, source: TableAlias @@ -165,6 +214,11 @@ export class AliasedQueryBuilder { ); } + /** + * Add an inner join using a typed, composable column predicate. + * Unmatched rows are removed; one-to-many matches can repeat parent rows. + * @throws If the alias already exists or a predicate uses an unknown column. + */ join( table: N extends keyof TTables ? never : TableAlias, on: (tables: TTables & AliasTables) => JoinPredicate @@ -173,6 +227,11 @@ export class AliasedQueryBuilder { return this as any; } + /** + * Add a left join and make the new alias's projected fields nullable. + * The right-hand schema's read filters stay inside its source so unmatched parents + * are retained. Nested eq()/and()/or() conditions are supported. + */ leftJoin( table: N extends keyof TTables ? never : TableAlias, on: (tables: TTables & AliasTables) => JoinPredicate @@ -198,15 +257,30 @@ export class AliasedQueryBuilder { } } + /** + * Add an AND comparison on a column from the joined table context. + * Omitting the operator means equality. Values are bound and columns quoted. + * @throws If the operator or selected column is unsupported. + */ where( column: (tables: TTables) => AliasedColumn, value: unknown ): this; + /** + * Add an AND comparison on a column from the joined table context. + * Omitting the operator means equality. Values are bound and columns quoted. + * @throws If the operator or selected column is unsupported. + */ where( column: (tables: TTables) => AliasedColumn, operator: string, value: unknown ): this; + /** + * Add an AND comparison on a column from the joined table context. + * Omitting the operator means equality. Values are bound and columns quoted. + * @throws If the operator or selected column is unsupported. + */ where( column: (tables: TTables) => AliasedColumn, ...args: [value: unknown] | [operator: string, value: unknown] @@ -222,6 +296,9 @@ export class AliasedQueryBuilder { return this; } + /** + * Require an aliased column to match one of the bound values; an empty list matches no rows. + */ whereIn( column: (tables: TTables) => AliasedColumn, values: readonly unknown[] @@ -230,16 +307,25 @@ export class AliasedQueryBuilder { return this; } + /** + * Add IS NULL for an aliased column, including a missing left-joined row. + */ whereNull(column: (tables: TTables) => AliasedColumn): this { this.sql.whereNull(this.column(column(this.tree()))); return this; } + /** + * Add IS NOT NULL for an aliased column; this can exclude unmatched left joins. + */ whereNotNull(column: (tables: TTables) => AliasedColumn): this { this.sql.whereNotNull(this.column(column(this.tree()))); return this; } + /** + * Append ordering on an aliased column, ascending unless a direction is supplied. + */ orderBy( column: (tables: TTables) => AliasedColumn, direction: 'asc' | 'desc' = 'asc' @@ -248,11 +334,17 @@ export class AliasedQueryBuilder { return this; } + /** + * Append raw ordering with Knex bindings; the caller owns aliases and SQL syntax. + */ orderByRaw(sql: string, bindings: readonly Knex.RawBinding[] = []): this { this.sql.orderByRaw(sql, bindings); return this; } + /** + * Group joined rows by aliased columns before evaluating aggregate projections. + */ groupBy(...columns: Array<(tables: TTables) => AliasedColumn>): this { this.sql.groupBy( columns.map(column => this.column(column(this.tree()))) @@ -260,6 +352,11 @@ export class AliasedQueryBuilder { return this; } + /** + * Filter groups by an aliased column or aggregate expression. + * Comparisons use native SQL aggregate values, not output-schema conversions or + * text casts, so numeric comparisons retain database semantics. + */ having( value: ( tables: TTables @@ -279,6 +376,12 @@ export class AliasedQueryBuilder { return this; } + /** + * Choose the exact flat DTO shape from aliased columns and aggregate expressions. + * Aggregates are decoded after execution; left-joined fields include null. + * @throws If the projection is empty or select() was already called. + * @returns This builder with an inferred result type for the selected fields. + */ select( selector: (tables: TTables) => S ): AliasedQueryBuilder> { @@ -301,10 +404,16 @@ export class AliasedQueryBuilder { return this as any; } + /** + * Set the maximum number of flat result rows; repeated joined parents each count as a row. + */ limit(limit: number): this { this.sql.limit(limit); return this; } + /** + * Skip flat result rows; pair with deterministic ordering for repeatable pages. + */ offset(offset: number): this { this.sql.offset(offset); return this; @@ -316,6 +425,10 @@ export class AliasedQueryBuilder { return this; } + /** + * Clone this builder onto an existing transaction, preserving its tables/projection. + * Does not modify the source or commit/roll back the transaction. + */ transacting(trx: Knex.Transaction): AliasedQueryBuilder { const [name, schema] = this.tables.entries().next().value!; const copy = new AliasedQueryBuilder( @@ -329,6 +442,11 @@ export class AliasedQueryBuilder { return copy; } + /** + * Return a clone of the underlying Knex query after validating the projection. + * Executing the clone bypasses aggregate output decoding. + * @throws If no explicit projection has been selected. + */ toKnexQuery(): Knex.QueryBuilder { if (!this.selected) throw new Error( @@ -336,6 +454,9 @@ export class AliasedQueryBuilder { ); return this.sql.clone(); } + /** + * Render debugging SQL without execution; interpolated bindings may contain sensitive values. + */ toQuery(): string { return this.toKnexQuery().toQuery(); } @@ -346,15 +467,25 @@ export class AliasedQueryBuilder { result[key] = decode(row[key]); return result as TResult; } + /** + * Execute the flat query and decode aggregate outputs for each returned row. + * @throws Database errors, missing projection errors and output-parser failures. + */ async execute(): Promise { return (await this.toKnexQuery()).map((row: Record) => this.decode(row) ); } + /** + * Execute a limited clone and return its first decoded DTO, or undefined when no row matches. + */ async first(): Promise { const row = await this.toKnexQuery().first(); return row === undefined ? undefined : this.decode(row); } + /** + * Enable awaiting the builder by executing and forwarding its decoded result or error. + */ // biome-ignore lint/suspicious/noThenProperty: intentional query thenable then( resolve?: ((rows: TResult[]) => T | PromiseLike) | null, diff --git a/libs/knex-schema/src/columns.ts b/libs/knex-schema/src/columns.ts index a014952a..4f620d2e 100644 --- a/libs/knex-schema/src/columns.ts +++ b/libs/knex-schema/src/columns.ts @@ -96,6 +96,11 @@ export function resolveColumnRef( label: string, knex: Knex ): string | Knex.Raw; +/** + * Resolve a schema property key/accessor to its mapped database column. + * With a Knex instance, nested JSON paths become bound SQL expressions. Without + * Knex, nested paths throw. Unknown string names pass through as database names. + */ export function resolveColumnRef( ref: ColumnRef, schema: ObjectSchemaBuilder, @@ -246,7 +251,13 @@ export function resolvePropertyKey( * @public */ export interface PrimaryKeyColumns { + /** + * Schema property names in primary-key declaration order; this order defines composite-key tuples. + */ readonly propertyKeys: readonly string[]; + /** + * Corresponding mapped SQL column names in the same order as propertyKeys. + */ readonly columnNames: readonly string[]; } diff --git a/libs/knex-schema/src/composable-query.test-d.ts b/libs/knex-schema/src/composable-query.test-d.ts index 5f8433e6..a03fa6f4 100644 --- a/libs/knex-schema/src/composable-query.test-d.ts +++ b/libs/knex-schema/src/composable-query.test-d.ts @@ -1,3 +1,4 @@ +import type { Knex as KnexTypes } from 'knex'; import Knex from 'knex'; import { expectTypeOf, test } from 'vitest'; import { @@ -6,6 +7,7 @@ import { createQuery, date, eq, + isSqlIdentifier, number, object, query, @@ -23,6 +25,61 @@ const Task = object({ createdAt: date() }).hasTableName('tasks'); +declare const trx: KnexTypes.Transaction; + +test('factories retain schema, alias and result inference through every call shape', async () => { + const bound = createQuery(db); + const transactional = bound.withTransaction(trx); + const plain = query(db, Task); + expectTypeOf(plain).not.toBeAny(); + expectTypeOf(await plain.select(t => ({ id: t.id }))).toEqualTypeOf< + { id: number }[] + >(); + expectTypeOf( + await query(db, Task, db('tasks')).select(t => ({ amount: t.amount })) + ).toEqualTypeOf<{ amount: number }[]>(); + for (const factory of [bound, transactional]) { + const ordinary = factory(Task); + expectTypeOf(ordinary).not.toBeAny(); + expectTypeOf( + await ordinary.select(t => ({ createdAt: t.createdAt })) + ).toEqualTypeOf<{ createdAt: Date }[]>(); + expectTypeOf( + await factory(Task, db('tasks')).select(t => ({ id: t.id })) + ).toEqualTypeOf<{ id: number }[]>(); + const aliased = factory(alias(Task, 'task')); + expectTypeOf(aliased).not.toBeAny(); + const rows = await aliased + .leftJoin(alias(User, 'owner'), t => eq(t.task.ownerId, t.owner.id)) + .select(t => ({ id: t.task.id, ownerName: t.owner.name })); + expectTypeOf(rows).toEqualTypeOf< + { id: number; ownerName: string | null }[] + >(); + expectTypeOf(rows[0].id).not.toBeAny(); + // @ts-expect-error Unselected fields are unavailable. + rows[0].amount; + // @ts-expect-error Invalid schema fields must not become any. + factory(Task).select(t => ({ missing: t.missing })); + // @ts-expect-error Aliased tables retain their own fields. + factory(alias(Task, 'task')).select(t => ({ missing: t.task.name })); + // @ts-expect-error An aliased query does not accept a custom base query. + factory(alias(Task, 'task'), db('tasks')); + } + expectTypeOf( + await bound.transaction(async tx => + tx(Task).select(t => ({ id: t.id })) + ) + ).toEqualTypeOf<{ id: number }[]>(); + expectTypeOf( + await bound.transaction(async tx => + tx(alias(Task, 'task')).select(t => ({ id: t.task.id })) + ) + ).toEqualTypeOf<{ id: number }[]>(); + const unknownName: unknown = 'task'; + if (isSqlIdentifier(unknownName)) + expectTypeOf(unknownName).toEqualTypeOf(); +}); + test('flat join projection inference and nullable right-hand fields', async () => { const task = alias(Task, 'task'); const owner = alias(User, 'owner'); diff --git a/libs/knex-schema/src/composable-query.test.ts b/libs/knex-schema/src/composable-query.test.ts index fcc8ad76..b3a3dbed 100644 --- a/libs/knex-schema/src/composable-query.test.ts +++ b/libs/knex-schema/src/composable-query.test.ts @@ -32,10 +32,7 @@ describe('typed aliases and aggregate SQL', () => { const before = Task.introspect(); const compiled = query(db, alias(Task, 'task')) .join(alias(User, 'owner'), t => - and( - eq(t.task.ownerId, t.owner.id), - or(eq(t.task.ownerId, t.owner.id)) - ) + or(eq(t.task.ownerId, t.owner.id), eq(t.task.id, t.owner.id)) ) .where(t => t.owner.name, "O'Reilly") .orderBy(t => t.task.id, 'desc') @@ -48,6 +45,34 @@ describe('typed aliases and aggregate SQL', () => { expect(Task.introspect()).toEqual(before); }); + it('preserves multiple predicates at every nested AND/OR level', () => { + const compiled = query(db, alias(Task, 'task')) + .join(alias(Task, 'peer'), t => + and( + or( + eq(t.task.ownerId, t.peer.ownerId), + eq(t.task.id, t.peer.id) + ), + or( + eq(t.task.id, t.peer.id), + and( + eq(t.task.ownerId, t.peer.id), + eq(t.task.id, t.peer.ownerId) + ) + ) + ) + ) + .select(t => ({ id: t.task.id })) + .toKnexQuery() + .toSQL(); + expect(compiled.sql).toContain( + 'on (("task"."owner_id" = "peer"."owner_id" or "task"."id" = "peer"."id") and ("task"."id" = "peer"."id" or ("task"."owner_id" = "peer"."id" and "task"."id" = "peer"."owner_id")))' + ); + expect(compiled.bindings).toEqual([]); + expect(() => and()).toThrow('at least one'); + expect(() => or()).toThrow('at least one'); + }); + it('supports two aliases of one schema and rejects duplicate aliases', () => { const users = query(db, alias(User, 'first')); const result = users.leftJoin(alias(User, 'second'), t => diff --git a/libs/knex-schema/src/entity.ts b/libs/knex-schema/src/entity.ts index ca22e669..93ff5896 100644 --- a/libs/knex-schema/src/entity.ts +++ b/libs/knex-schema/src/entity.ts @@ -48,7 +48,13 @@ export interface RelationInfo< any > = ObjectSchemaBuilder > { + /** + * Relation cardinality used to infer nested object or collection results. + */ readonly kind: TKind; + /** + * Foreign schema retained at the type level for relation callback completion. + */ readonly foreign: TForeign; } @@ -197,6 +203,11 @@ export class Entity< /** @internal Phantom slot to retain `TVariantUnion` in inferred types. */ private declare readonly __variantUnion__: TVariantUnion; + /** + * Wrap a schema as an entity definition with typed relation metadata. + * Prefer defineEntity(schema) for inference. Relation/variant methods return new + * definitions; constructing an Entity does not query or create database tables. + */ constructor(schema: TSchema) { this.schema = schema; } @@ -226,7 +237,7 @@ export class Entity< * via `opts.foreign` only when peeling fails. * * @param navSel Selector of nav property: `t => t.author` - * @param localSel Selector of local-side join key: `l => l.id` + * @param _localSel Selector of local-side join key: `l => l.id` * @param remoteSel Selector of remote-side FK on foreign schema: `r => r.userId` * @param opts Optional `{ optional?: boolean }` (default false). */ @@ -270,7 +281,7 @@ export class Entity< * Declare a one-to-many relation where the FK lives on the FOREIGN table. * * @param navSel Selector of nav array property: `t => t.posts` - * @param localSel Selector of local-side join key: `l => l.id` + * @param _localSel Selector of local-side join key: `l => l.id` * @param remoteSel Selector of remote-side FK on foreign schema: `r => r.userId` */ hasMany< @@ -311,7 +322,7 @@ export class Entity< * * @param navSel Selector of nav property (foreign schema, usually `.optional()`). * @param localSel Selector of local-side FK property: `l => l.userId` - * @param remoteSel Selector of foreign-side PK property: `r => r.id` + * @param _remoteSel Selector of foreign-side PK property: `r => r.id` */ belongsTo< TKey extends keyof SchemaProps & string, diff --git a/libs/knex-schema/src/expressions.ts b/libs/knex-schema/src/expressions.ts index 11fa41de..04aae2be 100644 --- a/libs/knex-schema/src/expressions.ts +++ b/libs/knex-schema/src/expressions.ts @@ -8,6 +8,9 @@ import type { Knex } from 'knex'; /** A synchronous schema parser. Framework schemas implement this interface. */ export interface OutputSchema { + /** + * Synchronously validate/convert a raw driver value, including null; throw to reject the query. + */ parse(value: unknown): T; } @@ -15,6 +18,9 @@ export interface OutputSchema { export interface AggregateOptions< S extends OutputSchema | undefined = undefined > { + /** + * Replace the default decoder with this parser; its output type becomes the aggregate result type. + */ output?: S; } @@ -36,6 +42,9 @@ export interface AliasedColumn { column: string; schema: any; }; + /** + * Type-only marker carrying column nullability and value type; not a runtime row value. + */ readonly __value?: T; } @@ -73,6 +82,9 @@ export interface AggregateExpression { column?: SelectableColumn; output?: OutputSchema; }; + /** + * Type-only marker describing the decoded result of this SQL expression. + */ readonly __result?: T; } @@ -106,6 +118,13 @@ export function createAggregate( /** Typed aggregate expressions for scalar or grouped object projections. */ export const aggregate = { + /** + * Describe COUNT(*) or COUNT(column) for a typed projection or HAVING clause. + * @param column - Omit to count rows; supply a column to count its non-null values. + * @param options - Optional raw-value parser; use undefined as column for custom COUNT(*). + * @returns An expression decoded as a safe number unless a parser is supplied. + * @throws During execution if the default result exceeds the safe integer range. + */ count | undefined = undefined>( column?: SelectableColumn, options?: AggregateOptions @@ -116,6 +135,11 @@ export const aggregate = { options ); }, + /** + * Describe COUNT(DISTINCT column), excluding nulls. + * @param options - Optional parser replacing checked safe-integer decoding. + * @returns A typed aggregate expression, not an executed query. + */ countDistinct | undefined = undefined>( column: SelectableColumn, options?: AggregateOptions @@ -126,6 +150,11 @@ export const aggregate = { options ); }, + /** + * Describe SUM(column) with exact database numeric text as the default result. + * Empty/all-null inputs produce null. An output parser receives the raw driver + * value and takes responsibility for precision and null handling. + */ sum | undefined = undefined>( column: SelectableColumn, options?: AggregateOptions @@ -136,6 +165,11 @@ export const aggregate = { options ); }, + /** + * Describe AVG(column), preserving database numeric text or null by default. + * An output parser can explicitly convert it to a number or domain decimal type. + * Text output cannot recover precision already lost in floating-point storage. + */ avg | undefined = undefined>( column: SelectableColumn, options?: AggregateOptions @@ -146,6 +180,11 @@ export const aggregate = { options ); }, + /** + * Describe MIN(column), returning the column representation or null. + * Numeric/decimal/bigint SQL overrides preserve exact strings; dates return Date. + * An optional output parser replaces this decoding policy. + */ min< C extends SelectableColumn, S extends OutputSchema | undefined = undefined @@ -156,6 +195,11 @@ export const aggregate = { options ); }, + /** + * Describe MAX(column), returning the column representation or null. + * Numeric/decimal/bigint SQL overrides preserve exact strings; dates return Date. + * An optional output parser replaces this decoding policy. + */ max< C extends SelectableColumn, S extends OutputSchema | undefined = undefined diff --git a/libs/knex-schema/src/extension.ts b/libs/knex-schema/src/extension.ts index eafe3fbc..5a421518 100644 --- a/libs/knex-schema/src/extension.ts +++ b/libs/knex-schema/src/extension.ts @@ -1146,14 +1146,41 @@ const extended = withExtensions( ddlExtension ); +/** + * Create a string schema with database column, key, reference and mapping extensions. + */ export const string = extended.string; +/** + * Create a numeric schema with database type, precision, key and reference extensions. + */ export const number = extended.number; +/** + * Create a boolean schema with database column mapping and DDL metadata extensions. + */ export const boolean = extended.boolean; +/** + * Create a date schema with database column mapping and DDL metadata extensions. + */ export const date = extended.date; +/** + * Create an object schema with table, relation, scope, projection and lifecycle extensions. + */ export const object = extended.object; +/** + * Create an array schema from its element schema; use object elements for collection navigation properties. + */ export const array = extended.array; +/** + * Create a union schema using the database-extended schema factory. + */ export const union = extended.union; +/** + * Create a function schema using the database-extended schema factory; this does not create a SQL function. + */ export const func = extended.func; +/** + * Create an unconstrained schema with database extensions; prefer a specific schema when value typing matters. + */ export const any = extended.any; // --------------------------------------------------------------------------- diff --git a/libs/knex-schema/src/index.ts b/libs/knex-schema/src/index.ts index bfc8e56c..e925f107 100644 --- a/libs/knex-schema/src/index.ts +++ b/libs/knex-schema/src/index.ts @@ -105,6 +105,7 @@ export { loadSnapshot, writeSnapshot } from './snapshot.js'; +export { isSqlIdentifier } from './sql-identifiers.js'; export type { AddColumnDiff, AddForeignKeyDiff, diff --git a/libs/knex-schema/src/operations/composite-cursor.ts b/libs/knex-schema/src/operations/composite-cursor.ts index 7265fbb8..6a36e639 100644 --- a/libs/knex-schema/src/operations/composite-cursor.ts +++ b/libs/knex-schema/src/operations/composite-cursor.ts @@ -16,9 +16,17 @@ import { getState } from './state.js'; export interface CompositeCursorOptions< S extends ObjectSchemaBuilder > { + /** Opaque nextCursor from a compatible page; null/undefined starts a new stream. */ cursor?: string | null; + /** Positive safe integer page size; one extra row determines whether more exist. */ limit: number; - orderBy: readonly { column: ColumnRef; direction: 'asc' | 'desc' }[]; + /** Complete non-null sort, including a declared primary/unique key; replaces prior ordering. */ + orderBy: readonly { + /** Required, non-null scalar schema property participating in the sort. */ + column: ColumnRef; + /** Direction for this component; mixed directions are supported. */ + direction: 'asc' | 'desc'; + }[]; } export async function compositeCursor( diff --git a/libs/knex-schema/src/operations/insert.ts b/libs/knex-schema/src/operations/insert.ts index 5961a244..83b18033 100644 --- a/libs/knex-schema/src/operations/insert.ts +++ b/libs/knex-schema/src/operations/insert.ts @@ -81,11 +81,18 @@ export interface OnConflictMergeOptions { ) => void; } +/** + * Configure one-row conflict handling after SchemaQueryBuilder.onConflict(); merge()/ignore() execute the insert. + */ export class OnConflictBuilder { readonly #knex: Knex; readonly #localSchema: TLocalSchema; readonly #conflictColumns: string[]; + /** + * Create conflict handling for a schema and resolved conflict columns. + * Prefer query(...).onConflict(...) to map property references automatically. + */ constructor( knex: Knex, localSchema: TLocalSchema, @@ -97,15 +104,33 @@ export class OnConflictBuilder { this.#conflictColumns = conflictColumns; } + /** + * Insert a row or merge values into the conflicting row. + * Without an explicit update payload, merges inserted values; a supplied payload + * can contain raw or helper-built expressions. options.where guards the update. + * Uses the configured connection/transaction and returns the mapped returned row. + */ async merge( data: InsertType, options?: OnConflictMergeOptions ): Promise; + /** + * Insert a row or merge values into the conflicting row. + * Without an explicit update payload, merges inserted values; a supplied payload + * can contain raw or helper-built expressions. options.where guards the update. + * Uses the configured connection/transaction and returns the mapped returned row. + */ async merge( data: InsertType, updateData?: OnConflictUpdateData, options?: OnConflictMergeOptions ): Promise; + /** + * Insert a row or merge values into the conflicting row. + * Without an explicit update payload, merges inserted values; a supplied payload + * can contain raw or helper-built expressions. options.where guards the update. + * Uses the configured connection/transaction and returns the mapped returned row. + */ async merge( data: InsertType, updateData?: @@ -132,6 +157,10 @@ export class OnConflictBuilder { ) as Promise; } + /** + * Insert the row but do nothing on conflict. + * @returns The mapped inserted row, or undefined when PostgreSQL returns no row. + */ async ignore(data: InsertType): Promise { return this.#execute(data, 'ignore'); } diff --git a/libs/knex-schema/src/public-api-docs.test.ts b/libs/knex-schema/src/public-api-docs.test.ts new file mode 100644 index 00000000..506bc058 --- /dev/null +++ b/libs/knex-schema/src/public-api-docs.test.ts @@ -0,0 +1,145 @@ +import { readFileSync } from 'node:fs'; +import { fileURLToPath } from 'node:url'; +import ts from 'typescript'; +import { describe, expect, it } from 'vitest'; + +/** Inspect emitted declarations, since those are what installed consumers read. */ +function declaration(path: string): ts.SourceFile { + const url = new URL(path, import.meta.url); + return ts.createSourceFile( + fileURLToPath(url), + readFileSync(url, 'utf8'), + ts.ScriptTarget.Latest, + true + ); +} + +function hasSummary(node: ts.Node): boolean { + const docs = (node as ts.Node & { jsDoc?: readonly ts.JSDoc[] }).jsDoc; + return !!docs?.some(doc => doc.comment); +} + +function isInternal(node: ts.Node): boolean { + return ts.getJSDocTags(node).some(tag => tag.tagName.text === 'internal'); +} + +describe('published query/ORM API documentation', () => { + it('preserves JSDoc for exported functions and every public class member', () => { + const missing: string[] = []; + for (const entry of [ + '../dist/index.d.ts', + '../../orm/dist/index.d.ts' + ]) { + const index = declaration(entry); + for (const statement of index.statements) { + if ( + !ts.isExportDeclaration(statement) || + !statement.exportClause || + !ts.isNamedExports(statement.exportClause) || + !statement.moduleSpecifier || + !ts.isStringLiteral(statement.moduleSpecifier) || + !statement.moduleSpecifier.text.startsWith('.') + ) + continue; + const names = new Set( + statement.exportClause.elements.map( + e => (e.propertyName ?? e.name).text + ) + ); + const moduleUrl = new URL( + statement.moduleSpecifier.text.replace(/\.js$/, '.d.ts'), + new URL(entry, import.meta.url) + ); + check(declaration(moduleUrl.href), names); + } + } + // Reachable through onConflict(), even though not a root named export. + check( + declaration('../dist/operations/insert.d.ts'), + new Set(['OnConflictBuilder']) + ); + expect(missing).toEqual([]); + + function check(source: ts.SourceFile, names: Set): void { + for (const node of source.statements) { + if ( + ts.isVariableStatement(node) && + node.declarationList.declarations.some(d => + names.has(d.name.getText(source)) + ) && + !isInternal(node) && + !hasSummary(node) + ) { + missing.push( + node.declarationList.declarations[0].name.getText( + source + ) + ); + } + if ( + (ts.isFunctionDeclaration(node) || + ts.isClassDeclaration(node)) && + node.name && + names.has(node.name.text) && + !isInternal(node) + ) { + if (!hasSummary(node)) missing.push(node.name.text); + if (ts.isClassDeclaration(node)) { + for (const member of node.members) { + if ( + ts.getCombinedModifierFlags(member) & + (ts.ModifierFlags.Private | + ts.ModifierFlags.Protected) || + (member.name && + ts.isPrivateIdentifier(member.name)) || + isInternal(member) + ) + continue; + if (!hasSummary(member)) + missing.push( + `${node.name.text}.${member.name?.getText(source) ?? 'constructor'}` + ); + } + } + } + } + } + }); + + it('documents aggregate expressions, bound factory overloads and cursor options', () => { + for (const [path, name] of [ + ['../dist/expressions.d.ts', 'aggregate'], + ['../dist/SchemaQueryBuilder.d.ts', 'BoundQuery'], + [ + '../dist/operations/composite-cursor.d.ts', + 'CompositeCursorOptions' + ] + ]) { + const source = declaration(path); + const missing: string[] = []; + function visit(node: ts.Node): void { + if ( + (ts.isMethodSignature(node) || + ts.isPropertySignature(node) || + ts.isCallSignatureDeclaration(node)) && + !isInternal(node) && + !hasSummary(node) + ) { + missing.push(node.getText(source).split('\n')[0]); + } + ts.forEachChild(node, visit); + } + const node = source.statements.find( + n => + (ts.isInterfaceDeclaration(n) && n.name.text === name) || + (ts.isVariableStatement(n) && + n.declarationList.declarations.some( + d => d.name.getText(source) === name + )) + ); + expect(node, name).toBeDefined(); + visit(node!); + expect(missing, name).toEqual([]); + } + }); +}); diff --git a/libs/knex-schema/src/sql-identifiers.test.ts b/libs/knex-schema/src/sql-identifiers.test.ts new file mode 100644 index 00000000..5d82666f --- /dev/null +++ b/libs/knex-schema/src/sql-identifiers.test.ts @@ -0,0 +1,46 @@ +import { describe, expect, it } from 'vitest'; +import { alias, isSqlIdentifier, number, object } from './index.js'; + +describe('isSqlIdentifier', () => { + it.each([ + 'task', + '_task', + 'task_owner2', + 'TaskOwner', + 'select' + ])('accepts the supported single-name format: %s', name => + expect(isSqlIdentifier(name)).toBe(true)); + it.each([ + '', + '2tasks', + 'public.tasks', + 'task owner', + 'task-owner', + 'task;drop', + 'task"owner', + '"task"', + 'tâche', + 'task\n', + null, + undefined, + 42, + {}, + { toString: () => 'task' } + ])('rejects invalid names without coercing input: %s', value => { + expect(isSqlIdentifier(value)).toBe(false); + }); + it('makes alias creation use the same validation', () => { + const schema = object({ id: number() }).hasTableName('tasks'); + for (const name of [ + 'task.owner', + '', + undefined, + { toString: () => 'task' } + ]) { + expect(() => alias(schema, name as string)).toThrow( + 'SQL identifier' + ); + } + expect(alias(schema, 'task_2').name).toBe('task_2'); + }); +}); diff --git a/libs/knex-schema/src/sql-identifiers.ts b/libs/knex-schema/src/sql-identifiers.ts new file mode 100644 index 00000000..ee74e4c0 --- /dev/null +++ b/libs/knex-schema/src/sql-identifiers.ts @@ -0,0 +1,18 @@ +/** + * Test whether a value is a supported, single SQL identifier, such as a table + * alias. Accepts ASCII letters/underscores followed by letters/digits/underscores. + * + * This deliberately excludes qualified names, quoted identifiers and Unicode; + * it is not a validator for every identifier accepted by a database dialect. + * Keywords are accepted because query builders quote identifiers. Always keep + * using identifier bindings (`??`), even after this check succeeds. + * + * @param value - Untrusted value to test without coercing it to a string. + * @returns Whether the value is a string in Framework's supported format. + * @example + * isSqlIdentifier('task_owner'); // true + * isSqlIdentifier('public.tasks'); // false: qualified, not a single name + */ +export function isSqlIdentifier(value: unknown): value is string { + return typeof value === 'string' && /^[A-Za-z_][A-Za-z0-9_]*$/.test(value); +} diff --git a/libs/knex-schema/src/types.ts b/libs/knex-schema/src/types.ts index ee96f00e..9832f2af 100644 --- a/libs/knex-schema/src/types.ts +++ b/libs/knex-schema/src/types.ts @@ -12,6 +12,9 @@ import type { AggregateExpression } from './expressions.js'; // --------------------------------------------------------------------------- // Utility: extract string keys from an ObjectSchemaBuilder's inferred type // --------------------------------------------------------------------------- +/** + * String property names available on a schema-inferred row, before SQL column-name mapping. + */ export type SchemaKeys< T extends ObjectSchemaBuilder > = keyof InferType & string; @@ -35,6 +38,9 @@ type SchemaBase< ? ObjectSchemaBuilder : never; +/** + * Reference a schema property by key or typed descriptor selector; nested selectors may address JSON paths. + */ export type ColumnRef< T extends ObjectSchemaBuilder > = @@ -46,6 +52,9 @@ export type ColumnRef< // --------------------------------------------------------------------------- // JoinOne specification — single related object (N:1 / belongsTo / hasOne) // --------------------------------------------------------------------------- +/** + * Configure a single nested eager relation, including its join keys, requiredness and foreign query. + */ export interface JoinOneSpec< TLocalSchema extends ObjectSchemaBuilder, TForeignSchema extends ObjectSchemaBuilder< @@ -81,6 +90,9 @@ export interface JoinOneSpec< // --------------------------------------------------------------------------- // JoinMany specification — collection of related objects (1:N / hasMany) // --------------------------------------------------------------------------- +/** + * Configure a nested eager collection with child-level ordering/paging independent of parent paging. + */ export interface JoinManySpec< TLocalSchema extends ObjectSchemaBuilder, TForeignSchema extends ObjectSchemaBuilder< @@ -163,26 +175,77 @@ export type WithJoinedMany< // --------------------------------------------------------------------------- // Internal validated spec (after runtime validation) // --------------------------------------------------------------------------- +/** + * Normalized one-object relation specification with resolved SQL names and an executable foreign query. + */ export interface ValidatedJoinOneSpec { + /** + * Resolved SQL join column on the parent table. + */ localColumn: string; + /** + * Resolved SQL join column on the related table. + */ foreignColumn: string; + /** + * Result property receiving the nested related object. + */ as: string; + /** + * Whether unmatched parent rows are excluded by an inner join. + */ required: boolean; + /** + * Prepared Knex query describing eligible related rows. + */ foreignQuery: Knex.QueryBuilder; + /** + * Optional related-field conversions applied after SQL returns. + */ mappers?: Record any) | string>; } +/** + * Normalized collection relation specification consumed by the eager-loading compiler. + */ export interface ValidatedJoinManySpec { + /** + * Resolved parent SQL column matched to each child group. + */ localColumn: string; + /** + * Resolved child SQL column used to group related rows. + */ foreignColumn: string; + /** + * Result property receiving the array of related rows. + */ as: string; + /** + * Prepared Knex query describing eligible children. + */ foreignQuery: Knex.QueryBuilder; + /** + * Maximum children per parent, or null for no child limit. + */ limit: number | null; + /** + * Children skipped per parent, or null for no offset. + */ offset: number | null; + /** + * Resolved child ordering, or null to leave child order unspecified. + */ orderBy: { column: string; direction: 'asc' | 'desc' } | null; + /** + * Optional child-field conversions applied after SQL returns. + */ mappers?: Record any) | string>; } +/** + * Discriminated normalized eager-relation specification used by row-mapping helpers. + */ export type ValidatedSpec = | ({ type: 'one' } & ValidatedJoinOneSpec) | ({ type: 'many' } & ValidatedJoinManySpec); @@ -190,6 +253,9 @@ export type ValidatedSpec = // --------------------------------------------------------------------------- // InsertType — all properties optional (DB may generate some, e.g. SERIAL id) // --------------------------------------------------------------------------- +/** + * Schema-shaped insert payload with optional properties so database-generated/defaulted values may be omitted. + */ export type InsertType< T extends ObjectSchemaBuilder > = InferType>; @@ -414,6 +480,9 @@ export type VariantStorageType = 'cti' | 'sti'; /** @internal Resolved form of a variant relation stored on {@link ResolvedVariantSpec}. */ export interface ResolvedVariantRelationSpec { + /** + * Physical column name reported by PostgreSQL. + */ name: string; type: 'hasMany' | 'hasOne' | 'belongsTo' | 'belongsToMany'; schema: any; @@ -477,42 +546,105 @@ export interface RelationSpec { /** Column information read from the database. */ export interface DatabaseColumnInfo { name: string; + /** + * Database type name used for schema comparison. + */ type: string; + /** + * Whether SQL NULL is accepted by this column. + */ nullable: boolean; + /** + * Database default expression, or null when no default is declared. + */ defaultValue: string | null; + /** + * Declared character limit, or null when the type has no such limit. + */ maxLength: number | null; + /** + * Declared numeric precision, or null when unavailable/not applicable. + */ numericPrecision: number | null; } /** Index information read from the database. */ export interface DatabaseIndexInfo { + /** + * Physical database index name. + */ name: string; + /** + * Indexed column names in database-reported order. + */ columns: string[]; + /** + * Whether this index enforces uniqueness. + */ unique: boolean; + /** + * Database-provided SQL definition of the index. + */ definition: string; } /** Foreign key information read from the database. */ export interface DatabaseForeignKeyInfo { + /** + * Physical foreign-key constraint name. + */ constraintName: string; + /** + * Referencing SQL column on the inspected table. + */ columnName: string; + /** + * Referenced table name. + */ foreignTable: string; + /** + * Referenced SQL column name. + */ foreignColumn: string; + /** + * Database ON DELETE action, such as CASCADE or NO ACTION. + */ deleteRule: string; + /** + * Database ON UPDATE action for referenced-key changes. + */ updateRule: string; } /** Check constraint information read from the database. */ export interface DatabaseCheckInfo { + /** + * Physical CHECK constraint name. + */ name: string; + /** + * Database-provided CHECK expression/definition. + */ definition: string; } /** Full database table state from introspection. */ export interface DatabaseTableState { + /** + * Column metadata keyed by physical SQL column name. + */ columns: Record; + /** + * Indexes discovered for the table. + */ indexes: DatabaseIndexInfo[]; + /** + * Foreign-key constraints discovered for the table. + */ foreignKeys: DatabaseForeignKeyInfo[]; + /** + * CHECK constraints discovered for the table. + */ checks: DatabaseCheckInfo[]; } @@ -530,6 +662,9 @@ export interface DatabaseTableState { * @public */ export interface SchemaSnapshot { + /** + * Snapshot format version; currently 1. + */ version: 1; /** Map of table name → database state derived from entity schemas. */ tables: Record; @@ -541,44 +676,116 @@ export interface SchemaSnapshot { /** A column to add in a migration. */ export interface AddColumnDiff { + /** + * Physical SQL name of the new column. + */ name: string; + /** + * SQL type to create, including any declared length/precision. + */ type: string; + /** + * Whether the new column permits SQL NULL. + */ nullable: boolean; + /** + * Optional default value or expression metadata for the new column. + */ defaultValue?: any; + /** + * Optional referenced table/column for a new foreign key. + */ references?: { table: string; column: string }; + /** + * Optional ON DELETE action for the reference. + */ onDelete?: string; + /** + * Optional ON UPDATE action for the reference. + */ onUpdate?: string; } /** Changes to apply to an existing column. */ export interface AlterColumnDiff { + /** + * Physical SQL name of the column to alter. + */ name: string; + /** + * Changed attributes with their previous and desired values. + */ changes: Record; } /** An index to add in a migration. */ export interface AddIndexDiff { + /** + * Physical column names forming the index, in order. + */ columns: string[]; + /** + * Optional explicit index name; otherwise migration generation chooses one. + */ name?: string; + /** + * Whether the new index must enforce uniqueness. + */ unique?: boolean; } /** A foreign key to add in a migration. */ export interface AddForeignKeyDiff { + /** + * Referencing SQL column on the table being altered. + */ column: string; + /** + * Referenced table name. + */ foreignTable: string; + /** + * Referenced SQL column name. + */ foreignColumn: string; + /** + * Optional ON DELETE action. + */ onDelete?: string; + /** + * Optional ON UPDATE action. + */ onUpdate?: string; } /** Schema diff result between the code-first model and the live database. */ export interface MigrationDiff { + /** + * New column definitions to create. + */ addColumns: AddColumnDiff[]; + /** + * Physical column names to remove; reviewing these avoids unintended data loss. + */ dropColumns: string[]; + /** + * Existing columns whose attributes must change. + */ alterColumns: AlterColumnDiff[]; + /** + * New indexes to create. + */ addIndexes: AddIndexDiff[]; + /** + * Physical index names to remove. + */ dropIndexes: string[]; + /** + * New foreign-key constraints to create. + */ addForeignKeys: AddForeignKeyDiff[]; + /** + * Physical foreign-key constraint names to remove. + */ dropForeignKeys: string[]; } diff --git a/libs/orm/src/dbcontext.ts b/libs/orm/src/dbcontext.ts index 1078aa1b..1ac50861 100644 --- a/libs/orm/src/dbcontext.ts +++ b/libs/orm/src/dbcontext.ts @@ -297,11 +297,19 @@ export function createDb( entities: TMap, opts: { tracking: true } ): TrackedDbContext; +/** + * Create a database context with a fresh typed query starter for each entity. + * @param knex - Database connection or transaction. + * @param entities - Named entity definitions exposed as context properties. + * @param opts - Enable tracking to add identity-map and explicit saveChanges() behavior. + * @returns A non-tracking context by default; the tracking overload adds unit-of-work APIs. + */ export function createDb( knex: Knex, entities: TMap, opts?: { tracking?: false | undefined } ): DbContext; +/** Create the tracking or non-tracking context selected by opts.tracking. */ export function createDb( knex: Knex, entities: TMap, diff --git a/libs/orm/src/dbset.ts b/libs/orm/src/dbset.ts index 8541a289..2369ce8d 100644 --- a/libs/orm/src/dbset.ts +++ b/libs/orm/src/dbset.ts @@ -23,6 +23,7 @@ import { type SchemaQueryBuilder, query as schemaQuery } from '@cleverbrush/knex-schema'; +import type { InferType } from '@cleverbrush/schema'; import type { Knex } from 'knex'; import { EntityNotFoundError } from './errors.js'; @@ -84,9 +85,7 @@ export interface EntityQuery, TResult> customize?: ( q: SchemaQueryBuilder< RelatedSchema, - import('@cleverbrush/schema').InferType< - RelatedSchema - > + InferType> > ) => void ): EntityQuery>; @@ -105,9 +104,7 @@ export interface EntityQuery, TResult> q: TRel extends keyof EntityRelations ? SchemaQueryBuilder< RelatedSchema, - import('@cleverbrush/schema').InferType< - RelatedSchema - > + InferType> > : SchemaQueryBuilder ) => void @@ -259,15 +256,33 @@ export interface VariantDbSet< > { // Re-declared so that `this` resolves to `VariantDbSet` // rather than the raw `SchemaQueryBuilder` (Omit doesn't preserve `this`). + /** + * Add an AND filter on this polymorphic branch using a mapped property, record or Knex callback. + */ where( column: ColumnRef>, operator: string, value: any ): this; + /** + * Add an AND filter on this polymorphic branch using a mapped property, record or Knex callback. + */ where(column: ColumnRef>, value: any): this; + /** + * Add an AND filter on this polymorphic branch using a mapped property, record or Knex callback. + */ where(raw: Knex.Raw, operator: string, value: any): this; + /** + * Add an AND filter on this polymorphic branch using a mapped property, record or Knex callback. + */ where(callback: (builder: Knex.QueryBuilder) => void): this; + /** + * Add an AND filter on this polymorphic branch using a mapped property, record or Knex callback. + */ where(record: Record): this; + /** + * Add an AND filter on this polymorphic branch using a mapped property, record or Knex callback. + */ where(raw: Knex.Raw): this; /** * Eager-load a relation declared on `TEntity`. Identical to @@ -278,9 +293,7 @@ export interface VariantDbSet< customize?: ( q: SchemaQueryBuilder< RelatedSchema, - import('@cleverbrush/schema').InferType< - RelatedSchema - > + InferType> > ) => void ): VariantDbSet; diff --git a/libs/orm/src/errors.ts b/libs/orm/src/errors.ts index 893d5f65..8307a051 100644 --- a/libs/orm/src/errors.ts +++ b/libs/orm/src/errors.ts @@ -9,9 +9,18 @@ * @public */ export class EntityNotFoundError extends Error { + /** + * Table/entity label identifying which lookup failed. + */ readonly entity: string; + /** + * Requested primary-key value, or ordered tuple for a composite key. + */ readonly pk: unknown; + /** + * Describe a failed entity lookup while retaining its entity label and requested key. + */ constructor(entity: string, pk: unknown) { super( `Entity "${entity}" not found for primary key ${JSON.stringify(pk)}` @@ -37,6 +46,9 @@ export class ConcurrencyError extends Error { /** The row-version value the ORM expected. */ readonly expected: unknown; + /** + * Describe an optimistic-concurrency failure with the key and row-version value expected by the caller. + */ constructor(entity: string, pk: unknown, expected: unknown) { super( `Concurrency conflict on "${entity}" (pk=${JSON.stringify(pk)}): ` + @@ -57,10 +69,22 @@ export class ConcurrencyError extends Error { * @public */ export class InvariantViolationError extends Error { + /** + * Table/entity label whose tracked identity invariant was violated. + */ readonly entity: string; + /** + * Primary-key value(s) identifying the affected tracked entity. + */ readonly pk: unknown; + /** + * Immutable identity/discriminator property that was changed. + */ readonly field: string; + /** + * Describe an invalid tracked identity change, preserving its entity, key and field for diagnostics. + */ constructor(entity: string, pk: unknown, field: string, detail: string) { super( `Invariant violation on "${entity}" (pk=${JSON.stringify(pk)}): ${detail}` @@ -85,6 +109,9 @@ export class PendingChangesError extends Error { /** Number of dirty / added / deleted entries. */ readonly pendingCount: number; + /** + * Describe disposal with unsaved changes; pendingCount is the number of dirty entries and summary explains them. + */ constructor(pendingCount: number, summary: string) { super( `DbContext disposed with ${pendingCount} pending change(s). ` + diff --git a/libs/orm/src/query-types.test-d.ts b/libs/orm/src/query-types.test-d.ts index e4926c7e..a52747f4 100644 --- a/libs/orm/src/query-types.test-d.ts +++ b/libs/orm/src/query-types.test-d.ts @@ -1,6 +1,17 @@ import Knex from 'knex'; import { expectTypeOf, test } from 'vitest'; -import { createDb, defineEntity, number, object, string } from './index.js'; +import { + alias, + createDb, + createQuery, + defineEntity, + eq, + isSqlIdentifier, + number, + object, + query, + string +} from './index.js'; const User = object({ id: number().primaryKey(), name: string() }).hasTableName( 'users' @@ -34,3 +45,18 @@ test('new terminal helpers propagate through ORM', async () => { await db.tasks.countValue({ output: string() }) ).toEqualTypeOf(); }); + +test('ORM re-exports retain typed factories and identifier narrowing', async () => { + const knex = Knex({ client: 'pg' }); + const bound = createQuery(knex); + expectTypeOf(query(knex, Task)).not.toBeAny(); + expectTypeOf( + await bound(alias(Task, 'task')) + .leftJoin(alias(User, 'owner'), t => eq(t.task.ownerId, t.owner.id)) + .select(t => ({ id: t.task.id, ownerName: t.owner.name })) + ).toEqualTypeOf<{ id: number; ownerName: string | null }[]>(); + // @ts-expect-error The ORM re-export must still reject unknown columns. + query(knex, Task).select(t => ({ missing: t.missing })); + const name: unknown = 'tasks'; + if (isSqlIdentifier(name)) expectTypeOf(name).toEqualTypeOf(); +}); From f9b1f564ad949a81a8407fd90ecc14d497bb445d Mon Sep 17 00:00:00 2001 From: Andrew Zolotukhin Date: Mon, 28 Sep 2026 20:23:01 +0000 Subject: [PATCH 04/41] feat(schema): compose typed schemas across boundaries --- .changeset/schema-boundaries.md | 12 + libs/knex-schema/src/entity.ts | 32 +- libs/schema-json/README.md | 11 + libs/schema-json/src/boundaries.test.ts | 108 ++++ libs/schema-json/src/standardJsonSchema.ts | 25 +- libs/schema-json/src/toJsonSchema.ts | 85 ++- libs/schema-json/src/types.ts | 2 + libs/schema/BOUNDARIES.md | 151 +++++ libs/schema/README.md | 9 + libs/schema/package.json | 3 +- libs/schema/src/boundaries-docs.test.ts | 62 ++ .../schema/src/builders/ArraySchemaBuilder.ts | 8 +- .../builders/BoundarySchemaBuilder.test.ts | 167 ++++++ .../src/builders/BoundarySchemaBuilder.ts | 528 ++++++++++++++++++ .../src/builders/ExternSchemaBuilder.ts | 3 +- .../src/builders/IntersectionSchemaBuilder.ts | 4 +- libs/schema/src/builders/LazySchemaBuilder.ts | 48 +- .../src/builders/ObjectSchemaBuilder.ts | 49 +- .../src/builders/RecordSchemaBuilder.ts | 4 +- libs/schema/src/builders/SchemaBuilder.ts | 205 ++++--- .../schema/src/builders/TupleSchemaBuilder.ts | 9 +- .../schema/src/builders/UnionSchemaBuilder.ts | 4 +- libs/schema/src/builders/boundaries.test-d.ts | 102 ++++ libs/schema/src/core.ts | 7 + libs/schema/tsconfig.build.json | 2 +- libs/schema/tsconfig.typecheck.json | 6 + libs/schema/vitest.config.mts | 12 + libs/server-openapi/README.md | 12 + libs/server-openapi/src/boundaries.test.ts | 102 ++++ .../src/generateAsyncApiSpec.ts | 17 +- .../server-openapi/src/generateOpenApiSpec.ts | 41 +- libs/server-openapi/src/schemaConverter.ts | 9 +- libs/server-openapi/src/schemaRegistry.ts | 103 +++- websites/docs/app/server-openapi/page.tsx | 13 + websites/schema/app/docs/[[...slug]]/page.tsx | 2 + websites/schema/app/docs/sections/index.ts | 6 + .../app/docs/sections/schema-boundaries.tsx | 87 +++ websites/schema/app/schema-json/page.tsx | 13 + 38 files changed, 1871 insertions(+), 192 deletions(-) create mode 100644 .changeset/schema-boundaries.md create mode 100644 libs/schema-json/src/boundaries.test.ts create mode 100644 libs/schema/BOUNDARIES.md create mode 100644 libs/schema/src/boundaries-docs.test.ts create mode 100644 libs/schema/src/builders/BoundarySchemaBuilder.test.ts create mode 100644 libs/schema/src/builders/BoundarySchemaBuilder.ts create mode 100644 libs/schema/src/builders/boundaries.test-d.ts create mode 100644 libs/schema/tsconfig.typecheck.json create mode 100644 libs/schema/vitest.config.mts create mode 100644 libs/server-openapi/src/boundaries.test.ts create mode 100644 websites/schema/app/docs/sections/schema-boundaries.tsx diff --git a/.changeset/schema-boundaries.md b/.changeset/schema-boundaries.md new file mode 100644 index 00000000..e5c45af5 --- /dev/null +++ b/.changeset/schema-boundaries.md @@ -0,0 +1,12 @@ +--- +"@cleverbrush/schema": minor +"@cleverbrush/schema-json": minor +"@cleverbrush/server-openapi": minor +"@cleverbrush/knex-schema": minor +--- + +Add optional-aware fallbacks and preprocessing, immutable named schema references, +and typed input/output decoding with nested inference and Standard Schema support. +Generate directional JSON Schema/OpenAPI components with strict name collision +checks. Preserve existing InferType output semantics and legacy optional null +acceptance. Keep ORM navigation inference compatible with the richer schema types. diff --git a/libs/knex-schema/src/entity.ts b/libs/knex-schema/src/entity.ts index 93ff5896..4fbb5254 100644 --- a/libs/knex-schema/src/entity.ts +++ b/libs/knex-schema/src/entity.ts @@ -9,7 +9,6 @@ // extension (compatible with the existing query/include implementation). import { - type ArraySchemaBuilder, type InferType, ObjectSchemaBuilder, type PropertyDescriptorTree, @@ -129,18 +128,27 @@ export type EntityPropSelector< * * @public */ -export type UnwrapNavSchema = - TProp extends ArraySchemaBuilder - ? TEl extends ObjectSchemaBuilder - ? TEl +export type UnwrapNavSchema = TProp extends { + introspect(): { elementSchema: infer TEl }; +} + ? NonNullable extends ObjectSchemaBuilder< + any, + any, + any, + any, + any, + any, + any + > + ? NonNullable + : never + : TProp extends ObjectSchemaBuilder + ? TProp + : TProp extends SchemaBuilder + ? T extends ObjectSchemaBuilder + ? T : never - : TProp extends ObjectSchemaBuilder - ? TProp - : TProp extends SchemaBuilder - ? T extends ObjectSchemaBuilder - ? T - : never - : never; + : never; /** * Merge type for a single polymorphic variant branch: variant schema fields diff --git a/libs/schema-json/README.md b/libs/schema-json/README.md index 97bb3743..dacf6292 100644 --- a/libs/schema-json/README.md +++ b/libs/schema-json/README.md @@ -12,6 +12,17 @@ for use in OpenAPI specs, form generators, or any other JSON Schema consumer. ## When to use this library +### Input and output views + +`toJsonSchema(schema, { mode: 'input' })` describes input before decoding/defaults; +`mode: 'output'` (the default) describes validated output. +`withStandardJsonSchema(schema)` exposes the same distinction through +`jsonSchema.input()` and `jsonSchema.output()`. Converters are never executed. +Their arbitrary logic is not representable in JSON Schema. + +Named reference wrappers preserve use-site annotations, optionality and nullability +without changing the shared definition. See the [composition guide](../schema/BOUNDARIES.md). + - **Consuming external APIs** — you have a JSON Schema from an OpenAPI spec or a third-party service and want to validate incoming data with full TypeScript type inference. diff --git a/libs/schema-json/src/boundaries.test.ts b/libs/schema-json/src/boundaries.test.ts new file mode 100644 index 00000000..404978f9 --- /dev/null +++ b/libs/schema-json/src/boundaries.test.ts @@ -0,0 +1,108 @@ +import { + array, + decode, + lazy, + number, + object, + record, + schemaRef, + string, + tuple, + union +} from '@cleverbrush/schema'; +import { describe, expect, it, vi } from 'vitest'; +import { withStandardJsonSchema } from './standardJsonSchema.js'; +import { toJsonSchema } from './toJsonSchema.js'; + +describe('boundary JSON Schema views', () => { + it('does not transfer output nullability or output defaults to input', () => { + const schema = decode(string(), number().nullable(), () => null); + expect(toJsonSchema(schema, { $schema: false, mode: 'input' })).toEqual( + { allOf: [{ type: 'string' }] } + ); + expect(toJsonSchema(schema, { $schema: false }).allOf).toEqual([ + { type: ['integer', 'null'] } + ]); + const withDefault = decode(string(), number(), Number).default(3); + expect( + toJsonSchema(withDefault, { mode: 'input' }).default + ).toBeUndefined(); + expect(toJsonSchema(withDefault).default).toBe(3); + }); + it('exports declared input/output without running converters', () => { + const converter = vi.fn(Number); + const size = decode( + string().minLength(1), + number().isInteger().min(1), + converter + ); + expect(toJsonSchema(size, { $schema: false, mode: 'input' })).toEqual({ + allOf: [{ type: 'string', minLength: 1 }] + }); + expect(toJsonSchema(size, { $schema: false })).toEqual({ + allOf: [{ type: 'integer', minimum: 1 }] + }); + const standard = withStandardJsonSchema(size)['~standard'].jsonSchema; + expect(standard.input({ target: 'draft-2020-12' })).not.toEqual( + standard.output({ target: 'draft-2020-12' }) + ); + expect(converter).not.toHaveBeenCalled(); + }); + + it('tracks input defaults separately from required output', () => { + const size = decode(string().default('1'), number(), Number); + const schema = object({ size, title: string().default('new') }); + expect( + toJsonSchema(schema, { mode: 'input' }).required + ).toBeUndefined(); + expect(toJsonSchema(schema).required).toEqual(['size', 'title']); + }); + + it.each([ + '2020-12', + '07' + ] as const)('keeps ref annotations outside the definition in draft %s', draft => { + const user = object({ name: string() }).schemaName('User'); + const schema = object({ + user: schemaRef(user), + previous: schemaRef(user) + .nullable() + .optional() + .describe('Previous user') + .example(null) + }); + const json = toJsonSchema(schema, { + draft, + $schema: false, + nameResolver: s => (s === user ? 'User' : null) + }) as any; + expect(json.required).toEqual(['user']); + expect(json.properties.user).toEqual({ + allOf: [{ $ref: '#/components/schemas/User' }] + }); + expect(json.properties.previous).toMatchObject({ + description: 'Previous user', + examples: [null], + anyOf: [ + { allOf: [{ $ref: '#/components/schemas/User' }] }, + { type: 'null' } + ] + }); + expect(user.introspect().description).toBeUndefined(); + }); + + it('projects nested containers and lazy wrappers', () => { + const size = decode(string(), number(), Number); + const schema = object({ + list: array(size), + pair: tuple([size]), + values: record(string(), size), + option: union(size).or(string()), + later: lazy(() => size) + }); + const input = JSON.stringify(toJsonSchema(schema, { mode: 'input' })); + const output = JSON.stringify(toJsonSchema(schema)); + expect(input).not.toContain('"type":"integer"'); + expect(output).toContain('"type":"integer"'); + }); +}); diff --git a/libs/schema-json/src/standardJsonSchema.ts b/libs/schema-json/src/standardJsonSchema.ts index b5e41e18..fb3ddc74 100644 --- a/libs/schema-json/src/standardJsonSchema.ts +++ b/libs/schema-json/src/standardJsonSchema.ts @@ -1,4 +1,8 @@ -import type { SchemaBuilder } from '@cleverbrush/schema'; +import type { + InferInput, + InferOutput, + SchemaBuilder +} from '@cleverbrush/schema'; import type { StandardJSONSchemaV1 } from '@standard-schema/spec'; import { toJsonSchema } from './toJsonSchema.js'; @@ -31,9 +35,8 @@ function targetToOptions(target: StandardJSONSchemaV1.Target): { * [Standard JSON Schema v1](https://standardschema.dev/) interface. * * The returned schema object's `~standard` property is enriched with a - * `jsonSchema` converter. Because `@cleverbrush/schema` does not - * distinguish between input and output types, both `input()` and `output()` - * produce the same JSON Schema document. + * `jsonSchema` converter. Input describes values before decoding/defaults; + * output describes validated values. Converter functions are never executed. * * **Note:** this mutates the schema instance by overriding the `~standard` * property. The returned reference is the same schema object. @@ -56,13 +59,19 @@ function targetToOptions(target: StandardJSONSchemaV1.Target): { */ export function withStandardJsonSchema< T extends SchemaBuilder ->(schema: T): T & StandardJSONSchemaV1 { +>(schema: T): T & StandardJSONSchemaV1, InferOutput> { const converter: StandardJSONSchemaV1.Converter = { input(options: StandardJSONSchemaV1.Options): Record { - return toJsonSchema(schema, targetToOptions(options.target)); + return toJsonSchema(schema, { + ...targetToOptions(options.target), + mode: 'input' + }); }, output(options: StandardJSONSchemaV1.Options): Record { - return toJsonSchema(schema, targetToOptions(options.target)); + return toJsonSchema(schema, { + ...targetToOptions(options.target), + mode: 'output' + }); } }; @@ -85,5 +94,5 @@ export function withStandardJsonSchema< enumerable: false }); - return schema as T & StandardJSONSchemaV1; + return schema as T & StandardJSONSchemaV1, InferOutput>; } diff --git a/libs/schema-json/src/toJsonSchema.ts b/libs/schema-json/src/toJsonSchema.ts index a322e59b..fdb460b8 100644 --- a/libs/schema-json/src/toJsonSchema.ts +++ b/libs/schema-json/src/toJsonSchema.ts @@ -11,19 +11,56 @@ function escapeJsonPointerSegment(s: string): string { return s.replace(/~/g, '~0').replace(/\//g, '~1'); } +/** Whether a property must be present on the selected side of a boundary. */ +function isRequiredInMode( + schema: SchemaBuilder, + mode: 'input' | 'output' +): boolean { + const info = schema.introspect() as any; + if (mode === 'input' && info.hasDefault) return false; + if (info.type === 'decode' || info.type === 'reference') { + if (info.presence !== undefined) return info.presence; + return isRequiredInMode( + mode === 'input' ? info.inputSchema : info.outputSchema, + mode + ); + } + return info.isRequired !== false; +} + type Resolver = | ((schema: SchemaBuilder) => string | null) | undefined; function convertNodeInner( schema: SchemaBuilder, - resolver: Resolver + resolver: Resolver, + mode: 'input' | 'output' ): Out { const info = schema.introspect() as any; const ext: Record = info.extensions ?? {}; const readOnly: Out = info.isReadonly === true ? { readOnly: true } : {}; switch (info.type) { + case 'reference': + case 'decode': { + const target = + mode === 'input' ? info.inputSchema : info.outputSchema; + const out: Out = { allOf: [convertNode(target, resolver, mode)] }; + if (info.nullability === false) + (out.allOf as Out[]).push({ not: { type: 'null' } }); + return out; + } + case 'record': + return { + type: 'object', + propertyNames: convertNode(info.keySchema, resolver, mode), + additionalProperties: convertNode( + info.valueSchema, + resolver, + mode + ) + }; case 'string': { if (info.equalsTo !== undefined) return { ...readOnly, const: info.equalsTo }; @@ -95,7 +132,7 @@ function convertNodeInner( case 'array': { const out: Out = { ...readOnly, type: 'array' }; if (info.elementSchema) - out['items'] = convertNode(info.elementSchema, resolver); + out['items'] = convertNode(info.elementSchema, resolver, mode); if (info.minLength !== undefined) out['minItems'] = info.minLength; if (info.maxLength !== undefined) out['maxItems'] = info.maxLength; if (ext['nonempty'] === true && out['minItems'] === undefined) @@ -108,11 +145,11 @@ function convertNodeInner( info.elements ?? []; const out: Out = { type: 'array', - prefixItems: elements.map(e => convertNode(e, resolver)), + prefixItems: elements.map(e => convertNode(e, resolver, mode)), minItems: elements.length }; if (info.restSchema) { - out['items'] = convertNode(info.restSchema, resolver); + out['items'] = convertNode(info.restSchema, resolver, mode); } else { out['items'] = false; out['maxItems'] = elements.length; @@ -129,9 +166,8 @@ function convertNodeInner( const outProps: Record = {}; const required: string[] = []; for (const [key, propSchema] of Object.entries(props)) { - outProps[key] = convertNode(propSchema, resolver); - if ((propSchema.introspect() as any).isRequired !== false) - required.push(key); + outProps[key] = convertNode(propSchema, resolver, mode); + if (isRequiredInMode(propSchema, mode)) required.push(key); } out['properties'] = outProps; if (required.length > 0) out['required'] = required; @@ -164,7 +200,7 @@ function convertNodeInner( } if (allConst) return { ...readOnly, enum: enumValues }; - const converted = options.map(o => convertNode(o, resolver)); + const converted = options.map(o => convertNode(o, resolver, mode)); const out: Out = { ...readOnly, anyOf: converted @@ -217,8 +253,8 @@ function convertNodeInner( return { ...readOnly, allOf: [ - convertNode(left, resolver), - convertNode(right, resolver) + convertNode(left, resolver, mode), + convertNode(right, resolver, mode) ] }; } @@ -230,7 +266,7 @@ function convertNodeInner( // Recursive schemas without a registered name will cause infinite // recursion here; callers must use .schemaName() to break the cycle. const resolved: SchemaBuilder = info.getter(); - return convertNode(resolved, resolver); + return convertNode(resolved, resolver, mode); } default: @@ -240,7 +276,8 @@ function convertNodeInner( function convertNode( schema: SchemaBuilder, - resolver: Resolver + resolver: Resolver, + mode: 'input' | 'output' ): Out { if (resolver) { const name = resolver(schema); @@ -250,7 +287,7 @@ function convertNode( }; } } - const out = convertNodeInner(schema, resolver); + const out = convertNodeInner(schema, resolver, mode); const info = schema.introspect() as any; if (typeof info.description === 'string' && info.description !== '') out['description'] = info.description; @@ -263,6 +300,10 @@ function convertNode( // Emit default for serializable primitives (not factory functions) if ( info.hasDefault === true && + !( + mode === 'input' && + (info.type === 'decode' || info.type === 'reference') + ) && info.defaultValue !== undefined && typeof info.defaultValue !== 'function' ) { @@ -270,7 +311,11 @@ function convertNode( } // Handle nullable — JSON Schema 2020-12 style: type becomes an array - if (info.isNullable === true) { + if ( + info.type === 'reference' || info.type === 'decode' + ? info.nullability === true + : info.isNullable === true + ) { if (out['anyOf'] !== undefined) { // Union type — add { type: 'null' } to anyOf if not already present const anyOf = out['anyOf'] as Out[]; @@ -278,7 +323,11 @@ function convertNode( if (!hasNull) anyOf.push({ type: 'null' }); } else if (out['allOf'] !== undefined && out['type'] === undefined) { // Intersection type without a top-level type — wrap in oneOf with null - out['oneOf'] = [{ allOf: out['allOf'] as Out[] }, { type: 'null' }]; + out[ + info.type === 'reference' || info.type === 'decode' + ? 'anyOf' + : 'oneOf' + ] = [{ allOf: out['allOf'] as Out[] }, { type: 'null' }]; delete out['allOf']; } else if (out['enum'] !== undefined) { // Enum — add null to enum values if not already present @@ -362,7 +411,11 @@ export function toJsonSchema( schema: SchemaBuilder, opts?: ToJsonSchemaOptions ): Record { - const body = convertNode(schema, opts?.nameResolver); + const body = convertNode( + schema, + opts?.nameResolver, + opts?.mode ?? 'output' + ); if (opts?.$schema === false) return body; const draft = opts?.draft ?? '2020-12'; const uri = diff --git a/libs/schema-json/src/types.ts b/libs/schema-json/src/types.ts index 089b9748..afb1f950 100644 --- a/libs/schema-json/src/types.ts +++ b/libs/schema-json/src/types.ts @@ -137,6 +137,8 @@ export type InferFromJsonSchema = S extends { readonly const: infer V } /** Options accepted by {@link toJsonSchema}. */ export type ToJsonSchemaOptions = { + /** Declared input before decoding/defaults, or validated output. @default 'output' */ + mode?: 'input' | 'output'; /** * JSON Schema draft version to reference in the `$schema` header. * @default '2020-12' diff --git a/libs/schema/BOUNDARIES.md b/libs/schema/BOUNDARIES.md new file mode 100644 index 00000000..589b6544 --- /dev/null +++ b/libs/schema/BOUNDARIES.md @@ -0,0 +1,151 @@ +# Schemas across boundaries + +These APIs are additive. `InferType` continues to mean validated output; +existing builder generic arguments and legacy preprocessors keep their meaning. + +## Optional fallbacks + +Before, consumers needed a separate safeParse helper for each optional scalar. +Now a fallback can use the optional or nullable schema's full output type: + +```ts +import { boolean, object, string } from '@cleverbrush/schema'; + +const optionalText = string().optional().catch(undefined); +const ExternalRecord = object({ + name: optionalText, + enabled: boolean().optional().catch(() => undefined) +}); +ExternalRecord.parse({ name: 42, enabled: 'unknown' }); +// { name: undefined, enabled: undefined } +``` + +Fallbacks are opt-in. A malformed required root object still fails. Arrays do +not silently discard invalid elements. A fallback factory runs only on failure. + +**Compatibility limitation:** legacy optional schemas also accept `null` at +runtime, even though their inferred type does not include it. This release does +not change that behavior. Consequently, `.optional().catch(undefined)` leaves +`null` unchanged. Normalize it explicitly when the application requires this: + +```ts +const normalizedText = string().optional() + .addPreprocessor(value => value == null ? undefined : value) + .catch(undefined); +``` + +Preprocessors can return optional/nullable values, including asynchronously. +Their existing callback parameter typing is preserved; it is not a guarantee +that unknown runtime input already has that type. Use explicit guards or +`decode` at untrusted boundaries. Global strict null rejection is a separate, +compatibility-sensitive follow-up. + +## One named definition, many annotated references + +Before, cloning `User.schemaName('User')` with `.optional()` created another +named instance and conflicted during OpenAPI generation. + +```ts +import { number, object, schemaRef, string } from '@cleverbrush/schema'; + +const User = object({ id: number(), name: string() }).schemaName('User'); +const History = object({ + current: schemaRef(User), + previous: schemaRef(User).nullable().optional() + .describe('The previous user, when known.') +}); +``` + +`schemaRef` requires a named target. Its local modifiers do not rename, clone, +or mutate that target. References delegate validation and preserve nested +property selectors/errors. Independent schemas sharing a name still conflict; +there is no name-only deduplication. Use-site optionality controls omission; +nullability controls null acceptance for the wrapper independently. + +JSON Schema/OpenAPI keeps one definition and uses reference composition for +local annotations, examples and nullability, including Draft 07 references. + +## Declare both sides of a conversion + +```ts +import { decode, type InferInput, type InferOutput, number, object, string } + from '@cleverbrush/schema'; + +const PageSize = decode( + string(), + number().isInteger().min(1).max(100), + value => Number(value) +); +const SearchInput = object({ + pageSize: PageSize, + term: string().default('') +}); + +type Editable = InferInput; // pageSize is string +type Validated = InferOutput; // pageSize is number +const request = SearchInput.parse({ pageSize: '20' }); +``` + +Parsing validates the input, invokes the converter once, then validates its +output. Converter exceptions/rejections become validation failures. Asynchronous +converters require `parseAsync`/`validateAsync`; synchronous parsing rejects +Promise-returning conversion. Runtime parsing always validates unknown values. + +Nested objects, arrays, tuples, records, unions, intersections, references and +lazy schemas retain input/output inference. Recursive schemas still require +explicit TypeScript annotations. Standard Schema exposes the corresponding +input/output types. `InferOutput` is an alias for `InferType`. + +An input-schema default runs before conversion. A default on the boundary itself +is an **output** default, validated without conversion. Optional/nullable +use-site modifiers bypass conversion for their allowed sentinel values. + +### Application-agnostic example + +```ts +const Priority = decode( + string().oneOf('low', 'normal', 'high'), + number().min(1).max(3), + value => ({ low: 1, normal: 2, high: 3 })[value] +); +const Ticket = object({ title: string().minLength(1), priority: Priority }); +Ticket.parse({ title: 'Improve documentation', priority: 'high' }); +// { title: 'Improve documentation', priority: 3 } +``` + +Conversion policy remains application-owned: trimming, empty strings, numeric +precision, date formats and intentional data loss are not global defaults. + +## JSON Schema and OpenAPI + +```ts +import { toJsonSchema, withStandardJsonSchema } from '@cleverbrush/schema-json'; + +toJsonSchema(PageSize, { mode: 'input' }); // declared string shape +toJsonSchema(PageSize, { mode: 'output' }); // constrained numeric shape +toJsonSchema(PageSize); // output remains the default + +const standard = withStandardJsonSchema(PageSize)['~standard']; +standard.jsonSchema.input({ target: 'draft-2020-12' }); +standard.jsonSchema.output({ target: 'draft-2020-12' }); +``` + +Converters are never executed by schema export. JSON Schema describes the +declared shapes, not arbitrary converter logic or opaque custom validators. + +OpenAPI uses input views for requests and output views for responses. Named +schemas with different views receive `NameInput` and `NameOutput` components; +unchanged views retain their original name. Generated-name collisions throw, +including collisions propagated through nested named or recursive references. +AsyncAPI incoming/outgoing payloads use the same directional model. + +## Adoption boundary + +This release does **not** redesign React form state or typed HTTP client request +inference. Those consumers may still assume input equals output. Do not treat a +decoder as a drop-in shared form/endpoint contract for those APIs. + +Until that adoption, keep an explicit wire schema in shared contracts and decode +inside the application boundary/handler, then return the validated output DTO. +A decoder is not an encoder: no reverse conversion is inferred for requests, +URLs, response serialization, database writes or editable form state. diff --git a/libs/schema/README.md b/libs/schema/README.md index 0fc779c0..f925db2a 100644 --- a/libs/schema/README.md +++ b/libs/schema/README.md @@ -1,5 +1,14 @@ # @cleverbrush/schema +## Schemas across boundaries + +Use optional-aware `catch(undefined)`, `schemaRef(namedSchema)` for per-use +annotations, and `decode(inputSchema, outputSchema, converter)` for explicit +conversion. `InferInput` describes editable input; `InferOutput` and the existing +`InferType` describe validated output. See the [boundary composition guide](./BOUNDARIES.md) +for examples, null-compatibility limitations, and the separate form/client +adoption boundary. + [![CI](https://github.com/cleverbrush/framework/actions/workflows/ci.yml/badge.svg)](https://github.com/cleverbrush/framework/actions/workflows/ci.yml) [![Standard Schema v1](https://img.shields.io/badge/Standard%20Schema-v1-blue)](https://standardschema.dev/) diff --git a/libs/schema/package.json b/libs/schema/package.json index c89f8fcc..dce29b43 100644 --- a/libs/schema/package.json +++ b/libs/schema/package.json @@ -6,7 +6,8 @@ }, "description": "Schema Definition And Validation library, that allows to define and validate objects of any complexity", "files": [ - "dist" + "dist", + "BOUNDARIES.md" ], "homepage": "https://schema.cleverbrush.com/docs/getting-started", "keywords": [ diff --git a/libs/schema/src/boundaries-docs.test.ts b/libs/schema/src/boundaries-docs.test.ts new file mode 100644 index 00000000..be8378e4 --- /dev/null +++ b/libs/schema/src/boundaries-docs.test.ts @@ -0,0 +1,62 @@ +import { readFileSync } from 'node:fs'; +import ts from 'typescript'; +import { describe, expect, it } from 'vitest'; + +describe('published boundary documentation', () => { + it('preserves summaries for new APIs, types and public boundary members', () => { + const missing: string[] = []; + for (const [path, names] of [ + [ + '../dist/builders/BoundarySchemaBuilder.d.ts', + ['BoundarySchemaBuilder', 'schemaRef', 'decode'] + ], + [ + '../dist/builders/SchemaBuilder.d.ts', + ['InferInput', 'InferOutput'] + ], + ['../../schema-json/dist/types.d.ts', ['ToJsonSchemaOptions']] + ] as const) { + const text = readFileSync(new URL(path, import.meta.url), 'utf8'); + const source = ts.createSourceFile( + path, + text, + ts.ScriptTarget.Latest, + true + ); + const hasSummary = (node: ts.Node) => + (node as ts.Node & { jsDoc?: readonly ts.JSDoc[] }).jsDoc?.some( + doc => doc.comment + ); + for (const node of source.statements) { + const name = + 'name' in node && node.name + ? (node.name as ts.Identifier).text + : ''; + if (!(names as readonly string[]).includes(name)) continue; + if (!hasSummary(node)) missing.push(name); + if (ts.isClassDeclaration(node)) + for (const member of node.members) { + if ( + ts.getCombinedModifierFlags(member) & + (ts.ModifierFlags.Private | + ts.ModifierFlags.Protected) + ) + continue; + if (member.name && ts.isPrivateIdentifier(member.name)) + continue; + if ( + ts + .getJSDocTags(member) + .some(tag => tag.tagName.text === 'internal') + ) + continue; + if (!hasSummary(member)) + missing.push( + name + '.' + member.name?.getText(source) + ); + } + } + } + expect(missing).toEqual([]); + }); +}); diff --git a/libs/schema/src/builders/ArraySchemaBuilder.ts b/libs/schema/src/builders/ArraySchemaBuilder.ts index a044538b..bcbd575f 100644 --- a/libs/schema/src/builders/ArraySchemaBuilder.ts +++ b/libs/schema/src/builders/ArraySchemaBuilder.ts @@ -5,6 +5,7 @@ import type { import { type BRAND, createHybridErrorArray, + type InferInput, type InferType, type NestedValidationResult, type PropertyDescriptor, @@ -101,8 +102,8 @@ export class ArraySchemaBuilder< TResult = TExplicitType extends undefined ? TElementSchema extends undefined ? Array - : TElementSchema extends SchemaBuilder - ? Array>> + : TElementSchema extends SchemaBuilder + ? Array> : never : TExplicitType > extends SchemaBuilder< @@ -110,7 +111,8 @@ export class ArraySchemaBuilder< TRequired, TNullable, THasDefault, - TExtensions + TExtensions, + Array> > { #minLength?: number; #defaultMinLengthErrorMessageProvider: ValidationErrorMessageProvider< diff --git a/libs/schema/src/builders/BoundarySchemaBuilder.test.ts b/libs/schema/src/builders/BoundarySchemaBuilder.test.ts new file mode 100644 index 00000000..b78c1b60 --- /dev/null +++ b/libs/schema/src/builders/BoundarySchemaBuilder.test.ts @@ -0,0 +1,167 @@ +import { describe, expect, it, vi } from 'vitest'; +import { + array, + boolean, + decode, + number, + object, + schemaRef, + string +} from '../index.js'; + +describe('schema boundaries', () => { + it('accepts optional/nullable fallbacks and preserves legacy null acceptance', async () => { + const text = string().optional().catch(undefined); + expect(text.parse(42)).toBeUndefined(); + expect(await text.parseAsync(false)).toBeUndefined(); + expect(text.parse(null)).toBeNull(); + expect(string().nullable().catch(null).parse(42)).toBeNull(); + const normalize = string() + .optional() + .addPreprocessor(v => (v == null ? undefined : v)) + .catch(undefined); + expect(normalize.parse(null)).toBeUndefined(); + expect(object({ text }).safeParse(null).valid).toBe(false); + expect( + object({ + text, + flag: boolean() + .optional() + .catch(() => undefined) + }).parse({ text: {}, flag: 1 }) + ).toEqual({ text: undefined, flag: undefined }); + }); + + it('validates both sides and converts once', () => { + const convert = vi.fn(Number); + const size = decode( + string(), + number().isInteger().min(1).max(100), + convert + ); + expect(size.parse('12')).toBe(12); + expect(convert).toHaveBeenCalledTimes(1); + expect(size.safeParse(12).valid).toBe(false); + expect(convert).toHaveBeenCalledTimes(1); + expect(size.safeParse('0').valid).toBe(false); + expect(size.safeParse('nope').valid).toBe(false); + expect(object({ size }).parse({ size: '5' })).toEqual({ size: 5 }); + expect(array(size).parse(['2', '3'])).toEqual([2, 3]); + }); + + it('supports async conversion and captures converter failures', async () => { + const size = decode(string(), number(), async value => Number(value)); + expect(() => size.parse('1')).toThrow(/parseAsync/); + expect(await size.parseAsync('2')).toBe(2); + expect(await size['~standard'].validate('3')).toEqual({ value: 3 }); + const broken = decode(string(), number(), () => { + throw new Error('not convertible'); + }); + expect(broken.safeParse('x')).toMatchObject({ + valid: false, + errors: [{ message: 'Decoder failed: not convertible' }] + }); + const rejected = decode(string(), number(), async () => { + throw new Error('rejected'); + }); + expect((await rejected.safeParseAsync('x')).valid).toBe(false); + }); + + it('handles input defaults, output defaults and use-site modifiers', () => { + const size = decode(string().default('2'), number(), Number); + expect(size.parse(undefined)).toBe(2); + expect(size.optional().parse(undefined)).toBeUndefined(); + expect(size.nullable().parse(null)).toBeNull(); + expect(size.default(4).parse(undefined)).toBe(4); + expect(size.default(4).clearDefault().parse(undefined)).toBe(2); + expect(size.optional().required().safeParse(undefined).valid).toBe( + false + ); + }); + + it('preserves one named definition and local metadata', () => { + const user = object({ name: string().minLength(1) }).schemaName('User'); + const ref = schemaRef(user); + const previous = ref.nullable().optional().describe('Previous user'); + expect(ref.introspect().outputSchema).toBe(user); + expect(previous.introspect().outputSchema).toBe(user); + expect(user.introspect().description).toBeUndefined(); + expect(ref.safeParse(null).valid).toBe(false); + expect(previous.parse(null)).toBeNull(); + expect(previous.parse(undefined)).toBeUndefined(); + expect(previous.parse({ name: 'Ada' })).toEqual({ name: 'Ada' }); + expect(() => schemaRef(string())).toThrow(/named schema/); + }); + + it('preserves nested reference errors and selectors', () => { + const user = object({ name: string().minLength(1) }).schemaName('User'); + const result = object({ user: schemaRef(user) }).validate({ + user: { name: '' } + }); + expect(result.valid).toBe(false); + expect( + result.getErrorsFor(t => t.user.name).errors.length + ).toBeGreaterThan(0); + expect( + result.getInvalidProperties().map(p => p.descriptor.toJsonPointer()) + ).toContain('/user/name'); + }); +}); + +describe('decoding boundary edge cases', () => { + it('uses output defaults and never re-runs conversion for catch', async () => { + const convert = vi.fn(() => undefined); + const schema = decode(string(), number().default(8), convert); + expect(schema.parse('missing')).toBe(8); + expect(convert).toHaveBeenCalledTimes(1); + const fail = vi.fn(() => { + throw new Error('conversion'); + }); + const fallback = decode(string(), number(), fail).catch(() => 4); + expect(fallback.parse('x')).toBe(4); + expect(await fallback.parseAsync('y')).toBe(4); + expect(fail).toHaveBeenCalledTimes(2); + }); + + it('keeps required messages and sync/async rules', async () => { + const schema = decode(string(), number(), Number).optional(); + expect( + schema.required('Provide a size').safeParse(undefined).errors?.[0] + .message + ).toBe('Provide a size'); + const asyncRequired = schema.required(async () => 'Async required'); + expect(() => asyncRequired.parse(undefined)).toThrow(/Async|async/); + expect( + (await asyncRequired.safeParseAsync(undefined)).errors?.[0].message + ).toBe('Async required'); + }); + + it('retains nested errors from both decoding stages', () => { + const schema = object({ + item: decode( + object({ input: object({ value: string().minLength(1) }) }), + object({ output: object({ count: number().min(1) }) }), + input => ({ output: { count: Number(input.input.value) } }) + ) + }); + const inputFailure = schema.validate({ + item: { input: { value: '' } } + } as any); + expect( + inputFailure + .getInvalidProperties() + .map(p => p.descriptor.toJsonPointer()) + ).toContain('/item/input/value'); + const outputFailure = schema.validate({ + item: { input: { value: '0' } } + } as any); + expect( + outputFailure.getErrorsFor(t => t.item.output.count).errors.length + ).toBeGreaterThan(0); + expect( + outputFailure + .getInvalidProperties() + .map(p => p.descriptor.toJsonPointer()) + ).toContain('/item/output/count'); + }); +}); diff --git a/libs/schema/src/builders/BoundarySchemaBuilder.ts b/libs/schema/src/builders/BoundarySchemaBuilder.ts new file mode 100644 index 00000000..c9eac67b --- /dev/null +++ b/libs/schema/src/builders/BoundarySchemaBuilder.ts @@ -0,0 +1,528 @@ +import { + type BRAND, + type InferInput, + type InferOutput, + SchemaBuilder, + type SchemaBuilderProps, + SYMBOL_HAS_PROPERTIES, + type ValidationContext, + type ValidationErrorMessageProvider, + type ValidationResult +} from './SchemaBuilder.js'; + +type AnySchema = SchemaBuilder; +type BoundaryOutput< + TOutputSchema, + TRequired extends boolean, + TNullable extends boolean, + TExplicitType +> = + | (TRequired extends true + ? Exclude< + TExplicitType extends undefined + ? InferOutput + : TExplicitType, + undefined + > + : + | (TExplicitType extends undefined + ? InferOutput + : TExplicitType) + | undefined) + | (TNullable extends true ? null : never); + +type BoundaryProps = Partial> & { + type: 'reference' | 'decode'; + inputSchema: AnySchema; + outputSchema: AnySchema; + converter?: (value: any) => any; + presence?: boolean; + nullability?: boolean; +}; + +/** + * Immutable schema boundary returned by {@link schemaRef} and {@link decode}. + * Use the factories rather than constructing this class. Local modifiers never + * mutate the input/output schemas or their named definitions. + * @typeParam TInputSchema - Schema validating values before conversion. + * @typeParam TOutputSchema - Schema validating converted values. + * @typeParam TRequired - Whether the output includes undefined. + * @typeParam TNullable - Whether null is allowed by a use-site modifier. + * @typeParam THasDefault - Whether the wrapper supplies an output default. + * @typeParam TExplicitType - Optional static output override. + * @typeParam TInput - Declared input, including use-site presence modifiers. + */ +export class BoundarySchemaBuilder< + TInputSchema extends AnySchema, + TOutputSchema extends AnySchema, + TRequired extends boolean = true, + TNullable extends boolean = false, + THasDefault extends boolean = false, + TExplicitType = undefined, + TInput = InferInput +> extends SchemaBuilder< + BoundaryOutput, + TRequired, + TNullable, + THasDefault, + {}, + InferInput, + TInput | (THasDefault extends true ? undefined : never) +> { + readonly #boundary: BoundaryProps; + /** @internal Enables nested property descriptors without subclassing objects. */ + readonly [SYMBOL_HAS_PROPERTIES] = true; + + /** @internal Factory configuration is exposed for immutable reconstruction. */ + constructor(props: BoundaryProps) { + super({ preprocessors: [], validators: [], ...props }); + this.#boundary = props; + } + + /** Describes both sides without evaluating the converter. */ + public introspect() { + return { + ...super.introspect(), + inputSchema: this.#boundary.inputSchema as TInputSchema, + outputSchema: this.#boundary.outputSchema as TOutputSchema, + converter: this.#boundary.converter, + presence: this.#boundary.presence, + nullability: this.#boundary.nullability, + // Object consumers can preserve real descriptor schemas through refs. + properties: + this.type === 'reference' + ? (this.#boundary.outputSchema.introspect() as any) + .properties + : undefined + }; + } + + /** @internal Rebuilds the wrapper while retaining the same target instances. */ + protected createFromProps(props: BoundaryProps): this { + return new BoundarySchemaBuilder(props) as this; + } + + #early(value: unknown): ValidationResult | undefined { + if (value === undefined && this.hasDefault) return undefined; + if (value === undefined && this.#boundary.presence !== undefined) { + return this.#boundary.presence + ? { valid: false, errors: [{ message: 'is required' }] } + : { valid: true, object: undefined }; + } + if (value === null && this.#boundary.nullability !== undefined) { + return this.#boundary.nullability + ? { valid: true, object: null } + : { valid: false, errors: [{ message: 'must not be null' }] }; + } + return undefined; + } + + #converterFailure(error: unknown): ValidationResult { + return { + valid: false, + errors: [ + { + message: `Decoder failed: ${error instanceof Error ? error.message : String(error)}` + } + ] + }; + } + + #stageFailure( + result: ValidationResult, + schema: AnySchema + ): ValidationResult { + return Object.assign(result, { __boundaryErrorSchema: schema }); + } + + /** Validates unknown input; an output fallback is never decoded a second time. */ + public validate( + value: unknown, + context?: ValidationContext + ): ValidationResult< + BoundaryOutput + > { + const result = this._validate(value, context); + if (result.valid || !this.hasCatch) return result; + const fallback = this.resolveCatchValue(); + const checked = this.#boundary.outputSchema.validate(fallback, context); + return checked.valid ? checked : { valid: true, object: fallback }; + } + + /** Async validation with the same output-fallback and error semantics as validate. */ + public async validateAsync( + value: unknown, + context?: ValidationContext + ): Promise< + ValidationResult< + BoundaryOutput + > + > { + const result = await this._validateAsync(value, context); + if (result.valid || !this.hasCatch) return result; + const fallback = this.resolveCatchValue(); + const checked = await this.#boundary.outputSchema.validateAsync( + fallback, + context + ); + return checked.valid ? checked : { valid: true, object: fallback }; + } + + /** @internal Validates input, converts once, and validates output. */ + protected _validate( + value: unknown, + context?: ValidationContext + ): ValidationResult { + const early = this.#early(value); + if (early) { + if (!early.valid && value === undefined) + early.errors = [ + { + message: this.getValidationErrorMessageSync( + this.requiredErrorMessage, + value as any + ) + } + ]; + return early; + } + const usesDefault = value === undefined && this.hasDefault; + const input = usesDefault + ? { valid: true, object: this.resolveDefaultValue() } + : this.#boundary.inputSchema.validate(value, context); + if (!input.valid) + return this.#stageFailure(input, this.#boundary.inputSchema); + let converted = input.object; + if (!usesDefault && this.#boundary.converter) { + try { + converted = this.#boundary.converter(converted); + } catch (error) { + return this.#converterFailure(error); + } + if (converted != null && typeof converted.then === 'function') { + throw new Error( + 'Decoder returned a Promise. Use validateAsync() or parseAsync().' + ); + } + } + const output = + this.type === 'reference' && !usesDefault + ? input + : this.#boundary.outputSchema.validate(converted, context); + if (!output.valid) + return this.#stageFailure(output, this.#boundary.outputSchema); + if (output.object === null && this.#boundary.nullability === false) { + return { valid: false, errors: [{ message: 'must not be null' }] }; + } + const prepared = this.preValidateSync(output.object, context); + if (!prepared.valid) return { valid: false, errors: prepared.errors }; + const preparedValue = prepared.transaction!.object.validatedObject; + if (this.preprocessors.length === 0) return output; + return this.#boundary.outputSchema.validate(preparedValue, context); + } + + /** @internal Async counterpart; converter rejections are validation failures. */ + protected async _validateAsync( + value: unknown, + context?: ValidationContext + ): Promise> { + const early = this.#early(value); + if (early) { + if (!early.valid && value === undefined) + early.errors = [ + { + message: await this.getValidationErrorMessage( + this.requiredErrorMessage, + value as any + ) + } + ]; + return early; + } + const usesDefault = value === undefined && this.hasDefault; + const input = usesDefault + ? { valid: true, object: this.resolveDefaultValue() } + : await this.#boundary.inputSchema.validateAsync(value, context); + if (!input.valid) + return this.#stageFailure(input, this.#boundary.inputSchema); + let converted = input.object; + if (!usesDefault && this.#boundary.converter) { + try { + converted = await this.#boundary.converter(converted); + } catch (error) { + return this.#converterFailure(error); + } + } + const output = + this.type === 'reference' && !usesDefault + ? input + : await this.#boundary.outputSchema.validateAsync( + converted, + context + ); + if (!output.valid) + return this.#stageFailure(output, this.#boundary.outputSchema); + if (output.object === null && this.#boundary.nullability === false) { + return { valid: false, errors: [{ message: 'must not be null' }] }; + } + const prepared = await this.preValidateAsync(output.object, context); + if (!prepared.valid) return { valid: false, errors: prepared.errors }; + const preparedValue = prepared.transaction!.object.validatedObject; + if (this.preprocessors.length === 0) return output; + return this.#boundary.outputSchema.validateAsync( + preparedValue, + context + ); + } + + /** Overrides only the static output type; runtime validation is unchanged. */ + public hasType( + _notUsed?: T + ): BoundarySchemaBuilder< + TInputSchema, + TOutputSchema, + TRequired, + TNullable, + THasDefault, + T, + TInput + > { + return this.createFromProps(this.#props()) as any; + } + + /** Restores output inference from the output schema. */ + public clearHasType(): BoundarySchemaBuilder< + TInputSchema, + TOutputSchema, + TRequired, + TNullable, + THasDefault, + undefined, + TInput + > { + return this.createFromProps(this.#props()) as any; + } + + #props(): BoundaryProps { + return { + ...this.#boundary, + ...this.introspect(), + type: this.#boundary.type, + preprocessors: [...this.preprocessors], + validators: [...this.validators] + }; + } + + /** Rejects missing input at this use site. */ + public required( + errorMessage?: ValidationErrorMessageProvider + ): BoundarySchemaBuilder< + TInputSchema, + TOutputSchema, + true, + TNullable, + THasDefault, + TExplicitType, + Exclude + > { + return this.createFromProps({ + ...this.#props(), + isRequired: true, + presence: true, + requiredValidationErrorMessageProvider: errorMessage + }) as any; + } + + /** Allows omitted input at this use site, without invoking the boundary. */ + public optional(): BoundarySchemaBuilder< + TInputSchema, + TOutputSchema, + false, + TNullable, + THasDefault, + TExplicitType, + TInput | undefined + > { + return this.createFromProps({ + ...this.#props(), + isRequired: false, + presence: false + }) as any; + } + + /** Allows null at this use site, independently of optionality. */ + public nullable(): BoundarySchemaBuilder< + TInputSchema, + TOutputSchema, + TRequired, + true, + THasDefault, + TExplicitType, + TInput | null + > { + return this.createFromProps({ + ...this.#props(), + isNullable: true, + nullability: true + }) as any; + } + + /** Rejects null at this use site without changing the referenced definition. */ + public notNullable(): BoundarySchemaBuilder< + TInputSchema, + TOutputSchema, + TRequired, + false, + THasDefault, + Exclude< + TExplicitType extends undefined + ? InferOutput + : TExplicitType, + null + >, + Exclude + > { + return this.createFromProps({ + ...this.#props(), + isNullable: false, + nullability: false + }) as any; + } + + /** Supplies an output default for missing input; validates it without decoding. */ + public default( + value: InferOutput | (() => InferOutput) + ): BoundarySchemaBuilder< + TInputSchema, + TOutputSchema, + true, + TNullable, + true, + TExplicitType, + TInput + > { + return this.createFromProps({ + ...this.#props(), + defaultValue: value, + isRequired: true + }) as any; + } + + /** Removes the use-site default; defaults on the target are unchanged. */ + public clearDefault(): BoundarySchemaBuilder< + TInputSchema, + TOutputSchema, + TRequired, + TNullable, + false, + TExplicitType, + TInput + > { + return this.createFromProps({ + ...this.#props(), + defaultValue: undefined + }) as any; + } + + /** Brands the output type only; it does not alter runtime validation. */ + public brand( + _name?: B + ): BoundarySchemaBuilder< + TInputSchema, + TOutputSchema, + TRequired, + TNullable, + THasDefault, + (TExplicitType extends undefined + ? InferOutput + : TExplicitType) & { + readonly [K in BRAND]: B; + }, + TInput + > { + return super.brand(_name); + } + + /** Makes the output type readonly without freezing runtime values. */ + public readonly(): BoundarySchemaBuilder< + TInputSchema, + TOutputSchema, + TRequired, + TNullable, + THasDefault, + Readonly< + TExplicitType extends undefined + ? InferOutput + : TExplicitType + >, + TInput + > { + return super.readonly(); + } +} + +type RequiredOf = undefined extends InferOutput ? false : true; +type NullableOf = null extends InferOutput ? true : false; + +/** + * References one named definition with independent use-site annotations. + * @param schema - A reused schema constant with a nonempty schemaName. + * @returns An immutable reference wrapper; the named target is not cloned. + * @throws Error if the target has no name. + * @example + * const User = object({ name: string() }).schemaName('User'); + * const previous = schemaRef(User).nullable().optional().describe('Previous user'); + */ +export function schemaRef( + schema: S +): BoundarySchemaBuilder, NullableOf> { + const info = schema.introspect(); + if (!info.schemaName?.trim()) + throw new Error('schemaRef requires a named schema.'); + return new BoundarySchemaBuilder({ + type: 'reference', + inputSchema: schema, + outputSchema: schema, + isRequired: info.isRequired, + isNullable: info.isNullable + }); +} + +/** + * Composes input validation, an explicit conversion, and output validation. + * @param inputSchema - Validates external input before the converter runs. + * @param outputSchema - Validates the converted result. + * @param converter - Receives validated input; may return a Promise. + * @returns A schema with distinct inferred input/output types. + * @remarks Converter exceptions become validation failures. Async converters + * require parseAsync/validateAsync. JSON Schema documents declared shapes only, + * not arbitrary conversion logic. This is not a bidirectional codec. + * @example + * const PageSize = decode(string(), number().isInteger().min(1), Number); + * PageSize.parse('12'); // 12 + */ +export function decode< + TInputSchema extends AnySchema, + TOutputSchema extends AnySchema +>( + inputSchema: TInputSchema, + outputSchema: TOutputSchema, + converter: ( + input: InferOutput + ) => InferInput | Promise> +): BoundarySchemaBuilder< + TInputSchema, + TOutputSchema, + RequiredOf, + NullableOf +> { + const info = outputSchema.introspect(); + return new BoundarySchemaBuilder({ + type: 'decode', + inputSchema, + outputSchema, + converter, + isRequired: info.isRequired, + isNullable: info.isNullable + }); +} diff --git a/libs/schema/src/builders/ExternSchemaBuilder.ts b/libs/schema/src/builders/ExternSchemaBuilder.ts index 6d4fb12d..76fb55ec 100644 --- a/libs/schema/src/builders/ExternSchemaBuilder.ts +++ b/libs/schema/src/builders/ExternSchemaBuilder.ts @@ -100,7 +100,8 @@ export class ExternSchemaBuilder< TRequired, TNullable, THasDefault, - TExtensions + TExtensions, + StandardSchemaV1.InferInput > { #standardSchema: TStandardSchema; diff --git a/libs/schema/src/builders/IntersectionSchemaBuilder.ts b/libs/schema/src/builders/IntersectionSchemaBuilder.ts index 6d746c6a..47488a6b 100644 --- a/libs/schema/src/builders/IntersectionSchemaBuilder.ts +++ b/libs/schema/src/builders/IntersectionSchemaBuilder.ts @@ -1,5 +1,6 @@ import { type BRAND, + type InferInput, type InferType, SchemaBuilder, type ValidationContext, @@ -36,7 +37,8 @@ export class IntersectionSchemaBuilder< TRequired, TNullable, THasDefault, - TExtensions + TExtensions, + InferInput & InferInput > { #left!: TLeft; #right!: TRight; diff --git a/libs/schema/src/builders/LazySchemaBuilder.ts b/libs/schema/src/builders/LazySchemaBuilder.ts index 12f0d7c5..cc0ede6c 100644 --- a/libs/schema/src/builders/LazySchemaBuilder.ts +++ b/libs/schema/src/builders/LazySchemaBuilder.ts @@ -1,5 +1,7 @@ import { type BRAND, + type InferInput, + type InferOutput, SchemaBuilder, type ValidationContext, type ValidationErrorMessageProvider, @@ -49,13 +51,15 @@ export class LazySchemaBuilder< TRequired extends boolean = true, TNullable extends boolean = false, THasDefault extends boolean = false, - TExtensions = {} + TExtensions = {}, + TInput = TResult > extends SchemaBuilder< TResult, TRequired, TNullable, THasDefault, - TExtensions + TExtensions, + TInput > { #getter: () => SchemaBuilder; #resolvedSchema: SchemaBuilder | null = null; @@ -210,7 +214,7 @@ export class LazySchemaBuilder< */ public hasType( _notUsed?: T - ): LazySchemaBuilder & + ): LazySchemaBuilder & TExtensions { return this.createFromProps({ ...this.introspect() @@ -225,7 +229,8 @@ export class LazySchemaBuilder< TRequired, TNullable, THasDefault, - TExtensions + TExtensions, + TInput > & TExtensions { return this.createFromProps({ @@ -238,7 +243,14 @@ export class LazySchemaBuilder< */ public required( errorMessage?: ValidationErrorMessageProvider - ): LazySchemaBuilder & + ): LazySchemaBuilder< + TResult, + true, + TNullable, + THasDefault, + TExtensions, + TInput + > & TExtensions { return super.required(errorMessage); } @@ -251,7 +263,8 @@ export class LazySchemaBuilder< false, TNullable, THasDefault, - TExtensions + TExtensions, + TInput > & TExtensions { return super.optional(); @@ -262,7 +275,7 @@ export class LazySchemaBuilder< */ public default( value: TResult | (() => TResult) - ): LazySchemaBuilder & + ): LazySchemaBuilder & TExtensions { return super.default(value) as any; } @@ -275,7 +288,8 @@ export class LazySchemaBuilder< TRequired, TNullable, false, - TExtensions + TExtensions, + TInput > & TExtensions { return super.clearDefault() as any; @@ -291,7 +305,8 @@ export class LazySchemaBuilder< TRequired, TNullable, THasDefault, - TExtensions + TExtensions, + TInput > & TExtensions { return super.brand(_name); @@ -305,7 +320,8 @@ export class LazySchemaBuilder< TRequired, TNullable, THasDefault, - TExtensions + TExtensions, + TInput > & TExtensions { return super.readonly(); @@ -319,7 +335,8 @@ export class LazySchemaBuilder< TRequired, true, THasDefault, - TExtensions + TExtensions, + TInput > & TExtensions { return super.nullable() as any; @@ -333,7 +350,8 @@ export class LazySchemaBuilder< TRequired, false, THasDefault, - TExtensions + TExtensions, + TInput > & TExtensions { return super.notNullable() as any; @@ -372,6 +390,12 @@ export class LazySchemaBuilder< * }); * ``` */ +export function lazy>( + getter: () => S +): LazySchemaBuilder, true, false, false, {}, InferInput>; +export function lazy( + getter: () => SchemaBuilder +): LazySchemaBuilder; export function lazy( getter: () => SchemaBuilder ): LazySchemaBuilder { diff --git a/libs/schema/src/builders/ObjectSchemaBuilder.ts b/libs/schema/src/builders/ObjectSchemaBuilder.ts index d78d89d8..4ce3529a 100644 --- a/libs/schema/src/builders/ObjectSchemaBuilder.ts +++ b/libs/schema/src/builders/ObjectSchemaBuilder.ts @@ -1,6 +1,7 @@ import { PropertyValidationResult } from './PropertyValidationResult.js'; import { type BRAND, + type InferInput, type InferType, type NestedValidationResult, type PreValidationResult, @@ -137,9 +138,9 @@ export type RespectPropsOptionality< type RespectPropsOptionalityForInput< T extends Record> > = { - [K in RequiredInputProps]: InferType; + [K in RequiredInputProps]: InferInput; } & { - [K in NotRequiredInputProps]?: InferType; + [K in NotRequiredInputProps]?: InferInput; }; type MakeChildrenRequired< @@ -376,7 +377,8 @@ export class ObjectSchemaBuilder< TRequired, TNullable, THasDefault, - TExtensions + TExtensions, + RespectPropsOptionalityForInput > { #properties: TProperties = {} as any; #acceptUnknownProps = false; @@ -1073,7 +1075,9 @@ export class ObjectSchemaBuilder< ObjectSchemaBuilder.#propagateNestedErrors( result as any, descriptor, - addErrorFor + addErrorFor, + (result as any).__boundaryErrorSchema ?? + this.#properties[key] ); // For extern schemas, also record errors on the extern // descriptor itself so getErrorsFor(t => t.extern) works, @@ -1842,7 +1846,8 @@ export class ObjectSchemaBuilder< TRequired, TNullable, THasDefault, - TExtensions + TExtensions, + RespectPropsOptionalityForInput > { return this.createFromProps({ ...this.introspect() @@ -2759,9 +2764,12 @@ export class ObjectSchemaBuilder< descriptor: any, message: string, parentDescriptor?: any - ) => void + ) => void, + schemaOverride?: SchemaBuilder ): void { const schema = + schemaOverride ?? + result.__boundaryErrorSchema ?? ObjectSchemaBuilder.#getSchemaForPropertyDescriptor(descriptor); const properties = (schema.introspect() as any).properties; @@ -2813,7 +2821,8 @@ export class ObjectSchemaBuilder< ObjectSchemaBuilder.#propagateNestedErrors( result, nestedPropertyDescriptor, - addErrorFor + addErrorFor, + nestedSchema ); } } @@ -3114,33 +3123,11 @@ type NotRequiredProps< type RequiredInputProps< T extends Record> > = keyof { - [k in keyof T as T[k] extends SchemaBuilder< - any, - infer TReq, - any, - infer THasDef - > - ? TReq extends true - ? THasDef extends true - ? never - : k - : never - : never]: T[k]; + [k in keyof T as undefined extends InferInput ? never : k]: T[k]; }; type NotRequiredInputProps< T extends Record> > = keyof { - [k in keyof T as T[k] extends SchemaBuilder< - any, - infer TReq, - any, - infer THasDef - > - ? TReq extends true - ? THasDef extends true - ? k - : never - : k - : never]: T[k]; + [k in keyof T as undefined extends InferInput ? k : never]: T[k]; }; diff --git a/libs/schema/src/builders/RecordSchemaBuilder.ts b/libs/schema/src/builders/RecordSchemaBuilder.ts index f9e2ab63..5b0e306d 100644 --- a/libs/schema/src/builders/RecordSchemaBuilder.ts +++ b/libs/schema/src/builders/RecordSchemaBuilder.ts @@ -14,6 +14,7 @@ */ import { type BRAND, + type InferInput, type InferType, type PreValidationResult, SchemaBuilder, @@ -241,7 +242,8 @@ export class RecordSchemaBuilder< TRequired, TNullable, THasDefault, - TExtensions + TExtensions, + Record, InferInput> > { #keySchema!: TKeySchema; #valueSchema!: TValueSchema; diff --git a/libs/schema/src/builders/SchemaBuilder.ts b/libs/schema/src/builders/SchemaBuilder.ts index 6b119bca..311e86ed 100644 --- a/libs/schema/src/builders/SchemaBuilder.ts +++ b/libs/schema/src/builders/SchemaBuilder.ts @@ -5,11 +5,12 @@ import { transaction } from '../utils/transaction.js'; import type { ArraySchemaBuilder } from './ArraySchemaBuilder.js'; -import type { ExternSchemaBuilder } from './ExternSchemaBuilder.js'; import type { ObjectSchemaBuilder } from './ObjectSchemaBuilder.js'; /** @internal Symbol used as the key for the type brand on schema builders. */ declare const __type: unique symbol; +/** @internal Input type marker. */ +declare const __input: unique symbol; /** @internal */ export type SchemaTypeBrand = typeof __type; @@ -58,6 +59,18 @@ export type InferType = T extends { ? TType : T; +/** Validated output of a schema; compatibility alias for {@link InferType}. */ +export type InferOutput = InferType; + +/** + * Declared input before decoding and defaults. Parsers still validate unknown + * data at runtime. Legacy preprocessors do not infer a separate input type. + * @typeParam T - Schema whose input is required. + */ +export type InferInput = T extends { readonly [__input]: infer I } + ? I + : InferType; + /** * Represents a single validation error with a human-readable error message. * @@ -538,77 +551,85 @@ export type PropertyDescriptorTree< TParentPropertyDescriptor = undefined > = PropertyDescriptor & (TSchema extends ObjectSchemaBuilder - ? { - [K in keyof TProperties]: TProperties[K] extends ObjectSchemaBuilder< - any, - any, - any - > - ? PropertyDescriptorTree< - TProperties[K], - TRootSchema, - any, - PropertyDescriptor< + ? 0 extends 1 & TProperties + ? { [key: string]: any } + : { + [K in keyof TProperties]: TProperties[K] extends ObjectSchemaBuilder< + any, + any, + any + > + ? PropertyDescriptorTree< + TProperties[K], TRootSchema, - TSchema, - TParentPropertyDescriptor + any, + PropertyDescriptor< + TRootSchema, + TSchema, + TParentPropertyDescriptor + > > - > - : TProperties[K] extends ExternSchemaBuilder< - any, - any, - any, - any, - any, - any, - infer TExternResult - > - ? PropertyDescriptor< - TRootSchema, - TProperties[K], - PropertyDescriptor< - TRootSchema, - TSchema, - TParentPropertyDescriptor - >, - K & string - > & - ExternOutputPropertyDescriptors< - TExternResult, + : TProperties[K] extends { + readonly [SYMBOL_HAS_PROPERTIES]: true; + } + ? PropertyDescriptor< TRootSchema, + TProperties[K], PropertyDescriptor< TRootSchema, - TProperties[K], + TSchema, + TParentPropertyDescriptor + >, + K & string + > & + ExternOutputPropertyDescriptors< + NonNullable>, + TRootSchema, PropertyDescriptor< TRootSchema, - TSchema, - TParentPropertyDescriptor - >, - K & string + TProperties[K], + PropertyDescriptor< + TRootSchema, + TSchema, + TParentPropertyDescriptor + >, + K & string + > > - > - : TProperties[K] extends ArraySchemaBuilder< - infer TArrayElement, - any, - any - > - ? TArrayElement extends ObjectSchemaBuilder< - any, - any, - any, - any, - any - > - ? PropertyDescriptor< - TRootSchema, - TProperties[K], - PropertyDescriptor< - TRootSchema, - TSchema, - TParentPropertyDescriptor - >, - K & string + : TProperties[K] extends ArraySchemaBuilder< + infer TArrayElement, + any, + any + > + ? TArrayElement extends ObjectSchemaBuilder< + any, + any, + any, + any, + any > + ? PropertyDescriptor< + TRootSchema, + TProperties[K], + PropertyDescriptor< + TRootSchema, + TSchema, + TParentPropertyDescriptor + >, + K & string + > + : InferType extends TAssignableTo + ? PropertyDescriptor< + TRootSchema, + TProperties[K], + PropertyDescriptor< + TRootSchema, + TSchema, + TParentPropertyDescriptor + >, + K & string + > + : never : InferType extends TAssignableTo ? PropertyDescriptor< TRootSchema, @@ -620,20 +641,8 @@ export type PropertyDescriptorTree< >, K & string > - : never - : InferType extends TAssignableTo - ? PropertyDescriptor< - TRootSchema, - TProperties[K], - PropertyDescriptor< - TRootSchema, - TSchema, - TParentPropertyDescriptor - >, - K & string - > - : never; - } + : never; + } : never); /** @@ -742,6 +751,8 @@ type ResolvedSchemaType< * **Note:** this class is not intended to be used directly, use one of the subclasses instead. * @typeparam TResult Type of the object that will be returned by `validate()` method. * @typeparam TRequired If `true`, object will be required. If `false`, object will be optional. + * @typeParam TInput - Declared input before decoding. Defaults to TResult so + * existing generic arguments retain their meaning. */ export abstract class SchemaBuilder< TResult = any, @@ -749,7 +760,11 @@ export abstract class SchemaBuilder< TNullable extends boolean = false, THasDefault extends boolean = false, // biome-ignore lint/correctness/noUnusedVariables: used in extensions - TExtensions = {} + TExtensions = {}, + TInput = TResult, + TResolvedInput = + | ResolvedSchemaType + | (THasDefault extends true ? undefined : never) > { #isRequired = true; #isNullable = false; @@ -777,6 +792,7 @@ export abstract class SchemaBuilder< */ #standardProps: | StandardSchemaV1.Props< + TResolvedInput, ResolvedSchemaType > | undefined; @@ -799,6 +815,9 @@ export abstract class SchemaBuilder< */ declare readonly [__hasDefault]: THasDefault; + /** @internal Input type, including omission when a default exists. */ + declare readonly [__input]: TResolvedInput; + /** * Standard Schema v1 interface. * @@ -807,13 +826,13 @@ export abstract class SchemaBuilder< * consumes the spec — including tRPC, TanStack Form, React Hook Form, T3 Env, * Hono, Elysia, next-safe-action, and 50+ other tools. * - * Every `SchemaBuilder` subclass (all 13 builders) inherits this property + * Every `SchemaBuilder` subclass inherits this property * automatically — no additional setup required. * * **Shape of the returned object:** * - `version` — always `1` (Standard Schema spec version) * - `vendor` — `'@cleverbrush/schema'` - * - `validate(value)` — synchronous; wraps this builder's own `.validate()` + * - `validate(value)` — asynchronous; wraps this builder's `.validateAsync()` * and converts its result to the Standard Schema `Result` format: * - Success: `{ value: }` * - Failure: `{ issues: [{ message: string }, …] }` @@ -849,6 +868,7 @@ export abstract class SchemaBuilder< * @see https://standardschema.dev/ */ get ['~standard'](): StandardSchemaV1.Props< + TResolvedInput, ResolvedSchemaType > { if (this.#standardProps) return this.#standardProps; @@ -1555,7 +1575,10 @@ export abstract class SchemaBuilder< * * When `.catch()` is set, {@link parse} and {@link parseAsync} will **never throw**. * - * @param value - the fallback value, or a factory function producing the fallback + * @param value - A value (or factory) compatible with the resolved output: + * optional schemas allow undefined; nullable schemas allow null. + * @remarks Legacy optional schemas also accept null at runtime, so + * catch(undefined) does not normalize null. Use an explicit preprocessor. * * @example * ```ts @@ -1584,7 +1607,11 @@ export abstract class SchemaBuilder< * c.validate(42); // { valid: true, object: 'anon' } ← also fires * ``` */ - public catch(value: TResult | (() => TResult)): this { + public catch( + value: + | ResolvedSchemaType + | (() => ResolvedSchemaType) + ): this { return this.createFromProps({ ...this.introspect(), catchValue: value, @@ -1750,10 +1777,20 @@ export abstract class SchemaBuilder< } /** - * Adds a `preprocessor` to a preprocessors list + * Adds an immutable preprocessing step. It may return the resolved value, + * including undefined for optional schemas and null for nullable schemas. + * @param preprocessor - Existing value-to-value conversion, optionally async. + * @param options - Whether the callback can mutate its argument. + * @returns A new builder preserving the original schema. + * @remarks Legacy callback parameter typing is preserved for compatibility. + * For a separately typed external input, use decode(input, output, fn). */ public addPreprocessor( - preprocessor: Preprocessor, + preprocessor: ( + object: TResult + ) => + | ResolvedSchemaType + | Promise>, options?: { mutates?: boolean } ): this { if (typeof preprocessor !== 'function') { diff --git a/libs/schema/src/builders/TupleSchemaBuilder.ts b/libs/schema/src/builders/TupleSchemaBuilder.ts index 8a5a6d76..d2d690ef 100644 --- a/libs/schema/src/builders/TupleSchemaBuilder.ts +++ b/libs/schema/src/builders/TupleSchemaBuilder.ts @@ -5,6 +5,7 @@ import type { import { type BRAND, createHybridErrorArray, + type InferInput, type InferType, type NestedValidationResult, type PropertyDescriptor, @@ -160,7 +161,13 @@ export class TupleSchemaBuilder< TRequired, TNullable, THasDefault, - TExtensions + TExtensions, + TRestSchema extends SchemaBuilder + ? [ + ...{ [K in keyof TElements]: InferInput }, + ...Array> + ] + : { [K in keyof TElements]: InferInput } > { #elements!: TElements; #restSchema: diff --git a/libs/schema/src/builders/UnionSchemaBuilder.ts b/libs/schema/src/builders/UnionSchemaBuilder.ts index 0560e4c4..9ac80679 100644 --- a/libs/schema/src/builders/UnionSchemaBuilder.ts +++ b/libs/schema/src/builders/UnionSchemaBuilder.ts @@ -5,6 +5,7 @@ import type { import { type BRAND, createHybridErrorArray, + type InferInput, type InferType, type NestedValidationResult, type PropertyDescriptor, @@ -172,7 +173,8 @@ export class UnionSchemaBuilder< TRequired, TNullable, THasDefault, - TExtensions + TExtensions, + InferInput > { #options!: TOptions; #discriminatorKey: string | null = null; diff --git a/libs/schema/src/builders/boundaries.test-d.ts b/libs/schema/src/builders/boundaries.test-d.ts new file mode 100644 index 00000000..f9f9ef39 --- /dev/null +++ b/libs/schema/src/builders/boundaries.test-d.ts @@ -0,0 +1,102 @@ +import { expectTypeOf, test } from 'vitest'; +import { + array, + decode, + type InferInput, + type InferOutput, + type InferType, + intersection, + lazy, + number, + object, + record, + schemaRef, + string, + tuple, + union +} from '../index.js'; + +test('input/output inference composes without changing InferType', () => { + const size = decode(string(), number(), Number); + expectTypeOf>().toEqualTypeOf(); + expectTypeOf>().toEqualTypeOf(); + expectTypeOf>().toEqualTypeOf(); + expectTypeOf(size.parse('1')).toEqualTypeOf(); + const form = object({ size, title: string().default('untitled') }); + expectTypeOf>().toMatchTypeOf<{ + size: string; + title?: string; + }>(); + expectTypeOf<{ size: string }>().toMatchTypeOf>(); + expectTypeOf>().toMatchTypeOf<{ + size: number; + title: string; + }>(); + const list = array(size); + expectTypeOf>().toEqualTypeOf(); + expectTypeOf>().toEqualTypeOf(); + const pair = tuple([size, string()]); + expectTypeOf>().toEqualTypeOf<[string, string]>(); + const dictionary = record(string(), size); + expectTypeOf>().toEqualTypeOf< + Record + >(); + const choice = union(size).or(string()); + expectTypeOf>().toEqualTypeOf(); + const joined = intersection(object({ size }), object({ title: string() })); + expectTypeOf>().toMatchTypeOf<{ + size: string; + title: string; + }>(); + const ref = schemaRef(form.schemaName('Form')); + expectTypeOf>().toEqualTypeOf< + InferInput + >(); + const deferred = lazy(() => size); + expectTypeOf>().toEqualTypeOf(); + // @ts-expect-error required schemas cannot fall back to undefined + string().catch(undefined); + // @ts-expect-error non-nullable schemas cannot fall back to null + string().catch(null); + // @ts-expect-error converter must return the output schema's input + decode(string(), number(), value => value); + string().optional().catch(undefined); + string() + .nullable() + .catch(() => null); + string() + .optional() + .addPreprocessor(() => undefined); +}); + +test('boundary presence belongs to each side independently', () => { + const nullableOutput = decode(string(), number().nullable(), () => null); + expectTypeOf>().toEqualTypeOf(); + expectTypeOf>().toEqualTypeOf< + number | null + >(); + const nullableInput = decode(string().nullable(), number(), value => + value === null ? 0 : Number(value) + ); + expectTypeOf>().toEqualTypeOf< + string | null + >(); + expectTypeOf>().toEqualTypeOf(); + const defaults = object({ + size: decode(string().default('1'), number(), Number) + }); + expectTypeOf<{}>().toMatchTypeOf>(); + const optimized = defaults.optimize(); + expectTypeOf>().toEqualTypeOf< + InferInput + >(); + const required = nullableInput.optional().required().notNullable(); + expectTypeOf>().toEqualTypeOf(); + const ref = schemaRef(object({ name: string() }).schemaName('User')) + .nullable() + .optional(); + const root = object({ user: ref }); + root.validate({ user: null }).getErrorsFor(t => t.user.name); + // @ts-expect-error concrete descriptor trees still reject unknown fields + root.validate({ user: null }).getErrorsFor(t => t.user.missing); +}); diff --git a/libs/schema/src/core.ts b/libs/schema/src/core.ts index 023f3b3b..b0123534 100644 --- a/libs/schema/src/core.ts +++ b/libs/schema/src/core.ts @@ -12,6 +12,11 @@ export { BooleanSchemaBuilder, boolean } from './builders/BooleanSchemaBuilder.js'; +export { + BoundarySchemaBuilder, + decode, + schemaRef +} from './builders/BoundarySchemaBuilder.js'; export { DateSchemaBuilder, date } from './builders/DateSchemaBuilder.js'; export { ExternSchemaBuilder, @@ -51,6 +56,8 @@ export { export type { RecordSchemaValidationResult } from './builders/RecordSchemaBuilder.js'; export { RecordSchemaBuilder, record } from './builders/RecordSchemaBuilder.js'; export type { + InferInput, + InferOutput, NestedValidationResult, PropertyDescriptor, PropertyDescriptorInner, diff --git a/libs/schema/tsconfig.build.json b/libs/schema/tsconfig.build.json index 4efcd94c..14e29984 100644 --- a/libs/schema/tsconfig.build.json +++ b/libs/schema/tsconfig.build.json @@ -14,5 +14,5 @@ "declarationMap": false }, "include": ["src/**/*.ts"], - "exclude": ["src/**/*.test.ts"] + "exclude": ["src/**/*.test.ts", "src/**/*.test-d.ts"] } diff --git a/libs/schema/tsconfig.typecheck.json b/libs/schema/tsconfig.typecheck.json new file mode 100644 index 00000000..213d3043 --- /dev/null +++ b/libs/schema/tsconfig.typecheck.json @@ -0,0 +1,6 @@ +{ + "extends": "./tsconfig.build.json", + "compilerOptions": { "noEmit": true, "types": ["vitest/globals"] }, + "include": ["src/**/*.ts"], + "exclude": ["src/**/*.test.ts"] +} diff --git a/libs/schema/vitest.config.mts b/libs/schema/vitest.config.mts new file mode 100644 index 00000000..c2329925 --- /dev/null +++ b/libs/schema/vitest.config.mts @@ -0,0 +1,12 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + include: ['src/**/*.test.ts'], + typecheck: { + enabled: true, + include: ['src/**/*.test-d.ts'], + tsconfig: './tsconfig.typecheck.json' + } + } +}); diff --git a/libs/server-openapi/README.md b/libs/server-openapi/README.md index 3b5e2cd3..84426fe1 100644 --- a/libs/server-openapi/README.md +++ b/libs/server-openapi/README.md @@ -7,6 +7,18 @@ OpenAPI 3.1 specification generation for [`@cleverbrush/server`](../server). Con ## Features +### Schema boundaries + +Requests use schema input views and responses use output views. A named schema +with different representations gets collision-checked `NameInput` and +`NameOutput` components; identical representations keep their original name. +AsyncAPI uses input for incoming messages and output for outgoing messages. + +Use `schemaRef(NamedSchema).optional().nullable().describe(...)` to annotate a +single use without cloning the named definition. Conflicting named definitions +still fail. See the [composition guide](../schema/BOUNDARIES.md), including the +separate adoption required for typed clients and editable form state. + - **`generateOpenApiSpec()`** — converts `@cleverbrush/server` endpoint registrations into an OpenAPI 3.1 document. - **`generateAsyncApiSpec()`** — converts `@cleverbrush/server` WebSocket subscription registrations into an AsyncAPI 3.0 document. - **`serveAsyncApi()`** — middleware that lazily generates and caches the AsyncAPI spec; serves it at a configurable path (default: `/asyncapi.json`). diff --git a/libs/server-openapi/src/boundaries.test.ts b/libs/server-openapi/src/boundaries.test.ts new file mode 100644 index 00000000..91421f28 --- /dev/null +++ b/libs/server-openapi/src/boundaries.test.ts @@ -0,0 +1,102 @@ +import { + array, + decode, + lazy, + number, + object, + type SchemaBuilder, + schemaRef, + string +} from '@cleverbrush/schema'; +import { endpoint } from '@cleverbrush/server'; +import { describe, expect, it } from 'vitest'; +import { generateOpenApiSpec } from './generateOpenApiSpec.js'; +import { SchemaRegistry, walkSchemas } from './schemaRegistry.js'; + +describe('schema boundaries in OpenAPI', () => { + it('uses input requests, output responses, and directional nested components', () => { + const size = decode(string(), number().isInteger(), Number).schemaName( + 'Size' + ); + const request = object({ size: schemaRef(size) }).schemaName( + 'Envelope' + ); + const contract = endpoint + .post('/items') + .body(request) + .responses({ 200: request }); + const spec = generateOpenApiSpec({ + registrations: [ + { endpoint: contract.introspect(), handler: () => {} } + ], + info: { title: 'Boundaries', version: '1' } + }) as any; + expect( + spec.paths['/items'].post.requestBody.content['application/json'] + .schema + ).toEqual({ $ref: '#/components/schemas/EnvelopeInput' }); + expect( + spec.paths['/items'].post.responses['200'].content[ + 'application/json' + ].schema + ).toEqual({ $ref: '#/components/schemas/EnvelopeOutput' }); + expect(spec.components.schemas.SizeInput).toEqual({ + allOf: [{ type: 'string' }] + }); + expect(spec.components.schemas.SizeOutput).toEqual({ + allOf: [{ type: 'integer' }] + }); + expect( + spec.components.schemas.EnvelopeInput.properties.size.allOf[0].$ref + ).toBe('#/components/schemas/SizeInput'); + }); + + it('registers one target with independently annotated references', () => { + const user = object({ name: string() }).schemaName('User'); + const root = object({ + user, + previous: schemaRef(user).nullable().optional().describe('Previous') + }); + const registry = new SchemaRegistry(); + walkSchemas(root, registry); + expect( + [...registry.directionalEntries()].map(([name]) => name) + ).toEqual(['User']); + expect(() => walkSchemas(user.optional(), registry)).toThrow( + /already registered/ + ); + }); + + it('rejects generated-name collisions regardless of registration order', () => { + const size = decode(string(), number(), Number).schemaName('Size'); + const collision = string().schemaName('SizeInput'); + for (const schemas of [ + [size, collision], + [collision, size] + ]) { + const registry = new SchemaRegistry(); + for (const schema of schemas) walkSchemas(schema, registry); + expect(() => [...registry.directionalEntries()]).toThrow( + /SizeInput/ + ); + } + }); + + it('terminates on named recursive references', () => { + type Node = { name: string; children: Node[] }; + const node: SchemaBuilder = object({ + name: string(), + children: array(lazy(() => schemaRef(node))) + }).schemaName('Node'); + const contract = endpoint.get('/nodes').responses({ 200: node }); + const spec = generateOpenApiSpec({ + registrations: [ + { endpoint: contract.introspect(), handler: () => {} } + ], + info: { title: 'Nodes', version: '1' } + }) as any; + expect( + spec.components.schemas.Node.properties.children.items.allOf[0].$ref + ).toBe('#/components/schemas/Node'); + }); +}); diff --git a/libs/server-openapi/src/generateAsyncApiSpec.ts b/libs/server-openapi/src/generateAsyncApiSpec.ts index 4f75278f..cdbf5fd1 100644 --- a/libs/server-openapi/src/generateAsyncApiSpec.ts +++ b/libs/server-openapi/src/generateAsyncApiSpec.ts @@ -256,7 +256,7 @@ export function generateAsyncApiSpec( messages['ClientMessage'] = { name: 'ClientMessage', ...(inInfo.description ? { summary: inInfo.description } : {}), - payload: convertSchema(m.incomingSchema, registry) + payload: convertSchema(m.incomingSchema, registry, 'input') }; } @@ -325,8 +325,19 @@ export function generateAsyncApiSpec( if (!registry.isEmpty) { const schemas: Record = {}; - for (const [name, schema] of registry.entries()) { - schemas[name] = convertSchema(schema, registry); + for (const [name, schema, mode] of registry.directionalEntries()) { + let rootInlined = false; + schemas[name] = convertSchema( + schema, + candidate => { + if (candidate === schema && !rootInlined) { + rootInlined = true; + return null; + } + return registry.getName(candidate, mode); + }, + mode + ); } doc.components = { schemas }; } diff --git a/libs/server-openapi/src/generateOpenApiSpec.ts b/libs/server-openapi/src/generateOpenApiSpec.ts index f566eb3e..352722cb 100644 --- a/libs/server-openapi/src/generateOpenApiSpec.ts +++ b/libs/server-openapi/src/generateOpenApiSpec.ts @@ -161,6 +161,16 @@ function buildParameterObject( return param; } +/** Determines omission on the request side without executing conversions. */ +function isInputRequired(schema: SchemaBuilder): boolean { + const info = schema.introspect() as any; + if (info.hasDefault) return false; + if (info.type === 'reference' || info.type === 'decode') { + return info.presence ?? isInputRequired(info.inputSchema); + } + return info.isRequired !== false; +} + function buildRequestBody( bodySchema: SchemaBuilder, registry: SchemaRegistry, @@ -173,18 +183,18 @@ function buildRequestBody( ): Record { const bodyInfo = bodySchema.introspect() as any; const body: Record = { - required: bodyInfo.isRequired !== false + required: isInputRequired(bodySchema) }; // When file uploads are enabled, emit multipart/form-data if (fileUpload) { - const jsonSchema = convertSchema(bodySchema, registry); + const jsonSchema = convertSchema(bodySchema, registry, 'input'); const mediaType: Record = { schema: jsonSchema }; body['content'] = { 'multipart/form-data': mediaType }; } else { - const jsonSchema = convertSchema(bodySchema, registry); + const jsonSchema = convertSchema(bodySchema, registry, 'input'); const mediaType: Record = { schema: jsonSchema }; if (example != null) { mediaType['example'] = example; @@ -481,7 +491,7 @@ function buildOperation( > = queryInfo.properties ?? {}; for (const [name, propSchema] of Object.entries(props)) { const propInfo = propSchema.introspect() as any; - const isRequired = propInfo.isRequired !== false; + const isRequired = isInputRequired(propSchema); const description = typeof propInfo.description === 'string' && propInfo.description !== '' @@ -491,7 +501,7 @@ function buildOperation( buildParameterObject( name, 'query', - convertSchema(propSchema, registry), + convertSchema(propSchema, registry, 'input'), isRequired, description ) @@ -508,7 +518,7 @@ function buildOperation( > = headerInfo.properties ?? {}; for (const [name, propSchema] of Object.entries(props)) { const propInfo = propSchema.introspect() as any; - const isRequired = propInfo.isRequired !== false; + const isRequired = isInputRequired(propSchema); const description = typeof propInfo.description === 'string' && propInfo.description !== '' @@ -518,7 +528,7 @@ function buildOperation( buildParameterObject( name, 'header', - convertSchema(propSchema, registry), + convertSchema(propSchema, registry, 'input'), isRequired, description ) @@ -667,6 +677,13 @@ export function generateOpenApiSpec(options: OpenApiOptions): OpenApiDocument { if (meta.bodySchema) walkSchemas(meta.bodySchema, registry, visited); if (meta.responseSchema) walkSchemas(meta.responseSchema, registry, visited); + if (meta.responseHeaderSchema) + walkSchemas(meta.responseHeaderSchema, registry, visited); + if (meta.produces) { + for (const entry of Object.values(meta.produces)) { + if (entry.schema) walkSchemas(entry.schema, registry, visited); + } + } if (meta.responsesSchemas) { for (const schema of Object.values(meta.responsesSchemas)) { if (schema) walkSchemas(schema, registry, visited); @@ -707,7 +724,8 @@ export function generateOpenApiSpec(options: OpenApiOptions): OpenApiDocument { } const resolveComponentSchemaName = ( - rootSchema: SchemaBuilder + rootSchema: SchemaBuilder, + mode: 'input' | 'output' ) => { // The root schema must be inlined exactly once — for the component // definition itself. Any subsequent encounter (e.g. through a lazy @@ -721,7 +739,7 @@ export function generateOpenApiSpec(options: OpenApiOptions): OpenApiDocument { inlinedRoot = true; return undefined; // inline the root definition once } - return registry.getName(candidate) ?? undefined; + return registry.getName(candidate, mode) ?? undefined; }; }; @@ -813,13 +831,14 @@ export function generateOpenApiSpec(options: OpenApiOptions): OpenApiDocument { // Components — security schemes + named component schemas const componentSchemas: Record = {}; - for (const [name, schema] of registry.entries()) { + for (const [name, schema, mode] of registry.directionalEntries()) { // Inline the root schema to avoid a self-referential $ref, but resolve // nested named schemas through the shared registry so component // definitions can still deduplicate via $ref. componentSchemas[name] = convertSchema( schema, - resolveComponentSchemaName(schema) + resolveComponentSchemaName(schema, mode), + mode ); } const hasSchemas = Object.keys(componentSchemas).length > 0; diff --git a/libs/server-openapi/src/schemaConverter.ts b/libs/server-openapi/src/schemaConverter.ts index c0e83dfc..817c0219 100644 --- a/libs/server-openapi/src/schemaConverter.ts +++ b/libs/server-openapi/src/schemaConverter.ts @@ -18,10 +18,12 @@ type NameResolver = ( * * @param schema - The schema to convert, or `null`/`undefined`. * @param registry - Optional registry or resolver function for `$ref` deduplication. + * @param mode - Input before decoding/defaults, or validated output (default). */ export function convertSchema( schema: SchemaBuilder | null | undefined, - registry?: SchemaRegistry | NameResolver + registry?: SchemaRegistry | NameResolver, + mode: 'input' | 'output' = 'output' ): Record { if (schema == null) return {}; @@ -32,13 +34,14 @@ export function convertSchema( if (typeof registry === 'function') { nameResolver = s => registry(s) ?? null; } else { - nameResolver = s => registry.getName(s); + nameResolver = s => registry.getName(s, mode); } } return toJsonSchema(schema, { $schema: false, draft: '2020-12', - nameResolver + nameResolver, + mode }); } diff --git a/libs/server-openapi/src/schemaRegistry.ts b/libs/server-openapi/src/schemaRegistry.ts index 009bfa45..b934a656 100644 --- a/libs/server-openapi/src/schemaRegistry.ts +++ b/libs/server-openapi/src/schemaRegistry.ts @@ -1,4 +1,5 @@ import type { SchemaBuilder } from '@cleverbrush/schema'; +import { toJsonSchema } from '@cleverbrush/schema-json'; // --------------------------------------------------------------------------- // SchemaRegistry @@ -30,6 +31,9 @@ export class SchemaRegistry { >(); /** name → first-registered schema instance */ private readonly byName = new Map>(); + private directions: + | Map, { input: string; output: string }> + | undefined; /** * Attempts to register `schema` in the registry. @@ -64,6 +68,7 @@ export class SchemaRegistry { this.byInstance.set(schema, name); this.byName.set(name, schema); + this.directions = undefined; } /** @@ -73,8 +78,93 @@ export class SchemaRegistry { * @param schema - The schema builder to look up. * @returns The registered name, or `null`. */ - getName(schema: SchemaBuilder): string | null { - return this.byInstance.get(schema) ?? null; + getName( + schema: SchemaBuilder, + mode: 'input' | 'output' = 'output' + ): string | null { + if (!this.byInstance.has(schema)) return null; + this.prepareDirections(); + return this.directions!.get(schema)![mode]; + } + + /** + * Emits independent input/output definitions only when their declared + * representations differ. Derived names are collision checked. + * @throws Error when a generated component name is already reserved. + */ + *directionalEntries(): IterableIterator< + [string, SchemaBuilder, 'input' | 'output'] + > { + this.prepareDirections(); + for (const [schema, names] of this.directions!) { + if (names.input !== names.output) + yield [names.input, schema, 'input']; + yield [names.output, schema, 'output']; + } + } + + private prepareDirections(): void { + if (this.directions) return; + const different = new Set>(); + // A changed named child changes its parents' references. Iterate to a + // fixed point; named recursive edges are always references, not recursion. + let changed = true; + while (changed) { + changed = false; + for (const [, schema] of this.byName) { + if (different.has(schema)) continue; + const render = (mode: 'input' | 'output') => { + let rootInlined = false; + return JSON.stringify( + toJsonSchema(schema, { + $schema: false, + mode, + nameResolver: candidate => { + if (candidate === schema && !rootInlined) { + rootInlined = true; + return null; + } + const name = this.byInstance.get(candidate); + return name + ? name + + (different.has(candidate) + ? mode === 'input' + ? 'Input' + : 'Output' + : '') + : null; + } + }) + ); + }; + if (render('input') !== render('output')) { + different.add(schema); + changed = true; + } + } + } + const names = new Map>( + this.byName + ); + const directions = new Map< + SchemaBuilder, + { input: string; output: string } + >(); + for (const [name, schema] of this.byName) { + const pair = different.has(schema) + ? { input: name + 'Input', output: name + 'Output' } + : { input: name, output: name }; + for (const derived of new Set(Object.values(pair))) { + if (names.has(derived) && names.get(derived) !== schema) { + throw new Error( + `Schema component name "${derived}" conflicts with a generated input/output name.` + ); + } + names.set(derived, schema); + } + directions.set(schema, pair); + } + this.directions = directions; } /** @@ -126,6 +216,15 @@ export function walkSchemas( const info = schema.introspect() as any; switch (info.type) { + case 'reference': + case 'decode': + walkSchemas(info.inputSchema, registry, visited); + walkSchemas(info.outputSchema, registry, visited); + break; + case 'intersection': + walkSchemas(info.left, registry, visited); + walkSchemas(info.right, registry, visited); + break; case 'object': { const props = info.properties as | Record> diff --git a/websites/docs/app/server-openapi/page.tsx b/websites/docs/app/server-openapi/page.tsx index 0cd6f614..0d96da94 100644 --- a/websites/docs/app/server-openapi/page.tsx +++ b/websites/docs/app/server-openapi/page.tsx @@ -20,6 +20,19 @@ export default function ServerOpenApiPage() {

+
+

Named references and input/output views

+

+ Use schemaRef to annotate one use of a named definition + without cloning it. Requests use input views and + responses use output views; differing named + representations receive collision-checked Input and + Output suffixes. +

+ + Schema boundary composition and compatibility + +
{/* ── Installation ─────────────────────────────────── */} = { 'parse-string': ParseStringSection, 'object-constructors': ObjectConstructorsSection, 'schema-modifiers': SchemaModifiersSection, + 'schema-boundaries': SchemaBoundariesSection, extensions: ExtensionsSection, 'built-in-extensions': BuiltInExtensionsSection, 'generic-schemas': GenericSchemasSection, diff --git a/websites/schema/app/docs/sections/index.ts b/websites/schema/app/docs/sections/index.ts index 79e3d249..a86e09a5 100644 --- a/websites/schema/app/docs/sections/index.ts +++ b/websites/schema/app/docs/sections/index.ts @@ -19,6 +19,7 @@ export const SECTION_GROUPS = [ label: 'Composition', slugs: [ 'immutability', + 'schema-boundaries', 'discriminated-unions', 'recursive-schemas', 'parse-string', @@ -50,6 +51,11 @@ export const SECTION_GROUPS = [ ]; export const SCHEMA_SECTIONS: SchemaSection[] = [ + { + slug: 'schema-boundaries', + title: 'Schema Boundaries', + group: 'Composition' + }, { slug: 'why', title: 'Why @cleverbrush/schema?', group: 'Fundamentals' }, { slug: 'getting-started', diff --git a/websites/schema/app/docs/sections/schema-boundaries.tsx b/websites/schema/app/docs/sections/schema-boundaries.tsx new file mode 100644 index 00000000..5a3f8235 --- /dev/null +++ b/websites/schema/app/docs/sections/schema-boundaries.tsx @@ -0,0 +1,87 @@ +export default function SchemaBoundariesSection() { + return ( + <> +
+

Schemas Across Boundaries

+

+ Compose named references and explicit input-to-output + decoding without duplicating validation rules. +

+
+
+

Optional fallbacks

+
+                    {`const text = string().optional().catch(undefined);
+const nullableText = string().nullable().catch(null);`}
+                
+

+ Legacy optional schemas accept null at runtime. A fallback + does not replace a value that passed validation. Normalize + null explicitly if your application requires undefined; this + release does not change that compatibility behavior. +

+
+
+

One named definition

+
+                    {`const User = object({ name: string() }).schemaName('User');
+const History = object({
+    current: schemaRef(User),
+    previous: schemaRef(User).nullable().optional()
+        .describe('Previous user')
+});`}
+                
+

+ Reference modifiers apply at the use site. The original + named definition remains unchanged, and genuinely + conflicting definitions still fail registration. +

+
+
+

Declared input and output

+
+                    {`const PageSize = decode(
+    string(),
+    number().isInteger().min(1).max(100),
+    value => Number(value)
+);
+type Editable = InferInput; // string
+type Validated = InferOutput; // number
+PageSize.parse('20'); // 20`}
+                
+

+ The input is validated before conversion; the converted + result is validated against the output schema. Converter + errors become validation failures. Use parseAsync for + asynchronous converters. InferType remains an output alias. +

+

+ Nested schemas and Standard Schema retain both types. + Defaults on the input schema run before conversion; a + default on the boundary is an output default. +

+
+
+

Export and adoption

+
+                    {`toJsonSchema(PageSize, { mode: 'input' });
+toJsonSchema(PageSize, { mode: 'output' }); // default`}
+                
+

+ OpenAPI uses input for requests and output for responses, + splitting named components when their shapes differ. Export + describes declared shapes, not arbitrary conversion logic. +

+

+ Form state and typed-client request inference are separate + integrations. Until adopted there, keep explicit wire + contracts and decode at your application boundary. No + reverse conversion is inferred. +

+ + Read the full composition guide + +
+ + ); +} diff --git a/websites/schema/app/schema-json/page.tsx b/websites/schema/app/schema-json/page.tsx index 4f3120a4..23926606 100644 --- a/websites/schema/app/schema-json/page.tsx +++ b/websites/schema/app/schema-json/page.tsx @@ -32,6 +32,19 @@ export default function SchemaJsonPage() { ]} /> +
+

Input and output views

+

+ Pass mode: 'input' to describe values before + decoding and defaults, or mode: 'output' for + validated values (the default). Standard JSON Schema + input/output converters use the same views without + executing conversions. +

+ + Named references, decoding, and compatibility + +
{/* ── Installation ─────────────────────────────────── */} Date: Mon, 28 Sep 2026 20:26:26 +0000 Subject: [PATCH 05/41] fix(schema-json): honor final boundary output presence --- libs/schema-json/src/boundaries.test.ts | 15 +++++++++++++++ libs/schema-json/src/toJsonSchema.ts | 11 ++++++----- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/libs/schema-json/src/boundaries.test.ts b/libs/schema-json/src/boundaries.test.ts index 404978f9..f0fbf6ac 100644 --- a/libs/schema-json/src/boundaries.test.ts +++ b/libs/schema-json/src/boundaries.test.ts @@ -58,6 +58,21 @@ describe('boundary JSON Schema views', () => { expect(toJsonSchema(schema).required).toEqual(['size', 'title']); }); + it('respects output presence when defaults follow optional modifiers', () => { + const size = decode(string(), number(), Number).optional().default(5); + const name = schemaRef(string().schemaName('Name')) + .optional() + .default('untitled'); + const schema = object({ size, name }); + expect(schema.parse({})).toEqual({ size: 5, name: 'untitled' }); + expect( + toJsonSchema(schema, { mode: 'input' }).required + ).toBeUndefined(); + expect(toJsonSchema(schema).required).toEqual(['size', 'name']); + const optionalOutput = object({ size: size.optional() }); + expect(toJsonSchema(optionalOutput).required).toBeUndefined(); + }); + it.each([ '2020-12', '07' diff --git a/libs/schema-json/src/toJsonSchema.ts b/libs/schema-json/src/toJsonSchema.ts index fdb460b8..fad5f28c 100644 --- a/libs/schema-json/src/toJsonSchema.ts +++ b/libs/schema-json/src/toJsonSchema.ts @@ -17,13 +17,14 @@ function isRequiredInMode( mode: 'input' | 'output' ): boolean { const info = schema.introspect() as any; - if (mode === 'input' && info.hasDefault) return false; + // Output presence follows the wrapper's final modifiers. In particular, + // optional().default(...) produces a required output despite the earlier + // explicit input-omission modifier. + if (mode === 'output') return info.isRequired !== false; + if (info.hasDefault) return false; if (info.type === 'decode' || info.type === 'reference') { if (info.presence !== undefined) return info.presence; - return isRequiredInMode( - mode === 'input' ? info.inputSchema : info.outputSchema, - mode - ); + return isRequiredInMode(info.inputSchema, mode); } return info.isRequired !== false; } From 1f0b254ceadeafe8619f3099c007d8f1dbf67e42 Mon Sep 17 00:00:00 2001 From: Andrew Zolotukhin Date: Mon, 28 Sep 2026 21:43:15 +0000 Subject: [PATCH 06/41] refactor(schema): drop explicit input and output support from PR --- .changeset/schema-boundaries.md | 10 +- libs/knex-schema/src/entity.ts | 32 +- libs/schema-json/README.md | 8 +- libs/schema-json/src/boundaries.test.ts | 115 +--- libs/schema-json/src/standardJsonSchema.ts | 25 +- libs/schema-json/src/toJsonSchema.ts | 86 +-- libs/schema-json/src/types.ts | 2 - libs/schema/BOUNDARIES.md | 98 +--- libs/schema/README.md | 9 +- libs/schema/src/boundaries-docs.test.ts | 8 +- .../schema/src/builders/ArraySchemaBuilder.ts | 8 +- .../builders/BoundarySchemaBuilder.test.ts | 167 ------ .../src/builders/BoundarySchemaBuilder.ts | 528 ------------------ .../src/builders/ExternSchemaBuilder.ts | 3 +- .../src/builders/IntersectionSchemaBuilder.ts | 4 +- libs/schema/src/builders/LazySchemaBuilder.ts | 48 +- .../src/builders/ObjectSchemaBuilder.ts | 41 +- .../src/builders/RecordSchemaBuilder.ts | 4 +- .../builders/ReferenceSchemaBuilder.test.ts | 149 +++++ .../src/builders/ReferenceSchemaBuilder.ts | 387 +++++++++++++ libs/schema/src/builders/SchemaBuilder.ts | 31 +- .../schema/src/builders/TupleSchemaBuilder.ts | 9 +- .../schema/src/builders/UnionSchemaBuilder.ts | 4 +- libs/schema/src/builders/boundaries.test-d.ts | 102 ---- libs/schema/src/builders/references.test-d.ts | 47 ++ libs/schema/src/core.ts | 11 +- libs/server-openapi/README.md | 9 +- libs/server-openapi/src/boundaries.test.ts | 140 +++-- .../src/generateAsyncApiSpec.ts | 22 +- .../server-openapi/src/generateOpenApiSpec.ts | 41 +- libs/server-openapi/src/schemaConverter.ts | 9 +- libs/server-openapi/src/schemaRegistry.ts | 98 +--- websites/docs/app/server-openapi/page.tsx | 10 +- .../app/docs/sections/schema-boundaries.tsx | 48 +- websites/schema/app/schema-json/page.tsx | 13 +- 35 files changed, 866 insertions(+), 1460 deletions(-) delete mode 100644 libs/schema/src/builders/BoundarySchemaBuilder.test.ts delete mode 100644 libs/schema/src/builders/BoundarySchemaBuilder.ts create mode 100644 libs/schema/src/builders/ReferenceSchemaBuilder.test.ts create mode 100644 libs/schema/src/builders/ReferenceSchemaBuilder.ts delete mode 100644 libs/schema/src/builders/boundaries.test-d.ts create mode 100644 libs/schema/src/builders/references.test-d.ts diff --git a/.changeset/schema-boundaries.md b/.changeset/schema-boundaries.md index e5c45af5..4694b904 100644 --- a/.changeset/schema-boundaries.md +++ b/.changeset/schema-boundaries.md @@ -2,11 +2,9 @@ "@cleverbrush/schema": minor "@cleverbrush/schema-json": minor "@cleverbrush/server-openapi": minor -"@cleverbrush/knex-schema": minor --- -Add optional-aware fallbacks and preprocessing, immutable named schema references, -and typed input/output decoding with nested inference and Standard Schema support. -Generate directional JSON Schema/OpenAPI components with strict name collision -checks. Preserve existing InferType output semantics and legacy optional null -acceptance. Keep ORM navigation inference compatible with the richer schema types. +Add optional-aware fallbacks and preprocessing, and immutable named schema +references with local annotations. Preserve one canonical definition in JSON +Schema, OpenAPI and AsyncAPI with strict name collision checks. Keep existing +type inference and legacy optional null acceptance unchanged. diff --git a/libs/knex-schema/src/entity.ts b/libs/knex-schema/src/entity.ts index 4fbb5254..93ff5896 100644 --- a/libs/knex-schema/src/entity.ts +++ b/libs/knex-schema/src/entity.ts @@ -9,6 +9,7 @@ // extension (compatible with the existing query/include implementation). import { + type ArraySchemaBuilder, type InferType, ObjectSchemaBuilder, type PropertyDescriptorTree, @@ -128,27 +129,18 @@ export type EntityPropSelector< * * @public */ -export type UnwrapNavSchema = TProp extends { - introspect(): { elementSchema: infer TEl }; -} - ? NonNullable extends ObjectSchemaBuilder< - any, - any, - any, - any, - any, - any, - any - > - ? NonNullable - : never - : TProp extends ObjectSchemaBuilder - ? TProp - : TProp extends SchemaBuilder - ? T extends ObjectSchemaBuilder - ? T +export type UnwrapNavSchema = + TProp extends ArraySchemaBuilder + ? TEl extends ObjectSchemaBuilder + ? TEl : never - : never; + : TProp extends ObjectSchemaBuilder + ? TProp + : TProp extends SchemaBuilder + ? T extends ObjectSchemaBuilder + ? T + : never + : never; /** * Merge type for a single polymorphic variant branch: variant schema fields diff --git a/libs/schema-json/README.md b/libs/schema-json/README.md index dacf6292..e6d64655 100644 --- a/libs/schema-json/README.md +++ b/libs/schema-json/README.md @@ -12,13 +12,7 @@ for use in OpenAPI specs, form generators, or any other JSON Schema consumer. ## When to use this library -### Input and output views - -`toJsonSchema(schema, { mode: 'input' })` describes input before decoding/defaults; -`mode: 'output'` (the default) describes validated output. -`withStandardJsonSchema(schema)` exposes the same distinction through -`jsonSchema.input()` and `jsonSchema.output()`. Converters are never executed. -Their arbitrary logic is not representable in JSON Schema. +### Named references Named reference wrappers preserve use-site annotations, optionality and nullability without changing the shared definition. See the [composition guide](../schema/BOUNDARIES.md). diff --git a/libs/schema-json/src/boundaries.test.ts b/libs/schema-json/src/boundaries.test.ts index f0fbf6ac..ea57988e 100644 --- a/libs/schema-json/src/boundaries.test.ts +++ b/libs/schema-json/src/boundaries.test.ts @@ -1,82 +1,13 @@ -import { - array, - decode, - lazy, - number, - object, - record, - schemaRef, - string, - tuple, - union -} from '@cleverbrush/schema'; -import { describe, expect, it, vi } from 'vitest'; +import { object, schemaRef, string } from '@cleverbrush/schema'; +import { describe, expect, it } from 'vitest'; import { withStandardJsonSchema } from './standardJsonSchema.js'; import { toJsonSchema } from './toJsonSchema.js'; -describe('boundary JSON Schema views', () => { - it('does not transfer output nullability or output defaults to input', () => { - const schema = decode(string(), number().nullable(), () => null); - expect(toJsonSchema(schema, { $schema: false, mode: 'input' })).toEqual( - { allOf: [{ type: 'string' }] } - ); - expect(toJsonSchema(schema, { $schema: false }).allOf).toEqual([ - { type: ['integer', 'null'] } - ]); - const withDefault = decode(string(), number(), Number).default(3); - expect( - toJsonSchema(withDefault, { mode: 'input' }).default - ).toBeUndefined(); - expect(toJsonSchema(withDefault).default).toBe(3); - }); - it('exports declared input/output without running converters', () => { - const converter = vi.fn(Number); - const size = decode( - string().minLength(1), - number().isInteger().min(1), - converter - ); - expect(toJsonSchema(size, { $schema: false, mode: 'input' })).toEqual({ - allOf: [{ type: 'string', minLength: 1 }] - }); - expect(toJsonSchema(size, { $schema: false })).toEqual({ - allOf: [{ type: 'integer', minimum: 1 }] - }); - const standard = withStandardJsonSchema(size)['~standard'].jsonSchema; - expect(standard.input({ target: 'draft-2020-12' })).not.toEqual( - standard.output({ target: 'draft-2020-12' }) - ); - expect(converter).not.toHaveBeenCalled(); - }); - - it('tracks input defaults separately from required output', () => { - const size = decode(string().default('1'), number(), Number); - const schema = object({ size, title: string().default('new') }); - expect( - toJsonSchema(schema, { mode: 'input' }).required - ).toBeUndefined(); - expect(toJsonSchema(schema).required).toEqual(['size', 'title']); - }); - - it('respects output presence when defaults follow optional modifiers', () => { - const size = decode(string(), number(), Number).optional().default(5); - const name = schemaRef(string().schemaName('Name')) - .optional() - .default('untitled'); - const schema = object({ size, name }); - expect(schema.parse({})).toEqual({ size: 5, name: 'untitled' }); - expect( - toJsonSchema(schema, { mode: 'input' }).required - ).toBeUndefined(); - expect(toJsonSchema(schema).required).toEqual(['size', 'name']); - const optionalOutput = object({ size: size.optional() }); - expect(toJsonSchema(optionalOutput).required).toBeUndefined(); - }); - +describe('named reference JSON Schema', () => { it.each([ '2020-12', '07' - ] as const)('keeps ref annotations outside the definition in draft %s', draft => { + ] as const)('keeps annotations outside the definition in draft %s', draft => { const user = object({ name: string() }).schemaName('User'); const schema = object({ user: schemaRef(user), @@ -106,18 +37,30 @@ describe('boundary JSON Schema views', () => { expect(user.introspect().description).toBeUndefined(); }); - it('projects nested containers and lazy wrappers', () => { - const size = decode(string(), number(), Number); - const schema = object({ - list: array(size), - pair: tuple([size]), - values: record(string(), size), - option: union(size).or(string()), - later: lazy(() => size) - }); - const input = JSON.stringify(toJsonSchema(schema, { mode: 'input' })); - const output = JSON.stringify(toJsonSchema(schema)); - expect(input).not.toContain('"type":"integer"'); - expect(output).toContain('"type":"integer"'); + it('keeps final local default and nullability modifiers', () => { + const target = string().nullable().schemaName('Name'); + const ref = schemaRef(target).notNullable().optional().default('new'); + const schema = object({ name: ref }); + const json = toJsonSchema(schema) as any; + expect(schema.parse({})).toEqual({ name: 'new' }); + expect(json.required).toEqual(['name']); + expect(json.properties.name.default).toBe('new'); + expect(json.properties.name.allOf).toEqual([ + { type: ['string', 'null'] }, + { not: { type: 'null' } } + ]); + const nullableAgain = toJsonSchema(ref.nullable()); + expect(nullableAgain.anyOf).toBeDefined(); + expect(toJsonSchema(ref.readonly()).readOnly).toBe(true); + }); + + it('retains identical Standard JSON Schema views', () => { + const ref = schemaRef(string().schemaName('Name')) + .optional() + .describe('A name'); + const standard = withStandardJsonSchema(ref)['~standard'].jsonSchema; + expect(standard.input({ target: 'draft-2020-12' })).toEqual( + standard.output({ target: 'draft-2020-12' }) + ); }); }); diff --git a/libs/schema-json/src/standardJsonSchema.ts b/libs/schema-json/src/standardJsonSchema.ts index fb3ddc74..b5e41e18 100644 --- a/libs/schema-json/src/standardJsonSchema.ts +++ b/libs/schema-json/src/standardJsonSchema.ts @@ -1,8 +1,4 @@ -import type { - InferInput, - InferOutput, - SchemaBuilder -} from '@cleverbrush/schema'; +import type { SchemaBuilder } from '@cleverbrush/schema'; import type { StandardJSONSchemaV1 } from '@standard-schema/spec'; import { toJsonSchema } from './toJsonSchema.js'; @@ -35,8 +31,9 @@ function targetToOptions(target: StandardJSONSchemaV1.Target): { * [Standard JSON Schema v1](https://standardschema.dev/) interface. * * The returned schema object's `~standard` property is enriched with a - * `jsonSchema` converter. Input describes values before decoding/defaults; - * output describes validated values. Converter functions are never executed. + * `jsonSchema` converter. Because `@cleverbrush/schema` does not + * distinguish between input and output types, both `input()` and `output()` + * produce the same JSON Schema document. * * **Note:** this mutates the schema instance by overriding the `~standard` * property. The returned reference is the same schema object. @@ -59,19 +56,13 @@ function targetToOptions(target: StandardJSONSchemaV1.Target): { */ export function withStandardJsonSchema< T extends SchemaBuilder ->(schema: T): T & StandardJSONSchemaV1, InferOutput> { +>(schema: T): T & StandardJSONSchemaV1 { const converter: StandardJSONSchemaV1.Converter = { input(options: StandardJSONSchemaV1.Options): Record { - return toJsonSchema(schema, { - ...targetToOptions(options.target), - mode: 'input' - }); + return toJsonSchema(schema, targetToOptions(options.target)); }, output(options: StandardJSONSchemaV1.Options): Record { - return toJsonSchema(schema, { - ...targetToOptions(options.target), - mode: 'output' - }); + return toJsonSchema(schema, targetToOptions(options.target)); } }; @@ -94,5 +85,5 @@ export function withStandardJsonSchema< enumerable: false }); - return schema as T & StandardJSONSchemaV1, InferOutput>; + return schema as T & StandardJSONSchemaV1; } diff --git a/libs/schema-json/src/toJsonSchema.ts b/libs/schema-json/src/toJsonSchema.ts index fad5f28c..b5bbccaf 100644 --- a/libs/schema-json/src/toJsonSchema.ts +++ b/libs/schema-json/src/toJsonSchema.ts @@ -11,57 +11,28 @@ function escapeJsonPointerSegment(s: string): string { return s.replace(/~/g, '~0').replace(/\//g, '~1'); } -/** Whether a property must be present on the selected side of a boundary. */ -function isRequiredInMode( - schema: SchemaBuilder, - mode: 'input' | 'output' -): boolean { - const info = schema.introspect() as any; - // Output presence follows the wrapper's final modifiers. In particular, - // optional().default(...) produces a required output despite the earlier - // explicit input-omission modifier. - if (mode === 'output') return info.isRequired !== false; - if (info.hasDefault) return false; - if (info.type === 'decode' || info.type === 'reference') { - if (info.presence !== undefined) return info.presence; - return isRequiredInMode(info.inputSchema, mode); - } - return info.isRequired !== false; -} - type Resolver = | ((schema: SchemaBuilder) => string | null) | undefined; function convertNodeInner( schema: SchemaBuilder, - resolver: Resolver, - mode: 'input' | 'output' + resolver: Resolver ): Out { const info = schema.introspect() as any; const ext: Record = info.extensions ?? {}; const readOnly: Out = info.isReadonly === true ? { readOnly: true } : {}; switch (info.type) { - case 'reference': - case 'decode': { - const target = - mode === 'input' ? info.inputSchema : info.outputSchema; - const out: Out = { allOf: [convertNode(target, resolver, mode)] }; + case 'reference': { + const out: Out = { + ...readOnly, + allOf: [convertNode(info.targetSchema, resolver)] + }; if (info.nullability === false) (out.allOf as Out[]).push({ not: { type: 'null' } }); return out; } - case 'record': - return { - type: 'object', - propertyNames: convertNode(info.keySchema, resolver, mode), - additionalProperties: convertNode( - info.valueSchema, - resolver, - mode - ) - }; case 'string': { if (info.equalsTo !== undefined) return { ...readOnly, const: info.equalsTo }; @@ -133,7 +104,7 @@ function convertNodeInner( case 'array': { const out: Out = { ...readOnly, type: 'array' }; if (info.elementSchema) - out['items'] = convertNode(info.elementSchema, resolver, mode); + out['items'] = convertNode(info.elementSchema, resolver); if (info.minLength !== undefined) out['minItems'] = info.minLength; if (info.maxLength !== undefined) out['maxItems'] = info.maxLength; if (ext['nonempty'] === true && out['minItems'] === undefined) @@ -146,11 +117,11 @@ function convertNodeInner( info.elements ?? []; const out: Out = { type: 'array', - prefixItems: elements.map(e => convertNode(e, resolver, mode)), + prefixItems: elements.map(e => convertNode(e, resolver)), minItems: elements.length }; if (info.restSchema) { - out['items'] = convertNode(info.restSchema, resolver, mode); + out['items'] = convertNode(info.restSchema, resolver); } else { out['items'] = false; out['maxItems'] = elements.length; @@ -167,8 +138,9 @@ function convertNodeInner( const outProps: Record = {}; const required: string[] = []; for (const [key, propSchema] of Object.entries(props)) { - outProps[key] = convertNode(propSchema, resolver, mode); - if (isRequiredInMode(propSchema, mode)) required.push(key); + outProps[key] = convertNode(propSchema, resolver); + if ((propSchema.introspect() as any).isRequired !== false) + required.push(key); } out['properties'] = outProps; if (required.length > 0) out['required'] = required; @@ -201,7 +173,7 @@ function convertNodeInner( } if (allConst) return { ...readOnly, enum: enumValues }; - const converted = options.map(o => convertNode(o, resolver, mode)); + const converted = options.map(o => convertNode(o, resolver)); const out: Out = { ...readOnly, anyOf: converted @@ -254,8 +226,8 @@ function convertNodeInner( return { ...readOnly, allOf: [ - convertNode(left, resolver, mode), - convertNode(right, resolver, mode) + convertNode(left, resolver), + convertNode(right, resolver) ] }; } @@ -267,7 +239,7 @@ function convertNodeInner( // Recursive schemas without a registered name will cause infinite // recursion here; callers must use .schemaName() to break the cycle. const resolved: SchemaBuilder = info.getter(); - return convertNode(resolved, resolver, mode); + return convertNode(resolved, resolver); } default: @@ -277,8 +249,7 @@ function convertNodeInner( function convertNode( schema: SchemaBuilder, - resolver: Resolver, - mode: 'input' | 'output' + resolver: Resolver ): Out { if (resolver) { const name = resolver(schema); @@ -288,7 +259,7 @@ function convertNode( }; } } - const out = convertNodeInner(schema, resolver, mode); + const out = convertNodeInner(schema, resolver); const info = schema.introspect() as any; if (typeof info.description === 'string' && info.description !== '') out['description'] = info.description; @@ -301,10 +272,6 @@ function convertNode( // Emit default for serializable primitives (not factory functions) if ( info.hasDefault === true && - !( - mode === 'input' && - (info.type === 'decode' || info.type === 'reference') - ) && info.defaultValue !== undefined && typeof info.defaultValue !== 'function' ) { @@ -313,7 +280,7 @@ function convertNode( // Handle nullable — JSON Schema 2020-12 style: type becomes an array if ( - info.type === 'reference' || info.type === 'decode' + info.type === 'reference' ? info.nullability === true : info.isNullable === true ) { @@ -324,11 +291,10 @@ function convertNode( if (!hasNull) anyOf.push({ type: 'null' }); } else if (out['allOf'] !== undefined && out['type'] === undefined) { // Intersection type without a top-level type — wrap in oneOf with null - out[ - info.type === 'reference' || info.type === 'decode' - ? 'anyOf' - : 'oneOf' - ] = [{ allOf: out['allOf'] as Out[] }, { type: 'null' }]; + out[info.type === 'reference' ? 'anyOf' : 'oneOf'] = [ + { allOf: out['allOf'] as Out[] }, + { type: 'null' } + ]; delete out['allOf']; } else if (out['enum'] !== undefined) { // Enum — add null to enum values if not already present @@ -412,11 +378,7 @@ export function toJsonSchema( schema: SchemaBuilder, opts?: ToJsonSchemaOptions ): Record { - const body = convertNode( - schema, - opts?.nameResolver, - opts?.mode ?? 'output' - ); + const body = convertNode(schema, opts?.nameResolver); if (opts?.$schema === false) return body; const draft = opts?.draft ?? '2020-12'; const uri = diff --git a/libs/schema-json/src/types.ts b/libs/schema-json/src/types.ts index afb1f950..089b9748 100644 --- a/libs/schema-json/src/types.ts +++ b/libs/schema-json/src/types.ts @@ -137,8 +137,6 @@ export type InferFromJsonSchema = S extends { readonly const: infer V } /** Options accepted by {@link toJsonSchema}. */ export type ToJsonSchemaOptions = { - /** Declared input before decoding/defaults, or validated output. @default 'output' */ - mode?: 'input' | 'output'; /** * JSON Schema draft version to reference in the `$schema` header. * @default '2020-12' diff --git a/libs/schema/BOUNDARIES.md b/libs/schema/BOUNDARIES.md index 589b6544..0fe12617 100644 --- a/libs/schema/BOUNDARIES.md +++ b/libs/schema/BOUNDARIES.md @@ -37,8 +37,8 @@ const normalizedText = string().optional() Preprocessors can return optional/nullable values, including asynchronously. Their existing callback parameter typing is preserved; it is not a guarantee that unknown runtime input already has that type. Use explicit guards or -`decode` at untrusted boundaries. Global strict null rejection is a separate, -compatibility-sensitive follow-up. +preprocessing/conversion followed by validation at untrusted boundaries. +Global strict null rejection is a separate, compatibility-sensitive follow-up. ## One named definition, many annotated references @@ -65,87 +65,21 @@ nullability controls null acceptance for the wrapper independently. JSON Schema/OpenAPI keeps one definition and uses reference composition for local annotations, examples and nullability, including Draft 07 references. -## Declare both sides of a conversion +## Defaults and validation -```ts -import { decode, type InferInput, type InferOutput, number, object, string } - from '@cleverbrush/schema'; - -const PageSize = decode( - string(), - number().isInteger().min(1).max(100), - value => Number(value) -); -const SearchInput = object({ - pageSize: PageSize, - term: string().default('') -}); - -type Editable = InferInput; // pageSize is string -type Validated = InferOutput; // pageSize is number -const request = SearchInput.parse({ pageSize: '20' }); -``` - -Parsing validates the input, invokes the converter once, then validates its -output. Converter exceptions/rejections become validation failures. Asynchronous -converters require `parseAsync`/`validateAsync`; synchronous parsing rejects -Promise-returning conversion. Runtime parsing always validates unknown values. - -Nested objects, arrays, tuples, records, unions, intersections, references and -lazy schemas retain input/output inference. Recursive schemas still require -explicit TypeScript annotations. Standard Schema exposes the corresponding -input/output types. `InferOutput` is an alias for `InferType`. - -An input-schema default runs before conversion. A default on the boundary itself -is an **output** default, validated without conversion. Optional/nullable -use-site modifiers bypass conversion for their allowed sentinel values. - -### Application-agnostic example - -```ts -const Priority = decode( - string().oneOf('low', 'normal', 'high'), - number().min(1).max(3), - value => ({ low: 1, normal: 2, high: 3 })[value] -); -const Ticket = object({ title: string().minLength(1), priority: Priority }); -Ticket.parse({ title: 'Improve documentation', priority: 'high' }); -// { title: 'Improve documentation', priority: 3 } -``` - -Conversion policy remains application-owned: trimming, empty strings, numeric -precision, date formats and intentional data loss are not global defaults. - -## JSON Schema and OpenAPI - -```ts -import { toJsonSchema, withStandardJsonSchema } from '@cleverbrush/schema-json'; - -toJsonSchema(PageSize, { mode: 'input' }); // declared string shape -toJsonSchema(PageSize, { mode: 'output' }); // constrained numeric shape -toJsonSchema(PageSize); // output remains the default - -const standard = withStandardJsonSchema(PageSize)['~standard']; -standard.jsonSchema.input({ target: 'draft-2020-12' }); -standard.jsonSchema.output({ target: 'draft-2020-12' }); -``` - -Converters are never executed by schema export. JSON Schema describes the -declared shapes, not arbitrary converter logic or opaque custom validators. - -OpenAPI uses input views for requests and output views for responses. Named -schemas with different views receive `NameInput` and `NameOutput` components; -unchanged views retain their original name. Generated-name collisions throw, -including collisions propagated through nested named or recursive references. -AsyncAPI incoming/outgoing payloads use the same directional model. +A default on the reference overrides missing values at that use site and is +validated by the target. Clearing it leaves any target default intact. Local +fallbacks use the existing catch semantics. Async target validators and local +callbacks require `parseAsync`/`validateAsync`. -## Adoption boundary +Use `InferType` for schema inference and the existing `hasType` method when an +explicit static override is needed. Static overrides and casts do not change +runtime validation or convert values. -This release does **not** redesign React form state or typed HTTP client request -inference. Those consumers may still assume input equals output. Do not treat a -decoder as a drop-in shared form/endpoint contract for those APIs. +## API documents -Until that adoption, keep an explicit wire schema in shared contracts and decode -inside the application boundary/handler, then return the validated output DTO. -A decoder is not an encoder: no reverse conversion is inferred for requests, -URLs, response serialization, database writes or editable form state. +JSON Schema, OpenAPI and AsyncAPI retain one canonical component per named +target. Reference annotations compose around that definition rather than +changing it. Named recursive references are supported; independently rebuilt +schemas with the same name still conflict. Standard JSON Schema `input()` and +`output()` retain their existing identical representation. diff --git a/libs/schema/README.md b/libs/schema/README.md index f925db2a..d602cdab 100644 --- a/libs/schema/README.md +++ b/libs/schema/README.md @@ -2,12 +2,9 @@ ## Schemas across boundaries -Use optional-aware `catch(undefined)`, `schemaRef(namedSchema)` for per-use -annotations, and `decode(inputSchema, outputSchema, converter)` for explicit -conversion. `InferInput` describes editable input; `InferOutput` and the existing -`InferType` describe validated output. See the [boundary composition guide](./BOUNDARIES.md) -for examples, null-compatibility limitations, and the separate form/client -adoption boundary. +Use optional-aware `catch(undefined)` and `schemaRef(namedSchema)` for per-use +annotations without cloning named definitions. See the +[composition guide](./BOUNDARIES.md) for examples and null-compatibility limits. [![CI](https://github.com/cleverbrush/framework/actions/workflows/ci.yml/badge.svg)](https://github.com/cleverbrush/framework/actions/workflows/ci.yml) [![Standard Schema v1](https://img.shields.io/badge/Standard%20Schema-v1-blue)](https://standardschema.dev/) diff --git a/libs/schema/src/boundaries-docs.test.ts b/libs/schema/src/boundaries-docs.test.ts index be8378e4..d023d40f 100644 --- a/libs/schema/src/boundaries-docs.test.ts +++ b/libs/schema/src/boundaries-docs.test.ts @@ -7,12 +7,8 @@ describe('published boundary documentation', () => { const missing: string[] = []; for (const [path, names] of [ [ - '../dist/builders/BoundarySchemaBuilder.d.ts', - ['BoundarySchemaBuilder', 'schemaRef', 'decode'] - ], - [ - '../dist/builders/SchemaBuilder.d.ts', - ['InferInput', 'InferOutput'] + '../dist/builders/ReferenceSchemaBuilder.d.ts', + ['ReferenceSchemaBuilder', 'schemaRef'] ], ['../../schema-json/dist/types.d.ts', ['ToJsonSchemaOptions']] ] as const) { diff --git a/libs/schema/src/builders/ArraySchemaBuilder.ts b/libs/schema/src/builders/ArraySchemaBuilder.ts index bcbd575f..a044538b 100644 --- a/libs/schema/src/builders/ArraySchemaBuilder.ts +++ b/libs/schema/src/builders/ArraySchemaBuilder.ts @@ -5,7 +5,6 @@ import type { import { type BRAND, createHybridErrorArray, - type InferInput, type InferType, type NestedValidationResult, type PropertyDescriptor, @@ -102,8 +101,8 @@ export class ArraySchemaBuilder< TResult = TExplicitType extends undefined ? TElementSchema extends undefined ? Array - : TElementSchema extends SchemaBuilder - ? Array> + : TElementSchema extends SchemaBuilder + ? Array>> : never : TExplicitType > extends SchemaBuilder< @@ -111,8 +110,7 @@ export class ArraySchemaBuilder< TRequired, TNullable, THasDefault, - TExtensions, - Array> + TExtensions > { #minLength?: number; #defaultMinLengthErrorMessageProvider: ValidationErrorMessageProvider< diff --git a/libs/schema/src/builders/BoundarySchemaBuilder.test.ts b/libs/schema/src/builders/BoundarySchemaBuilder.test.ts deleted file mode 100644 index b78c1b60..00000000 --- a/libs/schema/src/builders/BoundarySchemaBuilder.test.ts +++ /dev/null @@ -1,167 +0,0 @@ -import { describe, expect, it, vi } from 'vitest'; -import { - array, - boolean, - decode, - number, - object, - schemaRef, - string -} from '../index.js'; - -describe('schema boundaries', () => { - it('accepts optional/nullable fallbacks and preserves legacy null acceptance', async () => { - const text = string().optional().catch(undefined); - expect(text.parse(42)).toBeUndefined(); - expect(await text.parseAsync(false)).toBeUndefined(); - expect(text.parse(null)).toBeNull(); - expect(string().nullable().catch(null).parse(42)).toBeNull(); - const normalize = string() - .optional() - .addPreprocessor(v => (v == null ? undefined : v)) - .catch(undefined); - expect(normalize.parse(null)).toBeUndefined(); - expect(object({ text }).safeParse(null).valid).toBe(false); - expect( - object({ - text, - flag: boolean() - .optional() - .catch(() => undefined) - }).parse({ text: {}, flag: 1 }) - ).toEqual({ text: undefined, flag: undefined }); - }); - - it('validates both sides and converts once', () => { - const convert = vi.fn(Number); - const size = decode( - string(), - number().isInteger().min(1).max(100), - convert - ); - expect(size.parse('12')).toBe(12); - expect(convert).toHaveBeenCalledTimes(1); - expect(size.safeParse(12).valid).toBe(false); - expect(convert).toHaveBeenCalledTimes(1); - expect(size.safeParse('0').valid).toBe(false); - expect(size.safeParse('nope').valid).toBe(false); - expect(object({ size }).parse({ size: '5' })).toEqual({ size: 5 }); - expect(array(size).parse(['2', '3'])).toEqual([2, 3]); - }); - - it('supports async conversion and captures converter failures', async () => { - const size = decode(string(), number(), async value => Number(value)); - expect(() => size.parse('1')).toThrow(/parseAsync/); - expect(await size.parseAsync('2')).toBe(2); - expect(await size['~standard'].validate('3')).toEqual({ value: 3 }); - const broken = decode(string(), number(), () => { - throw new Error('not convertible'); - }); - expect(broken.safeParse('x')).toMatchObject({ - valid: false, - errors: [{ message: 'Decoder failed: not convertible' }] - }); - const rejected = decode(string(), number(), async () => { - throw new Error('rejected'); - }); - expect((await rejected.safeParseAsync('x')).valid).toBe(false); - }); - - it('handles input defaults, output defaults and use-site modifiers', () => { - const size = decode(string().default('2'), number(), Number); - expect(size.parse(undefined)).toBe(2); - expect(size.optional().parse(undefined)).toBeUndefined(); - expect(size.nullable().parse(null)).toBeNull(); - expect(size.default(4).parse(undefined)).toBe(4); - expect(size.default(4).clearDefault().parse(undefined)).toBe(2); - expect(size.optional().required().safeParse(undefined).valid).toBe( - false - ); - }); - - it('preserves one named definition and local metadata', () => { - const user = object({ name: string().minLength(1) }).schemaName('User'); - const ref = schemaRef(user); - const previous = ref.nullable().optional().describe('Previous user'); - expect(ref.introspect().outputSchema).toBe(user); - expect(previous.introspect().outputSchema).toBe(user); - expect(user.introspect().description).toBeUndefined(); - expect(ref.safeParse(null).valid).toBe(false); - expect(previous.parse(null)).toBeNull(); - expect(previous.parse(undefined)).toBeUndefined(); - expect(previous.parse({ name: 'Ada' })).toEqual({ name: 'Ada' }); - expect(() => schemaRef(string())).toThrow(/named schema/); - }); - - it('preserves nested reference errors and selectors', () => { - const user = object({ name: string().minLength(1) }).schemaName('User'); - const result = object({ user: schemaRef(user) }).validate({ - user: { name: '' } - }); - expect(result.valid).toBe(false); - expect( - result.getErrorsFor(t => t.user.name).errors.length - ).toBeGreaterThan(0); - expect( - result.getInvalidProperties().map(p => p.descriptor.toJsonPointer()) - ).toContain('/user/name'); - }); -}); - -describe('decoding boundary edge cases', () => { - it('uses output defaults and never re-runs conversion for catch', async () => { - const convert = vi.fn(() => undefined); - const schema = decode(string(), number().default(8), convert); - expect(schema.parse('missing')).toBe(8); - expect(convert).toHaveBeenCalledTimes(1); - const fail = vi.fn(() => { - throw new Error('conversion'); - }); - const fallback = decode(string(), number(), fail).catch(() => 4); - expect(fallback.parse('x')).toBe(4); - expect(await fallback.parseAsync('y')).toBe(4); - expect(fail).toHaveBeenCalledTimes(2); - }); - - it('keeps required messages and sync/async rules', async () => { - const schema = decode(string(), number(), Number).optional(); - expect( - schema.required('Provide a size').safeParse(undefined).errors?.[0] - .message - ).toBe('Provide a size'); - const asyncRequired = schema.required(async () => 'Async required'); - expect(() => asyncRequired.parse(undefined)).toThrow(/Async|async/); - expect( - (await asyncRequired.safeParseAsync(undefined)).errors?.[0].message - ).toBe('Async required'); - }); - - it('retains nested errors from both decoding stages', () => { - const schema = object({ - item: decode( - object({ input: object({ value: string().minLength(1) }) }), - object({ output: object({ count: number().min(1) }) }), - input => ({ output: { count: Number(input.input.value) } }) - ) - }); - const inputFailure = schema.validate({ - item: { input: { value: '' } } - } as any); - expect( - inputFailure - .getInvalidProperties() - .map(p => p.descriptor.toJsonPointer()) - ).toContain('/item/input/value'); - const outputFailure = schema.validate({ - item: { input: { value: '0' } } - } as any); - expect( - outputFailure.getErrorsFor(t => t.item.output.count).errors.length - ).toBeGreaterThan(0); - expect( - outputFailure - .getInvalidProperties() - .map(p => p.descriptor.toJsonPointer()) - ).toContain('/item/output/count'); - }); -}); diff --git a/libs/schema/src/builders/BoundarySchemaBuilder.ts b/libs/schema/src/builders/BoundarySchemaBuilder.ts deleted file mode 100644 index c9eac67b..00000000 --- a/libs/schema/src/builders/BoundarySchemaBuilder.ts +++ /dev/null @@ -1,528 +0,0 @@ -import { - type BRAND, - type InferInput, - type InferOutput, - SchemaBuilder, - type SchemaBuilderProps, - SYMBOL_HAS_PROPERTIES, - type ValidationContext, - type ValidationErrorMessageProvider, - type ValidationResult -} from './SchemaBuilder.js'; - -type AnySchema = SchemaBuilder; -type BoundaryOutput< - TOutputSchema, - TRequired extends boolean, - TNullable extends boolean, - TExplicitType -> = - | (TRequired extends true - ? Exclude< - TExplicitType extends undefined - ? InferOutput - : TExplicitType, - undefined - > - : - | (TExplicitType extends undefined - ? InferOutput - : TExplicitType) - | undefined) - | (TNullable extends true ? null : never); - -type BoundaryProps = Partial> & { - type: 'reference' | 'decode'; - inputSchema: AnySchema; - outputSchema: AnySchema; - converter?: (value: any) => any; - presence?: boolean; - nullability?: boolean; -}; - -/** - * Immutable schema boundary returned by {@link schemaRef} and {@link decode}. - * Use the factories rather than constructing this class. Local modifiers never - * mutate the input/output schemas or their named definitions. - * @typeParam TInputSchema - Schema validating values before conversion. - * @typeParam TOutputSchema - Schema validating converted values. - * @typeParam TRequired - Whether the output includes undefined. - * @typeParam TNullable - Whether null is allowed by a use-site modifier. - * @typeParam THasDefault - Whether the wrapper supplies an output default. - * @typeParam TExplicitType - Optional static output override. - * @typeParam TInput - Declared input, including use-site presence modifiers. - */ -export class BoundarySchemaBuilder< - TInputSchema extends AnySchema, - TOutputSchema extends AnySchema, - TRequired extends boolean = true, - TNullable extends boolean = false, - THasDefault extends boolean = false, - TExplicitType = undefined, - TInput = InferInput -> extends SchemaBuilder< - BoundaryOutput, - TRequired, - TNullable, - THasDefault, - {}, - InferInput, - TInput | (THasDefault extends true ? undefined : never) -> { - readonly #boundary: BoundaryProps; - /** @internal Enables nested property descriptors without subclassing objects. */ - readonly [SYMBOL_HAS_PROPERTIES] = true; - - /** @internal Factory configuration is exposed for immutable reconstruction. */ - constructor(props: BoundaryProps) { - super({ preprocessors: [], validators: [], ...props }); - this.#boundary = props; - } - - /** Describes both sides without evaluating the converter. */ - public introspect() { - return { - ...super.introspect(), - inputSchema: this.#boundary.inputSchema as TInputSchema, - outputSchema: this.#boundary.outputSchema as TOutputSchema, - converter: this.#boundary.converter, - presence: this.#boundary.presence, - nullability: this.#boundary.nullability, - // Object consumers can preserve real descriptor schemas through refs. - properties: - this.type === 'reference' - ? (this.#boundary.outputSchema.introspect() as any) - .properties - : undefined - }; - } - - /** @internal Rebuilds the wrapper while retaining the same target instances. */ - protected createFromProps(props: BoundaryProps): this { - return new BoundarySchemaBuilder(props) as this; - } - - #early(value: unknown): ValidationResult | undefined { - if (value === undefined && this.hasDefault) return undefined; - if (value === undefined && this.#boundary.presence !== undefined) { - return this.#boundary.presence - ? { valid: false, errors: [{ message: 'is required' }] } - : { valid: true, object: undefined }; - } - if (value === null && this.#boundary.nullability !== undefined) { - return this.#boundary.nullability - ? { valid: true, object: null } - : { valid: false, errors: [{ message: 'must not be null' }] }; - } - return undefined; - } - - #converterFailure(error: unknown): ValidationResult { - return { - valid: false, - errors: [ - { - message: `Decoder failed: ${error instanceof Error ? error.message : String(error)}` - } - ] - }; - } - - #stageFailure( - result: ValidationResult, - schema: AnySchema - ): ValidationResult { - return Object.assign(result, { __boundaryErrorSchema: schema }); - } - - /** Validates unknown input; an output fallback is never decoded a second time. */ - public validate( - value: unknown, - context?: ValidationContext - ): ValidationResult< - BoundaryOutput - > { - const result = this._validate(value, context); - if (result.valid || !this.hasCatch) return result; - const fallback = this.resolveCatchValue(); - const checked = this.#boundary.outputSchema.validate(fallback, context); - return checked.valid ? checked : { valid: true, object: fallback }; - } - - /** Async validation with the same output-fallback and error semantics as validate. */ - public async validateAsync( - value: unknown, - context?: ValidationContext - ): Promise< - ValidationResult< - BoundaryOutput - > - > { - const result = await this._validateAsync(value, context); - if (result.valid || !this.hasCatch) return result; - const fallback = this.resolveCatchValue(); - const checked = await this.#boundary.outputSchema.validateAsync( - fallback, - context - ); - return checked.valid ? checked : { valid: true, object: fallback }; - } - - /** @internal Validates input, converts once, and validates output. */ - protected _validate( - value: unknown, - context?: ValidationContext - ): ValidationResult { - const early = this.#early(value); - if (early) { - if (!early.valid && value === undefined) - early.errors = [ - { - message: this.getValidationErrorMessageSync( - this.requiredErrorMessage, - value as any - ) - } - ]; - return early; - } - const usesDefault = value === undefined && this.hasDefault; - const input = usesDefault - ? { valid: true, object: this.resolveDefaultValue() } - : this.#boundary.inputSchema.validate(value, context); - if (!input.valid) - return this.#stageFailure(input, this.#boundary.inputSchema); - let converted = input.object; - if (!usesDefault && this.#boundary.converter) { - try { - converted = this.#boundary.converter(converted); - } catch (error) { - return this.#converterFailure(error); - } - if (converted != null && typeof converted.then === 'function') { - throw new Error( - 'Decoder returned a Promise. Use validateAsync() or parseAsync().' - ); - } - } - const output = - this.type === 'reference' && !usesDefault - ? input - : this.#boundary.outputSchema.validate(converted, context); - if (!output.valid) - return this.#stageFailure(output, this.#boundary.outputSchema); - if (output.object === null && this.#boundary.nullability === false) { - return { valid: false, errors: [{ message: 'must not be null' }] }; - } - const prepared = this.preValidateSync(output.object, context); - if (!prepared.valid) return { valid: false, errors: prepared.errors }; - const preparedValue = prepared.transaction!.object.validatedObject; - if (this.preprocessors.length === 0) return output; - return this.#boundary.outputSchema.validate(preparedValue, context); - } - - /** @internal Async counterpart; converter rejections are validation failures. */ - protected async _validateAsync( - value: unknown, - context?: ValidationContext - ): Promise> { - const early = this.#early(value); - if (early) { - if (!early.valid && value === undefined) - early.errors = [ - { - message: await this.getValidationErrorMessage( - this.requiredErrorMessage, - value as any - ) - } - ]; - return early; - } - const usesDefault = value === undefined && this.hasDefault; - const input = usesDefault - ? { valid: true, object: this.resolveDefaultValue() } - : await this.#boundary.inputSchema.validateAsync(value, context); - if (!input.valid) - return this.#stageFailure(input, this.#boundary.inputSchema); - let converted = input.object; - if (!usesDefault && this.#boundary.converter) { - try { - converted = await this.#boundary.converter(converted); - } catch (error) { - return this.#converterFailure(error); - } - } - const output = - this.type === 'reference' && !usesDefault - ? input - : await this.#boundary.outputSchema.validateAsync( - converted, - context - ); - if (!output.valid) - return this.#stageFailure(output, this.#boundary.outputSchema); - if (output.object === null && this.#boundary.nullability === false) { - return { valid: false, errors: [{ message: 'must not be null' }] }; - } - const prepared = await this.preValidateAsync(output.object, context); - if (!prepared.valid) return { valid: false, errors: prepared.errors }; - const preparedValue = prepared.transaction!.object.validatedObject; - if (this.preprocessors.length === 0) return output; - return this.#boundary.outputSchema.validateAsync( - preparedValue, - context - ); - } - - /** Overrides only the static output type; runtime validation is unchanged. */ - public hasType( - _notUsed?: T - ): BoundarySchemaBuilder< - TInputSchema, - TOutputSchema, - TRequired, - TNullable, - THasDefault, - T, - TInput - > { - return this.createFromProps(this.#props()) as any; - } - - /** Restores output inference from the output schema. */ - public clearHasType(): BoundarySchemaBuilder< - TInputSchema, - TOutputSchema, - TRequired, - TNullable, - THasDefault, - undefined, - TInput - > { - return this.createFromProps(this.#props()) as any; - } - - #props(): BoundaryProps { - return { - ...this.#boundary, - ...this.introspect(), - type: this.#boundary.type, - preprocessors: [...this.preprocessors], - validators: [...this.validators] - }; - } - - /** Rejects missing input at this use site. */ - public required( - errorMessage?: ValidationErrorMessageProvider - ): BoundarySchemaBuilder< - TInputSchema, - TOutputSchema, - true, - TNullable, - THasDefault, - TExplicitType, - Exclude - > { - return this.createFromProps({ - ...this.#props(), - isRequired: true, - presence: true, - requiredValidationErrorMessageProvider: errorMessage - }) as any; - } - - /** Allows omitted input at this use site, without invoking the boundary. */ - public optional(): BoundarySchemaBuilder< - TInputSchema, - TOutputSchema, - false, - TNullable, - THasDefault, - TExplicitType, - TInput | undefined - > { - return this.createFromProps({ - ...this.#props(), - isRequired: false, - presence: false - }) as any; - } - - /** Allows null at this use site, independently of optionality. */ - public nullable(): BoundarySchemaBuilder< - TInputSchema, - TOutputSchema, - TRequired, - true, - THasDefault, - TExplicitType, - TInput | null - > { - return this.createFromProps({ - ...this.#props(), - isNullable: true, - nullability: true - }) as any; - } - - /** Rejects null at this use site without changing the referenced definition. */ - public notNullable(): BoundarySchemaBuilder< - TInputSchema, - TOutputSchema, - TRequired, - false, - THasDefault, - Exclude< - TExplicitType extends undefined - ? InferOutput - : TExplicitType, - null - >, - Exclude - > { - return this.createFromProps({ - ...this.#props(), - isNullable: false, - nullability: false - }) as any; - } - - /** Supplies an output default for missing input; validates it without decoding. */ - public default( - value: InferOutput | (() => InferOutput) - ): BoundarySchemaBuilder< - TInputSchema, - TOutputSchema, - true, - TNullable, - true, - TExplicitType, - TInput - > { - return this.createFromProps({ - ...this.#props(), - defaultValue: value, - isRequired: true - }) as any; - } - - /** Removes the use-site default; defaults on the target are unchanged. */ - public clearDefault(): BoundarySchemaBuilder< - TInputSchema, - TOutputSchema, - TRequired, - TNullable, - false, - TExplicitType, - TInput - > { - return this.createFromProps({ - ...this.#props(), - defaultValue: undefined - }) as any; - } - - /** Brands the output type only; it does not alter runtime validation. */ - public brand( - _name?: B - ): BoundarySchemaBuilder< - TInputSchema, - TOutputSchema, - TRequired, - TNullable, - THasDefault, - (TExplicitType extends undefined - ? InferOutput - : TExplicitType) & { - readonly [K in BRAND]: B; - }, - TInput - > { - return super.brand(_name); - } - - /** Makes the output type readonly without freezing runtime values. */ - public readonly(): BoundarySchemaBuilder< - TInputSchema, - TOutputSchema, - TRequired, - TNullable, - THasDefault, - Readonly< - TExplicitType extends undefined - ? InferOutput - : TExplicitType - >, - TInput - > { - return super.readonly(); - } -} - -type RequiredOf = undefined extends InferOutput ? false : true; -type NullableOf = null extends InferOutput ? true : false; - -/** - * References one named definition with independent use-site annotations. - * @param schema - A reused schema constant with a nonempty schemaName. - * @returns An immutable reference wrapper; the named target is not cloned. - * @throws Error if the target has no name. - * @example - * const User = object({ name: string() }).schemaName('User'); - * const previous = schemaRef(User).nullable().optional().describe('Previous user'); - */ -export function schemaRef( - schema: S -): BoundarySchemaBuilder, NullableOf> { - const info = schema.introspect(); - if (!info.schemaName?.trim()) - throw new Error('schemaRef requires a named schema.'); - return new BoundarySchemaBuilder({ - type: 'reference', - inputSchema: schema, - outputSchema: schema, - isRequired: info.isRequired, - isNullable: info.isNullable - }); -} - -/** - * Composes input validation, an explicit conversion, and output validation. - * @param inputSchema - Validates external input before the converter runs. - * @param outputSchema - Validates the converted result. - * @param converter - Receives validated input; may return a Promise. - * @returns A schema with distinct inferred input/output types. - * @remarks Converter exceptions become validation failures. Async converters - * require parseAsync/validateAsync. JSON Schema documents declared shapes only, - * not arbitrary conversion logic. This is not a bidirectional codec. - * @example - * const PageSize = decode(string(), number().isInteger().min(1), Number); - * PageSize.parse('12'); // 12 - */ -export function decode< - TInputSchema extends AnySchema, - TOutputSchema extends AnySchema ->( - inputSchema: TInputSchema, - outputSchema: TOutputSchema, - converter: ( - input: InferOutput - ) => InferInput | Promise> -): BoundarySchemaBuilder< - TInputSchema, - TOutputSchema, - RequiredOf, - NullableOf -> { - const info = outputSchema.introspect(); - return new BoundarySchemaBuilder({ - type: 'decode', - inputSchema, - outputSchema, - converter, - isRequired: info.isRequired, - isNullable: info.isNullable - }); -} diff --git a/libs/schema/src/builders/ExternSchemaBuilder.ts b/libs/schema/src/builders/ExternSchemaBuilder.ts index 76fb55ec..6d4fb12d 100644 --- a/libs/schema/src/builders/ExternSchemaBuilder.ts +++ b/libs/schema/src/builders/ExternSchemaBuilder.ts @@ -100,8 +100,7 @@ export class ExternSchemaBuilder< TRequired, TNullable, THasDefault, - TExtensions, - StandardSchemaV1.InferInput + TExtensions > { #standardSchema: TStandardSchema; diff --git a/libs/schema/src/builders/IntersectionSchemaBuilder.ts b/libs/schema/src/builders/IntersectionSchemaBuilder.ts index 47488a6b..6d746c6a 100644 --- a/libs/schema/src/builders/IntersectionSchemaBuilder.ts +++ b/libs/schema/src/builders/IntersectionSchemaBuilder.ts @@ -1,6 +1,5 @@ import { type BRAND, - type InferInput, type InferType, SchemaBuilder, type ValidationContext, @@ -37,8 +36,7 @@ export class IntersectionSchemaBuilder< TRequired, TNullable, THasDefault, - TExtensions, - InferInput & InferInput + TExtensions > { #left!: TLeft; #right!: TRight; diff --git a/libs/schema/src/builders/LazySchemaBuilder.ts b/libs/schema/src/builders/LazySchemaBuilder.ts index cc0ede6c..12f0d7c5 100644 --- a/libs/schema/src/builders/LazySchemaBuilder.ts +++ b/libs/schema/src/builders/LazySchemaBuilder.ts @@ -1,7 +1,5 @@ import { type BRAND, - type InferInput, - type InferOutput, SchemaBuilder, type ValidationContext, type ValidationErrorMessageProvider, @@ -51,15 +49,13 @@ export class LazySchemaBuilder< TRequired extends boolean = true, TNullable extends boolean = false, THasDefault extends boolean = false, - TExtensions = {}, - TInput = TResult + TExtensions = {} > extends SchemaBuilder< TResult, TRequired, TNullable, THasDefault, - TExtensions, - TInput + TExtensions > { #getter: () => SchemaBuilder; #resolvedSchema: SchemaBuilder | null = null; @@ -214,7 +210,7 @@ export class LazySchemaBuilder< */ public hasType( _notUsed?: T - ): LazySchemaBuilder & + ): LazySchemaBuilder & TExtensions { return this.createFromProps({ ...this.introspect() @@ -229,8 +225,7 @@ export class LazySchemaBuilder< TRequired, TNullable, THasDefault, - TExtensions, - TInput + TExtensions > & TExtensions { return this.createFromProps({ @@ -243,14 +238,7 @@ export class LazySchemaBuilder< */ public required( errorMessage?: ValidationErrorMessageProvider - ): LazySchemaBuilder< - TResult, - true, - TNullable, - THasDefault, - TExtensions, - TInput - > & + ): LazySchemaBuilder & TExtensions { return super.required(errorMessage); } @@ -263,8 +251,7 @@ export class LazySchemaBuilder< false, TNullable, THasDefault, - TExtensions, - TInput + TExtensions > & TExtensions { return super.optional(); @@ -275,7 +262,7 @@ export class LazySchemaBuilder< */ public default( value: TResult | (() => TResult) - ): LazySchemaBuilder & + ): LazySchemaBuilder & TExtensions { return super.default(value) as any; } @@ -288,8 +275,7 @@ export class LazySchemaBuilder< TRequired, TNullable, false, - TExtensions, - TInput + TExtensions > & TExtensions { return super.clearDefault() as any; @@ -305,8 +291,7 @@ export class LazySchemaBuilder< TRequired, TNullable, THasDefault, - TExtensions, - TInput + TExtensions > & TExtensions { return super.brand(_name); @@ -320,8 +305,7 @@ export class LazySchemaBuilder< TRequired, TNullable, THasDefault, - TExtensions, - TInput + TExtensions > & TExtensions { return super.readonly(); @@ -335,8 +319,7 @@ export class LazySchemaBuilder< TRequired, true, THasDefault, - TExtensions, - TInput + TExtensions > & TExtensions { return super.nullable() as any; @@ -350,8 +333,7 @@ export class LazySchemaBuilder< TRequired, false, THasDefault, - TExtensions, - TInput + TExtensions > & TExtensions { return super.notNullable() as any; @@ -390,12 +372,6 @@ export class LazySchemaBuilder< * }); * ``` */ -export function lazy>( - getter: () => S -): LazySchemaBuilder, true, false, false, {}, InferInput>; -export function lazy( - getter: () => SchemaBuilder -): LazySchemaBuilder; export function lazy( getter: () => SchemaBuilder ): LazySchemaBuilder { diff --git a/libs/schema/src/builders/ObjectSchemaBuilder.ts b/libs/schema/src/builders/ObjectSchemaBuilder.ts index 4ce3529a..5563d7f0 100644 --- a/libs/schema/src/builders/ObjectSchemaBuilder.ts +++ b/libs/schema/src/builders/ObjectSchemaBuilder.ts @@ -1,7 +1,6 @@ import { PropertyValidationResult } from './PropertyValidationResult.js'; import { type BRAND, - type InferInput, type InferType, type NestedValidationResult, type PreValidationResult, @@ -138,9 +137,9 @@ export type RespectPropsOptionality< type RespectPropsOptionalityForInput< T extends Record> > = { - [K in RequiredInputProps]: InferInput; + [K in RequiredInputProps]: InferType; } & { - [K in NotRequiredInputProps]?: InferInput; + [K in NotRequiredInputProps]?: InferType; }; type MakeChildrenRequired< @@ -377,8 +376,7 @@ export class ObjectSchemaBuilder< TRequired, TNullable, THasDefault, - TExtensions, - RespectPropsOptionalityForInput + TExtensions > { #properties: TProperties = {} as any; #acceptUnknownProps = false; @@ -1076,8 +1074,7 @@ export class ObjectSchemaBuilder< result as any, descriptor, addErrorFor, - (result as any).__boundaryErrorSchema ?? - this.#properties[key] + this.#properties[key] ); // For extern schemas, also record errors on the extern // descriptor itself so getErrorsFor(t => t.extern) works, @@ -1846,8 +1843,7 @@ export class ObjectSchemaBuilder< TRequired, TNullable, THasDefault, - TExtensions, - RespectPropsOptionalityForInput + TExtensions > { return this.createFromProps({ ...this.introspect() @@ -2769,7 +2765,6 @@ export class ObjectSchemaBuilder< ): void { const schema = schemaOverride ?? - result.__boundaryErrorSchema ?? ObjectSchemaBuilder.#getSchemaForPropertyDescriptor(descriptor); const properties = (schema.introspect() as any).properties; @@ -3123,11 +3118,33 @@ type NotRequiredProps< type RequiredInputProps< T extends Record> > = keyof { - [k in keyof T as undefined extends InferInput ? never : k]: T[k]; + [k in keyof T as T[k] extends SchemaBuilder< + any, + infer TReq, + any, + infer THasDef + > + ? TReq extends true + ? THasDef extends true + ? never + : k + : never + : never]: T[k]; }; type NotRequiredInputProps< T extends Record> > = keyof { - [k in keyof T as undefined extends InferInput ? k : never]: T[k]; + [k in keyof T as T[k] extends SchemaBuilder< + any, + infer TReq, + any, + infer THasDef + > + ? TReq extends true + ? THasDef extends true + ? k + : never + : k + : never]: T[k]; }; diff --git a/libs/schema/src/builders/RecordSchemaBuilder.ts b/libs/schema/src/builders/RecordSchemaBuilder.ts index 5b0e306d..f9e2ab63 100644 --- a/libs/schema/src/builders/RecordSchemaBuilder.ts +++ b/libs/schema/src/builders/RecordSchemaBuilder.ts @@ -14,7 +14,6 @@ */ import { type BRAND, - type InferInput, type InferType, type PreValidationResult, SchemaBuilder, @@ -242,8 +241,7 @@ export class RecordSchemaBuilder< TRequired, TNullable, THasDefault, - TExtensions, - Record, InferInput> + TExtensions > { #keySchema!: TKeySchema; #valueSchema!: TValueSchema; diff --git a/libs/schema/src/builders/ReferenceSchemaBuilder.test.ts b/libs/schema/src/builders/ReferenceSchemaBuilder.test.ts new file mode 100644 index 00000000..01ea34f4 --- /dev/null +++ b/libs/schema/src/builders/ReferenceSchemaBuilder.test.ts @@ -0,0 +1,149 @@ +import { describe, expect, it, vi } from 'vitest'; +import { array, boolean, number, object, schemaRef, string } from '../index.js'; + +describe('optional fallbacks', () => { + it('accepts optional/nullable fallbacks and preserves legacy null acceptance', async () => { + const text = string().optional().catch(undefined); + expect(text.parse(42)).toBeUndefined(); + expect(await text.parseAsync(false)).toBeUndefined(); + expect(text.parse(null)).toBeNull(); + expect(string().nullable().catch(null).parse(42)).toBeNull(); + const normalize = string() + .optional() + .addPreprocessor(v => (v == null ? undefined : v)) + .catch(undefined); + expect(normalize.parse(null)).toBeUndefined(); + expect(object({ text }).safeParse(null).valid).toBe(false); + expect( + object({ + text, + flag: boolean() + .optional() + .catch(() => undefined) + }).parse({ text: {}, flag: 1 }) + ).toEqual({ text: undefined, flag: undefined }); + }); + + it('supports async optional preprocessing without dropping array entries', async () => { + const fallback = vi.fn(() => undefined); + const text = string().optional().catch(fallback); + expect(array(text).parse(['ok', 42])).toEqual(['ok', undefined]); + expect(fallback).toHaveBeenCalledTimes(1); + const normalized = string() + .optional() + .addPreprocessor(async v => (v == null ? undefined : v)); + expect(await normalized.parseAsync(null)).toBeUndefined(); + expect(() => normalized.parse(null)).toThrow(/validateAsync/); + }); +}); + +describe('named schema references', () => { + it('preserves one target definition and independent local metadata', () => { + const user = object({ name: string().minLength(1) }).schemaName('User'); + const ref = schemaRef(user); + const previous = ref + .nullable() + .optional() + .describe('Previous user') + .example(null); + expect(ref.introspect().targetSchema).toBe(user); + expect(previous.introspect().targetSchema).toBe(user); + expect(user.introspect().description).toBeUndefined(); + expect(user.introspect().isRequired).toBe(true); + expect(ref.safeParse(null).valid).toBe(false); + expect(previous.parse(null)).toBeNull(); + expect(previous.parse(undefined)).toBeUndefined(); + expect(previous.parse({ name: 'Ada' })).toEqual({ name: 'Ada' }); + expect(() => schemaRef(string())).toThrow(/named schema/); + expect(() => schemaRef(string().schemaName(' '))).toThrow( + /named schema/ + ); + }); + + it('preserves deeply nested reference errors and selectors', async () => { + const address = object({ city: string().minLength(1) }).schemaName( + 'Address' + ); + const user = object({ address: schemaRef(address) }).schemaName('User'); + const root = object({ user: schemaRef(user) }); + for (const result of [ + root.validate({ user: { address: { city: '' } } }), + await root.validateAsync({ user: { address: { city: '' } } }) + ]) { + expect(result.valid).toBe(false); + expect( + result.getErrorsFor(t => t.user.address.city).errors.length + ).toBeGreaterThan(0); + expect( + result + .getInvalidProperties() + .map(p => p.descriptor.toJsonPointer()) + ).toContain('/user/address/city'); + } + }); + + it('keeps target defaults, local defaults and fallbacks independent', async () => { + const target = number().default(2).schemaName('Size'); + const ref = schemaRef(target); + expect(ref.parse(undefined)).toBe(2); + expect(ref.optional().parse(undefined)).toBeUndefined(); + expect(ref.optional().default(4).parse(undefined)).toBe(4); + expect(ref.default(4).clearDefault().parse(undefined)).toBe(2); + expect(target.parse(undefined)).toBe(2); + const fallback = vi.fn(() => 8); + const caught = ref.catch(fallback); + expect(caught.parse('invalid')).toBe(8); + expect(await caught.parseAsync('invalid')).toBe(8); + expect(fallback).toHaveBeenCalledTimes(2); + expect(ref.optional().catch(undefined).parse({})).toBeUndefined(); + }); + + it('keeps local optionality, nullability and required error messages distinct', async () => { + const ref = schemaRef( + string().nullable().optional().schemaName('Text') + ); + expect(ref.parse(null)).toBeNull(); + expect(ref.notNullable().safeParse(null).valid).toBe(false); + expect(ref.notNullable().parse(undefined)).toBeUndefined(); + const required = ref.required('Provide text'); + expect(required.safeParse(undefined).errors?.[0].message).toBe( + 'Provide text' + ); + expect(required.parse(null)).toBeNull(); + const asyncRequired = ref.required(async () => 'Async required'); + expect(() => asyncRequired.parse(undefined)).toThrow(/Async|async/); + expect( + (await asyncRequired.safeParseAsync(undefined)).errors?.[0].message + ).toBe('Async required'); + }); + + it('delegates async target validation and runs local callbacks', async () => { + const target = string() + .addPreprocessor(async v => v.trim()) + .schemaName('Trimmed'); + const ref = schemaRef(target); + expect(() => ref.parse(' text ')).toThrow(/validateAsync/); + expect(await ref.parseAsync(' text ')).toBe('text'); + expect(await ref['~standard'].validate(' text ')).toEqual({ + value: 'text' + }); + const local = schemaRef(number().schemaName('Count')) + .addPreprocessor(v => v + 1) + .addValidator(v => ({ valid: v < 5 })); + expect(local.parse(2)).toBe(3); + expect(local.safeParse(5).valid).toBe(false); + expect( + schemaRef(string().schemaName('OptionalText')) + .optional() + .addPreprocessor(() => undefined) + .parse('text') + ).toBeUndefined(); + }); + + it('retains existing hasType behavior without changing runtime validation', () => { + const ref = schemaRef(number().schemaName('Count')).hasType(); + expect(ref.parse(3)).toBe(3); + expect(ref.safeParse('three').valid).toBe(false); + expect(ref.clearHasType().parse(4)).toBe(4); + }); +}); diff --git a/libs/schema/src/builders/ReferenceSchemaBuilder.ts b/libs/schema/src/builders/ReferenceSchemaBuilder.ts new file mode 100644 index 00000000..fa11afc2 --- /dev/null +++ b/libs/schema/src/builders/ReferenceSchemaBuilder.ts @@ -0,0 +1,387 @@ +import { + type BRAND, + type InferType, + SchemaBuilder, + type SchemaBuilderProps, + SYMBOL_HAS_PROPERTIES, + type ValidationContext, + type ValidationErrorMessageProvider, + type ValidationResult +} from './SchemaBuilder.js'; + +type AnySchema = SchemaBuilder; +type ReferenceValue< + TSchema, + TRequired extends boolean, + TNullable extends boolean, + TExplicitType +> = + | (TRequired extends true + ? Exclude< + TExplicitType extends undefined + ? InferType + : TExplicitType, + undefined + > + : + | (TExplicitType extends undefined + ? InferType + : TExplicitType) + | undefined) + | (TNullable extends true ? null : never); +type ReferenceProps = Partial> & { + targetSchema: AnySchema; + presence?: boolean; + nullability?: boolean; +}; + +/** + * Immutable use-site wrapper around one named schema. Create it with schemaRef. + * Local modifiers never clone or mutate the target definition. + * @typeParam TSchema - Referenced schema. + * @typeParam TRequired - Whether a value is required at this use site. + * @typeParam TNullable - Whether null is allowed at this use site. + * @typeParam THasDefault - Whether the wrapper supplies a default. + * @typeParam TExplicitType - Optional static type override. + */ +export class ReferenceSchemaBuilder< + TSchema extends AnySchema, + TRequired extends boolean = true, + TNullable extends boolean = false, + THasDefault extends boolean = false, + TExplicitType = undefined +> extends SchemaBuilder< + ReferenceValue, + TRequired, + TNullable, + THasDefault +> { + readonly #reference: ReferenceProps; + /** @internal Enables nested property descriptors for referenced objects. */ + readonly [SYMBOL_HAS_PROPERTIES] = true; + + /** @internal Use schemaRef rather than constructing a reference directly. */ + constructor(props: ReferenceProps) { + super({ + preprocessors: [], + validators: [], + ...props, + type: 'reference' + }); + this.#reference = props; + } + + /** Describes the target and local modifiers without changing the target. */ + public introspect() { + return { + ...super.introspect(), + targetSchema: this.#reference.targetSchema as TSchema, + presence: this.#reference.presence, + nullability: this.#reference.nullability, + properties: (this.#reference.targetSchema.introspect() as any) + .properties + }; + } + + /** @internal Reconstructs an immutable wrapper around the same target. */ + protected createFromProps(props: ReferenceProps): this { + return new ReferenceSchemaBuilder(props) as this; + } + + /** Validates through the target and retains the inferred result type. */ + public validate( + value: unknown, + context?: ValidationContext + ): ValidationResult< + ReferenceValue + > { + return super.validate(value, context); + } + + /** Async validation with the same inference and fallback behavior. */ + public validateAsync( + value: unknown, + context?: ValidationContext + ): Promise< + ValidationResult< + ReferenceValue + > + > { + return super.validateAsync(value, context); + } + + #props(): ReferenceProps { + return { + ...this.#reference, + ...this.introspect(), + preprocessors: [...this.preprocessors], + validators: [...this.validators] + }; + } + + #early(value: unknown): ValidationResult | undefined { + if (value === undefined && this.hasDefault) return undefined; + if (value === undefined && this.#reference.presence !== undefined) { + return this.#reference.presence + ? { valid: false, errors: [{ message: 'is required' }] } + : { valid: true, object: undefined }; + } + if (value === null && this.#reference.nullability !== undefined) { + return this.#reference.nullability + ? { valid: true, object: null } + : { valid: false, errors: [{ message: 'must not be null' }] }; + } + return undefined; + } + + #checkNull(result: ValidationResult): ValidationResult { + if ( + result.valid && + result.object === null && + this.#reference.nullability === false + ) + return { valid: false, errors: [{ message: 'must not be null' }] }; + return result; + } + + /** @internal Delegates validation while applying local presence and validators. */ + protected _validate( + value: unknown, + context?: ValidationContext + ): ValidationResult { + const early = this.#early(value); + if (early) { + if (!early.valid && value === undefined) + early.errors = [ + { + message: this.getValidationErrorMessageSync( + this.requiredErrorMessage, + value as any + ) + } + ]; + return early; + } + const result = this.#checkNull( + this.#reference.targetSchema.validate( + value === undefined && this.hasDefault + ? this.resolveDefaultValue() + : value, + context + ) + ); + if (!result.valid) return result; + const prepared = this.preValidateSync(result.object, context); + if (!prepared.valid) return { valid: false, errors: prepared.errors }; + if (this.preprocessors.length === 0) return result; + const preparedValue = prepared.transaction!.object.validatedObject; + return this.#checkNull( + this.#early(preparedValue) ?? + this.#reference.targetSchema.validate(preparedValue, context) + ); + } + + /** @internal Async counterpart, including target validators and local callbacks. */ + protected async _validateAsync( + value: unknown, + context?: ValidationContext + ): Promise> { + const early = this.#early(value); + if (early) { + if (!early.valid && value === undefined) + early.errors = [ + { + message: await this.getValidationErrorMessage( + this.requiredErrorMessage, + value as any + ) + } + ]; + return early; + } + const result = this.#checkNull( + await this.#reference.targetSchema.validateAsync( + value === undefined && this.hasDefault + ? this.resolveDefaultValue() + : value, + context + ) + ); + if (!result.valid) return result; + const prepared = await this.preValidateAsync(result.object, context); + if (!prepared.valid) return { valid: false, errors: prepared.errors }; + if (this.preprocessors.length === 0) return result; + const preparedValue = prepared.transaction!.object.validatedObject; + return this.#checkNull( + this.#early(preparedValue) ?? + (await this.#reference.targetSchema.validateAsync( + preparedValue, + context + )) + ); + } + + /** Overrides the static type only; target validation remains unchanged. */ + public hasType( + _notUsed?: T + ): ReferenceSchemaBuilder { + return this.createFromProps(this.#props()) as any; + } + + /** Restores inference from the referenced schema. */ + public clearHasType(): ReferenceSchemaBuilder< + TSchema, + TRequired, + TNullable, + THasDefault + > { + return this.createFromProps(this.#props()) as any; + } + + /** Rejects omitted values at this use site, unless a local default exists. */ + public required( + errorMessage?: ValidationErrorMessageProvider + ): ReferenceSchemaBuilder< + TSchema, + true, + TNullable, + THasDefault, + TExplicitType + > { + return this.createFromProps({ + ...this.#props(), + isRequired: true, + presence: true, + requiredValidationErrorMessageProvider: errorMessage + }) as any; + } + + /** Allows omission without invoking the target, unless a local default exists. */ + public optional(): ReferenceSchemaBuilder< + TSchema, + false, + TNullable, + THasDefault, + TExplicitType + > { + return this.createFromProps({ + ...this.#props(), + isRequired: false, + presence: false + }) as any; + } + + /** Allows null independently of omission at this use site. */ + public nullable(): ReferenceSchemaBuilder< + TSchema, + TRequired, + true, + THasDefault, + TExplicitType + > { + return this.createFromProps({ + ...this.#props(), + isNullable: true, + nullability: true + }) as any; + } + + /** Rejects null without modifying the target definition. */ + public notNullable(): ReferenceSchemaBuilder< + TSchema, + TRequired, + false, + THasDefault, + Exclude< + TExplicitType extends undefined + ? InferType + : TExplicitType, + null + > + > { + return this.createFromProps({ + ...this.#props(), + isNullable: false, + nullability: false + }) as any; + } + + /** Supplies a local default for omission, validated by the target. */ + public default( + value: InferType | (() => InferType) + ): ReferenceSchemaBuilder { + return this.createFromProps({ + ...this.#props(), + defaultValue: value, + isRequired: true + }) as any; + } + + /** Removes the local default; target defaults are unchanged. */ + public clearDefault(): ReferenceSchemaBuilder< + TSchema, + TRequired, + TNullable, + false, + TExplicitType + > { + return this.createFromProps({ + ...this.#props(), + defaultValue: undefined + }) as any; + } + + /** Brands the inferred type without changing runtime validation. */ + public brand( + _name?: B + ): ReferenceSchemaBuilder< + TSchema, + TRequired, + TNullable, + THasDefault, + (TExplicitType extends undefined + ? InferType + : TExplicitType) & { readonly [K in BRAND]: B } + > { + return super.brand(_name); + } + + /** Makes the inferred type readonly without freezing runtime values. */ + public readonly(): ReferenceSchemaBuilder< + TSchema, + TRequired, + TNullable, + THasDefault, + Readonly< + TExplicitType extends undefined ? InferType : TExplicitType + > + > { + return super.readonly(); + } +} + +/** + * References one named definition with independent use-site annotations. + * @param schema - A reused schema constant with a nonempty schemaName. + * @returns An immutable reference wrapper; the target is neither cloned nor mutated. + * @throws Error if the target has no name. + * @example + * const User = object({ name: string() }).schemaName('User'); + * const previous = schemaRef(User).nullable().optional().describe('Previous user'); + */ +export function schemaRef( + schema: TSchema +): ReferenceSchemaBuilder< + TSchema, + undefined extends InferType ? false : true, + null extends InferType ? true : false +> { + const info = schema.introspect(); + if (!info.schemaName?.trim()) + throw new Error('schemaRef requires a named schema.'); + return new ReferenceSchemaBuilder({ + targetSchema: schema, + isRequired: info.isRequired, + isNullable: info.isNullable + }); +} diff --git a/libs/schema/src/builders/SchemaBuilder.ts b/libs/schema/src/builders/SchemaBuilder.ts index 311e86ed..5fdc8671 100644 --- a/libs/schema/src/builders/SchemaBuilder.ts +++ b/libs/schema/src/builders/SchemaBuilder.ts @@ -9,8 +9,6 @@ import type { ObjectSchemaBuilder } from './ObjectSchemaBuilder.js'; /** @internal Symbol used as the key for the type brand on schema builders. */ declare const __type: unique symbol; -/** @internal Input type marker. */ -declare const __input: unique symbol; /** @internal */ export type SchemaTypeBrand = typeof __type; @@ -59,18 +57,6 @@ export type InferType = T extends { ? TType : T; -/** Validated output of a schema; compatibility alias for {@link InferType}. */ -export type InferOutput = InferType; - -/** - * Declared input before decoding and defaults. Parsers still validate unknown - * data at runtime. Legacy preprocessors do not infer a separate input type. - * @typeParam T - Schema whose input is required. - */ -export type InferInput = T extends { readonly [__input]: infer I } - ? I - : InferType; - /** * Represents a single validation error with a human-readable error message. * @@ -583,7 +569,7 @@ export type PropertyDescriptorTree< K & string > & ExternOutputPropertyDescriptors< - NonNullable>, + NonNullable>, TRootSchema, PropertyDescriptor< TRootSchema, @@ -751,8 +737,6 @@ type ResolvedSchemaType< * **Note:** this class is not intended to be used directly, use one of the subclasses instead. * @typeparam TResult Type of the object that will be returned by `validate()` method. * @typeparam TRequired If `true`, object will be required. If `false`, object will be optional. - * @typeParam TInput - Declared input before decoding. Defaults to TResult so - * existing generic arguments retain their meaning. */ export abstract class SchemaBuilder< TResult = any, @@ -760,11 +744,7 @@ export abstract class SchemaBuilder< TNullable extends boolean = false, THasDefault extends boolean = false, // biome-ignore lint/correctness/noUnusedVariables: used in extensions - TExtensions = {}, - TInput = TResult, - TResolvedInput = - | ResolvedSchemaType - | (THasDefault extends true ? undefined : never) + TExtensions = {} > { #isRequired = true; #isNullable = false; @@ -792,7 +772,6 @@ export abstract class SchemaBuilder< */ #standardProps: | StandardSchemaV1.Props< - TResolvedInput, ResolvedSchemaType > | undefined; @@ -815,9 +794,6 @@ export abstract class SchemaBuilder< */ declare readonly [__hasDefault]: THasDefault; - /** @internal Input type, including omission when a default exists. */ - declare readonly [__input]: TResolvedInput; - /** * Standard Schema v1 interface. * @@ -868,7 +844,6 @@ export abstract class SchemaBuilder< * @see https://standardschema.dev/ */ get ['~standard'](): StandardSchemaV1.Props< - TResolvedInput, ResolvedSchemaType > { if (this.#standardProps) return this.#standardProps; @@ -1783,7 +1758,7 @@ export abstract class SchemaBuilder< * @param options - Whether the callback can mutate its argument. * @returns A new builder preserving the original schema. * @remarks Legacy callback parameter typing is preserved for compatibility. - * For a separately typed external input, use decode(input, output, fn). + * Unknown external data still needs runtime validation. */ public addPreprocessor( preprocessor: ( diff --git a/libs/schema/src/builders/TupleSchemaBuilder.ts b/libs/schema/src/builders/TupleSchemaBuilder.ts index d2d690ef..8a5a6d76 100644 --- a/libs/schema/src/builders/TupleSchemaBuilder.ts +++ b/libs/schema/src/builders/TupleSchemaBuilder.ts @@ -5,7 +5,6 @@ import type { import { type BRAND, createHybridErrorArray, - type InferInput, type InferType, type NestedValidationResult, type PropertyDescriptor, @@ -161,13 +160,7 @@ export class TupleSchemaBuilder< TRequired, TNullable, THasDefault, - TExtensions, - TRestSchema extends SchemaBuilder - ? [ - ...{ [K in keyof TElements]: InferInput }, - ...Array> - ] - : { [K in keyof TElements]: InferInput } + TExtensions > { #elements!: TElements; #restSchema: diff --git a/libs/schema/src/builders/UnionSchemaBuilder.ts b/libs/schema/src/builders/UnionSchemaBuilder.ts index 9ac80679..0560e4c4 100644 --- a/libs/schema/src/builders/UnionSchemaBuilder.ts +++ b/libs/schema/src/builders/UnionSchemaBuilder.ts @@ -5,7 +5,6 @@ import type { import { type BRAND, createHybridErrorArray, - type InferInput, type InferType, type NestedValidationResult, type PropertyDescriptor, @@ -173,8 +172,7 @@ export class UnionSchemaBuilder< TRequired, TNullable, THasDefault, - TExtensions, - InferInput + TExtensions > { #options!: TOptions; #discriminatorKey: string | null = null; diff --git a/libs/schema/src/builders/boundaries.test-d.ts b/libs/schema/src/builders/boundaries.test-d.ts deleted file mode 100644 index f9f9ef39..00000000 --- a/libs/schema/src/builders/boundaries.test-d.ts +++ /dev/null @@ -1,102 +0,0 @@ -import { expectTypeOf, test } from 'vitest'; -import { - array, - decode, - type InferInput, - type InferOutput, - type InferType, - intersection, - lazy, - number, - object, - record, - schemaRef, - string, - tuple, - union -} from '../index.js'; - -test('input/output inference composes without changing InferType', () => { - const size = decode(string(), number(), Number); - expectTypeOf>().toEqualTypeOf(); - expectTypeOf>().toEqualTypeOf(); - expectTypeOf>().toEqualTypeOf(); - expectTypeOf(size.parse('1')).toEqualTypeOf(); - const form = object({ size, title: string().default('untitled') }); - expectTypeOf>().toMatchTypeOf<{ - size: string; - title?: string; - }>(); - expectTypeOf<{ size: string }>().toMatchTypeOf>(); - expectTypeOf>().toMatchTypeOf<{ - size: number; - title: string; - }>(); - const list = array(size); - expectTypeOf>().toEqualTypeOf(); - expectTypeOf>().toEqualTypeOf(); - const pair = tuple([size, string()]); - expectTypeOf>().toEqualTypeOf<[string, string]>(); - const dictionary = record(string(), size); - expectTypeOf>().toEqualTypeOf< - Record - >(); - const choice = union(size).or(string()); - expectTypeOf>().toEqualTypeOf(); - const joined = intersection(object({ size }), object({ title: string() })); - expectTypeOf>().toMatchTypeOf<{ - size: string; - title: string; - }>(); - const ref = schemaRef(form.schemaName('Form')); - expectTypeOf>().toEqualTypeOf< - InferInput - >(); - const deferred = lazy(() => size); - expectTypeOf>().toEqualTypeOf(); - // @ts-expect-error required schemas cannot fall back to undefined - string().catch(undefined); - // @ts-expect-error non-nullable schemas cannot fall back to null - string().catch(null); - // @ts-expect-error converter must return the output schema's input - decode(string(), number(), value => value); - string().optional().catch(undefined); - string() - .nullable() - .catch(() => null); - string() - .optional() - .addPreprocessor(() => undefined); -}); - -test('boundary presence belongs to each side independently', () => { - const nullableOutput = decode(string(), number().nullable(), () => null); - expectTypeOf>().toEqualTypeOf(); - expectTypeOf>().toEqualTypeOf< - number | null - >(); - const nullableInput = decode(string().nullable(), number(), value => - value === null ? 0 : Number(value) - ); - expectTypeOf>().toEqualTypeOf< - string | null - >(); - expectTypeOf>().toEqualTypeOf(); - const defaults = object({ - size: decode(string().default('1'), number(), Number) - }); - expectTypeOf<{}>().toMatchTypeOf>(); - const optimized = defaults.optimize(); - expectTypeOf>().toEqualTypeOf< - InferInput - >(); - const required = nullableInput.optional().required().notNullable(); - expectTypeOf>().toEqualTypeOf(); - const ref = schemaRef(object({ name: string() }).schemaName('User')) - .nullable() - .optional(); - const root = object({ user: ref }); - root.validate({ user: null }).getErrorsFor(t => t.user.name); - // @ts-expect-error concrete descriptor trees still reject unknown fields - root.validate({ user: null }).getErrorsFor(t => t.user.missing); -}); diff --git a/libs/schema/src/builders/references.test-d.ts b/libs/schema/src/builders/references.test-d.ts new file mode 100644 index 00000000..1f8ca4a9 --- /dev/null +++ b/libs/schema/src/builders/references.test-d.ts @@ -0,0 +1,47 @@ +import { expectTypeOf, test } from 'vitest'; +import { type InferType, number, object, schemaRef, string } from '../index.js'; + +test('optional-aware fallback and preprocessing types remain checked', () => { + // @ts-expect-error required schemas cannot fall back to undefined + string().catch(undefined); + // @ts-expect-error non-nullable schemas cannot fall back to null + string().catch(null); + string().optional().catch(undefined); + string() + .nullable() + .catch(() => null); + string() + .optional() + .addPreprocessor(() => undefined); + string() + .nullable() + .addPreprocessor(async () => null); +}); + +test('references preserve inferred types, local modifiers and selectors', () => { + const user = object({ name: string() }).schemaName('User'); + const ref = schemaRef(user); + expectTypeOf>().toEqualTypeOf< + InferType + >(); + const optional = ref.optional().nullable(); + expectTypeOf>().toEqualTypeOf< + InferType | undefined | null + >(); + const required = optional.required().notNullable(); + expectTypeOf>().toEqualTypeOf< + InferType + >(); + const withDefault = ref.optional().default({ name: 'Ada' }); + expectTypeOf>().toEqualTypeOf< + InferType + >(); + const root = object({ user: optional }); + root.validate({ user: null }).getErrorsFor(t => t.user.name); + // @ts-expect-error concrete descriptor trees still reject unknown fields + root.validate({ user: null }).getErrorsFor(t => t.user.missing); + const override = schemaRef(number().schemaName('Number')).hasType(); + expectTypeOf>().toEqualTypeOf(); + const cleared = override.clearHasType(); + expectTypeOf>().toEqualTypeOf(); +}); diff --git a/libs/schema/src/core.ts b/libs/schema/src/core.ts index b0123534..c27c368c 100644 --- a/libs/schema/src/core.ts +++ b/libs/schema/src/core.ts @@ -12,11 +12,6 @@ export { BooleanSchemaBuilder, boolean } from './builders/BooleanSchemaBuilder.js'; -export { - BoundarySchemaBuilder, - decode, - schemaRef -} from './builders/BoundarySchemaBuilder.js'; export { DateSchemaBuilder, date } from './builders/DateSchemaBuilder.js'; export { ExternSchemaBuilder, @@ -55,9 +50,11 @@ export { } from './builders/PromiseSchemaBuilder.js'; export type { RecordSchemaValidationResult } from './builders/RecordSchemaBuilder.js'; export { RecordSchemaBuilder, record } from './builders/RecordSchemaBuilder.js'; +export { + ReferenceSchemaBuilder, + schemaRef +} from './builders/ReferenceSchemaBuilder.js'; export type { - InferInput, - InferOutput, NestedValidationResult, PropertyDescriptor, PropertyDescriptorInner, diff --git a/libs/server-openapi/README.md b/libs/server-openapi/README.md index 84426fe1..f44f40cd 100644 --- a/libs/server-openapi/README.md +++ b/libs/server-openapi/README.md @@ -9,15 +9,10 @@ OpenAPI 3.1 specification generation for [`@cleverbrush/server`](../server). Con ### Schema boundaries -Requests use schema input views and responses use output views. A named schema -with different representations gets collision-checked `NameInput` and -`NameOutput` components; identical representations keep their original name. -AsyncAPI uses input for incoming messages and output for outgoing messages. - Use `schemaRef(NamedSchema).optional().nullable().describe(...)` to annotate a single use without cloning the named definition. Conflicting named definitions -still fail. See the [composition guide](../schema/BOUNDARIES.md), including the -separate adoption required for typed clients and editable form state. +still fail. OpenAPI and AsyncAPI retain one canonical component per named target. +See the [composition guide](../schema/BOUNDARIES.md). - **`generateOpenApiSpec()`** — converts `@cleverbrush/server` endpoint registrations into an OpenAPI 3.1 document. - **`generateAsyncApiSpec()`** — converts `@cleverbrush/server` WebSocket subscription registrations into an AsyncAPI 3.0 document. diff --git a/libs/server-openapi/src/boundaries.test.ts b/libs/server-openapi/src/boundaries.test.ts index 91421f28..28c0702d 100644 --- a/libs/server-openapi/src/boundaries.test.ts +++ b/libs/server-openapi/src/boundaries.test.ts @@ -1,8 +1,6 @@ import { array, - decode, lazy, - number, object, type SchemaBuilder, schemaRef, @@ -10,93 +8,117 @@ import { } from '@cleverbrush/schema'; import { endpoint } from '@cleverbrush/server'; import { describe, expect, it } from 'vitest'; +import { generateAsyncApiSpec } from './generateAsyncApiSpec.js'; import { generateOpenApiSpec } from './generateOpenApiSpec.js'; import { SchemaRegistry, walkSchemas } from './schemaRegistry.js'; -describe('schema boundaries in OpenAPI', () => { - it('uses input requests, output responses, and directional nested components', () => { - const size = decode(string(), number().isInteger(), Number).schemaName( - 'Size' - ); - const request = object({ size: schemaRef(size) }).schemaName( - 'Envelope' - ); +describe('named schema references in API documents', () => { + it('uses one canonical component for requests, responses and annotated references', () => { + const user = object({ name: string() }).schemaName('User'); + const history = object({ + current: schemaRef(user), + previous: schemaRef(user).nullable().optional().describe('Previous') + }); const contract = endpoint - .post('/items') - .body(request) - .responses({ 200: request }); + .post('/history') + .body(history) + .responses({ 200: history }); const spec = generateOpenApiSpec({ registrations: [ { endpoint: contract.introspect(), handler: () => {} } ], - info: { title: 'Boundaries', version: '1' } + info: { title: 'References', version: '1' } }) as any; - expect( - spec.paths['/items'].post.requestBody.content['application/json'] - .schema - ).toEqual({ $ref: '#/components/schemas/EnvelopeInput' }); - expect( - spec.paths['/items'].post.responses['200'].content[ + expect(Object.keys(spec.components.schemas)).toEqual(['User']); + const request = + spec.paths['/history'].post.requestBody.content['application/json'] + .schema; + const response = + spec.paths['/history'].post.responses['200'].content[ 'application/json' - ].schema - ).toEqual({ $ref: '#/components/schemas/EnvelopeOutput' }); - expect(spec.components.schemas.SizeInput).toEqual({ - allOf: [{ type: 'string' }] - }); - expect(spec.components.schemas.SizeOutput).toEqual({ - allOf: [{ type: 'integer' }] + ].schema; + expect(request).toEqual(response); + expect(request.required).toEqual(['current']); + expect(request.properties.current.allOf[0].$ref).toBe( + '#/components/schemas/User' + ); + expect(request.properties.previous.description).toBe('Previous'); + expect(spec.components.schemas.User).toMatchObject({ + type: 'object', + required: ['name'] }); - expect( - spec.components.schemas.EnvelopeInput.properties.size.allOf[0].$ref - ).toBe('#/components/schemas/SizeInput'); }); - it('registers one target with independently annotated references', () => { + it('preserves strict instance-based naming conflicts', () => { const user = object({ name: string() }).schemaName('User'); - const root = object({ - user, - previous: schemaRef(user).nullable().optional().describe('Previous') - }); const registry = new SchemaRegistry(); - walkSchemas(root, registry); - expect( - [...registry.directionalEntries()].map(([name]) => name) - ).toEqual(['User']); + walkSchemas( + object({ + current: user, + previous: schemaRef(user).nullable().optional() + }), + registry + ); + expect([...registry.entries()].map(([name]) => name)).toEqual(['User']); expect(() => walkSchemas(user.optional(), registry)).toThrow( /already registered/ ); + expect(() => + walkSchemas(string().schemaName('User'), registry) + ).toThrow(/already registered/); }); - it('rejects generated-name collisions regardless of registration order', () => { - const size = decode(string(), number(), Number).schemaName('Size'); - const collision = string().schemaName('SizeInput'); - for (const schemas of [ - [size, collision], - [collision, size] - ]) { - const registry = new SchemaRegistry(); - for (const schema of schemas) walkSchemas(schema, registry); - expect(() => [...registry.directionalEntries()]).toThrow( - /SizeInput/ - ); - } - }); - - it('terminates on named recursive references', () => { + it('terminates on named recursive references in OpenAPI and AsyncAPI', () => { type Node = { name: string; children: Node[] }; const node: SchemaBuilder = object({ name: string(), children: array(lazy(() => schemaRef(node))) }).schemaName('Node'); const contract = endpoint.get('/nodes').responses({ 200: node }); - const spec = generateOpenApiSpec({ + const openapi = generateOpenApiSpec({ registrations: [ { endpoint: contract.introspect(), handler: () => {} } ], info: { title: 'Nodes', version: '1' } }) as any; - expect( - spec.components.schemas.Node.properties.children.items.allOf[0].$ref - ).toBe('#/components/schemas/Node'); + const asyncapi = generateAsyncApiSpec({ + subscriptions: [ + { + endpoint: { + protocol: 'subscription', + basePath: '/ws', + pathTemplate: '/nodes', + incomingSchema: schemaRef(node), + outgoingSchema: schemaRef(node), + querySchema: null, + headerSchema: null, + serviceSchemas: null, + authRoles: null, + summary: null, + description: null, + tags: [], + operationId: null, + deprecated: false, + externalDocs: null + }, + handler: async function* () {} + } + ], + info: { title: 'Nodes', version: '1' } + }) as any; + for (const spec of [openapi, asyncapi]) { + expect(Object.keys(spec.components.schemas)).toEqual(['Node']); + expect( + spec.components.schemas.Node.properties.children.items.allOf[0] + .$ref + ).toBe('#/components/schemas/Node'); + } + const channels = Object.values(asyncapi.channels) as any[]; + expect(channels).toHaveLength(1); + expect(channels[0].address).toBe('/ws/nodes'); + const messages = channels[0].messages; + expect(messages.ClientMessage.payload).toEqual( + messages.ServerEvent.payload + ); }); }); diff --git a/libs/server-openapi/src/generateAsyncApiSpec.ts b/libs/server-openapi/src/generateAsyncApiSpec.ts index cdbf5fd1..9bf6c091 100644 --- a/libs/server-openapi/src/generateAsyncApiSpec.ts +++ b/libs/server-openapi/src/generateAsyncApiSpec.ts @@ -256,7 +256,7 @@ export function generateAsyncApiSpec( messages['ClientMessage'] = { name: 'ClientMessage', ...(inInfo.description ? { summary: inInfo.description } : {}), - payload: convertSchema(m.incomingSchema, registry, 'input') + payload: convertSchema(m.incomingSchema, registry) }; } @@ -325,19 +325,15 @@ export function generateAsyncApiSpec( if (!registry.isEmpty) { const schemas: Record = {}; - for (const [name, schema, mode] of registry.directionalEntries()) { + for (const [name, schema] of registry.entries()) { let rootInlined = false; - schemas[name] = convertSchema( - schema, - candidate => { - if (candidate === schema && !rootInlined) { - rootInlined = true; - return null; - } - return registry.getName(candidate, mode); - }, - mode - ); + schemas[name] = convertSchema(schema, candidate => { + if (candidate === schema && !rootInlined) { + rootInlined = true; + return null; + } + return registry.getName(candidate); + }); } doc.components = { schemas }; } diff --git a/libs/server-openapi/src/generateOpenApiSpec.ts b/libs/server-openapi/src/generateOpenApiSpec.ts index 352722cb..f566eb3e 100644 --- a/libs/server-openapi/src/generateOpenApiSpec.ts +++ b/libs/server-openapi/src/generateOpenApiSpec.ts @@ -161,16 +161,6 @@ function buildParameterObject( return param; } -/** Determines omission on the request side without executing conversions. */ -function isInputRequired(schema: SchemaBuilder): boolean { - const info = schema.introspect() as any; - if (info.hasDefault) return false; - if (info.type === 'reference' || info.type === 'decode') { - return info.presence ?? isInputRequired(info.inputSchema); - } - return info.isRequired !== false; -} - function buildRequestBody( bodySchema: SchemaBuilder, registry: SchemaRegistry, @@ -183,18 +173,18 @@ function buildRequestBody( ): Record { const bodyInfo = bodySchema.introspect() as any; const body: Record = { - required: isInputRequired(bodySchema) + required: bodyInfo.isRequired !== false }; // When file uploads are enabled, emit multipart/form-data if (fileUpload) { - const jsonSchema = convertSchema(bodySchema, registry, 'input'); + const jsonSchema = convertSchema(bodySchema, registry); const mediaType: Record = { schema: jsonSchema }; body['content'] = { 'multipart/form-data': mediaType }; } else { - const jsonSchema = convertSchema(bodySchema, registry, 'input'); + const jsonSchema = convertSchema(bodySchema, registry); const mediaType: Record = { schema: jsonSchema }; if (example != null) { mediaType['example'] = example; @@ -491,7 +481,7 @@ function buildOperation( > = queryInfo.properties ?? {}; for (const [name, propSchema] of Object.entries(props)) { const propInfo = propSchema.introspect() as any; - const isRequired = isInputRequired(propSchema); + const isRequired = propInfo.isRequired !== false; const description = typeof propInfo.description === 'string' && propInfo.description !== '' @@ -501,7 +491,7 @@ function buildOperation( buildParameterObject( name, 'query', - convertSchema(propSchema, registry, 'input'), + convertSchema(propSchema, registry), isRequired, description ) @@ -518,7 +508,7 @@ function buildOperation( > = headerInfo.properties ?? {}; for (const [name, propSchema] of Object.entries(props)) { const propInfo = propSchema.introspect() as any; - const isRequired = isInputRequired(propSchema); + const isRequired = propInfo.isRequired !== false; const description = typeof propInfo.description === 'string' && propInfo.description !== '' @@ -528,7 +518,7 @@ function buildOperation( buildParameterObject( name, 'header', - convertSchema(propSchema, registry, 'input'), + convertSchema(propSchema, registry), isRequired, description ) @@ -677,13 +667,6 @@ export function generateOpenApiSpec(options: OpenApiOptions): OpenApiDocument { if (meta.bodySchema) walkSchemas(meta.bodySchema, registry, visited); if (meta.responseSchema) walkSchemas(meta.responseSchema, registry, visited); - if (meta.responseHeaderSchema) - walkSchemas(meta.responseHeaderSchema, registry, visited); - if (meta.produces) { - for (const entry of Object.values(meta.produces)) { - if (entry.schema) walkSchemas(entry.schema, registry, visited); - } - } if (meta.responsesSchemas) { for (const schema of Object.values(meta.responsesSchemas)) { if (schema) walkSchemas(schema, registry, visited); @@ -724,8 +707,7 @@ export function generateOpenApiSpec(options: OpenApiOptions): OpenApiDocument { } const resolveComponentSchemaName = ( - rootSchema: SchemaBuilder, - mode: 'input' | 'output' + rootSchema: SchemaBuilder ) => { // The root schema must be inlined exactly once — for the component // definition itself. Any subsequent encounter (e.g. through a lazy @@ -739,7 +721,7 @@ export function generateOpenApiSpec(options: OpenApiOptions): OpenApiDocument { inlinedRoot = true; return undefined; // inline the root definition once } - return registry.getName(candidate, mode) ?? undefined; + return registry.getName(candidate) ?? undefined; }; }; @@ -831,14 +813,13 @@ export function generateOpenApiSpec(options: OpenApiOptions): OpenApiDocument { // Components — security schemes + named component schemas const componentSchemas: Record = {}; - for (const [name, schema, mode] of registry.directionalEntries()) { + for (const [name, schema] of registry.entries()) { // Inline the root schema to avoid a self-referential $ref, but resolve // nested named schemas through the shared registry so component // definitions can still deduplicate via $ref. componentSchemas[name] = convertSchema( schema, - resolveComponentSchemaName(schema, mode), - mode + resolveComponentSchemaName(schema) ); } const hasSchemas = Object.keys(componentSchemas).length > 0; diff --git a/libs/server-openapi/src/schemaConverter.ts b/libs/server-openapi/src/schemaConverter.ts index 817c0219..c0e83dfc 100644 --- a/libs/server-openapi/src/schemaConverter.ts +++ b/libs/server-openapi/src/schemaConverter.ts @@ -18,12 +18,10 @@ type NameResolver = ( * * @param schema - The schema to convert, or `null`/`undefined`. * @param registry - Optional registry or resolver function for `$ref` deduplication. - * @param mode - Input before decoding/defaults, or validated output (default). */ export function convertSchema( schema: SchemaBuilder | null | undefined, - registry?: SchemaRegistry | NameResolver, - mode: 'input' | 'output' = 'output' + registry?: SchemaRegistry | NameResolver ): Record { if (schema == null) return {}; @@ -34,14 +32,13 @@ export function convertSchema( if (typeof registry === 'function') { nameResolver = s => registry(s) ?? null; } else { - nameResolver = s => registry.getName(s, mode); + nameResolver = s => registry.getName(s); } } return toJsonSchema(schema, { $schema: false, draft: '2020-12', - nameResolver, - mode + nameResolver }); } diff --git a/libs/server-openapi/src/schemaRegistry.ts b/libs/server-openapi/src/schemaRegistry.ts index b934a656..f2610a17 100644 --- a/libs/server-openapi/src/schemaRegistry.ts +++ b/libs/server-openapi/src/schemaRegistry.ts @@ -1,5 +1,4 @@ import type { SchemaBuilder } from '@cleverbrush/schema'; -import { toJsonSchema } from '@cleverbrush/schema-json'; // --------------------------------------------------------------------------- // SchemaRegistry @@ -31,9 +30,6 @@ export class SchemaRegistry { >(); /** name → first-registered schema instance */ private readonly byName = new Map>(); - private directions: - | Map, { input: string; output: string }> - | undefined; /** * Attempts to register `schema` in the registry. @@ -68,7 +64,6 @@ export class SchemaRegistry { this.byInstance.set(schema, name); this.byName.set(name, schema); - this.directions = undefined; } /** @@ -78,93 +73,8 @@ export class SchemaRegistry { * @param schema - The schema builder to look up. * @returns The registered name, or `null`. */ - getName( - schema: SchemaBuilder, - mode: 'input' | 'output' = 'output' - ): string | null { - if (!this.byInstance.has(schema)) return null; - this.prepareDirections(); - return this.directions!.get(schema)![mode]; - } - - /** - * Emits independent input/output definitions only when their declared - * representations differ. Derived names are collision checked. - * @throws Error when a generated component name is already reserved. - */ - *directionalEntries(): IterableIterator< - [string, SchemaBuilder, 'input' | 'output'] - > { - this.prepareDirections(); - for (const [schema, names] of this.directions!) { - if (names.input !== names.output) - yield [names.input, schema, 'input']; - yield [names.output, schema, 'output']; - } - } - - private prepareDirections(): void { - if (this.directions) return; - const different = new Set>(); - // A changed named child changes its parents' references. Iterate to a - // fixed point; named recursive edges are always references, not recursion. - let changed = true; - while (changed) { - changed = false; - for (const [, schema] of this.byName) { - if (different.has(schema)) continue; - const render = (mode: 'input' | 'output') => { - let rootInlined = false; - return JSON.stringify( - toJsonSchema(schema, { - $schema: false, - mode, - nameResolver: candidate => { - if (candidate === schema && !rootInlined) { - rootInlined = true; - return null; - } - const name = this.byInstance.get(candidate); - return name - ? name + - (different.has(candidate) - ? mode === 'input' - ? 'Input' - : 'Output' - : '') - : null; - } - }) - ); - }; - if (render('input') !== render('output')) { - different.add(schema); - changed = true; - } - } - } - const names = new Map>( - this.byName - ); - const directions = new Map< - SchemaBuilder, - { input: string; output: string } - >(); - for (const [name, schema] of this.byName) { - const pair = different.has(schema) - ? { input: name + 'Input', output: name + 'Output' } - : { input: name, output: name }; - for (const derived of new Set(Object.values(pair))) { - if (names.has(derived) && names.get(derived) !== schema) { - throw new Error( - `Schema component name "${derived}" conflicts with a generated input/output name.` - ); - } - names.set(derived, schema); - } - directions.set(schema, pair); - } - this.directions = directions; + getName(schema: SchemaBuilder): string | null { + return this.byInstance.get(schema) ?? null; } /** @@ -217,9 +127,7 @@ export function walkSchemas( switch (info.type) { case 'reference': - case 'decode': - walkSchemas(info.inputSchema, registry, visited); - walkSchemas(info.outputSchema, registry, visited); + walkSchemas(info.targetSchema, registry, visited); break; case 'intersection': walkSchemas(info.left, registry, visited); diff --git a/websites/docs/app/server-openapi/page.tsx b/websites/docs/app/server-openapi/page.tsx index 0d96da94..784a18fb 100644 --- a/websites/docs/app/server-openapi/page.tsx +++ b/websites/docs/app/server-openapi/page.tsx @@ -21,13 +21,13 @@ export default function ServerOpenApiPage() {
-

Named references and input/output views

+

Named references and local annotations

Use schemaRef to annotate one use of a named definition - without cloning it. Requests use input views and - responses use output views; differing named - representations receive collision-checked Input and - Output suffixes. + without cloning it. Optionality, nullability and + descriptions remain local, while the target has one + canonical component. Conflicting named definitions still + fail registration.

Schema boundary composition and compatibility diff --git a/websites/schema/app/docs/sections/schema-boundaries.tsx b/websites/schema/app/docs/sections/schema-boundaries.tsx index 5a3f8235..8d94821d 100644 --- a/websites/schema/app/docs/sections/schema-boundaries.tsx +++ b/websites/schema/app/docs/sections/schema-boundaries.tsx @@ -4,8 +4,8 @@ export default function SchemaBoundariesSection() {

Schemas Across Boundaries

- Compose named references and explicit input-to-output - decoding without duplicating validation rules. + Compose optional fallbacks and named references without + duplicating validation rules.

@@ -38,45 +38,13 @@ const History = object({

-

Declared input and output

-
-                    {`const PageSize = decode(
-    string(),
-    number().isInteger().min(1).max(100),
-    value => Number(value)
-);
-type Editable = InferInput; // string
-type Validated = InferOutput; // number
-PageSize.parse('20'); // 20`}
-                
-

- The input is validated before conversion; the converted - result is validated against the output schema. Converter - errors become validation failures. Use parseAsync for - asynchronous converters. InferType remains an output alias. -

-

- Nested schemas and Standard Schema retain both types. - Defaults on the input schema run before conversion; a - default on the boundary is an output default. -

-
-
-

Export and adoption

-
-                    {`toJsonSchema(PageSize, { mode: 'input' });
-toJsonSchema(PageSize, { mode: 'output' }); // default`}
-                
-

- OpenAPI uses input for requests and output for responses, - splitting named components when their shapes differ. Export - describes declared shapes, not arbitrary conversion logic. -

+

API documents

- Form state and typed-client request inference are separate - integrations. Until adopted there, keep explicit wire - contracts and decode at your application boundary. No - reverse conversion is inferred. + JSON Schema, OpenAPI and AsyncAPI preserve one canonical + named definition with local reference annotations. + Independent definitions with the same name still fail + registration. Existing inference and static type overrides + are unchanged.

Read the full composition guide diff --git a/websites/schema/app/schema-json/page.tsx b/websites/schema/app/schema-json/page.tsx index 23926606..1b936ffc 100644 --- a/websites/schema/app/schema-json/page.tsx +++ b/websites/schema/app/schema-json/page.tsx @@ -33,16 +33,15 @@ export default function SchemaJsonPage() { /> {/* ── Installation ─────────────────────────────────── */} From cbc2f14acf44f0dc47821a14cd9ffc30694fbe0f Mon Sep 17 00:00:00 2001 From: Andrew Zolotukhin Date: Tue, 29 Sep 2026 09:44:26 +0000 Subject: [PATCH 07/41] refactor(schema): make named references automatic --- .changeset/schema-boundaries.md | 7 +- libs/schema-json/README.md | 6 +- libs/schema-json/src/boundaries.test.ts | 85 +++- libs/schema-json/src/toJsonSchema.ts | 37 +- libs/schema/BOUNDARIES.md | 57 ++- libs/schema/README.md | 7 +- libs/schema/package.json | 3 +- libs/schema/src/boundaries-docs.test.ts | 64 ++- libs/schema/src/builders/AnySchemaBuilder.ts | 18 +- .../schema/src/builders/ArraySchemaBuilder.ts | 30 +- .../src/builders/BooleanSchemaBuilder.ts | 22 +- libs/schema/src/builders/DateSchemaBuilder.ts | 46 ++- .../src/builders/ExternSchemaBuilder.ts | 18 +- .../src/builders/FunctionSchemaBuilder.ts | 22 +- .../src/builders/GenericSchemaBuilder.ts | 18 +- .../src/builders/IntersectionSchemaBuilder.ts | 18 +- libs/schema/src/builders/LazySchemaBuilder.ts | 18 +- libs/schema/src/builders/NullSchemaBuilder.ts | 18 +- .../src/builders/NumberSchemaBuilder.ts | 44 +- .../src/builders/ObjectSchemaBuilder.ts | 73 ++-- .../src/builders/ParseStringSchemaBuilder.ts | 18 +- .../src/builders/PromiseSchemaBuilder.ts | 20 +- .../src/builders/RecordSchemaBuilder.ts | 18 +- .../builders/ReferenceSchemaBuilder.test.ts | 149 ------- .../src/builders/ReferenceSchemaBuilder.ts | 387 ------------------ libs/schema/src/builders/SchemaBuilder.ts | 314 ++++++++------ .../src/builders/StringSchemaBuilder.ts | 42 +- .../schema/src/builders/TupleSchemaBuilder.ts | 22 +- .../schema/src/builders/UnionSchemaBuilder.ts | 24 +- libs/schema/src/builders/namedSchemas.test.ts | 325 +++++++++++++++ libs/schema/src/builders/references.test-d.ts | 16 +- libs/schema/src/core.ts | 4 - libs/server-openapi/README.md | 8 +- libs/server-openapi/src/boundaries.test.ts | 68 ++- libs/server-openapi/src/schemaRegistry.ts | 20 +- websites/docs/app/server-openapi/page.tsx | 11 +- .../app/docs/sections/schema-boundaries.tsx | 13 +- websites/schema/app/schema-json/page.tsx | 10 +- 38 files changed, 1099 insertions(+), 981 deletions(-) delete mode 100644 libs/schema/src/builders/ReferenceSchemaBuilder.test.ts delete mode 100644 libs/schema/src/builders/ReferenceSchemaBuilder.ts create mode 100644 libs/schema/src/builders/namedSchemas.test.ts diff --git a/.changeset/schema-boundaries.md b/.changeset/schema-boundaries.md index 4694b904..c4c0d255 100644 --- a/.changeset/schema-boundaries.md +++ b/.changeset/schema-boundaries.md @@ -4,7 +4,10 @@ "@cleverbrush/server-openapi": minor --- -Add optional-aware fallbacks and preprocessing, and immutable named schema -references with local annotations. Preserve one canonical definition in JSON +Add optional-aware fallbacks and preprocessing, and automatic named schema +references through ordinary immutable use-site modifiers, without a wrapper API. +Shape, validation-rule, default, fallback and extension changes clear inherited +names; apply schemaName after those edits to establish a new named definition. +Preserve one canonical definition in JSON Schema, OpenAPI and AsyncAPI with strict name collision checks. Keep existing type inference and legacy optional null acceptance unchanged. diff --git a/libs/schema-json/README.md b/libs/schema-json/README.md index e6d64655..d6c137ff 100644 --- a/libs/schema-json/README.md +++ b/libs/schema-json/README.md @@ -14,8 +14,10 @@ for use in OpenAPI specs, form generators, or any other JSON Schema consumer. ### Named references -Named reference wrappers preserve use-site annotations, optionality and nullability -without changing the shared definition. See the [composition guide](../schema/BOUNDARIES.md). +Ordinary modifiers such as `User.optional().nullable().describe('Previous')` +preserve a named definition automatically. Shape and validation-rule changes +become unnamed derivatives; apply `schemaName` last to name a new definition. +See the [composition guide](https://github.com/cleverbrush/framework/blob/development/libs/schema/BOUNDARIES.md). - **Consuming external APIs** — you have a JSON Schema from an OpenAPI spec or a third-party service and want to validate incoming data with full TypeScript diff --git a/libs/schema-json/src/boundaries.test.ts b/libs/schema-json/src/boundaries.test.ts index ea57988e..c79286aa 100644 --- a/libs/schema-json/src/boundaries.test.ts +++ b/libs/schema-json/src/boundaries.test.ts @@ -1,4 +1,4 @@ -import { object, schemaRef, string } from '@cleverbrush/schema'; +import { object, string } from '@cleverbrush/schema'; import { describe, expect, it } from 'vitest'; import { withStandardJsonSchema } from './standardJsonSchema.js'; import { toJsonSchema } from './toJsonSchema.js'; @@ -10,8 +10,8 @@ describe('named reference JSON Schema', () => { ] as const)('keeps annotations outside the definition in draft %s', draft => { const user = object({ name: string() }).schemaName('User'); const schema = object({ - user: schemaRef(user), - previous: schemaRef(user) + user: user, + previous: user .nullable() .optional() .describe('Previous user') @@ -24,7 +24,7 @@ describe('named reference JSON Schema', () => { }) as any; expect(json.required).toEqual(['user']); expect(json.properties.user).toEqual({ - allOf: [{ $ref: '#/components/schemas/User' }] + $ref: '#/components/schemas/User' }); expect(json.properties.previous).toMatchObject({ description: 'Previous user', @@ -39,28 +39,85 @@ describe('named reference JSON Schema', () => { it('keeps final local default and nullability modifiers', () => { const target = string().nullable().schemaName('Name'); - const ref = schemaRef(target).notNullable().optional().default('new'); + const ref = target.notNullable().optional().default('new'); const schema = object({ name: ref }); const json = toJsonSchema(schema) as any; expect(schema.parse({})).toEqual({ name: 'new' }); - expect(json.required).toEqual(['name']); + expect(json.required).toBeUndefined(); expect(json.properties.name.default).toBe('new'); - expect(json.properties.name.allOf).toEqual([ - { type: ['string', 'null'] }, - { not: { type: 'null' } } - ]); + expect(json.properties.name.type).toBe('string'); + expect(json.properties.name.allOf).toBeUndefined(); const nullableAgain = toJsonSchema(ref.nullable()); - expect(nullableAgain.anyOf).toBeDefined(); + expect(nullableAgain.type).toEqual(['string', 'null']); expect(toJsonSchema(ref.readonly()).readOnly).toBe(true); }); it('retains identical Standard JSON Schema views', () => { - const ref = schemaRef(string().schemaName('Name')) - .optional() - .describe('A name'); + const ref = string().schemaName('Name').optional().describe('A name'); const standard = withStandardJsonSchema(ref)['~standard'].jsonSchema; expect(standard.input({ target: 'draft-2020-12' })).toEqual( standard.output({ target: 'draft-2020-12' }) ); }); + + it.each([ + '2020-12', + '07' + ] as const)('retains local modifiers before name resolution in draft %s', draft => { + const target = string() + .nullable() + .describe('Canonical') + .schemaName('Name'); + const local = target + .notNullable() + .describe('Use') + .example('Ada') + .readonly(); + const nameResolver = (s: typeof target) => + s.introspect().schemaName ?? null; + expect( + toJsonSchema(local, { draft, $schema: false, nameResolver }) + ).toEqual({ + allOf: [ + { $ref: '#/components/schemas/Name' }, + { not: { type: 'null' } } + ], + description: 'Use', + examples: ['Ada'], + readOnly: true + }); + expect(toJsonSchema(local, { draft, $schema: false }).allOf).toEqual([ + { type: ['string', 'null'], description: 'Canonical' }, + { not: { type: 'null' } } + ]); + expect( + toJsonSchema(local.nullable(), { + draft, + $schema: false, + nameResolver + }).allOf + ).toEqual([{ $ref: '#/components/schemas/Name' }]); + expect(target.introspect().description).toBe('Canonical'); + }); + + it('exports shape/rule derivatives inline while keeping nested named children', () => { + const name = string().schemaName('Name'); + const user = object({ name }).schemaName('User'); + const partial = user.partial().describe('Patch'); + const json = toJsonSchema(partial, { + $schema: false, + nameResolver: s => s.introspect().schemaName ?? null + }) as any; + expect(json.type).toBe('object'); + expect(json.required).toBeUndefined(); + expect(json.properties.name.allOf).toEqual([ + { $ref: '#/components/schemas/Name' } + ]); + expect( + toJsonSchema(name.maxLength(3), { + $schema: false, + nameResolver: s => s.introspect().schemaName ?? null + }) + ).toEqual({ type: 'string', maxLength: 3 }); + }); }); diff --git a/libs/schema-json/src/toJsonSchema.ts b/libs/schema-json/src/toJsonSchema.ts index b5bbccaf..82336ba6 100644 --- a/libs/schema-json/src/toJsonSchema.ts +++ b/libs/schema-json/src/toJsonSchema.ts @@ -24,15 +24,6 @@ function convertNodeInner( const readOnly: Out = info.isReadonly === true ? { readOnly: true } : {}; switch (info.type) { - case 'reference': { - const out: Out = { - ...readOnly, - allOf: [convertNode(info.targetSchema, resolver)] - }; - if (info.nullability === false) - (out.allOf as Out[]).push({ not: { type: 'null' } }); - return out; - } case 'string': { if (info.equalsTo !== undefined) return { ...readOnly, const: info.equalsTo }; @@ -251,6 +242,22 @@ function convertNode( schema: SchemaBuilder, resolver: Resolver ): Out { + const info = schema.introspect(); + if (info.referenceTarget) { + const target = info.referenceTarget; + const canonical = target.introspect(); + // Handle aliases before name lookup so use-site modifiers survive. + let out: Out = { allOf: [convertNode(target, resolver)] }; + if (info.isNullable && !canonical.isNullable) { + out = { anyOf: [out, { type: 'null' }] }; + } else if (!info.isNullable && canonical.isNullable) { + (out.allOf as Out[]).push({ not: { type: 'null' } }); + } + if (info.description !== undefined) out.description = info.description; + if (info.example !== undefined) out.examples = [info.example]; + if (info.isReadonly) out.readOnly = true; + return out; + } if (resolver) { const name = resolver(schema); if (typeof name === 'string' && name.length > 0) { @@ -260,7 +267,6 @@ function convertNode( } } const out = convertNodeInner(schema, resolver); - const info = schema.introspect() as any; if (typeof info.description === 'string' && info.description !== '') out['description'] = info.description; @@ -279,11 +285,7 @@ function convertNode( } // Handle nullable — JSON Schema 2020-12 style: type becomes an array - if ( - info.type === 'reference' - ? info.nullability === true - : info.isNullable === true - ) { + if (info.isNullable === true) { if (out['anyOf'] !== undefined) { // Union type — add { type: 'null' } to anyOf if not already present const anyOf = out['anyOf'] as Out[]; @@ -291,10 +293,7 @@ function convertNode( if (!hasNull) anyOf.push({ type: 'null' }); } else if (out['allOf'] !== undefined && out['type'] === undefined) { // Intersection type without a top-level type — wrap in oneOf with null - out[info.type === 'reference' ? 'anyOf' : 'oneOf'] = [ - { allOf: out['allOf'] as Out[] }, - { type: 'null' } - ]; + out['oneOf'] = [{ allOf: out['allOf'] as Out[] }, { type: 'null' }]; delete out['allOf']; } else if (out['enum'] !== undefined) { // Enum — add null to enum values if not already present diff --git a/libs/schema/BOUNDARIES.md b/libs/schema/BOUNDARIES.md index 0fe12617..14695a44 100644 --- a/libs/schema/BOUNDARIES.md +++ b/libs/schema/BOUNDARIES.md @@ -1,6 +1,6 @@ # Schemas across boundaries -These APIs are additive. `InferType` continues to mean validated output; +`InferType` continues to mean validated output; existing builder generic arguments and legacy preprocessors keep their meaning. ## Optional fallbacks @@ -46,31 +46,62 @@ Before, cloning `User.schemaName('User')` with `.optional()` created another named instance and conflicted during OpenAPI generation. ```ts -import { number, object, schemaRef, string } from '@cleverbrush/schema'; +import { number, object, string } from '@cleverbrush/schema'; const User = object({ id: number(), name: string() }).schemaName('User'); const History = object({ - current: schemaRef(User), - previous: schemaRef(User).nullable().optional() + current: User, + previous: User.nullable().optional() .describe('The previous user, when known.') }); ``` -`schemaRef` requires a named target. Its local modifiers do not rename, clone, -or mutate that target. References delegate validation and preserve nested -property selectors/errors. Independent schemas sharing a name still conflict; -there is no name-only deduplication. Use-site optionality controls omission; -nullability controls null acceptance for the wrapper independently. +No wrapper is needed. Ordinary immutable modifiers keep the concrete builder, +fluent methods, extension methods, inference, and nested property selectors. +They validate normally; canonical-reference metadata only affects exporters. +The original definition is never mutated. Reuse the plain constant when there +are no local modifiers. Independent definitions sharing a name still conflict; +there is no name-based or structural deduplication. + +### Which changes preserve the named definition? + +- Use-site presence/nullability: `optional`, `required`, `nullable`, `notNullable`. +- Annotations: `describe`, `example`, `readonly`. +- Type-only changes: `brand`, `hasType`, `clearHasType`, `optimize`. + +Chains of these modifiers always reference the original canonical definition, +not another alias. Calling `schemaName` explicitly creates a new independent +definition, even when the previous name is reused. + +### Shape and rule changes become unnamed + +Property additions/removals, `partial`, `pick`, `omit`, constraints, validators, +preprocessors, defaults, fallbacks, and their clear methods discard the inherited +name and canonical association. Extension changes detach conservatively, too. +These derivatives cannot safely claim to be the original definition. Later +annotations or optionality do not reconnect them. + +```ts +const PartialUser = User.partial(); // unnamed, all properties optional +const UserWithEmail = User.addProp('email', string()); // unnamed, new shape +const PublicUser = User.omit('id').schemaName('PublicUser'); // new definition +const ShortName = string().schemaName('Name').maxLength(20); // unnamed rule change +``` + +Existing nested named schemas still reuse their own definitions. To retain a +stable component name after a shape or rule change, call `schemaName` **last**. +This intentionally changes inherited-name behavior; review code that relied on +constraint/property modifications retaining the old component name. JSON Schema/OpenAPI keeps one definition and uses reference composition for local annotations, examples and nullability, including Draft 07 references. ## Defaults and validation -A default on the reference overrides missing values at that use site and is -validated by the target. Clearing it leaves any target default intact. Local -fallbacks use the existing catch semantics. Async target validators and local -callbacks require `parseAsync`/`validateAsync`. +Defaults and fallbacks retain ordinary builder behavior, not delegated wrapper +behavior. Adding or clearing either detaches the name. Clearing a default removes +it completely; it does not reveal a hidden canonical default. Async validators +and preprocessors still require `parseAsync`/`validateAsync`. Use `InferType` for schema inference and the existing `hasType` method when an explicit static override is needed. Static overrides and casts do not change diff --git a/libs/schema/README.md b/libs/schema/README.md index d602cdab..937bf4f4 100644 --- a/libs/schema/README.md +++ b/libs/schema/README.md @@ -2,9 +2,10 @@ ## Schemas across boundaries -Use optional-aware `catch(undefined)` and `schemaRef(namedSchema)` for per-use -annotations without cloning named definitions. See the -[composition guide](./BOUNDARIES.md) for examples and null-compatibility limits. +Use optional-aware `catch(undefined)` and ordinary named-schema modifiers for per-use +annotations while preserving canonical named definitions. See the +[composition guide](https://github.com/cleverbrush/framework/blob/development/libs/schema/BOUNDARIES.md) +for examples, naming rules and null-compatibility limits. [![CI](https://github.com/cleverbrush/framework/actions/workflows/ci.yml/badge.svg)](https://github.com/cleverbrush/framework/actions/workflows/ci.yml) [![Standard Schema v1](https://img.shields.io/badge/Standard%20Schema-v1-blue)](https://standardschema.dev/) diff --git a/libs/schema/package.json b/libs/schema/package.json index dce29b43..c89f8fcc 100644 --- a/libs/schema/package.json +++ b/libs/schema/package.json @@ -6,8 +6,7 @@ }, "description": "Schema Definition And Validation library, that allows to define and validate objects of any complexity", "files": [ - "dist", - "BOUNDARIES.md" + "dist" ], "homepage": "https://schema.cleverbrush.com/docs/getting-started", "keywords": [ diff --git a/libs/schema/src/boundaries-docs.test.ts b/libs/schema/src/boundaries-docs.test.ts index d023d40f..25eeffc0 100644 --- a/libs/schema/src/boundaries-docs.test.ts +++ b/libs/schema/src/boundaries-docs.test.ts @@ -3,12 +3,15 @@ import ts from 'typescript'; import { describe, expect, it } from 'vitest'; describe('published boundary documentation', () => { - it('preserves summaries for new APIs, types and public boundary members', () => { - const missing: string[] = []; + it('preserves declaration summaries for boundary types and methods', () => { + const hasSummary = (node: ts.Node) => + (node as ts.Node & { jsDoc?: readonly ts.JSDoc[] }).jsDoc?.some( + doc => doc.comment + ); for (const [path, names] of [ [ - '../dist/builders/ReferenceSchemaBuilder.d.ts', - ['ReferenceSchemaBuilder', 'schemaRef'] + '../dist/builders/SchemaBuilder.d.ts', + ['SchemaBuilder', 'SchemaBuilderProps'] ], ['../../schema-json/dist/types.d.ts', ['ToJsonSchemaOptions']] ] as const) { @@ -19,40 +22,31 @@ describe('published boundary documentation', () => { ts.ScriptTarget.Latest, true ); - const hasSummary = (node: ts.Node) => - (node as ts.Node & { jsDoc?: readonly ts.JSDoc[] }).jsDoc?.some( - doc => doc.comment + for (const name of names) { + const node = source.statements.find( + node => + 'name' in node && + (node.name as ts.Identifier)?.text === name ); - for (const node of source.statements) { - const name = - 'name' in node && node.name - ? (node.name as ts.Identifier).text - : ''; - if (!(names as readonly string[]).includes(name)) continue; - if (!hasSummary(node)) missing.push(name); - if (ts.isClassDeclaration(node)) - for (const member of node.members) { - if ( - ts.getCombinedModifierFlags(member) & - (ts.ModifierFlags.Private | - ts.ModifierFlags.Protected) - ) - continue; - if (member.name && ts.isPrivateIdentifier(member.name)) - continue; - if ( - ts - .getJSDocTags(member) - .some(tag => tag.tagName.text === 'internal') - ) - continue; - if (!hasSummary(member)) - missing.push( - name + '.' + member.name?.getText(source) - ); + expect(node, name).toBeDefined(); + expect(hasSummary(node!), name).toBe(true); + if (node && ts.isClassDeclaration(node)) { + for (const memberName of [ + 'schemaName', + 'introspect', + 'derive', + 'catch', + 'addPreprocessor' + ]) { + const member = node.members.find( + member => + member.name?.getText(source) === memberName + ); + expect(member, memberName).toBeDefined(); + expect(hasSummary(member!), memberName).toBe(true); } + } } } - expect(missing).toEqual([]); }); }); diff --git a/libs/schema/src/builders/AnySchemaBuilder.ts b/libs/schema/src/builders/AnySchemaBuilder.ts index 20f27099..451a85c1 100644 --- a/libs/schema/src/builders/AnySchemaBuilder.ts +++ b/libs/schema/src/builders/AnySchemaBuilder.ts @@ -62,9 +62,12 @@ export class AnySchemaBuilder< _notUsed?: T ): AnySchemaBuilder & TExtensions { - return this.createFromProps({ - ...this.introspect() - } as any) as any; + return this.derive( + { + ...this.introspect() + } as any, + true + ) as any; } /** @@ -78,9 +81,12 @@ export class AnySchemaBuilder< TExtensions > & TExtensions { - return this.createFromProps({ - ...this.introspect() - } as any) as any; + return this.derive( + { + ...this.introspect() + } as any, + true + ) as any; } #buildResult( diff --git a/libs/schema/src/builders/ArraySchemaBuilder.ts b/libs/schema/src/builders/ArraySchemaBuilder.ts index a044538b..03995a40 100644 --- a/libs/schema/src/builders/ArraySchemaBuilder.ts +++ b/libs/schema/src/builders/ArraySchemaBuilder.ts @@ -188,9 +188,12 @@ export class ArraySchemaBuilder< TExtensions > & TExtensions { - return this.createFromProps({ - ...this.introspect() - } as any) as any; + return this.derive( + { + ...this.introspect() + } as any, + true + ) as any; } /** @@ -205,9 +208,12 @@ export class ArraySchemaBuilder< TExtensions > & TExtensions { - return this.createFromProps({ - ...this.introspect() - } as any) as any; + return this.derive( + { + ...this.introspect() + } as any, + true + ) as any; } #createValidationSetup( @@ -839,7 +845,7 @@ export class ArraySchemaBuilder< TExtensions > & TExtensions { - return ArraySchemaBuilder.create({ + return this.derive({ ...this.introspect(), elementSchema: schema } as any) as any; @@ -858,7 +864,7 @@ export class ArraySchemaBuilder< TExtensions > & TExtensions { - return ArraySchemaBuilder.create({ + return this.derive({ ...this.introspect(), elementSchema: undefined } as any) as any; @@ -891,7 +897,7 @@ export class ArraySchemaBuilder< TExtensions { if (typeof length !== 'number' || length < 0) throw new Error('length is expected to be a number which is >= 0'); - return ArraySchemaBuilder.create({ + return this.derive({ ...this.introspect(), minLength: length, minLengthValidationErrorMessageProvider: errorMessage @@ -912,7 +918,7 @@ export class ArraySchemaBuilder< TExtensions { const schema = this.introspect(); delete schema.minLength; - return this.createFromProps({ + return this.derive({ ...schema } as any) as any; } @@ -944,7 +950,7 @@ export class ArraySchemaBuilder< TExtensions { if (typeof length !== 'number' || length < 0) throw new Error('length is expected to be a number which is >= 0'); - return ArraySchemaBuilder.create({ + return this.derive({ ...this.introspect(), maxLength: length, maxLengthValidationErrorMessageProvider: errorMessage @@ -965,7 +971,7 @@ export class ArraySchemaBuilder< TExtensions { const schema = this.introspect(); delete schema.maxLength; - return this.createFromProps({ + return this.derive({ ...schema } as any) as any; } diff --git a/libs/schema/src/builders/BooleanSchemaBuilder.ts b/libs/schema/src/builders/BooleanSchemaBuilder.ts index 050fdf4b..2a3815f4 100644 --- a/libs/schema/src/builders/BooleanSchemaBuilder.ts +++ b/libs/schema/src/builders/BooleanSchemaBuilder.ts @@ -122,9 +122,12 @@ export class BooleanSchemaBuilder< TExtensions > & TExtensions { - return this.createFromProps({ - ...this.introspect() - } as any) as any; + return this.derive( + { + ...this.introspect() + } as any, + true + ) as any; } /** @@ -139,9 +142,12 @@ export class BooleanSchemaBuilder< TExtensions > & TExtensions { - return this.createFromProps({ - ...this.introspect() - } as any) as any; + return this.derive( + { + ...this.introspect() + } as any, + true + ) as any; } #getConstraintViolation( @@ -458,7 +464,7 @@ export class BooleanSchemaBuilder< > ) { if (typeof value !== 'boolean') throw new Error('boolean expected'); - return this.createFromProps({ + return this.derive({ ...this.introspect(), equalsTo: value, equalsToValidationErrorMessageProvider: errorMessage @@ -485,7 +491,7 @@ export class BooleanSchemaBuilder< TExtensions > & TExtensions { - return this.createFromProps({ + return this.derive({ ...this.introspect(), equalsTo: undefined } as any) as any; diff --git a/libs/schema/src/builders/DateSchemaBuilder.ts b/libs/schema/src/builders/DateSchemaBuilder.ts index 17392297..161efd5d 100644 --- a/libs/schema/src/builders/DateSchemaBuilder.ts +++ b/libs/schema/src/builders/DateSchemaBuilder.ts @@ -309,9 +309,12 @@ export class DateSchemaBuilder< _notUsed?: T ): DateSchemaBuilder & TExtensions { - return this.createFromProps({ - ...this.introspect() - } as any) as any; + return this.derive( + { + ...this.introspect() + } as any, + true + ) as any; } /** @@ -325,9 +328,12 @@ export class DateSchemaBuilder< TExtensions > & TExtensions { - return this.createFromProps({ - ...this.introspect() - } as any) as any; + return this.derive( + { + ...this.introspect() + } as any, + true + ) as any; } #getConstraintViolation( @@ -582,7 +588,7 @@ export class DateSchemaBuilder< ): DateSchemaBuilder & TExtensions { if (!(value instanceof Date)) throw new Error('Date expected'); - return this.createFromProps({ + return this.derive({ ...this.introspect(), equalsTo: value, equalsToValidationErrorMessageProvider: errorMessage @@ -607,7 +613,7 @@ export class DateSchemaBuilder< TExtensions > & TExtensions { - return this.createFromProps({ + return this.derive({ ...this.introspect(), equalsTo: undefined }) as any; @@ -713,7 +719,7 @@ export class DateSchemaBuilder< TExtensions > & TExtensions { - return this.createFromProps({ + return this.derive({ ...this.introspect(), ensureIsInFuture: true, ensureIsInFutureValidationErrorMessageProvider: errorMessage @@ -731,7 +737,7 @@ export class DateSchemaBuilder< TExtensions > & TExtensions { - return this.createFromProps({ + return this.derive({ ...this.introspect(), ensureIsInFuture: false }) as any; @@ -755,7 +761,7 @@ export class DateSchemaBuilder< TExtensions > & TExtensions { - return this.createFromProps({ + return this.derive({ ...this.introspect(), ensureIsInPast: true, ensureIsInPastValidationErrorMessageProvider: errorMessage @@ -773,7 +779,7 @@ export class DateSchemaBuilder< TExtensions > & TExtensions { - return this.createFromProps({ + return this.derive({ ...this.introspect(), ensureIsInPast: false }) as any; @@ -800,7 +806,7 @@ export class DateSchemaBuilder< TExtensions { if (!(minValue instanceof Date)) throw new Error('minValue must be a Date'); - return this.createFromProps({ + return this.derive({ ...this.introspect(), min: minValue, minValidationErrorMessageProvider: errorMessage @@ -820,7 +826,7 @@ export class DateSchemaBuilder< TExtensions { const schema = this.introspect(); delete schema.min; - return this.createFromProps({ + return this.derive({ ...schema }) as any; } @@ -846,7 +852,7 @@ export class DateSchemaBuilder< TExtensions { if (!(maxValue instanceof Date)) throw new Error('maxValue must be a Date'); - return this.createFromProps({ + return this.derive({ ...this.introspect(), max: maxValue, maxValidationErrorMessageProvider: errorMessage @@ -866,7 +872,7 @@ export class DateSchemaBuilder< TExtensions { const schema = this.introspect(); delete schema.max; - return this.createFromProps({ + return this.derive({ ...schema }) as any; } @@ -920,7 +926,7 @@ export class DateSchemaBuilder< TExtensions > & TExtensions { - return this.createFromProps({ + return this.derive({ ...this.introspect(), parseFromJson: true }) as any; @@ -937,7 +943,7 @@ export class DateSchemaBuilder< TExtensions > & TExtensions { - return this.createFromProps({ + return this.derive({ ...this.introspect(), parseFromJson: false }) as any; @@ -955,7 +961,7 @@ export class DateSchemaBuilder< TExtensions > & TExtensions { - return this.createFromProps({ + return this.derive({ ...this.introspect(), parseFromEpoch: true }) as any; @@ -972,7 +978,7 @@ export class DateSchemaBuilder< TExtensions > & TExtensions { - return this.createFromProps({ + return this.derive({ ...this.introspect(), parseFromEpoch: false }) as any; diff --git a/libs/schema/src/builders/ExternSchemaBuilder.ts b/libs/schema/src/builders/ExternSchemaBuilder.ts index 6d4fb12d..65cad914 100644 --- a/libs/schema/src/builders/ExternSchemaBuilder.ts +++ b/libs/schema/src/builders/ExternSchemaBuilder.ts @@ -147,9 +147,12 @@ export class ExternSchemaBuilder< TExtensions > & TExtensions { - return this.createFromProps({ - ...this.introspect() - } as any) as any; + return this.derive( + { + ...this.introspect() + } as any, + true + ) as any; } /** @@ -164,9 +167,12 @@ export class ExternSchemaBuilder< TExtensions > & TExtensions { - return this.createFromProps({ - ...this.introspect() - } as any) as any; + return this.derive( + { + ...this.introspect() + } as any, + true + ) as any; } /** diff --git a/libs/schema/src/builders/FunctionSchemaBuilder.ts b/libs/schema/src/builders/FunctionSchemaBuilder.ts index be53b16e..b8aa381b 100644 --- a/libs/schema/src/builders/FunctionSchemaBuilder.ts +++ b/libs/schema/src/builders/FunctionSchemaBuilder.ts @@ -129,9 +129,12 @@ export class FunctionSchemaBuilder< TReturnTypeSchema > & TExtensions { - return this.createFromProps({ - ...this.introspect() - } as any) as any; + return this.derive( + { + ...this.introspect() + } as any, + true + ) as any; } /** @@ -147,9 +150,12 @@ export class FunctionSchemaBuilder< TReturnTypeSchema > & TExtensions { - return this.createFromProps({ - ...this.introspect() - } as any) as any; + return this.derive( + { + ...this.introspect() + } as any, + true + ) as any; } /** @@ -436,7 +442,7 @@ export class FunctionSchemaBuilder< TReturnTypeSchema > & TExtensions { - return this.createFromProps({ + return this.derive({ ...this.introspect(), parameters: [...this.#parameters, schema] } as any) as any; @@ -477,7 +483,7 @@ export class FunctionSchemaBuilder< TSchema > & TExtensions { - return this.createFromProps({ + return this.derive({ ...this.introspect(), returnType: schema } as any) as any; diff --git a/libs/schema/src/builders/GenericSchemaBuilder.ts b/libs/schema/src/builders/GenericSchemaBuilder.ts index addf3d1a..54dd9566 100644 --- a/libs/schema/src/builders/GenericSchemaBuilder.ts +++ b/libs/schema/src/builders/GenericSchemaBuilder.ts @@ -361,9 +361,12 @@ export class GenericSchemaBuilder< _notUsed?: T ): GenericSchemaBuilder & TExtensions { - return this.createFromProps({ - ...this.introspect() - } as any) as any; + return this.derive( + { + ...this.introspect() + } as any, + true + ) as any; } /** @@ -378,9 +381,12 @@ export class GenericSchemaBuilder< TExtensions > & TExtensions { - return this.createFromProps({ - ...this.introspect() - } as any) as any; + return this.derive( + { + ...this.introspect() + } as any, + true + ) as any; } /** diff --git a/libs/schema/src/builders/IntersectionSchemaBuilder.ts b/libs/schema/src/builders/IntersectionSchemaBuilder.ts index 6d746c6a..3ba5465e 100644 --- a/libs/schema/src/builders/IntersectionSchemaBuilder.ts +++ b/libs/schema/src/builders/IntersectionSchemaBuilder.ts @@ -96,9 +96,12 @@ export class IntersectionSchemaBuilder< TExtensions > & TExtensions { - return this.createFromProps({ - ...this.introspect() - } as any) as any; + return this.derive( + { + ...this.introspect() + } as any, + true + ) as any; } /** @@ -114,9 +117,12 @@ export class IntersectionSchemaBuilder< TExtensions > & TExtensions { - return this.createFromProps({ - ...this.introspect() - } as any) as any; + return this.derive( + { + ...this.introspect() + } as any, + true + ) as any; } /** diff --git a/libs/schema/src/builders/LazySchemaBuilder.ts b/libs/schema/src/builders/LazySchemaBuilder.ts index 12f0d7c5..0d154384 100644 --- a/libs/schema/src/builders/LazySchemaBuilder.ts +++ b/libs/schema/src/builders/LazySchemaBuilder.ts @@ -212,9 +212,12 @@ export class LazySchemaBuilder< _notUsed?: T ): LazySchemaBuilder & TExtensions { - return this.createFromProps({ - ...this.introspect() - } as any) as any; + return this.derive( + { + ...this.introspect() + } as any, + true + ) as any; } /** @@ -228,9 +231,12 @@ export class LazySchemaBuilder< TExtensions > & TExtensions { - return this.createFromProps({ - ...this.introspect() - } as any) as any; + return this.derive( + { + ...this.introspect() + } as any, + true + ) as any; } /** diff --git a/libs/schema/src/builders/NullSchemaBuilder.ts b/libs/schema/src/builders/NullSchemaBuilder.ts index 1ec973dc..d4c735cf 100644 --- a/libs/schema/src/builders/NullSchemaBuilder.ts +++ b/libs/schema/src/builders/NullSchemaBuilder.ts @@ -91,9 +91,12 @@ export class NullSchemaBuilder< _notUsed?: T ): NullSchemaBuilder & TExtensions { - return this.createFromProps({ - ...this.introspect() - } as any) as any; + return this.derive( + { + ...this.introspect() + } as any, + true + ) as any; } /** @@ -107,9 +110,12 @@ export class NullSchemaBuilder< TExtensions > & TExtensions { - return this.createFromProps({ - ...this.introspect() - } as any) as any; + return this.derive( + { + ...this.introspect() + } as any, + true + ) as any; } // The SchemaBuilder base-class preValidateSync/preValidateAsync treats diff --git a/libs/schema/src/builders/NumberSchemaBuilder.ts b/libs/schema/src/builders/NumberSchemaBuilder.ts index 36e250e7..951dc148 100644 --- a/libs/schema/src/builders/NumberSchemaBuilder.ts +++ b/libs/schema/src/builders/NumberSchemaBuilder.ts @@ -285,9 +285,12 @@ export class NumberSchemaBuilder< _notUsed?: T ): NumberSchemaBuilder & TExtensions { - return this.createFromProps({ - ...this.introspect() - } as any) as any; + return this.derive( + { + ...this.introspect() + } as any, + true + ) as any; } /** @@ -301,9 +304,12 @@ export class NumberSchemaBuilder< TExtensions > & TExtensions { - return this.createFromProps({ - ...this.introspect() - } as any) as any; + return this.derive( + { + ...this.introspect() + } as any, + true + ) as any; } #getConstraintViolation( @@ -557,7 +563,7 @@ export class NumberSchemaBuilder< > ) { if (typeof value !== 'number') throw new Error('number expected'); - return this.createFromProps({ + return this.derive({ ...this.introspect(), equalsTo: value, equalsToValidationErrorMessageProvider: errorMessage @@ -582,7 +588,7 @@ export class NumberSchemaBuilder< TExtensions > & TExtensions { - return this.createFromProps({ + return this.derive({ ...this.introspect(), equalsTo: undefined }) as any; @@ -600,7 +606,7 @@ export class NumberSchemaBuilder< TExtensions > & TExtensions { - return this.createFromProps({ + return this.derive({ ...this.introspect(), isInteger: false, ensureIsIntegerErrorMessageProvider: @@ -619,7 +625,7 @@ export class NumberSchemaBuilder< TExtensions > & TExtensions { - return this.createFromProps({ + return this.derive({ ...this.introspect(), isInteger: false, ensureIsIntegerErrorMessageProvider: @@ -645,7 +651,7 @@ export class NumberSchemaBuilder< TExtensions > & TExtensions { - return this.createFromProps({ + return this.derive({ ...this.introspect(), isInteger: true, ensureIsIntegerErrorMessageProvider: errorMessage @@ -752,7 +758,7 @@ export class NumberSchemaBuilder< TExtensions > & TExtensions { - return this.createFromProps({ + return this.derive({ ...this.introspect(), ensureNotNaN: true, ensureNotNaNErrorMessageProvider: errorMessage @@ -770,7 +776,7 @@ export class NumberSchemaBuilder< TExtensions > & TExtensions { - return this.createFromProps({ + return this.derive({ ...this.introspect(), ensureNotNaN: false, ensureNotNaNErrorMessageProvider: @@ -796,7 +802,7 @@ export class NumberSchemaBuilder< TExtensions > & TExtensions { - return this.createFromProps({ + return this.derive({ ...this.introspect(), ensureIsFinite: true, ensureIsFiniteErrorMessageProvider: errorMessage @@ -814,7 +820,7 @@ export class NumberSchemaBuilder< TExtensions > & TExtensions { - return this.createFromProps({ + return this.derive({ ...this.introspect(), ensureIsFinite: false, ensureIsFiniteErrorMessageProvider: @@ -870,7 +876,7 @@ export class NumberSchemaBuilder< TExtensions { if (typeof minValue !== 'number') throw new Error('minValue must be a number'); - return this.createFromProps({ + return this.derive({ ...this.introspect(), min: minValue, minValidationErrorMessageProvider: errorMessage @@ -890,7 +896,7 @@ export class NumberSchemaBuilder< TExtensions { const schema = this.introspect(); delete schema.min; - return this.createFromProps({ + return this.derive({ ...schema }) as any; } @@ -916,7 +922,7 @@ export class NumberSchemaBuilder< TExtensions { if (typeof maxValue !== 'number') throw new Error('maxValue must be a number'); - return this.createFromProps({ + return this.derive({ ...this.introspect(), max: maxValue, maxValidationErrorMessageProvider: errorMessage @@ -936,7 +942,7 @@ export class NumberSchemaBuilder< TExtensions { const schema = this.introspect(); delete schema.max; - return this.createFromProps({ + return this.derive({ ...schema }) as any; } diff --git a/libs/schema/src/builders/ObjectSchemaBuilder.ts b/libs/schema/src/builders/ObjectSchemaBuilder.ts index 5563d7f0..72e8ffd7 100644 --- a/libs/schema/src/builders/ObjectSchemaBuilder.ts +++ b/libs/schema/src/builders/ObjectSchemaBuilder.ts @@ -1073,8 +1073,7 @@ export class ObjectSchemaBuilder< ObjectSchemaBuilder.#propagateNestedErrors( result as any, descriptor, - addErrorFor, - this.#properties[key] + addErrorFor ); // For extern schemas, also record errors on the extern // descriptor itself so getErrorsFor(t => t.extern) works, @@ -1575,7 +1574,7 @@ export class ObjectSchemaBuilder< TConstructorSchemas > & TExtensions { - return this.createFromProps({ + return this.derive({ ...this.introspect(), acceptUnknownProps: true } as any) as any; @@ -1595,7 +1594,7 @@ export class ObjectSchemaBuilder< TConstructorSchemas > & TExtensions { - return this.createFromProps({ + return this.derive({ ...this.introspect(), acceptUnknownProps: false } as any) as any; @@ -1616,9 +1615,12 @@ export class ObjectSchemaBuilder< TConstructorSchemas > & TExtensions { - return this.createFromProps({ - ...this.introspect() - } as any) as any; + return this.derive( + { + ...this.introspect() + } as any, + true + ) as any; } /** @@ -1634,9 +1636,12 @@ export class ObjectSchemaBuilder< TConstructorSchemas > & TExtensions { - return this.createFromProps({ - ...this.introspect() - } as any) as any; + return this.derive( + { + ...this.introspect() + } as any, + true + ) as any; } /** @@ -1722,7 +1727,7 @@ export class ObjectSchemaBuilder< ); } - return this.createFromProps({ + return this.derive({ ...this.introspect(), constructorSchemas: [...this.#constructorSchemas, schema] } as any) as any; @@ -1768,7 +1773,7 @@ export class ObjectSchemaBuilder< [] > & TExtensions { - return this.createFromProps({ + return this.derive({ ...this.introspect(), constructorSchemas: [] } as any) as any; @@ -1810,7 +1815,7 @@ export class ObjectSchemaBuilder< ); } - return this.createFromProps({ + return this.derive({ ...this.introspect(), properties: { ...this.introspect().properties, @@ -1845,9 +1850,12 @@ export class ObjectSchemaBuilder< THasDefault, TExtensions > { - return this.createFromProps({ - ...this.introspect() - } as any) as any; + return this.derive( + { + ...this.introspect() + } as any, + true + ) as any; } /** @@ -1918,7 +1926,7 @@ export class ObjectSchemaBuilder< newProps[key] = props[key] as any; } - return this.createFromProps({ + return this.derive({ ...this.introspect(), properties: newProps } as any) as any; @@ -1997,7 +2005,7 @@ export class ObjectSchemaBuilder< ); } - return this.createFromProps({ + return this.derive({ ...this.introspect(), properties: (() => { const result = { ...this.#properties }; @@ -2037,7 +2045,7 @@ export class ObjectSchemaBuilder< delete props.properties[key]; } - return this.createFromProps(props as any); + return this.derive(props as any); } else if ( propNameOrArrayOrPropsOrBuilder instanceof ObjectSchemaBuilder ) { @@ -2055,7 +2063,7 @@ export class ObjectSchemaBuilder< } } - return this.createFromProps(props as any); + return this.derive(props as any); } throw new Error('this parameter type is not supported'); @@ -2109,7 +2117,7 @@ export class ObjectSchemaBuilder< {} as Record ); - return this.createFromProps({ + return this.derive({ ...this.introspect(), properties: newProps } as any) as any; @@ -2169,7 +2177,7 @@ export class ObjectSchemaBuilder< typeof propNameOrArray === 'undefined' || propNameOrArray === null ) { - return this.createFromProps({ + return this.derive({ ...this.introspect(), properties: Object.keys(this.#properties).reduce( (acc, key) => { @@ -2207,7 +2215,7 @@ export class ObjectSchemaBuilder< newProps.properties[key].optional(); }); - return this.createFromProps(newProps); + return this.derive(newProps); } if (typeof propNameOrArray === 'string') { @@ -2304,7 +2312,7 @@ export class ObjectSchemaBuilder< newProps[key] = prop.optional(); } } - return this.createFromProps({ + return this.derive({ ...this.introspect(), properties: newProps } as any) as any; @@ -2381,7 +2389,7 @@ export class ObjectSchemaBuilder< throw new Error(`property ${property} does not exists`); } - return this.createFromProps({ + return this.derive({ ...this.introspect(), properties: { [property]: this.#properties[property] @@ -2407,7 +2415,7 @@ export class ObjectSchemaBuilder< return acc; }, {}); - return this.createFromProps({ + return this.derive({ ...this.introspect(), properties: newProperties } as any); @@ -2483,7 +2491,7 @@ export class ObjectSchemaBuilder< [propName]: callbackResult }; - return this.createFromProps(props) as any; + return this.derive(props) as any; } /** @@ -2544,7 +2552,7 @@ export class ObjectSchemaBuilder< TConstructorSchemas > & TExtensions { - return this.createFromProps({ + return this.derive({ ...this.introspect(), properties: Object.keys(this.#properties).reduce( (acc, curr) => { @@ -2570,7 +2578,7 @@ export class ObjectSchemaBuilder< TConstructorSchemas > & TExtensions { - return this.createFromProps({ + return this.derive({ ...this.introspect(), properties: Object.keys(this.#properties).reduce( (acc, curr) => { @@ -2760,11 +2768,9 @@ export class ObjectSchemaBuilder< descriptor: any, message: string, parentDescriptor?: any - ) => void, - schemaOverride?: SchemaBuilder + ) => void ): void { const schema = - schemaOverride ?? ObjectSchemaBuilder.#getSchemaForPropertyDescriptor(descriptor); const properties = (schema.introspect() as any).properties; @@ -2816,8 +2822,7 @@ export class ObjectSchemaBuilder< ObjectSchemaBuilder.#propagateNestedErrors( result, nestedPropertyDescriptor, - addErrorFor, - nestedSchema + addErrorFor ); } } diff --git a/libs/schema/src/builders/ParseStringSchemaBuilder.ts b/libs/schema/src/builders/ParseStringSchemaBuilder.ts index 650a5171..cf33b0e7 100644 --- a/libs/schema/src/builders/ParseStringSchemaBuilder.ts +++ b/libs/schema/src/builders/ParseStringSchemaBuilder.ts @@ -550,9 +550,12 @@ export class ParseStringSchemaBuilder< _notUsed?: T ): ParseStringSchemaBuilder & TExtensions { - return this.createFromProps({ - ...this.introspect() - } as any) as any; + return this.derive( + { + ...this.introspect() + } as any, + true + ) as any; } /** @@ -566,9 +569,12 @@ export class ParseStringSchemaBuilder< TExtensions > & TExtensions { - return this.createFromProps({ - ...this.introspect() - } as any) as any; + return this.derive( + { + ...this.introspect() + } as any, + true + ) as any; } /** diff --git a/libs/schema/src/builders/PromiseSchemaBuilder.ts b/libs/schema/src/builders/PromiseSchemaBuilder.ts index 6de3edef..b1c2f594 100644 --- a/libs/schema/src/builders/PromiseSchemaBuilder.ts +++ b/libs/schema/src/builders/PromiseSchemaBuilder.ts @@ -107,9 +107,12 @@ export class PromiseSchemaBuilder< TResolvedTypeSchema > & TExtensions { - return this.createFromProps({ - ...this.introspect() - } as any) as any; + return this.derive( + { + ...this.introspect() + } as any, + true + ) as any; } /** @@ -124,9 +127,12 @@ export class PromiseSchemaBuilder< TResolvedTypeSchema > & TExtensions { - return this.createFromProps({ - ...this.introspect() - } as any) as any; + return this.derive( + { + ...this.introspect() + } as any, + true + ) as any; } /** @@ -410,7 +416,7 @@ export class PromiseSchemaBuilder< TSchema > & TExtensions { - return this.createFromProps({ + return this.derive({ ...this.introspect(), resolvedType: schema } as any) as any; diff --git a/libs/schema/src/builders/RecordSchemaBuilder.ts b/libs/schema/src/builders/RecordSchemaBuilder.ts index f9e2ab63..18c6ac3b 100644 --- a/libs/schema/src/builders/RecordSchemaBuilder.ts +++ b/libs/schema/src/builders/RecordSchemaBuilder.ts @@ -288,9 +288,12 @@ export class RecordSchemaBuilder< TExtensions > & TExtensions { - return this.createFromProps({ - ...this.introspect() - } as any) as any; + return this.derive( + { + ...this.introspect() + } as any, + true + ) as any; } /** @@ -306,9 +309,12 @@ export class RecordSchemaBuilder< TExtensions > & TExtensions { - return this.createFromProps({ - ...this.introspect() - } as any) as any; + return this.derive( + { + ...this.introspect() + } as any, + true + ) as any; } /** diff --git a/libs/schema/src/builders/ReferenceSchemaBuilder.test.ts b/libs/schema/src/builders/ReferenceSchemaBuilder.test.ts deleted file mode 100644 index 01ea34f4..00000000 --- a/libs/schema/src/builders/ReferenceSchemaBuilder.test.ts +++ /dev/null @@ -1,149 +0,0 @@ -import { describe, expect, it, vi } from 'vitest'; -import { array, boolean, number, object, schemaRef, string } from '../index.js'; - -describe('optional fallbacks', () => { - it('accepts optional/nullable fallbacks and preserves legacy null acceptance', async () => { - const text = string().optional().catch(undefined); - expect(text.parse(42)).toBeUndefined(); - expect(await text.parseAsync(false)).toBeUndefined(); - expect(text.parse(null)).toBeNull(); - expect(string().nullable().catch(null).parse(42)).toBeNull(); - const normalize = string() - .optional() - .addPreprocessor(v => (v == null ? undefined : v)) - .catch(undefined); - expect(normalize.parse(null)).toBeUndefined(); - expect(object({ text }).safeParse(null).valid).toBe(false); - expect( - object({ - text, - flag: boolean() - .optional() - .catch(() => undefined) - }).parse({ text: {}, flag: 1 }) - ).toEqual({ text: undefined, flag: undefined }); - }); - - it('supports async optional preprocessing without dropping array entries', async () => { - const fallback = vi.fn(() => undefined); - const text = string().optional().catch(fallback); - expect(array(text).parse(['ok', 42])).toEqual(['ok', undefined]); - expect(fallback).toHaveBeenCalledTimes(1); - const normalized = string() - .optional() - .addPreprocessor(async v => (v == null ? undefined : v)); - expect(await normalized.parseAsync(null)).toBeUndefined(); - expect(() => normalized.parse(null)).toThrow(/validateAsync/); - }); -}); - -describe('named schema references', () => { - it('preserves one target definition and independent local metadata', () => { - const user = object({ name: string().minLength(1) }).schemaName('User'); - const ref = schemaRef(user); - const previous = ref - .nullable() - .optional() - .describe('Previous user') - .example(null); - expect(ref.introspect().targetSchema).toBe(user); - expect(previous.introspect().targetSchema).toBe(user); - expect(user.introspect().description).toBeUndefined(); - expect(user.introspect().isRequired).toBe(true); - expect(ref.safeParse(null).valid).toBe(false); - expect(previous.parse(null)).toBeNull(); - expect(previous.parse(undefined)).toBeUndefined(); - expect(previous.parse({ name: 'Ada' })).toEqual({ name: 'Ada' }); - expect(() => schemaRef(string())).toThrow(/named schema/); - expect(() => schemaRef(string().schemaName(' '))).toThrow( - /named schema/ - ); - }); - - it('preserves deeply nested reference errors and selectors', async () => { - const address = object({ city: string().minLength(1) }).schemaName( - 'Address' - ); - const user = object({ address: schemaRef(address) }).schemaName('User'); - const root = object({ user: schemaRef(user) }); - for (const result of [ - root.validate({ user: { address: { city: '' } } }), - await root.validateAsync({ user: { address: { city: '' } } }) - ]) { - expect(result.valid).toBe(false); - expect( - result.getErrorsFor(t => t.user.address.city).errors.length - ).toBeGreaterThan(0); - expect( - result - .getInvalidProperties() - .map(p => p.descriptor.toJsonPointer()) - ).toContain('/user/address/city'); - } - }); - - it('keeps target defaults, local defaults and fallbacks independent', async () => { - const target = number().default(2).schemaName('Size'); - const ref = schemaRef(target); - expect(ref.parse(undefined)).toBe(2); - expect(ref.optional().parse(undefined)).toBeUndefined(); - expect(ref.optional().default(4).parse(undefined)).toBe(4); - expect(ref.default(4).clearDefault().parse(undefined)).toBe(2); - expect(target.parse(undefined)).toBe(2); - const fallback = vi.fn(() => 8); - const caught = ref.catch(fallback); - expect(caught.parse('invalid')).toBe(8); - expect(await caught.parseAsync('invalid')).toBe(8); - expect(fallback).toHaveBeenCalledTimes(2); - expect(ref.optional().catch(undefined).parse({})).toBeUndefined(); - }); - - it('keeps local optionality, nullability and required error messages distinct', async () => { - const ref = schemaRef( - string().nullable().optional().schemaName('Text') - ); - expect(ref.parse(null)).toBeNull(); - expect(ref.notNullable().safeParse(null).valid).toBe(false); - expect(ref.notNullable().parse(undefined)).toBeUndefined(); - const required = ref.required('Provide text'); - expect(required.safeParse(undefined).errors?.[0].message).toBe( - 'Provide text' - ); - expect(required.parse(null)).toBeNull(); - const asyncRequired = ref.required(async () => 'Async required'); - expect(() => asyncRequired.parse(undefined)).toThrow(/Async|async/); - expect( - (await asyncRequired.safeParseAsync(undefined)).errors?.[0].message - ).toBe('Async required'); - }); - - it('delegates async target validation and runs local callbacks', async () => { - const target = string() - .addPreprocessor(async v => v.trim()) - .schemaName('Trimmed'); - const ref = schemaRef(target); - expect(() => ref.parse(' text ')).toThrow(/validateAsync/); - expect(await ref.parseAsync(' text ')).toBe('text'); - expect(await ref['~standard'].validate(' text ')).toEqual({ - value: 'text' - }); - const local = schemaRef(number().schemaName('Count')) - .addPreprocessor(v => v + 1) - .addValidator(v => ({ valid: v < 5 })); - expect(local.parse(2)).toBe(3); - expect(local.safeParse(5).valid).toBe(false); - expect( - schemaRef(string().schemaName('OptionalText')) - .optional() - .addPreprocessor(() => undefined) - .parse('text') - ).toBeUndefined(); - }); - - it('retains existing hasType behavior without changing runtime validation', () => { - const ref = schemaRef(number().schemaName('Count')).hasType(); - expect(ref.parse(3)).toBe(3); - expect(ref.safeParse('three').valid).toBe(false); - expect(ref.clearHasType().parse(4)).toBe(4); - }); -}); diff --git a/libs/schema/src/builders/ReferenceSchemaBuilder.ts b/libs/schema/src/builders/ReferenceSchemaBuilder.ts deleted file mode 100644 index fa11afc2..00000000 --- a/libs/schema/src/builders/ReferenceSchemaBuilder.ts +++ /dev/null @@ -1,387 +0,0 @@ -import { - type BRAND, - type InferType, - SchemaBuilder, - type SchemaBuilderProps, - SYMBOL_HAS_PROPERTIES, - type ValidationContext, - type ValidationErrorMessageProvider, - type ValidationResult -} from './SchemaBuilder.js'; - -type AnySchema = SchemaBuilder; -type ReferenceValue< - TSchema, - TRequired extends boolean, - TNullable extends boolean, - TExplicitType -> = - | (TRequired extends true - ? Exclude< - TExplicitType extends undefined - ? InferType - : TExplicitType, - undefined - > - : - | (TExplicitType extends undefined - ? InferType - : TExplicitType) - | undefined) - | (TNullable extends true ? null : never); -type ReferenceProps = Partial> & { - targetSchema: AnySchema; - presence?: boolean; - nullability?: boolean; -}; - -/** - * Immutable use-site wrapper around one named schema. Create it with schemaRef. - * Local modifiers never clone or mutate the target definition. - * @typeParam TSchema - Referenced schema. - * @typeParam TRequired - Whether a value is required at this use site. - * @typeParam TNullable - Whether null is allowed at this use site. - * @typeParam THasDefault - Whether the wrapper supplies a default. - * @typeParam TExplicitType - Optional static type override. - */ -export class ReferenceSchemaBuilder< - TSchema extends AnySchema, - TRequired extends boolean = true, - TNullable extends boolean = false, - THasDefault extends boolean = false, - TExplicitType = undefined -> extends SchemaBuilder< - ReferenceValue, - TRequired, - TNullable, - THasDefault -> { - readonly #reference: ReferenceProps; - /** @internal Enables nested property descriptors for referenced objects. */ - readonly [SYMBOL_HAS_PROPERTIES] = true; - - /** @internal Use schemaRef rather than constructing a reference directly. */ - constructor(props: ReferenceProps) { - super({ - preprocessors: [], - validators: [], - ...props, - type: 'reference' - }); - this.#reference = props; - } - - /** Describes the target and local modifiers without changing the target. */ - public introspect() { - return { - ...super.introspect(), - targetSchema: this.#reference.targetSchema as TSchema, - presence: this.#reference.presence, - nullability: this.#reference.nullability, - properties: (this.#reference.targetSchema.introspect() as any) - .properties - }; - } - - /** @internal Reconstructs an immutable wrapper around the same target. */ - protected createFromProps(props: ReferenceProps): this { - return new ReferenceSchemaBuilder(props) as this; - } - - /** Validates through the target and retains the inferred result type. */ - public validate( - value: unknown, - context?: ValidationContext - ): ValidationResult< - ReferenceValue - > { - return super.validate(value, context); - } - - /** Async validation with the same inference and fallback behavior. */ - public validateAsync( - value: unknown, - context?: ValidationContext - ): Promise< - ValidationResult< - ReferenceValue - > - > { - return super.validateAsync(value, context); - } - - #props(): ReferenceProps { - return { - ...this.#reference, - ...this.introspect(), - preprocessors: [...this.preprocessors], - validators: [...this.validators] - }; - } - - #early(value: unknown): ValidationResult | undefined { - if (value === undefined && this.hasDefault) return undefined; - if (value === undefined && this.#reference.presence !== undefined) { - return this.#reference.presence - ? { valid: false, errors: [{ message: 'is required' }] } - : { valid: true, object: undefined }; - } - if (value === null && this.#reference.nullability !== undefined) { - return this.#reference.nullability - ? { valid: true, object: null } - : { valid: false, errors: [{ message: 'must not be null' }] }; - } - return undefined; - } - - #checkNull(result: ValidationResult): ValidationResult { - if ( - result.valid && - result.object === null && - this.#reference.nullability === false - ) - return { valid: false, errors: [{ message: 'must not be null' }] }; - return result; - } - - /** @internal Delegates validation while applying local presence and validators. */ - protected _validate( - value: unknown, - context?: ValidationContext - ): ValidationResult { - const early = this.#early(value); - if (early) { - if (!early.valid && value === undefined) - early.errors = [ - { - message: this.getValidationErrorMessageSync( - this.requiredErrorMessage, - value as any - ) - } - ]; - return early; - } - const result = this.#checkNull( - this.#reference.targetSchema.validate( - value === undefined && this.hasDefault - ? this.resolveDefaultValue() - : value, - context - ) - ); - if (!result.valid) return result; - const prepared = this.preValidateSync(result.object, context); - if (!prepared.valid) return { valid: false, errors: prepared.errors }; - if (this.preprocessors.length === 0) return result; - const preparedValue = prepared.transaction!.object.validatedObject; - return this.#checkNull( - this.#early(preparedValue) ?? - this.#reference.targetSchema.validate(preparedValue, context) - ); - } - - /** @internal Async counterpart, including target validators and local callbacks. */ - protected async _validateAsync( - value: unknown, - context?: ValidationContext - ): Promise> { - const early = this.#early(value); - if (early) { - if (!early.valid && value === undefined) - early.errors = [ - { - message: await this.getValidationErrorMessage( - this.requiredErrorMessage, - value as any - ) - } - ]; - return early; - } - const result = this.#checkNull( - await this.#reference.targetSchema.validateAsync( - value === undefined && this.hasDefault - ? this.resolveDefaultValue() - : value, - context - ) - ); - if (!result.valid) return result; - const prepared = await this.preValidateAsync(result.object, context); - if (!prepared.valid) return { valid: false, errors: prepared.errors }; - if (this.preprocessors.length === 0) return result; - const preparedValue = prepared.transaction!.object.validatedObject; - return this.#checkNull( - this.#early(preparedValue) ?? - (await this.#reference.targetSchema.validateAsync( - preparedValue, - context - )) - ); - } - - /** Overrides the static type only; target validation remains unchanged. */ - public hasType( - _notUsed?: T - ): ReferenceSchemaBuilder { - return this.createFromProps(this.#props()) as any; - } - - /** Restores inference from the referenced schema. */ - public clearHasType(): ReferenceSchemaBuilder< - TSchema, - TRequired, - TNullable, - THasDefault - > { - return this.createFromProps(this.#props()) as any; - } - - /** Rejects omitted values at this use site, unless a local default exists. */ - public required( - errorMessage?: ValidationErrorMessageProvider - ): ReferenceSchemaBuilder< - TSchema, - true, - TNullable, - THasDefault, - TExplicitType - > { - return this.createFromProps({ - ...this.#props(), - isRequired: true, - presence: true, - requiredValidationErrorMessageProvider: errorMessage - }) as any; - } - - /** Allows omission without invoking the target, unless a local default exists. */ - public optional(): ReferenceSchemaBuilder< - TSchema, - false, - TNullable, - THasDefault, - TExplicitType - > { - return this.createFromProps({ - ...this.#props(), - isRequired: false, - presence: false - }) as any; - } - - /** Allows null independently of omission at this use site. */ - public nullable(): ReferenceSchemaBuilder< - TSchema, - TRequired, - true, - THasDefault, - TExplicitType - > { - return this.createFromProps({ - ...this.#props(), - isNullable: true, - nullability: true - }) as any; - } - - /** Rejects null without modifying the target definition. */ - public notNullable(): ReferenceSchemaBuilder< - TSchema, - TRequired, - false, - THasDefault, - Exclude< - TExplicitType extends undefined - ? InferType - : TExplicitType, - null - > - > { - return this.createFromProps({ - ...this.#props(), - isNullable: false, - nullability: false - }) as any; - } - - /** Supplies a local default for omission, validated by the target. */ - public default( - value: InferType | (() => InferType) - ): ReferenceSchemaBuilder { - return this.createFromProps({ - ...this.#props(), - defaultValue: value, - isRequired: true - }) as any; - } - - /** Removes the local default; target defaults are unchanged. */ - public clearDefault(): ReferenceSchemaBuilder< - TSchema, - TRequired, - TNullable, - false, - TExplicitType - > { - return this.createFromProps({ - ...this.#props(), - defaultValue: undefined - }) as any; - } - - /** Brands the inferred type without changing runtime validation. */ - public brand( - _name?: B - ): ReferenceSchemaBuilder< - TSchema, - TRequired, - TNullable, - THasDefault, - (TExplicitType extends undefined - ? InferType - : TExplicitType) & { readonly [K in BRAND]: B } - > { - return super.brand(_name); - } - - /** Makes the inferred type readonly without freezing runtime values. */ - public readonly(): ReferenceSchemaBuilder< - TSchema, - TRequired, - TNullable, - THasDefault, - Readonly< - TExplicitType extends undefined ? InferType : TExplicitType - > - > { - return super.readonly(); - } -} - -/** - * References one named definition with independent use-site annotations. - * @param schema - A reused schema constant with a nonempty schemaName. - * @returns An immutable reference wrapper; the target is neither cloned nor mutated. - * @throws Error if the target has no name. - * @example - * const User = object({ name: string() }).schemaName('User'); - * const previous = schemaRef(User).nullable().optional().describe('Previous user'); - */ -export function schemaRef( - schema: TSchema -): ReferenceSchemaBuilder< - TSchema, - undefined extends InferType ? false : true, - null extends InferType ? true : false -> { - const info = schema.introspect(); - if (!info.schemaName?.trim()) - throw new Error('schemaRef requires a named schema.'); - return new ReferenceSchemaBuilder({ - targetSchema: schema, - isRequired: info.isRequired, - isNullable: info.isNullable - }); -} diff --git a/libs/schema/src/builders/SchemaBuilder.ts b/libs/schema/src/builders/SchemaBuilder.ts index 5fdc8671..c5344a38 100644 --- a/libs/schema/src/builders/SchemaBuilder.ts +++ b/libs/schema/src/builders/SchemaBuilder.ts @@ -5,6 +5,7 @@ import { transaction } from '../utils/transaction.js'; import type { ArraySchemaBuilder } from './ArraySchemaBuilder.js'; +import type { ExternSchemaBuilder } from './ExternSchemaBuilder.js'; import type { ObjectSchemaBuilder } from './ObjectSchemaBuilder.js'; /** @internal Symbol used as the key for the type brand on schema builders. */ @@ -244,6 +245,8 @@ export type SchemaBuilderProps = { hasCatch?: boolean; description?: string; schemaName?: string; + /** @internal Canonical named definition for a use-site-only derivative. */ + referenceTarget?: SchemaBuilder; example?: unknown; }; @@ -537,85 +540,77 @@ export type PropertyDescriptorTree< TParentPropertyDescriptor = undefined > = PropertyDescriptor & (TSchema extends ObjectSchemaBuilder - ? 0 extends 1 & TProperties - ? { [key: string]: any } - : { - [K in keyof TProperties]: TProperties[K] extends ObjectSchemaBuilder< - any, - any, - any - > - ? PropertyDescriptorTree< - TProperties[K], + ? { + [K in keyof TProperties]: TProperties[K] extends ObjectSchemaBuilder< + any, + any, + any + > + ? PropertyDescriptorTree< + TProperties[K], + TRootSchema, + any, + PropertyDescriptor< TRootSchema, - any, - PropertyDescriptor< - TRootSchema, - TSchema, - TParentPropertyDescriptor - > + TSchema, + TParentPropertyDescriptor > - : TProperties[K] extends { - readonly [SYMBOL_HAS_PROPERTIES]: true; - } - ? PropertyDescriptor< + > + : TProperties[K] extends ExternSchemaBuilder< + any, + any, + any, + any, + any, + any, + infer TExternResult + > + ? PropertyDescriptor< + TRootSchema, + TProperties[K], + PropertyDescriptor< + TRootSchema, + TSchema, + TParentPropertyDescriptor + >, + K & string + > & + ExternOutputPropertyDescriptors< + TExternResult, TRootSchema, - TProperties[K], PropertyDescriptor< TRootSchema, - TSchema, - TParentPropertyDescriptor - >, - K & string - > & - ExternOutputPropertyDescriptors< - NonNullable>, - TRootSchema, + TProperties[K], PropertyDescriptor< TRootSchema, - TProperties[K], - PropertyDescriptor< - TRootSchema, - TSchema, - TParentPropertyDescriptor - >, - K & string - > + TSchema, + TParentPropertyDescriptor + >, + K & string > - : TProperties[K] extends ArraySchemaBuilder< - infer TArrayElement, - any, - any - > - ? TArrayElement extends ObjectSchemaBuilder< - any, - any, - any, - any, - any - > - ? PropertyDescriptor< + > + : TProperties[K] extends ArraySchemaBuilder< + infer TArrayElement, + any, + any + > + ? TArrayElement extends ObjectSchemaBuilder< + any, + any, + any, + any, + any + > + ? PropertyDescriptor< + TRootSchema, + TProperties[K], + PropertyDescriptor< TRootSchema, - TProperties[K], - PropertyDescriptor< - TRootSchema, - TSchema, - TParentPropertyDescriptor - >, - K & string - > - : InferType extends TAssignableTo - ? PropertyDescriptor< - TRootSchema, - TProperties[K], - PropertyDescriptor< - TRootSchema, - TSchema, - TParentPropertyDescriptor - >, - K & string - > - : never + TSchema, + TParentPropertyDescriptor + >, + K & string + > : InferType extends TAssignableTo ? PropertyDescriptor< TRootSchema, @@ -627,8 +622,20 @@ export type PropertyDescriptorTree< >, K & string > - : never; - } + : never + : InferType extends TAssignableTo + ? PropertyDescriptor< + TRootSchema, + TProperties[K], + PropertyDescriptor< + TRootSchema, + TSchema, + TParentPropertyDescriptor + >, + K & string + > + : never; + } : never); /** @@ -751,6 +758,7 @@ export abstract class SchemaBuilder< #isReadonly = false; #description: string | undefined; #schemaName: string | undefined; + #referenceTarget: SchemaBuilder | undefined; #preprocessors: PreprocessorEntry[] = []; #validators: ValidatorEntry[] = []; #hasMutating = false; @@ -905,6 +913,27 @@ export abstract class SchemaBuilder< */ protected abstract createFromProps(props: any): this; + /** + * Constructs an immutable derivative through the existing subclass hook. + * Shape, rule and extension changes detach from inherited component names + * by default. Only presence, nullability, annotations and type-only changes + * may preserve the canonical definition. Preserve chains collapse to their + * original target; an unnamed derivative never reconnects automatically. + * @param props - Complete introspection properties for the new builder. + * @param preserveReference - Whether only use-site metadata changed. + * @internal + */ + protected derive(props: any, preserveReference = false): this { + return this.createFromProps({ + ...props, + schemaName: preserveReference ? this.#schemaName : undefined, + referenceTarget: + preserveReference && this.#schemaName + ? (this.#referenceTarget ?? this) + : undefined + }); + } + /** * The string identifier of the schema type (e.g. `'string'`, `'number'`, `'object'`). */ @@ -1455,6 +1484,14 @@ export abstract class SchemaBuilder< * or `undefined` if none was set. */ schemaName: this.#schemaName, + /** + * Canonical named definition retained by use-site modifiers. + * Exporters must compose local annotations/nullability around this + * target before resolving the derivative's inherited name. + * Structural and validation-rule derivatives have no target. + * @internal + */ + referenceTarget: this.#referenceTarget, /** * Whether a catch/fallback value has been set on this schema via `.catch()`. */ @@ -1476,10 +1513,13 @@ export abstract class SchemaBuilder< * Makes schema optional (consider `null` and `undefined` as valid objects for this schema) */ public optional() { - return this.createFromProps({ - ...this.introspect(), - isRequired: false - }) as any; + return this.derive( + { + ...this.introspect(), + isRequired: false + }, + true + ) as any; } /** @@ -1490,10 +1530,13 @@ export abstract class SchemaBuilder< * `.optional()` to accept both `null` and `undefined`. */ public nullable() { - return this.createFromProps({ - ...this.introspect(), - isNullable: true - }) as any; + return this.derive( + { + ...this.introspect(), + isNullable: true + }, + true + ) as any; } /** @@ -1501,10 +1544,13 @@ export abstract class SchemaBuilder< * value. This is the counterpart of `.nullable()`. */ public notNullable() { - return this.createFromProps({ - ...this.introspect(), - isNullable: false - }) as any; + return this.derive( + { + ...this.introspect(), + isNullable: false + }, + true + ) as any; } /** @@ -1529,7 +1575,7 @@ export abstract class SchemaBuilder< * ``` */ public default(value: TResult | (() => TResult)) { - return this.createFromProps({ + return this.derive({ ...this.introspect(), defaultValue: value }) as any; @@ -1587,7 +1633,7 @@ export abstract class SchemaBuilder< | ResolvedSchemaType | (() => ResolvedSchemaType) ): this { - return this.createFromProps({ + return this.derive({ ...this.introspect(), catchValue: value, hasCatch: true @@ -1598,7 +1644,7 @@ export abstract class SchemaBuilder< * Removes the default value set by a previous call to `.default()`. */ public clearDefault() { - return this.createFromProps({ + return this.derive({ ...this.introspect(), defaultValue: undefined }) as any; @@ -1624,10 +1670,13 @@ export abstract class SchemaBuilder< * ``` */ public describe(text: string): this { - return this.createFromProps({ - ...this.introspect(), - description: text - }) as unknown as this; + return this.derive( + { + ...this.introspect(), + description: text + }, + true + ) as unknown as this; } /** @@ -1647,10 +1696,13 @@ export abstract class SchemaBuilder< * ``` */ public example(value: TResult): this { - return this.createFromProps({ - ...this.introspect(), - example: value - }) as unknown as this; + return this.derive( + { + ...this.introspect(), + example: value + }, + true + ) as unknown as this; } /** @@ -1666,6 +1718,15 @@ export abstract class SchemaBuilder< * safe; how conflicts between different instances with the same name are * handled depends on the tool. * + * Ordinary presence, nullability, annotation and type-only modifiers retain + * this canonical definition for document exporters. Shape, validation-rule, + * default, fallback and extension changes discard the inherited name. Apply + * `schemaName` after those edits to give the derivative its own component. + * Calling this method always establishes a fresh definition, even on an alias. + * + * @param name - Component name for this independent schema definition. + * @returns A new named builder without an inherited canonical target. + * * @example * ```ts * import { object, string, number } from '@cleverbrush/schema'; @@ -1681,7 +1742,8 @@ export abstract class SchemaBuilder< public schemaName(name: string): this { return this.createFromProps({ ...this.introspect(), - schemaName: name + schemaName: name, + referenceTarget: undefined }) as unknown as this; } @@ -1702,9 +1764,12 @@ export abstract class SchemaBuilder< * ``` */ public brand(_name?: TBrand) { - return this.createFromProps({ - ...this.introspect() - }) as any; + return this.derive( + { + ...this.introspect() + }, + true + ) as any; } /** @@ -1725,10 +1790,13 @@ export abstract class SchemaBuilder< * ``` */ public readonly() { - return this.createFromProps({ - ...this.introspect(), - isReadonly: true - }) as any; + return this.derive( + { + ...this.introspect(), + isReadonly: true + }, + true + ) as any; } /** @@ -1736,19 +1804,22 @@ export abstract class SchemaBuilder< * @param errorMessage - optional custom error message or provider for the 'is required' validation error */ public required(errorMessage?: ValidationErrorMessageProvider) { - return this.createFromProps({ - ...this.introspect(), - isRequired: true, - ...(errorMessage !== undefined - ? { - requiredValidationErrorMessageProvider: - this.assureValidationErrorMessageProvider( - errorMessage, - this.#defaultRequiredErrorMessageProvider - ) - } - : {}) - }) as any; + return this.derive( + { + ...this.introspect(), + isRequired: true, + ...(errorMessage !== undefined + ? { + requiredValidationErrorMessageProvider: + this.assureValidationErrorMessageProvider( + errorMessage, + this.#defaultRequiredErrorMessageProvider + ) + } + : {}) + }, + true + ) as any; } /** @@ -1771,7 +1842,7 @@ export abstract class SchemaBuilder< if (typeof preprocessor !== 'function') { throw new Error('preprocessor must be a function'); } - return this.createFromProps({ + return this.derive({ ...this.introspect(), preprocessors: [ ...this.preprocessors, @@ -1784,7 +1855,7 @@ export abstract class SchemaBuilder< * Remove all preprocessors for this schema. */ public clearPreprocessors(): this { - return this.createFromProps({ + return this.derive({ ...this.introspect(), preprocessors: [] }); @@ -1800,7 +1871,7 @@ export abstract class SchemaBuilder< if (typeof validator !== 'function') { throw new Error('validator must be a function'); } - return this.createFromProps({ + return this.derive({ ...this.introspect(), validators: [ ...this.validators, @@ -1813,7 +1884,7 @@ export abstract class SchemaBuilder< * Remove all validators for this schema. */ public clearValidators(): this { - return this.createFromProps({ + return this.derive({ ...this.introspect(), validators: [] }); @@ -2009,7 +2080,7 @@ export abstract class SchemaBuilder< * @internal Used by extension authors inside `defineExtension()` callbacks. */ public withExtension(key: string, value: unknown): this { - return this.createFromProps({ + return this.derive({ ...this.introspect(), extensions: { ...this.#extensions, @@ -2133,6 +2204,7 @@ export abstract class SchemaBuilder< if (typeof props.schemaName === 'string') { this.#schemaName = props.schemaName; } + this.#referenceTarget = props.referenceTarget; if (props.example !== undefined) { this.#example = props.example; diff --git a/libs/schema/src/builders/StringSchemaBuilder.ts b/libs/schema/src/builders/StringSchemaBuilder.ts index 0f2c3814..5323b96c 100644 --- a/libs/schema/src/builders/StringSchemaBuilder.ts +++ b/libs/schema/src/builders/StringSchemaBuilder.ts @@ -314,9 +314,12 @@ export class StringSchemaBuilder< _notUsed?: T ): StringSchemaBuilder & TExtensions { - return this.createFromProps({ - ...this.introspect() - } as any) as any; + return this.derive( + { + ...this.introspect() + } as any, + true + ) as any; } /** @@ -330,9 +333,12 @@ export class StringSchemaBuilder< TExtensions > & TExtensions { - return this.createFromProps({ - ...this.introspect() - } as any) as any; + return this.derive( + { + ...this.introspect() + } as any, + true + ) as any; } #getConstraintViolation( @@ -584,7 +590,7 @@ export class StringSchemaBuilder< > ) { if (typeof value !== 'string') throw new Error('string expected'); - return this.createFromProps({ + return this.derive({ ...this.introspect(), equalsTo: value, equalsToValidationErrorMessageProvider: errorMessage @@ -609,7 +615,7 @@ export class StringSchemaBuilder< TExtensions > & TExtensions { - return this.createFromProps({ + return this.derive({ ...this.introspect(), equalsTo: undefined }) as any; @@ -747,7 +753,7 @@ export class StringSchemaBuilder< TExtensions { if (typeof length !== 'number') throw new Error('length must be a number'); - return this.createFromProps({ + return this.derive({ ...this.introspect(), minLength: length, minLengthValidationErrorMessageProvider: errorMessage @@ -767,7 +773,7 @@ export class StringSchemaBuilder< TExtensions { const schema = this.introspect(); delete schema.minLength; - return this.createFromProps({ + return this.derive({ ...schema }) as any; } @@ -794,7 +800,7 @@ export class StringSchemaBuilder< TExtensions { if (typeof length !== 'number') throw new Error('length must be a number'); - return this.createFromProps({ + return this.derive({ ...this.introspect(), maxLength: length, maxLengthValidationErrorMessageProvider: errorMessage @@ -814,7 +820,7 @@ export class StringSchemaBuilder< TExtensions { const schema = this.introspect(); delete schema.maxLength; - return this.createFromProps({ + return this.derive({ ...schema }) as any; } @@ -840,7 +846,7 @@ export class StringSchemaBuilder< TExtensions { if (typeof val !== 'string' || !val) throw new Error('non empty string expected'); - return this.createFromProps({ + return this.derive({ ...this.introspect(), startsWith: val, startsWithValidationErrorMessageProvider: errorMessage @@ -860,7 +866,7 @@ export class StringSchemaBuilder< TExtensions { const schema = this.introspect(); delete schema.startsWith; - return this.createFromProps({ + return this.derive({ ...schema }) as any; } @@ -886,7 +892,7 @@ export class StringSchemaBuilder< TExtensions { if (typeof val !== 'string' || !val) throw new Error('non empty string expected'); - return this.createFromProps({ + return this.derive({ ...this.introspect(), endsWith: val, endsWithValidationErrorMessageProvider: errorMessage @@ -906,7 +912,7 @@ export class StringSchemaBuilder< TExtensions { const schema = this.introspect(); delete schema.endsWith; - return this.createFromProps({ + return this.derive({ ...schema }) as any; } @@ -932,7 +938,7 @@ export class StringSchemaBuilder< > & TExtensions { if (!(regexp instanceof RegExp)) throw new Error('regexp expected'); - return this.createFromProps({ + return this.derive({ ...this.introspect(), matches: regexp, matchesValidationErrorMessageProvider: errorMessage @@ -952,7 +958,7 @@ export class StringSchemaBuilder< TExtensions { const schema = this.introspect(); delete schema.matches; - return this.createFromProps({ + return this.derive({ ...schema }) as any; } diff --git a/libs/schema/src/builders/TupleSchemaBuilder.ts b/libs/schema/src/builders/TupleSchemaBuilder.ts index 8a5a6d76..9f95b748 100644 --- a/libs/schema/src/builders/TupleSchemaBuilder.ts +++ b/libs/schema/src/builders/TupleSchemaBuilder.ts @@ -215,9 +215,12 @@ export class TupleSchemaBuilder< TRestSchema > & TExtensions { - return this.createFromProps({ - ...this.introspect() - } as any) as any; + return this.derive( + { + ...this.introspect() + } as any, + true + ) as any; } /** @@ -233,9 +236,12 @@ export class TupleSchemaBuilder< TRestSchema > & TExtensions { - return this.createFromProps({ - ...this.introspect() - } as any) as any; + return this.derive( + { + ...this.introspect() + } as any, + true + ) as any; } #getLengthError(arr: any[]): string | null { @@ -914,7 +920,7 @@ export class TupleSchemaBuilder< TSchema > & TExtensions { - return TupleSchemaBuilder.create({ + return this.derive({ ...this.introspect(), restSchema: schema } as any) as any; @@ -934,7 +940,7 @@ export class TupleSchemaBuilder< undefined > & TExtensions { - return TupleSchemaBuilder.create({ + return this.derive({ ...this.introspect(), restSchema: undefined } as any) as any; diff --git a/libs/schema/src/builders/UnionSchemaBuilder.ts b/libs/schema/src/builders/UnionSchemaBuilder.ts index 0560e4c4..2aaf8e4b 100644 --- a/libs/schema/src/builders/UnionSchemaBuilder.ts +++ b/libs/schema/src/builders/UnionSchemaBuilder.ts @@ -324,9 +324,12 @@ export class UnionSchemaBuilder< TExtensions > & TExtensions { - return this.createFromProps({ - ...this.introspect() - } as any) as any; + return this.derive( + { + ...this.introspect() + } as any, + true + ) as any; } /** @@ -341,9 +344,12 @@ export class UnionSchemaBuilder< TExtensions > & TExtensions { - return this.createFromProps({ - ...this.introspect() - } as any) as any; + return this.derive( + { + ...this.introspect() + } as any, + true + ) as any; } #createValidationSetup( @@ -995,7 +1001,7 @@ export class UnionSchemaBuilder< 'schema must be an instance of the SchemaBuilder class' ); } - return this.createFromProps({ + return this.derive({ ...this.introspect(), options: [...this.#options, schema] } as any) as any; @@ -1024,7 +1030,7 @@ export class UnionSchemaBuilder< ) { throw new Error('index must be >= 0 and <= count of the options'); } - return this.createFromProps({ + return this.derive({ ...this.introspect(), options: this.#options.filter((_v, i) => i !== index) } as any) as any; @@ -1071,7 +1077,7 @@ export class UnionSchemaBuilder< 'schema must be an instance of the SchemaBuilder class' ); } - return this.createFromProps({ + return this.derive({ ...this.introspect(), options: [schema] } as any) as any; diff --git a/libs/schema/src/builders/namedSchemas.test.ts b/libs/schema/src/builders/namedSchemas.test.ts new file mode 100644 index 00000000..1f2afa8e --- /dev/null +++ b/libs/schema/src/builders/namedSchemas.test.ts @@ -0,0 +1,325 @@ +import { describe, expect, it, vi } from 'vitest'; +import * as core from '../core.js'; +import { array, boolean, number, object, string, tuple } from '../index.js'; + +describe('optional fallbacks', () => { + it('accepts optional/nullable fallbacks and preserves legacy null acceptance', async () => { + const text = string().optional().catch(undefined); + expect(text.parse(42)).toBeUndefined(); + expect(await text.parseAsync(false)).toBeUndefined(); + expect(text.parse(null)).toBeNull(); + expect(string().nullable().catch(null).parse(42)).toBeNull(); + const normalize = string() + .optional() + .addPreprocessor(v => (v == null ? undefined : v)) + .catch(undefined); + expect(normalize.parse(null)).toBeUndefined(); + expect(object({ text }).safeParse(null).valid).toBe(false); + expect( + object({ + text, + flag: boolean() + .optional() + .catch(() => undefined) + }).parse({ text: {}, flag: 1 }) + ).toEqual({ text: undefined, flag: undefined }); + }); + + it('supports async optional preprocessing without dropping array entries', async () => { + const fallback = vi.fn(() => undefined); + const text = string().optional().catch(fallback); + expect(array(text).parse(['ok', 42])).toEqual(['ok', undefined]); + expect(fallback).toHaveBeenCalledTimes(1); + const normalized = string() + .optional() + .addPreprocessor(async v => (v == null ? undefined : v)); + expect(await normalized.parseAsync(null)).toBeUndefined(); + expect(() => normalized.parse(null)).toThrow(/validateAsync/); + }); +}); + +describe('named schema references', () => { + it('preserves one target definition and independent local metadata', () => { + const user = object({ name: string().minLength(1) }).schemaName('User'); + const ref = user; + const previous = ref + .nullable() + .optional() + .describe('Previous user') + .example(null); + expect(ref.introspect().referenceTarget).toBeUndefined(); + expect(previous.introspect().referenceTarget).toBe(user); + expect(user.introspect().description).toBeUndefined(); + expect(user.introspect().isRequired).toBe(true); + expect(ref.safeParse(null).valid).toBe(false); + expect(previous.parse(null)).toBeNull(); + expect(previous.parse(undefined)).toBeUndefined(); + expect(previous.parse({ name: 'Ada' })).toEqual({ name: 'Ada' }); + expect( + string().optional().introspect().referenceTarget + ).toBeUndefined(); + }); + + it('preserves deeply nested reference errors and selectors', async () => { + const address = object({ city: string().minLength(1) }).schemaName( + 'Address' + ); + const user = object({ address: address.optional() }).schemaName('User'); + const root = object({ user: user.optional().describe('User') }); + for (const result of [ + root.validate({ user: { address: { city: '' } } }), + await root.validateAsync({ user: { address: { city: '' } } }) + ]) { + expect(result.valid).toBe(false); + expect( + result.getErrorsFor(t => t.user.address.city).errors.length + ).toBeGreaterThan(0); + expect( + result + .getInvalidProperties() + .map(p => p.descriptor.toJsonPointer()) + ).toContain('/user/address/city'); + } + }); + + it('keeps target defaults, local defaults and fallbacks independent', async () => { + const target = number().default(2).schemaName('Size'); + const ref = target; + expect(ref.parse(undefined)).toBe(2); + expect(ref.optional().parse(undefined)).toBe(2); + expect(ref.optional().default(4).parse(undefined)).toBe(4); + expect(ref.default(4).clearDefault().safeParse(undefined).valid).toBe( + false + ); + expect(target.parse(undefined)).toBe(2); + const fallback = vi.fn(() => 8); + const caught = ref.catch(fallback); + expect(caught.parse('invalid')).toBe(8); + expect(await caught.parseAsync('invalid')).toBe(8); + expect(fallback).toHaveBeenCalledTimes(2); + expect(ref.optional().catch(undefined).parse({})).toBe( + number().default(2).optional().catch(undefined).parse({}) + ); + }); + + it('keeps local optionality, nullability and required error messages distinct', async () => { + const ref = string().nullable().optional().schemaName('Text'); + expect(ref.parse(null)).toBeNull(); + // Preserve the existing optional-null behavior, not wrapper semantics. + expect(ref.notNullable().parse(null)).toBeNull(); + expect(ref.notNullable().parse(undefined)).toBeUndefined(); + const required = ref.required('Provide text'); + expect(required.safeParse(undefined).errors?.[0].message).toBe( + 'Provide text' + ); + expect(required.parse(null)).toBeNull(); + const asyncRequired = ref.required(async () => 'Async required'); + expect(() => asyncRequired.parse(undefined)).toThrow(/Async|async/); + expect( + (await asyncRequired.safeParseAsync(undefined)).errors?.[0].message + ).toBe('Async required'); + }); + + it('delegates async target validation and runs local callbacks', async () => { + const target = string() + .addPreprocessor(async v => v.trim()) + .schemaName('Trimmed'); + const ref = target.optional(); + expect(() => ref.parse(' text ')).toThrow(/validateAsync/); + expect(await ref.parseAsync(' text ')).toBe('text'); + expect(await ref['~standard'].validate(' text ')).toEqual({ + value: 'text' + }); + const local = number() + .schemaName('Count') + .addPreprocessor(v => v + 1) + .addValidator(v => ({ valid: v < 5 })); + expect(local.parse(2)).toBe(3); + expect(local.safeParse(5).valid).toBe(false); + expect( + string() + .schemaName('OptionalText') + .optional() + .addPreprocessor(() => undefined) + .parse('text') + ).toBeUndefined(); + }); + + it('retains existing hasType behavior without changing runtime validation', () => { + const ref = number().schemaName('Count').hasType(); + expect(ref.parse(3)).toBe(3); + expect(ref.safeParse('three').valid).toBe(false); + expect(ref.clearHasType().parse(4)).toBe(4); + }); +}); + +describe('named schema derivation policy', () => { + it('uses the same naming policy for every concrete builder', () => { + const builders = [ + core.any(), + core.array(core.string()), + core.boolean(), + core.date(), + core.extern(core.string()), + core.func(), + core.generic(s => core.object({ value: s })), + core.intersection( + core.object({ a: core.string() }), + core.object({ b: core.number() }) + ), + core.lazy(() => core.string()), + core.nul(), + core.number(), + core.object({ name: core.string() }), + core.parseString( + core.object({ id: core.number() }), + t => t`/users/${p => p.id}` + ), + core.promise(core.string()), + core.record(core.string()), + core.string(), + core.tuple([core.string()]), + core.union([core.string(), core.number()]) + ]; + for (const builder of builders) { + const named = builder.schemaName('Definition'); + const alias = named.optional().nullable().describe('Use'); + expect(Object.getPrototypeOf(alias)).toBe( + Object.getPrototypeOf(named) + ); + expect(alias.introspect().referenceTarget).toBe(named); + expect(alias.introspect().schemaName).toBe('Definition'); + expect( + alias.hasType().clearHasType().introspect().referenceTarget + ).toBe(named); + const detached = alias.withExtension('custom', true); + expect(detached.introspect().schemaName).toBeUndefined(); + expect(detached.introspect().referenceTarget).toBeUndefined(); + } + }); + + it('preserves canonical identity through all use-site and type-only modifiers', () => { + const user = object({ name: string() }).schemaName('User'); + const variants = [ + user.optional(), + user.required(), + user.nullable(), + user.notNullable(), + user.describe('Use'), + user.example({ name: 'Ada' }), + user.readonly(), + user.brand<'User'>(), + user.hasType<{ name: string }>(), + user.clearHasType(), + user.optimize(), + user + .optional() + .nullable() + .required() + .notNullable() + .describe('Chained') + ]; + for (const variant of variants) { + expect(variant.introspect().schemaName).toBe('User'); + expect(variant.introspect().referenceTarget).toBe(user); + } + expect(user.introspect().referenceTarget).toBeUndefined(); + expect(user.introspect().description).toBeUndefined(); + }); + + it('detaches structural mutations and never reconnects them', () => { + const child = string().schemaName('Name'); + const user = object({ name: child, age: number() }).schemaName('User'); + const variants = [ + user.addProp('active', boolean()), + user.addProps({ active: boolean() }), + user.omit('age'), + user.pick('name'), + user.partial(), + user.deepPartial(), + user.modifyPropSchema('name', s => s.optional()), + user.makePropOptional('age'), + user.makePropRequired('age'), + user.makeAllPropsOptional(), + user.makeAllPropsRequired(), + user.acceptUnknownProps(), + user.notAcceptUnknownProps(), + user.optional().addProp('active', boolean()) + ]; + for (const variant of variants) { + expect(variant.introspect().schemaName).toBeUndefined(); + expect(variant.introspect().referenceTarget).toBeUndefined(); + expect( + variant.optional().describe('Use').introspect().referenceTarget + ).toBeUndefined(); + } + expect(user.omit('age').introspect().properties.name).toBe(child); + expect(Object.keys(user.introspect().properties)).toEqual([ + 'name', + 'age' + ]); + }); + + it('detaches rules, callbacks, defaults, fallbacks and extension changes including clear methods', () => { + const name = string().schemaName('Name').optional(); + const variants = [ + name.minLength(1), + name.maxLength(2), + name.clearMinLength(), + name.clearMaxLength(), + name.addValidator(() => ({ valid: true })), + name.clearValidators(), + name.addPreprocessor(v => v), + name.clearPreprocessors(), + name.default('Ada'), + name.clearDefault(), + name.catch(undefined), + name.withExtension('custom', true), + name.email(), + number().schemaName('Count').min(0), + boolean().schemaName('Flag').equals(true), + array(string()).schemaName('Names').minLength(1), + array(string()).schemaName('Names').maxLength(2), + array(string()).schemaName('Names').of(number()), + array(string()).schemaName('Names').clearOf(), + tuple([string()]).schemaName('Tuple').rest(number()), + tuple([string()]).schemaName('Tuple').clearRest() + ]; + for (const variant of variants) { + expect(variant.introspect().schemaName).toBeUndefined(); + expect(variant.introspect().referenceTarget).toBeUndefined(); + } + expect(name.minLength(1).email).toBeTypeOf('function'); + expect( + array(string()).schemaName('Names').minLength(1).nonempty + ).toBeTypeOf('function'); + }); + + it('explicit naming establishes a new independent definition', () => { + const original = object({ name: string() }).schemaName('User'); + const renamed = original + .optional() + .describe('Alias') + .schemaName('MaybeUser'); + expect(renamed.introspect().referenceTarget).toBeUndefined(); + expect(renamed.required().introspect().referenceTarget).toBe(renamed); + const extended = original + .addProp('id', number()) + .schemaName('UserWithId'); + expect(extended.optional().introspect().referenceTarget).toBe(extended); + expect(original.introspect().schemaName).toBe('User'); + }); + + it('keeps named and unnamed runtime behavior identical including async callbacks', async () => { + const plain = string().addPreprocessor(async value => value?.trim()); + const named = plain.schemaName('Text'); + for (const value of [undefined, null, '', ' a ']) { + expect(await named.optional().validateAsync(value)).toEqual( + await plain.optional().validateAsync(value) + ); + expect( + await named.required().nullable().validateAsync(value) + ).toEqual(await plain.required().nullable().validateAsync(value)); + } + }); +}); diff --git a/libs/schema/src/builders/references.test-d.ts b/libs/schema/src/builders/references.test-d.ts index 1f8ca4a9..b22b897d 100644 --- a/libs/schema/src/builders/references.test-d.ts +++ b/libs/schema/src/builders/references.test-d.ts @@ -1,5 +1,5 @@ import { expectTypeOf, test } from 'vitest'; -import { type InferType, number, object, schemaRef, string } from '../index.js'; +import { type InferType, number, object, string } from '../index.js'; test('optional-aware fallback and preprocessing types remain checked', () => { // @ts-expect-error required schemas cannot fall back to undefined @@ -20,7 +20,7 @@ test('optional-aware fallback and preprocessing types remain checked', () => { test('references preserve inferred types, local modifiers and selectors', () => { const user = object({ name: string() }).schemaName('User'); - const ref = schemaRef(user); + const ref = user; expectTypeOf>().toEqualTypeOf< InferType >(); @@ -40,8 +40,18 @@ test('references preserve inferred types, local modifiers and selectors', () => root.validate({ user: null }).getErrorsFor(t => t.user.name); // @ts-expect-error concrete descriptor trees still reject unknown fields root.validate({ user: null }).getErrorsFor(t => t.user.missing); - const override = schemaRef(number().schemaName('Number')).hasType(); + const override = number().schemaName('Number').hasType(); expectTypeOf>().toEqualTypeOf(); const cleared = override.clearHasType(); expectTypeOf>().toEqualTypeOf(); + const extended = user.optional().addProp('age', number()).required(); + expectTypeOf>().toEqualTypeOf<{ + name: string; + age: number; + }>(); + const email = string().schemaName('Name').optional().email(); + const plainEmail = string().optional().email(); + expectTypeOf>().toEqualTypeOf< + InferType + >(); }); diff --git a/libs/schema/src/core.ts b/libs/schema/src/core.ts index c27c368c..023f3b3b 100644 --- a/libs/schema/src/core.ts +++ b/libs/schema/src/core.ts @@ -50,10 +50,6 @@ export { } from './builders/PromiseSchemaBuilder.js'; export type { RecordSchemaValidationResult } from './builders/RecordSchemaBuilder.js'; export { RecordSchemaBuilder, record } from './builders/RecordSchemaBuilder.js'; -export { - ReferenceSchemaBuilder, - schemaRef -} from './builders/ReferenceSchemaBuilder.js'; export type { NestedValidationResult, PropertyDescriptor, diff --git a/libs/server-openapi/README.md b/libs/server-openapi/README.md index f44f40cd..9cb75e6a 100644 --- a/libs/server-openapi/README.md +++ b/libs/server-openapi/README.md @@ -9,10 +9,12 @@ OpenAPI 3.1 specification generation for [`@cleverbrush/server`](../server). Con ### Schema boundaries -Use `schemaRef(NamedSchema).optional().nullable().describe(...)` to annotate a -single use without cloning the named definition. Conflicting named definitions +Use `NamedSchema.optional().nullable().describe(...)` to annotate a +single use while preserving the canonical named definition. Conflicting named definitions still fail. OpenAPI and AsyncAPI retain one canonical component per named target. -See the [composition guide](../schema/BOUNDARIES.md). +Shape and rule changes detach the inherited name; name the result explicitly +with `schemaName` when it needs its own component. +See the [composition guide](https://github.com/cleverbrush/framework/blob/development/libs/schema/BOUNDARIES.md). - **`generateOpenApiSpec()`** — converts `@cleverbrush/server` endpoint registrations into an OpenAPI 3.1 document. - **`generateAsyncApiSpec()`** — converts `@cleverbrush/server` WebSocket subscription registrations into an AsyncAPI 3.0 document. diff --git a/libs/server-openapi/src/boundaries.test.ts b/libs/server-openapi/src/boundaries.test.ts index 28c0702d..a9fd4bc0 100644 --- a/libs/server-openapi/src/boundaries.test.ts +++ b/libs/server-openapi/src/boundaries.test.ts @@ -3,7 +3,6 @@ import { lazy, object, type SchemaBuilder, - schemaRef, string } from '@cleverbrush/schema'; import { endpoint } from '@cleverbrush/server'; @@ -16,8 +15,8 @@ describe('named schema references in API documents', () => { it('uses one canonical component for requests, responses and annotated references', () => { const user = object({ name: string() }).schemaName('User'); const history = object({ - current: schemaRef(user), - previous: schemaRef(user).nullable().optional().describe('Previous') + current: user, + previous: user.nullable().optional().describe('Previous') }); const contract = endpoint .post('/history') @@ -39,7 +38,7 @@ describe('named schema references in API documents', () => { ].schema; expect(request).toEqual(response); expect(request.required).toEqual(['current']); - expect(request.properties.current.allOf[0].$ref).toBe( + expect(request.properties.current.$ref).toBe( '#/components/schemas/User' ); expect(request.properties.previous.description).toBe('Previous'); @@ -55,14 +54,18 @@ describe('named schema references in API documents', () => { walkSchemas( object({ current: user, - previous: schemaRef(user).nullable().optional() + previous: user.nullable().optional() }), registry ); expect([...registry.entries()].map(([name]) => name)).toEqual(['User']); - expect(() => walkSchemas(user.optional(), registry)).toThrow( - /already registered/ - ); + expect(() => walkSchemas(user.optional(), registry)).not.toThrow(); + expect(() => + walkSchemas(user.optional().schemaName('User'), registry) + ).toThrow(/already registered/); + expect(() => + walkSchemas(object({ name: string() }).schemaName('User'), registry) + ).toThrow(/already registered/); expect(() => walkSchemas(string().schemaName('User'), registry) ).toThrow(/already registered/); @@ -72,7 +75,7 @@ describe('named schema references in API documents', () => { type Node = { name: string; children: Node[] }; const node: SchemaBuilder = object({ name: string(), - children: array(lazy(() => schemaRef(node))) + children: array(lazy(() => node.optional())) }).schemaName('Node'); const contract = endpoint.get('/nodes').responses({ 200: node }); const openapi = generateOpenApiSpec({ @@ -88,8 +91,8 @@ describe('named schema references in API documents', () => { protocol: 'subscription', basePath: '/ws', pathTemplate: '/nodes', - incomingSchema: schemaRef(node), - outgoingSchema: schemaRef(node), + incomingSchema: node, + outgoingSchema: node, querySchema: null, headerSchema: null, serviceSchemas: null, @@ -121,4 +124,47 @@ describe('named schema references in API documents', () => { messages.ServerEvent.payload ); }); + + it('separates inline derivatives, explicit new definitions and nested shared components', () => { + const name = string().schemaName('Name'); + const user = object({ name, role: string() }).schemaName('User'); + const patch = user.partial(); + const renamed = user.omit('role').schemaName('PublicUser'); + const schema = object({ + user, + patch, + public: renamed.optional(), + short: name.maxLength(2) + }); + const contract = endpoint + .post('/mixed') + .body(schema) + .responses({ 200: schema }); + const spec = generateOpenApiSpec({ + registrations: [ + { endpoint: contract.introspect(), handler: () => {} } + ], + info: { title: 'Mixed', version: '1' } + }) as any; + expect(Object.keys(spec.components.schemas).sort()).toEqual([ + 'Name', + 'PublicUser', + 'User' + ]); + expect( + spec.components.schemas.PublicUser.properties + ).not.toHaveProperty('role'); + const props = + spec.paths['/mixed'].post.requestBody.content['application/json'] + .schema.properties; + expect(props.patch.type).toBe('object'); + expect(props.patch.required).toBeUndefined(); + expect(props.patch.properties.name.allOf[0].$ref).toBe( + '#/components/schemas/Name' + ); + expect(props.short).toEqual({ type: 'string', maxLength: 2 }); + expect(props.public.allOf[0].$ref).toBe( + '#/components/schemas/PublicUser' + ); + }); }); diff --git a/libs/server-openapi/src/schemaRegistry.ts b/libs/server-openapi/src/schemaRegistry.ts index f2610a17..10f464dd 100644 --- a/libs/server-openapi/src/schemaRegistry.ts +++ b/libs/server-openapi/src/schemaRegistry.ts @@ -11,8 +11,8 @@ import type { SchemaBuilder } from '@cleverbrush/schema'; * `$ref: '#/components/schemas/'` pointers. * * **Conflict rule**: registering two *different* schema instances (different - * object references) under the same name throws immediately. Re-registering - * the same instance is a no-op. + * object references) under the same name throws immediately. Use-site aliases + * register their canonical target; re-registering that target is a no-op. * * @example * ```ts @@ -37,6 +37,7 @@ export class SchemaRegistry { * - If the schema has no `schemaName` in its introspect output, it is * silently skipped. * - If the same instance is already registered, this is a no-op. + * - Use-site modifiers register their canonical definition, not the alias. * - If a **different** instance is already registered under the same name, * an error is thrown. * @@ -44,6 +45,7 @@ export class SchemaRegistry { * @throws {Error} When two distinct schema instances share the same name. */ register(schema: SchemaBuilder): void { + schema = schema.introspect().referenceTarget ?? schema; const name = (schema.introspect() as any).schemaName as | string | undefined; @@ -74,6 +76,7 @@ export class SchemaRegistry { * @returns The registered name, or `null`. */ getName(schema: SchemaBuilder): string | null { + schema = schema.introspect().referenceTarget ?? schema; return this.byInstance.get(schema) ?? null; } @@ -104,9 +107,8 @@ export class SchemaRegistry { * schemas may safely be shared across multiple branches without causing * infinite recursion. * - * **Excluded schema types** - * - `lazy` — deferred resolution would require calling the getter, which may - * itself reference the parent schema; lazy schemas are handled separately. + * Use-site aliases walk their canonical definition. Lazy schemas resolve their + * getter; the shared visited set prevents cycles through named recursive roots. * * @param schema - Root schema to start the walk from. * @param registry - Registry to register named schemas into. @@ -125,10 +127,12 @@ export function walkSchemas( const info = schema.introspect() as any; + if (info.referenceTarget) { + walkSchemas(info.referenceTarget, registry, visited); + return; + } + switch (info.type) { - case 'reference': - walkSchemas(info.targetSchema, registry, visited); - break; case 'intersection': walkSchemas(info.left, registry, visited); walkSchemas(info.right, registry, visited); diff --git a/websites/docs/app/server-openapi/page.tsx b/websites/docs/app/server-openapi/page.tsx index 784a18fb..99aa5fd1 100644 --- a/websites/docs/app/server-openapi/page.tsx +++ b/websites/docs/app/server-openapi/page.tsx @@ -23,11 +23,12 @@ export default function ServerOpenApiPage() {

Named references and local annotations

- Use schemaRef to annotate one use of a named definition - without cloning it. Optionality, nullability and - descriptions remain local, while the target has one - canonical component. Conflicting named definitions still - fail registration. + Use ordinary fluent modifiers on a named definition. + Optionality, nullability and descriptions remain local, + while the target has one canonical component. + Conflicting named definitions still fail registration. + Shape and rule changes become unnamed; apply schemaName + last to name a new definition.

Schema boundary composition and compatibility diff --git a/websites/schema/app/docs/sections/schema-boundaries.tsx b/websites/schema/app/docs/sections/schema-boundaries.tsx index 8d94821d..385819d1 100644 --- a/websites/schema/app/docs/sections/schema-boundaries.tsx +++ b/websites/schema/app/docs/sections/schema-boundaries.tsx @@ -26,15 +26,18 @@ const nullableText = string().nullable().catch(null);`}
                     {`const User = object({ name: string() }).schemaName('User');
 const History = object({
-    current: schemaRef(User),
-    previous: schemaRef(User).nullable().optional()
+    current: User,
+    previous: User.nullable().optional()
         .describe('Previous user')
 });`}
                 

- Reference modifiers apply at the use site. The original - named definition remains unchanged, and genuinely - conflicting definitions still fail registration. + Ordinary modifiers apply at the use site. The original named + definition remains unchanged, and genuinely conflicting + definitions still fail registration. Shape, rule, default, + fallback and extension changes discard inherited names. + Apply schemaName after those edits when the result needs its + own component.

diff --git a/websites/schema/app/schema-json/page.tsx b/websites/schema/app/schema-json/page.tsx index 1b936ffc..ea95b003 100644 --- a/websites/schema/app/schema-json/page.tsx +++ b/websites/schema/app/schema-json/page.tsx @@ -35,10 +35,12 @@ export default function SchemaJsonPage() {

Named references

- Use schemaRef to reuse a named definition with local - annotations and nullability. Reference composition - preserves the original definition in both Draft 7 and - Draft 2020-12. + Use ordinary fluent modifiers to reuse a named + definition with local annotations and nullability. + Reference composition preserves the original definition + in both Draft 7 and Draft 2020-12. Shape and rule + changes detach the inherited name; apply schemaName last + when naming a new definition.

Named references and optional fallbacks From 89abbf53cd76c37947243d8548e5bc983f5d811b Mon Sep 17 00:00:00 2001 From: Andrew Zolotukhin Date: Tue, 29 Sep 2026 11:02:06 +0000 Subject: [PATCH 08/41] docs(schema): consolidate reference guidance after review --- libs/schema-json/README.md | 43 +++++-- libs/schema/BOUNDARIES.md | 116 ------------------ libs/schema/README.md | 102 +++++++++++++-- libs/schema/src/boundaries-docs.test.ts | 52 -------- libs/server-openapi/README.md | 41 +++++-- websites/docs/app/server-openapi/page.tsx | 57 ++++++--- websites/schema/app/docs/[[...slug]]/page.tsx | 2 - websites/schema/app/docs/sections/index.ts | 6 - .../app/docs/sections/schema-boundaries.tsx | 58 --------- .../app/docs/sections/schema-modifiers.tsx | 107 ++++++++++++++++ websites/schema/app/schema-json/page.tsx | 59 ++++++--- 11 files changed, 347 insertions(+), 296 deletions(-) delete mode 100644 libs/schema/BOUNDARIES.md delete mode 100644 libs/schema/src/boundaries-docs.test.ts delete mode 100644 websites/schema/app/docs/sections/schema-boundaries.tsx diff --git a/libs/schema-json/README.md b/libs/schema-json/README.md index d6c137ff..3084461a 100644 --- a/libs/schema-json/README.md +++ b/libs/schema-json/README.md @@ -12,13 +12,6 @@ for use in OpenAPI specs, form generators, or any other JSON Schema consumer. ## When to use this library -### Named references - -Ordinary modifiers such as `User.optional().nullable().describe('Previous')` -preserve a named definition automatically. Shape and validation-rule changes -become unnamed derivatives; apply `schemaName` last to name a new definition. -See the [composition guide](https://github.com/cleverbrush/framework/blob/development/libs/schema/BOUNDARIES.md). - - **Consuming external APIs** — you have a JSON Schema from an OpenAPI spec or a third-party service and want to validate incoming data with full TypeScript type inference. @@ -163,6 +156,40 @@ Descriptions set via `.describe(text)` are emitted as the `description` field on Examples set via `.example(value)` are emitted as the `examples` array on the corresponding JSON Schema node. +#### Named references and local annotations + +Ordinary modifiers such as `User.optional().nullable().describe('Previous')` +preserve the canonical named definition. With a `nameResolver`, direct reuse +emits a `$ref`; modified uses compose around that reference so annotations and +nullability remain local in both Draft 07 and Draft 2020-12. + +```ts +const User = object({ name: string() }).schemaName('User'); +const History = object({ + current: User, + previous: User.optional().nullable().describe('Previous user') +}); +const json = toJsonSchema(History, { + $schema: false, + nameResolver: schema => schema.introspect().schemaName ?? null +}); +// json.required: ['current'] +// json.properties.current: { $ref: '#/components/schemas/User' } +// json.properties.previous: local description and a nullable reference to User +``` + +Use-site modifiers are handled before name resolution, which receives the +canonical target. The resolver does not create component definitions itself; +supply them in the containing document or use `@cleverbrush/server-openapi`. +Without a resolver, the target is converted inline. + +Shape, validation-rule, default, fallback and extension changes discard the +inherited name and export inline, while nested named children still reuse their +definitions. Apply `schemaName` after such edits to name a new definition. See +the [schema naming rules](https://schema.cleverbrush.com/docs/schema-modifiers#schema-name). +Standard JSON Schema `input()` and `output()` retain their existing identical +representation; no separate directional schemas are introduced. + #### Discriminated unions When a `union()` is a **discriminated union** — all branches are objects sharing a required property with unique literal values — `toJsonSchema()` automatically emits the `discriminator` keyword alongside `anyOf`: @@ -195,7 +222,7 @@ This enables code-generation tools (openapi-generator, orval, etc.) to produce p | --- | --- | --- | --- | | `draft` | `'2020-12' \| '07'` | `'2020-12'` | JSON Schema draft version for the `$schema` URI | | `$schema` | `boolean` | `true` | Whether to include the `$schema` header in the output | -| `nameResolver` | `(schema: SchemaBuilder) => string \| null` | `undefined` | Called for every node before conversion. Return a non-null string to emit `{ $ref: '#/components/schemas/' }` instead of an inline schema. Used by `@cleverbrush/server-openapi` to wire named schemas from `.schemaName()` into `$ref` pointers. | +| `nameResolver` | `(schema: SchemaBuilder) => string \| null` | `undefined` | Return a component name to emit `{ $ref: '#/components/schemas/' }` instead of an inline definition. Use-site modifiers resolve their canonical target and compose local annotations/nullability around it. Used by `@cleverbrush/server-openapi` for named components. | ```ts // Embed in OpenAPI (suppress the $schema header) diff --git a/libs/schema/BOUNDARIES.md b/libs/schema/BOUNDARIES.md deleted file mode 100644 index 14695a44..00000000 --- a/libs/schema/BOUNDARIES.md +++ /dev/null @@ -1,116 +0,0 @@ -# Schemas across boundaries - -`InferType` continues to mean validated output; -existing builder generic arguments and legacy preprocessors keep their meaning. - -## Optional fallbacks - -Before, consumers needed a separate safeParse helper for each optional scalar. -Now a fallback can use the optional or nullable schema's full output type: - -```ts -import { boolean, object, string } from '@cleverbrush/schema'; - -const optionalText = string().optional().catch(undefined); -const ExternalRecord = object({ - name: optionalText, - enabled: boolean().optional().catch(() => undefined) -}); -ExternalRecord.parse({ name: 42, enabled: 'unknown' }); -// { name: undefined, enabled: undefined } -``` - -Fallbacks are opt-in. A malformed required root object still fails. Arrays do -not silently discard invalid elements. A fallback factory runs only on failure. - -**Compatibility limitation:** legacy optional schemas also accept `null` at -runtime, even though their inferred type does not include it. This release does -not change that behavior. Consequently, `.optional().catch(undefined)` leaves -`null` unchanged. Normalize it explicitly when the application requires this: - -```ts -const normalizedText = string().optional() - .addPreprocessor(value => value == null ? undefined : value) - .catch(undefined); -``` - -Preprocessors can return optional/nullable values, including asynchronously. -Their existing callback parameter typing is preserved; it is not a guarantee -that unknown runtime input already has that type. Use explicit guards or -preprocessing/conversion followed by validation at untrusted boundaries. -Global strict null rejection is a separate, compatibility-sensitive follow-up. - -## One named definition, many annotated references - -Before, cloning `User.schemaName('User')` with `.optional()` created another -named instance and conflicted during OpenAPI generation. - -```ts -import { number, object, string } from '@cleverbrush/schema'; - -const User = object({ id: number(), name: string() }).schemaName('User'); -const History = object({ - current: User, - previous: User.nullable().optional() - .describe('The previous user, when known.') -}); -``` - -No wrapper is needed. Ordinary immutable modifiers keep the concrete builder, -fluent methods, extension methods, inference, and nested property selectors. -They validate normally; canonical-reference metadata only affects exporters. -The original definition is never mutated. Reuse the plain constant when there -are no local modifiers. Independent definitions sharing a name still conflict; -there is no name-based or structural deduplication. - -### Which changes preserve the named definition? - -- Use-site presence/nullability: `optional`, `required`, `nullable`, `notNullable`. -- Annotations: `describe`, `example`, `readonly`. -- Type-only changes: `brand`, `hasType`, `clearHasType`, `optimize`. - -Chains of these modifiers always reference the original canonical definition, -not another alias. Calling `schemaName` explicitly creates a new independent -definition, even when the previous name is reused. - -### Shape and rule changes become unnamed - -Property additions/removals, `partial`, `pick`, `omit`, constraints, validators, -preprocessors, defaults, fallbacks, and their clear methods discard the inherited -name and canonical association. Extension changes detach conservatively, too. -These derivatives cannot safely claim to be the original definition. Later -annotations or optionality do not reconnect them. - -```ts -const PartialUser = User.partial(); // unnamed, all properties optional -const UserWithEmail = User.addProp('email', string()); // unnamed, new shape -const PublicUser = User.omit('id').schemaName('PublicUser'); // new definition -const ShortName = string().schemaName('Name').maxLength(20); // unnamed rule change -``` - -Existing nested named schemas still reuse their own definitions. To retain a -stable component name after a shape or rule change, call `schemaName` **last**. -This intentionally changes inherited-name behavior; review code that relied on -constraint/property modifications retaining the old component name. - -JSON Schema/OpenAPI keeps one definition and uses reference composition for -local annotations, examples and nullability, including Draft 07 references. - -## Defaults and validation - -Defaults and fallbacks retain ordinary builder behavior, not delegated wrapper -behavior. Adding or clearing either detaches the name. Clearing a default removes -it completely; it does not reveal a hidden canonical default. Async validators -and preprocessors still require `parseAsync`/`validateAsync`. - -Use `InferType` for schema inference and the existing `hasType` method when an -explicit static override is needed. Static overrides and casts do not change -runtime validation or convert values. - -## API documents - -JSON Schema, OpenAPI and AsyncAPI retain one canonical component per named -target. Reference annotations compose around that definition rather than -changing it. Named recursive references are supported; independently rebuilt -schemas with the same name still conflict. Standard JSON Schema `input()` and -`output()` retain their existing identical representation. diff --git a/libs/schema/README.md b/libs/schema/README.md index 937bf4f4..78bce142 100644 --- a/libs/schema/README.md +++ b/libs/schema/README.md @@ -1,12 +1,5 @@ # @cleverbrush/schema -## Schemas across boundaries - -Use optional-aware `catch(undefined)` and ordinary named-schema modifiers for per-use -annotations while preserving canonical named definitions. See the -[composition guide](https://github.com/cleverbrush/framework/blob/development/libs/schema/BOUNDARIES.md) -for examples, naming rules and null-compatibility limits. - [![CI](https://github.com/cleverbrush/framework/actions/workflows/ci.yml/badge.svg)](https://github.com/cleverbrush/framework/actions/workflows/ci.yml) [![Standard Schema v1](https://img.shields.io/badge/Standard%20Schema-v1-blue)](https://standardschema.dev/) @@ -1132,6 +1125,43 @@ console.log(info.hasCatch); // true console.log(info.catchValue); // 'unknown' ``` +### Optional and nullable fallbacks + +Fallback values and factories respect the schema's resolved output type: +optional schemas allow `undefined`, and nullable schemas allow `null`. + +```typescript +const optionalText = string().optional().catch(undefined); +const nullableText = string().nullable().catch(() => null); + +optionalText.parse(42); // undefined +nullableText.parse(42); // null +object({ text: optionalText }).parse({ text: false }); // { text: undefined } +array(optionalText).parse(['ok', 42]); // ['ok', undefined] — no entries dropped +``` + +Fallbacks are opt-in: a fallback on a property does not make a malformed required +root object valid. A fallback factory runs only when validation fails. + +**Null compatibility:** legacy optional schemas accept `null` at runtime even +though their inferred type does not include it. `.optional().catch(undefined)` +therefore leaves `null` unchanged. Normalize it explicitly when needed: + +```typescript +const normalizedText = string().optional() + .addPreprocessor(value => value == null ? undefined : value) + .catch(undefined); + +normalizedText.parse(null); // undefined +``` + +Preprocessors can return optional/nullable values, including asynchronously. +Their existing callback parameter typing does not guarantee that unknown input +already has that type: guard untrusted values before using type-specific methods. +Use `parseAsync` / `validateAsync` for async preprocessors or validators. +`InferType` and `hasType` keep their existing meaning; static overrides and casts +do not perform runtime conversion or validation. + ## Readonly Modifier Every schema builder supports `.readonly()`. This is a **type-level-only** modifier — it marks the inferred TypeScript type as immutable, but does not alter validation behaviour or freeze the validated value at runtime. @@ -1196,7 +1226,7 @@ export const UserSchema = object({ UserSchema.introspect().schemaName; // 'User' ``` -Chains naturally with all other modifiers: +Annotations can be applied after naming a definition: ```typescript const ProductSchema = object({ @@ -1217,12 +1247,64 @@ import { generateOpenApiSpec } from '@cleverbrush/server-openapi'; generateOpenApiSpec({ registrations, info: { title: 'My API', version: '1.0.0' } }); ``` -> **Name uniqueness:** Registering two *different* schema instances under the same name throws an error. Always export named schemas as constants and reuse the same reference everywhere. +### Reusing a named definition + +Use the plain constant directly, or apply ordinary use-site modifiers. No wrapper +is needed; the concrete builder, fluent and extension methods, inferred types, +and nested property selectors are preserved. The original remains unchanged. + +```typescript +const History = object({ + current: UserSchema, + previous: UserSchema.optional().nullable().describe('Previous user') +}); +// One canonical User component; previous has local annotations/nullability. +``` + +These modifiers retain the canonical named definition for document exporters: + +- Presence/nullability: `optional`, `required`, `nullable`, `notNullable`. +- Annotations: `describe`, `example`, `readonly`. +- Type-only changes: `brand`, `hasType`, `clearHasType`, `optimize`. + +Modifier chains reference the original definition, not another alias. JSON Schema, +OpenAPI and AsyncAPI compose local annotations and nullability around that +definition, including Draft 07 references. Runtime validation still follows the +ordinary builder's behavior; canonical-reference metadata is for exporters. + +### Shape and rule changes discard inherited names + +Property additions/removals, `partial`, `pick`, `omit`, constraints, validators, +preprocessors, defaults, fallbacks and their available clear methods produce +unnamed derivatives. Extension changes detach conservatively too. Later +annotations or optionality do not reconnect the derivative to the original. + +```typescript +const PatchUser = UserSchema.partial(); // unnamed, changed shape +const UserWithEmail = UserSchema.addProp('email', string()); // unnamed +const PublicUser = UserSchema.omit('id').schemaName('PublicUser'); // new definition +const ShortName = string().schemaName('Name').maxLength(20); // unnamed rule change +``` + +Existing nested named schemas still reuse their own definitions. Apply +`schemaName` **after** shape/rule edits when the result needs a stable component +name. This changes inherited-name behavior: code that relied on property or +constraint edits retaining a name should name the final result explicitly. + +Defaults and fallbacks keep ordinary builder semantics. Adding or clearing them +detaches the inherited name; `clearDefault()` removes the default completely, +without revealing a hidden default from the canonical definition. + +> **Name uniqueness:** Independent definitions with the same name still conflict, +> even with identical shapes; there is no name-only or structural deduplication. +> Use-site modifiers reuse the original definition and do not conflict. Calling +> `schemaName` explicitly always establishes a fresh independent definition, +> even on an alias or when the previous name is reused. | Method / Property | Signature | Notes | |---|---|---| | `.schemaName(name)` | `schemaName(name: string): this` | Returns a new builder; original is unchanged | -| `.introspect().schemaName` | `string \| undefined` | The name passed to `.schemaName()`, or `undefined` | +| `.introspect().schemaName` | `string \| undefined` | The explicit or preserved name; `undefined` after a shape/rule change | ## Describe diff --git a/libs/schema/src/boundaries-docs.test.ts b/libs/schema/src/boundaries-docs.test.ts deleted file mode 100644 index 25eeffc0..00000000 --- a/libs/schema/src/boundaries-docs.test.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { readFileSync } from 'node:fs'; -import ts from 'typescript'; -import { describe, expect, it } from 'vitest'; - -describe('published boundary documentation', () => { - it('preserves declaration summaries for boundary types and methods', () => { - const hasSummary = (node: ts.Node) => - (node as ts.Node & { jsDoc?: readonly ts.JSDoc[] }).jsDoc?.some( - doc => doc.comment - ); - for (const [path, names] of [ - [ - '../dist/builders/SchemaBuilder.d.ts', - ['SchemaBuilder', 'SchemaBuilderProps'] - ], - ['../../schema-json/dist/types.d.ts', ['ToJsonSchemaOptions']] - ] as const) { - const text = readFileSync(new URL(path, import.meta.url), 'utf8'); - const source = ts.createSourceFile( - path, - text, - ts.ScriptTarget.Latest, - true - ); - for (const name of names) { - const node = source.statements.find( - node => - 'name' in node && - (node.name as ts.Identifier)?.text === name - ); - expect(node, name).toBeDefined(); - expect(hasSummary(node!), name).toBe(true); - if (node && ts.isClassDeclaration(node)) { - for (const memberName of [ - 'schemaName', - 'introspect', - 'derive', - 'catch', - 'addPreprocessor' - ]) { - const member = node.members.find( - member => - member.name?.getText(source) === memberName - ); - expect(member, memberName).toBeDefined(); - expect(hasSummary(member!), memberName).toBe(true); - } - } - } - } - }); -}); diff --git a/libs/server-openapi/README.md b/libs/server-openapi/README.md index 9cb75e6a..8290de49 100644 --- a/libs/server-openapi/README.md +++ b/libs/server-openapi/README.md @@ -7,15 +7,6 @@ OpenAPI 3.1 specification generation for [`@cleverbrush/server`](../server). Con ## Features -### Schema boundaries - -Use `NamedSchema.optional().nullable().describe(...)` to annotate a -single use while preserving the canonical named definition. Conflicting named definitions -still fail. OpenAPI and AsyncAPI retain one canonical component per named target. -Shape and rule changes detach the inherited name; name the result explicitly -with `schemaName` when it needs its own component. -See the [composition guide](https://github.com/cleverbrush/framework/blob/development/libs/schema/BOUNDARIES.md). - - **`generateOpenApiSpec()`** — converts `@cleverbrush/server` endpoint registrations into an OpenAPI 3.1 document. - **`generateAsyncApiSpec()`** — converts `@cleverbrush/server` WebSocket subscription registrations into an AsyncAPI 3.0 document. - **`serveAsyncApi()`** — middleware that lazily generates and caches the AsyncAPI spec; serves it at a configurable path (default: `/asyncapi.json`). @@ -150,9 +141,31 @@ const AddressSchema = object({ street: string(), city: string() }).schemaName('A const CreateUserBody = object({ address: AddressSchema, name: string() }); ``` +### Local modifiers and changed shapes + +Ordinary use-site modifiers retain the canonical named component: + +```ts +const History = object({ + current: UserSchema, + previous: UserSchema.optional().nullable().describe('Previous user') +}); +// One User component; previous composes local nullability and annotations. + +const PatchUser = UserSchema.partial(); // unnamed, exported inline +const PublicUser = UserSchema.omit('id').schemaName('PublicUser'); // new component +``` + +Presence, nullability, annotations and type-only modifiers preserve the original +definition. Shape/rule edits, callbacks, defaults, fallbacks and extension changes +discard inherited names. Their nested named children still reuse components. +Apply `schemaName` after these edits when the result needs its own component; +later optionality or annotations do not reconnect an unnamed derivative. +See the [complete naming rules](https://schema.cleverbrush.com/docs/schema-modifiers#schema-name). + ### Conflict rule -Registering **two different schema instances** under the same name throws immediately during spec generation: +Registering **two independent definitions** under the same name throws immediately during spec generation, even if their shapes match: ```ts const A = object({ x: string() }).schemaName('Thing'); @@ -162,7 +175,9 @@ generateOpenApiSpec({ registrations: [...], info: { … } }); // Error: Schema name "Thing" is already registered by a different schema instance. ``` -Re-registering the **same** instance (because it appears in multiple endpoints) is a no-op. +Re-registering the **same** instance or its use-site modifiers is a no-op. Calling +`schemaName` explicitly establishes a new independent definition, even on a +modified use; reusing an already registered name then conflicts. ### `SchemaRegistry` (advanced) @@ -455,6 +470,10 @@ Each subscription endpoint becomes: Named schemas (registered via `.schemaName()`) are collected into `components.schemas` and referenced via `$ref` pointers in the channel messages. +AsyncAPI uses the same canonical-reference, local-modifier and name-conflict +rules as OpenAPI. Named recursive schemas are expanded once per component, +with recursive uses referencing that component. + ### `AsyncApiOptions` | Field | Type | Default | Description | diff --git a/websites/docs/app/server-openapi/page.tsx b/websites/docs/app/server-openapi/page.tsx index 99aa5fd1..0e815725 100644 --- a/websites/docs/app/server-openapi/page.tsx +++ b/websites/docs/app/server-openapi/page.tsx @@ -20,20 +20,6 @@ export default function ServerOpenApiPage() {

- {/* ── Installation ─────────────────────────────────── */}

- Conflict rule: registering two{' '} - different schema instances under the same name - throws during spec generation. Always export named - schemas as constants and share the same object - reference. + Ordinary use-site modifiers retain the canonical + component, with local annotations and nullability: +

+
+                        {`const History = object({
+    current: UserSchema,
+    previous: UserSchema.optional().nullable().describe('Previous user')
+});
+// One User component shared by both properties.
+
+const PatchUser = UserSchema.partial(); // unnamed, exported inline
+const PublicUser = UserSchema.omit('id').schemaName('PublicUser');`}
+                    
+

+ Shape/rule edits, callbacks, defaults, fallbacks and + extension changes discard inherited names. Nested named + children still reuse components. Apply{' '} + schemaName after these edits when the + result needs its own component. Later optionality or + annotations do not reconnect an unnamed derivative. See + the{' '} + + complete naming rules + + . +

+

+ Conflict rule: independent definitions + sharing a name throw during spec generation, even if + their shapes match. Reusing a constant or its use-site + modifiers does not conflict. Explicitly calling{' '} + schemaName always creates a new independent + definition, including on a modified use. +

+

+ AsyncAPI follows the same rules: one canonical component + per named definition, local annotations in message + payloads, and references for recursive uses.

diff --git a/websites/schema/app/docs/[[...slug]]/page.tsx b/websites/schema/app/docs/[[...slug]]/page.tsx index 2e4f66c8..854d0b28 100644 --- a/websites/schema/app/docs/[[...slug]]/page.tsx +++ b/websites/schema/app/docs/[[...slug]]/page.tsx @@ -17,7 +17,6 @@ import ObjectConstructorsSection from '../sections/object-constructors'; import ParseStringSection from '../sections/parse-string'; import PropertyDescriptorsSection from '../sections/property-descriptors'; import RecursiveSchemasSection from '../sections/recursive-schemas'; -import SchemaBoundariesSection from '../sections/schema-boundaries'; import SchemaModifiersSection from '../sections/schema-modifiers'; import SchemaTypesSection from '../sections/schema-types'; import StandardSchemaSection from '../sections/standard-schema'; @@ -50,7 +49,6 @@ const SECTION_COMPONENTS: Record = { 'parse-string': ParseStringSection, 'object-constructors': ObjectConstructorsSection, 'schema-modifiers': SchemaModifiersSection, - 'schema-boundaries': SchemaBoundariesSection, extensions: ExtensionsSection, 'built-in-extensions': BuiltInExtensionsSection, 'generic-schemas': GenericSchemasSection, diff --git a/websites/schema/app/docs/sections/index.ts b/websites/schema/app/docs/sections/index.ts index a86e09a5..79e3d249 100644 --- a/websites/schema/app/docs/sections/index.ts +++ b/websites/schema/app/docs/sections/index.ts @@ -19,7 +19,6 @@ export const SECTION_GROUPS = [ label: 'Composition', slugs: [ 'immutability', - 'schema-boundaries', 'discriminated-unions', 'recursive-schemas', 'parse-string', @@ -51,11 +50,6 @@ export const SECTION_GROUPS = [ ]; export const SCHEMA_SECTIONS: SchemaSection[] = [ - { - slug: 'schema-boundaries', - title: 'Schema Boundaries', - group: 'Composition' - }, { slug: 'why', title: 'Why @cleverbrush/schema?', group: 'Fundamentals' }, { slug: 'getting-started', diff --git a/websites/schema/app/docs/sections/schema-boundaries.tsx b/websites/schema/app/docs/sections/schema-boundaries.tsx deleted file mode 100644 index 385819d1..00000000 --- a/websites/schema/app/docs/sections/schema-boundaries.tsx +++ /dev/null @@ -1,58 +0,0 @@ -export default function SchemaBoundariesSection() { - return ( - <> -
-

Schemas Across Boundaries

-

- Compose optional fallbacks and named references without - duplicating validation rules. -

-
-
-

Optional fallbacks

-
-                    {`const text = string().optional().catch(undefined);
-const nullableText = string().nullable().catch(null);`}
-                
-

- Legacy optional schemas accept null at runtime. A fallback - does not replace a value that passed validation. Normalize - null explicitly if your application requires undefined; this - release does not change that compatibility behavior. -

-
-
-

One named definition

-
-                    {`const User = object({ name: string() }).schemaName('User');
-const History = object({
-    current: User,
-    previous: User.nullable().optional()
-        .describe('Previous user')
-});`}
-                
-

- Ordinary modifiers apply at the use site. The original named - definition remains unchanged, and genuinely conflicting - definitions still fail registration. Shape, rule, default, - fallback and extension changes discard inherited names. - Apply schemaName after those edits when the result needs its - own component. -

-
-
-

API documents

-

- JSON Schema, OpenAPI and AsyncAPI preserve one canonical - named definition with local reference annotations. - Independent definitions with the same name still fail - registration. Existing inference and static type overrides - are unchanged. -

- - Read the full composition guide - -
- - ); -} diff --git a/websites/schema/app/docs/sections/schema-modifiers.tsx b/websites/schema/app/docs/sections/schema-modifiers.tsx index 2a24b4df..71c123dd 100644 --- a/websites/schema/app/docs/sections/schema-modifiers.tsx +++ b/websites/schema/app/docs/sections/schema-modifiers.tsx @@ -120,6 +120,48 @@ console.log(schema.introspect().catchValue); // 'unknown'`) }} /> +

Optional and nullable fallbacks

+

+ Fallback values and factories respect the resolved output + type: optional schemas allow undefined, and + nullable schemas allow null. +

+
+                    {`const text = string().optional().catch(undefined);
+const nullableText = string().nullable().catch(() => null);
+
+text.parse(42); // undefined
+nullableText.parse(42); // null
+array(text).parse(['ok', 42]); // ['ok', undefined] — no entries dropped`}
+                
+

+ Fallbacks are opt-in. A property fallback does not make a + malformed required root object valid, and a fallback factory + runs only when validation fails. +

+

+ Legacy optional schemas accept null at runtime + even when their inferred type omits it. A fallback does not + replace a value that passed validation, so normalize null + explicitly when your application requires undefined: +

+
+                    {`const normalizedText = string().optional()
+    .addPreprocessor(value => value == null ? undefined : value)
+    .catch(undefined);
+
+normalizedText.parse(null); // undefined`}
+                
+

+ Preprocessors may return optional/nullable values, including + asynchronously. Their callback parameter types do not + guarantee that unknown input already has that type; guard + untrusted values before using type-specific methods. Use{' '} + parseAsync / validateAsync for + async callbacks. Existing InferType and{' '} + hasType behavior is unchanged; static overrides + do not convert or validate runtime values. +

{/* ── Readonly ─────────────────────────────────────── */} @@ -283,6 +325,71 @@ console.log(UserSchema.introspect().schemaName); // 'User' }} /> +

Reuse the definition with ordinary modifiers

+
+                    {`const History = object({
+    current: UserSchema,
+    previous: UserSchema.optional().nullable().describe('Previous user')
+});
+// One User component, with local annotations and nullability for previous.`}
+                
+

+ No wrapper is needed. The original remains unchanged, and + concrete builder methods, extensions, inference and nested + property selectors are preserved. Modifier chains reference + the original definition, not another alias. +

+
    +
  • + Presence/nullability: optional,{' '} + required, nullable,{' '} + notNullable. +
  • +
  • + Annotations: describe, example + , readonly. +
  • +
  • + Type-only changes: brand,{' '} + hasType, clearHasType,{' '} + optimize. +
  • +
+

Shape and rule changes become unnamed

+

+ Property edits, partial/pick/omit, constraints, validators, + preprocessors, defaults, fallbacks and their available clear + methods discard inherited names. Extension changes detach + conservatively too. Later annotations or optionality do not + reconnect the derivative; existing nested named children + still reuse their own definitions. +

+
+                    {`const PatchUser = UserSchema.partial(); // unnamed
+const UserWithEmail = UserSchema.addProp('email', string()); // unnamed
+const PublicUser = UserSchema.omit('id').schemaName('PublicUser');
+const ShortName = string().schemaName('Name').maxLength(20); // unnamed`}
+                
+

+ Apply schemaName after shape/rule edits when + the result needs a stable component name. Code that + previously relied on edits retaining an inherited name + should name the final result explicitly. +

+

+ Explicit naming always creates an independent definition, + even on an alias. Independent definitions sharing a name + still conflict, including identical shapes; use-site + modifiers of the same definition do not. +

+

+ Canonical-reference metadata affects exporters, not runtime + validation. Defaults and fallbacks follow ordinary builder + semantics; clearDefault() removes the default + completely without revealing a hidden canonical default. + JSON Schema, OpenAPI and AsyncAPI keep one canonical + definition with local annotations and nullability. +

{/* ── Promise Schemas ──────────────────────────────── */} diff --git a/websites/schema/app/schema-json/page.tsx b/websites/schema/app/schema-json/page.tsx index ea95b003..ba7b62a1 100644 --- a/websites/schema/app/schema-json/page.tsx +++ b/websites/schema/app/schema-json/page.tsx @@ -32,20 +32,6 @@ export default function SchemaJsonPage() { ]} /> -
-

Named references

-

- Use ordinary fluent modifiers to reuse a named - definition with local annotations and nullability. - Reference composition preserves the original definition - in both Draft 7 and Draft 2020-12. Shape and rule - changes detach the inherited name; apply schemaName last - when naming a new definition. -

- - Named references and optional fallbacks - -
{/* ── Installation ─────────────────────────────────── */} +

Named references and local annotations

+

+ Ordinary use-site modifiers preserve a named definition. + Direct reuse emits a $ref; modified uses + compose local annotations and nullability around it in + both Draft 7 and Draft 2020-12: +

+
+                        {`const User = object({ name: string() }).schemaName('User');
+const History = object({
+    current: User,
+    previous: User.optional().nullable().describe('Previous user')
+});
+const json = toJsonSchema(History, {
+    $schema: false,
+    nameResolver: schema => schema.introspect().schemaName ?? null
+});
+// json.required: ['current']
+// current references User; previous adds local description and nullability.`}
+                    
+

+ Use-site modifiers are processed before name resolution, + which receives their canonical target. The resolver does + not create component definitions: supply those in the + containing document or use{' '} + @cleverbrush/server-openapi. Without a + resolver, the target is converted inline. +

+

+ Shape, rule, default, fallback and extension changes + discard inherited names and export inline. Nested named + children still reuse their definitions. Apply{' '} + schemaName after those edits to name a new + definition. See the{' '} + + schema naming rules + + . +

+

+ Standard JSON Schema input() and{' '} + output() keep their existing identical + representation; no separate directional schemas are + introduced. +

{/* ── TypeScript inference ─────────────────────────── */} From 0a08509de5a2761b8cbc58c4510915f981bee8d9 Mon Sep 17 00:00:00 2001 From: Andrew Zolotukhin Date: Tue, 29 Sep 2026 18:29:12 +0000 Subject: [PATCH 09/41] feat(server): add modular implementations and typed error policies --- ...ular-implementations-and-error-policies.md | 9 + .../pr-evidence/contract-implementations.png | Bin 0 -> 164220 bytes .../tests/implementations.test.ts | 233 +++++++ .../src/implementations.test.ts | 83 +++ libs/server/README.md | 44 ++ libs/server/docs/implementations.md | 222 +++++++ libs/server/package.json | 3 +- libs/server/src/ErrorMap.test.ts | 121 ++++ libs/server/src/ErrorMap.ts | 166 +++++ .../src/Implementation.consumer.test.ts | 11 + libs/server/src/Implementation.test-d.ts | 153 +++++ libs/server/src/Implementation.test.ts | 199 ++++++ libs/server/src/Implementation.ts | 585 ++++++++++++++++++ libs/server/src/contract.ts | 2 +- libs/server/src/index.ts | 18 + libs/server/tsconfig.build.json | 2 +- libs/server/tsconfig.typecheck.json | 10 + libs/server/type-fixtures/contracts.ts | 30 + libs/server/type-fixtures/handlers/create.ts | 11 + libs/server/type-fixtures/handlers/list.ts | 7 + libs/server/type-fixtures/handlers/remove.ts | 7 + libs/server/type-fixtures/large-consumer.mjs | 176 ++++++ libs/server/type-fixtures/module.ts | 25 + libs/server/type-fixtures/policies.ts | 6 + libs/server/type-fixtures/scope.ts | 14 + libs/server/type-fixtures/server.ts | 6 + libs/server/vitest.config.mts | 12 + websites/docs/app/server/page.tsx | 84 +++ 28 files changed, 2236 insertions(+), 3 deletions(-) create mode 100644 .changeset/modular-implementations-and-error-policies.md create mode 100644 .github/pr-evidence/contract-implementations.png create mode 100644 libs/server-integration-tests/tests/implementations.test.ts create mode 100644 libs/server-openapi/src/implementations.test.ts create mode 100644 libs/server/docs/implementations.md create mode 100644 libs/server/src/ErrorMap.test.ts create mode 100644 libs/server/src/ErrorMap.ts create mode 100644 libs/server/src/Implementation.consumer.test.ts create mode 100644 libs/server/src/Implementation.test-d.ts create mode 100644 libs/server/src/Implementation.test.ts create mode 100644 libs/server/src/Implementation.ts create mode 100644 libs/server/tsconfig.typecheck.json create mode 100644 libs/server/type-fixtures/contracts.ts create mode 100644 libs/server/type-fixtures/handlers/create.ts create mode 100644 libs/server/type-fixtures/handlers/list.ts create mode 100644 libs/server/type-fixtures/handlers/remove.ts create mode 100644 libs/server/type-fixtures/large-consumer.mjs create mode 100644 libs/server/type-fixtures/module.ts create mode 100644 libs/server/type-fixtures/policies.ts create mode 100644 libs/server/type-fixtures/scope.ts create mode 100644 libs/server/type-fixtures/server.ts create mode 100644 libs/server/vitest.config.mts diff --git a/.changeset/modular-implementations-and-error-policies.md b/.changeset/modular-implementations-and-error-policies.md new file mode 100644 index 00000000..2f8176aa --- /dev/null +++ b/.changeset/modular-implementations-and-error-policies.md @@ -0,0 +1,9 @@ +--- +"@cleverbrush/server": minor +--- + +Add immutable, contract-bound implementation scopes and feature-module composition +with complete operation coverage, cross-file handler inference, shared/per-operation +DI, and unchanged HTTP/subscription registration. Add reusable, endpoint-checked +error policies and a standalone handler wrapper. Existing registration APIs and +the browser-safe contract entry point remain supported. diff --git a/.github/pr-evidence/contract-implementations.png b/.github/pr-evidence/contract-implementations.png new file mode 100644 index 0000000000000000000000000000000000000000..433a722fd78537769085528a9067187d43107ead GIT binary patch literal 164220 zcmZ6zWmsHG(>6*%fCPfO2X}XOcXxMpw*bL)aCe!(-6d#n9o*d|xN~^+e)sp|^pCk_ zdR0}|s$SizOYVtKl$U^q#es!@fPj~h6jg?RfXah__#*rD^GDAnOW_Oz1QLXlsF12> z)@e43FPa$c;5~iky*!FA<+ngZl&_ul`e^8ANVJ-Qdm>PxVq#)SH9zt`NB(pzx?k7% zOcnnnA%5Mb+GE3~dDz^=%q5VN^ztR(QEuPd!{VQo<7J`F!&Cax2+ImTUxXCp+lkUw zi!$C3`lzI>N3X5CzsM1ybN=E*NL7dGUYv`$#2#@8& zOO@o{>Lw|7B&6E6S)iUCj0{5I{>O5(8%`n}ZIHZAwc6#1JxG%}T(Dl&*;&rtOno^sb`Vl@t~ zVt1MxZ&k8}#>UZ+k$mTWr2Q;~JXTUdP5lJnsG^GYonAEPgug7SykJu!Jh6DNS@pQC zj>=L|RGLKv&ELAf)loUb`%$EbnLU}xswK$CFwa0eB@8O-9|QlM4N_H5_*c?#krShI zls#~kt%z*_V{VoG3oCPhLkSey#71yS!Tb;uogv28^7`n+yeajAS4y=wG|+$AQ6MQ4Ni-PY_=<9T~0Xr#BVZHw=?#IkAe- zxzUJwbdxEf1oz=|92t)X5JIRZ=7^Mu+=8t{@$k5K~aVKtueH zXoP|(1Rt1kL?o$W?IBV5DT(d9pzT3PV^5hP)#OZx?oTOxGP15mRl2YLpF%d%y-f7< zpRREJ(a5r-2Kt6hoAc=Kw=d*RY3gnYQssK+un{WiV^ajP7?GYy;6f5ZawoxGKouR?jRTk>Y_ zPcKcqwdM$A)tfdIo27xh3d!DKy|n0Wwb9g5qqeY=8&GcK=)KVR8K=L2TEQYem~Nx8 zvnvAwg>-d&#X`OeApRrsV^#Ak6UTH164&U5O0U4X`B4A*?Y<+W6z7hI<5iR~A!~#q zbIHucX0_7fCM=9{(N{ag{ePT!TFRZ!FwZ)gYw?n#yU0-k(K82151m?ji(iy~Z-i}A zq{eg;3BJ%CbN_vL2ubbpWQ_@qGSFPJly!A=)oya7qNE&~WT2#_rKO`IS#jFkBlBg)CryE(OH(2)>A}TYUq1IUeD}cw4^#)fhRm#z6=!4L+BgDN z^PL!(nTrIVf0BP2Tm4tRsV_=KO4#qs!ZI1}iPtpEO={=lNOYFlz$7fzG}VHeSNtx6 zGWjDQwFc=lld&G1Eb^y3XrRD93q;VRFu&ccOlN5M*p{OuS9ZKn7~Q<&(gQVbzL86C zR>-gzeM``+TlICTaS;0d%mHB;yN!bvU4~6I!VFV*JWKtOEp#o0+A2M+Kt)nx3{3f*e5w`csV)(3l8Yx|Ag}@)j40O zFgw?|z`;gIAC>|Fb6V2@osA*sQuSKZimIx*RY;^A{h{QU*4Z(_Gvb?i!!ax9;L5Xk zF)*kTgTlp-T&C|Y=OA0g5vKHK>;Mb#>;@&jnqSB#tf#P*5Uc`

J2H&|7Ybl7T% z>k;Z~Ejt~Wyt{^zlb5|ZPjOG3#s#&So&L$&txnF9`NQZ)oYWrG?auj9G#x-q93;wC zbX6tgUM$>U;VU>SKD`nh%u0IvfhX_pp2U__eqYZ)mP0B#G}Ov&wR4)LXrEyqU}B~5h;3K9W!CMjTOIdGQZ`_$Z=IZpKIOMy-g@*X<+=jX%YL)UwIJIg$;xXy@g zc*!szE6oK^&-l5nB4wwW1PT%<6^+H%cp3q}Ha@SZ-_oYy@GXRtd#tL02DrFzsJT8R zKd^*}g1q>Q$CYVQ-qTbyC_fOO0(Zhh;vI`UtwWo#w=eg8dC&i%Mv8KOy8agCaKIQN zBNk!`{$+4@s=d73=d)pk6N2B~>we}Zn8RW2gNVCLU30MJlRnx7UxZ775pnc(cxbt_ zbll#8<#ye8G`*GqDr^nwy;pp|Eqk5Ojt%<#>8CVng~P>qT)Q{L%fNJJOibCy)Gd#K zSEJMUQZfGQ?&HO-Tic9OpLdOb2+0n^bC}ze<#sqJf9z z#>5zEkp0jaOzk}(`R*=yIu33N_tKNAV}L1K>oX!Mp(sVM#eud?ns-aHqeqho4xsZ- zH4ZKgtEl-M?whW&G>+HD`=!nGm@!XbQfs!<(#mR%DuHI<#bP48JKz~wA#Q$*MMPKG zTTxS1+dQ@_r>Zl?tD64I)h+kZc0KJ^102T%{L$W-p-m4fDzghL(39qiJnqJZVD(?- zMC(m^d>xM~+hJa=hsV6aN;5mF|UcLw4d>gGT`9%i}dgt|JqXZooX zixHrH$zU?Z!;9?fJj#l8W}}OXvqx=dE(HUOx#_`dc?#jT=Qp!g)-F2-lj(uk@sZwN zR=sE#$xjkd)=Nw4Bh7{FIZxi?>{QwMJ*Z(%Z2Mxh9{JVP7VYZtFPFg<_D4t7 zh$pj;-kZTSLl4-A(98-XUXNlF^c%y&G_LM7B{++-onj7zh$TIgwA8Kc2SQ$AT#ZE6 zaFIzKNKC{eBAqY2#?%yi+|6^dHTZG`w}{lGxoho_vN1Np0Nmzty2tJN)2z>4-u+@? zOW0amLOn_p3eVNLZwQUhyAf!k^tz<>FU1N+(Zscy{^x@{?UL^FkETfJbRobyJ~3vl zKwot9nWCcYqN0S8h59OkNza4ICT{NDFq;OoC&@5Kh#aBQ%CU2?!P%+6rVhlcgd910 zYjK2T$j7tF@ig+^f1{dr5?N?vW0o6S!xe@*P@ih@fGq(Y41pq&T}(3zD)Y$p&|+Ug z#eCX$l&VQcXf96YHn$U)tLN!PXh;JtxMtVdW17Qg3YjzI8|3HG*6*`L#6KCWP%B(>#NltWKVb2^qrGT^cQVvITqlKewnTCQ7vF?_|y zt|l`tk0~)&;%ap)Y7LU$8#b8TR$zurz{mgK}*on4t5 z4z)^%ZxdSn#J6Cl!;OKF+D}?ENM<2RupUgxSTby4WL;7EOnTBMo+nJq<;_hl&?c;o6&C%OV;M)#5%>fe`@FeG<33`l}KGA zKL=3~JuZ3k z#lXCPf~aDMmYJ2iQnKU?3;VdOnVE_vm6QVWU^hi&i0-|ja>c~FYkM$CrLcU;ltU61 z0wS4nQF}cmTtRBmsjlAC^s@v)3>pB~!yfKp1{%xeXVBqt?@#*;Z%if7qMiMsiz)cFo6BLko9A9= z6N#LL<6T|yOH38w`4YfSugSSdz;{A`lXtK*nCE)8rj`+(Whm7uRMDLJ`#XQ;<@HwY zxKB}eTT@MKqwV)$PClBrV~1{eJIf9}cB-|xTC3Z~LR4it+VO^l{#~WRdZ%>p$m?zx z`c*$93R*|kD@QXrN-0z>-}(367$1h%vsqTM;OFUYH`4e#Ex7Hrq{Amgy#mn+b}KW1 zR#!KF?F20z<*!v7`C{qkhqe1L;x zNd=G3>!6+RZaU_Cu5g^gphJ{s!9k3G)0O7I{&Pf2rS`JCPi?A)#F8^Z^F_b^!>~N} zz~-kMz8CF_Rlj;+V!i8GFtrS7C^=7a&EfgUQ?H92=w|hstnSOB(K2^l zce??{0-sOt5pcociSF_0%fQh}@xXx$G*ca$v~=nCqKJl(dCB`^=(lLw2=(E=iAq93 zAVlJNpmjhR^79q3%ipyGEN(9iN_V3zVEw%oaB97tl&a7)L3`CBx zW%$0msIIm+J)7ln3%7S;vYG*SJ33P4e7S4x%m=Ztp~2hLUgY*E<~I!Ml!UckH+A{1 zFefT-Z7IMMmE^U_US4;ji@>QN`3Ps&N{iGHEjekrywf7nUE|_c;-Ha*T~1O4*~*`) zIwz@%oS*GVh;y`evH!&a3Q$K!X_lLv&S$#jZu4M>wwS7Av3?`Cs_=$QJgGdLbhh4Y z8WEfQ5P;!saFUXlEFL2Y4AzeVyM#x|439F@H8I}a*-DxGTtUzy<>C(>*6F?m7j5y; zd2xT;b8i*xeZ`~a`1^y+;s8Li+lqYigYlF|PgP&YNl?<%S2|RcxR~AJnVlZ(n+?nA zT01<5lzb36)VmGfL>0YC-DPp$?i!%B&K4nxgM@;PovN#^e?He_B=PIP_4v^1t~WU$ zLD^fba--qw0dy@TWfcs4gTrF%xS_vhrjec5Y`-%Pms(|Jw)Y(yeBb)5klTCCav(HR zOg5X%pNq%{piT34)>Ds zuu-W?m;{+3*TN}#YtS0!n=hhj5qvfaei)jCJA=sA%9KkC_Gl76aR^kr}?*{ z!NT}b?6%P^8JDE~73gMJJKfFl;F$IT_MFEn7^i2yMEs>R86d?4rSZ8Js3WE!-D~!K zt{-DwAWX65aqO+Z;L*ggs^B3@I{Q35gSRM^k?xzPM${~f{A3i(Q$2$n$x(i|k8m=3 zB=bm;Wlv7vD1W;VqfO_lu~S}en(52n5YTj<{<^9m z)+3}CNKSURz-M>caBroSP0#;U#7UqjuV%45n}$#2z+rWCXr!@@5r4TIwOz4zWTaFb zxI48)^5kX|z#lH9Oi2yP@Mjv*H({pkeAP#C{F{l0AErd6JOP~*M~F5(JyWNyGLx65 z0=qVK)eVQ8u0Yk3ovfss%f~U=CC52)^|a&j{45e_saZY22w|;erPlOXGDB;TqF-11+Q#N!q{;<@`SVSxSQ%6H3+fH8ydc%@Z~Qkdf8MSt zeMWXrNb&gws=F)LjN?-T;d3)J9M6^Wct35&z27r~aO-H0qr%{?vU&3jJPZ&ws?N4i zX41>}d3~762KED9{vej$K|>8-U?h{1n`Lw3-aNH;4^R{#o?cW|7RuE=ZbZ=2)0<49 zAR!G;Y+_AyL$>0+b2U2-H8dM6@i0*xtX#y2iWa-D z#F|>9G7D7m`@EXV3JGaxdLHiwIM_WrYtN}`y$nk|()jZd-ZH8XklM6HVb!Wqm1`+j zSq*GYPS`#0T+W~Eo@OPCRV4W2W77oO3HToqc_q70vRg}*x`BIujHJ}uUiO^s*P-4vB1`?uY!2L@9qA;N+5aFDe+Y#c@wMoD1d z$WHOQT`1n8stYC!hNR?ZXs8oJ#Zyk#QoHW%(X4AzlbJT?6;^9$Xc${4y9G0{RsQ}c zuwBc=K48FLg!nlalJVoiw?I!#x;>qdH&96Z6GGAn>moUAB$Kxk}+LkOQz$h{3^{3n0Km7QCuX?+&go-Ds!6 z=3+%KS2MFFNKKL#2?9^BvrgS3Mid|mBXUTT*^=x*;zxH#RaO?ym3^A8&r^cqIl=K} zV*5IXaA$^F61X+(aW1C9Qtr@v2OcV9SC{wSg6Kv7XB8trunjF@5J}KjtStUwoiRTD z#aAT%8CMdMts+kL=+bhJwMc{FDys`cGb1q}_2gZo>Zw-+0o$#Z^# zfVZu_!ps%S5DT`xA*<7{r&wq>)YJbEgg^3XR|ef zV3?b?^Kvosl9KAqXCqx-;}AUZ;`xPp4@CU2FIB=c~d52 zwtBYe(%HmAy}{KqwA6s)myQt+zS|_U9Cg?ZUz#LQL7ch!vqSmip7A^wSrZ{YF7G;^ ziI%D^&ef0DHuwr?(#xa}@xkVrX7a|QHs!F1^@7vmvmGhB;_HPA=VwL46nmA)Dgsy3 zxSV!1b$ye3ez(aT)L|GL+4sg=Lws|=g8#-tJ!BD_<&7tO!+4xG=YHMPcMz_r2b0Q?cS{ez0F>(2I^mj#Z_96o(RsO_+W(A%}b$MhaDh^ia<;UUZ*daK(rhoGICPn>_jG?9 z>ly#Bu+Orz1SRn9?l{0veRs6ybl%$;=^XKX23+S`nI_w~i8D66mUnx;v&F>1Yd2dl z<2I3CIQX{XckLW?WMOW;b?jE!{@9do0FbTx3a8-i)_8nAJF=)52by7^CY5!y-QWF| zU9eNnwt+=~OI6g6qBQ=JKq7w&kLJ+gnd?Fzf~o+RYw z$me@IN_do?7FlOu4CUVuy^v%`R862C6cH1(x8Ac`|^a-Ze8!F#-*W%+NFk18sf!nkIEm zQ{p3LZ~?IZnc-;HHGpaOCXv~|VD9BipFbz`>FJ($2N<(Qh&MMlm!oay8i%)c?Fy_O ztvcc?2so%?{zen481PfPxCIM1uv#)A9nv@ z!~U|mCP9vfj)8IZcEOnW6W<3x7LVtpF`e0DtgEvp z%J(D8GeL)!j4BXte!?*3>2qAs`fmS{ybP^kF<$ulz4IA*7Gg>=I<{#!bZLioAi9H2 z;>^=MM$mdbaY9X3TiVR9S5d&m>xY{j`#FC$Ap1{jtx6W8k2`Bp^TjnB%^yigH|pwm zMPy@4UE3p53v*)Jzg?K=f`Ju`5_;kIVGOfFbUgPXf(oTqR*j8|{)Z@hm9A~Q+sY&& zer>RA1M==EPi^pXQF#PtueJU@xKT`yenTH2tFyiq@XCDwv5Cs^D7PUqq-|hnh1{sL z33dXcWnP+IQ)^36((cchnGq$X;~}p`z?q3@o`fF%F?O9+e?b+7U4yUUPgoS2xF3q0 zI%(MV$JF%&)Rgo@e3oOP2FF`EX+ySuW|&OFrj^yPr&qLNb^K|(1&tXbYx@#or z-Dz03(Ku7dqQ&jVe{UohbiHq<;0s2Jd_=3!l~=KrWR{}!OVHI&Q6-&?4LC?KNJ&Qr zi3kQu;(Zx^SJxH%Xbp^%?mjHsYozv#rkO2ktdes{6f*Egkj@c{ZUU$(u*)wkRPnB#;BDaL*8 zN=w#r<)NIAG|(WONf;@w%zz5(dOQ6WS*E?0{72zkbIaOrzRaJYa*$N7TrKGLJO69$)s+vklw7uIjLm_{L28nMyKq7$WjQEbyTiw<7 zSDUebOwuvWu#dZ6l|MD?3jfSmHC1i5?yYHR(j*4V&45cLhZ%IcuhB3oBb0(=Sqt9~ z;R%$>iMjZq@Zaj1n_4iDb+pyxceGjCl(T=9rRTDej}3{!Xax_B51db|g*CXCyA!zK zYIBU~8uQ_w&6Jfu#K%R$y1p9`HwWaD%?)u;UW4XV8bxSkoQxA@ zdWpAXMrlHCuGAOhBxIg@`dS`#zgwTEpvHFx)wgDZ2&k^J;h+`tw-1E{V|lSV%K<}w znnFF9n66<}e)997&3eaplxp$D!f*CoD~TSf@G(M06E;y3BC4Z5{MpsH2-(TIGDD~` zxBIYtqITa)_|kl)fVwjhRqU}2*s);HZ3W~SAURT`t)1B)`nj;MsIUEizB}uI#Va!A z4UaDA4tQJZE2bl&8XlSH@Ic%!Sa@?g6aVRec@g;Pb5y4NG&)y2P!%vQm;QG?zES~bD0JHXH^wDx}KX3;Q^KT{Z`jcLmGqXRP9Gr(cvLXv!P)+Q}{S5h={eY zHj7Z{!c^5x#f7LRMzBnNSQ59DwlT@^)-EQRmwH4Fv(?N@lJt+~`X{To)W+Dw(#GU^ zd^a2qg4R<@3o%4~12~`ocaw`*>aCG!ZZoh0?|A+Ga3*$e7^E;-*+_Mnbabq~PvI8N z*{;FfH(Fj7#d5lhxaI;Z7sI6^MEgM%gKiB~<}qOy*y(#mkxc0ff}{7H zMUKy`Un6^;0=A&ZZ`L$1qHFlM{T>`qWrq@v&8X9!{0zg#qZ)1HnPo@N?AnlD#cv?B z1!ihnC?ak0Sg`yI1*ax$wui2|tGt&zmokx@TbchSg`SIy`a=zqEK1^hD=l>8bvF|5Hi+djP(U49lA^-Renb|7UluQ1F;; zncq8~V;~`mMnvr#Af>~7+ghWo^|bc1QbX&}5@BG_Z#hEWj?~d~Z=a?p1;BU3-7G>_ zVzxVT5}JW}$DSN^X~X4BjAu(LwM!hhBP5GL78gpBMj-_7We#MYG!74S1U9U8-80J5 z3vexI0bH@(7>QV!|Chbe;gHz>i=;N^vA4I^>*Jh~jAE7Tpl+gkKxOy&B%-XSK{X?Z z82(%0!v?_hg8Fz~Yjh+5TR^#8BlIStyTUhd-H0sUHYthuEwD~uaE2%agLtO@b`B_M zerilXjLcD#$KPt~g{d#9tZS@H?p5ys_l#&T=5O_@@ibnGrfC1>XiF&0#>r{v7MHml zl=+5ynv8JBP;O7aFPr*@B!}g~;jvv#mFqnOxwv>AyH(X+qtQ-BM|};*+p3E?y|8e! zdp2}F1u9e#HH98XOwpg}?a7)mSZ-)CpNq-h8p9-^t`2%x^TS)!9VZyv4GA@)eSBf& zOV>ZETyCnxVp<(vm2DoO7g=4OP4N5Xc5dspZ;OJjqfZV>XOZ3WP08@6{?VNUPf<)l z-W9$EDlY#7!rg6dm~yIF@WB#EXdq>4TMpVTg-CJkGyCW>y47 z*$y~TEH~;B{Y_sB$Vry5TSBliW&5Uw;I^e%uLhH;-KDTJILGvZG%_@k5*mlq9YYuX z98k;1Aum5_{OZnbe#*MZq9Nky+E9G;l!QY}-@!zw9)uif55qQns30K|rOmkNhz-{W z_0Ho@*9}bL7O2b`2f_)BXK3%Bwb(3c$21(SZGP&skoVDVs!FlICFzqU+nZ$wSggI@ zOhXP1LpbNLzo`ky^&3^~+yu+jFHFxdu`xaR?ab$P8;lG=0S-zhBjOY?Sp7{U7$)xs z?ARR=sW8DfOq((MAB*>?`0B-XXU@vc$8D!cTW3_8z((EA?_u$1MabhGpS#Qbb)T?H zi`gEmxc7yVhsXZ?xf#>Eqq4ZT({AS&TA2gu@${SWc%<~mLoRdY^N(1Zzo&UmBmx7l zlI82KMoNEE?L)LOaN9W-IhVBw+OZT*YE}0^m_iA&&5S5jQoHP`hxj3mNayT zW>5B29Y4{Je14>3p14v_xoqq%KIbrUWP-QZ6(8Pk#D`ECdno@UoNZOOwMZ7=xU)5H zJiA^GE~iM2%w5*b*Va&wurQoNcoBpb`0?~LIgZhoO^o9sT{^X-L;9SMBU#MH$*ZpS zy;AQ?%8`naI^S95!U>*&Z2C=!X&C?HYM8}nu{}N~eMgrKN9e)L+Qh=l{cTV$q2PgM z!P+JNo40qHm~&!PLj`Y$R12)*MiYzY3?Tz%3Bmj+vVLW7hI_rid>1Z#t8eG_Hro+h z`dI$ntdy+@S^d7@Jr#|~OEBreD-ERs-I!P(wDl+kwi;n+p{!lF!{E z$>Tvi!?fKZOu1Hu(1ZY`KkJj5G7tbte21?Uq zW#Lp}YM{z=b}AK6K6va1207%^ZE5*%6miD5I!Xp5q^7)CUG>B97pGR!fw;L9lfhUq zXjgK5bnXcbXP)^Y(kCq}BJ=qrNhBGdU%twy(SBvt}B$)uJ&A z8}k?q?Kbx}K<#kvMYlvKw_C|zsBLhXo=Z}w7A4>#8mFFDsYVC)mWg#V``~VDZEh`Y zFH+Ifv%PQYGa$gr$s4-d^^qc4N=V93(^eN30f5UA;gzMZ*{gv&Xvm48Qp%XqslfhN21`MuSAt9&@q7qI zc4m7El~KZ*AQ#LH@3UmYb-$R8at)0Mpz#7KpVxlD^XW*V@MKo|%kd57VxfALUTy>1ssESu%&2-5WoPS;C>zf#DdhtJuD!9ft%(_x z8L6%D$jC@sHn)TY>11Q(r#|RgANy@fSVAtRr-9K0HCVjp)!3cQs&1@wDU;x@7PPAN z4jVCTt|#m9`s=6d$pmxd&3#%ffB$$zVtX~GAXs$k3{M<$aIhi3M%6NNq;rnN0a9V? z>pHnDVQ@6vJ!)+j9K7uWe7Qad?W#2sxkh_J(91<-lj&HGzVh@2vh zWJ!dB^#k*#S&_Woje2i?!+-;Q8%m=URMiHCChAQD&hLx&A0W)H`h03hUhi59e;E9zgoM2gLB7l=U4NgPn1fI5XYL-9qN`FL~rN!OVh))92 z&%BFz7Oc&APVo5}I+m?Neo0lWRB&F!fp6NUR(vl_z`^vtXnV~Box=7Zhz2{UnH9Z{P7U8#_ ze^gJ9QKX9g*`KbhTkM~s0zDC#i?X?*0$P}}a`)qXS~2O(YPS6SF^Y?o?}Q6XqNFB% z5S7%_5Hr>OTH9FG{Bi;SF*upFoauc&a+t?uX z_BH^6cyO>Mm8e3qy*;|7&2F`a__Or8^@u>U44*Im@A4QKSG>;rt3|KwjH#}e>sq*G zE6w0RtHhbQ;69Ma)JUlaP06R4X7+Z%Y*A?#n|XQkBKg|4tyLtgTLfooZ}lU2$He)Xv4q92oi&xaW5vl%-#Y*t@v0oYU!9EYV!W)!J(F z_7Vo)&{&(n?{?)7U`tIySKr*c*5Rk%@4uC`U|`fd<6}1#-eWOo@aR2I-KEE)t)r!E zv>0&M65HhN+202lCSTJYgT-t(cYG_;rOjk9PlK(c#dAkc!K+J}@wENxHo&gAx!z{W zG~gq9{EmRPa<@?Z^z`JiuEXoTi-aP#jhcXxkYM0%RUkNmtGaB+#KClRHuYrg*xwDq zFe1Ao=DLvx9GxB(neXw;Doq0j$Z-S_e0WV32k27|jJK;mN@be#NG(xWX7uUJXQoDe zvs3THqR*a9_CnbOy#?EMS85JG%j|A?Ti%T#Bh(DisM? z<2K2YuKb+yv#GGBHg0;hR20QWUU#dD`G?2&WDTUucyY4`bY_B5@9NtUf#^glK2_Bg zD}?zJa#F{Stq>NEn|oPe;?cwMM3{(_u~wL%u;hPxp%tZS*!6R~>w@IK5YBTttxEJd3}6{Q>9~{-AeMgz6o)F(Cqwb>{(_6*~PoQl89RgC)fyq$JIv zU}5yC3$vkK&GylB?+{P6=gRbHtnUbwz ziI;l&=E7Kq1U3AoH$O{+{NnPs4rvhYT zgg@P*c-&O5{tS;!5gm|(xt~K(5-f%K zq^X@DDn>DCOW2=$tq6U0;dwb!nU&RBopOOEFwell^B$Iqh=!5k?Zy4xbnI3p+y2<1 zlZI<{fQHYFBIsZ+gZXq{sjF9_Q0<;tC8}uK{o-ysIO^x-*69C!?dxh=lAgZBAkgt! zRm+7^E3yvKX$*4%kB~D@PS^G>INWs}rO1V%v;q7wQs~))E+1QRYV`M8D;!47-H~;` zlPoPJVy&OWVgQV(&HIykBOyy$azsRxsJ5AmaRmt`=_0z67Zo5^X(=+9&%xJsxOrnV zg^l=@{n&^oGv^az#gapRLS~v~7C^u0sx)ogk5(Q}AywnK06~9{oLpOv8`oh4Ag-`I zXXDk@wmp9i{U_FSmVKsh1-+zV5pXNX`}*QIuzjpoG@=(RA)ttW^DS4iW-8I z8oW{BR93$b#IV{TQ{BhUpOe9`Cq@^V-^sHU70%-)*2Lc`K~q|#Z!g;?XlHL-xOgp2 zYHK$Jq_A+PoW_ERA=Gbo$sJ5;d0c_-x$M$A=MOK&FnZ`Cy-Tdk=F>hN(%>`fj+fwu za^nYy$v=)Y?O1(@Uap{^U&o&7E*F}Mgt%G9p6)(LFBf9f7oFp@A_T9S9qc2q`ikP~ z;ap~MSt(Xm5xn&Pz<8zdl3`5~%@<-ISuD1z0%Mg4eR%WKa22lwZ&xb`VS$Jrtm?AQ zqJI{==AQoSUMuiFoR$-scRU6d@5l*7%y)Q$ z+{c*)D%5leIf}`YlzryD$Z)Ks1qDl_%ya%{>45)jlnPh(N1Ogf>OfoZ%1o0ud1gp8 z>e|-F5U@y|zL3Gj9d@G@y`qAf;bbgFFfmX=7Fl`A;u+UY7awRQy9LH&0x#fCH`mwZ zFAr;}UV-3TmjrJ5$#6gkek6v1d@;V%sHs`V6bA5s5YnNRT~{0ng862a;#_f2DGT0! z>-8i+C#&xWcxz`a@~P@kY#^2$qifyHwZTS~Pf;ssCdP8tH}4HsYOwFg)!nH9LozMY zY2JHQ>V~K?tUElotBT%@*=jfa3|=`bQu>+fol(U^ggPs`{02GMtkIunEo;{>WSwN~ z=@R(m7;;5NhuMvSRryYhWCYebH_F5__5;o3tDWt7Q#>ZmMHE z-`S&@A}m~3UF_*bw^4w6`a@Vga=CO^y59bhn(ccU;C&7mh{4_s64YQ)x=?` zyN=WQT2s$%((U&8ps6*~1)H6de6Y}JXDR9{YFo!iUu-a^Q9e3KrrJc-p|G5pj-{0` z*R7<+M@&r*GQ>&fB{pB%s2k8avlHX<9XMO15uioEQg(U_eL2DPH%8&te59fk_C8Y= zlg>!Gx~|k{gue+HnNL3P5O{Sq@$VWd5GUO>cMpe#KfHP@0JXJo7kP9vZ+gHUE%jZ8 zIhdQ7?{&XT9D`LKKTE37SjIn3zx*{3SGSH4sN}D^$P>VgYfL_xpmSN`4(|^U%RTSF zM(P_UG+Ma8V*Twh9Y*qTR($sy4nR9!ncF*I7_3!NI%71S$!#bM46G`z7kdbHEpe`@ zumn@ad8{8|V$Oeo152yKAU@##RAsGffnz1!UCJx|~@@bQ zAFrpjDmtH;(YBA42Mi~0*|oIL4FWPVQW+}ONuz{M7xdoeuwS~ulAbAy`nluzA%GDL zR@J-UB1$^Cm5%q%@MG?F8$Y1Q^CA*ca(b4uvbbFU;KbRmCeRD}Nd4f4Yh?uZ%R&xs zD(HurnIylw_fhm_M=Oh+$Mh_}o|i+{9*s6;EE8d`EzJ4QlM z%G}^MKoy$@mqj_l`8vu3MfvmjNY}0W4%w|`u$HE-_nCXkN4T0TH(|CO{^l0XlO2cE zwck%rLqn%sBDLws8;AaBWr_v`Xivn^0u`43>3Vr|c>$8tLzwywAE2$JdUH8{{uBo~9!~4<8?#X1Ur%&S*lBA#@L5EYT(Qb#= zRZ*kcJ}X8s=Jo@66ut0zb+;@Ko73)DU7>5vJJY2XrNsj6abL;Kdc4v6`X=(}v<-z+ z-_aat_tE-jH=s$E-;3$`+VB7fsWAMCkY{f_O?(9S}J0W93+^7*tyyychr`?G0Z5X?$>8WZWl)r1AuT3p3 zsmZ~i<6%d={jTU&h=zY_i3>&I0r^VZF*K8TLr81L9e_j&1gdL{!^d;=dBTptGLp8g zPEMYuh_b!MA8U7MZ)s57-OSrtR_<=hY|1s@qy0b)K){L)l1mH}E2|x7r8b`TsE8OV zk4!nK{E5b6u5p-5Yk4?pNA&h?u-^jzAe{X`O(A7GV_8bK!(&fbX;-R=_CUah}}mNt*x z&GVXTp2n;#P%sig`8WG^Qi3%_7119a=Iu?goJKx^yCYC`d1xZ}_&Bo79nIr}nB5k5 zJ0U1Sg8oETxkst#2$6@P>1Zh|7P6cBJ`vH_kH6C5dIoVFW090-L0|Fi^L&=q4!**j zYCh1&rLSqUx(s2-fWks|;56*{Yxz3}l9dWYr7kw>o`Y%TV!9Q-{kPpL5k>V6BC)$i zb{ZEG8o0#JXEbepBPT~sTYaJY5D-%U2#_g+tkwF6wwRx7gOAzo#f*U$L*ZDHl*Gt! zA!!e#9v=oKoXLrl!GeSYI8fBaHESY@Jdfjk#e)C~AaVW!gc2l)2V_goDcIx~XQrf= z7gi3?59&(fzy}5wS46j>61N^32w|@EX_VKeYQp4#J#l{i{v`Mc8Tc_pCy4s%4>qS z_^gm0mr6py0jhadU;bgrvr;5N2@dXOL5lANV#oxJO#_C272xoqq@2{6=gOKMI8qj+)mB5eUgjOWY{%3yDQJ0xinv zUy4gpL!BMs@zizT9_q(A7JB(Rgd7yI!x=G1vjjWpuo;6|@?Sz60Bma;k-DxoRNO`GWK=WVJFvQeX$-NVMNv~sQRrsmspC44ZqHfQKTab>B0lj>5bo3npK2~+A^c)HK0KiNf5v~`MgskTE zF9SqewCr%a`U!Tyh!}@;LtjWNCe@3^E!W!UMquAl=0d(i` z1ZqWzL06;gDZT>9@6?aMw=77UKXH;Sx*AH*lsbc{w?w2)k(|WjC7Nopwt}#etzm=J zc>cXFLnXdRoqjm-YW6<%>hiW&<)&_}#%f71)v_c6@#HL`px(dV3nPB_sHU)s6^jU6 zBSj6&WrFj@H^gD$2Ze}s>q?W|WXo+iD6{4`Eu&seFrtIT@*Qz3@g`}h9sJ~8Ws30V zx80GbqVS2uD}x5@%be)_PyfAdh{+$;+<~w?Wly+fM8IPQh&NB9&YV)wOBx+?VW-$yrxob}WbbYeGuBV(iO0YqgJW#h1R zg}wY<(6-1JS%Np0AR$*Qf`2SuN>>w;$g)UyYKqPtzlCeBddq7gO4iF7Xpx~k2a}8w z)?jYgs1Y;RV`)hDFQ)f*eKff`dSe-GblV)q$5wJnsSt+($}KLSwPQRsLvXVItJ5#R z%0yC+;C=6_9PR-UDjobnyo@f8-cmNu7VUk$G|vxDGQmh;`QiT01pTytH_{TSMI3rJ zkE9k0p0<^bgmr_|>$M;NI7V#4;RVfv3WvANTDi2VSG6m#P{A_8sF;C>uCMzM=KHdt zuT>!Wz{HM>Zdnbz*BYtyBk;tH78PV6Q~du(7pyP-|H%64xTv?SZ%R@^Qb0hYK|pD# zp+mYGq`SLCN|2P2F6r(D2?6QuPU+5JX5JsibI!f@efWb93bSMFwO4#s>~dcg0w+<| zr<^m(ANI@b-aK-SmHd@rEuu2lwjzVoo7O8HDMU03Nx@2w|7mjW^!$MI-@n3h!{mIkq4L@QAb$Dd-4O7zP@`tr2OaD zve1>tb_y!VxT~7UI2vYgII!VIIYgSjF1J7Jl&D_%9?MD@fXV%wMA4o5DhKRJ)$2AN?s;hdYhPZKo@o zlP(Pm2szg#B?<%v^bT8GYoSnlP4Sy|j`EHo*Y6JvMrPy%wz=aee%RQ52@Yq9rC zj)iH-UEJG>*N9m{dYoAKT)zU9V4e6^_fOF2{vy2xp`sl&2Bz0+vs(!2K60T3(sxV= z2Q@4SQ4Fm7`bj3BLqHvKbAY4M%cll%DtB?~Nw4ZZPAdu&ha1>_;s^(Fbbv39#KJrj z&APZ^GAle*4khmAs4qT-N)U?H$!QpptE?&FaNbrijVdVJ{#qr5BOKmI;D7&F3IY^4 zW>NpS4lgC0r8mY!o?jvbcp)LNnfjL*g}$#P<_uhUkY;+NMiFZo|2U3ix;rMLIq#iQ!o_j##d&{J%N1Nh|c@^%>7P9Q{Rq{tMYM1QdU| z1h*GH{)UE>O~}Z|`(Mw$wY}%^6BQNBHxzo1qx1_t?|xNT9iocm&uw}@>GxoBPf->^ z!16=f=AQJmKMrU^^5HYZ8I@m8^zAdyh6a&;8xtyi_P}+ARMY_ENscmc6!h7~ZlTJZ zq3GOgWJH8jWPqrSrz7S%2imBi(wwSBn`oY!X7o#FK2C?`YjxO9yx0M0`d3$zI=6fv zzx&{5g0PIy%iI(xig*4`B7~u0k;Q4J*)AX{%JpvZr_$Hedo$} z_++%rLPIf}pojE`(2Ear*_85Z`4 z@EokrfX*Y!i7ol$#Kv zUG`2ag_UifP&-1@!xL*giUwT(CuEWq=o*mo(z%fRHSXBoMvF&c(E-pPWroLM&6Mm1 z`zP9;vKNqdwNJ3{Vz|i75isD;Q7d!@=?q?t6yXrbd~*t6Nc#Mp-uKU}{J2I8xipDZ zU&QWT6(uM3h?QCrVaIg}3n+ImwSES=8E8=?Vm*nBK1FEI{SX{4&5XAz^|N;&qN%=L z=*#%CFD_yc&#xH&j1?UuHV{9aDW^k~CLt!FtwyT8a{i2DeQx6VK6w_7N zDO5Xw6C#T?kdHSm4E&M(6bVD|#Ns@84xIr{r#LT{*^M3FGWQ=tFn}SBZ9I4aJ*+m^ z?Vb66Qb!yr9F9bsNS^u{JtNDeAOEKq_#;Gqgsy$$1BTc)<9XVN&9BT6Ra5><&q4lH zeBw~KsKhSVPmL9q1f|e`+|(Bn(@bg_hX?FRinu@mtlFC@jnIqr~>J@U)m8*;ovK3N0*T;-4TX ziDZkVF~ZZUVzS}>GrNaK55Dw;3{BZ3^+Wsjg(w;htkXh%k@X^l0K|`yqIj->Qp|V+ zZ?%sil*IoCoKtGF!6Xtkf_h%gl!GyzA9#{_hIn5*-oSA@Cn+X1Ricg{ zA9x`t+fzKOaZ{*Mm4?_tkeo0#N_BTQRqQcTdW}yEc}AqZ1go+|)|}ygZR6h^J-qF9 z6^lq(s7A`(?Hi~$`FWduItq~#jEJx~!lx!15S$2Q6Jtj6rz#gLg%Bs+MrPv(KLj*9; z6_A6&qan$x&vb-V{`^%IgJCw4bs@Xe!YLdF8Q=kgh{ye6SQ_m@FN#f6-L^aJ#s)q7 z^9_b~Mr!>9or!uNHQpZ`31JNN118p3CH<@&0_FP81@e3&-~PX6=O7Me{C3JO%?BCC z$USEyO$h>w^DHJb5*)c&9jKsbb#RI`kr>XOll_Mz+}e%hnlp+OuKscxNLj*E(gA=n(aK~PO|gARt$QO z>ts#no(gV0#{RL1h=DbxNIz?VPC0O8CRK&?`j5tiv#?s~|LQW9G_10|X!_$bA_wPK zGLizaD|%Hk&i}`R3XHnjSaruwg{U3}dpT9CRai=F*!gE&LU=(nYac%Jz^A6gU)nuV5rzcWuSXdB4mc)-{;KMpbu$@TO*%Ok7=OE;KrLN0wZ2zg+Pe^5DlEW( zqr>2h%X+I=aBhW*^`Bz^egbKAAnbE7gkp#x2(eJj?4d6wYX`le?64K@AmI+9YuF{lmlS6F|oqbCz6kPDI_H1QT%6qx_z=Q$mNHK zh#2fJ0*wBLRZ?E20gZwNK8r3ls5U~y5s4kMV8OQpkECa;LvI^Ee+xqT@B4}>c^ikR zA>qLU7l}Nx26q+Vbd;|vQ;ZSx1m(|waySVYGKDFNaG=fac4j+R20Ci0YsMYqvm zy(<`lh-Ha(8)2*m;Hg4|cqTzV)Lo5T;2;02Wad-gvxgw`#C14@7cR8IlOlO95&oCr z!XOaRM_P>6JVL%Xx@SeD^wXYz!~WOjh47F796;;i2(^XwDS^>HGd@nuMMm_I7GSi$ zKIBOGAcr2XqyS(xe|?Q1t-t2^#;Ehuup9I7v=M;QhJQxrrDmr#BOK3Z{QvP@B=N}V zz^Wu!7eI`cz})+I!Qrw^iCf?%oc}(h$L3OB8BnMipP~TsQa!H9hGX384;B89V{uA1 z0o4W}EA}sP;9GG+6-FvXMC~k+1^?$xcX{_bo z^Duu7)Lb}%VA>5vA67FS$QT(JACTpxM*BBJULlME_QBg|;RAUHP%hq&=W$e+92Q0! z3Y1BcUOZTDomm|C9d^jcLf(2VynyjhZr%B;w`v$91HCFR-3f++ySj3&mqV(d-QHYY zp0%cbkvoO7at&@60ibk#aJADC4ofCg-zcL^o8JMJ!E)gZ`^;6L*Jyy9;L282HHZDl zd_LudeOifyqWf@Ws*cxHc8BRIOuNAN4yBqhBm}u#&y;wjzAm*b-S%Pt<=-=J#}LAk zOod+y%Td%gS6dHpzIy?3T|XEFO-+xl*OT*k>KkU>3mEG~7vH?l7RWfG z3Kp~qK7bOaVZ?ZfCHG$1*?wzQPO?FMq74zQKsZd8VW57=2z>RW2bMQTmK#LUve!#1e2$!8hFT9K7xFl)&w`+Ix0 zyLWQj-b3FHp2|RTt6-H&zuAfXEkj*R!>-I|bS@%+lMW@!{e;iy_gu1fHnxjPoo|bW z0y!whz#e2r!L>sebxovjs9om;fl?JXIh`Y4ozz)$F3uzp7L4j?xA<9Gc$lQlFoSQ7 zq4y;!k&#cEjB|}QxgjmP3z3VCXJJ4Q({E(COx|BhQ}N5qev@w3MjiJqen4XZe=YD$ z!U2?bVPV;)bv2zmH=#tvP$^cU!BDq))_y_QKQ{zZv&M>;N+(midiRIYfEsME6Ud!D zwkt=xzaP#x%PEhN7dFgpMr`wr_`ts38w{yeSGRfpaDr6wTIz6St;O)L>;<3GX@h~! z!{SM*d`4S*Z1T}$-sWWz?fC_x0K4^IeVh9y(LEez_DOj%fl#b{fD9kKeDv4;60Cqo z(RvheNLXXFF$0(@BvacX({*vPd(KI~)s@d^($v-M(&hlJLB{gJasxY^gG2MxwEzl{ zFI0d?^t8?4ez6Ajd-cHY_gFg_DQw|NryaKE?uN2I1HJAun@lMQXDpc=uvEE@^X`U? zw7|gp%mQ(kqrZl~$Vl;euaoQneHBs$qXX{O?K@zW79K$Zx~5Y&!~_?^;j8r8*Au^W z<)f~@B$cmiyz_Z@4Y7rRlgO8w&o}QZuR=QN56vJ+6?c;qS1^#lW&1$M%bUPpgJV9I zuZ!_99!@~;_&XBh_6XNkK;W2uplzFJ7TSJha80-E>?r+fETC-_cFV-IB|j!`kAd3S zayP1WI34@IaWVXa8nKE`x9ypbzrX!F*i>LS>@i6gi&Jgr_0#|f)z6UyS>uF zLe0wC17o$H=Tq}CK$Qh#H=4rh?k;@GYQ&kf<0mt*D7w^E_gouFR5Xd;X#+)v$(C)b zgh&2A$2IzC5N>R%6Q5wL7KbzE+Q!OCgv?dKj?fW$&dGJ!A2yI-vbwTNpzON0FITRz z&{=a7Q52W{;^?_&g;Q@ThVq0-rfy_J6y$97>QE5tx}Lp2?)u#3VsN2jUZL>RSjByM z09@%8zTOtyZZaLYOBbcx;dLi@(qU<0AqC=osA1m%`uNcAPscGDS{pAH6xhqm0@>zM zH~#fUw%a>w*7x|lL72%GD|AZO#&nUS^8Q}U%{DJfOiwqnV`4?Y9ajs3K;iU`h*XqP zJGv8aheFl3b+viqy$!ocSV6nTJ6-+LadrN7JAJasgV)O_2H*J2hWdrIwW}-UUI@DF zEKjqp>}rNOg5}-5vEUv#+qT`M^zKe=qF?Pu6nSVxZ-kE7`zO z;{RZDmqgLh%ric!(+~)|bB~USiW)#9U`yU;^4Jb({>0%t68fvi^1G{2b)!C%cFqzw`FrP?+9

Iy$va_4>_jCAmo`u);fM^U>4`tMn;%bGlGH*h79< z8D!ks9_#tlEAfo4DbT$>XLAMrfG85)!V{en*6ihDkVj!m7q_`wUg?L;f-eyFS$OoN ztJPRLJw66qaZk^?6p#rcvgt{Ehrgp!Wx;7}M1)_rLDpi`MF$m721)|j$@{XJ%HxI< zY_s3$z1P6TgjOWhe6zah>gq!8u!K=jGcXd^Z^1h1=6y|J%FL#pdAC7F(LR{JJGc$9 zUutDy?O5xtVrLcPj{4G6TYK2y?@t#QcztIx|DKEV1Sxdi!dm6J{LYzuj~0KTC~$X) z+r09Q%ki*MojH9I_iG2(DLX2PEBHAnaXYwU)Uv^v+pa_Kf@Z<_=$?5g06%)bdze*f z^)*CFU4*ce9WYqRUn=o0L0vGeZL}uqoF(6j!d8}7V>6?sn3`YV8R!03Q*>)^U-8I` zY#}|`oNU^RY71SgbIk29drOG)w@GWu!h$Fi2iW^rXq^?J#5BW=)juI0$S;xf}?=Mt~Q_HOvt<4tE734%d0Ch+0-HAYLQ=MA3t30UKYhk zhkc0lJ-E`iO=2i6@@M)Uw-_ozM`~wca{JIT{+&v(A=$5&hE}h|lTUM{jqdycqtOFs zJ!7rRjdU(dv)t?z*W9VEaiCsqlclhWb*Q9&w5Xm@k|ji$u}d4VB|;lTHiE3*k=ON! z>dmdbl^3$-{neiQJ~FADwe2v8AT>?FO7!Oq3LxVfBh@e3?bt@D4~rbQ_pjdRpN}pL z#HmVwfFj@Gv@{SL7>3k;Zsj^L2z!H0+BsehEg|56-7H` zwX-vE6YWpv!^UFfsD2|Z8L5IYYTjw2Mu8KBt!3jb>c0*S$a)=)!x6B;GoCVXei%1C z7$9lZC0WvG_HaK%MMwJ*6;=>+Q}*$t+vI6BB#+aUUYVUu6Lb}>m-eD*ZlT`IxH~Rx zvfq@h7{^w-$qC$8>+qfYwKO$jMS3O|l=yDXWV!nM91voH{(JXrr=K@Aa1)yP?wN<= zo;ZC}LM*YX1XrqvpjK%PW#~z^NVs-J_sK(l5?^cbfd?u^dw$YMCmbpoZN|-IhDK#% zgSI((dT48l?$=PW^U8kaOX`%IA8KnG9qa18nvZELe!>}|@Gbk*P9u_^SH#vi9%;06 zLY=(0XYe^VHPgH0hV1TS?JUOoW+ zHM;0K?Tp|o*#44XV#OSrUha35gB&;wh$qM){ZFB7{EM}2&f6!yZe*x&1LnS~>8ae0 zu7)0DmhiuS$7SkosWo5PAgFz{*!%HE%Xhm*9=@pO6PeKX&2ehF>1-C7{fVKD{Q;aJ z#UVz6NFQ|cFZ*6@EMl*oRj0i!C9V*rmQM=--wuD{y&E?& z-g+Xv?E9=e`r-7rJsk$VxiJg`e=Y9}NlHkd0J$1YOud7;ew`s4fzSsY|0DrIJ# z%e6ACOC*H3(gLzT@L z=@?aYMG+5cR z7!-3}y7s(Deo4p=N(@|qc~e@f7w>)|N0A6hX-_W6Qyb7^yJJ&a@16ka=`21m5pr>& z&sC|QFwck!n7#9vsnBH^0Zp!q=>zDx0d26R=C>*+72QZeQj&_4ogWn1O?L-&*fW9H zn1B1mW$Gizs!*l*`l~O&Rk_G9!|n8TAaDGQQj-0H?~L7C*8-JdhZiKD%qFYCXB#!x z!-v=1WLGz>#fAA5W6GCZu-ZYpewEirfH4hC9=c?aY>kN5T#UXNx5ea)z>*+P=Q?C? zIZfeji-CqY`-WVCOQ%3NAV)_x88+@{(+@}`WbEIf+ro)3cM<&aApfiZpUK(TP4o$h zbJn#9K~+^QdvG-7_fOwhU<6%7L$4nmT7FIL$fj^f%Di^7-{Wr z!SD}U1JgQ19P8;Mc@+558JI_mX^vZ!@KAS=Io2jG&w5Auy{-`FmMW-*eo8-!^XW-B zqI);F%hA$$PZ0*1Gy}d!o4T9f;IB=I(#4ktbs?b7By4sIm7Nf~dz4^R<|hL`CDLJK zeAn#N1T^-Mo__Up3F3e)Z8z<%NvviS9GK1wc3vz;oT6~E-}XA(^1Kctd$4}IV5{&F zo)ne|W)*4nOQSVJ<(Qdo+7uL4orx+y5k>e2`LZN=FQNkipfaP8%crCA%|S&qE8ccp z^yt|SKz+?CTUTe-3=X>>RcUD@`I>W`L=oT{DQUjV-D%uM2S{fu7gqK4k#^rLwr)9}EeL4WHxkz+Nja4p0~ zS^_j#Q=2otpOSv~G?f=OTg0BUffq;YDeUF9LGOB3fn#T7X+EP|O%E1pz=3*HYj^?B2z}O~j!3 zSWy&*)eh7a3TZY;N5?&slObgu>soKu4HC@g6xMol%e zX?~hOb1IU2J9v2|%=SbXmly42?b8a-{s!g1hmC*={VVIFcHA6W8PyWcW;NkCyHn+P zhHih7%+ASDt=EKi=hE~)SU}_Yu^r14<;h(8GHFG-i_L2OTdLw{uahzj?$Wz*z%nHJ?g~#X`URAba#tA4H}CV2Fpk=p8bVKcGxuB`{cgJS z`-(ay32ch*Y2GPY-)ZkESj6shE95iJ=es;N z0J4}+<9oL-zK#8RF;F!cvIzUVadd@hz8e}rA#iyM^LthhN|7k!VE=X3U{A&JG$U|kcB ziYgdUtrzx_j^glsw;{|p^b7+xFRd-R>n4^$FiRm?Kxamg_+YVwbo+bBm&wnRkR%o_ z`_+1oP3i0ZqnDH%rJHuVi3W(?b8v8&kRbQ0mTqd4U)@q}nQwBxd9!A};eDL2f2U<7 zy{+z``|?3(L1ht?tog@7VAH#|+SBDb4_VJx5(aEuB9rC4jSpR8ILy1&YG%}a{4f05_RCm=Yvv}P>_xR)QD%KEU^A9TfwUXW|&uP%!W zLGX*ddOTZk>AE9)!IhZUPw^iN^t6EUK_YSM*=rvBS4y6|aQn~xLh@7-%py){Nk^7B zx3K>S6#>xmB-sey+rj7S;}LIF+#Av;2U+wGjEd zWmP3L?F0Hp>iz|n!+zcWaj~XI2kOW{K^M*hc}|VZoIL;86o9Ei>3;VC(pd`*0HAAQ zM5zAV@Z<0Dcg^7}&H=joGX#@rtPl3g+Q^NYaf8Hdw|gN~==UySxD@_> zhl@Rb%^B}s{eMY>4eaOjV=k4*=P8Tce_}y@kr9S>1L&lHAMhzSx<_dL3%0Ytad?u_$Ln#Heavm`Xo{}8JhgngfpyJ5#D7@}ph;>Lg|)*+Gk5@x z#1m0fp$z#iIsw0pqWA+i1+7^r{0qH4!tD%6@L9irq&*JGj5BxSzg^_Vg~`pB0tW!Z zs}$|&XT2V9Mp(<(Tvf0%8jw*|#s8NwEB%kF;lKcl`xKl9-gqUo#aI6miA42Rel-3c zcNa8}g8!cwgKne3(&IEhs7>y(`9nJVe@J2%=lV!)VBkL-AU2?5EqX_HuwK#G>E1;4 zZzSy2I3y`vs>b>Iwkd8H(q>g;Kq4X4jL~c6p62H2r;_i)JlHY+VzaDaxG@vOLWO^D z{i_2)e03Aku!smC>5}>FQ%}+-VL?TOG5OzB=jJT-_Oj~`8}6EMfmZ{tS8TG-0=QBB zP-oG>PC6`T3e(v+HYy5rUm{mnOODviuqYu>T}eO63AKT^x|2$pfc3y_NaftY8gU{ao_G07zs4nvawr(#eHGMgc3P_Sq$q_j?{xFXM$01zV zPwznpJV~Pc&}k!K_F9`9m$1qj7WS>NCwixy(I;Mt+NrXxzN-F13TWzUeO>+2=+Dwp z@~+hlYIDtN>3iylJMr(h?N`8Wu7oY%Y$>5 zLr+FbG6>(x4EA=MuYjHP$ptHkCXpIR39Ech-mZ@5v&z3%pRZSQv}6FmNKv4AektVT zW|1PDAIK95PM+DJUccb?T(|nM^)^tanTMF=@PwohI<@3N-)s^+r zrWq0}nWMTjjAmUIZf;m!L&jNbxgk;2^Nn0A5Bksu?zCiyp3artg$Z2+$xzFT()mUz zMqX&02JQU3CfhI!$o5nKe5^GsF-gf5XB6z2)iN0r8Rtn5bpB!`mGxk6=3E4F*!@oS zB9wP=_94)~-*jSi5i7090g}LAOyFiQ+glbKNJcf9HZBSt(W*SWO&(O~#Wp8-D#Jcm z$CUUct4d1hJmaw#}ysN95$5Fzs!_lY=Td3~U zy9==YSA44{c_%_dsq^K^Du{O(9pFP>3A=3oZ)rMhn|~iF16_9B8W{f3^L@&#OlKs8OE@mBmzMfS(1Gpu zF(kfLmQSa|-K!bY2(dG{K41Ryxn_h}} z&OD2(owc)z4iWRt%t@(5?MTf&TLnwR~gs&LvK?_AP&J@Heg{cRWB z_ZE&|Z34c7<=yMg#>x0~Mm-#LnPv%-=ik|2;i;JUN*!l(XzcIpSKooGqzurX(c9o3 z6k50x$e4{yJ`tJKGnyjdz7#Wf zJ-y1jPzMY0|4>*HN0#0eZJ;5+K9!II$X=}UMhEWK)mfGOgWZt827N>3R4W0pJlOA| zFW5OoWMnqx3aN$1tq2XNEK7C4qKh-k47tA@!8V<#`>(RWK&Xm=G4JhJn9HF4H=d1P zwC=lDk6K%Cjo6gLYzNo*CQs4^s5>7|Yhhud_birRI)4I{hSnRYJLQ|TH&*1Ba&~q= zjKiIX#h~gk5HPS+1tk&a)X;vec8y1c->h^O?Cl0A1xjEa-5g}KwN;PSAZLyi`=bwUp7~n?uzdb4VU(Do%o@E zi&ggw49gxIS>%Q2_hxsyqk-acq{2#*FxTDoKqOzNygsTwj;)c=*5=VW@V2z-&#FEv zW$90n$PlWY)&8^YPl)^nK?0u_nqVd!`hrW|$Imp|48h|nNghlI?#U%QoiDyQef+4YSNkHo&yZH_G7OxUNQI*{Al&kz+35eJI z3y?F-VW(&`m)-tEvVrC|4MhuE({dbn+b_{cC!x&> zRLD2=HFfF@&bv|M2FzZ&llK0(4igxMTYYx(uD@3WBvEb-1P!Nz7}-hdA2c*I`5{jT zj3zZe4}Ksa5dZ@vA+b%_dY++ zuuJgF*RQw<1%&O(4WeDrz0FGY*Z*JvDR&bdjO7S>u){^pXV}I?*g`b?zgHj~4M#xj z?2EA$(iYB3X!obC4TjAS+WhY)Ag^mfn=SM z9!Xk*hab-Y?1N#6Um&v z3W(e3N=B4TksJqa$@%CjG04cV%wL*6ENAhPkvYOT)mcXzre+AM3QjNC82c-DoL{xM z@@>wpx>~O1u*N98&}&I9Gr&tq&@wY*Fu`Ng_2$=(6t3$8wD%b%yFzA1d2a6T3@(CW zv9~MZ_jlBnox7`Ld4QEY7M0fe9OwD{dimB(ZJjC%5V1{`b(^b?{gWXBQhiJx{8!HhY| zso~*y z)m84J75A-(QzZ_w+p{GN0DZ62Gu^L{PlF0_4!mQMOC}SZj=^f%+;asVef6Arou3&9 zzK5LDP&5@<2(eMWJ`ZKx@%F3*{`>xRSf@43i-++E76}p-D!Q-t48~RgSs}O6eV3~% z0t%;=--9h)WbftiinyVQx*dxvHeoyWm+~Y(WiZvDUwnJUM(Iw}(W0_W=!jIfgqb`G z=JyDScWd%ew0(+;m z>%NGI4|1dsmDbK-dAX)-k9Wl-O=kr0YUbT{yS7_R6iG`zod5EQ*mM>eHgpKyAC`_1Bc~ zMY3EUY|H$NcFT==%Q&TM8YvijtF|8KZ>Gf9vngTyb~-rIuT+9X zeN*j0zR?h3pA+G+WpL>aN<}~%(HnC3)G|2#KG|xr{{DU{MFzor-A{~zAPf*p7Ius( z=u(KjTPLi|jl_O+B4#A@4;bQuU%qaH2g@wBUMqj-5LVx$ou^nz?JC9=vydVWdq&Oi zaBqCsPA08lK#($rOQv;uw2QqnDy5%ZsRsHg8lAD@-CZe{$^&!PiXZkue;G|8xvN;?FJ>p5KXru+R1Hc+jZQS zbS*Qx?73sTx(CWI+KRR#W#w1PO*Fy^2A2=D11O*kzxBpnZpL(rwz{MZZfcjaCHz6` z;Xfy|>lr2G&6+;`pajH?Q>5^yo`S&%;FCKcps1!D3C2cDG2K~uAqOseerPLHg zhiD0mXWKV{ms(WcYjsyqLc9TcY&W%@Li2Rw>9wXZp#@J6e_ONb$S@O+_Z=bH3yxM{ zf7Qj9+U#@Txn}Si8ne5ClPYs++u$Ax33ec)D44=MSpEL_^65!C%L@4*;V{7$Q>8lV z<@3}`E-}FfS9j;4By$SXk3fxv{nqUn0m13(t|+wuXyQ}E;d3%HyB}GY+Y%6yxzkYtjeM90zJ{kQ@!N%}moxMD3n_jJZemzm zH;E>jY9MX6@)G)7QUgSX-&9wOg%#!D;^sFWxkAsGt+cQ9lq`)`8_Z|F%pw$04Xo~7 z-E@2aeP=VB`P3M+rLfZ>FW?;PQ93kik!1`x73M4}QiJ_DiQHEXb8d(f?;{lGM)^9c z&&v6P4LK%c1iIJ8P7&>unu<(wV7hL!4+IDPF3G?O*gYk z3azyP;qNLnMl|7E*(s7-CHG(f%e3KviHMe~9_tEOa=uoOryWYL@~RoV{qzKIeu_*n zyvc_O`xg#)wuhz6(*D2H6D-3m@m|~1b+I<2n4?nccPj5-Cm3LmiijX$&g)%ZZ(KWW znzq#B>bcn+&HgN86`#7NSgHsGo(M8eo&azRII0FsLP0%kGj$2G5gdJ9?^`!zOH}oP zBeSwvtGqIA8D(y%`YbX1CP%t=H0i60_In#WgKtrsoVWL$`kuxhzj^m8j{H}EFGpK8 z0`^GmvaaiCCRIRO29Njl&so6@X#0J(wtSAr;N6vrtDIcPE*6kLGU33jqBHK57O^q* zFh27l;OX92J0^n)wI~>6WtjCfHCZxm{t%U+N$GTU4H~5C8pFrt=qggKR(80~_Q>_< z#btHPK$F~x-f)`kr2y}9Y%)t4L}unPlM5c;^{5-sizo6*`n|gC zG4E{i<3urhS?xEU8QX|_D#mE7$kgg%$*;BCzz3rkJ~M#*D{xkeG}0Q{=_g3mWa)U> zobA>hS)3GWW1h5c4!Dtlw60GC>ervW6}`W6H2;2$ShxCoIHnE0WD2vmmMX_c5_7M+ zPT33WnkR-lkeTb{c?}OF%L3r#=&J{Di6W}q`5D{eu5EMHWkv2i)o(ekl7Vgkj;`Jd zLqlS5i0;Rr_M5T2v?U+F?XxnOjB&y|Ak<%EV5U-8#~?DxpDxI%8u->o-7bfYapmWl zkSGUWYJ{8y`rjawpfS)Xxj$SQBs^S`8hEvOg`$PI-bBmMTdys!za*?C(^v$|elN{%` z!)~jO*4B3lh9GmZZTd@vLOIJ4lRBLy2924ShK3@R=Tm}QZ@EmmO{Z)ItSv3aUxHLf zyMoKytm^L$;=Nznbk8mn_Y$em<4tjXE-KKYEP}9)M%*jMYbZ844z8#WmB$TOnp^)g zYvk2oKXwrht`@8jv0l`jt}!?`nsFF{ER_9-gdNij$C{7~$Udu^@(jag&|_$+0`eCr zW6knY$}3+!tnqgZ`wqq3yB!HlV-Xd4YJ`e6S_sHXyqyl4y&Nx>NwZ?_nHl)XW-{DM zCet2U#wXM@)8$zswQod%ffzVo{(e=6iM1h7_!H3ZdvKS1FB*e^h0x0h1D&x@Y}mJ~ zIqvY#D$B=8Pw#Ep)Nciu1Eo@pa{d05YXuQq*=-GDf!1RC=5{~RAQ#v8uMhlT$xVbR z6sWW0(JIEbZr3@p^T}Vh7wg<|*HQlERHeIHhpnA$CLiR%ncnblJ6G`m84d-|1Y_VW6R6M+s0Z#ec%Ee#1%V}?{C+fJED ztm+OwfP0Cx=9hFQUtsqBl2(|ng{%SI5%%xNNU{{~v#aQ-%&u?v@P4QrHIkuxb6TU` z#>HJqOCLBTtt57qEBhJnLe5NsGyPWI55H{x(djEL{@hvygQP9{Eg{MCdDpeAV%O9* zew{^zt6m^$S&4iFBl;;SdOD{of@_!MZET1SRnA7U+oj^S*t2gjS?tyeJ$tMXU&3T~ ze9wCQLq}u0!~>P$130`!Ndz5EciVP%2u`_8&32oc`b*;vTv9n!lWqBZq2n)n+elW8 zT!84a>anHKPzq|%7wUJ+f$1?K_ykFcOxJI9%({Z*dOmLro~f(oXJ5k?sT@02dZ91Y zZcE9H+B8P@e{FW;qkiaiH^0C0nEa-1<1>*80~gQaYLdd&`wnF*#%OYMEF*mXZqA}} zw_6#|Ca8Cc-11|qI>FyUd0LT|DtGgaavE2&tgqPLVc)}9+~--bY^5>*4?|?1c8b6~ zdTf`t3{Nh{>$@wb3Id$+_Jsy#1IY45L}}U>IMzk7UB3<*<{vKpF+j9z$9GG;K-6z_ zX?zA+CAc?`ZT~Wn*zr{AJ-t>P|M}p_V%-H>eiH21KkmVP>rJ#|)6!TV$Fl(6AnWKp z2Jxv7!(E-Ww~!`44gMOfw+h-+z1iP7DLOwZYJY{dS$mnHpstNvgnV8D$~m=sWv^>$ zHrr2g?AtRy^l+DeK!A~YtC1g(twiX@Q*Kq zg2~HbCnJU5Jl4DUYLn!`ZaSQkFbrqWh(dUk2zO{VC9zDv$N-|s*dmcoaB2axR(Y1B znO;0eWaps6S8pGemLi->lg{T+=?^5ju;D$WIa)jXnQByJaXy#5lyNy*Q82nq>JEeh zzBLP>t$5#Zkcoc^wn?t#)_+AnwYB2AExry*f8P{{G}|{7_V)iZl^ruxUmg*A@7iL zg&D&ehk$_WWL|ydY4M~j?wl4i_m>3qtFt+_xFn4qd7J z$)a93MCY^hzK7_nHq>;ZdfQyFndiegD<6 z;}32aG2h}vZj8?7C`+4#lSRd~;}91cY!lK_GGfvOf^~1O%{Tz-y=ZcnhJc5KG8xR! z`q7|F;ed)tw>F6VefL)b)*Eg3fT!8j?-R(WGBs!WDwx7%&%&sK)vnnIyh1RA<>gIj zw@i`__83SArK|+kBzm>qy_=rYIY!>u-bItvlaSE189E%Tji31a`PI(b%DTxssawh_ zYz)8-0Cav$n`v;JlCv{oTwi_w`)?dt27R-1!xQ>inVqR_Hl`tiOW5@S%jPNqQrS6|$!C-$$gX*$y~l+cLjoe} z9)#Jm?-q^YrM?4Ljb&xm(vZnkj9`S1JVTozw+$p3ndA4B=WS20_7Pyi% zst=XdeNA6#w|lieGe6VoG@bKO$aTQOEa!#^W4%Nzz<;ZF{ zDTmOp=wUyfnvEX+mXl+27i!r}7eR9ShU;u@Z*c0JO@UdJ@<1kY3)bXk96sUMhA*=r zW#InFTphXu@Z!8Ca;U@-7M82sy3qWfMMz?z$6^K*FE4M6L58NLrpxsN^M0Xw$}1gA zyRJgvsgFA6NBg_ISPZWju~451I36=Lh%iz$80ekeMR%iI<-9F~NRCc4s=!vNbF0WTE>l@vEx7&s8nc}Cas_Jb+KF*3XWk@)Q}97Fd{g#`@N&A<2)bj zA4RrOk@p3!uDNi!@fLCZ+{uP|@rFEiCCc8sV$B;H0P5zNL|giZnar%1YybGd~3f-FI+9nn<0oQn z^;c+?&(UjT=y>U)=?{GU3&~EZ*6P|ai^0jIQ=rPPD7}We{vhGVCHrVr81Y3jhM6i zYQx~`f97r+dQ-47nY~G5f#Rk4t#5NWsn`EvG9+hX75VB&9ua%Dd}(8pF7IX&h$Lt? zI8{|uXYGFa%8Wyh>f!6VEV$efQ|PrWg3% zu9qyVM3ja`qe*$K7sMpkrDC+Ne=WKCA3f}cu1Ysob8!3mj|?7GzZ{XjW=b4^IbV>w z!Ml&qazw8N)gUT@;mXSGsc!CgCUslB)L`DfWr9wfx?c{YMJQMy4uLAn__ExMHMK@pMe?q*2oF6pkJySo`W z&cfGs?|shR=eo{^GatNU=7}}WGwWGv-S_YRzvIqoycM^*jPwq1CS2#1npr)ftM(R} zajEdkr(G*jgcl|&1xgPjX9t!V&{IFrPE@V7`@25`qHlfQ*{kcwdgUG1{5E05JrU$9 z%TFiE%t{zprm~fW?~)Q@A{4cV^>eQBPCr}&0ONWZ;wZxJREAq&>T-`Pj&FL3;>u|X z(|5{s4&LiZoAqF*n8kknK%8fNky7DyTs#aZIIA6b`1QdPu3tpn#TS9`nVBjt2^C2% zuC)r<33-AF8lLBM!QDNaA%SGMPa9_tmUvg=W9!$2En25^@<-tWE9WYTef z4*t?wI@x~DWt$<^<@-vgXTQzzxjdPy;ip*z%gK&RC7!6ukVP%_Z^zp*2`uSW<7Q~I zwJ5$?yJI1HZ5!(H%!?KRj25%mT+Zv$vj@AjU%2xPNS>Iw9;lGWvTf)p%zPDqb-5X7 znLhUfQ^c2|9KQ>X3*tc%uNMdZCuBMYa>vP~q@?6}{7VoS`7Ost=;U_EGNKwLwSJNa z{bjHi0AkDrON=k7QjWLDy1sb?cLiW}c8*+^Zmw)sn=u7X_2u!NPrL{XfegW_~95&XE;BMD;o0yA>t$ zvt8{FMscOb9Cg1m?b_hHZ@0yNy_-OJaecNPEQE1iJxiV+;5ycNP-A#d-GiVZ7tBeY zVJIXK+5*DoF^uw!)b1HF+S;C;`d2lEv^e#MWegnV-IbE3A8kI(8id^os+{DEb zFM+jW0x@8$;3QEgw~Q5s{vQ&{F97>|O#Vj^+xSKr*ND-Ey8(Je7NF=%)NcjQ?uK`* z*%jZovB#<%a0DkZr)xEUca2#78s5Enw6@`sn^#&?%+T2x#mB^Yhm5q-q;oI#CCtC{ z{t7!1QhyTQ=l(eoimPkuj4uBREhXh<<*=rhRM!4MLSs{D(yh{xfgMyNP|u5i@pjV& z_ItL)g%5zEoO>o-&0p6E@P7Xmzy@zOxP7@B;ACWhZ6R{T^r7L5FuF)pWtP{{(p=;- zzqJ9@ntuIfvjm3QrZx=8ybq>g4`pThQ1YPp!{hA^Awva43R&53buC{6BKaR{xmN;7 zrGQbBXG~9j03!i)S8*N*PrplcNt$9Qf0&smEhW8={>PxkJrj+?;SSOqjGABk!>4AX z@W)Sli>?2?CISHE11*m@V1q>v8obXEllBGmMgFv=0fG#C17q$KqDzu9>F`=i)Zj$q zzDsxr=nQW2-sc&OQ8(*8KwtKbII=j>!p~)XyXKql3VnLYH%BppjHTu90*xou3!jNE zLSG$)-bKMqjsu16dcLJnNEz3*oxLRkQAiM(jhs1kn4C$Kx!Rxnv0YGeB`K#{_v1o3 zeXv|m`*^)PC)&v~yA2R>tUYmw&{^T=)TcY-4uMQ8g7ls+e(H4n+3OOwgPg-QxmYcA zM>$_(^GNKw|ChS2@k1L_N?$GRhBp7g0qNY=J+M8&0DP z#!s>y0i?{LWurd2ZEa(Q+iZ* zyknaD6O%0R^a!Q)&0sK})U6<9u~OJQnTawmO6q$RdfRN1F?Fq|=ood4C{`r*738{< zyRX@w(et`~7OMY3i3%KA9?dv%QnBjNFg<=^Y(73JdWbw5gL^q89pE8uG-1TV80?1V z@Oaads~fZ4j50B?S$p+$bHpFLD`M(K-&I^kpnK>JmS=kO`UHV=l#~A8TH}#grikFh zXKZ9*-{vJ{HAAma-RSODO@A6=b7Xe7n%(yV>2>klyJ!w8bT62}sJ*j!r;)evOzybs zkvI-9UlMIK?0?34s$p3bOS|S5#t;*y3~`e3c@HPV?sAvKx#?t`^r%H2)cL%s-maCJ zs@!6k&FppGdt~P?hBa1;y&zrroBVBT)Z;S;=Uz8QJnlK`wdOOha7a(n?|&DcDBm`! z=P36wf8f!@*$HD?Z+j~`4w;ZV^pO~rlXa{0))S$q!-LsLoaR>A-Kl4>O z_O$tB5n84xEZ>)OFAokr-^}H8tM=vo8w*fdoB5)4a>z|S2@_?97yU$kWP;2{_}#SJ_<2Dci(J zV|oEX5Sz5$x0?TVW$k&jX!UX89?k<>yP{YQgU{sk`3%L%XM##xgZc^eR-12>%^V$h z!wXMlTr}j%t?(nIMk92*cBY}~N=j1RiRV*v;{37TS>STBIa`7NY3Vh~Z6A3$w8xdf zjOqT4Ry8+;T9SoSTNc-KIvp}1R##T4#;~QcNYZfbT9)bkr2&qK{T{5b_LqVy!9*Yzr0QREy$8S_v`XMW;$viW92HBOw3t(}YO z`6oWa)Tk~oX9=@?Yviov(sbRnxV4^&T=xz#ZT{2)A0Kb~FGZO#)*DNT&x2pGkE89C z?-CWv)||{-(V_8gTIld~JG_sJP))DRuIhZFFPl;{q3E^{7yqPkN6C`$t9=EZ*jTSv;v=e0=EY^1wM*$E+bTpVse9!}o0b&WTd0 zx)n9rJ!g52+WVaus5ri197esrdi;h?ZPaWm+0l3&1BtSrds?eZ{c8Gy*p+m0im-6Y z$Lq-gpu0@qvA3PDPNlp0ZHrR>_I5JO0EyuMljWob>nzGG|$bz&Bsa>lPnG8OHYoi_h)Y1fW}GU#(Ua5Fqx=XCjg4 zor*R&skzPfIV8p%UbmDv(lJn`b|PnEQlC${QgiM?WQha$NO|n{#hV`B7ycvziNvLi z$vA>%PMkU|(vQT|HKXEdZ4Nhj8gMEr++=>85w!-^h6@ z`sUo+_9f|^vEx&Yv&td}Z)%PLXwlu5+|$W>l92&by`Dz#KKST-ceFUi(vX?21;BAx zC{1OuutixP$yID~SYvRc-rnpyJN&~MJUL!?WoZ5SWF5zRS|?MEY`o6=g~_^-={p5I zp$VJIErQOmkU=G>$DG(%>41{qv--KEzf10LGGsXlQilCHo0F+s+es{Z7i05Rl{p}A z571N(Iayac6Q3Tfl2=0YKdbJ*b1SW01j*9c62o9u^Mm1G$W3U+#ABISuNCM@bq)?N z6Ul}A9^vwo-PqeK)?e^Dmb$u4^#gp0^dbP#Ef_yBl%Z)Id+tE`YEt1i#0FUXr-CRB zAMaRpx02_Dgule#0G(lm9I<4cE(4?SlV|~#n)NhC6i*wSunE?ti!(b5=)Oq<)JqO$ zXII?+qL*|+k(efslb*C-{Oak99^4@BTM`i2Xu%cy4d`?kkA;O*+FT({#sf3ex(1kVrLc)pn9zQq0b zs+gE4V=vUz+I_3f*OjY&fkPjN(@SITeZA<+;Q_})9g=ZA5?+1OcF${&i(3$th zv))|dif69%4>Y&G%_x(9>SWrs(tKItL!wsPAp%_?#Yj+_w13Uy*8TH>Pk3PrBYQ90e;7l0XHwECeIvx1bje8iQo5ZcMM z;HTGt7r3m>*a-(_lbwyd86!NBTbo0vFFajJY|_s@bUwT7$&U|&@K2=97eDw?WJ zK~cH=ku4%B)PvO44-0|dVRQh$y08S4-R?9S@Zb(>_bT*W)?Z!}!%k!HJoi81Q82Vs zR~d~@C_)zR3r;Y#G|dZ&GItKVuHAOGzu*ds29wH*z=ZU6m{N-D7P5oT^Oys>%l125 zBM~-dI3FK5U38fJln_!<kCWS}9P8?%!;wMivEofS^C3dPHcv-yo4o6P|MO3SNNAP7mlSZGysfCFH-`Crx zH;_*#F)iKo4zAaCOY?g^+)$f-I3G&1cCa>`oon-pJD%@Sd5&JdragIaRq_#)s8~`7 zp!^_MGDVoR97MH3v21Y(q+cWN8nY_D`mhipF&@X^#DYbuaE`Kp;rZcNf0cs6&$S5j zFoAiq`ABZU!9Y66G#0jvSh212Lh3{WZF&a(*ku3xp!@)A9iVlUB(fZ*yK79?<#rib z6i{^nHyEosQGcUYSezPPlndG1)Lq_Gp}-s8w3+%kH5&D>FostZtI3(hD=VmGhz0S3N}9AOZ?I zLu`|tqupf@f8GN~S3)bACSR9WjpW;;kV6uyu_s8e-!!gN`XC zQvCvx5Z=1;{SzR`7#b>nq$N94y$29k7ru@d+@s&UJw2Iu9v6tDuSr-pJCrIP##1V{ zcu)~m^=HN+OHJzb+>s5{Copf8#g_e|PiHJg2iB%Ao-pxkxAURl;p7OXRctbC9)B|z z4$Fvijb$HX0KtkA9ZVbU7Oy809mb(_$>~+}VjU@xdzmjR)U!(Qc z=+UWoweUXocTl`I2{#{Qd?a*mVIhRuP_WH_2+Q5&*QXYQ)*JXjM-TH@=?&E~5*A_M z*+(-ohq~PI+HbGfo;`JL)?p@lg$6|$C7?sLr;}!EA&`b*Qp%5(5G>+093)E~KR&O1C=BO+0f;%MT{A?ufjswhNWS z3+QD#%Po0Z<={5W$2Y7C@=(heyeukaVKD6%#R`e zRDeH*mYJXSWONx*W0S$j!LY7)DFeE<_onsT4QuGE1i+WlBZP&y2mD-9E3@0aM&vX z*m#@B@l_+>Oi@sOz=RWYc04lDVc{fyK3@dp!t)P}i0Ov_S39bk@HRnrnh(GNakVa{5trGL^r@E` z*Xzz^*FdJbIwU8B0PMkrKq6mFN&8|&FEl=T8%6;n`J?@ZZZN#=YTir z&h5t90S`7Y{R23GqLYhY!bP?@`mp@8uzlIMDZEs8`OiCdW!@tN%$)?Vq|I8W#%bw4wF|}7!Kx1=n#<`(g z&tc!2-t=Yymux>sxAiEbtc+!Jk3r(uoKp*j&FfSxfE~~ANyG7zSj$bX-%MQ-u7vY% zZmx%z(u@*49zVZdR3`WSeJ~9zCp+f~@d#We6Ehi;3i=m>tDzRAV+}**_?-Pv#Ov5R zYxrQ%GS(=JrvBHj(pbz=%E~-A(n5EXv5}meF>lc+%vgGx7xtFeNyz7if)Pt-usqj1 zwpq)g9~Sq%D~NoJJ^o<$QIyi{&A|g40IK0rt4_cBq=!y`vo++e*s`6Zuwinr-Qab+ z%e#w!f#BW}mtI!N8wNKeg1K4oZ$AcL>k(=SudnWOJ|`wf<9c4b9s~WQHySWycHab@ zG5Q9zzTzO6Y4dAdeFcoo)sUX~qlIo)!b$RE`+ga+mxg@&yt0xu?5B2hn1D?hVh&eT z;38T+dgFCOe8c;dtqn5mxJ?_r7ZNT`Q|e6`*~u;N$;HsIFX<1tG>GOqPrz z!0P~r$*0vNkld()eOYEKW8+Q@mLz_ezTZ^h_mW`{ZlszpoPuZTjZgRP?)}k^92xO( zF>>LL&pN1uJXwg9F)i{roz|5JAfiqOQz~M1@-LWlt7R7(I=x}tGBZybC=R@W&+)V+ z3M}Gz>Jwdl@?5^*pj7AmwPzZlnL`>5k9jptsmE#G-8-SA>bnBR%dE1GV9}132i6iX zF{&g2Pe`5|2wlGMi~vUaXYJW~qu5}Xi2or6VPRs$H~+2KD315Hck+2O6;~OFe7{zy zZwMm=d0iEUvaSv1OU9=$HTb8Gg70l$=)+5y#u6{RBr3LsIkkB1#fWv5Si$OKh*3I% zg_vzlnkYZ~I67QB@Y3X`Q6Y%GTPkQDQ=_Y2Af31|N=-o3IZsl<@Ga5O=DC#@c5Z&6 z7uH&1)*BsMYJLADT7J`<_B9@<;|^;z1}XyHOI4|!QPyz2{D~U!C$ife!5*H?b0MG@G$KZ74j1&r#NX+(#=gts>*!wb_zZ zZu}697YEVOs>wGRj%yVb(vP@%KtW@b*{zxMOGt-Cum0WARStmn#6>7e?s9KWVq8P7Y*~PPx`zVQOnW%W}1v&>&3C|uh_8UU=h1oJhyjR_R;GOii(B8 zshxhK7^|V7FE02}YyHEsWo^66O-__0sQma$h)r6Xsjn*?1EEPikPl zAoBS5$_i5kgyD~@oejY>n z*4W4%3kX9(i9JKJ@txF-UIt$|+%tEzZawrkw=?8;t@9iOBMPbVATT^Tr_F`mS#iRM zqe#b;d+N^L;Vf7}dB`Ne#?ke3 zzBwy*6-5vyO!-@Xq>AISh+8Tpwgz{*Wf=_A0?QjDNP<0)WK&iRcVJ5R= z&nzHfu=5_mj(02^1{<=@+(BetR)G?$DQ2sFE2n3w%F4p|0QUUYAR{}mM3hzbb7usgp+nC6dKNI?8(aeTzT1eG}Jy{C(Q7&nN=veaaP*O<9_AvS z(=rT4K0+(X?zL;8CPF#9IC16`jNkOv#b0df5*mJ52DJDTUAe(%f$)*i zhz=Vv<#;nUGHR9NUFZ>y0114C@4&csn3xvJ*6ny84o67uY}scPdb$9O+xIL@2QDTx za*K%^JGGk)9V(k#&W>ee#rc!pU@rGCqWaT2x@xMN{P-RK4el%3>j{#fM1E*X;-wi; zirnzsuAhyy@^RI~u|aRANfPA}7#JtQ*o(6&zB|>p6tXcFxWlwn)yob{B_-+kY2}iv z6f)$7<>Eus)Zn$nQBJ~*KD59>fPH__;d?dA@AI2%=~u$u$<;EE4LE9QeZ@7S+%=+b>pI3zuX>x927@2_Aab2m(A} zg7jfA*!IG|E8=e^$^zrPG%D#UoE}xj#ri^)(-chbrm^eV%mo}4YCJ1p@%{w0tC~C$ z)HIp4J9CZKmDRk4t4rgW9TV2vmRguLte*gV(v~{ z(%8Lc3=ujui@~_QZ)Mv*g|HATlTS8J^+_ocAJ4WGY=)sX zEj)q@vYW1#x6x2JmwnkB9rDt_2z!n@R+(zJ33Rjtc6pV}{l5}wlv{2PTZh0y+Zp*4LO4tMn zS^A___M^DC%LZYxRq*PRMo4rShI#Npcn3Zh!@)Ju+rzY)&&*fE!ddx!(!?|~G(O;F8~A-+bqFR zth`h-oJ@5YKRc9}FB@5kJh9z8o}Nc`hD~|-N5psh7Iu>=v%lCt+w1Ik-3widGP^ee znMozgdK!kCWp^)uM>a%__TG#JqGkHm{rnFUoc^t$0uv?5W2?A38EmD5RCi82wRu?6 zt^uSLsXSa_Bg(KE{#mQ z`Ix?%kTI2R#E20Kf5S!RJ5sQw7`^g<%Le2OZR(QR?B>s4EYvgg=~hX$$S(Jq)fJW} zcwS-1#3#|he@}h7Z2t-%$x{2g;+r22)}lek6OaT{!mvvwJfyi`81S8MGG_mIGw!V? zlDdW}EG=DQ-iJ#{8b8h~|MKNaKIe5+DHE|w`l9HpG-idSFaHU**}AU#SDbo`W^?D| zPTA}nuGlFX4gQ!NKoBe{iI*Y^|owc6- zjb@T8tGBu8g+U$X(o;h)Ue@`Y}0rrap z6=)w{=~(9E2G%4dhOd#~Mj9!D@Q7AZTT@N=fzC104y)F zu*`0IQ}C%k(B&mZn<-JT@ZH1HL-Ch+HW--HhVp5XW1Y&Vs}Vm8Ry42Bv`D97*=)l6 zlY>WAu)g5@#)N7^1UllHBlnyg?T(8IHPq~pA3ZYf!=}ktnaB)C!y@?@`dF=I@9Gy0 zVOddWK^S9Ajcfp!AC+P&TxK713>8BBAZ~+i0;#OO%XN{msm;t^61koo=0Ms=);2w7 zpr^CA<5gFOx`~=vaY|*XX*&Y8dZX8+p_;26=jQ|j1YJT@Pk@BF0mMI#WE6etb%rt6 zT(- zOtQ4Wt4O~qzsV*gVVW;z>Z`vU(6+-T)4Ctjoy@hveB=2`7Gv?WYoA1gL=3bQU@p%D zLn7C*$1NK%l(9Q$@v`jj6L_4G;q;ES!gKK|K)@cW*doj;&(`=Al(-n;l&edkPZY0? z?YvJ!bq61#^7RL!k~yI7+jYC_X{T_Nl9CQgto&e1apaR6z^$g4rJFt|EP^dVDlHwa z`%llln}><=y({5!+0hrZXBfja8C-L!tlEBOP z*Ruf=s1)_MMKN=ULs1B2i>z=8PhclP90tGG8Yd`*xHmp0ZK+5d)%+(cq#>R@FS9{*RMMeTs^qOU?Cp%k_ zS;;j9i*g&5{fZxdAe^tlSEIzg^*+b*y%~3V*Rmn&XO@S+w(NCD(Bj@1csy9Y3M3#| zii7#KU5R!1En^2)+be(MBp?IH+gDf z!*eJOUl#706au&|>PHfc{x#NBU_`!Bd2w;5z;vz<_wIWlY{)x zWf}D3Y5M-_4er7FlVDz!&z5kqq*ijW_hj&m1XeWr;Tf)qsk?xc#b``Ad0#AInwjM0 z)DTCX6v0gsKz0Ni3obV`PfqdyESB*!^-ey{jFTrxn={Dz3+11!0(os0Vg2Gz$7aL+ zp{HjHpceKU+bmwx`=4*6UW{;6)m~`HMJd7VzT)noV68J6#~b&t&zmH6tw(QDPOE@$PIE)vRcnjBET)LKRrZ<$Vib48( z?3_WaOQXi~JRFzdUBGc@>w}rX-P0WpT6>GrH}6@WeRcBltTLqP0hw6fT#l84BFK?_ zHd=oH)Mk{wNc1!EN~sa(^z7ri+H#T5gdZP)%9q<*Xs?H1ToWgaxSsW+)iP&x0T{3I z?M~&jSFsaprF7#TIv5TUfgBq4+V;hC0d&YbB@6n?QHse4c{LfdMp^DL?4Pl`?&cD? zO36uQP(G6I*rxS(dun+5W_~Iz0y<3Ui_NFsMOLkzQe^EQDC0x}U!u=kNeFZyJHWYULO>XSbs^)4y2_Y9emyIxx6%=usJ7qo`+}M}qR#U2r?E1q9V(;bjOSOx9Z1@J)D~ICE%BHeN-t$ zeV>l~W{3cutaCbJhRPw35Ho^eY<|{J|xB&1g=Vd3GKY5M2zFW>VtKANQgnp0&v$9fe zcejwFr>9@`@d}wX)20JQY|>Y5ZXi3}BQcHir+z9DQUU{D-;a)L1SUJXzm%33t@+_{ z3sqI3#cJLXL%EoK=>; z+x9C195O*sF0R&U3Eq+xb_7D_Jx-1(-odyeZija5$&ZM3euxs{6FNFpK=(#o0Jsbv zfPR)8+&OB{a--4fM*wo|m9qnnuARlvaNj-fYZ8~&ad}9vx%Q6VdE%|@>i-27+R8Xf z%>QgY-(P0iHH{`$#mDbfHYa=i)$FdSTj@KH9RP+S7w7Pb)3lyyY*4;}cVe=J z)7qz8O-nX^;eVudBFxGr^d^sWs_dMvCx=F_O4*qxDs5jx0#!RU$(XNnLSE_e?-K)S zNrcg)Pj3kDdf_Qku@6A53m>A7Y)qEqlLjldb^!p2nx}zckQ%J+$>Ul+O z3ono*{R0$Twzt`8}oHZ%5 z>klJb$p8UDdA_?OZaW7(z-xxk)VK#wO!=e&Zs)G1z{#u=!mLxb((Oqi;95HyeFf@j ze_B7;y!%bKG7osrfNB6eF2OEo>h+X(gpn)K>o^<50 z-&7Sc$R?ZrVR)j4^pzH~8}zvUj(~hZ_4#6q>=cdEapKJujpA)c(iUVxR)xw!@Y2|* zlTXOcXDhk&r}`y7{?Nv`e|8kxxy;LEZFOr9blMySM1fD(YiXS@~rgx0aSx4s+Am+S+BUIn+f-3KNaLuWSc%CVHkIvLK*rYXCR}UVdKB1^}O$ zq4;sbfXMmr_PR(yoj_G@+{HRDQmnRJe?8H7&gksQUw&gX&;LC5XIY5LUW?Ccc%SpM z5Z!+>D{;9QDAuVJ7$>!{wIQs%iFw_r7sF8mf@lYTr(ryGSzaZt8*eIqbY=6aIHCHp zV{?;wf!$82t|*aZA1qWnIFr8#@SMQHWpSxcWJ-&Vo$YIC(0BAiIo+Z>9RLrk-0b%y zG+sIVq9JqnYoW1O%E7HuX=nXGDke3)2T&!UVMQC8fiiv%jE5Qor)Q&XJi|SCk^f#G zEcBN=4aGkrz4&1yx%Jj)<0S!caj&efu#RBt%;6FuyW-R6=+&P&-R~A#A66hwYnIJj z_6FE(Wt4R1`gO;Fl+>?U*Kcppe5B55Mv;ZJ<4M(RJ)R9GL75YSe*N4y)ro)n=4H36 zMqph6QzfvE-;$@Sj8RZmPwP-Q+8FUZyy&29|1R{?0J^chZileYs~yh#_~yN$l1Yq} zlx7vrmr-dVQH%Ub{BjRr=X0mx4OB`Zg({n)cYm9o^!1N`ZU9eB+Id2gE!`u&G59|; z*pZQHW8<3Rnp#$|VYt361bFC?G@;PIt^wSE`$2O$^xjKsk5gnYUG5bMgw`ginncg~}&tiaSgn!20E8hf2)NFW5i zd96d7l1FmdQ%lCx&M|#_q@<*Ja$ddxwIrzVVCvfRdY?XZGIdUMhYdW&b7CvDI-_t| z#QpcA&j9Z3ZUQVa1tu#Ho9n5x<(WVKNHj6oAt3yIt(k1!M0u#9Apo+AG`yTmBdyuM z8uB=>8Rdnvbzy~IVzXw!!aos|F-I$b$HP0{Nknc(nB6(bKmL31 zvV?B$SdZ_cKfdPwDt)fDB5B=9Y{F^K z&!NY+$f^%t~k7&S&iF&9sZZ(6;O~#zlJU3fxD})0R-_Y$x1MD9-*{ zF&60+-@kK5M^-uD-E1g;A*3O16zyh@DHCh*`Vx7U@yq~`DC9cxyHU<@6AU!*d{EcT zD$D3LN_PIX!70Cs%F|7~w|;A2)yVeeA|yFlQA#hsAl-Rl1^+pZyNy64UqUedt$gTt ziuK^Z6^k&Pf}cb< zO<97G63t?im_#a`hrQJLY0t%|RG#2C)5Qj5TMzr`?cX=<*;EpY>`X=JOJ_4za?()M zA!K%=-zCoJqgJYE-FT&33HAR@pP->^t7kG*kgZIgD9XA@up6@x_o+CQOAAdfEAk%}_shhODg|16ewsPN=i>XFqMxYL|~4G<|dC zM9|j^uh32ZsG?W!VZub$(!a#mu6B4;30fP@538RcK9TN0_%O^;_^pg~{SaC~9BdK{ zk7}`d4y!SLz|VOY9OEUWVzx!eq!fI}U=>)OyrI5a!s=5{8}p^JOH9S}c~BYgYB*b< zYpvO}&~F4A=YbRgk?mNNT~K~-MF&2V&k0kUQ9X1DSHPu>HGoO%>C%nh`Ha3;5V+Y$ zc{feK5KiGmu!Y{1 zI!I;2y|(7_nq4!RYpCR2Ie zZ1ynw(bH|q<7+8`-j+QpCFS@~nVz`ZXs(R&6$wZC$|_NnLndiQb9JUwN8S#W%WCcD zP$~OL6DWP^2GfhBPl(Fw9paNTc!lYM8>TL4o+bhH2TjgO4AQu}+6)Pu*|eVX0`$Z3 z)bjU2Fa*P=DwSV_PhIKbCrA;HllGE}J@D9`a zs4Nt&lAgb@Q4#kkRLgbrF#$r$7W?yPd%P$GZB9}3!PWsg+bfi`4KbCO#%$d;`X(<5 zO2k(4t8O5$aTTHUsc9k=dOsO`6^<3s`E~wgE1<2yH3&Bn|ZxjKkVxr zM!WX%)v{NdDt~KfM1a4tDs_X;H}h&JYBs~OD`$vtNFs&v7qZ;kPwAJ!q2Yzz*}KmE zA!pFz9pqf^G=Jn%VWVXGG$P!$F$9<+#m+O1$1`2y&X$I}h^>U>qpjs)dx7c{I~gZCx0Pw)#HKR^HY_lgSxU?wHDr+a^g51dmgYscF_5mY1bC8W z;Lkiz-+DV6Vovm0TtAAc6#L1g+a>Ar+L3G9Y3e%<9fP`6l> zL7A_l6;z7e+hGlZroI?9OHwFS6FGS8lJt@iPlqr%*g z&^UMsbZa##K8NSNMAjR+9haV^pWq&PCJI3%@4V){$CK2^Yqwm(0T!%r3=#c2VkkBL|`s5}R1J_HAj>H2KIy)Caac;L$3T)K*(mS%3aqsqF%}y$lWZ9&uA45N$qxUY?|{IXdnhkN`Xqc;I=902*4P z*4sZTUl;LvnH3>iXlVI?3OC&O3 ze@1foc-zSPSO3(;e(QB;h=c)7$d*k0CmQn436s&#B#4_6{mWG`^9H6A*n z-X1-Rq`UDB)>Eg??w?>}6!~$7h_lf6QYW;) z4;90~{^t^*fOg!z;8-hj?x@({^hNKm|52V+H9mdX-*9{Whz-iCjgvp?gSiXJonoUn zX%FSs;1Dl|#m|R#DQ^$Za3VfsIKUGLepG$inq(i$t?{5itJ@25|Z@NeItZ~FTd zA8y+jdvE$1pJxr=K4-UKu|2jDTOkDXV8hw5dKmG;!su>yMPhw4>tYAat90iMXs(ig zg@Trze0lKuFJFS6iHk^2_QOjmeoEhQL7~=8%#e&LK%s4lknG z9$~Q!4KnOXOg22DrA*CL*1Qq=WoBY%F#SD5Gmqb1MNuttBRnHN0aA^PFO-ljzmZ9V zH23-*SIJ|f8|Vndh*j}GUmkYIpgQ<440v1=6#fwj8|R!=t^|4o2ju3tpHg_tHW z%4}#Ld0NfZmcq@+r+Gqrg%5<}1h`9^kcRh=+wYX!0v$F`TD>c^Fy;%pAZg4{i@?rXeW15nZ-c9pq&27t{ z(uS4^!oqURV%b!NrKB8qpF|hVCm&&!*jgk+hNmZGWu<5K87#MXdVRsfgdG_9rsu`S z{P^ML_p&1p9UTaaSAV~2t2h>whcfu@PDGSwB7-O=R3`}Ay> zV&{tv30X-Wf83`6*uIPf&*ZWBUodlXy~?flDKz(!qK&1vYydv;etC7-aJ8TF(8u@C z`gA>HaB$;dxPOGJu;e-abLOv4tB%sB`07>KdRgb+F9k8su@(;vEu{YTwBMr;_jqY@ z9`D7k6ZLlJ=|qXFU%+z&RqNZ}^3<#>ItHG##Q{j4oIH2gFDn1QK%efu4nnsh!O67F z3-js97miE6)ZYlsP$lPPo0u7=gL$H=W=v$fs35^_A!%@r_OOz`kJuA*1>-dCjodr{ zR>qv~KE2vHQdTUZW@NYg(A8@wde7}yGDf@@s-}|@K56)`V#?8=;KnygokQ6$(#nHO zZq{-OrS3&huX~}s)>e$NOxh@=!JArm_V@P>sR@GS?#II{KczG)2i$*v;V6GVk2#s~ zJN9k9rpVRos)6C^CxiYg{J{`BPmWSISXOq3PEeOI_KSLN59BNI?4lSaO2|-2^F1pL zp0hJm*;t>01csa}QBPEH&wHUi1M3RW>`#HqU#&sGcpJi+k^6nn5 z)B|3}Vj3=+jO1v~A|I(!w43HEI;#>uW;-snmyM90hv>3hf0jz-D-0@BvNaw+2eqYN7&>Zwaj%dDrViMMvh zB*g9IV(^yNX*l-nE;ltrf|kN-DAGOiXUUJ0XzN`*KNFGbZT}qt#zyxWVkfZlzJ11s zNu~C7GGt42c19Z~wq~+Cw%Ul%q`2M{9gkCFqU7~%G6>GRw$vRuOGAAkMMJ?5lGc%) z`z-~pv9~KcIGCEKuAjF+n4Kh-AK*|^jG`8 zM1X#+8qXKnq`R2q?+3>(V$`r=AC#Q>-uu99my+%^gW_<1T2A_D8?T3;ld-pV#)$vA z45zLC(b6YXT{4~I!u0UH_z>=ZxO-_-&5FyxcS(_vIkB+b1fn1CCda=0rb?y#d<tkN9x|+rC^$QEb z(7g*iLc3ykd~iTDA-ozH9{eM$oxUCNREo!Hn>kDBdU2qCaEP0Yoyf+qy`%e7IpJh| zt)o-<=nJLz?$AK~QGg3NeL+%^MBr9ZaG*FsCykc2qoWIg$SYCq|IK!g{ltosyjGLb zyJo$WFoFvEcW+l;M<>31((SPHGq$2H1q|$IckhDHExXwpMbZ1blL$?zGN8`wgPF{- zjE?J7?vbVpGcn=Aq`ZR6W@Xi3I2&8}{R3CEcG&tvZA6OjH|YCCGb|;ix4Aguj-;!#RYi!xOwU3QTIrx5i3RE>HP|0^b%a z5#Y!0aR*{y_T&ck-QE@#tba#(FmEc7_=tmz#mM+0&P6r7I-QP=9+s6O{^Q<`Wg@{LGQfvJRj$L1?@Ze*MY!nr|+W`0+7=BnFA504(q?eytLe|8wL`~v z%?I7>oa8VSWglN3Hl>jDK98+73)0_qvM2U*;xoa01i`RD97Gv^Ay3qr2Sb z#sQer@AV@U!#Un5@c~le66*lr zT$k-}a__K5~BQiOA&13) z5$Q%CXs&z(r6i4)I3vd^YU-woi(fmJa97>^ z7-eHxJvwzQYDK{`Ikozh{PQ#-JFmd2qF>MP!pR^M?GTb(YUtwj4$+!Xwqgv!)QC-V zT2k9J_Vs?&?MI-D$OaCH8Fn$4cDJrc?tAy*>sdaAb0=T<`|wIF)U|%|34@cZ2rc&C zBdN=C;r+ZkwqAZ$P&;J&U5Rr#&`PfV0lBC={F&P8Pbe2~xFfH&yHq_O|FdWTPSA4+ zLSP>XP&2f^On{mJR~U#Mk}*%pc}DN{|E*G1wF$GI0ADb=Ol13#DR5uqdiu0`;fFYw z{ikH8gmF!+{_j-=P2v+jDj5trqUyzN+1IccK7jgth+kIA2<*0e>)FQjF6eN z6MN*|eF&w6f90U@3vfKVyYf4@&Tt49WjwN3q;lzY`eIccneVvCY zvZNa*|K{C0u1vxoBdg+o)xcSYmJ3i9P{r3>TQA3b2uFWn`}q+)FpQYk^{ym>&e^`1 z|4>&)KYLb8Bd5Z}mD?gA5`cNL+x-A5aP@pK?F#+s@zp9#DCava+_m z3o}txGHBay!iZyWy`E)fWY>y5QEg7-+&&Zqvs+n}n6c*u1o)Ne)W-rN{xpD>2Zas@ zAer4Cu|j9J^g)QQj43*>QXoypD?$6tj-M9bRtw&*d0%WB7+?$i~# z#K>$O?@P=liUmc5(@exxd`JJ<%HxC>AEO19Hx#mw``g6}Ttu{wN3VAQsYLUdGMWC( zeD(PToan&~DO~}c3tUQANvU&=TSW)edgk{>2D4gIv*|`|YOwqHc0yE?$I2FXr)Z(h zosyTn16E=ZgFtg3eRh#^8wP@7Vxi|!X)Tdn*MXeQ&rV)=MKx9q_Px!%4t&HFEK3p- z0|83TaLa$I>$}@{x#wbm6jFjqrDpJ~2FliiXm+#VW{!QusxKL&m!!Q^ZY-@GwWwJ+ zQHbOksaWLMnlD9z{ez>6?T}!Yv$;&X%Jp-itUmb%hRyj!7c{fT+-&iaX%esd4h`?# zY2cSl5^o;)&9wLxr>pf?(!GGK!q?aB0)pG+Idy*0JKIa16gtbN95?H#A5`0W8Qc80 zAb+N;iL8jKBMrN+JKU0eDj93ZqI5a)Cr(4TKxS{Nm0>ILEz@seuTqWp606ddEQT(* z`LB6GB4YIC;rwu(EgYRx+=EY`-ztq@e15o2|5$LUhqRQNlj-O@szX4?8>u`Gm)$<& z%I&JaO$WYm%L%25@b+AI(&54%7pr(75BIV~K@JYiNSvs%ect8E0H5k6eHh=#2JmW% zK!369-0Wv>1U?Q8HV@5TK)Gs7XFPk$qO6i;abd3BE#4k3htg6qxjSLraV#Y@hv{Q2 zMXEUh?vi;)Hj6Te*#?%8MEI)lk(OMpw!?!d1=iNto-kRhMP^M?sL@lAgx5Yu@%D(e zY|q?Ht&{xp0*DuZJp;oa5w|%XPj7eMW}rW+rTP$9My33%3v%i5o1ugZ+Ouyw&hwr} zAFWl-8vSA0vX;g}YD!pfCoY;2}Osr}q#VB;}V49=vPasz{B4bF@*^4JSd?o~Vx z6dCj~@eJ!Upc8Z>NwR9QboJAYGR5$4>uB-ZE2cX=#44&_EN_;7)&T<}O~9W2=Q(S` zuRkvXJr^%`c6J>1=Goo}*mq4Xj3_EnL6ze|wQ6i~YmrtHSF~ZNDsCZEM(?>YMAP*T zhaGP`IW2aXY-~u9sPi&+Dvj8BY&_OXbtQim`upcbISdA33-dew%*rYx6@)HL;^$_E zdrsY^$a)-8APz;Stj23?Ds%csTy~{MsY7yQ$8-g12|-`pj2?;jql58Up@l6L0}F_Xy4yFQliG?MtF{pNxI++DMbI@am=N|Lj&KIR5_PTo!cSWAAu~;m2G(>GZZk9?ZfT;ItI5-)p_g?EYBIQ=FRNT^y zq~e@Nar8(XwT>zFCT-*DuXb{Mn|TuIZq{q;m$EvX#jV_Ve~|GGeXzEK^6!oWVk8vf zMw0af5hR(L@3<;kC0QI|rJPJ>7EPKOpEEnQgb2gD2UkhZbOlZwon*wHJoSCT6%i9N z0b!qYwCF{Cu3Y6~u_->3eD{ei;kdMKwet6^XVo`Rtyzt8E0c*lYuN@b*x+|+#-4S% z7|%#>Y!lGty~#3SW+Su`8N zXbWxCn-d33=(#6G78vRke*H3KNnivC%UR`*J+@dZj6l;mvgp`p(#vQk@D;R_!wiQJeMawzd4{uM#;$T^5+d7JKfuOZ_@gSP#k7TN}$0o z3P-rIBN%slTvt9Z`es8mMkH@6SGGS#+9p?q=CE$T_tG~j&%l_(ZqKy)V1cSrpWj3- zq)}mbc-ame_)0vibxD7n;c*nbdQL`0!exB{_jG~VTKU_&bo-56ov_0p=qvZRGJE4A z_&F8(RxiJ*ISDwtV>PVtv~c4kUw+b-fQAz?ZTpr|zOndP<0nKPt8cSASapm~Xvwy* zE_|xag+0=2bZ}JPb@zz>0XDw&mF-Q*?x@fXP2%q)6>h3jh<3lUT;WhR8BlLNyh91^ zQi|{6@MTl85xCh=b@-YKmDe?L1hx4#8#W{6wyAqaIHnH_E1PU*3F z=7NyRS?`GIc;EIzOPlUV%J{U(dHAmU*RpU&ciojEXNPSBm+Hd9m(2&UhkdLE>mxm7 zl2HciBHhYB;>@Uf?UvINNIK|b!!<57B=nB?b3uA0-H<1)D?JV6x9EgxXsV;2lPS)n zTN=|Kb8^ud)b^Y#EI5v!OSEg)Of#-j$Fs@nrrs$q+r@fe=62ItZV+oR74bDKHZe6Z zvRA+I<;qJSXb`6`^cLJ2Cp(cN(@C;&DD=y};MEnG&wE<+2y=dQG!1N3qkt zjjwg{ym+Pk*djK<5ciV_-sUDfpy84ETDtJAx%s8_0@ZeUiBJ3ug8iwdk^70yoJkjL zyH33fP6is*EBH={xqd1EPULc#C87TYGMbjtS&)PPYW=0f^%*K&{y+swC zo@07VWI@w?1SykNWJ@$u28EkDiLQs%dmX`uW&+%4RxRCC7OA@V3kx+ch3TBCy*kGp zaYa+}7Nnx$U3S3)_n+)a$$Z}!M46<*clkGN<5shhU7hd46Nn?k@iE!0boK4}$A){? z2l%<4)^8IX0@k00@=bg7hTlFyyzO;$KRD|Lh*Eu~n3a-HM zj`A(Lnw-v_r8pKcG!$Wp^SD_4)9xpFm(>#8VRAq!Bw8SZCeaK6QXvgtr{Z0u3g8tc znK&tyK7=#Qt@YfETXu{b_DFeJDJi!m9Fib{@T%{TkK?*tMAOq56wsSJNyW!kE4IgI zDbCH8ov1EACEX2@!JhW?Fc)jd$8=qr)aP#_;Q4aa&I}>JyjD9y;bJQ z`-Ydi*8KB4HU3BVHx($iA~sn2>lKZP3WU%3K)qfKwQ{s(ygyA3Z02$R?z z^X5(Ny{v}Aex-?ryf!m1{{Vs)Iu1Yb;^0aCC#PZZmfC)2=NamyZ~J#fD;!XynleE# zGkyNFQ|!?7d662#GPAJvn&-5D2c##gQ_|V|gl{$4KDaxHns#>h2gAsBzHl`~OK3W+ zhA30o-pejVhS%O+;>PNln(seMTiyCHIU~7(+OJh0kT)rB@(_HNHz{Z{GZYIv08wbh?OIsxN$jYKu?+{Q{UJbXx)a-TYT*X`DVgB5~pry^il;l`u zfnw1E<~)QmP^~*Zg3HzkI%_rBr);fb6Z0U*$-3+7qf%QA20<=+bIrHCIYl3O$3Plt zgWFr930GyP)=MNVmyuiRQKTSus691=v~E6ty&P~QeU1Va6;`2eyYzvV{IoK!G`d{z z@;K9LvGqsDGHaB#Z!Jj_V*xKWs?)X(>DYqm3CEvEANOYN6%RRz6<}va*q<06imzsPj3U7vwh0gPa0>cO=>w+L5$HD*^ zX9Lh#_a$9)uOJVd*(>gDdV>N+h+_d6VDVA3oc&#|(u4oUq#C#2R*ku4E&R|RHFsTY z-ar{{IQ0xqjMI(R&6@4DA+&8kSydq_!>E_;hBJvzIe1_oYX>iIi80&Yo42807rB+O zP4l(IWhpGAx|o4G2og`(R2Zp5BG?T)7tO(Xg?@69sM*1bAZ^3r;E<}nO^nUF%B%7l zP#rFIT?NX+aYAl6AGnkxQUG7NqrW(l%Z;}gt5l< zaaq}_lCM$bH|5doG*uAHH?p%)j=I8Jf_9y8emNJBxim&%M^eGwj;Y~#3U*==g!66Q zu3a=p2aI=f>SrGbHY7}*G-~CwG#uCHbIZF~_I#vfTZa&tsk=&mO0=Rh8>?tW9=T_K zmF6cPDdVB$r4}e&$qa2X=I7%db+JA2I82L6IzR0hD`~v>X<aLr{ibr*bh=%A~j^yW1;`Z zt<@x|E2882nR2}+O1071jH7Z06TRvUXYO%(khRyf0w=lt3y8Edl0`={k(j70G$;p# zT)G}gqzu{O^Zv z&e}BV`!D~@T>11$NpUhey+XG~P1qwO68|mEZY(b^E8Fb(2c4P_e)3J;+gk{bCqx4B zj=unl%0VkRo`dZ?3}jVm=waK$Uy$66bta%Kx+#CFuk6};t@h$v^6CO6J10I*ChXVs z1(ARyqU@=q<(#%)n3P~HbLiO<+thzePB;f#r7)8oW*l|^6d^6N364F zsgW0I-8Xh+&hu%^*++O~4;u;t96S!_=#1~me#W%n=%XMn=b_tiKe-~jHQWmI0uK_F z=PhGZP3;b4E|^XUvMypzrH|bRJ*%x{H7g8)J_>YqGVk`R4(!&}+RVspCJTC5k5q^u zug=o~aZkil1G5^;Rz}Oa; z*Cu>$95F`hBgquhWWlV-IW*9tQ(k2d-+vU*<^eB=*EETQ|Ie>{35mTm*P@8UrcH3FEn7!n6uNM~n zqQziMg6p*LBQv#SHF4q@YDbk?*@ttl9bZuciYuK4zOp4UN>KBt5B zt#ZmCRSPRT8R8frj{uC+(QR7BvcRRM%ZEsPg-Y_0t$sgl#al!#)av`t3v6PdugCHP z5xK@J`bb1~OXf#3!9(Rj z*+$9%v{~|P!FA5__iv2Q>jlu$g;cOfRR#;**|%K1caMC+qH3N+PdRz`Nm<$B@hT{I z7ZX6NGAy9`2af23RKRkPc-ykApBEZ^YHBoXx|zl=B`xh@xd8qx^FfM4$gX=1w(#ex z1l`E1q*rAc(An;3(;fshl{LkRs(oSM4p+^L_aX6AaRfx6m~BOwQI>#7rMCPy`M3i* zJPANQmP>Cg$X)k)tKI710-<|EWPb`Z989oCIo@$nLrzP)Q+S>B9(fx{;pAomT|q+( z^nW@!yq@oBoX!0M?4v-ITPE>v#d zZ2vO2uo?Tom%GDp*`=C(hC zbNgK-$ZW)+M?(_7K3si#|8Y^O7T9JPZ(Jw*#m;Rf{7!fDoP6ZJ$b1eFuQx}@#LTC@ zig=d49$&KEA-Gvrcf(ENA-O*Qph*%6E}g6A_@Aw(?bB>()|VnzlB(uV(R1+)?mP`;6VZB;Kf*06}}A>M8d3_ug_YX zkdt4U(daMC`EP)CV)O%6-on+$kN02pECUMm_oE33NkggJyZgJf!5hpkyo!!rcGc_- zPr^dfj6|s*Y5MB@qC2#?2XtbyAXC%H&gyENm5y065h$X}15$ z2@5{)yEcU~tV1AG-f|iob{+Pxc^e^JISEC-{ki#Pz1N?Aj*m2{saOhA>xS0@ahbw8 zu{4{xeVJgf9~-tF6RWWD2R<3h1iC$`tf`^7m&&04qbJ$2m7ibFzCle*J!M`*4A>{W ze(f#mnB{GUjvf;oov+Ej$c&sCt9VzKYT4|-#YI^yJ%;ZgF@%J#g%arB=*^0~_Z(j{ z)B+ob&XGRjsJiuZ_0Ogp!zs8W{MxFZqGD7zb4OVLqQYMf$o>cjq>Tmbs#)*N*A&^` z1ZC0AxtN+58Jzq^ULNfG;N##BKx|?-3{IHK8OFvkKH@k$^jtBP}wYYACH=n)Y z__&e0Jyo_SP<8v9nvg3vryZB`7n{vU@}k#uc3#dxlXH>1P>>LlX2Z{2Y#n=hdu&nx z#P0=>pM^EDSK-f*H1D<)(`yqWN7E-$P#<79eTwEd6jvxNK`E0g)xJ`WZDjD#!wlLRpYKHWd=G$rpU7O1i`RljW!Eamz#^oalWslBNP7u(3B z{6L@3`PE2y*uwj}+nW(pDx0LW#nrHRczIo-tgTyq6qjCFDn|l?Y5X0=J5}D(T7w>` z3cp8zs(KUsi`H|o`*XFH4*S#kJ{pb^2;ehLS(s0uf1CL#MZV? zCi=D!lUABoq?~(cS}rwKi>a}(El!*Gva&bffe$^fBc%{XMDwEi2%c`UBSe8nL^W1a z1{ZIgJ|ZC@0YK%0lqyUPNkGW?+p=aKWR1BFJ6dCJQ6iTGfZKx{X7_;1>Jwue13eow z7hE+yZ^?}3)T)frQMY#Kc)CQi{`$wn!_KEmH6fqIf>N$iy^yXw9U{U(Y+8Xn#wX+T zf@oUXL@WZeY1uJrc-)u??o+q2=Oq}S^|zIEhqg*z)3YnhR@dXOSQ}4WSOX`c8WEBc zejU9-eSO?)Y#H|t848eIQN39J>kkhLPpC!Yi>jOQXlV00{VccoVA9#y9^ucB2FtYn zgGD^I)ao(X_L~I2qvxU{3zW}K?9t^CeX*JZ;)(|*e z)g4VTQ!syFk{8jOBhpadq-WXKzcAb!jR~Hzxe5{32Ws(qLe=yaupEY~T5<)-+17XP zHE{m80kHKHUKbjT!nLCOLR%hx$3*S7!QKzmUWh!^NSI-aEe62joteC@y?XXMIYf1* ztYp;m-amXPfI*rYL|<4;D7b^7WMW*UOeD(B5KncFqU>|Ypvntf^^k&I`a&Le)Q))y z5_v7Sa+L2ak4Oxf(4$p7j(7(5oy1ezJdP%olRy7r0cr8J!ifVV(@y$!<*A91%7KGA zZ+Bz5EW$QfgM)+bb)26AFdtxj4lp=B6I5f>%W5h4{rjJWhmwjf&TB&`;L8`*GW_LP zIrZ>%IZ&e6Zr3NsvmtP|)Ztl|K%o#|O|iYRts~$=f9gOPfB(1;5(13wFq!Q%6Q(RC zUx`inQi}*b-+*!X1n2lxRa4V^h9MeIvxpT8w^unUgWe{{u+*wYNBa9~3r9IRRxy?- zDVKFmO-?E)gtJ~uXJlE+X1+Ex{ZxMPNS+fSbf5{z`WesYIoI@0O@O_a8)oiz-(+p9 z&9Ue-)(=SMMJR4uLd8lRo1>id1Fc;{q$nc>k+PLnVJWZzb!QcRNB>`o^gEF@ao`mR zRKbafi7j79QfTy_6rQEl*Pm}qh$t&73oGikuDBV}{>X(bU0?BXyIg%bV$I&T4Bq56 z&n6|tqn!Tk2V!Dk-a;m7#Xmhk!@61jJ>lT6F_bHsTU@OD>&13Ju6~C8fELgB?o!+% zrYq!l*$IP_6K92my}I#Wf}*;@^VcMhO&Z>Kb>|wV)Y0{>)HAD6s0T~83zyZN`TlVG zFGqvC7IN_MZ^q;ASY}hx*0#GW*@f#!iB0?In`6jfU*k<@56M}{9OuST9SR*Z=W>#G~uCNFIC|Tl)GOrR)(A=OKEb)eBpTzFd0*+TeB12ZMJzJ|&;W^S} zQd63u-2+0ppRo=O6xnILe*N110h6mcz%h4DhS-4Wz$f4*hWouvjyJ$sXlZG+(VqnF z=?-{=TBcFo^6k1{?)OCBRPDi)VW0C265zCWh4F>g*A!#PMS^~G7?_!xX{aXxfHXR* z+v*OcgTvSi%!ECm|DnfiVG{!zc>yFzH8_@;idDbO25MqrqUPOPZ9ZB-dP$!8+u$Jd zngG?o==tIZxy9oj++%D<-?5PUS9X751fCoTY6R1WQx>TX!69A#na zW)G6OFf-C^3|=m!p>?rpbK5Gt2y;2w9^j4;R?*?DwFQjy`UeL~S_*GJlM<&SVmlFeys8y(X(__UGi@uqQ-5d-m86 zP$4jDRX;(0h66N1UPJ~@u>$LNgP?bf^SX&KSH0cl&K$SyUF-x#|NTP+rQg9}*xBtp z?2Y4cE#WudpsS0yNHRr1sMM7-FA5w3SaVw#OLR2Z6Qp_>7(kd8+gB4r(d~5f^crtH z^pk2zfIc%IPXc08UawShvu9yhMODS<#8~6?kl>vX8YP_^5QHo@Rv2~QoU{pnFIr&D zwr3R7V96h=zzU5!j%Fi&$Xa5)Kl)C9X?|!b?C+&Zz7<8?!3+Sp0fEia19(KJ~}!o#$+>5^jbui1wrZ~^^ad*K$&`llC-qLc5lw#uXqyNr=3GLugS>PPOUGZ!RmqnqS3Z1KXI;Y7LDo(VQ*um?}xC5%f9%P{4<`+&#ZW{HWf2P%eGOFJq$VSh-(m z!jnP*`zVycvtUR-n<9o|wdrItI;02=PDl$!+IMC7sYOsZ{NHG1_8x}DjFP>;>PhS3 zKDmJ~Ht06_TzT;s<>VJD|*Amg{is0TtmEpGvR!D%6$MQo+Up2#&e zAdvp?nwyW6HLRUU@@D#}Apr7eLX9bt22yKnOVbO5MILiiTezdvSJa)!w4YJqvS2etd%nX1Fp>Q9X0e^2++w zL7gx!a1%hY&$J&{>s^i1A8nilSjN+NzAeYF1;<~RZv)pI*2Ds-n^_Q^%UvRdgy+^9 z4j2Bgc=}Bwx)9`I|Mf;A>YTq{i02qGaKa*^fHl4~JVC0{Z{g_Hj=vi;5WYN;! zk@~y_RF?0rrn#y$Dm;%{1g}~3>OL5}lvZV8d&iZn*3;cR9A&4lu8+}50}NrVY~o^$ zg$eNVxM6J8Ia}5`uk%SMi3vRMY&tF6TE9*3p4>1oVa7-iXO>BlH}!ECEjYyn|DC`b zRCfhg8W68ozxN!*3U# zn9$kPp^TFr-vQyC${njXsW2u^qG}Fi?tRG>B>psx!1Izgg~ZlA(}@)AUPz0ALP$7Y z{o?&-xrQZ%bg-NbUu4Jp?;mTT;-coJrawryr67=M**Pw*8ZO`88Li|gjm{&ZqZCEj z{PpN3Q^=OH!_~koDetYBkZ}#(hU2-;>f1)w2CZ{z0QE3rPgnD6g{9?~Yfu*RSKJ_TTMM zXDrX1YF(2J$Q!#u`;X=~Cym8T#GJh4W24WHh2xqE%HDdf)EymtqhN`<4_PSNB@fP5kON8m>UjP<5LwQ3Os1%h9XQ@Y@5>+5gc5dUtY@ZK76`n~q_ zt2g0?iQ0!ghYr?%WN@s*7O31IyWdtmT`Pk$V-Y)noV6x2!7uPW zT{ipgv0Gtdb;tmMGXX2ghDJYBfCAxS*<*EnKB%C0J`>_FHAtLAkwwqOb2{|`s0iOi zRaH4kq5Izlnn*beYd#SRAOy3r-uA5K{U=D_0nbwlH;jPw=TDB!V^>lH$a0}61?MXY z$VV#ilZgpH?_caO(3))0VyAudybt!D$6KG{<#Pk!`fgGm?dyL-N5OPaykC@n9R)x$ z;r(m}a4f<9Jgxsv;rzegKmV6QPq6%IrI!f8+>t<{I2jvRR&D-D4IDZc(s>(b{#HDU z$m!r@hQMZl9wmt5fWAg+a7ZamM zMh#%0?Z)LkdeC~QmW2AtJ-5om7Vk#WMI0%E{QSa;%ND5HKF!2Ox}yB>k7EU^c?Ow= z1&?hIm15p`i%pvo+WUh0+^bjhfA7*2J{YbV-~XAfHsANHk$ng< z=t8ozXl>hv0U}Lr(OmLs>sf8)C9q&hNKTIQ+-wOd0M9wIL_a~tz?dg#Twh;)+WukvC;O~zXRt)9aYBXU&A6JBk93P3JUopS+bl|R0z>y=oN(S!uQDI zK?Jt%TJ##T&(HmOtE1bi17>5pf1T*5Fs zkY(+BV)@rH6q^L|2uAyVMxG862ch2Uor6}5k7TQ@4VpbClrW?n^uA4vm+eL zzyUTkHvF75JqfIEK}~ga9zI^ri|0)yU1@A1BYJ%98~DbwH!dq{c zsBN7UYgZO~Z0b5DjBUybIXHm4*V>mezPg_tM8qWI6yB-oQDFmdCq0-G z&7gm=fSSU>LI;9DJL?f`5s?8{$kYu8J3A*g!n0xw0Ba6sTTFI-(2I$6)Y>2%Hr8H8 z`W&2Su*#PK`0a4x%~A(DaDRmWCFRxjXW@rH0qc$2836J&MZGUE(L^wgXet9eKY8!^ z{$C?Jf1IM53Jt=Tp|5xndVAU4wJD{Q)m_d_bO z*qIu+Kjm#eFJX2~64^&_0t;mZO-jpRhXhH7qh?BBWAV;07=OiHbJ%-lK5z!rnSQ~l)I-TJBksN3I1M(pm3_2IjF zxZfUMlZG9D5;?3Qb7EpXmPA#yrKWg*hcm>aH}xq4M-#F-Lpiv(X6g>kQ7Z`|^7_j)gA|Gn7yh)Lt^3g<3TZrSMJ_I$_{Ed0uR8Y*TC1cebxp zQ}4X@)_m^?pTltY7uo$plFRGqhKXGuI^r|kOhE*r3fhe#@p~0ABO)Szj7&yO?nSxh zE>}sZb_17JFB5OT-aKlhAE_WJ>Se9XqI)y^V5D&~61A_p$idNhO>Je=eCw#S)_R^s zg7qCm-11L3QiU4n0LxxNDjW> zv881aE&(i3Y)eYSSrqHys|U6ki;mO!N(_+yMYd6UMu~?!>&}w~gB8`}4-cU?B=0n`(l~&nDW1q(@sq{9RKKHA4=l|xy_2YpW)lTX>i;ZB_JcU z#3A%R93AJ$8hz^dqofj@C#o8+^Xn6yw;6N2!ls>DLPi1Ag69V`rXL`ZV;$nt>W4W2yqZN$=+bDu^WY$-qaT_ z8Tho$ctgu+ZGv}OL2>my6Av}vlDjj7jQnw1>_&kmg+?PVD=G zMWBH)@L9}@NPDlnpyKW-60OHQYpOCb= z%ImmmIJ#m~O`$ahyS6rGZiWOfab_Xe9mVjDKN|#!6w+Y1k&(#^sIF*4bi8ECBf{5Q znRgGaXuuscQ)G2rv*zwLb+&Li27tLP2eWK^g$6heY~;&+4%=36*v!lq)K{kWFU+}Y z^=((03`Xe@thhA?33BHp=v{u(9tG$lN3spkX15!}sZ{|wKj>9JPucp@s>5*xJV{sFqo6mrJ+8b%Qj+h6WL>!mw%Gp=~df^ z6?z7AF-Rt^RqYOkHnCV)G0)}7a>Wc8ez12HSOoY~$wblD4d;jqU}`(&VN-DMI3l*d z+uN@*t8Q1|!JVA}+AQZst!+V1gE(WSMkdy6dGbQja<36f4af2!Nr2|+r+RU8G%n8j zpkP@t8#XVes~H4^wc`4Lz?$n|yr9mJik#fRMZ`;^qFpr`#04yDpT7zSgFd#0tw1f@ zEirZ5tXF%WV_>-QLF6~k)`=Z9)OhYVMEIiK29bA_{sTXXKhmG7?$UoTa2})L;;VcA zz1UFN#oyIu<w6ikvDp$^v7_f{&6#0M=JZJ5iF2y!iD^@R^GH_jMIWOpZ5^r>8EYBj$w!u#oo{EE~<|=Uxh->M(C*O<8-pw2sYR z?EMN}q&hy6uch%K=45t!=j-oZwMD{+MLDZ7NL4}|9FV|O_A{R4{maGitHSAH4M~&se=sqeaKrGV(=ty{}o9Y>*UGIoQ#5hnXNVY_5 zVcj!{zX9TstbTlaqRv0fJ7VJ}FCdih&9ihCyR}jh*U$)(V=T%aOy-Ybny_G`15&l0 zKR;fs#EdAiQ2}r?)O5xd;AOVIG@VObSSAuFna!NB)3kvXb#_Hz{ zh!?)+ws>FeoP)SX1l@QT7_L$P&kVFMhOk=NKaUkNiBv8H300Xiz(Ad%*w!ig2DVx1 zm1#-MLr67RZtWySCel4}%>?0uVC7|!*u!;IREi67z%iuydZbHdrNok-vw-SuZ8QZ- zI^u+Ck^I%F$Ro7JYNZO%3aD1svHOLE41iuh**nGacJLvN^9$X@rKvEELmvWp2|o!` z)W_c|z*Yc?nJVa#Tar>z%mkHqm^6T2OmWC0==Yt>=6Rkc9xqd?a4S`n@IP<%`KsWq zHx*L;cRV@0klh6PHZRXC>(1+2h7;uRcb)Dcx*EOVC_s3LJ02sc{r;#bUMD-d2ix-q z{d?q6N4(Pt8V}*QW$eooux!JM%+mJ6W&K+;c)t0C4_XhFf+SB^vOe? zk??r0J#v2+eN~|kb001AhvBbpmb;(tSKDs;4&i6fx@FW0dh?lXrNeF;KhBLiZ%*n& zzZ!P1-J0dHf3`H=yIA zB4A9*0W_{3-)`kmp+uymv8oqA7BxNtsVLKm>a&2&pBjXTc+CQ*n5O_cOzTOofsY8n zmUR4@JuyC>-_Sd>dD~u?1uFn&A9Gsc5x#N1SdIXAYvj$`Awc21Xi`cnNT3HiHoi;w zt}1X>3%Xn4YYi)kX=zCd3k%Wat>kTN%BNZEnsQg#Og4!*oSWe3aCNhh+fWF~qm2|g z^)ZxadW)s(a%D%S>g{cieMRLu9&T?Q{~yYM zzTQIVAuM7Y9l*X1!-O?_>#J2UTPI9_*)B0|PxNoG#*&ZQ?I!!qk+N^R5HNRgJ~P z#oe!f_43D$5Xtxezar6@?~jx{o0j0D!?!tIMLU=+w($An%gTZ)h47wGj~9!MA2F`X z#r>zd?)!KJ^s<-G|QDQV}t73G7iYvfjE%{V9JPrn!B^9H9}3AHRB z4#X@=KmK?Yq}=W%I*n~3($h`1TLhow?9a4NCWkwW!e-3e23Kbb5=;w{Of}C;r6yt$ zBWTR1G;k+kB=-X3Fmi?0HwX&1ibfIu5MgI{oR8Ay2}5u76Wg`T%IJ6*VU9cVg7>)h zJlZ?fpY7lthJkF}#S| za=t?UCX*Ma22JGCN(9{f8K5RIC8b+DmfkAeBRy<1e5$TJTHMzBJiLgSWA28)?&`j& zum60_KS_8uS+>CAbQN70H`w0UZlww3CD+ZSe^q#G1rL~UFacgM&qXP?I_lpyuqW0a z=j?Nq3FMvfBtiv|@}y`Q;>|is0ov#LwLZ};QFe(wng2^}*KG73xm``N<78!Zt#%yT znQ$TY(Yr;&W%h|DsU1lK)vp)!ZM7#f@>7d@KBoPr=N5D~1F9dIvFkCGIN=fRw&HCp4YTQz?2+#sXIsQ({ z_wh#R5hrS*t?@)baTO`-{*fD$TRY4-A-%)w-iQ247=m7wB>x`?!zB^zp*GkhVg_UP z%<%fWw|jaEV5&|};iB~tZ7!=*3Cdk^%kpO{U~n*NIg*Z|-H-MQ(7H3B&m5yz@)W@e!{T3~20wK=o{?L(2o zx)PGm&-epSG?~#uz5O)nVEu}xe~~f(PycmJ2?~Q;#?oPmhK!|1GR@_38E@pC9|~nJ zUsKl&MSKI$D#B$wHehhZF#y0ZJ2E;{0wte`gX&qD5wH^_pLJ{HUl#BGzxM3EV~_7E z03-V#PSU&Mr<3O|!OW9&zN&<0p-=_=`0+#iuR|B1@0DO#=M1MLDq!CApY4BxN8j6n zZ#>@sU43=V*S)^fu%b17PM5`IA2qb8vwMj4SFP{mUiue+!Jvv;8|o@w4NEx~nn%MX zUISEZydV}Du6F__=Oxgg1W?jFAbUacHjS9W78tnk6ac3Jxg4z8*U!!-#=sox?E$&r z$K4I9HVMp13*-9~2oT=I0~ziS3)D;?dvsYwPx^y~cc#hV54gcFpzXNy?~bT;Q=J{R5oM2~V|%;b6n&Swz~jRYLp@ulZG1UVi_jsv#>F0I9CBxQoBP$m`@oE(9m zAhLVx5d|*!ZYa&}uQ9@%(MFDazxtbP_dLM9uPD#u7?Cr)JiKGEe%I2%az8R;-heAd zCtxFh2ZZJx3MU6!p!N!vfZ)Xpm2z^i$;rxP+~4+g`O%GKl#9+g^EgMn@Ay+{H)<3U z_VwC$6GM-9x_us&rtm!ird;GL(3O8Dg4-WWyuX?GHaOll&&Y)CevRDk%~f0LKgId^ z@hK@CF7i)jPc*ui9d zCTi7oW-0OUDuOikm!x1aI)P32UIrL3FqICH$9x^o`5FBkr=1}ePvCO-=EYE{q}NBh zRwVBgp`K;!E-WGc8qcAYo7|o7^Z&B7qc~l?+k^6)crfh&-JMaMpZ8yWKeO$U{jYh~ z|JP?vc<KfE?ADXZhW_=t1B9@E z#ol+o8%z@aUsDNg0Ffi)xjVftkR{)3|HbF8FzmEwN#btjosZs7=AB8!gFBZ#71C`r zXxQC902>WJ_j_lf@eg2;XLPBQT-S1PH!Dy8S#1je`Cz^VZ=H9N#Q{|LY_F$=Ung->H2AfO`MJ{Qb@BGi_x~#sN6K`yWF6 zi;0*`4TW$(<<*$~`3`U5{UsVgRV3L{r}Oh)KP*c@ha3WQ$mzY0{nUlOd2iz&sT?-x z@%Uc?48T6L1|@A^ex?R(_QP=cpPFLdzXTc;#IYQIvr3?k=&977hd=cR$Qxil)=5Z) zSX{JGhzpCW(DEN}kaak~0J(2oKcrzu!AZKlXD*%OPbF#tb1HJd<+w;@bKNQ0UgMOex98G>h2B<}R z#lIV~@*ZRXx{$%YzXK-Ih)v6{BaZ(QRpo@`!zKqDv|avOEtHK2G@~I@@2%td6_5Yq z;O6U~Bo^>g{@i55r~#+m;1N0WQ*L`ffPq2>9@ZPc0dfBu0?GOl%5#C<4)mhH>mv^I zpJ2cg!2oEAA+r*G`XpShfOZ;Re0BUkG8ydKMsD}IH+Z}L1 zUB}YS%#fQ4t^CF<&d;xC0C$H6NOYB7cX&sc#Z)=6Y;Xiy^8HM<`cyagLOau2MY)B9 zK$n%RRFcVS-UKTkybsD@h zPr2PAe8eRQ@dO~KM@;d*G^L<-zb^*8`%giSLWmZFIAk<=3O8AdZ3uj*I|j!_Y01gE zyStDpy!rV9Ma2LtjsU>sV*5r0hQ^rbmS7{M67UvDrOv;n~Th)L@-_*%kk0#5UEzQb(JP3!;9U&AfZ?Xt``r0L?<+nF2yC-4`*EuOapMk#7c(u9?qxEB?Vb66kS6T^qQ&S{If!rafw+kqxTOB_iSW{Cs z@bk;s6a50LDYj&kH|GRQ?6O&*-=dP{nkYbBt@it}p}SEtuaWS$kk{vZ0Z$lvFqMa6 zFZoG?MOS=({s=j1T+Z<_k>S2bO-*fGC)0YBH{rWq8iq)%%2As`^dKTC<~0U(YiECz z;Z%f+o+bV8Xa#43G@MCdLa+wD7w504IV~ld~7T>n#fz6T+B^(F+m|y zZf-Rjc~kyce?z``9x+uy4wl%+=yr`V3fr`EL`1fZ?yjCr!8H`~rMHBFf_#c{V#QJQ zZ%bdvtC`w3VB*kdM05*^zrE`1?mTckV!eWtzyeZRx|5WK#)_!)dw_J*&TMNB{|Gpg z>6L|QO45jITvf$xJZg!#-rhf)=&C}LKmVkp0Tl@3RAdnflJm@R0?f2*q}1ee%#`$i zCi+AmqWc$z{p6&q{oSivcB1su!ldv{1b{btFIY@S#}v2C%tgvZNiEk<-xD3NFMMce zF|pF{Nig3hz4Mc;xRj(U)qHW;(2$_Grl{;Zn*?`)j(zW67wyL!ILN$_OK$HD$^LFF<} zNSLTh9>tBBUyv1zj-#qWOC-)sDtM01{_bP3(JL&hQpr?}j_z>Z{&t+dv4^+fN2R3< z)>cBt-*_1W?R-tc60q-LK2#b|W`BF42>5Yt!b#x8#S-Jo6paxnJNtTm-tB|?#FqkW zEwR2vvIl-pesjp7nZzXR$x?Q-lQ67c1?%OdUkP0#z4ggS9_(=TV-7+>RS*7!hu0c! zmUC1Cq9V|>(}~(Wy zO#-Qxh~BSx;{g7!Y-n>qmy$&hgMT#&kYd4PXLSbmu!*^d;(5}hcR5Q(yRwY3g1B1W zOdCJF3^NIpCv@ug@EBOll9mn&9xHz*{GvR9+hYgkfJIR6_R#?^@B`9v~6j zQCKen4@=90`PNxJ?J3=A$#g!Hl^V}3sZVfkX+N}pedeK{GMGZhOb-;-p{*){o?s!L zkF@1_WBf^;lAIC*#Qi$8owhHe2@zX`gnUJOgZyD(i4Le>KS4LSes95o*2VGw5gtkx zlV*MHQ`yLEDzCee=Wxr8d~pE)_1PYem_)>QcvO{ru3c00^oe9F*S~SeWC8>t3L~Qh zT~SJ!jJ=%D%V37ER(wHZ4=SR!AHi%S(@C>V>B>Qv*4B&ddAG+`X*inm%KlsWv%d(4 z=6rWA6rb^kNYE0>jo@Nn7#ILru=WMPvp-xz%Y_xi8WzmBxG9HA?QsCTtY6gRUeBu6 z609^>Y9o5_wwl94(Ll(CzxG?`OM5<$J#1~35)n|4#FCL4O%a>U>{XVV6cMr?;FVGE z+2%XZ>iJ#o7g!);d08F0{w%otmjwEKhtr1c9iU9O&>Z{iUgt)Yq=KX%p#H)lzS-&*Ec!bZ@Ropes3*>qv5#^ggQPVt+c_>G z0{dHa$BW^%G5(blPauSfIIn($O36u4s@N@GTKXL%u4KQ4>_2#Jz@x$&;}?m-K`p2z zZo_Z!TQ)O}l{JI7o`R6qv!OQq2@2yVDh_MdnHMkdTMy0`v=XU;LI>ukm6ho^Gc7Iq zKi#^_^u={aUh<@qkjTyvkx-TUrCG+)%#yi~ky3-eQL+D%_ky3(v$G9f`?piBLOR;K zT}99kdF<~liG@Nu%rvwFAiPnnl7`rW&?CZrAix=6T7Gqt4Iy7XBy+ozylJVn2*OuA z-NO=-6aQz;9(Tky+|=QbQGg5HI$O>7;xCE9SdrOBeLdGm65TG#qiM1SO0BTbf&yH@ z7rU9|rhB5{;gOA%=@%uuXS?{++%NJE*%#1F6ZtZn&JT<-cXSG-QFvKc9b>JmtumCa zdneS_*GAdcIB@i!-=765h;MPR!NDZ`Beec60z%1s0YN$$CH!l1u1+C&yF-38ncW(l zic-;AWcz0HnS3jsw+tM@%k^_R_AGEYpnf0!|GqBpaOFG$7kgdtezS@1S>2vBQt(e4 zySw1(*}czzRPxC z?UA`SVF~B`?>V`CMTG+w0ljDN`hSzJorC4LZPS|4Y^K5Gyp=$B3X~u&Ozlv?OK7jUZ@ULX=s+%|-Yq(v8U0JpJ0JV0`su$FAo7tHnf>50UHnX_#UuP^`&=vQ zivFyb=Q#^2n-rXMo;on#GLk~<&uj{pE7HA>Z7>Le;Eq$lZ7=EfjpA0`?zqcJhY5r` zt#!u1ZY)EkgrwE9=8??XS3rSdkYfN+H~U8?NEuGiriod-F;jUGMHCmzd$Z>TA6+-6 z4;{8n*7}^mny9QSb6n7ok~FKe73xRZsd2XxEi=MA;*`1tr03ZVsaje;_P$`d+&v~f zV5Qnxs!fmf^}5={5=Xu7W{qg)y%_UGiS`vY=JOd7J+EOJzspEwr>7G+Twp1f5s_xt zHJ+psJ^s6-Fx70RV&e-^0f{3XHHiUyG@lUl^us=u!B~(ljA*^mn~E(BlfM6EOd=4| z+cb^oP5?JNw9(l!^(~Amk?0u? z$5rl7qu4t;X23g)2|+12>?)?M7#>W&33GYAe%x3RywUnSTonMDl)Y763ffuk_R_Fg z9)*Z-mh39j!-t5io=ugV^nDjfRG>$Rz;mg#Yv1EN$>fBo-=F`bDE!12Rm6{6+AZxb z2;6W}fzsXbAQJ1&!bO5Om2yP{6;X-7%_>m2hVz~!&5}yQYY%kb)6*Y~olM`cop6P* z*scG-ZE)1q(FKK2b2TUZzJr9bxOF%;SLlkPsX9kM+EQs^DATia0W^rS4YcHRigtM; zqobW#E-uuI$f8dpvBe!ewrq99COh*8xe&q~8K{oO>ob#6tv+dOVqa_w(%#I)Fu`%S z@gKk4J>@B~yBY1);8o*3P4an_ZPs0%XENgPu~{ZfqMJy3_aXN-ir0qejNxF zH_A(s4722JFd3O6736zf2s_vw^VJIw$%UW9yFlwGuf|jnb~%4QNAX98FTOAzXE|Qg zl-%s*57So3t4FHGIQL!+{1~GT;(!R!D5~Z=3|(xBQXg9Nj)rQG?*S!A9XroA?Jj!c zETH@%I5^?1LZNLjg|m&#D>9|X?&@qkp{r5z`S@c9{KRY^2T(w4^1Ft?QwWw*yo-tUq^SiUaNTH2Kt-K{t|$h zVH&eUW{5PdIRA9Vc1y}%o~Wlakbw9tHde?`IF5`MWIGf<_8-+0?7W>=>4AoKu|~vd zYAunrQ$b2fvD|opzDiHaJFv#;_Ao-76iBA|%!aZ-cPcePLP8RL5^%Lm`Yj6p@ZvD42>d8`WOJKRTJ6SH zuxYl|%dD%Mf+ph2w=}O_CDPK8N~C^qF{fplI)<2=1vQieconJ!!p&=!`cLr5I_r-N ziOzneU%btFAdt7As;#Y~cI|SuF{KQX>tCR2m2spjx|wZKux7dZI}Zmz4wk{e7(;L^ zzP!u|dk4|#B=PFf^?i#p+ubP=F(FTp^pGUQBC;x$CHp8>W4GCjkgw-mm>ddQ(I(o- zhx0{R*QeKeCh>}@LU1iu8`k@iHy3D~h-+`8SRgKTScp6a?EBjXrFk1EIXKa01@)Eq z0l#|hdZgZlejp~1S=Azht|=dtKy2;fER>z*)!SRtNI}R&PEAYK^e&*A65rq?m|i_3 z3n1CZZ+}MpZ%DSOp;RNv0Mj#oHHr@j5wH-4Rb)@Yoy4kYTC(+@EBfY*QB_?m{QO(L zCfZ7Hy#F&?AT@0V{!TjeamVdSBXC+RM^nS*=s5{0wGGRU@+vj+F zHU^gg-)c9A`<+Lce6nR-c~H=WPf1M1)v$2F--yD5*j7gJDVz;pSzVN0dydrGc~g1F zMD(w&8c=LWG78z@kgszbM8?5?6~79J!HA;h&@dzy;DCX@YEMqrO7ey|gfh(@>9J@9z>FN-mOi+*Y5# zllUbK>f#iL_=|9y)r4NVStbQKPGeP8{$O)G$UbV=*MGcpxsjUzE~ez@iR8eknBI2WU`5p6#-d1O_O?aHjUIFiPBS zM8t%6_REW_HBnwNWRs5_A*T?XBZh853e9N|=k*QdCfTOMiv9o4&E6DA3Vm~(&Cbsj zrzzerrzCh4i4qVP4&`PS=*Pj9bPIa|+-v{{^m(mQ$6LZxCIu2hgW{%!*uXC&MmBgsh z2?y{pn2LT7%0iKi^k>225~QLj@@*fHPDwt5vA0U~?4~5A2~}9I)t8o(ksgzZ-9016 z=6_2io7md$Vz0uoDwVh4z0Jl&e`ld0yeE{b;zM#Q2!Vb4S{6EgPhQ)=otRd z17Qi@@i%9eAA%aTY^Q`F3+DlWj8PK(A}Ur3q{0jUDr|-3m-=?s42y5GS?W1?CpphE zSfqyQl*c|?Po9A4*`eX_*^9Lx=ejfX8Y{VT5+x<2S_cQTesvf)_>4`zn7IK5?ZHug zH95NNWVfzZv$NWab5it52AM&Ht+VlLg=svO4|{y0dDrO)WzJ{P>eQlJkE1+~-U zxs=u_W7GAP;q4+t_d%QeL|~;bA1{3~!N|iWC8j2xq}+4&JN{o_vF!J`PD$`g%)yuP zY65duqb>*i)Fh;9ysz4_B!LW!j52#@7Dh1KU&MbsGnc}-RxY=qQ3jrr!y{5 zt!^@{cq{46BjVjl%*v`lS7l2{o6wrFpPfV;WI3M7gO2VgWLbJ<5vU=ON-8I}gkmmM z!lywitEjS_!Op1ss9|5SO5=_#Qy*jhHZBa){k{Jhtoj9dHVuq^Tt|X*0eQwb!fW)_ zvdhTJFr}22#bnv!a(!zkhg<}F7he9DqPOfgD`wdx0mPJy!0qKo<|Qt9zjX>gO3u`1eO6sz@HFV0J4w-pM&UctK>6twH02!~@r@%Woo! z!suPsL%WF5rgPB#-jn3&z4nSvZ4UwCu|87|?=!!~ zKW30JZM-5OU@Z$r{)UW_674H*ZF_D(qF5FUPUqY9FASBHZ(kyoogY(77z^kL)IRVt z3Q4Fcf>?Y=X#V9LQZ8e;hU2>Xjv+TiDB4U#rO^Q+2TIJQR%XodKx+wIe;M5^Cxs&7 z=Fv^*D};bMU_oJTH1*lWOly>b;deA5LiFUU3kyri(jlii_Be5a3kzM!O-quTa2T0~ zVtbp0?W5e~;9BOY?%HIk+DRoFGsBU#di=UY6EWxHf%K+uYxU=05~nS_c`pKpuG%mv z-j`twg&7Z-awCK#Zz|B~czf4WDrS*%IT#Wpw^NJ15`7zcfcxfm!dstE8lu^3FU6)N z{u~Tf|D1}rF~9Q4qp9177qxeEU*}^xwVSj{c8BwQf1?oBLiyqU%v9z86#D~f=7KHO z$ASLSiB#KVKJ1*AUk`fn3O+FrpcN9ezN>3zVo}WQ=(+hj7I2Zai?zOiKEY@2T0@;Y zU@mvJiUi|7p{EWuP;?w|%MY>f&(w!xnC)MGJ>^-%3R9Gou0C4`yJ)bL*sjlwQE>XT_Ep~> zf%p+>Kt@i6j)nm)5)Nhk@*gNv^#m@nIhFl)|L>U07LO7wPmgPW1ovdCzX_);Uw!TT z;xaT2U`UG1yS*<0R*_Lqk~y3K4kl|~b$hDP@iy$~jq7db;@Q05bcHj59MT$UpTEEV zvUen$VgK2dHr-ZRY>8p- zJe2#5bq1|hA|-}Df4E1Ik1sFnjs=a@# z5P6*8En@Z^MC(JWaaH6v`N4W|dbH^jc)u$pnBh_jbbRnfWK)per_ zJ-9}E;tm8NfJTb=V6PiJ)rkgUnx+Qq75-W9POj*8tz>3$;GuV%W;l6*VNCIF5UYS=Zu76zs6RBQPopgh4?FRIkhZApN88+5v3TU7)=cITn*4~Qm$jI zhp*huUfmzk1+l=f6_ZtqniB9RqY>^>TEDk`0HsVKLIh?KX1U)wCAwIK43UW8K+WPY zKJwyC=eVDlR(8=qTZXl!rnCo)E_74s#QguOM!q8cyW6jY5CN#c9Xr(EF1b_tezAJ6 z-|*{SY$x#j(3fDt)XDtozZ@g-AjbEP7^Iy4l3;*@&R?(pCSCdK-TwpGNic8D*%4ZA z*D>J>f-L&`Am{>$1PLe!+4?G~!VR=w$b=Q-oDIis0~yN6^|P6b)vAEZwW^4t?0p%? zJ-R)E(xMDTf4Q9F@f1mg@ji+tk`K6o=i<_$P8^dNegU!RQ-XM28e%;cV_|T4BV>%l z=`kWidm?=ly^Y7_+C5+};@bSXYj@_jg1|L_pvYY3j*c-3fE_;5f4NS;^#HS}<<8O9 zPI2Mf7jx^ZTT2r*22E02RqJG$_6F?2_`D!)QfIYQYPgZBXI zcbU+h&i2CQAzs zz!cpXsXq^=W%9{rB#i~@_}bZ&_V%N@zFE5T$Vc{3zwtueZ7fPRK4;vsyKLP67tr2lg@|bLeBzW-_z5ZsWq6N!rraJ zp)vwV}Cqhlt%ktDq&8*?}{3du&GwFv0sJav7 z;n6xhW)br1lvO<`H{&Rg;d+kr%HqcUd~!#*kyc1oPk9Ycq)ZwtZJgRUElR&@_3tIP zT)5Hf>1$S8u9=I$iq7yr(4r#-Vl~JQvKAvV%9Io*y6BfViTG)2_7#Lp zQ9ErbY(9L@Sco%fk3Pm}UODJ%vbP$!5nqApEk9X3#hmKTnXUd64@8qg`6tvp@dJ6@ z_RVbbranmt7P1juLodp_?&-Qi9 zP_NHU8IcNRhLF5@<%mFtvYDORuA5m{=h8yS$~%B7M@$TvC|*l>tC|?5I_xKdd*<3? z9Vbq^!)ypfXXGp1bduxQnqv{Mw*vEXi;0f7YM6tSS91ai?KbO?on2Qa%kZ_{kvHvD zMq@)N?QYl?ugsFJ_f7~G#5Pw3yz5z!Om0T%w=IkCLeFFe!np9%Hm1sJyiC&^ZFi#AR3^UXa^4&u?z%xw zvP>3=@Uw;USE6XXpyM3>Gt+u&rTsSNvBkz;IHH&WnQaKB!_+kN*6j_izhxyJHb0TRysDVe51XJ@gOd^(;SQAzIvyxLrb`w*i)HX?sLCbuQ|gD z%bc~Y2*aZWk{f89+fYw%8uRb6or4SK5cbnse@PAlY}$nwY(h=FJ2?B$IO6;`!rEei zw~jT**!%d_`x1};1r2fVX{2q}f3Tgx5~oHN~LBo3iP!bXp? zTJy=G+c?TTlk2JP!3wzuD4d9N8vw92iTdw1IS-@R&-gONu|dW;f8*d+J5-f%{(?vL z!DeCda5X=s?iDWW&CM9m;W016VX&EwDwz3XdX~f$B8q|% z`KK;2{KN0Gt6&nbcx?b9I!xwrF3ijv%e5A9m_9AsxxRS>ElXIVNeGXPWO44wSDm(D zG+SWTIP~l)kd~5@)1;75=N6FDI?J96H4y5i#UVknnD*&^-Gk8_5=l2Ugk!0{loO3G z28#|k)cUG19FkM>G{5<3oc(%!wt1?tO;vPjDp`fDkE_mhgy1&IbgLM{U2b`*zcO@k z-q{F&tD(kMrP^ht;#=+MDuGOAMT2)K#bl^0>>aE9(GGohu*r!(j5)#q;mgvHiHDs{ zTW7V^p5x<#UUQW`&Ut{|XNB*fZ!&2$dlDW%dp+7WrJ=dj*b)x{NaW;}rzcCqXb4Y< z+l+BI6Z_6)zkXLS2w&~pqzl3ImRWj@QtNel5E@BOYtKm>d*^sU#zGoSQ@pxqz91$Y z5>8lj#`pOrEj61s=c$0>mM+omM`ml4_BrOch8PPcte0@tOkY#?H>f*KnCzE!FPkQPpfxo{ge z>+n=I8?;JntvYT?UI|uM+3P(0jge&oZ!jDf(R6e>nr$=tRA5i1`fl;nbJNRue1ZN? z;~~pj*Yi0!`BPmj-gBouy3`Q42WD&4*N88Bj_wVS!yt28=sTY)uZXUADo zZ?!4?>s|83EED;=7%(oYk8ZW2Gaqjh+4|$5CXly(!M3kFrL9`&f-zhs@9bI7enQ${ zS+dC;ZJ=}UI6htkj5-;5lj)f6^N_;8pnm_Dam#3S57%SC^>l#yHRX=JbE)-i4T?Ty z`;q@cc$AlihaO4B42*5r`{UI3Q0mt3ywUNVSrr6Nb>K>ZHCZ*ncK4)^4ks!i;sBPB z>dvY7bMecIlYYW&CZPoTih}srFP4d!ZwzkX+e~!G6c1%^J6+L^B4nq#Ql~lY{PD7d zItW=vy{VFseGEu#K^GK=uIo8F$eJ4xTl;R!#d7LsUkh~?622f$5N4ECSR zok^|ape}ZCY3Hb)`j&Qqt!j7s&XS8%50Ij6xy6NqfIkpO`1kf}5tC*a>L1oIm7751 z`MswqoS9Yie1dk^Yea;wrup)odC%u-|{D=As>7LB4^blOkWsC*A@s^c5#cXz&FPW<|=l8CFRpR*yp`Ahz#0hPhr&e?ULC?mX7it>j>t>ms)I*d+j zg7G%5-+Xco?k`w`&0`JBV{?ciLX>|J1SG|g{7x3+3zz$BH?X5?ph#}-a5MXAVFy4k zWqX!(oUJ0$`y1@9Ek(vp$4=dE$+gFir5rGarsg`_mtVN15y~J5A^Q;pRo|7ZE&WKR z#c41W=e*Gr5zY&;yx7(g?T{LhlWE$y@^_MaDp1W&By6#;gA_L5a(4Y;e6CM-jL4$p zjD_LvSis=);EGPn9UPtuSN;jJc%c4tLyaQRr9RP$cIMhzDGW;qM$Svc4U_zBL0wWT z0mOH+c3ZGQ5QKdqGgKCQpX6B*v-Y})VlaA}0$!$_tF|TdH982sbmr;Iy6G2C=&N`5 zP}lyWL2ETsaA4rEkr$|>y$FyUgqu2aS7N>3pEmM9@H24_WcG~5X# zyvR29+Vz_p7tXL8qklIH(i{bl!FUXqS zD&!uO&V0n$Tu=FS|8eNA4@fp0O@@srFLW*FH#g@(+ND+Pbr;DSc}

ZwU#*6(kRyg&J*RKE}=!T^Z#HCKNf5 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 literal 0 HcmV?d00001 diff --git a/libs/server-integration-tests/tests/implementations.test.ts b/libs/server-integration-tests/tests/implementations.test.ts new file mode 100644 index 00000000..a59fa3c9 --- /dev/null +++ b/libs/server-integration-tests/tests/implementations.test.ts @@ -0,0 +1,233 @@ +import { jwtScheme, signJwt } from '@cleverbrush/auth'; +import { object, string } from '@cleverbrush/schema'; +import { + ActionResult, + cacheResponse, + createServer, + defineApi, + endpoint, + errorMap, + implement, + type Middleware, + type Server +} from '@cleverbrush/server'; +import { afterEach, describe, expect, it, vi } from 'vitest'; + +const secret = 'implementation-integration-test-secret'; +const Principal = object({ userId: string(), role: string() }); +const Db = object({ label: string() }); +const Message = object({ message: string() }); +class MissingItem extends Error {} + +describe('modular implementation HTTP pipeline', () => { + let server: Server | undefined; + afterEach(async () => { + await server?.close(); + vi.restoreAllMocks(); + }); + + async function start( + options: { middleware?: Middleware; missingService?: boolean } = {} + ) { + let reads = 0; + const translated = vi.fn(() => + ActionResult.notFound({ message: 'Item not found' }) + ); + const errors = errorMap().on(MissingItem, translated); + const resource = endpoint + .resource('/items') + .authorize(Principal, 'admin'); + const api = defineApi({ + items: { + get: resource + .get() + .responses({ 200: Message }) + .clearsCacheTag('items'), + update: resource + .post() + .body(object({ title: string() })) + .responses({ 200: Message, 404: Message }) + .clearsCacheTag('items'), + upload: endpoint + .post('/upload') + .authorize(Principal, 'admin') + .body(object({})) + .upload() + .responses({ 200: Message }) + } + }); + const scope = implement(api).group('items', { inject: { db: Db } }); + const module = scope.withHandlers({ + get: ({ principal }, { db }) => ({ + message: `${principal.userId}:${db.label}:${++reads}` + }), + update: { + errors, + middlewares: options.middleware ? [options.middleware] : [], + handler: ({ body }, { db }) => { + if (body.title === 'missing') + throw new MissingItem('Do not expose this detail'); + if (body.title === 'crash') + throw new Error('private database credentials'); + return { message: `${body.title}:${db.label}` }; + } + }, + upload: ({ files }, { db }) => ({ + message: `${files.image?.filename}:${db.label}` + }) + }); + const builder = createServer() + .useAuthentication({ + defaultScheme: 'jwt', + schemes: [ + jwtScheme({ + secret, + mapClaims: claims => ({ + userId: claims.sub as string, + role: claims.role as string + }) + }) + ] + }) + .useAuthorization() + .use(cacheResponse()) + .useBatching() + .handleAll(implement(api).use(module).complete()); + if (!options.missingService) + builder.services(services => + services.addSingleton(Db, { label: 'db' }) + ); + server = await builder.listen(0); + const base = `http://127.0.0.1:${server.address!.port}`; + const authorization = `Bearer ${signJwt({ sub: 'user-1', role: 'admin' }, secret)}`; + const request = (path: string, body?: unknown, auth = authorization) => + fetch(`${base}${path}`, { + method: body === undefined ? 'GET' : 'POST', + headers: { + authorization: auth, + 'content-type': 'application/json' + }, + body: body === undefined ? undefined : JSON.stringify(body) + }); + return { base, authorization, request, translated }; + } + + it('preserves authentication, role checks, validation and merged DI', async () => { + const { request, translated } = await start(); + const anonymous = await request('/items', undefined, ''); + expect(anonymous.status).toBe(401); + await anonymous.text(); + const viewer = await request( + '/items', + undefined, + `Bearer ${signJwt({ sub: 'viewer', role: 'viewer' }, secret)}` + ); + expect(viewer.status).toBe(403); + await viewer.text(); + const invalid = await request('/items', { title: 42 }); + expect(invalid.status).toBe(400); + expect(invalid.headers.get('content-type')).toContain( + 'application/problem+json' + ); + await invalid.text(); + expect(translated).not.toHaveBeenCalled(); + expect(await (await request('/items')).json()).toEqual({ + message: 'user-1:db:1' + }); + }); + + it('maps only known handler failures and logs sanitized unexpected failures', async () => { + const logged = vi.spyOn(console, 'error').mockImplementation(() => {}); + const { request, translated } = await start(); + const known = await request('/items', { title: 'missing' }); + expect(known.status).toBe(404); + expect(await known.json()).toEqual({ message: 'Item not found' }); + expect(logged).not.toHaveBeenCalled(); + const unknown = await request('/items', { title: 'crash' }); + expect(unknown.status).toBe(500); + const text = await unknown.text(); + expect(text).not.toContain('private database credentials'); + expect(logged).toHaveBeenCalledWith( + '[server] Unhandled error:', + expect.objectContaining({ message: 'private database credentials' }) + ); + expect(translated).toHaveBeenCalledTimes(1); + }); + + it('does not translate middleware or DI failures', async () => { + vi.spyOn(console, 'error').mockImplementation(() => {}); + const { request, translated } = await start({ + middleware: async () => { + throw new MissingItem('middleware'); + } + }); + const response = await request('/items', { title: 'valid' }); + expect(response.status).toBe(500); + await response.text(); + expect(translated).not.toHaveBeenCalled(); + await server!.close(); + const withoutService = await start({ missingService: true }); + const missing = await withoutService.request('/items', { + title: 'valid' + }); + expect(missing.status).toBe(500); + await missing.text(); + expect(withoutService.translated).not.toHaveBeenCalled(); + }); + + it('preserves cache invalidation, failed mutations and batched error responses', async () => { + const { request, authorization } = await start(); + expect(await (await request('/items')).json()).toEqual({ + message: 'user-1:db:1' + }); + expect(await (await request('/items')).json()).toEqual({ + message: 'user-1:db:1' + }); + await (await request('/items', { title: 'missing' })).text(); + expect(await (await request('/items')).json()).toEqual({ + message: 'user-1:db:1' + }); + await (await request('/items', { title: 'changed' })).text(); + expect(await (await request('/items')).json()).toEqual({ + message: 'user-1:db:2' + }); + const batch = await request('/__batch', { + requests: [ + { + method: 'POST', + url: '/items', + body: JSON.stringify({ title: 'missing' }), + headers: { + 'content-type': 'application/json', + authorization + } + } + ] + }); + expect(batch.status).toBe(200); + const { responses: result } = (await batch.json()) as { + responses: { status: number; body: string }[]; + }; + expect(result[0].status).toBe(404); + expect(JSON.parse(result[0].body)).toEqual({ + message: 'Item not found' + }); + }); + + it('preserves multipart upload contexts', async () => { + const { base, authorization } = await start(); + const data = new FormData(); + data.set( + 'image', + new Blob(['image data'], { type: 'text/plain' }), + 'sample.txt' + ); + const response = await fetch(`${base}/upload`, { + method: 'POST', + headers: { authorization }, + body: data + }); + expect(response.status).toBe(200); + expect(await response.json()).toEqual({ message: 'sample.txt:db' }); + }); +}); diff --git a/libs/server-openapi/src/implementations.test.ts b/libs/server-openapi/src/implementations.test.ts new file mode 100644 index 00000000..e0238975 --- /dev/null +++ b/libs/server-openapi/src/implementations.test.ts @@ -0,0 +1,83 @@ +import { object, string } from '@cleverbrush/schema'; +import { + ActionResult, + createServer, + defineApi, + endpoint, + errorMap, + implement, + mapHandlers +} from '@cleverbrush/server'; +import { expect, it } from 'vitest'; +import { generateOpenApiSpec } from './generateOpenApiSpec.js'; + +it('emits the same OpenAPI contract for modular and existing registrations', () => { + const Principal = object({ userId: string() }); + const Db = object({ name: string() }); + const Message = object({ message: string() }); + const api = defineApi({ + items: { + create: endpoint + .post('/items') + .body(object({ title: string() })) + .authorize(Principal, 'admin') + .responses({ 201: Message, 404: Message }) + .clearsCacheTag('items') + } + }); + const scope = implement(api).group('items', { + inject: { db: Db }, + tags: ['items'], + operations: { + create: { + summary: 'Create item', + description: 'Create a new item.', + operationId: 'createItem', + deprecated: true + } + } + }); + const handler = () => ActionResult.created({ message: 'created' }); + const modular = createServer().handleAll( + implement(api) + .use( + scope.withHandlers({ + create: { + handler, + errors: errorMap().on(Error, () => + ActionResult.notFound({ message: 'Missing' }) + ) + } + }) + ) + .complete() + ); + const previous = createServer().handleAll( + mapHandlers( + { + items: { + create: api.items.create + .inject({ db: Db }) + .tags('items') + .summary('Create item') + .description('Create a new item.') + .operationId('createItem') + .deprecated() + } + }, + { items: { create: handler } } + ) + ); + const info = { title: 'Items', version: '1' }; + expect( + generateOpenApiSpec({ + info, + registrations: [...modular.getRegistrations()] + }) + ).toEqual( + generateOpenApiSpec({ + info, + registrations: [...previous.getRegistrations()] + }) + ); +}); diff --git a/libs/server/README.md b/libs/server/README.md index 52a224bf..22e7b025 100644 --- a/libs/server/README.md +++ b/libs/server/README.md @@ -20,6 +20,50 @@ A schema-first HTTP server framework for Node.js. Combines [`@cleverbrush/schema - **Health check** — optional `/health` endpoint via `server.withHealthcheck()`. - **WebSocket subscriptions** — `endpoint.subscription('/ws/path')` with typed incoming/outgoing schemas, `tracked()` events, and async generator handlers. - **Contract composition** — `mergeContracts`, `pickGroups`, and `omitGroups` enable audience-scoped bundles: ship only the endpoints each consumer needs. +- **Modular implementations** — `implement(api)` derives server-configured scopes, keeps separate handler files strongly typed, and checks full contract coverage at final registration. +- **Typed error policies** — `errorMap()` and `withErrors()` translate known handler exceptions without repeated catch blocks or widening endpoint responses. + +## Large APIs and shared error handling + +Keep contracts, server configuration, handlers, and composition in separate files: + +```ts +// scope.ts — does not import handlers +export const items = implement(api).group('items', { + inject: { db: DbToken }, + tags: ['items'], + operations: { remove: { summary: 'Remove an item' } } +}); + +// handlers/remove.ts +import type { items } from '../scope.js'; +export const remove: Handler = async ( + { params }, { db } +) => { + await deleteItem(db, params.id); + return ActionResult.noContent(); +}; + +// module.ts — bind only compatible, declared error responses +const missing = errorMap().on(MissingItemError, () => + ActionResult.notFound({ message: 'Item not found' }) +); +export const itemsModule = items.withHandlers({ + list, + remove: { handler: remove, errors: missing } +}); + +// server.ts — every operation in api must be implemented +server.handleAll(implement(api).use(itemsModule).complete()); +``` + +The excerpt assumes an `items` contract with `list` and `remove`, including the +remove operation's 204/404 responses. `pick(...)` splits a large group into +smaller modules without losing root completeness checks. Existing `handle` and +`mapHandlers` users can adopt `withErrors(endpoint, policy, handler)` alone. + +See the [complete modular consumer guide](docs/implementations.md), including +configuration precedence, subscriptions, failure behavior, and migration examples. ## Installation diff --git a/libs/server/docs/implementations.md b/libs/server/docs/implementations.md new file mode 100644 index 00000000..bf7746d1 --- /dev/null +++ b/libs/server/docs/implementations.md @@ -0,0 +1,222 @@ +# Modular implementations and shared error policies + +`implement` adds server-only configuration and complete handler registration to +an existing shared API contract. It does not replace endpoint builders, change +the wire contract, or require business logic inside one fluent expression. +`errorMap` and `withErrors` also work independently of this registration API. + +## A complete multi-file example + +The application functions and service registration below are application-owned. +The contract in this example has exactly two operations, so its root is complete. + +### Shared contract + +```ts +// contracts.ts — browser-safe; no server configuration or handler imports +import { defineApi, endpoint, route } from '@cleverbrush/server/contract'; +import { array, number, object, string } from '@cleverbrush/schema'; + +export const Item = object({ id: number(), title: string() }); +const Message = object({ message: string() }); +export const Principal = object({ userId: string() }); +const resource = endpoint.resource('/items').authorize(Principal); + +export const api = defineApi({ + items: { + list: resource.get().responses({ 200: array(Item) }), + remove: resource.delete( + route({ id: number().coerce() })`/${p => p.id}` + ).responses({ 204: null, 404: Message }) + } +}); +``` + +### Server configuration without handlers + +```ts +// features/items/scope.ts +import { implement } from '@cleverbrush/server'; +import { api } from '../../contracts.js'; +import { DbToken } from '../../di/tokens.js'; + +export const items = implement(api).group('items', { + inject: { db: DbToken }, + tags: ['items'], + operations: { + list: { summary: 'List items', operationId: 'listItems' }, + remove: { summary: 'Remove an item', operationId: 'removeItem' } + } +}); +``` + +`items.endpoints` contains immutable, server-configured builders. Export the +scope constant and reference it with `typeof`; do not annotate it with a broad +base type that erases operation names or service types. + +### Separate handlers + +```ts +// features/items/handlers/list.ts +import type { Handler } from '@cleverbrush/server'; +import type { items } from '../scope.js'; +import { listItems } from '../../../application/items.js'; + +export const list: Handler = ( + { principal }, { db } +) => listItems(db, principal.userId); +``` + +```ts +// features/items/handlers/remove.ts +import { ActionResult, type Handler } from '@cleverbrush/server'; +import type { items } from '../scope.js'; +import { removeItem } from '../../../application/items.js'; + +export const remove: Handler = async ( + { params, principal }, { db } +) => { + await removeItem(db, principal.userId, params.id); + return ActionResult.noContent(); +}; +``` + +The application function can throw a domain exception. Handlers do not need a +repeated catch block. Requests, principals, injected services, and responses are +derived at the handler's declaration site, not inferred retrospectively from a +later registration call. Type-only scope imports avoid runtime import cycles. + +### Application-owned policy and feature registration + +```ts +// features/items/errors.ts +import { ActionResult, errorMap } from '@cleverbrush/server'; +import { MissingItemError } from '../../application/errors.js'; + +export const itemErrors = errorMap().on(MissingItemError, () => + ActionResult.notFound({ message: 'Item not found' }) +); +``` + +```ts +// features/items/index.ts +import { items } from './scope.js'; +import { itemErrors } from './errors.js'; +import { list } from './handlers/list.js'; +import { remove } from './handlers/remove.js'; + +export const itemsModule = items.withHandlers({ + list, + remove: { handler: remove, errors: itemErrors } +}); +``` + +Attaching this policy to `list` is a type error: `list` does not declare 404. +Declaring 204 on `remove` does not permit arbitrary other statuses or bodies. + +```ts +// server.ts — after the application's ordinary server/DI setup +import { implement } from '@cleverbrush/server'; +import { api } from './contracts.js'; +import { itemsModule } from './features/items/index.js'; + +server.handleAll(implement(api).use(itemsModule).complete()); +``` + +`complete()` fails at compile time if an operation is missing, and checks again +at runtime for JavaScript callers and erased types. The output is the existing +`HandlerMapping`. Authentication, validation, caching, batching, middleware, +serialization, logging, and OpenAPI generation use their existing paths. + +## Split large features and compose contract slices + +```ts +export const reads = items.pick('list').withHandlers({ list }); +export const writes = items.pick('remove').withHandlers({ + remove: { handler: remove, errors: itemErrors } +}); +export const feature = implement(api).use(reads, writes); + +// Partial roots can be exported and composed; finalize only at the full root. +server.handleAll(implement(api).use(feature).complete()); +``` + +Other groups are separate feature modules added to the same `use(...)` call. +Pass modules directly or in a literal tuple, not an array widened to a generic +module type. Duplicate bindings are rejected across modules and calls. Source +endpoint identity is checked at runtime as well: independently recreated +endpoints are not interchangeable just because their TypeScript shapes match. +`pickGroups`, `omitGroups`, and `mergeContracts` preserve endpoint references, +so intentional contract slices can be implemented and recomposed. + +Subscriptions use the same scopes, `SubscriptionHandler`, +and existing subscription handler descriptors. They count toward completeness. +HTTP error policies are not accepted on subscription handlers and do not change +the WebSocket error protocol. + +## Configuration rules + +- `inject` merges contract bindings, then group bindings, then operation bindings. + A same-name binding is replaced by the later value in both the type and runtime + service map. Other dependencies remain available. Endpoint `.inject()` itself + retains its existing replacement behavior. +- An operation's `authorize` schema takes precedence over a group's schema; + existing endpoint roles are retained. Supplying authorization explicitly makes + even a previously public operation authenticated. Omit it when authorization + already lives entirely in the shared contract. There is no implicit auth default. +- Operation `tags` replace group tags; group tags replace existing tags. Other + metadata changes only when supplied: `summary`, `description`, `operationId`, + and `deprecated: true`. Deprecation is additive and cannot be cleared here. +- Request/response schemas, cache definitions, upload settings, links, examples, + and other endpoint metadata remain on the shared endpoint. Scopes do not edit + the wire contract or silently add error responses. +- Handler descriptors support existing per-operation `middlewares`. Configuration + scopes do not register anything until explicitly bound and composed. + +## Error policy behavior and limits + +Policies are immutable. Each `.on(ErrorClass, translator)` returns a new policy. +Rules match by `instanceof` in declaration order; put subclasses before base +classes. Both handlers and translators may be synchronous or asynchronous. + +Translators return explicit JSON or bodyless `ActionResult` values. Every result +must fit the target endpoint's `.responses()` status/body map. Policies cannot +use raw/file/stream results to escape that check, and endpoints without explicit +responses cannot attach a policy. TypeScript escape hatches (`any`, assertions, +or deliberately erased annotations) still bypass static guarantees; this is not +a replacement for runtime response validation. + +Only exceptions from the handler invocation are translated. Authentication, +request validation, DI resolution, middleware, and response serialization are +outside the wrapper. Unknown thrown values are rethrown unchanged. If a translator +fails, its failure propagates without recursively applying the policy again. +Existing centralized handling still logs unexpected failures and sends safe 500 +Problem Details. There is no automatic catch-all or exposure of `Error.message`. + +Application authors decide which errors are safe to map and which details can +be returned. Framework has no knowledge of domain ownership or privacy rules. + +## Incremental adoption + +The old `handle` and `mapHandlers` APIs remain unchanged. Adopt just error policies +without migrating registration: + +```ts +import { withErrors } from '@cleverbrush/server'; + +server.handle( + RemoveItemEndpoint, + withErrors(RemoveItemEndpoint, itemErrors, removeHandler) +); +``` + +The returned function can also be placed in an existing handler map. To migrate +registration, move server-only metadata/DI into scopes, type the existing handler +files against `scope.endpoints`, bind feature modules, and finalize at the root. +Keep the shared contract in `/contract` imports; implementation facilities and +policies are server-entry-point exports only. + +The repository tests include a strict multi-file consumer against emitted package +declarations and a generated 1,000-operation consumer with one handler per file. +The latter records compiler diagnostics, memory, and timings for both existing +and modular registration without using environment-dependent timing thresholds. diff --git a/libs/server/package.json b/libs/server/package.json index 4fdc5423..d6d02d82 100644 --- a/libs/server/package.json +++ b/libs/server/package.json @@ -17,7 +17,8 @@ }, "description": "Schema-first HTTP server framework — schema-driven controllers, DI, auto-validation, RFC 9457 errors", "files": [ - "dist" + "dist", + "docs" ], "homepage": "https://docs.cleverbrush.com/server", "keywords": [ diff --git a/libs/server/src/ErrorMap.test.ts b/libs/server/src/ErrorMap.test.ts new file mode 100644 index 00000000..b7b7858b --- /dev/null +++ b/libs/server/src/ErrorMap.test.ts @@ -0,0 +1,121 @@ +import { object, string } from '@cleverbrush/schema'; +import { describe, expect, it, vi } from 'vitest'; +import { ActionResult, endpoint, errorMap, withErrors } from './index.js'; + +class Missing extends Error {} +class SpecialMissing extends Missing {} +const message = object({ message: string() }); +const ep = endpoint + .get('/items') + .responses({ 200: string(), 404: message, 204: null }); + +describe('errorMap and withErrors', () => { + it('translates sync failures and preserves successful results and arguments', async () => { + const configured = ep.inject({ db: object({ name: string() }) }); + const policy = errorMap().on(Missing, () => + ActionResult.notFound({ message: 'Not found' }) + ); + const handler = vi.fn( + (_context, { db }: { db: { name: string } }) => db.name + ); + const wrapped = withErrors(configured, policy, handler); + const context = {} as never; + const services = { db: { name: 'Connected' } }; + expect(await wrapped(context, services)).toBe('Connected'); + expect(handler).toHaveBeenCalledWith(context, services); + const failing = withErrors(ep, policy, () => { + throw new Missing('private details'); + }); + expect(await failing(context)).toMatchObject({ + status: 404, + body: { message: 'Not found' } + }); + }); + + it('supports async handlers and translators', async () => { + const policy = errorMap().on(Missing, async () => + ActionResult.notFound({ message: 'Async' }) + ); + const wrapped = withErrors(ep, policy, async () => { + throw new Missing(); + }); + expect(await wrapped({} as never)).toMatchObject({ + status: 404, + body: { message: 'Async' } + }); + }); + + it('is immutable and uses the first matching constructor including subclasses', async () => { + const empty = errorMap(); + const specific = empty.on(SpecialMissing, () => + ActionResult.notFound({ message: 'Specific' }) + ); + const all = specific.on(Missing, () => + ActionResult.notFound({ message: 'General' }) + ); + const error = new Missing(); + await expect(empty.translate(error)).rejects.toBe(error); + await expect(specific.translate(error)).rejects.toBe(error); + expect(await all.translate(new SpecialMissing())).toMatchObject({ + body: { message: 'Specific' } + }); + const first = errorMap() + .on(Missing, () => ActionResult.notFound({ message: 'First' })) + .on(SpecialMissing, () => + ActionResult.notFound({ message: 'Later' }) + ); + expect(await first.translate(new SpecialMissing())).toMatchObject({ + body: { message: 'First' } + }); + }); + + it.each([ + new Error('Database password'), + 'non-error', + undefined, + null + ])('rethrows unmatched values without changing identity: %s', async error => { + const wrapped = withErrors( + ep, + errorMap().on(Missing, () => ActionResult.noContent()), + () => { + throw error; + } + ); + await expect(wrapped({} as never)).rejects.toBe(error); + }); + + it('does not feed translator failures back into the policy', async () => { + const failure = new SpecialMissing('translator failed'); + const later = vi.fn(() => ActionResult.noContent()); + const policy = errorMap() + .on(Missing, async () => { + throw failure; + }) + .on(SpecialMissing, later); + const wrapped = withErrors(ep, policy, () => { + throw new Missing(); + }); + await expect(wrapped({} as never)).rejects.toBe(failure); + expect(later).not.toHaveBeenCalled(); + }); + + it('requires declared responses for erased/JavaScript callers', () => { + expect(() => + (withErrors as any)(endpoint.get('/legacy'), errorMap(), () => null) + ).toThrow('explicit endpoint responses'); + }); + + it('rejects raw, arbitrary, and plain-object translator results at runtime', async () => { + for (const response of [ + ActionResult.raw(() => {}), + ActionResult.content('text'), + { message: 'not an ActionResult' } + ]) { + const policy = errorMap().on(Missing, () => response as any); + await expect(policy.translate(new Missing())).rejects.toThrow( + 'explicit JSON or bodyless' + ); + } + }); +}); diff --git a/libs/server/src/ErrorMap.ts b/libs/server/src/ErrorMap.ts new file mode 100644 index 00000000..655ea8ee --- /dev/null +++ b/libs/server/src/ErrorMap.ts @@ -0,0 +1,166 @@ +import { + type ContentResult, + type FileResult, + JsonResult, + NoContentResult, + type RawResult, + type RedirectResult, + StatusCodeResult, + type StreamResult +} from './ActionResult.js'; +import type { EndpointBuilder, Handler, ResponsesOf } from './Endpoint.js'; + +/** Explicit, contract-checkable responses supported by error policies. */ +export type ErrorResponse = + | JsonResult + | NoContentResult + | StatusCodeResult; + +/** The declared JSON and bodyless responses of an HTTP endpoint. */ +export type ErrorResponsesOf = { + [K in keyof ResponsesOf & number]: ResponsesOf[K] extends null + ? K extends 204 + ? NoContentResult + : StatusCodeResult + : JsonResult[K]>; +}[keyof ResponsesOf & number]; + +type ErrorConstructor = abstract new (...args: any[]) => E; +const responseTypes: unique symbol = Symbol('errorResponseTypes'); +// Result classes are structural (NoContentResult only has executeAsync). +// Keep a discriminated description as well as R so a declared 204 cannot +// accidentally admit every other ActionResult through structural assignability. +type ResponseSignature = R extends + | FileResult + | StreamResult + | ContentResult + | RedirectResult + | RawResult + ? { kind: 'unsupported' } + : R extends JsonResult + ? { kind: 'json'; status: S; body: B } + : R extends StatusCodeResult + ? { kind: 'empty'; status: S } + : R extends NoContentResult + ? { kind: 'empty'; status: 204 } + : never; +type Rule = { + matches: (error: unknown) => boolean; + translate: (error: any) => ErrorResponse | Promise; +}; + +/** + * Immutable, ordered exception translators. Create one with {@link errorMap}. + * + * Policies retain their exact response union until attached to an endpoint. + * They do not change that endpoint's responses, catch infrastructure errors, + * or automatically expose exception messages. + * + * @typeParam R - Union of all responses produced by this policy. + */ +export class ErrorMap< + R extends ErrorResponse = never, + Signature = ResponseSignature +> { + /** @internal Retains status/body discrimination across exported policies. */ + declare readonly [responseTypes]: Signature; + readonly #rules: readonly Rule[]; + + /** @internal Use {@link errorMap}. */ + constructor(rules: readonly Rule[] = []) { + this.#rules = [...rules]; + } + + /** + * Return a new policy with a translator appended. First matching rule wins. + * Put subclass rules before base-class rules. Translators may be async; + * translator failures propagate without re-entering this policy. + * + * @param errorType - Error constructor matched using `instanceof`. + * @param translate - Application-owned conversion to an explicit response. + */ + on( + errorType: ErrorConstructor, + translate: (error: E) => T | Promise + ): ErrorMap> { + return new ErrorMap([ + ...this.#rules, + { + matches: error => error instanceof errorType, + translate + } + ]); + } + + /** + * Translate a recognized exception or rethrow the original value unchanged. + * Usually invoked by {@link withErrors}, not directly by an application. + */ + async translate(error: unknown): Promise { + const rule = this.#rules.find(candidate => candidate.matches(error)); + if (!rule) throw error; + const result = await rule.translate(error); + if ( + !(result instanceof JsonResult) && + !(result instanceof NoContentResult) && + !(result instanceof StatusCodeResult) + ) { + throw new TypeError( + 'Error translators must return an explicit JSON or bodyless status result' + ); + } + return result as R; + } +} + +/** + * Create an empty, immutable error policy. Unknown exceptions are rethrown. + * + * @example + * ```ts + * const errors = errorMap().on(MissingItemError, () => + * ActionResult.notFound({ message: 'Item not found' }) + * ); + * ``` + */ +export function errorMap(): ErrorMap { + return new ErrorMap(); +} + +/** + * Wrap only a handler's invocation in an endpoint-checked error policy. + * + * Requires explicit `.responses()` declarations. Every possible translated + * status/body must fit the endpoint; file/raw/stream escape hatches are not + * accepted. Request and injected-service types are unchanged. Authentication, + * validation, middleware, DI and response serialization remain outside this + * wrapper and use the server's normal error handling. + * + * @param endpoint - Configured HTTP endpoint, the sole source of handler types. + * @param policy - Reusable policy compatible with the endpoint's responses. + * @param handler - Named or inline handler to wrap. + * @returns A handler suitable for `handle`, `mapHandlers`, or implementation scopes. + */ +export function withErrors< + E extends EndpointBuilder +>( + endpoint: E, + policy: keyof ResponsesOf> extends never + ? never + : ErrorMap>>, + handler: Handler> +): Handler { + const responses = endpoint.introspect().responsesSchemas; + if (!responses || Object.keys(responses).length === 0) { + throw new TypeError( + 'Error policies require explicit endpoint responses' + ); + } + return (async (...args: unknown[]) => { + try { + return await (handler as (...args: unknown[]) => unknown)(...args); + } catch (error) { + return policy.translate(error); + } + }) as Handler; +} diff --git a/libs/server/src/Implementation.consumer.test.ts b/libs/server/src/Implementation.consumer.test.ts new file mode 100644 index 00000000..64d0b212 --- /dev/null +++ b/libs/server/src/Implementation.consumer.test.ts @@ -0,0 +1,11 @@ +import { expect, it } from 'vitest'; +import { checkLargeConsumers } from '../type-fixtures/large-consumer.mjs'; + +it('typechecks and emits a 1,000-operation multi-file consumer against published declarations', () => { + const metrics = checkLargeConsumers(); + expect(metrics).toHaveProperty('existing'); + expect(metrics).toHaveProperty('modular'); + process.stdout.write( + `Implementation consumer compiler metrics: ${JSON.stringify(metrics)}\n` + ); +}, 200000); diff --git a/libs/server/src/Implementation.test-d.ts b/libs/server/src/Implementation.test-d.ts new file mode 100644 index 00000000..3032035b --- /dev/null +++ b/libs/server/src/Implementation.test-d.ts @@ -0,0 +1,153 @@ +import { number, object, string } from '@cleverbrush/schema'; +import { + ActionResult, + errorMap, + type Handler, + type HandlerMapping, + implement, + withErrors +} from '@cleverbrush/server'; +import { defineApi, endpoint, pickGroups } from '@cleverbrush/server/contract'; +import { expectTypeOf, test } from 'vitest'; +import { api } from '../type-fixtures/contracts.js'; +import type { create } from '../type-fixtures/handlers/create.js'; +import { list } from '../type-fixtures/handlers/list.js'; +import { remove } from '../type-fixtures/handlers/remove.js'; +import { + itemsImplementation, + live, + reads, + writes +} from '../type-fixtures/module.js'; +import { missingItem } from '../type-fixtures/policies.js'; +import { Db, items } from '../type-fixtures/scope.js'; +import { mapping } from '../type-fixtures/server.js'; + +test('cross-file declarations preserve exact request, DI and return types', () => { + expectTypeOf(mapping).toEqualTypeOf(); + expectTypeOf[0]['query']>().toEqualTypeOf<{ + search: string; + }>(); + expectTypeOf[0]['principal']>().toEqualTypeOf<{ + userId: string; + }>(); + expectTypeOf[1]>().toEqualTypeOf<{ + db: { name: string }; + }>(); + expectTypeOf[1]>().toEqualTypeOf<{ + db: { name: string }; + mailer: { host: string }; + }>(); + expectTypeOf[0]['params']>().toEqualTypeOf<{ + id: number; + }>(); + expectTypeOf[0]>().not.toBeAny(); + items.pick('list').withHandlers({ + list: ({ query }, { db }) => { + expectTypeOf(query.search).toEqualTypeOf(); + expectTypeOf(db.name).toEqualTypeOf(); + // @ts-expect-error undeclared query property + query.missing; + return []; + } + }); + const wrong = () => ActionResult.created([]); + // @ts-expect-error independently declared handlers cannot return an undeclared status + const checked: Handler = wrong; + const noMailer: Handler = (_ctx, services) => { + // @ts-expect-error per-operation mailer does not leak into list + services.mailer; + return []; + }; + void checked; + void noMailer; +}); + +test('coverage, identity-compatible slices, and exact keys survive composition', () => { + implement(api).use(itemsImplementation, live).complete(); + implement(pickGroups(api, 'items')).use(reads, writes).complete(); + // @ts-expect-error live.changes has not been registered + implement(api).use(itemsImplementation).complete(); + // @ts-expect-error an empty root is incomplete + implement(api).complete(); + // @ts-expect-error missing selected operations + items.withHandlers({ list }); + // @ts-expect-error duplicate operation in the same use call + implement(api).use(reads, reads); + // @ts-expect-error duplicate operation across calls + implement(api).use(reads).use(reads); + // @ts-expect-error unknown group + implement(api).group('unknown'); + // @ts-expect-error unknown operation + items.pick('unknown'); + implement(api).group('items', { + // @ts-expect-error unknown operation-specific configuration + operations: { unknown: { summary: 'No' } } + }); + const extra = { list, unknown: list }; + // @ts-expect-error extra keys also rejected from named objects + items.pick('list').withHandlers(extra); + const changed = defineApi({ + items: { list: endpoint.get('/items').responses({ 200: string() }) } + }); + const changedModule = implement(changed) + .group('items') + .withHandlers({ list: () => 'different' }); + // @ts-expect-error incompatible response contract + implement(api).use(changedModule); +}); + +test('service overrides and authorization retain inference', () => { + const contract = defineApi({ + things: { + get: endpoint + .get('/things') + .inject({ original: Db, db: Db }) + .responses({ 200: string() }) + } + }); + const scope = implement(contract).group('things', { + inject: { db: object({ shared: number() }) }, + authorize: object({ subject: string() }), + operations: { get: { inject: { db: object({ specific: string() }) } } } + }); + scope.withHandlers({ + get: ({ principal }, { original, db }) => { + expectTypeOf(principal.subject).toEqualTypeOf(); + expectTypeOf(original.name).toEqualTypeOf(); + expectTypeOf(db).toEqualTypeOf<{ specific: string }>(); + return db.specific; + } + }); +}); + +test('error responses are constrained even when an endpoint declares 204', () => { + withErrors(items.endpoints.remove, missingItem, remove); + // @ts-expect-error list does not declare 404 + withErrors(items.endpoints.list, missingItem, list); + items.pick('list').withHandlers({ + // @ts-expect-error descriptors enforce the same policy check + list: { handler: list, errors: missingItem } + }); + const wrongBody = errorMap().on(Error, () => + ActionResult.notFound({ message: 42 }) + ); + // @ts-expect-error wrong body must not be accepted via the declared 204 branch + withErrors(items.endpoints.remove, wrongBody, remove); + const wrongStatus = errorMap().on(Error, () => + ActionResult.forbidden({ message: 'No' }) + ); + // @ts-expect-error undeclared status must not be accepted via 204 + withErrors(items.endpoints.remove, wrongStatus, remove); + const raw = errorMap().on(Error, () => ActionResult.raw(() => {})); + // @ts-expect-error raw response cannot bypass a policy contract check + withErrors(items.endpoints.remove, raw, remove); + // @ts-expect-error a declared responses map is required, even for an empty policy + withErrors(endpoint.get('/legacy'), errorMap(), () => 'legacy'); + implement(api) + .group('live') + .withHandlers({ + // @ts-expect-error error policies are HTTP-only + changes: { handler: async function* () {}, errors: missingItem } + }); +}); diff --git a/libs/server/src/Implementation.test.ts b/libs/server/src/Implementation.test.ts new file mode 100644 index 00000000..984d6e59 --- /dev/null +++ b/libs/server/src/Implementation.test.ts @@ -0,0 +1,199 @@ +import { number, object, string } from '@cleverbrush/schema'; +import { describe, expect, it } from 'vitest'; +import { + ActionResult, + createServer, + defineApi, + endpoint, + errorMap, + implement, + type Middleware, + pickGroups +} from './index.js'; + +const Db = object({ name: string() }); +const Mailer = object({ host: string() }); +const Principal = object({ userId: string() }); +const Message = object({ message: string() }); +function contract() { + return defineApi({ + items: { + list: endpoint.get('/items').responses({ 200: string() }), + remove: endpoint + .delete('/items') + .responses({ 204: null, 404: Message }) + }, + live: { changes: endpoint.subscription('/changes').outgoing(string()) } + }); +} + +describe('contract-bound implementations', () => { + it('composes split scopes, partial roots and contract slices', () => { + const api = contract(); + const items = implement(pickGroups(api, 'items')).group('items', { + inject: { db: Db } + }); + const reads = items + .pick('list') + .withHandlers({ list: (_ctx, { db }) => db.name }); + const writes = items + .pick('remove') + .withHandlers({ remove: () => ActionResult.noContent() }); + const feature = implement(api).use(reads, writes); + const live = implement(api) + .group('live') + .withHandlers({ + changes: async function* () { + yield 'changed'; + } + }); + const mapping = implement(api).use(feature, live).complete(); + expect(mapping._entries).toHaveLength(2); + expect(mapping._subscriptions).toHaveLength(1); + const server = createServer().handleAll(mapping); + expect(server.getRegistrations()).toHaveLength(2); + expect(server.getSubscriptionRegistrations()).toHaveLength(1); + expect(() => (feature as any).complete()).toThrow('live.changes'); + }); + + it('merges injections and preserves all unrelated metadata without mutating the source', () => { + const source = endpoint + .post('/upload') + .authorize(Principal, 'admin') + .inject({ db: Db, original: Db }) + .body(object({ title: string() })) + .query(object({ page: number() })) + .headers(object({ authorization: string() })) + .responses({ 204: null }) + .upload({ maxFileSize: 1000 }) + .summary('Original') + .description('Keep me') + .tags('original') + .operationId('uploadItem') + .deprecated() + .clearsCacheTag('items'); + const api = defineApi({ items: { upload: source } }); + const Replacement = object({ replacement: string() }); + const scope = implement(api).group('items', { + authorize: Principal, + inject: { db: Mailer }, + tags: ['shared'], + operations: { + upload: { + inject: { db: Replacement, mailer: Mailer }, + summary: 'Configured', + tags: ['specific'] + } + } + }); + const before = source.introspect(); + const after = scope.endpoints.upload.introspect(); + expect(after.serviceSchemas).toEqual({ + original: Db, + db: Replacement, + mailer: Mailer + }); + expect(after).toEqual({ + ...before, + summary: 'Configured', + tags: ['specific'], + serviceSchemas: after.serviceSchemas + }); + expect(source.introspect()).toEqual(before); + expect(Object.isFrozen(scope.endpoints)).toBe(true); + expect(implement(api).group('items').endpoints.upload).toBe(source); + }); + + it('keeps configuration-only scopes independent and includes endpoint middleware', () => { + const api = defineApi({ items: { list: endpoint.get('/items') } }); + const scope = implement(api).group('items'); + const middleware: Middleware = async (_ctx, next) => next(); + const middlewares = [middleware]; + const module = scope.withHandlers({ + list: { handler: () => 'ok', middlewares } + }); + middlewares.length = 0; + const root = implement(api).use(module); + expect(root.complete()._entries[0].middlewares).toEqual([middleware]); + expect(() => (implement(api) as any).complete()).toThrow('items.list'); + }); + + it('applies endpoint-checked error policies when binding handlers', async () => { + class Missing extends Error {} + const api = defineApi({ + items: { + remove: endpoint + .delete('/items') + .responses({ 204: null, 404: Message }) + } + }); + const scope = implement(api).group('items'); + const errors = errorMap().on(Missing, () => + ActionResult.notFound({ message: 'Missing' }) + ); + const module = scope.withHandlers({ + remove: { + handler: () => { + throw new Missing(); + }, + errors + } + }); + const mapping = implement(api).use(module).complete(); + expect(await mapping._entries[0].handler({})).toMatchObject({ + status: 404, + body: { message: 'Missing' } + }); + }); + + it('checks missing, unknown, duplicate and incompatible bindings at runtime', () => { + const api = contract(); + const root = implement(api); + const scope = root.group('items'); + const reads = scope.pick('list').withHandlers({ list: () => 'ok' }); + expect(() => (root as any).group('missing')).toThrow( + 'Unknown contract group' + ); + expect(() => + (root as any).group('items', { operations: { missing: {} } }) + ).toThrow('Unknown operation'); + expect(() => (scope as any).pick('missing')).toThrow( + 'Unknown operation' + ); + expect(() => scope.pick('list', 'list')).toThrow('Duplicate operation'); + expect(() => (scope as any).withHandlers({ list: () => 'ok' })).toThrow( + 'Missing handler items.remove' + ); + expect(() => + (scope as any).withHandlers({ extra: () => null }) + ).toThrow('Unknown handler'); + expect(() => (root as any).use(reads, reads)).toThrow( + 'Duplicate implementation' + ); + const different = contract(); + const foreign = implement(different) + .group('items') + .pick('list') + .withHandlers({ list: () => 'foreign' }); + expect(() => root.use(foreign)).toThrow('Incompatible source endpoint'); + expect(() => (root as any).use({})).toThrow( + 'Expected an implementation module' + ); + expect(() => + (root.group('live') as any).withHandlers({ + changes: { handler: async function* () {}, errors: errorMap() } + }) + ).toThrow('HTTP error policies'); + }); + + it('treats unusual group and operation names as literal keys, not prototype properties', () => { + const api = defineApi({ + ['__proto__']: { ['constructor']: endpoint.get('/special') } + }); + const module = implement(api) + .group('__proto__') + .pick('constructor') + .withHandlers({ constructor: () => 'ok' }); + expect(implement(api).use(module).complete()._entries).toHaveLength(1); + }); +}); diff --git a/libs/server/src/Implementation.ts b/libs/server/src/Implementation.ts new file mode 100644 index 00000000..15e7fbd6 --- /dev/null +++ b/libs/server/src/Implementation.ts @@ -0,0 +1,585 @@ +import type { InferType, SchemaBuilder } from '@cleverbrush/schema'; +import type { ApiContract, ApiGroup } from './contract.js'; +import { + type EndpointBuilder, + type Handler, + type HandlerMapping, + mapHandlers, + type ResponsesOf +} from './Endpoint.js'; +import { + type ErrorMap, + type ErrorResponsesOf, + withErrors +} from './ErrorMap.js'; +import { + isSubscriptionBuilder, + type SubscriptionBuilder, + type SubscriptionHandlerEntry +} from './Subscription.js'; +import type { Middleware } from './types.js'; + +type AnySchema = SchemaBuilder; +type Services = Record; +type AnyEndpoint = EndpointBuilder< + any, + any, + any, + any, + any, + any, + any, + any, + any, + any +>; +type AnySubscription = SubscriptionBuilder< + any, + any, + any, + any, + any, + any, + any, + any +>; +type Definition = AnyEndpoint | AnySubscription; +type Merge = { + [K in keyof A | keyof B]: K extends keyof B + ? B[K] + : K extends keyof A + ? A[K] + : never; +}; + +/** Server-only enrichment shared by every operation in a scope. */ +export interface ImplementationDefaults { + /** Merged with contract services; later same-name bindings win. */ + readonly inject?: Services; + /** Explicitly require authentication, retaining any existing role requirements. */ + readonly authorize?: AnySchema; + /** Replace inherited documentation tags when supplied. */ + readonly tags?: readonly string[]; +} + +/** Per-operation overrides. Wire schemas and cache metadata are not configurable here. */ +export interface ImplementationOperationOptions extends ImplementationDefaults { + /** Short documentation summary. */ + readonly summary?: string; + /** Longer documentation description. */ + readonly description?: string; + /** Stable OpenAPI/AsyncAPI operation identifier. */ + readonly operationId?: string; + /** Mark deprecated; this cannot clear an inherited deprecation. */ + readonly deprecated?: true; +} + +/** Typed defaults and operation-specific server settings for a contract group. */ +export interface ImplementationGroupOptions + extends ImplementationDefaults { + /** Keys must belong to the selected group. */ + readonly operations?: { + readonly [K in keyof G]?: ImplementationOperationOptions; + }; +} + +type Injected = O extends { readonly inject: infer I extends Services } + ? I + : {}; +type Principal = O extends { + readonly authorize: infer S extends AnySchema; +} + ? InferType + : P; +type OperationOptions = O extends { + readonly operations: infer Operations; +} + ? K extends keyof Operations + ? Operations[K] + : {} + : {}; + +type Configured = + E extends EndpointBuilder< + infer P, + infer B, + infer Q, + infer H, + infer S, + infer A, + infer Roles, + infer R, + infer Rs, + infer U + > + ? EndpointBuilder< + P, + B, + Q, + H, + Merge>, Injected>, + Principal, Options>, + Roles, + R, + Rs, + U + > + : E extends SubscriptionBuilder< + infer P, + infer Q, + infer H, + infer S, + infer A, + infer Roles, + infer I, + infer O + > + ? SubscriptionBuilder< + P, + Q, + H, + Merge>, Injected>, + Principal, Options>, + Roles, + I, + O + > + : never; + +type ConfiguredGroup = { + readonly [K in keyof G]: Configured>; +}; + +/** Handler binding accepted by an implementation scope. Policies apply only to HTTP handlers. */ +export type ImplementationHandlerEntry = E extends AnySubscription + ? SubscriptionHandlerEntry & { errors?: never } + : E extends AnyEndpoint + ? + | Handler + | { + handler: Handler; + middlewares?: Middleware[]; + errors?: keyof ResponsesOf extends never + ? never + : ErrorMap>; + } + : never; + +/** Complete, endpoint-specific handler bindings for one configured scope. */ +export type ImplementationHandlers = { + [K in keyof G]: ImplementationHandlerEntry; +}; + +type ExactKeys = Record< + Exclude, + never +>; +type ExactOperations = O extends { readonly operations: infer Ops } + ? { readonly operations: ExactKeys } + : unknown; + +type Entry = { + readonly group: string; + readonly name: string; + readonly source: Definition; + readonly endpoint: Definition; + readonly handler: (...args: any[]) => any; + readonly middlewares?: Middleware[]; +}; +type RuntimeBinding = + | Entry['handler'] + | { + handler: Entry['handler']; + middlewares?: Middleware[]; + errors?: ErrorMap; + }; + +const moduleContract: unique symbol = Symbol('implementationContract'); +const moduleEntries: unique symbol = Symbol('implementationEntries'); + +/** + * Exportable, immutable set of bound operations. Its type retains the original + * contract slice, not just an erased array of registrations. + * Obtain modules with `scope.withHandlers()` or `implement(api).use(...)`. + */ +export class ImplementationModule { + /** @internal Compile-time contract coverage. */ + declare readonly [moduleContract]: C; + readonly #entries: readonly Entry[]; + + /** @internal Construct modules through an implementation scope. */ + constructor(entries: readonly Entry[]) { + this.#entries = Object.freeze( + entries.map(entry => + Object.freeze({ + ...entry, + middlewares: entry.middlewares + ? [...entry.middlewares] + : undefined + }) + ) + ); + } + + /** @internal */ + [moduleEntries](): readonly Entry[] { + return this.#entries; + } +} + +/** + * Configured, unbound operations from a single contract group. + * Export the scope from a configuration-only module, then use + * `Handler` in separate handler files. + * No handler imports or registration side effects are needed here. + */ +export class ImplementationScope< + G extends string, + Source extends ApiGroup, + Endpoints extends ApiGroup +> { + readonly #group: G; + readonly #source: Source; + readonly #endpoints: Endpoints; + + /** @internal Use `implement(api).group(...)`. */ + constructor(group: G, source: Source, endpoints: Endpoints) { + this.#group = group; + this.#source = Object.freeze({ ...source }); + this.#endpoints = Object.freeze({ ...endpoints }); + } + + /** Configured endpoint builders: the source of handler request, DI and response types. */ + get endpoints(): Endpoints { + return this.#endpoints; + } + + /** + * Select operations for a smaller module without losing source identity. + * The composition root still checks coverage of the full contract. + */ + pick( + ...names: K[] + ): ImplementationScope, Pick> { + const source: ApiGroup = {}; + const endpoints: ApiGroup = {}; + const seen = new Set(); + for (const name of names) { + if (!Object.hasOwn(this.#source, name)) { + throw new TypeError(`Unknown operation ${this.#group}.${name}`); + } + if (seen.has(name)) + throw new TypeError( + `Duplicate operation ${this.#group}.${name}` + ); + seen.add(name); + Object.defineProperty(source, name, { + value: this.#source[name], + enumerable: true + }); + Object.defineProperty(endpoints, name, { + value: this.#endpoints[name], + enumerable: true + }); + } + return new ImplementationScope( + this.#group, + source, + endpoints + ) as ImplementationScope, Pick>; + } + + /** + * Bind exactly one handler for every operation in this scope. + * Named handlers and inline functions receive the same endpoint typing. + * Optional descriptors attach middleware and HTTP error policies. + */ + withHandlers>( + handlers: H & ExactKeys + ): ImplementationModule<{ [K in G]: Source }> { + for (const key of Object.keys(handlers)) { + if (!Object.hasOwn(this.#endpoints, key)) { + throw new TypeError(`Unknown handler ${this.#group}.${key}`); + } + } + const entries: Entry[] = []; + for (const name of Object.keys(this.#endpoints)) { + const endpoint = this.#endpoints[name]; + const binding = ( + Object.hasOwn(handlers, name) ? handlers[name] : undefined + ) as RuntimeBinding | undefined; + const handler = + typeof binding === 'function' ? binding : binding?.handler; + if (typeof handler !== 'function') { + throw new TypeError(`Missing handler ${this.#group}.${name}`); + } + const errors = + typeof binding === 'function' ? undefined : binding?.errors; + if (errors && isSubscriptionBuilder(endpoint)) { + throw new TypeError( + 'HTTP error policies cannot wrap subscription handlers' + ); + } + entries.push({ + group: this.#group, + name, + source: this.#source[name], + endpoint, + handler: errors + ? withErrors(endpoint as AnyEndpoint, errors, handler) + : handler, + middlewares: + typeof binding === 'function' + ? undefined + : binding?.middlewares + }); + } + return new ImplementationModule(entries); + } +} + +type ContractOf = M extends ImplementationModule ? C : never; +type MergeContracts = { + [G in keyof A | keyof B]: G extends keyof A + ? G extends keyof B + ? A[G] & B[G] + : A[G] + : G extends keyof B + ? B[G] + : never; +}; +type Joined< + Bound extends ApiContract, + Modules extends readonly ImplementationModule[] +> = Modules extends readonly [ + infer Head, + ...infer Tail extends readonly ImplementationModule[] +] + ? Joined>, Tail> + : Bound; +type Missing = { + [G in keyof C & + string]: `${G}.${Exclude & string}`; +}[keyof C & string]; +type Overlap = { + [G in keyof A & + keyof B & + string]: `${G}.${keyof A[G] & keyof B[G] & string}`; +}[keyof A & keyof B & string]; +type Incompatible = { + [G in keyof S & string]: G extends keyof C + ? { + [K in keyof S[G] & string]: K extends keyof C[G] + ? S[G][K] extends C[G][K] + ? never + : `${G}.${K}` + : `${G}.${K}`; + }[keyof S[G] & string] + : `${G}.${keyof S[G] & string}`; +}[keyof S & string]; +type CheckModules< + C, + B extends ApiContract, + M extends readonly ImplementationModule[] +> = number extends M['length'] + ? { + readonly implementationError: 'Use a tuple of modules with known operation keys'; + } + : M extends readonly [ + infer Head, + ...infer Tail extends readonly ImplementationModule[] + ] + ? [ + Overlap> | Incompatible> + ] extends [never] + ? CheckModules>, Tail> + : { + readonly duplicateOrIncompatibleOperations: + | Overlap> + | Incompatible>; + } + : unknown; + +/** + * Immutable composition root bound to a shared contract. Compose exported + * feature modules with `use`, then pass `complete()` to `server.handleAll`. + * Partial roots are themselves modules and can be composed in larger roots. + */ +export class ApiImplementation< + C extends ApiContract, + Bound extends ApiContract = {} +> extends ImplementationModule { + readonly #contract: C; + + /** @internal Use {@link implement}. */ + constructor(contract: C, entries: readonly Entry[] = []) { + super(entries); + this.#contract = Object.freeze( + Object.fromEntries( + Object.entries(contract).map(([name, group]) => [ + name, + Object.freeze({ ...group }) + ]) + ) + ) as C; + } + + /** + * Create an unbound scope; does not register handlers or change this root. + * Services merge contract → group → operation. Only explicitly supplied + * documentation fields override inherited values. Authorization retains roles. + */ + group< + K extends keyof C & string, + const O extends ImplementationGroupOptions = {} + >( + name: K, + options?: O & ExactOperations + ): ImplementationScope> { + if (!Object.hasOwn(this.#contract, name)) { + throw new TypeError(`Unknown contract group ${name}`); + } + const source = this.#contract[name]; + const config: ImplementationGroupOptions = options ?? {}; + for (const key of Object.keys(config.operations ?? {})) { + if (!Object.hasOwn(source, key)) + throw new TypeError(`Unknown operation ${name}.${key}`); + } + const endpoints = Object.fromEntries( + Object.entries(source).map(([key, endpoint]) => [ + key, + configure(endpoint, config, config.operations?.[key] ?? {}) + ]) + ); + return new ImplementationScope( + name, + source, + endpoints + ) as ImplementationScope>; + } + + /** + * Compose modules without erasing their operation coverage. Rejects duplicate + * and incompatible bindings, including runtime source-identity mismatches. + */ + use[]>( + ...modules: M & CheckModules + ): ApiImplementation> { + const entries = [...this[moduleEntries]()]; + const seen = new Map>(); + for (const entry of entries) { + if (!seen.has(entry.group)) seen.set(entry.group, new Set()); + seen.get(entry.group)!.add(entry.name); + } + for (const module of modules) { + if (!(module instanceof ImplementationModule)) + throw new TypeError('Expected an implementation module'); + for (const entry of module[moduleEntries]()) { + if ( + !Object.hasOwn(this.#contract, entry.group) || + !Object.hasOwn(this.#contract[entry.group], entry.name) || + this.#contract[entry.group][entry.name] !== entry.source + ) { + throw new TypeError( + `Incompatible source endpoint ${entry.group}.${entry.name}` + ); + } + if (seen.get(entry.group)?.has(entry.name)) { + throw new TypeError( + `Duplicate implementation ${entry.group}.${entry.name}` + ); + } + if (!seen.has(entry.group)) seen.set(entry.group, new Set()); + seen.get(entry.group)!.add(entry.name); + entries.push(entry); + } + } + return new ApiImplementation>( + this.#contract, + entries + ); + } + + /** + * Finalize only when every operation in the original contract is covered. + * Rechecks coverage at runtime for JavaScript callers and erased types. + * Returns the existing registration format; the server pipeline is unchanged. + */ + complete( + this: [Missing] extends [never] + ? ApiImplementation + : { readonly missingOperations: Missing } + ): HandlerMapping; + complete(): HandlerMapping { + const endpoints: Record = Object.create(null); + const handlers: Record> = Object.create( + null + ); + for (const entry of this[moduleEntries]()) { + endpoints[entry.group] ??= Object.create(null); + handlers[entry.group] ??= Object.create(null); + endpoints[entry.group][entry.name] = entry.endpoint; + handlers[entry.group][entry.name] = { + handler: entry.handler, + middlewares: entry.middlewares + ? [...entry.middlewares] + : undefined + }; + } + const missing: string[] = []; + for (const [group, operations] of Object.entries(this.#contract)) { + for (const name of Object.keys(operations)) { + if (!Object.hasOwn(endpoints[group] ?? {}, name)) + missing.push(`${group}.${name}`); + } + } + if (missing.length) + throw new TypeError( + `Missing implementations: ${missing.join(', ')}` + ); + return mapHandlers(endpoints, handlers); + } +} + +function configure( + endpoint: Definition, + defaults: ImplementationDefaults, + options: ImplementationOperationOptions +): Definition { + let result: any = endpoint; + if (defaults.inject || options.inject) { + result = result.inject({ + ...endpoint.introspect().serviceSchemas, + ...defaults.inject, + ...options.inject + }); + } + const authorize = options.authorize ?? defaults.authorize; + if (authorize) result = result.authorize(authorize); + const tags = options.tags ?? defaults.tags; + if (tags) result = result.tags(...tags); + if (options.summary !== undefined) result = result.summary(options.summary); + if (options.description !== undefined) + result = result.description(options.description); + if (options.operationId !== undefined) + result = result.operationId(options.operationId); + if (options.deprecated) result = result.deprecated(); + return result; +} + +/** + * Start an immutable implementation bound to a shared API contract. + * + * @param contract - Complete shared contract, or an intentional audience slice. + * @example + * ```ts + * const todos = implement(api).group('todos', { inject: { db: DbToken } }); + * const module = todos.withHandlers({ list: listHandler, create: createHandler }); + * server.handleAll(implement(api).use(module).complete()); + * ``` + */ +export function implement( + contract: C +): ApiImplementation { + return new ApiImplementation(contract); +} diff --git a/libs/server/src/contract.ts b/libs/server/src/contract.ts index 6fc5f109..a51045ca 100644 --- a/libs/server/src/contract.ts +++ b/libs/server/src/contract.ts @@ -72,7 +72,7 @@ import type { SubscriptionBuilder as _SB } from './Subscription.js'; */ export type ApiGroup = Record< string, - | _EB + | _EB | _SB >; diff --git a/libs/server/src/index.ts b/libs/server/src/index.ts index 1869b4bb..e7a1e057 100644 --- a/libs/server/src/index.ts +++ b/libs/server/src/index.ts @@ -50,6 +50,13 @@ export { type ResponsesOf, type ScopedEndpointFactory } from './Endpoint.js'; +export { + ErrorMap, + type ErrorResponse, + type ErrorResponsesOf, + errorMap, + withErrors +} from './ErrorMap.js'; export { BadRequestError, ConflictError, @@ -58,6 +65,17 @@ export { NotFoundError, UnauthorizedError } from './HttpError.js'; +export { + ApiImplementation, + type ImplementationDefaults, + type ImplementationGroupOptions, + type ImplementationHandlerEntry, + type ImplementationHandlers, + ImplementationModule, + type ImplementationOperationOptions, + ImplementationScope, + implement +} from './Implementation.js'; export { idempotency, type ServerIdempotencyOptions diff --git a/libs/server/tsconfig.build.json b/libs/server/tsconfig.build.json index cd010194..c4f9c52a 100644 --- a/libs/server/tsconfig.build.json +++ b/libs/server/tsconfig.build.json @@ -15,5 +15,5 @@ "types": ["node"] }, "include": ["src/**/*.ts"], - "exclude": ["src/**/*.test.ts"] + "exclude": ["src/**/*.test.ts", "src/**/*.test-d.ts"] } diff --git a/libs/server/tsconfig.typecheck.json b/libs/server/tsconfig.typecheck.json new file mode 100644 index 00000000..3442974a --- /dev/null +++ b/libs/server/tsconfig.typecheck.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.build.json", + "compilerOptions": { + "noEmit": true, + "strict": true, + "rootDir": "." + }, + "include": ["src/**/*.test-d.ts", "type-fixtures/**/*.ts"], + "exclude": [] +} diff --git a/libs/server/type-fixtures/contracts.ts b/libs/server/type-fixtures/contracts.ts new file mode 100644 index 00000000..8b338a1c --- /dev/null +++ b/libs/server/type-fixtures/contracts.ts @@ -0,0 +1,30 @@ +import { array, number, object, string } from '@cleverbrush/schema'; +import { defineApi, endpoint, route } from '@cleverbrush/server/contract'; + +export const Item = object({ id: number(), title: string() }); +export const Message = object({ message: string() }); +export const Principal = object({ userId: string() }); +const resource = endpoint.resource('/items').authorize(Principal, 'member'); +const byId = route({ id: number().coerce() })`/${p => p.id}`; + +export const api = defineApi({ + items: { + list: resource + .get() + .query(object({ search: string() })) + .responses({ 200: array(Item), 400: Message }), + create: resource + .post() + .body(object({ title: string() })) + .responses({ 201: Item, 404: Message }), + remove: resource.delete(byId).responses({ 204: null, 404: Message }), + upload: endpoint + .post('/items/upload') + .authorize(Principal) + .upload() + .responses({ 204: null }) + }, + live: { + changes: endpoint.subscription('/changes').outgoing(Item) + } +}); diff --git a/libs/server/type-fixtures/handlers/create.ts b/libs/server/type-fixtures/handlers/create.ts new file mode 100644 index 00000000..98e92893 --- /dev/null +++ b/libs/server/type-fixtures/handlers/create.ts @@ -0,0 +1,11 @@ +import { ActionResult, type Handler } from '@cleverbrush/server'; +import type { items } from '../scope.js'; + +export const create: Handler = ( + { body }, + { db, mailer } +) => + ActionResult.created({ + id: 1, + title: `${body.title}:${db.name}:${mailer.host}` + }); diff --git a/libs/server/type-fixtures/handlers/list.ts b/libs/server/type-fixtures/handlers/list.ts new file mode 100644 index 00000000..35c2abeb --- /dev/null +++ b/libs/server/type-fixtures/handlers/list.ts @@ -0,0 +1,7 @@ +import type { Handler } from '@cleverbrush/server'; +import type { items } from '../scope.js'; + +export const list: Handler = async ( + { principal, query }, + { db } +) => [{ id: 1, title: `${principal.userId}:${query.search}:${db.name}` }]; diff --git a/libs/server/type-fixtures/handlers/remove.ts b/libs/server/type-fixtures/handlers/remove.ts new file mode 100644 index 00000000..95658910 --- /dev/null +++ b/libs/server/type-fixtures/handlers/remove.ts @@ -0,0 +1,7 @@ +import { ActionResult, type Handler } from '@cleverbrush/server'; +import type { items } from '../scope.js'; + +export const remove: Handler = ({ params }) => { + if (params.id < 0) throw new Error('Not a persisted item'); + return ActionResult.noContent(); +}; diff --git a/libs/server/type-fixtures/large-consumer.mjs b/libs/server/type-fixtures/large-consumer.mjs new file mode 100644 index 00000000..5214dfb6 --- /dev/null +++ b/libs/server/type-fixtures/large-consumer.mjs @@ -0,0 +1,176 @@ +import { spawnSync } from 'node:child_process'; +import { + mkdirSync, + mkdtempSync, + readFileSync, + rmSync, + symlinkSync, + writeFileSync +} from 'node:fs'; +import { tmpdir } from 'node:os'; +import { dirname, join, resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const repository = resolve(dirname(fileURLToPath(import.meta.url)), '../../..'); + +/** Generate and compile equivalent, separately packaged 1,000-operation consumers. */ +export function checkLargeConsumers() { + const temporary = mkdtempSync( + join(tmpdir(), 'framework-implementation-consumer-') + ); + const write = (path, contents) => { + const destination = join(temporary, path); + mkdirSync(dirname(destination), { recursive: true }); + writeFileSync(destination, contents); + }; + const metrics = {}; + try { + symlinkSync( + join(repository, 'node_modules'), + join(temporary, 'node_modules'), + 'dir' + ); + write('package.json', JSON.stringify({ type: 'module' })); + for (const style of ['existing', 'modular']) { + write( + `${style}/shared.ts`, + `import { object, string } from '@cleverbrush/schema'; +export const Db = object({ name: string() }); +export const Query = object({ search: string() }); +export const Output = object({ title: string() });` + ); + const contractImports = []; + const rootImports = []; + for (let group = 0; group < 10; group++) { + const name = `feature${group}`; + const names = Array.from( + { length: 100 }, + (_, i) => `operation${i}` + ); + write( + `${style}/${name}/contract.ts`, + `import { endpoint } from '@cleverbrush/server/contract'; +import { Query, Output } from '../shared.js'; +export const ${name} = { +${names.map(operation => `${operation}: endpoint.get('/${name}/${operation}').query(Query).responses({ 200: Output })`).join(',\n')} +};` + ); + contractImports.push( + `import { ${name} } from './${name}/contract.js';` + ); + const scope = + style === 'modular' + ? `import { implement } from '@cleverbrush/server'; +export const scope = implement(api).group('${name}', { inject: { db: Db }, tags: ['${name}'] });` + : `export const scope = { endpoints: { +${names.map(operation => `${operation}: api.${name}.${operation}.inject({ db: Db }).tags('${name}')`).join(',\n')} +} };`; + write( + `${style}/${name}/scope.ts`, + `import { api } from '../contract.js'; +import { Db } from '../shared.js'; +${scope}` + ); + for (const operation of names) { + write( + `${style}/${name}/handlers/${operation}.ts`, + `import type { Handler } from '@cleverbrush/server'; +import type { scope } from '../scope.js'; +export const ${operation}: Handler = ({ query }, { db }) => ({ title: query.search + db.name });` + ); + } + const handlers = `{ ${names.join(', ')} }`; + write( + `${style}/${name}/index.ts`, + `import { scope } from './scope.js'; +${names.map(operation => `import { ${operation} } from './handlers/${operation}.js';`).join('\n')} +${ + style === 'modular' + ? `export const ${name} = scope.withHandlers(${handlers});` + : `export const ${name} = { endpoints: scope.endpoints, handlers: ${handlers} };` +}` + ); + rootImports.push( + `import { ${name} } from './${name}/index.js';` + ); + } + const groups = Array.from({ length: 10 }, (_, i) => `feature${i}`); + write( + `${style}/contract.ts`, + `import { defineApi } from '@cleverbrush/server/contract'; +${contractImports.join('\n')} +export const api = defineApi({ ${groups.join(', ')} });` + ); + write( + `${style}/index.ts`, + `${rootImports.join('\n')} +import { api } from './contract.js'; +${ + style === 'modular' + ? `import { implement } from '@cleverbrush/server'; +export const registration = implement(api).use(${groups.join(', ')}).complete();` + : `import { mapHandlers } from '@cleverbrush/server'; +export const registration = mapHandlers({ ${groups.map(g => `${g}: ${g}.endpoints`).join(', ')} }, { ${groups.map(g => `${g}: ${g}.handlers`).join(', ')} });` +}` + ); + write( + `${style}/tsconfig.json`, + JSON.stringify({ + compilerOptions: { + target: 'ES2022', + module: 'ESNext', + moduleResolution: 'bundler', + strict: true, + declaration: true, + emitDeclarationOnly: true, + outDir: 'dist', + types: ['node'], + lib: ['ES2022', 'ESNext.Disposable'], + skipLibCheck: false + }, + include: ['**/*.ts'], + exclude: ['dist'] + }) + ); + const result = spawnSync( + process.execPath, + [ + join(repository, 'node_modules/typescript/lib/tsc.js'), + '-p', + join(temporary, style, 'tsconfig.json'), + '--extendedDiagnostics' + ], + { encoding: 'utf8', timeout: 90000, maxBuffer: 4 * 1024 * 1024 } + ); + if (result.status !== 0) + throw new Error( + `${style} consumer failed:\n${result.stdout}\n${result.stderr}\n${result.error ?? ''}` + ); + const declaration = readFileSync( + join(temporary, style, 'dist/index.d.ts'), + 'utf8' + ); + if (!declaration.includes('HandlerMapping')) + throw new Error('Missing public registration declaration'); + metrics[style] = Object.fromEntries( + result.stdout + .split('\n') + .map(line => line.split(/:\s+/, 2)) + .filter(([key]) => + [ + 'Types', + 'Instantiations', + 'Memory used', + 'Check time', + 'Emit time', + 'Total time' + ].includes(key) + ) + ); + } + return metrics; + } finally { + // Only this test's generated temporary directory is removed. + rmSync(temporary, { recursive: true, force: true }); + } +} diff --git a/libs/server/type-fixtures/module.ts b/libs/server/type-fixtures/module.ts new file mode 100644 index 00000000..208747bf --- /dev/null +++ b/libs/server/type-fixtures/module.ts @@ -0,0 +1,25 @@ +import { ActionResult, implement } from '@cleverbrush/server'; +import { api } from './contracts.js'; +import { create } from './handlers/create.js'; +import { list } from './handlers/list.js'; +import { remove } from './handlers/remove.js'; +import { missingItem } from './policies.js'; +import { items } from './scope.js'; + +export const reads = items.pick('list').withHandlers({ list }); +export const writes = items.pick('create', 'remove', 'upload').withHandlers({ + create: { handler: create, errors: missingItem }, + remove: { handler: remove, errors: missingItem }, + upload: ({ files }, { db }) => { + if (!files.image || !db.name) throw new Error('Missing image'); + return ActionResult.noContent(); + } +}); +export const itemsImplementation = implement(api).use(reads, writes); +export const live = implement(api) + .group('live') + .withHandlers({ + changes: async function* ({ signal }) { + if (!signal.aborted) yield { id: 1, title: 'Changed' }; + } + }); diff --git a/libs/server/type-fixtures/policies.ts b/libs/server/type-fixtures/policies.ts new file mode 100644 index 00000000..de09c259 --- /dev/null +++ b/libs/server/type-fixtures/policies.ts @@ -0,0 +1,6 @@ +import { ActionResult, errorMap } from '@cleverbrush/server'; + +export class MissingItem extends Error {} +export const missingItem = errorMap().on(MissingItem, () => + ActionResult.notFound({ message: 'Item not found' }) +); diff --git a/libs/server/type-fixtures/scope.ts b/libs/server/type-fixtures/scope.ts new file mode 100644 index 00000000..35d1fa40 --- /dev/null +++ b/libs/server/type-fixtures/scope.ts @@ -0,0 +1,14 @@ +import { object, string } from '@cleverbrush/schema'; +import { implement } from '@cleverbrush/server'; +import { api } from './contracts.js'; + +export const Db = object({ name: string() }); +export const Mailer = object({ host: string() }); +export const items = implement(api).group('items', { + inject: { db: Db }, + tags: ['items'], + operations: { + list: { summary: 'List items' }, + create: { inject: { mailer: Mailer }, operationId: 'createItem' } + } +}); diff --git a/libs/server/type-fixtures/server.ts b/libs/server/type-fixtures/server.ts new file mode 100644 index 00000000..5b7c7c19 --- /dev/null +++ b/libs/server/type-fixtures/server.ts @@ -0,0 +1,6 @@ +import { createServer, implement } from '@cleverbrush/server'; +import { api } from './contracts.js'; +import { itemsImplementation, live } from './module.js'; + +export const mapping = implement(api).use(itemsImplementation, live).complete(); +export const server = createServer().handleAll(mapping); diff --git a/libs/server/vitest.config.mts b/libs/server/vitest.config.mts new file mode 100644 index 00000000..c2329925 --- /dev/null +++ b/libs/server/vitest.config.mts @@ -0,0 +1,12 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + include: ['src/**/*.test.ts'], + typecheck: { + enabled: true, + include: ['src/**/*.test-d.ts'], + tsconfig: './tsconfig.typecheck.json' + } + } +}); diff --git a/websites/docs/app/server/page.tsx b/websites/docs/app/server/page.tsx index cacc013f..2f6252f3 100644 --- a/websites/docs/app/server/page.tsx +++ b/websites/docs/app/server/page.tsx @@ -490,6 +490,90 @@ const AdminEp = endpoint +

+

Modular implementations

+

+ Build large APIs with separate configuration, handler, + and feature-module files. implement(api) + derives configured scopes from the shared contract; + complete() checks that every operation is + implemented before producing an ordinary handler + mapping. +

+
+                         = async (
+    { params }, { db }
+) => {
+    await removeItem(db, params.id);
+    return ActionResult.noContent();
+};
+
+// module.ts — list/remove are this example's complete contract
+export const itemsModule = items.withHandlers({ list, remove });
+
+// server.ts
+server.handleAll(implement(api).use(itemsModule).complete());`)
+                            }}
+                        />
+                    
+

+ Use pick(...operationNames) to split a + large group. Shared and per-operation services merge + while request, principal, service, and response types + remain available inside each handler file. Subscription + handlers can be composed through the same API. Existing + handle and mapHandlers remain + supported. +

+

Shared, typed error policies

+
+                        
+    ActionResult.notFound({ message: 'Item not found' })
+);
+
+const itemsModule = items.withHandlers({
+    list,
+    remove: { handler: remove, errors: itemErrors }
+});
+
+// Or adopt the policy without changing existing registration:
+server.handle(RemoveItemEndpoint,
+    withErrors(RemoveItemEndpoint, itemErrors, removeHandler));`)
+                            }}
+                        />
+                    
+

+ A policy must fit each endpoint's explicitly + declared response statuses and bodies. Only known + exceptions from the handler are translated. Unknown + exceptions retain the existing safe 500 handling; + middleware, validation, DI, and serialization failures + are not intercepted. Policies are HTTP-only and do not + change subscription errors. +

+

+ See the{' '} + + complete multi-file consumer guide + {' '} + for configuration precedence, module composition, and + migration. +

+
+ {/* ── WebSocket Subscriptions ──────────────────────── */}

WebSocket Subscriptions

From 6b628e1f3bfdd4693eac7cbe31503e823717c993 Mon Sep 17 00:00:00 2001 From: Andrew Zolotukhin Date: Tue, 29 Sep 2026 19:51:14 +0000 Subject: [PATCH 10/41] refactor(server): consolidate implementation docs and tests --- .../pr-evidence/contract-implementations.png | Bin 164220 -> 241740 bytes libs/server/README.md | 214 +++++++++++++++-- libs/server/docs/implementations.md | 222 ------------------ libs/server/package.json | 3 +- .../src/Implementation.consumer.test.ts | 177 +++++++++++++- libs/server/src/Implementation.test-d.ts | 109 +++++++-- libs/server/tsconfig.typecheck.json | 2 +- libs/server/type-fixtures/contracts.ts | 30 --- libs/server/type-fixtures/handlers/create.ts | 11 - libs/server/type-fixtures/handlers/list.ts | 7 - libs/server/type-fixtures/handlers/remove.ts | 7 - libs/server/type-fixtures/large-consumer.mjs | 176 -------------- libs/server/type-fixtures/module.ts | 25 -- libs/server/type-fixtures/policies.ts | 6 - libs/server/type-fixtures/scope.ts | 14 -- libs/server/type-fixtures/server.ts | 6 - websites/docs/app/server/page.tsx | 2 +- 17 files changed, 470 insertions(+), 541 deletions(-) delete mode 100644 libs/server/docs/implementations.md delete mode 100644 libs/server/type-fixtures/contracts.ts delete mode 100644 libs/server/type-fixtures/handlers/create.ts delete mode 100644 libs/server/type-fixtures/handlers/list.ts delete mode 100644 libs/server/type-fixtures/handlers/remove.ts delete mode 100644 libs/server/type-fixtures/large-consumer.mjs delete mode 100644 libs/server/type-fixtures/module.ts delete mode 100644 libs/server/type-fixtures/policies.ts delete mode 100644 libs/server/type-fixtures/scope.ts delete mode 100644 libs/server/type-fixtures/server.ts diff --git a/.github/pr-evidence/contract-implementations.png b/.github/pr-evidence/contract-implementations.png index 433a722fd78537769085528a9067187d43107ead..ab584dfc31bfd242297d02dc055e8dd4b0e39cf4 100644 GIT binary patch literal 241740 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
gc4EGNmoA zr2PRrQr-t-KE&Xd2z>nR%*;0oqC-RP(^T8@ZlK1l7&@bH-W=uhD<7n)xmW@vB`M+eJ5 z3KlZAQu~D8GPYMCAfz&;F_|`AB2S+&YQ%+wg$38=7bOv0S)460Hov0PNhEP}dyK;Y zb^K&8(LXySiO2XJBH*~BfdGD1-%opLMn=C!MdN$in#9?e)W$}cxSLyVAilv#@%iQH z?mr0NHPU@qKBJ=>?yO|0ZX);MBpx;wWWvdlxS1ZHqV^ihd=OJ8kD^hfiw~@HcyDz3_8n9;(iGWrbZg29jMV`6gdL;e^=UfX?de6mr zMb_M)4KAD*yyCQUboFnY7eDz*~r*n)soX)Syx?8u-xLmGF znVGju^8`^h^3s!4k5@vJuZ;E21dPjXPuksQz56Pi-Iy2#Oh5L!wtS9fU`Wom=~b=e z)lhVvD}Ae-PK%5jluQugW;``u*|}{=BKFAZYh1O(aBD9I3H8`}4gI0@d!>?Iin5|z z8%P!EwU)?_Q6S$Vi3e)BKPPZl?-`pJ$#-|Tj~SZjiJM18M%pirtYj3ZerO^w9(|K= zxRqGMsMwRhoeq(EMR98sgRz!BTyn#k)aK>1qs+27osyEuIt$(R_p6bTwG#EHE}LdD zFLY_eOT*YxBpCnO%=pQWvJu6)3cm%n4OC z#{I!1kwG`D;SJTElat*QOBf;BCb^GphFbfoAIX6Vr%kp6OLgOAnlr*BhI-rVR&%hN zA}18K{)SoWQ~%~_`gQDQ+RYxH=KJ^g%x9e0Q_We81gH!RuWmTjwl@i}F!Xf|#~Ktf z1W&dKw*Wm5ws#!=OC8Sccr7w1K6&AdwTDPtSvK5=7MYxQmtfokI_u_ZdOP`2bVrJ0I zI2;bGXur2$#%OMnw0(58A!y#RtReJ%M{~7hk>f1xG2)YoZ1p_3*z~w5mL>J`<<=T8 zR$_;XbI^_B9os}8?xkOG2#H*!8_c|SW*FO?8@h40HdXa}R9wB@HZ9xY==ys|jGn%n zcH39YQn5Mc@vk7$s||7$d!qCPLj313(Kt^ka!QZ=!K;m<#z{c1eQKn1dnR9LOAmR% zUf++^_}6~(D|+XPOSvUXv!_iC^(SP^9?7QZnlN_lbhI!OXY4?sy-=d=_V~T3D)*^WsjC1n=KK8`kM4 zYL^Q8%`|v!moM-O;<$RmpJw*Z;*GB<&}Bgp-PCWi-}NV zTnCRFkQrI!*#1%qn2-{_hh1MC($*7uT%NAKDYVDdxJ{fCV`(KPi?Apo+6#5EcR6X~ zu)X|Pfd-wAdxzP^Rd#G|?qswr9a+}x;;8}L#TB-3^XvEe_?+q{OET%)=tmljoB6Z#6`XM$9!etL^uHJrF+WhKyI zRasIQjq%%eX>d-{FueBYJ+=}{kF0fyc)vo-(Xuk)mO$OIBJr!ZO1<>j-_q>NtgSG* z9p$SuEv%}Mhngf5{g}0Qp5rtN!@GHXabV7TP3p`);9{HNhkl@^99veYyq+>`Y^RxD z4Qn!0Xtv_H+;=DBk-b^p=NBWBNSjy$jH={Kgrk`th=Xz_*`9SWMwe9G>r|{`^|4Z?&9NJPd=o=T(ru}SY4GJvP(

?A2~9mq+&;q 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 G#rzNTu4Z-s literal 164220 zcmZ6zWmsHG(>6*%fCPfO2X}XOcXxMpw*bL)aCe!(-6d#n9o*d|xN~^+e)sp|^pCk_ zdR0}|s$SizOYVtKl$U^q#es!@fPj~h6jg?RfXah__#*rD^GDAnOW_Oz1QLXlsF12> z)@e43FPa$c;5~iky*!FA<+ngZl&_ul`e^8ANVJ-Qdm>PxVq#)SH9zt`NB(pzx?k7% zOcnnnA%5Mb+GE3~dDz^=%q5VN^ztR(QEuPd!{VQo<7J`F!&Cax2+ImTUxXCp+lkUw zi!$C3`lzI>N3X5CzsM1ybN=E*NL7dGUYv`$#2#@8& zOO@o{>Lw|7B&6E6S)iUCj0{5I{>O5(8%`n}ZIHZAwc6#1JxG%}T(Dl&*;&rtOno^sb`Vl@t~ zVt1MxZ&k8}#>UZ+k$mTWr2Q;~JXTUdP5lJnsG^GYonAEPgug7SykJu!Jh6DNS@pQC zj>=L|RGLKv&ELAf)loUb`%$EbnLU}xswK$CFwa0eB@8O-9|QlM4N_H5_*c?#krShI zls#~kt%z*_V{VoG3oCPhLkSey#71yS!Tb;uogv28^7`n+yeajAS4y=wG|+$AQ6MQ4Ni-PY_=<9T~0Xr#BVZHw=?#IkAe- zxzUJwbdxEf1oz=|92t)X5JIRZ=7^Mu+=8t{@$k5K~aVKtueH zXoP|(1Rt1kL?o$W?IBV5DT(d9pzT3PV^5hP)#OZx?oTOxGP15mRl2YLpF%d%y-f7< zpRREJ(a5r-2Kt6hoAc=Kw=d*RY3gnYQssK+un{WiV^ajP7?GYy;6f5ZawoxGKouR?jRTk>Y_ zPcKcqwdM$A)tfdIo27xh3d!DKy|n0Wwb9g5qqeY=8&GcK=)KVR8K=L2TEQYem~Nx8 zvnvAwg>-d&#X`OeApRrsV^#Ak6UTH164&U5O0U4X`B4A*?Y<+W6z7hI<5iR~A!~#q zbIHucX0_7fCM=9{(N{ag{ePT!TFRZ!FwZ)gYw?n#yU0-k(K82151m?ji(iy~Z-i}A zq{eg;3BJ%CbN_vL2ubbpWQ_@qGSFPJly!A=)oya7qNE&~WT2#_rKO`IS#jFkBlBg)CryE(OH(2)>A}TYUq1IUeD}cw4^#)fhRm#z6=!4L+BgDN z^PL!(nTrIVf0BP2Tm4tRsV_=KO4#qs!ZI1}iPtpEO={=lNOYFlz$7fzG}VHeSNtx6 zGWjDQwFc=lld&G1Eb^y3XrRD93q;VRFu&ccOlN5M*p{OuS9ZKn7~Q<&(gQVbzL86C zR>-gzeM``+TlICTaS;0d%mHB;yN!bvU4~6I!VFV*JWKtOEp#o0+A2M+Kt)nx3{3f*e5w`csV)(3l8Yx|Ag}@)j40O zFgw?|z`;gIAC>|Fb6V2@osA*sQuSKZimIx*RY;^A{h{QU*4Z(_Gvb?i!!ax9;L5Xk zF)*kTgTlp-T&C|Y=OA0g5vKHK>;Mb#>;@&jnqSB#tf#P*5Uc`

J2H&|7Ybl7T% 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

ZwU#*6(kRyg&J*RKE}=!T^Z#HCKNf5 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 diff --git a/libs/server/README.md b/libs/server/README.md index 22e7b025..ba422ef2 100644 --- a/libs/server/README.md +++ b/libs/server/README.md @@ -25,45 +25,227 @@ A schema-first HTTP server framework for Node.js. Combines [`@cleverbrush/schema ## Large APIs and shared error handling -Keep contracts, server configuration, handlers, and composition in separate files: +`implement` adds server-only configuration and complete handler registration to +an existing shared API contract. It does not replace endpoint builders, change +the wire contract, or require business logic inside one fluent expression. +`errorMap` and `withErrors` also work independently of this registration API. + +### A complete multi-file example + +The application functions and service registration below are application-owned. +The contract in this example has exactly two operations, so its root is complete. + +#### Shared contract ```ts -// scope.ts — does not import handlers +// contracts.ts — browser-safe; no server configuration or handler imports +import { defineApi, endpoint, route } from '@cleverbrush/server/contract'; +import { array, number, object, string } from '@cleverbrush/schema'; + +export const Item = object({ id: number(), title: string() }); +const Message = object({ message: string() }); +export const Principal = object({ userId: string() }); +const resource = endpoint.resource('/items').authorize(Principal); + +export const api = defineApi({ + items: { + list: resource.get().responses({ 200: array(Item) }), + remove: resource.delete( + route({ id: number().coerce() })`/${p => p.id}` + ).responses({ 204: null, 404: Message }) + } +}); +``` + +#### Server configuration without handlers + +```ts +// features/items/scope.ts +import { implement } from '@cleverbrush/server'; +import { api } from '../../contracts.js'; +import { DbToken } from '../../di/tokens.js'; + export const items = implement(api).group('items', { inject: { db: DbToken }, tags: ['items'], - operations: { remove: { summary: 'Remove an item' } } + operations: { + list: { summary: 'List items', operationId: 'listItems' }, + remove: { summary: 'Remove an item', operationId: 'removeItem' } + } }); +``` + +`items.endpoints` contains immutable, server-configured builders. Export the +scope constant and reference it with `typeof`; do not annotate it with a broad +base type that erases operation names or service types. + +#### Separate handlers -// handlers/remove.ts +```ts +// features/items/handlers/list.ts +import type { Handler } from '@cleverbrush/server'; import type { items } from '../scope.js'; +import { listItems } from '../../../application/items.js'; + +export const list: Handler = ( + { principal }, { db } +) => listItems(db, principal.userId); +``` + +```ts +// features/items/handlers/remove.ts +import { ActionResult, type Handler } from '@cleverbrush/server'; +import type { items } from '../scope.js'; +import { removeItem } from '../../../application/items.js'; + export const remove: Handler = async ( - { params }, { db } + { params, principal }, { db } ) => { - await deleteItem(db, params.id); + await removeItem(db, principal.userId, params.id); return ActionResult.noContent(); }; +``` -// module.ts — bind only compatible, declared error responses -const missing = errorMap().on(MissingItemError, () => +The application function can throw a domain exception. Handlers do not need a +repeated catch block. Requests, principals, injected services, and responses are +derived at the handler's declaration site, not inferred retrospectively from a +later registration call. Type-only scope imports avoid runtime import cycles. + +#### Application-owned policy and feature registration + +```ts +// features/items/errors.ts +import { ActionResult, errorMap } from '@cleverbrush/server'; +import { MissingItemError } from '../../application/errors.js'; + +export const itemErrors = errorMap().on(MissingItemError, () => ActionResult.notFound({ message: 'Item not found' }) ); +``` + +```ts +// features/items/index.ts +import { items } from './scope.js'; +import { itemErrors } from './errors.js'; +import { list } from './handlers/list.js'; +import { remove } from './handlers/remove.js'; + export const itemsModule = items.withHandlers({ list, - remove: { handler: remove, errors: missing } + remove: { handler: remove, errors: itemErrors } }); +``` + +Attaching this policy to `list` is a type error: `list` does not declare 404. +Declaring 204 on `remove` does not permit arbitrary other statuses or bodies. + +```ts +// server.ts — after the application's ordinary server/DI setup +import { implement } from '@cleverbrush/server'; +import { api } from './contracts.js'; +import { itemsModule } from './features/items/index.js'; -// server.ts — every operation in api must be implemented server.handleAll(implement(api).use(itemsModule).complete()); ``` -The excerpt assumes an `items` contract with `list` and `remove`, including the -remove operation's 204/404 responses. `pick(...)` splits a large group into -smaller modules without losing root completeness checks. Existing `handle` and -`mapHandlers` users can adopt `withErrors(endpoint, policy, handler)` alone. +`complete()` fails at compile time if an operation is missing, and checks again +at runtime for JavaScript callers and erased types. The output is the existing +`HandlerMapping`. Authentication, validation, caching, batching, middleware, +serialization, logging, and OpenAPI generation use their existing paths. + +### Split large features and compose contract slices + +```ts +export const reads = items.pick('list').withHandlers({ list }); +export const writes = items.pick('remove').withHandlers({ + remove: { handler: remove, errors: itemErrors } +}); +export const feature = implement(api).use(reads, writes); + +// Partial roots can be exported and composed; finalize only at the full root. +server.handleAll(implement(api).use(feature).complete()); +``` + +Other groups are separate feature modules added to the same `use(...)` call. +Pass modules directly or in a literal tuple, not an array widened to a generic +module type. Duplicate bindings are rejected across modules and calls. Source +endpoint identity is checked at runtime as well: independently recreated +endpoints are not interchangeable just because their TypeScript shapes match. +`pickGroups`, `omitGroups`, and `mergeContracts` preserve endpoint references, +so intentional contract slices can be implemented and recomposed. + +Subscriptions use the same scopes, `SubscriptionHandler`, +and existing subscription handler descriptors. They count toward completeness. +HTTP error policies are not accepted on subscription handlers and do not change +the WebSocket error protocol. + +### Configuration rules + +- `inject` merges contract bindings, then group bindings, then operation bindings. + A same-name binding is replaced by the later value in both the type and runtime + service map. Other dependencies remain available. Endpoint `.inject()` itself + retains its existing replacement behavior. +- An operation's `authorize` schema takes precedence over a group's schema; + existing endpoint roles are retained. Supplying authorization explicitly makes + even a previously public operation authenticated. Omit it when authorization + already lives entirely in the shared contract. There is no implicit auth default. +- Operation `tags` replace group tags; group tags replace existing tags. Other + metadata changes only when supplied: `summary`, `description`, `operationId`, + and `deprecated: true`. Deprecation is additive and cannot be cleared here. +- Request/response schemas, cache definitions, upload settings, links, examples, + and other endpoint metadata remain on the shared endpoint. Scopes do not edit + the wire contract or silently add error responses. +- Handler descriptors support existing per-operation `middlewares`. Configuration + scopes do not register anything until explicitly bound and composed. + +### Error policy behavior and limits + +Policies are immutable. Each `.on(ErrorClass, translator)` returns a new policy. +Rules match by `instanceof` in declaration order; put subclasses before base +classes. Both handlers and translators may be synchronous or asynchronous. + +Translators return explicit JSON or bodyless `ActionResult` values. Every result +must fit the target endpoint's `.responses()` status/body map. Policies cannot +use raw/file/stream results to escape that check, and endpoints without explicit +responses cannot attach a policy. TypeScript escape hatches (`any`, assertions, +or deliberately erased annotations) still bypass static guarantees; this is not +a replacement for runtime response validation. + +Only exceptions from the handler invocation are translated. Authentication, +request validation, DI resolution, middleware, and response serialization are +outside the wrapper. Unknown thrown values are rethrown unchanged. If a translator +fails, its failure propagates without recursively applying the policy again. +Existing centralized handling still logs unexpected failures and sends safe 500 +Problem Details. There is no automatic catch-all or exposure of `Error.message`. + +Application authors decide which errors are safe to map and which details can +be returned. Framework has no knowledge of domain ownership or privacy rules. + +### Incremental adoption + +The old `handle` and `mapHandlers` APIs remain unchanged. Adopt just error policies +without migrating registration: + +```ts +import { withErrors } from '@cleverbrush/server'; + +server.handle( + RemoveItemEndpoint, + withErrors(RemoveItemEndpoint, itemErrors, removeHandler) +); +``` + +The returned function can also be placed in an existing handler map. To migrate +registration, move server-only metadata/DI into scopes, type the existing handler +files against `scope.endpoints`, bind feature modules, and finalize at the root. +Keep the shared contract in `/contract` imports; implementation facilities and +policies are server-entry-point exports only. -See the [complete modular consumer guide](docs/implementations.md), including -configuration precedence, subscriptions, failure behavior, and migration examples. +The repository tests include strict type assertions against emitted package +declarations and a generated 1,000-operation consumer with one handler per file. +The generated consumer verifies cross-file inference and records compiler +diagnostics, memory, and timings for both existing and modular registration +without using environment-dependent timing thresholds. ## Installation diff --git a/libs/server/docs/implementations.md b/libs/server/docs/implementations.md deleted file mode 100644 index bf7746d1..00000000 --- a/libs/server/docs/implementations.md +++ /dev/null @@ -1,222 +0,0 @@ -# Modular implementations and shared error policies - -`implement` adds server-only configuration and complete handler registration to -an existing shared API contract. It does not replace endpoint builders, change -the wire contract, or require business logic inside one fluent expression. -`errorMap` and `withErrors` also work independently of this registration API. - -## A complete multi-file example - -The application functions and service registration below are application-owned. -The contract in this example has exactly two operations, so its root is complete. - -### Shared contract - -```ts -// contracts.ts — browser-safe; no server configuration or handler imports -import { defineApi, endpoint, route } from '@cleverbrush/server/contract'; -import { array, number, object, string } from '@cleverbrush/schema'; - -export const Item = object({ id: number(), title: string() }); -const Message = object({ message: string() }); -export const Principal = object({ userId: string() }); -const resource = endpoint.resource('/items').authorize(Principal); - -export const api = defineApi({ - items: { - list: resource.get().responses({ 200: array(Item) }), - remove: resource.delete( - route({ id: number().coerce() })`/${p => p.id}` - ).responses({ 204: null, 404: Message }) - } -}); -``` - -### Server configuration without handlers - -```ts -// features/items/scope.ts -import { implement } from '@cleverbrush/server'; -import { api } from '../../contracts.js'; -import { DbToken } from '../../di/tokens.js'; - -export const items = implement(api).group('items', { - inject: { db: DbToken }, - tags: ['items'], - operations: { - list: { summary: 'List items', operationId: 'listItems' }, - remove: { summary: 'Remove an item', operationId: 'removeItem' } - } -}); -``` - -`items.endpoints` contains immutable, server-configured builders. Export the -scope constant and reference it with `typeof`; do not annotate it with a broad -base type that erases operation names or service types. - -### Separate handlers - -```ts -// features/items/handlers/list.ts -import type { Handler } from '@cleverbrush/server'; -import type { items } from '../scope.js'; -import { listItems } from '../../../application/items.js'; - -export const list: Handler = ( - { principal }, { db } -) => listItems(db, principal.userId); -``` - -```ts -// features/items/handlers/remove.ts -import { ActionResult, type Handler } from '@cleverbrush/server'; -import type { items } from '../scope.js'; -import { removeItem } from '../../../application/items.js'; - -export const remove: Handler = async ( - { params, principal }, { db } -) => { - await removeItem(db, principal.userId, params.id); - return ActionResult.noContent(); -}; -``` - -The application function can throw a domain exception. Handlers do not need a -repeated catch block. Requests, principals, injected services, and responses are -derived at the handler's declaration site, not inferred retrospectively from a -later registration call. Type-only scope imports avoid runtime import cycles. - -### Application-owned policy and feature registration - -```ts -// features/items/errors.ts -import { ActionResult, errorMap } from '@cleverbrush/server'; -import { MissingItemError } from '../../application/errors.js'; - -export const itemErrors = errorMap().on(MissingItemError, () => - ActionResult.notFound({ message: 'Item not found' }) -); -``` - -```ts -// features/items/index.ts -import { items } from './scope.js'; -import { itemErrors } from './errors.js'; -import { list } from './handlers/list.js'; -import { remove } from './handlers/remove.js'; - -export const itemsModule = items.withHandlers({ - list, - remove: { handler: remove, errors: itemErrors } -}); -``` - -Attaching this policy to `list` is a type error: `list` does not declare 404. -Declaring 204 on `remove` does not permit arbitrary other statuses or bodies. - -```ts -// server.ts — after the application's ordinary server/DI setup -import { implement } from '@cleverbrush/server'; -import { api } from './contracts.js'; -import { itemsModule } from './features/items/index.js'; - -server.handleAll(implement(api).use(itemsModule).complete()); -``` - -`complete()` fails at compile time if an operation is missing, and checks again -at runtime for JavaScript callers and erased types. The output is the existing -`HandlerMapping`. Authentication, validation, caching, batching, middleware, -serialization, logging, and OpenAPI generation use their existing paths. - -## Split large features and compose contract slices - -```ts -export const reads = items.pick('list').withHandlers({ list }); -export const writes = items.pick('remove').withHandlers({ - remove: { handler: remove, errors: itemErrors } -}); -export const feature = implement(api).use(reads, writes); - -// Partial roots can be exported and composed; finalize only at the full root. -server.handleAll(implement(api).use(feature).complete()); -``` - -Other groups are separate feature modules added to the same `use(...)` call. -Pass modules directly or in a literal tuple, not an array widened to a generic -module type. Duplicate bindings are rejected across modules and calls. Source -endpoint identity is checked at runtime as well: independently recreated -endpoints are not interchangeable just because their TypeScript shapes match. -`pickGroups`, `omitGroups`, and `mergeContracts` preserve endpoint references, -so intentional contract slices can be implemented and recomposed. - -Subscriptions use the same scopes, `SubscriptionHandler`, -and existing subscription handler descriptors. They count toward completeness. -HTTP error policies are not accepted on subscription handlers and do not change -the WebSocket error protocol. - -## Configuration rules - -- `inject` merges contract bindings, then group bindings, then operation bindings. - A same-name binding is replaced by the later value in both the type and runtime - service map. Other dependencies remain available. Endpoint `.inject()` itself - retains its existing replacement behavior. -- An operation's `authorize` schema takes precedence over a group's schema; - existing endpoint roles are retained. Supplying authorization explicitly makes - even a previously public operation authenticated. Omit it when authorization - already lives entirely in the shared contract. There is no implicit auth default. -- Operation `tags` replace group tags; group tags replace existing tags. Other - metadata changes only when supplied: `summary`, `description`, `operationId`, - and `deprecated: true`. Deprecation is additive and cannot be cleared here. -- Request/response schemas, cache definitions, upload settings, links, examples, - and other endpoint metadata remain on the shared endpoint. Scopes do not edit - the wire contract or silently add error responses. -- Handler descriptors support existing per-operation `middlewares`. Configuration - scopes do not register anything until explicitly bound and composed. - -## Error policy behavior and limits - -Policies are immutable. Each `.on(ErrorClass, translator)` returns a new policy. -Rules match by `instanceof` in declaration order; put subclasses before base -classes. Both handlers and translators may be synchronous or asynchronous. - -Translators return explicit JSON or bodyless `ActionResult` values. Every result -must fit the target endpoint's `.responses()` status/body map. Policies cannot -use raw/file/stream results to escape that check, and endpoints without explicit -responses cannot attach a policy. TypeScript escape hatches (`any`, assertions, -or deliberately erased annotations) still bypass static guarantees; this is not -a replacement for runtime response validation. - -Only exceptions from the handler invocation are translated. Authentication, -request validation, DI resolution, middleware, and response serialization are -outside the wrapper. Unknown thrown values are rethrown unchanged. If a translator -fails, its failure propagates without recursively applying the policy again. -Existing centralized handling still logs unexpected failures and sends safe 500 -Problem Details. There is no automatic catch-all or exposure of `Error.message`. - -Application authors decide which errors are safe to map and which details can -be returned. Framework has no knowledge of domain ownership or privacy rules. - -## Incremental adoption - -The old `handle` and `mapHandlers` APIs remain unchanged. Adopt just error policies -without migrating registration: - -```ts -import { withErrors } from '@cleverbrush/server'; - -server.handle( - RemoveItemEndpoint, - withErrors(RemoveItemEndpoint, itemErrors, removeHandler) -); -``` - -The returned function can also be placed in an existing handler map. To migrate -registration, move server-only metadata/DI into scopes, type the existing handler -files against `scope.endpoints`, bind feature modules, and finalize at the root. -Keep the shared contract in `/contract` imports; implementation facilities and -policies are server-entry-point exports only. - -The repository tests include a strict multi-file consumer against emitted package -declarations and a generated 1,000-operation consumer with one handler per file. -The latter records compiler diagnostics, memory, and timings for both existing -and modular registration without using environment-dependent timing thresholds. diff --git a/libs/server/package.json b/libs/server/package.json index d6d02d82..4fdc5423 100644 --- a/libs/server/package.json +++ b/libs/server/package.json @@ -17,8 +17,7 @@ }, "description": "Schema-first HTTP server framework — schema-driven controllers, DI, auto-validation, RFC 9457 errors", "files": [ - "dist", - "docs" + "dist" ], "homepage": "https://docs.cleverbrush.com/server", "keywords": [ diff --git a/libs/server/src/Implementation.consumer.test.ts b/libs/server/src/Implementation.consumer.test.ts index 64d0b212..5b09f6bd 100644 --- a/libs/server/src/Implementation.consumer.test.ts +++ b/libs/server/src/Implementation.consumer.test.ts @@ -1,5 +1,180 @@ +import { spawnSync } from 'node:child_process'; +import { + mkdirSync, + mkdtempSync, + readFileSync, + rmSync, + symlinkSync, + writeFileSync +} from 'node:fs'; +import { tmpdir } from 'node:os'; +import { dirname, join, resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; import { expect, it } from 'vitest'; -import { checkLargeConsumers } from '../type-fixtures/large-consumer.mjs'; + +const repository = resolve(dirname(fileURLToPath(import.meta.url)), '../../..'); + +/** Generate and compile equivalent, separately packaged 1,000-operation consumers. */ +function checkLargeConsumers() { + const temporary = mkdtempSync( + join(tmpdir(), 'framework-implementation-consumer-') + ); + const write = (path: string, contents: string) => { + const destination = join(temporary, path); + mkdirSync(dirname(destination), { recursive: true }); + writeFileSync(destination, contents); + }; + const metrics: Record> = {}; + try { + symlinkSync( + join(repository, 'node_modules'), + join(temporary, 'node_modules'), + 'dir' + ); + write('package.json', JSON.stringify({ type: 'module' })); + for (const style of ['existing', 'modular']) { + write( + `${style}/shared.ts`, + `import { object, string } from '@cleverbrush/schema'; +export const Db = object({ name: string() }); +export const Query = object({ search: string() }); +export const Output = object({ title: string() });` + ); + const contractImports: string[] = []; + const rootImports: string[] = []; + for (let group = 0; group < 10; group++) { + const name = `feature${group}`; + const names = Array.from( + { length: 100 }, + (_, i) => `operation${i}` + ); + write( + `${style}/${name}/contract.ts`, + `import { endpoint } from '@cleverbrush/server/contract'; +import { Query, Output } from '../shared.js'; +export const ${name} = { +${names.map(operation => `${operation}: endpoint.get('/${name}/${operation}').query(Query).responses({ 200: Output })`).join(',\n')} +};` + ); + contractImports.push( + `import { ${name} } from './${name}/contract.js';` + ); + const scope = + style === 'modular' + ? `import { implement } from '@cleverbrush/server'; +export const scope = implement(api).group('${name}', { inject: { db: Db }, tags: ['${name}'] });` + : `export const scope = { endpoints: { +${names.map(operation => `${operation}: api.${name}.${operation}.inject({ db: Db }).tags('${name}')`).join(',\n')} +} };`; + write( + `${style}/${name}/scope.ts`, + `import { api } from '../contract.js'; +import { Db } from '../shared.js'; +${scope}` + ); + for (const operation of names) { + write( + `${style}/${name}/handlers/${operation}.ts`, + `import type { Handler } from '@cleverbrush/server'; +import type { scope } from '../scope.js'; +export const ${operation}: Handler = ({ query }, { db }) => ({ title: query.search + db.name });` + ); + } + const handlers = `{ ${names.join(', ')} }`; + write( + `${style}/${name}/index.ts`, + `import { scope } from './scope.js'; +${names.map(operation => `import { ${operation} } from './handlers/${operation}.js';`).join('\n')} +${ + style === 'modular' + ? `export const ${name} = scope.withHandlers(${handlers});` + : `export const ${name} = { endpoints: scope.endpoints, handlers: ${handlers} };` +}` + ); + rootImports.push( + `import { ${name} } from './${name}/index.js';` + ); + } + const groups = Array.from({ length: 10 }, (_, i) => `feature${i}`); + write( + `${style}/contract.ts`, + `import { defineApi } from '@cleverbrush/server/contract'; +${contractImports.join('\n')} +export const api = defineApi({ ${groups.join(', ')} });` + ); + write( + `${style}/index.ts`, + `${rootImports.join('\n')} +import { api } from './contract.js'; +${ + style === 'modular' + ? `import { implement } from '@cleverbrush/server'; +export const registration = implement(api).use(${groups.join(', ')}).complete();` + : `import { mapHandlers } from '@cleverbrush/server'; +export const registration = mapHandlers({ ${groups.map(g => `${g}: ${g}.endpoints`).join(', ')} }, { ${groups.map(g => `${g}: ${g}.handlers`).join(', ')} });` +}` + ); + write( + `${style}/tsconfig.json`, + JSON.stringify({ + compilerOptions: { + target: 'ES2022', + module: 'ESNext', + moduleResolution: 'bundler', + strict: true, + declaration: true, + emitDeclarationOnly: true, + outDir: 'dist', + types: ['node'], + lib: ['ES2022', 'ESNext.Disposable'], + skipLibCheck: false + }, + include: ['**/*.ts'], + exclude: ['dist'] + }) + ); + const result = spawnSync( + process.execPath, + [ + join(repository, 'node_modules/typescript/lib/tsc.js'), + '-p', + join(temporary, style, 'tsconfig.json'), + '--extendedDiagnostics' + ], + { encoding: 'utf8', timeout: 90000, maxBuffer: 4 * 1024 * 1024 } + ); + if (result.status !== 0) + throw new Error( + `${style} consumer failed:\n${result.stdout}\n${result.stderr}\n${result.error ?? ''}` + ); + const declaration = readFileSync( + join(temporary, style, 'dist/index.d.ts'), + 'utf8' + ); + if (!declaration.includes('HandlerMapping')) + throw new Error('Missing public registration declaration'); + metrics[style] = Object.fromEntries( + result.stdout + .split('\n') + .map(line => line.split(/:\s+/, 2)) + .filter(([key]) => + [ + 'Types', + 'Instantiations', + 'Memory used', + 'Check time', + 'Emit time', + 'Total time' + ].includes(key) + ) + ); + } + return metrics; + } finally { + // Only this test's generated temporary directory is removed. + rmSync(temporary, { recursive: true, force: true }); + } +} it('typechecks and emits a 1,000-operation multi-file consumer against published declarations', () => { const metrics = checkLargeConsumers(); diff --git a/libs/server/src/Implementation.test-d.ts b/libs/server/src/Implementation.test-d.ts index 3032035b..4da5fc97 100644 --- a/libs/server/src/Implementation.test-d.ts +++ b/libs/server/src/Implementation.test-d.ts @@ -1,29 +1,106 @@ -import { number, object, string } from '@cleverbrush/schema'; +import { array, number, object, string } from '@cleverbrush/schema'; import { ActionResult, + createServer, errorMap, type Handler, type HandlerMapping, implement, withErrors } from '@cleverbrush/server'; -import { defineApi, endpoint, pickGroups } from '@cleverbrush/server/contract'; -import { expectTypeOf, test } from 'vitest'; -import { api } from '../type-fixtures/contracts.js'; -import type { create } from '../type-fixtures/handlers/create.js'; -import { list } from '../type-fixtures/handlers/list.js'; -import { remove } from '../type-fixtures/handlers/remove.js'; import { - itemsImplementation, - live, - reads, - writes -} from '../type-fixtures/module.js'; -import { missingItem } from '../type-fixtures/policies.js'; -import { Db, items } from '../type-fixtures/scope.js'; -import { mapping } from '../type-fixtures/server.js'; + defineApi, + endpoint, + pickGroups, + route +} from '@cleverbrush/server/contract'; +import { expectTypeOf, test } from 'vitest'; + +const Item = object({ id: number(), title: string() }); +const Message = object({ message: string() }); +const Principal = object({ userId: string() }); +const resource = endpoint.resource('/items').authorize(Principal, 'member'); +const byId = route({ id: number().coerce() })`/${p => p.id}`; + +const api = defineApi({ + items: { + list: resource + .get() + .query(object({ search: string() })) + .responses({ 200: array(Item), 400: Message }), + create: resource + .post() + .body(object({ title: string() })) + .responses({ 201: Item, 404: Message }), + remove: resource.delete(byId).responses({ 204: null, 404: Message }), + upload: endpoint + .post('/items/upload') + .authorize(Principal) + .upload() + .responses({ 204: null }) + }, + live: { + changes: endpoint.subscription('/changes').outgoing(Item) + } +}); + +const Db = object({ name: string() }); +const Mailer = object({ host: string() }); +const items = implement(api).group('items', { + inject: { db: Db }, + tags: ['items'], + operations: { + list: { summary: 'List items' }, + create: { inject: { mailer: Mailer }, operationId: 'createItem' } + } +}); + +const list: Handler = async ( + { principal, query }, + { db } +) => [{ id: 1, title: `${principal.userId}:${query.search}:${db.name}` }]; + +const create: Handler = ( + { body }, + { db, mailer } +) => + ActionResult.created({ + id: 1, + title: `${body.title}:${db.name}:${mailer.host}` + }); + +const remove: Handler = ({ params }) => { + if (params.id < 0) throw new Error('Not a persisted item'); + return ActionResult.noContent(); +}; + +class MissingItem extends Error {} +const missingItem = errorMap().on(MissingItem, () => + ActionResult.notFound({ message: 'Item not found' }) +); + +const reads = items.pick('list').withHandlers({ list }); +const writes = items.pick('create', 'remove', 'upload').withHandlers({ + create: { handler: create, errors: missingItem }, + remove: { handler: remove, errors: missingItem }, + upload: ({ files }, { db }) => { + if (!files.image || !db.name) throw new Error('Missing image'); + return ActionResult.noContent(); + } +}); +const itemsImplementation = implement(api).use(reads, writes); +const live = implement(api) + .group('live') + .withHandlers({ + changes: async function* ({ signal }) { + if (!signal.aborted) yield { id: 1, title: 'Changed' }; + } + }); + +const mapping = implement(api).use(itemsImplementation, live).complete(); -test('cross-file declarations preserve exact request, DI and return types', () => { +test('separately declared handlers preserve exact request, DI and return types', () => { + createServer().handleAll(mapping); expectTypeOf(mapping).toEqualTypeOf(); expectTypeOf[0]['query']>().toEqualTypeOf<{ search: string; diff --git a/libs/server/tsconfig.typecheck.json b/libs/server/tsconfig.typecheck.json index 3442974a..56426e83 100644 --- a/libs/server/tsconfig.typecheck.json +++ b/libs/server/tsconfig.typecheck.json @@ -5,6 +5,6 @@ "strict": true, "rootDir": "." }, - "include": ["src/**/*.test-d.ts", "type-fixtures/**/*.ts"], + "include": ["src/**/*.test-d.ts"], "exclude": [] } diff --git a/libs/server/type-fixtures/contracts.ts b/libs/server/type-fixtures/contracts.ts deleted file mode 100644 index 8b338a1c..00000000 --- a/libs/server/type-fixtures/contracts.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { array, number, object, string } from '@cleverbrush/schema'; -import { defineApi, endpoint, route } from '@cleverbrush/server/contract'; - -export const Item = object({ id: number(), title: string() }); -export const Message = object({ message: string() }); -export const Principal = object({ userId: string() }); -const resource = endpoint.resource('/items').authorize(Principal, 'member'); -const byId = route({ id: number().coerce() })`/${p => p.id}`; - -export const api = defineApi({ - items: { - list: resource - .get() - .query(object({ search: string() })) - .responses({ 200: array(Item), 400: Message }), - create: resource - .post() - .body(object({ title: string() })) - .responses({ 201: Item, 404: Message }), - remove: resource.delete(byId).responses({ 204: null, 404: Message }), - upload: endpoint - .post('/items/upload') - .authorize(Principal) - .upload() - .responses({ 204: null }) - }, - live: { - changes: endpoint.subscription('/changes').outgoing(Item) - } -}); diff --git a/libs/server/type-fixtures/handlers/create.ts b/libs/server/type-fixtures/handlers/create.ts deleted file mode 100644 index 98e92893..00000000 --- a/libs/server/type-fixtures/handlers/create.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { ActionResult, type Handler } from '@cleverbrush/server'; -import type { items } from '../scope.js'; - -export const create: Handler = ( - { body }, - { db, mailer } -) => - ActionResult.created({ - id: 1, - title: `${body.title}:${db.name}:${mailer.host}` - }); diff --git a/libs/server/type-fixtures/handlers/list.ts b/libs/server/type-fixtures/handlers/list.ts deleted file mode 100644 index 35c2abeb..00000000 --- a/libs/server/type-fixtures/handlers/list.ts +++ /dev/null @@ -1,7 +0,0 @@ -import type { Handler } from '@cleverbrush/server'; -import type { items } from '../scope.js'; - -export const list: Handler = async ( - { principal, query }, - { db } -) => [{ id: 1, title: `${principal.userId}:${query.search}:${db.name}` }]; diff --git a/libs/server/type-fixtures/handlers/remove.ts b/libs/server/type-fixtures/handlers/remove.ts deleted file mode 100644 index 95658910..00000000 --- a/libs/server/type-fixtures/handlers/remove.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { ActionResult, type Handler } from '@cleverbrush/server'; -import type { items } from '../scope.js'; - -export const remove: Handler = ({ params }) => { - if (params.id < 0) throw new Error('Not a persisted item'); - return ActionResult.noContent(); -}; diff --git a/libs/server/type-fixtures/large-consumer.mjs b/libs/server/type-fixtures/large-consumer.mjs deleted file mode 100644 index 5214dfb6..00000000 --- a/libs/server/type-fixtures/large-consumer.mjs +++ /dev/null @@ -1,176 +0,0 @@ -import { spawnSync } from 'node:child_process'; -import { - mkdirSync, - mkdtempSync, - readFileSync, - rmSync, - symlinkSync, - writeFileSync -} from 'node:fs'; -import { tmpdir } from 'node:os'; -import { dirname, join, resolve } from 'node:path'; -import { fileURLToPath } from 'node:url'; - -const repository = resolve(dirname(fileURLToPath(import.meta.url)), '../../..'); - -/** Generate and compile equivalent, separately packaged 1,000-operation consumers. */ -export function checkLargeConsumers() { - const temporary = mkdtempSync( - join(tmpdir(), 'framework-implementation-consumer-') - ); - const write = (path, contents) => { - const destination = join(temporary, path); - mkdirSync(dirname(destination), { recursive: true }); - writeFileSync(destination, contents); - }; - const metrics = {}; - try { - symlinkSync( - join(repository, 'node_modules'), - join(temporary, 'node_modules'), - 'dir' - ); - write('package.json', JSON.stringify({ type: 'module' })); - for (const style of ['existing', 'modular']) { - write( - `${style}/shared.ts`, - `import { object, string } from '@cleverbrush/schema'; -export const Db = object({ name: string() }); -export const Query = object({ search: string() }); -export const Output = object({ title: string() });` - ); - const contractImports = []; - const rootImports = []; - for (let group = 0; group < 10; group++) { - const name = `feature${group}`; - const names = Array.from( - { length: 100 }, - (_, i) => `operation${i}` - ); - write( - `${style}/${name}/contract.ts`, - `import { endpoint } from '@cleverbrush/server/contract'; -import { Query, Output } from '../shared.js'; -export const ${name} = { -${names.map(operation => `${operation}: endpoint.get('/${name}/${operation}').query(Query).responses({ 200: Output })`).join(',\n')} -};` - ); - contractImports.push( - `import { ${name} } from './${name}/contract.js';` - ); - const scope = - style === 'modular' - ? `import { implement } from '@cleverbrush/server'; -export const scope = implement(api).group('${name}', { inject: { db: Db }, tags: ['${name}'] });` - : `export const scope = { endpoints: { -${names.map(operation => `${operation}: api.${name}.${operation}.inject({ db: Db }).tags('${name}')`).join(',\n')} -} };`; - write( - `${style}/${name}/scope.ts`, - `import { api } from '../contract.js'; -import { Db } from '../shared.js'; -${scope}` - ); - for (const operation of names) { - write( - `${style}/${name}/handlers/${operation}.ts`, - `import type { Handler } from '@cleverbrush/server'; -import type { scope } from '../scope.js'; -export const ${operation}: Handler = ({ query }, { db }) => ({ title: query.search + db.name });` - ); - } - const handlers = `{ ${names.join(', ')} }`; - write( - `${style}/${name}/index.ts`, - `import { scope } from './scope.js'; -${names.map(operation => `import { ${operation} } from './handlers/${operation}.js';`).join('\n')} -${ - style === 'modular' - ? `export const ${name} = scope.withHandlers(${handlers});` - : `export const ${name} = { endpoints: scope.endpoints, handlers: ${handlers} };` -}` - ); - rootImports.push( - `import { ${name} } from './${name}/index.js';` - ); - } - const groups = Array.from({ length: 10 }, (_, i) => `feature${i}`); - write( - `${style}/contract.ts`, - `import { defineApi } from '@cleverbrush/server/contract'; -${contractImports.join('\n')} -export const api = defineApi({ ${groups.join(', ')} });` - ); - write( - `${style}/index.ts`, - `${rootImports.join('\n')} -import { api } from './contract.js'; -${ - style === 'modular' - ? `import { implement } from '@cleverbrush/server'; -export const registration = implement(api).use(${groups.join(', ')}).complete();` - : `import { mapHandlers } from '@cleverbrush/server'; -export const registration = mapHandlers({ ${groups.map(g => `${g}: ${g}.endpoints`).join(', ')} }, { ${groups.map(g => `${g}: ${g}.handlers`).join(', ')} });` -}` - ); - write( - `${style}/tsconfig.json`, - JSON.stringify({ - compilerOptions: { - target: 'ES2022', - module: 'ESNext', - moduleResolution: 'bundler', - strict: true, - declaration: true, - emitDeclarationOnly: true, - outDir: 'dist', - types: ['node'], - lib: ['ES2022', 'ESNext.Disposable'], - skipLibCheck: false - }, - include: ['**/*.ts'], - exclude: ['dist'] - }) - ); - const result = spawnSync( - process.execPath, - [ - join(repository, 'node_modules/typescript/lib/tsc.js'), - '-p', - join(temporary, style, 'tsconfig.json'), - '--extendedDiagnostics' - ], - { encoding: 'utf8', timeout: 90000, maxBuffer: 4 * 1024 * 1024 } - ); - if (result.status !== 0) - throw new Error( - `${style} consumer failed:\n${result.stdout}\n${result.stderr}\n${result.error ?? ''}` - ); - const declaration = readFileSync( - join(temporary, style, 'dist/index.d.ts'), - 'utf8' - ); - if (!declaration.includes('HandlerMapping')) - throw new Error('Missing public registration declaration'); - metrics[style] = Object.fromEntries( - result.stdout - .split('\n') - .map(line => line.split(/:\s+/, 2)) - .filter(([key]) => - [ - 'Types', - 'Instantiations', - 'Memory used', - 'Check time', - 'Emit time', - 'Total time' - ].includes(key) - ) - ); - } - return metrics; - } finally { - // Only this test's generated temporary directory is removed. - rmSync(temporary, { recursive: true, force: true }); - } -} diff --git a/libs/server/type-fixtures/module.ts b/libs/server/type-fixtures/module.ts deleted file mode 100644 index 208747bf..00000000 --- a/libs/server/type-fixtures/module.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ActionResult, implement } from '@cleverbrush/server'; -import { api } from './contracts.js'; -import { create } from './handlers/create.js'; -import { list } from './handlers/list.js'; -import { remove } from './handlers/remove.js'; -import { missingItem } from './policies.js'; -import { items } from './scope.js'; - -export const reads = items.pick('list').withHandlers({ list }); -export const writes = items.pick('create', 'remove', 'upload').withHandlers({ - create: { handler: create, errors: missingItem }, - remove: { handler: remove, errors: missingItem }, - upload: ({ files }, { db }) => { - if (!files.image || !db.name) throw new Error('Missing image'); - return ActionResult.noContent(); - } -}); -export const itemsImplementation = implement(api).use(reads, writes); -export const live = implement(api) - .group('live') - .withHandlers({ - changes: async function* ({ signal }) { - if (!signal.aborted) yield { id: 1, title: 'Changed' }; - } - }); diff --git a/libs/server/type-fixtures/policies.ts b/libs/server/type-fixtures/policies.ts deleted file mode 100644 index de09c259..00000000 --- a/libs/server/type-fixtures/policies.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { ActionResult, errorMap } from '@cleverbrush/server'; - -export class MissingItem extends Error {} -export const missingItem = errorMap().on(MissingItem, () => - ActionResult.notFound({ message: 'Item not found' }) -); diff --git a/libs/server/type-fixtures/scope.ts b/libs/server/type-fixtures/scope.ts deleted file mode 100644 index 35d1fa40..00000000 --- a/libs/server/type-fixtures/scope.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { object, string } from '@cleverbrush/schema'; -import { implement } from '@cleverbrush/server'; -import { api } from './contracts.js'; - -export const Db = object({ name: string() }); -export const Mailer = object({ host: string() }); -export const items = implement(api).group('items', { - inject: { db: Db }, - tags: ['items'], - operations: { - list: { summary: 'List items' }, - create: { inject: { mailer: Mailer }, operationId: 'createItem' } - } -}); diff --git a/libs/server/type-fixtures/server.ts b/libs/server/type-fixtures/server.ts deleted file mode 100644 index 5b7c7c19..00000000 --- a/libs/server/type-fixtures/server.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { createServer, implement } from '@cleverbrush/server'; -import { api } from './contracts.js'; -import { itemsImplementation, live } from './module.js'; - -export const mapping = implement(api).use(itemsImplementation, live).complete(); -export const server = createServer().handleAll(mapping); diff --git a/websites/docs/app/server/page.tsx b/websites/docs/app/server/page.tsx index 2f6252f3..77771ae4 100644 --- a/websites/docs/app/server/page.tsx +++ b/websites/docs/app/server/page.tsx @@ -566,7 +566,7 @@ server.handle(RemoveItemEndpoint,

See the{' '} - + complete multi-file consumer guide {' '} for configuration precedence, module composition, and From 47133eb1e93683b3af4f977e8be6d09d08c71fec Mon Sep 17 00:00:00 2001 From: Andrew Zolotukhin Date: Wed, 30 Sep 2026 07:22:15 +0000 Subject: [PATCH 11/41] feat: bridge server validation issues to typed form fields --- .changeset/server-form-validation.md | 10 + .../pr-evidence/server-form-validation.png | Bin 0 -> 35430 bytes demos/e2e/src/ui/todo-crud.ui.test.ts | 24 ++ demos/todo-backend/src/api/contract.ts | 9 +- .../src/features/todos/CreateTodoPage.tsx | 34 +-- libs/client/README.md | 29 ++ libs/client/src/index.ts | 4 + .../src/validationIssues.integration.test.ts | 64 +++++ libs/client/src/validationIssues.test.ts | 63 +++++ libs/client/src/validationIssues.ts | 71 +++++ libs/react-form/README.md | 111 ++++++++ libs/react-form/src/FormStore.ts | 162 ++++++++++- libs/react-form/src/hooks.ts | 22 +- libs/react-form/src/index.ts | 1 + libs/react-form/src/issues.test-d.tsx | 32 +++ libs/react-form/src/issues.test.tsx | 263 ++++++++++++++++++ libs/react-form/src/types.ts | 14 +- libs/schema/README.md | 24 ++ .../schema/src/builders/ArraySchemaBuilder.ts | 30 +- .../src/builders/IndexedProperties.test.ts | 87 ++++++ .../src/builders/ObjectSchemaBuilder.ts | 186 +++++++++++++ libs/schema/src/builders/SchemaBuilder.ts | 29 +- libs/schema/src/core.ts | 1 + libs/server/README.md | 14 + libs/server/src/ParameterResolver.ts | 4 +- libs/server/tests/ParameterResolver.test.ts | 32 ++- .../docs/app/react-form/LifecycleDemo.tsx | 28 +- websites/docs/app/react-form/page.tsx | 39 ++- 28 files changed, 1325 insertions(+), 62 deletions(-) create mode 100644 .changeset/server-form-validation.md create mode 100644 .github/pr-evidence/server-form-validation.png create mode 100644 libs/client/src/validationIssues.integration.test.ts create mode 100644 libs/client/src/validationIssues.test.ts create mode 100644 libs/client/src/validationIssues.ts create mode 100644 libs/react-form/src/issues.test-d.tsx create mode 100644 libs/react-form/src/issues.test.tsx create mode 100644 libs/schema/src/builders/IndexedProperties.test.ts diff --git a/.changeset/server-form-validation.md b/.changeset/server-form-validation.md new file mode 100644 index 00000000..55850f3a --- /dev/null +++ b/.changeset/server-form-validation.md @@ -0,0 +1,10 @@ +--- +'@cleverbrush/schema': minor +'@cleverbrush/server': minor +'@cleverbrush/client': minor +'@cleverbrush/react-form': minor +--- + +Preserve structured server validation issues through typed clients and form +submissions. Add transport-independent external form issues, typed indexed array +fields, and precise indexed validation paths without changing existing form APIs. diff --git a/.github/pr-evidence/server-form-validation.png b/.github/pr-evidence/server-form-validation.png new file mode 100644 index 0000000000000000000000000000000000000000..275945d06dd0ea0de1de189bcfe3761a6a30b06e GIT binary patch literal 35430 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 literal 0 HcmV?d00001 diff --git a/demos/e2e/src/ui/todo-crud.ui.test.ts b/demos/e2e/src/ui/todo-crud.ui.test.ts index 1abe3411..4a93b440 100644 --- a/demos/e2e/src/ui/todo-crud.ui.test.ts +++ b/demos/e2e/src/ui/todo-crud.ui.test.ts @@ -22,6 +22,30 @@ async function registerAndLogin( } describe('UI — todo CRUD', () => { + it('shows a real server rejection beside the field, preserves edits and retries', async () => { + await withPage(async page => { + await registerAndLogin(page, uniqueEmail('ui-field-errors'), 'TestPass123!'); + await page.goto('/todos/new'); + const title = page.locator('input').first(); + await title.fill(uniqueTitle('rejected')); + await page.locator('textarea').fill('Keep this description'); + // Simulate a stale client's request shape while keeping the browser + // input locally valid. The actual backend produces the 400 response. + await page.route(/\/api\/todos\/?$/, async route => { + if (route.request().method() !== 'POST') return route.continue(); + await route.continue({postData: JSON.stringify({...route.request().postDataJSON(), title: ''})}); + }); + await page.getByRole('button', {name: 'Create Todo', exact: true}).click(); + await page.getByText('Check the highlighted fields.').waitFor(); + expect(await title.getAttribute('aria-invalid')).toBe('true'); + expect(await page.locator('textarea').inputValue()).toBe('Keep this description'); + await page.unroute(/\/api\/todos\/?$/); + await title.fill(uniqueTitle('corrected')); + expect(await title.getAttribute('aria-invalid')).toBe('false'); + await page.getByRole('button', {name: 'Create Todo', exact: true}).click(); + await page.waitForURL(/\/todos\/\d+$/); + }); + }); it('create → appears in list → delete → disappears; DB row removed', async () => { const email = uniqueEmail('ui-crud'); const title = uniqueTitle('crud'); diff --git a/demos/todo-backend/src/api/contract.ts b/demos/todo-backend/src/api/contract.ts index df3d5b93..0f546852 100644 --- a/demos/todo-backend/src/api/contract.ts +++ b/demos/todo-backend/src/api/contract.ts @@ -4,8 +4,9 @@ * This is the **single source of truth** for both the backend and the * frontend. It defines the shape of every API endpoint (HTTP method, * path, body / query / header schemas, and response schemas) without any - * server-specific concerns like authorization, dependency injection, or - * OpenAPI metadata. + * server-only dependencies or OpenAPI metadata. Authentication requirements + * belong in shared contracts so clients know when to attach their tokens; + * the backend remains responsible for enforcing permissions. * * - The **backend** imports this contract and extends each endpoint with * `.authorize()`, `.inject()`, and OpenAPI metadata. @@ -29,6 +30,7 @@ import { ImportTodosBodySchema, LoginBodySchema, PaginationQuerySchema, + PrincipalSchema, RegisterBodySchema, TodoEventSchema, TodoListQuerySchema, @@ -47,7 +49,7 @@ const ById = route({ id: number().coerce() })`/${t => t.id}`; // ── Resource factories ──────────────────────────────────────────────────────── -const todosResource = endpoint.resource('/api/todos'); +const todosResource = endpoint.resource('/api/todos').authorize(PrincipalSchema); const usersResource = endpoint.resource('/api/users'); const activityResource = endpoint.resource('/api/activity'); @@ -222,6 +224,7 @@ export const api = defineApi({ }), me: usersResource.get(route({})`/me`) + .authorize(PrincipalSchema) .cacheTag('user-profile') .returns(UserResponseSchema) }, diff --git a/demos/todo-frontend/src/features/todos/CreateTodoPage.tsx b/demos/todo-frontend/src/features/todos/CreateTodoPage.tsx index 73aea85b..3a8be8d8 100644 --- a/demos/todo-frontend/src/features/todos/CreateTodoPage.tsx +++ b/demos/todo-frontend/src/features/todos/CreateTodoPage.tsx @@ -1,4 +1,3 @@ -import { useState } from 'react'; import { useNavigate } from 'react-router'; import { Box, @@ -9,31 +8,26 @@ import { } from '@radix-ui/themes'; import { Field, useSchemaForm } from '@cleverbrush/react-form'; import { CreateTodoBodySchema } from '@cleverbrush/todo-backend/contract'; -import { ApiError } from '@cleverbrush/client'; +import { ApiError, decodeValidationIssues } from '@cleverbrush/client'; import { client } from '../../api/client'; export function CreateTodoPage() { const navigate = useNavigate(); - const [error, setError] = useState(null); - const [loading, setLoading] = useState(false); - const form = useSchemaForm(CreateTodoBodySchema); - const handleSubmit = async () => { - const result = await form.submit(); - if (!result.valid || !result.object) return; - - setLoading(true); - setError(null); + const handleSubmit = form.handleSubmit(async values => { try { - const todo = await client.todos.create({ body: result.object }); - navigate(`/todos/${todo.id}`); + const todo = await client.todos.create({ body: values }); + return { ok: true, data: todo }; } catch (e) { - setError(e instanceof ApiError ? e.message : 'Failed to create todo.'); - } finally { - setLoading(false); + const issues = decodeValidationIssues(e, { source: 'body' }); + return { + ok: false, + error: issues ? 'Check the highlighted fields.' : e instanceof ApiError ? e.message : 'Failed to create todo.', + issues + }; } - }; + }, { onSuccess: todo => { navigate(`/todos/${todo!.id}`); } }); return ( @@ -42,9 +36,9 @@ export function CreateTodoPage() { New Todo - {error && ( + {form.error && ( - {error} + {form.error} )} @@ -52,7 +46,7 @@ export function CreateTodoPage() { t.description} form={form} label="Description (optional)" variant="textarea" /> - + ; +} +``` + +Ordinary shared-schema errors are already caught locally. This bridge handles +structured server rejections (including schema-version differences); it does +not manufacture field errors from business-error strings. Never serialize an +`ApiError` instance to the browser. Only its decoded issue data crosses the action +boundary. A form with different property names must explicitly map the returned +pointers to its own paths before returning the failure result. + +### Manual issues, indexed fields and lifecycle + +Use `form.setIssues(issues)` for custom flows; it replaces the external issue set. +`form.setIssues([])` clears only external errors, not local schema errors. Prefer +returned issues for asynchronous submissions: `handleSubmit` ignores stale issues +after any value update, reset or unmount. Manual callers own that race protection. + +```tsx +const form = useSchemaForm(object({ addresses: array(object({ city: string() })) })); +const city = form.useField(t => t.addresses[0].city); // string | undefined +form.setIssues([{ pointer: '/addresses/0/city', detail: 'Choose another city.' }]); +// Equivalent with Field / a typed form system: +// t.addresses[0].city} /> +``` + +- Matched fields become touched and show their first external message through + `field.error`. External messages take precedence until cleared. +- Local validation, including debounced validation, does not erase external + issues on unchanged fields. Editing clears related ancestor/descendant issues, + not unrelated fields. Root issues clear when values change. +- `setValue` clears issues for changed values. Replacing/reordering an array + clears its indexed issues: indices are positions, not stable item identities. +- Reset and the next submission clear all external issues. Existing string-only + submission errors continue to work and clear on reset/resubmission. +- Root, unknown, and currently unbound field issues are included in `form.error` + alongside the application message, joined by newlines. Render that summary even + when using inline messages. Binding/unbinding a field updates the summary. +- Indexed selectors support object, primitive and nested arrays, but are not + native arrays: no `push`, negative indices, or add/remove/reorder UI helpers. + +JSON Pointer escaping preserves distinct names: `/a.b`, `/a/b`, `/a~1b`, and +`/a~0b` target a dotted name, a nested field, a slash in a name, and a tilde in a +name respectively. Unknown paths never create values or mutate the form. + ## Why @cleverbrush/react-form? **The problem:** Every popular React form library — React Hook Form, Formik, React Final Form — requires you to reference fields by **string names**: `register("email")`, ``. The moment you pass a field name as a string, you lose TypeScript's type safety. Rename a property in your data model and the compiler stays silent — your form just silently breaks at runtime. The larger your codebase, the more of these invisible string references you accumulate, and the more fragile every refactor becomes. diff --git a/libs/react-form/src/FormStore.ts b/libs/react-form/src/FormStore.ts index 45971e0e..7079aec3 100644 --- a/libs/react-form/src/FormStore.ts +++ b/libs/react-form/src/FormStore.ts @@ -1,5 +1,5 @@ import { deepClone, deepEqual } from '@cleverbrush/deep'; -import type { FieldState, FormSubmissionState } from './types.js'; +import type { FieldState, FormIssue, FormSubmissionState } from './types.js'; type Binding = { getValue: (values: any) => { success: boolean; value?: any }; @@ -11,6 +11,9 @@ export function createFormStore(initialValues: any) { let values = deepClone(initialValues ?? {}); let baseline = values; let revision = 0; + let issues: readonly FormIssue[] = []; + let submissionError: string | undefined; + const localErrors = new Map(); let submission: FormSubmissionState = { submitting: false, error: undefined @@ -19,6 +22,32 @@ export function createFormStore(initialValues: any) { const fieldStates = new Map(); const listeners = new Map void>>(); const globalListeners = new Set<() => void>(); + let batching = 0; + const pendingPaths = new Set(); + let pendingGlobal = false; + function batch(callback: () => void) { + batching++; + try { + callback(); + } finally { + batching--; + if (batching === 0) { + const paths = [...pendingPaths]; + pendingPaths.clear(); + const global = pendingGlobal; + pendingGlobal = false; + for (const path of paths) notifyPath(path); + if (global) notifyGlobal(); + } + } + } + function notifyGlobal() { + if (batching) { + pendingGlobal = true; + return; + } + for (const listener of globalListeners) listener(); + } function read(binding: Binding | undefined, source: any) { const result = binding?.getValue(source); @@ -33,8 +62,8 @@ export function createFormStore(initialValues: any) { value, initialValue, dirty: !deepEqual(value, initialValue), - touched: false, - error: undefined, + touched: issues.some(issue => issue.pointer === path), + error: externalError(path), validating: false }); } @@ -45,13 +74,17 @@ export function createFormStore(initialValues: any) { return getFieldState(path); } function notifyPath(path: string) { + if (batching) { + pendingPaths.add(path); + return; + } for (const listener of listeners.get(path) ?? []) listener(); } function notifyAll() { for (const path of listeners.keys()) notifyPath(path); - for (const listener of globalListeners) listener(); + notifyGlobal(); } - function updateFieldState(path: string, patch: Partial) { + function commitFieldState(path: string, patch: Partial) { const current = getFieldState(path); if ( Object.entries(patch).every(([key, value]) => @@ -62,6 +95,39 @@ export function createFormStore(initialValues: any) { fieldStates.set(path, { ...current, ...patch }); notifyPath(path); } + function externalError(path: string) { + return path === '' + ? undefined + : issues.find(issue => issue.pointer === path)?.detail; + } + function updateFieldState(path: string, patch: Partial) { + if (Object.hasOwn(patch, 'error')) localErrors.set(path, patch.error); + commitFieldState(path, { + ...patch, + error: externalError(path) ?? localErrors.get(path) + }); + } + function setIssues(next: readonly FormIssue[]) { + batch(() => { + // Copy caller-owned data; later mutations must not change store snapshots. + issues = next.map(({ pointer, detail }) => ({ pointer, detail })); + for (const path of bindings.keys()) { + commitFieldState(path, { + error: externalError(path) ?? localErrors.get(path), + ...(externalError(path) !== undefined + ? { touched: true } + : {}) + }); + } + setSubmissionState({}); + }); + } + function setSubmissionFailure(error: string, next?: readonly FormIssue[]) { + batch(() => { + if (next) setIssues(next); + setSubmissionState({ error }); + }); + } function syncFields(reset: boolean) { for (const [path, binding] of bindings) { const value = read(binding, values); @@ -82,9 +148,11 @@ export function createFormStore(initialValues: any) { listeners.set(path, set); } set.add(listener); + setSubmissionState({}); return () => { set.delete(listener); if (set.size === 0) listeners.delete(path); + setSubmissionState({}); }; } function subscribeGlobal(listener: () => void): () => void { @@ -97,14 +165,29 @@ export function createFormStore(initialValues: any) { return submission; } function setSubmissionState(patch: Partial) { - const next = { ...submission, ...patch }; + if (Object.hasOwn(patch, 'error')) submissionError = patch.error; + const messages = [ + submissionError, + ...issues + .filter( + issue => + issue.pointer === '' || + !listeners.get(issue.pointer)?.size + ) + .map(issue => issue.detail) + ].filter((message): message is string => !!message); + const next = { + ...submission, + ...patch, + error: [...new Set(messages)].join('\n') || undefined + }; if ( next.submitting === submission.submitting && next.error === submission.error ) return; submission = next; - for (const listener of globalListeners) listener(); + notifyGlobal(); } function getValues() { return values; @@ -112,9 +195,66 @@ export function createFormStore(initialValues: any) { function getRevision() { return revision; } - function setValues(newValues: any) { + function setValues(newValues: any, changedPath?: string) { + const previous = values; values = deepClone(newValues ?? {}); revision++; + const changed = issues.length > 0 && !deepEqual(previous, values); + if (changed) { + const readPointer = (source: any, pointer: string) => { + if (pointer === '') return source; + if (!pointer.startsWith('/') || /~(?![01])/.test(pointer)) + return undefined; + return pointer + .slice(1) + .split('/') + .reduce((value, part) => { + const key = part + .replace(/~1/g, '/') + .replace(/~0/g, '~'); + return value != null && Object.hasOwn(value, key) + ? value[key] + : undefined; + }, source); + }; + // Arrays are positional: replacing/reordering a container invalidates + // all of its indexed issues, even when two items have equal values. + const arrayChanges = [...bindings.keys()].filter( + path => + Array.isArray(readPointer(previous, path)) && + !deepEqual( + readPointer(previous, path), + readPointer(values, path) + ) && + (!changedPath || + changedPath === path || + path.startsWith(changedPath + '/')) + ); + setIssues( + issues.filter(issue => { + const path = issue.pointer; + if (path === '') return false; + if ( + changedPath && + (path === changedPath || + path.startsWith(changedPath + '/') || + changedPath.startsWith(path + '/')) + ) + return false; + if ( + arrayChanges.some( + array => + path === array || path.startsWith(array + '/') + ) + ) + return false; + return deepEqual( + readPointer(previous, path), + readPointer(values, path) + ); + }) + ); + } syncFields(false); } function setFieldValue( @@ -128,13 +268,15 @@ export function createFormStore(initialValues: any) { .get(path) ?.setValue(next, deepClone(value), { createMissingStructure }) ) { - setValues(next); + setValues(next, path); } } function resetAll(newInitialValues?: any) { values = deepClone(newInitialValues ?? {}); baseline = values; revision++; + issues = []; + localErrors.clear(); syncFields(true); setSubmissionState({ error: undefined }); } @@ -156,6 +298,8 @@ export function createFormStore(initialValues: any) { getRevision, getSubmissionState, setSubmissionState, + setIssues, + setSubmissionFailure, notifyAll }; } diff --git a/libs/react-form/src/hooks.ts b/libs/react-form/src/hooks.ts index 1d77d4e6..350e61a5 100644 --- a/libs/react-form/src/hooks.ts +++ b/libs/react-form/src/hooks.ts @@ -27,6 +27,7 @@ import { } from './helpers.js'; import type { FieldRenderer, + FormIssue, FormSubmissionState, FormSubmitHandler, FormSubmitOptions, @@ -53,6 +54,13 @@ export type SchemaFormInstance< getValue: () => InferType; /** Shallow-merge values without marking fields touched. */ setValue: (values: Partial>) => void; + /** + * Replace external issues without changing values. Empty pointers and unbound + * fields appear in form.error; bound fields receive the first issue and are + * marked touched. Prefer returned submission issues for async race protection. + * Pass [] to clear external issues without clearing local validation errors. + */ + setIssues: (issues: readonly FormIssue[]) => void; /** Validate and submit once; repeated calls while pending are ignored. */ handleSubmit: ( onValid: ( @@ -159,8 +167,7 @@ export function useSchemaForm< } const getErrorsFor = (result as any).getErrorsFor; if (typeof getErrorsFor === 'function') { - for (const [descriptor] of pathMap) { - const path = descriptor.toJsonPointer(); + for (const path of store.getAllFieldPaths()) { const parts = path .slice(1) .split('/') @@ -190,7 +197,7 @@ export function useSchemaForm< } return result; }, - [cancelScheduledValidation, store, pathMap] + [cancelScheduledValidation, store] ); const validate = useCallback(() => runValidation(true), [runValidation]); @@ -245,6 +252,7 @@ export function useSchemaForm< const epoch = epochRef.current; const current = () => mountedRef.current && epoch === epochRef.current; + store.setIssues([]); store.setSubmissionState({ submitting: true, error: undefined @@ -273,7 +281,12 @@ export function useSchemaForm< } if (!current()) return; if (outcome && !outcome.ok) { - store.setSubmissionState({ error: outcome.error }); + store.setSubmissionFailure( + outcome.error, + revision === store.getRevision() + ? outcome.issues + : undefined + ); return; } // Errors from success callbacks (including redirects) propagate; @@ -332,6 +345,7 @@ export function useSchemaForm< reset, getValue, setValue, + setIssues: store.setIssues, handleSubmit, _getFormContext, get submitting() { diff --git a/libs/react-form/src/index.ts b/libs/react-form/src/index.ts index 60aeebc1..7f4460cf 100644 --- a/libs/react-form/src/index.ts +++ b/libs/react-form/src/index.ts @@ -30,6 +30,7 @@ export type { FieldRenderer, FieldRenderProps, FieldState, + FormIssue, FormSubmissionState, FormSubmitHandler, FormSubmitOptions, diff --git a/libs/react-form/src/issues.test-d.tsx b/libs/react-form/src/issues.test-d.tsx new file mode 100644 index 00000000..39706366 --- /dev/null +++ b/libs/react-form/src/issues.test-d.tsx @@ -0,0 +1,32 @@ +import { array, number, object, string } from '@cleverbrush/schema'; +import { expectTypeOf, test } from 'vitest'; +import { useSchemaForm } from './hooks.js'; +import type { FormIssue } from './types.js'; + +test('indexed fields keep value inference and serializable submission issues', () => { + const form = useSchemaForm( + object({ + addresses: array(object({ city: string() })), + matrix: array(array(number())) + }) + ); + const city = form.useField(t => t.addresses[0].city); + expectTypeOf(city.value).toEqualTypeOf(); + city.setValue('Paris'); + // @ts-expect-error indexed fields preserve value types + city.setValue(1); + // @ts-expect-error invalid element property + form.useField(t => t.addresses[0].country); + // @ts-expect-error array descriptors are not native JS arrays + form.useField(t => t.addresses.push); + const cell = form.useField(t => t.matrix[1][2]); + expectTypeOf(cell.value).toEqualTypeOf(); + const issues: readonly FormIssue[] = [ + { pointer: '/addresses/0/city', detail: 'Unsupported' } + ]; + form.setIssues(issues); + form.handleSubmit(() => ({ ok: false, error: 'Check fields', issues })); + form.handleSubmit(() => ({ ok: false, error: 'Legacy failure' })); + // @ts-expect-error issues are data, not selector functions + form.setIssues([{ pointer: t => t.addresses, detail: 'No' }]); +}); diff --git a/libs/react-form/src/issues.test.tsx b/libs/react-form/src/issues.test.tsx new file mode 100644 index 00000000..3d3a07f9 --- /dev/null +++ b/libs/react-form/src/issues.test.tsx @@ -0,0 +1,263 @@ +import { array, object, string } from '@cleverbrush/schema'; +import { act, render, renderHook, screen } from '@testing-library/react'; +import { expect, test, vi } from 'vitest'; +import type { SchemaFormInstance } from './hooks.js'; +import { useSchemaForm } from './hooks.js'; + +const schema = object({ + name: string().minLength(2), + addresses: array(object({ city: string().minLength(2) })), + hidden: string().optional() +}); +function ready() { + const hook = renderHook(() => { + const form = useSchemaForm(schema); + return { + form, + name: form.useField(t => t.name), + city: form.useField(t => t.addresses[0].city) + }; + }); + act(() => + hook.result.current.form.reset({ + name: 'Ada', + addresses: [{ city: 'Paris' }] + }) + ); + return hook; +} +test('submission issues bind indexed fields, stay through validation, and preserve input', async () => { + const { result } = ready(); + const success = vi.fn(); + await act(() => + result.current.form.handleSubmit( + () => ({ + ok: false, + error: 'Check input', + issues: [ + { pointer: '/name', detail: 'Reserved name' }, + { pointer: '/addresses/0/city', detail: 'Unsupported city' } + ] + }), + { onSuccess: success } + )() + ); + expect(result.current.name).toMatchObject({ + error: 'Reserved name', + touched: true + }); + expect(result.current.city).toMatchObject({ + error: 'Unsupported city', + touched: true + }); + await act(() => result.current.form.validate()); + expect(result.current.city.error).toBe('Unsupported city'); + expect(result.current.form.getValue().name).toBe('Ada'); + expect(success).not.toHaveBeenCalled(); + await act(async () => result.current.name.onChange('Grace')); + expect(result.current.name.error).toBeUndefined(); + expect(result.current.city.error).toBe('Unsupported city'); + await act(() => result.current.form.handleSubmit(() => ({ ok: true }))()); + expect(result.current.city.error).toBeUndefined(); + expect(result.current.form.error).toBeUndefined(); +}); +test('root, unknown and unbound issues stay visible; mounting/unmounting rehomes them', () => { + const hook = renderHook( + ({ show }: { show: boolean }) => { + const form = useSchemaForm(schema); + // A separate hook component is not necessary here: the store subscription + // models conditional binding without changing the order of React hooks. + return { form, context: form._getFormContext(), show }; + }, + { initialProps: { show: false } } + ); + act(() => + hook.result.current.form.setIssues([ + { pointer: '/hidden', detail: 'Hidden issue' }, + { pointer: '/missing', detail: 'Unknown' }, + { pointer: '', detail: 'General' } + ]) + ); + expect(hook.result.current.form.error).toBe( + 'Hidden issue\nUnknown\nGeneral' + ); + let unsubscribe!: () => void; + act(() => { + unsubscribe = hook.result.current.context.store.subscribe( + '/hidden', + () => {} + ); + }); + expect(hook.result.current.form.error).toBe('Unknown\nGeneral'); + act(unsubscribe); + expect(hook.result.current.form.error).toContain('Hidden issue'); +}); +test('clearing issues preserves local errors, and reset clears all issue state', async () => { + const { result } = ready(); + await act(async () => result.current.name.onChange('')); + const local = result.current.name.error; + const issues = [{ pointer: '/name', detail: 'Server' }]; + act(() => result.current.form.setIssues(issues)); + issues[0].detail = 'Mutated'; + expect(result.current.name.error).toBe('Server'); + act(() => result.current.form.setIssues([])); + expect(result.current.name.error).toBe(local); + act(() => result.current.form.reset()); + expect(result.current.name.error).toBeUndefined(); + expect(result.current.form.error).toBeUndefined(); +}); +test.each([ + 'edit', + 'reset', + 'unmount' +] as const)('ignores late issues after %s', async action => { + const { result, unmount } = ready(); + let resolve!: (result: any) => void; + const pending = new Promise(r => { + resolve = r; + }); + let submit!: Promise; + await act(async () => { + submit = result.current.form.handleSubmit(() => pending)(); + }); + if (action === 'edit') + await act(async () => result.current.name.onChange('Grace')); + if (action === 'reset') act(() => result.current.form.reset()); + if (action === 'unmount') unmount(); + await act(async () => { + resolve({ + ok: false, + error: 'Rejected', + issues: [{ pointer: '/name', detail: 'Old issue' }] + }); + await submit; + }); + if (action !== 'unmount') expect(result.current.name.error).toBeUndefined(); +}); +test('local validation reaches indexed fields and programmatic array replacement clears stale issues', async () => { + const { result } = ready(); + await act(async () => result.current.city.onChange('')); + expect(result.current.city.error).toBeDefined(); + act(() => + result.current.form.setIssues([ + { pointer: '/addresses/0/city', detail: 'Old city' } + ]) + ); + act(() => result.current.form.setValue({ addresses: [{ city: 'Rome' }] })); + expect(result.current.city.error).not.toBe('Old city'); +}); + +test('conditional React field bindings move issues between inline state and summary', () => { + let controller!: SchemaFormInstance; + function HiddenField({ + form + }: { + form: SchemaFormInstance; + }) { + const hidden = form.useField(t => t.hidden); + return {hidden.error}; + } + function Form({ show }: { show: boolean }) { + const form = useSchemaForm(schema); + controller = form; + return ( + <> +

{form.error}

+ {show && } + + ); + } + const view = render(
); + act(() => + controller.setIssues([{ pointer: '/hidden', detail: 'Hidden issue' }]) + ); + expect(screen.getByTestId('summary').textContent).toBe('Hidden issue'); + view.rerender(); + expect(screen.getByTestId('inline').textContent).toBe('Hidden issue'); + expect(screen.getByTestId('summary').textContent).toBe(''); + view.rerender(); + expect(screen.getByTestId('summary').textContent).toBe('Hidden issue'); + view.unmount(); +}); + +test('submission failure notifications expose the complete new snapshot', () => { + const { result } = ready(); + const store = result.current.form._getFormContext().store; + const snapshots: unknown[] = []; + const unsubscribe = store.subscribe('/name', () => + snapshots.push([ + store.getFieldState('/name').error, + store.getSubmissionState().error + ]) + ); + act(() => + store.setSubmissionFailure('Check input', [ + { pointer: '/name', detail: 'Taken' } + ]) + ); + expect(snapshots).toEqual([['Taken', 'Check input']]); + unsubscribe(); +}); + +test('escaped fields remain distinct and unknown paths never mutate values', () => { + const special = object({ + 'a/b': string(), + 'a.b': string(), + a: object({ b: string() }) + }); + const { result } = renderHook(() => { + const form = useSchemaForm(special); + return { + form, + slash: form.useField(t => t['a/b']), + dot: form.useField(t => t['a.b']), + nested: form.useField(t => t.a.b) + }; + }); + act(() => + result.current.form.setIssues([ + { pointer: '/a~1b', detail: 'Slash' }, + { pointer: '/a.b', detail: 'Dot' }, + { pointer: '/a/b', detail: 'Nested' }, + { pointer: '/__proto__/polluted', detail: 'Unknown' } + ]) + ); + expect(result.current.slash.error).toBe('Slash'); + expect(result.current.dot.error).toBe('Dot'); + expect(result.current.nested.error).toBe('Nested'); + expect(result.current.form.error).toBe('Unknown'); + expect(result.current.form.getValue()).toEqual({}); + expect(({} as any).polluted).toBeUndefined(); +}); + +test('unrelated debounced validation preserves external issues and first message wins', async () => { + vi.useFakeTimers(); + try { + const { result, unmount } = renderHook(() => { + const form = useSchemaForm(schema, { validationDebounceMs: 50 }); + return { + form, + name: form.useField(t => t.name), + city: form.useField(t => t.addresses[0].city) + }; + }); + act(() => + result.current.form.reset({ + name: 'Ada', + addresses: [{ city: 'Paris' }] + }) + ); + act(() => + result.current.form.setIssues([ + { pointer: '/name', detail: 'First' }, + { pointer: '/name', detail: 'Second' } + ]) + ); + act(() => result.current.city.onChange('Rome')); + await act(() => vi.advanceTimersByTimeAsync(50)); + expect(result.current.name.error).toBe('First'); + unmount(); + } finally { + vi.useRealTimers(); + } +}); diff --git a/libs/react-form/src/types.ts b/libs/react-form/src/types.ts index 77f20191..d72a6657 100644 --- a/libs/react-form/src/types.ts +++ b/libs/react-form/src/types.ts @@ -139,6 +139,16 @@ export type UseSchemaFormOptions = { validationDebounceMs?: number; }; +/** + * Plain external validation issue. `pointer` is a form-relative JSON Pointer + * (RFC 6901), or '' for a form-level issue. Safe to serialize through actions. + * The form does not decode HTTP responses or infer paths from message text. + */ +export type FormIssue = { + readonly pointer: string; + readonly detail: string; +}; + /** Reactive state for handleSubmit; independent of any UI kit. */ export type FormSubmissionState = { readonly submitting: boolean; @@ -148,7 +158,9 @@ export type FormSubmissionState = { /** Void denotes success without data; explicit failures preserve user input. */ export type FormSubmitResult = // biome-ignore lint/suspicious/noConfusingVoidType: callbacks returning void are valid successful submissions - void | { ok: true; data?: TData } | { ok: false; error: string }; + | void + | { ok: true; data?: TData } + | { ok: false; error: string; issues?: readonly FormIssue[] }; /** Application-owned success UI and exception translation. Rethrows propagate. */ export type FormSubmitOptions = { diff --git a/libs/schema/README.md b/libs/schema/README.md index 78bce142..e8c5cf37 100644 --- a/libs/schema/README.md +++ b/libs/schema/README.md @@ -14,6 +14,30 @@ A schema definition and validation library for TypeScript — faster than Zod in Define a schema **once** and get TypeScript type inference, runtime validation, object mapping ([`@cleverbrush/mapper`](../mapper)), auto-generated React forms ([`@cleverbrush/react-form`](../react-form)), and bidirectional JSON Schema conversion ([`@cleverbrush/schema-json`](../schema-json)) — all from the same immutable, fluent API. +## Indexed property descriptors + +Array descriptors keep their whole-array binding and expose lazy, cached indexed +children for primitive, object and nested-array elements: + +```ts +import { object, array, string, SYMBOL_SCHEMA_PROPERTY_DESCRIPTOR } from '@cleverbrush/schema'; +const Profile = object({ addresses: array(object({ city: string().minLength(2) })) }); +const profile = { addresses: [{ city: 'Rome' }] }; +const properties = object.getPropertiesFor(Profile); +const city = properties.addresses[0].city[SYMBOL_SCHEMA_PROPERTY_DESCRIPTOR]; +city.toJsonPointer(); // '/addresses/0/city' +city.setValue(profile, 'Paris', { createMissingStructure: true }); +const result = Profile.validate(profile, { doNotStopOnFirstError: true }); +result.getErrorsFor(t => t.addresses[0].city); +``` + +Both sync and async validation expose precise indexed paths in +`getInvalidProperties()`, while retaining aggregate array errors. Indexed setters +create actual arrays when requested; with `createMissingStructure: false` they +do not create missing containers. Valid indices are canonical non-negative array +indices, not negative/fractional positions. Descriptors are positional, not keyed +item identities, and do not add array mutation methods to the descriptor tree. + ## Why @cleverbrush/schema? **The problem:** In a typical TypeScript project, types and runtime validation are separate concerns. You define a `User` type in one file, then write Joi / Yup / Zod schemas (or manual `if` checks) in another. Over time these drift apart — the type says a field is required, but the validation allows it to be `undefined`. Tests pass, but production data breaks because the validation didn't match the type. diff --git a/libs/schema/src/builders/ArraySchemaBuilder.ts b/libs/schema/src/builders/ArraySchemaBuilder.ts index 03995a40..2d41dba6 100644 --- a/libs/schema/src/builders/ArraySchemaBuilder.ts +++ b/libs/schema/src/builders/ArraySchemaBuilder.ts @@ -364,6 +364,17 @@ export class ArraySchemaBuilder< ) as any; } + /** Keep indexed object validators attached to their actual root descriptor. */ + #elementContext( + context: ValidationContext, + index: number + ): ValidationContext { + const descriptor = (context.currentPropertyDescriptor as any)?.[index]; + return descriptor?.[SYMBOL_SCHEMA_PROPERTY_DESCRIPTOR] + ? { ...context, currentPropertyDescriptor: descriptor } + : { ...context }; + } + /** * Performs synchronous validation of the schema over `object`. {@inheritDoc SchemaBuilder.validate} */ @@ -535,9 +546,10 @@ export class ArraySchemaBuilder< for (let i = 0; i < objToValidate.length; i++) { results.push( - this.#elementSchema.validate(objToValidate[i], { - ...prevalidationContext - }) + this.#elementSchema.validate( + objToValidate[i], + this.#elementContext(prevalidationContext, i) + ) ); } @@ -551,9 +563,7 @@ export class ArraySchemaBuilder< for (let i = 0; i < objToValidate.length; i++) { const result = this.#elementSchema.validate( objToValidate[i], - { - ...prevalidationContext - } + this.#elementContext(prevalidationContext, i) ); elementResults[i] = result as any; if (result.valid) { @@ -630,10 +640,10 @@ export class ArraySchemaBuilder< ) { if (prevalidationContext.doNotStopOnFirstError) { const results = await Promise.all( - objToValidate.map(o => + objToValidate.map((o, i) => this.#elementSchema?.validateAsync( o, - prevalidationContext + this.#elementContext(prevalidationContext, i) ) ) ); @@ -648,9 +658,7 @@ export class ArraySchemaBuilder< for (let i = 0; i < objToValidate.length; i++) { const result = await this.#elementSchema.validateAsync( objToValidate[i], - { - ...prevalidationContext - } + this.#elementContext(prevalidationContext, i) ); elementResults[i] = result as any; if (result.valid) { diff --git a/libs/schema/src/builders/IndexedProperties.test.ts b/libs/schema/src/builders/IndexedProperties.test.ts new file mode 100644 index 00000000..24132499 --- /dev/null +++ b/libs/schema/src/builders/IndexedProperties.test.ts @@ -0,0 +1,87 @@ +import { expect, test } from 'vitest'; +import { array } from './ArraySchemaBuilder.js'; +import { object } from './ObjectSchemaBuilder.js'; +import { SYMBOL_SCHEMA_PROPERTY_DESCRIPTOR as key } from './SchemaBuilder.js'; +import { string } from './StringSchemaBuilder.js'; + +const schema = object({ + addresses: array(object({ city: string().minLength(2) })), + tags: array(string().minLength(2)), + matrix: array(array(string().minLength(2))) +}); +test('indexed descriptors are stable, lazy, typed and preserve arrays when setting', () => { + const tree = object.getPropertiesFor(schema); + expect(tree.addresses[0]).toBe(tree.addresses[0]); + expect(tree.addresses[0].city[key].toJsonPointer()).toBe( + '/addresses/0/city' + ); + expect(tree.tags[1][key].toJsonPointer()).toBe('/tags/1'); + expect(tree.matrix[1][0][key].toJsonPointer()).toBe('/matrix/1/0'); + const value: any = {}; + expect(tree.addresses[0].city[key].setValue(value, 'Paris')).toBe(false); + expect( + tree.addresses[0].city[key].setValue(value, 'Paris', { + createMissingStructure: true + }) + ).toBe(true); + expect(value).toEqual({ addresses: [{ city: 'Paris' }] }); + expect(tree.addresses[0].city[key].getValue(value)).toEqual({ + success: true, + value: 'Paris' + }); + expect( + tree.matrix[0][0][key].setValue(value, 'ok', { + createMissingStructure: true + }) + ).toBe(true); + expect(value.matrix).toEqual([['ok']]); + expect((tree.addresses as any)[-1]).toBeUndefined(); + expect((tree.addresses as any)['01']).toBeUndefined(); + expect((tree.addresses as any)[1.5]).toBeUndefined(); +}); +test.each([ + 'sync', + 'async' +] as const)('indexed errors use precise descriptors (%s)', async mode => { + const value = { + addresses: [{ city: '' }, { city: 'Paris' }], + tags: [''], + matrix: [['']] + }; + const result = await (mode === 'sync' + ? schema.validate(value, { doNotStopOnFirstError: true }) + : schema.validateAsync(value, { doNotStopOnFirstError: true })); + expect(result.valid).toBe(false); + expect(result.getErrorsFor(t => t.addresses[0].city).isValid).toBe(false); + expect(result.getErrorsFor(t => t.addresses[1].city).isValid).toBe(true); + expect(result.getErrorsFor(t => t.tags[0]).isValid).toBe(false); + expect(result.getErrorsFor(t => t.matrix[0][0]).isValid).toBe(false); + expect( + result.getInvalidProperties().map(p => p.descriptor.toJsonPointer()) + ).toEqual( + expect.arrayContaining([ + '/addresses', + '/addresses/0/city', + '/tags', + '/tags/0', + '/matrix/0/0' + ]) + ); +}); +test('indexed validation works below a nested object and with escaped keys', () => { + const nested = object({ + profile: object({ + 'a/b': array(object({ 'x~y': string().minLength(2) })) + }) + }); + const result = nested.validate( + { profile: { 'a/b': [{ 'x~y': '' }] } }, + { doNotStopOnFirstError: true } + ); + expect(result.getErrorsFor(t => t.profile['a/b'][0]['x~y']).isValid).toBe( + false + ); + expect( + result.getInvalidProperties().map(p => p.descriptor.toJsonPointer()) + ).toContain('/profile/a~1b/0/x~0y'); +}); diff --git a/libs/schema/src/builders/ObjectSchemaBuilder.ts b/libs/schema/src/builders/ObjectSchemaBuilder.ts index 72e8ffd7..a21c58a8 100644 --- a/libs/schema/src/builders/ObjectSchemaBuilder.ts +++ b/libs/schema/src/builders/ObjectSchemaBuilder.ts @@ -1101,6 +1101,15 @@ export class ObjectSchemaBuilder< for (const error of result.errors) { addErrorFor(descriptor, error.message); } + if ( + Array.isArray((result as any).getNestedErrors?.()) + ) { + ObjectSchemaBuilder.#propagateIndexedErrors( + result, + descriptor, + addErrorFor + ); + } } } } @@ -2676,6 +2685,13 @@ export class ObjectSchemaBuilder< result[SYMBOL_SCHEMA_PROPERTY_DESCRIPTOR] ); } + } else if (propSchema.introspect().type === 'array') { + (result as any)[propName] = createIndexedDescriptor( + propSchema, + selector, + propName, + result[SYMBOL_SCHEMA_PROPERTY_DESCRIPTOR] + ); } else if ((propSchema as any)[SYMBOL_HAS_PROPERTIES] === true) { // Extern schema — create a Proxy-based descriptor that // lazily creates child descriptors on property access. @@ -2807,6 +2823,38 @@ export class ObjectSchemaBuilder< ); } } + // Indexed descriptors are created lazily, so they are not keys in + // an object's static property map. Copy precise invalid descriptors + // below this property as well as the existing aggregate messages. + if ( + nestedPropertyDescriptor[SYMBOL_SCHEMA_PROPERTY_DESCRIPTOR] + .getSchema() + ?.introspect().type === 'array' && + typeof result.getInvalidProperties === 'function' + ) { + const prefix = + nestedPropertyDescriptor[ + SYMBOL_SCHEMA_PROPERTY_DESCRIPTOR + ].toJsonPointer() + '/'; + for (const invalid of result.getInvalidProperties()) { + const pointer = invalid.descriptor.toJsonPointer(); + if (!pointer.startsWith(prefix)) continue; + const target = pointer + .slice(prefix.length) + .split('/') + .reduce( + (node: any, part: string) => + node?.[ + part.replace(/~1/g, '/').replace(/~0/g, '~') + ], + nestedPropertyDescriptor + ); + if (!ObjectSchemaBuilder.isValidPropertyDescriptor(target)) + continue; + for (const message of invalid.errors) + addErrorFor(target, message, nestedPropertyDescriptor); + } + } // Recurse into nested object schemas (only when we have a property map) if (properties) { const nestedSchema = properties[nestedPropertyName]; @@ -2829,6 +2877,65 @@ export class ObjectSchemaBuilder< } } + /** Propagate structured array results without interpreting message strings. */ + static #propagateIndexedErrors( + result: any, + descriptor: any, + addErrorFor: (descriptor: any, message: string, parent?: any) => void + ): void { + const children = result.getNestedErrors?.(); + if (!Array.isArray(children)) return; + children.forEach((child, index) => { + const indexed = descriptor[index]; + if ( + !child || + child.valid || + !ObjectSchemaBuilder.isValidPropertyDescriptor(indexed) + ) + return; + if (typeof child.getInvalidProperties === 'function') { + const prefix = + indexed[SYMBOL_SCHEMA_PROPERTY_DESCRIPTOR].toJsonPointer(); + for (const invalid of child.getInvalidProperties()) { + const pointer = invalid.descriptor.toJsonPointer(); + const relative = + pointer === prefix + ? '' + : pointer.startsWith(prefix + '/') + ? pointer.slice(prefix.length) + : pointer; + const target = + relative === '' + ? indexed + : relative + .slice(1) + .split('/') + .reduce( + (node: any, part: string) => + node?.[ + part + .replace(/~1/g, '/') + .replace(/~0/g, '~') + ], + indexed + ); + if (!ObjectSchemaBuilder.isValidPropertyDescriptor(target)) + continue; + for (const message of invalid.errors) + addErrorFor(target, message, descriptor); + } + } else { + for (const error of child.errors ?? []) + addErrorFor(indexed, error.message, descriptor); + ObjectSchemaBuilder.#propagateIndexedErrors( + child, + indexed, + addErrorFor + ); + } + }); + } + static #getSchemaForPropertyDescriptor( descriptor: PropertyDescriptor ): SchemaBuilder { @@ -3003,6 +3110,85 @@ const createPropertyDescriptorFor = ( } }); +/** Build only requested array indices, preserving descriptor identity. */ +const createIndexedDescriptor = ( + schema: SchemaBuilder, + parentSelector: (value: any, create: boolean) => any, + name: string, + parent: PropertyDescriptorInner +): any => { + const base = createPropertyDescriptorFor( + parentSelector, + name, + schema, + parent + ); + const intro = schema.introspect() as any; + const valueSelector = (root: any, create: boolean) => { + const container = parentSelector(root, create); + if (!container || typeof container !== 'object') return null; + if ( + create && + (!Object.hasOwn(container, name) || container[name] == null) + ) { + Object.defineProperty(container, name, { + value: intro.type === 'array' ? [] : {}, + enumerable: true, + writable: true, + configurable: true + }); + } + return Object.hasOwn(container, name) ? container[name] : null; + }; + const inner = base[SYMBOL_SCHEMA_PROPERTY_DESCRIPTOR]; + if (intro.type === 'array') { + const indices = new Map(); + return new Proxy(base, { + get(target, key, receiver) { + if ( + typeof key !== 'string' || + !/^(0|[1-9]\d*)$/.test(key) || + Number(key) >= 4294967295 + ) { + return Reflect.get(target, key, receiver); + } + if (!intro.elementSchema) return undefined; + if (!indices.has(key)) { + indices.set( + key, + createIndexedDescriptor( + intro.elementSchema, + (root, create) => { + const array = valueSelector(root, create); + return Array.isArray(array) ? array : null; + }, + key, + inner as any + ) + ); + } + return indices.get(key); + } + }); + } + if (intro.properties) { + for (const [key, child] of Object.entries(intro.properties)) { + Object.defineProperty(base, key, { + value: createIndexedDescriptor( + child as any, + valueSelector, + key, + inner as any + ), + enumerable: true + }); + } + } else if ((schema as any)[SYMBOL_HAS_PROPERTIES]) { + return createExternProxyDescriptor(base, valueSelector); + } + return base; +}; + /** * Creates a Proxy-wrapped property descriptor for an extern schema. * Child descriptors are lazily created when accessed by name, enabling diff --git a/libs/schema/src/builders/SchemaBuilder.ts b/libs/schema/src/builders/SchemaBuilder.ts index c5344a38..bd6e9595 100644 --- a/libs/schema/src/builders/SchemaBuilder.ts +++ b/libs/schema/src/builders/SchemaBuilder.ts @@ -601,7 +601,7 @@ export type PropertyDescriptorTree< any, any > - ? PropertyDescriptor< + ? IndexedPropertyDescriptor< TRootSchema, TProperties[K], PropertyDescriptor< @@ -612,7 +612,7 @@ export type PropertyDescriptorTree< K & string > : InferType extends TAssignableTo - ? PropertyDescriptor< + ? IndexedPropertyDescriptor< TRootSchema, TProperties[K], PropertyDescriptor< @@ -638,6 +638,31 @@ export type PropertyDescriptorTree< } : never); +/** + * A descriptor that preserves its array binding and exposes lazy indexed child + * descriptors. Indices are non-negative integers; they are positions, not item + * identities. Object and nested-array elements retain their schema types. + * + * @example `object.getPropertiesFor(schema).addresses[0].city` + */ +export type IndexedPropertyDescriptor< + TRoot extends ObjectSchemaBuilder, + TSchema, + TParent, + TKey extends string = string +> = PropertyDescriptor & + (TSchema extends ObjectSchemaBuilder + ? PropertyDescriptorTree + : TSchema extends ArraySchemaBuilder + ? { + readonly [index: number]: IndexedPropertyDescriptor< + TRoot, + TElement, + PropertyDescriptor + >; + } + : {}); + /** * Recursively maps the keys of an extern schema's output type into * property descriptors. When a value is a plain-object type its keys diff --git a/libs/schema/src/core.ts b/libs/schema/src/core.ts index 023f3b3b..8a8d60f7 100644 --- a/libs/schema/src/core.ts +++ b/libs/schema/src/core.ts @@ -51,6 +51,7 @@ export { export type { RecordSchemaValidationResult } from './builders/RecordSchemaBuilder.js'; export { RecordSchemaBuilder, record } from './builders/RecordSchemaBuilder.js'; export type { + IndexedPropertyDescriptor, NestedValidationResult, PropertyDescriptor, PropertyDescriptorInner, diff --git a/libs/server/README.md b/libs/server/README.md index ba422ef2..1dff6f41 100644 --- a/libs/server/README.md +++ b/libs/server/README.md @@ -5,6 +5,20 @@ A schema-first HTTP server framework for Node.js. Combines [`@cleverbrush/schema`](../schema) for request validation, [`@cleverbrush/di`](../di) for dependency injection, and [`@cleverbrush/auth`](../auth) for authentication — all wired together through a fluent builder API. +## Structured validation paths for forms + +Request validation retains its existing 400 Problem Details envelope and +`errors: [{ pointer, detail }]` extension. Nested arrays now expose indexed paths +such as `/body/addresses/0/city` alongside existing aggregate errors. Property +names use JSON Pointer escaping (`~0` for `~`, `~1` for `/`), including query and +header names. These paths describe the request, not a particular UI. + +The optional client `decodeValidationIssues(error, { source: 'body' })` adapter +produces serializable form-relative issues; see the +[multi-file consumer example](../react-form/README.md#server-validation-issues). +Application-owned business errors need explicit structured paths to appear beside +fields; the framework never derives a field name from an exception's message. + ## Features - **Fluent endpoint builder** — `endpoint.get('/users').body(schema).query(schema).authorize()` with fully typed handler context. diff --git a/libs/server/src/ParameterResolver.ts b/libs/server/src/ParameterResolver.ts index 36787826..a44b3089 100644 --- a/libs/server/src/ParameterResolver.ts +++ b/libs/server/src/ParameterResolver.ts @@ -110,7 +110,7 @@ export async function resolveArgs( } else { for (const err of result.errors ?? []) { errors.push({ - pointer: `/query/${qName}`, + pointer: `/query/${qName.replace(/~/g, '~0').replace(/\//g, '~1')}`, detail: err.message }); } @@ -142,7 +142,7 @@ export async function resolveArgs( } else { for (const err of result.errors ?? []) { errors.push({ - pointer: `/headers/${hName}`, + pointer: `/headers/${hName.replace(/~/g, '~0').replace(/\//g, '~1')}`, detail: err.message }); } diff --git a/libs/server/tests/ParameterResolver.test.ts b/libs/server/tests/ParameterResolver.test.ts index 321a4df3..6a33a0df 100644 --- a/libs/server/tests/ParameterResolver.test.ts +++ b/libs/server/tests/ParameterResolver.test.ts @@ -1,6 +1,6 @@ import { IncomingMessage, ServerResponse } from 'node:http'; import { Socket } from 'node:net'; -import { number, object, string } from '@cleverbrush/schema'; +import { array, number, object, string } from '@cleverbrush/schema'; import { describe, expect, it } from 'vitest'; import type { EndpointMetadata } from '../src/Endpoint.js'; import { needsBody, resolveArgs } from '../src/ParameterResolver.js'; @@ -43,6 +43,36 @@ function makeMeta(overrides: Partial = {}): EndpointMetadata { } describe('ParameterResolver', () => { + it('keeps indexed body paths and escapes query/header property names', async () => { + const result = await resolveArgs( + makeMeta({ + bodySchema: object({ + addresses: array(object({ city: string() })) + }), + querySchema: object({ 'a/b': number() }), + headerSchema: object({ 'x~name': number() }) + }), + null, + createMockContext({ + queryParams: { 'a/b': 'bad' }, + headers: { 'x~name': 'bad' } + }), + { addresses: [{ city: 123 }] } + ); + expect(result.valid).toBe(false); + if (!result.valid) + expect( + (result.problemDetails.errors as any[]).map( + issue => issue.pointer + ) + ).toEqual( + expect.arrayContaining([ + '/body/addresses/0/city', + '/query/a~1b', + '/headers/x~0name' + ]) + ); + }); describe('needsBody', () => { it('returns false when no body schema', () => { expect(needsBody(makeMeta())).toBe(false); diff --git a/websites/docs/app/react-form/LifecycleDemo.tsx b/websites/docs/app/react-form/LifecycleDemo.tsx index b5e320a5..419761a7 100644 --- a/websites/docs/app/react-form/LifecycleDemo.tsx +++ b/websites/docs/app/react-form/LifecycleDemo.tsx @@ -5,7 +5,7 @@ import { defineFieldRenderer, useSchemaForm } from '@cleverbrush/react-form'; -import { boolean, object, string } from '@cleverbrush/schema'; +import { array, boolean, object, string } from '@cleverbrush/schema'; import { useState } from 'react'; import styles from './LifecycleDemo.module.css'; @@ -14,7 +14,8 @@ const ProfileSchema = object({ .required('Name is required') .minLength(2, 'Use at least two characters'), role: string().required('Choose a role'), - active: boolean() + active: boolean(), + addresses: array(object({ city: string().required('City is required') })) }); const text = defineFieldRenderer(props => (
@@ -85,7 +86,13 @@ export default function LifecycleDemo() { if (fail) return { ok: false, - error: 'Demo failure: your values are preserved. Try again.' + error: 'Demo failure: your values are preserved. Try again.', + issues: [ + { + pointer: '/addresses/0/city', + detail: 'This city is unavailable in the simulated response.' + } + ] }; return { ok: true, data: values }; }, @@ -143,12 +150,25 @@ export default function LifecycleDemo() { Simulate failure

+
+ + t.addresses[0].city} + fieldProps={{ id: 'profile-city' }} + /> +
+ + {/* ── Installation ─────────────────────────────────── */}

+
+

Synchronous mapping and query row schemas

+

+ Keep the existing configure() API. When the final + computations and nested mappings are synchronous, + getSyncMapper() returns ordinary values while retaining + completeness checks. getMapper() remains asynchronous. +

+
+                         ({ id: u.id, name: u.name }));
+const Source = read.rowSchema; // no SQL
+const toDto = mapper().configure(Source, UserDto, m => m)
+    .getSyncMapper(Source, UserDto);
+const result = (await read).map(toDto);`)
+                            }}
+                        />
+                    
+

+ Known async mappings are rejected; disguised promises or + thenables throw at invocation. Configuration never + probes callbacks. Fetching, enrichment, authorization + and union dispatch remain explicit application code. +

+ + Read the multi-file consumer guide and compatibility + rules + +
+ {/* ── Install ─────────────────────────────────────── */}

Installation

diff --git a/websites/docs/app/orm/page.tsx b/websites/docs/app/orm/page.tsx index e52c1e89..45b1433a 100644 --- a/websites/docs/app/orm/page.tsx +++ b/websites/docs/app/orm/page.tsx @@ -19,6 +19,37 @@ export default function OrmPage() {

+
+

Detached reads with projection schemas

+

+ db.users.withRowSchema() returns an immutable read-only + query with runtime metadata matching its projection and + relation graph. Results stay detached even in a tracking + context, so partial selections cannot silently become + incomplete tracked entities. +

+
+                         ({ id: p.id, name: p.name }))
+    .include(r => r.tasks, tasks => tasks
+        .select(t => ({ title: t.title })));
+const Source = read.rowSchema; // nested task schema included
+const projects = await read; // one SQL statement`)
+                            }}
+                        />
+                    
+

+ Return child queries from customizers. STI/CTI reads + expose variantRowSchemas for explicit mapper dispatch. + Ordinary entity reads and writes remain unchanged. +

+ + Projection-aware consumer guide + +
+ {/* ── Installation ─────────────────────────────────── */} +
+

Synchronous mapping

+

+ Use the existing configure() chain, then + getSyncMapper(Source, Target) for pure synchronous + mappings. Completeness and nested-mapping checks remain. + Async computations are rejected, and a disguised + promise/thenable throws when invoked. getMapper() keeps + its async behavior. +

+

+ Opt-in Framework database reads expose projection-aware + rowSchema metadata, so source schemas need not be copied + by hand. Reuse schema instances and configure once; + fetching and domain conversions remain + application-owned. +

+ + Query mapping examples and consumer guide + +
+ Date: Wed, 30 Sep 2026 15:59:43 +0000 Subject: [PATCH 13/41] fix: preserve read safety and support strict mapper consumers --- libs/knex-schema/integration/queries.test.ts | 19 ++ libs/knex-schema/src/SchemaQueryBuilder.ts | 1 + libs/mapper/src/MappingRegistry.ts | 220 +++++++++++-------- libs/mapper/src/sync.test.ts | 24 ++ 4 files changed, 172 insertions(+), 92 deletions(-) diff --git a/libs/knex-schema/integration/queries.test.ts b/libs/knex-schema/integration/queries.test.ts index b0c7fb8a..0609dd02 100644 --- a/libs/knex-schema/integration/queries.test.ts +++ b/libs/knex-schema/integration/queries.test.ts @@ -73,6 +73,25 @@ const taskEntity = defineEntity(Task) ); const db = createDb(knex, { tasks: taskEntity }); +it('transaction clones retain row schemas and raw-query safety guards', async () => { + const read = db.tasks.withRowSchema().select(t => ({ title: t.title })); + await knex.transaction(async trx => { + const inTransaction = read.transacting(trx); + expect(inTransaction.rowSchema).toBe(read.rowSchema); + expect(await inTransaction.where(t => t.id, 104).first()).toEqual( + await read.where(t => t.id, 104).first() + ); + expect(() => + query(knex, Task) + .apply(q => { + q.whereRaw('true'); + }) + .transacting(trx) + .withRowSchema() + ).toThrow(/before raw/); + }); +}); + it('schema-aware reads stay detached in a tracked context', async () => { const tracked = createDb(knex, { tasks: taskEntity }, { tracking: true }); const calls: unknown[] = []; diff --git a/libs/knex-schema/src/SchemaQueryBuilder.ts b/libs/knex-schema/src/SchemaQueryBuilder.ts index 080c3b6f..104a8724 100644 --- a/libs/knex-schema/src/SchemaQueryBuilder.ts +++ b/libs/knex-schema/src/SchemaQueryBuilder.ts @@ -1311,6 +1311,7 @@ export class SchemaQueryBuilder< builderState.includeDeleted = state.includeDeleted; builderState.onlyDeleted = state.onlyDeleted; builderState.skipDefaultScope = state.skipDefaultScope; + builderState.opaqueReadShape = state.opaqueReadShape; builderState.variantConfig = state.variantConfig; builderState.enabledVariants = state.enabledVariants !== null diff --git a/libs/mapper/src/MappingRegistry.ts b/libs/mapper/src/MappingRegistry.ts index 3b122021..e07113fb 100644 --- a/libs/mapper/src/MappingRegistry.ts +++ b/libs/mapper/src/MappingRegistry.ts @@ -28,18 +28,53 @@ type IsAsync = 0 extends 1 & T : [Extract>] extends [never] ? false : true; -type NestedAsync = - S extends ArraySchemaBuilder - ? T extends ArraySchemaBuilder - ? NestedAsync< - ExtractArrayElementSchema, - ExtractArrayElementSchema, - Registered - > +// Inspect metadata instead of recursively comparing the entire fluent builder. +type ArraySchemaShape = { introspect(): { elementSchema: unknown } }; +type ObjectSchemaShape = { introspect(): { properties: unknown } }; +type SameProperties = [keyof A, keyof B] extends [keyof B, keyof A] + ? [A, B] extends [B, A] + ? true + : false + : false; +// Runtime registration still uses schema identity. At compile time compare the +// declared fields, not every recursive builder/validation method. Exact key sets +// prevent an empty or smaller schema from matching an unrelated registration. +type RegisteredMatch = S extends ObjectSchemaShape + ? T extends ObjectSchemaShape + ? Registered extends [infer From, infer To] + ? [InferType, InferType] extends [ + InferType, + InferType + ] + ? [InferType, InferType] extends [ + InferType, + InferType + ] + ? SameProperties< + ExtractSchemaProperties, + ExtractSchemaProperties + > extends true + ? SameProperties< + ExtractSchemaProperties, + ExtractSchemaProperties + > + : false + : false + : false : false - : [S, T] extends Registered - ? true - : false; + : false + : false; +type NestedAsync = S extends ArraySchemaShape + ? T extends ArraySchemaShape + ? NestedAsync< + ExtractArrayElementSchema, + ExtractArrayElementSchema, + Registered + > + : false + : true extends RegisteredMatch + ? true + : false; type AsyncKeys = { [K in keyof ExtractSchemaProperties & string]: K extends keyof Steps ? Steps[K] extends false @@ -97,15 +132,16 @@ function synchronous(fn: Function): (source: any) => any { /** * Extracts the properties record from an ObjectSchemaBuilder. */ -type ExtractSchemaProperties = - T extends ObjectSchemaBuilder - ? TProperties - : never; +type ExtractSchemaProperties = T extends { + introspect(): { properties: infer TProperties }; +} + ? TProperties + : never; /** * Gets all top-level property key names of an ObjectSchemaBuilder. */ -type SchemaKeys> = +type SchemaKeys = keyof ExtractSchemaProperties & string; /** @@ -125,7 +161,7 @@ type TargetPropertyKey = { * type of the selector callback. */ type TargetPropertyTree< - TSchema extends ObjectSchemaBuilder, + TSchema extends ObjectSchemaBuilder, TAllowedKeys extends string > = { [K in SchemaKeys & TAllowedKeys]: TargetPropertyKey & @@ -137,7 +173,7 @@ type TargetPropertyTree< * by its key name. */ type SchemaPropertyInferredType< - TSchema extends ObjectSchemaBuilder, + TSchema extends ObjectSchemaBuilder, K extends string > = K extends keyof ExtractSchemaProperties ? InferType[K]> @@ -148,7 +184,7 @@ type SchemaPropertyInferredType< * ObjectSchemaBuilder by its key name. */ type TargetPropertySchema< - TSchema extends ObjectSchemaBuilder, + TSchema extends ObjectSchemaBuilder, K extends string > = K extends keyof ExtractSchemaProperties ? ExtractSchemaProperties[K] @@ -190,43 +226,23 @@ type ExtractPropertySchema = T extends { * - Neither is ObjectSchemaBuilder + incompatible InferType → `true` */ type NeedsMapping = - TSourcePropSchema extends ArraySchemaBuilder< - any, - any, - any, - any, - any, - any, - any - > - ? TTargetPropSchema extends ArraySchemaBuilder< - any, - any, - any, - any, - any, - any, - any - > + TSourcePropSchema extends ArraySchemaShape + ? TTargetPropSchema extends ArraySchemaShape ? NeedsMapping< ExtractArrayElementSchema, ExtractArrayElementSchema, TRegistered > : true - : TTargetPropSchema extends ArraySchemaBuilder< - any, - any, - any, - any, - any, - any, - any - > + : TTargetPropSchema extends ArraySchemaShape ? true - : TSourcePropSchema extends ObjectSchemaBuilder - ? TTargetPropSchema extends ObjectSchemaBuilder - ? [TSourcePropSchema, TTargetPropSchema] extends TRegistered + : TSourcePropSchema extends ObjectSchemaShape + ? TTargetPropSchema extends ObjectSchemaShape + ? true extends RegisteredMatch< + TSourcePropSchema, + TTargetPropSchema, + TRegistered + > ? false : InferType extends InferType ? InferType extends InferType @@ -234,7 +250,7 @@ type NeedsMapping = : true : true : true - : TTargetPropSchema extends ObjectSchemaBuilder + : TTargetPropSchema extends ObjectSchemaShape ? true : InferType extends InferType ? false @@ -246,8 +262,8 @@ type NeedsMapping = * Keys where `NeedsMapping` is `false` can be auto-mapped via the registry. */ type KeysNeedingMapping< - TFromSchema extends ObjectSchemaBuilder, - TToSchema extends ObjectSchemaBuilder, + TFromSchema extends ObjectSchemaBuilder, + TToSchema extends ObjectSchemaBuilder, TRegistered > = { [K in SchemaKeys]: K extends SchemaKeys @@ -273,24 +289,8 @@ type CheckSchemaCompatible = [InferType] extends [InferType] ? true : // Both arrays → recurse into element schemas - TSourceSchema extends ArraySchemaBuilder< - any, - any, - any, - any, - any, - any, - any - > - ? TTargetSchema extends ArraySchemaBuilder< - any, - any, - any, - any, - any, - any, - any - > + TSourceSchema extends ArraySchemaShape + ? TTargetSchema extends ArraySchemaShape ? CheckSchemaCompatible< ExtractArrayElementSchema, ExtractArrayElementSchema, @@ -298,9 +298,13 @@ type CheckSchemaCompatible = > : false : // Both objects → check registration - TSourceSchema extends ObjectSchemaBuilder - ? TTargetSchema extends ObjectSchemaBuilder - ? [TSourceSchema, TTargetSchema] extends TRegistered + TSourceSchema extends ObjectSchemaShape + ? TTargetSchema extends ObjectSchemaShape + ? true extends RegisteredMatch< + TSourceSchema, + TTargetSchema, + TRegistered + > ? true : false : false @@ -317,7 +321,7 @@ type CheckSchemaCompatible = */ type IsFromCompatible< TReturn, - TToSchema extends ObjectSchemaBuilder, + TToSchema extends ObjectSchemaBuilder, TKey extends string, TRegistered > = [ExtractPropertySchema] extends [never] @@ -332,14 +336,14 @@ type IsFromCompatible< /** A mapping function that always returns a Promise, including for pure mappings. */ export type SchemaToSchemaMapperResult< - TFromSchema extends ObjectSchemaBuilder, - TToSchema extends ObjectSchemaBuilder + TFromSchema extends ObjectSchemaBuilder, + TToSchema extends ObjectSchemaBuilder > = (from: InferType) => Promise>; /** A complete synchronous mapping; unexpected thenables throw instead of leaking into DTOs. */ export type SyncSchemaToSchemaMapperResult< - TFromSchema extends ObjectSchemaBuilder, - TToSchema extends ObjectSchemaBuilder + TFromSchema extends ObjectSchemaBuilder, + TToSchema extends ObjectSchemaBuilder > = (from: InferType) => InferType; // ── Error Class ─────────────────────────────────────────────────────── @@ -493,8 +497,8 @@ function resolveElementMapper( * - `ignore()` — explicitly skip the property */ export class PropertyMappingBuilder< - TFromSchema extends ObjectSchemaBuilder, - TToSchema extends ObjectSchemaBuilder, + TFromSchema extends ObjectSchemaBuilder, + TToSchema extends ObjectSchemaBuilder, TKey extends string, TUnmapped extends string, TRegistered = never, @@ -737,8 +741,8 @@ export class PropertyMappingBuilder< * @typeParam TUnmapped - union of target property key names not yet mapped */ export class Mapper< - TFromSchema extends ObjectSchemaBuilder, - TToSchema extends ObjectSchemaBuilder, + TFromSchema extends ObjectSchemaBuilder, + TToSchema extends ObjectSchemaBuilder, TUnmapped extends string = SchemaKeys, TRegistered = never, TAsyncRegistered = never, @@ -1132,16 +1136,16 @@ export class Mapper< export class MappingRegistry { protected readonly _mappers: Map< - ObjectSchemaBuilder, + ObjectSchemaBuilder, Map< - ObjectSchemaBuilder, + ObjectSchemaBuilder, SchemaToSchemaMapperResult > > = new Map(); #ensureObjectSchemas( - fromSchema: ObjectSchemaBuilder, - toSchema: ObjectSchemaBuilder + fromSchema: ObjectSchemaBuilder, + toSchema: ObjectSchemaBuilder ): boolean { return !( !fromSchema || @@ -1168,8 +1172,24 @@ export class MappingRegistry { * properties remain that cannot be auto-mapped */ public configure< - TFromSchema extends ObjectSchemaBuilder, - TToSchema extends ObjectSchemaBuilder, + TFromSchema extends ObjectSchemaBuilder< + any, + any, + any, + any, + any, + any, + any + >, + TToSchema extends ObjectSchemaBuilder< + any, + any, + any, + any, + any, + any, + any + >, TSteps = {} >( fromSchema: TFromSchema, @@ -1259,8 +1279,16 @@ export class MappingRegistry { * @throws Error if the schema pair has not been registered. */ public getSyncMapper< - TFromSchema extends ObjectSchemaBuilder, - TToSchema extends ObjectSchemaBuilder + TFromSchema extends ObjectSchemaBuilder< + any, + any, + any, + any, + any, + any, + any + >, + TToSchema extends ObjectSchemaBuilder >( fromSchema: TFromSchema, toSchema: TToSchema, @@ -1282,8 +1310,16 @@ export class MappingRegistry { * return a promise resolving to a value of the toSchema type */ public getMapper< - TFromSchema extends ObjectSchemaBuilder, - TToSchema extends ObjectSchemaBuilder + TFromSchema extends ObjectSchemaBuilder< + any, + any, + any, + any, + any, + any, + any + >, + TToSchema extends ObjectSchemaBuilder >( fromSchema: TFromSchema, toSchema: TToSchema diff --git a/libs/mapper/src/sync.test.ts b/libs/mapper/src/sync.test.ts index e6df6f24..65a29571 100644 --- a/libs/mapper/src/sync.test.ts +++ b/libs/mapper/src/sync.test.ts @@ -6,6 +6,30 @@ const Source = object({ id: number(), title: string() }); const Target = object({ id: number(), label: string() }); describe('inferred synchronous mapping', () => { + it('does not confuse unrelated registered schemas with primitive steps', () => { + const Id = object({ id: number() }); + const IdDto = object({ id: number() }); + const registry = mapper() + .configure(Source, Target, m => + m.for(t => t.label).compute(async s => s.title) + ) + .configure(Id, IdDto, m => m); + expect(registry.getSyncMapper(Id, IdDto)({ id: 1 })).toEqual({ id: 1 }); + const OptionalChild = object({ child: Source.optional() }); + const RequiredChild = object({ child: Target }); + expect(() => { + // @ts-expect-error a required child mapping does not map an optional source + registry.configure(OptionalChild, RequiredChild, m => m); + }).toThrow(/not mapped/); + const Empty = object({}); + const Parent = object({ child: Source }); + const ParentDto = object({ child: Target }); + const emptyRegistry = mapper().configure(Empty, Empty, m => m); + expect(() => { + // @ts-expect-error an empty registration cannot supply the missing child mapping + emptyRegistry.configure(Parent, ParentDto, m => m); + }).toThrow(/not mapped/); + }); it('returns an ordinary value and preserves the async API', async () => { const compute = vi.fn((s: { title: string }) => s.title.toUpperCase()); const registry = mapper().configure(Source, Target, m => From 6f7fc68956a5384ae1cc141043883167d6c783db Mon Sep 17 00:00:00 2001 From: Andrew Zolotukhin Date: Wed, 30 Sep 2026 17:18:36 +0000 Subject: [PATCH 14/41] fix: address projection mapping review with native typed metadata --- .../projection-aware-synchronous-mapping.md | 9 + docs/assets/projection-read-schemas.png | Bin 153082 -> 124840 bytes docs/assets/projection-sync-mapper.png | Bin 139024 -> 125139 bytes libs/di/src/ServiceCollection.ts | 50 +- libs/di/src/ServiceProvider.ts | 11 +- libs/di/src/ServiceScope.ts | 11 +- libs/knex-schema/COMPOSABLE_QUERIES.md | 188 ------ libs/knex-schema/READ-SCHEMAS.md | 217 ------- libs/knex-schema/README.md | 398 +++++++++++- libs/knex-schema/package.json | 4 +- libs/knex-schema/src/extension.ts | 43 +- libs/knex-schema/src/index.ts | 3 +- libs/knex-schema/src/read-consumer.test.ts | 166 +++++ libs/knex-schema/src/read-schema.ts | 31 +- libs/knex-schema/src/read-storage.test-d.ts | 49 +- libs/knex-schema/src/read-storage.test.ts | 25 + libs/knex-schema/src/read-storage.ts | 105 ---- libs/knex-schema/src/unit.test.ts | 6 +- libs/mapper/README.md | 61 +- libs/orm/README.md | 49 +- libs/schema/README.md | 49 ++ libs/schema/src/builders/AnySchemaBuilder.ts | 10 + .../schema/src/builders/ArraySchemaBuilder.ts | 11 + .../src/builders/BooleanSchemaBuilder.ts | 11 + libs/schema/src/builders/DateSchemaBuilder.ts | 9 + .../src/builders/FunctionSchemaBuilder.ts | 12 + .../src/builders/GenericSchemaBuilder.ts | 11 + .../src/builders/NumberSchemaBuilder.ts | 9 + .../src/builders/ObjectSchemaBuilder.ts | 11 + .../src/builders/PromiseSchemaBuilder.ts | 11 + .../src/builders/RecordSchemaBuilder.ts | 12 + .../src/builders/StringSchemaBuilder.ts | 9 + .../schema/src/builders/TupleSchemaBuilder.ts | 12 + .../schema/src/builders/UnionSchemaBuilder.ts | 10 + libs/schema/src/core.ts | 8 + libs/schema/src/extension.ts | 21 +- libs/schema/src/metadata-extension.test-d.ts | 210 +++++++ libs/schema/src/metadata-extension.test.ts | 96 +++ libs/schema/src/metadata-extension.ts | 375 +++++++++++ websites/docs/app/knex-schema/page.tsx | 186 +++--- websites/docs/app/mapper/page.tsx | 64 +- websites/docs/app/orm/page.tsx | 62 +- websites/docs/public/llms.txt | 589 ++++++------------ websites/schema/app/mapper/page.tsx | 72 +-- .../app/playground/schemaDeclarations.ts | 412 +++++++++++- 45 files changed, 2459 insertions(+), 1249 deletions(-) delete mode 100644 libs/knex-schema/COMPOSABLE_QUERIES.md delete mode 100644 libs/knex-schema/READ-SCHEMAS.md create mode 100644 libs/knex-schema/src/read-consumer.test.ts create mode 100644 libs/knex-schema/src/read-storage.test.ts delete mode 100644 libs/knex-schema/src/read-storage.ts create mode 100644 libs/schema/src/metadata-extension.test-d.ts create mode 100644 libs/schema/src/metadata-extension.test.ts create mode 100644 libs/schema/src/metadata-extension.ts diff --git a/.changeset/projection-aware-synchronous-mapping.md b/.changeset/projection-aware-synchronous-mapping.md index 58b463a4..647a4c89 100644 --- a/.changeset/projection-aware-synchronous-mapping.md +++ b/.changeset/projection-aware-synchronous-mapping.md @@ -2,6 +2,8 @@ "@cleverbrush/mapper": minor "@cleverbrush/knex-schema": minor "@cleverbrush/orm": minor +"@cleverbrush/schema": minor +"@cleverbrush/di": minor --- Add opt-in immutable, detached PostgreSQL reads with projection-aware runtime @@ -12,3 +14,10 @@ application mappings without duplicating projection schemas. Add `getSyncMapper()` with synchronous eligibility inferred through the existing `configure()` API, completeness checks, nested mapping propagation and runtime thenable guards. Existing queries and asynchronous mapping behavior are unchanged. + +Add application-agnostic typed metadata extension methods that retain metadata +through immutable chains. Use these in database extensions without modifying +global schema prototypes. + +Preserve typed function-schema compatibility in dependency injection when a +function declares its return schema. diff --git a/docs/assets/projection-read-schemas.png b/docs/assets/projection-read-schemas.png index 4258257a9f7ef48fe95744a6bf0899c3ef3cc3ef..399e7888e7ee8dfaee535b388ff3082469b6e2c2 100644 GIT binary patch literal 124840 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 C>L^e{tkIdA-Mb~d9{fh`@KQ3FMdu} z@+b20I+NaGADu4`^YikAA9?mBi>YpGKYNSt0w>LmMZSS}^JPQo6AKOsD(csy=985p zFR+?C4&Y|XzqUXRehc+dI?4IUe-PTx;41|!0Odmbu{)6ej(6N#Q`kfLp=VZ7ROB+U z%k|4oZzQA{<*a8F89eh(HPjqDUe=7U3wGzSFC@~eYqrW zm*Ps^kiP9pt9<><*c-LE zcKv^ihpZ|93GkCXdGR(?7UX$^{>a|Ibw9EFdwt1pxV3qWcl5Kf)9S5`pzD;yJW;Pv zN)b`fk{k26;(O-M6gKfsZ_k{IR2t7#&+ma##$^;`*4S+yF2-Ja!2n&H|L)5;qh9~H zi?8b{2#uPeW4UF=;4vnjSIQxP#u871BfsAxkFxrBw8VO5*xqc3we0%+CHBtFUJw@h zc$;+U9k$^%@V(lvD4tQB(PB!HIGl53GLNslpih#WZdUsI#yYNWz*MB9)FCe(g)B6= z*>e!U2q3_!X>PF!S&YZ7`tp z+g{p0NzK(7(;Mz}N`lxaRd0vKo#hpaGWd1EHmYvb$(}Djpd*R*L;>_{9u8_I82C9N?i(H6O$xuAk z%kb-S~`xwOcXfCkR`TEhm4S3Oj0uB&eROlii-JR^Pw-E^EZDP(xYuy9?&Kt0M~AE3ame$H$IU)#RVl4wLQ{*nlYzm>=75&HnV0^# zT<)ZaiO8#tqs3K>J)3PH<=fel6LN@tO+A>Xqc@byYOwQd4O$MlYvDKqgCl~R0+7pC zZI5ma94mp<^sA&pJLOnbZgyW^EafY&A;*cD;7-@aVaBzc#bR?nzCNGa+cZw$bQA;& zN#T~5$|cq{+H5az1GCLjj&0&{lhZr1`x;Y}Xp~#o@*=Hzo!ifHm3ss+?oStv=XXQ( z^^O;Fa@$gQ1qH)#bo78F@Z*;}U75q}=NpI~A4Y6^u=5x4ro19LsmGIhTDwjMWI=i0 z89;jCkB7@0j2q9lhEZUg@&inPMkE$@N*-l`fGga2BnMm-8)}Q zye1OgE=k^^N?51|Dake@R2O@B@umg;(AGvevOA@w;O~ z7aI{+g$);$mU?GQa@z%)7whVy!)C*IJFMv3=y17&;cl-bgZS=msPMKhSy7)6hAc?_HLd zI)9t!96y}1rl25A3=jWwF`0XvDj0-Sl9d$|6Qh{X3UY0vVrTjV=_`)K{_C$CSd{iE z=z;jVWD>zAvfXA~Yry~54NFJ+Nb2}li}f%h7!twEaCKv@U}j}Bq+DsDRAiCD7EO#d zL?Tgugt5|St?${0t)^<;;e)=|fTpAGMPS-!W_yPFePCc^K~dBFxd6^X;VTL`MbK?wT8@w9pmaoWD26Z-8HEMG<2U7U>u_#KdkmT`uYir;*(y>a_*t*RKf>Dwy+h zs*MQL`};-Zh-G}{A>!RT^R$${g5Dv*nN8FTbyMx%UE>LxxeH5*ayai%Uc{tB_#VzT zPNZw!Pmm6OliZ?CxxN^aqn4tUqo1&h>~40yCZi$v$r(M*R9#~>uV~;J53Heyf-%zKJHL4gDEa9*X!?5twlviO)jk9Oplk<@|o_-D?)czy1hMM#ssP* zq@y^c){Sq;ip9T^&3c-*RV*QflZ#so>76+mOc%Nu>)!8|jKmCeH#_Ao%yqG|8&@0j z0n*`;nnQh3NKI4AYnHZocp;z!JRcvA+eP~3F z`s%!Rna2weMU#$xU!DL$c%QAe6P%R^3 z{z4<1l%-rDDmhhF(2nwRU^MN27kw)!6hyy4tdBMjK7JIB(!3>lV<9Vx+$$*~Ba?RU z78VggH6y49Uf6#~mC5~LrF$|MA1<+?oMonImN6?JOJ%9L*bVa$~sN8z1i%JAms^?kYw@4 zRvAS_k9GgbR`C}8-{~UjJPH!uYyiC*)zzGdfLbF)=}A;rcrb;#P%c)o%8g%8umRu! z$0sKIv5R8K-=uDTAZpB8h`e{$>>May88@FB9h-`8bui294%X4t^$%q*&W~1zs;sQo zNyXg7EGQ_D7s<*+$I7U5e^cc7uNF{g%~|&De9YFvc}$l}a@NgeQ`O$;!Zjh(+l#(f-Ocm0jDrIl zo^wgV58G%4h`yCpy9E(Lt-mXxfc~yXmX&p`a3%@)}9qD zFE+cqGNWD5GnD-~vD|$3pRDKlKu9zglj|!3k-UJy=2K*&{ATwc_+s@@2azk)m=?w^(Iv$UH+jhIVOJ`(6^fRfX zq~e#r!Toht2E`NFeNz>Kz{kkn^y9MgR4OEOjoaB-8#y^Z-6JL}YURLuJ*`|#KDKW> zJA{owK|40a*6_oX_7~KZYFfKPox|L3XGx?^$5(NjV((FB8}puFT$YiAB_upDb8<*N z{51Zq>{)+Y7|V?NssgTiux|GI-nF!>EL|lHX)S^hj!U+flo&G|Es2?-;S0|J%%Z{) zWVeR0T)@P~+2Vk_8;d-`lo*~OxWGNd$Y4O>WMxJEh({Mj9vLZ@x7^V?D~w|+?!U9Q z+dn`-bJ#Z}QOLe%_u0HwR#EXQtxwe?!wxx(;l{b(*QgMVx_2=rfbY4P5uTlq5fK%~ zukb3(3i;B?_KTREogKe}cii8`;DHO6%oIY$)&+wTS|1#ncawuy+h_4Tps_P_Rgd`r*EJN^bD zGlkQ*&N|n~G*JiNyi$vhvOC0eDf&KQ0a6JaRwO^cdaJXst{2!E+5P~>>M{1>-H%G3 zGYe_vtef!i8u#+_Z{0>8*{#g&AW4*J@{p*nsZlh(S6uNit&QDQiaD!Te$(uD-#t27 z_UMcxz4nP*?5C$EubyB--06GFd_aPl&Dq}GY<2H(?VoRmi4F-tWXU2TrlK5b&q@kU zS>2QUlJ2phZ=@$Gii?cHt7;D<;;@*^-pY9R$x635UT=YnMCW_1Q|}OWwvVm^kW0xRonw*>ZYDFc_hFIIc^%&l<-N5&oej0RS+aKdz;2HWYeO+_&S;qTI#qk;O= zH3wj|LOUuA{N?rzAE0Z=u%FSu_w*FrW6nFaxmWie$-jF(!RIn^=o!XM;dZ6fxp|Md z8?kL|PJJv1VuyNw9~>FMX34`h2={CCy^mdTb>>axE8UrE>_M-kj>7OW8f|&JAJpJD z?(ZtRw>w5B#gnOqk=>6E%mw;r-wS*+JTyrT2#7Ze_69Iex2xCIZ7Wa2f=^wKfmvCT zL30yewMB$r_@Tieu$p~@Tne5#1Psz!__wbKsThucJ?uq;Bn)cx0d12{WQBO!+Ya%H zOT!gXqwj0K`*J$x*ck1gBN9;M^Ms89ldbHfU$FlsZeVlitp0wC$~$z->pg^{!5xER z(*?ihkx0^LDq|K7CrHJ*$)9c112N;VC_1`NELO8tYeW;D`0755Bwevvyn+NhYYQdf zv67QfL?*}WRGXQ)kz8Z;CV4}SJS)zqm!;jc@#MdLy`;)S>iis`!qWy_Ucbt8%z6KctK{OAt+p@dg?FY>m zN|`1YW$9akO55oCUcAG8dgJ=viIQ#8qG*GZl+lM zd8b`l)W%CsR~L`l>c>N8IfSnT_m%b2;4QGsdJ;i@IO495QdETAXqMP#(${-(YHAWX zKC<1L2B4xZ3djINvxmJi0;18sY*0WS0fhvLeL0OF^bOhD-7lRh!}951PBmX(LPd-O zTx&x^V`@pm(u^346#e>j@o0Vs1_7qt~7GOb#VKxHTWN7;CQMpmA4M3JR^yLTMVRh9S> zj}R(|YVuGcv%A%8o1KLoBt((b+S%PdoULq5OVhlM!Ch+_-a{fF7t^$Wh_B@7xZ_&l zx+xxeMz1{rJzt#CKT3eI_9~1HMMq&gv|ReV$@0m%mgb<@{1i=9%onR3#~yvxZXh6_ zk>VKbyVF|uGCpU%V3}D&XXodMj2NqV)n0H~7T1vq~F$Qa!kgRu*%VUv+}75X zBR`tHrG$lrv1nZowKswVZsnS!J~lSG^6a9&yijf*0l|piMXJe?hsU8yQw=TA77EIJ zpT&Y+3aYbtikLX;f0{N1-aOGaKmbA}?UkAb(DnSQ{NMrDsEquJT>a0#4ZwT+H(|l^ zek1k&-><$E$fwiO(XHgArF~O?|G)5~qWZ5(3>HYbL;X77eTxAQgLJv*BWYPx)#P}z z7|_5F5fVOj9S%Hk!gTOj&^j^Cc$`kPL2%mow0>Xyt<2=IE z3DCsbSzEHZtbF;4>z+MB|D&LVwG@#e7I$D59j$#}cF!G3&|5A+_!s&`<=drfd;2@2Dr<1VZolXfOH@SE*}JLv!cyN# zkAropbTvv*kyBxlF++}5s&#G${Sk@-hB4kSUzM5TQ<}d(k9SqxJA6BrKpW!KPZp$! zpSrOak;gMZUg~O=ONkm`wG}h@SWb3C-xgF{S8u>Qrxy#sl*$z)hL?Mr`xNMe^Y9r6!9p7q@;-BAlU})V|oKax)+_$(J zsqa+h+%}?wuYR!Lnx=nz)Zo-`ywtQ@Z>!|w#CB6_U6xAYn32-*bvC9HWY^@pjVCf+ z;jjYb>!j-m_uZ!$Lg8aZ_xHeQ+yD=GsDaU4elva=fhqlPce%-)gjeT*upua98Aub`& zYoUf;ugJbs%A|{u^S`@6k8SCL(dF&r~0+3PB0LXq$ zD`B1dH>ky?kbVAp$DYsrD!n#}B8klsc#0oo$Hyo1B-1<7EGK-h zr%luvtw4{^m(U2f!lxT0fIj1DX}#QFxv(&EjP?~Y+9W`a>@eLFe+qjlMA-w}JhVtUA*^C{cqF zX&lu6OIqY6nTCrT76Av0zaf|x4D>zi8oa!39y&UBgC*d3(BFT=)z&d70&00G zVpJU9Sj>NUI^^vdi3QwJ7Ub(D0c(H-=Xvrj`j@BMRjD@SDXXX7qM)Dvc)L&sUN0c^ zUwm)QdDAgMOc67>8X1W^lETKW2kr$*Lmhoxb{i9fndhFCYJ>Gd=+QiG|KF)o^XR{T)lu(V63oWX2SD!~74kc1~Hx zW5>z$#@~@Yt8Z(!$x^Etwla91O3lBDZJC7N{=X4P7EFK&z0zMF6 z7vXgnsmGS*pWJ2S%m&||Cr>AaR2aPWz%`CAuxZ7a#kr+0h`Ol6Z)w~nA)oO9dr;dL zLQ(Omx7KtXdYnuF3uxOU@z|qdV(iZEijSHbn9avf2IInr%hvEXZQ$R0d(E>{xSYmS z-Wh^Ro6>?t^qmIEiw|JS!M|PZV?YEIzcm2SPUpWg)>JJC zG!L9cv39k2;ZMJURI%ByeQmlw>)_}X?C0lg)Hl>;Yi-NSFkWh=h>P;^J#E<}ueq=LLLRWe}*>1VLbqFg52epn?oUm-) z08^uDp}}GgYqD;00|*l|LjNU9*kW-2>@cD`(a*+(SZv9Vn3x!##OU1qJr}5X1rrSW zH)5cWV|17u&ixAT7a-oh@(!swJENvX(TSq7ruVzoFPag|rz@o}1DM9!~RLI&X zqTy<;&+}&1R#d>@NF{Mfre^%2kooyaBpSI)&+9@A3~(X?E75N&veMIs83^v3?vaH` zTR44#F^qIf_}$#Lvhy+u-ZXy(aI2KTL2*k+%~7oPLVuC7HxQn}Df&V0pO=q|__u5|EwC{hsOa>qkJBhw4!fQvz;s_`H}Hl?g$a zHhtu9Kji`a+#G9#fSxLpK(=9JPCGs^-hVM{l*dP}zNrW%V7|)Mcqwo4$N!50AuyVZ zj&*?%+~qH4s-i=PHylE!xLDP|!b;yXFr&ACYZlbL+69$-3aa=Z0G!x|8m)|8gk z>}&Ty!uo)N!t37yOkeN_m+@T12~lgo(t|?ZGe2iSU*L73w>9KU{U(0bwgyK>D!%zH z_AA4e6t(zISKrZid3h5V&EG5@1EfudAUuQ?3j=?k=`tvIGE(=f1ixIlNdI2pJ_UoZqzt}tPFKNL(IYO~6 z9(HHxp^4VFeE5oM0$p1$M#xIvQm*WKQ8d}cq7ma@BM)DT*x(A>-X|^0a^#|8@C9|2#PfiO*W!17Ov42!#d(ioN_01>ElBuo_m*W{nzG!yr-z+tftB+H9$YOwV zRO^g}0)V4H^jz{ z%ugAUDIy~y&pg+@&Z-0KH=YOfnuD~|OCbIAxAk{|IMYLfx0&=e?$2Ab#`h&!gg%nVv{3M6C8?m`LhMMf>0%XT?ct!xSjl_W^YgP4 zc|8n|_KM{9so$mBUhkXvi*UO>R4E=N0Jd>NbhLk9FhJ2DqL>-T5jELn}uDMmyfEbtULx=y-82zuhtsMi8hWg2RD2I7{S{K^jK;&EvdV~ zzDj~-cFqO_1T2jARX{xKVDIS= zt0pQDH#apy)sJO;%-z`FSjz!Yf-gHRT+DQn_x=N#5V*e(8G>T6e+Tj35s~{Z zAJSj4v;Untalj}3%Z>c^zj>U=@BN1t*(>>{wFhVo*Qmb(Nw1bbwaNOod(N<)kp#MACK`scFj1*RC%eY0W0SE8)<4(I z@h^`P!avryMZV+rP%JEsjBA8MH&Gz)N%zNL_cP!o-|u=^^SXRiVEhNsm~7<{mOdH5 z=bkZF=C&S&|MP+azsV1fBC_^qJGA!erYXq0QB6@ZWr|}i3|W4Sw0aG#3_+Mn|0iKt zAP#`|{YG~-1)k;RGuH4luG(8d48pOr{HE zKQ8GC7zR^-*XbcXW7zI+Y4a$PebQXohZ6Se;Bp-hH9eo+pQ~=qTr2~*P{TFNScsgPJh$;N<0TzqrN%Ds*?+h3VHx`RWfs6cEo1Ort#p$$v zvl3f@_NO#LMU|)L?<`9>s|xG9fWP3x=jx>BCWI1@rOV}+ZRiqbRdux#E_ZZN5;=yC zoOIjv`OZ`3lB<)=@!Zr*&p)l=hnJhf5grp24>n7#R_7xVF$@i>jpaHL9}XhTy<q!G&;=*HYJ_2{wj`hdy(^x>))XK!{&x!G>> z=aSb-#L}bF_2KfuAefSgSwFt1!DcLjJs1!j0zNt^?ZxZsjt1o8Ww`h^v0AmhAxDnW)!v;JuH7EK2=7- z5!VW-qf@)gN`j>qIQN2eq2G#~Xl$|g-5t&^{B7Iobq>5~O&1n`faINXf5-c;8}kY*6ovV7 z4$rR@uoHETOP5q@^}M}*<^pWRVuP(wjV)1Dw%p@G({xGS3)*rRL$z-{f6#22I5kNI z#mbsqYX+0VB_Lb=KU14&^wO1fLyt!&(|2TJNIVhBF@z0OMpQQ*5-yS+cxeK4MS^cXTah+`(fSCohJV4caBn-NWo>- zR%a&%8QovRVlTZZOQ0_Q6Qk6o;v<78pj5H zj?Ehj05ivFH{t;lK6iy&)y1)HEJbEDB>k-{+cHd+A+3p=#>lp1(OPxpMj2)`#GV|V znNl+(Ub^t*S054f?cJ^c6!vJwVDBJ=T_3a)mY7PxBNAj*-^scH%O9-~#$A4xu)@-6 z|76d@s~Dwlr0lL{XEwcFioSYQSJjJbt*fQ=bl0^HWK!YrSxo?`AeFn`^U-v+H=Trp zBv&%2uYd4hE_b^sUQUr(<9vc!nomwnMWuhVmxhdXY;th2ZIpmA$e2GmDhgQc?*`CI zN0K-aQ&U?t`#b@e;TUX#9Q{Sj;U$U@8d^J&RWA4ajJ2!}KFkf@wK*;(8eDzkcY0N5 z$C>ak1tTpd4J46~kWwIGrI!S-9yJv_@^nfYh34ZqQeGn09K+tEPbNQ>EY)LOt-sp6 zW_+DAZP}`F;`-sQ%Bc9G8DD@2$94!-U!$Bt-Vyidm=q3#->N>9pjN)X_+yQz^OF_VWaEEZc!z2JDtp)!Z8;T!2fJUr%(1V{Z|XX@%Q&9>mwtX zD#XUvYpicjVrHaeV0er4&P%SpzrVuDs;v0>VeK`yMypFlioqYuuM00!Ttq~-6;iyq zs=6k@8}hqX`)gu}A<=O~rg0hCGg$j+x#E({AIQ--@VQ_^Iu z96%ry5)%^(djJHT{}GO)@8DH1UigB6neFoYDYqDkivTJ2&XrJq9h9WKY_ZRMu@#IZ z2bazAA4(^NVg)$V`)<5kAu{5O+m3;nifW@FQ>Ij%0NU$S(LxQVDNt-SdEtGV{(#=P zdh_Jr!CG?iJL-Irc6(=2&2O(BJapM9C;~?a$lyK`SNu0P$LE)iKODrBEQ{U#7$YYY zXfUgfn6b#{1h%c()R^1xVq*fvtb^0>!e+2eMn3+1bT+^V_)g>QrWPNn&P^4HL2BCC zPN9#eb2dD`1$$;o%gI6X-S&4Gry*)e#1|MVp_|OuAA=#TZ|Tt+-!^T&!;;KMAWGf- zRf+y-M5DRsFUs*`DoXlFsmk=@dgdnn5gdEPNp^q-*>1BBLGPq%zCR_?^sWM zwzr|LXts*&V|7-s@`a+SxFaZup-f?Tzlr_JQKEZQPtVUDf_fQUsEvi+RTXrxl;6=X z-b0!JJmLrR8$HM>nZzqAy_6RFF&3(>EIVE6H1_4sjW z`*tFh0I{41&d{H%a5T<%A;h5kRmfCZ6i907yO{EGd~Ie*L4HYqjIbyE zO<}KLkYV%Sa9ws)6eTQ>AP3T4yv9;IGKTX-h9^Df7<;BqYxTic%x_dxwPJL#R`aro zAY<&<0ArHGIphDCPT6lIu}a(m3v_jNO<_ia&3(J636K5CQgH0LVHv?K8?4^uwrCv>n!DJEvdG z%U0$_cItZC^uDlH&mW$5qNHhpwl{RWR%b*@Q)(*Ods30w-Q^3r_5$VuORoaO0;6IT zIp}I2GcS%iikd+Sb{_{U%0CaL7U$

fNy9aiS_j-%B0I>i%y5JrcDwg{6g>a9?lb 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 AxBvhE literal 153082 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/F_E#$(bJ8LR0feVlsnX&R@|S09C|{ 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 IM6N<$g5c1|Y5)KL literal 139024 zcmdSB^;cZY5;jU8K!5-Vmf*qN-QC^Y-3E8}0KwgLaCe^s3GO<$%i!+tanAdmKj7YP z-5>5=Yu5DM)z#h8yH|DBQ}s-QqPzq$A`T)H6cn8fBVH}x}cAGA$A{%>1KGj!R zcemz!_9IBS$h}DN%;B!f9p=a}T7>I^=c|C<$nnbQ=<)IBG4Iv*IK+G(!vT+?n#?6q zlGGT5%fEU!zt!v~7k0}p0guN|AA=+S@;~+&KvhoXwR-sY_+0*S8w&BxgJhN3h-NGA zL;TN`hvTTEqyzu}tgNU`4vvm8)6>~(=4DewVO8>R%8}f7h3dnVYMz&;(n@s5lDcGJ;EPCdgYSVyNd34kgA(a{>Pov#P4R!~>pmqR z*atFK)MU*5XExuj0A(j9rz9`xI;bmi9j*J`9iJo_gY@)?&hLBW!Zldc^{u~WL_%TH zRM?QTS+FbDB$#~uQG_ZL86F-^@*36&z+8=_Oz!T~0gMcd`KKT>WH7?rga{^TO%Aix z?g6UX=QM7=%QroITl)Tw>bb{HQDR_D`!foI`dns^S$q@02>nm83U4!aOp)H_{YSAp zxB9vQR?Jd%Sm)u7wbTl2t=6;cUwZ#h51=SGx_hM6#6Jc(IqPJA0s%Fh~Xk==rZz_gSJ~RER zQ%d7vqY8qE)lg?LQm~w8RX!s1rXlHpN{4)Iungs!zR&lCt5h}q`{o5@C|jVM5i>$w zNEJ0dL`me;5;qEhpDp@f8#yNp6-|8SMB!{oo7QCgzSD5Pz11hmHCQ!rFi!tTVub+)!oL%>T0k@Dfo#Ecc0}FuQqHYB4&S`~ zSb%c!yUEo-5%f=`fRgb-_W*FW*9{F?#9)45VJ{W!87++yhKNccG}wgFXQ}?Y=|hi2 zX+moKW`#fg-32QnVRwo-|Mu%YYjx7am@v9j&6xup)& z4)fXj>}1=EbNpuimGa(dBOws!$;i&$2`(Y)B?kjmhQ;b_u4 zfdVnJjZH)7wQqag{C~&F%0(?&FnfKR^$b1HjFOcy#6XLJ5<5Xdsrp!v99ou|S(qKqVjhF-VxY8m~TVvXEFF8-kyb0G6;^S$dfyn@v zo1i^v)t7jM>cl@LA3pqdiBE=5($ut~eIdZiB}S8a3~V6(Jh`y2+b9n3o2uFvyo^L- z8#p*RbUiw-o|SbLTloEvQ6#yzDmgm^UssW`8=JBnpO*NlCbTUtye6il!*r~ALviW` zO35u|QP4mTXR)RsMu|mEL|$HM-TlB=(9lEGB|(X0TfM4k;MW0{xu`upz7$~X8r9(X z^$a>tegcp~)15xSr$3k93R8j|Pz zE{FTU--Ays2d@W*2s%sOxw&!NZ)~OtGubp`tR6k)^-9;4o!;#q8r-+U?T zzhgsCkCxLbC`#p5qke)26O$4(OwFf9%aWsO+?NOF&+beTNQ_mO>z%9U##WY_0Y{Sw z-jT;#esg`L>Fmr6>*xC_ghh!W8XAkh#Jd1~zWwnG<>jW+8r`d07XOP^yEm`a4kx*= zkfdLEwXN6TTw!pJ&2+S0u2wZQ1{3z^{bWFcR&3@X4GA7xndp4d@@zN*-0bsvC)qkpu8qLe#MCoW^Zl7Zb@nf}&t`!7Sa5Ug@z$oT znbk0xA!3yD%b8d|MTttov7ycGLVi^s#EqPvESTUAdbpc^#<%`cVFQ8KTly-~7u1|K zv%DIfN`?I+cjBG`Gz$fsLB6P+-EY~gcxj0m2Zk1MbhQ%8^Ig8HTvbY%s!nu_1)T+1 zk8uyMVv+ElI0NhAKcxRG%ep>T85f)>QGWSksMqiAYo?@ot~G9OSmU&_>%8zH=HA<9 zw!4L;&b{j6%Da4czVCjE<#vq`CLUR{N=-p_Oh{U=3efv#Ud*;L7_CE;>(kB6QzDo_ zkX=x4JX)ERw{ehI^5Xw^D+fWAL@y(Whl9>8sc9n3l}V`_mU9&7T7*q#B^8T9N3urC zohE@zVEW{wrutJwIZ{Pgy4ql(-H-2TY+?EEkgwaV>V#Pv$}*@b*;7)L7?}?u%{CqU z%XX>QZ0{UCZh3ww%LWP$+ zJl@bU(4c-seArx2>nH0++5`1{Xj(yt?!v~CA|C6XQZFTGB}`0+Pv!wQaQO1kp*%1A zjF10-=}~C@sB04Jbvs5!;0l%+b&x|#L7i15BelqBMg92f1izZc;|akiy{OTMY+$Mo^`b(!$>z zAIz4+F8m<6ky%QBxOTALhW3*=N?9S4rB5KA35k&E1`kY+_6dUcmwQVDLnU2yd<3nu z!1sSv(Ue&vq1-Lc2CWkF&NY=mJ9$hz@tSz}Z@>Ene=iQkB`$JCAw^1O=`1Vqak;+$ zq^z)`Er!%m!or5dYIhWYA-jINo2WFjTd%9KtGMIy;**6Hwb=~`5=e)lHEz%~ZeDkV z{TlY_A3v&n40p00n^S4vSNGWpMooQHQq&}l)+>ol)YI2D+Uw;_aBYF^@z-uU@{cm8 z#8de)yWK0RNZ6xeJT*tD9cb$Edr=Zp6=kK>M#89qp2ea@tg*3BVSJ~-o5Kg$!mmSg z@boKDl8OugJZ(I6*qTM@sJS;F2NF}rB0sW<@>;B1fdpjnj~=-GeHWK5Y-EbCI$2tD zM9$&&(`F4}|6)nXT9fxvTMzO{>~BdzY*`)Fw>;uR5r7|XPD4T>uY{z?(erg-Z;yOb z2s4mtns9IO!kipu;?NhOiuMtruf9c%J`gRj zza_X2b($=f<<^!$(VpYQ`KCH3NI7y~rfY0~a2&7?`GFQ8pN*vX_@K>wG8tb{GfF_m z0|b2d!o?h~ zO*h)@Y*qb7$V>vbe9%obC)Vi;D?U(T41)<-#p;Om^=a` zVo$4i+*T{UM7%wlX(yAZQ;;+m?i%c$g%)!+HXrZpU-w+`t9n77k@{aB8a=uSzBR9Q zaG$K9%UX0XmpoAzWaTlwv^Tz9CkpKhGEipodvoZ8wzX}B`BOL~koAcUD2T(u0>wnl zl%i~HY?z%|WzKREg6;=zX};XA%ddAZP}5Z{jx;MEjAN0g1B=M znWVBhBc6Tr&f5x+V>{Az4mQ51j}A&w*laI+t4jvRpDB=6rk9Ax=wzH^M~27Yo8&&+ z6_6Mwj*QUouHv`xpciq|~`_52OGk!{) zoN+pZ;&B8KpN8~LitS=zz^_D0`@~UUMU*M*9qvg6)^b^yl96NDSx=7+3JOqfexS&9 z1vfZ*w}Yh5G9*b+T5<7{v#Ykcz9E1!-VfFKt7jQp=s&a@nk~JW)T^e zr1oXm^^#_~cZ<7IoOI~>0Zox&sAp8Ox!DP=%)o){$FKHP7a(ix94K=^g~d^&=t*Ah z?!tOxcKp;tqfCd{QPUmR^b0bwq*vnGsXNW$tjyxPwAgZRIPSc#VlUcA!IiMZS1!K};`J zT{_5zCxLn{CpCfiIU@fwBqBb)&^Jo{)b4<>O`V>It58?l$ zW71MaCp?9ApQ^~-qH^?zDzDke-{^3ZLCmk=xy_`Yf~b3=|>Tk#4w)b(jAv4^HDggf1b~!x8w7=pe3|L^NhG3GbqSa6lYnv54=W>b&Q}Vh`B7%u!NAn zAqf+k*9!Sf$Q>+ZIBUD*$kTV5q)hrcg^3afMIL-z>3>*(tKHAeXK)0ia${`#)?WC?ly z^=@dsVxjQzDvHn?a|Q9Ir~Od#)wkaJ$~*#hC+TsHb;5{W;~N%@GN8KAm-fr!n@mSo zSTmzdE8LcqNB5Veas#r>lH#4W^X-R&v~XnxsR_N`hd(jvGq|K>X!y0=PSL8d0}B1;cOkE2K#b>S8$(f5fE(a2`N(Pn)Rvt?FJNHsqwQ%Ldq&N} zJN@oxCMX(brISiZLEGzadO{cl&*uxiisZ}mVCh!2H-XQMovBg&&((|Hzn>>k2Xa7h zi7EQ(s-%&T)Zhk&?V7o=SrY~tbpI>6>1KQ__n@dtq&_eg=GS<$iq~;of2Ld*WK=KF z>`pvYUFG=(8E+97U$hjXsfc5Wa*XR%AOS%H2PAT}`q*sFWtP|wDxtwJ)BG`HfgREKW6aDEilS_x2TB4vK=Z{|TDlUps}QR@mqEb`|F z;DEz=b8$=lDjz|zf@ErUh=X;3EXzyY+k)AZLlJ}60Pa7lIub>e3**v z7@e$7=W>`B#s0SxCxy_W9aR_@Utiy@IUDwu27t{3pxeOr(NEU4C+IFE{u&6w{{ktA z)^SHAn6&tF-8Oavt(dVEeZAbU$*HS}pHy)DyIz&+W0Z zQ_tW}I#E!trSZ+@JC57iDl7vJ56^4oCE@G!*z(;=v-Rr6hc1v#ci+nB@ovkSf~0Km z_WH~Ex1`duRDV{_tpm^kAm0O1rTcmWlZ0X{Mxm7U%JCwCBsa6`xPp+2PEb#un%e11 zed@(--*$pei*Aopy)4rE-6$lil=)^3w$3&z1aTc!__B+~}toJ3LG?t_PAyt}xJ0;IMewIQNK5eGcv=V`+(w{#?3lps7ks_23D6 zi~*4vnNz>)^r14AZnx)v>&2Oz^GQB)ZbE=1E= z)}FD%acx4)?h*sfEiVM;0QYOww_}MyMOw;AVtH2k3ikoY$r?J6;%dH?sXlpit~5vu zE1kmfc31LkLVTYLYMM>)xLwI8=}1aSYIv;nY+8CPYXelgXUvGcTAG*%nf8jXNXCEhSGkzJmO@D@^Hdh&imicrpPmO00t_Z2xtx}g_ zfc^R{0euzmHo?2@esBR15rYQ2m&5v}NYb05>2|Xg`IAz7lHH*)J0I2(VbTIenu+GB z!#bICS{>E}yQ^PkVyeT16ErkTwL#cdCuOB-d?faQg)yb+ zn4Z}ProcNUwYgKY+H4e8R~vJ!waFJJR8HTd5Hj6mJy`2*Z!h;-YIs!Hscro7i=cd_ zBJ=*zb*k$;axo;b+3urnyUfmdzfD1@rm{+wh4x zhr#Z}m#3K@?r2W3l(RvePw6@>BtsVWlk_i7uD^as>bG3Ty1D(S@yC1KJW74Mb`o$W zDk{+3@#krGpSX1y;&>_K8uFHV^!08Aq2qz9j?5zKf>V1#F8n;(`Wv6ljW&nXN;)3f zB(Ee3%zJxOva>4NAKKH>zB{NrHVgOl{}u272$w8|951(&F%U0$Z=5bpttE5)Md&#z z;o;W4f8fkWJ7{ny+8;KrKmm2Rkx(&HM^*RKM6Kf1Jgp#&X*RHPGSnO|HO+2{WRbxc zmKF1P(T=Z-PWA|<#ASaMM4cnQz&)u)cbP|)?wIl8$}3k$v+wuO zZxE8!ntrybqMfrsDZH9SEqWd!miR&ki=Ytjv3d0wO0Ur{$l>yM{cK3=8#Xnz<+XU- zY7Hq$VW&eO6u27KVF0~e%3hvr>^kl}?@muE&-)}NC660i$163MgR1U>=n9)I2N)uw zWOSA!+hHT5sE#$vHJyx4$jtoqT2DNDJjG*rk~wGH zH`FDtmZTaA8oR+yQr1iqzVj*qu~kMQtNb|dRP=N}W=11RcbhT_SG%F5^z`fjTNjMI z-#Pfdie5m^J;O}uILVYXUzENYBSAM=%}uYU8Z#k9NE0itJBa9wo`f?b?uL(@*qi5R zXzAF|w&1smHYFF((9*N96MGl(t!}B)W#U3?DpIBRY#&Vk%UCHUaE}RvIs@t@^vwf<}+C?`Y#fysrC*{M6HL_Cv~(E!p9RPZTc zpVg`kR7T*rN`EkU7ia8c+varnkTx(PM#@-r8jgwzC9rOoSd3r1{yY zx=d~W6eNtSVQ`MzUbDtxaENij^i*`fKhQYR2gj$!3rd$*Fij8&hV}d{p;TEInuPh* z*djJJI}>-Xz%MV`@^Z~pVYewI7$3{YO?^}1mnoQ30zQ}E1Li}5DU(ofQ_dj~a27!^ zrW(3|m1GbfKvI?*DE+t0WQ#Da6K}GsKK}=ov>4EUL&42wA*R};=1}-`*}1u`jj2M^ z#rUttkYr27UkPW)th*yfKS2@(4<-=~v8liiKOP0j(b_L@WT41*RpYE%}8jBU# zx5w-!)?aJ=GofKX0`vX5GX1n%99sX;iWJkr?k{tqIN+k@{(*|6$V}7oibNpx@Gy0% zY_+4O#Vb@~hRttFR!!h$qXkeA$mv$xGpagS)er-0GaO|!QV`e#;$j+oE%K%b7vNh$ zkov5nC2gF4dn+y|=J!ED+)$1EwzE^X7)?i0r@T(}=u;YAWg`qBms`|$JtNEO!OJ%n z*U%Sl@9+@vmGjtkHx_0FP};BG`wU^z7aTCeQlH-iX8RaZ7hT@1xY*cu0+@Z3_4Z?g z^W$>UTNoHA)q4I+G#v+Sia~Yx-GVB4-qw!jLtxOjm{-Pk6^v{ZTSLCXEfEG;yyR%(x~<$LT$wJknKk<`k{ zNbOJHCfDZ1Mn+av45wsv&!Nn&Z0<(Q%RtnV=LYuc(KgddDQWtIF&ej`9dq>wL3DJz zJ(W0v_#AzwJ3x+R!bDgU7AGz?LKm-Gs*ew-RMX|fd~NiQRWmL(l|l)W&7I!KyAXpn zMt8$*CvSgZSXx6vS#Bt;uc%7t6{o(|R+yh?BIC@GANWBZrdq)g!@%u#LVM3>`~_nR zFc}t?IT02M2Q&*H%%qguEs!n2!Z?*P0*J0mmDkl%dCX*MO59naQVsF`ebz7u z+1CS7?QK0De7&FTFOD4A_;LP+1?&_DA~Qc%>)sgb^;X8!N?zvIo#u6*MKI^tGq@F` zO7J{xmlH_k`rkN9di1STy`^QS>eDtwNW>&|-HQA92?-i9@*L|Q_#!zw7yCs7`g${d zkfr7zrcQZfw*`-t&{2`~m$!+X5%_`LnogIZp+NNb@V95c8e1zwih+3^j>-(?ryC-Z zlBsGrqzb#Y7x2RheF@eLoyDl-8mu7lU-iDnl*!)!5EDZ`Bw62H} zkwL@ciP3Ggw-UoNP^X!v!(Za5GlS(Ey6j9&6}hZ=M@CF7NXB|=V1dOchesNF6s~y> zo@%tcBNg>gx!;Lx9=Da|BKezq;)27p7X@?PEhUFX{fI?}YJsH;n%s-rKG74MonBGm zr!0JJ{Yz9b8XAUx_ehjWxw@R4kr{cqF`by0R+Y&IS=aDLrt}5PyRv9sq=cY)=}bbt zd~Z1txu!=%8a8Ru5g>6YIVOu89(C$!v9(O<^ADDRY9JXO{z?UN++&|@*3ZNgvNr0! zRv*frOyD0dF;oAN^8JkQ78HMt5b0o%`2mvT#C|q2z}P3`ASDMMJ9v?j$otyV_J`1UNYv}7&ze@U{G}dFcPTD5NliSm-tebx0wSlCtJ{D9e`VEtu@`o`ua>Id#BPt4qew^^3p7WF@))v%U}33Al%vNY-ANsa=Z*%Lw>$~NzCnWfIPmo zn0UOe8UFeL)-qK+yb~xo zgd8?Hv$!};5iYJTj#fs{H-Nv?+87xX2xmhE(?r0*5_#auYh!s?1!*vY=clHI1ZwYo z4icKwNA5KM8WNEnit7cqk+K7e&BwogY>0mYz>2J)^2yZ2NwGtF$i&3TNO)d*4*>4T z>I!q&gXr<`>D4uMPX!MvnSaida=Dp2$&=uGIYbD(4%rT0#-7z!^nTX%Q(|(B(Zd@p zi;{}%!s%6YUT_Ijuu@9-1LHN3&aYK}8XTTkrv#kVf9#Ju@kWWkX7V`L=-w7beOj-# zZ!L#YoU`%sdh{|cF0NPryxu%baF!Y7@Y?tp8zZJW45=Ryte1ClvfQo3X!`2L8-|S;hX3oScjHI&bjc zz)<1UDjN-JsTZeda2sp6vZ^xqQyBsCl`=&v_AWsO)(BCx7kh{pg?>Bc{7O&XRCQ>V z+?B~U7;E0tVcr{Nt3h&V`s8WxRR#+ycdcgK!-Ls4>UxIw-SAm+X)i2f?|6|HZb)o& zXj%MpXw;&p1T&#ju{$DRLkg9cRf&|EuaEV^4#iKA}{Hde5N*K8V<1kyOWG!?NO1o+fop zEfv>LjpXyQ!W_Dz;xfY?EY$38Y>C5-){U!mcL&IcYb*P*MiON%;pD3?2rAecD%fi& zAPdA@eUFaya#6)t9j)vXv9O=2{SnQfWQB?ntAQC*kw}Md8B~Bq-Exh$;4saDPl%to zl+T`PtBBfxWD4(Aic>}2?(Sq`W#;$#mk*~rj<1zHcSkKEFwigFMOxBJJ!eHm-|2jP z&r*Gza9>3MzY;s|)y@dAG?tm~&7kY@(0;JRHdQ6)$U%s|F3(L@`Ozd?Z5~q3JT4&V zvI+{iOsVYag+nBZGAu)x(Pze?m$$x9F`bmwH84lj8LQLOr- zdMhJJKB>X#COSMI6j&9sP+?)*xjv@uC+3^GGO+Im9;-P9jyf8S_LhHz z2UyugPj4|07wbKtpwvW9Tl?>*L=hU@STvhYK_)itE+*DR_F(C~>dncviAc5|3p&ZX zk+F^O6eAs30{4emncBMYO=LtB6OsB@vJyVokx|#Fr3II4eB0{#aQN^6rS+emVUy^n zth9h;W~Re=CEccRI-_-+1u?Fsx`<>_YKpVFd_MCa9SIG;X+1Z<2k#esw;d*mmH=5+ zktY{p=iWt{B({R)Ddn_|MkOTHkEANw1qmZ zZ5Cf7-O>t0Dw1X!L;6hF6S*ikLmo0S(i>~7>GwowncibC1M=C0--jGe%zxJkz2xL_ zW;{#CXSrTnx&ooo5|;u|Pjv^RibpNY3`2!>Z*RK}WLiiKR?O@e)aEK$dciJz6lMKc zs<)Ge#~rlCRl-OtiFvi0G)OZMz3tA^m%l;BC5YSspH=Meb-bhr$CgnHVibn**0`cO z#59s=>Zz0{hUTPJ89!k9QG3|#(PgRmh&G zbt1Vv6;br3R5u=vtwMWW-AZd0g5x!>NQXOLg1$aMX#PKvf*x_>Ci7+|cbtuH?B4O14#@gS5E*j*jQK-f=aHd}t7gt&`) zsKajXLta~zc1$*HE}P;o(6q?p@&1+8=p7LL{5ffY+yOwBUL+W7pbGHqN@D0V(AM^& zpj98g^0RdkcU${Su%@dgxP3fZJF^&G3AI<0@-XiWbUR$jC*ZS-PE1(1Kk;aB~<@})JDjlP0Mk!Tomr^eC}{s zNP9epy80<9GP3Mq8ha%d1$~yY+SCZZTnd^1BL!kSa|qbJ9&dBm70E%y0?zfG=#_^^ z-X{1nF!3`BNapM@3d+jj)6*UO{FrX|L2phdEF`4l7TRnayCuOW2m8Lqri^7hM;wL1 zy@^sc$OIczB@_sM=I4otrKeHGGiTOEM5dkJT|d(8ZZ+qj>xkt*1Y5WIV`)RQXv(G- zEX-sI@;y#YO~r7wAB^ev;OW0fV;1w9)C#5+hlfX!60aW*vHNF1!0eqQA1oA=d^0o5 zDJHHW%Wn*qB)DgDM^wx1YZF6sGIDeg(G!V2&S}0|E!1RcJlt7%8P!+^s*fYZ4*<#2 zP?_{mkhi-`{aOQ3L^K0=n~ZQ*Z7nfZTL`|rU6qAh)r52Uk-6w7iF|okGbJfG@g{(~!#1p0Vp-k&YycM* zI|0>|%mi(wG)hE|FCqIq)nYc*YHB5m<20VVxv9DJD@J;zf#~#q@*84G#tRzL<5ahj z8pHR@#cknm#3Z`Vy{0AlD|CxPp{eL-Vx>JMS4KtW^a}mdELG8viBu+NNs0e#l%Z}d zExn&JJ%AD#xmhbK0&n2oyms1}V;Q$Ag#K?D>e}Y-DT9v7r_awl4>hBvAmt7TtnG&V z8lRiqGe3U(%Bl<%qecIN)|_g9hv{gb2*siiN!aIm&)p1#ls88I)6vmN+Ikj^9QrS^ zncPNW?RL#{I?Vtx@8g}eF8CNby}OS5{LN=E!f1T15K&iSWocz;$ggh{nf!(OGA3oAAA$EN2P3LqVs+}2W=g9Lf11WP2@xp-xQRl ziTwpCe?{&l)G(nlIUB|>SQYBxsU~Ng zPQ8`D^0DVh9PY72#N_kM4PFIkxU`Yq?ZUYbqJL;dc8L*XynyMuTvLdDxPD9bhXncixW#pMOFBL83*46U}Oz29|a&FWbLq8 zb48LOZS!#hUj<~!;Hr=|5Wl)V3WsJk#55%46_&gwgvu-aJh+UGWJ#sAlvzzlKpTHY zn?R{Kb5?`@!vf^tW2IrNRVyjE<#}6c6r<5{-Y)NtIC?F08CiM#Ajb@PdfHl=Y40&q z!}$>@^hZ{E01kd8bzL?@b=;X?5!CyKq{YbzG1b4rT<5SesgzRpf4@}f3 znk>z=Q~^UB-Q=h8Nj_X(lf8gJ_Pfg`zFtir7qSH5r;}Lp28(MlkyD8O_`qKQRt}Cw zyM83yWHwEsVr-UKhg^SOpAD#%ko)7GgP+Z%PFKp*ytMsxwV0d1>bK^{jeSKccdzbC z3j?>;=^p%e#>+9aUGStfGY=1oG1w=@*5wRn8sGxC>!P6Ksx-1hG^<~c4I7%B5fNnT zJ`7swf#P=sCWu;IaGz_<*98mgoSYoZ#lZ@ozME4M&n=IzM)0@yfNfd^VuuSmxScQC zdTY+c^YM|px_T@Ie?(q}L1v=#U~TMvBR`8|;F6Rk+%xqvzOk__@lIbt>ZiehzV9k| zxOhbamRV27O&drYr%KM?fd!E(Ao)QAbEA7n++fIz2I&z^dq?Bth0|Um%+1gNwmA(; zfz?b;me*tRJWjM@!po-ihA&Ry-a6q7Tt#+zF&(VD}Jn5BPJX)jAW?*{MNxc^~ve=g(O8=YT6YwOP4+|iKs(eBjgn1cC8SNs!r zAPVO6Bj{@L8xQ;I&0PJR|Lc4BGh9I)kHh%(*AVErE-dkT7Tuf93wqgs#y7vkq2;U9 z&>FwiYh1U}qbu`_^o(pyU;ZDAi{s6^cLsht%VL)WH-rMd4>M=}6F$2|b@5X)&iYyW zX2crnE|-=wE5gQU(Z3Qa*JQ;R+n*|j{QqMZ4VbTQ0N#h{r906C7Ec7(r0992eS3S~ zlu;ABqTeH=EH?E%2?^MX4ZUM|lFD)zKQR5~30Z7c!!|9!nQvhM=F(ELqPV`A4<^NT zu~wRupWiqU*(DmN+OGFZ*A!;1EEps=7r2n*IPojK<%D5`-y9xW+E$)j;-0W@m@U4STU*~(a{~AYR%8^~TrVvu-xo?=?;C0$p1BsYsRZ=BO4?8$GU67L_r4~ZQtM?R|$_`d$HcgF%ZlI6V=;*kB8&Mvxscj{- zf)JNRW=La#x&E@<9q4!I z?N6Pi?#@bGTN{#t(~|AAW+$T^9(O6IL@czsQ+iUP(J+c0;{FAI8n5KHBZ!lIXVLPg zq8_;2>1A!2VSaC4hW1j8Mog+X7|!LvWr)?+mv6c^YE4IupU>N)^4{yTxAIwIO*cJ- zTrVIWf~>#fSL^Yd7N2aQ1ghk%Kg$z98dw^(9VmvaL?*syGd+yS{NVWfY~TX(lZGf1g$W!3; zuAGj*ys7Bb?$+e<@{WA*4Z((m?9|+IrHq1PH5#sQagkDe7K>eJhRzrBd$qi8&4xp_ zXMo^m4ZHgKVbCKv9fQI10fp2T?$r+L@oba7f$c>?HLR0)lyr2%p*dD$4d(3-3jq;AgKp) zt4AQvoBR2>+8a;&)KpoOj#iVi^LOsS5^oK^7@?*+t4y7Y%Eyyv&?~>!sj;M%C+vfF zvpt{t?FPUvmYn+f?5OQc5z4zJxsT3XoNVB7B4@ew@bVAIpNEHj(_UNfv~5o-ed1sD zGVTC_x`(f{csRt5kf`_N*6HyejfXkLRLHkCcANOBd(*WJvFLj6YDuA!vtN@QnqW9v zt(a>p(?9EUfA`+l>3;d$7r&+08FAPH-$7)aMs}+syREUt_TG@iGe^AfgYjOG%ueV|Kp_D{wciCW-^Vv`>E;UvopKw3z~_zjPgk3|wgH{HiOI!z>SV2JkIWxx z5>Dx&Yzo0j6_eMxL7l?GTvFbX(PgEPi6s2<@iGfNk>hf8Fu`ecm5!AelfyelX9BGV z-}pT*RVu5|tgFI6{!yrD3dZ-{_(6-95S#MT3AOhwECUn0apl&KX7ETvd=1W;TY^aJ z;UtlrKQs~)tVyxN69G1WK~>s}&9ScW-4!WYrY1-}iItkO+^6{p<^Toa_fgG9vM zDGuN^V_)Bd?w;yw*I$iIYlu)2)U{9xvSOi@y=%_g!r3T*82&ZJH+CiYoVHr?m*!=m zyHX3rJo|}Vne_&%{F`s?xUjY5R;Zc*gzq1rVB!a%`S`2X;=f^h+$|PJwQP7!mxu`j zlKcWjW=6(lR^?p^Tsz;e-VvI8ObqRe^ucb34+|wT4M#3-*D}xCW$5!`9h3myhfzwZ zO#ocv^O+=;4?AO=E-TmI;?aWEKucka5Psz>vLO0L=zj=>mf7#r%{on6I+lXeSH@IZ zkZs*>?P=DJjD?lII(#*Z?}0Jir~*b74ETJs2%mp%!~DZeg2MSGCk4eKE!{7SA6Pwa zAOg3M4*zeHtn@ikVzsk|c{Qsx|I)#rpghjG)c>V>LCHaXGW>sC4qEbslOjc%QkRg> zsmI-Nnf_{zg`0@LR(uk zfv>et|M2#ppe)e@|35Atn46mZXNCUv`rQyy-PD8$|G#@)8VrmbnwtR(%l|$3znY}~ zn+g7ZtgDB@Y91-7TPLYVzenAdrTODaRNFvdW235pLGBFmPuMyKZMeE0Sn?x3u=;we zu=|2EIq8BmXMe;!M}$JlYy4)L`HI`4eoqViVTF>a{L5}~Boa-ZJEF)L#+tukO1APN zW803ApBRGwXEnnMl9s%7ol&2UYB|a+f0121QXO{fbKT7hk(&H%d_y*VZ|sl;cER)))c zo0o3ME8V|(*d)6N#do_(1+d8i732P5{%*?2;qTq*Q6*pacdjU&7Ir2L59l10IF#5p zmte@)C+m1g^i_rk4D&jgy`F6ySsx<+y5FOP1=bHIuRggLv{}#l3-zr&|Ok%iL$dkt)9WK3D zxEXnhvBm5(DNRMGhs~O=9F1amT%g^uDpeVH7wTStXrM;R29(n}B2om0Y1r&zE;-AK zRrE0H<=;&1bW_$eXww0oXVj%K$xAn_DxT?`vmnZkg9f)Ts`kAVZ9w3)lDEEV2`N10 zP&36G%$D`)xQ0xZEfrnO(Yy$)N74_+Iedl`PfMxDJi+28GDFyFr32&i-~G(_G+cY} zI!=m21NG-hevxewQ^R|qD=Z59;ysds;O~f4H?Z??+<;=Q6WN=Z++#j zhLzSi>H5ZW{59F8%F2bY#S-dg7g1_uHPrhiMWSV~x|Xp%oLXGUbjVu}-z{rx`3ByF z-x9@yg{<$?g@xQ#-}s5#0ThFoS@qkY`&aCBlenWvsxh6mr-F@M<9NEw*wdhd6-7$i z_ql?^RJJ9R({Hkc*DUr>jx0l};1%TVfZBw00O`Y-E{0gJS7~(vbG}+xhlG1RdlmeM z|3%@N_05y=T&SvckBv9bRash%e;cwVUq(g5Y)3@{jJ-6_ORsUQc$JL01iW%RCCMDl zSo6(3sW$Da0qSIz^{Z}5$5@go*1`mE@Jq|G%g$CN^OEKZZYD|XVwc>i_tp%_d z0R@66^4%*bf^WLL-mi@Us5_TfB9U0VI$NIc4W8^5+{aa9#sD2im#_e~$0gml``A0_b zW)7U;KHZq#ladCOCYl3~Z~xfNJPe4(@^^>FcJ4#7Ag8bJI6O_>@S5IB_?s0Hq+~Fp39_UAQa%h zG+90EQyt`APW=t4>xkTq%Oy4Ef2ET@Iji$zZOfyG$p2{_=VNiZZoDKsk}!wzj{sa& zAZAu~%#Iuk%0J>ss7Xx8_5&azG>80u#QnzA>0kB?{?+{=-kuP{ZTahc+?KfzY7$mH$tfa&cKsrR_c~y!MgL702MR9(y&i|v^rPHwrD{ZpO(}0cj zyCa=kGkBgEeTcFLTgbZD44RaV)A5;z8@=6lQ?7re`K(NbO2r6YU+1^Y0Ov#3T(b*1 zB8(&^JG|S~4&bXi6>$kpX%N9x=7(>87=#OT?gl4$}zwjEzil|u4v_&?Ey z$bpUV`gA8jn7U4_XQ`bk&2O+~VhV^cF8$%LwOPVKc{dt)=xmgc(L%1R`3C{vL#68|H&~ZC$JiW(}M*-U4ri z{(=1k`5fkS@a@*j9TXoQVqhgg+#8%`;4O(wI#I!VgVzrKcZW_9`;F6=R9Ar#HUIJy zpw>?M%PkAA;c$f)0szVn3&J9AmXria5;iO2tH})XPwLIhW?v`JECJgf97=kBP5};# z)tSD3pn-Q*v(7o-oYQJUNO>{1tSf=XM$W!k0WIWb&J?uewJO(+`4+sKplAX8p}44| zn7Ejkk?!7TXK7--4acH1{K|H6ax8-PJq<^(!cbTlpZE3o)%nmtUvKX@@q7ErnZnSL zpOFw-5wzE9*xNLMB(lX7q=84w+5q@&Kw4l!qSa7 zQTD`Uu&IQY)U`v~Sw06+>%NGxqM`;*=~(J7lKYFzYVgwY_lb-5^*Y<`yrT0ANp3nk zy0$o~*D1aDV28Ln*5fkSly2M_7#MuLy8~j>Y^2?JksK=NvB{`)?J}>_HF1{ge#$PU zA2Y$(c@%7!1~moP%@%xjrw|?X;f?lv zGK=&iTsa}5kzjbsCgr?7uW;+D?T}T*+e(A63@eJJ3%$~$B3Y@140lirT*+1E-Tg81 z2!BCm1q`IqH{mNiJ^k_CoZy77t?n1uhu|F#?ik#}T|_P?b3rgvuP9<#=Qk2-+O-otHM@6bVFxFou59H@s&}7I8Tc6 z10wwVN_BE}LDJ?6+;`Wnz$qKp)N=3mRIUcLZK6Mu;5;WT)9-R;BQKb(QBcaUIR@`P ztS9TpHMn#D_hhl~yt=CNA?tgi{&_g;;KqUzOc$Mu+nR(-^By?&rP$x?HkTuaz2{Fh z{bqOQ`-JrHy79ZP?>|p?CS$MzPtT^yGvS?!k&Ug^D*fSpd8b2 zXI|f$jEfXfyqPV5F9$g>kSaCOX1IPfomo7uc-yj8u$xeE`gmi1X?-C(J9)*V4LDW- z-3PzNtgo)Gn>f_v)n@9m7cV6yosvUKx+?-DiA?e@zOUuPI8J-J*qtyiFeu>Fl$MSJ z424Jy_4jtW#w3Lqjn7#RZH(8Aau`U6*Y!Ie)$SwHWEk?Sg+y!ei9cB!TmVLt(Slg= zT3_t#&GqTqz61AY-ldga@wjRjI~(FM9!8xf$&60%wKOusuug7?kVGyfmu8@_6u*Hz zK0?yHiK@C_QoVS<*!$(VqS&*bQ|0r88%-?$%u z4hs-4?nkFi-xb`g@bFQ9^4aUOP~#+01_M)UE*8sFkG}hbE+`jH?1$%>DbP?*7bAGf3^~YH6e57h7*m+qh{T>h zuO#Q^_x&JsFMyFEE-D_zFIwxr_L?`5%dz_^^d|`ftnB!qqQFqp@%!i)+Sv{*U6P;D z83VV&VS`=$jB@b7kMGrX_K$09lqbs5($W-)!xGd;4fMw<-&a*B-)vtVrT>TN3Vd`z zG3yE7qSP&vAF*H?Ub^!Dg;kIlk~-!qvb{ue^KwPCL^ zr1uwE&!;VV1m3u;{UnE*Jl+fOV81=?0_zj1`+e3nHO<({twFG}Dm})lm5ej8cQ!I| za{8#P{Y2SCF_8*)g^Kq6qQ0zr*6cG{Nfi_r_ur}{T&blr)x2R~ibx!gOS(MR? znC7**ZCrLkgNCxQa_(jIV9UwJh(kG#`w&pzvM`vn?ob=?e#(<%cAoMC0ggkd&4Knb z$QN^4S@)sGZMmHNWV68C`ZSXyAxBwZxvrQPz*B44<34{s@bFQ<%dv{NxbfvD$H`}v zRb`6K&MJ->?_@5=rqM_3tJuqsrXUc<R1g+bYAv=F#Ft6}=M?qSDtJ9`l`P(A$a6^w7Sc zh^{oTOV@A}R;IfU0tvGnWiwr;hO2xh`Z!;vr+#a$l$cqpX@YPU`0*y!!rkb&dYLcg z{$vD+QeKHUi;oz8M+eQvE+s%Gz=WysVk5u&{kBhu4GWn;Poe}qs(6D=3~jCv8dkEN z1qlm!fIk)~Cxe5Ex*-jEt)#X#G@WLs5#A}0VLHwD(Te*uWzAKfd0JyUOX5P$EU)6H zw-IN9y@Tw=6Ow1$1-rygdx8tqANg>VoqsfPhfeskJQyMv0FYkQ@}wC(;LUx$0M4Mz zsp%_eKt|8xq>sCiEfATTOBtD*O z-`yYedTiiFu!iKSFMwnJbhC-)EUrsKy$=p8F*o?tRn@vLZz>HGl#_$?eo!Ggovl<3 zfiHjMV`iv{@NyVlEV%>pjszYTzti$LMBciqnE2Q{E_i1lw|AE`5u523cfl3_37uf9 zO$GoN_2Zo`-g-MLqt(|YO}7?(``iw~XxLlhJ+l#y!SU4x_3m_`5pR~ex87fw?5wl{ zeIG&U(eF^}5Fv#x=FMeDrT;A@g$d8(LJ<}1I0S9GLFTLD+E2goM&4PJMU0_=zD;BA z*xW~nLf=jfkIKcdU!LruS%9-{PctNffU)$Cb|3&lG1bps^ERjcnwMb7dRr~~`sTKe zD#Ead{CXs-IR)oR!MVt%c6x_tXbm_7&#VW0_i%VgH9axEJl?jqlwQ+~JG`v$NCVKK zaac&8*^G^dcesq>R{*1;UNH?gCXGE-CdiIul2){7Mhn<P@p33L1!~Xb;>@f?}94JJE+j$gj?N6!> z-mR-L?Jk~$B+H1fwVds4l$(r!gwbHj_oqgUnk4{4kR4H9aN0Hx(cKkpu;?LVGg~z9 zlsBr+RuWZ3EJt6euvI^QS29FrlT}w&acQz=FyQ@ecoI~8Tt9yuqSfHMswMhC%{fch zq@Iz4*HAKXZGBm3bvwfy`#`JO=$h}&Go^V+_SnkWbiCSda+^s~7AC0sj`m>Y!cfN= z+QUNNecHwCmMa3URIIH}xM0MzJF8zS z&V~ARUdA@mbNy`oL~NJ)9ZKP-+ynIA3+tobVEzAFpL3AKCHkuNIj{E1@FEPrCkxs9 z=CckB1q}_I<$!_>1;}yruqQwxVpHkML;a6B$H+z6<>ot0+b7Yl;bQdo;M?2iWcPEL z^T4OcF;^@3Wb&MwNnF`Xb20A@c<;DV{rTCV!rT12MlF=e<~t;mUC(FLiWqacu8(bV z+8T_z>9wxfs=>E?g#;wCb2nZ=)bCO|<;xfz^T+seixDH%xL zFQr~pvXTU_vKa;jBmuFB9yf|5Mt!+n@5e=Qax@*@ z1GT81gv}AyQnB(m5d`wLCZJobtwJ+|FJ4&9ATH-;r=@+X5=spn!&1WrePCAn$_<|p z{(Kwi_7WlDZk`g4qW#=Yrh=9#dx zN%san9Sabf(U|u-OHR#;qwq-DI|Ravnil}dK|uKEFYa$=YrAV&=tQPW(3L(*CgsCG z|K`?W){EPrO<|0sai%(v$6dwn;OwUORoK?zfJ^b*L(21%rg=~TtGtLvvwNL0%U1hk z{_>O3tgOx^5+EBJqX+2^jhNwzaxVueRTpL}PGrA+2o&MoL}8K%kdd6O*m-Mabm4Tn zOPkm*TPo14V}G&cY6G;{?hks`+=eQnE|E(Qt<65qCeI1Wcy72Y%zWLy8_C-5npdJh0 zw$akk?rp3}3HD$`8E&qbO}l+BDynQ8Xdm&uK0DODg)q%E9b8nZ3zk0WvAt<-nx_sS z>2+7Dwp;X}L&N|jo(*-*Z@*BTcWqdR^+Hn=CK9m^B~pIBQa$Ql#ycLt8+)~)`v}7NsYEA-MIlz+lwlI#T*j6nb+B?+Py5+tTV@i2hhCjUDu}$$B-oFlc-?ch%Ia;7+5Och@~I*YD{2 zh&OdGVS88oPIFJZ7dia`Vq-lYhe64)tHSKJ@fZsai>Z&*mA)X~>W#)4U2wQ-1YLyn zCAF_crB2~1eIK2cpMDZEWt*a+j<%|*vDNiE5@XcwE5ZZiCRCh%eQI$}s{?Cadre*F z>82YfuD;F(MuTpEa&U8SXRnF(zBVUv$M|kC!F?A{cQVU_$wD8B^>q_WQO{!?d)TC%%AI5{?LABeSExl zcbaYR1C@@?Ls>>9#M-m+u)rFAyBDsBCVjE^=yQRfwVl&yu&_B}u)m#ZaKp{Fc{G`k zF&cLAp5f*%z3opFXdWB#_k8}|z2!*AbbCAIur<2YTUD-*pSBVXQ$JUjmgsYwS{RQN z_qozur*V4U1c%xx38}oK17B|~O1TK_i_BJ5?9X(#oMEg^sX_ztcgIUNDjMT4I>Mup zrpJmYeo@^fjoL)171pPQQFjh}!rF_ERuw}3$qe;)=9Z0fBB~7lQAc&cpWW2v}CxtYlR>DW&B12J;QCGI7 zDdpy9K5nHtY?$K_NaU-tN9D=~a~RoeTQpG8#70{R-V<$(MJ#V;2h0%vdRtykXKM=7 zbMi-tk;h+#mK7k#V|eHmC=2Rmd&#G+nfsc_q?$A3PkoyFzRc{izp>uDiPnQybDiKnxD zWh7lkn zO(^qHAd#i+b)Dc)5Xn26-sez1`7Swj-*v{b{*ImMeZ_hesKmHqDegnNi&tr@KTZ!g zbu2BUo8|6C>uNJi#;GW&v-J)1gNT?*Kr)Mvic?H(EP3VG(Ye6Y2Z|c?m$qLgC;af{ zAr+6gXYm!OVK7)uxddt^<7k@1d`+?YRaaFen-Mvn$TWLKO85FrRuWYrowC8#g0;DI z^+@+Op@6^=>r+J~rG@!wiugUrZ)4RFBG};I0>?li=H~Q7iIWX{2$B0;Atz*{+Gs?h zYEAZAt_-cZ^;++y;UYYH?NIqjj{()OaUBLv$U+9cmv5Ar$0< zxKCRM9zRXP;J;$$2mfT{4_eh|wAsfb%V z_xLe-t&9|7B5Zaso=F2UMIk3xVW(RATJTLBLjnD|we`+I`cBpE!PuJ-SDRU*19_@z9WptP_U$7_FNQ>0mmH~T|rFxf7e6qU} zsIb+)jsk|RqPs&dlY67<>KOnaIx)!veC)3mba7M4b?IvTo5j$yLXw(TZ3ScqDI(}* zo$Kl-Kjh{NZ#~vG)zIl3gwu%Paf|Ec(cdWSijf9G@JoFuFur$M(h}uPmsXj(Z(TSU z>p5T8r>Gdy7nP0kP_cQNcXbOks#lj~j?m>HM?UTOY`Dp&am)}D&%^JoqE5)n??k&U z$n{a`kz)g&q}jE_eKPmTHxA%5!)5MsQMZM8DrJ4|6;hvHWw!iCj)+KykOAq8BwS}w zFrPzjo*j43nhV8Ea{jIICVOO-F zq9}UARpQ!LbEDf^Lw*LA zgUTdL?h!^zWk8Wi(gWgqX1W;lm;~-}y)8y$4!w{^V`L=H3`*zSlP3#{Xt4jB2a?aq zr_1PKw+j{v4xb@MqxoeFS&ikgx&Y=-qiPQ(5Hzwtt=b#%WXGix=Q;iNf&>jHuWOAZ zBT;s?x#|}DtFW+lS=ngfb%+8%?5CP(ocAy{kDC+l_jW}Cl$8wom?H|*P;cDH{>kWs zT3c`8i~#$6ela*X)N4cr`P!C^nVHLScP_9eefp#zqr$XjmT6~OjPWhS$?^nmmwoYd zPq(N}Dedbwuk1t`d7&zSgfo*JxprW!CiZhY7|D58mu31EX;=tp5{K@fD@>x&9%n5({(eWM2dxB}by9{* zi_dMM1OJHyyo$%$GoN;w>TBGqmLMp#!haf+H-Wk{k=a(o+m(|pMshUUqMebO^A@-m zrW|!il$@zGBdBv^dIW^_xDwz@Q>SLg83qT8RkH^vag=VwW zqbC>O-_Sd4bbpkjDE`u7lN(-o`8ktgQ=00d2>(b40e`rtu8i&Fvrkxhmok`4&s@qx z%S?t!b0a>zRe$wahR`yjg^%x9jxQYSbCN^8x4&aHRWR)VfC{`6ajQKgoS=I6;k1qg zwlbHg<>G$E9yT$z1Yv#WTTUa`-NnwL(e+6**=v$Cs;_~7h8W!Ws$aF_bZ$K!0MoTI z5Pi;#p;$>~d7T`kQRLTLjN8YsS;c-xLYhid?rzw~b$$pziJ&%@+hs_8?w3>OjNhoR zFvF{`8YrQJdiP@jzRR|-6vQV=bVlFXdRuSm7bk*WOoR-s7%L2PBsc%u{>3G10cKAmbx}5-1D@cpF%9?vK3w(m56%t&x25lHZGB(J zO=@OfuqT~ya<*8CV!qoQI@8f702<;~dH1ofpdipyGVt-VpOBGA(097o@o4)o8*6K$ zXm{vrx`ddOn5Zf4G=9-F+L#P0m-*x<6mq#kcQ@Y&5<-)iT)%UPh#-XKl68Ko+b8>w z_#7&5Lc2Se-Uo$o_nb1@tMF%%%jRuuOLt}hDMF}TC~dlg@0l$gE)r&2L`y_?mr%MQ z_-?~A3UAk+XO_2@ico5(cQ92`92qkLn`|oJF4se5v5kgNo~GC=ej-v)em-(7{Amvn zAD{zCI75Jrvik*)kPAmcLGhu~1d8nE#pRhwk7)JR^(m2aCi7L)AfR_2Mb6Sln-*@0 zk)1C!n@FEWhkiK2hXw@{1o=xbr*n0-4z`K%IHB3+*7m1z9Y4Y7e>*hQp;gh77eUEaZG0lG)x>& z`x75=d_xg#7KK$HM99TGgZ99u!emD@@yolC5VDawX8{}-b*}7Dhwvz=l0$jJiUgLR zPyiFBwN-AeAKQX0W?ziP!c%LfKErRK{&6c(Y60f$y=>}(T6G;Dr0sD6>c`Oxl%pwY z2N+_ie5`J~yw7xn-J_jnDTyu|eNT6aD%8g9nttUl6|rp)_0hq`^EB$VUV`4{6jG2I ze@*GKXXuv_Jqq`8?;mb57B9Yfo#Q%6byH$Z@`(JMGFO#x&u3l?(d{sJNoEjUW<#ZB zpOz-KHF}6&?=EzkE@G4Kw96P>Gre9t-rwK)Djm6DMof!HOk&7XTixQk_0AK4>N5DREFH{F+71LU`bK;$1w( zLWW7@0UJ@z7~ff2?nXM=+d9e-5I2+>`@-n5^;K)Ys6Tj!*Jay9e)~nNQk221*LmHw zBarC(EdTWGkr;Ml)y)h-DdaPK_-sBl^Y}$GugNg*_!FWnYt->= zB{sK5$`8*ys%-a{m~~`}Z(7r$7z!e({bJ2?D7x?7*!?t8*SHF`_fT#0xz&^D>7z>l zO-o|K^PWvJnoToap479-Hrk&gDG(GzM=Q&221>b6wmpPH%GEcOM#Tb8OR~Lt2z#Vy zuCZbAvGpaQqbuB1RjWZlYcg(Mq0f7MG%pEXm`~5Fwz8l3DV)>`0oR-@Ie zrs`^R1L*dT2D)26!{{y*e^RQ-DbjEA_B+BUY88$#{I`_FeAQkq4ULYEMa-|W_+QbL z9`&%YxA0}Ij%Kl`TYO?>hBC#bQBTrOhIdH7e$Nbx;< zz*SZ)zyG{8;MeTo{H}UcK^!~Kv5$Cgk!FLp&?^J!7er4lXjgRlYYU;!hn#iOLfKAt9m6%|<5Qy# ztFY)SNQ`D#Xm-;=I?<$L9MLYL0!pBaWa8T$l3IlvO33q#@%ZrQgj|w|Xs6-s4Nnap zo!gaT>(6$vKXMeu^;L@&8i3H_?e`2t!V60qE69^@LCutlpUZjtV8AifnWk8M+b4ER z*=G!>x1VHZtGIA%);Yf~E6*{Dc4Hkgqe`T|#$8g#%!=FT)yUP>52rM8iAkIt?@~V- zjZ=@Iq0Xi?yR3YmlN+IO+P8g_H;;GW$?l1Ox+F%fj>*fWKR^ux0?40z)srOdg1zHl zOVtLH)Ky}{vZlgXvb_ztRqtlpYrc^lRv-KTpKm0Px|8$-KZy=~ch|VSOCwJRXc%>| zedgtv+HHYUNV@0drL8=La>R(iFLBmV+}pYi8st?JiJ#zscb0lUN*1SQmX&W=sF@=e zSnb+sMX$qe_<@k$3RIQiOS59{+tZk?WV9?pf6 zLxP@=DLc(JZd@N~t2x<=-tM0?J45D+tLwsrvL2Ks6pJ1>|9QIeVs`kE#?%i-jR8c)#RS=r$n7FIlu`*UT7 zoZo})fLwBQUYZj9LSd%Gm+<+JLI%)giKCd%p~Uf9-2BgNJshxcajZOjJ#1o@0&qb# zpn8{}W*pd>o_NxGz?ZfLMDu1!;7gO>0_~lMi0?_k3#$$8skOuwDhmZ%tsI8;=b8(F^?w9WEsUnw4t8m#wT>6wIus)$D{QR<~Zd1wq#?^KXi21~oH5+|D(*T)eB=XZvm05)yrZaWCwT z&8wGw5g57hzF%viWW}D`L2QBW8;Fc9!6*5PYn`r1v+<))%bE{WwRKE0D2BBYSun{1 z(B>m=8|%Yy4I86krarKZt5u&NdR@_hbi2IspNGO9zuSqsJ&86YcJrMXF&lg)jL8 zKGxYErL9!CEn1Z+DoD$tHAX03BXahOuZElIL{Y-hPsjat*XDLWeo!|IAw% zSa_@`o{0Mtp9!{VQlNxMvj|b9tNkWeNzcwVJv;x4|3X_Sc-LiBT#oFco@A?^&1ARs z_*{bpHW^`xn527XSnOvdCHLKaJb76~XH89FP$G;clSh`i>rDjZK#{^`@e!XP)BFv9 z7UiU>!_5(SF}m@4v;Eb`3720X>q=>(cMC|(#C)Qp&|SGxsSnD>6yGVELx`0RmnW5_ zJDrOmHjiB&G(q;aLneUO2`Wl;VV!zgXkzv9YS{7V#wck)Dm6X?>Y!5 zjP-g4CSJ?PChLaVR{mO;=Nhv)%1^$1!QGG?A)HSH++so1^;aiAjjF+E{@R%8)Y<5EH(@!G%uE1YfD> zwNF)TK8KOGaXZap2EDh2>Hs+aMl(e<5FjlvX)#S;%i(&{?Zy14r%MKuwU2WBc=RI7 zJ2<)V_^fL&=*7aK0O;=22Y5P=-$@3>P>$D!Cz)P#fDHJ@;KJQkx~sI30G=vq`)WRb zgKj4pM8@M@RFly@U5clvDJ%LtZVRIEjyA%B;{XHQFC&1JE@4#E~99!L3eg^reoyxD9a9rKK=NCntwOD?m-jDxV%$Z?PA_Lsk06z&HhxI5zP7!1(N{9@ohEHE8vvIPz zd=o&}wCRzAm8O}E{m%@GFYJyC77a&n*w{)tF1pF&&s z7e?dg7siR~0qM@%VkOKsix5RR_JW~mlNI<{lO8lHoeCQYODPProBbo zTQzPXgIHvc{LT)eZTzW~NAVh4he+d8#9!d=4^OJC) zrf$`{dl<^_T!rw+o0K5k{3c$vBr@(u)I81}4E{PgKJ}aPAM-#EFq(LG`D$GR!anFM>> zj2}dFVP>upG_rdakl7m13~FU29mQzF4WwRVZ`cyThL5@ai3J>kuJ%oc97xk}-uJu_ zDQwa_V}}umi;EMh&${1juZ-XA-CTn;DMznhr*4L~l2V@r7TwKIVdfmB{3;q6X~o5p z16?jazN<2>PsFw6%f17+7;e~R&K1V>^VuiNw5Eblig8dGkk_CI0A1erj$a2SFuxs6 zhOb=Eu15AlGG}RU(P=mFERwHWU!IJ}c$kH{rmZ$AyV&pb^WsC9qF6UK$(jT?elmI; zE9^g=spo!@)dyIQU1gMWw||uN#DA}!WF=a8h7Q63v3oV z-@mrYyQzu-(F~2t%VeS{AjY#Ayd4kFM3XsQM4Wg4V=Jv%*T5@t%FlA_K7QU2&qUc5 z-7uXgJP_oU=Ln=pjRUI%*W=@iKL!PwwtT5H9mtwD9oM<~6|R;Pv>0V7XGGbqca$wc*J84RqCK@vdqAQ}d^Hd1EY@sw{1++q?QYU++j$m*wiQ5@t#d9^lcu z=?4mY`;zI@tKeKNZ~+dh6H=wKt=3I2tNz^Kt%j!TYTJ=Vz=qkB`%*k;!gADZ1DHM% zc2Op(;`#&~pgS`7Zgt;gfzpTQNSl<@aE(0O zZ1pQ#t$mNcb3=fjAV_cB?_p6JA23#L(Z2#kV$j5Rp(ULNZgLvu5Z6_0I7J&}ft;)+ zA&eqS*E-!?FK1@zGc_EyU_286&~U;SHB75>?N~{o6he+k8O7DZQK38Y^P`()5^SRj z2o}e{TBm3N0qN~opbqN?J=|cOpWovRKzPQN(EMx@zBs@@#z1;Bq6~iYzD1dgDMe*a z>+J4i(X4**uAQ$j3sV*ZeG@f>RNBag-(pu~~9Ll>6BVCY0;+cn6^B5aRjU)mBtQj_Vtrz9Tazj}8?yt97La zHSJsd^w`qgl;No#<6?~)_v^qrMHj#?by23-%LOPo#z4^v5ACC#Tp|Zz=yc^+P76-+ z91z3=Tm&FYoInm2&yEjR4*b=@ys9Q)Z^dGsoyP0AvGWam82=RwNEV1 z4|_1qThq|d0~+RLn^-&y=(vfF!FbQhPUC-pJ?ix)y`J4V2$85&CcFpK-AVa&>BB@T z^v}cS00HXkjN01wgYnE_pD*~~mB7?%QpN{Rp03$%gs@6g8r&9-Osc;DB4K-G>Ogg~ z+3{5BZcK-Sho!OE=0w%NzBf%G@oseEIib@&kL3z&(;DQZ5vyCMy2s+ z6a$D(k{PT^CWF6A*OK8m-1^^{*d%3B7)3v|*=l#f&#m^Qqnd)W{{*9eU17^f!Zh2h z9`Gw+!)zsowzLV;IXt3d$wwv!8x33I+ZzVd_jKanr6=xXwlB~K-#FnRDI}t6Y8Hkl zC@TIjIEls%Yr4aQGK)J_X7jVw?@uz$flMS2iQ)uOkx!#~a<>6wDk?2?a%@QislN6; z?PsVDsWRDVUpqQ50dSmcojQSqd`B#HId)=AXf$Z5IJ;QaguC|j2OZ|b(U!KL+nM^R zM~!5ABZE#;o=K-;S&6>vdpvW~^&}|a$)J*h!xy9D02^aW2FL*V`N=RcF_CfWd|6E5 zi`pa6AP@AN}i)q=7!B!=2qsM>*R^`~?~ovt=Ct5ueyuSf`rqK4{B@ zmFwmMA&7AiLgJ@_wc2L-occGG7&Z~<*^HX!*rd!k9P6l>^Q}~i8w9w)FBXQf)3ZHf zyB8=7QP20J-$dfF1);RlWDQr!5VO@pDA$)A`*ZMJyy1l}16lu1nA;MU<+^uAK*C>5 zEynK979%8(ibSHd(z`w%kVsDn{VCI=B^D-~__nooG~uZSY=Z=!wjRaGuP2eaM!|Ty z0L>`&fKgr0!HaPqJ+bdsyq6&P`Sw1~!hG?w--NNpK;QSjoz_ptmF@THM5S*A?j7{S z(3#nyo37H`g1hr5>5m}06KuXa&OezK?k|v~Cb;uucsfWXnG+)_soph$KGv@XTa>to z)vOiB%x+~Txsyy-aMv7kzsQt3-JgiPjk)gP=Xn0&1*0l!$Q+Qmis0Zi268vvMk)(%zceMhc4sL!_nGfd5?7M__4%>c>Xb2n=74dO zlCH?qmQv(yzM-qQe3JkO7f<^(&S`>GO5@;pe4_x8hM8{O%$HS9`vEa{vso8b3YL1G z%Jo5b7f`O^aS26Mc&2-0wB?z^#B_BE-a}h(v0=xkl|Vap8l#gM$jIS$+@Tt6vu7wY zs`dqS`IRp;SzYg6JVD;Ne-H}3LDt$AwBq@O=*I`H8E!5YO#s&`dk{p%UP8nD<)&K@ zo>}er@<>BX?QCN%7k?wGVs>I$@E7KNzxeufiR26L4twlZN)C7V`Ee!ma0^JS5EP?? z8rqwadU#62Pc+Q7G*MmCuDP?C#o|RXS9pXFuD+Vx$UT`{@UW4#k+7M8fuG5LLS0x! zzCiwQx&u5(50@mm-M(k3=MEPKSG?6?%Tue2IsA;`GcAFHvw;$juxWuiANH0QPDaP zaly8B_DjIYdUhiGHLS9NqWOkRh|dndTmner-AMgnK{?{s)SAlVPs7r4YQ9$)WQAz) z>Z6LWwRh6o)j5v=5Vf1QS43)-_GBS~`xu}}(csyYMM*vNuc)jnU2zi~i;H`{E)LhH zrKitgC{|n#&!(0K1WjzF^J-DD1LqoCv%Wj2Rh0DhF*!ymk7Jh3o|7%QY_U?!PUXDl zQM{j3kvgmBpt{_V$}@z-O6o8Ks!}T@D1!4yFa13>9G6K$KTXD;4O(9=5lR* z;bJjJt|_iGQ1d}m&{+c`8T}Q2hl893(yJz)o=S#K z%l8#FRPfpyb^b6z1I5DTnin)x0~J7*0!AhH22b^q!c-a7Dgu42b=2{h&Z_{T%g=&2 z^7C|dQ~nDWlgaJnrNaFL`SlQDj&7TZD{b=96{aYKg|QAwIL6cUokhHtp`iX&M+k$mY2_{GWCH8;MCqC|1|trxI8_BBuyZ3H^ic| z%~Z?lS((LNnW&6bO{WOqvuNBWBnNxTS*&Z_G2e9!i!7f?R5}5Zbwn3-`r6Tzs`MGl zp({`eoD5KP!0v6ne<{!vDc8&;q}stwTzcTW%~2h-p(;o9*2XG)@`~g< zeYMW99#s26R7h>S1@M<@tyc$s3O0_il#k|T#8uau*kF`ij=_aJ&6x_NUCkhp1&@JFUKF2? z$j%Ny!4eJD6rqaDWWjNwG(n^{v;69Ox6pGS8qeR~!)v)#keh4OhaYaVyefjl<$l&X zOXk60;ON11d+3LeVVoRs=^jqcN5V@hpU0?vK@j(X@DMETdET0i{7r~N zeO69dnwahIoNZPmL+_f`a+f%Fg&ZCURv^KPINX6s8EwaE?H9F>p96>!ko@l)6*`t? z`{=N?mPy9v5p7QOyReSOn8x$ISj6nx;Wz~@I;UA0?9lGJTF^HXEiJ7-DlFdBN0jJblk8; z(X3akmnG5pgTKjG+wAhpghdq7e9FC~rse|(6!HOfGp&F-&a@g-%QQ8ka=>f7(LSAT z+yBRr?V{~V_De?{v+vud;6U1!rw9BtK&^4-0yO@C%UYDItlfOx#_&! zWz&=f0XY%4`82mj;q2|XNBtBd%1&l0lBE3xO0nd%!$}grz8VPw@^G*&@a?Kc;@R9* z2>2=p_h8LRn6^y>b1$0$GG7Bn_$UsRch-vMjdep)30wAdUfiRL@%-zL`s*IVg0?^&)iP5 zeO2#I0NfUcc0oU2$NAHqXf58;e_{du@psdn)QJCu_5c6R zf3Jy`d0{XR#>y!CN1Nfzn>SzSfZhUV6C8fT751qbE9ND1yZxhab6b92SbZ;fbK{Io zc3of9i5ywvq}CJckw^HMS^=uUZ^s$ z{$*vY$4{lNBP0LAQT+W6tAD1DB#9kjcJVw_mKTr?G9P{p-9hI>{x-(Phw9oi>W zKVCiQ^5Yzyy5DvrXfEW|Jl-L@*oBpj-ry_<2U?gErbkP zqC*cc>#sUQ5CUSC>Z6aB>nj?rxIi=kSUj&@RwvNW6DU*@Gu^Qp0}Y^YAr;jYz0VKa zZN7(zz_Mf{RJB+jAC@VbfqXgJ4V(n))}xvz=ap7#IknQ~WS{LXAp0p5Ftf(JR`G9AiF%b$W*N)4ocr(kJ(&Dfga6 zLKF~b@cEaPP>z?W7!q@A4mV%@zM(S~E6z#29NqjNxsaz^JKT&(_HgOPH$qt7 z-G@8$_nIUmgF?zF-o1aWtY=g%j?J__gp7d52G12uBWTzM)qH8oG6gZk?<%t{nhqa| zQM=(R3;uhpFux-Wii1*UaAlPn(s~sl7P!C02p~-I$3e)#V)_WS2r*C$>X16hmwphL z*DU|@vR6CsJ;5*Or3^hT?e%9YHhwQ>G=-F%7oW$|o#$7NIa8a8nl%Wb?u)B|1?rn% zT~wiA+WMWwRAzW>ivYffGwH>?Brp8-o2toXAwP<}9yPWM&J z!JSDD)?@hR&HF;q5?RHL4xQAn5_!1JF6O_TN6pR%1Fq!{A!fUgT4*=vW5RciXf^J# zYQng@M*QjpCcxm|dh^HN1&}=hn~kV+Fa&FLur+fV37C*MUVlL>LSrQ+OKa=xpmgiV zaG$1~(g|Rw`sc+AZf^I!v&Lp7c$1-*e4s9gzT@;^|+N9!hh`-Xn}pIFv)YZ@MnL7LTP^I zGYCcr0>2rq1eh>cLwZO&d8`BJ@0`KB9s+N?iKqCUip~AZ}rGgP<5LG;r-}tX<4T_j^1dNq)w5vS%b5k(` z)^tksf1$+4t@bqof>=5Yf-|-M{TifC^>VRhRCOVn0qu?nm$vs^cJIG) zs1it~Z(iH*4fqes+IM!yj#z2A)GD$>aM?gZn21mDz2M=Hwykzw%6zz@||3WR4_3KG7#eZ$3pLI6>}g_ zzBM*L+>vadC711?4RC8YfIn;z7a}*%6ip=VCH|-vupZ@A%dqE3=+>;Xx5UV6TSlY?!#T6I@oXbDaOS zJ-@z(G{Z_9*JVl*fTUjM|PX%bv8uY9ghC-B*X^nZX*Vsg2|Y zB7e+cxI~l@KmIc=hN6r+ez%GrN(|Ec7f+N6qjbf;-4r2-YIx5A7-aqqaleHXO$ad2 zTp*I)fhzp_g;kQYo+xC&-3{@7N&HE}A}97dMETD!fB>*7lox9}5!~}~iji~3|L#$K z7OVF{~Yr#)`>-&zy1;U->@}(&R?{^s*+Q$rKtD;OIKG{np=Qu-09+8F@iMt zvkAxfbJnAP1NUcsAO3b^Od>%mF;29K9|?HM_R$Xc*2C;F)v=AKo-S{`i+tFdvboUu z+79o2uBkb1Uu4EJKflrMxUf(~rA%hK#mB=076>o#WC3FS#9tk8@$sGPNqXme9g1Pr z7F}%8<|q$%`A;ydZBOm_OWZKg2p@m_?K-Q32Xthue?Zqh=L;B9n#(1A|>73T|?(E@LqfG=YD_p^L~E+s(`Fn*Sgkup2zV$ zg7PXy8xG0coO+GUJc?HEKLG})v;E>mQA1-jwQg8mzKvlE*d73)KEvS_Ns-2H5YUN9 zxGygcWDfxtPpzW@*+1hBguoCi0NJ&5(D{%SonGTTn4}0t|0=%6=;=MvcSKXwmc~-rozZM0nVh%QmgsCD^5(S6yaa?|!>c!#Swv z4aB)QrLRFuVX5{uHx#Swv-uG;J_UIN8SO4#k;PCe95W_1|JfMRgv>q$Y+Yq&O-0Fk zyTsF-NeTI=?!L{9zMjw@p^=$%AaS#a`ZPq1J!aa*<`mnmd`Zjq)}d>L$_G*G}Pt(@K=8;J+wwY0RJ zXa*YQ*yYDyuUntJ5g%#kk-Paz40K-SHPFN34h$H?q>_LeK;*pOfhILcpP7C%Ag**w zZ~FIa1}w?%2AQ8OlKkefaVU8YU}dOewfeDL1*l&jJCAvFWC#vtp0`aZ?6RG-?mXuz zz#h{~f}tV&g8Xef&ZJT?aY?r)VWMm%w_`(00C+gGqErWD^0b`3+@`d2W86vLP0u$C z_zvsKr@nCX^hHth1z>d$@p%0i+CDqjzV06zN`k%Wt{<<*Jb{5QU}6nMyUG-G1`iR=9uc{XglU4PZ=5HHnpL@MZZ#+wDX>py%}&TNmrXJ2Ym2-Ra#KAvk8 zq*RuY>b+S(1DyzxQs8dwn?BE$*6J_nx^ugp|B0w411+P!Y^bSuBkZ>h`(b=E>Fc5G zg$?)ETU2w`&=~n4?iBD;Q0_aH-svXF**BP@#oMXOrc82rcuWhT@&`Y#nA|{dL@PU7 z?)w0)(oc&mHluc_r!2p-*`eCPi&we7?$3#s1}19L#%4VM2$7zas)=7svJf0O_`vYb za6H<9;}YMbaO(LcFo3(cnrakXZMUH4AZoH|Kccy& zpY~m0#RJG4z{xD-pNZ-|U@^RT3M6ZUj<3bw+00cMo7pJSFB8)emkt=U#yJ7 z%x-g^4B)wuk(L1;t+j8`b=I)3U)i7mCgsWNOcBV}yaABOV-$HVl?lA+BI|nTZe?ih z@gS<@__^${AkEoE%SH|Kd_?(_{Us(X_I$QAtD&Y5zF$juS0>{3$P9OUKD~to7=5~Z zC|~kW1ouhaFlET5KyH3vCfQ;GOb! z%|7?(+YP$_yXta1Mq_CfE*)Z`%zfyd5F%x4RP{xgaK76%i8IOXq1{ozlTq{Xh}s{v zDq|A!)~vN~)L6iG<1nOC=L$;2P^TGd;&TMCVKubsROexRT))Iw4T#Vf%6fKqd`g-b zR{H!L)yWIQ9k@kF_4Sl3RI+vuk#>6>WKOOCDaKRVe>6V2s`|pL$TGq&lA_B+R@;=2`0KgzM`rBud-cn*Qke%llU}DQPLq z#Ql~6Yc-dqgEb%fCVgrPu1+;ZW3N58!AiiU3{Rj@o$O-v<548K1X;F8h9|_&k-Ie1|eC z)ll8=;4t`8t22PxTo$6txSh!QEI0CmF%a12x6AgxCqNf4*|c$GlWo$> z3Z$S4@)t`vO`w^uC-C`f7I8CmzO%JqhO;krl6j586R=VooN!~RJ=8o-G6dzPG35Gz zM`O4S5$8K~>29KXfhe!VAxce>n>ymz0&l0QomyOJ{D4ZwT}-iwq$Dz@ta^oUt4|vK z*OGBNPouncWTeyB1GhhU6D=(gUPdMX&uB2uz15z!hwBTM+`q%2}l>n*opQ zZnmEU4afw(DnFi7Ui;kN8=mMr^r9C82!dNRp2l}{^^-NwJB`ojBQORiqtR$9qPutep~7pRUz`&oHssjC>04J>frR*B?IMs&pRnHLzYXJpgd7; zyc>XeI=*=)ybENlL=$i2O&(qQa9I{!mrxb`iJfh?x3PZuX?$U0^6X$~`LQMA3P-fm z5Sz0cz|PRaA2yaQVNrfTeYgM`jv4OK-KNJjUI{>P@>xabIWl_XolO>6F^nU_BXc!b z!0>k$B%D<^8NV)`FFYXuAzWL9&LR}koxJoJ+x!prNxx`*%5g=L2VDG?0mXe@tUiw- z)E*fm&x&7$++ldE0dHnGCmthh20ORwL#*fhdGEz{p5RY=ofWK(1MRo#)u5-_{C_rg zyl5*g{9q}crWx((;Hl4i@V7-Qgtl33`eYgOg}hG%3O~!3%gVYJaE{foJPopN_|Es* zww1U1XAHR;+x=B*c`LSCJ*^OR7>NVC#bdr9;N8?-{DvjNPTr=W*KYZTTVvz1#Ww*- z9^?_ns!v%$o~{oVcmsQ96I_ax*p$n2x+nDOR>7$v&baR5^HXzK{$i0)tG<`b2bXdO zYKZgId+c(v#=?FJs&g6He{uetOh%%dUWtZj4!v&?)XLW%{Ue`eW!XnBOBYyI<<#LF zWJ$`i!bwCQn%snN^5%ngGj7$LVf}G-##{ z`Ga&1U0NHb&0+s(XK$p*(~7gECr^oaLX@sHy za1ObG%l^ip5)<>?A9yLQ-{aNCDvXkCyp$`BIe_hBc9;}L%5#5~(n2TO8cAkELX;-+ zrzc$MOGoDF03$C()->l*zI)0;LX!-ZRfuX>uPA%+6lUmb!oB5AdELEz>us>DBl3jkPg=HDcxB(kvdYUU=P0c2 zIq&Ug)#}CyyO<_)Wy3_AG_9VZgVb)SsF1;2*F$ncVr#|;>U$3nOX+sg+dwMdAGtXT zX-sS2zdU?OKI*2$P~TE9d(!~KT>z{tS{g2Qo1N|W`1lKr4wDQW{{$wY9|uLV?KfRI)yU$i;CD_YrjMT9yjM#ui;k4 zOS{tz$eM-otfC5EiA7s#peD@}Z~r+T>23djJK?)+SsnLZpgMg$%q15|rLh@I!n@U_ zJb!PQLsZ>BGW6>X^kty1*srWBW9DI{S|4rC@WqCqt>$aScv=k)h$F*pw(~C2Q|R)Z zco#zN@5k`^2Ri*eFhq--^rt`&E@+|EDpAF<7$I}h}-j1Q*;VMO!-;L{i z{ao^X`isge@vfh%5E0ORlSP+`ilpL~0K#$QwJe)PlXxYoY$6#3&(R>U5g5zecq__U9V zq3szF4o~w9WpzO4JImgfX`Cj1an*)qE}ae+SM5A2M263{qNTacthoe#q;hC}UY17} z!@YLee2~0wvw!SO0cN~WYp%sn z^GAK*z9o^++6^t*Ke;^&a=*yJ`6)>!zV?1B&)N6(Y)g}d3_t6YN0eoM`JJMyQi3Is z=uZz70YpAA#z5cOtD(V>R!>2`eWxN{SOczFb-D*@V?_NUY$?76!#HbXb#bNU5&<3) z3`OOpJ8iq>d}XRNn4S8|a}!@}3Y%85oSWV6mqRb!*6UbHki9_;-+=*wFZP>OB2p?| zXdnIEc?s~@2HL##!ztbXMi)gd7LH_Bl>D8Jp(CY5I{iXEIfB-|-_kj-8g_JRrPN|x zUCTth85VxAIQ!^H)R9~ooUILi;3oMxkMSiOz-}J0jzM4+6_M{5STbM_Xrj;6iQDMK zA8U#ui6^t#V~V~lw~o8D)(e;Md}p@6HuH4MuBODB#55sULhDU~T+Gb?ESe=}VgA6~#H#)a* z#yxS?*5JL41t_;?V~{1;!E^!N1Fv!6UX=l%7idxG=9fBxpsPo>19O#IF987o(MrP} zw(raemL6|jDFn;_@{GIE#LJ{5N3)f5U*@tBZE_X4Vrx+qMR_ex`SJ<{tl7lGVe!PC zfqmW8DoSln$%M&YCHw~@%5EnU0U`-;r52lb^GE|isrbQ!T0X7E5RARi^q;_kFIjF2 zzkih*U~)}K9|!t!@Sk3Q-WP^_K#O(hr)+)b98r}p|B6)p?NL#jWWEDN2HF}^Q=JbYO-_4x4*vWzk(mRR+jSE6p?-Ki|ONI>GqV4m4m;Hw8- zc<#?1_&EEGgXXts`p0zj^gW>a*BhI2@DgLKgtP?sJUfZlu(#Rg#zH~Z?q6wbB`;Ub z0q7vtZSWQ5Q>kWKpM|UlME|ZM2O z$Sa&#$_aMcV-Ow=88x-@mXddngv~t-+nz_~Aqs)yW}S+~x1eOY-awNrJD|VV7Er)W z_>OJObc1y&j z*8x5ubaRPPaB#5dCKJlO&3B@HGVIz{bqFPZ)7}DG>|uoD(-YJAy+l+*9XYh)r>PnVCACYo8Rk3Ka+S z>@QD@wSNHrep@qoPC1dIn>-#{-UMCMROPn*Qb%4#^hW4o3T z8X~P)MXzkKo|FuoEOv7Ec+dTh@VA*|M>a0%A~G+k?T{q+}c{tTVdSMb0V+TZ;_sv+PHu4EXGLw?BisrRd`0 z_FR6*Af61zj^bxgYRmmwH570e4D0E{VaH9YiA8COC^BU*u{e z7OOnAK3D+dE~Iir{#}^7nzk3~j4Pv>re;y#M5U;{|1g`CiNSH{syBVTihfJ5j<5Vi zNr@VA-&FDcJquneA0LdVkm@kF*1EeDE6BI=76g2+Ol)UrMTu8^zm2n-xAxK}JPC)0 z%{wK9q}QC|U@$Ad1doKgUvBPVqtpC?R`qUJUV1}g%>!sU3@=KzAD$*Xt6V0$8km&r zujQY~8)JBb9?|Z(Fj6@M)J3*#5{)dS5S}L`Oq0ri_^pxJhA&E#`=htS-yTGeK`XNX<4``y#(Ki(PF!yTRt70_I zQ|@KVBOuas+pUcv)JshpqTm6_VBgk6fTJx0z7S#}&>mq)ggaB+HUURpTkDzCZU-6o zc`xC)!mvGv)2HrmY<~8zWtz)sl6dt@mdB_49U5bXI-C=5VguG40)Hd$(=ZeoSx*Lu{Npb3n2C2#HA3a~Tmm(0WvF zp)Lqus3S1(x16g{zn-{@JpP26<=k$yt6G$*BECg)SvtE=5GINGRLPw-UkH}LF870^ z#c}|x4=>D>A8R^r5cKEo7s@2C>%!A>45zu5@9s)f)-2-g2b~o43pXVV zI_aHjlOWzCPX$|R~>5a%olGiQ~S z#L+kd_R~^r_OKs^V*JO0kHc;AIgLH0$wVAx;NM-p)Wd=ETFXFcUrx^?wCmIRUHjVd zGy}IkMKiJB$uo$k$MIEAPocyw8o(L4)Xa|qUGqKMuFmVQBM9(qY@o+>SZ=sn2PmMY zGQU*|muuUPnkFRs!ik5OAe^a=#tc)PkDZ`kLN2-lJv5_ zzJ8ISrKR(2Y6bh&k@4EeCLQuW(yBro^x3P8=(g_70p zU}0lPtk15uPZsgV6h?xb7n46S1ik-++Rpf0E~1|LH9bC*ivh6=PyQ{PPZyZ0v<3#c zB4Zi+y}#$bc{l^%11IXqS^ifyVQWv;{R7y=Ra^F+Mu$0FbCnOSL!sJ1#xReR}Tu7aG3L@)ALgI4go>saEg2nrTxca z?|oE(OdF^{k=F=F{%c#u>KL}}$NV{D*J>IoCtdfo@ga=`b5YD6qxvUL50Dv(RQHx24w$?n3W^`6AHbhZ6y`< zkNY_pf?%g5&-KL-F;agQPp^v`2bo3Bk|eZTKK(oZ64^?*tq2;!!+TOw~|*6!9c`J}LG(Mo(Y6tZC?tPs_+L z7MbCRK)}PJJ;uAzG_Qm0deD#^_6J7U>xc|$j;;ofJAa3Ba7oYXW8=xtsZMOL;#bwZ{n)sO7wZoU$NCeZ#D@tNGu(s@dYO>Nk0gjhm;ZX^(xKxkns ztZ#=Z{AF+`1$&lvtqV*b4^I|tLH`6RjmLLW>td1T*A^W0l2hQ0fS2;rjZ^vWf!+mo zdR@1XK_jz@+wfL1QTx+mNGIfYp&X+#IZn&{2hc%IpYNO~jJvIk5A`%eJC&(6YHV=i zsf6cippEtE-u#bz0jB2`ERD8`I7=PoDQP=mhTUwm`ziT92{hxsy9K)<@PYCdjo2di zzmzo4kgXSg|9Sm4b1XG|NV23;5mk^E^Z%`qXfG3m{dFctr%zyqdfxJr2qVmfiGUxBH*RhJy*WNV87DI2*ts0kt{5Z z_}>zep0&@?=>M~}v!S3NEm}RaT7L%-^;&`Y3-@sTGS-} zuUrI;l)ehV9#>mZ^Zv}KgPP%Cr~{eVVCuiumkbK_upro%M*sV}aQr`OAJi-kd?x>_ zy`{f5uSo_z{2ZJ8ztu~;V!VKo8CbLBaWihE@N=I3PdC-H;l%EQ{XyA-f4s_!8|!~* zD;)U@fWHCiiv17giT_*jv7U$=f!BsyCiNSgMzThv&A^a5L1Mz>hTOFG;l=;fxO5sn zo@4*JYa-3d@pK?Ki2sqI{i{lQ*0|Xd+d=_;1L}&J9mZ?iAzd&5C`Ix{uRd zbs+z}h5r4706cgc0+8HtR_AlsQwe#nN9K1zT_uBWrU91He zsCd?_0)7`rXkr-vPPz%O6{m_ozL%+({|VkR0a&>>9gK{u8<_$}4bV7+F^#P#NaKj# z)>e9(--wEwtUN#z$7zJ}|KWb|v=m@En?@Psw*gEEsBBnQ0lsy6V74msU=y-u?BTEp zxTXe9<`#zf7VY{w@VGO9tm^i7hs8hl8VBznH@pG6KW|0gu3M48e$B$5d%Ao2{DNYf z$GA!e32p`x41d7=;y^^bD1|2F5?Sp_)TZeqwqU-Nc%0OIc(RdH$U87cyZO}rVI>Q&oUGTq(qd|%5xk+)d9>}h3BHP3-m0Xka(^BK9Dc_RWh08=fDdiS zXPx%nb=#)8znw_xOi3k%)Ox6KNg^x5$`+_paiWBnrZ$0=up9G{5jH$4UVVhV;!)#QY^rYBh&wm zfRNx)q%pYXi$q3t^vi{w&yrBkl?M$(83s5=lfpFsZ`&Y94 z2N*u~7gA85z$Q?a0566p!-ytIg4@HTtbY0eMPlx=5g)c>VzTl(3vGVa|C=co+|cj8 zU+sCZ%+0R?PR{IbfgcD>*r8%whe-YY+x~Z=PQM|pzuSKH9y_o_G6`8MBzBThy>ogG zcAW+qQBrE6>&u%6KB&|#`~cwVjzU$M`oz@3e*g8*{fob#uWx&QedA_qEXz%WC`Q(A zMbvvgkfKdRr85$6vtQw$A8ahC&FIlCaZ>Iw`=8G2Fg;D=Dqc zI9b8{WAJ7#8E;EPUm#q9tHtB$FXu(yJtyz6ii~8H@pc$so^e|3xP7~2rf{^oEqRgr z@uKYjuca%C;4YnqXc;4OKb;bH_&wDyvqyg&u!z#Xq4Fx1b zNtJ6ic58{q*^vNLDeA3jjbCrc_ViU&QfI#aJe-La2`8iNFA7|HJG zQ38B|@}-*7(G}Qqc#D9bB8g~OnhKh-z$-hz@++dtPJiZf7ZKPxov215=-l^vm+<1I z5AaIo6Ay}86UI^wt@=jXhklW9T=k@7=ImQq@w}OK1z6%Kq7iz~dC=owdG`DlOVU`% z>Bgl?i%`b)H(It!ZAWK`D>6FecfWHISWYrK-Hw(_<^rzIk-!pVOD$2yacMgKJraB# zn~zVqd%&DHR6}A_}ju!-K=Gd-?%Q&A$9#CXb!0iPy|&J3kX0 z>vwfoAj)NJ>+35T4-dw<+aKQ|bAJG?DO>Yphw1SSz&0As4|%Rr2r@7kRgnAbprzk6-%>z zDqC;e79@mtZO-#Jf(u1OQ;jY*d9C|;>9hDio)4F~eNk`n827$6eaQpxRj%I%*qOev= z@w3{c1@Zxc#B+MkuIW@-h%|5fEY&mP;u@{yVhn<)%1<2M^FDaoZa~zvtTb2NHeWpg zHpyzP*Ku3Rs6+3~1fPt~=Q%Fkvmn2Ccg8tTNErp2ZGHpTe|vV+R1BU|qmop&769s__1;^>Hz3}BNS=$7Aoy>nc13}ekO#<} zLZnFN**M_15U{gKU^Y8x8cl5%fTB7$L|=#j`0R#@ ze8<9m0)q5oLo1$#dAMb9zvby#KM)>gN)|q?wB4S~ipECU2{T}Z^OGr=T(RLp7 z&#@;u1w4X9#iz{ki`vp&+Q5NbS<15(6~@9=>Edd4eK9O2|D$wL^IWH}pg1R5PeYQ3 z&stYhi&qw|v^Sl|)Vs?e$eWbFQRAA?>}~OszE{kxx@JCQCZl2${w=bxu{MR*|L23p zQ{7{Ggdp};>EGUU?ggCD(aANgduBCxYE_kEDU%bW698Qb#oFh0FlFmdT-4=# z1_<~nlLJW!NzcH$48T+IH{ZwSea}V1A|KZ{H=mj2)?Qy~ZpcyJ*fv#(QW&B9CjVo3 zVk#*B<~x*XB5I-cQ8iciC?bleUBL18x(Ktttru&27U0=yZ}CbMw4f#v+_D49e*Z{a z;-nd{UGr_{Qt;BIY|ZPf2#05Xr)cz^=W{l23{GX_Qy|U6H%~DT(kT5Ye89UeBs)I< zK?sxL0~(JVN1VTG`m0@k%QLaqisLyIk-({`so^}VYy05;Ik=r=?eNd+x1T@F85I=a zoOBT+5|C|KxuI-n+wLJY^}!8D#`!~RWaf#8?wNW-6pq~{s}W9kq>_t+BQN;VS`IS! zyf;=~ld&4`-Nz7gS>ibz9gEqe6Lo2(?;C3rek-vATut?Z0JFj@yRzR_Ra}$1H+|75 zZSq2FK{gnv4J+j0@cB3cRhK}CC@={sO`0dpfNOwHASf!@+KSuS+68?$hC;jgBm`*l zTU)n8Z?VggeA$RTo}uxd_S6mw3knKy33~1hAE%NY-J^X~d#MgufBoqTqNu2-M;I*9 z1cltRXHsub|L}@IB`c7{SGnuX^Clj5_C!C3u_ge9`*7TMA|p%W<+|rO zE1W+E6$#FThgXj)_WyoYHeV;2WubA-**a(>*pL{L=wWCh>N+h({Uwv&g@BQO?r1un z5G}LaLP$Gs5!=QOFU-k7K{eedb7kKY@;`unJ;G_GD=BG;pjgDwKZHLUA%VP{py%$q zIpj844lgT3{e;~fT0CLer9?`h9oy$aIE@q?fhhwlrMuk=X2D>IF9`|w{HMOK38t_p zoH~DEeB);L_VSGH$IR52SNwmGr?H!DcLn)7WD5AB7`)d)HSl`gyL!Ud#~kPAk~QDi zMIN7u)6h8;6868R2wx=}OF?KSdVD;6RCY!AvjKfmnBJzido-PB|JMQy@5&g2{x6H*J`m}X-Z_u(xnvD_UyR@po3f)nO10`%c1kO`mo@Qsp z^;l+$Ze@D?Rf;g@uVyOl0q)cE*YZRa@NZ#WvH{c1-+K{0)OIK`{- zpg(RbmY*){gYw>)J*CFAUkxz;5k>-}H(u{<@v`TPi})i4_<5Wo)Z_JieZBe9zJVM) zDr|$CWAu1r;E!>gS5n&EZMT1GxdA8MBHDloak#d@n!OqcL%~Cf`BukO`0&Bjvk{+f zTXfZ5)3~z)cV9}(rF@G@ioZuH1QH^b!2x{b=VoN$iOJq%CM{tPik&d~OW8lfnDs0p z5#8eY$P_F*_&G+QW9Jwz#bTTst=pbEhqCq0zU}p zlIKLkSXK8UhY3ej08EW|d@P;MA!Q}+_;@)&FtQq&HV-P-gx3e_n8<|E$d>+Nk58%D6x_O5~emj1P5{(2k=w z0Zw0bC*;(^zvm=HpF~S#yNbsH`)nw6OqFeY!BMv_`Sj)-Cu9JhkYFr>^EKlTk`f*_l9C3D&D9{gwa~eW|e_ZJO+1G1v>7 z$l5=pj0_Tft5rfyvKI1o(x=d!2mUDN*5XQ`DvenCm&Cv5WUw<@zz-MX0&m_UoGc}` z!?vYMUiH4Q;)h%ZI;C>=n@Vr(ryQ~8*DpI=#B)fR67JqLlU?bp5`2--7;cTPNkDr` zEikHD$!|Z}m5f+I@b#@HntmYe3)AXA>(PT1B4Xn-9iGaJ4mX@dXnE;wT=7R5f5%XG zA>@nH;lU?yXEdc%sL~I!1{~$_m+c@_} z5hDl)*;ff|zPN-d>?#2=Tv+Is6C%~dqn{ra9oE(`9x< z8Z7tfw+KfZ-`TI29Ech|Onw!A!PjN}YU-WvDZ-%P5$m;XpghyeD|uhs*rUxgd)kDk$}CN9sG&%HHYd;&${WTjCPJD6Og$< zFx6AwHeI zz&)*+Kr}e~YGh>ObmT+N&FRX{L;D{4_`zfjx6T;*RcJRB z%1hLQ2ZHQq$lWHk`=jaF+1V?Ep8C9|rmw}gm@(ghU^P>PT6ryGf#dFB9UmY#^H;i7 zHpO3(yitsjTJS(!$rn>WPVOO@$PGkVg!!djAlfck0UMHa=5}PT*TLjOm^mw5mJoy- z6Yu+=>u5Z#sXw zXZluOr>|~!c>XRg0i)n`E^jg`z!Z>@nm1|cqS5{>silN9Oc53qb_~+RwjvJjI$dCWpMMy?*RjdH&if!=O5xN)`XG4u6)#5%IA4z_v zYOHL15YoIcdX4Gc+P_A#%M=@8xdYzEy1S4!RQ;_u!D>83Wm zjj@$cLwDn3zeK7f123kAqornGsMXh)GE)VmCZwcbSxq+Bqm3%X*4uA)GdoNT+R1i8 z*P*6X*d^EpTl4Eib6>uG(Pl|kUgkditCZ30%u+lJ4BuG#5)=GQrSR6Ie92(4^7(!4 zA29`599d&+QjgyGFSPGhg#;KrcSI6qNC8(cXOX7pECk)%q$QR7B-m#G6g|WSJvX8v z8Q=!%fBnSdm{4BhrwuaGnm!Y+`qlaa<+30<`|UKJc^!%rXm)cX+A^8jv=ldd`|1## zaCE3Kvx~AQ21s(@w#`vtiwr)v^Y3R1x?t`frc6!?~-XF@yk(wYP{!H9owK|STj9# z*wp8gtpSx)g1nM~rbYEX+7$2m_^7n%FA{xstkD;WTUo;;BfV5T%I$=#{9e zTSy}B2O-j3Tw5OiDRR2pAnN)jUqKFjXg;|Rv5*7(GdDQUd7WA6D3=+)P2f^2P7dXom zF6qBX&bto{!GU^i4|}Q(n;NHJ;w>QLV_Uxg&HxJH*V>wzn8Fp*yjBT#M&()36631} zy;2mbPwY$bEofmWREgGohLQ-VD&ock1Val4cmNjDLJ}!Rxm2gOg(j@I1ry9iOclS=c7LRzvdHnkzQ|_16(>SRP11` zai)P(zjvrUs!C?2-G@}%EWrV|SHn_iR#ti4cKtk0rHQkIEF1d=&yTjlZnb& zpbBfIsdeRz)q%;f-(n+AE|KD|Xi{cX^owjcD!0n7zBAxXRBzMAOFzVatE#HI z8oR}nmH$?&ubiDX;Tcx#SXOU)7WMLwC}E9Hh-bXStIXt#IuqQ7f>ML0Te z!!MCfauNxEcfVtJhxKA4dwDXda<{sqq&Uc$FqO1LFF0gqGJdWCu>vOp)LdeAIgs0{ zEU$z-ML5XehF+&P+80F7q8Z(b!AWrW>Gd#D^pJz(TNL7$q=ZD^qAgL-{(P)FDSGzHys7Yb-EM#ECk(AJjZ6Oy6K zW!q7z@?}wp+PEnX#%22R=GeRXhN`?a`4 zj=}kd?uTb%9`X~L@O&;bYfjVms5fR0{sCiaemu^$2u6(d%j@)?I@xhCa2Q4xSt0s~$w}gh_UBZYMt;T|^0T%P^cE;tn8Ie1)=?lRe7Xs(ikWy1I zWMOLiz;V~l=pRKf805as{3uXURFcy%(D;}2D2s=5g zD{}h)@BP>tpSYFY4`l*8+wN+vue6L3%v4L!t_(nBEH16FVKc5KhV8&zkdgoohlYpP zNNH#T#DMIMrf|xyV6xk+HJ>YV3gPg&w?PsT z5;OUgHwn1Xp-XdYcc+gm7f!mezslrjz#g`@L)9feiwB2>Lgl+jvFqBo{c`!><335H zq&!hV`VQjOG-HG+dMPHhUQLJvRa{BXKoY#Z@jvqDdCAqRL5b!J?AbS6$s&S{Z91{> ze{EU#SkiJX!^-rzFKX!{qVb7ZUEmvoKS1jp><3&ne`H6ifcx<*wbmtej7&_hHn!WV zU6P0^Pvdr*HixXt4$IaIgjzV2>&Ao}d^iz3d8{Rzo2M>rnEbu=YBds-4mbQ`(wIqm zbONc!OKopZ%=l5z3k9ZXlm@9bhrp6o_c#!M;|&zOd;!pq{O0PA63(kw9`f>4fxq*} z`g>Q<^lMj{(OtBZ&}|HU6C~#Zaw51h<>%+KOQMkSrG( zlfx4Qs?kL0ma?Zb4quVvQ1Q71tdRzP zwa_hY3878tH)tw`ghWJG5#M}n2NMEd*kt~W!|}P$HsjQFP3Ta_!^5wf+iMK;@;=4FM5c0&)UEf9^*^^air4p68gMed|g{l_j=~PoF661(3@nhUdZ847B|AXZ2R7|^p@2P{F=uJQamuJc`4}WfM_cH$;#&i{RX$1_ zoz}Ey6L30O#Uq&^smM`%SIzw0@@wrEdfI%|`bh{MX$od6m8D{Di+Rd0k;_g*?a;kF zj*ar0*^w3&j;-*_>hzMxwc_xw3pabhkwBj}RW+-AXKrifKj>Jl5|~757JI|YcZIf* zOKE8?i8>sWiy91P@_e=@%;Pdb9i~1wsMHb$-W+X^y`=F?Uii{n1z?u-6dJ0)1D_3w z;#=Lbxf$N)fh;X;_C56<*7-8CI?Yn@TzjxZg#MpbCeSrTE6`1$Aht8GGFp z^s-=HXH!S3Fpk^!=tP&KZkjOW<6kaxzoT_Yji2@)mXOuSWRr|uLrfB*!5lay?M=r; zv(Pt`;0(8ZZ%tpAQ}Bi?3kChfJ@Pd|*$2yoaG=h;`;DJ(jeey^toVLlXws{MtwNND z1{Ea~(0uHEpEl_8< zoNW^{bW?Ang;tgpQr7j3(_=xG$~Bg>jXQ$g?pZWES#f($y&xMG2jAUI(OhiTdEjIr zRESVrj6e83JPG;U9Jc$a7*FwwIV-+%N-p5G`C}hZTpb``F0bj(oR38P3eMrLt*`(3 z#dr$AY2mA=ForVkm=|*cmjgbNdlO7XuO_Nr3Ft33ng$t37$}r0gwA?=B45%cCfjeT zXhUxa0W1xP+D4Q5X^k(V!tW`F7bjJdX2%RtNP4_E?qohPW&V)0_0~yAm3-l1Wi>PR zqosug$9(H`wk#&ubX@oVmG(wV^^CFAti*F^tBUql|Lp9l0kbuRA`N__UwVI@FL|@N z28#2ahVU!{5UH+MOkHqxX6MDy%=N=ezYvkb+`meVN4YGHB(`VM4Gzj<9n59yr>OEC zbiavuFh2V8a%0Ws5uFh?S#d-Ob8qYoa<2Q@>G5gtCN9%z*QeDU`e@d}XqMH^4vI|R z`cmSPm+Yfp!yH9upe#+wTvx`XbcOL4V^sT2Lg-ugcW1Ngsrp<3y;m1BLSZ94h0exx zunDe^!3rrr9w;^4vnS|(v+)DuRx|l$MsG%UV`8A^BL%*jcL96k+|)!WzbhZ@T2ER# z#$A4kHgI@@VvZKdY3A80mjjTdc)5KjIeTm49^T1v_})V?jI6V9v9Tj))7tI*snlA2 z{)F6o%E6uZZPfGcgRm&ztw<;Ra1|VwLQb%A0k8{ZUyf5W9`jf44fxEetie#(J6sf; zuL8|p4>t<5!#58%=0dGPQ7iX36h7k(B?YVnJic&$<4}nb7aP65T#<08gY!OrMX=Gz zm+U1i`k|m=V+!#R9t%;QLm7qlKhH#Jk~*oQQvJ7mK5aQohtG*2jFgm=Kwkm{=u3EE zdZa~>F77R6*vygxV7~AWtU6(r&9I`PDo;V6dEoc3OY+wnr|daHBdJ#}gyl!JbsR<5 zt&acVP{V!Bu4+{=Uh;Bu7R_CLNJ>d)_vpzK5f%ud+JBnjWfydsO8HSv(2@nrzHqWu zvV(F>w0;rzkQ_i~9dWWc664a)G9`aeXSF}PXQuV=?zda4Q&`94RoymK$75cNR(E8% zE>s?EjY9FGNrkYjpS5Kvrh;w>p5JCJXqPM_!XM?TP z=B4o6_bIgTk&;x!a;j{zRiEuTzbz5=QoAAsVeom7C%J7X&u$^x%8Jj~@L6}e>6fdk z1TGvhqEq#p%3RdcSK$fQOsiubJNSP;7=KDFOMgRb8bKx!sI*#dafC< zPty(cw)K>vWdJO*OV$L9V(0s1W401P`_AAH4!6(Dp(xz9OU!-akld6Q7Z=wHe7hs# zeN}fJ4nj>xI&0r~_jn?sQ)C_|jkCFoX29ZB!|8(Y$r9*dt{)f>_v1iyp7PdN$BZG9 zb2FdakhJBAJ12Fjttu0whU`IEl%gPH{kET*n?Mlql;F7cKTU(SHoslaFQn&#HDP8> zLQ;JuRgecwf7at~*oIB^sUH0duTC%Io?vGS1+&HHzdvXo6W`xwkXO1sKo~YP= z%}%SLZV^Ng`npi2#Sxu$F`OY=ZN>edKUzIqL`?C5-W0u%`5My*& z+HKzg0eW7q?2T=`Nr^qs4e%l2?_+i4+9JC(sk5C?udpU`rpTDCln7f$bqobB)~NtW zh_hpsE4Bt6@_;>wm0fnO+?TV;|Jebc0=MWE&-mHZZArZEiD29f|T7odD$Qh-?{!R z?056y`{q^mCN6K;Wh8wAXX``U$6u;Tsv=4^v77yV%N`Bo^S;@B!UFD2s3<7eEP#Uu zxi=YYW~sqighV$u!QpoIT_Nl8s?Yu#MHhJmIk8Gn&*L#|f`aNejmcZeP82YzVni_d z?`uyDVMl?_Xoqe4|LFyYkC{E&()gdimrC@u8eL|+_mxLYATJ$1TsfZTr;TO`#nzJS z;5JIqSBgoB+F!VY@wXUR^V&`l6XB+%QYA`9k=;V$H9&uQGdYkZlIOF#Ucb z-2(IT#GTa#7cvK~77>LVAB!Eov&-S%D zQ#?h5O5BS~-^C}frB%Tr z=}N0B!Y-*b`O_t-39}P~XCx5LIXJ`knBtc9Uk}b1u>)HkdN|& zY-W9%>vNS|x$)5IW+&;7gOlsOYMzCx7Iw|^u_g#7o3EZVPjnFZ`fQ@~Vj0gwwv2r@ z&>TG6RXQOs*aZFF;1>x`dB>>N<3h9(B&RA>OV&cCfOvpVztj8C-AZgvaKPK>EEUTB z63q`}uzlPKeQ)k;O{|Key=n1p4d;Mzndc#cg;X+$yYtctfIOC_`R>cbToYDX%9?C{EQfh<2ebB zM|WB%ikssd`YdXU&6_n2YzrZt^s>SiPVtQ7f(T5K)Fnv;?uQhx~bLr$Tm=Aog|+*cZ=}!A*Sot z4*HQ=5SvR05u~b*cI2JCD9GM%?{|VX*6+o~pJay*i#&u&jh~CF0~s-{rQK}1t#0@- zO5-UxB0*myYr*3bSZl^0q&FJvNcud9&|I{D8))5DL-W zqZgtF3~TD!1?pAvRn#6lsYD1Zh=VcfL(Yy5x>xSCQ=TjKvb(=1n_K|z4Am09?vg_ZUr?E@i> z3-FY!V&=j>yPssU_wZ*fq#`ejjEDpxtAhUf*l;4p7-|8iyU5eUKrbv+iEjGmwZUkv z&@R`bo~0ezhsdZW2@wU0n~`R&^Y%Z%1nkC$sE8hH`;lM%MNeBpG4p-X>mx5$^Su~B z#8NwjBwW|()$b1!@7Yre`wWurE3r1qAN%_<8s;otMM1}jPDn3=d|l2a*iy+1c-=|o zL#%DBpKhO&xBVO+i2(}@kuk7BGW{CO3PJ?s&(C92H^tOfj28s7AYz!me`d%Z>M5q0 zo1-0kBBC_k-8z;7x5)lIrX~Ce6d#SnH2UX!5tKaX0Plbk)K&24ee!$uP`|7}NYqV^zf6s&oVuuADJAd8Sp8@F*MIirPIfz&uObsZrnYp1N$}^%I z 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 z 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 diff --git a/libs/di/src/ServiceCollection.ts b/libs/di/src/ServiceCollection.ts index 0784b381..4c0cf780 100644 --- a/libs/di/src/ServiceCollection.ts +++ b/libs/di/src/ServiceCollection.ts @@ -260,7 +260,16 @@ export class ServiceCollection { */ public addSingletonFromSchema< TTargetSchema extends SchemaBuilder, - TFuncSchema extends FunctionSchemaBuilder + TFuncSchema extends FunctionSchemaBuilder< + any, + any, + any, + any, + any, + any, + any, + any + > >( targetSchema: TTargetSchema, funcSchema: TFuncSchema, @@ -295,7 +304,16 @@ export class ServiceCollection { */ public addScopedFromSchema< TTargetSchema extends SchemaBuilder, - TFuncSchema extends FunctionSchemaBuilder + TFuncSchema extends FunctionSchemaBuilder< + any, + any, + any, + any, + any, + any, + any, + any + > >( targetSchema: TTargetSchema, funcSchema: TFuncSchema, @@ -330,7 +348,16 @@ export class ServiceCollection { */ public addTransientFromSchema< TTargetSchema extends SchemaBuilder, - TFuncSchema extends FunctionSchemaBuilder + TFuncSchema extends FunctionSchemaBuilder< + any, + any, + any, + any, + any, + any, + any, + any + > >( targetSchema: TTargetSchema, funcSchema: TFuncSchema, @@ -416,7 +443,16 @@ export class ServiceCollection { #addFromSchema< TTargetSchema extends SchemaBuilder, - TFuncSchema extends FunctionSchemaBuilder + TFuncSchema extends FunctionSchemaBuilder< + any, + any, + any, + any, + any, + any, + any, + any + > >( targetSchema: TTargetSchema, funcSchema: TFuncSchema, @@ -451,7 +487,7 @@ export class ServiceCollection { * Used internally to type-check `addSingletonFromSchema`-style registrations. */ type FuncSchemaParameters< - T extends FunctionSchemaBuilder + T extends FunctionSchemaBuilder > = T extends FunctionSchemaBuilder< any, @@ -459,7 +495,9 @@ type FuncSchemaParameters< any, any, any, - infer TParams extends SchemaBuilder[] + infer TParams extends SchemaBuilder[], + any, + any > ? { [K in keyof TParams]: InferType } : never; diff --git a/libs/di/src/ServiceProvider.ts b/libs/di/src/ServiceProvider.ts index 26b335e0..63816393 100644 --- a/libs/di/src/ServiceProvider.ts +++ b/libs/di/src/ServiceProvider.ts @@ -193,7 +193,16 @@ export class ServiceProvider implements IServiceProvider { * @see {@link FunctionSchemaBuilder.hasReturnType} */ public invoke< - TFuncSchema extends FunctionSchemaBuilder + TFuncSchema extends FunctionSchemaBuilder< + any, + any, + any, + any, + any, + any, + any, + any + > >( funcSchema: TFuncSchema, implementation: InferType diff --git a/libs/di/src/ServiceScope.ts b/libs/di/src/ServiceScope.ts index 87c8b087..d55622eb 100644 --- a/libs/di/src/ServiceScope.ts +++ b/libs/di/src/ServiceScope.ts @@ -305,7 +305,16 @@ export class ScopedServiceProvider implements IServiceProvider { * @see {@link ServiceProvider.invoke} */ public invoke< - TFuncSchema extends FunctionSchemaBuilder + TFuncSchema extends FunctionSchemaBuilder< + any, + any, + any, + any, + any, + any, + any, + any + > >( funcSchema: TFuncSchema, implementation: InferType diff --git a/libs/knex-schema/COMPOSABLE_QUERIES.md b/libs/knex-schema/COMPOSABLE_QUERIES.md deleted file mode 100644 index e86394bb..00000000 --- a/libs/knex-schema/COMPOSABLE_QUERIES.md +++ /dev/null @@ -1,188 +0,0 @@ -# Composable read queries - -These APIs are additive. Existing single-schema selectors, nested eager loading, -legacy aggregate methods, and single-column cursor calls remain available. - -## Typed flat joins - -```ts -import { alias, eq, query } from '@cleverbrush/knex-schema'; - -const task = alias(TaskSchema, 'task'); -const owner = alias(UserSchema, 'owner'); -const rows = await query(knex, task) - .leftJoin(owner, t => eq(t.task.ownerId, t.owner.id)) - .where(t => t.task.projectId, projectId) - .orderBy(t => t.task.id, 'desc') - .select(t => ({ id: t.task.id, ownerName: t.owner.name })); -// ownerName includes null because owner is left-joined. -``` - -Aliases do not mutate schemas. Each source retains default scopes and soft-delete -filters; filtering the right-hand source does not turn a left join into an inner -join. `createQuery(knex)` also accepts aliased schemas. `eq`, `and`, and `or` -compose column-based join conditions. Duplicate aliases are errors. - -Both `and` and `or` accept multiple predicates and can be nested. Each group -becomes a parenthesized SQL expression, preserving the intended precedence: - -```ts -import { alias, and, eq, or, query } from '@cleverbrush/knex-schema'; - -const rows = await query(knex, alias(TaskSchema, 'task')) - .join(alias(UserSchema, 'owner'), t => or( - eq(t.task.ownerId, t.owner.id), - and( - eq(t.task.approverId, t.owner.id), - or( - eq(t.task.teamId, t.owner.teamId), - eq(t.task.creatorId, t.owner.id) - ) - ) - )) - .select(t => ({ id: t.task.id, ownerName: t.owner.name })); -``` - -This example assumes the illustrated ID properties exist on the schemas. -Empty `and()`/`or()` groups are rejected. Predicates describe SQL; they do not -execute a JavaScript callback for each returned row. - -`isSqlIdentifier(value)` is an exported type guard used by `alias()`. It accepts -one ASCII identifier (`task_owner2`), not qualified names (`public.tasks`), quoted -names, whitespace or non-string values. This deliberately conservative format -does not describe every valid PostgreSQL identifier and does not replace Knex -identifier quoting. Existing table/column metadata APIs are not restricted by it. - -The read-only aliased builder requires an explicit, non-empty projection and -supports `where`, `whereIn`, `whereNull`, `whereNotNull`, `orderBy`, `orderByRaw`, -`groupBy`, `having`, `limit`, `offset`, `first`, `execute`, `transacting`, and -awaiting the query. `apply`/`toKnexQuery` remain raw escape hatches whose effects -on result shape/cardinality are the caller's responsibility. Values remain bound -and identifiers quoted. Flat collection joins can repeat parents; they do not -deduplicate or fetch one related row at a time. Choose ORM eager loading for -nested related objects instead. - -For reusable connection/transaction handling, ordinary and aliased schemas retain -the same inference through `createQuery(knex)`, `withTransaction(trx)`, and -`transaction(callback)`. Only ordinary-schema calls accept a custom Knex base -query. These APIs and their JSDoc are also available through `@cleverbrush/orm`. - -## Aggregates with optional output schemas - -```ts -import { aggregate, number } from '@cleverbrush/knex-schema'; - -const count = await query(knex, TaskSchema).countValue(); // number -const total = await query(knex, TaskSchema) - .sumValue(t => t.estimate); // string | null - -const grouped = await query(knex, TaskSchema) - .groupBy(t => t.ownerId) - .select(t => ({ - ownerId: t.ownerId, - count: aggregate.count(), - total: aggregate.sum(t.estimate) - })); - -// Explicit floating-point conversion when appropriate for your domain. -const average = await query(knex, TaskSchema) - .avgValue(t => t.estimate, { - output: number().isFloat().coerce().nullable() - }); // number | null -``` - -| API | Default result | -| --- | --- | -| `countValue(options?)`, `countValue(column, options?)` | Safe number; counts rows or non-null values | -| `countDistinctValue(column, options?)` | Safe number | -| `sumValue(column, options?)`, `avgValue(column, options?)` | Database numeric text, or null | -| `minValue(column, options?)`, `maxValue(column, options?)` | Column's database representation, or null | - -The corresponding `aggregate.count/countDistinct/sum/avg/min/max` expressions -work in ordinary and aliased object projections. Expression options are the -second argument: `aggregate.count(undefined, { output: schema })` customizes -`COUNT(*)`. Aliased `having` also accepts aggregate expressions; its comparisons -use native SQL values, not decoded/text-formatted values. - -Counts reject malformed results and integers outside JavaScript's safe range. -Sum/average preserve PostgreSQL's result as text without changing global driver -parsers. This does not make floating-point source columns exact. Numeric/decimal/ -bigint extrema retain strings; because existing SQL overrides are not fully -represented in schema types, numeric extrema are conservatively typed as -`number | string | null`. Date extrema return `Date | null`. - -An optional **output schema replaces the default decoder**. Its synchronous -`parse` receives the raw driver value, including null, before default conversion. -Its schema output type determines the result, including nullable/optional -modifiers. PostgreSQL counts normally reach it as strings, so a number schema -needs explicit coercion. Validation failures reject the query. Custom parsers -may return bigint/domain decimal types; JSON serialization remains application -code. With custom parsers, the application owns their conversion/precision policy. - -Scalar helpers clone the source, ignore its limit/offset/order, and retain -filters, semantic joins, scopes, and transactions. They reject grouped, HAVING, -distinct, and already aggregated queries; use aggregate projections for those. -An empty scalar count is zero; other empty/all-null aggregates are null. An -empty grouped query returns no rows. Legacy `.count()`, `.sum()`, etc. keep their -existing behavior and signatures. - -## Eager-loading order - -```ts -const tasks = await query(knex, TaskSchema) - .orderBy(t => t.createdAt, 'desc') - .orderBy(t => t.id, 'desc') - .joinMany({ - foreignSchema: NoteSchema, - localColumn: t => t.id, - foreignColumn: t => t.taskId, - as: 'notes' - }) - .limit(20); -``` - -The final SELECT retains parent order, including bound raw ordering expressions. -Limits/offsets select parents, not expanded child rows. Internal fields are -removed from mapped results. Parent ordering, child ordering, and relation -filtering are separate operations. Add a unique tie-breaker for deterministic -ordering of tied parents. - -## Composite cursors - -```ts -const page = await query(knex, TaskSchema) - .where(t => t.projectId, projectId) - .select(t => ({ id: t.id, title: t.title })) - .paginateAfter({ - cursor: previousPage?.nextCursor, - limit: 50, - orderBy: [ - { column: t => t.createdAt, direction: 'desc' }, - { column: t => t.id, direction: 'desc' } - ] - }); -// { data, nextCursor: string | null, hasMore: boolean } -``` - -The opt-in `orderBy` form controls the full sort, replacing earlier ordering. -Mixed directions, projections, and eager loading are supported. Sort fields must -be non-null scalar columns and include a schema-declared primary/unique key. -Required eager relations filter parents before the cursor page limit is applied. -Offsets, flat joins, distinct/grouped/aggregate queries, malformed cursors, and -cursors from a different table/order are rejected. The source builder is not -mutated. The original `column`/`direction` form is unchanged. - -Cursors are versioned opaque strings preserving database timestamp precision -and numeric values without Date/number round-trips. Clients must not parse them. -Reapply access filters on every request and discard cursors when filters change: -they are positions, not authorization. They do not provide snapshot isolation; -sort-key updates can move records across the cursor. Sequential paging does not -support arbitrary page-number jumps; counts remain separate queries. Indexes -and representative query-plan measurements remain application work. - -## Integration verification - -From the repository root, run `npm run test:queries:integration` with -`QUERY_TEST_DATABASE_URL` pointing to a dedicated PostgreSQL test database. -The suite creates/drops only its randomly named fixture tables and fails if the -URL is missing. CI runs PostgreSQL 16 integration tests alongside unit/type tests. diff --git a/libs/knex-schema/READ-SCHEMAS.md b/libs/knex-schema/READ-SCHEMAS.md deleted file mode 100644 index b4e65cc5..00000000 --- a/libs/knex-schema/READ-SCHEMAS.md +++ /dev/null @@ -1,217 +0,0 @@ -# Projection-aware reads and synchronous mapping - -`withRowSchema()` is an **opt-in PostgreSQL read API**. Existing queries and -`getMapper()` retain their existing behavior. Schema-aware queries are immutable, -detached read plans: capture the returned value when adding filters or includes. -They do not track entities, save changes, or run SQL when inspecting metadata. - -## Before and after - -Previously, a projection needed a separately maintained source schema: - -```ts -const Source = object({ id: number(), name: string(), lastSeen: date().nullable() }); -const registry = mapper().configure(Source, PublicUser, m => m - .for(t => t.lastSeen).compute(s => s.lastSeen ?? undefined)); -const toUser = registry.getMapper(Source, PublicUser); -const result = await Promise.all(rows.map(toUser)); -``` - -The query now supplies that schema, and pure mapping needs no promises: - -```ts -const read = db.users.withRowSchema().select(u => ({ - id: u.id, name: u.name, lastSeen: u.lastSeen -})); -const Source = read.rowSchema; -const toUser = mapper().configure(Source, PublicUser, m => m - .for(t => t.lastSeen).compute(s => s.lastSeen ?? undefined)) - .getSyncMapper(Source, PublicUser); -const result = (await read.where(u => u.active, true)).map(toUser); -``` - -Select sensitive fields explicitly. The mapper does not fetch data, authorize -access, enrich rows, or decide how database nulls should appear in public DTOs. - -## Definitions can live in separate files - -```ts -// user-read.ts -import { createQuery, date, number, object, string } from '@cleverbrush/knex-schema'; -import { knex } from './database.js'; - -const UserTable = object({ - id: number().primaryKey(), name: string(), - lastSeen: date().optional().hasColumnName('last_seen'), - secret: string() -}).hasTableName('users'); - -export const userRead = createQuery(knex)(UserTable).withRowSchema() - .select(u => ({ id: u.id, name: u.name, lastSeen: u.lastSeen })); -export const UserRow = userRead.rowSchema; -``` - -```ts -// user-mapping.ts -import { date, number, object, string } from '@cleverbrush/schema'; -import { mapper } from '@cleverbrush/mapper'; -import { UserRow } from './user-read.js'; - -export const PublicUser = object({ - id: number(), name: string(), lastSeen: date().optional() -}); -export const toPublicUser = mapper().configure(UserRow, PublicUser, m => m - .for(t => t.lastSeen).compute(row => row.lastSeen ?? undefined)) - .getSyncMapper(UserRow, PublicUser); -``` - -```ts -// user-service.ts -import { userRead } from './user-read.js'; -import { toPublicUser } from './user-mapping.js'; - -export async function findPublicUser(id: number) { - const row = await userRead.where(u => u.id, id).first(); - return row === undefined ? undefined : toPublicUser(row); -} -``` - -Configure reusable mappings once. `where`, ordering, limits, offsets and -transaction clones retain the same `rowSchema` object. A different projection or -include produces a different schema. Independently created queries do not share -schema identity; the mapper registry keys mappings by schema identity. - -## What values does the schema describe? - -| Stored value | Decoded read value | -| --- | --- | -| Required integer/float | Finite JavaScript `number` | -| `number().bigint()` or `.decimal(p, s)` | Exact `string` | -| Optional or nullable SQL column | Present property containing its value or `null` | -| Date/timestamp | `Date`, including inside JSON relation graphs | -| Missing optional JSON property | Absent property, unlike SQL null | -| Missing optional object relation | `null` | -| Missing collection relation | `[]` | - -Exact numeric fields are cast to text **before** PostgreSQL JSON aggregation and -driver parsing. Converting a rounded JavaScript number to a string is not used. -Use the SQL-type builder methods to declare storage accurately; unknown SQL types -are rejected. A widened dynamic numeric SQL type has a conservative -`number | string` read type. Driver custom parsers must still honor the declared -representation, or decoding fails. - -Timezone-less SQL dates/timestamps are interpreted as UTC in this opt-in mode; -explicit offsets preserve their instant. Native date fields are projected as text -before decoding, so root and nested values do not depend on a driver's local-time -date parser. This is a deliberate opt-in convention, not a change to legacy reads. - -Input defaults, preprocessors and input-only validators are not replayed on stored -rows. Read schemas are structural output schemas. Optional schemas with input -defaults are rejected: `optional().default(...)` hides the storage requirement -in the inferred input/output type. Keep defaults in a separate input schema, -and use an accurately required/optional storage schema for these reads. -JavaScript `Date` has -millisecond precision: use explicit application representations if an API must -expose microseconds. Composite cursor tokens retain native timestamp precision -in private text columns, independently of the public date values. - -## Projections, aliases and aggregates - -```ts -const read = query(knex, alias(UserTable, 'user')).withRowSchema() - .leftJoin(alias(ProfileTable, 'profile'), t => eq(t.user.id, t.profile.userId)) - .select(t => ({ id: t.user.id, displayName: t.profile.displayName })); -// displayName is nullable even if ProfileTable declares it required. -const rows = await read; -read.rowSchema.validate(rows[0]); -``` - -Aliased reads require an explicit selection before execution or accessing -`rowSchema`. Declared named projections use `.projected('name')` on ordinary -readers. Typed aggregates work in object selections: count returns a safe number, -sum/average preserve exact text, and empty extrema/sums remain nullable. An explicit -Framework output schema replaces aggregate decoding and is parsed once; opaque -parser objects without schema introspection are rejected in this mode. - -## Nested graphs - -Declare relations on entities as usual, and return the child query from customizers: - -```ts -const read = db.projects.withRowSchema() - .select(p => ({ id: p.id, name: p.name })) - .include(r => r.tasks, tasks => tasks - .select(t => ({ title: t.title, createdAt: t.createdAt })) - .orderBy(t => t.id, 'desc').limit(3) - .include(r => r.notes, notes => notes.select(n => ({ body: n.body })))); -``` - -This executes one SQL statement. Child scopes, filters, ordering, projections and -limits apply independently per parent. Collections are not lazy-loaded. Required -belongs-to joins filter missing parents; `{ optional: true }` belongs-to and has-one -reads expose nullable objects. `joinOne(spec, customize)` and -`joinMany(spec, customize)` support explicit local/foreign keys without declaring -an entity relation. Use their typed child customizer for ordering/projections; -raw `foreignQuery` and post-load `mappers` cannot supply trustworthy row metadata. - -Numbered `.paginate({ page, pageSize })` performs a count and a page query. -`.paginateAfter({ limit, cursor, orderBy })` on ordinary readers reuses lossless -composite cursors, including unique-key validation. Cursor fields need not be in -the public projection. Reapply authorization filters for every page; a cursor is -not a permission or a transaction snapshot. Grouped/aggregate cursor reads are -rejected. - -## Polymorphic graphs and explicit dispatch - -STI/CTI entities produce a genuine union `rowSchema` and an object schema for each -discriminator in `variantRowSchemas`. All declared branch bodies are selected by -default. Use `selectVariants(['photo'])` to narrow the returned union, or -`forVariant()` to project a branch or load its relations: - -```ts -const read = db.assets.withRowSchema() - .forVariant('photo', q => q.include(r => r.tags)) - .forVariant('text', q => q.select(a => ({ id: a.id, kind: a.kind, body: a.body }))); - -const photoSource = read.variantRowSchemas.photo; -const textSource = read.variantRowSchemas.text; -const registry = mapper() - .configure(photoSource, PublicPhoto, configurePhoto) - .configure(textSource, PublicText, configureText); -const photo = registry.getSyncMapper(photoSource, PublicPhoto); -const text = registry.getSyncMapper(textSource, PublicText); -const result = (await read).map(row => row.kind === 'photo' ? photo(row) : text(row)); -``` - -Keep the original discriminator in branch projections. Framework intentionally -does not choose a public DTO or automatically dispatch a union mapper. Polymorphic -readers also work inside ordinary includes. A missing required CTI body or unknown -discriminator fails decoding. Explicit `allowOrphan: true` makes body fields -nullable. Union ordering/pagination applies to the combined branches, not to each -branch separately. Use `forVariant()` for branch-specific filtering/includes. - -## Boundaries and migration - -- Enter read mode **before** legacy select/include/join, ordering/pagination, - raw callbacks or variant-specific operations. Continue configuration on the - immutable reader. Default scopes may filter rows but must not preselect, - order or paginate them. -- The opt-in surface is deliberately read-only. It is not a replacement for - entity writes or tracked queries, and has no raw SQL shape escape hatch. -- Reads are PostgreSQL-oriented; this does not promise equivalent JSON/CTI SQL - behavior on other Knex dialects. -- Declared graph metadata must match storage. Unsupported opaque shapes throw - rather than pretending an entity schema describes their output. Explicit - TypeScript assertions such as `hasType()` remain the caller's responsibility. -- Existing queries keep their old mutability and driver-value behavior. Migrate - one read at a time; do not replace all application nulls or numeric values - globally. -- `getSyncMapper()` accepts only complete mappings with synchronous final steps - and nested mappings. It never probes callbacks. Known async mappings are - rejected; a disguised thenable throws when invoked. Keep `getMapper()` for - asynchronous work. Fetch/enrich data explicitly before pure mapping. - -Run the mapper-only benchmark with -`npm run bench -- --project benchmarks mapper.bench.ts`. It compares prepared -sync/async functions with identical rows and excludes SQL/network time. Do not -interpret its result as an endpoint-latency guarantee. diff --git a/libs/knex-schema/README.md b/libs/knex-schema/README.md index 75815930..0811875a 100644 --- a/libs/knex-schema/README.md +++ b/libs/knex-schema/README.md @@ -10,24 +10,6 @@ npm install @cleverbrush/knex-schema **Peer dependency:** `knex >= 3.1.0` -## Opt-in projection-aware reads - -Call `.withRowSchema()` before selecting or including fields to get an immutable, -detached PostgreSQL read query. Its `rowSchema` describes the actual decoded -projection, including SQL nulls, nested dates and exact decimal/bigint strings. - -```ts -const read = query(knex, UserSchema).withRowSchema() - .select(u => ({ id: u.id, createdAt: u.createdAt })); -const SourceSchema = read.rowSchema; // metadata only; no SQL -const rows = await read.where(u => u.id, 42); -``` - -Supports typed flat joins/aggregates, declared and explicit nested relations, -named projections, composite cursors and STI/CTI branch schemas. Existing query -behavior is unchanged. See the [consumer guide](./READ-SCHEMAS.md) for multi-file -mapping examples, representation rules, supported operations and migration limits. - ## Quick Start ```typescript @@ -480,9 +462,387 @@ The schema's `hasColumnName()` metadata is used to map `firstName` → `first_na --- +## Composable read queries + +Use aliases for flat results, aggregate expressions for summaries, and composite +cursors for deterministic sequential paging. Nested eager loading returns graphs. + +### Typed flat joins + +```ts +import { alias, eq, query } from '@cleverbrush/knex-schema'; + +const task = alias(TaskSchema, 'task'); +const owner = alias(UserSchema, 'owner'); +const rows = await query(knex, task) + .leftJoin(owner, t => eq(t.task.ownerId, t.owner.id)) + .where(t => t.task.projectId, projectId) + .orderBy(t => t.task.id, 'desc') + .select(t => ({ id: t.task.id, ownerName: t.owner.name })); +// ownerName includes null because owner is left-joined. +``` + +Aliases do not mutate schemas. Each source retains default scopes and soft-delete +filters; filtering the right-hand source does not turn a left join into an inner +join. `createQuery(knex)` also accepts aliased schemas. `eq`, `and`, and `or` +compose column-based join conditions. Duplicate aliases are errors. + +Both `and` and `or` accept multiple predicates and can be nested. Each group +becomes a parenthesized SQL expression, preserving the intended precedence: + +```ts +import { alias, and, eq, or, query } from '@cleverbrush/knex-schema'; + +const rows = await query(knex, alias(TaskSchema, 'task')) + .join(alias(UserSchema, 'owner'), t => or( + eq(t.task.ownerId, t.owner.id), + and( + eq(t.task.approverId, t.owner.id), + or( + eq(t.task.teamId, t.owner.teamId), + eq(t.task.creatorId, t.owner.id) + ) + ) + )) + .select(t => ({ id: t.task.id, ownerName: t.owner.name })); +``` + +This example assumes the illustrated ID properties exist on the schemas. +Empty `and()`/`or()` groups are rejected. Predicates describe SQL; they do not +execute a JavaScript callback for each returned row. + +`isSqlIdentifier(value)` is an exported type guard used by `alias()`. It accepts +one ASCII identifier (`task_owner2`), not qualified names (`public.tasks`), quoted +names, whitespace or non-string values. This deliberately conservative format +does not describe every valid PostgreSQL identifier and does not replace Knex +identifier quoting. Existing table/column metadata APIs are not restricted by it. + +The read-only aliased builder requires an explicit, non-empty projection and +supports `where`, `whereIn`, `whereNull`, `whereNotNull`, `orderBy`, `orderByRaw`, +`groupBy`, `having`, `limit`, `offset`, `first`, `execute`, `transacting`, and +awaiting the query. `apply`/`toKnexQuery` remain raw escape hatches whose effects +on result shape/cardinality are the caller's responsibility. Values remain bound +and identifiers quoted. Flat collection joins can repeat parents; they do not +deduplicate or fetch one related row at a time. Choose ORM eager loading for +nested related objects instead. + +For reusable connection/transaction handling, ordinary and aliased schemas retain +the same inference through `createQuery(knex)`, `withTransaction(trx)`, and +`transaction(callback)`. Only ordinary-schema calls accept a custom Knex base +query. These APIs and their JSDoc are also available through `@cleverbrush/orm`. + +### Aggregates with optional output schemas + +```ts +import { aggregate, number } from '@cleverbrush/knex-schema'; + +const count = await query(knex, TaskSchema).countValue(); // number +const total = await query(knex, TaskSchema) + .sumValue(t => t.estimate); // string | null + +const grouped = await query(knex, TaskSchema) + .groupBy(t => t.ownerId) + .select(t => ({ + ownerId: t.ownerId, + count: aggregate.count(), + total: aggregate.sum(t.estimate) + })); + +// Explicit floating-point conversion when appropriate for your domain. +const average = await query(knex, TaskSchema) + .avgValue(t => t.estimate, { + output: number().isFloat().coerce().nullable() + }); // number | null +``` + +| API | Default result | +| --- | --- | +| `countValue(options?)`, `countValue(column, options?)` | Safe number; counts rows or non-null values | +| `countDistinctValue(column, options?)` | Safe number | +| `sumValue(column, options?)`, `avgValue(column, options?)` | Database numeric text, or null | +| `minValue(column, options?)`, `maxValue(column, options?)` | Column's database representation, or null | + +The corresponding `aggregate.count/countDistinct/sum/avg/min/max` expressions +work in ordinary and aliased object projections. Expression options are the +second argument: `aggregate.count(undefined, { output: schema })` customizes +`COUNT(*)`. Aliased `having` also accepts aggregate expressions; its comparisons +use native SQL values, not decoded/text-formatted values. + +Counts reject malformed results and integers outside JavaScript's safe range. +Sum/average preserve PostgreSQL's result as text without changing global driver +parsers. This does not make floating-point source columns exact. Numeric/decimal/ +bigint extrema retain strings; because existing SQL overrides are not fully +represented in schema types, numeric extrema are conservatively typed as +`number | string | null`. Date extrema return `Date | null`. + +An optional **output schema replaces the default decoder**. Its synchronous +`parse` receives the raw driver value, including null, before default conversion. +Its schema output type determines the result, including nullable/optional +modifiers. PostgreSQL counts normally reach it as strings, so a number schema +needs explicit coercion. Validation failures reject the query. Custom parsers +may return bigint/domain decimal types; JSON serialization remains application +code. With custom parsers, the application owns their conversion/precision policy. + +Scalar helpers clone the source, ignore its limit/offset/order, and retain +filters, semantic joins, scopes, and transactions. They reject grouped, HAVING, +distinct, and already aggregated queries; use aggregate projections for those. +An empty scalar count is zero; other empty/all-null aggregates are null. An +empty grouped query returns no rows. Legacy `.count()`, `.sum()`, etc. keep their +existing behavior and signatures. + +### Eager-loading order + +```ts +const tasks = await query(knex, TaskSchema) + .orderBy(t => t.createdAt, 'desc') + .orderBy(t => t.id, 'desc') + .joinMany({ + foreignSchema: NoteSchema, + localColumn: t => t.id, + foreignColumn: t => t.taskId, + as: 'notes' + }) + .limit(20); +``` + +The final SELECT retains parent order, including bound raw ordering expressions. +Limits/offsets select parents, not expanded child rows. Internal fields are +removed from mapped results. Parent ordering, child ordering, and relation +filtering are separate operations. Add a unique tie-breaker for deterministic +ordering of tied parents. + +### Composite cursors + +```ts +const page = await query(knex, TaskSchema) + .where(t => t.projectId, projectId) + .select(t => ({ id: t.id, title: t.title })) + .paginateAfter({ + cursor: previousPage?.nextCursor, + limit: 50, + orderBy: [ + { column: t => t.createdAt, direction: 'desc' }, + { column: t => t.id, direction: 'desc' } + ] + }); +// { data, nextCursor: string | null, hasMore: boolean } +``` + +The opt-in `orderBy` form controls the full sort, replacing earlier ordering. +Mixed directions, projections, and eager loading are supported. Sort fields must +be non-null scalar columns and include a schema-declared primary/unique key. +Required eager relations filter parents before the cursor page limit is applied. +Offsets, flat joins, distinct/grouped/aggregate queries, malformed cursors, and +cursors from a different table/order are rejected. The source builder is not +mutated. The original `column`/`direction` form is unchanged. + +Cursors are versioned opaque strings preserving database timestamp precision +and numeric values without Date/number round-trips. Clients must not parse them. +Reapply access filters on every request and discard cursors when filters change: +they are positions, not authorization. They do not provide snapshot isolation; +sort-key updates can move records across the cursor. Sequential paging does not +support arbitrary page-number jumps; counts remain separate queries. Indexes +and representative query-plan measurements remain application work. + +### Integration verification + +From the repository root, run `npm run test:queries:integration` with +`QUERY_TEST_DATABASE_URL` pointing to a dedicated PostgreSQL test database. +The suite creates/drops only its randomly named fixture tables and fails if the +URL is missing. CI runs PostgreSQL 16 integration tests alongside unit/type tests. + +## Projection-aware reads + +`withRowSchema()` is an **opt-in PostgreSQL read API**. Schema-aware queries are immutable, +detached read plans: capture the returned value when adding filters or includes. +They do not track entities, save changes, or run SQL when inspecting metadata. + +### Definitions can live in separate files + +```ts +// user-read.ts +import { createQuery, date, number, object, string } from '@cleverbrush/knex-schema'; +import { knex } from './database.js'; + +const UserTable = object({ + id: number().primaryKey(), name: string(), + lastSeen: date().optional().hasColumnName('last_seen'), + secret: string() +}).hasTableName('users'); + +export const userRead = createQuery(knex)(UserTable).withRowSchema() + .select(u => ({ id: u.id, name: u.name, lastSeen: u.lastSeen })); +export const UserRow = userRead.rowSchema; +``` + +```ts +// user-mapping.ts +import { date, number, object, string } from '@cleverbrush/schema'; +import { mapper } from '@cleverbrush/mapper'; +import { UserRow } from './user-read.js'; + +export const PublicUser = object({ + id: number(), name: string(), lastSeen: date().optional() +}); +export const toPublicUser = mapper().configure(UserRow, PublicUser, m => m + .for(t => t.lastSeen).compute(row => row.lastSeen ?? undefined)) + .getSyncMapper(UserRow, PublicUser); +``` + +```ts +// user-service.ts +import { userRead } from './user-read.js'; +import { toPublicUser } from './user-mapping.js'; + +export async function findPublicUser(id: number) { + const row = await userRead.where(u => u.id, id).first(); + return row === undefined ? undefined : toPublicUser(row); +} +``` + +Configure reusable mappings once. `where`, ordering, limits, offsets and +transaction clones retain the same `rowSchema` object. A different projection or +include produces a different schema. Independently created queries do not share +schema identity; the mapper registry keys mappings by schema identity. + +### What values does the schema describe? + +| Stored value | Decoded read value | +| --- | --- | +| Required integer/float | Finite JavaScript `number` | +| `number().bigint()` or `.decimal(p, s)` | Exact `string` | +| Optional or nullable SQL column | Present property containing its value or `null` | +| Date/timestamp | `Date`, including inside JSON relation graphs | +| Missing optional JSON property | Absent property, unlike SQL null | +| Missing optional object relation | `null` | +| Missing collection relation | `[]` | + +Exact numeric fields are cast to text **before** PostgreSQL JSON aggregation and +driver parsing. Converting a rounded JavaScript number to a string is not used. +Use the SQL-type builder methods to declare storage accurately; unknown SQL types +are rejected. A widened dynamic numeric SQL type has a conservative +`number | string` read type. Driver custom parsers must still honor the declared +representation, or decoding fails. + +Timezone-less SQL dates/timestamps are interpreted as UTC in this opt-in mode; +explicit offsets preserve their instant. Native date fields are projected as text +before decoding, so root and nested values do not depend on a driver's local-time +date parser. This is a deliberate opt-in convention, not a change to legacy reads. + +Input defaults, preprocessors and input-only validators are not replayed on stored +rows. Read schemas are structural output schemas. Optional schemas with input +defaults are rejected: `optional().default(...)` hides the storage requirement +in the inferred input/output type. Keep defaults in a separate input schema, +and use an accurately required/optional storage schema for these reads. +JavaScript `Date` has +millisecond precision: use explicit application representations if an API must +expose microseconds. Composite cursor tokens retain native timestamp precision +in private text columns, independently of the public date values. + +### Projections, aliases and aggregates + +```ts +const read = query(knex, alias(UserTable, 'user')).withRowSchema() + .leftJoin(alias(ProfileTable, 'profile'), t => eq(t.user.id, t.profile.userId)) + .select(t => ({ id: t.user.id, displayName: t.profile.displayName })); +// displayName is nullable even if ProfileTable declares it required. +const rows = await read; +read.rowSchema.validate(rows[0]); +``` + +Aliased reads require an explicit selection before execution or accessing +`rowSchema`. Declared named projections use `.projected('name')` on ordinary +readers. Typed aggregates work in object selections: count returns a safe number, +sum/average preserve exact text, and empty extrema/sums remain nullable. An explicit +Framework output schema replaces aggregate decoding and is parsed once; opaque +parser objects without schema introspection are rejected in this mode. + +### Nested graphs + +Declare relations on entities as usual, and return the child query from customizers: + +```ts +const read = db.projects.withRowSchema() + .select(p => ({ id: p.id, name: p.name })) + .include(r => r.tasks, tasks => tasks + .select(t => ({ title: t.title, createdAt: t.createdAt })) + .orderBy(t => t.id, 'desc').limit(3) + .include(r => r.notes, notes => notes.select(n => ({ body: n.body })))); +``` + +This executes one SQL statement. Child scopes, filters, ordering, projections and +limits apply independently per parent. Collections are not lazy-loaded. Required +belongs-to joins filter missing parents; `{ optional: true }` belongs-to and has-one +reads expose nullable objects. `joinOne(spec, customize)` and +`joinMany(spec, customize)` support explicit local/foreign keys without declaring +an entity relation. Use their typed child customizer for ordering/projections; +raw `foreignQuery` and post-load `mappers` cannot supply trustworthy row metadata. + +Numbered `.paginate({ page, pageSize })` performs a count and a page query. +`.paginateAfter({ limit, cursor, orderBy })` on ordinary readers reuses lossless +composite cursors, including unique-key validation. Cursor fields need not be in +the public projection. Reapply authorization filters for every page; a cursor is +not a permission or a transaction snapshot. Grouped/aggregate cursor reads are +rejected. + +### Polymorphic graphs and explicit dispatch + +STI/CTI entities produce a genuine union `rowSchema` and an object schema for each +discriminator in `variantRowSchemas`. All declared branch bodies are selected by +default. Use `selectVariants(['photo'])` to narrow the returned union, or +`forVariant()` to project a branch or load its relations: + +```ts +const read = db.assets.withRowSchema() + .forVariant('photo', q => q.include(r => r.tags)) + .forVariant('text', q => q.select(a => ({ id: a.id, kind: a.kind, body: a.body }))); + +const photoSource = read.variantRowSchemas.photo; +const textSource = read.variantRowSchemas.text; +const registry = mapper() + .configure(photoSource, PublicPhoto, configurePhoto) + .configure(textSource, PublicText, configureText); +const photo = registry.getSyncMapper(photoSource, PublicPhoto); +const text = registry.getSyncMapper(textSource, PublicText); +const result = (await read).map(row => row.kind === 'photo' ? photo(row) : text(row)); +``` + +Keep the original discriminator in branch projections. Framework intentionally +does not choose a public DTO or automatically dispatch a union mapper. Polymorphic +readers also work inside ordinary includes. A missing required CTI body or unknown +discriminator fails decoding. Explicit `allowOrphan: true` makes body fields +nullable. Union ordering/pagination applies to the combined branches, not to each +branch separately. Use `forVariant()` for branch-specific filtering/includes. + +### API boundaries + +- Enter read mode **before** legacy select/include/join, ordering/pagination, + raw callbacks or variant-specific operations. Continue configuration on the + immutable reader. Default scopes may filter rows but must not preselect, + order or paginate them. +- The opt-in surface is deliberately read-only. It is not a replacement for + entity writes or tracked queries, and has no raw SQL shape escape hatch. +- Reads are PostgreSQL-oriented; this does not promise equivalent JSON/CTI SQL + behavior on other Knex dialects. +- Declared graph metadata must match storage. Unsupported opaque shapes throw + rather than pretending an entity schema describes their output. Explicit + TypeScript assertions such as `hasType()` remain the caller's responsibility. +- Ordinary queries are mutable and retain their driver-value behavior. + Read mode is opt-in; it does not change application nulls or numeric values + globally. +- `getSyncMapper()` accepts only complete mappings with synchronous final steps + and nested mappings. It never probes callbacks. Known async mappings are + rejected; a disguised thenable throws when invoked. Keep `getMapper()` for + asynchronous work. Fetch/enrich data explicitly before pure mapping. + +Run the mapper-only benchmark with +`npm run bench -- --project benchmarks mapper.bench.ts`. It compares prepared +sync/async functions with identical rows and excludes SQL/network time. Do not +interpret its result as an endpoint-latency guarantee. + ## API Reference -See [Composable read queries](./COMPOSABLE_QUERIES.md) for typed flat joins with +See [Composable read queries](#composable-read-queries) for typed flat joins with `alias`, all aggregate families with optional output schemas, preserved eager-load ordering, and multi-column cursor pagination. These APIs preserve existing calls and include runtime, type, and PostgreSQL integration coverage. diff --git a/libs/knex-schema/package.json b/libs/knex-schema/package.json index 46c60b9e..d7bb3a5a 100644 --- a/libs/knex-schema/package.json +++ b/libs/knex-schema/package.json @@ -12,9 +12,7 @@ }, "description": "Type-safe schema-driven query builder for Knex using @cleverbrush/schema — strongly typed CRUD, eager loading, and column mapping for PostgreSQL", "files": [ - "dist", - "COMPOSABLE_QUERIES.md", - "READ-SCHEMAS.md" + "dist" ], "homepage": "https://docs.cleverbrush.com/knex-schema", "keywords": [ diff --git a/libs/knex-schema/src/extension.ts b/libs/knex-schema/src/extension.ts index cbd16f47..e5875aac 100644 --- a/libs/knex-schema/src/extension.ts +++ b/libs/knex-schema/src/extension.ts @@ -1,6 +1,4 @@ // @cleverbrush/knex-schema — Schema extension: hasColumnName / hasTableName -export { READ_SQL_TYPE } from './read-storage.js'; - import type { AnySchemaBuilder, ArraySchemaBuilder, @@ -19,6 +17,7 @@ import type { import { arrayExtensions, defineExtension, + defineMetadataMethod, EXTRA_TYPE_BRAND, METHOD_LITERAL_BRAND, NumberSchemaBuilder as NumberSchemaBuilderClass, @@ -57,6 +56,9 @@ export const PRIMARY_KEY_BRAND: unique symbol = Symbol.for( '@cleverbrush/knex-schema:primaryKey' ); +/** @internal Named primary-key result so exported consumer schemas emit portable declarations. */ +export type PrimaryKeyColumn = S & { readonly [PRIMARY_KEY_BRAND]?: true }; + /** * Phantom-type brand placed on an object schema by `.hasPrimaryKey([cols])` * to record the composite primary-key column tuple at the type level. @@ -335,34 +337,19 @@ export const ddlExtension = defineExtension({ return this.withExtension('unique', name ?? true); }, /** Override the SQL column type (e.g. `'bigint'`, `'smallint'`). */ - columnType( - this: NumberSchemaBuilder, - type: string - ) { - return this.withExtension('columnType', type); - }, + columnType: defineMetadataMethod('columnType').argument(), /** Shorthand for `.columnType('bigint')`. */ - bigint(this: NumberSchemaBuilder) { - return this.withExtension('columnType', 'bigint'); - }, + bigint: defineMetadataMethod('columnType').value('bigint'), /** Shorthand for `.columnType('smallint')`. */ - smallint(this: NumberSchemaBuilder) { - return this.withExtension('columnType', 'smallint'); - }, + smallint: defineMetadataMethod('columnType').value('smallint'), /** Shorthand for `.columnType('decimal(p,s)')` — exact numeric. * @param precision - Total digits. * @param scale - Digits after decimal point. */ - decimal( - this: NumberSchemaBuilder, - precision: number, - scale: number - ) { - return this.withExtension( - 'columnType', - `decimal(${precision},${scale})` - ); - }, + decimal: defineMetadataMethod('columnType').compute( + (precision: number, scale: number) => + `decimal(${precision},${scale})` as const + ), /** Set a raw SQL default expression. * @param expression - Raw SQL expression (e.g. `"nextval('my_seq')"`). */ @@ -1216,9 +1203,7 @@ declare module '@cleverbrush/schema' { /** Mark this column as a primary key. * @param opts - Options. `autoIncrement` defaults to `true`. */ - primaryKey(opts?: { autoIncrement?: boolean }): this & { - readonly [PRIMARY_KEY_BRAND]?: true; - }; + primaryKey(opts?: { autoIncrement?: boolean }): PrimaryKeyColumn; } interface StringSchemaBuilder< @@ -1229,9 +1214,7 @@ declare module '@cleverbrush/schema' { TExtensions > { /** Mark this column as a primary key (non-auto-increment). */ - primaryKey(): this & { - readonly [PRIMARY_KEY_BRAND]?: true; - }; + primaryKey(): PrimaryKeyColumn; } interface ObjectSchemaBuilder< diff --git a/libs/knex-schema/src/index.ts b/libs/knex-schema/src/index.ts index f583f211..90904f0b 100644 --- a/libs/knex-schema/src/index.ts +++ b/libs/knex-schema/src/index.ts @@ -52,6 +52,7 @@ export type { } from './expressions.js'; export { aggregate } from './expressions.js'; // Schema extension (hasColumnName / hasTableName + DDL/ORM) +export type { PrimaryKeyColumn } from './extension.js'; export { any, array, @@ -118,8 +119,6 @@ export type { SchemaForValue } from './read-schema.js'; export { ReadSchemaError } from './read-schema.js'; -export type { SqlNumber } from './read-storage.js'; -export { READ_SQL_TYPE } from './read-storage.js'; export type { BoundQuery } from './SchemaQueryBuilder.js'; // Main entry point export { diff --git a/libs/knex-schema/src/read-consumer.test.ts b/libs/knex-schema/src/read-consumer.test.ts new file mode 100644 index 00000000..5cfb3d9f --- /dev/null +++ b/libs/knex-schema/src/read-consumer.test.ts @@ -0,0 +1,166 @@ +import { spawnSync } from 'node:child_process'; +import { + mkdtempSync, + readFileSync, + rmSync, + symlinkSync, + writeFileSync +} from 'node:fs'; +import { tmpdir } from 'node:os'; +import { dirname, join, resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { expect, test } from 'vitest'; + +const repository = resolve(dirname(fileURLToPath(import.meta.url)), '../../..'); + +test('documentation and multi-file metadata consumers compile against published declarations', () => { + const directory = mkdtempSync(join(tmpdir(), 'framework-read-consumer-')); + try { + symlinkSync( + join(repository, 'node_modules'), + join(directory, 'node_modules'), + 'dir' + ); + const write = (name: string, text: string) => + writeFileSync(join(directory, name), text); + write('package.json', JSON.stringify({ type: 'module' })); + const llms = readFileSync( + join(repository, 'websites/docs/public/llms.txt'), + 'utf8' + ); + const queryDocs = readFileSync( + join(repository, 'libs/knex-schema/README.md'), + 'utf8' + ); + const schemaDocs = readFileSync( + join(repository, 'libs/schema/README.md'), + 'utf8' + ); + const namedBlocks = (text: string) => [ + ...text.matchAll( + /```(?:typescript|ts)\n\/\/ ([\w-]+\.ts)\n([\s\S]*?)```/g + ) + ]; + expect(namedBlocks(llms)).toHaveLength(4); + expect(namedBlocks(queryDocs)).toHaveLength(3); + for (const [, name, content] of [ + ...namedBlocks(llms), + ...namedBlocks(queryDocs) + ]) + write(name, content); + const metadataDocs = schemaDocs + .split('### Typed metadata methods\n')[1] + .split('### Stacking Extensions')[0]; + write( + 'metadata-doc.ts', + metadataDocs.match(/```ts\n([\s\S]*?)```/)![1] + ); + write( + 'database.ts', + `import Knex from 'knex'; export const knex = Knex({ client: 'pg' });` + ); + write( + 'storage.ts', + ` +import { number, object, string } from '@cleverbrush/knex-schema'; +import { defineExtension, defineMetadataMethod, withExtensions } from '@cleverbrush/schema'; +export const Account = object({ + id: number().primaryKey().bigint(), + balance: number().decimal(24, 6).optional().hasColumnName('balance_value'), + label: string() +}).hasTableName('accounts') + .projection('summary', 'id', 'label') + .projection('withBalance', a => a.id, a => a.balance); +export const tagged = withExtensions(defineExtension({ + number: { unit: defineMetadataMethod('unit').argument() } +})).number().unit('metres').optional(); +` + ); + write( + 'storage-consumer.ts', + ` +import { type InferExtensionMetadata, type InferType, number } from '@cleverbrush/schema'; +import { query } from '@cleverbrush/knex-schema'; +import { mapper } from '@cleverbrush/mapper'; +import { object, string } from '@cleverbrush/schema'; +import { Account, tagged } from './storage.js'; +import { knex } from './database.js'; +const unit: InferExtensionMetadata['unit'] = 'metres'; +const value: InferType = undefined; +// @ts-expect-error metadata literal must not widen to string +const invalidUnit: InferExtensionMetadata['unit'] = 'seconds'; +// @ts-expect-error importing database libraries cannot install global storage methods +number().bigint(); +export const read = query(knex, Account).withRowSchema().select(a => ({ id: a.id, balance: a.balance })); +const PublicAccount = object({ id: string(), balance: string().nullable() }); +export const convert = mapper().configure(read.rowSchema, PublicAccount, m => m) + .getSyncMapper(read.rowSchema, PublicAccount); +const row: InferType = { id: '9007199254740993', balance: null }; +const dto: { id: string; balance: string | null } = convert(row); +// @ts-expect-error exact numeric storage is text, never a rounded JS number +const invalid: InferType = { id: 1, balance: 2 }; +` + ); + write( + 'function-consumer.ts', + ` +import { ServiceCollection } from '@cleverbrush/di'; +import { func, number, string } from '@cleverbrush/schema'; +const Dependency = string(); +const Result = number(); +const factory = func().addParameter(Dependency).hasReturnType(Result); +const services = new ServiceCollection().addSingleton(Dependency, 'hello'); +services.addSingletonFromSchema(Result, factory, text => text.length); +services.addScopedFromSchema(Result, factory, text => text.length); +services.addTransientFromSchema(Result, factory, text => text.length); +const provider = services.buildServiceProvider(); +export const result: number = provider.invoke(factory, text => text.length); +const scope = provider.createScope(); +export const scoped: number = scope.serviceProvider.invoke(factory, text => text.length); +// @ts-expect-error dependency types must not widen to any +provider.invoke(factory, (value: number) => value); +// @ts-expect-error implementation must honor the declared return schema +provider.invoke(factory, text => text); +// @ts-expect-error schema-based registration retains parameter types +services.addSingletonFromSchema(Result, factory, (value: number) => value); +` + ); + write( + 'tsconfig.json', + JSON.stringify({ + compilerOptions: { + target: 'ES2022', + module: 'ESNext', + moduleResolution: 'bundler', + strict: true, + skipLibCheck: false, + declaration: true, + emitDeclarationOnly: true, + outDir: 'dist', + types: ['node'], + lib: ['ES2022', 'DOM', 'ESNext.Disposable'] + }, + include: ['*.ts'] + }) + ); + const result = spawnSync( + process.execPath, + [ + join(repository, 'node_modules/typescript/lib/tsc.js'), + '-p', + join(directory, 'tsconfig.json') + ], + { encoding: 'utf8', timeout: 60000 } + ); + expect(result.status, `${result.stdout}\n${result.stderr}`).toBe(0); + expect( + readFileSync(join(directory, 'dist/storage.d.ts'), 'utf8') + ).toContain('Account'); + for (const text of [llms, queryDocs]) { + expect(text).not.toContain('READ-SCHEMAS.md'); + expect(text).not.toContain('COMPOSABLE_QUERIES.md'); + } + } finally { + rmSync(directory, { recursive: true, force: true }); + } +}, 90000); diff --git a/libs/knex-schema/src/read-schema.ts b/libs/knex-schema/src/read-schema.ts index 0803b794..a075e2f2 100644 --- a/libs/knex-schema/src/read-schema.ts +++ b/libs/knex-schema/src/read-schema.ts @@ -3,6 +3,7 @@ import { array, boolean, date, + type InferExtensionMetadata, type InferType, number, type ObjectSchemaBuilder, @@ -12,7 +13,6 @@ import { union } from '@cleverbrush/schema'; import type { Knex } from 'knex'; -import { READ_SQL_TYPE } from './read-storage.js'; /** A schema builder accepted by the database-read schema compiler. */ export type ReadSchema = SchemaBuilder; @@ -53,20 +53,21 @@ export type SchemaForValue = 0 extends 1 & T null extends T ? true : false >; -type StorageValue = S extends { - readonly [READ_SQL_TYPE]: infer SQL extends string; -} - ? string extends SQL - ? string | NonNullable> - : Lowercase extends - | 'bigint' - | 'bigserial' - | 'int8' - | `decimal${string}` - | `numeric${string}` - ? string - : NonNullable> - : NonNullable>; +type StorageValue = + InferExtensionMetadata extends { + columnType: infer SQL extends string; + } + ? string extends SQL + ? string | NonNullable> + : Lowercase extends + | 'bigint' + | 'bigserial' + | 'int8' + | `decimal${string}` + | `numeric${string}` + ? string + : NonNullable> + : NonNullable>; /** Database columns are present; optional persisted values are represented by SQL null. */ export type ReadValue = | StorageValue diff --git a/libs/knex-schema/src/read-storage.test-d.ts b/libs/knex-schema/src/read-storage.test-d.ts index c0571fcf..251b5178 100644 --- a/libs/knex-schema/src/read-storage.test-d.ts +++ b/libs/knex-schema/src/read-storage.test-d.ts @@ -1,7 +1,11 @@ -import type { InferType } from '@cleverbrush/schema'; +import { + type InferExtensionMetadata, + type InferType, + number as plainNumber +} from '@cleverbrush/schema'; import { expectTypeOf, test } from 'vitest'; -import { number } from './extension.js'; -import type { READ_SQL_TYPE } from './read-storage.js'; +import { number, type PRIMARY_KEY_BRAND } from './extension.js'; +import type { ReadValue } from './read-schema.js'; test('numeric storage metadata survives schema modifiers', () => { const price = number() @@ -10,8 +14,8 @@ test('numeric storage metadata survives schema modifiers', () => { .hasColumnName('price_value'); expectTypeOf>().toEqualTypeOf(); expectTypeOf< - (typeof price)[typeof READ_SQL_TYPE] - >().toEqualTypeOf<'decimal'>(); + InferExtensionMetadata['columnType'] + >().toEqualTypeOf<`decimal(${number},${number})`>(); const named = number() .hasColumnName('price_value') .decimal(20, 4) @@ -19,11 +23,40 @@ test('numeric storage metadata survives schema modifiers', () => { .index(); expectTypeOf>().toEqualTypeOf(); expectTypeOf< - (typeof named)[typeof READ_SQL_TYPE] - >().toEqualTypeOf<'decimal'>(); + InferExtensionMetadata['columnType'] + >().toEqualTypeOf<`decimal(${number},${number})`>(); const overridden = named.columnType('integer').required().notNullable(); expectTypeOf< - (typeof overridden)[typeof READ_SQL_TYPE] + InferExtensionMetadata['columnType'] >().toEqualTypeOf<'integer'>(); expectTypeOf>().toEqualTypeOf(); }); + +test('storage inference retains precision, dynamic types and other brands', () => { + const id = number().primaryKey().bigint().optional().hasColumnName('key'); + expectTypeOf>().toEqualTypeOf(); + expectTypeOf< + NonNullable<(typeof id)[typeof PRIMARY_KEY_BRAND]> + >().toEqualTypeOf(); + const small = id.smallint().required(); + expectTypeOf>().toEqualTypeOf(); + const exact = small.columnType('NUMERIC(24,6)').nullable().index(); + expectTypeOf>().toEqualTypeOf(); + const dynamic = (type: string) => number().columnType(type).optional(); + expectTypeOf>>().toEqualTypeOf< + number | string | null + >(); + // @ts-expect-error storage types must be strings + number().columnType(5); +}); + +test('database methods do not augment plain schema numbers', () => { + // @ts-expect-error database storage methods require the database factory + plainNumber().bigint(); + // @ts-expect-error database storage methods require the database factory + plainNumber().decimal(10, 2); + // @ts-expect-error database storage methods require the database factory + plainNumber().columnType('integer'); + // @ts-expect-error database storage methods require the database factory + plainNumber().smallint(); +}); diff --git a/libs/knex-schema/src/read-storage.test.ts b/libs/knex-schema/src/read-storage.test.ts new file mode 100644 index 00000000..c97559bc --- /dev/null +++ b/libs/knex-schema/src/read-storage.test.ts @@ -0,0 +1,25 @@ +import { number as plainNumber } from '@cleverbrush/schema'; +import { expect, test } from 'vitest'; +import { number } from './extension.js'; +import { compileReadSchema } from './read-schema.js'; + +test('native storage metadata is immutable and does not install global methods', () => { + const initial = number().decimal(24, 6).optional().hasColumnName('amount'); + const changed = initial.columnType('integer').required().index(); + expect(initial.introspect().extensions).toMatchObject({ + columnType: 'decimal(24,6)', + columnName: 'amount' + }); + expect(changed.introspect().extensions).toMatchObject({ + columnType: 'integer', + columnName: 'amount', + index: true + }); + expect( + compileReadSchema(initial).decode('123456789012345678.123456', 'amount') + ).toBe('123456789012345678.123456'); + expect(compileReadSchema(changed).decode(42, 'amount')).toBe(42); + for (const method of ['columnType', 'bigint', 'smallint', 'decimal']) { + expect(method in plainNumber()).toBe(false); + } +}); diff --git a/libs/knex-schema/src/read-storage.ts b/libs/knex-schema/src/read-storage.ts deleted file mode 100644 index 96a22a23..00000000 --- a/libs/knex-schema/src/read-storage.ts +++ /dev/null @@ -1,105 +0,0 @@ -import { NumberSchemaBuilder } from '@cleverbrush/schema'; - -/** SQL storage type retained by numeric column builders for schema-aware reads. */ -export const READ_SQL_TYPE: unique symbol = Symbol.for( - '@cleverbrush/knex-schema:read-sql-type' -); - -type Preserved = { - [K in Exclude< - keyof E, - typeof READ_SQL_TYPE | 'columnType' | 'bigint' | 'smallint' | 'decimal' - >]: E[K] extends (...args: infer A) => any - ? (this: S, ...args: A) => S - : E[K]; -} & { readonly [READ_SQL_TYPE]: SQL }; - -/** A numeric validation schema whose SQL representation survives ordinary modifiers. */ -export type SqlNumber< - T, - R extends boolean, - N extends boolean, - D extends boolean, - E, - SQL extends string -> = NumberSchemaBuilder> & Preserved; - -declare module '@cleverbrush/schema' { - interface NumberSchemaBuilder< - TResult, - TRequired extends boolean, - TNullable extends boolean, - THasDefault extends boolean, - TExtensions - > { - /** Set a SQL storage type; schema-aware reads retain its representation. */ - columnType( - type: SQL - ): SqlNumber< - TResult, - TRequired, - TNullable, - THasDefault, - TExtensions, - SQL - >; - /** Set bigint storage; schema-aware reads return exact strings. */ - bigint(): SqlNumber< - TResult, - TRequired, - TNullable, - THasDefault, - TExtensions, - 'bigint' - >; - /** Set smallint storage; schema-aware reads return numbers. */ - smallint(): SqlNumber< - TResult, - TRequired, - TNullable, - THasDefault, - TExtensions, - 'smallint' - >; - /** Set decimal storage; schema-aware reads return exact strings. */ - decimal( - precision: number, - scale: number - ): SqlNumber< - TResult, - TRequired, - TNullable, - THasDefault, - TExtensions, - 'decimal' - >; - } -} - -// Match the declaration augmentation for base-schema factories too, just as the -// package's primary-key augmentation does. Every method still returns a clone. -const prototype = NumberSchemaBuilder.prototype as any; -const methods = { - columnType(this: NumberSchemaBuilder, type: string) { - return this.withExtension('columnType', type); - }, - bigint(this: NumberSchemaBuilder) { - return this.withExtension('columnType', 'bigint'); - }, - smallint(this: NumberSchemaBuilder) { - return this.withExtension('columnType', 'smallint'); - }, - decimal(this: NumberSchemaBuilder, precision: number, scale: number) { - return this.withExtension( - 'columnType', - `decimal(${precision},${scale})` - ); - } -}; -for (const [name, method] of Object.entries(methods)) - if (typeof prototype[name] !== 'function') - Object.defineProperty(prototype, name, { - value: method, - configurable: true, - writable: true - }); diff --git a/libs/knex-schema/src/unit.test.ts b/libs/knex-schema/src/unit.test.ts index 70ece32b..18a70a4e 100644 --- a/libs/knex-schema/src/unit.test.ts +++ b/libs/knex-schema/src/unit.test.ts @@ -104,12 +104,12 @@ describe('schema extension', () => { it('hasColumnName survives .optional() chaining', () => { const schema = string().hasColumnName('col_name').optional(); - expect(schema.getExtension('columnName')).toBe('col_name'); + expect(schema.introspect().extensions.columnName).toBe('col_name'); }); it('hasColumnName survives .required() chaining', () => { const schema = number().hasColumnName('col_a').optional().required(); - expect(schema.getExtension('columnName')).toBe('col_a'); + expect(schema.introspect().extensions.columnName).toBe('col_a'); }); it('hasTableName survives .optional()/.required() chaining', () => { @@ -117,7 +117,7 @@ describe('schema extension', () => { .hasTableName('my_table') .optional() .required(); - expect(schema.getExtension('tableName')).toBe('my_table'); + expect(schema.introspect().extensions.tableName).toBe('my_table'); }); }); diff --git a/libs/mapper/README.md b/libs/mapper/README.md index e1c6a6c2..4f0a7a5a 100644 --- a/libs/mapper/README.md +++ b/libs/mapper/README.md @@ -40,32 +40,6 @@ npm install @cleverbrush/mapper **Peer dependency:** `@cleverbrush/schema` -## Synchronous mapping - -Use the same `configure()` API and retrieve a synchronous mapper when every final -step and nested mapping is synchronous: - -```ts -const registry = mapper().configure(Source, Target, m => m - .for(t => t.label).compute(s => s.name.toUpperCase())); -const toTarget = registry.getSyncMapper(Source, Target); -const results = rows.map(toTarget); // ordinary values, not promises -``` - -Completeness checking, `.from()`, ignores, nested objects/arrays and compatible -auto-mapping still apply. Async computations or nested async mappings reject -`getSyncMapper()` at compile time; runtime guards cover JavaScript and unsafe -casts too. Callbacks are never probed during configuration. A function falsely -typed as synchronous that returns a promise/thenable throws when invoked. -`getMapper()` still always returns an async function. There is no separate -`configureSync()` API. - -Configure once and reuse the same source/target schema instances. Queries can -provide their projection schema through `.withRowSchema().rowSchema`; see the -[projection-aware read guide](../knex-schema/READ-SCHEMAS.md), including separate -definition/mapping/service files and explicit polymorphic dispatch. The mapper -performs no database calls or application enrichment. - ## Quick Start ```typescript @@ -112,7 +86,7 @@ const dto = await mapFn({ 1. **Define schemas** — use `@cleverbrush/schema` to define source and target shapes 2. **Configure mappings** — use `.for()` to select a target property, then `.from()`, `.compute()`, or `.ignore()` to define how it's populated 3. **Auto-mapping fills the gaps** — properties with the same name and compatible type are mapped automatically -4. **Get a mapper function** — `registry.getMapper(from, to)` returns an async function that transforms objects +4. **Get a mapper function** — use `getMapper(from, to)` for an async function or `getSyncMapper(from, to)` when all steps are synchronous 5. **TypeScript enforces completeness** — if any target property is unmapped, you get a compile-time error ## Compile-Time Safety @@ -251,6 +225,32 @@ Every non-auto-mappable target property must be either mapped or explicitly igno - A **compile-time TypeScript type error** — a type-assignability mismatch that includes the unmapped property names in the type parameters - A **runtime `MapperConfigurationError`** if type checks are bypassed +## Synchronous mapping + +Use the same `configure()` API and retrieve a synchronous mapper when every final +step and nested mapping is synchronous: + +```ts +const registry = mapper().configure(Source, Target, m => m + .for(t => t.label).compute(s => s.name.toUpperCase())); +const toTarget = registry.getSyncMapper(Source, Target); +const results = rows.map(toTarget); // ordinary values, not promises +``` + +Completeness checking, `.from()`, ignores, nested objects/arrays and compatible +auto-mapping still apply. Async computations or nested async mappings reject +`getSyncMapper()` at compile time; runtime guards cover JavaScript and unsafe +casts too. Callbacks are never probed during configuration. A function falsely +typed as synchronous that returns a promise/thenable throws when invoked. +`getMapper()` still always returns an async function. There is no separate +`configureSync()` API. + +Configure once and reuse the same source/target schema instances. Queries can +provide their projection schema through `.withRowSchema().rowSchema`; see the +[projection-aware read guide](../knex-schema/README.md#projection-aware-reads), including separate +definition/mapping/service files and explicit polymorphic dispatch. The mapper +performs no database calls or application enrichment. + ## API ### `mapper()` @@ -278,6 +278,13 @@ const mapFn = registry.getMapper(ApiUser, DomainUser); const result = await mapFn(sourceObject); ``` +### `registry.getSyncMapper(fromSchema, toSchema)` + +Retrieves an ordinary function for a complete, synchronous mapping. It returns +the target value directly and can be passed to `rows.map(...)`. Async final steps +or nested async mappings are rejected. See [Synchronous mapping](#synchronous-mapping) +for runtime guards and schema identity requirements. + ### `Mapper` A fluent builder for configuring how each target property is populated: diff --git a/libs/orm/README.md b/libs/orm/README.md index d4ec01cf..5d78ac10 100644 --- a/libs/orm/README.md +++ b/libs/orm/README.md @@ -21,29 +21,6 @@ npm install @cleverbrush/orm `knex` is a peer dependency (install it alongside `@cleverbrush/orm`). `@cleverbrush/knex-schema` is a direct dependency and is installed automatically. -## Detached reads with result schemas - -`db.users.withRowSchema()` enters an immutable read-only API whose `rowSchema` -matches its decoded selection and includes. Results remain **detached even when -the context uses `{ tracking: true }`**. This avoids attaching partial projections -as incomplete tracked entities. Ordinary entity queries keep their old behavior. - -```ts -const read = db.users.withRowSchema() - .select(u => ({ id: u.id, name: u.name })); -const Source = read.rowSchema; -const toDto = mapper().configure(Source, UserDto, m => m) - .getSyncMapper(Source, UserDto); -const users = (await read).map(toDto); -``` - -Typed relation customizers return their configured query; nested graphs are -decoded in one SQL statement. STI/CTI readers expose `variantRowSchemas` for -explicit application mapping. See the [read-schema consumer guide](../knex-schema/READ-SCHEMAS.md) -for numeric/null/date rules, examples and compatibility boundaries. - ---- - ## Quick start ### 1. Define a schema and entity @@ -103,6 +80,7 @@ const updated = await db.users.save({ id: 1, email: 'alice@example.com', name: ' | `.include(t => t.rel)` | Eager-loads a relation (chainable) | | `.save(graph)` | Insert or update a row graph (transactional) | | `.ofVariant(key)` | Return a typed `VariantDbSet` scoped to a polymorphic variant | +| `.withRowSchema()` | Creates a detached read-only query with a matching result schema | | `.query()` | Returns the underlying `EntityQuery` for advanced querying | | `.withTransaction(trx)` | Returns a new `DbSet` bound to an existing transaction | @@ -233,6 +211,29 @@ async function updateUser(userId: number) { --- +## Detached reads with result schemas + +`db.users.withRowSchema()` enters an immutable read-only API whose `rowSchema` +matches its decoded selection and includes. Results remain **detached even when +the context uses `{ tracking: true }`**. This avoids attaching partial projections +as incomplete tracked entities. Ordinary entity queries keep their old behavior. + +```ts +const read = db.users.withRowSchema() + .select(u => ({ id: u.id, name: u.name })); +const Source = read.rowSchema; +const toDto = mapper().configure(Source, UserDto, m => m) + .getSyncMapper(Source, UserDto); +const users = (await read).map(toDto); +``` + +Typed relation customizers return their configured query; nested graphs are +decoded in one SQL statement. STI/CTI readers expose `variantRowSchemas` for +explicit application mapping. See the [read-schema consumer guide](../knex-schema/README.md#projection-aware-reads) +for numeric/null/date rules, examples and compatibility boundaries. + +--- + ## Polymorphic entities (STI / CTI) ### Single-Table Inheritance (STI) @@ -392,7 +393,7 @@ schema, including variant queries when the relation schema is known. `paginateAfter({ limit, cursor, orderBy: [...] })` supports non-null scalar sorts with a declared unique tie-breaker; single-column cursor calls are unchanged. -See the [complete query guide](../knex-schema/COMPOSABLE_QUERIES.md) for defaults, +See the [complete query guide](../knex-schema/README.md#composable-read-queries) for defaults, precision policy, grouped aggregates, cursor restrictions, and migration examples. ## Related packages diff --git a/libs/schema/README.md b/libs/schema/README.md index e8c5cf37..36bf1af8 100644 --- a/libs/schema/README.md +++ b/libs/schema/README.md @@ -1565,6 +1565,55 @@ console.log(priceSchema.introspect().extensions.currency); // { maxDecimals: 4 } — structured metadata, not the raw args ``` +### Typed metadata methods + +Use `defineMetadataMethod()` when a method only records metadata and its value +must also be available to TypeScript consumers. It works inside the same +`defineExtension()` / `withExtensions()` system: + +```ts +import { + defineExtension, defineMetadataMethod, withExtensions, + type InferExtensionMetadata, type InferType +} from '@cleverbrush/schema'; + +const labels = defineExtension({ + string: { + label: defineMetadataMethod('label').argument(), + internal: defineMetadataMethod('visibility').value('internal'), + lengthHint: defineMetadataMethod('lengthHint').compute( + (min: number, max: number) => ({ min, max }) + ) + } +}); +const s = withExtensions(labels); +const title = s.string().label('Title').internal().optional(); +type Value = InferType; // string | undefined +type Label = InferExtensionMetadata['label']; // 'Title' + +const renamed = title.label('Display name').lengthHint(1, 80); +type UpdatedLabel = InferExtensionMetadata['label']; // 'Display name' +renamed.introspect().extensions.lengthHint; // { min: 1, max: 80 } +title.introspect().extensions.label; // 'Title' — original is unchanged +``` + +- `.argument()` creates a one-argument method constrained to `T` and retains + the caller's literal type. Omit `T` to accept any metadata value. +- `.value(value)` creates a zero-argument method storing a fixed value. +- `.compute(fn)` retains the callback's parameter and return types. Use a literal + or template-literal return type when that precision matters; arbitrary callback + results cannot be evaluated by TypeScript. + +The key passed to `defineMetadataMethod` controls runtime storage independently +of the method name. A subsequent write replaces that key's value and inferred +type. Metadata and ordinary extension methods compose through native modifiers +without resetting optionality, nullability or defaults. Only factories produced +by `withExtensions()` receive the methods; global builder prototypes are not +modified. Metadata is descriptive: these helpers do not add validators, transform +schema values or assign domain meaning to keys. Consumers decide how to use it. +Ordinary `defineExtension()` methods remain appropriate for validation and other +behavior; use `this.withExtension()` inside them for runtime-only metadata. + ### Stacking Extensions Multiple extensions can be stacked — their methods are merged per builder type. A runtime error is thrown if two extensions define the same method name on the same builder type: diff --git a/libs/schema/src/builders/AnySchemaBuilder.ts b/libs/schema/src/builders/AnySchemaBuilder.ts index 451a85c1..85341c0c 100644 --- a/libs/schema/src/builders/AnySchemaBuilder.ts +++ b/libs/schema/src/builders/AnySchemaBuilder.ts @@ -41,6 +41,16 @@ export class AnySchemaBuilder< THasDefault, TExtensions > { + /** Native type parameters for extension rebinding; never emitted at runtime. @internal */ + declare readonly __cleverbrush_builder_type__: readonly [ + 'any', + TRequired, + TNullable, + TExplicitType, + THasDefault, + TResult + ]; + /** * @hidden */ diff --git a/libs/schema/src/builders/ArraySchemaBuilder.ts b/libs/schema/src/builders/ArraySchemaBuilder.ts index 2d41dba6..0cca75e6 100644 --- a/libs/schema/src/builders/ArraySchemaBuilder.ts +++ b/libs/schema/src/builders/ArraySchemaBuilder.ts @@ -112,6 +112,17 @@ export class ArraySchemaBuilder< THasDefault, TExtensions > { + /** Native type parameters for extension rebinding; never emitted at runtime. @internal */ + declare readonly __cleverbrush_builder_type__: readonly [ + 'array', + TElementSchema, + TRequired, + TNullable, + TExplicitType, + THasDefault, + TResult + ]; + #minLength?: number; #defaultMinLengthErrorMessageProvider: ValidationErrorMessageProvider< ArraySchemaBuilder diff --git a/libs/schema/src/builders/BooleanSchemaBuilder.ts b/libs/schema/src/builders/BooleanSchemaBuilder.ts index 2a3815f4..6b9a83d2 100644 --- a/libs/schema/src/builders/BooleanSchemaBuilder.ts +++ b/libs/schema/src/builders/BooleanSchemaBuilder.ts @@ -55,6 +55,17 @@ export class BooleanSchemaBuilder< THasDefault, TExtensions > { + /** Native type parameters for extension rebinding; never emitted at runtime. @internal */ + declare readonly __cleverbrush_builder_type__: readonly [ + 'boolean', + TResult, + TRequired, + TNullable, + TExplicitType, + THasDefault, + TFinalResult + ]; + #equalsTo?: boolean; #defaultEqualsToErrorMessageProvider: ValidationErrorMessageProvider< BooleanSchemaBuilder diff --git a/libs/schema/src/builders/DateSchemaBuilder.ts b/libs/schema/src/builders/DateSchemaBuilder.ts index 161efd5d..006eb8d7 100644 --- a/libs/schema/src/builders/DateSchemaBuilder.ts +++ b/libs/schema/src/builders/DateSchemaBuilder.ts @@ -86,6 +86,15 @@ export class DateSchemaBuilder< THasDefault, TExtensions > { + /** Native type parameters for extension rebinding; never emitted at runtime. @internal */ + declare readonly __cleverbrush_builder_type__: readonly [ + 'date', + TResult, + TRequired, + TNullable, + THasDefault + ]; + #min?: Date; #defaultMinErrorMessageProvider: ValidationErrorMessageProvider< DateSchemaBuilder diff --git a/libs/schema/src/builders/FunctionSchemaBuilder.ts b/libs/schema/src/builders/FunctionSchemaBuilder.ts index b8aa381b..31d85da2 100644 --- a/libs/schema/src/builders/FunctionSchemaBuilder.ts +++ b/libs/schema/src/builders/FunctionSchemaBuilder.ts @@ -87,6 +87,18 @@ export class FunctionSchemaBuilder< THasDefault, TExtensions > { + /** Native type parameters for extension rebinding; never emitted at runtime. @internal */ + declare readonly __cleverbrush_builder_type__: readonly [ + 'func', + TRequired, + TNullable, + TExplicitType, + THasDefault, + TParameters, + TReturnTypeSchema, + TResult + ]; + #parameters: SchemaBuilder[] = []; #returnType?: SchemaBuilder; diff --git a/libs/schema/src/builders/GenericSchemaBuilder.ts b/libs/schema/src/builders/GenericSchemaBuilder.ts index 54dd9566..4e6b40e2 100644 --- a/libs/schema/src/builders/GenericSchemaBuilder.ts +++ b/libs/schema/src/builders/GenericSchemaBuilder.ts @@ -113,6 +113,17 @@ export class GenericSchemaBuilder< THasDefault, TExtensions > { + /** Native type parameters for extension rebinding; never emitted at runtime. @internal */ + declare readonly __cleverbrush_builder_type__: readonly [ + 'generic', + TFn, + TRequired, + TNullable, + TExplicitType, + THasDefault, + TResult + ]; + #templateFn?: (...args: any[]) => SchemaBuilder; #defaults?: readonly any[]; #cachedDefaultSchema?: SchemaBuilder; diff --git a/libs/schema/src/builders/NumberSchemaBuilder.ts b/libs/schema/src/builders/NumberSchemaBuilder.ts index 951dc148..d15d4b22 100644 --- a/libs/schema/src/builders/NumberSchemaBuilder.ts +++ b/libs/schema/src/builders/NumberSchemaBuilder.ts @@ -63,6 +63,15 @@ export class NumberSchemaBuilder< THasDefault, TExtensions > { + /** Native type parameters for extension rebinding; never emitted at runtime. @internal */ + declare readonly __cleverbrush_builder_type__: readonly [ + 'number', + TResult, + TRequired, + TNullable, + THasDefault + ]; + #min?: number; #defaultMinErrorMessageProvider: ValidationErrorMessageProvider< NumberSchemaBuilder diff --git a/libs/schema/src/builders/ObjectSchemaBuilder.ts b/libs/schema/src/builders/ObjectSchemaBuilder.ts index a21c58a8..3be56a3c 100644 --- a/libs/schema/src/builders/ObjectSchemaBuilder.ts +++ b/libs/schema/src/builders/ObjectSchemaBuilder.ts @@ -378,6 +378,17 @@ export class ObjectSchemaBuilder< THasDefault, TExtensions > { + /** Native type parameters for extension rebinding; never emitted at runtime. @internal */ + declare readonly __cleverbrush_builder_type__: readonly [ + 'object', + TProperties, + TRequired, + TNullable, + TExplicitType, + THasDefault, + TConstructorSchemas + ]; + #properties: TProperties = {} as any; #acceptUnknownProps = false; #propKeys: string[] = []; diff --git a/libs/schema/src/builders/PromiseSchemaBuilder.ts b/libs/schema/src/builders/PromiseSchemaBuilder.ts index b1c2f594..61da354d 100644 --- a/libs/schema/src/builders/PromiseSchemaBuilder.ts +++ b/libs/schema/src/builders/PromiseSchemaBuilder.ts @@ -73,6 +73,17 @@ export class PromiseSchemaBuilder< THasDefault, TExtensions > { + /** Native type parameters for extension rebinding; never emitted at runtime. @internal */ + declare readonly __cleverbrush_builder_type__: readonly [ + 'promise', + TRequired, + TNullable, + TExplicitType, + THasDefault, + TResolvedTypeSchema, + TResult + ]; + #resolvedType?: SchemaBuilder; /** diff --git a/libs/schema/src/builders/RecordSchemaBuilder.ts b/libs/schema/src/builders/RecordSchemaBuilder.ts index 18c6ac3b..ab865908 100644 --- a/libs/schema/src/builders/RecordSchemaBuilder.ts +++ b/libs/schema/src/builders/RecordSchemaBuilder.ts @@ -243,6 +243,18 @@ export class RecordSchemaBuilder< THasDefault, TExtensions > { + /** Native type parameters for extension rebinding; never emitted at runtime. @internal */ + declare readonly __cleverbrush_builder_type__: readonly [ + 'record', + TKeySchema, + TValueSchema, + TRequired, + TNullable, + TExplicitType, + THasDefault, + TResult + ]; + #keySchema!: TKeySchema; #valueSchema!: TValueSchema; diff --git a/libs/schema/src/builders/StringSchemaBuilder.ts b/libs/schema/src/builders/StringSchemaBuilder.ts index 5323b96c..166b9406 100644 --- a/libs/schema/src/builders/StringSchemaBuilder.ts +++ b/libs/schema/src/builders/StringSchemaBuilder.ts @@ -80,6 +80,15 @@ export class StringSchemaBuilder< THasDefault, TExtensions > { + /** Native type parameters for extension rebinding; never emitted at runtime. @internal */ + declare readonly __cleverbrush_builder_type__: readonly [ + 'string', + TResult, + TRequired, + TNullable, + THasDefault + ]; + #minLength?: number; #defaultMinLengthErrorMessageProvider: ValidationErrorMessageProvider< StringSchemaBuilder diff --git a/libs/schema/src/builders/TupleSchemaBuilder.ts b/libs/schema/src/builders/TupleSchemaBuilder.ts index 9f95b748..0fb1c9d1 100644 --- a/libs/schema/src/builders/TupleSchemaBuilder.ts +++ b/libs/schema/src/builders/TupleSchemaBuilder.ts @@ -162,6 +162,18 @@ export class TupleSchemaBuilder< THasDefault, TExtensions > { + /** Native type parameters for extension rebinding; never emitted at runtime. @internal */ + declare readonly __cleverbrush_builder_type__: readonly [ + 'tuple', + TElements, + TRequired, + TNullable, + TExplicitType, + THasDefault, + TRestSchema, + TResult + ]; + #elements!: TElements; #restSchema: | (TRestSchema & SchemaBuilder) diff --git a/libs/schema/src/builders/UnionSchemaBuilder.ts b/libs/schema/src/builders/UnionSchemaBuilder.ts index 2aaf8e4b..ede1d90e 100644 --- a/libs/schema/src/builders/UnionSchemaBuilder.ts +++ b/libs/schema/src/builders/UnionSchemaBuilder.ts @@ -174,6 +174,16 @@ export class UnionSchemaBuilder< THasDefault, TExtensions > { + /** Native type parameters for extension rebinding; never emitted at runtime. @internal */ + declare readonly __cleverbrush_builder_type__: readonly [ + 'union', + TOptions, + TRequired, + TNullable, + TExplicitType, + THasDefault + ]; + #options!: TOptions; #discriminatorKey: string | null = null; #discriminatorMap: Map< diff --git a/libs/schema/src/core.ts b/libs/schema/src/core.ts index 8a8d60f7..c177c919 100644 --- a/libs/schema/src/core.ts +++ b/libs/schema/src/core.ts @@ -87,13 +87,21 @@ export type { CleanExtended, ExtensionConfig, ExtensionDescriptor, + ExtraProperties, ExtraTypeBrandSymbol, FixedMethods, HiddenExtensionMethods, + InferExtensionMetadata, + MetadataExtended, + MetadataMethod, + MetadataMethodBuilder, + MetadataMethods, + MetadataState, MethodLiteralBrandSymbol } from './extension.js'; export { defineExtension, + defineMetadataMethod, EXTRA_TYPE_BRAND, METHOD_LITERAL_BRAND, withExtensions diff --git a/libs/schema/src/extension.ts b/libs/schema/src/extension.ts index 9569434c..ba53cf5a 100644 --- a/libs/schema/src/extension.ts +++ b/libs/schema/src/extension.ts @@ -91,6 +91,19 @@ import type { import { StringSchemaBuilder, string } from './builders/StringSchemaBuilder.js'; import { TupleSchemaBuilder, tuple } from './builders/TupleSchemaBuilder.js'; import { UnionSchemaBuilder, union } from './builders/UnionSchemaBuilder.js'; +import type { MetadataExtended } from './metadata-extension.js'; +import { isMetadataMethod } from './metadata-extension.js'; + +export type { + ExtraProperties, + InferExtensionMetadata, + MetadataExtended, + MetadataMethod, + MetadataMethodBuilder, + MetadataMethods, + MetadataState +} from './metadata-extension.js'; +export { defineMetadataMethod } from './metadata-extension.js'; // --------------------------------------------------------------------------- // Builder type name mapping @@ -432,9 +445,7 @@ export type FixedMethods< * `withExtension` / `getExtension` overridden to `never` so they * don't appear as callable in consumer code. */ -export type CleanExtended = TBuilder & - FixedMethods & - HiddenExtensionMethods; +export type CleanExtended = MetadataExtended; // -- Factory types that return builders with corrected extension methods ------ @@ -747,6 +758,10 @@ export function defineExtension( `Extension method "${builderName}.${methodName}" must be a function` ); } + if (isMetadataMethod(origMethod)) { + wrappedConfig[builderName][methodName] = origMethod; + continue; + } // Wrap the method to auto-infer extension key if not already set wrappedConfig[builderName][methodName] = function ( this: any, diff --git a/libs/schema/src/metadata-extension.test-d.ts b/libs/schema/src/metadata-extension.test-d.ts new file mode 100644 index 00000000..34c569f2 --- /dev/null +++ b/libs/schema/src/metadata-extension.test-d.ts @@ -0,0 +1,210 @@ +import { expectTypeOf, test } from 'vitest'; +import { + defineExtension, + defineMetadataMethod, + EXTRA_TYPE_BRAND, + type InferExtensionMetadata, + METHOD_LITERAL_BRAND, + withExtensions +} from './extension.js'; +import { + type DateSchemaBuilder, + type InferType, + type NumberSchemaBuilder, + number, + type ObjectSchemaBuilder, + type object, + string +} from './index.js'; + +const tagged = defineExtension({ + number: { + unit: defineMetadataMethod('unit').argument(), + metres: defineMetadataMethod('unit').value('m'), + rangeHint: defineMetadataMethod('range').compute( + (min: number, max: number) => [min, max] as const + ), + positive(this: NumberSchemaBuilder) { + return this.min(0); + } + }, + string: { label: defineMetadataMethod('label').argument() }, + object: { tag: defineMetadataMethod('tag').argument() } +}); + +test('ordinary extensions retain receiver types even without typed metadata methods', () => { + const labels = defineExtension({ + date: { + label( + this: DateSchemaBuilder, + text: string + ) { + return this.withExtension('label', text); + } + } + }); + const value = withExtensions(labels) + .date() + .optional() + .label('Updated') + .nullable(); + expectTypeOf>().toEqualTypeOf< + Date | undefined | null + >(); + expectTypeOf>().not.toBeAny(); +}); + +test('metadata replacement and native modifiers preserve precise value types', () => { + const s = withExtensions(tagged); + const base = s.number().unit('cm').optional().nullable().positive(); + expectTypeOf>().toEqualTypeOf< + number | undefined | null + >(); + expectTypeOf< + InferExtensionMetadata['unit'] + >().toEqualTypeOf<'cm'>(); + const changed = base.metres().rangeHint(0, 10).required().notNullable(); + expectTypeOf>().toEqualTypeOf(); + expectTypeOf< + InferExtensionMetadata['unit'] + >().toEqualTypeOf<'m'>(); + expectTypeOf< + InferExtensionMetadata['range'] + >().toEqualTypeOf(); + const defaulted = base.default(2).unit('km'); + expectTypeOf>().toEqualTypeOf(); + // @ts-expect-error metadata argument constraints are enforced + base.unit(12); + // @ts-expect-error computed metadata arguments remain typed + base.rangeHint('min', 'max'); +}); + +test('metadata is independent of builder kind and retains structural edits', () => { + const s = withExtensions(tagged); + const text = s.string().label('Title').optional().minLength(1); + expectTypeOf>().toEqualTypeOf(); + expectTypeOf< + InferExtensionMetadata['label'] + >().toEqualTypeOf<'Title'>(); + const record = s + .object({ name: string() }) + .tag('input') + .addProp('title', text) + .tag('output'); + expectTypeOf>().toEqualTypeOf<{ + name: string; + title?: string; + }>(); + expectTypeOf< + InferExtensionMetadata['tag'] + >().toEqualTypeOf<'output'>(); + expectTypeOf< + InferExtensionMetadata> + >().toEqualTypeOf<{}>(); +}); + +test('metadata works across every extension factory kind', () => { + const methods = { tag: defineMetadataMethod('tag').argument() }; + const s = withExtensions( + defineExtension({ + boolean: methods, + date: methods, + array: methods, + tuple: methods, + record: methods, + union: methods, + any: methods, + promise: methods, + generic: methods, + func: methods + }) + ); + const bool = s.boolean().optional().tag('bool').nullable(); + const date = s.date().tag('date').optional(); + const array = s.array(number()).tag('array').optional(); + const tuple = s.tuple([string(), number()]).tag('tuple').optional(); + const record = s.record(string(), number()).tag('record').optional(); + const union = s.union(string()).or(number()).tag('union').optional(); + const any = s.any().hasType<{ value: string }>().tag('any').optional(); + const promise = s.promise(string()).tag('promise').optional(); + const generic = s.generic((value: string) => string(value)).tag('generic'); + const fn = s + .func() + .addParameter(string()) + .hasReturnType(number()) + .tag('function'); + expectTypeOf>().toEqualTypeOf< + boolean | undefined | null + >(); + expectTypeOf>().toEqualTypeOf(); + expectTypeOf>().toEqualTypeOf< + number[] | undefined + >(); + expectTypeOf>().toEqualTypeOf< + [string, number] | undefined + >(); + expectTypeOf>().toEqualTypeOf< + Record | undefined + >(); + expectTypeOf>().toEqualTypeOf< + string | number | undefined + >(); + expectTypeOf>().toEqualTypeOf< + { value: string } | undefined + >(); + expectTypeOf>().toEqualTypeOf< + Promise | undefined + >(); + expectTypeOf< + InferExtensionMetadata['tag'] + >().toEqualTypeOf<'generic'>(); + expectTypeOf>().toEqualTypeOf< + (arg: string) => number + >(); +}); + +test('metadata composes with existing literal-name and property-list extensions', () => { + const naming = defineExtension({ + object: { + named(this: ObjectSchemaBuilder, name: string) { + return this.withExtension('name', name) as typeof this & { + readonly [METHOD_LITERAL_BRAND]?: string; + }; + }, + fields( + this: ObjectSchemaBuilder, + name: string, + ...fields: string[] + ) { + return this.withExtension(name, fields) as typeof this & { + readonly [EXTRA_TYPE_BRAND]?: Record< + string, + readonly string[] + >; + }; + } + } + }); + const s = withExtensions(tagged, naming) + .object({ name: string(), age: number() }) + .named('first') + .tag('input') + .fields('summary', 'name') + .optional() + .named('second') + .tag('output'); + expectTypeOf< + NonNullable<(typeof s)[typeof METHOD_LITERAL_BRAND]> + >().toEqualTypeOf<'first' | 'second'>(); + expectTypeOf< + NonNullable<(typeof s)[typeof EXTRA_TYPE_BRAND]>['summary'] + >().toEqualTypeOf(); + expectTypeOf< + InferExtensionMetadata['tag'] + >().toEqualTypeOf<'output'>(); + expectTypeOf>().toEqualTypeOf< + { name: string; age: number } | undefined + >(); + // @ts-expect-error extension-author methods stay hidden after fluent calls + s.withExtension('tag', 'unsafe'); +}); diff --git a/libs/schema/src/metadata-extension.test.ts b/libs/schema/src/metadata-extension.test.ts new file mode 100644 index 00000000..46e1bada --- /dev/null +++ b/libs/schema/src/metadata-extension.test.ts @@ -0,0 +1,96 @@ +import { describe, expect, it } from 'vitest'; +import { + defineExtension, + defineMetadataMethod, + withExtensions +} from './extension.js'; +import { number, type StringSchemaBuilder, string } from './index.js'; + +const labels = defineExtension({ + string: { + label: defineMetadataMethod('label').argument(), + internal: defineMetadataMethod('visibility').value('internal'), + external: defineMetadataMethod('visibility').value('external'), + lengthHint: defineMetadataMethod('lengthHint').compute( + (min: number, max: number) => ({ min, max }) + ), + trim(this: StringSchemaBuilder) { + return this.addPreprocessor(v => + typeof v === 'string' ? v.trim() : v + ); + } + } +}); + +describe('typed metadata extensions', () => { + it('stores only the declared key, including explicit undefined values', () => { + const s = withExtensions( + defineExtension({ + string: { + label: defineMetadataMethod('label').value(undefined), + anonymous: defineMetadataMethod('label').compute( + () => undefined + ), + internal: + defineMetadataMethod('visibility').value('internal') + } + }) + ); + expect(s.string().label().introspect().extensions).toEqual({ + label: undefined + }); + expect( + s.string().anonymous().internal().introspect().extensions + ).toEqual({ label: undefined, visibility: 'internal' }); + }); + it('stores literal, constant and computed values through immutable chains', () => { + const s = withExtensions(labels); + const original = s.string().label('Title').internal(); + const changed = original + .optional() + .nullable() + .lengthHint(1, 20) + .external() + .trim() + .label('Name'); + expect(original.introspect().extensions).toMatchObject({ + label: 'Title', + visibility: 'internal' + }); + expect(changed.introspect().extensions).toMatchObject({ + label: 'Name', + visibility: 'external', + lengthHint: { min: 1, max: 20 } + }); + expect(changed.parse(' Name ')).toBe('Name'); + expect(changed.parse(null)).toBeNull(); + expect(changed.parse(undefined)).toBeUndefined(); + }); + + it('isolates factories and never mutates global builder prototypes', () => { + const tagged = withExtensions(labels).string(); + expect(typeof tagged.label).toBe('function'); + expect('label' in string()).toBe(false); + expect('label' in number()).toBe(false); + expect('label' in withExtensions().string()).toBe(false); + }); + + it('composes with ordinary extensions and overwrites metadata', () => { + const other = defineExtension({ + string: { + searchable: defineMetadataMethod('searchable').value(true) + } + }); + const s = withExtensions(labels, other) + .string() + .label('First') + .searchable() + .trim() + .label('Second'); + expect(s.introspect().extensions).toMatchObject({ + label: 'Second', + searchable: true + }); + expect(s.parse(' x ')).toBe('x'); + }); +}); diff --git a/libs/schema/src/metadata-extension.ts b/libs/schema/src/metadata-extension.ts new file mode 100644 index 00000000..2e727b26 --- /dev/null +++ b/libs/schema/src/metadata-extension.ts @@ -0,0 +1,375 @@ +import type { AnySchemaBuilder } from './builders/AnySchemaBuilder.js'; +import type { ArraySchemaBuilder } from './builders/ArraySchemaBuilder.js'; +import type { BooleanSchemaBuilder } from './builders/BooleanSchemaBuilder.js'; +import type { DateSchemaBuilder } from './builders/DateSchemaBuilder.js'; +import type { FunctionSchemaBuilder } from './builders/FunctionSchemaBuilder.js'; +import type { GenericSchemaBuilder } from './builders/GenericSchemaBuilder.js'; +import type { NumberSchemaBuilder } from './builders/NumberSchemaBuilder.js'; +import type { ObjectSchemaBuilder } from './builders/ObjectSchemaBuilder.js'; +import type { PromiseSchemaBuilder } from './builders/PromiseSchemaBuilder.js'; +import type { RecordSchemaBuilder } from './builders/RecordSchemaBuilder.js'; +import type { + PropertyDescriptorTree, + SchemaBuilder +} from './builders/SchemaBuilder.js'; +import type { StringSchemaBuilder } from './builders/StringSchemaBuilder.js'; +import type { TupleSchemaBuilder } from './builders/TupleSchemaBuilder.js'; +import type { UnionSchemaBuilder } from './builders/UnionSchemaBuilder.js'; +import type { + EXTRA_TYPE_BRAND, + HiddenExtensionMethods, + METHOD_LITERAL_BRAND +} from './extension.js'; + +const metadataMethods = new WeakSet(); + +/** @internal Metadata helpers own their key, including explicitly undefined values. */ +export function isMetadataMethod(method: Function): boolean { + return metadataMethods.has(method); +} + +/** Metadata recorded by typed extension methods; unannotated builders yield `{}`. */ +export type InferExtensionMetadata = S extends { + readonly __cleverbrush_extension_metadata__: infer M; +} + ? M + : {}; + +/** @internal Description carried on a metadata method's type, not on schemas. */ +export type MetadataMethod = (( + this: SchemaBuilder, + ...args: A +) => SchemaBuilder) & { + readonly __cleverbrush_metadata_method__: { key: K; value: V; mode: Mode }; +}; + +/** Defines the source of a typed metadata value for an extension method. */ +export interface MetadataMethodBuilder { + /** Store the caller's argument, retaining its literal type. */ + argument(): MetadataMethod< + K, + [value: TValue], + TValue, + 'argument' + >; + /** Create a zero-argument method that stores a fixed value. */ + value(value: TValue): MetadataMethod; + /** Compute metadata from typed arguments; inference uses the callback's return type. */ + compute( + compute: (...args: TArgs) => TValue + ): MetadataMethod; +} + +/** + * Define an immutable metadata-only method for use inside `defineExtension()`. + * + * Unlike ordinary extension methods, its stored value is also available through + * `InferExtensionMetadata`. Repeated writes replace the value for that key. + * The method does not validate input or change the schema's inferred value type. + * Methods are installed only on factories returned by `withExtensions()`. + * + * @param key - Runtime introspection key, independent of the fluent method name. + * @example + * ```ts + * const labels = defineExtension({ + * string: { + * label: defineMetadataMethod('label').argument(), + * internal: defineMetadataMethod('visibility').value('internal') + * } + * }); + * const s = withExtensions(labels).string().label('Title').optional(); + * type Label = InferExtensionMetadata['label']; // 'Title' + * ``` + */ +export function defineMetadataMethod( + key: K +): MetadataMethodBuilder { + const method = (compute: (...args: any[]) => unknown) => { + const apply = function ( + this: SchemaBuilder, + ...args: any[] + ) { + return this.withExtension(key, compute(...args)); + }; + metadataMethods.add(apply); + return apply; + }; + return { + argument: () => method(value => value), + value: value => method(() => value), + compute: method + } as MetadataMethodBuilder; +} + +/** @internal Rebuild a native builder with new extension state, preserving its value flags. */ +type WithExtensions = S extends { + readonly __cleverbrush_builder_type__: infer P; +} + ? P extends readonly [ + 'number', + infer T, + infer R extends boolean, + infer N extends boolean, + infer D extends boolean + ] + ? NumberSchemaBuilder + : P extends readonly [ + 'string', + infer T, + infer R extends boolean, + infer N extends boolean, + infer D extends boolean + ] + ? StringSchemaBuilder + : P extends readonly [ + 'date', + infer T, + infer R extends boolean, + infer N extends boolean, + infer D extends boolean + ] + ? DateSchemaBuilder + : P extends readonly [ + 'object', + infer P extends Record< + string, + SchemaBuilder + >, + infer R extends boolean, + infer N extends boolean, + infer T, + infer D extends boolean, + infer C extends SchemaBuilder[] + ] + ? ObjectSchemaBuilder + : P extends readonly [ + 'array', + infer P extends SchemaBuilder, + infer R extends boolean, + infer N extends boolean, + infer T, + infer D extends boolean, + infer V + ] + ? ArraySchemaBuilder + : P extends readonly [ + 'boolean', + infer T, + infer R extends boolean, + infer N extends boolean, + infer X, + infer D extends boolean, + infer V + ] + ? BooleanSchemaBuilder + : P extends readonly [ + 'tuple', + infer P extends readonly SchemaBuilder< + any, + any, + any, + any, + any + >[], + infer R extends boolean, + infer N extends boolean, + infer T, + infer D extends boolean, + infer Rest extends + | SchemaBuilder + | undefined, + infer V + ] + ? TupleSchemaBuilder + : P extends readonly [ + 'record', + infer K extends StringSchemaBuilder< + any, + any, + any, + any + >, + infer P extends SchemaBuilder< + any, + any, + any, + any, + any + >, + infer R extends boolean, + infer N extends boolean, + infer T, + infer D extends boolean, + infer V + ] + ? RecordSchemaBuilder + : P extends readonly [ + 'union', + infer P extends readonly SchemaBuilder< + any, + any, + any, + any, + any + >[], + infer R extends boolean, + infer N extends boolean, + infer T, + infer D extends boolean + ] + ? UnionSchemaBuilder + : P extends readonly [ + 'func', + infer R extends boolean, + infer N extends boolean, + infer T, + infer D extends boolean, + infer P extends SchemaBuilder< + any, + any, + any, + any, + any + >[], + infer Return extends + | SchemaBuilder + | undefined, + infer V + ] + ? FunctionSchemaBuilder + : P extends readonly [ + 'promise', + infer R extends boolean, + infer N extends boolean, + infer T, + infer D extends boolean, + infer P extends + | SchemaBuilder + | undefined, + infer V + ] + ? PromiseSchemaBuilder + : P extends readonly [ + 'generic', + infer F extends ( + ...args: any[] + ) => SchemaBuilder, + infer R extends boolean, + infer N extends boolean, + infer T, + infer D extends boolean, + infer V + ] + ? GenericSchemaBuilder + : P extends readonly [ + 'any', + infer R extends boolean, + infer N extends boolean, + infer T, + infer D extends boolean, + infer V + ] + ? AnySchemaBuilder + : never + : never; + +/** @internal Named declaration support for metadata-aware fluent builders. */ +export type MetadataState = + MetadataMethods & + HiddenExtensionMethods & + Extras & { + readonly __cleverbrush_extension_metadata__: Metadata; + }; + +/** @internal A metadata-aware factory result; state survives native builder modifiers. */ +export type MetadataExtended< + S, + Methods, + Metadata = {}, + Extras = ExtraProperties +> = WithExtensions> & + MetadataState; + +/** @internal Preserve author-defined type brands without intersecting stale metadata or methods. */ +export type ExtraProperties = Pick< + S, + Exclude< + keyof S, + | keyof WithExtensions + | keyof Methods + | '__cleverbrush_extension_metadata__' + > +>; + +type ExtraTypes = S extends { readonly [EXTRA_TYPE_BRAND]?: infer T } + ? T + : {}; +type LiteralNames = S extends { readonly [METHOD_LITERAL_BRAND]?: infer T } + ? T + : never; +type WithBrand = MetadataExtended< + S, + Methods, + InferExtensionMetadata, + Omit, K> & { readonly [P in K]?: V } +>; + +type SetMetadata = MetadataExtended< + S, + Methods, + Omit, K> & Record +>; + +/** Describe fields without recursively inspecting the receiver's fluent methods. */ +type MetadataPropertyTree = S extends { + readonly __cleverbrush_builder_type__: readonly [ + 'object', + infer P extends Record>, + ...unknown[] + ]; +} + ? PropertyDescriptorTree, ObjectSchemaBuilder

> + : never; + +/** @internal Named declaration support for extension method signatures. */ +export type MetadataMethods = { + [M in keyof Methods]: Methods[M] extends MetadataMethod< + infer K, + infer A, + infer V, + infer Mode + > + ? Mode extends 'argument' + ? ( + this: S, + value: Value + ) => SetMetadata + : (this: S, ...args: A) => SetMetadata + : Methods[M] extends (this: any, ...args: infer A) => infer R + ? typeof EXTRA_TYPE_BRAND extends keyof R + ? ( + this: S, + name: Name, + ...columns: ReadonlyArray< + Key | ((t: MetadataPropertyTree) => any) + > + ) => WithBrand< + S, + Methods, + typeof EXTRA_TYPE_BRAND, + ExtraTypes & Record + > + : typeof METHOD_LITERAL_BRAND extends keyof R + ? ( + this: S, + name: Name, + ...rest: A extends [any, ...infer Rest] ? Rest : [] + ) => WithBrand< + S, + Methods, + typeof METHOD_LITERAL_BRAND, + LiteralNames | Name + > + : (this: S, ...args: A) => S + : Methods[M]; +}; diff --git a/websites/docs/app/knex-schema/page.tsx b/websites/docs/app/knex-schema/page.tsx index 7cae6e15..917f8b4a 100644 --- a/websites/docs/app/knex-schema/page.tsx +++ b/websites/docs/app/knex-schema/page.tsx @@ -18,37 +18,6 @@ export default function KnexSchemaPage() {

- - {/* ── Installation ─────────────────────────────────── */} t.id, taskId);`) -
-

Composable read queries

-

- Use alias(schema, name) with typed flat - joins and object projections for DTOs. Left-joined - fields include null; source scopes and soft deletion are - retained. -

-
 eq(t.task.ownerId, t.owner.id))
-    .select(t => ({ id: t.task.id, ownerName: t.owner.name }));`)
-                        }}
-                    />
-                    

Aggregates and optional output schemas

-

- Count helpers return checked numbers; sum and average - preserve database numeric text or null. Min/max follow - the column representation. Optional output schemas - replace decoding and receive raw driver values, - including null. Typed aggregate expressions support - grouped results. -

-
 t.estimate, {
-    output: number().isFloat().coerce().nullable()
-});`)
-                        }}
-                    />
-                    

Ordering and composite cursors

-

- Eager loading preserves final parent order and page - size. Composite cursors retain timestamp precision and - require non-null scalar columns with a declared unique - tie-breaker. Reapply access filters; cursors are not - authorization. -

-
 t.createdAt, direction: 'desc' },
-        { column: t => t.id, direction: 'desc' }
-    ]
-});`)
-                        }}
-                    />
-                    

- Existing APIs remain unchanged. Read the{' '} - - complete query guide - {' '} - for examples, precision policy, and restrictions. -

-
- {/* ── Quick Start ──────────────────────────────────── */}

Quick Start

@@ -412,6 +319,99 @@ const activeUsers = await query(db, UserSchema, base)
+
+

Composable read queries

+

+ Use alias(schema, name) with typed flat + joins and object projections for DTOs. Left-joined + fields include null; source scopes and soft deletion are + retained. +

+
 eq(t.task.ownerId, t.owner.id))
+    .select(t => ({ id: t.task.id, ownerName: t.owner.name }));`)
+                        }}
+                    />
+                    

Aggregates and optional output schemas

+

+ Count helpers return checked numbers; sum and average + preserve database numeric text or null. Min/max follow + the column representation. Optional output schemas + replace decoding and receive raw driver values, + including null. Typed aggregate expressions support + grouped results. +

+
 t.estimate, {
+    output: number().isFloat().coerce().nullable()
+});`)
+                        }}
+                    />
+                    

Ordering and composite cursors

+

+ Eager loading preserves final parent order and page + size. Composite cursors retain timestamp precision and + require non-null scalar columns with a declared unique + tie-breaker. Reapply access filters; cursors are not + authorization. +

+
 t.createdAt, direction: 'desc' },
+        { column: t => t.id, direction: 'desc' }
+    ]
+});`)
+                        }}
+                    />
+                    

+ Existing APIs remain unchanged. Read the{' '} + + complete query guide + {' '} + for examples, precision policy, and restrictions. +

+
+ +
+

Opt-in projection-aware reads

+

+ Start with withRowSchema() before selecting or including + fields. The immutable PostgreSQL reader exposes the + actual decoded result schema: SQL null stays null, dates + are Date objects at every depth, and decimal/bigint + values are exact strings before JSON parsing. +

+
+                         ({ title: t.title, amount: t.amount }));
+const Source = read.rowSchema;
+const rows = await read.where(t => t.id, taskId);`)
+                            }}
+                        />
+                    
+

+ Typed aliases, aggregates, named projections and nested + graphs retain their selected shape. Polymorphic readers + expose a union rowSchema and per-variant object schemas. + Raw shapes are rejected; existing query behavior is + unchanged. +

+ + Read representation, pagination and migration details + +
+ {/* ── API Reference ────────────────────────────────── */}

API Reference

diff --git a/websites/docs/app/mapper/page.tsx b/websites/docs/app/mapper/page.tsx index 55e0f844..fdf8aed4 100644 --- a/websites/docs/app/mapper/page.tsx +++ b/websites/docs/app/mapper/page.tsx @@ -17,38 +17,6 @@ export default function MapperPage() {

-
-

Synchronous mapping and query row schemas

-

- Keep the existing configure() API. When the final - computations and nested mappings are synchronous, - getSyncMapper() returns ordinary values while retaining - completeness checks. getMapper() remains asynchronous. -

-
-                         ({ id: u.id, name: u.name }));
-const Source = read.rowSchema; // no SQL
-const toDto = mapper().configure(Source, UserDto, m => m)
-    .getSyncMapper(Source, UserDto);
-const result = (await read).map(toDto);`)
-                            }}
-                        />
-                    
-

- Known async mappings are rejected; disguised promises or - thenables throw at invocation. Configuration never - probes callbacks. Fetching, enrichment, authorization - and union dispatch remain explicit application code. -

- - Read the multi-file consumer guide and compatibility - rules - -
- {/* ── Install ─────────────────────────────────────── */}

Installation

@@ -250,6 +218,38 @@ const registry = mapper()
+
+

Synchronous mapping and query row schemas

+

+ Keep the existing configure() API. When the final + computations and nested mappings are synchronous, + getSyncMapper() returns ordinary values while retaining + completeness checks. getMapper() remains asynchronous. +

+
+                         ({ id: u.id, name: u.name }));
+const Source = read.rowSchema; // no SQL
+const toDto = mapper().configure(Source, UserDto, m => m)
+    .getSyncMapper(Source, UserDto);
+const result = (await read).map(toDto);`)
+                            }}
+                        />
+                    
+

+ Known async mappings are rejected; disguised promises or + thenables throw at invocation. Configuration never + probes callbacks. Fetching, enrichment, authorization + and union dispatch remain explicit application code. +

+ + Read the multi-file consumer guide and compatibility + rules + +
+ {/* ── Compile-time safety ─────────────────────────── */}

Compile-time completeness

diff --git a/websites/docs/app/orm/page.tsx b/websites/docs/app/orm/page.tsx index 45b1433a..610c276b 100644 --- a/websites/docs/app/orm/page.tsx +++ b/websites/docs/app/orm/page.tsx @@ -19,37 +19,6 @@ export default function OrmPage() {

-
-

Detached reads with projection schemas

-

- db.users.withRowSchema() returns an immutable read-only - query with runtime metadata matching its projection and - relation graph. Results stay detached even in a tracking - context, so partial selections cannot silently become - incomplete tracked entities. -

-
-                         ({ id: p.id, name: p.name }))
-    .include(r => r.tasks, tasks => tasks
-        .select(t => ({ title: t.title })));
-const Source = read.rowSchema; // nested task schema included
-const projects = await read; // one SQL statement`)
-                            }}
-                        />
-                    
-

- Return child queries from customizers. STI/CTI reads - expose variantRowSchemas for explicit mapper dispatch. - Ordinary entity reads and writes remain unchanged. -

- - Projection-aware consumer guide - -
- {/* ── Installation ─────────────────────────────────── */} +
+

Detached reads with projection schemas

+

+ db.users.withRowSchema() returns an immutable read-only + query with runtime metadata matching its projection and + relation graph. Results stay detached even in a tracking + context, so partial selections cannot silently become + incomplete tracked entities. +

+
+                         ({ id: p.id, name: p.name }))
+    .include(r => r.tasks, tasks => tasks
+        .select(t => ({ title: t.title })));
+const Source = read.rowSchema; // nested task schema included
+const projects = await read; // one SQL statement`)
+                            }}
+                        />
+                    
+

+ Return child queries from customizers. STI/CTI reads + expose variantRowSchemas for explicit mapper dispatch. + Ordinary entity reads and writes remain unchanged. +

+ + Projection-aware consumer guide + +
+ {/* ── Polymorphic entities ─────────────────────────── */}

Polymorphic Entities (STI / CTI)

diff --git a/websites/docs/public/llms.txt b/websites/docs/public/llms.txt index 68120c88..a43783c6 100644 --- a/websites/docs/public/llms.txt +++ b/websites/docs/public/llms.txt @@ -1,418 +1,219 @@ # Cleverbrush Framework -> A schema-first TypeScript web framework. Define schemas once — get a type-safe HTTP server, auto-typed client with resilience, OpenAPI 3.1 docs, auth, dependency injection, schema-driven forms, and object mapping. Zero codegen, zero type duplication. - -The key differentiator is **contract-first architecture**: a shared API contract (defined with `@cleverbrush/schema`) is the single source of truth for both server and client. TypeScript enforces exhaustive handler mapping at compile time — add an endpoint to the contract and forget a handler? Compilation fails. - -## Packages - -| Package | Description | Docs | -|---------|-------------|------| -| `@cleverbrush/server` | HTTP server with typed endpoints, middleware, batching, WebSocket | [/server](/server) | -| `@cleverbrush/client` | Auto-typed REST client with retry, timeout, dedup, cache, batching | [/client/getting-started](/client/getting-started) | -| `@cleverbrush/auth` | JWT, cookies, OAuth2, OIDC, policy-based authorization | [/auth](/auth) | -| `@cleverbrush/di` | Dependency injection with schema-as-key tokens | [/di](/di) | -| `@cleverbrush/server-openapi` | OpenAPI 3.1 generation (links, callbacks, webhooks, security) | [/server-openapi](/server-openapi) | -| `@cleverbrush/env` | Typed environment config with schema validation | [/env](/env) | -| `@cleverbrush/knex-schema` | Schema-aware Knex query builder (`.hasTableName()`, `.hasColumnName()`) | [/knex-schema](/knex-schema) | -| `@cleverbrush/react-form` | Headless schema-driven React forms | [/react-form](/react-form) | -| `@cleverbrush/mapper` | Schema-to-schema object mapping with compile-time completeness | [/mapper](/mapper) | -| `@cleverbrush/scheduler` | Job scheduling with worker thread isolation | [/scheduler](/scheduler) | -| `@cleverbrush/schema` | Schema validation library (see [schema.cleverbrush.com](https://schema.cleverbrush.com)) | — | - -## Projection-aware reads and synchronous mapping - -`query(knex, Schema).withRowSchema()` and `db.entities.withRowSchema()` opt into -immutable detached PostgreSQL reads. `rowSchema` matches the selected decoded -shape, including nested relations, SQL nulls, Date values and exact decimal/bigint -strings. Metadata access never executes SQL. STI/CTI readers expose -`variantRowSchemas` for explicit application discriminator dispatch. Legacy reads -are unchanged. See [/knex-schema#row-schemas](/knex-schema#row-schemas) and -[/orm#detached-read-schemas](/orm#detached-read-schemas). - -`mapper().configure(Source, Target, configure).getSyncMapper(Source, Target)` -returns a synchronous complete mapping when all final steps and nested mappings -are synchronous. Async or disguised thenables are rejected; callbacks are not -probed at configuration time. `getMapper()` remains asynchronous. Reuse schemas -and prepared mappings; do not fetch data inside pure mapping. See -[/mapper#synchronous-mapping](/mapper#synchronous-mapping). - -## Core Workflow - -### 1. Define schemas (shared) - -```typescript -import { object, string, number, array } from '@cleverbrush/schema'; - -const CreateTodoBody = object({ - title: string().minLength(1).maxLength(200), - description: string().optional(), +> Schema-first TypeScript libraries for validation, HTTP APIs, typed clients, +> database access, forms and object mapping. Libraries compose without codegen. + +Start with schemas, share a browser-safe API contract, implement its handlers on +the server, then create a client from that same contract. Database schemas and +public response schemas can differ; select and map fields explicitly. + +## Package map + +| Area | Package | Documentation | +| --- | --- | --- | +| Validation and extensions | `@cleverbrush/schema` | [Schema](https://schema.cleverbrush.com) | +| JSON Schema conversion | `@cleverbrush/schema-json` | [README](https://github.com/cleverbrush/framework/tree/development/libs/schema-json) | +| HTTP contracts and handlers | `@cleverbrush/server` | [Server](/server) | +| HTTP clients and React hooks | `@cleverbrush/client` | [Client](/client/getting-started) | +| API specifications | `@cleverbrush/server-openapi` | [OpenAPI / AsyncAPI](/server-openapi) | +| Authentication and authorization | `@cleverbrush/auth` | [Auth](/auth) | +| Dependency injection | `@cleverbrush/di` | [DI](/di) | +| Environment configuration | `@cleverbrush/env` | [Env](/env) | +| SQL queries and schema metadata | `@cleverbrush/knex-schema` | [Queries](/knex-schema) | +| Entities, relations and tracking | `@cleverbrush/orm` | [ORM](/orm) | +| Database migrations | `@cleverbrush/orm-cli` | [README](https://github.com/cleverbrush/framework/tree/development/libs/orm-cli) | +| Object transformations | `@cleverbrush/mapper` | [Mapper](/mapper) | +| Schema-driven React forms | `@cleverbrush/react-form` | [Forms](/react-form) | +| Worker-thread jobs | `@cleverbrush/scheduler` | [Scheduler](/scheduler) | + +## Core workflow + +This small example uses an in-memory collection, not persistent storage. Keep +`contracts.ts` shared; do not import server implementations into browser bundles. + +### 1. Define schemas and the shared contract + +```typescript +// contracts.ts +import { defineApi, endpoint } from '@cleverbrush/server/contract'; +import { array, boolean, number, object, string } from '@cleverbrush/schema'; + +export const Todo = object({ + id: number(), + title: string(), + completed: boolean() }); - -const Todo = object({ - id: number().integer(), - title: string(), - description: string().optional(), - completed: boolean(), +const CreateTodo = object({ title: string().minLength(1).maxLength(200) }); + +export const api = defineApi({ + todos: { + list: endpoint.get('/api/todos').responses({ 200: array(Todo) }), + create: endpoint.post('/api/todos') + .body(CreateTodo).responses({ 201: Todo }) + } }); ``` -### 2. Define the API contract (shared) +### 2. Implement the handlers ```typescript -import { defineApi, endpoint } from '@cleverbrush/server'; - -const api = defineApi({ - todos: { - list: endpoint.get('/api/todos').returns(array(Todo)), - create: endpoint.post('/api/todos').body(CreateTodoBody).returns(Todo), - update: endpoint.patch('/api/todos/:id').body(UpdateTodoBody).returns(Todo), - delete: endpoint.delete('/api/todos/:id'), - }, -}); -``` - -### 3. Server — exhaustive handler mapping - -```typescript -import { createServer, mapHandlers } from '@cleverbrush/server'; - -const server = createServer() - .useAuthentication({ defaultScheme: 'jwt', schemes: [jwtScheme({ secret })] }) - .useAuthorization() - .services(svc => configureDI(svc)) - .useBatching() - .withHealthcheck(); - -mapHandlers(server, api, { - todos: { - list: async ({ query }) => db.todos.findAll(query), - create: async ({ body }) => db.todos.insert(body), - update: async ({ params, body }) => db.todos.update(params.id, body), - delete: async ({ params }) => db.todos.delete(params.id), - // TypeScript error if any endpoint is missing - }, -}); - -server.listen(3000); -``` - -### 4. Client — typed, resilient +// todos.ts +import { ActionResult, implement } from '@cleverbrush/server'; +import type { InferType } from '@cleverbrush/schema'; +import { api, Todo } from './contracts.js'; -```typescript -import { createClient, retry, timeout, dedupe, throttlingCache, batching } from '@cleverbrush/client'; - -const client = createClient(api, { - baseUrl: 'http://localhost:3000', - getToken: () => loadToken(), - middlewares: [ - retry({ limit: 3 }), - timeout({ timeout: 10_000 }), - dedupe(), - throttlingCache({ throttle: 2000 }), - batching({ maxSize: 10 }), - ], +const rows: InferType[] = []; +let nextId = 1; +export const todosModule = implement(api).group('todos').withHandlers({ + list: () => rows, + create: ({ body }) => { + const todo = { id: nextId++, title: body.title, completed: false }; + rows.push(todo); + return ActionResult.created(todo); + } }); - -// Fully typed — autocomplete on endpoints and params -const todos = await client.todos.list(); -const newTodo = await client.todos.create({ body: { title: 'Buy milk' } }); ``` -## @cleverbrush/server - -Install: `npm install @cleverbrush/server @cleverbrush/schema` +For large APIs, export a configured scope and define each handler in its own file +using `Handler`. Compose feature modules at the +root. See the [multi-file example](https://github.com/cleverbrush/framework/blob/development/libs/server/README.md#large-apis-and-shared-error-handling). -### Endpoint builder +### 3. Register the complete implementation ```typescript -import { endpoint, route } from '@cleverbrush/server'; - -const myEndpoint = endpoint - .get('/api/users/:id') // HTTP method + path (path params auto-typed) - .query(QuerySchema) // query string schema - .body(BodySchema) // request body schema - .headers(HeadersSchema) // typed request headers - .returns(ResponseSchema) // 200 response schema - .responses({ // multi-status responses - 200: SuccessSchema, - 404: NotFoundSchema, - }) - .produces('application/json') // content type(s) - .producesFile() // binary file response - .deprecated() // OpenAPI deprecated flag - .tags('users') // OpenAPI tags - .summary('Get user by ID') // OpenAPI summary - .description('...') // OpenAPI description - .example({ ... }) // OpenAPI request example - .examples([...]) // multiple examples - .links({ ... }) // OpenAPI response links - .callbacks({ ... }) // OpenAPI callbacks (webhooks) - .security([{ bearerAuth: [] }]); // OpenAPI security schemes -``` - -### Server setup +// server.ts +import { createServer, implement } from '@cleverbrush/server'; +import { api } from './contracts.js'; +import { todosModule } from './todos.js'; -```typescript -const server = createServer() - .use(myMiddleware) // global middleware - .services(svc => { svc.addSingleton(Token, impl); }) // DI registration - .useAuthentication({ defaultScheme, schemes }) // auth middleware - .useAuthorization() // authorization middleware - .withHealthcheck() // GET /health - .useBatching(); // request batching support +const server = createServer().withHealthcheck(); +server.handleAll(implement(api).use(todosModule).complete()); +await server.listen(3000); ``` -### ActionResult helpers +`complete()` checks contract coverage. Server request validation and response +types come from the endpoint schemas. Application persistence, permissions and +business rules remain application code. -```typescript -import { ActionResult } from '@cleverbrush/server'; - -// In handlers: -return ActionResult.ok(data); // 200 -return ActionResult.created(data); // 201 -return ActionResult.noContent(); // 204 -return ActionResult.notFound(); // 404 -return ActionResult.conflict(); // 409 -return ActionResult.redirect(url); // 302 -return ActionResult.file(buffer, mime); // binary file -return ActionResult.stream(readable); // streaming response -``` - -### WebSocket subscriptions - -```typescript -const api = defineApi({ - live: { - updates: endpoint.ws('/ws/updates') - .receives(ClientMessageSchema) - .sends(ServerMessageSchema), - }, -}); -``` - -## @cleverbrush/client - -Install: `npm install @cleverbrush/client @cleverbrush/schema` - -### Client creation +### 4. Call the API from a typed client ```typescript +// client.ts import { createClient } from '@cleverbrush/client'; -// Or for React: import { createClient } from '@cleverbrush/client/react'; - -const client = createClient(api, { - baseUrl: 'http://localhost:3000', - getToken: () => localStorage.getItem('token'), - middlewares: [...], -}); -``` - -### Resilience middleware - -| Middleware | Purpose | -|-----------|---------| -| `retry({ limit, backoff, jitter })` | Retry failed requests with exponential backoff | -| `timeout({ timeout })` | Abort requests after N ms | -| `dedupe()` | Deduplicate identical concurrent GET requests | -| `throttlingCache({ throttle })` | TTL cache for GET requests | -| `batching({ maxSize, delay })` | Batch multiple requests into one HTTP call | - -### React integration - -```typescript -import { createClient } from '@cleverbrush/client/react'; - -const client = createClient(api, { baseUrl, getToken }); - -// In components: -const { data, error, loading } = client.todos.list.useQuery({ query: { page: 1 } }); -``` - -## @cleverbrush/auth - -Install: `npm install @cleverbrush/auth @cleverbrush/schema` - -```typescript -import { jwtScheme, signJwt } from '@cleverbrush/auth'; - -// Configure JWT auth scheme -const jwt = jwtScheme({ - secret: process.env.JWT_SECRET, - mapClaims: (claims) => ({ - userId: claims.sub, - role: claims.role, - }), -}); - -// Sign tokens -const token = await signJwt({ sub: user.id, role: 'admin' }, secret, { expiresIn: '1h' }); - -// Server setup -server.useAuthentication({ - defaultScheme: 'jwt', - schemes: [jwt], -}); - -// Per-endpoint authorization -endpoint.get('/admin/users') - .authorize('admin') // role-based - .authorize((principal) => principal.role === 'admin'); // policy-based -``` +import { timeout } from '@cleverbrush/client/timeout'; +import { api } from './contracts.js'; -## @cleverbrush/di - -Install: `npm install @cleverbrush/di @cleverbrush/schema` - -Uses schema builders as DI tokens — fully typed, no string keys or decorators. - -```typescript -import { any } from '@cleverbrush/schema'; - -// Define tokens -const DbToken = any().hasType(); -const LoggerToken = any().hasType(); - -// Register services -server.services(svc => { - svc.addSingleton(DbToken, () => new Database(config)); - svc.addScoped(LoggerToken, () => new Logger()); -}); - -// Resolve in handlers (injected via context) -const handler = async ({ services }) => { - const db = services.resolve(DbToken); // typed as Database - const logger = services.resolve(LoggerToken); // typed as Logger -}; -``` - -## @cleverbrush/server-openapi - -Install: `npm install @cleverbrush/server-openapi` - -```typescript -import { generateOpenApiSpec, serveAsyncApi } from '@cleverbrush/server-openapi'; - -// Generate OpenAPI 3.1 spec -const spec = generateOpenApiSpec(server, api, { - info: { title: 'My API', version: '1.0.0' }, - servers: [{ url: 'https://api.example.com' }], +export const client = createClient(api, { + baseUrl: 'http://localhost:3000', + middlewares: [timeout({ timeout: 10_000 })] }); - -// Serve at GET /openapi.json -server.get('/openapi.json', () => ActionResult.ok(spec)); - -// AsyncAPI for WebSocket endpoints -const asyncSpec = serveAsyncApi(server, api, { ... }); -``` - -Features: response links, callbacks, webhooks, response headers, security schemes, discriminated union `discriminator` mapping, tags, deprecation. - -## @cleverbrush/env - -Install: `npm install @cleverbrush/env @cleverbrush/schema` - -```typescript -import { env, parseEnv } from '@cleverbrush/env'; -import { string, number } from '@cleverbrush/schema'; - -const config = parseEnv({ - db: { - host: env('DB_HOST', string().default('localhost')), - port: env('DB_PORT', number().coerce().default(5432)), - name: env('DB_NAME', string()), - }, - jwt: { - secret: env('JWT_SECRET', string().minLength(32)), - }, - port: env('PORT', number().coerce().default(3000)), -}); -// config is fully typed: { db: { host: string; port: number; name: string }; ... } -// Throws with clear error messages if env vars are missing or invalid -``` - -## @cleverbrush/knex-schema - -Install: `npm install @cleverbrush/knex-schema @cleverbrush/schema knex` - -Schema-aware Knex query builder. Attach table/column metadata to schemas, then query with type-safe selectors. - -```typescript -import { object, string, number } from '@cleverbrush/schema'; - -// Attach DB metadata to schemas -const UserSchema = object({ - id: number().integer(), - name: string(), - email: string().email(), - createdAt: date().hasColumnName('created_at'), -}).hasTableName('users'); - -// Query with type-safe selectors -import { createQuery } from '@cleverbrush/knex-schema'; - -const db = createQuery(knex); -const users = await db(UserSchema) - .where(u => u.email, 'alice@example.com') - .orderBy(u => u.createdAt, 'desc') - .select(); -``` - -## @cleverbrush/mapper - -Install: `npm install @cleverbrush/mapper @cleverbrush/schema` - -Schema-to-schema object mapping with compile-time completeness. Unmapped target properties are TypeScript errors. - -```typescript -import { mapper } from '@cleverbrush/mapper'; - -const registry = mapper() - .configure(SourceSchema, TargetSchema, (m) => - m - .for(t => t.fullName).compute(s => `${s.firstName} ${s.lastName}`) - .for(t => t.age).from(s => s.birthYear) // auto-transform - .for(t => t.internal).ignore() - // Same-name, same-type properties are auto-mapped - ); - -const mapFn = registry.getMapper(SourceSchema, TargetSchema); -const result = await mapFn(sourceObject); -``` - -## @cleverbrush/scheduler - -Install: `npm install @cleverbrush/scheduler` - -Job scheduling with worker thread isolation, retries, and event streaming. Requires Node.js 16+. - -```typescript -import { JobScheduler } from '@cleverbrush/scheduler'; - -const scheduler = new JobScheduler({ rootFolder: './jobs' }); - -scheduler.addJob({ - id: 'cleanup', - path: 'cleanup.js', - schedule: { every: 'day', interval: 1, hour: 3, minute: 0 }, - timeout: 60_000, - maxRetries: 3, - noConcurrentRuns: true, -}); - -scheduler.on('job:end', ({ jobId }) => console.log(`${jobId} done`)); -scheduler.on('job:error', ({ jobId, error }) => console.error(jobId, error)); - -scheduler.start(); -``` - -Schedule types: `minute`, `day`, `week`, `month`, `year` — each with `interval` and time fields. - -## Links - -- [Getting Started](/getting-started): End-to-end tutorial -- [Why Cleverbrush?](/why): Problem statement and design philosophy -- [Comparisons](/comparisons): Feature matrix vs tRPC, ts-rest, Hono -- [Examples](/examples): Full-stack Todo app demo -- [Schema Library](https://schema.cleverbrush.com): Schema validation docs, playground, benchmarks -- [GitHub](https://github.com/cleverbrush/framework): Source code +const todos = await client.todos.list(); +const created = await client.todos.create({ body: { title: 'Buy milk' } }); +``` + +## Schemas and extension authoring + +Schemas are immutable. Capture the returned builder when adding properties, +validators or modifiers. `number()` validates integers by default; +`.clearIsInteger()` permits fractional values. Use `.coerce()` explicitly when +parsing strings such as query parameters. `InferType` derives the +value type. Named schemas and `schemaRef()` support composition across packages. + +Define custom methods with `defineExtension()` and apply them with +`withExtensions()`. Metadata is available from `schema.introspect().extensions`. +For metadata-only methods whose values must also survive in TypeScript, use +`defineMetadataMethod(key).argument()`, `.value(value)` or `.compute(fn)` and +`InferExtensionMetadata`. These do not alter global builder prototypes or +interpret application-specific metadata. See [schema extensions](https://github.com/cleverbrush/framework/blob/development/libs/schema/README.md#extensions). + +## HTTP APIs and supporting services + +- **Server:** endpoint builders describe request schemas, response statuses, + injection and authorization. `route()` supports schema-typed path parameters. + `implement()` binds modular handlers; `errorMap()` / `withErrors()` translate + known exceptions only into responses declared by the endpoint. `ActionResult` + supplies status-specific, file and streaming results. Unexpected errors retain + the server's Problem Details handling. [Server reference](/server). +- **Subscriptions:** use `endpoint.subscription()` with `.incoming()` and + `.outgoing()` schemas and async-generator handlers. Subscriptions participate + in implementation coverage but do not use HTTP error policies. [Subscriptions](https://github.com/cleverbrush/framework/blob/development/libs/server/README.md#websocket-subscriptions). +- **Client:** `createClient(contract, options)` infers calls from the contract. + Middleware is imported from subpaths such as `/retry`, `/timeout`, `/dedupe`, + `/cache` and `/batching`. Authentication, retry and cache policy must match the + application. The `/react` client adds TanStack Query hooks including + `.useQuery()` and `.useMutation()`; query state uses `isLoading`. + `decodeValidationIssues()` extracts structured request-validation issues. + [Client reference](/client/getting-started). +- **OpenAPI / AsyncAPI:** configure `serveOpenApi({ server, info })` or + `serveAsyncApi({ server, info })` as middleware before listening. For generation + without middleware, pass registration metadata to `generateOpenApiSpec()` or + `generateAsyncApiSpec()`. Named schemas become reusable components. + [Specification generation](/server-openapi). +- **Authentication:** configure authentication schemes and authorization policies + on the server; declare endpoint principal requirements with `.authorize()`. + JWT, cookies, OAuth2 and OIDC are supported. Keep signing keys and server-only + configuration out of shared contracts. [Authentication](/auth). +- **Dependency injection:** schemas act as typed service tokens. Register values + or factories with singleton/scoped/transient lifetimes. Endpoint `.inject()` + declares dependencies supplied as the handler's second argument. + [Dependency injection](/di). +- **Environment:** `env(name, schema)` binds leaves in a nested configuration; + `parseEnv()` validates and resolves it. `parseEnvFlat()` supports flat configs. + Use explicit coercion and `envBoolean()` for environment boolean conventions. + [Environment configuration](/env). + +## Database queries, entities and result mapping + +Import database-capable schema factories from `@cleverbrush/knex-schema` or +`@cleverbrush/orm`, not plain `@cleverbrush/schema`. Table and column metadata +belong to these packages. Knex is a peer dependency; PostgreSQL also needs `pg`. + +- **Queries:** `query(knex, schema)` / `createQuery(knex)` provide typed selectors, + CRUD, scopes, named projections, eager loading and transactions. Aliases express + flat joins; aggregate expressions support summaries and explicit output schemas. + Composite cursors require a deterministic, non-null sort with a unique + tie-breaker. [Query guide](/knex-schema). +- **ORM:** `defineEntity(schema)` declares relations; `createDb(knex, entities)` + exposes typed DbSets. Ordinary entity queries support identity tracking, + change persistence, optimistic concurrency and STI/CTI variants. Use + `@cleverbrush/orm-cli` for migrations. [ORM guide](/orm). +- **Projection-aware reads:** enter `.withRowSchema()` before selecting or + including. It returns an immutable, read-only query. `rowSchema` describes the + decoded selection, not the full table, and accessing it never executes SQL. + Results are detached even in tracking contexts. SQL nulls stay `null`, dates + decode to `Date` throughout nested graphs, and declared decimal/bigint columns + retain exact strings. Input defaults and preprocessors are not replayed. + [Read schemas](/knex-schema#row-schemas), [detached ORM reads](/orm#detached-read-schemas). +- **Nested and polymorphic reads:** child customizers return their configured + queries. Nested includes execute in one SQL statement. STI/CTI readers expose + a union `rowSchema` and per-variant `variantRowSchemas`; DTO selection and + discriminator dispatch remain explicit application code. +- **Mapping:** `mapper().configure(Source, Target, configure)` checks that every + target property is mapped, auto-mapped or ignored. `.from()` copies values; + `.compute()` transforms them. `getMapper()` returns an asynchronous function. + `getSyncMapper()` returns ordinary values when all final steps and nested + mappings are synchronous; known async mappings are rejected and disguised + thenables throw when invoked. Configuration does not probe callbacks. Reuse + schema instances and configured mappings; the registry uses schema identity. + Mapping does not fetch data or authorize access. [Mapper guide](/mapper), + [synchronous mapping](/mapper#synchronous-mapping). + +For separate query, mapping and service files, storage representation rules and +supported read operations, see the [complete query README](https://github.com/cleverbrush/framework/blob/development/libs/knex-schema/README.md#projection-aware-reads). + +## Forms and background work + +- **React Form:** schema-driven fields, validation and submission state. + Structured `FormIssue` values carry server validation errors to nested fields; + application business errors require explicit paths. [Forms](/react-form). +- **Scheduler:** `JobScheduler` runs configured jobs in worker threads with + scheduling, retry, timeout and lifecycle events. Configure job files and + timezone explicitly. [Scheduler](/scheduler). + +## Further reading + +- [Getting Started](/getting-started): full-stack tutorial +- [Examples](/examples): Todo application +- [Why Cleverbrush?](/why): design goals +- [Schema library](https://schema.cleverbrush.com): validation and playground +- [GitHub](https://github.com/cleverbrush/framework): source and tests diff --git a/websites/schema/app/mapper/page.tsx b/websites/schema/app/mapper/page.tsx index 36cce506..b2d75974 100644 --- a/websites/schema/app/mapper/page.tsx +++ b/websites/schema/app/mapper/page.tsx @@ -17,42 +17,6 @@ export default function MapperPage() {

-
-

Synchronous mapping

-

- Use the existing configure() chain, then - getSyncMapper(Source, Target) for pure synchronous - mappings. Completeness and nested-mapping checks remain. - Async computations are rejected, and a disguised - promise/thenable throws when invoked. getMapper() keeps - its async behavior. -

-

- Opt-in Framework database reads expose projection-aware - rowSchema metadata, so source schemas need not be copied - by hand. Reuse schema instances and configure once; - fetching and domain conversions remain - application-owned. -

- - Query mapping examples and consumer guide - -
- - - {/* ── Installation ─────────────────────────────────── */} +
+

Synchronous mapping

+

+ Use the existing configure() chain, then + getSyncMapper(Source, Target) for pure synchronous + mappings. Completeness and nested-mapping checks remain. + Async computations are rejected, and a disguised + promise/thenable throws when invoked. getMapper() keeps + its async behavior. +

+

+ Opt-in Framework database reads expose projection-aware + rowSchema metadata, so source schemas need not be copied + by hand. Reuse schema instances and configure once; + fetching and domain conversions remain + application-owned. +

+ + Query mapping examples and consumer guide + +
+ + + {/* ── API Reference ────────────────────────────────── */}

API Reference

diff --git a/websites/schema/app/playground/schemaDeclarations.ts b/websites/schema/app/playground/schemaDeclarations.ts index d94e918d..11108581 100644 --- a/websites/schema/app/playground/schemaDeclarations.ts +++ b/websites/schema/app/playground/schemaDeclarations.ts @@ -25,6 +25,15 @@ type AnySchemaBuilderCreateProps = Partial extends SchemaBuilder { #private; + /** Native type parameters for extension rebinding; never emitted at runtime. @internal */ + readonly __cleverbrush_builder_type__: readonly [ + 'any', + TRequired, + TNullable, + TExplicitType, + THasDefault, + TResult + ]; /** * @hidden */ @@ -167,6 +176,16 @@ type ArraySchemaBuilderCreateProps, TRequired extends boolean = true, TNullable extends boolean = false, TExplicitType = undefined, THasDefault extends boolean = false, TExtensions = {}, TResult = TExplicitType extends undefined ? TElementSchema extends undefined ? Array : TElementSchema extends SchemaBuilder ? Array>> : never : TExplicitType> extends SchemaBuilder { #private; + /** Native type parameters for extension rebinding; never emitted at runtime. @internal */ + readonly __cleverbrush_builder_type__: readonly [ + 'array', + TElementSchema, + TRequired, + TNullable, + TExplicitType, + THasDefault, + TResult + ]; /** * @hidden */ @@ -271,6 +290,7 @@ export declare class ArraySchemaBuilder TResult) | undefined; description: string | undefined; schemaName: string | undefined; + referenceTarget: SchemaBuilder | undefined; hasCatch: boolean; catchValue: TResult | (() => TResult) | undefined; example: unknown; @@ -372,6 +392,16 @@ type BooleanSchemaBuilderCreateProps = Partial extends SchemaBuilder { #private; + /** Native type parameters for extension rebinding; never emitted at runtime. @internal */ + readonly __cleverbrush_builder_type__: readonly [ + 'boolean', + TResult, + TRequired, + TNullable, + TExplicitType, + THasDefault, + TFinalResult + ]; /** * @hidden */ @@ -401,6 +431,7 @@ export declare class BooleanSchemaBuilder TFinalResult) | undefined; description: string | undefined; schemaName: string | undefined; + referenceTarget: SchemaBuilder | undefined; hasCatch: boolean; catchValue: TFinalResult | (() => TFinalResult) | undefined; example: unknown; @@ -544,6 +575,14 @@ type DateSchemaBuilderCreateProps = Partial< */ export declare class DateSchemaBuilder extends SchemaBuilder { #private; + /** Native type parameters for extension rebinding; never emitted at runtime. @internal */ + readonly __cleverbrush_builder_type__: readonly [ + 'date', + TResult, + TRequired, + TNullable, + THasDefault + ]; /** * @hidden */ @@ -625,6 +664,7 @@ export declare class DateSchemaBuilder TResult) | undefined; description: string | undefined; schemaName: string | undefined; + referenceTarget: SchemaBuilder | undefined; hasCatch: boolean; catchValue: TResult | (() => TResult) | undefined; example: unknown; @@ -908,6 +948,7 @@ export declare class ExternSchemaBuilder TResult) | undefined; description: string | undefined; schemaName: string | undefined; + referenceTarget: SchemaBuilder | undefined; hasCatch: boolean; catchValue: TResult | (() => TResult) | undefined; example: unknown; @@ -1053,6 +1094,17 @@ type InferParameters[]> = */ export declare class FunctionSchemaBuilder[] = [], TReturnTypeSchema extends SchemaBuilder | undefined = undefined, TResult = TExplicitType extends undefined ? (...args: TParameters extends [] ? any[] : InferParameters) => TReturnTypeSchema extends SchemaBuilder ? InferType : any : TExplicitType> extends SchemaBuilder { #private; + /** Native type parameters for extension rebinding; never emitted at runtime. @internal */ + readonly __cleverbrush_builder_type__: readonly [ + 'func', + TRequired, + TNullable, + TExplicitType, + THasDefault, + TParameters, + TReturnTypeSchema, + TResult + ]; /** * @hidden */ @@ -1109,6 +1161,7 @@ export declare class FunctionSchemaBuilder TResult) | undefined; description: string | undefined; schemaName: string | undefined; + referenceTarget: SchemaBuilder | undefined; hasCatch: boolean; catchValue: TResult | (() => TResult) | undefined; example: unknown; @@ -1339,6 +1392,16 @@ type GenericSchemaBuilderCreateProps = Partial */ export declare class GenericSchemaBuilder SchemaBuilder, TRequired extends boolean = true, TNullable extends boolean = false, TExplicitType = undefined, THasDefault extends boolean = false, TExtensions = {}, TResult = TExplicitType extends undefined ? ReturnType extends SchemaBuilder ? R : any : TExplicitType> extends SchemaBuilder { #private; + /** Native type parameters for extension rebinding; never emitted at runtime. @internal */ + readonly __cleverbrush_builder_type__: readonly [ + 'generic', + TFn, + TRequired, + TNullable, + TExplicitType, + THasDefault, + TResult + ]; /** * Applies the template function with concrete schema arguments, returning * a fully typed concrete schema builder. TypeScript infers the result type @@ -1404,6 +1467,7 @@ export declare class GenericSchemaBuilder Schema defaultValue: TResult | (() => TResult) | undefined; description: string | undefined; schemaName: string | undefined; + referenceTarget: SchemaBuilder | undefined; hasCatch: boolean; catchValue: TResult | (() => TResult) | undefined; example: unknown; @@ -1573,6 +1637,7 @@ export declare class IntersectionSchemaBuilder : TExplicitType) | (() => TExplicitType extends undefined ? SchemaIntersection : TExplicitType) | undefined; description: string | undefined; schemaName: string | undefined; + referenceTarget: SchemaBuilder | undefined; hasCatch: boolean; catchValue: (TExplicitType extends undefined ? SchemaIntersection : TExplicitType) | (() => TExplicitType extends undefined ? SchemaIntersection : TExplicitType) | undefined; example: unknown; @@ -1741,6 +1806,7 @@ export declare class LazySchemaBuilder TResult) | undefined; description: string | undefined; schemaName: string | undefined; + referenceTarget: SchemaBuilder | undefined; hasCatch: boolean; catchValue: TResult | (() => TResult) | undefined; example: unknown; @@ -2044,6 +2110,14 @@ type NumberSchemaBuilderCreateProps = Part */ export declare class NumberSchemaBuilder extends SchemaBuilder { #private; + /** Native type parameters for extension rebinding; never emitted at runtime. @internal */ + readonly __cleverbrush_builder_type__: readonly [ + 'number', + TResult, + TRequired, + TNullable, + THasDefault + ]; /** * @hidden */ @@ -2123,6 +2197,7 @@ export declare class NumberSchemaBuilder TResult) | undefined; description: string | undefined; schemaName: string | undefined; + referenceTarget: SchemaBuilder | undefined; hasCatch: boolean; catchValue: TResult | (() => TResult) | undefined; example: unknown; @@ -2523,6 +2598,16 @@ export type ObjectSchemaValidationResult> = {}, TRequired extends boolean = true, TNullable extends boolean = false, TExplicitType = undefined, THasDefault extends boolean = false, TExtensions = {}, TConstructorSchemas extends SchemaBuilder[] = []> extends SchemaBuilder> : TExplicitType, TRequired, TNullable, THasDefault, TExtensions> { #private; + /** Native type parameters for extension rebinding; never emitted at runtime. @internal */ + readonly __cleverbrush_builder_type__: readonly [ + 'object', + TProperties, + TRequired, + TNullable, + TExplicitType, + THasDefault, + TConstructorSchemas + ]; /** Marks this builder as having sub-properties for descriptor tree recursion. */ readonly [SYMBOL_HAS_PROPERTIES] = true; /** @@ -2564,6 +2649,7 @@ export declare class ObjectSchemaBuilder> : TExplicitType) | (() => undefined extends TExplicitType ? WithConstructors> : TExplicitType) | undefined; description: string | undefined; schemaName: string | undefined; + referenceTarget: SchemaBuilder | undefined; hasCatch: boolean; catchValue: (undefined extends TExplicitType ? WithConstructors> : TExplicitType) | (() => undefined extends TExplicitType ? WithConstructors> : TExplicitType) | undefined; example: unknown; @@ -3120,6 +3206,7 @@ export declare class ParseStringSchemaBuilder TResult) | undefined; description: string | undefined; schemaName: string | undefined; + referenceTarget: SchemaBuilder | undefined; hasCatch: boolean; catchValue: TResult | (() => TResult) | undefined; example: unknown; @@ -3290,6 +3377,16 @@ type PromiseSchemaBuilderCreateProps = Partial | undefined = undefined, TResult = TExplicitType extends undefined ? TResolvedTypeSchema extends SchemaBuilder ? Promise> : Promise : TExplicitType> extends SchemaBuilder { #private; + /** Native type parameters for extension rebinding; never emitted at runtime. @internal */ + readonly __cleverbrush_builder_type__: readonly [ + 'promise', + TRequired, + TNullable, + TExplicitType, + THasDefault, + TResolvedTypeSchema, + TResult + ]; /** * @hidden */ @@ -3337,6 +3434,7 @@ export declare class PromiseSchemaBuilder TResult) | undefined; description: string | undefined; schemaName: string | undefined; + referenceTarget: SchemaBuilder | undefined; hasCatch: boolean; catchValue: TResult | (() => TResult) | undefined; example: unknown; @@ -3716,6 +3814,17 @@ type RecordSchemaBuilderCreateProps, TValueSchema extends SchemaBuilder, TRequired extends boolean = true, TNullable extends boolean = false, TExplicitType = undefined, THasDefault extends boolean = false, TExtensions = {}, TResult = TExplicitType extends undefined ? Record, InferType> : TExplicitType> extends SchemaBuilder { #private; + /** Native type parameters for extension rebinding; never emitted at runtime. @internal */ + readonly __cleverbrush_builder_type__: readonly [ + 'record', + TKeySchema, + TValueSchema, + TRequired, + TNullable, + TExplicitType, + THasDefault, + TResult + ]; /** * @hidden */ @@ -3781,6 +3890,7 @@ export declare class RecordSchemaBuilder TResult) | undefined; description: string | undefined; schemaName: string | undefined; + referenceTarget: SchemaBuilder | undefined; hasCatch: boolean; catchValue: TResult | (() => TResult) | undefined; example: unknown; @@ -4066,6 +4176,8 @@ export type SchemaBuilderProps = { hasCatch?: boolean; description?: string; schemaName?: string; + /** @internal Canonical named definition for a use-site-only derivative. */ + referenceTarget?: SchemaBuilder; example?: unknown; }; export type ValidationContext = SchemaBuilder> = { @@ -4278,8 +4390,18 @@ export type PropertyDescriptor, TRootSchema extends ObjectSchemaBuilder = TSchema, TAssignableTo = any, TParentPropertyDescriptor = undefined> = PropertyDescriptor & (TSchema extends ObjectSchemaBuilder ? { - [K in keyof TProperties]: TProperties[K] extends ObjectSchemaBuilder ? PropertyDescriptorTree> : TProperties[K] extends ExternSchemaBuilder ? PropertyDescriptor, K & string> & ExternOutputPropertyDescriptors, K & string>> : TProperties[K] extends ArraySchemaBuilder ? TArrayElement extends ObjectSchemaBuilder ? PropertyDescriptor, K & string> : InferType extends TAssignableTo ? PropertyDescriptor, K & string> : never : InferType extends TAssignableTo ? PropertyDescriptor, K & string> : never; + [K in keyof TProperties]: TProperties[K] extends ObjectSchemaBuilder ? PropertyDescriptorTree> : TProperties[K] extends ExternSchemaBuilder ? PropertyDescriptor, K & string> & ExternOutputPropertyDescriptors, K & string>> : TProperties[K] extends ArraySchemaBuilder ? TArrayElement extends ObjectSchemaBuilder ? IndexedPropertyDescriptor, K & string> : InferType extends TAssignableTo ? IndexedPropertyDescriptor, K & string> : never : InferType extends TAssignableTo ? PropertyDescriptor, K & string> : never; } : never); +/** + * A descriptor that preserves its array binding and exposes lazy indexed child + * descriptors. Indices are non-negative integers; they are positions, not item + * identities. Object and nested-array elements retain their schema types. + * + * @example \`object.getPropertiesFor(schema).addresses[0].city\` + */ +export type IndexedPropertyDescriptor, TSchema, TParent, TKey extends string = string> = PropertyDescriptor & (TSchema extends ObjectSchemaBuilder ? PropertyDescriptorTree : TSchema extends ArraySchemaBuilder ? { + readonly [index: number]: IndexedPropertyDescriptor>; +} : {}); /** * Recursively maps the keys of an extern schema's output type into * property descriptors. When a value is a plain-object type its keys @@ -4340,13 +4462,13 @@ export declare abstract class SchemaBuilder\` format: * - Success: \`{ value: }\` * - Failure: \`{ issues: [{ message: string }, …] }\` @@ -4400,6 +4522,17 @@ export declare abstract class SchemaBuilder | undefined; /** * Whether a catch/fallback value has been set on this schema via \`.catch()\`. */ @@ -4635,7 +4776,10 @@ export declare abstract class SchemaBuilder TResult)): this; + catch(value: ResolvedSchemaType | (() => ResolvedSchemaType)): this; /** * Removes the default value set by a previous call to \`.default()\`. */ @@ -4719,6 +4863,15 @@ export declare abstract class SchemaBuilder, options?: { + addPreprocessor(preprocessor: (object: TResult) => ResolvedSchemaType | Promise>, options?: { mutates?: boolean; }): this; /** @@ -4973,6 +5132,14 @@ type StringSchemaBuilderCreateProps = Part */ export declare class StringSchemaBuilder extends SchemaBuilder { #private; + /** Native type parameters for extension rebinding; never emitted at runtime. @internal */ + readonly __cleverbrush_builder_type__: readonly [ + 'string', + TResult, + TRequired, + TNullable, + THasDefault + ]; /** * @hidden */ @@ -5053,6 +5220,7 @@ export declare class StringSchemaBuilder TResult) | undefined; description: string | undefined; schemaName: string | undefined; + referenceTarget: SchemaBuilder | undefined; hasCatch: boolean; catchValue: TResult | (() => TResult) | undefined; example: unknown; @@ -5297,6 +5465,17 @@ export declare class TupleSchemaBuilder; } : TExplicitType> extends SchemaBuilder { #private; + /** Native type parameters for extension rebinding; never emitted at runtime. @internal */ + readonly __cleverbrush_builder_type__: readonly [ + 'tuple', + TElements, + TRequired, + TNullable, + TExplicitType, + THasDefault, + TRestSchema, + TResult + ]; /** * @hidden */ @@ -5381,6 +5560,7 @@ export declare class TupleSchemaBuilder TResult) | undefined; description: string | undefined; schemaName: string | undefined; + referenceTarget: SchemaBuilder | undefined; hasCatch: boolean; catchValue: TResult | (() => TResult) | undefined; example: unknown; @@ -5553,6 +5733,15 @@ type TakeExceptIndex[], TRequired extends boolean = true, TNullable extends boolean = false, TExplicitType = undefined, THasDefault extends boolean = false, TExtensions = {}> extends SchemaBuilder : TExplicitType, TRequired, TNullable, THasDefault, TExtensions> { #private; + /** Native type parameters for extension rebinding; never emitted at runtime. @internal */ + readonly __cleverbrush_builder_type__: readonly [ + 'union', + TOptions, + TRequired, + TNullable, + TExplicitType, + THasDefault + ]; /** * @hidden */ @@ -5583,6 +5772,7 @@ export declare class UnionSchemaBuilder : TExplicitType) | (() => TExplicitType extends undefined ? SchemaArrayToUnion : TExplicitType) | undefined; description: string | undefined; schemaName: string | undefined; + referenceTarget: SchemaBuilder | undefined; hasCatch: boolean; catchValue: (TExplicitType extends undefined ? SchemaArrayToUnion : TExplicitType) | (() => TExplicitType extends undefined ? SchemaArrayToUnion : TExplicitType) | undefined; example: unknown; @@ -5717,15 +5907,15 @@ export { ParseStringSchemaBuilder, parseString } from './builders/ParseStringSch export { PromiseSchemaBuilder, promise } from './builders/PromiseSchemaBuilder.js'; export type { RecordSchemaValidationResult } from './builders/RecordSchemaBuilder.js'; export { RecordSchemaBuilder, record } from './builders/RecordSchemaBuilder.js'; -export type { NestedValidationResult, PropertyDescriptor, PropertyDescriptorInner, PropertyDescriptorTree, PropertySetterOptions, ValidationErrorMessageProvider } from './builders/SchemaBuilder.js'; +export type { IndexedPropertyDescriptor, NestedValidationResult, PropertyDescriptor, PropertyDescriptorInner, PropertyDescriptorTree, PropertySetterOptions, ValidationErrorMessageProvider } from './builders/SchemaBuilder.js'; export { BRAND, Brand, InferType, MakeOptional, SchemaBuilder, SchemaTypeBrand, SchemaValidationError, SYMBOL_HAS_PROPERTIES, SYMBOL_SCHEMA_PROPERTY_DESCRIPTOR, ValidationError, ValidationResult } from './builders/SchemaBuilder.js'; export { StringSchemaBuilder, string } from './builders/StringSchemaBuilder.js'; export type { TupleElementValidationResults, TupleSchemaValidationResult } from './builders/TupleSchemaBuilder.js'; export { TupleSchemaBuilder, tuple } from './builders/TupleSchemaBuilder.js'; export type { OptionValidationResults, UnionSchemaValidationResult } from './builders/UnionSchemaBuilder.js'; export { UnionSchemaBuilder, union } from './builders/UnionSchemaBuilder.js'; -export type { CleanExtended, ExtensionConfig, ExtensionDescriptor, ExtraTypeBrandSymbol, FixedMethods, HiddenExtensionMethods, MethodLiteralBrandSymbol } from './extension.js'; -export { defineExtension, EXTRA_TYPE_BRAND, METHOD_LITERAL_BRAND, withExtensions } from './extension.js'; +export type { CleanExtended, ExtensionConfig, ExtensionDescriptor, ExtraProperties, ExtraTypeBrandSymbol, FixedMethods, HiddenExtensionMethods, InferExtensionMetadata, MetadataExtended, MetadataMethod, MetadataMethodBuilder, MetadataMethods, MetadataState, MethodLiteralBrandSymbol } from './extension.js'; +export { defineExtension, defineMetadataMethod, EXTRA_TYPE_BRAND, METHOD_LITERAL_BRAND, withExtensions } from './extension.js'; `, "file:///node_modules/@cleverbrush/schema/extension.d.ts": `/** * @module extension @@ -5805,6 +5995,9 @@ import type { PropertyDescriptorTree, SchemaBuilder } from './builders/SchemaBui import { StringSchemaBuilder } from './builders/StringSchemaBuilder.js'; import { TupleSchemaBuilder } from './builders/TupleSchemaBuilder.js'; import { UnionSchemaBuilder } from './builders/UnionSchemaBuilder.js'; +import type { MetadataExtended } from './metadata-extension.js'; +export type { ExtraProperties, InferExtensionMetadata, MetadataExtended, MetadataMethod, MetadataMethodBuilder, MetadataMethods, MetadataState } from './metadata-extension.js'; +export { defineMetadataMethod } from './metadata-extension.js'; /** * Maps each builder type name to the corresponding generic builder class. * @@ -6008,7 +6201,7 @@ export type FixedMethods = TBuilder & FixedMethods & HiddenExtensionMethods; +export type CleanExtended = MetadataExtended; type ExtendedStringFactory = { (): CleanExtended, TExt>; (equals: T): CleanExtended, TExt>; @@ -7283,6 +7476,203 @@ export type { TupleElementValidationResults, TupleSchemaValidationResult } from export { TupleSchemaBuilder } from './builders/TupleSchemaBuilder.js'; export * from './core.js'; export { type ArrayBuiltinExtensions, any, array, arrayExtensions, boolean, date, type ExtendedAny, type ExtendedArray, type ExtendedBoolean, type ExtendedDate, type ExtendedFunc, type ExtendedNumber, type ExtendedObject, type ExtendedPromise, type ExtendedRecord, type ExtendedString, type ExtendedTuple, type ExtendedUnion, enumOf, func, type NumberBuiltinExtensions, type NumberOneOfExtension, number, numberExtensions, object, promise, record, type StringBuiltinExtensions, type StringOneOfExtension, string, stringExtensions, tuple, union } from './extensions/index.js'; +`, + "file:///node_modules/@cleverbrush/schema/metadata-extension.d.ts": `import type { AnySchemaBuilder } from './builders/AnySchemaBuilder.js'; +import type { ArraySchemaBuilder } from './builders/ArraySchemaBuilder.js'; +import type { BooleanSchemaBuilder } from './builders/BooleanSchemaBuilder.js'; +import type { DateSchemaBuilder } from './builders/DateSchemaBuilder.js'; +import type { FunctionSchemaBuilder } from './builders/FunctionSchemaBuilder.js'; +import type { GenericSchemaBuilder } from './builders/GenericSchemaBuilder.js'; +import type { NumberSchemaBuilder } from './builders/NumberSchemaBuilder.js'; +import type { ObjectSchemaBuilder } from './builders/ObjectSchemaBuilder.js'; +import type { PromiseSchemaBuilder } from './builders/PromiseSchemaBuilder.js'; +import type { RecordSchemaBuilder } from './builders/RecordSchemaBuilder.js'; +import type { PropertyDescriptorTree, SchemaBuilder } from './builders/SchemaBuilder.js'; +import type { StringSchemaBuilder } from './builders/StringSchemaBuilder.js'; +import type { TupleSchemaBuilder } from './builders/TupleSchemaBuilder.js'; +import type { UnionSchemaBuilder } from './builders/UnionSchemaBuilder.js'; +import type { EXTRA_TYPE_BRAND, HiddenExtensionMethods, METHOD_LITERAL_BRAND } from './extension.js'; +/** @internal Metadata helpers own their key, including explicitly undefined values. */ +export declare function isMetadataMethod(method: Function): boolean; +/** Metadata recorded by typed extension methods; unannotated builders yield \`{}\`. */ +export type InferExtensionMetadata = S extends { + readonly __cleverbrush_extension_metadata__: infer M; +} ? M : {}; +/** @internal Description carried on a metadata method's type, not on schemas. */ +export type MetadataMethod = ((this: SchemaBuilder, ...args: A) => SchemaBuilder) & { + readonly __cleverbrush_metadata_method__: { + key: K; + value: V; + mode: Mode; + }; +}; +/** Defines the source of a typed metadata value for an extension method. */ +export interface MetadataMethodBuilder { + /** Store the caller's argument, retaining its literal type. */ + argument(): MetadataMethod; + /** Create a zero-argument method that stores a fixed value. */ + value(value: TValue): MetadataMethod; + /** Compute metadata from typed arguments; inference uses the callback's return type. */ + compute(compute: (...args: TArgs) => TValue): MetadataMethod; +} +/** + * Define an immutable metadata-only method for use inside \`defineExtension()\`. + * + * Unlike ordinary extension methods, its stored value is also available through + * \`InferExtensionMetadata\`. Repeated writes replace the value for that key. + * The method does not validate input or change the schema's inferred value type. + * Methods are installed only on factories returned by \`withExtensions()\`. + * + * @param key - Runtime introspection key, independent of the fluent method name. + * @example + * \`\`\`ts + * const labels = defineExtension({ + * string: { + * label: defineMetadataMethod('label').argument(), + * internal: defineMetadataMethod('visibility').value('internal') + * } + * }); + * const s = withExtensions(labels).string().label('Title').optional(); + * type Label = InferExtensionMetadata['label']; // 'Title' + * \`\`\` + */ +export declare function defineMetadataMethod(key: K): MetadataMethodBuilder; +/** @internal Rebuild a native builder with new extension state, preserving its value flags. */ +type WithExtensions = S extends { + readonly __cleverbrush_builder_type__: infer P; +} ? P extends readonly [ + 'number', + infer T, + infer R extends boolean, + infer N extends boolean, + infer D extends boolean +] ? NumberSchemaBuilder : P extends readonly [ + 'string', + infer T, + infer R extends boolean, + infer N extends boolean, + infer D extends boolean +] ? StringSchemaBuilder : P extends readonly [ + 'date', + infer T, + infer R extends boolean, + infer N extends boolean, + infer D extends boolean +] ? DateSchemaBuilder : P extends readonly [ + 'object', + infer P extends Record>, + infer R extends boolean, + infer N extends boolean, + infer T, + infer D extends boolean, + infer C extends SchemaBuilder[] +] ? ObjectSchemaBuilder : P extends readonly [ + 'array', + infer P extends SchemaBuilder, + infer R extends boolean, + infer N extends boolean, + infer T, + infer D extends boolean, + infer V +] ? ArraySchemaBuilder : P extends readonly [ + 'boolean', + infer T, + infer R extends boolean, + infer N extends boolean, + infer X, + infer D extends boolean, + infer V +] ? BooleanSchemaBuilder : P extends readonly [ + 'tuple', + infer P extends readonly SchemaBuilder[], + infer R extends boolean, + infer N extends boolean, + infer T, + infer D extends boolean, + infer Rest extends SchemaBuilder | undefined, + infer V +] ? TupleSchemaBuilder : P extends readonly [ + 'record', + infer K extends StringSchemaBuilder, + infer P extends SchemaBuilder, + infer R extends boolean, + infer N extends boolean, + infer T, + infer D extends boolean, + infer V +] ? RecordSchemaBuilder : P extends readonly [ + 'union', + infer P extends readonly SchemaBuilder[], + infer R extends boolean, + infer N extends boolean, + infer T, + infer D extends boolean +] ? UnionSchemaBuilder : P extends readonly [ + 'func', + infer R extends boolean, + infer N extends boolean, + infer T, + infer D extends boolean, + infer P extends SchemaBuilder[], + infer Return extends SchemaBuilder | undefined, + infer V +] ? FunctionSchemaBuilder : P extends readonly [ + 'promise', + infer R extends boolean, + infer N extends boolean, + infer T, + infer D extends boolean, + infer P extends SchemaBuilder | undefined, + infer V +] ? PromiseSchemaBuilder : P extends readonly [ + 'generic', + infer F extends (...args: any[]) => SchemaBuilder, + infer R extends boolean, + infer N extends boolean, + infer T, + infer D extends boolean, + infer V +] ? GenericSchemaBuilder : P extends readonly [ + 'any', + infer R extends boolean, + infer N extends boolean, + infer T, + infer D extends boolean, + infer V +] ? AnySchemaBuilder : never : never; +/** @internal Named declaration support for metadata-aware fluent builders. */ +export type MetadataState = MetadataMethods & HiddenExtensionMethods & Extras & { + readonly __cleverbrush_extension_metadata__: Metadata; +}; +/** @internal A metadata-aware factory result; state survives native builder modifiers. */ +export type MetadataExtended> = WithExtensions> & MetadataState; +/** @internal Preserve author-defined type brands without intersecting stale metadata or methods. */ +export type ExtraProperties = Pick | keyof Methods | '__cleverbrush_extension_metadata__'>>; +type ExtraTypes = S extends { + readonly [EXTRA_TYPE_BRAND]?: infer T; +} ? T : {}; +type LiteralNames = S extends { + readonly [METHOD_LITERAL_BRAND]?: infer T; +} ? T : never; +type WithBrand = MetadataExtended, Omit, K> & { + readonly [P in K]?: V; +}>; +type SetMetadata = MetadataExtended, K> & Record>; +/** Describe fields without recursively inspecting the receiver's fluent methods. */ +type MetadataPropertyTree = S extends { + readonly __cleverbrush_builder_type__: readonly [ + 'object', + infer P extends Record>, + ...unknown[] + ]; +} ? PropertyDescriptorTree, ObjectSchemaBuilder

> : never; +/** @internal Named declaration support for extension method signatures. */ +export type MetadataMethods = { + [M in keyof Methods]: Methods[M] extends MetadataMethod ? Mode extends 'argument' ? (this: S, value: Value) => SetMetadata : (this: S, ...args: A) => SetMetadata : Methods[M] extends (this: any, ...args: infer A) => infer R ? typeof EXTRA_TYPE_BRAND extends keyof R ? (this: S, name: Name, ...columns: ReadonlyArray) => any)>) => WithBrand & Record> : typeof METHOD_LITERAL_BRAND extends keyof R ? (this: S, name: Name, ...rest: A extends [any, ...infer Rest] ? Rest : []) => WithBrand | Name> : (this: S, ...args: A) => S : Methods[M]; +}; +export {}; `, "file:///node_modules/@cleverbrush/schema/utils/transaction.d.ts": `/** * Options for customizing transaction behavior. From 81c2de4a11a3923565ed7cf315bf72b10c299839 Mon Sep 17 00:00:00 2001 From: Andrew Zolotukhin Date: Wed, 30 Sep 2026 18:39:08 +0000 Subject: [PATCH 15/41] feat(knex-schema): add shape-preserving read predicates --- .changeset/schema-aware-read-predicates.md | 10 + docs/assets/schema-aware-read-predicates.png | Bin 0 -> 146640 bytes libs/knex-schema/README.md | 78 ++++ .../integration/read-graphs.test.ts | 17 + .../integration/read-predicates.test.ts | 376 +++++++++++++++++ libs/knex-schema/src/AliasedReadQuery.ts | 69 ++-- libs/knex-schema/src/SchemaReadQuery.ts | 83 ++-- libs/knex-schema/src/index.ts | 6 + libs/knex-schema/src/read-consumer.test.ts | 2 +- .../knex-schema/src/read-predicates.test-d.ts | 92 +++++ libs/knex-schema/src/read-predicates.test.ts | 293 +++++++++++++ libs/knex-schema/src/read-predicates.ts | 386 ++++++++++++++++++ libs/orm/README.md | 8 + websites/docs/app/knex-schema/page.tsx | 37 ++ websites/docs/public/llms.txt | 12 + 15 files changed, 1389 insertions(+), 80 deletions(-) create mode 100644 .changeset/schema-aware-read-predicates.md create mode 100644 docs/assets/schema-aware-read-predicates.png create mode 100644 libs/knex-schema/integration/read-predicates.test.ts create mode 100644 libs/knex-schema/src/read-predicates.test-d.ts create mode 100644 libs/knex-schema/src/read-predicates.test.ts create mode 100644 libs/knex-schema/src/read-predicates.ts diff --git a/.changeset/schema-aware-read-predicates.md b/.changeset/schema-aware-read-predicates.md new file mode 100644 index 00000000..c105dbec --- /dev/null +++ b/.changeset/schema-aware-read-predicates.md @@ -0,0 +1,10 @@ +--- +"@cleverbrush/knex-schema": minor +--- + +Add shape-preserving grouped AND/OR predicates, captured IN/EXISTS subqueries, +bound raw predicates and ordering, and typed SQL column references to ordinary +and aliased schema-aware readers. These capabilities also work in ordinary ORM +reads and nested relation customizers while retaining immutable query plans and +stable row-schema identity. Group callbacks are synchronous and predicate-only; +unrestricted raw query mutation remains unavailable. diff --git a/docs/assets/schema-aware-read-predicates.png b/docs/assets/schema-aware-read-predicates.png new file mode 100644 index 0000000000000000000000000000000000000000..c762f48c585adde7b73546c7b10af67040328371 GIT binary patch literal 146640 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

?qE*1ra0 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 literal 0 HcmV?d00001 diff --git a/libs/knex-schema/README.md b/libs/knex-schema/README.md index 0811875a..d0f086b9 100644 --- a/libs/knex-schema/README.md +++ b/libs/knex-schema/README.md @@ -666,6 +666,7 @@ import { knex } from './database.js'; const UserTable = object({ id: number().primaryKey(), name: string(), + tenantId: number().hasColumnName('tenant_id'), lastSeen: date().optional().hasColumnName('last_seen'), secret: string() }).hasTableName('users'); @@ -757,6 +758,83 @@ sum/average preserve exact text, and empty extrema/sums remain nullable. An expl Framework output schema replaces aggregate decoding and is parsed once; opaque parser objects without schema introspection are rejected in this mode. +### Filtering and ordering without changing the result schema + +Ordinary and aliased readers provide the following shape-preserving operations. +All return an independent reader with the **same `rowSchema` object**; retain the +returned reader when adding conditional filters. Filtering a nullable field does +not implicitly narrow its declared result type. + +| Operation | API | +| --- | --- | +| Comparisons and parenthesized groups | `where`, `andWhere`, `orWhere` | +| SQL null checks | `whereNull`, `whereNotNull`, `orWhereNull`, `orWhereNotNull` | +| Value-list or SELECT-subquery membership | `whereIn`, `whereNotIn`, `orWhereIn`, `orWhereNotIn` | +| SELECT-subquery existence | `whereExists`, `whereNotExists`, `orWhereExists`, `orWhereNotExists` | +| Bound custom predicates | `whereRaw(sql, bindings)`, `orWhereRaw(sql, bindings)` | +| Bound custom ordering | `orderByRaw(sql, bindings)` | +| Quoted mapped column reference | `ref(columnSelector)` | + +Reuse the prepared read from `user-read.ts` in a separate query-composition file: + +```ts +// user-search.ts +import { number, object, query, string } from '@cleverbrush/knex-schema'; +import { knex } from './database.js'; +import { userRead } from './user-read.js'; + +const UserLabel = object({ + userId: number().hasColumnName('user_id'), label: string() +}).hasTableName('user_labels'); + +export function searchUsers(tenantId: number, term: string, priorityUserId: number) { + const labeledUsers = query(knex, UserLabel) + .where(l => l.userId, userRead.ref(u => u.id)) + .where(l => l.label, term) + .select(l => l.userId).toKnexQuery(); + + return userRead.where(u => u.tenantId, tenantId) + .andWhere(group => group + .where(u => u.name, 'ilike', `%${term}%`) + .orWhereExists(labeledUsers)) + .orderByRaw('case when ?? = ? then 0 else 1 end', [ + userRead.ref(u => u.id), priorityUserId + ]) + .orderBy(u => u.name) + .orderBy(u => u.id); +} +``` + +The outer tenant filter applies to the **entire** search group. Group callbacks +are synchronous and run once when the predicate is attached, not during SQL +execution. Their scoped builder accumulates predicates, has no selection, join, +ordering, mutation, or execution methods, and is closed after the callback. +Return the provided group builder or nothing. An empty group adds no condition. +Async callbacks and returned thenables are rejected; thenables are not executed. + +`ref()` resolves mapped columns and generated aliases for ordinary readers, +explicit aliases for joined readers, and the correct child alias inside relation +customizers. Pass references as `??` identifier bindings or as Knex comparison +values when correlating a subquery. Values use `?` bindings. Raw SQL fragments +must be application-authored, not interpolated user input; this API is **not a SQL +sandbox**. Search escaping and application authorization remain caller policies. + +For membership, pass a value array or a single-column Knex SELECT subquery, for +example `read.whereIn(u => u.id, labelPage.toKnexQuery())`. Put ordering and limits +on that subquery to restrict IDs before joining/aggregating. EXISTS accepts a +Knex SELECT subquery; construct it separately instead of passing a Knex callback. +Subquery SQL and bindings are captured on attachment without database execution, +including nested subquery callbacks. Later changes to those builders do not +change the prepared reader. Empty IN lists match no rows; empty NOT IN lists +match all rows, with ordinary SQL null semantics for non-empty lists/subqueries. + +These operations also work in ordinary ORM reads and nested relation customizers. +For polymorphic reads, use them inside `forVariant()`; the union root does not +offer raw filtering or ordering. Numbered pagination retains raw ordering while +its count drops ordering/limits/offsets. `paginateAfter()` uses its explicit +complete `orderBy` specification, replacing prior ordering, including raw order. +No unrestricted `.apply()` or raw result-shape mutation is available in read mode. + ### Nested graphs Declare relations on entities as usual, and return the child query from customizers: diff --git a/libs/knex-schema/integration/read-graphs.test.ts b/libs/knex-schema/integration/read-graphs.test.ts index 7d6b4917..fac586db 100644 --- a/libs/knex-schema/integration/read-graphs.test.ts +++ b/libs/knex-schema/integration/read-graphs.test.ts @@ -136,6 +136,23 @@ afterAll(async () => { }); describe('schema-aware polymorphic graphs', () => { + it('allows schema-preserving predicates inside an explicit variant branch', async () => { + const read = db.assets + .withRowSchema() + .selectVariants(['photo']) + .forVariant('photo', photo => + photo + .where(p => p.where(a => a.id, 1).orWhere(a => a.id, 999)) + .whereRaw('?? > ?', [ + photo.ref(a => a.size), + '9007199254740992' + ]) + .orderByRaw('?? desc', [photo.ref(a => a.id)]) + ); + const rows = await read; + expect(rows.map(row => row.id)).toEqual([1]); + expect(read.rowSchema.validate(rows[0]).valid).toBe(true); + }); it('orders using native values even when branch projections omit sort fields', async () => { const read = db.assets .withRowSchema() diff --git a/libs/knex-schema/integration/read-predicates.test.ts b/libs/knex-schema/integration/read-predicates.test.ts new file mode 100644 index 00000000..ad2c439c --- /dev/null +++ b/libs/knex-schema/integration/read-predicates.test.ts @@ -0,0 +1,376 @@ +import { randomUUID } from 'node:crypto'; +import { mapper } from '@cleverbrush/mapper'; +import { + aggregate, + alias, + array, + createDb, + date, + defineEntity, + eq, + number, + object, + query, + string +} from '@cleverbrush/orm'; +import Knex from 'knex'; +import { afterAll, beforeAll, describe, expect, it } from 'vitest'; + +const connection = process.env.QUERY_TEST_DATABASE_URL; +if (!connection) throw new Error('QUERY_TEST_DATABASE_URL is required'); +const knex = Knex({ client: 'pg', connection }); +const prefix = `cb_pred_${randomUUID().replaceAll('-', '')}`; +const names = { + projects: `${prefix}_projects`, + tasks: `${prefix}_tasks`, + labels: `${prefix}_labels`, + links: `${prefix}_links` +}; +const Task = object({ + id: number().primaryKey(), + projectId: number().hasColumnName('project_id'), + title: string(), + kind: string(), + amount: number().decimal(24, 6), + done: date().optional() +}).hasTableName(names.tasks); +const Project = object({ + id: number().primaryKey(), + ownerId: number().hasColumnName('owner_id'), + name: string() +}).hasTableName(names.projects); +const Label = object({ + id: number().primaryKey(), + projectId: number().hasColumnName('project_id'), + name: string() +}).hasTableName(names.labels); +const Link = object({ + taskId: number().hasColumnName('task_id'), + labelId: number().hasColumnName('label_id') +}).hasTableName(names.links); +const ProjectEntity = defineEntity( + Project.addProp('tasks', array(Task).optional()) +).hasMany( + p => p.tasks, + p => p.id, + t => t.projectId +); +const timestamp = '2026-09-30T12:00:00.123456Z'; + +beforeAll(async () => { + await knex.schema.createTable(names.projects, t => { + t.integer('id').primary(); + t.integer('owner_id'); + t.text('name'); + }); + await knex.schema.createTable(names.tasks, t => { + t.integer('id').primary(); + t.integer('project_id'); + t.text('title'); + t.text('kind'); + t.decimal('amount', 24, 6); + t.timestamp('done', { useTz: true }); + }); + await knex.schema.createTable(names.labels, t => { + t.integer('id').primary(); + t.integer('project_id'); + t.text('name'); + }); + await knex.schema.createTable(names.links, t => { + t.integer('task_id'); + t.integer('label_id'); + }); + await knex(names.projects).insert([ + { id: 1, owner_id: 1, name: 'Alpha' }, + { id: 2, owner_id: 1, name: 'Beta' }, + { id: 3, owner_id: 2, name: 'Private' } + ]); + await knex(names.tasks).insert([ + { + id: 101, + project_id: 1, + title: 'literal 50%_!', + kind: 'task', + amount: '9007199254740993.000001', + done: timestamp + }, + { + id: 102, + project_id: 1, + title: 'label match', + kind: 'task', + amount: '12.340000', + done: null + }, + { + id: 103, + project_id: 2, + title: 'other project', + kind: 'task', + amount: '1.000000', + done: null + }, + { + id: 104, + project_id: 1, + title: 'milestone', + kind: 'milestone', + amount: '2.000000', + done: null + }, + { + id: 201, + project_id: 3, + title: 'literal 50%_!', + kind: 'task', + amount: '3.000000', + done: null + } + ]); + await knex(names.labels).insert([ + { id: 1, project_id: 1, name: 'Alpha' }, + { id: 2, project_id: 1, name: 'Beta' }, + { id: 3, project_id: 1, name: 'Unused' }, + { id: 4, project_id: 3, name: 'Private' } + ]); + await knex(names.links).insert([ + { task_id: 101, label_id: 1 }, + { task_id: 102, label_id: 1 }, + { task_id: 102, label_id: 2 }, + { task_id: 201, label_id: 2 } + ]); +}); +afterAll(async () => { + for (const name of [names.links, names.labels, names.tasks, names.projects]) + await knex.schema.dropTableIfExists(name); + await knex.destroy(); +}); + +describe('schema-aware read predicates against PostgreSQL', () => { + it('keeps outer access filters around grouped raw search and correlated EXISTS', async () => { + const base = query(knex, alias(Task, 'task')) + .withRowSchema() + .join(alias(Project, 'project'), t => + eq(t.task.projectId, t.project.id) + ); + const linked = query(knex, Link) + .where(l => l.labelId, 2) + .where( + l => l.taskId, + base.ref(t => t.task.id) + ) + .select(l => l.taskId) + .toKnexQuery(); + const filtered = base + .where(t => t.project.ownerId, 1) + .whereRaw('case when ?? = ? then ? else ? end = ?', [ + base.ref(t => t.task.kind), + 'milestone', + 'planned', + 'active', + 'active' + ]) + .andWhere(p => + p + .whereRaw("?? ilike ? escape '!'", [ + p.ref(t => t.task.title), + '%50!%!_!!%' + ]) + .orWhereExists(linked) + ); + const rowsQuery = filtered + .select(t => ({ + id: t.task.id, + amount: t.task.amount, + done: t.task.done + })) + .orderBy(t => t.task.id); + const countQuery = filtered.select(() => ({ + total: aggregate.count() + })); + const [rows, count] = await Promise.all([ + rowsQuery, + countQuery.first() + ]); + expect(rows.map(row => row.id)).toEqual([101, 102]); + expect(count?.total).toBe(2); + expect(rows[0].amount).toBe('9007199254740993.000001'); + expect(rows[0].done).toEqual(new Date(timestamp)); + expect(rows[1].done).toBeNull(); + for (const row of rows) + expect(rowsQuery.rowSchema.validate(row).valid).toBe(true); + expect(await rowsQuery.limit(1).offset(1)).toEqual([rows[1]]); + expect((await rowsQuery).length).toBe(2); + expect((await countQuery.first())?.total).toBe(2); + }); + + it('limits label IDs in a subquery before aggregating matching links', async () => { + const page = query(knex, Label) + .where(l => l.projectId, 1) + .orderBy(l => l.name) + .limit(1) + .offset(1) + .select(l => l.id) + .toKnexQuery(); + const read = query(knex, alias(Label, 'label')) + .withRowSchema() + .leftJoin(alias(Link, 'link'), t => eq(t.label.id, t.link.labelId)) + .whereIn(t => t.label.id, page) + .groupBy( + t => t.label.id, + t => t.label.name + ) + .select(t => ({ + id: t.label.id, + name: t.label.name, + total: aggregate.count(t.link.taskId) + })); + page.clear('limit').where('id', 99); + expect(await read).toEqual([{ id: 2, name: 'Beta', total: 2 }]); + expect(read.rowSchema.validate((await read)[0]).valid).toBe(true); + }); + + it('uses raw conditional ordering with independent ordinary numbered and cursor pages', async () => { + const source = query(knex, Project) + .withRowSchema() + .where(p => p.ownerId, 1) + .select(p => ({ id: p.id, name: p.name })); + const priority = source + .orderByRaw('case when ?? = ? then 0 else 1 end', [ + source.ref(p => p.id), + 2 + ]) + .orderBy(p => p.name); + const first = await priority.paginate({ page: 1, pageSize: 1 }); + const second = await priority.paginate({ page: 2, pageSize: 1 }); + expect(first.data.map(p => p.id)).toEqual([2]); + expect(second.data.map(p => p.id)).toEqual([1]); + expect(first.total).toBe(2); + expect(second.total).toBe(2); + expect(priority.rowSchema).toBe(source.rowSchema); + expect(source.toQuery()).not.toContain('order by'); + const cursor = await priority.paginateAfter({ + limit: 1, + orderBy: [{ column: p => p.id, direction: 'asc' }] + }); + expect(cursor.data.map(p => p.id)).toEqual([1]); + const next = await priority.paginateAfter({ + limit: 1, + cursor: cursor.nextCursor, + orderBy: [{ column: p => p.id, direction: 'asc' }] + }); + expect(next.data.map(p => p.id)).toEqual([2]); + }); + + it('orders aliased reads with bound CASE expressions and retains nullable left joins', async () => { + const source = query(knex, alias(Project, 'project')) + .withRowSchema() + .leftJoin(alias(Task, 'task'), t => + eq(t.project.id, t.task.projectId) + ) + .where(t => t.project.ownerId, 1) + .select(t => ({ id: t.project.id, taskId: t.task.id })); + const result = source + .orderByRaw('case when ?? = ? then 0 else 1 end', [ + source.ref(t => t.project.id), + 2 + ]) + .orderBy(t => t.task.id); + expect((await result)[0]).toEqual({ id: 2, taskId: 103 }); + expect(result.rowSchema).toBe(source.rowSchema); + const empty = query(knex, alias(Project, 'project')) + .withRowSchema() + .leftJoin(alias(Label, 'label'), t => + eq(t.project.id, t.label.projectId) + ) + .where(t => t.project.id, 2) + .select(t => ({ id: t.project.id, label: t.label.name })); + expect(await empty).toEqual([{ id: 2, label: null }]); + expect(empty.rowSchema.validate({ id: 2, label: null }).valid).toBe( + true + ); + }); + + it('filters nested ORM reads, stays detached, and reuses the prepared mapper', async () => { + const db = createDb( + knex, + { projects: ProjectEntity }, + { tracking: true } + ); + const source = db.projects + .withRowSchema() + .select(p => ({ id: p.id })) + .include( + p => p.tasks, + tasks => + tasks + .where(p => + p + .where(t => t.kind, 'task') + .orWhere(t => t.kind, 'note') + ) + .orderByRaw('?? desc', [tasks.ref(t => t.id)]) + .limit(1) + .select(t => ({ + title: t.title, + amount: t.amount, + done: t.done + })) + ); + const Target = object({ + id: number(), + tasks: array( + object({ + title: string(), + amount: string(), + done: date().nullable() + }) + ) + }); + const map = mapper() + .configure(source.rowSchema, Target, m => m) + .getSyncMapper(source.rowSchema, Target); + const read = source.where(p => p.id, 1); + expect(read.rowSchema).toBe(source.rowSchema); + const [row] = await read; + expect(map(row)).toEqual({ + id: 1, + tasks: [{ title: 'label match', amount: '12.340000', done: null }] + }); + row.tasks[0].title = 'detached mutation'; + await db.saveChanges(); + expect((await knex(names.tasks).where('id', 102).first()).title).toBe( + 'label match' + ); + }); + + it('preserves captured predicates in transaction clones without touching the source', async () => { + const read = query(knex, Task) + .withRowSchema() + .where(t => t.projectId, 1); + const noLabels = knex(names.links) + .select('task_id') + .where( + 'task_id', + read.ref(t => t.id) + ); + const filtered = read + .whereNotExists(noLabels) + .select(t => ({ id: t.id })); + await knex.transaction(async trx => { + await trx(names.tasks).insert({ + id: 105, + project_id: 1, + title: 'transaction', + kind: 'task', + amount: '1', + done: null + }); + const transactional = filtered.transacting(trx).orderBy(t => t.id); + expect(transactional.rowSchema).toBe(filtered.rowSchema); + expect((await transactional).map(t => t.id)).toEqual([104, 105]); + await trx.rollback(); + }); + expect((await filtered).map(t => t.id)).toEqual([104]); + }); +}); diff --git a/libs/knex-schema/src/AliasedReadQuery.ts b/libs/knex-schema/src/AliasedReadQuery.ts index 8b34cb1f..dd60da2b 100644 --- a/libs/knex-schema/src/AliasedReadQuery.ts +++ b/libs/knex-schema/src/AliasedReadQuery.ts @@ -11,6 +11,12 @@ import { type AliasedColumn, COLUMN } from './expressions.js'; +import { + captureReadRaw, + type ReadPredicate, + type ReadPredicateContext, + ReadPredicates +} from './read-predicates.js'; import { compileReadProjection, type ReadField } from './read-projection.js'; import { compileReadSchema, @@ -36,11 +42,17 @@ type Selection = Record | AggregateExpression>; type Selector = (tables: ReadAliasTables) => AliasedColumn; /** Immutable flat joined read. Supply select() before accessing rowSchema or executing. */ -export class AliasedReadQuery { +export class AliasedReadQuery< + T, + Row extends ReadObject = never +> extends ReadPredicates> { private fields?: Record; private schema?: Row; + private predicates: readonly ReadPredicate[] = []; /** @internal Enter through an aliased query's withRowSchema() method. */ - constructor(private planner: AliasedQueryBuilder) {} + constructor(private planner: AliasedQueryBuilder) { + super(); + } /** Exact structural schema, stable across operations that do not change selection. */ get rowSchema(): Row { @@ -113,33 +125,27 @@ export class AliasedReadQuery { ) as unknown as Row; return copy as any; } - /** Add a bound equality predicate. */ - where(column: Selector, value: unknown): this; - /** Add a bound predicate with an explicit supported operator. */ - where(column: Selector, operator: string, value: unknown): this; - /** Return a filtered clone without changing metadata identity. */ - where(column: Selector, ...args: [unknown] | [string, unknown]): this { - const copy = this.copy(); - if (args.length === 1) copy.planner.where(column as any, args[0]); - else copy.planner.where(column as any, args[0], args[1]); - return copy; - } - /** Match SQL null, including absent outer-joined rows. */ - whereNull(column: Selector): this { - const copy = this.copy(); - copy.planner.whereNull(column as any); - return copy; - } - /** Exclude SQL null without silently narrowing result types. */ - whereNotNull(column: Selector): this { - const copy = this.copy(); - copy.planner.whereNotNull(column as any); - return copy; + protected readPredicateContext(): ReadPredicateContext> { + const { knex, columns } = this.planner.readContext(); + const entries = Object.values( + columns as Record>> + ).flatMap(table => Object.values(table)); + return { + knex, + column: selector => { + const column = selector(columns as ReadAliasTables); + if (!entries.includes(column)) + throw new ReadSchemaError( + 'Predicate column does not belong to this query' + ); + const info = column[COLUMN]; + return `${info.alias}.${info.column}`; + } + }; } - /** Match a bound value list. */ - whereIn(column: Selector, values: readonly unknown[]): this { + protected addReadPredicate(predicate: ReadPredicate): this { const copy = this.copy(); - copy.planner.whereIn(column as any, values); + copy.predicates = [...this.predicates, predicate]; return copy; } /** Order by native database values before decoding. */ @@ -148,6 +154,14 @@ export class AliasedReadQuery { copy.planner.orderBy(column as any, direction); return copy; } + /** Append trusted raw ordering with captured bindings; ref() quotes mapped aliased columns. */ + orderByRaw(sql: string, bindings: readonly Knex.RawBinding[] = []): this { + const { knex } = this.planner.readContext(); + const captured = captureReadRaw(knex, sql, bindings)().toSQL(); + const copy = this.copy(); + copy.planner.orderByRaw(captured.sql, captured.bindings); + return copy; + } /** Group native columns for an aggregate projection. */ groupBy(...columns: Selector[]): this { const copy = this.copy(); @@ -192,6 +206,7 @@ export class AliasedReadQuery { compile(): Knex.QueryBuilder { void this.rowSchema; const { sql, knex } = this.planner.readContext(); + for (const predicate of this.predicates) predicate(sql); return sql .clearSelect() .select( diff --git a/libs/knex-schema/src/SchemaReadQuery.ts b/libs/knex-schema/src/SchemaReadQuery.ts index c980565b..ddaa13b6 100644 --- a/libs/knex-schema/src/SchemaReadQuery.ts +++ b/libs/knex-schema/src/SchemaReadQuery.ts @@ -26,13 +26,19 @@ import { compositeCursor } from './operations/composite-cursor.js'; import { - ALLOWED_OPS, getEffectiveBaseQuery, getSchemaQueryBuilderCtor } from './operations/helpers.js'; import { getState } from './operations/state.js'; import { PolymorphicReadQuery } from './PolymorphicReadQuery.js'; import type { ReadRelations, ReadVariantMetadata } from './read-entity.js'; +import { + captureReadRaw, + type ReadPredicate, + type ReadPredicateContext, + type ReadPredicateSelector, + ReadPredicates +} from './read-predicates.js'; import { compileReadProjection, type ReadField } from './read-projection.js'; import { type ColumnReadSchema, @@ -156,7 +162,7 @@ export class SchemaReadQuery< S extends ReadObject, Row extends ReadObject = ObjectReadSchema>, Relations extends Record = ReadRelations -> { +> extends ReadPredicates> { /** @internal Nominal identity for typed child-query customizers. */ declare readonly [READ_QUERY]: true; private readonly alias = `__schema_read_${readAliasSequence++}`; @@ -175,6 +181,7 @@ export class SchemaReadQuery< private readonly source: S, base: Knex.QueryBuilder ) { + super(); this.base = knex.queryBuilder().from(base.clone().as(this.alias)); const relations = (source.introspect().extensions?.relations ?? []) as RelationSpec[]; @@ -233,16 +240,19 @@ export class SchemaReadQuery< } private column( - selector: Selector> + selector: ReadPredicateSelector> ): ReadColumn { const column = selector( this.columns as ReadColumns ); - if (!column || !Object.values(this.columns).includes(column)) + if ( + !column || + !Object.values(this.columns).some(candidate => candidate === column) + ) throw new ReadSchemaError( 'Column does not belong to this read query' ); - return column; + return column as ReadColumn; } private name(column: ReadColumn): string { @@ -328,55 +338,17 @@ export class SchemaReadQuery< ) as any; } - /** Add a bound comparison, returning an independent query with the same row schema. */ - where( - column: Selector>, - value: unknown - ): this; - /** Add a bound comparison using a supported SQL operator. */ - where( - column: Selector>, - operator: string, - value: unknown - ): this; - /** Add a bound comparison using a supported SQL operator. */ - where( - column: Selector>, - ...args: [unknown] | [string, unknown] - ): this { - const operator = args.length === 1 ? '=' : args[0].toLowerCase(); - if (!ALLOWED_OPS.has(operator)) - throw new ReadSchemaError( - `Unsupported comparison operator: ${operator}` - ); - const copy = this.copy(); - copy.base.where( - this.name(this.column(column)), - operator, - (args.length === 1 ? args[0] : args[1]) as any - ); - return copy; - } - - /** Filter SQL null values without changing the declared read shape. */ - whereNull(column: Selector>): this { - const copy = this.copy(); - copy.base.whereNull(this.name(this.column(column))); - return copy; - } - /** Exclude SQL null values without implicitly narrowing schema nullability. */ - whereNotNull(column: Selector>): this { - const copy = this.copy(); - copy.base.whereNotNull(this.name(this.column(column))); - return copy; + protected readPredicateContext(): ReadPredicateContext< + ReadColumns + > { + return { + knex: this.knex, + column: selector => this.name(this.column(selector)) + }; } - /** Filter against a bound list of values. An empty list produces no rows. */ - whereIn( - column: Selector>, - values: readonly unknown[] - ): this { + protected addReadPredicate(predicate: ReadPredicate): this { const copy = this.copy(); - copy.base.whereIn(this.name(this.column(column)), [...values] as any[]); + predicate(copy.base); return copy; } /** Order parent rows independently of any child relation's ordering. */ @@ -388,6 +360,13 @@ export class SchemaReadQuery< copy.base.orderBy(this.name(this.column(column)), direction); return copy; } + /** Append trusted raw ordering with captured positional bindings; ref() supplies quoted columns. */ + orderByRaw(sql: string, bindings: readonly Knex.RawBinding[] = []): this { + const captured = captureReadRaw(this.knex, sql, bindings); + const copy = this.copy(); + copy.base.orderByRaw(captured()); + return copy; + } /** Group rows before typed aggregate projection. */ groupBy(...columns: Selector>[]): this { const copy = this.copy(); diff --git a/libs/knex-schema/src/index.ts b/libs/knex-schema/src/index.ts index 90904f0b..90d301f6 100644 --- a/libs/knex-schema/src/index.ts +++ b/libs/knex-schema/src/index.ts @@ -110,6 +110,12 @@ export type { WithReadVariant } from './read-entity.js'; export { READ_ENTITY } from './read-entity.js'; +export type { + ReadMembership, + ReadPredicateBuilder, + ReadPredicateGroup, + ReadPredicateSelector +} from './read-predicates.js'; export type { ColumnReadSchema, ObjectReadSchema, diff --git a/libs/knex-schema/src/read-consumer.test.ts b/libs/knex-schema/src/read-consumer.test.ts index 5cfb3d9f..d0cc1587 100644 --- a/libs/knex-schema/src/read-consumer.test.ts +++ b/libs/knex-schema/src/read-consumer.test.ts @@ -42,7 +42,7 @@ test('documentation and multi-file metadata consumers compile against published ) ]; expect(namedBlocks(llms)).toHaveLength(4); - expect(namedBlocks(queryDocs)).toHaveLength(3); + expect(namedBlocks(queryDocs)).toHaveLength(4); for (const [, name, content] of [ ...namedBlocks(llms), ...namedBlocks(queryDocs) diff --git a/libs/knex-schema/src/read-predicates.test-d.ts b/libs/knex-schema/src/read-predicates.test-d.ts new file mode 100644 index 00000000..c3fcec0c --- /dev/null +++ b/libs/knex-schema/src/read-predicates.test-d.ts @@ -0,0 +1,92 @@ +import type { InferType } from '@cleverbrush/schema'; +import Knex from 'knex'; +import { expectTypeOf, test } from 'vitest'; +import { alias, eq } from './aliased-query.js'; +import { number, object, string } from './extension.js'; +import type { ReadPredicateBuilder } from './read-predicates.js'; +import { query } from './SchemaQueryBuilder.js'; + +const knex = Knex({ client: 'pg' }); +const Item = object({ + id: number().primaryKey(), + name: string(), + amount: number().decimal(18, 2).optional() +}).hasTableName('items'); + +test('ordinary reader predicates retain projection types and contextual groups', async () => { + const read = query(knex, Item) + .withRowSchema() + .select(t => ({ name: t.name, amount: t.amount })); + const filtered = read + .where(p => p.where(t => t.id, 1).orWhere(t => t.name, 'two')) + .whereIn(t => t.id, knex('links').select('item_id')) + .whereExists( + knex('links') + .select('item_id') + .where( + 'item_id', + read.ref(t => t.id) + ) + ) + .whereRaw('?? = ?', [read.ref(t => t.name), 'name']) + .orderByRaw('?? asc', [read.ref(t => t.name)]); + expectTypeOf(filtered.rowSchema).toEqualTypeOf(read.rowSchema); + expectTypeOf(await filtered).toEqualTypeOf< + { name: string; amount: string | null }[] + >(); + // @ts-expect-error only projected fields are available on rows + const _id: number = (await filtered)[0].id; + // @ts-expect-error unknown selector properties are rejected + read.where(p => p.where(t => t.missing, 1)); + // @ts-expect-error refs use the same typed column context + read.ref(t => t.missing); + // @ts-expect-error grouped callbacks cannot be async + read.where(async p => { + p.where(t => t.id, 1); + }); + read.where(p => { + expectTypeOf(p).toExtend>(); + // @ts-expect-error groups cannot shape rows + p.select(t => t.id); + // @ts-expect-error groups cannot order rows + p.orderByRaw('id'); + // @ts-expect-error groups cannot execute SQL + p.execute(); + // @ts-expect-error group lifecycle is owned by the reader + p.finish(); + }); + // @ts-expect-error unrestricted mutation is still unavailable + read.apply(q => q.select('*')); +}); + +test('aliased selectors preserve joined nullability and exact storage types', async () => { + const read = query(knex, alias(Item, 'item')) + .withRowSchema() + .leftJoin(alias(Item, 'parent'), t => eq(t.item.id, t.parent.id)) + .select(t => ({ + id: t.item.id, + parentName: t.parent.name, + amount: t.parent.amount + })); + const filtered = read + .where(t => t.item.id, 1) + .andWhere(p => + p + .whereNull(t => t.parent.name) + .orWhere(n => n.where(t => t.parent.id, 2)) + ) + .orWhereNotExists(knex('links').select('item_id')) + .orderByRaw('?? asc', [read.ref(t => t.item.id)]); + expectTypeOf>().toEqualTypeOf<{ + id: number; + parentName: string | null; + amount: string | null; + }>(); + expectTypeOf(await filtered).toEqualTypeOf< + InferType[] + >(); + // @ts-expect-error unknown aliases are rejected inside groups + filtered.where(p => p.where(t => t.unknown.id, 1)); + // @ts-expect-error async group callbacks are rejected on aliased readers too + filtered.orWhere(async p => p.where(t => t.item.id, 1)); +}); diff --git a/libs/knex-schema/src/read-predicates.test.ts b/libs/knex-schema/src/read-predicates.test.ts new file mode 100644 index 00000000..6b00a8d8 --- /dev/null +++ b/libs/knex-schema/src/read-predicates.test.ts @@ -0,0 +1,293 @@ +import Knex, { type Knex as KnexTypes } from 'knex'; +import { describe, expect, it, vi } from 'vitest'; +import { alias, eq } from './aliased-query.js'; +import type { AliasedColumn } from './expressions.js'; +import { date, number, object, string } from './extension.js'; +import type { + ReadPredicateBuilder, + ReadPredicateGroup +} from './read-predicates.js'; +import { query } from './SchemaQueryBuilder.js'; + +const Task = object({ + id: number().primaryKey(), + projectId: number().hasColumnName('project_id'), + title: string(), + amount: number().decimal(24, 6).optional(), + completedAt: date().optional().hasColumnName('completed_at') +}).hasTableName('tasks'); +const knex = Knex({ client: 'pg' }); +const readTask = () => query(knex, Task).withRowSchema(); + +describe('shape-preserving read predicates', () => { + it('groups AND/OR conditions without mutating the source or its schema', () => { + const source = readTask().select(t => ({ id: t.id, amount: t.amount })); + const filtered = source + .where(t => t.projectId, 1) + .andWhere(p => + p + .where(t => t.title, 'one') + .orWhere(n => + n + .where(t => t.id, '>', 2) + .whereNotNull(t => t.completedAt) + ) + ); + expect(filtered.rowSchema).toBe(source.rowSchema); + expect(filtered.toQuery()).toMatch( + /"project_id" = 1 and \(.*"title" = 'one' or \(.*"id" > 2 and .*"completed_at" is not null\)\)/ + ); + expect(source.toQuery()).not.toContain(' where '); + expect(source.where(t => t.projectId, 2).toQuery()).not.toContain( + "'one'" + ); + expect(Object.keys(filtered.rowSchema.introspect().properties)).toEqual( + ['id', 'amount'] + ); + }); + + it('supports comparisons, null variants and empty membership lists', () => { + const read = readTask(); + expect(read.where(t => t.completedAt, null).toQuery()).toContain( + 'is null' + ); + expect( + read.where(t => t.completedAt, 'is not', null).toQuery() + ).toContain('is not null'); + expect(read.whereIn(t => t.id, []).toQuery()).toContain('1 = 0'); + expect(read.whereNotIn(t => t.id, []).toQuery()).toContain('1 = 1'); + const sql = read + .where(t => t.id, 1) + .orWhereIn(t => t.id, [2, 3]) + .orWhereNotIn(t => t.id, [4]) + .orWhereNull(t => t.completedAt) + .orWhereNotNull(t => t.amount) + .toQuery(); + expect(sql).toContain('in (2, 3)'); + expect(sql).toContain('not in (4)'); + expect(sql).toContain('or '); + expect(() => read.where(t => t.id, 'unsafe operator', 1)).toThrow( + /Unsupported comparison operator/ + ); + }); + + it('captures value lists, dates and raw bindings before external mutation', () => { + const read = readTask(); + const ids = [1, 2]; + const time = new Date('2026-01-01T00:00:00Z'); + const bindings: KnexTypes.RawBinding[] = [ + read.ref(t => t.title), + 'old' + ]; + const filtered = read + .whereIn(t => t.id, ids) + .where(t => t.completedAt, '>=', time) + .whereRaw('lower(??) = ?', bindings) + .orderByRaw('case when ?? = ? then 0 else 1 end', bindings); + const before = filtered.toQuery(); + ids.push(3); + time.setUTCFullYear(2030); + bindings[1] = 'new'; + expect(filtered.toQuery()).toBe(before); + expect(filtered.rowSchema).toBe(read.rowSchema); + const compiled = filtered.compile().toSQL(); + expect(compiled.sql).not.toContain("'old'"); + expect(compiled.bindings.filter(x => x === 'old')).toHaveLength(2); + }); + + it('quotes references for mapped columns and rejects foreign descriptors', () => { + const read = readTask(); + expect(read.ref(t => t.projectId).toSQL().sql).toMatch( + /^"__schema_read_\d+"\."project_id"$/ + ); + let other!: AliasedColumn; + readTask().ref(t => { + other = t.id; + return t.id; + }); + expect(() => read.ref(() => other)).toThrow(/does not belong/); + expect(() => read.ref(() => undefined as any)).toThrow( + /does not belong/ + ); + }); + + it('snapshots nested subquery callbacks once without executing SQL', () => { + const event = vi.fn(); + knex.on('query', event); + try { + const source = readTask(); + const inner = knex('links').select('task_id').where('label', 'old'); + const callback = vi.fn((q: KnexTypes.QueryBuilder) => { + q.whereIn('task_id', inner); + }); + const subquery = knex('labels').select('task_id').where(callback); + const filtered = source.whereIn(t => t.id, subquery); + expect(callback).toHaveBeenCalledTimes(1); + const before = filtered.toQuery(); + inner.where('label', 'changed'); + subquery.where('id', 99); + expect(filtered.toQuery()).toBe(before); + expect(callback).toHaveBeenCalledTimes(1); + expect(filtered.rowSchema).toBe(source.rowSchema); + expect(event).not.toHaveBeenCalled(); + } finally { + knex.removeListener('query', event); + } + }); + + it('supports correlated EXISTS and all OR/negative subquery forms', () => { + const read = readTask(); + const linked = knex('links') + .select('task_id') + .where( + 'task_id', + read.ref(t => t.id) + ); + const sql = read + .whereExists(linked) + .whereNotExists(linked) + .orWhereExists(linked) + .orWhereNotExists(linked) + .whereNotIn(t => t.id, linked) + .orWhereIn(t => t.id, linked) + .orWhereNotIn(t => t.id, linked) + .toQuery(); + expect(sql).toContain('exists (select'); + expect(sql).toContain('not exists (select'); + expect(sql).toContain('or exists (select'); + expect(sql).toContain('or not exists (select'); + expect(sql).toContain('not in (select'); + expect(sql).toContain('or '); + expect(sql).toMatch(/"task_id" = "__schema_read_\d+"\."id"/); + expect(() => read.whereExists(knex('links').delete())).toThrow( + /SELECT subquery/ + ); + expect(() => + read.whereIn(t => t.id, knex('links').update({ label: 'bad' })) + ).toThrow(/SELECT subquery/); + }); + + it('supports grouped raw predicates and escaped question-mark operators', () => { + const read = readTask(); + const value = "' OR 1=1 --"; + const filtered = read.where(p => + p + .whereRaw('?? = ?', [p.ref(t => t.title), value]) + .orWhereRaw('?::jsonb \\? ?', ['{"key":1}', 'key']) + ); + const compiled = filtered.compile().toSQL(); + expect(compiled.sql).not.toContain(value); + expect(compiled.bindings).toEqual([value, '{"key":1}', 'key']); + expect(compiled.toNative().sql).toContain('::jsonb ?'); + }); + + it('runs group callbacks once and seals retained group builders', () => { + const read = readTask(); + let retained!: ReadPredicateBuilder; + const callback = vi.fn((p: ReadPredicateBuilder) => { + retained = p; + p.where(t => t.id, 1); + for (const method of [ + 'select', + 'join', + 'orderBy', + 'orderByRaw', + 'apply', + 'finish', + 'execute', + 'then' + ]) + expect(method in p).toBe(false); + }); + const filtered = read.where(callback); + filtered.toQuery(); + filtered.toQuery(); + expect(callback).toHaveBeenCalledTimes(1); + expect(() => retained.where(t => t.id, 2)).toThrow(/already closed/); + expect(filtered.toQuery()).toContain('= 1'); + expect(read.where(() => {}).toQuery()).toBe(read.toQuery()); + }); + + it('rejects async or throwing groups without changing their parent', async () => { + const read = readTask(); + const asyncGroup = async (p: ReadPredicateBuilder) => { + await Promise.resolve(); + p.where(t => t.id, 1); + }; + expect(() => + read.where(asyncGroup as unknown as ReadPredicateGroup) + ).toThrow(/must be synchronous/); + expect(() => + read.where(p => { + p.where(t => t.id, 1); + throw new Error('stop'); + }) + ).toThrow('stop'); + await Promise.resolve(); + expect(read.toQuery()).not.toContain(' where '); + expect(() => read.where(p => (p as any).select('id'))).toThrow(); + }); + + it('rejects returned thenables without invoking them or executing a returned query', () => { + const read = readTask(); + const then = vi.fn(); + expect(() => read.where((() => ({ then })) as any)).toThrow( + /must be synchronous/ + ); + expect(then).not.toHaveBeenCalled(); + const foreign = knex('tasks').select('id'); + const execute = vi.spyOn(foreign, 'then'); + expect(() => read.where((() => foreign) as any)).toThrow( + /must be synchronous/ + ); + expect(execute).not.toHaveBeenCalled(); + }); + + it('applies the same predicates and binding snapshots to aliased joins', () => { + const base = query(knex, alias(Task, 'task')) + .withRowSchema() + .leftJoin(alias(Task, 'other'), t => + eq(t.task.id, t.other.projectId) + ); + const source = base.select(t => ({ + id: t.task.id, + otherId: t.other.id, + amount: t.other.amount + })); + const subquery = knex('links') + .select('task_id') + .where( + 'task_id', + source.ref(t => t.task.id) + ); + const bindings: KnexTypes.RawBinding[] = [ + source.ref(t => t.task.projectId), + 1 + ]; + const filtered = source + .where(t => t.task.projectId, 1) + .andWhere(p => + p.where(t => t.task.title, 'text').orWhereExists(subquery) + ) + .whereIn(t => t.task.id, subquery) + .orderByRaw('case when ?? = ? then 0 else 1 end', bindings); + const before = filtered.toQuery(); + bindings[1] = 2; + subquery.where('label', 'late'); + expect(filtered.toQuery()).toBe(before); + expect(before).toContain('"task"."project_id" = 1'); + expect(before).toContain('or exists (select'); + expect(filtered.rowSchema).toBe(source.rowSchema); + expect( + source.rowSchema.validate({ id: 1, otherId: null, amount: null }) + .valid + ).toBe(true); + expect(source.toQuery()).not.toContain(' where '); + expect('apply' in source).toBe(false); + expect(() => + query(knex, alias(Task, 'task')) + .apply(q => q.where('id', 1)) + .withRowSchema() + ).toThrow(/before select\/apply/); + }); +}); diff --git a/libs/knex-schema/src/read-predicates.ts b/libs/knex-schema/src/read-predicates.ts new file mode 100644 index 00000000..9c907720 --- /dev/null +++ b/libs/knex-schema/src/read-predicates.ts @@ -0,0 +1,386 @@ +import type { Knex } from 'knex'; +import type { AliasedColumn } from './expressions.js'; +import { ALLOWED_OPS } from './operations/helpers.js'; +import { ReadSchemaError } from './read-schema.js'; + +const finishGroup = Symbol('finishReadPredicateGroup'); + +/** Select a column from the current reader's ordinary or aliased table context. */ +export type ReadPredicateSelector = (columns: C) => AliasedColumn; + +/** A synchronous, parenthesized predicate group. The callback cannot shape or execute a query. */ +export type ReadPredicateGroup = ( + predicates: ReadPredicateBuilder + // biome-ignore lint/suspicious/noConfusingVoidType: Accept existing void-returning callbacks while rejecting async callbacks via the explicit return union. +) => ReadPredicateBuilder | void; + +/** A bound value list or a caller-built SELECT subquery; captured without executing it. */ +export type ReadMembership = readonly unknown[] | Knex.QueryBuilder; + +/** @internal Predicate application contains only library-owned, already captured operations. */ +export type ReadPredicate = (query: Knex.QueryBuilder) => void; + +/** @internal Resolve references without exposing the parent's mutable SQL builder. */ +export interface ReadPredicateContext { + knex: Knex; + column: (selector: ReadPredicateSelector) => string; +} + +/** @internal Snapshot common mutable binding values independently of query builders. */ +function copyValue(value: any): any { + if (value instanceof Date) return new Date(value.getTime()); + if (Buffer.isBuffer(value)) return Buffer.from(value); + if (Array.isArray(value)) return value.map(copyValue); + if (value && typeof value === 'object') { + const prototype = Object.getPrototypeOf(value); + if (prototype === Object.prototype || prototype === null) { + return Object.fromEntries( + Object.entries(value).map(([key, item]) => [ + key, + copyValue(item) + ]) + ); + } + } + return value; +} + +/** @internal Compiled SQL is recreated per use, so externally owned builders are never retained. */ +function captureSql( + knex: Knex, + source: Knex.Raw | Knex.QueryBuilder +): () => Knex.Raw { + const compiled = source.toSQL(); + if (Array.isArray(compiled)) + throw new ReadSchemaError( + 'Read predicates require a single SQL expression' + ); + const sql = compiled.sql; + const bindings = compiled.bindings?.map(copyValue) ?? []; + return () => knex.raw(sql, bindings.map(copyValue)); +} + +/** @internal Capture trusted SQL and positional bindings now, including refs and nested raw expressions. */ +export function captureReadRaw( + knex: Knex, + sql: string, + bindings: readonly Knex.RawBinding[] = [] +): () => Knex.Raw { + return captureSql(knex, knex.raw(sql, [...bindings])); +} + +function captureSubquery(knex: Knex, query: Knex.QueryBuilder): () => Knex.Raw { + if ( + !query || + typeof query.toSQL !== 'function' || + typeof query.clone !== 'function' + ) + throw new ReadSchemaError('Expected a Knex SELECT subquery'); + const compiled = query.clone().toSQL(); + if ( + Array.isArray(compiled) || + !['select', 'first'].includes(compiled.method) + ) + throw new ReadSchemaError('Read predicates require a SELECT subquery'); + // Rewrap the compiled statement, not the original builder or its callbacks. + return captureSql( + knex, + knex.raw(compiled.sql, [...(compiled.bindings ?? [])]) + ); +} + +function captureValue(knex: Knex, value: any): () => any { + if (value && typeof value.toSQL === 'function') { + return typeof value.clone === 'function' + ? captureSubquery(knex, value) + : captureSql(knex, value); + } + if (typeof value === 'function') + throw new ReadSchemaError('Predicate values cannot be callbacks'); + const captured = copyValue(value); + return () => copyValue(captured); +} + +/** + * Shared shape-preserving predicate methods for immutable readers and scoped groups. + * @internal Consumers obtain these methods through withRowSchema(), not inheritance. + */ +export abstract class ReadPredicates { + protected abstract readPredicateContext(): ReadPredicateContext; + protected abstract addReadPredicate(predicate: ReadPredicate): this; + + /** + * Quote a schema-backed column for raw bindings or correlated subqueries. + * The reference uses this reader's actual SQL alias and never executes SQL. + * @example read.whereRaw('lower(??) = ?', [read.ref(t => t.name), 'alice']) + */ + ref(selector: ReadPredicateSelector): Knex.Ref { + const { knex, column } = this.readPredicateContext(); + return knex.ref(column(selector)); + } + + /** Add a parenthesized AND group using a synchronous predicate-only callback. */ + where(group: ReadPredicateGroup): this; + /** Add a bound equality comparison. Null uses SQL IS NULL. */ + where(column: ReadPredicateSelector, value: unknown): this; + /** Add a bound comparison using a supported SQL operator. */ + where( + column: ReadPredicateSelector, + operator: string, + value: unknown + ): this; + where( + first: ReadPredicateSelector | ReadPredicateGroup, + ...args: [] | [unknown] | [string, unknown] + ): this { + return this.comparison('and', first, args); + } + + /** Explicit AND spelling of where(), including nested groups. */ + andWhere(group: ReadPredicateGroup): this; + /** Add a bound AND equality comparison. */ + andWhere(column: ReadPredicateSelector, value: unknown): this; + /** Add a bound AND comparison. */ + andWhere( + column: ReadPredicateSelector, + operator: string, + value: unknown + ): this; + andWhere( + first: ReadPredicateSelector | ReadPredicateGroup, + ...args: [] | [unknown] | [string, unknown] + ): this { + return this.comparison('and', first, args); + } + + /** Add a parenthesized OR group. Use an enclosing AND group beside authorization filters. */ + orWhere(group: ReadPredicateGroup): this; + /** Add a bound OR equality comparison. */ + orWhere(column: ReadPredicateSelector, value: unknown): this; + /** Add a bound OR comparison. */ + orWhere( + column: ReadPredicateSelector, + operator: string, + value: unknown + ): this; + orWhere( + first: ReadPredicateSelector | ReadPredicateGroup, + ...args: [] | [unknown] | [string, unknown] + ): this { + return this.comparison('or', first, args); + } + + private comparison( + boolean: 'and' | 'or', + first: ReadPredicateSelector | ReadPredicateGroup, + args: [] | [unknown] | [string, unknown] + ): this { + const context = this.readPredicateContext(); + const method = boolean === 'and' ? 'where' : 'orWhere'; + if (!args.length) { + const group = new ReadPredicateBuilder(context); + let operations: readonly ReadPredicate[]; + try { + const result: unknown = (first as ReadPredicateGroup)(group); + if ( + result && + typeof (result as PromiseLike).then === 'function' + ) { + // Consume native async rejection without assimilating foreign + // thenables (a Knex query's then() would execute SQL). + if (result instanceof Promise) void result.catch(() => {}); + throw new ReadSchemaError( + 'Read predicate groups must be synchronous' + ); + } + operations = group[finishGroup](); + } finally { + group[finishGroup](); + } + return this.addReadPredicate(query => { + query[method](nested => { + for (const operation of operations) operation(nested); + }); + }); + } + const operator = args.length === 1 ? '=' : args[0]; + if ( + typeof operator !== 'string' || + !ALLOWED_OPS.has(operator.toLowerCase()) + ) + throw new ReadSchemaError( + `Unsupported comparison operator: ${operator}` + ); + const column = context.column(first as ReadPredicateSelector); + const value = captureValue( + context.knex, + args.length === 1 ? args[0] : args[1] + ); + return this.addReadPredicate(query => { + if (args.length === 1) query[method](column, value()); + else query[method](column, operator, value()); + }); + } + + private nullPredicate( + column: ReadPredicateSelector, + method: 'whereNull' | 'whereNotNull' | 'orWhereNull' | 'orWhereNotNull' + ): this { + const name = this.readPredicateContext().column(column); + return this.addReadPredicate(query => { + query[method](name); + }); + } + /** Match SQL null without changing the row schema. */ + whereNull(column: ReadPredicateSelector): this { + return this.nullPredicate(column, 'whereNull'); + } + /** Exclude SQL null without narrowing the declared row schema. */ + whereNotNull(column: ReadPredicateSelector): this { + return this.nullPredicate(column, 'whereNotNull'); + } + /** Add an OR SQL-null condition. */ + orWhereNull(column: ReadPredicateSelector): this { + return this.nullPredicate(column, 'orWhereNull'); + } + /** Add an OR SQL-not-null condition. */ + orWhereNotNull(column: ReadPredicateSelector): this { + return this.nullPredicate(column, 'orWhereNotNull'); + } + + private membership( + column: ReadPredicateSelector, + values: ReadMembership, + method: 'whereIn' | 'whereNotIn' | 'orWhereIn' | 'orWhereNotIn' + ): this { + const context = this.readPredicateContext(); + const name = context.column(column); + const captured = Array.isArray(values) + ? values.map(value => captureValue(context.knex, value)) + : captureSubquery(context.knex, values as Knex.QueryBuilder); + return this.addReadPredicate(query => { + if (typeof captured === 'function') { + const rawMethod = method.startsWith('or') + ? 'orWhereRaw' + : 'whereRaw'; + const operator = method.includes('Not') ? 'not in' : 'in'; + query[rawMethod](`?? ${operator} (?)`, [name, captured()]); + } else { + query[method]( + name, + captured.map(value => value()) + ); + } + }); + } + /** Match captured values or a SELECT subquery. An empty list matches no rows. */ + whereIn(column: ReadPredicateSelector, values: ReadMembership): this { + return this.membership(column, values, 'whereIn'); + } + /** Exclude captured values or a SELECT subquery. SQL NOT IN null semantics apply. */ + whereNotIn(column: ReadPredicateSelector, values: ReadMembership): this { + return this.membership(column, values, 'whereNotIn'); + } + /** Add an OR membership condition. */ + orWhereIn(column: ReadPredicateSelector, values: ReadMembership): this { + return this.membership(column, values, 'orWhereIn'); + } + /** Add an OR negative membership condition. */ + orWhereNotIn( + column: ReadPredicateSelector, + values: ReadMembership + ): this { + return this.membership(column, values, 'orWhereNotIn'); + } + + private exists( + subquery: Knex.QueryBuilder, + method: + | 'whereExists' + | 'whereNotExists' + | 'orWhereExists' + | 'orWhereNotExists' + ): this { + const captured = captureSubquery( + this.readPredicateContext().knex, + subquery + ); + return this.addReadPredicate(query => { + const rawMethod = method.startsWith('or') + ? 'orWhereRaw' + : 'whereRaw'; + const operator = method.includes('Not') ? 'not exists' : 'exists'; + query[rawMethod](`${operator} (?)`, [captured()]); + }); + } + /** Require a row in a captured SELECT subquery; use ref() to correlate it. */ + whereExists(subquery: Knex.QueryBuilder): this { + return this.exists(subquery, 'whereExists'); + } + /** Require no rows in a captured SELECT subquery. */ + whereNotExists(subquery: Knex.QueryBuilder): this { + return this.exists(subquery, 'whereNotExists'); + } + /** Add an OR EXISTS predicate. */ + orWhereExists(subquery: Knex.QueryBuilder): this { + return this.exists(subquery, 'orWhereExists'); + } + /** Add an OR NOT EXISTS predicate. */ + orWhereNotExists(subquery: Knex.QueryBuilder): this { + return this.exists(subquery, 'orWhereNotExists'); + } + + /** Trusted SQL predicate with positional value (?) and identifier (??) bindings; not a SQL sandbox. */ + whereRaw(sql: string, bindings: readonly Knex.RawBinding[] = []): this { + const captured = captureReadRaw( + this.readPredicateContext().knex, + sql, + bindings + ); + return this.addReadPredicate(query => { + query.whereRaw(captured()); + }); + } + /** Add an OR trusted SQL predicate with captured positional bindings. */ + orWhereRaw(sql: string, bindings: readonly Knex.RawBinding[] = []): this { + const captured = captureReadRaw( + this.readPredicateContext().knex, + sql, + bindings + ); + return this.addReadPredicate(query => { + query.orWhereRaw(captured()); + }); + } +} + +/** + * Predicate-only builder supplied to grouped where/andWhere/orWhere callbacks. + * Group methods accumulate synchronously; outer readers remain immutable. + * No select, join, order, raw-query escape hatch, then, or execution method exists. + * Retaining this builder and mutating it after the callback throws. + */ +export class ReadPredicateBuilder extends ReadPredicates { + #context: ReadPredicateContext; + #operations: ReadPredicate[] = []; + #closed = false; + /** @internal Created only for grouped predicates. */ + constructor(context: ReadPredicateContext) { + super(); + this.#context = context; + } + protected readPredicateContext(): ReadPredicateContext { + return this.#context; + } + protected addReadPredicate(predicate: ReadPredicate): this { + if (this.#closed) + throw new ReadSchemaError('Predicate group is already closed'); + this.#operations.push(predicate); + return this; + } + /** @internal Close the scoped builder and snapshot its predicate list. */ + [finishGroup](): readonly ReadPredicate[] { + this.#closed = true; + return [...this.#operations]; + } +} diff --git a/libs/orm/README.md b/libs/orm/README.md index 5d78ac10..6573d147 100644 --- a/libs/orm/README.md +++ b/libs/orm/README.md @@ -232,6 +232,14 @@ decoded in one SQL statement. STI/CTI readers expose `variantRowSchemas` for explicit application mapping. See the [read-schema consumer guide](../knex-schema/README.md#projection-aware-reads) for numeric/null/date rules, examples and compatibility boundaries. +Detached ordinary readers also support grouped `where`/`andWhere`/`orWhere`, +IN/EXISTS subqueries, bound `whereRaw`/`orderByRaw`, and `ref(selector)` for quoted +column references. These operations preserve the reader's `rowSchema` identity +and work in nested relation customizers; polymorphic branches use `forVariant()`. +Group callbacks are synchronous and predicate-only. See +[filtering and ordering](../knex-schema/README.md#filtering-and-ordering-without-changing-the-result-schema) +for scoped search, subquery snapshots, pagination, and raw-SQL boundaries. + --- ## Polymorphic entities (STI / CTI) diff --git a/websites/docs/app/knex-schema/page.tsx b/websites/docs/app/knex-schema/page.tsx index 917f8b4a..1be30d69 100644 --- a/websites/docs/app/knex-schema/page.tsx +++ b/websites/docs/app/knex-schema/page.tsx @@ -412,6 +412,43 @@ const rows = await read.where(t => t.id, taskId);`)

+
+

Filtering and ordering schema-aware reads

+

+ Group AND/OR search predicates without changing the + selected row schema. IN/EXISTS subqueries, null checks, + and bound raw predicates and ordering remain explicit. + Every outer operation returns an independent reader. +

+
+                         ({ id: t.id, title: t.title }));
+const read = base.where(t => t.projectId, projectId)
+    .andWhere(group => group
+        .where(t => t.title, 'ilike', pattern)
+        .orWhereExists(labelMatches))
+    .orderByRaw('case when ?? = ? then 0 else 1 end', [
+        base.ref(t => t.id), priorityTaskId
+    ]);
+// read.rowSchema === base.rowSchema`)
+                            }}
+                        />
+                    
+

+ Group callbacks run synchronously once and expose only + predicates. Subquery SQL and bindings are captured on + attachment, with no database execution. Use ref() for + quoted columns and generated aliases; keep values in + bindings and raw SQL fragments application-authored. + Unrestricted apply() remains unavailable. +

+ + Multi-file examples and compatibility boundaries + +
+ {/* ── API Reference ────────────────────────────────── */}

API Reference

diff --git a/websites/docs/public/llms.txt b/websites/docs/public/llms.txt index a43783c6..d1bc3fa1 100644 --- a/websites/docs/public/llms.txt +++ b/websites/docs/public/llms.txt @@ -184,6 +184,18 @@ belong to these packages. Knex is a peer dependency; PostgreSQL also needs `pg`. decode to `Date` throughout nested graphs, and declared decimal/bigint columns retain exact strings. Input defaults and preprocessors are not replayed. [Read schemas](/knex-schema#row-schemas), [detached ORM reads](/orm#detached-read-schemas). +- **Shape-preserving predicates:** ordinary/aliased readers and ordinary ORM reads + support grouped `where`/`andWhere`/`orWhere`, null checks, IN/NOT IN value arrays + or SELECT subqueries, EXISTS/NOT EXISTS, and OR variants. Use `whereRaw` / + `orWhereRaw` / `orderByRaw` with positional bindings and `ref(selector)` for + quoted mapped columns, including generated child aliases. Group callbacks run + synchronously once and receive only predicate methods; retained groups are + closed after the callback. Subquery SQL/bindings are captured without executing + SQL. These operations retain rowSchema identity; assign their returned reader. + Raw fragments are trusted application SQL, not a sandbox. Keep authorization + outside grouped search ORs. No unrestricted apply() exists in read mode. + Numbered pagination retains ordering; composite cursors replace it with their + explicit orderBy specification. [Read predicates](/knex-schema#read-predicates). - **Nested and polymorphic reads:** child customizers return their configured queries. Nested includes execute in one SQL statement. STI/CTI readers expose a union `rowSchema` and per-variant `variantRowSchemas`; DTO selection and From d91656675294046de81edf164b0c2e8e30b79391 Mon Sep 17 00:00:00 2001 From: Andrew Zolotukhin Date: Wed, 30 Sep 2026 22:12:45 +0000 Subject: [PATCH 16/41] feat(framework)!: make query builders immutable with automatic row schemas --- .changeset/immutable-query-major.md | 27 + demos/e2e/README.md | 3 +- demos/e2e/src/api/telemetry.smoke.test.ts | 8 +- demos/e2e/src/api/todos.api.test.ts | 9 +- demos/e2e/src/support/playwright.ts | 1 + demos/e2e/src/ui/todo-crud.ui.test.ts | 6 + demos/todo-backend/src/api/handlers/todos.ts | 6 +- demos/todo-backend/src/api/mappers.ts | 13 +- demos/todo-backend/src/db/schemas.ts | 40 +- .../src/features/todos/TodoDetailPage.tsx | 6 +- docs/assets/immutable-query-demo.png | Bin 0 -> 82574 bytes docs/assets/immutable-query-docs.png | Bin 0 -> 157494 bytes libs/knex-schema/MIGRATION-v5.md | 212 ++ libs/knex-schema/README.md | 134 +- .../integration/immutable-queries.test.ts | 375 +++ libs/knex-schema/integration/queries.test.ts | 80 +- .../integration/read-graphs.test.ts | 29 +- .../integration/read-predicates.test.ts | 23 +- ...sedReadQuery.ts => AliasedQueryBuilder.ts} | 67 +- libs/knex-schema/src/OpaqueQuery.ts | 130 + ...eadQuery.ts => PolymorphicQueryBuilder.ts} | 501 ++- libs/knex-schema/src/QuerySource.ts | 1389 ++++++++ libs/knex-schema/src/SchemaQueryBuilder.ts | 2896 +++++++++-------- libs/knex-schema/src/SchemaReadQuery.ts | 864 ----- libs/knex-schema/src/aliased-query.ts | 51 +- .../src/composable-query.test-d.ts | 16 +- libs/knex-schema/src/composable-query.test.ts | 4 +- libs/knex-schema/src/entity.ts | 2 +- libs/knex-schema/src/extension.ts | 30 +- .../knex-schema/src/immutable-query.test-d.ts | 60 + libs/knex-schema/src/immutable-query.test.ts | 163 + libs/knex-schema/src/index.ts | 27 +- libs/knex-schema/src/mappers.ts | 2 +- libs/knex-schema/src/operations/aggregate.ts | 12 +- .../src/operations/composite-cursor.ts | 4 +- libs/knex-schema/src/operations/delete.ts | 19 +- libs/knex-schema/src/operations/helpers.ts | 82 +- libs/knex-schema/src/operations/insert.ts | 39 +- libs/knex-schema/src/operations/join.ts | 24 +- libs/knex-schema/src/operations/pagination.ts | 18 +- libs/knex-schema/src/operations/select.ts | 29 +- libs/knex-schema/src/operations/state.ts | 21 +- libs/knex-schema/src/operations/update.ts | 14 +- libs/knex-schema/src/operations/where.ts | 54 +- libs/knex-schema/src/orm-extensions.test.ts | 6 +- libs/knex-schema/src/orm.test.ts | 248 +- libs/knex-schema/src/public-api-docs.test.ts | 2 +- libs/knex-schema/src/query-scope.ts | 24 + libs/knex-schema/src/query.ts | 74 + libs/knex-schema/src/raw.test.ts | 194 +- libs/knex-schema/src/raw.ts | 89 +- libs/knex-schema/src/read-consumer.test.ts | 2 +- libs/knex-schema/src/read-graph.test-d.ts | 24 +- libs/knex-schema/src/read-mapping.test.ts | 2 +- .../knex-schema/src/read-predicates.test-d.ts | 10 +- libs/knex-schema/src/read-predicates.test.ts | 27 +- libs/knex-schema/src/read-predicates.ts | 184 +- libs/knex-schema/src/read-projection.ts | 5 +- libs/knex-schema/src/read-schema.test-d.ts | 22 +- libs/knex-schema/src/read-schema.test.ts | 82 +- libs/knex-schema/src/read-schema.ts | 30 +- libs/knex-schema/src/types.ts | 34 +- libs/knex-schema/src/unit.test.ts | 387 ++- libs/knex-schema/src/validate.ts | 2 +- libs/mapper/README.md | 2 +- libs/orm/README.md | 23 +- libs/orm/src/change-tracker.ts | 124 +- libs/orm/src/dbset.ts | 520 ++- libs/orm/src/index.ts | 9 +- libs/orm/src/orm.test.ts | 223 +- libs/orm/src/query-types.test-d.ts | 1 + libs/orm/src/result-types.ts | 14 +- libs/orm/src/save-graph.ts | 4 +- libs/orm/src/variant-write.ts | 68 +- websites/docs/app/knex-schema/page.tsx | 61 +- websites/docs/app/mapper/page.tsx | 2 +- websites/docs/app/orm/page.tsx | 16 +- websites/docs/public/llms.txt | 13 +- 78 files changed, 6218 insertions(+), 3800 deletions(-) create mode 100644 .changeset/immutable-query-major.md create mode 100644 docs/assets/immutable-query-demo.png create mode 100644 docs/assets/immutable-query-docs.png create mode 100644 libs/knex-schema/MIGRATION-v5.md create mode 100644 libs/knex-schema/integration/immutable-queries.test.ts rename libs/knex-schema/src/{AliasedReadQuery.ts => AliasedQueryBuilder.ts} (79%) create mode 100644 libs/knex-schema/src/OpaqueQuery.ts rename libs/knex-schema/src/{PolymorphicReadQuery.ts => PolymorphicQueryBuilder.ts} (53%) create mode 100644 libs/knex-schema/src/QuerySource.ts delete mode 100644 libs/knex-schema/src/SchemaReadQuery.ts create mode 100644 libs/knex-schema/src/immutable-query.test-d.ts create mode 100644 libs/knex-schema/src/immutable-query.test.ts create mode 100644 libs/knex-schema/src/query-scope.ts create mode 100644 libs/knex-schema/src/query.ts diff --git a/.changeset/immutable-query-major.md b/.changeset/immutable-query-major.md new file mode 100644 index 00000000..d792313b --- /dev/null +++ b/.changeset/immutable-query-major.md @@ -0,0 +1,27 @@ +--- +"@cleverbrush/async": major +"@cleverbrush/auth": major +"@cleverbrush/client": major +"@cleverbrush/deep": major +"@cleverbrush/di": major +"@cleverbrush/env": major +"@cleverbrush/knex-clickhouse": major +"@cleverbrush/knex-schema": major +"@cleverbrush/log": major +"@cleverbrush/mapper": major +"@cleverbrush/orm-cli": major +"@cleverbrush/orm": major +"@cleverbrush/otel": major +"@cleverbrush/react-form": major +"@cleverbrush/scheduler": major +"@cleverbrush/schema-json": major +"@cleverbrush/schema": major +"@cleverbrush/server-openapi": major +"@cleverbrush/server": major +--- + +Make Framework query builders immutable and infer row schemas automatically. + +This breaking release requires consumers to retain returned query builders, return synchronous builders from scopes and grouped predicates, and supply an explicit Framework object output schema for opaque raw SELECTs. Remove withRowSchema() calls: ordinary, aliased, polymorphic and ORM queries now expose their row schemas directly. Projections replace scalar selections, and projected/aggregate/raw queries cannot perform entity writes. Reads and write-returning rows consistently preserve exact decimal/bigint strings, Date objects and SQL nulls. + +All published Framework packages advance together to the next major version. See the knex-schema and ORM migration guides before upgrading; tracked entity objects remain mutable. diff --git a/demos/e2e/README.md b/demos/e2e/README.md index 94ed7f84..8fad4eb8 100644 --- a/demos/e2e/README.md +++ b/demos/e2e/README.md @@ -27,7 +27,7 @@ npx vitest --run src/api/todos.api.test.ts # single file ### One-time browser install -The UI project requires Chromium. After `npm install`, run: +The UI project requires Chromium. After `npm ci`, run: ```bash cd demos/e2e && npx playwright install chromium @@ -41,6 +41,7 @@ cd demos/e2e && npx playwright install chromium | `RESET` | `0` | If `1`, run `docker compose down -v` before bringing the stack up (wipes Postgres). | | `CI` | unset | Setting `CI=true` flips `KEEP_STACK` default to `0` and forces full teardown. | | `HEADED` | `0` | If `1`, launch Chromium headed so you can watch UI tests run. | +| `E2E_BROWSER_EXECUTABLE_PATH` | unset | Optional path to an existing Chromium executable; otherwise uses Playwright's managed browser. | | `SLOWMO` | `0` | Slow-motion delay (ms) for Playwright actions — useful with `HEADED=1`. | | `E2E_API_URL` | `http://localhost:3000` | Backend HTTP base URL. | | `E2E_WS_URL` | `ws://localhost:3000` | Backend WebSocket base URL. | diff --git a/demos/e2e/src/api/telemetry.smoke.test.ts b/demos/e2e/src/api/telemetry.smoke.test.ts index 0fb18998..55c78690 100644 --- a/demos/e2e/src/api/telemetry.smoke.test.ts +++ b/demos/e2e/src/api/telemetry.smoke.test.ts @@ -41,8 +41,6 @@ describe('Telemetry smoke — ClickHouse logs & traces correlation', () => { TraceId: string; }>( `SELECT body AS Body, trace_id AS TraceId FROM signoz_logs.distributed_logs_v2 WHERE trace_id = '${traceId}' FORMAT JSON`, -ace_id = '${traceId}' FORMAT JSON`, - 45_000, 1_000 ); @@ -55,10 +53,8 @@ ace_id = '${traceId}' FORMAT JSON`, const spans = await waitForRows<{ SpanName: string; ServiceName: string; - }>(name AS SpanName, resources_string['service.name'] AS ServiceName FROM signoz_traces.distributed_signoz_index_v3 WHERE trace_id = '${traceId}' FORMAT JSON`, - + }>( `SELECT name AS SpanName, resources_string['service.name'] AS ServiceName FROM signoz_traces.distributed_signoz_index_v3 WHERE trace_id = '${traceId}' FORMAT JSON`, - 45_000, 1_000 ); @@ -67,7 +63,7 @@ ace_id = '${traceId}' FORMAT JSON`, expect(services.has('todo-backend')).toBe(true); }); - it('ClickHouse is reachable and reports recent losignoz_logs.distributed_logs_v2 WHERE toDateTime(intDiv(timestamp, 1000000000)) + it('ClickHouse is reachable and reports recent logs', async () => { const { rows } = await clickhouseQuery<{ recent: string }>( `SELECT toString(count()) AS recent FROM signoz_logs.distributed_logs_v2 WHERE toDateTime(intDiv(timestamp, 1000000000)) >= now() - INTERVAL 1 HOUR FORMAT JSON` ); diff --git a/demos/e2e/src/api/todos.api.test.ts b/demos/e2e/src/api/todos.api.test.ts index fdf28824..edb420cb 100644 --- a/demos/e2e/src/api/todos.api.test.ts +++ b/demos/e2e/src/api/todos.api.test.ts @@ -228,10 +228,17 @@ describe('Todos — attachment & legacyReplace', () => { body: { title: uniqueTitle('attach') } }) ); + const boundary = 'framework-attachment-fixture'; + const uploaded = await r('POST', `/api/todos/${created.id}/attachment`, { + raw: true, + headers: { 'content-type': `multipart/form-data; boundary=${boundary}` }, + body: `--${boundary}\r\nContent-Disposition: form-data; name="attachment"; filename="example.txt"\r\nContent-Type: text/plain\r\n\r\nImmutable query demo\r\n--${boundary}--\r\n` + }); + expect(uploaded.status).toBe(201); const res = await r('GET', `/api/todos/${created.id}/attachment`); expect(res.status).toBe(200); expect(res.headers['content-type']).toMatch(/text\/plain/); - expect(res.body.length).toBeGreaterThan(0); + expect(res.body).toBe('Immutable query demo'); }); it('legacyReplace (PUT) returns a redirect', async () => { diff --git a/demos/e2e/src/support/playwright.ts b/demos/e2e/src/support/playwright.ts index c01df835..bf5239d5 100644 --- a/demos/e2e/src/support/playwright.ts +++ b/demos/e2e/src/support/playwright.ts @@ -11,6 +11,7 @@ let browser: Browser | null = null; async function getBrowser(): Promise { if (!browser) { browser = await chromium.launch({ + executablePath: process.env.E2E_BROWSER_EXECUTABLE_PATH || undefined, headless: !config.headed, slowMo: config.slowMo }); diff --git a/demos/e2e/src/ui/todo-crud.ui.test.ts b/demos/e2e/src/ui/todo-crud.ui.test.ts index 4a93b440..8c252195 100644 --- a/demos/e2e/src/ui/todo-crud.ui.test.ts +++ b/demos/e2e/src/ui/todo-crud.ui.test.ts @@ -62,6 +62,12 @@ describe('UI — todo CRUD', () => { // Detail page after creation await page.waitForURL(/\/todos\/\d+$/, { timeout: 10_000 }); + // Stay on the detail page until its requests settle: an admin-only + // picker lookup must not sign out an ordinary user after creation. + await page.getByRole('button', { name: 'Save Changes', exact: true }).waitFor(); + await page.waitForLoadState('networkidle'); + expect(page.url()).toMatch(/\/todos\/\d+$/); + expect(await page.locator('input').first().inputValue()).toBe(title); const url = page.url(); const todoId = Number(url.match(/\/todos\/(\d+)$/)![1]); diff --git a/demos/todo-backend/src/api/handlers/todos.ts b/demos/todo-backend/src/api/handlers/todos.ts index 0c60aea1..04bc0eef 100644 --- a/demos/todo-backend/src/api/handlers/todos.ts +++ b/demos/todo-backend/src/api/handlers/todos.ts @@ -452,13 +452,13 @@ export const uploadAttachmentHandler: Handler< return ActionResult.created({ id: updated.id, title: updated.title, - description: updated.description, + description: updated.description ?? undefined, completed: updated.completed, userId: updated.userId, createdAt: updated.createdAt, updatedAt: updated.updatedAt, - attachmentName: updated.attachmentName, - attachmentMimeType: updated.attachmentMimeType, + attachmentName: updated.attachmentName ?? undefined, + attachmentMimeType: updated.attachmentMimeType ?? undefined, attachmentSize: file.size }); }; diff --git a/demos/todo-backend/src/api/mappers.ts b/demos/todo-backend/src/api/mappers.ts index eaba2470..74a74b47 100644 --- a/demos/todo-backend/src/api/mappers.ts +++ b/demos/todo-backend/src/api/mappers.ts @@ -7,7 +7,6 @@ import type { TodoActivityResponse } from './schemas.js'; const UserRowSchema = object({ id: number(), email: string(), - passwordHash: string().optional(), role: string(), authProvider: string(), createdAt: date() @@ -16,13 +15,13 @@ const UserRowSchema = object({ const TodoRowSchema = object({ id: number(), title: string(), - description: string().optional(), + description: string().nullable(), completed: boolean(), userId: number(), createdAt: date(), updatedAt: date(), - attachmentName: string().optional(), - attachmentMimeType: string().optional() + attachmentName: string().nullable(), + attachmentMimeType: string().nullable() }); export const mappingRegistry = mapper() @@ -33,6 +32,10 @@ export const mappingRegistry = mapper() m .for(t => t.description) .compute(f => f.description ?? undefined) + .for(t => t.attachmentName) + .compute(f => f.attachmentName ?? undefined) + .for(t => t.attachmentMimeType) + .compute(f => f.attachmentMimeType ?? undefined) .for(t => t.attachmentSize) .ignore() ); @@ -40,7 +43,7 @@ export const mappingRegistry = mapper() const _mapUserFn = mappingRegistry.getMapper(UserRowSchema, UserResponseSchema); const _mapTodoFn = mappingRegistry.getMapper(TodoRowSchema, TodoResponseSchema); -export const mapUser = (row: UserDb) => _mapUserFn(row); +export const mapUser = (row: Omit) => _mapUserFn(row); export const mapTodo = (row: TodoDb) => _mapTodoFn(row); export function mapTodoActivity(row: ActivityDb & Record): TodoActivityResponse { diff --git a/demos/todo-backend/src/db/schemas.ts b/demos/todo-backend/src/db/schemas.ts index 277907e2..6333b074 100644 --- a/demos/todo-backend/src/db/schemas.ts +++ b/demos/todo-backend/src/db/schemas.ts @@ -1,4 +1,5 @@ import { + type EntityResult, array, boolean, date, @@ -144,12 +145,7 @@ const TodoSchema = object({ 'attachmentMimeType' ) .projection('ownership', 'id', 'userId') - .scope( - 'recentFirst', - (q: { - orderBy: (column: string, direction: 'asc' | 'desc') => unknown; - }) => q.orderBy('created_at', 'desc') - ); + .scope('recentFirst', q => q.orderBy('createdAt', 'desc')); export const TodoEntity = defineEntity(TodoSchema) .belongsTo( @@ -187,32 +183,6 @@ export const entityMap: AppEntityMap = { // ── Plain row types (used by mappers) ─────────────────────────────────────── -export type ActivityDb = { - id: number; - todoId: number; - type: string; - actorUserId?: number; - completedAt?: Date | null; - createdAt: Date; -}; - -export type UserDb = { - id: number; - email: string; - passwordHash?: string; - role: string; - authProvider: string; - createdAt: Date; -}; - -export type TodoDb = { - id: number; - title: string; - description?: string; - completed: boolean; - userId: number; - createdAt: Date; - updatedAt: Date; - attachmentName?: string; - attachmentMimeType?: string; -}; +export type ActivityDb = EntityResult; +export type UserDb = EntityResult; +export type TodoDb = EntityResult; diff --git a/demos/todo-frontend/src/features/todos/TodoDetailPage.tsx b/demos/todo-frontend/src/features/todos/TodoDetailPage.tsx index e095545c..c1e58291 100644 --- a/demos/todo-frontend/src/features/todos/TodoDetailPage.tsx +++ b/demos/todo-frontend/src/features/todos/TodoDetailPage.tsx @@ -18,6 +18,7 @@ import { Field, useSchemaForm } from '@cleverbrush/react-form'; import { UpdateTodoBodySchema } from '@cleverbrush/todo-backend/contract'; import { ApiError, isTimeoutError, isNetworkError } from '@cleverbrush/client'; import { client } from '../../api/client'; +import { useAuth } from '../../lib/auth-context'; type TodoEvent = Parameters[0]['body']; import { ConfirmDialog } from '../../components/ConfirmDialog'; @@ -25,6 +26,7 @@ import { ConfirmDialog } from '../../components/ConfirmDialog'; type TodoWithAuthor = Awaited>; export function TodoDetailPage() { + const { isAdmin } = useAuth(); const { id } = useParams<{ id: string }>(); const navigate = useNavigate(); @@ -79,11 +81,13 @@ export function TodoDetailPage() { // Load user list once for the "assigned" picker useEffect(() => { + // The user directory is admin-only. Regular users retain the ID input. + if (!isAdmin) return; client.users .list({ query: { page: 1, limit: 100 } }) .then(rows => setUsers(rows.map(u => ({ id: u.id, email: u.email })))) .catch(() => {/* ignore — picker will fall back to text input */}); - }, []); + }, [isAdmin]); useEffect(() => { load(); }, [load]); diff --git a/docs/assets/immutable-query-demo.png b/docs/assets/immutable-query-demo.png new file mode 100644 index 0000000000000000000000000000000000000000..e73fa294eb084e6b0fa6789725d363dc432f82ae GIT binary patch literal 82574 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%0Dutj9raD3%WEuLGGrn(c@Lb+y)0S3cOjP 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

9gSsbr(mw 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 { + group.where('name', 'Alice'); + group.orWhere('name', 'Bob'); +}); +``` + +After: + +```ts +query(knex, User).where(group => + group.where('name', 'Alice').orWhere('name', 'Bob')); + +db.projects.include(r => r.tasks, tasks => + tasks.where('done', false).orderBy('id').limit(3)); +``` + +Grouped predicates expose predicates only. Scopes expose filters, ordering and +paging, not selection, writes or execution. All Framework customizers must return +a configured builder derived from the supplied one; void, async and unrelated +results are rejected. Configuration callbacks run once when attached. An empty +group must return its input unchanged. Later branches from a retained group cannot +modify the attached query. Transaction work callbacks remain asynchronous. + +Default scopes run once when the source is created. Cloning, inspecting metadata, +rendering SQL and repeated execution do not rerun them. `.unscoped()` removes only +the default scope; explicit predicates remain. It **does not** disable soft deletion: +use `.withDeleted()` or `.onlyDeleted()` explicitly. A default scope and caller OR +groups are combined independently, so OR cannot bypass the default scope. + +## 3. Remove `.withRowSchema()` and use the actual result schema + +Before: + +```ts +const userRead = query(knex, User).withRowSchema() + .select(u => ({ id: u.id, name: u.name })); +``` + +After: + +```ts +export const userRead = query(knex, User) + .select(u => ({ id: u.id, name: u.name })); +export const UserRow = userRead.rowSchema; +``` + +`userRead` is a prepared query, not a schema or a row. `UserRow` describes exactly +the decoded result. Export both from a query module and import the schema into +separate mapper modules; no monolithic query/mapper expression is needed. The +[README](./README.md#definitions-can-live-in-separate-files) has a compiled +four-file example. Filters, ordering, paging and transaction clones retain schema +identity, allowing reuse of prepared mapper registrations. + +`select()` and `projected()` replace the scalar selection on a new query; existing +queries are unchanged. Included relation fields remain independent. Aliased flat +joins need an explicit non-empty selection before reading metadata or executing. +Polymorphic roots expose a union `rowSchema` and per-variant `variantRowSchemas`. +Use `forVariant()` for typed branch projections and retain the discriminator. +Use `selectVariants()` for union narrowing, and common root filters/order/pagination +for the combined result. Table-only operations are not advertised on ORM unions. + +## 4. Adopt one storage representation for reads and writes + +| Storage | Framework row value | +| --- | --- | +| Integer / floating-point column | finite `number` | +| Declared decimal / numeric / bigint | exact `string` | +| Optional / nullable SQL column | present property with a value or `null` | +| SQL date / timestamp | `Date` | +| Missing optional JSON property | absent property | +| Optional object relation / missing collection | `null` / `[]` | + +These rules apply to ordinary reads, nested graphs, ORM reloads, inserts, upserts +and other returning writes. SQL text casts protect exact numbers before driver +parsing. Timezone-less timestamps are interpreted as UTC; JavaScript dates still +have millisecond precision. Input defaults, coercers and preprocessors are not +replayed on persisted rows. Separate request/input schemas from storage schemas; +optional storage fields with input defaults are ambiguous and rejected. + +Before, application code often relied on an omitted optional property: + +```ts +// Previous entity output type: { amount?: number; deletedAt?: Date } +``` + +After, derive the row type from `rowSchema` (or `EntityResult` / `InferDatabaseRow`): + +```ts +// Decimal optional storage: { amount: string | null; deletedAt: Date | null } +// Map SQL null to undefined explicitly when an HTTP DTO omits optional fields. +``` + +Do not blindly convert exact strings to numbers. Use explicit domain conversion +only where rounding is acceptable. Insert/update payloads accept exact storage +values, and bigint optimistic-concurrency versions increment without rounding. + +## 5. Declare complete raw output contracts + +Implicit raw base-query overloads and untyped shape-changing escapes are removed. +Before: + +```ts +const report = query(knex, User, knex('users').count({ total: '*' })); +``` + +After: + +```ts +const Report = object({ total: number().coerce() }); +const report = query(knex, User).apply( + sql => sql.clearSelect().count({ total: '*' }), + { output: Report } +); +// report.rowSchema === Report +const rows = await report; + +const rawRows = await rawQuery(knex, Report, + 'select count(*)::text as total from users where enabled = ?', [true]); +``` + +`selectRaw(sql, bindings, { output })` uses the same contract. The output must be +a synchronous, introspectable Framework object schema. It parses each raw row +**once**, with no entity decoding pass or implicit column-to-property remapping. +Alias SQL columns to output property names and cast exact numeric expressions to +text yourself. SQL and bindings are captured; modifying a retained native builder +after configuration does not affect the query. Async raw callbacks are rejected. +Native Knex configuration is the explicit mutable boundary; return that builder +or `undefined`. Raw queries are read-only and detached. Raw SQL remains trusted +application code, not a sandbox or an authorization mechanism. + +## 6. Keep entity writes and projection reads separate + +Full ORM entity reads still use the identity map when tracking is enabled. Their +objects remain mutable, including the familiar `saveChanges()`, `reload()` and +concurrency flow. Repeated queries can return the same tracked object even though +the query builders are independent. Generated IDs/versions are applied to tracked +objects only after the write transaction commits. + +Selected, grouped, distinct and raw rows are detached. Selecting every scalar +field explicitly is still a projection; it is not implicitly promoted to an entity. +Page containers and scalar results are not tracked. A partial row cannot overwrite +a full tracked entity. Writes through projections, relation-loaded queries or +aggregate queries are rejected both statically and at runtime. Start writes from +an unprojected table query; use ORM `ofVariant()` for polymorphic writes. Paginated +writes require a declared primary key. + +Replace `joinOne` / `joinMany` `foreignQuery`, `mappers` and `orderBy` spec properties +with typed child customizers. Use application mappers after decoding for DTO changes. +Child default scopes and soft deletion apply automatically; disable them explicitly +on the child when that is the intended policy. + +## Upgrade checklist + +- Upgrade the fixed Framework package group together; remove `.withRowSchema()` calls. +- Retain returned queries and return synchronous configuration results. +- Replace raw base queries and shape-changing SQL with explicit output contracts. +- Audit API DTOs for exact numbers, dates, SQL nulls and storage/input separation. +- Migrate relation customizers and polymorphic branch projections. +- Verify identity tracking, writes, transaction rollback and concurrency in the app. +- Run TypeScript, unit and real PostgreSQL tests; test representative endpoint flows. + +This release does not change native Knex itself, make entity objects immutable, +introduce automatic DTO mapping, or guarantee equivalent graph SQL on other dialects. diff --git a/libs/knex-schema/README.md b/libs/knex-schema/README.md index d0f086b9..d820d92c 100644 --- a/libs/knex-schema/README.md +++ b/libs/knex-schema/README.md @@ -2,6 +2,9 @@ Type-safe, schema-driven query builder for [Knex](https://knexjs.org/). Use `@cleverbrush/schema` object builders to describe your PostgreSQL tables — column name mapping, eager loading, and full CRUD are handled automatically with complete TypeScript inference. +This major release makes every Framework query immutable and exposes `.rowSchema` automatically. +See the [migration guide](./MIGRATION-v5.md) before upgrading from v4 or an opt-in read beta. + ## Installation ```bash @@ -32,7 +35,7 @@ const db = knex({ client: 'pg', connection: process.env.DB_URL }); const adults = await query(db, UserSchema) .where(t => t.age, '>', 18) .orderBy(t => t.lastName); -// → typed as Array<{ id: number; firstName: string; lastName: string; age?: number; createdAt: Date }> +// → typed as Array<{ id: number; firstName: string; lastName: string; age: number | null; createdAt: Date }> ``` ## Schema Definition @@ -217,7 +220,7 @@ query(db, UserSchema) ## Eager Loading (No N+1) -Related rows are loaded in a **single query** using PostgreSQL CTEs and `jsonb_agg`. +Related rows are loaded in a **single query** using correlated PostgreSQL subqueries and `jsonb_agg`. ### `joinOne` — one-to-one / many-to-one @@ -248,27 +251,32 @@ const users = await query(db, UserSchema) foreignColumn: t => t.authorId, as: 'posts', limit: 5, - orderBy: { column: t => t.id, direction: 'desc' }, - }); + }, posts => posts.orderBy(t => t.id, 'desc')); // users[0].posts — typed as Array<{ id: number; title: string; authorId: number }> ✓ ``` -The `joinMany` spec supports: -- `limit` / `offset` — per-parent pagination using `row_number()` window functions -- `orderBy` — `{ column, direction }` for the sub-collection -- `foreignQuery` — pre-filtered `Knex.QueryBuilder` (e.g. for soft-delete scopes) -- `required` (`joinOne` only) — `true` = inner join, `false` = left join (nullable result) +The `joinMany` spec accepts per-parent `limit` / `offset`. Return the configured +child from its second argument for filtering, ordering and projection. Child +default scopes and soft-delete filters apply automatically. `joinOne` additionally +accepts `required: false` for nullable related objects; required relations filter +parents without a matching child. Raw `foreignQuery`, `mappers` and `orderBy` spec +properties are replaced by the typed child customizer. --- ## Escape Hatch -When you need a Knex feature not exposed by this API, use `.apply()`: +When Framework cannot infer a SQL shape, declare a complete object output schema. +The Knex callback runs once on an isolated builder. The output parser receives +each raw row once; it does not get an additional entity-decoding pass: ```typescript -const rows = await query(db, UserSchema) - .apply(qb => qb.forUpdate().noWait()) - .where(t => t.id, id); +const Totals = object({ count: number().coerce() }); +const totals = query(db, UserSchema) + .where(t => t.age, '>', 18) + .apply(qb => qb.clearSelect().count({ count: '*' }), { output: Totals }); +const rows = await totals; +// totals.rowSchema === Totals ``` --- @@ -295,7 +303,7 @@ const posts = await query(db, PostSchema) .scoped('published') .scoped('recent'); -// Bypass default scope (also skips soft-delete filter if present) +// Bypass only the default scope; use .withDeleted() separately for soft deletes const all = await query(db, PostSchema).unscoped(); ``` @@ -340,10 +348,12 @@ The accessor receives the schema's property-descriptor tree; each element resolv property name at runtime. This form is more refactor-safe but does not provide the compile-time `Pick<>` narrowing that the tuple form offers. -### Conflict rules +### Projection replacement -`.projected()` cannot be combined with `.select()`, `.distinct()`, or any aggregate -(`.count()`, `.min()`, etc.) on the same query. Attempting to do so throws at runtime. +Each `.select()`, `.projected()`, or aggregate projection returns a new query and +replaces its scalar selection. Previously prepared queries keep their shape. +Included relations remain independent of scalar projections. Projected, grouped, +distinct and joined queries are read-only; begin writes from an unprojected table query. ### Column-name mapping @@ -382,7 +392,7 @@ export const PostEntity = defineEntity(PostSchema) .belongsTo(t => t.author, l => l.authorId, r => r.id); ``` -The returned `Entity` carries the relation map in its type, so downstream `query(db, entity)` +The returned `Entity` carries the relation map in its type, so downstream `query(db, entity.schema)` calls (and `@cleverbrush/orm`'s `DbSet.include()`) get full inference. For many-to-many replacement flows, use the link table directly: delete the @@ -520,16 +530,16 @@ identifier quoting. Existing table/column metadata APIs are not restricted by it The read-only aliased builder requires an explicit, non-empty projection and supports `where`, `whereIn`, `whereNull`, `whereNotNull`, `orderBy`, `orderByRaw`, `groupBy`, `having`, `limit`, `offset`, `first`, `execute`, `transacting`, and -awaiting the query. `apply`/`toKnexQuery` remain raw escape hatches whose effects -on result shape/cardinality are the caller's responsibility. Values remain bound +awaiting the query. `apply` requires `{ output }`; `toKnexQuery()` returns an independent native SQL +snapshot whose execution bypasses Framework decoding. Values remain bound and identifiers quoted. Flat collection joins can repeat parents; they do not deduplicate or fetch one related row at a time. Choose ORM eager loading for nested related objects instead. For reusable connection/transaction handling, ordinary and aliased schemas retain the same inference through `createQuery(knex)`, `withTransaction(trx)`, and -`transaction(callback)`. Only ordinary-schema calls accept a custom Knex base -query. These APIs and their JSDoc are also available through `@cleverbrush/orm`. +`transaction(callback)`. Custom Knex base-query overloads are removed; use `rawQuery(knex, Output, sql)` +or `.apply(configure, { output })` for an explicit raw output contract. These APIs and their JSDoc are also available through `@cleverbrush/orm`. ### Aggregates with optional output schemas @@ -571,9 +581,10 @@ use native SQL values, not decoded/text-formatted values. Counts reject malformed results and integers outside JavaScript's safe range. Sum/average preserve PostgreSQL's result as text without changing global driver parsers. This does not make floating-point source columns exact. Numeric/decimal/ -bigint extrema retain strings; because existing SQL overrides are not fully -represented in schema types, numeric extrema are conservatively typed as -`number | string | null`. Date extrema return `Date | null`. +bigint extrema retain strings; known SQL-type metadata controls their inferred +representation. Ordinary number extrema are `number | null`, exact numeric extrema +are `string | null`, and Date extrema are `Date | null`. Dynamic widened SQL hints +may conservatively infer `number | string | null`. An optional **output schema replaces the default decoder**. Its synchronous `parse` receives the raw driver value, including null, before default conversion. @@ -587,8 +598,8 @@ Scalar helpers clone the source, ignore its limit/offset/order, and retain filters, semantic joins, scopes, and transactions. They reject grouped, HAVING, distinct, and already aggregated queries; use aggregate projections for those. An empty scalar count is zero; other empty/all-null aggregates are null. An -empty grouped query returns no rows. Legacy `.count()`, `.sum()`, etc. keep their -existing behavior and signatures. +empty grouped query returns no rows. `.count()`, `.sum()`, etc. now produce typed +single-field projections with automatically updated row schemas. ### Eager-loading order @@ -653,9 +664,11 @@ URL is missing. CI runs PostgreSQL 16 integration tests alongside unit/type test ## Projection-aware reads -`withRowSchema()` is an **opt-in PostgreSQL read API**. Schema-aware queries are immutable, -detached read plans: capture the returned value when adding filters or includes. -They do not track entities, save changes, or run SQL when inspecting metadata. +Every Framework query is immutable and exposes its decoded `.rowSchema` +automatically. There is no `.withRowSchema()` call or mutable compatibility mode. +Capture returned queries when adding filters, projections or includes. Inspecting +metadata never runs SQL. Ordinary table queries also support writes; projected +results are detached, while full ORM entities can still use identity tracking. ### Definitions can live in separate files @@ -671,7 +684,7 @@ const UserTable = object({ secret: string() }).hasTableName('users'); -export const userRead = createQuery(knex)(UserTable).withRowSchema() +export const userRead = createQuery(knex)(UserTable) .select(u => ({ id: u.id, name: u.name, lastSeen: u.lastSeen })); export const UserRow = userRead.rowSchema; ``` @@ -725,10 +738,10 @@ are rejected. A widened dynamic numeric SQL type has a conservative `number | string` read type. Driver custom parsers must still honor the declared representation, or decoding fails. -Timezone-less SQL dates/timestamps are interpreted as UTC in this opt-in mode; +Timezone-less SQL dates/timestamps are interpreted as UTC; explicit offsets preserve their instant. Native date fields are projected as text before decoding, so root and nested values do not depend on a driver's local-time -date parser. This is a deliberate opt-in convention, not a change to legacy reads. +date parser. This applies to ordinary reads, nested graphs and write-returning rows. Input defaults, preprocessors and input-only validators are not replayed on stored rows. Read schemas are structural output schemas. Optional schemas with input @@ -743,7 +756,7 @@ in private text columns, independently of the public date values. ### Projections, aliases and aggregates ```ts -const read = query(knex, alias(UserTable, 'user')).withRowSchema() +const read = query(knex, alias(UserTable, 'user')) .leftJoin(alias(ProfileTable, 'profile'), t => eq(t.user.id, t.profile.userId)) .select(t => ({ id: t.user.id, displayName: t.profile.displayName })); // displayName is nullable even if ProfileTable declares it required. @@ -756,7 +769,7 @@ Aliased reads require an explicit selection before execution or accessing readers. Typed aggregates work in object selections: count returns a safe number, sum/average preserve exact text, and empty extrema/sums remain nullable. An explicit Framework output schema replaces aggregate decoding and is parsed once; opaque -parser objects without schema introspection are rejected in this mode. +parser objects without schema introspection cannot supply projection metadata. ### Filtering and ordering without changing the result schema @@ -807,10 +820,11 @@ export function searchUsers(tenantId: number, term: string, priorityUserId: numb The outer tenant filter applies to the **entire** search group. Group callbacks are synchronous and run once when the predicate is attached, not during SQL -execution. Their scoped builder accumulates predicates, has no selection, join, -ordering, mutation, or execution methods, and is closed after the callback. -Return the provided group builder or nothing. An empty group adds no condition. -Async callbacks and returned thenables are rejected; thenables are not executed. +execution. Their predicate-only builder is immutable too: it has no selection, +join, ordering, write or execution methods. Return the configured group; a void +return, async result or unrelated builder is rejected. An empty group returned +unchanged adds no condition. Retaining a group and deriving another branch later +cannot change the already-attached predicates. `ref()` resolves mapped columns and generated aliases for ordinary readers, explicit aliases for joined readers, and the correct child alias inside relation @@ -829,18 +843,20 @@ change the prepared reader. Empty IN lists match no rows; empty NOT IN lists match all rows, with ordinary SQL null semantics for non-empty lists/subqueries. These operations also work in ordinary ORM reads and nested relation customizers. -For polymorphic reads, use them inside `forVariant()`; the union root does not -offer raw filtering or ordering. Numbered pagination retains raw ordering while +Polymorphic roots also offer common-property predicates, including bound raw +filters. Use `forVariant()` for branch-specific predicates, projections and raw +ordering; root `orderBy()` orders the union globally. Numbered pagination retains raw ordering while its count drops ordering/limits/offsets. `paginateAfter()` uses its explicit complete `orderBy` specification, replacing prior ordering, including raw order. -No unrestricted `.apply()` or raw result-shape mutation is available in read mode. +Opaque SQL changes require `.apply(configure, { output })` or +`.selectRaw(sql, bindings, { output })`; the declared schema owns raw row parsing. ### Nested graphs Declare relations on entities as usual, and return the child query from customizers: ```ts -const read = db.projects.withRowSchema() +const read = db.projects .select(p => ({ id: p.id, name: p.name })) .include(r => r.tasks, tasks => tasks .select(t => ({ title: t.title, createdAt: t.createdAt })) @@ -871,7 +887,7 @@ default. Use `selectVariants(['photo'])` to narrow the returned union, or `forVariant()` to project a branch or load its relations: ```ts -const read = db.assets.withRowSchema() +const read = db.assets .forVariant('photo', q => q.include(r => r.tags)) .forVariant('text', q => q.select(a => ({ id: a.id, kind: a.kind, body: a.body }))); @@ -894,20 +910,22 @@ branch separately. Use `forVariant()` for branch-specific filtering/includes. ### API boundaries -- Enter read mode **before** legacy select/include/join, ordering/pagination, - raw callbacks or variant-specific operations. Continue configuration on the - immutable reader. Default scopes may filter rows but must not preselect, - order or paginate them. -- The opt-in surface is deliberately read-only. It is not a replacement for - entity writes or tracked queries, and has no raw SQL shape escape hatch. -- Reads are PostgreSQL-oriented; this does not promise equivalent JSON/CTI SQL - behavior on other Knex dialects. -- Declared graph metadata must match storage. Unsupported opaque shapes throw - rather than pretending an entity schema describes their output. Explicit - TypeScript assertions such as `hasType()` remain the caller's responsibility. -- Ordinary queries are mutable and retain their driver-value behavior. - Read mode is opt-in; it does not change application nulls or numeric values - globally. +- Query configuration is immutable across tables, aliases, polymorphic roots and + ORM entry points. Native Knex remains mutable only inside explicit raw callbacks + or separately obtained snapshots. +- Scopes are synchronous, shape-preserving callbacks. Return their configured + query. They can filter, order and paginate; they cannot select, load relations, + execute or write. Defaults are captured once when creating the query, not on + every render/execution. `unscoped()` preserves explicit filters and soft deletion. +- Writes require an unprojected, ungrouped, non-distinct table query with no loaded + relations. A primary key is required to target a limited/offset write safely. + Polymorphic writes use ORM `ofVariant()` instead of a union query. +- Reads and JSON/CTI SQL are PostgreSQL-oriented; equivalent behavior is not + promised on other Knex dialects. Schema metadata must match actual storage. +- Raw outputs require synchronous, introspectable Framework object schemas. They + are detached and read-only. Explicit assertions such as `hasType()` remain the + caller's responsibility. Use SQL aliases matching output property names and + text casts for exact numbers before driver parsing. - `getSyncMapper()` accepts only complete mappings with synchronous final steps and nested mappings. It never probes callbacks. Known async mappings are rejected; a disguised thenable throws when invoked. Keep `getMapper()` for diff --git a/libs/knex-schema/integration/immutable-queries.test.ts b/libs/knex-schema/integration/immutable-queries.test.ts new file mode 100644 index 00000000..c519f797 --- /dev/null +++ b/libs/knex-schema/integration/immutable-queries.test.ts @@ -0,0 +1,375 @@ +import { randomUUID } from 'node:crypto'; +import { + alias, + boolean, + ConcurrencyError, + createDb, + date, + defineEntity, + number, + object, + query, + rawQuery, + string +} from '@cleverbrush/orm'; +import Knex from 'knex'; +import { + afterAll, + beforeAll, + beforeEach, + describe, + expect, + it, + vi +} from 'vitest'; + +const connection = process.env.QUERY_TEST_DATABASE_URL; +if (!connection) throw new Error('QUERY_TEST_DATABASE_URL is required'); +const knex = Knex({ client: 'pg', connection, pool: { min: 0, max: 4 } }); +const table = `cb_immutable_${randomUUID().replaceAll('-', '')}`; +const firstId = '9007199254740993'; +const secondId = '9007199254740994'; +const otherId = '9007199254740995'; +const scope = vi.fn(q => q.where('tenantId', 1).where('enabled', true)); +const Account = object({ + id: number().bigint().primaryKey(), + tenantId: number().hasColumnName('tenant_id'), + enabled: boolean(), + name: string(), + balance: number().decimal(30, 6), + version: number().bigint().rowVersion(), + createdAt: date().hasColumnName('created_at'), + deletedAt: date().optional().hasColumnName('deleted_at') +}) + .hasTableName(table) + .softDelete() + .defaultScope(scope); +const Entity = defineEntity(Account); + +beforeAll(async () => { + await knex.schema.createTable(table, t => { + t.bigInteger('id').primary(); + t.integer('tenant_id').notNullable(); + t.boolean('enabled').notNullable(); + t.text('name').notNullable(); + t.decimal('balance', 30, 6).notNullable(); + t.bigInteger('version').notNullable().defaultTo('9007199254740993'); + t.timestamp('created_at', { useTz: true }) + .notNullable() + .defaultTo(knex.fn.now()); + t.timestamp('deleted_at', { useTz: true }); + }); +}); +beforeEach(async () => { + await knex(table).delete(); + await knex(table).insert([ + { + id: firstId, + tenant_id: 1, + enabled: true, + name: 'first', + balance: '12345678901234567890.012345' + }, + { + id: secondId, + tenant_id: 1, + enabled: true, + name: 'second', + balance: '0.000001' + }, + { + id: otherId, + tenant_id: 2, + enabled: false, + name: 'other', + balance: '9.000001' + } + ]); + scope.mockClear(); +}); +afterAll(async () => { + await knex.schema.dropTableIfExists(table); + await knex.destroy(); +}); + +describe('immutable public query semantics against PostgreSQL', () => { + it('inserts exact CTI keys and filters mapped polymorphic columns without losing the discriminator', async () => { + const baseName = `${table}_poly`; + const detailsName = `${table}_details`; + await knex.transaction(async trx => { + await trx.schema.createTable(baseName, t => { + t.bigInteger('asset_id').primary(); + t.text('asset_kind').notNullable(); + t.text('display_name').notNullable(); + }); + await trx.schema.createTable(detailsName, t => { + t.bigInteger('asset_id').primary(); + t.bigInteger('size').notNullable(); + }); + const Asset = defineEntity( + object({ + id: number() + .bigint() + .primaryKey() + .hasColumnName('asset_id'), + kind: string().hasColumnName('asset_kind'), + name: string().hasColumnName('display_name') + }).hasTableName(baseName) + ) + .discriminator('kind') + .ctiVariant( + 'photo', + defineEntity( + object({ + assetId: number() + .bigint() + .hasColumnName('asset_id'), + size: number().bigint() + }).hasTableName(detailsName) + ), + p => p.assetId + ); + const db = createDb(trx, { assets: Asset }, { tracking: true }); + const inserted = await db.assets + .ofVariant('photo') + .insert({ id: firstId, name: 'photo', size: secondId }); + expect(inserted).toMatchObject({ + id: firstId, + kind: 'photo', + name: 'photo', + size: secondId + }); + expect( + await db.assets + .where('name', 'photo') + .where('kind', 'photo') + .first() + ).toBe(inserted); + const page = await db.assets + .orderBy('id') + .paginate({ page: 1, pageSize: 1 }); + expect(page.total).toBe(1); + expect(page.data[0]).toBe(inserted); + expect(() => db.entry(page as any)).toThrow(/not tracked/i); + const variantPage = await db.assets + .ofVariant('photo') + .paginate({ page: 1, pageSize: 1 }); + expect(variantPage.data[0]).toBe(inserted); + expect(() => db.entry(variantPage as any)).toThrow(/not tracked/i); + const bindings = ['id']; + const rawOrdered = db.assets.orderByRaw( + '(__read_poly ->> ?)::numeric desc', + bindings + ); + bindings[0] = 'missing'; + expect((await rawOrdered)[0]).toBe(inserted); + expect(db.entry(inserted).isModified()).toBe(false); + inserted.size = otherId; + expect(db.entry(inserted).isModified()).toBe(true); + expect((await db.saveChanges()).updated).toBe(1); + expect((await trx(detailsName).first()).size).toBe(otherId); + expect(db.entry(inserted).isModified()).toBe(false); + await trx.schema.dropTable(detailsName); + await trx.schema.dropTable(baseName); + }); + }); + + it('captures scopes once, isolates branches and does not let OR bypass visibility', async () => { + const root = query(knex, Account); + const first = root.where('id', firstId); + const withAlternative = first.orWhere('id', otherId); + expect((await withAlternative).map(row => row.id)).toEqual([firstId]); + expect((await root).map(row => row.id)).toEqual([firstId, secondId]); + expect((await withAlternative.unscoped()).map(row => row.id)).toEqual([ + firstId, + otherId + ]); + expect(scope).toHaveBeenCalledTimes(1); + expect(first.rowSchema).toBe(root.rowSchema); + }); + + it('keeps scoped writes independent and applies scope/predicates to bulk updates', async () => { + const root = query(knex, Account); + const first = root.where('id', firstId); + expect( + await first.bulkUpdate([ + { where: { id: firstId }, set: { name: 'changed' } }, + { where: { id: secondId }, set: { name: 'wrong sibling' } }, + { where: { id: otherId }, set: { name: 'wrong tenant' } } + ]) + ).toBe(1); + expect((await root.orderBy('id')).map(row => row.name)).toEqual([ + 'changed', + 'second' + ]); + expect((await root.unscoped().where('id', otherId).first())?.name).toBe( + 'other' + ); + expect( + (await first.update({ balance: '12345678901234567890.999999' }))[0] + .balance + ).toBe('12345678901234567890.999999'); + expect(await root.where('id', secondId).delete()).toBe(1); + expect((await root).map(row => row.id)).toEqual([firstId]); + const restored = await root.onlyDeleted().restore(); + expect(restored[0].id).toBe(secondId); + expect(restored[0].deletedAt).toBeNull(); + }); + + it('decodes insert, conflict and bulk returning rows identically to SELECT', async () => { + const root = query(knex, Account); + const inserted = await root.insert({ + id: '9007199254740996', + tenantId: 1, + enabled: true, + name: 'inserted', + balance: '4.123456' + }); + expect(inserted).toMatchObject({ + id: '9007199254740996', + balance: '4.123456', + version: firstId, + deletedAt: null + }); + expect(inserted.createdAt).toBeInstanceOf(Date); + expect(await root.where('id', inserted.id).first()).toEqual(inserted); + const merged = await root.onConflict('id').merge({ + id: inserted.id, + tenantId: 1, + enabled: true, + name: 'merged', + balance: '5.123456' + }); + expect(merged).toMatchObject({ + id: inserted.id, + balance: '5.123456', + deletedAt: null + }); + const rows = await root.bulkInsert([ + { + id: '9007199254740997', + tenantId: 1, + enabled: true, + name: 'bulk', + balance: '6.123456' + } + ]); + expect(rows[0].createdAt).toBeInstanceOf(Date); + expect(rows[0].version).toBe(firstId); + expect(await root.insertMany([])).toEqual([]); + }); + + it('maintains tracked identity through immutable branches and page data only', async () => { + const tracked = createDb( + knex, + { accounts: Entity }, + { tracking: true } + ); + const root = tracked.accounts.query(); + const one = root.where('id', firstId); + const a = (await one)[0]; + expect((await one)[0]).toBe(a); + expect(await root.find(firstId)).toBe(a); + const page = await root + .orderBy('id') + .paginate({ page: 1, pageSize: 1 }); + expect(page.data[0]).toBe(a); + expect(() => tracked.entry(page as any)).toThrow(/not tracked/i); + const projected = await one + .select(t => ({ id: t.id, name: t.name })) + .first(); + expect(projected).not.toBe(a); + expect(() => tracked.entry(projected!)).toThrow(/not tracked/i); + const raw = await one + .selectRaw('id::text as id', [], { + output: object({ id: string() }) + }) + .first(); + expect(() => tracked.entry(raw!)).toThrow(/not tracked/i); + expect(tracked.entry(a).state).toBe('Unchanged'); + }); + + it('increments exact bigint versions and reloads using the same decoded shape', async () => { + const tracked = createDb( + knex, + { accounts: Entity }, + { tracking: true } + ); + const a = await tracked.accounts.findOrFail(firstId); + a.name = 'saved'; + await tracked.saveChanges(); + expect(a.version).toBe(secondId); + expect(tracked.entry(a).state).toBe('Unchanged'); + await knex(table).where('id', firstId).update({ + balance: '12345678901234567890.999998', + deleted_at: knex.fn.now() + }); + await tracked.reload(a); + expect(a.balance).toBe('12345678901234567890.999998'); + expect(a.createdAt).toBeInstanceOf(Date); + expect(a.deletedAt).toBeInstanceOf(Date); + }); + + it('rolls back writes and generated in-memory versions on a later concurrency failure', async () => { + const tracked = createDb( + knex, + { accounts: Entity }, + { tracking: true } + ); + const a = await tracked.accounts.findOrFail(firstId); + const b = await tracked.accounts.findOrFail(secondId); + a.name = 'pending first'; + b.name = 'pending second'; + await knex(table).where('id', secondId).update({ version: secondId }); + await expect(tracked.saveChanges()).rejects.toBeInstanceOf( + ConcurrencyError + ); + expect(a.version).toBe(firstId); + expect(b.version).toBe(firstId); + expect( + (await query(knex, Account).where('id', firstId).first())?.name + ).toBe('first'); + expect(tracked.entry(a).isModified()).toBe(true); + await tracked.reload(b); + await tracked.saveChanges(); + expect(a.version).toBe(secondId); + }); + + it('captures raw aliases and bindings while applying a parser exactly once', async () => { + const output = object({ count: number().coerce() }); + const parse = vi.spyOn(output, 'parse'); + const root = query(knex, alias(Account, 'account')).where( + t => t.account.id, + firstId + ); + const raw = root.selectRaw('count(*)::text as count', [], { output }); + expect(await raw).toEqual([{ count: 1 }]); + expect(parse).toHaveBeenCalledTimes(1); + expect( + await rawQuery( + knex, + object({ id: string() }), + knex(table) + .select(knex.raw('id::text as id')) + .where('id', firstId) + ) + ).toEqual([{ id: firstId }]); + }); + + it('allows filtered writes without a declared primary key when not paginated', async () => { + const NoKey = object({ name: string() }).hasTableName(table); + expect( + await query(knex, NoKey) + .where('name', 'other') + .update({ name: 'updated without key' }) + ).toEqual([{ name: 'updated without key' }]); + expect( + await query(knex, NoKey) + .where('name', 'updated without key') + .delete() + ).toBe(1); + await expect( + query(knex, NoKey).limit(1).update({ name: 'unsafe' }) + ).rejects.toThrow(/primary key/); + }); +}); diff --git a/libs/knex-schema/integration/queries.test.ts b/libs/knex-schema/integration/queries.test.ts index 0609dd02..c033de8b 100644 --- a/libs/knex-schema/integration/queries.test.ts +++ b/libs/knex-schema/integration/queries.test.ts @@ -74,7 +74,7 @@ const taskEntity = defineEntity(Task) const db = createDb(knex, { tasks: taskEntity }); it('transaction clones retain row schemas and raw-query safety guards', async () => { - const read = db.tasks.withRowSchema().select(t => ({ title: t.title })); + const read = db.tasks.select(t => ({ title: t.title })); await knex.transaction(async trx => { const inTransaction = read.transacting(trx); expect(inTransaction.rowSchema).toBe(read.rowSchema); @@ -82,13 +82,12 @@ it('transaction clones retain row schemas and raw-query safety guards', async () await read.where(t => t.id, 104).first() ); expect(() => - query(knex, Task) + query(knex, taskEntity.schema) .apply(q => { q.whereRaw('true'); }) .transacting(trx) - .withRowSchema() - ).toThrow(/before raw/); + ).toThrow(/output/); }); }); @@ -98,9 +97,7 @@ it('schema-aware reads stay detached in a tracked context', async () => { const listener = (sql: unknown) => calls.push(sql); knex.on('query', listener); try { - const read = tracked.tasks - .withRowSchema() - .select(t => ({ id: t.id, title: t.title })); + const read = tracked.tasks.select(t => ({ id: t.id, title: t.title })); expect(calls).toHaveLength(0); const row = await read.where(t => t.id, 102).first(); expect(calls).toHaveLength(1); @@ -112,8 +109,8 @@ it('schema-aware reads stay detached in a tracked context', async () => { }); it('schema-aware explicit joins preserve nullable objects and custom collections', async () => { - const read = query(knex, Task) - .withRowSchema() + const read = query(knex, taskEntity.schema) + .select(t => ({ id: t.id })) .joinOne( { @@ -152,7 +149,7 @@ it('schema-aware optional belongs-to joins keep unmatched parents', async () => { optional: true } ); const read = query(knex, optional.schema) - .withRowSchema() + .select(t => ({ id: t.id })) .include( r => r.owner, @@ -166,7 +163,7 @@ it('schema-aware optional belongs-to joins keep unmatched parents', async () => it('schema-aware flat joins preserve precision and scoped outer join nulls', async () => { const read = query(knex, alias(Task, 'task')) - .withRowSchema() + .leftJoin(alias(User, 'owner'), t => eq(t.task.ownerId, t.owner.id)) .select(t => ({ id: t.task.id, @@ -190,7 +187,7 @@ it('schema-aware flat joins preserve precision and scoped outer join nulls', asy it('schema-aware cursor pages keep microsecond ordering private', async () => { const read = db.tasks - .withRowSchema() + .select(t => ({ title: t.title })) .include(r => r.notes) .where(t => t.projectId, 1); @@ -321,7 +318,7 @@ afterAll(async () => { describe('flat joins', () => { it('reads exact values and selected relation schemas without hidden queries', async () => { const read = db.tasks - .withRowSchema() + .select(t => ({ id: t.id, amount: t.amount, @@ -353,14 +350,12 @@ describe('flat joins', () => { ]); expect(read.rowSchema.validate(rows[0]).valid).toBe(true); const exact = await db.tasks - .withRowSchema() + .where(t => t.id, 102) .select(t => ({ amount: t.amount })) .first(); expect(exact).toEqual({ amount: '9007199254740993.000001' }); - const AmountRow = db.tasks - .withRowSchema() - .select(t => ({ amount: t.amount })); + const AmountRow = db.tasks.select(t => ({ amount: t.amount })); const PublicAmount = object({ amount: string().optional() }); const toPublic = mapper() .configure(AmountRow.rowSchema, PublicAmount, m => @@ -377,7 +372,7 @@ describe('flat joins', () => { it('decodes typed aggregate outputs once in schema-aware reads', async () => { const read = db.tasks - .withRowSchema() + .where(t => t.projectId, 1) .select(t => ({ count: aggregate.count(), @@ -476,7 +471,10 @@ describe('eager ordering', () => { .orderBy(t => t.title) .orderBy(t => t.id, 'desc') .include(t => t.notes) - .include(t => t.owner) + .include( + t => t.owner, + owner => owner.unscoped().withDeleted() + ) .limit(2); expect(rows.map(row => row.id)).toEqual([104, 103]); expect(rows[0].notes).toHaveLength(2); @@ -488,7 +486,7 @@ describe('eager ordering', () => { it('handles projected-away sort/FK fields, mapped aliases, raw bindings, offset and transactions', async () => { await knex.transaction(async trx => { - const rows = await query(knex, Task) + const rows = await query(knex, taskEntity.schema) .where(t => t.projectId, 1) .orderByRaw('case when ?? = ? then 0 else 1 end, ?? desc', [ 'id', @@ -513,7 +511,7 @@ describe('eager ordering', () => { it('retains distinct/grouped parent cardinality', async () => { for (const distinct of [true, false]) { - let q = query(knex, Task) + let q = query(knex, taskEntity.schema) .where(t => t.projectId, 1) .select(t => ({ owner_id: t.ownerId })) .orderBy(t => t.ownerId); @@ -533,7 +531,7 @@ describe('eager ordering', () => { '"taskId" desc', '1 desc' ])('retains ordering by a projected alias or position: %s', async order => { - const rows = await query(knex, Task) + const rows = await query(knex, taskEntity.schema) .where(t => t.projectId, 1) .select(t => ({ taskId: t.id })) .orderByRaw(order) @@ -563,11 +561,10 @@ describe('aggregate results', () => { .include(t => t.notes) .countValue() ).toBe(4); - const visibleOwner = query(knex, Task) + const visibleOwner = query(knex, taskEntity.schema) .where(t => t.projectId, 1) .joinOne({ foreignSchema: User, - foreignQuery: query(knex, User), localColumn: t => t.ownerId, foreignColumn: t => t.id, as: 'owner', @@ -580,20 +577,22 @@ describe('aggregate results', () => { }); it('retains default-scope filters while ignoring default-scope pagination', async () => { - const Scoped = object({ id: number().primaryKey() }) + const Scoped = object({ + id: number().primaryKey(), + projectId: number().hasColumnName('project_id'), + deletedAt: date().optional().hasColumnName('deleted_at') + }) .hasTableName(tables.tasks) .defaultScope((q: any) => q - .where('project_id', 1) - .whereNull('deleted_at') + .where('projectId', 1) + .whereNull('deletedAt') .limit(1) .offset(1) ); expect(await query(knex, Scoped).countValue()).toBe(4); const Grouped = Scoped.defaultScope((q: any) => q.groupBy('id')); - await expect(query(knex, Grouped).countValue()).rejects.toThrow( - 'ungrouped' - ); + expect(() => query(knex, Grouped)).toThrow(/Scopes/); }); it('preserves sum/average/decimal extrema and returns date/string extrema', async () => { @@ -615,7 +614,7 @@ describe('aggregate results', () => { }); it('handles empty/all-null inputs and caller-supplied parsers', async () => { - const empty = () => query(knex, Task).where(t => t.id, -1); + const empty = () => query(knex, taskEntity.schema).where(t => t.id, -1); expect(await empty().countValue()).toBe(0); for (const method of [ 'sumValue', @@ -626,12 +625,12 @@ describe('aggregate results', () => { expect(await empty()[method]('amount')).toBe(null); } expect( - await query(knex, Task) + await query(knex, taskEntity.schema) .where(t => t.id, 103) .sumValue(t => t.amount) ).toBe(null); expect( - await query(knex, Task) + await query(knex, taskEntity.schema) .where(t => t.id, 105) .sumValue(t => t.amount, { output: number().isFloat().coerce() @@ -643,7 +642,7 @@ describe('aggregate results', () => { }); it('decodes every grouped aggregate without treating rows as entities', async () => { - const rows = await query(knex, Task) + const rows = await query(knex, taskEntity.schema) .where(t => t.projectId, 1) .groupBy(t => t.ownerId) .orderBy(t => t.ownerId) @@ -671,14 +670,14 @@ describe('aggregate results', () => { max: 'A' }); await expect( - query(knex, Task) + query(knex, taskEntity.schema) .groupBy(t => t.ownerId) .countValue() ).rejects.toThrow('ungrouped'); }); it('retains source state and transaction visibility', async () => { - const base = query(knex, Task) + const base = query(knex, taskEntity.schema) .where(t => t.projectId, 1) .select(t => ({ id: t.id })) .limit(1); @@ -745,11 +744,10 @@ describe('aggregate results', () => { describe('composite cursor pages', () => { it('applies required relation filters before testing whether another page exists', async () => { const base = () => - query(knex, Task) + query(knex, taskEntity.schema) .where(t => t.projectId, 1) .joinOne({ foreignSchema: User, - foreignQuery: query(knex, User), localColumn: t => t.ownerId, foreignColumn: t => t.id, as: 'owner', @@ -769,7 +767,7 @@ describe('composite cursor pages', () => { it('does not skip tied timestamps and retains microsecond precision with projections and includes', async () => { const base = () => - query(knex, Task) + query(knex, taskEntity.schema) .where(t => t.projectId, 1) .select(t => ({ taskId: t.id })) .joinMany({ @@ -813,7 +811,7 @@ describe('composite cursor pages', () => { .where(t => t.projectId, -1) .paginateAfter({ limit: 1, orderBy }); expect(empty).toEqual({ data: [], hasMore: false, nextCursor: null }); - const projected = await query(knex, Task) + const projected = await query(knex, taskEntity.schema) .where(t => t.projectId, 1) .select(t => t.id) .paginateAfter({ limit: 2, orderBy }); @@ -847,7 +845,7 @@ describe('composite cursor pages', () => { it('groups an existing OR filter before applying continuation predicates', async () => { const base = () => - query(knex, Task) + query(knex, taskEntity.schema) .where(t => t.id, 105) .orWhere(t => t.id, 104); const first = await base().paginateAfter({ limit: 1, orderBy }); diff --git a/libs/knex-schema/integration/read-graphs.test.ts b/libs/knex-schema/integration/read-graphs.test.ts index fac586db..2cf4763e 100644 --- a/libs/knex-schema/integration/read-graphs.test.ts +++ b/libs/knex-schema/integration/read-graphs.test.ts @@ -138,7 +138,7 @@ afterAll(async () => { describe('schema-aware polymorphic graphs', () => { it('allows schema-preserving predicates inside an explicit variant branch', async () => { const read = db.assets - .withRowSchema() + .selectVariants(['photo']) .forVariant('photo', photo => photo @@ -155,7 +155,7 @@ describe('schema-aware polymorphic graphs', () => { }); it('orders using native values even when branch projections omit sort fields', async () => { const read = db.assets - .withRowSchema() + .forVariant('photo', q => q.select(a => ({ id: a.id, kind: a.kind })) ) @@ -171,14 +171,12 @@ describe('schema-aware polymorphic graphs', () => { { id: 1, kind: 'photo' } ]); expect(() => - db.assets - .withRowSchema() - .forVariant('text', q => q.select(a => ({ id: a.id }))) + db.assets.forVariant('text', q => q.select(a => ({ id: a.id }))) ).toThrow(/retain.*discriminator/); }); it('exposes exact branch schemas, dates and numeric ordering in one statement', async () => { const read = db.assets - .withRowSchema() + .forVariant('photo', q => q.include( r => r.labels, @@ -221,7 +219,7 @@ describe('schema-aware polymorphic graphs', () => { it('decodes nested polymorphic relations and empty arrays without hidden fetches', async () => { const read = db.albums - .withRowSchema() + .include( r => r.assets, assets => @@ -259,25 +257,20 @@ describe('schema-aware polymorphic graphs', () => { ]); try { await expect( - db.assets - .withRowSchema() - .where(a => a.id, 3) - .execute() + db.assets.where(a => a.id, 3).execute() ).rejects.toThrow('unknown polymorphic discriminator'); await expect( - db.assets - .withRowSchema() - .where(a => a.id, 4) - .execute() + db.assets.where(a => a.id, 4).execute() ).rejects.toThrow('missing CTI variant body'); const tolerant = defineEntity(Asset.schema) .discriminator(a => a.kind) .ctiVariant('photo', Photo, p => p.assetId, { allowOrphan: true }); - const reader = createDb(knex, { assets: tolerant }) - .assets.withRowSchema() - .where(a => a.id, 4); + const reader = createDb(knex, { assets: tolerant }).assets.where( + a => a.id, + 4 + ); const orphan = await reader.first(); expect(orphan).toMatchObject({ id: 4, diff --git a/libs/knex-schema/integration/read-predicates.test.ts b/libs/knex-schema/integration/read-predicates.test.ts index ad2c439c..8e7af343 100644 --- a/libs/knex-schema/integration/read-predicates.test.ts +++ b/libs/knex-schema/integration/read-predicates.test.ts @@ -148,11 +148,10 @@ afterAll(async () => { describe('schema-aware read predicates against PostgreSQL', () => { it('keeps outer access filters around grouped raw search and correlated EXISTS', async () => { - const base = query(knex, alias(Task, 'task')) - .withRowSchema() - .join(alias(Project, 'project'), t => - eq(t.task.projectId, t.project.id) - ); + const base = query(knex, alias(Task, 'task')).join( + alias(Project, 'project'), + t => eq(t.task.projectId, t.project.id) + ); const linked = query(knex, Link) .where(l => l.labelId, 2) .where( @@ -213,7 +212,7 @@ describe('schema-aware read predicates against PostgreSQL', () => { .select(l => l.id) .toKnexQuery(); const read = query(knex, alias(Label, 'label')) - .withRowSchema() + .leftJoin(alias(Link, 'link'), t => eq(t.label.id, t.link.labelId)) .whereIn(t => t.label.id, page) .groupBy( @@ -232,7 +231,7 @@ describe('schema-aware read predicates against PostgreSQL', () => { it('uses raw conditional ordering with independent ordinary numbered and cursor pages', async () => { const source = query(knex, Project) - .withRowSchema() + .where(p => p.ownerId, 1) .select(p => ({ id: p.id, name: p.name })); const priority = source @@ -264,7 +263,7 @@ describe('schema-aware read predicates against PostgreSQL', () => { it('orders aliased reads with bound CASE expressions and retains nullable left joins', async () => { const source = query(knex, alias(Project, 'project')) - .withRowSchema() + .leftJoin(alias(Task, 'task'), t => eq(t.project.id, t.task.projectId) ) @@ -279,7 +278,7 @@ describe('schema-aware read predicates against PostgreSQL', () => { expect((await result)[0]).toEqual({ id: 2, taskId: 103 }); expect(result.rowSchema).toBe(source.rowSchema); const empty = query(knex, alias(Project, 'project')) - .withRowSchema() + .leftJoin(alias(Label, 'label'), t => eq(t.project.id, t.label.projectId) ) @@ -298,7 +297,7 @@ describe('schema-aware read predicates against PostgreSQL', () => { { tracking: true } ); const source = db.projects - .withRowSchema() + .select(p => ({ id: p.id })) .include( p => p.tasks, @@ -345,9 +344,7 @@ describe('schema-aware read predicates against PostgreSQL', () => { }); it('preserves captured predicates in transaction clones without touching the source', async () => { - const read = query(knex, Task) - .withRowSchema() - .where(t => t.projectId, 1); + const read = query(knex, Task).where(t => t.projectId, 1); const noLabels = knex(names.links) .select('task_id') .where( diff --git a/libs/knex-schema/src/AliasedReadQuery.ts b/libs/knex-schema/src/AliasedQueryBuilder.ts similarity index 79% rename from libs/knex-schema/src/AliasedReadQuery.ts rename to libs/knex-schema/src/AliasedQueryBuilder.ts index dd60da2b..d7cebc8c 100644 --- a/libs/knex-schema/src/AliasedReadQuery.ts +++ b/libs/knex-schema/src/AliasedQueryBuilder.ts @@ -1,7 +1,7 @@ import { type InferType, object } from '@cleverbrush/schema'; import type { Knex } from 'knex'; import type { - AliasedQueryBuilder, + AliasedQuerySource, AliasTables, JoinPredicate, TableAlias @@ -11,8 +11,10 @@ import { type AliasedColumn, COLUMN } from './expressions.js'; +import { OpaqueQuery, type QueryOutput } from './OpaqueQuery.js'; import { captureReadRaw, + captureValue, type ReadPredicate, type ReadPredicateContext, ReadPredicates @@ -26,7 +28,7 @@ import { type ReadValue, type SchemaForValue } from './read-schema.js'; -import type { ReadColumn, ReadProjection } from './SchemaReadQuery.js'; +import type { ReadColumn, ReadProjection } from './SchemaQueryBuilder.js'; /** Schema-backed aliases whose exact numeric and outer-join values match decoded rows. */ export type ReadAliasTables = { @@ -42,15 +44,15 @@ type Selection = Record | AggregateExpression>; type Selector = (tables: ReadAliasTables) => AliasedColumn; /** Immutable flat joined read. Supply select() before accessing rowSchema or executing. */ -export class AliasedReadQuery< +export class AliasedQueryBuilder< T, Row extends ReadObject = never > extends ReadPredicates> { private fields?: Record; private schema?: Row; private predicates: readonly ReadPredicate[] = []; - /** @internal Enter through an aliased query's withRowSchema() method. */ - constructor(private planner: AliasedQueryBuilder) { + /** @internal Create through query(knex, alias(schema, name)). */ + constructor(private planner: AliasedQuerySource) { super(); } @@ -71,7 +73,7 @@ export class AliasedReadQuery< join( table: N extends keyof T ? never : TableAlias, on: (tables: ReadAliasTables>) => JoinPredicate - ): AliasedReadQuery, Row> { + ): AliasedQueryBuilder, Row> { const copy = this.copy(); copy.planner = copy.planner.join(table, on as any) as any; return copy as any; @@ -82,7 +84,7 @@ export class AliasedReadQuery< on: ( tables: ReadAliasTables> ) => JoinPredicate - ): AliasedReadQuery, Row> { + ): AliasedQueryBuilder, Row> { const copy = this.copy(); copy.planner = copy.planner.leftJoin(table, on as any) as any; return copy as any; @@ -90,11 +92,7 @@ export class AliasedReadQuery< /** Select exact columns and aggregates; opaque raw expressions are deliberately unsupported. */ select

( select: (tables: ReadAliasTables) => P - ): AliasedReadQuery> { - if (this.fields) - throw new ReadSchemaError( - 'Only one projection is allowed per read query' - ); + ): AliasedQueryBuilder> { const { knex, columns } = this.planner.readContext(); const entries = Object.values( columns as Record>> @@ -133,6 +131,10 @@ export class AliasedReadQuery< return { knex, column: selector => { + if (typeof selector !== 'function') + throw new ReadSchemaError( + 'Aliased predicates require a column selector' + ); const column = selector(columns as ReadAliasTables); if (!entries.includes(column)) throw new ReadSchemaError( @@ -177,7 +179,11 @@ export class AliasedReadQuery< right: unknown ): this { const copy = this.copy(); - copy.planner.having(value as any, operator, right); + copy.planner.having( + value as any, + operator, + captureValue(this.planner.readContext().knex, right)() + ); return copy; } /** Limit the flat row count, including repeated parents produced by joins. */ @@ -222,6 +228,41 @@ export class AliasedReadQuery< toQuery(): string { return this.compile().toQuery(); } + /** Return an independent mutable Knex snapshot. */ + toKnexQuery(): Knex.QueryBuilder { + return this.compile(); + } + /** Configure raw SQL once and declare its complete output contract. */ + apply( + configure: (query: Knex.QueryBuilder) => Knex.QueryBuilder | undefined, + options: QueryOutput + ): OpaqueQuery { + const { knex, sql: source } = this.planner.readContext(); + const sql = this.fields ? this.compile() : source; + if (!this.fields) + for (const predicate of this.predicates) predicate(sql); + const result = configure(sql); + if (result !== undefined && result !== sql) { + if (result instanceof Promise) void result.catch(() => {}); + throw new ReadSchemaError( + 'Raw configuration must synchronously configure the supplied Knex builder' + ); + } + return OpaqueQuery.capture(knex, sql, options); + } + /** Replace the projection with trusted SQL and an explicit output contract. */ + selectRaw( + sql: string, + bindings: readonly Knex.RawBinding[], + options: QueryOutput + ): OpaqueQuery { + const { knex } = this.planner.readContext(); + const captured = captureReadRaw(knex, sql, bindings); + return this.apply( + query => query.clearSelect().select(captured()), + options + ); + } /** Execute one statement and validate/decode its detached results. */ async execute(): Promise[]> { const nodes = Object.fromEntries( diff --git a/libs/knex-schema/src/OpaqueQuery.ts b/libs/knex-schema/src/OpaqueQuery.ts new file mode 100644 index 00000000..72b1a842 --- /dev/null +++ b/libs/knex-schema/src/OpaqueQuery.ts @@ -0,0 +1,130 @@ +import type { InferType } from '@cleverbrush/schema'; +import type { Knex } from 'knex'; +import { captureReadRaw } from './read-predicates.js'; +import { type ReadObject, ReadSchemaError } from './read-schema.js'; + +/** Explicit output contract required when Framework cannot infer the SQL row shape. */ +export interface QueryOutput { + /** Synchronous, introspectable Framework object schema; parses each raw row once. */ + output: S; +} + +/** + * Immutable raw SELECT with an explicit output contract. Knex remains mutable only + * inside apply(); its compiled SQL and bindings are captured before this object is returned. + */ +export class OpaqueQuery { + /** The supplied output schema, without a second decoding or input-parser pass. */ + readonly rowSchema: S; + /** @internal Use a query's apply() or selectRaw() method. */ + constructor( + private readonly knex: Knex, + private readonly sql: Knex.QueryBuilder, + options: QueryOutput + ) { + if ( + !options?.output || + typeof options.output.introspect !== 'function' || + options.output.introspect().type !== 'object' + ) + throw new ReadSchemaError( + 'Raw query output requires an introspectable Framework object schema' + ); + this.rowSchema = options.output; + } + /** @internal Capture the completed SELECT; external builders and callbacks are not retained. */ + static capture( + knex: Knex, + sql: Knex.QueryBuilder, + options: QueryOutput + ): OpaqueQuery { + const compiled = sql.toSQL(); + if (Array.isArray(compiled) || compiled.method !== 'select') + throw new ReadSchemaError( + 'Raw query configuration must produce a SELECT' + ); + const raw = captureReadRaw( + knex, + compiled.sql, + compiled.bindings as Knex.RawBinding[] + ); + return new OpaqueQuery( + knex, + knex + .queryBuilder() + .from(raw().wrap('(', ') as __opaque')) + .select('*'), + options + ); + } + /** Configure isolated Knex SQL once; every opaque change must declare its resulting output. */ + apply( + configure: (query: Knex.QueryBuilder) => Knex.QueryBuilder | undefined, + options: QueryOutput + ): OpaqueQuery { + const sql = this.toKnexQuery(); + const result = configure(sql); + if (result !== undefined && result !== sql) { + if (result instanceof Promise) void result.catch(() => {}); + throw new ReadSchemaError( + 'Raw configuration must synchronously configure the supplied Knex builder' + ); + } + return OpaqueQuery.capture(this.knex, sql, options); + } + /** Return an independent mutable SQL snapshot. */ + toKnexQuery(): Knex.QueryBuilder { + return this.sql.clone(); + } + /** Render debug SQL without execution. */ + toQuery(): string { + return this.sql.toQuery(); + } + /** Limit an independent query while keeping schema identity. */ + limit(count: number): OpaqueQuery { + if (!Number.isInteger(count) || count < 0) + throw new ReadSchemaError('Limit must be a non-negative integer'); + return new OpaqueQuery(this.knex, this.sql.clone().limit(count), { + output: this.rowSchema + }); + } + /** Offset an independent query while keeping schema identity. */ + offset(count: number): OpaqueQuery { + if (!Number.isInteger(count) || count < 0) + throw new ReadSchemaError('Offset must be a non-negative integer'); + return new OpaqueQuery(this.knex, this.sql.clone().offset(count), { + output: this.rowSchema + }); + } + /** Bind an independent query to an existing transaction. */ + transacting(trx: Knex.Transaction): OpaqueQuery { + return new OpaqueQuery(trx, this.sql.clone().transacting(trx), { + output: this.rowSchema + }); + } + /** Execute again on every call and synchronously parse each raw row exactly once. */ + async execute(): Promise[]> { + return (await this.sql.clone()).map((row: unknown) => { + const result = this.rowSchema.parse(row); + if (result && typeof (result as any).then === 'function') { + if (result instanceof Promise) void result.catch(() => {}); + throw new ReadSchemaError( + 'Raw output schemas must parse synchronously' + ); + } + return result; + }); + } + /** Fetch the first row, or undefined. */ + async first(): Promise | undefined> { + return (await this.limit(1).execute())[0]; + } + /** Awaiting executes this query; results are not cached. */ + // biome-ignore lint/suspicious/noThenProperty: query builders intentionally support await + then[], E = never>( + resolve?: ((rows: InferType[]) => R | PromiseLike) | null, + reject?: ((error: any) => E | PromiseLike) | null + ): Promise { + return this.execute().then(resolve, reject); + } +} diff --git a/libs/knex-schema/src/PolymorphicReadQuery.ts b/libs/knex-schema/src/PolymorphicQueryBuilder.ts similarity index 53% rename from libs/knex-schema/src/PolymorphicReadQuery.ts rename to libs/knex-schema/src/PolymorphicQueryBuilder.ts index e813f368..b412ec7a 100644 --- a/libs/knex-schema/src/PolymorphicReadQuery.ts +++ b/libs/knex-schema/src/PolymorphicQueryBuilder.ts @@ -10,18 +10,21 @@ import { import type { Knex } from 'knex'; import { buildColumnMap, getPrimaryKeyColumns } from './columns.js'; import type { SchemaProps } from './entity.js'; -import { COLUMN } from './expressions.js'; -import { getVariants } from './extension.js'; -import { - getEffectiveBaseQuery, - getSchemaQueryBuilderCtor -} from './operations/helpers.js'; +import { type AliasedColumn, COLUMN } from './expressions.js'; +import { getTableName, getVariants } from './extension.js'; +import { OpaqueQuery, type QueryOutput } from './OpaqueQuery.js'; import { privateColumn } from './operations/ordering.js'; import type { EntityReadSchema, ReadRelations, ReadVariantMetadata } from './read-entity.js'; +import { + captureReadRaw, + type ReadPredicate, + type ReadPredicateContext, + ReadPredicates +} from './read-predicates.js'; import { type ObjectReadSchema, type ReadObject, @@ -34,8 +37,12 @@ import { type ReadColumns, type ReadCorrelation, type ReadQueryShape, - SchemaReadQuery -} from './SchemaReadQuery.js'; + type Related, + type RelationField, + type SchemaAwareQuery, + SchemaQueryBuilder +} from './SchemaQueryBuilder.js'; +import type { PaginationResult } from './types.js'; type VariantMap = ReadVariantMetadata extends { variants: infer V } ? V : {}; @@ -109,7 +116,7 @@ type BranchQueries< S extends ReadObject, B extends Record > = { - [K in keyof B & keyof VariantMap & string]: SchemaReadQuery< + [K in keyof B & keyof VariantMap & string]: SchemaQueryBuilder< BranchSource, B[K], ReadRelations & ReadRelations> @@ -118,35 +125,69 @@ type BranchQueries< type Selector = ( columns: ReadColumns> ) => { readonly [COLUMN]: { column: string } }; +let polymorphicAliasSequence = 0; +type PolymorphicOrder = + | { key: string; direction: 'asc' | 'desc' } + | { raw: () => Knex.Raw }; /** * Immutable polymorphic read graph. Branches are combined in one PostgreSQL statement; * rowSchema is a real discriminated union and variantRowSchemas supplies object schemas * for separately configured mappers. Framework does not choose application DTO mappings. */ -export class PolymorphicReadQuery< +export class PolymorphicQueryBuilder< S extends ReadObject, B extends Record = VariantReadSchemas -> { +> extends ReadPredicates>> { /** @internal Nominal identity for typed child-query customizers. */ declare readonly [READ_QUERY]: true; /** Runtime union matching decoded results, including selected variant bodies. */ readonly rowSchema: PolymorphicRowSchema; /** Stable object schemas keyed by discriminator, suitable for mapper.configure(). */ readonly variantRowSchemas: Readonly; - private branches: Record>; - private fallback: SchemaReadQuery; - private orders: Array<{ key: string; direction: 'asc' | 'desc' }> = []; + private branches: Record< + string, + SchemaQueryBuilder + >; + private fallback: SchemaQueryBuilder; + private orders: PolymorphicOrder[] = []; private rowLimit?: number; private rowOffset?: number; private includeUnknown = true; + private predicates: readonly ReadPredicate[] = []; + private defaults?: { + predicates: readonly ReadPredicate[]; + orders: PolymorphicOrder[]; + limit?: number; + offset?: number; + }; + private skipDefaults = false; + private deleted: 'exclude' | 'include' | 'only' = 'exclude'; + private readonly predicateAlias = + `__polymorphic_${polymorphicAliasSequence++}`; + private readonly columns: Record>; - /** @internal Use withRowSchema() instead of constructing polymorphic readers. */ + /** @internal Create through query() or an ORM DbSet. */ constructor( private readonly knex: Knex, private readonly source: S, private readonly base: Knex.QueryBuilder ) { + super(); + this.columns = Object.fromEntries( + Object.entries(source.introspect().properties).map( + ([key, schema]) => [ + key, + { + [COLUMN]: { + alias: this.predicateAlias, + column: key, + schema + } + } + ] + ) + ); const config = getVariants(source); if (!config) throw new ReadSchemaError('No polymorphic variants are declared'); @@ -158,16 +199,27 @@ export class PolymorphicReadQuery< buildColumnMap(source).propToCol.get(config.discriminatorKey) ?? config.discriminatorKey; // Invert only the discriminator guard, not caller/default-scope filters. - this.fallback = new SchemaReadQuery( + this.fallback = new SchemaQueryBuilder( knex, common, knex .from(base.clone().as('__read_unknown')) + .select( + Object.fromEntries( + Object.keys(common.introspect().properties).map(key => [ + key, + knex.ref( + `__read_unknown.${buildColumnMap(source).propToCol.get(key) ?? key}` + ) + ]) + ) + ) .where(q => q .whereNotIn(discriminator, Object.keys(config.variants)) .orWhereNull(discriminator) - ) + ), + this.predicateAlias ); const schemas = Object.fromEntries( Object.entries(this.branches).map(([key, q]) => [key, q.rowSchema]) @@ -176,11 +228,47 @@ export class PolymorphicReadQuery< this.rowSchema = this.unionSchema( schemas ) as unknown as PolymorphicRowSchema; + const scope = source.introspect().extensions?.defaultScope; + if (typeof scope === 'function') { + const configured = scope(this.copy()); + if ( + !this.sameSource(configured) || + configured.rowSchema !== this.rowSchema || + configured.deleted !== this.deleted || + configured.skipDefaults !== this.skipDefaults || + configured.knex !== this.knex + ) { + if (configured instanceof Promise) + void configured.catch(() => {}); + throw new ReadSchemaError( + 'Scopes must synchronously return a shape-preserving query' + ); + } + this.defaults = { + predicates: configured.predicates, + orders: configured.orders, + limit: configured.rowLimit, + offset: configured.rowOffset + }; + } } private commonSource(): ReadObject { const info = this.source.introspect(); - return (object(info.properties) as any) + const relationNames = new Set( + ((info.extensions?.relations ?? []) as { name: string }[]).map( + relation => relation.name + ) + ); + const properties = Object.fromEntries( + Object.entries(info.properties) + .filter(([key]) => !relationNames.has(key)) + .map(([key, schema]) => [ + key, + (schema as ReadSchema).withExtension('columnName', key) + ]) + ); + return (object(properties) as any) .withExtension('tableName', info.extensions?.tableName) .withExtension('relations', info.extensions?.relations ?? []); } @@ -197,7 +285,10 @@ export class PolymorphicReadQuery< ); } - private branch(key: string, body: boolean): SchemaReadQuery { + private branch( + key: string, + body: boolean + ): SchemaQueryBuilder { const config = getVariants(this.source)!; const variant = config.variants[key]; const baseInfo = this.source.introspect(); @@ -237,10 +328,11 @@ export class PolymorphicReadQuery< throw new ReadSchemaError( 'CTI read graphs require a single-column primary key' ); - const Constructor = getSchemaQueryBuilderCtor(); - const bodyQuery = getEffectiveBaseQuery( - new Constructor(this.knex, variant.schema) - ).clone(); + const bodyQuery = new SchemaQueryBuilder( + this.knex, + variant.schema, + this.knex(getTableName(variant.schema)) + ).storageQuery(); query.leftJoin( bodyQuery.as(bodyAlias), `${bodyAlias}.${variant.foreignKey}`, @@ -310,10 +402,11 @@ export class PolymorphicReadQuery< '__read_cti_present' ); } - return new SchemaReadQuery( + return new SchemaQueryBuilder( this.knex, schema, - query.select(columns) + query.select(columns), + this.predicateAlias ); } @@ -327,7 +420,7 @@ export class PolymorphicReadQuery< /** @internal Check the identity of the original read source, retained by clones. */ sameSource(other: unknown): boolean { return ( - other instanceof PolymorphicReadQuery && + other instanceof PolymorphicQueryBuilder && this.base === other.base && this.source === other.source ); @@ -343,37 +436,189 @@ export class PolymorphicReadQuery< }); } - /** Add a comparison to every branch without changing its declared result schema. */ - where(selector: Selector, value: unknown): this; - /** Add an explicit supported comparison operator to every branch. */ - where(selector: Selector, operator: string, value: unknown): this; - /** Add a bound comparison; existing reader instances remain unchanged. */ - where(selector: Selector, ...args: unknown[]): this { + protected readPredicateContext(): ReadPredicateContext< + ReadColumns> + > { + return { + knex: this.knex, + column: selector => { + const column = + typeof selector === 'string' + ? this.columns[selector] + : selector(this.columns as any); + if (!column || !Object.values(this.columns).includes(column)) + throw new ReadSchemaError( + 'Column does not belong to this polymorphic query' + ); + return `${this.predicateAlias}.${column[COLUMN].column}`; + } + }; + } + protected addReadPredicate(predicate: ReadPredicate): this { + const copy = this.copy(); + copy.predicates = [...this.predicates, predicate]; + return copy; + } + /** Remove the default scope while preserving explicit predicates. */ + unscoped(): this { + const copy = this.copy(); + copy.skipDefaults = true; + return copy; + } + /** Include soft-deleted entities in every branch. */ + withDeleted(): this { + const copy = this.copy(); + copy.deleted = 'include'; + return copy; + } + /** Match only soft-deleted entities in every branch. */ + onlyDeleted(): this { const copy = this.copy(); - for (const [key, branch] of Object.entries(copy.branches)) - copy.branches[key] = (branch.where as Function)(selector, ...args); - copy.fallback = (copy.fallback.where as Function)(selector, ...args); + copy.deleted = 'only'; return copy; } + /** Apply a named immutable scope once. */ + scoped(name: string): this { + const scope = ( + this.source.introspect().extensions?.scopes as + | Record + | undefined + )?.[name]; + if (!scope) throw new ReadSchemaError(`Unknown scope: ${name}`); + const configured = scope(this.copy()); + if ( + !this.sameSource(configured) || + configured.rowSchema !== this.rowSchema || + configured.deleted !== this.deleted || + configured.skipDefaults !== this.skipDefaults || + configured.knex !== this.knex + ) { + if (configured instanceof Promise) void configured.catch(() => {}); + throw new ReadSchemaError( + 'Scopes must synchronously return a shape-preserving query' + ); + } + return configured; + } + /** True when all branches retain complete entity rows. */ + get returnsEntityRows(): boolean { + return Object.values(this.branches).every( + branch => branch.returnsEntityRows + ); + } + /** Customize a relation on one discriminator branch. */ + includeVariant( + key: keyof B & keyof VariantMap & string, + relation: string, + customize?: (query: SchemaQueryBuilder) => ReadQueryShape + ): this { + return this.forVariant(key, query => + query.include(() => relation as any, customize as any) + ) as unknown as this; + } + /** Load a common relation on every branch, configuring the child exactly once. */ + include< + K extends keyof ReadRelations & string, + Child extends ReadQueryShape = SchemaAwareQuery< + Related[K]> + > + >( + selector: K | ((relations: { [P in keyof ReadRelations]: P }) => K), + customize?: ( + query: SchemaAwareQuery[K]>> + ) => Child + ): PolymorphicQueryBuilder< + S, + { + [P in keyof B]: ObjectSchemaBuilder< + SchemaProps & + Record< + K, + RelationField[K], Child['rowSchema']> + > + >; + } + > { + const relations = (this.source.introspect().extensions?.relations ?? + []) as { name: string }[]; + const name = + typeof selector === 'string' + ? selector + : selector( + Object.fromEntries( + relations.map(relation => [ + relation.name, + relation.name + ]) + ) as any + ); + if (!relations.some(relation => relation.name === name)) { + const variants = getVariants(this.source)!.variants; + const candidates = Object.entries(variants).filter(([, variant]) => + variant.relations.some(relation => relation.name === name) + ); + if (candidates.length > 1) + throw new ReadSchemaError( + `Ambiguous relation: ${name}; use includeVariant` + ); + if (candidates.length === 1) + return this.includeVariant( + candidates[0][0] as any, + name, + customize as any + ) as any; + throw new ReadSchemaError(`Unknown relation: ${name}`); + } + const copy = this.copy(); + const entries = Object.entries(copy.branches); + const [firstKey, first] = entries[0]; + const prepared = first.include(name, customize as any); + copy.branches[firstKey] = prepared; + for (const [key, branch] of entries.slice(1)) + copy.branches[key] = branch.includeFrom(name, prepared); + copy.fallback = copy.fallback.includeFrom(name, prepared); + copy.refresh(); + return copy as any; + } + /** Filter one branch using schema property names; other variants remain unaffected. */ + whereVariant( + key: keyof B & keyof VariantMap & string, + selector: string | ((columns: any) => any), + operator: string, + value: unknown + ): this { + return this.forVariant(key, query => + query.where(selector as any, operator, value) + ) as unknown as this; + } /** Order all variants together, not independently within each branch. */ - orderBy(selector: Selector, direction: 'asc' | 'desc' = 'asc'): this { + orderBy( + selector: + | Selector + | (keyof ReadColumns> & string), + direction: 'asc' | 'desc' = 'asc' + ): this { if (direction !== 'asc' && direction !== 'desc') throw new ReadSchemaError('Invalid ordering direction'); - const properties = this.source.introspect().properties; - const key = selector( - Object.fromEntries( - Object.keys(properties).map(k => [ - k, - { [COLUMN]: { column: k } } - ]) - ) as any - )[COLUMN].column; - if (!Object.hasOwn(properties, key)) - throw new ReadSchemaError('Unknown polymorphic ordering column'); + const column = + typeof selector === 'string' + ? this.columns[selector] + : selector(this.columns as any); + if (!column || !Object.values(this.columns).includes(column as any)) + throw new ReadSchemaError( + 'Column does not belong to this polymorphic query' + ); + const key = column[COLUMN].column; const copy = this.copy(); copy.orders.push({ key, direction }); return copy; } + /** Order the combined JSON-envelope SQL using trusted SQL and captured bindings. */ + orderByRaw(sql: string, bindings: readonly Knex.RawBinding[] = []): this { + const copy = this.copy(); + copy.orders.push({ raw: captureReadRaw(this.knex, sql, bindings) }); + return copy; + } /** Limit the combined result across all variants. */ limit(count: number): this { if (!Number.isInteger(count) || count < 0) @@ -385,7 +630,7 @@ export class PolymorphicReadQuery< /** Restrict returned discriminator branches and narrow both runtime and inferred schemas. */ selectVariants( keys: K - ): PolymorphicReadQuery> { + ): PolymorphicQueryBuilder> { if ( !keys.length || new Set(keys).size !== keys.length || @@ -421,14 +666,16 @@ export class PolymorphicReadQuery< >( key: K, configure: (query: BranchQueries[K]) => Q - ): PolymorphicReadQuery & Record> { + ): PolymorphicQueryBuilder & Record> { const current = this.branches[key]; if (!current) throw new ReadSchemaError(`Unknown variant: ${key}`); const configured = configure(current as any); - if (!current.sameSource(configured)) + if (!current.sameSource(configured)) { + if (configured instanceof Promise) void configured.catch(() => {}); throw new ReadSchemaError( 'Variant customizer must return its configured read query' ); + } const discriminator = getVariants(this.source)!.discriminatorKey; if ( configured.rowSchema @@ -439,7 +686,7 @@ export class PolymorphicReadQuery< 'Variant projections must retain the original discriminator' ); const copy = this.copy(); - copy.branches[key] = configured as unknown as SchemaReadQuery< + copy.branches[key] = configured as unknown as SchemaQueryBuilder< any, any, any @@ -450,36 +697,71 @@ export class PolymorphicReadQuery< /** @internal Compile one UNION ALL statement; JSON preserves distinct branch shapes. */ compile(correlate?: ReadCorrelation): Knex.QueryBuilder { + const defaults = this.skipDefaults ? undefined : this.defaults; const reserved = Object.values(this.branches).flatMap(branch => Object.keys(branch.rowSchema.introspect().properties) ); - const order = this.orders.map(item => { - const hidden = privateColumn(reserved, 'read_order'); - reserved.push(hidden); - return { ...item, hidden }; - }); + const order = [...(defaults?.orders ?? []), ...this.orders].map( + item => { + if ('raw' in item) return item; + const hidden = privateColumn(reserved, 'read_order'); + reserved.push(hidden); + return { ...item, hidden }; + } + ); const queries = [ ...Object.values(this.branches), ...(this.includeUnknown ? [this.fallback] : []) - ].map(branch => - this.knex + ].map(original => { + let branch = original; + for (const predicates of [ + defaults?.predicates ?? [], + this.predicates + ]) { + if (predicates.length) + branch = branch.withPredicate(query => { + query.where(nested => { + for (const predicate of predicates) + predicate(nested); + }); + }); + } + const softDelete = this.source.introspect().extensions + ?.softDelete as { column: string } | undefined; + if (softDelete && this.deleted !== 'include') { + const key = + buildColumnMap(this.source).colToProp.get( + softDelete.column + ) ?? softDelete.column; + branch = branch.withPredicate(query => { + query[ + this.deleted === 'only' ? 'whereNotNull' : 'whereNull' + ](key); + }); + } + return this.knex .from( branch .compile((sql, alias, source) => { correlate?.(sql, alias, source); const columns = buildColumnMap(source).propToCol; - for (const { key, hidden } of order) + for (const item of order) { + if ('raw' in item) continue; + const { key, hidden } = item; sql.select({ [hidden]: this.knex.raw( 'cast(?? as text)', [`${alias}.${columns.get(key) ?? key}`] ) }); + } }) .as('__read_branch') ) - .select(this.knex.raw('to_jsonb(__read_branch) as __read_poly')) - ); + .select( + this.knex.raw('to_jsonb(__read_branch) as __read_poly') + ); + }); const query = this.knex .from( this.knex @@ -488,7 +770,12 @@ export class PolymorphicReadQuery< .as('__read_variants') ) .select('__read_poly'); - for (const { key, direction, hidden } of order) { + for (const item of order) { + if ('raw' in item) { + query.orderByRaw(item.raw()); + continue; + } + const { key, direction, hidden } = item; const info = this.source.introspect().properties[key].introspect(); const type = info.type === 'number' @@ -509,8 +796,10 @@ export class PolymorphicReadQuery< [hidden] ); } - if (this.rowLimit !== undefined) query.limit(this.rowLimit); - if (this.rowOffset !== undefined) query.offset(this.rowOffset); + const limit = this.rowLimit ?? defaults?.limit; + const offset = this.rowOffset ?? defaults?.offset; + if (limit !== undefined) query.limit(limit); + if (offset !== undefined) query.offset(offset); return query; } /** @internal Decode using exactly the selected branch's schema and codecs. */ @@ -528,6 +817,90 @@ export class PolymorphicReadQuery< toQuery(): string { return this.compile().toQuery(); } + /** Return a separately mutable Knex snapshot of the union statement. */ + toKnexQuery(): Knex.QueryBuilder { + return this.compile(); + } + /** Configure a captured union SELECT and declare its complete raw output shape. */ + apply( + configure: (query: Knex.QueryBuilder) => Knex.QueryBuilder | undefined, + options: QueryOutput + ): OpaqueQuery { + const sql = this.compile(); + const result = configure(sql); + if (result !== undefined && result !== sql) { + if (result instanceof Promise) void result.catch(() => {}); + throw new ReadSchemaError( + 'Raw configuration must synchronously configure the supplied Knex builder' + ); + } + return OpaqueQuery.capture(this.knex, sql, options); + } + /** Select trusted SQL from the union envelope with an explicit output contract. */ + selectRaw( + sql: string, + bindings: readonly Knex.RawBinding[], + options: QueryOutput + ): OpaqueQuery { + const captured = captureReadRaw(this.knex, sql, bindings); + return this.apply( + query => query.clearSelect().select(captured()), + options + ); + } + /** Count matching rows across variants, excluding global pagination and ordering. */ + async countValue(): Promise { + const source = this.compile() + .clearOrder() + .clear('limit') + .clear('offset'); + const row = await this.knex + .from(source.as('__variant_count')) + .count({ count: '*' }) + .first(); + const count = Number(row?.count ?? 0); + if (!Number.isSafeInteger(count)) + throw new ReadSchemaError('Count exceeds the safe integer range'); + return count; + } + /** Globally paginate the discriminated union, leaving the source and its metadata unchanged. */ + async paginate({ + page, + pageSize + }: { + page: number; + pageSize: number; + }): Promise>>> { + if ( + !Number.isInteger(page) || + page < 1 || + !Number.isInteger(pageSize) || + pageSize < 1 + ) + throw new ReadSchemaError( + 'Page and pageSize must be positive integers' + ); + const total = await this.countValue(); + const data = await this.offset((page - 1) * pageSize) + .limit(pageSize) + .execute(); + const totalPages = Math.ceil(total / pageSize); + return { + data, + total, + page, + pageSize, + totalPages, + hasNextPage: page < totalPages, + hasPreviousPage: page > 1 + }; + } + /** Read a property common to the selected variants; returned scalar values are detached. */ + async pluck>>( + key: K + ): Promise>[K][]> { + return (await this.execute()).map(row => (row as any)[key]); + } /** Execute and decode one statement containing every requested branch. */ async execute(): Promise>[]> { return (await this.compile()).map((row: any) => this.decode(row)); diff --git a/libs/knex-schema/src/QuerySource.ts b/libs/knex-schema/src/QuerySource.ts new file mode 100644 index 00000000..2d14ae23 --- /dev/null +++ b/libs/knex-schema/src/QuerySource.ts @@ -0,0 +1,1389 @@ +// @cleverbrush/knex-schema — QuerySource + +import type { InferType } from '@cleverbrush/schema'; +import { + EXTRA_TYPE_BRAND, + METHOD_LITERAL_BRAND, + type ObjectSchemaBuilder +} from '@cleverbrush/schema'; +import type { Knex } from 'knex'; +import { buildColumnMap } from './columns.js'; +import type { + AggregateOptions, + AggregateResult, + ExtremumResult, + ExtremumValue, + OutputSchema +} from './expressions.js'; +import { getTableName } from './extension.js'; +import { scalarAggregate } from './operations/aggregate.js'; +import { + type CompositeCursorOptions, + compositeCursor +} from './operations/composite-cursor.js'; +// Operations +import { + avgImpl, + countDistinctImpl, + countImpl, + distinctImpl, + maxImpl, + minImpl, + projectedImpl, + scopedImpl, + selectImpl, + selectRawImpl, + sumImpl, + unscopedImpl +} from './operations/select.js'; +import type { + ColumnRef, + CursorPaginationResult, + InsertType, + JoinManySpec, + JoinOneSpec, + PaginationResult, + SelectProjection, + SelectSelector +} from './types.js'; + +export { + OnConflictBuilder, + type OnConflictMergeHelpers, + type OnConflictMergeOptions, + type OnConflictUpdateData, + type OnConflictUpdateValue +} from './operations/insert.js'; + +import { + deleteImpl, + hardDeleteImpl, + onlyDeletedImpl, + restoreImpl, + withDeletedImpl +} from './operations/delete.js'; +import { + ALLOWED_OPS, + buildQuery, + cleanAndMapRow, + getQuery, + getVariantConfig, + invalidateCache, + registerQuerySource, + resolveColumn +} from './operations/helpers.js'; +import { + bulkInsertImpl, + bulkUpsertImpl, + insertImpl, + insertManyImpl, + onConflictImpl, + upsertImpl +} from './operations/insert.js'; +import { + includeImpl, + includeVariantImpl, + joinManyImpl, + joinOneImpl +} from './operations/join.js'; +import { + executeImpl, + limitImpl, + offsetImpl, + paginateAfterImpl, + paginateImpl +} from './operations/pagination.js'; +import { getState, setState } from './operations/state.js'; +import { bulkUpdateImpl, updateImpl } from './operations/update.js'; +import { + andWhereImpl, + groupByImpl, + groupByRawImpl, + havingImpl, + havingRawImpl, + orderByImpl, + orderByRawImpl, + orWhereImpl, + orWhereInImpl, + orWhereNotInImpl, + orWhereNotNullImpl, + orWhereNullImpl, + whereBetweenImpl, + whereExistsImpl, + whereILikeImpl, + whereImpl, + whereInImpl, + whereJsonPathImpl, + whereLikeImpl, + whereNotBetweenImpl, + whereNotExistsImpl, + whereNotImpl, + whereNotInImpl, + whereNotNullImpl, + whereNullImpl, + whereRawImpl +} from './operations/where.js'; + +// --------------------------------------------------------------------------- +// Type-level helpers +// --------------------------------------------------------------------------- + +type ScopesOf = S extends { + readonly [METHOD_LITERAL_BRAND]?: infer N; +} + ? Extract + : never; + +type ProjectionsOf = S extends { + readonly [EXTRA_TYPE_BRAND]?: infer P; +} + ? P extends Record + ? P + : Record + : Record; + +type ProjectionKeysOf< + S, + K extends keyof ProjectionsOf & string +> = ProjectionsOf[K] extends readonly (infer T extends string)[] + ? T + : string; + +// --------------------------------------------------------------------------- +// QuerySource +// --------------------------------------------------------------------------- + +/** + * Build schema-aware SQL with mapped columns, projections and eager relations. + * Fluent configuration methods mutate this builder; create a fresh query for each + * independent operation. Await the builder or call execute() to obtain mapped rows. + * @internal Private native SQL/write planner; public consumers use immutable query(). + */ +export class QuerySource< + TLocalSchema extends ObjectSchemaBuilder, + TResult +> { + /** + * Create a query over the schema's configured table. + * @param knex - Database connection or transaction used to execute the query. + * @param localSchema - Schema containing property/column and relation metadata. + * @param baseQuery - Optional existing Knex query to configure; it is not cloned. + */ + constructor( + knex: Knex, + localSchema: TLocalSchema, + baseQuery?: Knex.QueryBuilder + ) { + const tableName = getTableName(localSchema); + setState(this, { + knex, + baseQuery: baseQuery ?? knex(tableName), + localSchema, + specs: [], + tableName, + explicitSelects: null, + selectionMode: null, + appliedProjection: null, + projectionColumns: null, + projectionDecoders: {}, + hiddenColumns: new Set(), + includeDeleted: false, + onlyDeleted: false, + skipDefaultScope: false, + variantConfig: undefined, + enabledVariants: null, + variantWhereFilters: [], + variantRelationIncludes: [], + cachedBuiltQuery: null + }); + } + + // ======================================================================= + // SELECT / DISTINCT / AGGREGATES + // ======================================================================= + + /** + * Choose columns, or use an object selector to infer a flat result shape. + * Object values can be schema descriptors or aggregate expressions. Column-list + * selection retains the existing result type; raw SQL cannot infer a new shape. + * @returns This builder, narrowed to the object projection when one is supplied. + */ + select(...columns: (ColumnRef | Knex.Raw)[]): this; + /** + * Choose columns, or use an object selector to infer a flat result shape. + * Object values can be schema descriptors or aggregate expressions. Column-list + * selection retains the existing result type; raw SQL cannot infer a new shape. + * @returns This builder, narrowed to the object projection when one is supplied. + */ + select>( + selector: TSel + ): QuerySource>>; + /** + * Choose columns, or use an object selector to infer a flat result shape. + * Object values can be schema descriptors or aggregate expressions. Column-list + * selection retains the existing result type; raw SQL cannot infer a new shape. + * @returns This builder, narrowed to the object projection when one is supplied. + */ + select(...args: unknown[]): any { + return selectImpl(this as any, ...args); + } + + /** + * Apply SQL DISTINCT to the selected columns, optionally adding columns. + * Property selectors are mapped to database names; SQL decides row equality. + */ + distinct(...columns: (ColumnRef | Knex.Raw)[]): this { + return (distinctImpl as any)(this, ...columns); + } + + /** + * Append a legacy SQL COUNT selection without executing the query. + * The driver controls the result shape/value type. Prefer countValue() for a + * checked scalar number, or aggregate.count() in a typed object projection. + */ + count(column?: ColumnRef | Knex.Raw): this { + return (countImpl as any)(this, column); + } + + /** + * Append a legacy COUNT(DISTINCT column) selection. + * Prefer countDistinctValue() for a checked scalar or aggregate.countDistinct() + * for an inferred grouped result; this legacy method retains the builder type. + */ + countDistinct(column?: ColumnRef | Knex.Raw): this { + return (countDistinctImpl as any)(this, column); + } + + /** + * Append a legacy MIN selection without changing the result type. + * Use minValue() for a scalar with explicit decoding, or aggregate.min() in a + * typed projection. SQL returns null for an empty/all-null input. + */ + min(column: ColumnRef | Knex.Raw): this { + return (minImpl as any)(this, column); + } + + /** + * Append a legacy MAX selection without changing the result type. + * Use maxValue() for a scalar with explicit decoding, or aggregate.max() in a + * typed projection. SQL returns null for an empty/all-null input. + */ + max(column: ColumnRef | Knex.Raw): this { + return (maxImpl as any)(this, column); + } + + /** + * Append a legacy SUM selection, leaving numeric conversion to the driver. + * Prefer sumValue() or aggregate.sum() to preserve exact numeric text by default. + */ + sum(column: ColumnRef | Knex.Raw): this { + return (sumImpl as any)(this, column); + } + + /** + * Append a legacy AVG selection, leaving numeric conversion to the driver. + * Prefer avgValue() or aggregate.avg() for a typed, precision-preserving result. + */ + avg(column: ColumnRef | Knex.Raw): this { + return (avgImpl as any)(this, column); + } + + /** + * Count matching rows, or non-null column values, without mutating this query. + * Ignores source ordering/limits/offsets while retaining filters and transactions. + * @param options - Optional output parser; receives the raw driver value. + * @returns A safe integer by default, including zero for an empty source. + * @throws If the default count overflows, the source is grouped/distinct, or parsing fails. + */ + countValue | undefined = undefined>( + options?: AggregateOptions + ): Promise>; + /** + * Count non-null column values without mutating the source query. + * Source paging/order is ignored; filters, scopes and transactions remain. + * @param column - Mapped schema property to count. + * @param options - Optional parser replacing safe-integer decoding. + * @throws If the default result overflows or the source is grouped/distinct. + */ + countValue | undefined = undefined>( + column: ColumnRef, + options?: AggregateOptions + ): Promise>; + /** + * Count matching rows, or non-null column values, without mutating this query. + * Ignores source ordering/limits/offsets while retaining filters and transactions. + * @param options - Optional output parser; receives the raw driver value. + * @returns A safe integer by default, including zero for an empty source. + * @throws If the default count overflows, the source is grouped/distinct, or parsing fails. + */ + countValue( + columnOrOptions?: ColumnRef | AggregateOptions, + options?: AggregateOptions + ): Promise { + const hasColumn = + typeof columnOrOptions === 'string' || + typeof columnOrOptions === 'function'; + return scalarAggregate( + this, + 'count', + hasColumn ? columnOrOptions : undefined, + hasColumn ? options : columnOrOptions + ); + } + + /** + * Count distinct non-null values in an unpaginated clone of this query. + * @param column - Schema property to count; SQL nulls do not contribute. + * @param options - Optional parser replacing default safe-integer conversion. + * @returns A safe integer, or the parser's inferred output type. + * @throws If the count is unsafe, the source is grouped/distinct, or parsing fails. + */ + countDistinctValue | undefined = undefined>( + column: ColumnRef, + options?: AggregateOptions + ): Promise> { + return scalarAggregate(this, 'countDistinct', column, options); + } + + /** + * Sum non-null values in an unpaginated clone, preserving numeric precision. + * @param column - Numeric schema property to sum. + * @param options - Optional parser receiving the raw driver value, including null. + * @returns Database numeric text, or null for empty/all-null input by default. + * An output parser replaces default decoding and controls the result type. + */ + sumValue | undefined = undefined>( + column: ColumnRef, + options?: AggregateOptions + ): Promise> { + return scalarAggregate(this, 'sum', column, options); + } + + /** + * Average non-null values in an unpaginated clone of this query. + * @param column - Numeric schema property to aggregate. + * @param options - Optional parser receiving the raw driver result, including null. + * @returns Exact database numeric text or null by default; a parser overrides this. + * @remarks Text preserves database precision, not precision already lost in floating-point storage. + */ + avgValue | undefined = undefined>( + column: ColumnRef, + options?: AggregateOptions + ): Promise> { + return scalarAggregate(this, 'avg', column, options); + } + + /** + * Find the smallest non-null column value without retaining source paging. + * @param column - Schema property to aggregate. + * @param options - Optional parser replacing default decoding, including null handling. + * @returns Null for empty/all-null input; otherwise the column representation. + * Dates return Date; numeric SQL overrides may return exact strings. + */ + minValue< + C extends ColumnRef, + S extends OutputSchema | undefined = undefined + >( + column: C, + options?: AggregateOptions + ): Promise< + AggregateResult< + S, + C extends (...args: any[]) => infer D + ? ExtremumValue + : C extends keyof InferType + ? ExtremumResult[C]> + : unknown + > + > { + return scalarAggregate(this, 'min', column, options); + } + + /** + * Find the largest non-null column value without retaining source paging. + * @param column - Schema property to aggregate. + * @param options - Optional parser replacing default decoding, including null handling. + * @returns Null for empty/all-null input; otherwise the column representation. + * Dates return Date; numeric SQL overrides may return exact strings. + */ + maxValue< + C extends ColumnRef, + S extends OutputSchema | undefined = undefined + >( + column: C, + options?: AggregateOptions + ): Promise< + AggregateResult< + S, + C extends (...args: any[]) => infer D + ? ExtremumValue + : C extends keyof InferType + ? ExtremumResult[C]> + : unknown + > + > { + return scalarAggregate(this, 'max', column, options); + } + + /** + * Append a raw SELECT expression with optional Knex value/identifier bindings. + * The caller owns its SQL and result shape; this does not infer a new result type. + */ + selectRaw(sql: string, bindings?: any[]): this { + return selectRawImpl(this as any, sql, bindings); + } + + /** + * Apply a named schema projection and narrow the selected property type. + * @param name - Projection registered with the schema's projection() extension. + * @throws If the projection is unknown or conflicts with a prior selection. + */ + projected & string>( + name: K + ): QuerySource< + TLocalSchema, + Pick & keyof TResult> + > { + return projectedImpl(this as any, name); + } + + /** + * Apply a named schema scope to this query. + * @param name - Scope registered with the schema's scope() extension. + * @throws If the requested scope is not registered. + */ + scoped>(name: K): this { + return scopedImpl(this as any, name as string); + } + + /** + * Disable the default read scope and include soft-deleted rows. + * Explicit filters already added to this builder remain in place. + */ + unscoped(): this { + return unscopedImpl(this as any); + } + + // ======================================================================= + // WHERE + // ======================================================================= + + /** + * Add an AND filter using mapped schema columns, a record, or raw Knex SQL. + * Selector/key and record forms map property names to database columns. Grouped + * callbacks receive a Knex builder and therefore use database column names. + * Values are bound; use the operator form for comparisons other than equality. + */ + where(column: ColumnRef, operator: string, value: any): this; + /** + * Add an AND filter using mapped schema columns, a record, or raw Knex SQL. + * Selector/key and record forms map property names to database columns. Grouped + * callbacks receive a Knex builder and therefore use database column names. + * Values are bound; use the operator form for comparisons other than equality. + */ + where(column: ColumnRef, value: any): this; + /** + * Add an AND filter using mapped schema columns, a record, or raw Knex SQL. + * Selector/key and record forms map property names to database columns. Grouped + * callbacks receive a Knex builder and therefore use database column names. + * Values are bound; use the operator form for comparisons other than equality. + */ + where(raw: Knex.Raw, operator: string, value: any): this; + /** + * Add an AND filter using mapped schema columns, a record, or raw Knex SQL. + * Selector/key and record forms map property names to database columns. Grouped + * callbacks receive a Knex builder and therefore use database column names. + * Values are bound; use the operator form for comparisons other than equality. + */ + where(callback: (builder: Knex.QueryBuilder) => void): this; + /** + * Add an AND filter using mapped schema columns, a record, or raw Knex SQL. + * Selector/key and record forms map property names to database columns. Grouped + * callbacks receive a Knex builder and therefore use database column names. + * Values are bound; use the operator form for comparisons other than equality. + */ + where(record: Record): this; + /** + * Add an AND filter using mapped schema columns, a record, or raw Knex SQL. + * Selector/key and record forms map property names to database columns. Grouped + * callbacks receive a Knex builder and therefore use database column names. + * Values are bound; use the operator form for comparisons other than equality. + */ + where(raw: Knex.Raw): this; + /** + * Add an AND filter using mapped schema columns, a record, or raw Knex SQL. + * Selector/key and record forms map property names to database columns. Grouped + * callbacks receive a Knex builder and therefore use database column names. + * Values are bound; use the operator form for comparisons other than equality. + */ + where(columnOrRaw: any, ...args: any[]): this { + return whereImpl(this as any, columnOrRaw, ...args); + } + + /** + * Add an AND condition; an explicit synonym for where(). + * Property references and record keys are mapped; raw callbacks use Knex columns. + */ + andWhere( + column: ColumnRef, + operator: string, + value: any + ): this; + /** + * Add an AND condition; an explicit synonym for where(). + * Property references and record keys are mapped; raw callbacks use Knex columns. + */ + andWhere(column: ColumnRef, value: any): this; + /** + * Add an AND condition; an explicit synonym for where(). + * Property references and record keys are mapped; raw callbacks use Knex columns. + */ + andWhere(record: Record): this; + /** + * Add an AND condition; an explicit synonym for where(). + * Property references and record keys are mapped; raw callbacks use Knex columns. + */ + andWhere(callback: (builder: Knex.QueryBuilder) => void): this; + /** + * Add an AND condition; an explicit synonym for where(). + * Property references and record keys are mapped; raw callbacks use Knex columns. + */ + andWhere(raw: Knex.Raw): this; + /** + * Add an AND condition; an explicit synonym for where(). + * Property references and record keys are mapped; raw callbacks use Knex columns. + */ + andWhere(columnOrRaw: any, ...args: any[]): this { + return andWhereImpl(this as any, columnOrRaw, ...args); + } + + /** + * Add an OR condition using a mapped property, record, raw SQL or Knex group. + * Group mixed AND/OR conditions explicitly when SQL precedence would change intent. + */ + orWhere( + column: ColumnRef, + operator: string, + value: any + ): this; + /** + * Add an OR condition using a mapped property, record, raw SQL or Knex group. + * Group mixed AND/OR conditions explicitly when SQL precedence would change intent. + */ + orWhere(column: ColumnRef, value: any): this; + /** + * Add an OR condition using a mapped property, record, raw SQL or Knex group. + * Group mixed AND/OR conditions explicitly when SQL precedence would change intent. + */ + orWhere(record: Record): this; + /** + * Add an OR condition using a mapped property, record, raw SQL or Knex group. + * Group mixed AND/OR conditions explicitly when SQL precedence would change intent. + */ + orWhere(callback: (builder: Knex.QueryBuilder) => void): this; + /** + * Add an OR condition using a mapped property, record, raw SQL or Knex group. + * Group mixed AND/OR conditions explicitly when SQL precedence would change intent. + */ + orWhere(raw: Knex.Raw): this; + /** + * Add an OR condition using a mapped property, record, raw SQL or Knex group. + * Group mixed AND/OR conditions explicitly when SQL precedence would change intent. + */ + orWhere(columnOrRaw: any, ...args: any[]): this { + return orWhereImpl(this as any, columnOrRaw, ...args); + } + + /** + * Add a negated condition using a mapped property, record or Knex group. + * Use whereNotIn()/whereNotBetween() for their dedicated SQL operators. + */ + whereNot( + column: ColumnRef, + operator: string, + value: any + ): this; + /** + * Add a negated condition using a mapped property, record or Knex group. + * Use whereNotIn()/whereNotBetween() for their dedicated SQL operators. + */ + whereNot(column: ColumnRef, value: any): this; + /** + * Add a negated condition using a mapped property, record or Knex group. + * Use whereNotIn()/whereNotBetween() for their dedicated SQL operators. + */ + whereNot(record: Record): this; + /** + * Add a negated condition using a mapped property, record or Knex group. + * Use whereNotIn()/whereNotBetween() for their dedicated SQL operators. + */ + whereNot(callback: (builder: Knex.QueryBuilder) => void): this; + /** + * Add a negated condition using a mapped property, record or Knex group. + * Use whereNotIn()/whereNotBetween() for their dedicated SQL operators. + */ + whereNot(raw: Knex.Raw): this; + /** + * Add a negated condition using a mapped property, record or Knex group. + * Use whereNotIn()/whereNotBetween() for their dedicated SQL operators. + */ + whereNot(columnOrRaw: any, ...args: any[]): this { + return whereNotImpl(this as any, columnOrRaw, ...args); + } + + /** + * Require the mapped column to match a value list or a single-column subquery. + * An empty list matches no rows. Subqueries use Knex's database column names. + */ + whereIn( + column: ColumnRef, + values: readonly any[] | Knex.QueryBuilder + ): this { + return (whereInImpl as any)(this, column, values); + } + + /** + * Exclude values returned by a list or single-column subquery. + * SQL null semantics apply; a null in the set is not equivalent to a missing value. + */ + whereNotIn( + column: ColumnRef, + values: readonly any[] | Knex.QueryBuilder + ): this { + return (whereNotInImpl as any)(this, column, values); + } + + /** + * Add an OR membership condition against a list or single-column subquery. + */ + orWhereIn( + column: ColumnRef, + values: readonly any[] | Knex.QueryBuilder + ): this { + return (orWhereInImpl as any)(this, column, values); + } + + /** + * Add an OR non-membership condition; SQL NOT IN null semantics apply. + */ + orWhereNotIn( + column: ColumnRef, + values: readonly any[] | Knex.QueryBuilder + ): this { + return (orWhereNotInImpl as any)(this, column, values); + } + + /** + * Add an AND IS NULL condition for a mapped schema property. + */ + whereNull(column: ColumnRef): this { + return (whereNullImpl as any)(this, column); + } + + /** + * Add an AND IS NOT NULL condition for a mapped schema property. + */ + whereNotNull(column: ColumnRef): this { + return (whereNotNullImpl as any)(this, column); + } + + /** + * Add an OR IS NULL condition for a mapped schema property. + */ + orWhereNull(column: ColumnRef): this { + return (orWhereNullImpl as any)(this, column); + } + + /** + * Add an OR IS NOT NULL condition for a mapped schema property. + */ + orWhereNotNull(column: ColumnRef): this { + return (orWhereNotNullImpl as any)(this, column); + } + + /** + * Require the mapped column to lie within an inclusive [lower, upper] range. + */ + whereBetween( + column: ColumnRef, + range: readonly [any, any] + ): this { + return (whereBetweenImpl as any)(this, column, range); + } + + /** + * Exclude the inclusive [lower, upper] range from a mapped column. + */ + whereNotBetween( + column: ColumnRef, + range: readonly [any, any] + ): this { + return (whereNotBetweenImpl as any)(this, column, range); + } + + /** + * Match a mapped column against a SQL LIKE pattern. + * Percent and underscore remain wildcards; values are bound, not wildcard-escaped. + */ + whereLike(column: ColumnRef, value: string): this { + return (whereLikeImpl as any)(this, column, value); + } + + /** + * Match a mapped column using PostgreSQL's case-insensitive ILIKE operator. + * Percent and underscore remain pattern wildcards. + */ + whereILike(column: ColumnRef, value: string): this { + return (whereILikeImpl as any)(this, column, value); + } + + /** + * Append raw WHERE SQL with Knex bindings. Never interpolate untrusted values. + * Raw SQL uses database names and is outside schema-level result/type checking. + */ + whereRaw(sql: string, ...bindings: any[]): this { + return (whereRawImpl as any)(this, sql, ...bindings); + } + + /** + * Add an EXISTS filter from a Knex subquery or query-building callback. + * Use qualified database columns to correlate it with the parent query. + */ + whereExists(callback: Knex.QueryCallback | Knex.QueryBuilder): this { + return (whereExistsImpl as any)(this, callback); + } + + /** + * Add a NOT EXISTS filter from a Knex subquery or query-building callback. + */ + whereNotExists(callback: Knex.QueryCallback | Knex.QueryBuilder): this { + return (whereNotExistsImpl as any)(this, callback); + } + + /** + * Compare a JSON-path value inside a mapped JSON column. + * @param path - JSON path understood by the Knex database dialect. + * @param operator - SQL comparison operator forwarded to Knex. + * @param value - Bound comparison value. + */ + whereJsonPath( + column: ColumnRef, + path: string, + operator?: string, + value?: any + ): this { + return (whereJsonPathImpl as any)(this, column, path, operator, value); + } + + // ======================================================================= + // ORDER BY + // ======================================================================= + + /** + * Append ordering by a mapped property or raw expression (ascending by default). + * Add a unique tie-breaker for stable pages. Eager loading retains parent order. + */ + orderBy( + column: ColumnRef | Knex.Raw, + direction?: 'asc' | 'desc' + ): this { + return (orderByImpl as any)(this, column, direction); + } + + /** + * Append a raw ORDER BY expression with Knex bindings. + * Use database column names; parent ordering is retained during eager loading. + */ + orderByRaw(sql: string, ...bindings: any[]): this { + return (orderByRawImpl as any)(this, sql, ...bindings); + } + + // ======================================================================= + // GROUP BY / HAVING + // ======================================================================= + + /** + * Group rows by mapped schema properties or raw expressions. + * Combine with aggregate expressions in select() to infer grouped DTO results. + */ + groupBy(...columns: (ColumnRef | Knex.Raw)[]): this { + return (groupByImpl as any)(this, ...columns); + } + + /** + * Append raw GROUP BY SQL with optional Knex bindings. + */ + groupByRaw(sql: string, ...bindings: any[]): this { + return (groupByRawImpl as any)(this, sql, ...bindings); + } + + /** + * Filter SQL groups by a mapped column/raw expression, operator and bound value. + */ + having( + column: ColumnRef | Knex.Raw, + operator: string, + value: any + ): this { + return (havingImpl as any)(this, column, operator, value); + } + + /** + * Append raw HAVING SQL with Knex bindings, for example aggregate comparisons. + */ + havingRaw(sql: string, ...bindings: any[]): this { + return havingRawImpl(this as any, sql, ...bindings); + } + + // ======================================================================= + // PAGINATION + // ======================================================================= + + /** + * Set the maximum number of parent rows to select; mutates this query. + * Included collections do not consume the parent limit. + */ + limit(n: number): this { + return limitImpl(this as any, n); + } + + /** + * Skip this many parent rows before applying the limit; mutates this query. + * Use deterministic ordering when navigating offset-based pages. + */ + offset(n: number): this { + return offsetImpl(this as any, n); + } + + /** + * Execute a one-based offset page and a separate matching-source count query. + * Mutates this builder's limit/offset and returns mapped rows plus page metadata. + * The count and page are separate reads, not a snapshot unless your transaction provides one. + */ + async paginate(opts: { + /** One-based page number. */ + page: number; + /** Maximum parent rows in a page. */ + pageSize: number; + }): Promise> { + return paginateImpl(this as any, opts) as Promise< + PaginationResult + >; + } + + /** + * Read a cursor page without running a total-count query. + * The orderBy form clones the source and preserves exact composite sort values; + * its non-null sort must contain a declared unique key. The legacy column form + * mutates this builder and defaults to id descending. Reapply access filters on + * every request: cursors are positions, not authorization or snapshots. + * @returns Mapped data, hasMore, and a nextCursor that is null on the last page. + * @throws For invalid composite cursors or unsupported composite query shapes. + */ + paginateAfter( + opts: CompositeCursorOptions + ): Promise>; + /** + * Read a cursor page without running a total-count query. + * The orderBy form clones the source and preserves exact composite sort values; + * its non-null sort must contain a declared unique key. The legacy column form + * mutates this builder and defaults to id descending. Reapply access filters on + * every request: cursors are positions, not authorization or snapshots. + * @returns Mapped data, hasMore, and a nextCursor that is null on the last page. + * @throws For invalid composite cursors or unsupported composite query shapes. + */ + paginateAfter(opts: { + /** Previous raw single-column position; omit for the first page. */ + cursor?: any; + /** Maximum parent rows to return; one extra row determines hasMore. */ + limit: number; + /** Unique sort property; defaults to id in the legacy API. */ + column?: ColumnRef; + /** Sort/continuation direction; defaults to descending. */ + direction?: 'asc' | 'desc'; + }): Promise>; + /** + * Read a cursor page without running a total-count query. + * The orderBy form clones the source and preserves exact composite sort values; + * its non-null sort must contain a declared unique key. The legacy column form + * mutates this builder and defaults to id descending. Reapply access filters on + * every request: cursors are positions, not authorization or snapshots. + * @returns Mapped data, hasMore, and a nextCursor that is null on the last page. + * @throws For invalid composite cursors or unsupported composite query shapes. + */ + async paginateAfter(opts: any): Promise> { + if ('orderBy' in opts) return compositeCursor(this as any, opts); + return (paginateAfterImpl as any)(this, opts) as Promise< + CursorPaginationResult + >; + } + + // ======================================================================= + // WRITE OPERATIONS + // ======================================================================= + + /** + * Insert one schema-shaped row and return its mapped database representation. + * Applies configured insert hooks, column mappings and timestamp defaults. + */ + async insert(data: InsertType): Promise { + return insertImpl(this as any, data) as Promise; + } + + /** + * Insert an array of schema-shaped rows and return their mapped representations. + * Returns an empty array for empty input; use bulkInsert() to control chunking. + */ + async insertMany(data: InsertType[]): Promise { + return insertManyImpl(this as any, data) as Promise; + } + + /** + * Configure an upsert conflict target using mapped properties. + * Call merge() or ignore() on the returned builder to insert the row. + */ + onConflict( + ...conflictColumns: ColumnRef[] + ): import('./operations/insert.js').OnConflictBuilder< + TLocalSchema, + TResult + > { + return (onConflictImpl as any)(this, ...conflictColumns); + } + + /** + * Insert one row or update it when the chosen conflict target already exists. + * @param opts - Conflict properties and optional subset of properties to update. + * @returns The inserted or updated row mapped to schema property names. + */ + async upsert( + data: InsertType, + opts: { + /** Properties identifying an existing row on conflict. */ + conflictColumns: ColumnRef[]; + /** Properties to update on conflict; omit to merge insert values. */ + updateColumns?: ColumnRef[]; + } + ): Promise { + return (upsertImpl as any)(this, data, opts); + } + + /** + * Insert rows in chunks, optionally ignoring or merging conflicts. + * @param opts - Chunk size (default 500), conflict policy and conflict properties. + * @returns Mapped rows returned by PostgreSQL; ignored conflicts produce no row. + */ + async bulkInsert( + rows: InsertType[], + opts?: { + /** Requested rows per statement, capped by parameter limits; default 500. */ + chunkSize?: number; + /** Optional PostgreSQL conflict policy applied to each chunk. */ + onConflict?: 'ignore' | 'merge'; + /** Conflict target properties when a conflict policy is supplied. */ + conflictColumns?: ColumnRef[]; + } + ): Promise { + return (bulkInsertImpl as any)(this, rows, opts); + } + + /** + * Insert/update rows in chunks using the specified conflict properties. + * @param opts - Required conflict target and optional chunk size (default 500). + * @returns The database rows produced by each chunk, mapped to schema properties. + */ + async bulkUpsert( + rows: InsertType[], + opts: { + /** Properties identifying an existing row on conflict. */ + conflictColumns: ColumnRef[]; + /** Requested rows per statement, capped by parameter limits; default 500. */ + chunkSize?: number; + } + ): Promise { + return (bulkUpsertImpl as any)(this, rows, opts); + } + + // ======================================================================= + // UPDATE + // ======================================================================= + + /** + * Update rows matching this query's explicit filters and return mapped rows. + * Applies update hooks and timestamp metadata. Add a WHERE clause to avoid a + * table-wide update; this method does not track entity identity. + */ + async update(data: Partial>): Promise { + return updateImpl(this as any, data) as Promise; + } + + /** + * Apply per-row where/set pairs and return the total affected-row count. + * Maps both filter and update property names and applies configured update hooks. + */ + async bulkUpdate( + updates: ReadonlyArray<{ + /** Equality filters identifying the rows for this update. */ + where: Partial>; + /** Schema properties to assign to those rows. */ + set: Partial>; + }> + ): Promise { + return bulkUpdateImpl(this as any, updates as any); + } + + // ======================================================================= + // DELETE / SOFT DELETE + // ======================================================================= + + /** + * Delete rows matching explicit filters and return the affected-row count. + * Runs beforeDelete hooks; with soft-delete metadata it sets the deletion timestamp + * instead of removing rows. Add filters to avoid a table-wide write. + */ + async delete(): Promise { + return deleteImpl(this as any); + } + + /** + * Include soft-deleted rows in read results without removing explicit filters. + */ + withDeleted(): this { + return withDeletedImpl(this as any); + } + + /** + * Restrict reads to rows whose configured soft-delete column is non-null. + */ + onlyDeleted(): this { + return onlyDeletedImpl(this as any); + } + + /** + * Permanently delete rows matching explicit filters, even on a soft-delete schema. + * Runs beforeDelete hooks and returns the affected count. This cannot be undone + * without a transaction rollback or backup. + */ + async hardDelete(): Promise { + return hardDeleteImpl(this as any); + } + + /** + * Clear the deletion timestamp on rows matching explicit filters and return them. + * @throws If the schema has no soft-delete configuration. + */ + async restore(): Promise { + return restoreImpl(this as any) as Promise; + } + + // ======================================================================= + // EAGER LOADING (JOIN) + // ======================================================================= + + /** + * Eager-load a related object under spec.as using mapped join columns. + * Required joins remove unmatched parents; optional joins return null. Unlike a + * flat join, related fields remain nested and are mapped with the foreign schema. + */ + joinOne< + TForeignSchema extends ObjectSchemaBuilder< + any, + any, + any, + any, + any, + any, + any + >, + TFieldName extends string, + TRequired extends boolean = true + >( + spec: JoinOneSpec + ): QuerySource< + TLocalSchema, + import('./types.js').WithJoinedOne< + TResult, + TFieldName, + TForeignSchema, + TRequired + > + > { + return joinOneImpl(this as any, spec); + } + + /** + * Eager-load a nested array without multiplying parent rows. + * The relation's own order/limit/offset controls children separately from parent paging. + */ + joinMany< + TForeignSchema extends ObjectSchemaBuilder< + any, + any, + any, + any, + any, + any, + any + >, + TFieldName extends string + >( + spec: JoinManySpec + ): QuerySource< + TLocalSchema, + import('./types.js').WithJoinedMany + > { + return joinManyImpl(this as any, spec); + } + + /** + * Eager-load a relation registered on the schema by name. + * @param customize - Optional callback configuring the related query. + * Use an ORM DbSet when you need typed relation names and customization fields. + */ + include( + relationName: string, + customize?: (q: QuerySource) => void + ): this { + return includeImpl(this as any, relationName, customize); + } + + /** + * Eager-load a relation declared for one polymorphic discriminator value. + * Other variants are not populated with this relation. Use ORM entity declarations + * to retain known relation customization types. + */ + includeVariant( + variantKey: string, + relationName: string, + customize?: (q: QuerySource) => void + ): this { + return includeVariantImpl( + this as any, + variantKey, + relationName, + customize + ); + } + + // ======================================================================= + // POLYMORPHIC VARIANTS + // ======================================================================= + + /** + * Add a filter applying only to the named polymorphic branch. + * Other discriminator values remain eligible. Maps the variant property to its + * CTI/STI storage column; throws for unknown variants or unsupported operators. + */ + whereVariant( + key: string, + column: string, + operator: string, + value: any + ): this { + const state = getState(this); + const variantConfig = getVariantConfig(this); + if (!variantConfig) { + throw new Error( + 'whereVariant() can only be used on a polymorphic schema (created with .withVariants())' + ); + } + + const spec = variantConfig.variants[key]; + if (!spec) { + throw new Error( + `whereVariant: unknown variant key "${key}". ` + + `Valid keys: ${Object.keys(variantConfig.variants).join(', ')}` + ); + } + + const op = operator.toLowerCase(); + if (!ALLOWED_OPS.has(op)) { + throw new Error( + `whereVariant: operator "${operator}" is not allowed. ` + + `Allowed operators: ${[...ALLOWED_OPS].join(', ')}` + ); + } + + const { propToCol } = buildColumnMap(spec.schema); + const colName = propToCol.get(column) ?? column; + + let qualifiedColumn: string; + if (spec.storage === 'cti') { + qualifiedColumn = `__v_${key}.${colName}`; + } else { + qualifiedColumn = `${state.tableName}.${colName}`; + } + + state.variantWhereFilters.push({ key, qualifiedColumn, op, value }); + invalidateCache(this); + return this; + } + + /** + * Choose which polymorphic variant bodies are loaded. + * This controls variant joins/selection, not a discriminator filter on base rows. + * @throws If the schema is not polymorphic. + */ + selectVariants(keys: string[]): this { + const state = getState(this); + if (!getVariantConfig(this)) { + throw new Error( + 'selectVariants() can only be used on a polymorphic schema (created with .withVariants())' + ); + } + state.enabledVariants = new Set(keys); + invalidateCache(this); + return this; + } + + // ======================================================================= + // ESCAPE HATCH + // ======================================================================= + + /** + * Configure the underlying mutable Knex query as an escape hatch. + * Raw changes do not infer a new result type; the caller owns column names, + * result shape and cardinality introduced by the callback. + */ + apply(fn: (builder: Knex.QueryBuilder) => void): this { + const state = getState(this); + state.opaqueReadShape = true; + invalidateCache(this); + fn(state.baseQuery); + return this; + } + + // ======================================================================= + // TRANSACTION + // ======================================================================= + + /** + * Clone this query and its eager-relation queries onto an existing transaction. + * The source builder is unchanged; transaction commit/rollback stays with the caller. + */ + transacting(trx: Knex.Transaction): QuerySource { + const state = getState(this); + const builder = new QuerySource( + trx as unknown as Knex, + state.localSchema as TLocalSchema, + state.baseQuery.clone().transacting(trx) + ); + const builderState = getState(builder); + for (const spec of state.specs) { + builderState.specs.push({ + ...spec, + foreignQuery: spec.foreignQuery.clone().transacting(trx) + }); + } + builderState.explicitSelects = state.explicitSelects + ? [...state.explicitSelects] + : null; + builderState.selectionMode = state.selectionMode; + builderState.appliedProjection = state.appliedProjection; + builderState.projectionColumns = state.projectionColumns + ? { ...state.projectionColumns } + : null; + builderState.projectionDecoders = { ...state.projectionDecoders }; + builderState.hiddenColumns = new Set(state.hiddenColumns); + builderState.includeDeleted = state.includeDeleted; + builderState.onlyDeleted = state.onlyDeleted; + builderState.skipDefaultScope = state.skipDefaultScope; + builderState.opaqueReadShape = state.opaqueReadShape; + builderState.variantConfig = state.variantConfig; + builderState.enabledVariants = + state.enabledVariants !== null + ? new Set(state.enabledVariants) + : null; + builderState.variantWhereFilters = [...state.variantWhereFilters]; + builderState.variantRelationIncludes = [ + ...state.variantRelationIncludes + ]; + return builder; + } + + // ======================================================================= + // EXECUTION + // ======================================================================= + + /** + * Render SQL for debugging without executing it. + * Bindings may appear as literal values; avoid logging sensitive inputs. + */ + toQuery(): string { + return getQuery(this).toQuery(); + } + + /** @internal ORM tracking must never attach aggregate or DTO rows as entities. */ + get returnsEntityRows(): boolean { + return getState(this).selectionMode === null; + } + + /** + * Expose the built Knex query without executing Framework row mapping. + * Direct execution returns raw database rows, potentially including internal fields. + * Treat mutations as an escape hatch rather than typed Framework configuration. + */ + toKnexQuery(): Knex.QueryBuilder { + return getQuery(this); + } + + /** + * Render the query as a debugging SQL string; equivalent to toQuery(). + */ + toString(): string { + return getQuery(this).toString(); + } + + /** + * Execute SQL and map all rows, including eager relations and aggregate decoders. + * @returns An empty array when no rows match. + * @throws Database errors and output-parser validation failures. + */ + async execute(): Promise { + return executeImpl(this) as Promise; + } + + /** + * Execute this query for its first mapped row, or undefined if none matches. + * Set ordering when the choice of first row matters. + */ + async first(): Promise { + const query = getQuery(this).first(); + const row = await query; + + if (!row) return undefined; + return cleanAndMapRow(this, row) as TResult; + } + + /** + * Execute a selection and collect one mapped column's values into an array. + * @param column - Schema property whose database column should be read. + */ + async pluck( + column: ColumnRef + ): Promise { + const _state = getState(this); + const col = resolveColumn(this, column, 'pluck') as string; + const rows = await buildQuery(this).select(col); + return rows.map( + (row: any) => row[col] ?? row[column as string] + ) as TResult[K][]; + } + + /** + * Promise-compatible execution hook enabling await query(...). + * Runs execute() and forwards fulfillment/rejection; repeated awaits may execute again. + */ + // biome-ignore lint/suspicious/noThenProperty: intentional thenable + then( + onfulfilled?: + | ((value: TResult[]) => TReturn1 | PromiseLike) + | null, + onrejected?: ((reason: any) => TReturn2 | PromiseLike) | null + ): Promise { + return this.execute().then(onfulfilled, onrejected); + } +} + +// Register the constructor for circular-dependency-safe access +registerQuerySource(QuerySource); diff --git a/libs/knex-schema/src/SchemaQueryBuilder.ts b/libs/knex-schema/src/SchemaQueryBuilder.ts index 104a8724..197c057a 100644 --- a/libs/knex-schema/src/SchemaQueryBuilder.ts +++ b/libs/knex-schema/src/SchemaQueryBuilder.ts @@ -1,47 +1,67 @@ -// @cleverbrush/knex-schema — SchemaQueryBuilder - -import type { InferType } from '@cleverbrush/schema'; import { + type ArraySchemaBuilder, + array, EXTRA_TYPE_BRAND, - METHOD_LITERAL_BRAND, - type ObjectSchemaBuilder + type InferType, + type ObjectSchemaBuilder, + object, + SYMBOL_SCHEMA_PROPERTY_DESCRIPTOR } from '@cleverbrush/schema'; import type { Knex } from 'knex'; import { - AliasedQueryBuilder, - type AliasTables, - isTableAlias, - type TableAlias -} from './aliased-query.js'; -import { buildColumnMap } from './columns.js'; -import type { - AggregateOptions, - AggregateResult, - ExtremumResult, - ExtremumValue, - OutputSchema + buildColumnMap, + getPrimaryKeyColumns, + resolvePropertyKey +} from './columns.js'; +import type { RelationInfo, SchemaProps } from './entity.js'; +import { + type AggregateExpression, + type AggregateKind, + type AggregateOptions, + type AggregateResult, + type AliasedColumn, + COLUMN, + compileAggregate, + createAggregate, + isAggregate, + type OutputSchema } from './expressions.js'; -import { getTableName, POLYMORPHIC_TYPE_BRAND } from './extension.js'; -import { scalarAggregate } from './operations/aggregate.js'; +import { getProjections, getTableName, getVariants } from './extension.js'; +import { OpaqueQuery, type QueryOutput } from './OpaqueQuery.js'; import { type CompositeCursorOptions, compositeCursor } from './operations/composite-cursor.js'; -// Operations +import type { ScopesOf } from './operations/helpers.js'; +import { getQuerySourceCtor } from './operations/helpers.js'; +import { getState } from './operations/state.js'; +import { PolymorphicQueryBuilder } from './PolymorphicQueryBuilder.js'; +import { QuerySource } from './QuerySource.js'; +import type { ReadRelations, ReadVariantMetadata } from './read-entity.js'; +import { + captureReadRaw, + captureValue, + type ReadPredicate, + type ReadPredicateContext, + type ReadPredicateSelector, + ReadPredicates +} from './read-predicates.js'; +import { compileReadProjection, type ReadField } from './read-projection.js'; import { - avgImpl, - countDistinctImpl, - countImpl, - distinctImpl, - maxImpl, - minImpl, - projectedImpl, - scopedImpl, - selectImpl, - selectRawImpl, - sumImpl, - unscopedImpl -} from './operations/select.js'; + type ColumnReadSchema, + compileReadSchema, + decodeObject, + type ObjectReadSchema, + type ReadNode, + type ReadObject, + type ReadSchema, + ReadSchemaError, + readExpression, + type SchemaForValue +} from './read-schema.js'; + +export { type BoundQuery, createQuery, query } from './query.js'; + import type { ColumnRef, CursorPaginationResult, @@ -49,264 +69,429 @@ import type { JoinManySpec, JoinOneSpec, PaginationResult, - SelectProjection, - SelectSelector + RelationSpec } from './types.js'; -export { - OnConflictBuilder, - type OnConflictMergeHelpers, - type OnConflictMergeOptions, - type OnConflictUpdateData, - type OnConflictUpdateValue -} from './operations/insert.js'; - -import { - deleteImpl, - hardDeleteImpl, - onlyDeletedImpl, - restoreImpl, - withDeletedImpl -} from './operations/delete.js'; -import { - ALLOWED_OPS, - buildQuery, - cleanAndMapRow, - getQuery, - getVariantConfig, - invalidateCache, - registerSchemaQueryBuilder, - resolveColumn -} from './operations/helpers.js'; -import { - bulkInsertImpl, - bulkUpsertImpl, - insertImpl, - insertManyImpl, - onConflictImpl, - upsertImpl -} from './operations/insert.js'; -import { - includeImpl, - includeVariantImpl, - joinManyImpl, - joinOneImpl -} from './operations/join.js'; -import { - executeImpl, - limitImpl, - offsetImpl, - paginateAfterImpl, - paginateImpl -} from './operations/pagination.js'; -import { getState, setState } from './operations/state.js'; -import { bulkUpdateImpl, updateImpl } from './operations/update.js'; -import { - andWhereImpl, - groupByImpl, - groupByRawImpl, - havingImpl, - havingRawImpl, - orderByImpl, - orderByRawImpl, - orWhereImpl, - orWhereInImpl, - orWhereNotInImpl, - orWhereNotNullImpl, - orWhereNullImpl, - whereBetweenImpl, - whereExistsImpl, - whereILikeImpl, - whereImpl, - whereInImpl, - whereJsonPathImpl, - whereLikeImpl, - whereNotBetweenImpl, - whereNotExistsImpl, - whereNotImpl, - whereNotInImpl, - whereNotNullImpl, - whereNullImpl, - whereRawImpl -} from './operations/where.js'; -import { type SchemaAwareQuery, schemaReadQuery } from './SchemaReadQuery.js'; - -// --------------------------------------------------------------------------- -// Type-level helpers -// --------------------------------------------------------------------------- - -type ScopesOf = S extends { - readonly [METHOD_LITERAL_BRAND]?: infer N; +const READ_COLUMN = Symbol('schema-read-column'); +const JSON_PATH = Symbol('schema-json-path'); +/** @internal Nominal read-query identity used without recursively comparing fluent APIs. */ +export const READ_QUERY = Symbol('schema-read-query'); +/** Minimal type surface for a customizer's strongly inferred result schema. */ +export interface ReadQueryShape { + /** @internal Nominal marker; constructing a plain schema object is not a query. */ + readonly [READ_QUERY]: true; + /** Decoded result schema inferred from the returned query. */ + readonly rowSchema: R; } - ? Extract - : never; - -type ProjectionsOf = S extends { - readonly [EXTRA_TYPE_BRAND]?: infer P; +let readAliasSequence = 0; +/** A typed SQL column; selectors receive descriptions, not row values. */ +export interface ReadColumn + extends AliasedColumn> { + /** @internal Decoding and projection metadata shared by the query compiler. */ + readonly [READ_COLUMN]: ReadNode; + /** @internal Captured JSON path beneath a storage column. */ + readonly [JSON_PATH]?: readonly string[]; + /** Type-only property identity for column-list projections. */ + readonly __property?: K; } - ? P extends Record - ? P - : Record - : Record; - -type ProjectionKeysOf< +/** A JSON object column also exposes its known nested properties. */ +export type NestedReadColumn = ReadColumn< + ColumnReadSchema, + Key +> & + (S extends ReadObject + ? { + [K in keyof SchemaProps & string]: NestedReadColumn< + SchemaProps[K], + `${Key}.${K}` + >; + } + : {}); +/** Columns available for typed projections and filters. */ +export type ReadColumns< + S extends ReadObject, + Relations extends PropertyKey = never +> = { + [K in Exclude, Relations> & string]: NestedReadColumn< + SchemaProps[K], + K + >; +}; +type SelectedValue = + | (Selector extends (...args: any[]) => AliasedColumn + ? Value + : Selector extends keyof Columns + ? Columns[Selector] extends AliasedColumn + ? Value + : never + : never) + | null; +type Selection = Record | AggregateExpression>; +type MergeProps = { + [K in keyof A | keyof B]: K extends keyof B + ? B[K] + : K extends keyof A + ? A[K] + : never; +}; +type NamedProjections = S extends { readonly [EXTRA_TYPE_BRAND]?: infer P } + ? P + : {}; +type NamedKeys< S, - K extends keyof ProjectionsOf & string -> = ProjectionsOf[K] extends readonly (infer T extends string)[] - ? T - : string; - -type QueryResultType = TLocalSchema extends { - readonly [POLYMORPHIC_TYPE_BRAND]?: infer U; -} - ? NonNullable - : InferType; - -// --------------------------------------------------------------------------- -// SchemaQueryBuilder -// --------------------------------------------------------------------------- + K extends keyof NamedProjections +> = NamedProjections[K] extends readonly (infer Key extends string)[] + ? Key + : never; +/** Structural schema inferred from a typed projection. */ +export type ReadProjection = ObjectSchemaBuilder<{ + [K in keyof S & string]: S[K] extends ReadColumn + ? R + : S[K] extends AggregateExpression + ? SchemaForValue + : never; +}>; +type AddField< + S extends ReadObject, + K extends string, + F extends ReadSchema +> = ObjectSchemaBuilder, K> & Record>; +/** @internal Foreign schema retained by a declared relation. */ +export type Related = R extends RelationInfo ? S : never; +/** @internal Output cardinality and nullability of a loaded relation. */ +export type RelationField = + R extends RelationInfo<'hasMany' | 'belongsToMany', any> + ? ArraySchemaBuilder + : R extends RelationInfo<'belongsTo', any> + ? R extends { optional: infer O } + ? true extends O + ? SchemaForValue | null> + : S + : S + : SchemaForValue | null>; +type AnyReadQuery = + | SchemaQueryBuilder + | PolymorphicQueryBuilder; +type Loaded = { + name: string; + query: AnyReadQuery; + relation: RelationSpec; + required: boolean; +}; +/** Query factory result: a table query or a declared polymorphic union. */ +export type SchemaAwareQuery = + ReadVariantMetadata extends { + discriminator: string; + variants: Record; + } + ? PolymorphicQueryBuilder + : SchemaQueryBuilder; +/** @internal Apply parent correlation before child selection, ordering and pagination. */ +export type ReadCorrelation = ( + query: Knex.QueryBuilder, + alias: string, + source: ReadObject +) => void; /** - * Build schema-aware SQL with mapped columns, projections and eager relations. - * Fluent configuration methods mutate this builder; create a fresh query for each - * independent operation. Await the builder or call execute() to obtain mapped rows. - * Use query() to infer both the schema and result types automatically. + * Immutable table query whose row schema follows its decoded selection and relations. + * Configuration returns independent lazy builders; metadata access never executes SQL. + * Only unprojected table queries can write. Full ORM rows may participate in tracking. */ export class SchemaQueryBuilder< - TLocalSchema extends ObjectSchemaBuilder, - TResult -> { - /** - * Enter immutable, detached schema-aware read mode before selecting/loading fields. - * Row metadata never runs SQL; existing query behavior remains unchanged. - * @throws ReadSchemaError if result-shaping operations were already applied. - */ - withRowSchema(): SchemaAwareQuery { - return schemaReadQuery(this); - } - /** - * Create a query over the schema's configured table. - * @param knex - Database connection or transaction used to execute the query. - * @param localSchema - Schema containing property/column and relation metadata. - * @param baseQuery - Optional existing Knex query to configure; it is not cloned. - */ + S extends ReadObject, + Row extends ReadObject = ObjectReadSchema>, + Relations extends Record = ReadRelations, + Writable extends boolean = true +> extends ReadPredicates> { + /** @internal Nominal identity for typed child-query customizers. */ + declare readonly [READ_QUERY]: true; + private declare readonly writable: Writable; + private readonly alias = `__schema_read_${readAliasSequence++}`; + private fields: Record; + private loaded: Loaded[] = []; + private base: Knex.QueryBuilder; + private selected = false; + private grouped = false; + private distinctRows = false; + private defaults?: Knex.QueryBuilder; + private skipDefaults = false; + private deleted: 'exclude' | 'include' | 'only' = 'exclude'; + private readonly columns: Record>; + private readonly columnSet = new Set>(); + /** Runtime structural schema; stable across filters, pagination and transaction clones. */ + readonly rowSchema: Row; + + /** @internal Use query() or createQuery() instead of constructing directly. */ constructor( - knex: Knex, - localSchema: TLocalSchema, - baseQuery?: Knex.QueryBuilder + private readonly knex: Knex, + private readonly source: S, + base: Knex.QueryBuilder, + alias?: string ) { - const tableName = getTableName(localSchema); - setState(this, { - knex, - baseQuery: baseQuery ?? knex(tableName), - localSchema, - specs: [], - tableName, - explicitSelects: null, - selectionMode: null, - appliedProjection: null, - projectionColumns: null, - projectionDecoders: {}, - hiddenColumns: new Set(), - includeDeleted: false, - onlyDeleted: false, - skipDefaultScope: false, - variantConfig: undefined, - enabledVariants: null, - variantWhereFilters: [], - variantRelationIncludes: [], - cachedBuiltQuery: null + super(); + if (alias !== undefined) this.alias = alias; + this.base = knex.queryBuilder().from(base.clone().as(this.alias)); + const relations = (source.introspect().extensions?.relations ?? + []) as RelationSpec[]; + const excluded = new Set(relations.map(r => r.name)); + const { propToCol } = buildColumnMap(source); + this.fields = Object.create(null); + this.columns = Object.create(null); + for (const [key, schema] of Object.entries( + source.introspect().properties ?? {} + )) { + if (excluded.has(key)) continue; + const node = compileReadSchema(schema as ReadSchema); + const column = `${this.alias}.${propToCol.get(key) ?? key}`; + this.columns[key] = this.describeColumn( + schema as ReadSchema, + propToCol.get(key) ?? key + ); + this.fields[key] = { + node, + expression: knex => readExpression(knex, node, column) + }; + } + this.rowSchema = this.schema() as Row; + const defaultScope = source.introspect().extensions?.defaultScope; + if (typeof defaultScope === 'function') { + const scope = this.copy(); + scope.base = knex.queryBuilder(); + this.defaults = this.checkScope( + scope, + defaultScope(scope) + ).base.clone(); + } + } + + private describeColumn( + schema: ReadSchema, + column: string, + path: readonly string[] = [] + ): ReadColumn { + const described: ReadColumn = { + [COLUMN]: { + alias: this.alias, + column, + schema + }, + [READ_COLUMN]: compileReadSchema(schema), + [JSON_PATH]: path + }; + this.columnSet.add(described); + const info = schema.introspect(); + if (info.type === 'object') { + for (const [key, child] of Object.entries((info as any).properties)) + Object.defineProperty(described, key, { + value: this.describeColumn(child as ReadSchema, column, [ + ...path, + key + ]), + enumerable: true + }); + } + return described; + } + + private schema(): ReadObject { + return object( + Object.fromEntries( + Object.entries(this.fields).map(([key, field]) => [ + key, + field.node.schema + ]) + ) + ); + } + + private copy(): this { + const copy = Object.create(Object.getPrototypeOf(this)) as this; + Object.assign(copy, this, { + base: this.base.clone(), + fields: { ...this.fields }, + loaded: [...this.loaded] }); + return copy; } - // ======================================================================= - // SELECT / DISTINCT / AGGREGATES - // ======================================================================= + /** @internal Prevent customizers from substituting an unrelated query source. */ + sameSource(other: unknown): boolean { + return ( + other instanceof SchemaQueryBuilder && + this.columns === other.columns + ); + } - /** - * Choose columns, or use an object selector to infer a flat result shape. - * Object values can be schema descriptors or aggregate expressions. Column-list - * selection retains the existing result type; raw SQL cannot infer a new shape. - * @returns This builder, narrowed to the object projection when one is supplied. - */ - select(...columns: (ColumnRef | Knex.Raw)[]): this; - /** - * Choose columns, or use an object selector to infer a flat result shape. - * Object values can be schema descriptors or aggregate expressions. Column-list - * selection retains the existing result type; raw SQL cannot infer a new shape. - * @returns This builder, narrowed to the object projection when one is supplied. - */ - select>( - selector: TSel - ): SchemaQueryBuilder>>; - /** - * Choose columns, or use an object selector to infer a flat result shape. - * Object values can be schema descriptors or aggregate expressions. Column-list - * selection retains the existing result type; raw SQL cannot infer a new shape. - * @returns This builder, narrowed to the object projection when one is supplied. - */ - select(...args: unknown[]): any { - return selectImpl(this as any, ...args); + private column( + selector: ReadPredicateSelector> + ): ReadColumn { + const column = + typeof selector === 'string' + ? selector + .split('.') + .reduce((node: any, key) => node?.[key], this.columns) + : selector(this.columns as ReadColumns); + if (!column || !this.columnSet.has(column as ReadColumn)) + throw new ReadSchemaError( + 'Column does not belong to this read query' + ); + return column as ReadColumn; + } + + private name( + column: ReadColumn, + alias = column[COLUMN].alias + ): string | Knex.Raw { + const name = `${alias}.${column[COLUMN].column}`; + const path = column[JSON_PATH]; + if (!path?.length) return name; + const type = column[READ_COLUMN].schema.introspect().type; + const json = type === 'array' || type === 'object'; + const extracted = this.knex.raw(`?? ${json ? '#>' : '#>>'} ?::text[]`, [ + name, + [...path] + ]); + if (type === 'number') + return this.knex.raw('cast(? as numeric)', [extracted]); + if (type === 'boolean') + return this.knex.raw('cast(? as boolean)', [extracted]); + return extracted; + } + + private checkScope(input: this, result: unknown): this { + if ( + !(result instanceof SchemaQueryBuilder) || + !input.sameSource(result) || + result.rowSchema !== input.rowSchema || + result.grouped !== input.grouped || + result.selected !== input.selected || + result.distinctRows !== input.distinctRows || + result.deleted !== input.deleted || + result.skipDefaults !== input.skipDefaults || + result.knex !== input.knex + ) { + if (result instanceof Promise) void result.catch(() => {}); + throw new ReadSchemaError( + 'Scopes must synchronously return the supplied query with filters, ordering or pagination only' + ); + } + return result as this; } - /** - * Apply SQL DISTINCT to the selected columns, optionally adding columns. - * Property selectors are mapped to database names; SQL decides row equality. - */ - distinct(...columns: (ColumnRef | Knex.Raw)[]): this { - return (distinctImpl as any)(this, ...columns); + /** Apply a named, synchronous shape-preserving scope once to an independent query. */ + scoped(name: ScopesOf): this { + const scope = ( + this.source.introspect().extensions?.scopes as + | Record + | undefined + )?.[name]; + if (!scope) throw new ReadSchemaError(`Unknown scope: ${name}`); + const copy = this.copy(); + return this.checkScope(copy, scope(copy)); } - /** - * Append a legacy SQL COUNT selection without executing the query. - * The driver controls the result shape/value type. Prefer countValue() for a - * checked scalar number, or aggregate.count() in a typed object projection. - */ - count(column?: ColumnRef | Knex.Raw): this { - return (countImpl as any)(this, column); + /** Exclude only the default scope; keep explicitly configured predicates. */ + unscoped(): this { + const copy = this.copy(); + copy.skipDefaults = true; + return copy; } - /** - * Append a legacy COUNT(DISTINCT column) selection. - * Prefer countDistinctValue() for a checked scalar or aggregate.countDistinct() - * for an inferred grouped result; this legacy method retains the builder type. - */ - countDistinct(column?: ColumnRef | Knex.Raw): this { - return (countDistinctImpl as any)(this, column); + /** Include soft-deleted rows without changing the source query. */ + withDeleted(): this { + const copy = this.copy(); + copy.deleted = 'include'; + return copy; } - /** - * Append a legacy MIN selection without changing the result type. - * Use minValue() for a scalar with explicit decoding, or aggregate.min() in a - * typed projection. SQL returns null for an empty/all-null input. - */ - min(column: ColumnRef | Knex.Raw): this { - return (minImpl as any)(this, column); + /** Match only soft-deleted rows. */ + onlyDeleted(): this { + const copy = this.copy(); + copy.deleted = 'only'; + return copy; } - /** - * Append a legacy MAX selection without changing the result type. - * Use maxValue() for a scalar with explicit decoding, or aggregate.max() in a - * typed projection. SQL returns null for an empty/all-null input. - */ - max(column: ColumnRef | Knex.Raw): this { - return (maxImpl as any)(this, column); + /** True only when rows retain their complete entity shape. */ + get returnsEntityRows(): boolean { + return !this.selected && !this.grouped && !this.distinctRows; } - /** - * Append a legacy SUM selection, leaving numeric conversion to the driver. - * Prefer sumValue() or aggregate.sum() to preserve exact numeric text by default. - */ - sum(column: ColumnRef | Knex.Raw): this { - return (sumImpl as any)(this, column); + /** @internal Build an independent statement containing defaults and explicit filters. */ + private filtered(): Knex.QueryBuilder { + const query = this.base.clone(); + const explicitWhere = (query as any)._statements.filter( + (statement: any) => statement.grouping === 'where' + ); + (query as any)._statements = (query as any)._statements.filter( + (statement: any) => statement.grouping !== 'where' + ); + if (this.defaults && !this.skipDefaults) { + const defaults = this.defaults.clone() as any; + const where = defaults._statements.filter( + (statement: any) => statement.grouping === 'where' + ); + (query as any)._statements = [ + ...defaults._statements.filter( + (statement: any) => statement.grouping !== 'where' + ), + ...(query as any)._statements + ]; + (query as any)._single = { + ...defaults._single, + ...(query as any)._single + }; + if (where.length) + query.where(nested => { + (nested as any)._statements = [...where]; + }); + } + if (explicitWhere.length) + query.where(nested => { + (nested as any)._statements = [...explicitWhere]; + }); + const softDelete = this.source.introspect().extensions?.softDelete as + | { column: string } + | undefined; + if (softDelete && this.deleted !== 'include') { + query[this.deleted === 'only' ? 'whereNotNull' : 'whereNull']( + `${this.alias}.${softDelete.column}` + ); + } + return query; } - /** - * Append a legacy AVG selection, leaving numeric conversion to the driver. - * Prefer avgValue() or aggregate.avg() for a typed, precision-preserving result. - */ - avg(column: ColumnRef | Knex.Raw): this { - return (avgImpl as any)(this, column); + private async scalar( + kind: AggregateKind, + selector?: ReadPredicateSelector>, + options?: AggregateOptions + ): Promise { + if ( + this.grouped || + this.distinctRows || + Object.values(this.fields).some(field => field.aggregate) + ) + throw new ReadSchemaError( + 'Scalar aggregates require an ungrouped source' + ); + const column = + selector === undefined ? undefined : this.column(selector); + const compiled = compileAggregate( + this.knex, + createAggregate(kind, column, options), + () => this.name(column!, '__aggregate') + ); + const source = this.compile() + .clearSelect() + .clearOrder() + .clear('limit') + .clear('offset') + .select(this.knex.raw('??.*', [this.alias])); + const row = await this.knex + .from(source.as('__aggregate')) + .select({ value: compiled.sql }) + .first(); + return compiled.decode(row?.value); } /** @@ -316,9 +501,9 @@ export class SchemaQueryBuilder< * @returns A safe integer by default, including zero for an empty source. * @throws If the default count overflows, the source is grouped/distinct, or parsing fails. */ - countValue | undefined = undefined>( - options?: AggregateOptions - ): Promise>; + countValue | undefined = undefined>( + options?: AggregateOptions + ): Promise>; /** * Count non-null column values without mutating the source query. * Source paging/order is ignored; filters, scopes and transactions remain. @@ -326,10 +511,10 @@ export class SchemaQueryBuilder< * @param options - Optional parser replacing safe-integer decoding. * @throws If the default result overflows or the source is grouped/distinct. */ - countValue | undefined = undefined>( - column: ColumnRef, - options?: AggregateOptions - ): Promise>; + countValue | undefined = undefined>( + column: ReadPredicateSelector>, + options?: AggregateOptions + ): Promise>; /** * Count matching rows, or non-null column values, without mutating this query. * Ignores source ordering/limits/offsets while retaining filters and transactions. @@ -338,14 +523,15 @@ export class SchemaQueryBuilder< * @throws If the default count overflows, the source is grouped/distinct, or parsing fails. */ countValue( - columnOrOptions?: ColumnRef | AggregateOptions, + columnOrOptions?: + | ReadPredicateSelector> + | AggregateOptions, options?: AggregateOptions ): Promise { const hasColumn = typeof columnOrOptions === 'string' || typeof columnOrOptions === 'function'; - return scalarAggregate( - this, + return this.scalar( 'count', hasColumn ? columnOrOptions : undefined, hasColumn ? options : columnOrOptions @@ -359,11 +545,11 @@ export class SchemaQueryBuilder< * @returns A safe integer, or the parser's inferred output type. * @throws If the count is unsafe, the source is grouped/distinct, or parsing fails. */ - countDistinctValue | undefined = undefined>( - column: ColumnRef, - options?: AggregateOptions - ): Promise> { - return scalarAggregate(this, 'countDistinct', column, options); + countDistinctValue | undefined = undefined>( + column: ReadPredicateSelector>, + options?: AggregateOptions + ): Promise> { + return this.scalar('countDistinct', column, options); } /** @@ -373,11 +559,11 @@ export class SchemaQueryBuilder< * @returns Database numeric text, or null for empty/all-null input by default. * An output parser replaces default decoding and controls the result type. */ - sumValue | undefined = undefined>( - column: ColumnRef, - options?: AggregateOptions - ): Promise> { - return scalarAggregate(this, 'sum', column, options); + sumValue | undefined = undefined>( + column: ReadPredicateSelector>, + options?: AggregateOptions + ): Promise> { + return this.scalar('sum', column, options); } /** @@ -387,11 +573,11 @@ export class SchemaQueryBuilder< * @returns Exact database numeric text or null by default; a parser overrides this. * @remarks Text preserves database precision, not precision already lost in floating-point storage. */ - avgValue | undefined = undefined>( - column: ColumnRef, - options?: AggregateOptions - ): Promise> { - return scalarAggregate(this, 'avg', column, options); + avgValue | undefined = undefined>( + column: ReadPredicateSelector>, + options?: AggregateOptions + ): Promise> { + return this.scalar('avg', column, options); } /** @@ -402,22 +588,15 @@ export class SchemaQueryBuilder< * Dates return Date; numeric SQL overrides may return exact strings. */ minValue< - C extends ColumnRef, - S extends OutputSchema | undefined = undefined + C extends ReadPredicateSelector>, + O extends OutputSchema | undefined = undefined >( column: C, - options?: AggregateOptions + options?: AggregateOptions ): Promise< - AggregateResult< - S, - C extends (...args: any[]) => infer D - ? ExtremumValue - : C extends keyof InferType - ? ExtremumResult[C]> - : unknown - > + AggregateResult, C>> > { - return scalarAggregate(this, 'min', column, options); + return this.scalar('min', column, options); } /** @@ -428,1177 +607,1038 @@ export class SchemaQueryBuilder< * Dates return Date; numeric SQL overrides may return exact strings. */ maxValue< - C extends ColumnRef, - S extends OutputSchema | undefined = undefined + C extends ReadPredicateSelector>, + O extends OutputSchema | undefined = undefined >( column: C, - options?: AggregateOptions + options?: AggregateOptions ): Promise< - AggregateResult< - S, - C extends (...args: any[]) => infer D - ? ExtremumValue - : C extends keyof InferType - ? ExtremumResult[C]> - : unknown - > + AggregateResult, C>> > { - return scalarAggregate(this, 'max', column, options); + return this.scalar('max', column, options); } - /** - * Append a raw SELECT expression with optional Knex value/identifier bindings. - * The caller owns its SQL and result shape; this does not infer a new result type. - */ - selectRaw(sql: string, bindings?: any[]): this { - return selectRawImpl(this as any, sql, bindings); + /** Select an exact flat row shape, retaining per-field runtime schemas. */ + select & string>( + ...columns: Array< + | K + | ((columns: ReadColumns) => ReadColumn) + > + ): SchemaQueryBuilder< + S, + ObjectSchemaBuilder>, K>>, + Relations, + false + >; + /** Select named output fields and aggregates, replacing the previous scalar projection. */ + select

( + selector: (columns: ReadColumns) => P + ): SchemaQueryBuilder< + S, + ObjectSchemaBuilder< + MergeProps< + SchemaProps>, + Pick< + SchemaProps, + Extract, keyof Relations> + > + > + >, + Relations, + false + >; + select(...selectors: any[]): any { + const selections = selectors.map(selector => + typeof selector === 'function' + ? selector(this.columns) + : this.columns[selector] + ); + const selection = + selections.length === 1 && + selections[0] && + !(COLUMN in selections[0]) + ? selections[0] + : Object.fromEntries( + selections.map(column => { + const key = Object.keys(this.columns).find( + key => this.columns[key] === column + ); + if (!key) + throw new ReadSchemaError( + 'Selection must reference columns from this query' + ); + return [key, column]; + }) + ); + if (this.loaded.length && Object.values(selection).some(isAggregate)) + throw new ReadSchemaError( + 'Aggregate projections cannot contain relations' + ); + const copy = this.copy(); + copy.fields = compileReadProjection( + this.knex, + selection, + expression => { + if (!this.columnSet.has(expression as ReadColumn)) + throw new ReadSchemaError( + 'Projection column does not belong to this query' + ); + const column = expression as ReadColumn; + return { node: column[READ_COLUMN], name: this.name(column) }; + } + ); + copy.selected = true; + // Included relations are independent of the scalar projection. + for (const relation of copy.loaded) + copy.fields[relation.name] = this.fields[relation.name]; + Object.assign(copy, { rowSchema: copy.schema() }); + return copy as any; } - /** - * Apply a named schema projection and narrow the selected property type. - * @param name - Projection registered with the schema's projection() extension. - * @throws If the projection is unknown or conflicts with a prior selection. - */ - projected & string>( + /** Select a typed COUNT result on a new query. */ + count( + column?: ReadPredicateSelector> + ): SchemaQueryBuilder< + S, + ReadProjection<{ count: AggregateExpression }>, + Relations, + false + > { + return this.select(() => ({ + count: createAggregate( + 'count', + column === undefined ? undefined : this.column(column) + ) + })) as any; + } + /** Select a typed COUNTDISTINCT result on a new query. */ + countDistinct( + column: ReadPredicateSelector> + ): SchemaQueryBuilder< + S, + ReadProjection<{ countDistinct: AggregateExpression }>, + Relations, + false + > { + return this.select(() => ({ + countDistinct: createAggregate( + 'countDistinct', + column === undefined ? undefined : this.column(column) + ) + })) as any; + } + /** Select a typed SUM result on a new query. */ + sum( + column: ReadPredicateSelector> + ): SchemaQueryBuilder< + S, + ReadProjection<{ sum: AggregateExpression }>, + Relations, + false + > { + return this.select(() => ({ + sum: createAggregate( + 'sum', + column === undefined ? undefined : this.column(column) + ) + })) as any; + } + /** Select a typed AVG result on a new query. */ + avg( + column: ReadPredicateSelector> + ): SchemaQueryBuilder< + S, + ReadProjection<{ avg: AggregateExpression }>, + Relations, + false + > { + return this.select(() => ({ + avg: createAggregate( + 'avg', + column === undefined ? undefined : this.column(column) + ) + })) as any; + } + /** Select a typed MIN result on a new query. */ + min>>( + column: C + ): SchemaQueryBuilder< + S, + ReadProjection<{ + min: AggregateExpression< + SelectedValue, C> + >; + }>, + Relations, + false + > { + return this.select(() => ({ + min: createAggregate< + SelectedValue, C> + >('min', this.column(column)) + })) as any; + } + /** Select a typed MAX result on a new query. */ + max>>( + column: C + ): SchemaQueryBuilder< + S, + ReadProjection<{ + max: AggregateExpression< + SelectedValue, C> + >; + }>, + Relations, + false + > { + return this.select(() => ({ + max: createAggregate< + SelectedValue, C> + >('max', this.column(column)) + })) as any; + } + + /** Keep only distinct selected rows, preserving the row schema. */ + distinct(): SchemaQueryBuilder; + /** Select a property subset and eliminate duplicate rows on that immutable projection. */ + distinct & string>( + ...columns: Array< + | K + | ((columns: ReadColumns) => ReadColumn) + > + ): SchemaQueryBuilder< + S, + ObjectSchemaBuilder>, K>>, + Relations, + false + >; + distinct(...columns: any[]): any { + const copy = columns.length ? this.select(...columns) : this.copy(); + copy.distinctRows = true; + return copy as any; + } + /** Filter grouped results using trusted SQL and captured bindings. */ + havingRaw( + sql: string, + bindings: readonly Knex.RawBinding[] = [] + ): SchemaQueryBuilder { + const copy = this.copy(); + copy.base.havingRaw(captureReadRaw(this.knex, sql, bindings)()); + copy.grouped = true; + return copy as any; + } + /** Filter groups by a mapped column comparison. */ + having( + column: ReadPredicateSelector>, + operator: string, + value: unknown + ): SchemaQueryBuilder { + const copy = this.copy(); + copy.base.having( + this.name(this.column(column)), + operator, + captureValue(this.knex, value)() + ); + copy.grouped = true; + return copy as any; + } + /** Group using trusted SQL without changing the explicit projection. */ + groupByRaw( + sql: string, + bindings: readonly Knex.RawBinding[] = [] + ): SchemaQueryBuilder { + const copy = this.copy(); + copy.base.groupByRaw(captureReadRaw(this.knex, sql, bindings)()); + copy.grouped = true; + return copy as any; + } + + /** Apply a named schema projection with the same exact row-schema guarantees. */ + projected & string>( name: K ): SchemaQueryBuilder< - TLocalSchema, - Pick & keyof TResult> + S, + ObjectSchemaBuilder< + Pick< + SchemaProps>, + Extract, keyof SchemaProps>> + > & + Pick< + SchemaProps, + Extract, keyof Relations> + > + >, + Relations, + false > { - return projectedImpl(this as any, name); - } - - /** - * Apply a named schema scope to this query. - * @param name - Scope registered with the schema's scope() extension. - * @throws If the requested scope is not registered. - */ - scoped>(name: K): this { - return scopedImpl(this as any, name as string); - } - - /** - * Disable the default read scope and include soft-deleted rows. - * Explicit filters already added to this builder remain in place. - */ - unscoped(): this { - return unscopedImpl(this as any); - } - - // ======================================================================= - // WHERE - // ======================================================================= - - /** - * Add an AND filter using mapped schema columns, a record, or raw Knex SQL. - * Selector/key and record forms map property names to database columns. Grouped - * callbacks receive a Knex builder and therefore use database column names. - * Values are bound; use the operator form for comparisons other than equality. - */ - where(column: ColumnRef, operator: string, value: any): this; - /** - * Add an AND filter using mapped schema columns, a record, or raw Knex SQL. - * Selector/key and record forms map property names to database columns. Grouped - * callbacks receive a Knex builder and therefore use database column names. - * Values are bound; use the operator form for comparisons other than equality. - */ - where(column: ColumnRef, value: any): this; - /** - * Add an AND filter using mapped schema columns, a record, or raw Knex SQL. - * Selector/key and record forms map property names to database columns. Grouped - * callbacks receive a Knex builder and therefore use database column names. - * Values are bound; use the operator form for comparisons other than equality. - */ - where(raw: Knex.Raw, operator: string, value: any): this; - /** - * Add an AND filter using mapped schema columns, a record, or raw Knex SQL. - * Selector/key and record forms map property names to database columns. Grouped - * callbacks receive a Knex builder and therefore use database column names. - * Values are bound; use the operator form for comparisons other than equality. - */ - where(callback: (builder: Knex.QueryBuilder) => void): this; - /** - * Add an AND filter using mapped schema columns, a record, or raw Knex SQL. - * Selector/key and record forms map property names to database columns. Grouped - * callbacks receive a Knex builder and therefore use database column names. - * Values are bound; use the operator form for comparisons other than equality. - */ - where(record: Record): this; - /** - * Add an AND filter using mapped schema columns, a record, or raw Knex SQL. - * Selector/key and record forms map property names to database columns. Grouped - * callbacks receive a Knex builder and therefore use database column names. - * Values are bound; use the operator form for comparisons other than equality. - */ - where(raw: Knex.Raw): this; - /** - * Add an AND filter using mapped schema columns, a record, or raw Knex SQL. - * Selector/key and record forms map property names to database columns. Grouped - * callbacks receive a Knex builder and therefore use database column names. - * Values are bound; use the operator form for comparisons other than equality. - */ - where(columnOrRaw: any, ...args: any[]): this { - return whereImpl(this as any, columnOrRaw, ...args); + const definition = getProjections(this.source)[name]; + if (!definition) + throw new ReadSchemaError(`Unknown projection: ${name}`); + return this.select(() => + Object.fromEntries( + definition.keys.map(key => [key, this.columns[key]]) + ) + ) as any; + } + + protected readPredicateContext(): ReadPredicateContext< + ReadColumns + > { + return { + knex: this.knex, + column: selector => this.name(this.column(selector)) + }; } - - /** - * Add an AND condition; an explicit synonym for where(). - * Property references and record keys are mapped; raw callbacks use Knex columns. - */ - andWhere( - column: ColumnRef, - operator: string, - value: any - ): this; - /** - * Add an AND condition; an explicit synonym for where(). - * Property references and record keys are mapped; raw callbacks use Knex columns. - */ - andWhere(column: ColumnRef, value: any): this; - /** - * Add an AND condition; an explicit synonym for where(). - * Property references and record keys are mapped; raw callbacks use Knex columns. - */ - andWhere(record: Record): this; - /** - * Add an AND condition; an explicit synonym for where(). - * Property references and record keys are mapped; raw callbacks use Knex columns. - */ - andWhere(callback: (builder: Knex.QueryBuilder) => void): this; - /** - * Add an AND condition; an explicit synonym for where(). - * Property references and record keys are mapped; raw callbacks use Knex columns. - */ - andWhere(raw: Knex.Raw): this; - /** - * Add an AND condition; an explicit synonym for where(). - * Property references and record keys are mapped; raw callbacks use Knex columns. - */ - andWhere(columnOrRaw: any, ...args: any[]): this { - return andWhereImpl(this as any, columnOrRaw, ...args); + protected addReadPredicate(predicate: ReadPredicate): this { + const copy = this.copy(); + predicate(copy.base); + return copy; } - - /** - * Add an OR condition using a mapped property, record, raw SQL or Knex group. - * Group mixed AND/OR conditions explicitly when SQL precedence would change intent. - */ - orWhere( - column: ColumnRef, - operator: string, - value: any - ): this; - /** - * Add an OR condition using a mapped property, record, raw SQL or Knex group. - * Group mixed AND/OR conditions explicitly when SQL precedence would change intent. - */ - orWhere(column: ColumnRef, value: any): this; - /** - * Add an OR condition using a mapped property, record, raw SQL or Knex group. - * Group mixed AND/OR conditions explicitly when SQL precedence would change intent. - */ - orWhere(record: Record): this; - /** - * Add an OR condition using a mapped property, record, raw SQL or Knex group. - * Group mixed AND/OR conditions explicitly when SQL precedence would change intent. - */ - orWhere(callback: (builder: Knex.QueryBuilder) => void): this; - /** - * Add an OR condition using a mapped property, record, raw SQL or Knex group. - * Group mixed AND/OR conditions explicitly when SQL precedence would change intent. - */ - orWhere(raw: Knex.Raw): this; - /** - * Add an OR condition using a mapped property, record, raw SQL or Knex group. - * Group mixed AND/OR conditions explicitly when SQL precedence would change intent. - */ - orWhere(columnOrRaw: any, ...args: any[]): this { - return orWhereImpl(this as any, columnOrRaw, ...args); + /** @internal Apply an already captured Framework predicate to an independent query. */ + withPredicate(predicate: ReadPredicate): this { + return this.addReadPredicate(predicate); } - - /** - * Add a negated condition using a mapped property, record or Knex group. - * Use whereNotIn()/whereNotBetween() for their dedicated SQL operators. - */ - whereNot( - column: ColumnRef, - operator: string, - value: any - ): this; - /** - * Add a negated condition using a mapped property, record or Knex group. - * Use whereNotIn()/whereNotBetween() for their dedicated SQL operators. - */ - whereNot(column: ColumnRef, value: any): this; - /** - * Add a negated condition using a mapped property, record or Knex group. - * Use whereNotIn()/whereNotBetween() for their dedicated SQL operators. - */ - whereNot(record: Record): this; - /** - * Add a negated condition using a mapped property, record or Knex group. - * Use whereNotIn()/whereNotBetween() for their dedicated SQL operators. - */ - whereNot(callback: (builder: Knex.QueryBuilder) => void): this; - /** - * Add a negated condition using a mapped property, record or Knex group. - * Use whereNotIn()/whereNotBetween() for their dedicated SQL operators. - */ - whereNot(raw: Knex.Raw): this; - /** - * Add a negated condition using a mapped property, record or Knex group. - * Use whereNotIn()/whereNotBetween() for their dedicated SQL operators. - */ - whereNot(columnOrRaw: any, ...args: any[]): this { - return whereNotImpl(this as any, columnOrRaw, ...args); + /** @internal Native storage columns for composing CTI table sources. */ + storageQuery(): Knex.QueryBuilder { + return this.filtered().select(this.knex.raw('??.*', [this.alias])); } - - /** - * Require the mapped column to match a value list or a single-column subquery. - * An empty list matches no rows. Subqueries use Knex's database column names. - */ - whereIn( - column: ColumnRef, - values: readonly any[] | Knex.QueryBuilder + /** Order parent rows independently of any child relation's ordering. */ + orderBy( + column: ReadPredicateSelector>, + direction: 'asc' | 'desc' = 'asc' ): this { - return (whereInImpl as any)(this, column, values); + const copy = this.copy(); + copy.base.orderBy(this.name(this.column(column)), direction); + return copy; + } + /** Append trusted raw ordering with captured positional bindings; ref() supplies quoted columns. */ + orderByRaw(sql: string, bindings: readonly Knex.RawBinding[] = []): this { + const captured = captureReadRaw(this.knex, sql, bindings); + const copy = this.copy(); + copy.base.orderByRaw(captured()); + return copy; + } + /** Group rows before typed aggregate projection. */ + groupBy( + ...columns: ReadPredicateSelector>[] + ): SchemaQueryBuilder { + const copy = this.copy(); + copy.base.groupBy(columns.map(c => this.name(this.column(c)))); + copy.grouped = true; + return copy as any; + } + /** Limit parent rows; relation limits apply independently within each parent. */ + limit(count: number): this { + if (!Number.isInteger(count) || count < 0) + throw new ReadSchemaError('Limit must be a non-negative integer'); + const copy = this.copy(); + copy.base.limit(count); + return copy; + } + /** Skip parent rows; use a deterministic order for pagination. */ + offset(count: number): this { + if (!Number.isInteger(count) || count < 0) + throw new ReadSchemaError('Offset must be a non-negative integer'); + const copy = this.copy(); + copy.base.offset(count); + return copy; + } + + /** + * Load a declared relation in the same SQL statement. Return the customized child + * query so its selected fields and nested includes remain strongly typed. + */ + include< + K extends keyof Relations & string, + Child extends ReadQueryShape = SchemaAwareQuery> + >( + selector: K | ((relations: { [P in keyof Relations]: P }) => K), + customize?: (query: SchemaAwareQuery>) => Child + ): SchemaQueryBuilder< + S, + AddField>, + Relations, + false + > { + if (Object.values(this.fields).some(f => f.aggregate) || this.grouped) + throw new ReadSchemaError( + 'Grouped/aggregate reads cannot load entity relations' + ); + const definitions = (this.source.introspect().extensions?.relations ?? + []) as RelationSpec[]; + const key = + typeof selector === 'string' + ? selector + : selector( + Object.fromEntries( + definitions.map(r => [r.name, r.name]) + ) as any + ); + const relation = definitions.find(r => r.name === key); + if (!relation) throw new ReadSchemaError(`Unknown relation: ${key}`); + if (this.loaded.some(r => r.name === key)) + throw new ReadSchemaError(`Duplicate relation: ${key}`); + const foreign = + typeof relation.schema === 'function' + ? relation.schema() + : relation.schema; + return this.load( + relation, + this.child(foreign, customize as any), + relation.type === 'belongsTo' && !relation.optional + ) as any; + } + + private child( + foreign: ReadObject, + customize?: (query: any) => ReadQueryShape + ): AnyReadQuery { + let child: AnyReadQuery = createReadQuery( + this.knex, + foreign, + this.knex(getTableName(foreign)) + ); + if (customize) { + const customized = customize(child as any); + if (!child.sameSource(customized)) { + if (customized instanceof Promise) + void customized.catch(() => {}); + throw new ReadSchemaError( + 'Relation customizer must return its configured read query' + ); + } + child = customized as any; + } + return child; } - /** - * Exclude values returned by a list or single-column subquery. - * SQL null semantics apply; a null in the set is not equivalent to a missing value. - */ - whereNotIn( - column: ColumnRef, - values: readonly any[] | Knex.QueryBuilder + private load( + relation: RelationSpec, + child: AnyReadQuery, + required: boolean ): this { - return (whereNotInImpl as any)(this, column, values); - } - - /** - * Add an OR membership condition against a list or single-column subquery. - */ - orWhereIn( - column: ColumnRef, - values: readonly any[] | Knex.QueryBuilder + const key = relation.name; + if (!key || typeof key !== 'string') + throw new ReadSchemaError('A non-empty relation alias is required'); + if (Object.values(this.fields).some(f => f.aggregate)) + throw new ReadSchemaError( + 'Grouped/aggregate reads cannot load entity relations' + ); + if ( + this.loaded.some(r => r.name === key) || + Object.hasOwn(this.fields, key) + ) + throw new ReadSchemaError(`Duplicate result field: ${key}`); + const many = + relation.type === 'hasMany' || relation.type === 'belongsToMany'; + const schema = many + ? array(child.rowSchema) + : required + ? child.rowSchema + : child.rowSchema.nullable(); + const node: ReadNode = { + schema, + exact: false, + decode: (value, path) => { + if (value === null && !required && !many) return null; + if (many) { + if (!Array.isArray(value)) + throw new ReadSchemaError( + `${path}: expected a relation array` + ); + return value.map((row, i) => + child.decode(row, `${path}[${i}]`) + ); + } + return child.decode(value, path); + } + }; + const copy = this.copy(); + copy.loaded.push({ name: key, query: child, relation, required }); + copy.fields[key] = { + node, + expression: () => { + throw new ReadSchemaError( + 'Relation expression must be compiled in context' + ); + } + }; + Object.assign(copy, { rowSchema: copy.schema() }); + return copy as any; + } + + /** @internal Reuse a captured child query across polymorphic parent branches. */ + includeFrom( + name: string, + prepared: SchemaQueryBuilder ): this { - return (orWhereInImpl as any)(this, column, values); + const loaded = prepared.loaded.find(relation => relation.name === name); + if (!loaded) + throw new ReadSchemaError(`Unknown prepared relation: ${name}`); + return this.load(loaded.relation, loaded.query, loaded.required); } - /** - * Add an OR non-membership condition; SQL NOT IN null semantics apply. - */ - orWhereNotIn( - column: ColumnRef, - values: readonly any[] | Knex.QueryBuilder - ): this { - return (orWhereNotInImpl as any)(this, column, values); + /** Join one typed nested object with explicit property keys, including nullable joins. */ + joinOne< + F extends ReadObject, + K extends string, + Required extends boolean = true, + Child extends ReadQueryShape = SchemaAwareQuery + >( + spec: Omit, 'foreignQuery' | 'mappers'>, + customize?: (query: SchemaAwareQuery) => Child + ): SchemaQueryBuilder< + S, + AddField< + Row, + K, + Required extends true + ? Child['rowSchema'] + : SchemaForValue | null> + >, + Relations & Record>, + false + > { + if ('foreignQuery' in spec || 'mappers' in spec) + throw new ReadSchemaError( + 'Use the typed child customizer instead of foreignQuery/mappers in schema-aware mode' + ); + return this.load( + { + name: spec.as, + type: 'hasOne', + schema: spec.foreignSchema, + localKey: resolvePropertyKey( + spec.localColumn as any, + this.source, + 'joinOne' + ), + remoteKey: resolvePropertyKey( + spec.foreignColumn as any, + spec.foreignSchema, + 'joinOne' + ) + }, + this.child(spec.foreignSchema, customize as any), + spec.required !== false + ) as any; + } + + /** Join a typed collection, applying child projection and pagination independently per parent. */ + joinMany< + F extends ReadObject, + K extends string, + Child extends ReadQueryShape = SchemaAwareQuery + >( + spec: Omit< + JoinManySpec, + 'orderBy' | 'foreignQuery' | 'mappers' + >, + customize?: (query: SchemaAwareQuery) => Child + ): SchemaQueryBuilder< + S, + AddField>, + Relations & Record>, + false + > { + if ('foreignQuery' in spec || 'mappers' in spec || 'orderBy' in spec) + throw new ReadSchemaError( + 'Use the typed child customizer for ordering instead of raw foreignQuery/mappers' + ); + let child = this.child(spec.foreignSchema, customize as any); + if (spec.limit !== undefined) child = child.limit(spec.limit); + if (spec.offset !== undefined) child = child.offset(spec.offset); + return this.load( + { + name: spec.as, + type: 'hasMany', + schema: spec.foreignSchema, + localKey: resolvePropertyKey( + spec.localColumn as any, + this.source, + 'joinMany' + ), + remoteKey: resolvePropertyKey( + spec.foreignColumn as any, + spec.foreignSchema, + 'joinMany' + ) + }, + child, + false + ) as any; + } + + /** @internal Decode a SQL/JSON row using the same metadata exposed to consumers. */ + decode(row: any, path = 'row'): any { + if ( + this.source.introspect().extensions?.readOrphanColumn && + row.__read_cti_present == null + ) + throw new ReadSchemaError(`${path}: missing CTI variant body`); + return decodeObject( + Object.fromEntries( + Object.entries(this.fields).map(([key, field]) => [ + key, + field.node + ]) + ), + row, + path + ); } - /** - * Add an AND IS NULL condition for a mapped schema property. - */ - whereNull(column: ColumnRef): this { - return (whereNullImpl as any)(this, column); + /** @internal Compile a bound SQL statement; callers never receive the mutable builder. */ + compile(correlate?: ReadCorrelation): Knex.QueryBuilder { + const query = this.filtered().clearSelect(); + correlate?.(query, this.alias, this.source); + const expressions: Record = Object.create(null); + for (const [key, field] of Object.entries(this.fields)) { + if (!this.loaded.some(r => r.name === key)) + expressions[key] = field.expression(this.knex); + } + const orphanColumn = + this.source.introspect().extensions?.readOrphanColumn; + if (orphanColumn) + expressions.__read_cti_present = this.knex.raw('??', [ + `${this.alias}.${orphanColumn}` + ]); + for (const loaded of this.loaded) { + const { relation, query: child } = loaded; + const parentTable = this.alias; + const parentPk = getPrimaryKeyColumns(this.source).columnNames; + const foreignKey = relation.foreignKey; + const resolveKey = (schema: ReadObject, key: any) => { + if (typeof key === 'function') { + const descriptor = key( + ObjectSchemaBuilderValue.getPropertiesFor(schema) + ); + key = + descriptor[SYMBOL_SCHEMA_PROPERTY_DESCRIPTOR] + .propertyName; + } + return buildColumnMap(schema).propToCol.get(key) ?? key; + }; + const childSql = child.compile((sql, childTable, childSource) => { + const childPk = getPrimaryKeyColumns(childSource).columnNames; + if (relation.localKey && relation.remoteKey) { + sql.where( + `${childTable}.${resolveKey(childSource, relation.remoteKey)}`, + this.knex.ref( + `${parentTable}.${resolveKey(this.source, relation.localKey)}` + ) + ); + return; + } + if (parentPk.length !== 1) + throw new ReadSchemaError( + 'Automatic relation reads require single-column primary keys' + ); + if (childPk.length !== 1) + throw new ReadSchemaError( + 'Automatic relation reads require single-column primary keys' + ); + if (relation.type === 'belongsTo') + sql.where( + `${childTable}.${childPk[0]}`, + this.knex.ref( + `${parentTable}.${resolveKey(this.source, foreignKey)}` + ) + ); + else if (relation.type === 'belongsToMany') { + const through = relation.through!; + sql.join( + through.table, + `${through.table}.${through.foreignKey}`, + `${childTable}.${childPk[0]}` + ).where( + `${through.table}.${through.localKey}`, + this.knex.ref(`${parentTable}.${parentPk[0]}`) + ); + } else + sql.where( + `${childTable}.${resolveKey(childSource, foreignKey)}`, + this.knex.ref(`${parentTable}.${parentPk[0]}`) + ); + }); + const many = + relation.type === 'hasMany' || + relation.type === 'belongsToMany'; + if (!many) childSql.limit(1); + const wrapped = this.knex + .queryBuilder() + .from(childSql.clone().as('__read_relation')); + expressions[loaded.name] = many + ? this.knex.raw( + "(select coalesce(jsonb_agg(to_jsonb(__read_relation)), '[]'::jsonb) from (?) as __read_relation)", + [childSql] + ) + : this.knex.raw( + '(select to_jsonb(__read_relation) from (?) as __read_relation)', + [childSql] + ); + if (loaded.required) + query.whereExists(wrapped.clone().select(this.knex.raw('1'))); + } + return (this.distinctRows ? query.distinct() : query).select( + expressions + ); } - /** - * Add an AND IS NOT NULL condition for a mapped schema property. - */ - whereNotNull(column: ColumnRef): this { - return (whereNotNullImpl as any)(this, column); + /** Render debugging SQL without execution; bound values may be sensitive. */ + toQuery(): string { + return this.compile().toQuery(); } - - /** - * Add an OR IS NULL condition for a mapped schema property. - */ - orWhereNull(column: ColumnRef): this { - return (orWhereNullImpl as any)(this, column); + /** Return an independent mutable Knex snapshot, never the query's owned state. */ + toKnexQuery(): Knex.QueryBuilder { + return this.compile(); + } + + /** Configure an isolated Knex SELECT once, declaring the complete raw row output. */ + apply( + configure: (query: Knex.QueryBuilder) => Knex.QueryBuilder | undefined, + options: QueryOutput + ): OpaqueQuery { + const sql = this.compile(); + const result = configure(sql); + if (result !== undefined && result !== sql) { + if (result instanceof Promise) void result.catch(() => {}); + throw new ReadSchemaError( + 'Raw configuration must synchronously configure the supplied Knex builder' + ); + } + return OpaqueQuery.capture(this.knex, sql, options); + } + /** Replace the projection with trusted raw SQL and an explicit output schema. */ + selectRaw( + sql: string, + bindings: readonly Knex.RawBinding[], + options: QueryOutput + ): OpaqueQuery { + const captured = captureReadRaw(this.knex, sql, bindings); + return this.apply( + query => query.clearSelect().select(captured()), + options + ); } - /** - * Add an OR IS NOT NULL condition for a mapped schema property. - */ - orWhereNotNull(column: ColumnRef): this { - return (orWhereNotNullImpl as any)(this, column); + private writer(filtered = true): QuerySource> { + if (!this.returnsEntityRows || this.loaded.length) + throw new ReadSchemaError( + 'Writes require an unprojected table query without relations or aggregation' + ); + let base = this.knex(getTableName(this.source)); + if (filtered) { + const keys = getPrimaryKeyColumns(this.source).columnNames; + if (keys.length) { + base.whereIn( + keys, + this.filtered() + .clearSelect() + .select(keys.map(key => `${this.alias}.${key}`)) + ); + } else { + const captured = this.filtered(); + if ( + (captured as any)._single.limit !== undefined || + (captured as any)._single.offset !== undefined + ) + throw new ReadSchemaError( + 'Paginated writes require a primary key' + ); + base = captured + .from({ [this.alias]: getTableName(this.source) }) + .clearSelect() + .clearOrder(); + } + } + const writer = new QuerySource>( + this.knex, + this.source, + base + ); + const state = getState(writer); + state.skipDefaultScope = true; + state.includeDeleted = true; + state.decodeRow = row => this.decode(row); + state.hookQuery = this; + return writer; } - /** - * Require the mapped column to lie within an inclusive [lower, upper] range. - */ - whereBetween( - column: ColumnRef, - range: readonly [any, any] - ): this { - return (whereBetweenImpl as any)(this, column, range); + /** Configure immutable conflict handling for one-row inserts. */ + onConflict( + this: Writable extends true ? this : never, + ...columns: ColumnRef[] + ): Pick< + ReturnType>['onConflict']>, + 'merge' | 'ignore' + > { + const conflict = this.writer(false).onConflict(...columns); + return { + merge: (async (...args: any[]) => { + const row = await (conflict.merge as Function)(...args); + return row; + }) as typeof conflict.merge, + ignore: async data => { + const row = await conflict.ignore(data); + return row; + } + }; + } + + /** Insert one row, returning the same decoded storage representation as reads. */ + async insert( + this: Writable extends true ? this : never, + data: InsertType + ): Promise> { + return this.writer(false).insert(data); + } + /** Insert multiple rows and decode each returned row. */ + async insertMany( + this: Writable extends true ? this : never, + data: InsertType[] + ): Promise[]> { + const writer = this.writer(false); + if (data.length === 0) return []; + return writer.insertMany(data); + } + /** Update matching entities; projections and relations cannot be written. */ + async update( + this: Writable extends true ? this : never, + data: Partial | InferType> + ): Promise[]> { + return this.writer().update(data as any); + } + /** Delete matching rows, respecting configured soft deletion. */ + delete(this: Writable extends true ? this : never): Promise { + return this.writer().delete(); + } + /** Permanently delete matching rows. */ + hardDelete(this: Writable extends true ? this : never): Promise { + return this.writer().hardDelete(); + } + /** Restore matching soft-deleted rows. */ + async restore( + this: Writable extends true ? this : never + ): Promise[]> { + return this.writer().restore(); + } + /** Insert in parameter-safe chunks, retaining schema hooks and conflict handling. */ + async bulkInsert( + this: Writable extends true ? this : never, + ...args: Parameters>['bulkInsert']> + ): Promise[]> { + return this.writer(false).bulkInsert(...args); } - - /** - * Exclude the inclusive [lower, upper] range from a mapped column. - */ - whereNotBetween( - column: ColumnRef, - range: readonly [any, any] - ): this { - return (whereNotBetweenImpl as any)(this, column, range); + /** Upsert a row using mapped conflict keys. */ + async upsert( + this: Writable extends true ? this : never, + ...args: Parameters>['upsert']> + ): Promise> { + return this.writer(false).upsert(...args); } - - /** - * Match a mapped column against a SQL LIKE pattern. - * Percent and underscore remain wildcards; values are bound, not wildcard-escaped. + /** Upsert rows in parameter-safe chunks. */ + async bulkUpsert( + this: Writable extends true ? this : never, + ...args: Parameters>['bulkUpsert']> + ): Promise[]> { + return this.writer(false).bulkUpsert(...args); + } + /** Update rows by their declared keys in parameter-safe chunks. */ + bulkUpdate( + this: Writable extends true ? this : never, + updates: ReadonlyArray<{ + where: Partial>; + set: Partial | InferType>; + }> + ): Promise { + return this.writer().bulkUpdate(updates as any); + } + + /** Read values of one selected property without altering this query. */ + async pluck & string>( + key: K + ): Promise[K]>[]> { + return (await this.execute()).map(row => (row as any)[key]); + } + /** Execute one statement and decode its selected row graph. */ + async execute(): Promise[]> { + return (await this.compile()).map((row: unknown) => this.decode(row)); + } + /** Execute a limited copy, returning undefined when no row matches. */ + async first(): Promise | undefined> { + return (await this.limit(1).execute())[0]; + } + /** Awaiting executes the query; repeated awaits deliberately execute again. */ + // biome-ignore lint/suspicious/noThenProperty: query readers intentionally support await + then[], E = never>( + resolve?: ((rows: InferType[]) => T | PromiseLike) | null, + reject?: ((error: any) => E | PromiseLike) | null + ): Promise { + return this.execute().then(resolve, reject); + } + /** Bind an independent query graph to a caller-owned transaction. */ + transacting(trx: Knex.Transaction): this { + const copy = this.copy(); + copy.base.transacting(trx); + Object.assign(copy, { knex: trx }); + copy.loaded = this.loaded.map(r => ({ + ...r, + query: r.query.transacting(trx) + })); + return copy; + } + /** + * Read a lossless composite cursor page using native SQL ordering. Cursor sort + * values remain private text columns, independent of projections and Date decoding. + * Requires non-null scalar order columns containing a declared unique key. */ - whereLike(column: ColumnRef, value: string): this { - return (whereLikeImpl as any)(this, column, value); + paginateAfter( + options: CompositeCursorOptions + ): Promise>>; + /** Read a page using a single raw cursor value; choose a unique, non-null sort column. */ + paginateAfter(options: { + cursor?: unknown; + limit: number; + column?: ColumnRef; + direction?: 'asc' | 'desc'; + }): Promise>>; + /** Execute a cursor page without changing this query's filters, ordering or schema. */ + async paginateAfter( + options: + | CompositeCursorOptions + | { + cursor?: unknown; + limit: number; + column?: ColumnRef; + direction?: 'asc' | 'desc'; + } + ): Promise>> { + if (this.grouped || Object.values(this.fields).some(f => f.aggregate)) + throw new ReadSchemaError( + 'Cursor pagination cannot be used for grouped or aggregate reads' + ); + if (!('orderBy' in options)) { + if (!Number.isInteger(options.limit) || options.limit < 1) + throw new ReadSchemaError( + 'Cursor page limit must be a positive integer' + ); + const key = + options.column === undefined + ? 'id' + : resolvePropertyKey( + options.column as any, + this.source, + 'cursor' + ); + const column = this.columns[key]; + if (!column) + throw new ReadSchemaError(`Unknown cursor column: ${key}`); + const direction = options.direction ?? 'desc'; + if (direction !== 'asc' && direction !== 'desc') + throw new ReadSchemaError('Invalid cursor direction'); + const name = this.name(column); + let hidden = '__cursor_value'; + while (Object.hasOwn(this.fields, hidden)) hidden += '_'; + const sql = this.compile() + .clearOrder() + .clear('offset') + .limit(options.limit + 1) + .orderBy(name, direction) + .select({ + [hidden]: readExpression( + this.knex, + column[READ_COLUMN], + name + ) + }); + if (options.cursor != null) + sql.where( + name as any, + direction === 'desc' ? '<' : '>', + options.cursor as any + ); + const rows = await sql; + const hasMore = rows.length > options.limit; + const page = rows.slice(0, options.limit); + return { + data: page.map((row: any) => this.decode(row)), + hasMore, + nextCursor: hasMore + ? String(page[page.length - 1][hidden]) + : null + }; + } + const Constructor = getQuerySourceCtor(); + const source = this.source.withExtension('tableName', this.alias); + const legacy = new Constructor(this.knex, source, this.compile()); + const state = getState(legacy); + state.skipDefaultScope = true; + state.includeDeleted = true; + // The query is already projected; reserve its aliases against cursor fields. + state.hiddenColumns = new Set(Object.keys(this.fields)); + return compositeCursor( + legacy, + options, + row => this.decode(row), + this.source.introspect().extensions?.tableName as string + ); } - - /** - * Match a mapped column using PostgreSQL's case-insensitive ILIKE operator. - * Percent and underscore remain pattern wildcards. - */ - whereILike(column: ColumnRef, value: string): this { - return (whereILikeImpl as any)(this, column, value); - } - - /** - * Append raw WHERE SQL with Knex bindings. Never interpolate untrusted values. - * Raw SQL uses database names and is outside schema-level result/type checking. - */ - whereRaw(sql: string, ...bindings: any[]): this { - return (whereRawImpl as any)(this, sql, ...bindings); - } - - /** - * Add an EXISTS filter from a Knex subquery or query-building callback. - * Use qualified database columns to correlate it with the parent query. - */ - whereExists(callback: Knex.QueryCallback | Knex.QueryBuilder): this { - return (whereExistsImpl as any)(this, callback); - } - - /** - * Add a NOT EXISTS filter from a Knex subquery or query-building callback. - */ - whereNotExists(callback: Knex.QueryCallback | Knex.QueryBuilder): this { - return (whereNotExistsImpl as any)(this, callback); - } - - /** - * Compare a JSON-path value inside a mapped JSON column. - * @param path - JSON path understood by the Knex database dialect. - * @param operator - SQL comparison operator forwarded to Knex. - * @param value - Bound comparison value. - */ - whereJsonPath( - column: ColumnRef, - path: string, - operator?: string, - value?: any - ): this { - return (whereJsonPathImpl as any)(this, column, path, operator, value); - } - - // ======================================================================= - // ORDER BY - // ======================================================================= - - /** - * Append ordering by a mapped property or raw expression (ascending by default). - * Add a unique tie-breaker for stable pages. Eager loading retains parent order. - */ - orderBy( - column: ColumnRef | Knex.Raw, - direction?: 'asc' | 'desc' - ): this { - return (orderByImpl as any)(this, column, direction); - } - - /** - * Append a raw ORDER BY expression with Knex bindings. - * Use database column names; parent ordering is retained during eager loading. - */ - orderByRaw(sql: string, ...bindings: any[]): this { - return (orderByRawImpl as any)(this, sql, ...bindings); - } - - // ======================================================================= - // GROUP BY / HAVING - // ======================================================================= - - /** - * Group rows by mapped schema properties or raw expressions. - * Combine with aggregate expressions in select() to infer grouped DTO results. - */ - groupBy(...columns: (ColumnRef | Knex.Raw)[]): this { - return (groupByImpl as any)(this, ...columns); - } - - /** - * Append raw GROUP BY SQL with optional Knex bindings. - */ - groupByRaw(sql: string, ...bindings: any[]): this { - return (groupByRawImpl as any)(this, sql, ...bindings); - } - - /** - * Filter SQL groups by a mapped column/raw expression, operator and bound value. - */ - having( - column: ColumnRef | Knex.Raw, - operator: string, - value: any - ): this { - return (havingImpl as any)(this, column, operator, value); - } - - /** - * Append raw HAVING SQL with Knex bindings, for example aggregate comparisons. - */ - havingRaw(sql: string, ...bindings: any[]): this { - return havingRawImpl(this as any, sql, ...bindings); - } - - // ======================================================================= - // PAGINATION - // ======================================================================= - - /** - * Set the maximum number of parent rows to select; mutates this query. - * Included collections do not consume the parent limit. - */ - limit(n: number): this { - return limitImpl(this as any, n); - } - - /** - * Skip this many parent rows before applying the limit; mutates this query. - * Use deterministic ordering when navigating offset-based pages. - */ - offset(n: number): this { - return offsetImpl(this as any, n); - } - - /** - * Execute a one-based offset page and a separate matching-source count query. - * Mutates this builder's limit/offset and returns mapped rows plus page metadata. - * The count and page are separate reads, not a snapshot unless your transaction provides one. - */ - async paginate(opts: { - /** One-based page number. */ + /** Fetch a numbered page and a count without mutating the source query. */ + async paginate(options: { page: number; - /** Maximum parent rows in a page. */ pageSize: number; - }): Promise> { - return paginateImpl(this as any, opts) as Promise< - PaginationResult - >; - } - - /** - * Read a cursor page without running a total-count query. - * The orderBy form clones the source and preserves exact composite sort values; - * its non-null sort must contain a declared unique key. The legacy column form - * mutates this builder and defaults to id descending. Reapply access filters on - * every request: cursors are positions, not authorization or snapshots. - * @returns Mapped data, hasMore, and a nextCursor that is null on the last page. - * @throws For invalid composite cursors or unsupported composite query shapes. - */ - paginateAfter( - opts: CompositeCursorOptions - ): Promise>; - /** - * Read a cursor page without running a total-count query. - * The orderBy form clones the source and preserves exact composite sort values; - * its non-null sort must contain a declared unique key. The legacy column form - * mutates this builder and defaults to id descending. Reapply access filters on - * every request: cursors are positions, not authorization or snapshots. - * @returns Mapped data, hasMore, and a nextCursor that is null on the last page. - * @throws For invalid composite cursors or unsupported composite query shapes. - */ - paginateAfter(opts: { - /** Previous raw single-column position; omit for the first page. */ - cursor?: any; - /** Maximum parent rows to return; one extra row determines hasMore. */ - limit: number; - /** Unique sort property; defaults to id in the legacy API. */ - column?: ColumnRef; - /** Sort/continuation direction; defaults to descending. */ - direction?: 'asc' | 'desc'; - }): Promise>; - /** - * Read a cursor page without running a total-count query. - * The orderBy form clones the source and preserves exact composite sort values; - * its non-null sort must contain a declared unique key. The legacy column form - * mutates this builder and defaults to id descending. Reapply access filters on - * every request: cursors are positions, not authorization or snapshots. - * @returns Mapped data, hasMore, and a nextCursor that is null on the last page. - * @throws For invalid composite cursors or unsupported composite query shapes. - */ - async paginateAfter(opts: any): Promise> { - if ('orderBy' in opts) return compositeCursor(this as any, opts); - return (paginateAfterImpl as any)(this, opts) as Promise< - CursorPaginationResult - >; - } - - // ======================================================================= - // WRITE OPERATIONS - // ======================================================================= - - /** - * Insert one schema-shaped row and return its mapped database representation. - * Applies configured insert hooks, column mappings and timestamp defaults. - */ - async insert(data: InsertType): Promise { - return insertImpl(this as any, data) as Promise; - } - - /** - * Insert an array of schema-shaped rows and return their mapped representations. - * Returns an empty array for empty input; use bulkInsert() to control chunking. - */ - async insertMany(data: InsertType[]): Promise { - return insertManyImpl(this as any, data) as Promise; - } - - /** - * Configure an upsert conflict target using mapped properties. - * Call merge() or ignore() on the returned builder to insert the row. - */ - onConflict( - ...conflictColumns: ColumnRef[] - ): import('./operations/insert.js').OnConflictBuilder< - TLocalSchema, - TResult - > { - return (onConflictImpl as any)(this, ...conflictColumns); - } - - /** - * Insert one row or update it when the chosen conflict target already exists. - * @param opts - Conflict properties and optional subset of properties to update. - * @returns The inserted or updated row mapped to schema property names. - */ - async upsert( - data: InsertType, - opts: { - /** Properties identifying an existing row on conflict. */ - conflictColumns: ColumnRef[]; - /** Properties to update on conflict; omit to merge insert values. */ - updateColumns?: ColumnRef[]; - } - ): Promise { - return (upsertImpl as any)(this, data, opts); - } - - /** - * Insert rows in chunks, optionally ignoring or merging conflicts. - * @param opts - Chunk size (default 500), conflict policy and conflict properties. - * @returns Mapped rows returned by PostgreSQL; ignored conflicts produce no row. - */ - async bulkInsert( - rows: InsertType[], - opts?: { - /** Requested rows per statement, capped by parameter limits; default 500. */ - chunkSize?: number; - /** Optional PostgreSQL conflict policy applied to each chunk. */ - onConflict?: 'ignore' | 'merge'; - /** Conflict target properties when a conflict policy is supplied. */ - conflictColumns?: ColumnRef[]; - } - ): Promise { - return (bulkInsertImpl as any)(this, rows, opts); - } - - /** - * Insert/update rows in chunks using the specified conflict properties. - * @param opts - Required conflict target and optional chunk size (default 500). - * @returns The database rows produced by each chunk, mapped to schema properties. - */ - async bulkUpsert( - rows: InsertType[], - opts: { - /** Properties identifying an existing row on conflict. */ - conflictColumns: ColumnRef[]; - /** Requested rows per statement, capped by parameter limits; default 500. */ - chunkSize?: number; - } - ): Promise { - return (bulkUpsertImpl as any)(this, rows, opts); - } - - // ======================================================================= - // UPDATE - // ======================================================================= - - /** - * Update rows matching this query's explicit filters and return mapped rows. - * Applies update hooks and timestamp metadata. Add a WHERE clause to avoid a - * table-wide update; this method does not track entity identity. - */ - async update(data: Partial>): Promise { - return updateImpl(this as any, data) as Promise; - } - - /** - * Apply per-row where/set pairs and return the total affected-row count. - * Maps both filter and update property names and applies configured update hooks. - */ - async bulkUpdate( - updates: ReadonlyArray<{ - /** Equality filters identifying the rows for this update. */ - where: Partial>; - /** Schema properties to assign to those rows. */ - set: Partial>; - }> - ): Promise { - return bulkUpdateImpl(this as any, updates as any); - } - - // ======================================================================= - // DELETE / SOFT DELETE - // ======================================================================= - - /** - * Delete rows matching explicit filters and return the affected-row count. - * Runs beforeDelete hooks; with soft-delete metadata it sets the deletion timestamp - * instead of removing rows. Add filters to avoid a table-wide write. - */ - async delete(): Promise { - return deleteImpl(this as any); - } - - /** - * Include soft-deleted rows in read results without removing explicit filters. - */ - withDeleted(): this { - return withDeletedImpl(this as any); - } - - /** - * Restrict reads to rows whose configured soft-delete column is non-null. - */ - onlyDeleted(): this { - return onlyDeletedImpl(this as any); - } - - /** - * Permanently delete rows matching explicit filters, even on a soft-delete schema. - * Runs beforeDelete hooks and returns the affected count. This cannot be undone - * without a transaction rollback or backup. - */ - async hardDelete(): Promise { - return hardDeleteImpl(this as any); - } - - /** - * Clear the deletion timestamp on rows matching explicit filters and return them. - * @throws If the schema has no soft-delete configuration. - */ - async restore(): Promise { - return restoreImpl(this as any) as Promise; - } - - // ======================================================================= - // EAGER LOADING (JOIN) - // ======================================================================= - - /** - * Eager-load a related object under spec.as using mapped join columns. - * Required joins remove unmatched parents; optional joins return null. Unlike a - * flat join, related fields remain nested and are mapped with the foreign schema. - */ - joinOne< - TForeignSchema extends ObjectSchemaBuilder< - any, - any, - any, - any, - any, - any, - any - >, - TFieldName extends string, - TRequired extends boolean = true - >( - spec: JoinOneSpec - ): SchemaQueryBuilder< - TLocalSchema, - import('./types.js').WithJoinedOne< - TResult, - TFieldName, - TForeignSchema, - TRequired - > - > { - return joinOneImpl(this as any, spec); - } - - /** - * Eager-load a nested array without multiplying parent rows. - * The relation's own order/limit/offset controls children separately from parent paging. - */ - joinMany< - TForeignSchema extends ObjectSchemaBuilder< - any, - any, - any, - any, - any, - any, - any - >, - TFieldName extends string - >( - spec: JoinManySpec - ): SchemaQueryBuilder< - TLocalSchema, - import('./types.js').WithJoinedMany - > { - return joinManyImpl(this as any, spec); - } - - /** - * Eager-load a relation registered on the schema by name. - * @param customize - Optional callback configuring the related query. - * Use an ORM DbSet when you need typed relation names and customization fields. - */ - include( - relationName: string, - customize?: (q: SchemaQueryBuilder) => void - ): this { - return includeImpl(this as any, relationName, customize); - } - - /** - * Eager-load a relation declared for one polymorphic discriminator value. - * Other variants are not populated with this relation. Use ORM entity declarations - * to retain known relation customization types. - */ - includeVariant( - variantKey: string, - relationName: string, - customize?: (q: SchemaQueryBuilder) => void - ): this { - return includeVariantImpl( - this as any, - variantKey, - relationName, - customize - ); - } - - // ======================================================================= - // POLYMORPHIC VARIANTS - // ======================================================================= - - /** - * Add a filter applying only to the named polymorphic branch. - * Other discriminator values remain eligible. Maps the variant property to its - * CTI/STI storage column; throws for unknown variants or unsupported operators. - */ - whereVariant( - key: string, - column: string, - operator: string, - value: any - ): this { - const state = getState(this); - const variantConfig = getVariantConfig(this); - if (!variantConfig) { - throw new Error( - 'whereVariant() can only be used on a polymorphic schema (created with .withVariants())' + }): Promise>> { + const { page, pageSize } = options; + if ( + !Number.isInteger(page) || + page < 1 || + !Number.isInteger(pageSize) || + pageSize < 1 + ) + throw new ReadSchemaError( + 'Page and pageSize must be positive integers' ); - } - - const spec = variantConfig.variants[key]; - if (!spec) { - throw new Error( - `whereVariant: unknown variant key "${key}". ` + - `Valid keys: ${Object.keys(variantConfig.variants).join(', ')}` - ); - } - - const op = operator.toLowerCase(); - if (!ALLOWED_OPS.has(op)) { - throw new Error( - `whereVariant: operator "${operator}" is not allowed. ` + - `Allowed operators: ${[...ALLOWED_OPS].join(', ')}` - ); - } - - const { propToCol } = buildColumnMap(spec.schema); - const colName = propToCol.get(column) ?? column; - - let qualifiedColumn: string; - if (spec.storage === 'cti') { - qualifiedColumn = `__v_${key}.${colName}`; - } else { - qualifiedColumn = `${state.tableName}.${colName}`; - } - - state.variantWhereFilters.push({ key, qualifiedColumn, op, value }); - invalidateCache(this); - return this; - } - - /** - * Choose which polymorphic variant bodies are loaded. - * This controls variant joins/selection, not a discriminator filter on base rows. - * @throws If the schema is not polymorphic. - */ - selectVariants(keys: string[]): this { - const state = getState(this); - if (!getVariantConfig(this)) { - throw new Error( - 'selectVariants() can only be used on a polymorphic schema (created with .withVariants())' + const countQuery = this.compile() + .clearOrder() + .clear('limit') + .clear('offset'); + const countRow = await this.knex + .from(countQuery.as('__read_count')) + .count({ count: '*' }) + .first(); + const total = Number(countRow?.count ?? 0); + if (!Number.isSafeInteger(total)) + throw new ReadSchemaError( + 'Pagination count exceeds the safe integer range' ); - } - state.enabledVariants = new Set(keys); - invalidateCache(this); - return this; - } - - // ======================================================================= - // ESCAPE HATCH - // ======================================================================= - - /** - * Configure the underlying mutable Knex query as an escape hatch. - * Raw changes do not infer a new result type; the caller owns column names, - * result shape and cardinality introduced by the callback. - */ - apply(fn: (builder: Knex.QueryBuilder) => void): this { - const state = getState(this); - state.opaqueReadShape = true; - invalidateCache(this); - fn(state.baseQuery); - return this; - } - - // ======================================================================= - // TRANSACTION - // ======================================================================= - - /** - * Clone this query and its eager-relation queries onto an existing transaction. - * The source builder is unchanged; transaction commit/rollback stays with the caller. - */ - transacting( - trx: Knex.Transaction - ): SchemaQueryBuilder { - const state = getState(this); - const builder = new SchemaQueryBuilder( - trx as unknown as Knex, - state.localSchema as TLocalSchema, - state.baseQuery.clone().transacting(trx) - ); - const builderState = getState(builder); - for (const spec of state.specs) { - builderState.specs.push({ - ...spec, - foreignQuery: spec.foreignQuery.clone().transacting(trx) - }); - } - builderState.explicitSelects = state.explicitSelects - ? [...state.explicitSelects] - : null; - builderState.selectionMode = state.selectionMode; - builderState.appliedProjection = state.appliedProjection; - builderState.projectionColumns = state.projectionColumns - ? { ...state.projectionColumns } - : null; - builderState.projectionDecoders = { ...state.projectionDecoders }; - builderState.hiddenColumns = new Set(state.hiddenColumns); - builderState.includeDeleted = state.includeDeleted; - builderState.onlyDeleted = state.onlyDeleted; - builderState.skipDefaultScope = state.skipDefaultScope; - builderState.opaqueReadShape = state.opaqueReadShape; - builderState.variantConfig = state.variantConfig; - builderState.enabledVariants = - state.enabledVariants !== null - ? new Set(state.enabledVariants) - : null; - builderState.variantWhereFilters = [...state.variantWhereFilters]; - builderState.variantRelationIncludes = [ - ...state.variantRelationIncludes - ]; - return builder; - } - - // ======================================================================= - // EXECUTION - // ======================================================================= - - /** - * Render SQL for debugging without executing it. - * Bindings may appear as literal values; avoid logging sensitive inputs. - */ - toQuery(): string { - return getQuery(this).toQuery(); - } - - /** @internal ORM tracking must never attach aggregate or DTO rows as entities. */ - get returnsEntityRows(): boolean { - return getState(this).selectionMode === null; - } - - /** - * Expose the built Knex query without executing Framework row mapping. - * Direct execution returns raw database rows, potentially including internal fields. - * Treat mutations as an escape hatch rather than typed Framework configuration. - */ - toKnexQuery(): Knex.QueryBuilder { - return getQuery(this); - } - - /** - * Render the query as a debugging SQL string; equivalent to toQuery(). - */ - toString(): string { - return getQuery(this).toString(); - } - - /** - * Execute SQL and map all rows, including eager relations and aggregate decoders. - * @returns An empty array when no rows match. - * @throws Database errors and output-parser validation failures. - */ - async execute(): Promise { - return executeImpl(this) as Promise; - } - - /** - * Execute this query for its first mapped row, or undefined if none matches. - * Set ordering when the choice of first row matters. - */ - async first(): Promise { - const query = getQuery(this).first(); - const row = await query; - - if (!row) return undefined; - return cleanAndMapRow(this, row) as TResult; - } - - /** - * Execute a selection and collect one mapped column's values into an array. - * @param column - Schema property whose database column should be read. - */ - async pluck( - column: ColumnRef - ): Promise { - const _state = getState(this); - const col = resolveColumn(this, column, 'pluck') as string; - const rows = await buildQuery(this).select(col); - return rows.map( - (row: any) => row[col] ?? row[column as string] - ) as TResult[K][]; - } - - /** - * Promise-compatible execution hook enabling await query(...). - * Runs execute() and forwards fulfillment/rejection; repeated awaits may execute again. - */ - // biome-ignore lint/suspicious/noThenProperty: intentional thenable - then( - onfulfilled?: - | ((value: TResult[]) => TReturn1 | PromiseLike) - | null, - onrejected?: ((reason: any) => TReturn2 | PromiseLike) | null - ): Promise { - return this.execute().then(onfulfilled, onrejected); + const data = await this.offset((page - 1) * pageSize) + .limit(pageSize) + .execute(); + const totalPages = Math.ceil(total / pageSize); + return { + data, + total, + page, + pageSize, + totalPages, + hasNextPage: page < totalPages, + hasPreviousPage: page > 1 + }; } } -// Register the constructor for circular-dependency-safe access -registerSchemaQueryBuilder(SchemaQueryBuilder); - -// --------------------------------------------------------------------------- -// query() — main entry point -// --------------------------------------------------------------------------- - -/** - * Create a schema-aware query while preserving its schema and inferred row type. - * Pass a table alias for a flat multi-table query requiring an explicit projection; - * pass an ordinary schema for nested eager loading and schema-aware writes. - * @param knex - Knex connection or transaction. - * @param schema - Table schema or immutable alias(schema, name). - * @returns The appropriately typed, unexecuted query builder. - */ -export function query< - S extends ObjectSchemaBuilder, - N extends string ->(knex: Knex, schema: TableAlias): AliasedQueryBuilder>; -/** - * Create a schema-aware query while preserving its schema and inferred row type. - * Pass a table alias for a flat multi-table query requiring an explicit projection; - * pass an ordinary schema for nested eager loading and schema-aware writes. - * @param knex - Knex connection or transaction. - * @param schema - Table schema or immutable alias(schema, name). - * @returns The appropriately typed, unexecuted query builder. - */ -export function query< - TLocalSchema extends ObjectSchemaBuilder ->( - knex: Knex, - schema: TLocalSchema -): SchemaQueryBuilder>; - -/** - * Create a schema-aware query while preserving its schema and inferred row type. - * Pass a table alias for a flat multi-table query requiring an explicit projection; - * pass an ordinary schema for nested eager loading and schema-aware writes. - * @param knex - Knex connection or transaction. - * @param schema - Table schema or immutable alias(schema, name). - * @returns The appropriately typed, unexecuted query builder. - */ -export function query< - TLocalSchema extends ObjectSchemaBuilder ->( - knex: Knex, - schema: TLocalSchema, - baseQuery: Knex.QueryBuilder -): SchemaQueryBuilder>; +import { ObjectSchemaBuilder as ObjectSchemaBuilderValue } from '@cleverbrush/schema'; -/** - * Create a schema-aware query while preserving its schema and inferred row type. - * Pass a table alias for a flat multi-table query requiring an explicit projection; - * pass an ordinary schema for nested eager loading and schema-aware writes. - * @param knex - Knex connection or transaction. - * @param schema - Table schema or immutable alias(schema, name). - * @returns The appropriately typed, unexecuted query builder. - */ -export function query< - S extends ObjectSchemaBuilder, - N extends string ->( +/** @internal Shared reader factory for roots and nested relations. */ +export function createReadQuery( knex: Knex, - schema: S | TableAlias, - baseQuery?: Knex.QueryBuilder -): - | SchemaQueryBuilder> - | AliasedQueryBuilder> { - if (isTableAlias(schema)) - return new AliasedQueryBuilder>(knex, schema); - return new SchemaQueryBuilder>( - knex, - schema, - baseQuery - ); -} - -// --------------------------------------------------------------------------- -// createQuery() — knex-bound factory -// --------------------------------------------------------------------------- - -/** - * A query factory bound to a connection or transaction. - * Ordinary schemas retain schema/result inference; aliases retain the table context. - * Use withTransaction() to reuse a transaction or transaction() to create one. - */ -export interface BoundQuery { - /** - * Start a typed query on the bound connection using a schema or table alias. - * Only ordinary schema calls accept an existing Knex base query. - */ - < - S extends ObjectSchemaBuilder, - N extends string - >( - schema: TableAlias - ): AliasedQueryBuilder>; - /** - * Start a typed query on the bound connection using a schema or table alias. - * Only ordinary schema calls accept an existing Knex base query. - */ - < - TLocalSchema extends ObjectSchemaBuilder< - any, - any, - any, - any, - any, - any, - any - > - >( - schema: TLocalSchema - ): SchemaQueryBuilder>; - /** - * Start a typed query on the bound connection using a schema or table alias. - * Only ordinary schema calls accept an existing Knex base query. - */ - < - TLocalSchema extends ObjectSchemaBuilder< - any, - any, - any, - any, - any, - any, - any - > - >( - schema: TLocalSchema, - baseQuery: Knex.QueryBuilder - ): SchemaQueryBuilder>; - /** - * Create a factory bound to an existing transaction without committing it. - */ - withTransaction(trx: Knex.Transaction): BoundQuery; - /** - * Run a callback with a transaction-bound factory. - * Resolves to the callback result on commit; rejects and rolls back on failure. - */ - transaction(callback: (db: BoundQuery) => Promise): Promise; -} - -/** - * Bind query() to a connection, retaining all schema/alias overloads. - * @param knexInstance - Connection or existing transaction to bind. - * @returns A callable factory with transaction helpers. - * @example - * const db = createQuery(knex); - * const rows = await db(TaskSchema).select(t => ({ id: t.id })); - */ -export function createQuery(knexInstance: Knex): BoundQuery { - function boundQuery< - S extends ObjectSchemaBuilder, - N extends string - >(schema: TableAlias): AliasedQueryBuilder>; - function boundQuery< - TLocalSchema extends ObjectSchemaBuilder< - any, - any, - any, - any, - any, - any, - any - > - >( - schema: TLocalSchema, - baseQuery?: Knex.QueryBuilder - ): SchemaQueryBuilder>; - function boundQuery< - S extends ObjectSchemaBuilder, - N extends string - >( - schema: S | TableAlias, - baseQuery?: Knex.QueryBuilder - ): - | SchemaQueryBuilder> - | AliasedQueryBuilder> { - if (isTableAlias(schema)) return query(knexInstance, schema); - return baseQuery - ? query(knexInstance, schema, baseQuery) - : query(knexInstance, schema); - } - - return Object.assign(boundQuery, { - withTransaction(trx: Knex.Transaction): BoundQuery { - return createQuery(trx); - }, - transaction(callback: (db: BoundQuery) => Promise): Promise { - return knexInstance.transaction(trx => callback(createQuery(trx))); - } - }) satisfies BoundQuery; + schema: S, + base: Knex.QueryBuilder +): SchemaAwareQuery { + return ( + getVariants(schema) + ? new PolymorphicQueryBuilder(knex, schema, base) + : new SchemaQueryBuilder(knex, schema, base) + ) as SchemaAwareQuery; } diff --git a/libs/knex-schema/src/SchemaReadQuery.ts b/libs/knex-schema/src/SchemaReadQuery.ts deleted file mode 100644 index ddaa13b6..00000000 --- a/libs/knex-schema/src/SchemaReadQuery.ts +++ /dev/null @@ -1,864 +0,0 @@ -import { - type ArraySchemaBuilder, - array, - EXTRA_TYPE_BRAND, - type InferType, - type ObjectSchemaBuilder, - object, - SYMBOL_SCHEMA_PROPERTY_DESCRIPTOR -} from '@cleverbrush/schema'; -import type { Knex } from 'knex'; -import { - buildColumnMap, - getPrimaryKeyColumns, - resolvePropertyKey -} from './columns.js'; -import type { RelationInfo, SchemaProps } from './entity.js'; -import { - type AggregateExpression, - type AliasedColumn, - COLUMN, - isAggregate -} from './expressions.js'; -import { getProjections, getVariants } from './extension.js'; -import { - type CompositeCursorOptions, - compositeCursor -} from './operations/composite-cursor.js'; -import { - getEffectiveBaseQuery, - getSchemaQueryBuilderCtor -} from './operations/helpers.js'; -import { getState } from './operations/state.js'; -import { PolymorphicReadQuery } from './PolymorphicReadQuery.js'; -import type { ReadRelations, ReadVariantMetadata } from './read-entity.js'; -import { - captureReadRaw, - type ReadPredicate, - type ReadPredicateContext, - type ReadPredicateSelector, - ReadPredicates -} from './read-predicates.js'; -import { compileReadProjection, type ReadField } from './read-projection.js'; -import { - type ColumnReadSchema, - compileReadSchema, - decodeObject, - type ObjectReadSchema, - type ReadNode, - type ReadObject, - type ReadSchema, - ReadSchemaError, - readExpression, - type SchemaForValue -} from './read-schema.js'; -import type { SchemaQueryBuilder } from './SchemaQueryBuilder.js'; -import type { - CursorPaginationResult, - JoinManySpec, - JoinOneSpec, - PaginationResult, - RelationSpec -} from './types.js'; - -const READ_COLUMN = Symbol('schema-read-column'); -/** @internal Nominal read-query identity used without recursively comparing fluent APIs. */ -export const READ_QUERY = Symbol('schema-read-query'); -/** Minimal type surface for a customizer's strongly inferred result schema. */ -export interface ReadQueryShape { - /** @internal Nominal marker; constructing a plain schema object is not a query. */ - readonly [READ_QUERY]: true; - /** Decoded result schema inferred from the returned query. */ - readonly rowSchema: R; -} -let readAliasSequence = 0; -/** A typed SQL column; selectors receive descriptions, not row values. */ -export interface ReadColumn - extends AliasedColumn> { - /** @internal Decoding and projection metadata shared by the query compiler. */ - readonly [READ_COLUMN]: ReadNode; -} -/** Columns available for typed projections and filters. */ -export type ReadColumns< - S extends ReadObject, - Relations extends PropertyKey = never -> = { - [K in Exclude, Relations> & string]: ReadColumn< - ColumnReadSchema[K]> - >; -}; -type Selection = Record | AggregateExpression>; -type MergeProps = { - [K in keyof A | keyof B]: K extends keyof B - ? B[K] - : K extends keyof A - ? A[K] - : never; -}; -type NamedProjections = S extends { readonly [EXTRA_TYPE_BRAND]?: infer P } - ? P - : {}; -type NamedKeys< - S, - K extends keyof NamedProjections -> = NamedProjections[K] extends readonly (infer Key extends string)[] - ? Key - : never; -/** Structural schema inferred from a typed projection. */ -export type ReadProjection = ObjectSchemaBuilder<{ - [K in keyof S & string]: S[K] extends ReadColumn - ? R - : S[K] extends AggregateExpression - ? SchemaForValue - : never; -}>; -type AddField< - S extends ReadObject, - K extends string, - F extends ReadSchema -> = ObjectSchemaBuilder, K> & Record>; -type Related = R extends RelationInfo ? S : never; -type RelationField = - R extends RelationInfo<'hasMany' | 'belongsToMany', any> - ? ArraySchemaBuilder - : R extends RelationInfo<'belongsTo', any> - ? R extends { optional: infer O } - ? true extends O - ? SchemaForValue | null> - : S - : S - : SchemaForValue | null>; -type Selector = (columns: C) => ReadColumn; -type AnyReadQuery = - | SchemaReadQuery - | PolymorphicReadQuery; -type Loaded = { - name: string; - query: AnyReadQuery; - relation: RelationSpec; - required: boolean; -}; -/** Result of entering opt-in read mode: an object reader or a declared variant union. */ -export type SchemaAwareQuery = - ReadVariantMetadata extends { - discriminator: string; - variants: Record; - } - ? PolymorphicReadQuery - : SchemaReadQuery; -/** @internal Apply parent correlation before child selection, ordering and pagination. */ -export type ReadCorrelation = ( - query: Knex.QueryBuilder, - alias: string, - source: ReadObject -) => void; - -/** - * Immutable, detached read query whose row schema matches its decoded SQL result. - * Enter through withRowSchema() before projections/includes. Ordinary legacy queries - * remain mutable and keep their existing values. Reading metadata never executes SQL. - */ -export class SchemaReadQuery< - S extends ReadObject, - Row extends ReadObject = ObjectReadSchema>, - Relations extends Record = ReadRelations -> extends ReadPredicates> { - /** @internal Nominal identity for typed child-query customizers. */ - declare readonly [READ_QUERY]: true; - private readonly alias = `__schema_read_${readAliasSequence++}`; - private fields: Record; - private loaded: Loaded[] = []; - private base: Knex.QueryBuilder; - private selected = false; - private grouped = false; - private readonly columns: Record>; - /** Runtime structural schema; stable across filters, pagination and transaction clones. */ - readonly rowSchema: Row; - - /** @internal Use withRowSchema() on a query/DbSet instead of constructing directly. */ - constructor( - private readonly knex: Knex, - private readonly source: S, - base: Knex.QueryBuilder - ) { - super(); - this.base = knex.queryBuilder().from(base.clone().as(this.alias)); - const relations = (source.introspect().extensions?.relations ?? - []) as RelationSpec[]; - const excluded = new Set(relations.map(r => r.name)); - const { propToCol } = buildColumnMap(source); - this.fields = Object.create(null); - this.columns = Object.create(null); - for (const [key, schema] of Object.entries( - source.introspect().properties ?? {} - )) { - if (excluded.has(key)) continue; - const node = compileReadSchema(schema as ReadSchema); - const column = `${this.alias}.${propToCol.get(key) ?? key}`; - this.columns[key] = { - [COLUMN]: { - alias: this.alias, - column: propToCol.get(key) ?? key, - schema - }, - [READ_COLUMN]: node - }; - this.fields[key] = { - node, - expression: knex => readExpression(knex, node, column) - }; - } - this.rowSchema = this.schema() as Row; - } - - private schema(): ReadObject { - return object( - Object.fromEntries( - Object.entries(this.fields).map(([key, field]) => [ - key, - field.node.schema - ]) - ) - ); - } - - private copy(): this { - const copy = Object.create(Object.getPrototypeOf(this)) as this; - Object.assign(copy, this, { - base: this.base.clone(), - fields: { ...this.fields }, - loaded: [...this.loaded] - }); - return copy; - } - - /** @internal Prevent customizers from substituting an unrelated query source. */ - sameSource(other: unknown): boolean { - return ( - other instanceof SchemaReadQuery && this.columns === other.columns - ); - } - - private column( - selector: ReadPredicateSelector> - ): ReadColumn { - const column = selector( - this.columns as ReadColumns - ); - if ( - !column || - !Object.values(this.columns).some(candidate => candidate === column) - ) - throw new ReadSchemaError( - 'Column does not belong to this read query' - ); - return column as ReadColumn; - } - - private name(column: ReadColumn): string { - return `${column[COLUMN].alias}.${column[COLUMN].column}`; - } - - /** Select an exact flat row shape, retaining per-field runtime schemas. */ - select

( - selector: (columns: ReadColumns) => P - ): SchemaReadQuery< - S, - ObjectSchemaBuilder< - MergeProps< - SchemaProps>, - Pick< - SchemaProps, - Extract, keyof Relations> - > - > - >, - Relations - > { - if (this.selected) - throw new ReadSchemaError( - 'Only one projection is allowed per read query' - ); - const selection = selector( - this.columns as ReadColumns - ); - if (this.loaded.length && Object.values(selection).some(isAggregate)) - throw new ReadSchemaError( - 'Aggregate projections cannot contain relations' - ); - const copy = this.copy(); - copy.fields = compileReadProjection( - this.knex, - selection, - expression => { - if ( - !Object.values(this.columns).includes( - expression as ReadColumn - ) - ) - throw new ReadSchemaError( - 'Projection column does not belong to this query' - ); - const column = expression as ReadColumn; - return { node: column[READ_COLUMN], name: this.name(column) }; - } - ); - copy.selected = true; - // Included relations are independent of the scalar projection. - for (const relation of copy.loaded) - copy.fields[relation.name] = this.fields[relation.name]; - Object.assign(copy, { rowSchema: copy.schema() }); - return copy as any; - } - - /** Apply a named schema projection with the same exact row-schema guarantees. */ - projected & string>( - name: K - ): SchemaReadQuery< - S, - ObjectSchemaBuilder< - Pick< - SchemaProps>, - Extract, keyof SchemaProps>> - > & - Pick< - SchemaProps, - Extract, keyof Relations> - > - >, - Relations - > { - const definition = getProjections(this.source)[name]; - if (!definition) - throw new ReadSchemaError(`Unknown projection: ${name}`); - return this.select(() => - Object.fromEntries( - definition.keys.map(key => [key, this.columns[key]]) - ) - ) as any; - } - - protected readPredicateContext(): ReadPredicateContext< - ReadColumns - > { - return { - knex: this.knex, - column: selector => this.name(this.column(selector)) - }; - } - protected addReadPredicate(predicate: ReadPredicate): this { - const copy = this.copy(); - predicate(copy.base); - return copy; - } - /** Order parent rows independently of any child relation's ordering. */ - orderBy( - column: Selector>, - direction: 'asc' | 'desc' = 'asc' - ): this { - const copy = this.copy(); - copy.base.orderBy(this.name(this.column(column)), direction); - return copy; - } - /** Append trusted raw ordering with captured positional bindings; ref() supplies quoted columns. */ - orderByRaw(sql: string, bindings: readonly Knex.RawBinding[] = []): this { - const captured = captureReadRaw(this.knex, sql, bindings); - const copy = this.copy(); - copy.base.orderByRaw(captured()); - return copy; - } - /** Group rows before typed aggregate projection. */ - groupBy(...columns: Selector>[]): this { - const copy = this.copy(); - copy.base.groupBy(columns.map(c => this.name(this.column(c)))); - copy.grouped = true; - return copy; - } - /** Limit parent rows; relation limits apply independently within each parent. */ - limit(count: number): this { - if (!Number.isInteger(count) || count < 0) - throw new ReadSchemaError('Limit must be a non-negative integer'); - const copy = this.copy(); - copy.base.limit(count); - return copy; - } - /** Skip parent rows; use a deterministic order for pagination. */ - offset(count: number): this { - if (!Number.isInteger(count) || count < 0) - throw new ReadSchemaError('Offset must be a non-negative integer'); - const copy = this.copy(); - copy.base.offset(count); - return copy; - } - - /** - * Load a declared relation in the same SQL statement. Return the customized child - * query so its selected fields and nested includes remain strongly typed. - */ - include< - K extends keyof Relations & string, - Child extends ReadQueryShape = SchemaAwareQuery> - >( - selector: (relations: { [P in keyof Relations]: P }) => K, - customize?: (query: SchemaAwareQuery>) => Child - ): SchemaReadQuery< - S, - AddField>, - Relations - > { - if (Object.values(this.fields).some(f => f.aggregate) || this.grouped) - throw new ReadSchemaError( - 'Grouped/aggregate reads cannot load entity relations' - ); - const definitions = (this.source.introspect().extensions?.relations ?? - []) as RelationSpec[]; - const key = selector( - Object.fromEntries(definitions.map(r => [r.name, r.name])) as any - ); - const relation = definitions.find(r => r.name === key); - if (!relation) throw new ReadSchemaError(`Unknown relation: ${key}`); - if (this.loaded.some(r => r.name === key)) - throw new ReadSchemaError(`Duplicate relation: ${key}`); - const foreign = - typeof relation.schema === 'function' - ? relation.schema() - : relation.schema; - return this.load( - relation, - this.child(foreign, customize as any), - relation.type === 'belongsTo' && !relation.optional - ) as any; - } - - private child( - foreign: ReadObject, - customize?: (query: any) => ReadQueryShape - ): AnyReadQuery { - const Constructor = getSchemaQueryBuilderCtor(); - let child: AnyReadQuery = createReadQuery( - this.knex, - foreign, - getEffectiveBaseQuery(new Constructor(this.knex, foreign)).clone() - ); - if (customize) { - const customized = customize(child as any); - if (!child.sameSource(customized)) - throw new ReadSchemaError( - 'Relation customizer must return its configured read query' - ); - child = customized as any; - } - return child; - } - - private load( - relation: RelationSpec, - child: AnyReadQuery, - required: boolean - ): this { - const key = relation.name; - if (this.grouped || Object.values(this.fields).some(f => f.aggregate)) - throw new ReadSchemaError( - 'Grouped/aggregate reads cannot load entity relations' - ); - if ( - this.loaded.some(r => r.name === key) || - Object.hasOwn(this.fields, key) - ) - throw new ReadSchemaError(`Duplicate result field: ${key}`); - const many = - relation.type === 'hasMany' || relation.type === 'belongsToMany'; - const schema = many - ? array(child.rowSchema) - : required - ? child.rowSchema - : child.rowSchema.nullable(); - const node: ReadNode = { - schema, - exact: false, - decode: (value, path) => { - if (value === null && !required && !many) return null; - if (many) { - if (!Array.isArray(value)) - throw new ReadSchemaError( - `${path}: expected a relation array` - ); - return value.map((row, i) => - child.decode(row, `${path}[${i}]`) - ); - } - return child.decode(value, path); - } - }; - const copy = this.copy(); - copy.loaded.push({ name: key, query: child, relation, required }); - copy.fields[key] = { - node, - expression: () => { - throw new ReadSchemaError( - 'Relation expression must be compiled in context' - ); - } - }; - Object.assign(copy, { rowSchema: copy.schema() }); - return copy as any; - } - - /** Join one typed nested object with explicit property keys, including nullable joins. */ - joinOne< - F extends ReadObject, - K extends string, - Required extends boolean = true, - Child extends ReadQueryShape = SchemaAwareQuery - >( - spec: JoinOneSpec, - customize?: (query: SchemaAwareQuery) => Child - ): SchemaReadQuery< - S, - AddField< - Row, - K, - Required extends true - ? Child['rowSchema'] - : SchemaForValue | null> - >, - Relations & Record> - > { - if (spec.foreignQuery || spec.mappers) - throw new ReadSchemaError( - 'Use the typed child customizer instead of foreignQuery/mappers in schema-aware mode' - ); - return this.load( - { - name: spec.as, - type: 'hasOne', - schema: spec.foreignSchema, - localKey: resolvePropertyKey( - spec.localColumn as any, - this.source, - 'joinOne' - ), - remoteKey: resolvePropertyKey( - spec.foreignColumn as any, - spec.foreignSchema, - 'joinOne' - ) - }, - this.child(spec.foreignSchema, customize as any), - spec.required !== false - ) as any; - } - - /** Join a typed collection, applying child projection and pagination independently per parent. */ - joinMany< - F extends ReadObject, - K extends string, - Child extends ReadQueryShape = SchemaAwareQuery - >( - spec: Omit, 'orderBy'>, - customize?: (query: SchemaAwareQuery) => Child - ): SchemaReadQuery< - S, - AddField>, - Relations & Record> - > { - if (spec.foreignQuery || spec.mappers || 'orderBy' in spec) - throw new ReadSchemaError( - 'Use the typed child customizer for ordering instead of raw foreignQuery/mappers' - ); - let child = this.child(spec.foreignSchema, customize as any); - if (spec.limit !== undefined) child = child.limit(spec.limit); - if (spec.offset !== undefined) child = child.offset(spec.offset); - return this.load( - { - name: spec.as, - type: 'hasMany', - schema: spec.foreignSchema, - localKey: resolvePropertyKey( - spec.localColumn as any, - this.source, - 'joinMany' - ), - remoteKey: resolvePropertyKey( - spec.foreignColumn as any, - spec.foreignSchema, - 'joinMany' - ) - }, - child, - false - ) as any; - } - - /** @internal Decode a SQL/JSON row using the same metadata exposed to consumers. */ - decode(row: any, path = 'row'): any { - if ( - this.source.introspect().extensions?.readOrphanColumn && - row.__read_cti_present == null - ) - throw new ReadSchemaError(`${path}: missing CTI variant body`); - return decodeObject( - Object.fromEntries( - Object.entries(this.fields).map(([key, field]) => [ - key, - field.node - ]) - ), - row, - path - ); - } - - /** @internal Compile a bound SQL statement; callers never receive the mutable builder. */ - compile(correlate?: ReadCorrelation): Knex.QueryBuilder { - const query = this.base.clone().clearSelect(); - correlate?.(query, this.alias, this.source); - const expressions: Record = Object.create(null); - for (const [key, field] of Object.entries(this.fields)) { - if (!this.loaded.some(r => r.name === key)) - expressions[key] = field.expression(this.knex); - } - const orphanColumn = - this.source.introspect().extensions?.readOrphanColumn; - if (orphanColumn) - expressions.__read_cti_present = this.knex.raw('??', [ - `${this.alias}.${orphanColumn}` - ]); - for (const loaded of this.loaded) { - const { relation, query: child } = loaded; - const parentTable = this.alias; - const parentPk = getPrimaryKeyColumns(this.source).columnNames; - const foreignKey = relation.foreignKey; - const resolveKey = (schema: ReadObject, key: any) => { - if (typeof key === 'function') { - const descriptor = key( - ObjectSchemaBuilderValue.getPropertiesFor(schema) - ); - key = - descriptor[SYMBOL_SCHEMA_PROPERTY_DESCRIPTOR] - .propertyName; - } - return buildColumnMap(schema).propToCol.get(key) ?? key; - }; - const childSql = child.compile((sql, childTable, childSource) => { - const childPk = getPrimaryKeyColumns(childSource).columnNames; - if (relation.localKey && relation.remoteKey) { - sql.where( - `${childTable}.${resolveKey(childSource, relation.remoteKey)}`, - this.knex.ref( - `${parentTable}.${resolveKey(this.source, relation.localKey)}` - ) - ); - return; - } - if (parentPk.length !== 1) - throw new ReadSchemaError( - 'Automatic relation reads require single-column primary keys' - ); - if (childPk.length !== 1) - throw new ReadSchemaError( - 'Automatic relation reads require single-column primary keys' - ); - if (relation.type === 'belongsTo') - sql.where( - `${childTable}.${childPk[0]}`, - this.knex.ref( - `${parentTable}.${resolveKey(this.source, foreignKey)}` - ) - ); - else if (relation.type === 'belongsToMany') { - const through = relation.through!; - sql.join( - through.table, - `${through.table}.${through.foreignKey}`, - `${childTable}.${childPk[0]}` - ).where( - `${through.table}.${through.localKey}`, - this.knex.ref(`${parentTable}.${parentPk[0]}`) - ); - } else - sql.where( - `${childTable}.${resolveKey(childSource, foreignKey)}`, - this.knex.ref(`${parentTable}.${parentPk[0]}`) - ); - }); - const many = - relation.type === 'hasMany' || - relation.type === 'belongsToMany'; - if (!many) childSql.limit(1); - const wrapped = this.knex - .queryBuilder() - .from(childSql.clone().as('__read_relation')); - expressions[loaded.name] = many - ? this.knex.raw( - "(select coalesce(jsonb_agg(to_jsonb(__read_relation)), '[]'::jsonb) from (?) as __read_relation)", - [childSql] - ) - : this.knex.raw( - '(select to_jsonb(__read_relation) from (?) as __read_relation)', - [childSql] - ); - if (loaded.required) - query.whereExists(wrapped.clone().select(this.knex.raw('1'))); - } - return query.select(expressions); - } - - /** Render debugging SQL without execution; bound values may be sensitive. */ - toQuery(): string { - return this.compile().toQuery(); - } - /** Execute one statement and decode its selected row graph. */ - async execute(): Promise[]> { - return (await this.compile()).map((row: unknown) => this.decode(row)); - } - /** Execute a limited copy, returning undefined when no row matches. */ - async first(): Promise | undefined> { - return (await this.limit(1).execute())[0]; - } - /** Awaiting executes the query; repeated awaits deliberately execute again. */ - // biome-ignore lint/suspicious/noThenProperty: query readers intentionally support await - then[], E = never>( - resolve?: ((rows: InferType[]) => T | PromiseLike) | null, - reject?: ((error: any) => E | PromiseLike) | null - ): Promise { - return this.execute().then(resolve, reject); - } - /** Bind an independent query graph to a caller-owned transaction. */ - transacting(trx: Knex.Transaction): this { - const copy = this.copy(); - copy.base.transacting(trx); - Object.assign(copy, { knex: trx }); - copy.loaded = this.loaded.map(r => ({ - ...r, - query: r.query.transacting(trx) - })); - return copy; - } - /** - * Read a lossless composite cursor page using native SQL ordering. Cursor sort - * values remain private text columns, independent of projections and Date decoding. - * Requires non-null scalar order columns containing a declared unique key. - */ - async paginateAfter( - options: CompositeCursorOptions - ): Promise>> { - if (this.grouped || Object.values(this.fields).some(f => f.aggregate)) - throw new ReadSchemaError( - 'Cursor pagination cannot be used for aggregate reads' - ); - const Constructor = getSchemaQueryBuilderCtor(); - const source = this.source.withExtension('tableName', this.alias); - const legacy = new Constructor(this.knex, source, this.compile()); - const state = getState(legacy); - state.skipDefaultScope = true; - state.includeDeleted = true; - // The query is already projected; reserve its aliases against cursor fields. - state.hiddenColumns = new Set(Object.keys(this.fields)); - return compositeCursor( - legacy, - options, - row => this.decode(row), - this.source.introspect().extensions?.tableName as string - ); - } - /** Fetch a numbered page and a count without mutating the source query. */ - async paginate(options: { - page: number; - pageSize: number; - }): Promise>> { - const { page, pageSize } = options; - if ( - !Number.isInteger(page) || - page < 1 || - !Number.isInteger(pageSize) || - pageSize < 1 - ) - throw new ReadSchemaError( - 'Page and pageSize must be positive integers' - ); - const countQuery = this.compile() - .clearOrder() - .clear('limit') - .clear('offset'); - const countRow = await this.knex - .from(countQuery.as('__read_count')) - .count({ count: '*' }) - .first(); - const total = Number(countRow?.count ?? 0); - if (!Number.isSafeInteger(total)) - throw new ReadSchemaError( - 'Pagination count exceeds the safe integer range' - ); - const data = await this.offset((page - 1) * pageSize) - .limit(pageSize) - .execute(); - const totalPages = Math.ceil(total / pageSize); - return { - data, - total, - page, - pageSize, - totalPages, - hasNextPage: page < totalPages, - hasPreviousPage: page > 1 - }; - } -} - -import { ObjectSchemaBuilder as ObjectSchemaBuilderValue } from '@cleverbrush/schema'; - -/** @internal Enter schema-aware mode only before result-shaping legacy operations. */ -export function schemaReadQuery( - builder: SchemaQueryBuilder -): SchemaAwareQuery { - const state = getState(builder); - if ( - state.selectionMode !== null || - state.specs.length || - state.variantRelationIncludes.length - ) - throw new ReadSchemaError( - 'Call withRowSchema() before select/include/join operations' - ); - if ( - state.opaqueReadShape || - state.enabledVariants || - state.variantWhereFilters.length - ) - throw new ReadSchemaError( - 'Call withRowSchema() before raw or variant-specific operations' - ); - const base = getEffectiveBaseQuery(builder).clone(); - const statements = (base as any)._statements as Array<{ grouping: string }>; - if ( - statements.some(s => s.grouping === 'order') || - (base as any)._single.limit !== undefined || - (base as any)._single.offset !== undefined - ) - throw new ReadSchemaError( - 'Call withRowSchema() before ordering or pagination' - ); - if ( - statements.some(s => - ['columns', 'join', 'group', 'having', 'union'].includes(s.grouping) - ) - ) - throw new ReadSchemaError( - 'Existing raw projections, joins and aggregates cannot declare a read schema' - ); - return createReadQuery(state.knex, state.localSchema as S, base); -} - -/** @internal Shared reader factory for roots and nested relations. */ -export function createReadQuery( - knex: Knex, - schema: S, - base: Knex.QueryBuilder -): SchemaAwareQuery { - return ( - getVariants(schema) - ? new PolymorphicReadQuery(knex, schema, base) - : new SchemaReadQuery(knex, schema, base) - ) as SchemaAwareQuery; -} diff --git a/libs/knex-schema/src/aliased-query.ts b/libs/knex-schema/src/aliased-query.ts index 455b16dd..1b98e8c9 100644 --- a/libs/knex-schema/src/aliased-query.ts +++ b/libs/knex-schema/src/aliased-query.ts @@ -1,6 +1,6 @@ import type { InferType, ObjectSchemaBuilder } from '@cleverbrush/schema'; import type { Knex } from 'knex'; -import { AliasedReadQuery } from './AliasedReadQuery.js'; + import { buildColumnMap } from './columns.js'; import type { SchemaProps } from './entity.js'; import { @@ -10,11 +10,9 @@ import { compileAggregate, isAggregate } from './expressions.js'; -import { - ALLOWED_OPS, - getEffectiveBaseQuery, - getSchemaQueryBuilderCtor -} from './operations/helpers.js'; +import { getTableName } from './extension.js'; +import { ALLOWED_OPS } from './operations/helpers.js'; +import { SchemaQueryBuilder } from './SchemaQueryBuilder.js'; import { isSqlIdentifier } from './sql-identifiers.js'; type TableSchema = ObjectSchemaBuilder; @@ -135,8 +133,8 @@ export function or(...items: JoinPredicate[]): JoinPredicate { return { [PREDICATE]: { op: 'or', items } }; } -/** Read-only flat query builder. Explicit projections avoid ambiguous SELECT *. */ -export class AliasedQueryBuilder { +/** @internal Mutable native SQL planner, never returned by a public factory. */ +export class AliasedQuerySource { private sql: Knex.QueryBuilder; private tables = new Map(); private selected = false; @@ -144,17 +142,8 @@ export class AliasedQueryBuilder { private nullableTables = new Set(); private opaqueReadShape = false; - /** Enter immutable read mode before select/raw changes; an explicit projection is required. */ - withRowSchema(): AliasedReadQuery { - if (this.selected || this.opaqueReadShape) - throw new Error( - 'Call withRowSchema() before select/apply operations' - ); - return new AliasedReadQuery(this.cloneReadSource()); - } - /** @internal Snapshot the SQL planner without sharing mutable query state. */ - cloneReadSource(): AliasedQueryBuilder { + cloneReadSource(): AliasedQuerySource { const copy = Object.assign( Object.create(Object.getPrototypeOf(this)), this @@ -166,7 +155,7 @@ export class AliasedQueryBuilder { return copy; } - /** @internal Schema-backed state used by the immutable opt-in adapter. */ + /** @internal Schema-backed state used by the immutable public builder. */ readContext(): { knex: Knex; sql: Knex.QueryBuilder; columns: TTables } { return { knex: this.knex, sql: this.sql.clone(), columns: this.tree() }; } @@ -185,9 +174,12 @@ export class AliasedQueryBuilder { } private source(table: TableAlias): Knex.QueryBuilder { - const Constructor = getSchemaQueryBuilderCtor(); - return getEffectiveBaseQuery(new Constructor(this.knex, table.schema)) - .clone() + return new SchemaQueryBuilder( + this.knex, + table.schema, + this.knex(getTableName(table.schema)) + ) + .storageQuery() .as(table.name); } @@ -257,7 +249,7 @@ export class AliasedQueryBuilder { join( table: N extends keyof TTables ? never : TableAlias, on: (tables: TTables & AliasTables) => JoinPredicate - ): AliasedQueryBuilder, TResult> { + ): AliasedQuerySource, TResult> { this.addJoin(table, on as any, false); return this as any; } @@ -270,7 +262,7 @@ export class AliasedQueryBuilder { leftJoin( table: N extends keyof TTables ? never : TableAlias, on: (tables: TTables & AliasTables) => JoinPredicate - ): AliasedQueryBuilder, TResult> { + ): AliasedQuerySource, TResult> { this.addJoin(table, on as any, true); return this as any; } @@ -421,7 +413,7 @@ export class AliasedQueryBuilder { */ select( selector: (tables: TTables) => S - ): AliasedQueryBuilder> { + ): AliasedQuerySource> { if (this.selected) throw new Error('Only one object projection per query'); const columns: Record = {}; @@ -467,12 +459,9 @@ export class AliasedQueryBuilder { * Clone this builder onto an existing transaction, preserving its tables/projection. * Does not modify the source or commit/roll back the transaction. */ - transacting(trx: Knex.Transaction): AliasedQueryBuilder { - const [name, schema] = this.tables.entries().next().value!; - const copy = new AliasedQueryBuilder( - trx as unknown as Knex, - alias(schema, name) - ); + transacting(trx: Knex.Transaction): AliasedQuerySource { + const copy = this.cloneReadSource(); + Object.assign(copy, { knex: trx }); copy.sql = this.sql.clone().transacting(trx); copy.tables = new Map(this.tables); copy.selected = this.selected; diff --git a/libs/knex-schema/src/composable-query.test-d.ts b/libs/knex-schema/src/composable-query.test-d.ts index a03fa6f4..77dc4b84 100644 --- a/libs/knex-schema/src/composable-query.test-d.ts +++ b/libs/knex-schema/src/composable-query.test-d.ts @@ -35,8 +35,12 @@ test('factories retain schema, alias and result inference through every call sha expectTypeOf(await plain.select(t => ({ id: t.id }))).toEqualTypeOf< { id: number }[] >(); + // @ts-expect-error implicit raw base queries cannot declare an output contract + query(db, Task, db('tasks')); expectTypeOf( - await query(db, Task, db('tasks')).select(t => ({ amount: t.amount })) + await query(db, Task).selectRaw('1 as amount', [], { + output: object({ amount: number() }) + }) ).toEqualTypeOf<{ amount: number }[]>(); for (const factory of [bound, transactional]) { const ordinary = factory(Task); @@ -44,8 +48,12 @@ test('factories retain schema, alias and result inference through every call sha expectTypeOf( await ordinary.select(t => ({ createdAt: t.createdAt })) ).toEqualTypeOf<{ createdAt: Date }[]>(); + // @ts-expect-error bound factories cannot accept an opaque raw base query + factory(Task, db('tasks')); expectTypeOf( - await factory(Task, db('tasks')).select(t => ({ id: t.id })) + await factory(Task).selectRaw('1 as id', [], { + output: object({ id: number() }) + }) ).toEqualTypeOf<{ id: number }[]>(); const aliased = factory(alias(Task, 'task')); expectTypeOf(aliased).not.toBeAny(); @@ -113,10 +121,10 @@ test('aggregate defaults and supplied output schemas infer accurately', async () await query(db, Task).maxValue('createdAt') ).toEqualTypeOf(); expectTypeOf(await query(db, Task).minValue('amount')).toEqualTypeOf< - number | string | null + number | null >(); expectTypeOf(await query(db, Task).minValue(t => t.amount)).toEqualTypeOf< - number | string | null + number | null >(); expectTypeOf( await query(db, Task).countValue({ output: string() }) diff --git a/libs/knex-schema/src/composable-query.test.ts b/libs/knex-schema/src/composable-query.test.ts index b3a3dbed..9a9e2f6e 100644 --- a/libs/knex-schema/src/composable-query.test.ts +++ b/libs/knex-schema/src/composable-query.test.ts @@ -118,8 +118,8 @@ describe('typed aliases and aggregate SQL', () => { count: aggregate.countDistinct(t.id) })) .toQuery(); - expect(sql).toContain('count(distinct "id")'); - expect(sql).toContain('group by "owner_id"'); + expect(sql).toMatch(/count\(distinct "__schema_read_\d+"\."id"\)/); + expect(sql).toMatch(/group by "__schema_read_\d+"\."owner_id"/); }); }); diff --git a/libs/knex-schema/src/entity.ts b/libs/knex-schema/src/entity.ts index fe6ea98e..d226d506 100644 --- a/libs/knex-schema/src/entity.ts +++ b/libs/knex-schema/src/entity.ts @@ -910,7 +910,7 @@ export type EntityVariantUnion = /** * Type-level helper: union of relation key names declared on an entity. - * Used by `SchemaQueryBuilder.insert()/update()/upsert()` to omit relation + * Used by `QuerySource.insert()/update()/upsert()` to omit relation * navigation properties from accepted input. * @public */ diff --git a/libs/knex-schema/src/extension.ts b/libs/knex-schema/src/extension.ts index e5875aac..f24b14d5 100644 --- a/libs/knex-schema/src/extension.ts +++ b/libs/knex-schema/src/extension.ts @@ -1,4 +1,5 @@ // @cleverbrush/knex-schema — Schema extension: hasColumnName / hasTableName + import type { AnySchemaBuilder, ArraySchemaBuilder, @@ -28,6 +29,7 @@ import { stringExtensions, withExtensions } from '@cleverbrush/schema'; +import type { QueryScope } from './query-scope.js'; import type { ResolvedVariantConfig, ResolvedVariantRelationSpec, @@ -731,12 +733,15 @@ export const ddlExtension = defineExtension({ }, /** Register a named query scope. * @param name - Scope name to use with `.scoped(name)`. - * @param fn - Function that receives a `SchemaQueryBuilder` and applies filters. + * @param fn - Synchronous callback returning its configured immutable query (filters/order/paging only). */ - scope( - this: ObjectSchemaBuilder, + scope< + N extends string, + S extends ObjectSchemaBuilder + >( + this: S, name: N, - fn: Function + fn: (query: QueryScope) => QueryScope ): typeof this & { readonly [METHOD_LITERAL_BRAND]?: N } { const existing = (this.getExtension('scopes') as Record) ?? {}; @@ -886,12 +891,11 @@ export const ddlExtension = defineExtension({ }; }, /** Set a default scope applied to all queries unless `.unscoped()` is called. - * @param fn - Function that receives a `SchemaQueryBuilder` and applies filters. + * @param fn - Synchronous function that returns its configured immutable query scope. */ - defaultScope( - this: ObjectSchemaBuilder, - fn: Function - ) { + defaultScope< + S extends ObjectSchemaBuilder + >(this: S, fn: (query: QueryScope) => QueryScope) { return this.withExtension('defaultScope', fn); }, /** Register a before-insert lifecycle hook. @@ -928,7 +932,7 @@ export const ddlExtension = defineExtension({ return this.withExtension('beforeUpdate', [...existing, fn]); }, /** Register a before-delete lifecycle hook. - * @param fn - Async function `(query)` called before deleting. + * @param fn - Observational async function `(query)` called before deleting; query configuration is immutable. Apply delete filters before calling delete(). */ beforeDelete( this: ObjectSchemaBuilder, @@ -1004,7 +1008,7 @@ export const ddlExtension = defineExtension({ // The internal worker {@link applyVariantsToSchema} (below this // `defineExtension` block) is invoked by the Entity layer and stores // the same `'variants'` / `'polymorphicVariants'` extensions that - // `SchemaQueryBuilder` reads at runtime. + // `QuerySource` reads at runtime. } }); @@ -1035,7 +1039,7 @@ export interface VariantInputForResolver { /** * @internal Validate + apply a fully-resolved variant config to a base * schema. Stores the `'variants'` and `'polymorphicVariants'` extensions - * read by {@link SchemaQueryBuilder}. + * read by {@link QuerySource}. * * Called by the {@link Entity} chain (`.discriminator().ctiVariant().stiVariant()`). * Replaces the previous schema-level `.withVariants()` method. @@ -1333,7 +1337,7 @@ export function getProjections( * Retrieve the resolved variant configuration stored by `.withVariants()`. * Returns `null` when the schema is not polymorphic. * - * @internal — used by {@link SchemaQueryBuilder}. + * @internal — used by {@link QuerySource}. */ export function getVariants( schema: ObjectSchemaBuilder diff --git a/libs/knex-schema/src/immutable-query.test-d.ts b/libs/knex-schema/src/immutable-query.test-d.ts new file mode 100644 index 00000000..014aba57 --- /dev/null +++ b/libs/knex-schema/src/immutable-query.test-d.ts @@ -0,0 +1,60 @@ +import type { InferType } from '@cleverbrush/schema'; +import Knex from 'knex'; +import { expectTypeOf, test } from 'vitest'; +import { number, object, string } from './extension.js'; +import { query } from './query.js'; + +const db = Knex({ client: 'pg' }); +const User = object({ + id: number().bigint().primaryKey(), + name: string(), + settings: object({ enabled: number() }) +}).hasTableName('users'); + +test('automatic projections preserve exact structural row types', async () => { + const users = query(db, User); + const selected = users.select(u => ({ userId: u.id, displayName: u.name })); + type Row = InferType; + expectTypeOf().toEqualTypeOf<{ + userId: string; + displayName: string; + }>(); + expectTypeOf(await selected.first()).toEqualTypeOf(); + const ids = users.select(u => u.id); + expectTypeOf>().toEqualTypeOf<{ + id: string; + }>(); + const nested = users.select(u => ({ enabled: u.settings.enabled })); + expectTypeOf>().toEqualTypeOf<{ + enabled: number; + }>(); + // @ts-expect-error projected queries cannot update entities + selected.update({ name: 'unsafe' }); + // @ts-expect-error projected queries cannot insert entities + selected.insert({ name: 'unsafe' }); + // @ts-expect-error grouped predicate callbacks must return their configured builder + users.where(group => { + group.where('name', 'discarded'); + }); + // @ts-expect-error raw SQL cannot infer its output shape + users.apply(sql => sql.select('*')); + // @ts-expect-error removed opt-in method has no compatibility alias + users.withRowSchema(); + // Lossless storage representations are valid update values. + users.update({ id: '9007199254740993' }); + // @ts-expect-error grouped sources cannot write entities + users.groupBy(u => u.name).update({ name: 'unsafe' }); + // @ts-expect-error distinct sources cannot write entities + users.distinct().delete(); + // @ts-expect-error HAVING queries are grouped read-only sources + users.havingRaw('count(*) > 0').delete(); + User.scope('named', scope => { + // @ts-expect-error scopes cannot change projections + scope.where('name', 'x').select('id'); + return scope.where('name', 'x'); + }); + // @ts-expect-error scope callbacks cannot discard their immutable result + User.defaultScope(scope => { + scope.where('name', 'x'); + }); +}); diff --git a/libs/knex-schema/src/immutable-query.test.ts b/libs/knex-schema/src/immutable-query.test.ts new file mode 100644 index 00000000..bb2cee50 --- /dev/null +++ b/libs/knex-schema/src/immutable-query.test.ts @@ -0,0 +1,163 @@ +import { + number as outputNumber, + object as outputObject +} from '@cleverbrush/schema'; +import Knex from 'knex'; +import { describe, expect, it, vi } from 'vitest'; +import { defineEntity } from './entity.js'; +import { number, object, string } from './extension.js'; +import { createQuery, query } from './query.js'; + +const knex = Knex({ client: 'pg' }); +const Account = object({ + id: number().primaryKey(), + name: string(), + active: number() +}).hasTableName('accounts'); + +describe('immutable public queries', () => { + it('owns polymorphic ordering columns and rejects visibility-changing scopes', () => { + const Asset = defineEntity( + object({ id: number().primaryKey(), kind: string() }).hasTableName( + 'assets' + ) + ) + .discriminator('kind') + .stiVariant('note', object({ text: string() })); + const one = query(knex, Asset.schema); + const two = query(knex, Asset.schema); + let foreign: any; + one.orderBy(c => { + foreign = c.id; + return c.id; + }); + expect(() => two.orderBy(() => foreign)).toThrow(/does not belong/); + const invalid = Asset.schema.defaultScope(((q: any) => + q.withDeleted()) as any); + expect(() => query(knex, invalid)).toThrow(/shape-preserving/); + }); + it('rejects removed raw-source overloads instead of silently dropping SQL', () => { + expect(() => (query as any)(knex, Account, knex('accounts'))).toThrow( + /output/ + ); + expect(() => + (createQuery(knex) as any)(Account, knex('accounts')) + ).toThrow(/output/); + }); + it('derives metadata automatically and preserves it across filters and paging', () => { + const base = query(knex, Account); + const one = base.where('id', 1).limit(1); + const two = base.where('id', 2).offset(3); + expect(one).not.toBe(base); + expect(one.rowSchema).toBe(base.rowSchema); + expect(two.rowSchema).toBe(base.rowSchema); + expect(base.toQuery()).not.toContain('where'); + expect(one.toQuery()).toContain('= 1'); + expect(two.toQuery()).toContain('= 2'); + expect('withRowSchema' in base).toBe(false); + }); + + it('replaces projections without mutating either source', () => { + const base = query(knex, Account); + const named = base.select(t => ({ name: t.name })); + const ids = named.select(t => ({ key: t.id })); + expect(Object.keys(base.rowSchema.introspect().properties)).toEqual([ + 'id', + 'name', + 'active' + ]); + expect(Object.keys(named.rowSchema.introspect().properties)).toEqual([ + 'name' + ]); + expect(Object.keys(ids.rowSchema.introspect().properties)).toEqual([ + 'key' + ]); + expect(ids.rowSchema).not.toBe(named.rowSchema); + }); + + it('runs groups once and ignores discarded immutable branches', () => { + let retained: any; + const callback = vi.fn(group => { + retained = group; + group.where('id', 99); + return group.where('id', 1).orWhere('id', 2); + }); + const filtered = query(knex, Account).where(callback); + retained.where('id', 3); + expect(filtered.toQuery()).toContain('= 1 or'); + expect(filtered.toQuery()).not.toContain('99'); + expect(filtered.toQuery()).not.toContain('= 3'); + expect(callback).toHaveBeenCalledTimes(1); + }); + + it('rejects void, async and unrelated group results without executing them', () => { + const base = query(knex, Account); + expect(() => base.where((() => undefined) as any)).toThrow( + /must return/ + ); + expect(() => base.where((async () => undefined) as any)).toThrow( + /synchronous/ + ); + expect(() => base.where((() => base) as any)).toThrow( + /synchronous|must return/ + ); + }); + + it('captures default scopes once and removes only their effects', () => { + const scope = vi.fn(q => q.where('active', 1)); + const schema = Account.defaultScope(scope); + const base = query(knex, schema); + const explicit = base.where('id', 7); + const unscoped = explicit.unscoped(); + expect(explicit.toQuery()).toMatch(/"active" = 1/); + expect(unscoped.toQuery()).not.toMatch(/"active" = 1/); + expect(unscoped.toQuery()).toMatch(/"id" = 7/); + expect(scope).toHaveBeenCalledTimes(1); + expect(unscoped.rowSchema).toBe(base.rowSchema); + }); + + it('isolates mutable Knex snapshots', () => { + const base = query(knex, Account).where('active', 1); + const snapshot = base.toKnexQuery(); + snapshot.where('id', 9).limit(1); + expect(base.toQuery()).not.toContain('= 9'); + expect(base.toQuery()).not.toContain('limit'); + }); + + it('captures opaque SQL once and requires an explicit object output', () => { + const output = outputObject({ total: outputNumber().coerce() }); + let retained: any; + const configure = vi.fn(sql => { + retained = sql; + return sql.clearSelect().count({ total: '*' }); + }); + const raw = query(knex, Account).apply(configure, { output }); + retained.where('id', 99); + expect(raw.rowSchema).toBe(output); + expect(raw.toQuery()).toContain('count(*)'); + expect(raw.toQuery()).not.toContain('99'); + raw.toQuery(); + expect(configure).toHaveBeenCalledTimes(1); + expect(() => + (query(knex, Account) as any).selectRaw('1 as total', []) + ).toThrow(/output/); + }); + + it('rejects writes through projected query instances at runtime too', async () => { + const selected = query(knex, Account).select(t => ({ name: t.name })); + await expect( + (selected as any).insert({ name: 'unsafe' }) + ).rejects.toThrow(/unprojected/); + await expect( + (selected as any).update({ name: 'unsafe' }) + ).rejects.toThrow(/unprojected/); + await expect((selected as any).insertMany([])).rejects.toThrow( + /unprojected/ + ); + await expect( + (query(knex, Account).havingRaw('count(*) > 0') as any).update({ + name: 'unsafe' + }) + ).rejects.toThrow(/unprojected/); + }); +}); diff --git a/libs/knex-schema/src/index.ts b/libs/knex-schema/src/index.ts index 90d301f6..e727ed58 100644 --- a/libs/knex-schema/src/index.ts +++ b/libs/knex-schema/src/index.ts @@ -1,7 +1,7 @@ // @cleverbrush/knex-schema — Type-safe schema-driven query builder for Knex -export type { ReadAliasTables } from './AliasedReadQuery.js'; -export { AliasedReadQuery } from './AliasedReadQuery.js'; +export type { ReadAliasTables } from './AliasedQueryBuilder.js'; +export { AliasedQueryBuilder } from './AliasedQueryBuilder.js'; export type { AliasTables, JoinedProjection, @@ -9,7 +9,7 @@ export type { TableAlias } from './aliased-query.js'; // Types -export { AliasedQueryBuilder, alias, and, eq, or } from './aliased-query.js'; +export { alias, and, eq, or } from './aliased-query.js'; export type { PrimaryKeyColumns, RowVersionColumn, @@ -92,13 +92,18 @@ export { tableExistsInDb, validateEntitiesAgainstDatabase } from './migration.js'; +export { OpaqueQuery, type QueryOutput } from './OpaqueQuery.js'; export type { CompositeCursorOptions } from './operations/composite-cursor.js'; export type { PolymorphicRowSchema, VariantReadSchema, VariantReadSchemas -} from './PolymorphicReadQuery.js'; -export { PolymorphicReadQuery } from './PolymorphicReadQuery.js'; +} from './PolymorphicQueryBuilder.js'; +export { PolymorphicQueryBuilder } from './PolymorphicQueryBuilder.js'; +export type { BoundQuery } from './query.js'; +// Main entry point +export { createQuery, query } from './query.js'; +export type { QueryScope } from './query-scope.js'; // Raw query execution export { rawQuery } from './raw.js'; export type { @@ -125,20 +130,14 @@ export type { SchemaForValue } from './read-schema.js'; export { ReadSchemaError } from './read-schema.js'; -export type { BoundQuery } from './SchemaQueryBuilder.js'; -// Main entry point -export { - createQuery, - query, - SchemaQueryBuilder -} from './SchemaQueryBuilder.js'; export type { ReadColumn, ReadColumns, ReadProjection, + ReadQueryShape, SchemaAwareQuery -} from './SchemaReadQuery.js'; -export { SchemaReadQuery } from './SchemaReadQuery.js'; +} from './SchemaQueryBuilder.js'; +export { SchemaQueryBuilder } from './SchemaQueryBuilder.js'; // Snapshot-based migration export { entitiesToSnapshot, diff --git a/libs/knex-schema/src/mappers.ts b/libs/knex-schema/src/mappers.ts index 050c3058..c59d3586 100644 --- a/libs/knex-schema/src/mappers.ts +++ b/libs/knex-schema/src/mappers.ts @@ -98,7 +98,7 @@ export function mapObject>( * the `mappers` defined on each spec to the nested data, and returns the * mutated row. * - * This is an internal helper used by {@link SchemaQueryBuilder}'s result + * This is an internal helper used by {@link QuerySource}'s result * mapping pipeline. Exported to allow custom post-processing if needed. * * @param row - The raw result row (mutated in place). diff --git a/libs/knex-schema/src/operations/aggregate.ts b/libs/knex-schema/src/operations/aggregate.ts index 063ee36c..964fa5fd 100644 --- a/libs/knex-schema/src/operations/aggregate.ts +++ b/libs/knex-schema/src/operations/aggregate.ts @@ -8,21 +8,21 @@ import { createAggregate, type SelectableColumn } from '../expressions.js'; -import type { SchemaQueryBuilder } from '../SchemaQueryBuilder.js'; +import type { QuerySource } from '../QuerySource.js'; import type { ColumnRef } from '../types.js'; import { buildQuery, getEffectiveBaseQuery, - getSchemaQueryBuilderCtor + getQuerySourceCtor } from './helpers.js'; import { getState } from './state.js'; /** Clone Framework metadata as well as Knex state; terminal helpers never mutate the source. */ export function cloneQuery( - builder: SchemaQueryBuilder -): SchemaQueryBuilder { + builder: QuerySource +): QuerySource { const state = getState(builder); - const Constructor = getSchemaQueryBuilderCtor(); + const Constructor = getQuerySourceCtor(); const copy = new Constructor( state.knex, state.localSchema, @@ -78,7 +78,7 @@ export function assertScalarSource(query: Knex.QueryBuilder): void { export async function scalarAggregate< S extends ObjectSchemaBuilder >( - builder: SchemaQueryBuilder, + builder: QuerySource, kind: AggregateKind, column?: ColumnRef, options?: AggregateOptions diff --git a/libs/knex-schema/src/operations/composite-cursor.ts b/libs/knex-schema/src/operations/composite-cursor.ts index 342bda95..243d2ef9 100644 --- a/libs/knex-schema/src/operations/composite-cursor.ts +++ b/libs/knex-schema/src/operations/composite-cursor.ts @@ -5,7 +5,7 @@ import { getPrimaryKeyColumns, resolvePropertyKey } from '../columns.js'; -import type { SchemaQueryBuilder } from '../SchemaQueryBuilder.js'; +import type { QuerySource } from '../QuerySource.js'; import type { ColumnRef, CursorPaginationResult } from '../types.js'; import { cloneQuery, statements } from './aggregate.js'; import { cleanAndMapRow, getEffectiveBaseQuery, getQuery } from './helpers.js'; @@ -30,7 +30,7 @@ export interface CompositeCursorOptions< } export async function compositeCursor( - builder: SchemaQueryBuilder, + builder: QuerySource, options: CompositeCursorOptions, decode?: (row: Record) => any, sourceIdentity?: string diff --git a/libs/knex-schema/src/operations/delete.ts b/libs/knex-schema/src/operations/delete.ts index 5f8a7962..506d275f 100644 --- a/libs/knex-schema/src/operations/delete.ts +++ b/libs/knex-schema/src/operations/delete.ts @@ -1,11 +1,12 @@ // @cleverbrush/knex-schema — DELETE / soft-delete / restore operations -import type { SchemaQueryBuilder } from '../SchemaQueryBuilder.js'; +import type { QuerySource } from '../QuerySource.js'; +import { returningReadColumns } from '../read-schema.js'; import { getSoftDelete, invalidateCache, mapRow } from './helpers.js'; import { getState } from './state.js'; export async function deleteImpl( - builder: SchemaQueryBuilder + builder: QuerySource ): Promise { const state = getState(builder); @@ -14,7 +15,7 @@ export async function deleteImpl( | Function[] | undefined) ?? []; for (const hook of hooks) { - await hook(builder); + await hook(state.hookQuery ?? builder); } const softDelete = getSoftDelete(builder); @@ -26,14 +27,14 @@ export async function deleteImpl( return state.baseQuery.delete(); } -export function withDeletedImpl(builder: SchemaQueryBuilder): any { +export function withDeletedImpl(builder: QuerySource): any { const state = getState(builder); invalidateCache(builder); state.includeDeleted = true; return builder; } -export function onlyDeletedImpl(builder: SchemaQueryBuilder): any { +export function onlyDeletedImpl(builder: QuerySource): any { const state = getState(builder); invalidateCache(builder); state.onlyDeleted = true; @@ -42,7 +43,7 @@ export function onlyDeletedImpl(builder: SchemaQueryBuilder): any { } export async function hardDeleteImpl( - builder: SchemaQueryBuilder + builder: QuerySource ): Promise { const state = getState(builder); const hooks = @@ -50,13 +51,13 @@ export async function hardDeleteImpl( | Function[] | undefined) ?? []; for (const hook of hooks) { - await hook(builder); + await hook(state.hookQuery ?? builder); } return state.baseQuery.delete(); } export async function restoreImpl( - builder: SchemaQueryBuilder + builder: QuerySource ): Promise { const state = getState(builder); const softDelete = getSoftDelete(builder); @@ -67,6 +68,6 @@ export async function restoreImpl( } const rows = await state.baseQuery .update({ [softDelete.column]: null }) - .returning('*'); + .returning(returningReadColumns(state.knex, state.localSchema)); return rows.map((row: any) => mapRow(builder, row)); } diff --git a/libs/knex-schema/src/operations/helpers.ts b/libs/knex-schema/src/operations/helpers.ts index f47c5ad9..a39c1c01 100644 --- a/libs/knex-schema/src/operations/helpers.ts +++ b/libs/knex-schema/src/operations/helpers.ts @@ -1,4 +1,4 @@ -// @cleverbrush/knex-schema — Extracted helper functions from SchemaQueryBuilder +// @cleverbrush/knex-schema — Extracted helper functions from QuerySource import type { InferType } from '@cleverbrush/schema'; import { @@ -19,7 +19,7 @@ import { POLYMORPHIC_TYPE_BRAND } from '../extension.js'; import { clearRow } from '../mappers.js'; -import type { SchemaQueryBuilder } from '../SchemaQueryBuilder.js'; +import type { QuerySource } from '../QuerySource.js'; import type { ColumnRef, ResolvedVariantConfig, @@ -65,7 +65,7 @@ export type QueryResultType = TLocalSchema extends { // --------------------------------------------------------------------------- export function resolveColumn( - builder: SchemaQueryBuilder, + builder: QuerySource, ref: any, label = 'column' ): string | Knex.Raw { @@ -78,12 +78,12 @@ export function resolveColumn( ); } -export function invalidateCache(builder: SchemaQueryBuilder): void { +export function invalidateCache(builder: QuerySource): void { getState(builder).cachedBuiltQuery = null; } export function getSoftDelete( - builder: SchemaQueryBuilder + builder: QuerySource ): { column: string } | null { const state = getState(builder); const ext = (state.localSchema as any).getExtension?.('softDelete'); @@ -91,7 +91,7 @@ export function getSoftDelete( } export function getDefaultScope( - builder: SchemaQueryBuilder + builder: QuerySource ): Function | null { const state = getState(builder); const fn = (state.localSchema as any).getExtension?.('defaultScope'); @@ -99,7 +99,7 @@ export function getDefaultScope( } export function getTimestamps( - builder: SchemaQueryBuilder + builder: QuerySource ): { createdAt: string; updatedAt: string } | null { const state = getState(builder); const ts = (state.localSchema as any).getExtension?.('timestamps'); @@ -127,7 +127,7 @@ const ALLOWED_OPS = new Set([ export { ALLOWED_OPS }; export function getVariantConfig( - builder: SchemaQueryBuilder + builder: QuerySource ): ResolvedVariantConfig | null { const state = getState(builder); if (state.variantConfig !== undefined) return state.variantConfig; @@ -149,7 +149,7 @@ export function getVariantConfig( } export function applyVariantJoins( - builder: SchemaQueryBuilder, + builder: QuerySource, base: Knex.QueryBuilder, variantConfig: ResolvedVariantConfig ): Knex.QueryBuilder { @@ -289,24 +289,22 @@ export function applyVariantJoins( return qb; } -// Circular-dependency-safe SchemaQueryBuilder constructor reference -// Set by SchemaQueryBuilder.ts after the class is defined. -let SchemaQueryBuilderCtor: new (...args: any[]) => any = null!; -export function registerSchemaQueryBuilder( - ctor: new (...args: any[]) => any -): void { - SchemaQueryBuilderCtor = ctor; +// Circular-dependency-safe QuerySource constructor reference +// Set by QuerySource.ts after the class is defined. +let QuerySourceCtor: new (...args: any[]) => any = null!; +export function registerQuerySource(ctor: new (...args: any[]) => any): void { + QuerySourceCtor = ctor; } -export function getSchemaQueryBuilderCtor(): new (...args: any[]) => any { - return SchemaQueryBuilderCtor; +export function getQuerySourceCtor(): new (...args: any[]) => any { + return QuerySourceCtor; } export function buildVariantRelationSelect( - builder: SchemaQueryBuilder, + builder: QuerySource, foreignSchema: ObjectSchemaBuilder, relAlias: string, foreignTableName: string, - customize?: (q: SchemaQueryBuilder) => void + customize?: (q: QuerySource) => void ): Knex.Raw[] { const state = getState(builder); const knex = state.knex; @@ -318,7 +316,7 @@ export function buildVariantRelationSelect( let columnsToSelect: string[]; if (customize) { - const probe = new (SchemaQueryBuilderCtor as any)( + const probe = new (QuerySourceCtor as any)( state.knex, foreignSchema, state.knex(foreignTableName) @@ -348,7 +346,7 @@ export function buildVariantRelationSelect( } export function mapPolymorphicRow( - builder: SchemaQueryBuilder, + builder: QuerySource, row: Record, variantConfig: ResolvedVariantConfig ): Record { @@ -458,14 +456,14 @@ export function mapPolymorphicRow( } export function resolveSchema( - _builder: SchemaQueryBuilder, + _builder: QuerySource, schema: any ): ObjectSchemaBuilder { return typeof schema === 'function' ? schema() : schema; } export function findPrimaryKeyColumn( - _builder: SchemaQueryBuilder, + _builder: QuerySource, schema: ObjectSchemaBuilder ): string { const pk = getPrimaryKeyColumns(schema); @@ -473,7 +471,7 @@ export function findPrimaryKeyColumn( return 'id'; } -export function resolvePkColumns(builder: SchemaQueryBuilder): { +export function resolvePkColumns(builder: QuerySource): { propertyKeys: readonly string[]; columnNames: readonly string[]; } { @@ -488,7 +486,7 @@ export function resolvePkColumns(builder: SchemaQueryBuilder): { } export function getEffectiveBaseQuery( - builder: SchemaQueryBuilder + builder: QuerySource ): Knex.QueryBuilder { const state = getState(builder); let effectiveBase = state.baseQuery; @@ -516,7 +514,7 @@ export function getEffectiveBaseQuery( effectiveBase = effectiveBase.clone(); cloned = true; } - const proxy = new (SchemaQueryBuilderCtor as any)( + const proxy = new (QuerySourceCtor as any)( state.knex, state.localSchema, effectiveBase @@ -531,7 +529,7 @@ export function getEffectiveBaseQuery( } export function buildJoinOne( - builder: SchemaQueryBuilder, + builder: QuerySource, resultQuery: Knex.QueryBuilder, spec: ValidatedSpec & { type: 'one' }, relationAlias: string @@ -592,7 +590,7 @@ export function buildJoinOne( } export function buildJoinMany( - builder: SchemaQueryBuilder, + builder: QuerySource, resultQuery: Knex.QueryBuilder, spec: ValidatedSpec & { type: 'many' }, relationAlias: string, @@ -738,9 +736,7 @@ export function buildJoinMany( }); } -export function buildQuery( - builder: SchemaQueryBuilder -): Knex.QueryBuilder { +export function buildQuery(builder: QuerySource): Knex.QueryBuilder { const state = getState(builder); const effectiveBase = getEffectiveBaseQuery(builder); @@ -853,9 +849,7 @@ export function buildQuery( return resultQuery; } -export function getQuery( - builder: SchemaQueryBuilder -): Knex.QueryBuilder { +export function getQuery(builder: QuerySource): Knex.QueryBuilder { const state = getState(builder); if (!state.cachedBuiltQuery) { state.cachedBuiltQuery = buildQuery(builder); @@ -864,7 +858,7 @@ export function getQuery( } export function mapRow( - builder: SchemaQueryBuilder, + builder: QuerySource, row: Record ): Record { if (!row) return row; @@ -887,11 +881,11 @@ export function mapRow( } } - return result; + return state.decodeRow ? state.decodeRow(result) : result; } export function cleanAndMapRow( - builder: SchemaQueryBuilder, + builder: QuerySource, row: Record ): Record { const state = getState(builder); @@ -911,7 +905,7 @@ export function cleanAndMapRow( } export function mapObjectToColumns( - builder: SchemaQueryBuilder, + builder: QuerySource, obj: Record ): Record { const state = getState(builder); @@ -931,14 +925,14 @@ export function mapObjectToColumns( } export function mapRecordToColumns( - builder: SchemaQueryBuilder, + builder: QuerySource, record: Record ): Record { return mapObjectToColumns(builder, record); } export function resolveColumnArg( - builder: SchemaQueryBuilder, + builder: QuerySource, col: any ): string | Knex.Raw { if (typeof col === 'string') { @@ -951,7 +945,7 @@ export function resolveColumnArg( } export function isColumnAccessor( - builder: SchemaQueryBuilder, + builder: QuerySource, fn: Function ): boolean { const state = getState(builder); @@ -972,7 +966,7 @@ export function isColumnAccessor( } export function assertNotProjection( - builder: SchemaQueryBuilder, + builder: QuerySource, method: string ): void { const state = getState(builder); @@ -986,7 +980,7 @@ export function assertNotProjection( } export function assertNotExplicitSelect( - builder: SchemaQueryBuilder, + builder: QuerySource, method: string ): void { const state = getState(builder); diff --git a/libs/knex-schema/src/operations/insert.ts b/libs/knex-schema/src/operations/insert.ts index 83b18033..8595f497 100644 --- a/libs/knex-schema/src/operations/insert.ts +++ b/libs/knex-schema/src/operations/insert.ts @@ -4,7 +4,8 @@ import type { InferType, ObjectSchemaBuilder } from '@cleverbrush/schema'; import type { Knex } from 'knex'; import { buildColumnMap, resolveColumnRef } from '../columns.js'; import { getTableName } from '../extension.js'; -import type { SchemaQueryBuilder } from '../SchemaQueryBuilder.js'; +import type { QuerySource } from '../QuerySource.js'; +import { returningReadColumns } from '../read-schema.js'; import type { ColumnRef, InsertType } from '../types.js'; import { getTimestamps, @@ -82,12 +83,13 @@ export interface OnConflictMergeOptions { } /** - * Configure one-row conflict handling after SchemaQueryBuilder.onConflict(); merge()/ignore() execute the insert. + * Configure one-row conflict handling after QuerySource.onConflict(); merge()/ignore() execute the insert. */ export class OnConflictBuilder { readonly #knex: Knex; readonly #localSchema: TLocalSchema; readonly #conflictColumns: string[]; + readonly #decodeRow?: (row: Record) => Record; /** * Create conflict handling for a schema and resolved conflict columns. @@ -96,12 +98,13 @@ export class OnConflictBuilder { constructor( knex: Knex, localSchema: TLocalSchema, - _parent: SchemaQueryBuilder, + _parent: QuerySource, conflictColumns: string[] ) { this.#knex = knex; this.#localSchema = localSchema; this.#conflictColumns = conflictColumns; + this.#decodeRow = getState(_parent).decodeRow; } /** @@ -221,7 +224,9 @@ export class OnConflictBuilder { options?.where?.(qb as unknown as Knex.QueryBuilder, helpers); } - const rows = await (qb as any).returning('*'); + const rows = await (qb as any).returning( + returningReadColumns(this.#knex, this.#localSchema) + ); if (!rows || rows.length === 0) return undefined; const { colToProp } = buildColumnMap(this.#localSchema as any); @@ -229,7 +234,7 @@ export class OnConflictBuilder { for (const [col, val] of Object.entries(rows[0])) { result[colToProp.get(col) ?? col] = val; } - return result as TResult; + return (this.#decodeRow ? this.#decodeRow(result) : result) as TResult; } #createMergeHelpers(): OnConflictMergeHelpers { @@ -273,7 +278,7 @@ function isMergeOptions( // --------------------------------------------------------------------------- export async function insertImpl( - builder: SchemaQueryBuilder, + builder: QuerySource, data: InsertType ): Promise { const state = getState(builder); @@ -299,7 +304,7 @@ export async function insertImpl( const [row] = await state .knex(state.tableName) .insert(mapped) - .returning('*'); + .returning(returningReadColumns(state.knex, state.localSchema)); const result = mapRow(builder, row); const afterHooks = @@ -314,7 +319,7 @@ export async function insertImpl( } export async function insertManyImpl( - builder: SchemaQueryBuilder, + builder: QuerySource, data: InsertType[] ): Promise { const state = getState(builder); @@ -341,7 +346,7 @@ export async function insertManyImpl( const rows = await state .knex(state.tableName) .insert(mapped) - .returning('*'); + .returning(returningReadColumns(state.knex, state.localSchema)); const results = rows.map((row: any) => mapRow(builder, row)); const afterHooks = @@ -358,7 +363,7 @@ export async function insertManyImpl( } export function onConflictImpl( - builder: SchemaQueryBuilder, + builder: QuerySource, ...conflictColumns: ColumnRef[] ): OnConflictBuilder { const state = getState(builder); @@ -369,7 +374,7 @@ export function onConflictImpl( } export async function upsertImpl( - builder: SchemaQueryBuilder, + builder: QuerySource, data: InsertType, opts: { conflictColumns: ColumnRef[]; @@ -395,12 +400,14 @@ export async function upsertImpl( (qb as any).merge(); } - const [row] = await (qb as any).returning('*'); + const [row] = await (qb as any).returning( + returningReadColumns(state.knex, state.localSchema) + ); return mapRow(builder, row); } export async function bulkInsertImpl( - builder: SchemaQueryBuilder, + builder: QuerySource, rows: InsertType[], opts?: { chunkSize?: number; @@ -485,7 +492,9 @@ export async function bulkInsertImpl( } } - const inserted: any[] = await qb.returning('*'); + const inserted: any[] = await qb.returning( + returningReadColumns(state.knex, state.localSchema) + ); for (const row of inserted) { const mappedRow = mapRow(builder, row); for (const hook of afterHooks) { @@ -499,7 +508,7 @@ export async function bulkInsertImpl( } export async function bulkUpsertImpl( - builder: SchemaQueryBuilder, + builder: QuerySource, rows: InsertType[], opts: { conflictColumns: ColumnRef[]; diff --git a/libs/knex-schema/src/operations/join.ts b/libs/knex-schema/src/operations/join.ts index b1390aae..617107c7 100644 --- a/libs/knex-schema/src/operations/join.ts +++ b/libs/knex-schema/src/operations/join.ts @@ -3,7 +3,7 @@ import type { Knex } from 'knex'; import { resolveColumnRef } from '../columns.js'; import { getTableName } from '../extension.js'; -import type { SchemaQueryBuilder } from '../SchemaQueryBuilder.js'; +import type { QuerySource } from '../QuerySource.js'; import type { JoinManySpec, JoinOneSpec, @@ -17,7 +17,7 @@ import { } from '../validate.js'; import { findPrimaryKeyColumn, - getSchemaQueryBuilderCtor, + getQuerySourceCtor, getVariantConfig, invalidateCache, resolveSchema @@ -25,7 +25,7 @@ import { import { getState } from './state.js'; export function joinOneImpl( - builder: SchemaQueryBuilder, + builder: QuerySource, spec: JoinOneSpec ): any { const state = getState(builder); @@ -37,7 +37,7 @@ export function joinOneImpl( } export function joinManyImpl( - builder: SchemaQueryBuilder, + builder: QuerySource, spec: JoinManySpec ): any { const state = getState(builder); @@ -49,9 +49,9 @@ export function joinManyImpl( } export function includeImpl( - builder: SchemaQueryBuilder, + builder: QuerySource, relationName: string, - customize?: (q: SchemaQueryBuilder) => void + customize?: (q: QuerySource) => void ): any { const state = getState(builder); invalidateCache(builder); @@ -110,7 +110,7 @@ export function includeImpl( const foreignQuery1: Knex.QueryBuilder = state.knex(foreignTableName); if (customize) { - const SQB = getSchemaQueryBuilderCtor(); + const SQB = getQuerySourceCtor(); const proxy = new SQB(state.knex, foreignSchema, foreignQuery1); customize(proxy); } @@ -138,7 +138,7 @@ export function includeImpl( const foreignQuery2: Knex.QueryBuilder = state.knex(foreignTableName); if (customize) { - const SQB = getSchemaQueryBuilderCtor(); + const SQB = getQuerySourceCtor(); const proxy = new SQB(state.knex, foreignSchema, foreignQuery2); customize(proxy); } @@ -167,7 +167,7 @@ export function includeImpl( const foreignQuery3: Knex.QueryBuilder = state.knex(foreignTableName); if (customize) { - const SQB = getSchemaQueryBuilderCtor(); + const SQB = getQuerySourceCtor(); const proxy = new SQB(state.knex, foreignSchema, foreignQuery3); customize(proxy); } @@ -201,7 +201,7 @@ export function includeImpl( ); if (customize) { - const SQB = getSchemaQueryBuilderCtor(); + const SQB = getQuerySourceCtor(); const proxy = new SQB(state.knex, foreignSchema, foreignQuery); customize(proxy); } @@ -221,10 +221,10 @@ export function includeImpl( } export function includeVariantImpl( - builder: SchemaQueryBuilder, + builder: QuerySource, variantKey: string, relationName: string, - customize?: (q: SchemaQueryBuilder) => void + customize?: (q: QuerySource) => void ): any { const state = getState(builder); invalidateCache(builder); diff --git a/libs/knex-schema/src/operations/pagination.ts b/libs/knex-schema/src/operations/pagination.ts index 5968b16b..b3ad95d6 100644 --- a/libs/knex-schema/src/operations/pagination.ts +++ b/libs/knex-schema/src/operations/pagination.ts @@ -1,7 +1,7 @@ // @cleverbrush/knex-schema — Pagination (offset & cursor-based) import { resolvePropertyKey } from '../columns.js'; -import type { SchemaQueryBuilder } from '../SchemaQueryBuilder.js'; +import type { QuerySource } from '../QuerySource.js'; import type { ColumnRef, CursorPaginationResult, @@ -16,20 +16,14 @@ import { import { getState } from './state.js'; import { orderByImpl, whereImpl } from './where.js'; -export function limitImpl( - builder: SchemaQueryBuilder, - n: number -): any { +export function limitImpl(builder: QuerySource, n: number): any { const state = getState(builder); invalidateCache(builder); state.baseQuery.limit(n); return builder; } -export function offsetImpl( - builder: SchemaQueryBuilder, - n: number -): any { +export function offsetImpl(builder: QuerySource, n: number): any { const state = getState(builder); invalidateCache(builder); state.baseQuery.offset(n); @@ -37,7 +31,7 @@ export function offsetImpl( } export async function paginateImpl( - builder: SchemaQueryBuilder, + builder: QuerySource, opts: { page: number; pageSize: number; @@ -74,7 +68,7 @@ export async function paginateImpl( } export async function paginateAfterImpl( - builder: SchemaQueryBuilder, + builder: QuerySource, opts: { cursor?: any; limit: number; @@ -112,7 +106,7 @@ export async function paginateAfterImpl( } export async function executeImpl( - builder: SchemaQueryBuilder + builder: QuerySource ): Promise { const query = getQuery(builder); const rows = await query; diff --git a/libs/knex-schema/src/operations/select.ts b/libs/knex-schema/src/operations/select.ts index 223631bc..5c62e018 100644 --- a/libs/knex-schema/src/operations/select.ts +++ b/libs/knex-schema/src/operations/select.ts @@ -8,7 +8,7 @@ import type { Knex } from 'knex'; import { buildColumnMap } from '../columns.js'; import { compileAggregate, isAggregate } from '../expressions.js'; import { getProjections } from '../extension.js'; -import type { SchemaQueryBuilder } from '../SchemaQueryBuilder.js'; +import type { QuerySource } from '../QuerySource.js'; import type { ColumnRef } from '../types.js'; import { assertNotExplicitSelect, @@ -20,7 +20,7 @@ import { import { getState } from './state.js'; export function selectImpl( - builder: SchemaQueryBuilder, + builder: QuerySource, ...args: unknown[] ): any { const state = getState(builder); @@ -104,7 +104,7 @@ export function selectImpl( } export function distinctImpl( - builder: SchemaQueryBuilder, + builder: QuerySource, ...columns: (ColumnRef | Knex.Raw)[] ): any { invalidateCache(builder); @@ -114,7 +114,7 @@ export function distinctImpl( } export function countImpl( - builder: SchemaQueryBuilder, + builder: QuerySource, column?: ColumnRef | Knex.Raw ): any { const state = getState(builder); @@ -130,7 +130,7 @@ export function countImpl( } export function countDistinctImpl( - builder: SchemaQueryBuilder, + builder: QuerySource, column?: ColumnRef | Knex.Raw ): any { const state = getState(builder); @@ -148,7 +148,7 @@ export function countDistinctImpl( } export function minImpl( - builder: SchemaQueryBuilder, + builder: QuerySource, column: ColumnRef | Knex.Raw ): any { const state = getState(builder); @@ -160,7 +160,7 @@ export function minImpl( } export function maxImpl( - builder: SchemaQueryBuilder, + builder: QuerySource, column: ColumnRef | Knex.Raw ): any { const state = getState(builder); @@ -172,7 +172,7 @@ export function maxImpl( } export function sumImpl( - builder: SchemaQueryBuilder, + builder: QuerySource, column: ColumnRef | Knex.Raw ): any { const state = getState(builder); @@ -184,7 +184,7 @@ export function sumImpl( } export function avgImpl( - builder: SchemaQueryBuilder, + builder: QuerySource, column: ColumnRef | Knex.Raw ): any { const state = getState(builder); @@ -196,7 +196,7 @@ export function avgImpl( } export function selectRawImpl( - builder: SchemaQueryBuilder, + builder: QuerySource, sql: string, bindings?: any[] ): any { @@ -211,7 +211,7 @@ export function selectRawImpl( } export function projectedImpl( - builder: SchemaQueryBuilder, + builder: QuerySource, name: string ): any { const state = getState(builder); @@ -245,10 +245,7 @@ export function projectedImpl( return builder; } -export function scopedImpl( - builder: SchemaQueryBuilder, - name: string -): any { +export function scopedImpl(builder: QuerySource, name: string): any { const state = getState(builder); invalidateCache(builder); const scopes = (state.localSchema as any).getExtension?.('scopes') as @@ -264,7 +261,7 @@ export function scopedImpl( return builder; } -export function unscopedImpl(builder: SchemaQueryBuilder): any { +export function unscopedImpl(builder: QuerySource): any { const state = getState(builder); invalidateCache(builder); state.skipDefaultScope = true; diff --git a/libs/knex-schema/src/operations/state.ts b/libs/knex-schema/src/operations/state.ts index c71645fa..42c8a211 100644 --- a/libs/knex-schema/src/operations/state.ts +++ b/libs/knex-schema/src/operations/state.ts @@ -1,8 +1,8 @@ -// @cleverbrush/knex-schema — Shared mutable state store for SchemaQueryBuilder +// @cleverbrush/knex-schema — Shared mutable state store for QuerySource import type { ObjectSchemaBuilder } from '@cleverbrush/schema'; import type { Knex } from 'knex'; -import type { SchemaQueryBuilder } from '../SchemaQueryBuilder.js'; +import type { QuerySource } from '../QuerySource.js'; import type { ResolvedVariantConfig, ValidatedSpec, @@ -10,6 +10,8 @@ import type { } from '../types.js'; export interface QueryBuilderState { + /** Decode write-returning property rows before lifecycle hooks observe them. */ + decodeRow?: (row: Record) => Record; /** Raw callbacks have no statically declared result shape for opt-in reads. */ opaqueReadShape?: boolean; knex: Knex; @@ -31,6 +33,9 @@ export interface QueryBuilderState { projectionDecoders: Record unknown>; hiddenColumns: Set; + /** Immutable public query snapshot supplied to observational delete hooks. */ + hookQuery?: unknown; + /** When true, soft-delete filter is NOT applied. */ includeDeleted: boolean; @@ -53,29 +58,27 @@ export interface QueryBuilderState { variantRelationIncludes: Array<{ variantKey: string; relationName: string; - customize?: (q: SchemaQueryBuilder) => void; + customize?: (q: QuerySource) => void; }>; /** Memoized result of buildQuery(). null = needs rebuild. */ cachedBuiltQuery: Knex.QueryBuilder | null; } -const STATE = new WeakMap, QueryBuilderState>(); +const STATE = new WeakMap, QueryBuilderState>(); -export function getState( - builder: SchemaQueryBuilder -): QueryBuilderState { +export function getState(builder: QuerySource): QueryBuilderState { const s = STATE.get(builder); if (!s) { throw new Error( - 'SchemaQueryBuilder state not found — builder was not properly initialized' + 'QuerySource state not found — builder was not properly initialized' ); } return s; } export function setState( - builder: SchemaQueryBuilder, + builder: QuerySource, state: QueryBuilderState ): void { STATE.set(builder, state); diff --git a/libs/knex-schema/src/operations/update.ts b/libs/knex-schema/src/operations/update.ts index ba89037a..c65461de 100644 --- a/libs/knex-schema/src/operations/update.ts +++ b/libs/knex-schema/src/operations/update.ts @@ -3,7 +3,8 @@ import type { InferType } from '@cleverbrush/schema'; import type { Knex } from 'knex'; import { buildColumnMap } from '../columns.js'; -import type { SchemaQueryBuilder } from '../SchemaQueryBuilder.js'; +import type { QuerySource } from '../QuerySource.js'; +import { returningReadColumns } from '../read-schema.js'; import { getTimestamps, mapObjectToColumns, @@ -13,7 +14,7 @@ import { import { getState } from './state.js'; export async function updateImpl( - builder: SchemaQueryBuilder, + builder: QuerySource, data: Partial> ): Promise { const state = getState(builder); @@ -35,12 +36,14 @@ export async function updateImpl( mapped[timestamps.updatedAt] = state.knex.fn.now(); } - const rows = await state.baseQuery.update(mapped).returning('*'); + const rows = await state.baseQuery + .update(mapped) + .returning(returningReadColumns(state.knex, state.localSchema)); return rows.map((row: any) => mapRow(builder, row)); } export async function bulkUpdateImpl( - builder: SchemaQueryBuilder, + builder: QuerySource, updates: ReadonlyArray<{ where: Partial>; set: Partial>; @@ -124,7 +127,8 @@ export async function bulkUpdateImpl( ] as any); } - let qb: any = knex(state.tableName).update(updateExpr); + // Preserve the immutable caller's captured visibility and predicates. + let qb: any = state.baseQuery.clone().update(updateExpr); if (pk.columnNames.length === 1) { qb = qb.whereIn( pk.columnNames[0], diff --git a/libs/knex-schema/src/operations/where.ts b/libs/knex-schema/src/operations/where.ts index 51c77f74..2163c113 100644 --- a/libs/knex-schema/src/operations/where.ts +++ b/libs/knex-schema/src/operations/where.ts @@ -1,7 +1,7 @@ // @cleverbrush/knex-schema — WHERE / ORDER BY / GROUP BY / HAVING operations import type { Knex } from 'knex'; -import type { SchemaQueryBuilder } from '../SchemaQueryBuilder.js'; +import type { QuerySource } from '../QuerySource.js'; import type { ColumnRef } from '../types.js'; import { invalidateCache, @@ -13,7 +13,7 @@ import { import { getState } from './state.js'; export function whereImpl( - builder: SchemaQueryBuilder, + builder: QuerySource, columnOrRaw: any, ...args: any[] ): any { @@ -42,7 +42,7 @@ export function whereImpl( } export function andWhereImpl( - builder: SchemaQueryBuilder, + builder: QuerySource, columnOrRaw: any, ...args: any[] ): any { @@ -71,7 +71,7 @@ export function andWhereImpl( } export function orWhereImpl( - builder: SchemaQueryBuilder, + builder: QuerySource, columnOrRaw: any, ...args: any[] ): any { @@ -100,7 +100,7 @@ export function orWhereImpl( } export function whereNotImpl( - builder: SchemaQueryBuilder, + builder: QuerySource, columnOrRaw: any, ...args: any[] ): any { @@ -129,7 +129,7 @@ export function whereNotImpl( } export function whereInImpl( - builder: SchemaQueryBuilder, + builder: QuerySource, column: ColumnRef, values: readonly any[] | Knex.QueryBuilder ): any { @@ -143,7 +143,7 @@ export function whereInImpl( } export function whereNotInImpl( - builder: SchemaQueryBuilder, + builder: QuerySource, column: ColumnRef, values: readonly any[] | Knex.QueryBuilder ): any { @@ -157,7 +157,7 @@ export function whereNotInImpl( } export function orWhereInImpl( - builder: SchemaQueryBuilder, + builder: QuerySource, column: ColumnRef, values: readonly any[] | Knex.QueryBuilder ): any { @@ -171,7 +171,7 @@ export function orWhereInImpl( } export function orWhereNotInImpl( - builder: SchemaQueryBuilder, + builder: QuerySource, column: ColumnRef, values: readonly any[] | Knex.QueryBuilder ): any { @@ -185,7 +185,7 @@ export function orWhereNotInImpl( } export function whereNullImpl( - builder: SchemaQueryBuilder, + builder: QuerySource, column: ColumnRef ): any { const state = getState(builder); @@ -197,7 +197,7 @@ export function whereNullImpl( } export function whereNotNullImpl( - builder: SchemaQueryBuilder, + builder: QuerySource, column: ColumnRef ): any { const state = getState(builder); @@ -209,7 +209,7 @@ export function whereNotNullImpl( } export function orWhereNullImpl( - builder: SchemaQueryBuilder, + builder: QuerySource, column: ColumnRef ): any { const state = getState(builder); @@ -221,7 +221,7 @@ export function orWhereNullImpl( } export function orWhereNotNullImpl( - builder: SchemaQueryBuilder, + builder: QuerySource, column: ColumnRef ): any { const state = getState(builder); @@ -233,7 +233,7 @@ export function orWhereNotNullImpl( } export function whereBetweenImpl( - builder: SchemaQueryBuilder, + builder: QuerySource, column: ColumnRef, range: readonly [any, any] ): any { @@ -247,7 +247,7 @@ export function whereBetweenImpl( } export function whereNotBetweenImpl( - builder: SchemaQueryBuilder, + builder: QuerySource, column: ColumnRef, range: readonly [any, any] ): any { @@ -261,7 +261,7 @@ export function whereNotBetweenImpl( } export function whereLikeImpl( - builder: SchemaQueryBuilder, + builder: QuerySource, column: ColumnRef, value: string ): any { @@ -275,7 +275,7 @@ export function whereLikeImpl( } export function whereILikeImpl( - builder: SchemaQueryBuilder, + builder: QuerySource, column: ColumnRef, value: string ): any { @@ -289,7 +289,7 @@ export function whereILikeImpl( } export function whereRawImpl( - builder: SchemaQueryBuilder, + builder: QuerySource, sql: string, ...bindings: any[] ): any { @@ -300,7 +300,7 @@ export function whereRawImpl( } export function whereExistsImpl( - builder: SchemaQueryBuilder, + builder: QuerySource, callback: Knex.QueryCallback | Knex.QueryBuilder ): any { const state = getState(builder); @@ -310,7 +310,7 @@ export function whereExistsImpl( } export function whereNotExistsImpl( - builder: SchemaQueryBuilder, + builder: QuerySource, callback: Knex.QueryCallback | Knex.QueryBuilder ): any { const state = getState(builder); @@ -320,7 +320,7 @@ export function whereNotExistsImpl( } export function whereJsonPathImpl( - builder: SchemaQueryBuilder, + builder: QuerySource, column: ColumnRef, path: string, operator?: string, @@ -356,7 +356,7 @@ export function whereJsonPathImpl( } export function orderByImpl( - builder: SchemaQueryBuilder, + builder: QuerySource, column: ColumnRef | Knex.Raw, direction?: 'asc' | 'desc' ): any { @@ -368,7 +368,7 @@ export function orderByImpl( } export function orderByRawImpl( - builder: SchemaQueryBuilder, + builder: QuerySource, sql: string, ...bindings: any[] ): any { @@ -379,7 +379,7 @@ export function orderByRawImpl( } export function groupByImpl( - builder: SchemaQueryBuilder, + builder: QuerySource, ...columns: (ColumnRef | Knex.Raw)[] ): any { const state = getState(builder); @@ -390,7 +390,7 @@ export function groupByImpl( } export function groupByRawImpl( - builder: SchemaQueryBuilder, + builder: QuerySource, sql: string, ...bindings: any[] ): any { @@ -401,7 +401,7 @@ export function groupByRawImpl( } export function havingImpl( - builder: SchemaQueryBuilder, + builder: QuerySource, column: ColumnRef | Knex.Raw, operator: string, value: any @@ -414,7 +414,7 @@ export function havingImpl( } export function havingRawImpl( - builder: SchemaQueryBuilder, + builder: QuerySource, sql: string, ...bindings: any[] ): any { diff --git a/libs/knex-schema/src/orm-extensions.test.ts b/libs/knex-schema/src/orm-extensions.test.ts index bc7d113e..f946a764 100644 --- a/libs/knex-schema/src/orm-extensions.test.ts +++ b/libs/knex-schema/src/orm-extensions.test.ts @@ -76,12 +76,14 @@ describe('SchemaQueryBuilder.select(selector) — DTO projection', () => { query(knex, User).select(_t => ({ bogus: 'not-a-descriptor' as any })) - ).toThrow(/property descriptor/); + ).toThrow(/does not belong/); }); it('still supports the existing column-list overload', () => { const sql = query(knex, User).select('id', 'name').toQuery(); - expect(sql).toContain('select "id", "name"'); + expect(sql).toMatch( + /select "__schema_read_\d+"\."id" as "id", "__schema_read_\d+"\."name" as "name"/ + ); }); }); diff --git a/libs/knex-schema/src/orm.test.ts b/libs/knex-schema/src/orm.test.ts index 5d9e00b8..174df58a 100644 --- a/libs/knex-schema/src/orm.test.ts +++ b/libs/knex-schema/src/orm.test.ts @@ -3,6 +3,7 @@ import Knex from 'knex'; import { afterAll, describe, expect, expectTypeOf, it, vi } from 'vitest'; import { + array, boolean, date, defineEntity, @@ -317,7 +318,9 @@ describe('DDL extensions', () => { }); it('string.jsonb() shorthand stores columnType', () => { - const schema = object({ meta: string().jsonb() }).hasTableName('test'); + const schema = object({ + meta: object({ status: string() }).jsonb() + }).hasTableName('test'); const ext = (schema.introspect() as any).properties.meta.introspect() .extensions; expect(ext.columnType).toBe('jsonb'); @@ -484,7 +487,7 @@ describe('generateCreateTable', () => { id: number().primaryKey(), count: number().bigint(), externalId: string().asUuid(), - meta: string().jsonb(), + meta: object({ status: string() }).jsonb(), price: number().decimal(10, 2), createdAt: date().timestamptz(), birthDate: date().dateOnly() @@ -599,55 +602,64 @@ describe('relation metadata', () => { // ═══════════════════════════════════════════════════════════════════════════ describe('include()', () => { - const PostWithRelations = Post.belongsTo('author', { - schema: User, - foreignKey: (t: any) => t.authorId - }); + const PostWithRelations = defineEntity( + Post.addProp('author', User.optional()) + ).belongsTo( + t => t.author, + t => t.authorId, + u => u.id + ).schema; it('include belongsTo generates joinOne SQL', () => { const sql = query(knex, PostWithRelations).include('author').toQuery(); - expect(sql).toContain('originalQuery'); + expect(sql).toContain('to_jsonb'); expect(sql).toContain('"users"'); expect(sql).toContain('"author"'); }); it('include category belongsTo generates joinOne SQL', () => { - const PostWithCategory = Post.belongsTo('category', { - schema: Category, - foreignKey: (t: any) => t.categoryId - }); + const PostWithCategory = defineEntity( + Post.addProp('category', Category.optional()) + ).belongsTo( + t => t.category, + t => t.categoryId, + c => c.id + ).schema; const sql = query(knex, PostWithCategory).include('category').toQuery(); - expect(sql).toContain('originalQuery'); + expect(sql).toContain('to_jsonb'); expect(sql).toContain('"categories"'); expect(sql).toContain('"category"'); }); it('include throws for unknown relation', () => { expect(() => + // @ts-expect-error runtime guard for an undeclared relation query(knex, PostWithRelations).include('nonexistent') - ).toThrow('Unknown relation "nonexistent"'); + ).toThrow('Unknown relation: nonexistent'); }); it('hasMany include generates joinMany SQL', () => { - const UserWithPosts = User.hasMany('posts', { - schema: Post, - foreignKey: (t: any) => t.authorId - }); + const UserWithPosts = defineEntity( + User.addProp('posts', array(Post).optional()) + ).hasMany( + u => u.posts, + u => u.id, + p => p.authorId + ).schema; const sql = query(knex, UserWithPosts).include('posts').toQuery(); - expect(sql).toContain('originalQuery'); + expect(sql).toContain('to_jsonb'); expect(sql).toContain('"posts"'); }); it('belongsToMany include generates pivot join SQL', () => { - const PostWithTags = Post.belongsToMany('tags', { - schema: Tag, - through: { - table: 'post_tags', - localKey: 'post_id', - foreignKey: 'tag_id' - } - }); + const PostWithTags = defineEntity( + Post.addProp('tags', array(Tag).optional()) + ).belongsToMany(p => p.tags, { + table: 'post_tags', + localKey: 'post_id', + foreignKey: 'tag_id' + }).schema; const sql = query(knex, PostWithTags).include('tags').toQuery(); expect(sql).toContain('post_tags'); @@ -698,9 +710,9 @@ describe('soft delete', () => { expect(sql).toContain('"deleted_at" is not null'); }); - it('unscoped() removes soft delete filter', () => { + it('unscoped() preserves the independent soft delete filter', () => { const sql = query(knex, SoftPost).unscoped().toQuery(); - expect(sql).not.toContain('deleted_at'); + expect(sql).toContain('"deleted_at" is null'); }); it('delete() generates UPDATE for soft-delete schemas', () => { @@ -807,7 +819,7 @@ describe('scopes', () => { expect(() => // @ts-expect-error — 'nonexistent' is not a registered scope name query(knex, ScopedPost).scoped('nonexistent') - ).toThrow('Unknown scope "nonexistent"'); + ).toThrow('Unknown scope: nonexistent'); }); it('scoped() type: only registered scope names are accepted', () => { @@ -834,7 +846,7 @@ describe('scopes', () => { it('unscoped() bypasses default scope', () => { const sql = query(knex, ScopedPost).unscoped().toQuery(); - expect(sql).not.toContain('is_active'); + expect(sql).not.toContain('"is_active" = true'); }); }); @@ -912,7 +924,7 @@ describe('projections', () => { expect(() => // @ts-expect-error — 'bogus' is not a registered projection name query(knex, PostSchema).projected('bogus') - ).toThrow('Unknown projection "bogus"'); + ).toThrow('Unknown projection: bogus'); }); it('projected() type: only registered names are accepted', () => { @@ -927,40 +939,46 @@ describe('projections', () => { void _check3; }); - it('projected() after select() throws', () => { - expect(() => - query(knex, PostSchema) - .select(t => t.id) - .projected('summary') - ).toThrow(/projected.*select|select.*projected/i); - }); - - it('select() after projected() throws', () => { - expect(() => - query(knex, PostSchema) - .projected('summary') - .select(t => t.id) - ).toThrow(/select.*projected|projected.*select/i); - }); - - it('count() after projected() throws', () => { - expect(() => - query(knex, PostSchema).projected('summary').count() - ).toThrow(/count.*projected|projected.*count/i); - }); - - it('projected() after count() throws', () => { - expect(() => - query(knex, PostSchema).count().projected('summary') - ).toThrow(/projected.*aggregate|aggregate.*projected/i); - }); - - it('two projected() calls throw', () => { - expect(() => - query(knex, PostSchema).projected('summary').projected('withStatus') - ).toThrow( - /Cannot call .projected\(\).*projected\(|Only one projection/i - ); + it.each([ + [ + 'selected to named', + (q: any) => q.select('id').projected('summary'), + ['id', 'title'] + ], + [ + 'named to selected', + (q: any) => q.projected('summary').select('id'), + ['id'] + ], + [ + 'named to aggregate', + (q: any) => q.projected('summary').count(), + ['count'] + ], + [ + 'aggregate to named', + (q: any) => q.count().projected('summary'), + ['id', 'title'] + ], + [ + 'named to named', + (q: any) => q.projected('summary').projected('withStatus'), + ['id', 'status'] + ] + ])('replaces a projection: %s', (_name, configure, keys) => { + const root = query(knex, PostSchema); + const projected = configure(root); + expect( + Object.keys(projected.rowSchema.introspect().properties) + ).toEqual(keys); + expect(Object.keys(root.rowSchema.introspect().properties)).toEqual([ + 'id', + 'title', + 'body', + 'status', + 'isActive' + ]); + expect(projected).not.toBe(root); }); it('projection() throws on duplicate name', () => { @@ -1035,8 +1053,9 @@ describe('selectRaw', () => { it('selectRaw() adds raw SQL to select clause', () => { const sql = query(knex, Post) .selectRaw( - '*, ts_rank(search_vector, plainto_tsquery(?)) AS rank', - ['search term'] + 'ts_rank(search_vector, plainto_tsquery(?)) AS rank', + ['search term'], + { output: object({ rank: number() }) } ) .toQuery(); expect(sql).toContain('ts_rank'); @@ -1619,21 +1638,25 @@ describe('extension method chaining', () => { describe('Phase 2 query methods', () => { it('whereNotExists generates correct SQL', () => { - const sql = query(knex, User) + const root = query(knex, User); + const sql = root .whereNotExists( knex .queryBuilder() .from('posts') - .where('posts.author_id', knex.raw('users.id')) + .where( + 'posts.author_id', + root.ref(t => t.id) + ) ) .toQuery(); - expect(sql).toContain('where not exists'); + expect(sql).toContain('not exists'); }); it('whereJsonPath generates jsonb_path_query_first SQL', () => { const DataSchema = object({ id: number().primaryKey(), - meta: string().jsonb() + meta: object({ status: string() }).jsonb() }).hasTableName('data_items'); const sql = query(knex, DataSchema) @@ -1646,7 +1669,7 @@ describe('Phase 2 query methods', () => { it('whereJsonPath throws on non-pg client', () => { const DataSchema = object({ id: number().primaryKey(), - meta: string().jsonb() + meta: object({ status: string() }).jsonb() }).hasTableName('data_items'); // Create a separate pg knex instance and override the client config @@ -1669,7 +1692,7 @@ describe('Phase 2 query methods', () => { it('whereJsonPath with @? operator generates existence check SQL', () => { const DataSchema = object({ id: number().primaryKey(), - tags: string().jsonb() + tags: object({ tags: array(string()) }).jsonb() }).hasTableName('data_items'); const sql = query(knex, DataSchema) @@ -1751,16 +1774,16 @@ describe('Phase 2 query methods', () => { expect(typeof q.pluck).toBe('function'); }); - it('toQuery() result is memoized and invalidated by mutations', () => { + it('toQuery() is stable and configuration creates an independent branch', () => { const q = query(knex, User).where(t => t.name, 'Alice'); const sql1 = q.toQuery(); const sql2 = q.toQuery(); // Same instance, same result — should be identical strings expect(sql1).toBe(sql2); - // Mutating invalidates the cache — new SQL includes the extra condition - q.where(t => t.role, 'admin'); - const sql3 = q.toQuery(); + const branch = q.where(t => t.role, 'admin'); + const sql3 = branch.toQuery(); + expect(q.toQuery()).toBe(sql1); expect(sql3).not.toBe(sql1); expect(sql3).toContain('admin'); }); @@ -1832,19 +1855,19 @@ describe('nested object jsonb columns', () => { }).jsonb() }).hasTableName('people'); - it('accessor t => t.address.city generates ->? SQL', () => { + it('accessor t => t.address.city generates typed JSON path SQL', () => { const sql = query(knex, PersonSchema) .where(t => (t as any).address.city, '=', 'NYC') .toQuery(); - expect(sql).toContain('->'); + expect(sql).toContain('#>>'); expect(sql).toContain('city'); }); - it('dotted string path address.city generates ->? SQL', () => { + it('dotted string path address.city generates typed JSON path SQL', () => { const sql = query(knex, PersonSchema) .where('address.city' as any, '=', 'NYC') .toQuery(); - expect(sql).toContain('->'); + expect(sql).toContain('#>>'); expect(sql).toContain('city'); }); @@ -2091,9 +2114,10 @@ describe('withVariants (polymorphic schemas)', () => { it('documents the expected result shape via SQL analysis', () => { // Integration-style: verify the SELECT aliases are generated const sql = query(knex, FileSchema).toQuery(); - // Each CTI column should appear as __v_image__ - expect(sql).toContain('__v_image'); - expect(sql).toContain('__v_document'); + // Branch shapes stay separate inside the union's JSON envelope. + expect(sql).toContain('to_jsonb(__read_branch)'); + expect(sql).toContain('image_file'); + expect(sql).toContain('document_file'); }); }); @@ -2188,23 +2212,23 @@ describe('withVariants — per-variant relations', () => { // SQL generation — includeVariant // ------------------------------------------------------------------------- - it('includeVariant generates LEFT JOIN with namespaced alias', () => { + it('includeVariant generates a CTI body join and a correlated relation', () => { const sql = query(knex, AssetSchema) .includeVariant('licensed', 'owner') .toQuery(); expect(sql.toLowerCase()).toContain('left join'); expect(sql.toLowerCase()).toContain('owners'); - expect(sql).toContain('__v_licensed__rel_owner'); + expect(sql).toContain('as "owner"'); }); - it('includeVariant selects foreign columns with prefix', () => { + it('includeVariant aliases foreign properties inside a nested object', () => { const sql = query(knex, AssetSchema) .includeVariant('licensed', 'owner') .toQuery(); - expect(sql).toContain('__v_licensed__rel_owner__id'); - expect(sql).toContain('__v_licensed__rel_owner__email'); + expect(sql).toContain('"id" as "id"'); + expect(sql).toContain('"email" as "email"'); }); it('includeVariant with projection selects only projected columns', () => { @@ -2233,9 +2257,9 @@ describe('withVariants — per-variant relations', () => { ) .toQuery(); - expect(sql).toContain('__v_licensed__rel_owner__id'); - expect(sql).toContain('__v_licensed__rel_owner__email'); - expect(sql).not.toContain('__v_licensed__rel_owner__name'); + expect(sql).toContain('"id" as "id"'); + expect(sql).toContain('"email" as "email"'); + expect(sql).not.toContain('"name" as "name"'); }); // ------------------------------------------------------------------------- @@ -2243,13 +2267,15 @@ describe('withVariants — per-variant relations', () => { // ------------------------------------------------------------------------- it('include() auto-routes to includeVariant when relation is unambiguous', () => { - const sql = query(knex, AssetSchema).include('owner').toQuery(); - expect(sql).toContain('__v_licensed__rel_owner'); + const sql = (query(knex, AssetSchema) as any) + .include('owner') + .toQuery(); + expect(sql).toContain('as "owner"'); }); it('include() throws for truly unknown relations on polymorphic schema', () => { expect(() => { - query(knex, AssetSchema).include('nonexistent').toQuery(); + (query(knex, AssetSchema) as any).include('nonexistent').toQuery(); }).toThrow(/Unknown relation/); }); @@ -2280,7 +2306,7 @@ describe('withVariants — per-variant relations', () => { }).schema; expect(() => { - query(knex, AmbigSchema).include('owner').toQuery(); + (query(knex, AmbigSchema) as any).include('owner').toQuery(); }).toThrow(/[Aa]mbiguous/); }); @@ -2291,39 +2317,40 @@ describe('withVariants — per-variant relations', () => { it('includeVariant throws for non-polymorphic schema', () => { const Plain = object({ id: number().primaryKey() }).hasTableName('t'); expect(() => { + // @ts-expect-error non-polymorphic queries do not expose variant operations query(knex, Plain).includeVariant('x', 'y'); - }).toThrow(/not polymorphic/); + }).toThrow(/includeVariant is not a function/); }); it('includeVariant throws for unknown variant key', () => { expect(() => { + // @ts-expect-error runtime guard for an unknown variant query(knex, AssetSchema).includeVariant('unknown_variant', 'owner'); - }).toThrow(/unknown variant key/); + }).toThrow(/Unknown variant/); }); it('includeVariant throws for unknown relation name', () => { expect(() => { query(knex, AssetSchema).includeVariant('licensed', 'nonexistent'); - }).toThrow(/unknown relation/); + }).toThrow(/Unknown relation/); }); // ------------------------------------------------------------------------- // Row mapping — Pass 3 (observable via SQL + alias presence) // ------------------------------------------------------------------------- - it('includeVariant generates relation column aliases in SQL (Pass 3 input)', () => { - // Verify all 3 Owner columns are aliased into the query result so that - // Pass 3 of #mapPolymorphicRow can read them. + it('includeVariant includes every related property inside its JSON object', () => { + // All three Owner properties are selected inside the related JSON object. const sql = query(knex, AssetSchema) .includeVariant('licensed', 'owner') .toQuery(); - expect(sql).toContain('__v_licensed__rel_owner__id'); - expect(sql).toContain('__v_licensed__rel_owner__email'); - expect(sql).toContain('__v_licensed__rel_owner__name'); + expect(sql).toContain('"id" as "id"'); + expect(sql).toContain('"email" as "email"'); + expect(sql).toContain('"name" as "name"'); }); - it('STI variant with includeVariant generates correct ON discriminator gate', () => { + it('STI relation is confined to the matching discriminator branch', () => { // STI variant: no separate table alias, gate uses base table discriminator const StiSchema = defineEntity(AssetBase) .discriminator('kind') @@ -2344,7 +2371,7 @@ describe('withVariants — per-variant relations', () => { // Should join owners and gate ON discriminator = 'free' expect(sql.toLowerCase()).toContain('owners'); - expect(sql).toContain('__v_free__rel_owner'); + expect(sql).toContain('as "owner"'); expect(sql).toContain('free'); }); }); @@ -2358,7 +2385,7 @@ describe('joinOne / joinMany validation errors', () => { foreignColumn: (t: any) => t.authorId, as: '' as any }) - ).toThrow('as must be a non-empty string'); + ).toThrow(/non-empty/); }); it('joinMany throws when as is missing', () => { @@ -2369,7 +2396,7 @@ describe('joinOne / joinMany validation errors', () => { foreignColumn: (t: any) => t.authorId, as: '' as any }) - ).toThrow('as must be a non-empty string'); + ).toThrow(/non-empty/); }); it('joinOne throws when mappers is not an object', () => { @@ -2379,8 +2406,9 @@ describe('joinOne / joinMany validation errors', () => { localColumn: (t: any) => t.id, foreignColumn: (t: any) => t.authorId, as: 'posts', + // @ts-expect-error removed raw mapper escape cannot supply a row schema mappers: 'invalid' as any }) - ).toThrow('mappers must be an object'); + ).toThrow(/typed child customizer/); }); }); diff --git a/libs/knex-schema/src/public-api-docs.test.ts b/libs/knex-schema/src/public-api-docs.test.ts index 506bc058..bc3039e4 100644 --- a/libs/knex-schema/src/public-api-docs.test.ts +++ b/libs/knex-schema/src/public-api-docs.test.ts @@ -109,7 +109,7 @@ describe('published query/ORM API documentation', () => { it('documents aggregate expressions, bound factory overloads and cursor options', () => { for (const [path, name] of [ ['../dist/expressions.d.ts', 'aggregate'], - ['../dist/SchemaQueryBuilder.d.ts', 'BoundQuery'], + ['../dist/query.d.ts', 'BoundQuery'], [ '../dist/operations/composite-cursor.d.ts', 'CompositeCursorOptions' diff --git a/libs/knex-schema/src/query-scope.ts b/libs/knex-schema/src/query-scope.ts new file mode 100644 index 00000000..1e815379 --- /dev/null +++ b/libs/knex-schema/src/query-scope.ts @@ -0,0 +1,24 @@ +import type { Knex } from 'knex'; +import type { ReadRelations } from './read-entity.js'; +import type { + ReadPredicateSelector, + ReadPredicates +} from './read-predicates.js'; +import type { ReadObject } from './read-schema.js'; +import type { ReadColumns } from './SchemaQueryBuilder.js'; + +/** Shape-preserving immutable API supplied to named and default scopes. */ +export interface QueryScope + extends ReadPredicates>> { + /** Append native column ordering. Return the new query. */ + orderBy( + column: ReadPredicateSelector>>, + direction?: 'asc' | 'desc' + ): this; + /** Append trusted ordering with captured bindings. */ + orderByRaw(sql: string, bindings?: readonly Knex.RawBinding[]): this; + /** Limit a new query without changing its row shape. */ + limit(count: number): this; + /** Offset a new query without changing its row shape. */ + offset(count: number): this; +} diff --git a/libs/knex-schema/src/query.ts b/libs/knex-schema/src/query.ts new file mode 100644 index 00000000..7c5e517e --- /dev/null +++ b/libs/knex-schema/src/query.ts @@ -0,0 +1,74 @@ +import type { Knex } from 'knex'; +import { AliasedQueryBuilder } from './AliasedQueryBuilder.js'; +import { + AliasedQuerySource, + type AliasTables, + isTableAlias, + type TableAlias +} from './aliased-query.js'; +import { getTableName } from './extension.js'; +import { QuerySource } from './QuerySource.js'; +import type { ReadObject } from './read-schema.js'; +import { + createReadQuery, + type SchemaAwareQuery +} from './SchemaQueryBuilder.js'; + +// Register the private SQL/write planner before creating relation queries. +void QuerySource; + +/** Create an immutable, lazy query with an automatically inferred row schema. */ +export function query( + knex: Knex, + schema: TableAlias +): AliasedQueryBuilder>; +/** Create an immutable table or polymorphic query. Raw output requires apply(..., { output }). */ +export function query( + knex: Knex, + schema: S +): SchemaAwareQuery; +export function query( + knex: Knex, + schema: S | TableAlias, + ...unsupported: unknown[] +): SchemaAwareQuery | AliasedQueryBuilder> { + if (unsupported.length) + throw new TypeError( + 'Raw query sources are not supported; use apply(..., { output })' + ); + if (isTableAlias(schema)) + return new AliasedQueryBuilder(new AliasedQuerySource(knex, schema)); + return createReadQuery(knex, schema, knex(getTableName(schema))); +} + +/** Connection-bound query factory. Query configuration is lazy and immutable. */ +export interface BoundQuery { + /** Start a flat multi-table query. Select its output before execution. */ + ( + schema: TableAlias + ): AliasedQueryBuilder>; + /** Start a schema-backed table query. */ + (schema: S): SchemaAwareQuery; + /** Reuse an existing transaction without committing it. */ + withTransaction(trx: Knex.Transaction): BoundQuery; + /** Run work atomically with a transaction-bound factory. */ + transaction(callback: (db: BoundQuery) => Promise): Promise; +} + +/** Bind query() to a connection while preserving schema and alias inference. */ +export function createQuery(knex: Knex): BoundQuery { + return Object.assign( + (schema: any, ...unsupported: unknown[]) => { + if (unsupported.length) + throw new TypeError( + 'Raw query sources are not supported; use apply(..., { output })' + ); + return query(knex, schema); + }, + { + withTransaction: (trx: Knex.Transaction) => createQuery(trx), + transaction: (callback: (db: BoundQuery) => Promise) => + knex.transaction(trx => callback(createQuery(trx))) + } + ) as BoundQuery; +} diff --git a/libs/knex-schema/src/raw.test.ts b/libs/knex-schema/src/raw.test.ts index 087f0f09..10019a40 100644 --- a/libs/knex-schema/src/raw.test.ts +++ b/libs/knex-schema/src/raw.test.ts @@ -1,123 +1,115 @@ -// @cleverbrush/knex-schema — rawQuery() tests - -import Knex from 'knex'; -import { afterAll, describe, expect, it, vi } from 'vitest'; +import Knex, { type Knex as Connection } from 'knex'; +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import { number, object, string } from './index.js'; import { rawQuery } from './raw.js'; -const Post = object({ - id: number(), - title: string(), - authorId: number().hasColumnName('author_id'), - createdAt: string().hasColumnName('created_at') -}).hasTableName('posts'); - -const knex = Knex({ client: 'pg' }); - -afterAll(async () => { - await knex.destroy(); -}); - -describe('rawQuery', () => { - it('runs a raw SQL string and maps column names back to property names', async () => { - const rawSpy = vi.spyOn(knex, 'raw').mockResolvedValueOnce({ - rows: [ - { id: 1, title: 'Hi', author_id: 7, created_at: '2024-01-01' } - ] - } as any); +// Stub only the driver boundary: raw() must still build real captured SQL. +describe('rawQuery explicit output contract', () => { + let knex: Connection; + let response: unknown[]; + let statements: Array<{ sql: string; bindings: unknown[] }>; + beforeEach(() => { + knex = Knex({ client: 'pg' }); + response = []; + statements = []; + const client = knex.client as any; + client.acquireConnection = async () => ({}); + client.releaseConnection = async () => {}; + client._query = async (_connection: unknown, statement: any) => { + statements.push(statement); + return { rows: response }; + }; + client.processResponse = (result: any) => result.rows; + }); + afterEach(async () => { + await knex.destroy(); + }); + it('parses SQL-aliased properties once, preserving the caller output contract', async () => { + const output = object({ + id: number(), + authorId: number(), + total: number().coerce() + }); + const parse = vi.spyOn(output, 'parse'); + response = [{ id: 1, authorId: 7, total: '12' }]; const rows = await rawQuery( knex, - Post, - 'SELECT * FROM posts WHERE id = ?', - [1] - ); - - expect(rawSpy).toHaveBeenCalledWith( - 'SELECT * FROM posts WHERE id = ?', + output, + 'select id, author_id as "authorId", total from posts where id = ?', [1] ); - expect(rows).toEqual([ - { id: 1, title: 'Hi', authorId: 7, createdAt: '2024-01-01' } - ]); - - rawSpy.mockRestore(); + expect(rows).toEqual([{ id: 1, authorId: 7, total: 12 }]); + expect(parse).toHaveBeenCalledExactlyOnceWith(response[0]); + expect(statements[0].bindings).toEqual([1]); }); - it('defaults bindings to [] when omitted', async () => { - const rawSpy = vi - .spyOn(knex, 'raw') - .mockResolvedValueOnce({ rows: [] } as any); - - await rawQuery(knex, Post, 'SELECT 1'); - - expect(rawSpy).toHaveBeenCalledWith('SELECT 1', []); - - rawSpy.mockRestore(); + it('does not silently remap raw output or accept a missing selected column', async () => { + response = [{ author_id: 7 }]; + await expect( + rawQuery( + knex, + object({ authorId: number() }), + 'select author_id from posts' + ) + ).rejects.toThrow(); }); - it('handles drivers that return an array directly (no .rows wrapper)', async () => { - const rawSpy = vi - .spyOn(knex, 'raw') - .mockResolvedValueOnce([ - { id: 2, title: 'X', author_id: 3, created_at: '2024-02-02' } - ] as any); - - const rows = await rawQuery(knex, Post, 'SELECT *'); - - expect(rows).toEqual([ - { id: 2, title: 'X', authorId: 3, createdAt: '2024-02-02' } - ]); - - rawSpy.mockRestore(); + it('returns an empty result without invoking the row parser', async () => { + const output = object({ id: number() }); + const parse = vi.spyOn(output, 'parse'); + expect(await rawQuery(knex, output, 'select id from posts')).toEqual( + [] + ); + expect(parse).not.toHaveBeenCalled(); + expect(statements[0].bindings).toEqual([]); }); - it('returns [] when rows is not an array', async () => { - const rawSpy = vi - .spyOn(knex, 'raw') - .mockResolvedValueOnce({ rows: { not: 'an array' } } as any); - - const rows = await rawQuery(knex, Post, 'SELECT *'); - expect(rows).toEqual([]); - - rawSpy.mockRestore(); + it('snapshots a caller-owned Knex SELECT without mutating or retaining it', async () => { + response = [{ id: 9 }]; + const source = knex('posts').select('id').where('id', 9); + const pending = rawQuery(knex, object({ id: number() }), source); + source.where('id', 100); + expect(await pending).toEqual([{ id: 9 }]); + expect(statements[0].bindings).toEqual([9]); }); - it('passes through extra columns not in the schema unchanged', async () => { - const rawSpy = vi.spyOn(knex, 'raw').mockResolvedValueOnce({ - rows: [ - { - id: 1, - title: 'Hi', - author_id: 7, - created_at: '2024-01-01', - extra_count: 42 - } - ] - } as any); - - const rows = await rawQuery(knex, Post, 'SELECT *'); - - expect(rows[0]).toMatchObject({ - id: 1, - authorId: 7, - createdAt: '2024-01-01', - extra_count: 42 // unmapped column passes through - }); - - rawSpy.mockRestore(); + it('keeps exact numeric text exact with an explicit text output', async () => { + response = [{ amount: '12345678901234567890.012345' }]; + expect( + await rawQuery( + knex, + object({ amount: string() }), + 'select amount::text as amount from invoices' + ) + ).toEqual(response); }); - it('awaits a Knex query builder directly', async () => { - const result = [ - { id: 9, title: 'Q', author_id: 1, created_at: '2024-03-03' } - ]; - const qb = Promise.resolve(result) as any; + it('rejects invalid raw rows', async () => { + response = [{ id: 'not a number' }]; + await expect( + rawQuery(knex, object({ id: number() }), 'select id from posts') + ).rejects.toThrow(); + }); - const rows = await rawQuery(knex, Post, qb); + it('rejects non-object output and non-SELECT builders before execution', () => { + expect(() => + rawQuery(knex, string() as any, 'select id from posts') + ).toThrow(/object schema/); + expect(() => + rawQuery(knex, object({ id: number() }), knex('posts').delete()) + ).toThrow(/SELECT/); + expect(statements).toEqual([]); + }); - expect(rows).toEqual([ - { id: 9, title: 'Q', authorId: 1, createdAt: '2024-03-03' } - ]); + it('rejects asynchronous output parsers instead of returning promises as rows', async () => { + response = [{ id: 1 }]; + const output = object({ id: number() }); + vi.spyOn(output, 'parse').mockImplementation((async () => ({ + id: 1 + })) as any); + await expect( + rawQuery(knex, output, 'select id from posts') + ).rejects.toThrow(/synchronously/); }); }); diff --git a/libs/knex-schema/src/raw.ts b/libs/knex-schema/src/raw.ts index d2a21dc8..d1550fe3 100644 --- a/libs/knex-schema/src/raw.ts +++ b/libs/knex-schema/src/raw.ts @@ -1,68 +1,43 @@ -// @cleverbrush/knex-schema — Raw query execution with schema result mapping - -import type { InferType, ObjectSchemaBuilder } from '@cleverbrush/schema'; +import type { InferType } from '@cleverbrush/schema'; import type { Knex } from 'knex'; -import { buildColumnMap } from './columns.js'; +import { OpaqueQuery } from './OpaqueQuery.js'; +import { captureReadRaw } from './read-predicates.js'; +import type { ReadObject } from './read-schema.js'; /** - * Execute a raw SQL query or Knex query builder and map the result rows - * through the schema's column→property name mapping. - * - * This is the escape hatch for complex queries that can't be expressed with - * the typed `SchemaQueryBuilder` API. The schema is used only for result - * mapping — column names in the result are converted back to property names. - * Extra columns (not in the schema) are passed through unchanged. - * - * @param knex - A configured Knex instance. - * @param schema - The `ObjectSchemaBuilder` for result mapping. - * @param queryOrSql - A raw SQL string or a `Knex.QueryBuilder`. - * @param bindings - Optional bindings for parameterised SQL queries. - * @returns Mapped result rows. + * Execute a captured raw SELECT with an explicit complete output schema. + * SQL must alias columns to the output property names. Each driver row is parsed + * exactly once; there is no implicit column mapping or entity decoding. Cast + * exact numeric values to text in SQL before a driver can lose their precision. * + * @param knex - Connection or transaction used for execution. + * @param output - Synchronous Framework object schema describing every returned row. + * @param queryOrSql - Trusted SELECT SQL or an independently captured Knex SELECT. + * @param bindings - Bound values for the trusted SQL string. + * @returns Parsed rows, never attached to an ORM identity map. * @example * ```ts - * // Raw SQL with schema result mapping - * const results = await rawQuery(knex, PostSchema, ` - * SELECT p.*, COUNT(c.id) AS comment_count - * FROM posts p - * LEFT JOIN comments c ON c.post_id = p.id - * GROUP BY p.id - * ORDER BY comment_count DESC - * LIMIT ? - * `, [10]); - * - * // Knex query builder as the source - * const subQuery = knex('posts').select('author_id', knex.raw('COUNT(*) as post_count')).groupBy('author_id'); - * const results = await rawQuery(knex, UserSchema, subQuery); + * const totals = await rawQuery(knex, object({ total: string() }), + * 'select sum(amount)::text as total from invoices where owner_id = ?', [ownerId]); * ``` */ -export async function rawQuery< - TSchema extends ObjectSchemaBuilder ->( +export function rawQuery( knex: Knex, - schema: TSchema, + output: S, queryOrSql: string | Knex.QueryBuilder, - bindings?: any[] -): Promise<(InferType & Record)[]> { - let rows: any[]; - - if (typeof queryOrSql === 'string') { - const result = await knex.raw(queryOrSql, bindings ?? []); - rows = result.rows ?? result; - } else { - rows = await queryOrSql; - } - - if (!rows || !Array.isArray(rows)) return []; - - const { colToProp } = buildColumnMap(schema); - - return rows.map(row => { - const mapped: Record = {}; - for (const [key, value] of Object.entries(row)) { - const propName = colToProp.get(key); - mapped[propName ?? key] = value; - } - return mapped; - }) as any; + bindings: readonly Knex.RawBinding[] = [] +): Promise[]> { + const sql = + typeof queryOrSql === 'string' + ? knex + .queryBuilder() + .from( + captureReadRaw(knex, queryOrSql, bindings)().wrap( + '(', + ') as __raw_output' + ) + ) + .select('*') + : queryOrSql; + return OpaqueQuery.capture(knex, sql, { output }).execute(); } diff --git a/libs/knex-schema/src/read-consumer.test.ts b/libs/knex-schema/src/read-consumer.test.ts index d0cc1587..fc612086 100644 --- a/libs/knex-schema/src/read-consumer.test.ts +++ b/libs/knex-schema/src/read-consumer.test.ts @@ -91,7 +91,7 @@ const value: InferType = undefined; const invalidUnit: InferExtensionMetadata['unit'] = 'seconds'; // @ts-expect-error importing database libraries cannot install global storage methods number().bigint(); -export const read = query(knex, Account).withRowSchema().select(a => ({ id: a.id, balance: a.balance })); +export const read = query(knex, Account).select(a => ({ id: a.id, balance: a.balance })); const PublicAccount = object({ id: string(), balance: string().nullable() }); export const convert = mapper().configure(read.rowSchema, PublicAccount, m => m) .getSyncMapper(read.rowSchema, PublicAccount); diff --git a/libs/knex-schema/src/read-graph.test-d.ts b/libs/knex-schema/src/read-graph.test-d.ts index 25ec2482..14de479c 100644 --- a/libs/knex-schema/src/read-graph.test-d.ts +++ b/libs/knex-schema/src/read-graph.test-d.ts @@ -46,14 +46,12 @@ const Album = defineEntity( const knex = Knex({ client: 'pg' }); test('polymorphic read branches retain discriminators and nested relation types', async () => { - const read = query(knex, Asset.schema) - .withRowSchema() - .forVariant('photo', q => - q.include( - r => r.labels, - labels => labels.select(l => ({ text: l.label })) - ) - ); + const read = query(knex, Asset.schema).forVariant('photo', q => + q.include( + r => r.labels, + labels => labels.select(l => ({ text: l.label })) + ) + ); type PhotoRow = InferType; type Expected = { id: number; @@ -80,12 +78,10 @@ test('polymorphic read branches retain discriminators and nested relation types' }); test('polymorphic reads compose inside an ordinary relation', async () => { - const read = query(knex, Album.schema) - .withRowSchema() - .include( - r => r.assets, - assets => assets.forVariant('photo', q => q.include(r => r.labels)) - ); + const read = query(knex, Album.schema).include( + r => r.assets, + assets => assets.forVariant('photo', q => q.include(r => r.labels)) + ); const rows = await read; const asset = rows[0].assets[0]; if (asset.kind === 'photo') diff --git a/libs/knex-schema/src/read-mapping.test.ts b/libs/knex-schema/src/read-mapping.test.ts index c138e1bc..e5dd4333 100644 --- a/libs/knex-schema/src/read-mapping.test.ts +++ b/libs/knex-schema/src/read-mapping.test.ts @@ -25,7 +25,7 @@ describe('query schemas as reusable mapping sources', () => { n => n.taskId ); const read = query(Knex({ client: 'pg' }), Task.schema) - .withRowSchema() + .select(t => ({ id: t.id, amount: t.amount, done: t.done })) .include( r => r.notes, diff --git a/libs/knex-schema/src/read-predicates.test-d.ts b/libs/knex-schema/src/read-predicates.test-d.ts index c3fcec0c..bee3769a 100644 --- a/libs/knex-schema/src/read-predicates.test-d.ts +++ b/libs/knex-schema/src/read-predicates.test-d.ts @@ -14,9 +14,10 @@ const Item = object({ }).hasTableName('items'); test('ordinary reader predicates retain projection types and contextual groups', async () => { - const read = query(knex, Item) - .withRowSchema() - .select(t => ({ name: t.name, amount: t.amount })); + const read = query(knex, Item).select(t => ({ + name: t.name, + amount: t.amount + })); const filtered = read .where(p => p.where(t => t.id, 1).orWhere(t => t.name, 'two')) .whereIn(t => t.id, knex('links').select('item_id')) @@ -54,6 +55,7 @@ test('ordinary reader predicates retain projection types and contextual groups', p.execute(); // @ts-expect-error group lifecycle is owned by the reader p.finish(); + return p; }); // @ts-expect-error unrestricted mutation is still unavailable read.apply(q => q.select('*')); @@ -61,7 +63,7 @@ test('ordinary reader predicates retain projection types and contextual groups', test('aliased selectors preserve joined nullability and exact storage types', async () => { const read = query(knex, alias(Item, 'item')) - .withRowSchema() + .leftJoin(alias(Item, 'parent'), t => eq(t.item.id, t.parent.id)) .select(t => ({ id: t.item.id, diff --git a/libs/knex-schema/src/read-predicates.test.ts b/libs/knex-schema/src/read-predicates.test.ts index 6b00a8d8..c6371f3c 100644 --- a/libs/knex-schema/src/read-predicates.test.ts +++ b/libs/knex-schema/src/read-predicates.test.ts @@ -17,7 +17,7 @@ const Task = object({ completedAt: date().optional().hasColumnName('completed_at') }).hasTableName('tasks'); const knex = Knex({ client: 'pg' }); -const readTask = () => query(knex, Task).withRowSchema(); +const readTask = () => query(knex, Task); describe('shape-preserving read predicates', () => { it('groups AND/OR conditions without mutating the source or its schema', () => { @@ -181,12 +181,12 @@ describe('shape-preserving read predicates', () => { expect(compiled.toNative().sql).toContain('::jsonb ?'); }); - it('runs group callbacks once and seals retained group builders', () => { + it('runs group callbacks once and isolates retained immutable builders', () => { const read = readTask(); let retained!: ReadPredicateBuilder; const callback = vi.fn((p: ReadPredicateBuilder) => { retained = p; - p.where(t => t.id, 1); + const configured = p.where(t => t.id, 1); for (const method of [ 'select', 'join', @@ -198,14 +198,16 @@ describe('shape-preserving read predicates', () => { 'then' ]) expect(method in p).toBe(false); + return configured; }); const filtered = read.where(callback); filtered.toQuery(); filtered.toQuery(); expect(callback).toHaveBeenCalledTimes(1); - expect(() => retained.where(t => t.id, 2)).toThrow(/already closed/); + expect(retained.where(t => t.id, 2)).not.toBe(retained); + expect(filtered.toQuery()).not.toContain('= 2'); expect(filtered.toQuery()).toContain('= 1'); - expect(read.where(() => {}).toQuery()).toBe(read.toQuery()); + expect(read.where(p => p).toQuery()).toBe(read.toQuery()); }); it('rejects async or throwing groups without changing their parent', async () => { @@ -244,11 +246,10 @@ describe('shape-preserving read predicates', () => { }); it('applies the same predicates and binding snapshots to aliased joins', () => { - const base = query(knex, alias(Task, 'task')) - .withRowSchema() - .leftJoin(alias(Task, 'other'), t => - eq(t.task.id, t.other.projectId) - ); + const base = query(knex, alias(Task, 'task')).leftJoin( + alias(Task, 'other'), + t => eq(t.task.id, t.other.projectId) + ); const source = base.select(t => ({ id: t.task.id, otherId: t.other.id, @@ -283,11 +284,11 @@ describe('shape-preserving read predicates', () => { .valid ).toBe(true); expect(source.toQuery()).not.toContain(' where '); - expect('apply' in source).toBe(false); + expect('apply' in source).toBe(true); expect(() => query(knex, alias(Task, 'task')) + // @ts-expect-error opaque SQL requires its output contract .apply(q => q.where('id', 1)) - .withRowSchema() - ).toThrow(/before select\/apply/); + ).toThrow(/output/); }); }); diff --git a/libs/knex-schema/src/read-predicates.ts b/libs/knex-schema/src/read-predicates.ts index 9c907720..48f15f9f 100644 --- a/libs/knex-schema/src/read-predicates.ts +++ b/libs/knex-schema/src/read-predicates.ts @@ -6,13 +6,14 @@ import { ReadSchemaError } from './read-schema.js'; const finishGroup = Symbol('finishReadPredicateGroup'); /** Select a column from the current reader's ordinary or aliased table context. */ -export type ReadPredicateSelector = (columns: C) => AliasedColumn; +export type ReadPredicateSelector = + | ((columns: C) => AliasedColumn) + | (keyof C & string); /** A synchronous, parenthesized predicate group. The callback cannot shape or execute a query. */ export type ReadPredicateGroup = ( predicates: ReadPredicateBuilder - // biome-ignore lint/suspicious/noConfusingVoidType: Accept existing void-returning callbacks while rejecting async callbacks via the explicit return union. -) => ReadPredicateBuilder | void; +) => ReadPredicateBuilder; /** A bound value list or a caller-built SELECT subquery; captured without executing it. */ export type ReadMembership = readonly unknown[] | Knex.QueryBuilder; @@ -23,7 +24,7 @@ export type ReadPredicate = (query: Knex.QueryBuilder) => void; /** @internal Resolve references without exposing the parent's mutable SQL builder. */ export interface ReadPredicateContext { knex: Knex; - column: (selector: ReadPredicateSelector) => string; + column: (selector: ReadPredicateSelector) => string | Knex.Raw; } /** @internal Snapshot common mutable binding values independently of query builders. */ @@ -89,7 +90,8 @@ function captureSubquery(knex: Knex, query: Knex.QueryBuilder): () => Knex.Raw { ); } -function captureValue(knex: Knex, value: any): () => any { +/** @internal Capture mutable bindings without retaining caller-owned values. */ +export function captureValue(knex: Knex, value: any): () => any { if (value && typeof value.toSQL === 'function') { return typeof value.clone === 'function' ? captureSubquery(knex, value) @@ -103,7 +105,7 @@ function captureValue(knex: Knex, value: any): () => any { /** * Shared shape-preserving predicate methods for immutable readers and scoped groups. - * @internal Consumers obtain these methods through withRowSchema(), not inheritance. + * @internal Consumers obtain these methods through query factories, not inheritance. */ export abstract class ReadPredicates { protected abstract readPredicateContext(): ReadPredicateContext; @@ -114,13 +116,16 @@ export abstract class ReadPredicates { * The reference uses this reader's actual SQL alias and never executes SQL. * @example read.whereRaw('lower(??) = ?', [read.ref(t => t.name), 'alice']) */ - ref(selector: ReadPredicateSelector): Knex.Ref { + ref(selector: ReadPredicateSelector): Knex.Ref | Knex.Raw { const { knex, column } = this.readPredicateContext(); - return knex.ref(column(selector)); + const resolved = column(selector); + return typeof resolved === 'string' ? knex.ref(resolved) : resolved; } /** Add a parenthesized AND group using a synchronous predicate-only callback. */ where(group: ReadPredicateGroup): this; + /** Match a record of property names and bound equality values. */ + where(values: Partial>): this; /** Add a bound equality comparison. Null uses SQL IS NULL. */ where(column: ReadPredicateSelector, value: unknown): this; /** Add a bound comparison using a supported SQL operator. */ @@ -130,14 +135,30 @@ export abstract class ReadPredicates { value: unknown ): this; where( - first: ReadPredicateSelector | ReadPredicateGroup, + first: + | ReadPredicateSelector + | ReadPredicateGroup + | Partial>, ...args: [] | [unknown] | [string, unknown] ): this { - return this.comparison('and', first, args); + if (typeof first === 'object' && first !== null && !args.length) { + return Object.entries(first).reduce( + (query, [key, value]) => + query.where(key as keyof C & string, value), + this + ); + } + return this.comparison( + 'and', + first as ReadPredicateSelector | ReadPredicateGroup, + args + ); } /** Explicit AND spelling of where(), including nested groups. */ andWhere(group: ReadPredicateGroup): this; + /** Match all property/value pairs with AND semantics. */ + andWhere(values: Partial>): this; /** Add a bound AND equality comparison. */ andWhere(column: ReadPredicateSelector, value: unknown): this; /** Add a bound AND comparison. */ @@ -147,14 +168,25 @@ export abstract class ReadPredicates { value: unknown ): this; andWhere( - first: ReadPredicateSelector | ReadPredicateGroup, + first: + | ReadPredicateSelector + | ReadPredicateGroup + | Partial>, ...args: [] | [unknown] | [string, unknown] ): this { - return this.comparison('and', first, args); + if (typeof first === 'object' && first !== null && !args.length) + return this.where(first); + return this.comparison( + 'and', + first as ReadPredicateSelector | ReadPredicateGroup, + args + ); } /** Add a parenthesized OR group. Use an enclosing AND group beside authorization filters. */ orWhere(group: ReadPredicateGroup): this; + /** Match a parenthesized AND record as one alternative to the preceding predicates. */ + orWhere(values: Partial>): this; /** Add a bound OR equality comparison. */ orWhere(column: ReadPredicateSelector, value: unknown): this; /** Add a bound OR comparison. */ @@ -164,10 +196,19 @@ export abstract class ReadPredicates { value: unknown ): this; orWhere( - first: ReadPredicateSelector | ReadPredicateGroup, + first: + | ReadPredicateSelector + | ReadPredicateGroup + | Partial>, ...args: [] | [unknown] | [string, unknown] ): this { - return this.comparison('or', first, args); + if (typeof first === 'object' && first !== null && !args.length) + return this.orWhere(group => group.where(first)); + return this.comparison( + 'or', + first as ReadPredicateSelector | ReadPredicateGroup, + args + ); } private comparison( @@ -180,7 +221,7 @@ export abstract class ReadPredicates { if (!args.length) { const group = new ReadPredicateBuilder(context); let operations: readonly ReadPredicate[]; - try { + { const result: unknown = (first as ReadPredicateGroup)(group); if ( result && @@ -193,9 +234,14 @@ export abstract class ReadPredicates { 'Read predicate groups must be synchronous' ); } - operations = group[finishGroup](); - } finally { - group[finishGroup](); + if ( + !(result instanceof ReadPredicateBuilder) || + !result.sameSource(group) + ) + throw new ReadSchemaError( + 'Predicate callbacks must return a builder from the supplied group' + ); + operations = result[finishGroup](); } return this.addReadPredicate(query => { query[method](nested => { @@ -217,8 +263,8 @@ export abstract class ReadPredicates { args.length === 1 ? args[0] : args[1] ); return this.addReadPredicate(query => { - if (args.length === 1) query[method](column, value()); - else query[method](column, operator, value()); + if (args.length === 1) query[method](column as any, value()); + else query[method](column as any, operator, value()); }); } @@ -228,7 +274,7 @@ export abstract class ReadPredicates { ): this { const name = this.readPredicateContext().column(column); return this.addReadPredicate(query => { - query[method](name); + query[method](name as any); }); } /** Match SQL null without changing the row schema. */ @@ -267,7 +313,7 @@ export abstract class ReadPredicates { query[rawMethod](`?? ${operator} (?)`, [name, captured()]); } else { query[method]( - name, + name as any, captured.map(value => value()) ); } @@ -352,18 +398,94 @@ export abstract class ReadPredicates { query.orWhereRaw(captured()); }); } + + /** Negated bound equality (null uses SQL IS NOT NULL). */ + whereNot(column: ReadPredicateSelector, value: unknown): this { + const context = this.readPredicateContext(); + const name = context.column(column); + const captured = captureValue(context.knex, value); + return this.addReadPredicate(query => { + query.whereNot(name as any, captured()); + }); + } + /** Match an inclusive range of captured values. */ + whereBetween( + column: ReadPredicateSelector, + range: readonly [unknown, unknown] + ): this { + return this.range(column, range, false); + } + /** Exclude an inclusive range of captured values. */ + whereNotBetween( + column: ReadPredicateSelector, + range: readonly [unknown, unknown] + ): this { + return this.range(column, range, true); + } + private range( + column: ReadPredicateSelector, + range: readonly [unknown, unknown], + not: boolean + ): this { + const context = this.readPredicateContext(); + const name = context.column(column); + const values = range.map(value => captureValue(context.knex, value)); + return this.addReadPredicate(query => { + query[not ? 'whereNotBetween' : 'whereBetween'](name as any, [ + values[0](), + values[1]() + ]); + }); + } + /** Match a SQL LIKE pattern. Wildcards retain their SQL meaning. */ + whereLike(column: ReadPredicateSelector, value: string): this { + return this.where(column, 'like', value); + } + /** Match a case-insensitive PostgreSQL pattern. */ + whereILike(column: ReadPredicateSelector, value: string): this { + return this.where(column, 'ilike', value); + } + /** Compare a JSON path while preserving the declared output schema. */ + whereJsonPath( + column: ReadPredicateSelector, + path: string, + operator = '=', + value?: unknown + ): this { + const context = this.readPredicateContext(); + const name = context.column(column); + const client = context.knex.client.config.client; + if (!['pg', 'postgres', 'postgresql'].includes(client)) + throw new ReadSchemaError( + 'whereJsonPath() is only supported on PostgreSQL' + ); + if (operator === '@?' || operator === '@@') + return this.whereRaw(`?? ${operator === '@?' ? '@\\?' : '@@'} ?`, [ + name, + path + ]); + if (!ALLOWED_OPS.has(operator.toLowerCase())) + throw new ReadSchemaError('Unsupported JSON comparison operator'); + return this.whereRaw( + `jsonb_path_query_first(??, ?) ${operator} ?::jsonb`, + [ + name, + path.startsWith('$') ? path : `$.${path}`, + JSON.stringify(value) + ] + ); + } } /** * Predicate-only builder supplied to grouped where/andWhere/orWhere callbacks. - * Group methods accumulate synchronously; outer readers remain immutable. + * Group methods return independent builders; attachment snapshots the returned group. * No select, join, order, raw-query escape hatch, then, or execution method exists. * Retaining this builder and mutating it after the callback throws. */ export class ReadPredicateBuilder extends ReadPredicates { #context: ReadPredicateContext; #operations: ReadPredicate[] = []; - #closed = false; /** @internal Created only for grouped predicates. */ constructor(context: ReadPredicateContext) { super(); @@ -373,14 +495,16 @@ export class ReadPredicateBuilder extends ReadPredicates { return this.#context; } protected addReadPredicate(predicate: ReadPredicate): this { - if (this.#closed) - throw new ReadSchemaError('Predicate group is already closed'); - this.#operations.push(predicate); - return this; + const copy = new ReadPredicateBuilder(this.#context); + copy.#operations = [...this.#operations, predicate]; + return copy as this; + } + /** @internal Verify that a returned builder belongs to the supplied group. */ + sameSource(other: ReadPredicateBuilder): boolean { + return this.#context === other.#context; } - /** @internal Close the scoped builder and snapshot its predicate list. */ + /** @internal Snapshot the immutable predicate list. */ [finishGroup](): readonly ReadPredicate[] { - this.#closed = true; return [...this.#operations]; } } diff --git a/libs/knex-schema/src/read-projection.ts b/libs/knex-schema/src/read-projection.ts index 3d1251ff..923d5e2d 100644 --- a/libs/knex-schema/src/read-projection.ts +++ b/libs/knex-schema/src/read-projection.ts @@ -25,7 +25,10 @@ export type ReadField = { export function compileReadProjection( knex: Knex, selection: Record | AggregateExpression>, - resolve: (column: AliasedColumn) => { name: string; node: ReadNode } + resolve: (column: AliasedColumn) => { + name: string | Knex.Raw; + node: ReadNode; + } ): Record { if (!Object.keys(selection).length) throw new ReadSchemaError('A non-empty projection is required'); diff --git a/libs/knex-schema/src/read-schema.test-d.ts b/libs/knex-schema/src/read-schema.test-d.ts index 21da993e..5add4404 100644 --- a/libs/knex-schema/src/read-schema.test-d.ts +++ b/libs/knex-schema/src/read-schema.test-d.ts @@ -13,9 +13,11 @@ const Task = object({ done: date().optional() }).hasTableName('tasks'); test('projection row type equals its runtime schema inference', async () => { - const read = query(Knex({ client: 'pg' }), Task) - .withRowSchema() - .select(t => ({ id: t.id, amount: t.amount, done: t.done })); + const read = query(Knex({ client: 'pg' }), Task).select(t => ({ + id: t.id, + amount: t.amount, + done: t.done + })); type Row = { id: number; amount: string | null; done: Date | null }; expectTypeOf>().toEqualTypeOf(); expectTypeOf(await read).toEqualTypeOf(); @@ -25,7 +27,7 @@ test('projection row type equals its runtime schema inference', async () => { test('flat joins retain exact storage and left join nullability', async () => { const read = query(Knex({ client: 'pg' }), alias(Task, 'task')) - .withRowSchema() + .leftJoin(alias(Task, 'other'), t => eq(t.task.id, t.other.id)) .select(t => ({ amount: t.task.amount, @@ -56,18 +58,16 @@ test('optional declared joins and explicit relation customizers retain their sha u => u.id, { optional: true } ); - const read = query(Knex({ client: 'pg' }), entity.schema) - .withRowSchema() - .include( - r => r.owner, - q => q.select(u => ({ name: u.name })) - ); + const read = query(Knex({ client: 'pg' }), entity.schema).include( + r => r.owner, + q => q.select(u => ({ name: u.name })) + ); const row = (await read)[0]; expectTypeOf(row.owner).toExtend<{ name: string } | null>(); // @ts-expect-error the relation may be null const _required: { name: string } = row.owner; const explicit = query(Knex({ client: 'pg' }), Task) - .withRowSchema() + .select(t => ({ title: t.title })) .joinMany( { diff --git a/libs/knex-schema/src/read-schema.test.ts b/libs/knex-schema/src/read-schema.test.ts index 41db89f3..bb9a215d 100644 --- a/libs/knex-schema/src/read-schema.test.ts +++ b/libs/knex-schema/src/read-schema.test.ts @@ -16,13 +16,11 @@ const knex = Knex({ client: 'pg' }); describe('schema-aware read metadata', () => { it('describes only projected fields, SQL nulls and exact storage', () => { - const read = query(knex, Task) - .withRowSchema() - .select(t => ({ - title: t.title, - amount: t.amount, - done: t.completedAt - })); + const read = query(knex, Task).select(t => ({ + title: t.title, + amount: t.amount, + done: t.completedAt + })); const properties = read.rowSchema.introspect().properties; expect(Object.keys(properties)).toEqual(['title', 'amount', 'done']); expect( @@ -41,7 +39,7 @@ describe('schema-aware read metadata', () => { expect(read.toQuery()).not.toContain('"id" as'); }); it('preserves schema identity across immutable filters and transactions', () => { - const read = query(knex, Task).withRowSchema(); + const read = query(knex, Task); const one = read.where(t => t.id, 1).limit(1); const two = read.where(t => t.id, 2).offset(1); expect(one.rowSchema).toBe(read.rowSchema); @@ -88,58 +86,48 @@ describe('schema-aware read metadata', () => { ).toBe('2026-01-02T01:04:05.000Z'); }); it('retains aggregate output schemas and rejects opaque parsers', () => { - const read = query(knex, Task) - .withRowSchema() - .select(t => ({ - count: aggregate.count(), - total: aggregate.sum(t.amount) - })); + const read = query(knex, Task).select(t => ({ + count: aggregate.count(), + total: aggregate.sum(t.amount) + })); expect(read.rowSchema.validate({ count: 3, total: null }).valid).toBe( true ); expect(() => - query(knex, Task) - .withRowSchema() - .select(() => ({ - count: aggregate.count(undefined, { - output: { parse: () => 1 } - }) - })) + query(knex, Task).select(() => ({ + count: aggregate.count(undefined, { + output: { parse: () => 1 } + }) + })) ).toThrow(/introspectable/); }); - it('rejects entry after legacy shape changes', () => { - expect(() => + it('exposes metadata automatically and requires schemas for opaque SQL', () => { + expect( query(knex, Task) .orderBy(t => t.id) - .withRowSchema() - ).toThrow(/before ordering/); - expect(() => query(knex, Task).limit(1).withRowSchema()).toThrow( - /before ordering/ - ); - expect(() => query(knex, Task).offset(1).withRowSchema()).toThrow( - /before ordering/ - ); - expect(() => - query(knex, Task) - .select(t => ({ id: t.id })) - .withRowSchema() - ).toThrow(/before/); + .limit(1).rowSchema + ).toBeDefined(); + expect( + Object.keys( + query(knex, Task) + .select(t => ({ id: t.id })) + .rowSchema.introspect().properties + ) + ).toEqual(['id']); expect(() => - query(knex, Task).selectRaw('1 as other').withRowSchema() - ).toThrow(); + (query(knex, Task) as any).selectRaw('1 as other', []) + ).toThrow(/output/); expect(() => - query(knex, Task) - .apply(q => q.whereRaw('true')) - .withRowSchema() - ).toThrow(/before/); + (query(knex, Task) as any).apply((q: any) => q.whereRaw('true')) + ).toThrow(/output/); expect(() => - query(knex, alias(Task, 'task')) - .apply(q => q.select('id')) - .withRowSchema() - ).toThrow(/before/); + (query(knex, alias(Task, 'task')) as any).apply((q: any) => + q.select('id') + ) + ).toThrow(/output/); }); it('describes immutable flat left joins with SQL nulls', () => { - const base = query(knex, alias(Task, 'task')).withRowSchema(); + const base = query(knex, alias(Task, 'task')); expect(() => base.rowSchema).toThrow(/explicit select/); const joined = base .leftJoin(alias(Task, 'other'), t => eq(t.task.id, t.other.id)) diff --git a/libs/knex-schema/src/read-schema.ts b/libs/knex-schema/src/read-schema.ts index a075e2f2..16e8399f 100644 --- a/libs/knex-schema/src/read-schema.ts +++ b/libs/knex-schema/src/read-schema.ts @@ -13,6 +13,7 @@ import { union } from '@cleverbrush/schema'; import type { Knex } from 'knex'; +import { buildColumnMap } from './columns.js'; /** A schema builder accepted by the database-read schema compiler. */ export type ReadSchema = SchemaBuilder; @@ -298,9 +299,36 @@ export function decodeObject( export function readExpression( knex: Knex, node: ReadNode, - column: string + column: string | Knex.Raw ): Knex.Raw { return node.exact || node.schema.introspect().type === 'date' ? knex.raw('cast(?? as text)', [column]) : knex.raw('??', [column]); } + +/** @internal Preserve exact numerics and dates before driver parsing of write-returning rows. */ +export function returningReadColumns( + knex: Knex, + source: ReadObject +): Knex.Raw[] { + const info = source.introspect(); + const excluded = new Set( + ((info.extensions?.relations ?? []) as { name: string }[]).map( + relation => relation.name + ) + ); + const { propToCol } = buildColumnMap(source); + return Object.entries(info.properties) + .filter(([key]) => !excluded.has(key)) + .map(([key, schema]) => { + const column = propToCol.get(key) ?? key; + return knex.raw('? as ??', [ + readExpression( + knex, + compileReadSchema(schema as ReadSchema), + column + ), + column + ]); + }); +} diff --git a/libs/knex-schema/src/types.ts b/libs/knex-schema/src/types.ts index cd070d25..2b74183d 100644 --- a/libs/knex-schema/src/types.ts +++ b/libs/knex-schema/src/types.ts @@ -7,7 +7,10 @@ import type { PropertyDescriptorTree } from '@cleverbrush/schema'; import type { Knex } from 'knex'; +import type { SchemaProps } from './entity.js'; import type { AggregateExpression } from './expressions.js'; +import type { ReadRelations } from './read-entity.js'; +import type { ObjectReadSchema, ReadValue } from './read-schema.js'; // --------------------------------------------------------------------------- // Utility: extract string keys from an ObjectSchemaBuilder's inferred type @@ -258,18 +261,16 @@ export type ValidatedSpec = */ export type InsertType< T extends ObjectSchemaBuilder -> = InferType>; +> = { + [K in Exclude, keyof ReadRelations>]?: + | InferType[K]> + | ReadValue[K]>; +}; // --------------------------------------------------------------------------- // Database row helpers // --------------------------------------------------------------------------- -type OptionalKeys = { - [K in keyof T]-?: undefined extends T[K] ? K : never; -}[keyof T]; - -type RequiredKeys = Exclude>; - /** * Normalize a schema-inferred property type to the value shape commonly * returned by database rows. @@ -290,11 +291,7 @@ export type InferDatabaseValue = undefined extends T */ export type InferDatabaseRow< T extends ObjectSchemaBuilder -> = { - [K in RequiredKeys>]: InferDatabaseValue[K]>; -} & { - [K in OptionalKeys>]?: InferDatabaseValue[K]>; -}; +> = InferType>>; // --------------------------------------------------------------------------- // Primary-key type helpers (driven by PRIMARY_KEY_BRAND / COMPOSITE_PRIMARY_KEY_BRAND) @@ -379,7 +376,12 @@ export type PrimaryKeyValueOf< ? PkTupleValue> : never : PrimaryKeyOf extends string - ? InferType[PrimaryKeyOf & keyof InferType] + ? + | InferType[PrimaryKeyOf & keyof InferType] + | ReadValue< + SchemaPropsForPk[PrimaryKeyOf & + keyof SchemaPropsForPk] + > : never; /** @@ -392,7 +394,11 @@ type PkTupleValue< TKeys extends readonly string[] > = { [I in keyof TKeys]: TKeys[I] extends keyof InferType - ? InferType[TKeys[I]] + ? + | InferType[TKeys[I]] + | ReadValue< + SchemaPropsForPk[TKeys[I] & keyof SchemaPropsForPk] + > : unknown; }; diff --git a/libs/knex-schema/src/unit.test.ts b/libs/knex-schema/src/unit.test.ts index 18a70a4e..8987ff3c 100644 --- a/libs/knex-schema/src/unit.test.ts +++ b/libs/knex-schema/src/unit.test.ts @@ -18,6 +18,19 @@ import { string } from './index.js'; +import { QuerySource } from './QuerySource.js'; +import type { ReadObject } from './read-schema.js'; + +// Preserve low-level SQL planner regressions independently of public immutable +// queries (covered by immutable-query, read-predicates and PostgreSQL suites). +function privateSource( + connection: KnexType, + schema: S, + base?: KnexType.QueryBuilder +) { + return new QuerySource(connection, schema, base); +} + // ═══════════════════════════════════════════════════════════════════════════ // Test schemas // ═══════════════════════════════════════════════════════════════════════════ @@ -180,43 +193,43 @@ describe('resolveColumnRef', () => { // Query builder — SQL snapshot tests // ═══════════════════════════════════════════════════════════════════════════ -describe('SchemaQueryBuilder', () => { +describe('private QuerySource planner', () => { describe('basic SELECT', () => { it('produces SELECT * FROM table', () => { - const sql = query(knex, User).toQuery(); + const sql = privateSource(knex, User).toQuery(); expect(sql).toBe('select * from "users"'); }); it('produces SELECT with SimpleTag (no column mapping needed)', () => { - const sql = query(knex, SimpleTag).toQuery(); + const sql = privateSource(knex, SimpleTag).toQuery(); expect(sql).toBe('select * from "tags"'); }); }); describe('WHERE', () => { it('.where with property descriptor', () => { - const sql = query(knex, User) + const sql = privateSource(knex, User) .where(t => t.fullName, '=', 'John') .toQuery(); expect(sql).toContain('"full_name" = \'John\''); }); it('.where with string property key', () => { - const sql = query(knex, User) + const sql = privateSource(knex, User) .where('fullName', '=', 'John') .toQuery(); expect(sql).toContain('"full_name" = \'John\''); }); it('.where with default column name', () => { - const sql = query(knex, User) + const sql = privateSource(knex, User) .where('email', '=', 'test@test.com') .toQuery(); expect(sql).toContain('"email" = \'test@test.com\''); }); it('.where with record syntax', () => { - const sql = query(knex, User) + const sql = privateSource(knex, User) .where({ fullName: 'John', role: 'admin' }) .toQuery(); expect(sql).toContain('"full_name" = \'John\''); @@ -224,7 +237,7 @@ describe('SchemaQueryBuilder', () => { }); it('.where with callback (knex sub-builder)', () => { - const sql = query(knex, User) + const sql = privateSource(knex, User) .where((builder: KnexType.QueryBuilder) => { builder.where('role', 'admin'); }) @@ -233,42 +246,42 @@ describe('SchemaQueryBuilder', () => { }); it('.whereIn with property descriptor', () => { - const sql = query(knex, User) + const sql = privateSource(knex, User) .whereIn(t => t.role, ['admin', 'user']) .toQuery(); expect(sql).toContain("\"role\" in ('admin', 'user')"); }); it('.whereNotIn', () => { - const sql = query(knex, User) + const sql = privateSource(knex, User) .whereNotIn('role', ['banned']) .toQuery(); expect(sql).toContain('"role" not in (\'banned\')'); }); it('.whereNull with descriptor', () => { - const sql = query(knex, User) + const sql = privateSource(knex, User) .whereNull(t => t.managerId) .toQuery(); expect(sql).toContain('"manager_id" is null'); }); it('.whereNotNull', () => { - const sql = query(knex, User) + const sql = privateSource(knex, User) .whereNotNull(t => t.managerId) .toQuery(); expect(sql).toContain('"manager_id" is not null'); }); it('.whereBetween', () => { - const sql = query(knex, User) + const sql = privateSource(knex, User) .whereBetween(t => t.departmentId, [1, 10]) .toQuery(); expect(sql).toContain('"department_id" between 1 and 10'); }); it('.andWhere / .orWhere chaining', () => { - const sql = query(knex, User) + const sql = privateSource(knex, User) .where('role', '=', 'admin') .andWhere(t => t.departmentId, '>', 5) .orWhere('email', 'like', '%@co.com') @@ -279,7 +292,7 @@ describe('SchemaQueryBuilder', () => { }); it('.whereRaw passthrough', () => { - const sql = query(knex, User) + const sql = privateSource(knex, User) .whereRaw('full_name ILIKE ?', '%smith%') .toQuery(); expect(sql).toContain("full_name ILIKE '%smith%'"); @@ -288,21 +301,24 @@ describe('SchemaQueryBuilder', () => { describe('ORDER BY', () => { it('.orderBy with descriptor', () => { - const sql = query(knex, User) + const sql = privateSource(knex, User) .orderBy(t => t.createdAt, 'desc') .toQuery(); expect(sql).toContain('order by "created_at" desc'); }); it('.orderBy with string key', () => { - const sql = query(knex, User).orderBy('fullName').toQuery(); + const sql = privateSource(knex, User).orderBy('fullName').toQuery(); expect(sql).toContain('order by "full_name"'); }); }); describe('LIMIT / OFFSET', () => { it('.limit and .offset', () => { - const sql = query(knex, User).limit(10).offset(20).toQuery(); + const sql = privateSource(knex, User) + .limit(10) + .offset(20) + .toQuery(); expect(sql).toContain('limit 10'); expect(sql).toContain('offset 20'); }); @@ -310,14 +326,14 @@ describe('SchemaQueryBuilder', () => { describe('GROUP BY / HAVING', () => { it('.groupBy with descriptor', () => { - const sql = query(knex, User) + const sql = privateSource(knex, User) .groupBy(t => t.role) .toQuery(); expect(sql).toContain('group by "role"'); }); it('.having', () => { - const sql = query(knex, User) + const sql = privateSource(knex, User) .groupBy('role') .having('role', '!=', 'banned') .toQuery(); @@ -328,7 +344,7 @@ describe('SchemaQueryBuilder', () => { describe('SELECT / DISTINCT', () => { it('.select with descriptors', () => { - const sql = query(knex, User) + const sql = privateSource(knex, User) .select( t => t.fullName, t => t.email @@ -339,7 +355,7 @@ describe('SchemaQueryBuilder', () => { }); it('.distinct with descriptor', () => { - const sql = query(knex, User) + const sql = privateSource(knex, User) .distinct(t => t.role) .toQuery(); expect(sql).toContain('distinct "role"'); @@ -348,7 +364,7 @@ describe('SchemaQueryBuilder', () => { describe('escape hatch', () => { it('.apply passes through to knex builder', () => { - const sql = query(knex, User) + const sql = privateSource(knex, User) .apply(qb => { qb.where('id', '>', 100); }) @@ -359,7 +375,7 @@ describe('SchemaQueryBuilder', () => { describe('chained queries', () => { it('complex chained query', () => { - const sql = query(knex, User) + const sql = privateSource(knex, User) .where(t => t.role, '=', 'admin') .andWhere(t => t.departmentId, '>', 5) .whereNotNull(t => t.managerId) @@ -385,7 +401,7 @@ describe('SchemaQueryBuilder', () => { describe('eager loading', () => { it('joinOne produces CTE with jsonb_agg', () => { - const sql = query(knex, User) + const sql = privateSource(knex, User) .joinOne({ localColumn: t => t.departmentId, foreignColumn: t => t.id, @@ -401,7 +417,7 @@ describe('eager loading', () => { }); it('joinMany produces CTE with jsonb_agg and coalesce', () => { - const sql = query(knex, User) + const sql = privateSource(knex, User) .joinMany({ localColumn: t => t.id, foreignColumn: t => t.authorId, @@ -417,7 +433,7 @@ describe('eager loading', () => { }); it('joinOne with string column refs', () => { - const sql = query(knex, User) + const sql = privateSource(knex, User) .joinOne({ localColumn: 'departmentId', foreignColumn: 'id', @@ -430,7 +446,7 @@ describe('eager loading', () => { }); it('joinMany with limit and orderBy', () => { - const sql = query(knex, User) + const sql = privateSource(knex, User) .joinMany({ localColumn: t => t.id, foreignColumn: t => t.authorId, @@ -446,7 +462,7 @@ describe('eager loading', () => { }); it('chained joinOne + joinMany', () => { - const sql = query(knex, User) + const sql = privateSource(knex, User) .joinOne({ localColumn: t => t.departmentId, foreignColumn: t => t.id, @@ -468,7 +484,7 @@ describe('eager loading', () => { }); it('joinOne with explicit foreignQuery as raw knex', () => { - const sql = query(knex, User) + const sql = privateSource(knex, User) .joinOne({ localColumn: t => t.departmentId, foreignColumn: t => t.id, @@ -482,13 +498,13 @@ describe('eager loading', () => { }); it('joinOne with SchemaQueryBuilder as foreignQuery', () => { - const sql = query(knex, User) + const sql = privateSource(knex, User) .joinOne({ localColumn: t => t.departmentId, foreignColumn: t => t.id, as: 'department', foreignSchema: Department, - foreignQuery: query(knex, Department).where( + foreignQuery: privateSource(knex, Department).where( t => t.budget, '>', 1000 @@ -500,7 +516,7 @@ describe('eager loading', () => { }); it('SchemaQueryBuilder foreignQuery produces same SQL as raw knex foreignQuery', () => { - const rawSql = query(knex, User) + const rawSql = privateSource(knex, User) .joinOne({ localColumn: t => t.departmentId, foreignColumn: t => t.id, @@ -510,13 +526,13 @@ describe('eager loading', () => { }) .toQuery(); - const schemaSql = query(knex, User) + const schemaSql = privateSource(knex, User) .joinOne({ localColumn: t => t.departmentId, foreignColumn: t => t.id, as: 'department', foreignSchema: Department, - foreignQuery: query(knex, Department).where( + foreignQuery: privateSource(knex, Department).where( t => t.budget, '>', 1000 @@ -528,13 +544,17 @@ describe('eager loading', () => { }); it('joinMany with SchemaQueryBuilder as foreignQuery', () => { - const sql = query(knex, User) + const sql = privateSource(knex, User) .joinMany({ localColumn: t => t.id, foreignColumn: t => t.authorId, as: 'posts', foreignSchema: Post, - foreignQuery: query(knex, Post).where(t => t.categoryId, '=', 5) + foreignQuery: privateSource(knex, Post).where( + t => t.categoryId, + '=', + 5 + ) }) .toQuery(); @@ -542,7 +562,7 @@ describe('eager loading', () => { }); it('joinMany SchemaQueryBuilder foreignQuery matches raw knex', () => { - const rawSql = query(knex, User) + const rawSql = privateSource(knex, User) .joinMany({ localColumn: t => t.id, foreignColumn: t => t.authorId, @@ -552,13 +572,17 @@ describe('eager loading', () => { }) .toQuery(); - const schemaSql = query(knex, User) + const schemaSql = privateSource(knex, User) .joinMany({ localColumn: t => t.id, foreignColumn: t => t.authorId, as: 'posts', foreignSchema: Post, - foreignQuery: query(knex, Post).where(t => t.categoryId, '=', 5) + foreignQuery: privateSource(knex, Post).where( + t => t.categoryId, + '=', + 5 + ) }) .toQuery(); @@ -567,7 +591,7 @@ describe('eager loading', () => { it('throws on duplicate field names', () => { expect(() => { - query(knex, User) + privateSource(knex, User) .joinOne({ localColumn: t => t.departmentId, foreignColumn: t => t.id, @@ -586,7 +610,7 @@ describe('eager loading', () => { it('joinOne with .select() still includes localColumn in CTE', () => { // If the caller uses .select() and omits the join key (departmentId), // the generated SQL should still include it in the CTE so the join works. - const sql = query(knex, User) + const sql = privateSource(knex, User) .select(t => t.fullName) // intentionally omit departmentId .joinOne({ localColumn: t => t.departmentId, @@ -603,7 +627,7 @@ describe('eager loading', () => { }); it('joinMany with .select() still includes localColumn in CTE', () => { - const sql = query(knex, User) + const sql = privateSource(knex, User) .select(t => t.fullName) // intentionally omit id (localColumn for joinMany) .joinMany({ localColumn: t => t.id, @@ -683,7 +707,7 @@ describe('mappers', () => { describe('validateMappers via joinOne/joinMany', () => { it('accepts a function mapper in joinOne spec', () => { expect(() => - query(knex, User).joinOne({ + privateSource(knex, User).joinOne({ localColumn: t => t.departmentId, foreignColumn: t => t.id, as: 'department', @@ -695,7 +719,7 @@ describe('mappers', () => { it('accepts a built-in string mapper name in joinOne spec', () => { expect(() => - query(knex, Post).joinOne({ + privateSource(knex, Post).joinOne({ localColumn: t => t.authorId, foreignColumn: t => t.id, as: 'author', @@ -707,7 +731,7 @@ describe('mappers', () => { it('rejects an unknown built-in string mapper name in joinOne spec', () => { expect(() => - query(knex, User).joinOne({ + privateSource(knex, User).joinOne({ localColumn: t => t.departmentId, foreignColumn: t => t.id, as: 'department', @@ -719,7 +743,7 @@ describe('mappers', () => { it('accepts a built-in string mapper name in joinMany spec', () => { expect(() => - query(knex, User).joinMany({ + privateSource(knex, User).joinMany({ localColumn: t => t.id, foreignColumn: t => t.authorId, as: 'posts', @@ -731,7 +755,7 @@ describe('mappers', () => { it('rejects a non-function, non-string mapper value', () => { expect(() => - query(knex, User).joinOne({ + privateSource(knex, User).joinOne({ localColumn: t => t.departmentId, foreignColumn: t => t.id, as: 'department', @@ -750,16 +774,18 @@ describe('mappers', () => { // keys → column names; all other knex behaviour is preserved unchanged. // ═══════════════════════════════════════════════════════════════════════════ -describe('SQL parity with raw knex', () => { +describe('private planner SQL parity with raw knex', () => { // ── SELECT ──────────────────────────────────────────────────────────── it('SELECT *', () => { - expect(query(knex, User).toQuery()).toBe(knex('users').toQuery()); + expect(privateSource(knex, User).toQuery()).toBe( + knex('users').toQuery() + ); }); it('SELECT specific columns (descriptor)', () => { expect( - query(knex, User) + privateSource(knex, User) .select( t => t.fullName, t => t.email, @@ -772,38 +798,38 @@ describe('SQL parity with raw knex', () => { }); it('SELECT specific columns (string key)', () => { - expect(query(knex, User).select('fullName', 'email').toQuery()).toBe( - knex('users').select('full_name', 'email').toQuery() - ); + expect( + privateSource(knex, User).select('fullName', 'email').toQuery() + ).toBe(knex('users').select('full_name', 'email').toQuery()); }); it('SELECT — identity mapping (no hasColumnName)', () => { - expect(query(knex, SimpleTag).select('id', 'name').toQuery()).toBe( - knex('tags').select('id', 'name').toQuery() - ); + expect( + privateSource(knex, SimpleTag).select('id', 'name').toQuery() + ).toBe(knex('tags').select('id', 'name').toQuery()); }); // ── DISTINCT ────────────────────────────────────────────────────────── it('DISTINCT (descriptor)', () => { expect( - query(knex, User) + privateSource(knex, User) .distinct(t => t.role) .toQuery() ).toBe(knex('users').distinct('role').toQuery()); }); it('DISTINCT (string key)', () => { - expect(query(knex, User).distinct('departmentId').toQuery()).toBe( - knex('users').distinct('department_id').toQuery() - ); + expect( + privateSource(knex, User).distinct('departmentId').toQuery() + ).toBe(knex('users').distinct('department_id').toQuery()); }); // ── WHERE ───────────────────────────────────────────────────────────── it('.where (operator, descriptor)', () => { expect( - query(knex, User) + privateSource(knex, User) .where(t => t.fullName, '=', 'Alice') .toQuery() ).toBe(knex('users').where('full_name', '=', 'Alice').toQuery()); @@ -811,19 +837,19 @@ describe('SQL parity with raw knex', () => { it('.where (operator, string key)', () => { expect( - query(knex, User).where('fullName', '=', 'Alice').toQuery() + privateSource(knex, User).where('fullName', '=', 'Alice').toQuery() ).toBe(knex('users').where('full_name', '=', 'Alice').toQuery()); }); it('.where (operator, identity column)', () => { - expect(query(knex, User).where('email', '=', 'a@b.com').toQuery()).toBe( - knex('users').where('email', '=', 'a@b.com').toQuery() - ); + expect( + privateSource(knex, User).where('email', '=', 'a@b.com').toQuery() + ).toBe(knex('users').where('email', '=', 'a@b.com').toQuery()); }); it('.where (record)', () => { expect( - query(knex, User) + privateSource(knex, User) .where({ fullName: 'Alice', role: 'admin' }) .toQuery() ).toBe( @@ -833,7 +859,7 @@ describe('SQL parity with raw knex', () => { it('.where (callback)', () => { expect( - query(knex, User) + privateSource(knex, User) .where((b: KnexType.QueryBuilder) => { b.where('role', 'admin'); }) @@ -849,7 +875,7 @@ describe('SQL parity with raw knex', () => { it('.andWhere (descriptor)', () => { expect( - query(knex, User) + privateSource(knex, User) .where('role', '=', 'admin') .andWhere(t => t.departmentId, '>', 5) .toQuery() @@ -863,7 +889,7 @@ describe('SQL parity with raw knex', () => { it('.orWhere (descriptor)', () => { expect( - query(knex, User) + privateSource(knex, User) .where('role', '=', 'admin') .orWhere(t => t.role, '=', 'editor') .toQuery() @@ -877,21 +903,21 @@ describe('SQL parity with raw knex', () => { it('.whereNot (descriptor)', () => { expect( - query(knex, User) + privateSource(knex, User) .whereNot(t => t.role, 'banned') .toQuery() ).toBe(knex('users').whereNot('role', 'banned').toQuery()); }); it('.whereNot (string key)', () => { - expect(query(knex, User).whereNot('departmentId', 99).toQuery()).toBe( - knex('users').whereNot('department_id', 99).toQuery() - ); + expect( + privateSource(knex, User).whereNot('departmentId', 99).toQuery() + ).toBe(knex('users').whereNot('department_id', 99).toQuery()); }); it('.whereIn (descriptor)', () => { expect( - query(knex, User) + privateSource(knex, User) .whereIn(t => t.role, ['admin', 'editor']) .toQuery() ).toBe(knex('users').whereIn('role', ['admin', 'editor']).toQuery()); @@ -899,13 +925,15 @@ describe('SQL parity with raw knex', () => { it('.whereIn (string key, mapped column)', () => { expect( - query(knex, User).whereIn('departmentId', [1, 2, 3]).toQuery() + privateSource(knex, User) + .whereIn('departmentId', [1, 2, 3]) + .toQuery() ).toBe(knex('users').whereIn('department_id', [1, 2, 3]).toQuery()); }); it('.whereNotIn (descriptor)', () => { expect( - query(knex, User) + privateSource(knex, User) .whereNotIn(t => t.role, ['banned']) .toQuery() ).toBe(knex('users').whereNotIn('role', ['banned']).toQuery()); @@ -913,7 +941,7 @@ describe('SQL parity with raw knex', () => { it('.whereNull (descriptor)', () => { expect( - query(knex, User) + privateSource(knex, User) .whereNull(t => t.managerId) .toQuery() ).toBe(knex('users').whereNull('manager_id').toQuery()); @@ -921,7 +949,7 @@ describe('SQL parity with raw knex', () => { it('.whereNotNull (descriptor)', () => { expect( - query(knex, User) + privateSource(knex, User) .whereNotNull(t => t.managerId) .toQuery() ).toBe(knex('users').whereNotNull('manager_id').toQuery()); @@ -929,7 +957,7 @@ describe('SQL parity with raw knex', () => { it('.orWhereNull (descriptor)', () => { expect( - query(knex, User) + privateSource(knex, User) .whereNull(t => t.managerId) .orWhereNull(t => t.departmentId) .toQuery() @@ -943,7 +971,7 @@ describe('SQL parity with raw knex', () => { it('.orWhereNotNull (descriptor)', () => { expect( - query(knex, User) + privateSource(knex, User) .whereNull(t => t.managerId) .orWhereNotNull(t => t.departmentId) .toQuery() @@ -957,7 +985,7 @@ describe('SQL parity with raw knex', () => { it('.whereBetween (descriptor)', () => { expect( - query(knex, User) + privateSource(knex, User) .whereBetween(t => t.departmentId, [1, 10]) .toQuery() ).toBe(knex('users').whereBetween('department_id', [1, 10]).toQuery()); @@ -965,7 +993,7 @@ describe('SQL parity with raw knex', () => { it('.whereNotBetween (string key)', () => { expect( - query(knex, User) + privateSource(knex, User) .whereNotBetween('departmentId', [20, 30]) .toQuery() ).toBe( @@ -975,7 +1003,9 @@ describe('SQL parity with raw knex', () => { it('.whereRaw passthrough', () => { expect( - query(knex, User).whereRaw('full_name ILIKE ?', '%smith%').toQuery() + privateSource(knex, User) + .whereRaw('full_name ILIKE ?', '%smith%') + .toQuery() ).toBe( knex('users').whereRaw('full_name ILIKE ?', '%smith%').toQuery() ); @@ -985,21 +1015,21 @@ describe('SQL parity with raw knex', () => { it('.orderBy asc (descriptor)', () => { expect( - query(knex, User) + privateSource(knex, User) .orderBy(t => t.fullName, 'asc') .toQuery() ).toBe(knex('users').orderBy('full_name', 'asc').toQuery()); }); it('.orderBy desc (string key)', () => { - expect(query(knex, User).orderBy('createdAt', 'desc').toQuery()).toBe( - knex('users').orderBy('created_at', 'desc').toQuery() - ); + expect( + privateSource(knex, User).orderBy('createdAt', 'desc').toQuery() + ).toBe(knex('users').orderBy('created_at', 'desc').toQuery()); }); it('.orderByRaw passthrough', () => { expect( - query(knex, User) + privateSource(knex, User) .orderByRaw('"created_at" DESC NULLS LAST') .toQuery() ).toBe( @@ -1010,19 +1040,19 @@ describe('SQL parity with raw knex', () => { // ── LIMIT / OFFSET ──────────────────────────────────────────────────── it('.limit', () => { - expect(query(knex, User).limit(25).toQuery()).toBe( + expect(privateSource(knex, User).limit(25).toQuery()).toBe( knex('users').limit(25).toQuery() ); }); it('.offset', () => { - expect(query(knex, User).offset(50).toQuery()).toBe( + expect(privateSource(knex, User).offset(50).toQuery()).toBe( knex('users').offset(50).toQuery() ); }); it('.limit + .offset', () => { - expect(query(knex, User).limit(10).offset(20).toQuery()).toBe( + expect(privateSource(knex, User).limit(10).offset(20).toQuery()).toBe( knex('users').limit(10).offset(20).toQuery() ); }); @@ -1031,33 +1061,33 @@ describe('SQL parity with raw knex', () => { it('.groupBy (descriptor)', () => { expect( - query(knex, User) + privateSource(knex, User) .groupBy(t => t.role) .toQuery() ).toBe(knex('users').groupBy('role').toQuery()); }); it('.groupBy (string key, mapped column)', () => { - expect(query(knex, User).groupBy('departmentId').toQuery()).toBe( - knex('users').groupBy('department_id').toQuery() - ); + expect( + privateSource(knex, User).groupBy('departmentId').toQuery() + ).toBe(knex('users').groupBy('department_id').toQuery()); }); it('.groupBy multiple columns', () => { expect( - query(knex, User).groupBy('role', 'departmentId').toQuery() + privateSource(knex, User).groupBy('role', 'departmentId').toQuery() ).toBe(knex('users').groupBy('role', 'department_id').toQuery()); }); it('.groupByRaw passthrough', () => { - expect(query(knex, User).groupByRaw('"role"').toQuery()).toBe( + expect(privateSource(knex, User).groupByRaw('"role"').toQuery()).toBe( knex('users').groupByRaw('"role"').toQuery() ); }); it('.having (string key)', () => { expect( - query(knex, User) + privateSource(knex, User) .groupBy('role') .having('role', '!=', 'banned') .toQuery() @@ -1071,7 +1101,7 @@ describe('SQL parity with raw knex', () => { it('.havingRaw passthrough', () => { expect( - query(knex, User) + privateSource(knex, User) .groupBy('role') .havingRaw('count(*) > 5') .toQuery() @@ -1083,14 +1113,14 @@ describe('SQL parity with raw knex', () => { // ── AGGREGATES ──────────────────────────────────────────────────────── it('.count()', () => { - expect(query(knex, User).count().toQuery()).toBe( + expect(privateSource(knex, User).count().toQuery()).toBe( knex('users').count().toQuery() ); }); it('.count(column, descriptor)', () => { expect( - query(knex, User) + privateSource(knex, User) .count(t => t.id) .toQuery() ).toBe(knex('users').count('id').toQuery()); @@ -1098,7 +1128,7 @@ describe('SQL parity with raw knex', () => { it('.countDistinct(column, descriptor)', () => { expect( - query(knex, User) + privateSource(knex, User) .countDistinct(t => t.departmentId) .toQuery() ).toBe(knex('users').countDistinct('department_id').toQuery()); @@ -1106,7 +1136,7 @@ describe('SQL parity with raw knex', () => { it('.min (descriptor)', () => { expect( - query(knex, User) + privateSource(knex, User) .min(t => t.createdAt) .toQuery() ).toBe(knex('users').min('created_at').toQuery()); @@ -1114,20 +1144,20 @@ describe('SQL parity with raw knex', () => { it('.max (descriptor)', () => { expect( - query(knex, User) + privateSource(knex, User) .max(t => t.createdAt) .toQuery() ).toBe(knex('users').max('created_at').toQuery()); }); it('.sum (string key)', () => { - expect(query(knex, User).sum('departmentId').toQuery()).toBe( + expect(privateSource(knex, User).sum('departmentId').toQuery()).toBe( knex('users').sum('department_id').toQuery() ); }); it('.avg (string key)', () => { - expect(query(knex, User).avg('departmentId').toQuery()).toBe( + expect(privateSource(knex, User).avg('departmentId').toQuery()).toBe( knex('users').avg('department_id').toQuery() ); }); @@ -1136,7 +1166,7 @@ describe('SQL parity with raw knex', () => { it('combined: SELECT + WHERE + ORDER BY + LIMIT + OFFSET', () => { expect( - query(knex, User) + privateSource(knex, User) .select( t => t.fullName, t => t.email, @@ -1162,7 +1192,7 @@ describe('SQL parity with raw knex', () => { it('combined: WHERE complex + GROUP BY + HAVING', () => { expect( - query(knex, User) + privateSource(knex, User) .select(t => t.role) .whereIn(t => t.role, ['admin', 'editor']) .groupBy(t => t.role) @@ -1182,7 +1212,7 @@ describe('SQL parity with raw knex', () => { describe('knex.raw() as column argument', () => { it('.where(knex.raw()) — raw as full WHERE expression', () => { expect( - query(knex, User) + privateSource(knex, User) .where(knex.raw('status = ?', ['active'])) .toQuery() ).toBe( @@ -1194,7 +1224,7 @@ describe('SQL parity with raw knex', () => { it('.where(knex.raw(), operator, value) — raw as LHS column', () => { expect( - query(knex, User) + privateSource(knex, User) .where(knex.raw('"full_name"'), '=', 'Alice') .toQuery() ).toBe( @@ -1206,7 +1236,7 @@ describe('SQL parity with raw knex', () => { it('.andWhere(knex.raw())', () => { expect( - query(knex, User) + privateSource(knex, User) .where('role', '=', 'admin') .andWhere(knex.raw('deleted_at IS NULL')) .toQuery() @@ -1220,7 +1250,7 @@ describe('SQL parity with raw knex', () => { it('.orWhere(knex.raw())', () => { expect( - query(knex, User) + privateSource(knex, User) .where('role', '=', 'admin') .orWhere(knex.raw('role = ?', ['superuser'])) .toQuery() @@ -1234,7 +1264,7 @@ describe('SQL parity with raw knex', () => { it('.whereNot(knex.raw())', () => { expect( - query(knex, User) + privateSource(knex, User) .whereNot(knex.raw('deleted_at IS NULL')) .toQuery() ).toBe( @@ -1244,7 +1274,7 @@ describe('SQL parity with raw knex', () => { it('.select(knex.raw()) — computed expression', () => { expect( - query(knex, User) + privateSource(knex, User) .select(knex.raw('count(*) as total')) .toQuery() ).toBe( @@ -1254,7 +1284,7 @@ describe('SQL parity with raw knex', () => { it('.select() mixing schema column and knex.raw()', () => { expect( - query(knex, User) + privateSource(knex, User) .select(t => t.role, knex.raw('count(*) as total')) .toQuery() ).toBe( @@ -1266,13 +1296,13 @@ describe('SQL parity with raw knex', () => { it('.distinct(knex.raw())', () => { expect( - query(knex, User).distinct(knex.raw('"role"')).toQuery() + privateSource(knex, User).distinct(knex.raw('"role"')).toQuery() ).toBe(knex('users').distinct(knex.raw('"role"')).toQuery()); }); it('.orderBy(knex.raw())', () => { expect( - query(knex, User) + privateSource(knex, User) .orderBy(knex.raw('"created_at" DESC NULLS LAST')) .toQuery() ).toBe( @@ -1284,7 +1314,7 @@ describe('SQL parity with raw knex', () => { it('.groupBy(knex.raw())', () => { expect( - query(knex, User) + privateSource(knex, User) .groupBy(knex.raw("date_trunc('day', created_at)")) .toQuery() ).toBe( @@ -1296,7 +1326,7 @@ describe('SQL parity with raw knex', () => { it('.groupBy() mixing schema column and knex.raw()', () => { expect( - query(knex, User) + privateSource(knex, User) .groupBy( t => t.role, knex.raw("date_trunc('day', created_at)") @@ -1311,7 +1341,7 @@ describe('SQL parity with raw knex', () => { it('.having(knex.raw(), operator, value)', () => { expect( - query(knex, User) + privateSource(knex, User) .groupBy(t => t.role) .having(knex.raw('count(*)'), '>', 5) .toQuery() @@ -1335,7 +1365,15 @@ describe('createQuery factory', () => { const q = createQuery(knex); it('produces same SQL as query(knex, schema) for SELECT *', () => { - expect(q(User).toQuery()).toBe(query(knex, User).toQuery()); + expect( + q(User) + .toQuery() + .replace(/__schema_read_\d+/g, '__schema_read') + ).toBe( + query(knex, User) + .toQuery() + .replace(/__schema_read_\d+/g, '__schema_read') + ); }); it('produces same SQL for WHERE via descriptor', () => { @@ -1343,10 +1381,12 @@ describe('createQuery factory', () => { q(User) .where(t => t.fullName, '=', 'Alice') .toQuery() + .replace(/__schema_read_\d+/g, '__schema_read') ).toBe( query(knex, User) .where(t => t.fullName, '=', 'Alice') .toQuery() + .replace(/__schema_read_\d+/g, '__schema_read') ); }); @@ -1357,27 +1397,22 @@ describe('createQuery factory', () => { .orderBy(t => t.createdAt, 'desc') .limit(10) .toQuery() + .replace(/__schema_read_\d+/g, '__schema_read') ).toBe( query(knex, User) .where(t => t.role, '=', 'admin') .orderBy(t => t.createdAt, 'desc') .limit(10) .toQuery() + .replace(/__schema_read_\d+/g, '__schema_read') ); }); - it('the baseQuery overload works', () => { - const base1 = knex('users').where('deleted_at', null); - const base2 = knex('users').where('deleted_at', null); - expect( - q(User, base1) - .where(t => t.role, '=', 'admin') - .toQuery() - ).toBe( - query(knex, User, base2) - .where(t => t.role, '=', 'admin') - .toQuery() - ); + it('raw SQL extensions declare their output explicitly', () => { + const schema = object({ role: string() }); + const configured = q(User).selectRaw('role', [], { output: schema }); + expect(configured.rowSchema).toBe(schema); + expect(configured.toQuery()).toContain('select role'); }); it('works with joinOne', () => { @@ -1390,6 +1425,7 @@ describe('createQuery factory', () => { foreignSchema: Department }) .toQuery() + .replace(/__schema_read_\d+/g, '__schema_read') ).toBe( query(knex, User) .joinOne({ @@ -1399,6 +1435,7 @@ describe('createQuery factory', () => { foreignSchema: Department }) .toQuery() + .replace(/__schema_read_\d+/g, '__schema_read') ); }); @@ -1412,6 +1449,7 @@ describe('createQuery factory', () => { foreignSchema: Post }) .toQuery() + .replace(/__schema_read_\d+/g, '__schema_read') ).toBe( query(knex, User) .joinMany({ @@ -1421,6 +1459,7 @@ describe('createQuery factory', () => { foreignSchema: Post }) .toQuery() + .replace(/__schema_read_\d+/g, '__schema_read') ); }); @@ -1430,7 +1469,15 @@ describe('createQuery factory', () => { // Both produce the same SQL — knex client config doesn't affect SQL // generation without a real connection, but they must be independent objects expect(q(User)).not.toBe(q2(User)); - expect(q(User).toQuery()).toBe(q2(User).toQuery()); + expect( + q(User) + .toQuery() + .replace(/__schema_read_\d+/g, '__schema_read') + ).toBe( + q2(User) + .toQuery() + .replace(/__schema_read_\d+/g, '__schema_read') + ); knex2.destroy(); }); }); @@ -1462,7 +1509,8 @@ describe('transaction support', () => { const sql = query(knex, User) .where(t => t.role, '=', 'admin') .transacting(trx) - .toQuery(); + .toQuery() + .replace(/__schema_read_\d+/g, '__schema_read'); expect(sql).toContain('"role" = \'admin\''); }); @@ -1470,8 +1518,9 @@ describe('transaction support', () => { const sql = query(knex, User) .orderBy(t => t.createdAt, 'desc') .transacting(trx) - .toQuery(); - expect(sql).toContain('order by "created_at" desc'); + .toQuery() + .replace(/__schema_read_\d+/g, '__schema_read'); + expect(sql).toContain('order by "__schema_read"."created_at" desc'); }); it('preserves LIMIT / OFFSET after transacting()', () => { @@ -1479,12 +1528,13 @@ describe('transaction support', () => { .limit(10) .offset(5) .transacting(trx) - .toQuery(); + .toQuery() + .replace(/__schema_read_\d+/g, '__schema_read'); expect(sql).toContain('limit 10'); expect(sql).toContain('offset 5'); }); - it('transacting() after joinOne preserves CTE structure', () => { + it('transacting() after joinOne preserves correlated relation SQL', () => { const sql = query(knex, User) .joinOne({ localColumn: t => t.departmentId, @@ -1493,15 +1543,16 @@ describe('transaction support', () => { foreignSchema: Department }) .transacting(trx) - .toQuery(); + .toQuery() + .replace(/__schema_read_\d+/g, '__schema_read'); - expect(sql).toContain('with "originalQuery" as'); + expect(sql).toContain('to_jsonb'); expect(sql).toContain('"departments"'); - expect(sql).toContain('jsonb_agg'); + expect(sql).toContain('limit 1'); expect(sql).toContain('"department"'); }); - it('transacting() after joinMany preserves CTE structure', () => { + it('transacting() after joinMany preserves correlated relation SQL', () => { const sql = query(knex, User) .joinMany({ localColumn: t => t.id, @@ -1510,9 +1561,10 @@ describe('transaction support', () => { foreignSchema: Post }) .transacting(trx) - .toQuery(); + .toQuery() + .replace(/__schema_read_\d+/g, '__schema_read'); - expect(sql).toContain('with "originalQuery" as'); + expect(sql).toContain('to_jsonb'); expect(sql).toContain('"posts"'); expect(sql).toContain('jsonb_agg'); expect(sql).toContain('coalesce'); @@ -1522,13 +1574,15 @@ describe('transaction support', () => { const plain = query(knex, User) .where(t => t.departmentId, '>', 3) .orderBy(t => t.fullName) - .toQuery(); + .toQuery() + .replace(/__schema_read_\d+/g, '__schema_read'); const transacted = query(knex, User) .where(t => t.departmentId, '>', 3) .orderBy(t => t.fullName) .transacting(trx) - .toQuery(); + .toQuery() + .replace(/__schema_read_\d+/g, '__schema_read'); expect(transacted).toBe(plain); }); @@ -1538,7 +1592,8 @@ describe('transaction support', () => { .transacting(trx) .where(t => t.role, '=', 'editor') .limit(20) - .toQuery(); + .toQuery() + .replace(/__schema_read_\d+/g, '__schema_read'); expect(sql).toContain('"role" = \'editor\''); expect(sql).toContain('limit 20'); @@ -1556,7 +1611,15 @@ describe('transaction support', () => { it('withTransaction() factory produces same SQL as query(trx, schema)', () => { const dbTrx = db.withTransaction(trx); - expect(dbTrx(User).toQuery()).toBe(query(knex, User).toQuery()); + expect( + dbTrx(User) + .toQuery() + .replace(/__schema_read_\d+/g, '__schema_read') + ).toBe( + query(knex, User) + .toQuery() + .replace(/__schema_read_\d+/g, '__schema_read') + ); }); it('withTransaction() factory supports chaining', () => { @@ -1565,17 +1628,24 @@ describe('transaction support', () => { .where(t => t.role, '=', 'admin') .orderBy(t => t.createdAt, 'desc') .limit(5) - .toQuery(); + .toQuery() + .replace(/__schema_read_\d+/g, '__schema_read'); expect(sql).toContain('"role" = \'admin\''); - expect(sql).toContain('order by "created_at" desc'); + expect(sql).toContain('order by "__schema_read"."created_at" desc'); expect(sql).toContain('limit 5'); }); it('withTransaction() does not affect the original bound factory', () => { - const plainSql = db(User).toQuery(); + const plainSql = db(User) + .toQuery() + .replace(/__schema_read_\d+/g, '__schema_read'); db.withTransaction(trx); // should not mutate db - expect(db(User).toQuery()).toBe(plainSql); + expect( + db(User) + .toQuery() + .replace(/__schema_read_\d+/g, '__schema_read') + ).toBe(plainSql); }); it('withTransaction() supports joinOne', () => { @@ -1587,7 +1657,8 @@ describe('transaction support', () => { as: 'department', foreignSchema: Department }) - .toQuery(); + .toQuery() + .replace(/__schema_read_\d+/g, '__schema_read'); expect(sql).toContain('"departments"'); expect(sql).toContain('"department"'); @@ -1650,7 +1721,8 @@ describe('transaction support', () => { await db.transaction(async dbTrx => { sql = dbTrx(User) .where(t => t.role, '=', 'admin') - .toQuery(); + .toQuery() + .replace(/__schema_read_\d+/g, '__schema_read'); }); } finally { spy.mockRestore(); @@ -1672,7 +1744,8 @@ describe('default extensions', () => { }).hasTableName('test'); const sql = db(Schema) .where(t => t.id, '=', '1234') - .toQuery(); + .toQuery() + .replace(/__schema_read_\d+/g, '__schema_read'); expect(sql).toContain('"id" = \'1234\''); }); }); diff --git a/libs/knex-schema/src/validate.ts b/libs/knex-schema/src/validate.ts index d54a9bf2..5a46cb73 100644 --- a/libs/knex-schema/src/validate.ts +++ b/libs/knex-schema/src/validate.ts @@ -15,7 +15,7 @@ import type { /** * Resolve foreignQuery: use the provided one, or auto-derive from * the foreign schema's tableName extension. - * Also normalizes SchemaQueryBuilder instances to raw Knex.QueryBuilder + * Also normalizes QuerySource instances to raw Knex.QueryBuilder * by calling `.toKnexQuery()` if available. */ function resolveForeignQuery( diff --git a/libs/mapper/README.md b/libs/mapper/README.md index 4f0a7a5a..f2e54b7a 100644 --- a/libs/mapper/README.md +++ b/libs/mapper/README.md @@ -246,7 +246,7 @@ typed as synchronous that returns a promise/thenable throws when invoked. `configureSync()` API. Configure once and reuse the same source/target schema instances. Queries can -provide their projection schema through `.withRowSchema().rowSchema`; see the +provide their projection schema through `.rowSchema`; see the [projection-aware read guide](../knex-schema/README.md#projection-aware-reads), including separate definition/mapping/service files and explicit polymorphic dispatch. The mapper performs no database calls or application enrichment. diff --git a/libs/orm/README.md b/libs/orm/README.md index 6573d147..3037edee 100644 --- a/libs/orm/README.md +++ b/libs/orm/README.md @@ -13,6 +13,8 @@ EF-Core-like typed ORM layer on top of [`@cleverbrush/knex-schema`](../knex-sche --- +For the breaking immutable-query release, read the [v5 migration guide](../knex-schema/MIGRATION-v5.md). All published Framework packages advance together. + ## Installation ```sh @@ -80,7 +82,7 @@ const updated = await db.users.save({ id: 1, email: 'alice@example.com', name: ' | `.include(t => t.rel)` | Eager-loads a relation (chainable) | | `.save(graph)` | Insert or update a row graph (transactional) | | `.ofVariant(key)` | Return a typed `VariantDbSet` scoped to a polymorphic variant | -| `.withRowSchema()` | Creates a detached read-only query with a matching result schema | +| `.rowSchema` | Automatically describes the decoded result; reading metadata runs no SQL | | `.query()` | Returns the underlying `EntityQuery` for advanced querying | | `.withTransaction(trx)` | Returns a new `DbSet` bound to an existing transaction | @@ -211,15 +213,17 @@ async function updateUser(userId: number) { --- -## Detached reads with result schemas +## Immutable queries and projection schemas -`db.users.withRowSchema()` enters an immutable read-only API whose `rowSchema` -matches its decoded selection and includes. Results remain **detached even when -the context uses `{ tracking: true }`**. This avoids attaching partial projections -as incomplete tracked entities. Ordinary entity queries keep their old behavior. +Every DbSet/query chain is immutable and automatically exposes `rowSchema`. +Full entity reads still participate in the identity map when `{ tracking: true }`. +Selected, grouped, distinct and raw results are detached; partial rows never +replace tracked entities. Entity objects themselves remain mutable: edit a full +entity and call `saveChanges()` as before. Reads, reloads and write-returning rows +now consistently use exact bigint/decimal strings, `Date` objects and SQL `null`. ```ts -const read = db.users.withRowSchema() +const read = db.users .select(u => ({ id: u.id, name: u.name })); const Source = read.rowSchema; const toDto = mapper().configure(Source, UserDto, m => m) @@ -232,11 +236,12 @@ decoded in one SQL statement. STI/CTI readers expose `variantRowSchemas` for explicit application mapping. See the [read-schema consumer guide](../knex-schema/README.md#projection-aware-reads) for numeric/null/date rules, examples and compatibility boundaries. -Detached ordinary readers also support grouped `where`/`andWhere`/`orWhere`, +Ordinary queries also support grouped `where`/`andWhere`/`orWhere`, IN/EXISTS subqueries, bound `whereRaw`/`orderByRaw`, and `ref(selector)` for quoted column references. These operations preserve the reader's `rowSchema` identity and work in nested relation customizers; polymorphic branches use `forVariant()`. -Group callbacks are synchronous and predicate-only. See +Group callbacks are synchronous, immutable and predicate-only; always return +the configured group. Conditional filters must reassign the returned query. See [filtering and ordering](../knex-schema/README.md#filtering-and-ordering-without-changing-the-result-schema) for scoped search, subquery snapshots, pagination, and raw-SQL boundaries. diff --git a/libs/orm/src/change-tracker.ts b/libs/orm/src/change-tracker.ts index 84726117..edbd7657 100644 --- a/libs/orm/src/change-tracker.ts +++ b/libs/orm/src/change-tracker.ts @@ -15,10 +15,13 @@ import { buildColumnMap, getPrimaryKeyColumns, - getRowVersionColumn + getRowVersionColumn, + getVariants, + query as schemaQuery } from '@cleverbrush/knex-schema'; import type { Knex } from 'knex'; import { ConcurrencyError, InvariantViolationError } from './errors.js'; +import { insertVariant } from './variant-write.js'; // --------------------------------------------------------------------------- // Types @@ -210,6 +213,12 @@ function snapshotEntity(entity: object, schema: any): Record { properties?: Record; }; const propKeys = new Set(Object.keys(introspected?.properties ?? {})); + const variants = getVariants(schema); + const variant = + variants?.variants[(entity as any)[variants.discriminatorKey]]; + if (variant) + for (const key of Object.keys(variant.schema.introspect().properties)) + propKeys.add(key); const snap: Record = {}; for (const [k, v] of Object.entries(entity as Record)) { if (propKeys.has(k)) snap[k] = v; @@ -498,16 +507,15 @@ export class ChangeTracker { const tableName = config.schema.getExtension?.('tableName') as string; if (!tableName || pkInfo.propertyKeys.length === 0) return; - const { propToCol, colToProp } = buildColumnMap(config.schema); - const qb = knex(tableName); + let qb = schemaQuery(knex, config.schema as any) + .unscoped() + .withDeleted(); const pkValues = extractPkValues( config.schema, entity as Record ); for (let i = 0; i < pkInfo.propertyKeys.length; i++) { - const colName = - propToCol.get(pkInfo.propertyKeys[i]) ?? pkInfo.propertyKeys[i]; - qb.andWhere(colName, pkValues[i] as any); + qb = qb.andWhere(pkInfo.propertyKeys[i], pkValues[i]); } const row = await qb.first(); if (!row) return; @@ -517,7 +525,7 @@ export class ChangeTracker { for (const [col, val] of Object.entries( row as Record )) { - mapped[colToProp.get(col) ?? col] = val; + mapped[col] = val; } // Refresh snapshot and rowVersion entry.originalSnapshot = snapshotEntity(entity, config.schema); @@ -667,6 +675,9 @@ export class ChangeTracker { } } + // Keep generated values local until every statement has committed. + // A later concurrency failure must not advance in-memory IDs/versions. + const committedValues = new Map>(); // 4. Execute all changes in a single transaction await knex.transaction(async (trx: Knex.Transaction) => { // Inserts (Added) @@ -678,27 +689,20 @@ export class ChangeTracker { ) as string; if (!tableName) continue; - const { propToCol } = buildColumnMap(config.schema); const current = entry.entity as Record; - const row: Record = {}; - for (const [propKey, val] of Object.entries(current)) { - const colName = propToCol.get(propKey) ?? propKey; - if (val !== undefined) row[colName] = val; - } - const result = await trx(tableName).insert(row).returning('*'); - const returned = - Array.isArray(result) && result.length > 0 - ? result[0] - : null; - if (returned && typeof returned === 'object') { - const { colToProp } = buildColumnMap(config.schema); - const mapped = entry.entity as Record; - for (const [col, val] of Object.entries( - returned as Record - )) { - mapped[colToProp.get(col) ?? col] = val; - } - } + const variants = getVariants(config.schema as any); + const returned = variants + ? await insertVariant( + trx, + config.schema, + String(current[variants.discriminatorKey]), + current, + trx + ) + : await schemaQuery(trx, config.schema as any).insert( + current as any + ); + if (returned) committedValues.set(current, returned); inserted++; } @@ -718,6 +722,23 @@ export class ChangeTracker { // Build the SET clause — only changed columns, excluding PK const pkPropSet = new Set(pkInfo.propertyKeys); const updateData: Record = {}; + const variant = getVariants(config.schema)?.variants[ + entry.variantKey ?? '' + ]; + const variantColumns = variant + ? buildColumnMap(variant.schema).propToCol + : new Map(); + const variantData: Record = {}; + const put = (key: string, value: unknown) => { + const variantColumn = + !propToCol.has(key) && variantColumns.get(key); + if (variantColumn && variant?.storage === 'cti') { + if (variantColumn !== variant.foreignKey) + variantData[variantColumn] = value; + } else + updateData[variantColumn || propToCol.get(key) || key] = + value; + }; for (const propKey of Object.keys(entry.originalSnapshot)) { if (pkPropSet.has(propKey)) continue; if ( @@ -726,8 +747,7 @@ export class ChangeTracker { current[propKey] ) ) { - updateData[propToCol.get(propKey) ?? propKey] = - current[propKey]; + put(propKey, current[propKey]); } } // Also pick up new keys not in snapshot @@ -737,7 +757,7 @@ export class ChangeTracker { !(propKey in entry.originalSnapshot) && val !== undefined ) { - updateData[propToCol.get(propKey) ?? propKey] = val; + put(propKey, val); } } @@ -747,18 +767,34 @@ export class ChangeTracker { const rvCol = propToCol.get(rv.propertyKey) ?? rv.propertyKey; if (rv.strategy === 'increment') { - const newVal = Number(rv.snapshotValue ?? 0) + 1; + const newVal = + typeof rv.snapshotValue === 'string' + ? (BigInt(rv.snapshotValue) + 1n).toString() + : Number(rv.snapshotValue ?? 0) + 1; + if ( + typeof newVal === 'number' && + !Number.isSafeInteger(newVal) + ) + throw new Error( + 'Row-version increment exceeds the safe integer range; use a bigint storage column' + ); updateData[rvCol] = newVal; - current[rv.propertyKey] = newVal; + committedValues.set(current, { + [rv.propertyKey]: newVal + }); } else if (rv.strategy === 'timestamp') { const now = new Date(); updateData[rvCol] = now; - current[rv.propertyKey] = now; + committedValues.set(current, { [rv.propertyKey]: now }); } // 'manual': caller already set the new value in current } - if (Object.keys(updateData).length === 0) continue; + if ( + Object.keys(updateData).length === 0 && + Object.keys(variantData).length === 0 + ) + continue; // Build WHERE clause with PK + optional rowVersion check let qb = trx(tableName); @@ -778,7 +814,11 @@ export class ChangeTracker { qb = qb.andWhere(rvCol, rv.snapshotValue as any) as any; } - const affected = await qb.update(updateData); + const affected = Object.keys(updateData).length + ? await qb.update(updateData) + : (await qb.forUpdate().first()) + ? 1 + : 0; if (affected === 0 && entry.rowVersion) { const tableName2 = config.schema.getExtension?.( 'tableName' @@ -789,6 +829,17 @@ export class ChangeTracker { entry.rowVersion.snapshotValue ); } + if ( + affected && + variant?.storage === 'cti' && + Object.keys(variantData).length + ) + await trx(variant.tableName!) + .where( + variant.foreignKey!, + current[pkInfo.propertyKeys[0]] as any + ) + .update(variantData); updated++; } @@ -836,6 +887,9 @@ export class ChangeTracker { } }); + for (const [entity, values] of committedValues) + Object.assign(entity, values); + // 5. Refresh snapshots for inserted and updated entries; detach deleted for (const entry of added) { entry.originalSnapshot = snapshotEntity( diff --git a/libs/orm/src/dbset.ts b/libs/orm/src/dbset.ts index 35110ac4..ff5c5787 100644 --- a/libs/orm/src/dbset.ts +++ b/libs/orm/src/dbset.ts @@ -8,15 +8,18 @@ // Calling any query method (`.where()`, `.include()`, `.first()`, `.insert()`, // etc.) on a `DbSet` allocates a fresh `SchemaQueryBuilder` and forwards the // call to it. Subsequent calls on the returned `EntityQuery` reuse that -// same underlying builder. +// independent immutable builders. import type { - ColumnRef, Entity, EntityRelations, EntitySchema, + PolymorphicQueryBuilder, PrimaryKeyValueOf, - SchemaAwareQuery + ReadQueryShape, + SchemaAwareQuery, + SchemaForValue, + VariantReadSchemas } from '@cleverbrush/knex-schema'; import { getPrimaryKeyColumns, @@ -24,7 +27,7 @@ import { type SchemaQueryBuilder, query as schemaQuery } from '@cleverbrush/knex-schema'; -import type { InferType } from '@cleverbrush/schema'; +import type { InferType, ObjectSchemaBuilder } from '@cleverbrush/schema'; import type { Knex } from 'knex'; import { EntityNotFoundError } from './errors.js'; @@ -37,7 +40,6 @@ import type { VariantInsertPayload, VariantResult, VariantUpdatePayload, - WithIncluded, WithVariantIncluded } from './result-types.js'; import { saveGraph } from './save-graph.js'; @@ -47,9 +49,45 @@ import { updateVariant as _updateVariant } from './variant-write.js'; +type EntityRowSchema = ObjectSchemaBuilder< + { [K in keyof T & string]-?: SchemaForValue }, + true, + false, + T +>; +type WriteMethod = + | 'insert' + | 'insertMany' + | 'update' + | 'delete' + | 'hardDelete' + | 'restore' + | 'bulkInsert' + | 'bulkUpdate' + | 'bulkUpsert' + | 'upsert' + | 'onConflict'; +type EntityWrites< + TEntity extends Entity, + TResult, + Writable extends boolean +> = { + [K in WriteMethod]: Writable extends true + ? OmitThisParameter< + SchemaQueryBuilder< + EntitySchema, + EntityRowSchema + >[K] + > + : never; +}; + // These methods return scalars or detached read plans, not tracked entity rows. const untrackedResultMethods = new Set([ - 'withRowSchema', + 'apply', + 'selectRaw', + 'toKnexQuery', + 'pluck', 'countValue', 'countDistinctValue', 'sumValue', @@ -73,30 +111,79 @@ const untrackedResultMethods = new Set([ * * @public */ -export interface EntityQuery, TResult> - extends Omit< - SchemaQueryBuilder, TResult>, - 'include' | 'includeVariant' | 'withRowSchema' - > { - /** - * Start an immutable detached read model with inferred runtime row schemas. - * Enable before select/include operations; results never attach to tracking. - */ - withRowSchema(): SchemaAwareQuery>; +export type EntityQuery< + TEntity extends Entity, + TResult, + Writable extends boolean = true +> = + SchemaAwareQuery> extends PolymorphicQueryBuilder< + any, + any + > + ? PolymorphicEntityQuery + : TableEntityQuery; + +/** A tracked-capable polymorphic read; projections use forVariant(). */ +export interface PolymorphicEntityQuery> + extends PolymorphicQueryBuilder>, + Pick< + TableEntityQuery>, + 'find' | 'findOrFail' | 'findMany' + > {} + +/** Table query with ORM identity tracking and primary-key lookup helpers. */ +export interface TableEntityQuery< + TEntity extends Entity, + TResult, + Writable extends boolean = true +> extends Omit< + SchemaQueryBuilder< + EntitySchema, + EntityRowSchema, + EntityRelations, + Writable + >, + 'include' | 'includeVariant' | WriteMethod + >, + EntityWrites { + /** Configure a discriminator branch with the canonical strongly typed query API. */ + forVariant: SchemaAwareQuery> extends { + forVariant: infer F; + } + ? F + : never; + /** Restrict a polymorphic query to declared variants and narrow its row schema. */ + selectVariants: SchemaAwareQuery> extends { + selectVariants: infer F; + } + ? F + : never; /** * Eager-load a relation declared on `TEntity` via `.hasOne()` / * `.hasMany()` / `.belongsTo()` / `.belongsToMany()`. Selector returns * the relation key as a string literal. */ - include & string>( + include< + K extends keyof EntityRelations & string, + Child extends ReadQueryShape = SchemaAwareQuery< + RelatedSchema + > + >( sel: (t: RelKeyTree) => K, customize?: ( - q: SchemaQueryBuilder< - RelatedSchema, - InferType> - > - ) => void - ): EntityQuery>; + query: SchemaAwareQuery> + ) => Child + ): EntityQuery< + TEntity, + TResult & { + [P in K]: EntityRelations[K] extends { + kind: 'hasMany' | 'belongsToMany'; + } + ? InferType[] + : InferType | null; + }, + false + >; /** * Eager-load a relation declared inside a polymorphic variant (CTI/STI). @@ -112,10 +199,10 @@ export interface EntityQuery, TResult> q: TRel extends keyof EntityRelations ? SchemaQueryBuilder< RelatedSchema, - InferType> + EntityRowSchema>> > : SchemaQueryBuilder - ) => void + ) => ReadQueryShape ): EntityQuery< TEntity, TRel extends keyof EntityRelations & string @@ -178,8 +265,14 @@ export interface EntityQuery, TResult> * * @public */ -export interface DbSet> - extends EntityQuery> { +export type DbSet> = EntityQuery< + TEntity, + EntityResult +> & + DbSetOperations; + +/** Entity registration, transactions and graph/variant write entry points. */ +export interface DbSetOperations> { /** The wrapped entity definition. */ readonly entity: TEntity; @@ -258,54 +351,13 @@ export interface DbSet> export interface VariantDbSet< TEntity extends Entity, K extends string -> extends Omit< - SchemaQueryBuilder, VariantResult>, - 'include' | 'includeVariant' | 'insert' | 'update' | 'delete' | 'where' +> extends PolymorphicQueryBuilder< + EntitySchema, + Pick< + VariantReadSchemas>, + Extract>> + > > { - // Re-declared so that `this` resolves to `VariantDbSet` - // rather than the raw `SchemaQueryBuilder` (Omit doesn't preserve `this`). - /** - * Add an AND filter on this polymorphic branch using a mapped property, record or Knex callback. - */ - where( - column: ColumnRef>, - operator: string, - value: any - ): this; - /** - * Add an AND filter on this polymorphic branch using a mapped property, record or Knex callback. - */ - where(column: ColumnRef>, value: any): this; - /** - * Add an AND filter on this polymorphic branch using a mapped property, record or Knex callback. - */ - where(raw: Knex.Raw, operator: string, value: any): this; - /** - * Add an AND filter on this polymorphic branch using a mapped property, record or Knex callback. - */ - where(callback: (builder: Knex.QueryBuilder) => void): this; - /** - * Add an AND filter on this polymorphic branch using a mapped property, record or Knex callback. - */ - where(record: Record): this; - /** - * Add an AND filter on this polymorphic branch using a mapped property, record or Knex callback. - */ - where(raw: Knex.Raw): this; - /** - * Eager-load a relation declared on `TEntity`. Identical to - * {@link EntityQuery.include}. - */ - include & string>( - sel: (t: RelKeyTree) => R, - customize?: ( - q: SchemaQueryBuilder< - RelatedSchema, - InferType> - > - ) => void - ): VariantDbSet; - /** Look up a single row by PK, typed to this variant. */ find( pk: PrimaryKeyValueOf> @@ -347,33 +399,6 @@ export interface VariantDbSet< // Runtime construction // --------------------------------------------------------------------------- -const ENTITY_KEY_TREE_CACHE = new WeakMap>(); - -function getEntityKeyTree( - entity: Entity -): Record { - const cached = ENTITY_KEY_TREE_CACHE.get(entity); - if (cached) return cached; - const props = - ( - entity.schema as { - introspect?: () => { properties?: Record }; - } - ).introspect?.()?.properties ?? {}; - const tree: Record = {}; - for (const k of Object.keys(props)) tree[k] = k; - ENTITY_KEY_TREE_CACHE.set(entity, tree); - return tree; -} - -/** - * Extract the Knex instance from a `SchemaQueryBuilder`. - * SchemaQueryBuilder stores it as `#knex` (private), but the `query()` - * factory function passes it as the first constructor argument. - * We retrieve it via the `.toQuery()` builder's knex client reference. - * @internal - */ - /** * Wrap a `SchemaQueryBuilder` in a Proxy that overlays typed * `.include()` / `.includeVariant()` methods and re-wraps `this`-returning @@ -382,7 +407,7 @@ function getEntityKeyTree( * @internal */ function wrapQuery, TResult>( - sqb: SchemaQueryBuilder, TResult>, + sqb: SchemaQueryBuilder, EntityRowSchema>, entity: TEntity, _knexInst: Knex, onResults?: (items: unknown[]) => unknown[] | undefined @@ -391,45 +416,6 @@ function wrapQuery, TResult>( sqb as unknown as object, { get(target, prop, receiver) { - if (prop === 'include') { - return ( - sel: (t: Record) => string, - customize?: (q: SchemaQueryBuilder) => void - ) => { - const name = sel(getEntityKeyTree(entity)); - ( - sqb as unknown as { - include: ( - n: string, - c?: ( - q: SchemaQueryBuilder - ) => void - ) => void; - } - ).include(name, customize); - return proxy; - }; - } - if (prop === 'includeVariant') { - return ( - variantKey: string, - relationName: string, - customize?: (q: SchemaQueryBuilder) => void - ) => { - ( - sqb as unknown as { - includeVariant: ( - v: string, - r: string, - c?: ( - q: SchemaQueryBuilder - ) => void - ) => void; - } - ).includeVariant(variantKey, relationName, customize); - return proxy; - }; - } if (prop === '_sqb') return sqb; if (prop === '_entity') return entity; @@ -466,9 +452,27 @@ function wrapQuery, TResult>( const value = Reflect.get(target, prop, receiver); if (typeof value !== 'function') return value; return function (this: unknown, ...args: unknown[]) { + if (prop === 'then') { + const [resolve, reject] = args; + return sqb + .execute() + .then(rows => { + if (!onResults || !sqb.returnsEntityRows) + return rows; + return onResults(rows) ?? rows; + }) + .then(resolve as any, reject as any); + } const result = (value as Function).apply(sqb, args); // Re-wrap `this`-returning methods so chains keep typing. if (result === sqb) return proxy; + if ( + result && + typeof result.execute === 'function' && + typeof result.sameSource === 'function' && + sqb.sameSource(result) + ) + return wrapQuery(result, entity, _knexInst, onResults); // Wrap Promise results to auto-attach tracked entities. if ( onResults != null && @@ -479,6 +483,21 @@ function wrapQuery, TResult>( ) { return (result as Promise).then( (resolved: unknown) => { + if ( + (prop === 'paginate' || + prop === 'paginateAfter') && + resolved && + typeof resolved === 'object' && + 'data' in resolved && + Array.isArray(resolved.data) + ) { + return { + ...resolved, + data: + onResults(resolved.data) ?? + resolved.data + }; + } if (Array.isArray(resolved)) { const entities = resolved.filter( r => @@ -544,9 +563,9 @@ function wrapQuery, TResult>( */ function makeFindMethod>( method: 'find' | 'findOrFail' | 'findMany', - sqb: SchemaQueryBuilder, + _sqb: SchemaQueryBuilder, entity: TEntity, - proxy: EntityQuery + proxy: any ): (...args: unknown[]) => Promise { return async (...args: unknown[]): Promise => { const pkInfo = getPrimaryKeyColumns( @@ -568,87 +587,51 @@ function makeFindMethod>( ).getExtension?.('tableName') ?? ''; const entityLabel = String(tableName); - const applyPkFilter = (pk: unknown): void => { + const tupleFor = (pk: unknown) => { const tuple = normalisePkTuple(pk, isComposite, method); - if (tuple.length !== propertyKeys.length) { + if (tuple.length !== propertyKeys.length) throw new Error( `${method}(): expected ${propertyKeys.length} primary-key value(s), got ${tuple.length}.` ); - } - for (let i = 0; i < propertyKeys.length; i++) { - ( - proxy as unknown as { - andWhere: ( - col: string, - op: string, - val: unknown - ) => void; - } - ).andWhere(propertyKeys[i], '=', tuple[i]); - } + return tuple; }; - if (method === 'findMany') { - const pks = (args[0] ?? []) as ReadonlyArray; - if (!Array.isArray(pks)) { + const pks = args[0] ?? []; + if (!Array.isArray(pks)) throw new Error( 'findMany(): expected an array of primary-key values.' ); - } - if (pks.length === 0) return []; - if (!isComposite) { - const propKey = propertyKeys[0]; - const tuples = pks.map(p => - normalisePkTuple(p, false, 'findMany') - ); - ( - proxy as unknown as { - whereIn: ( - col: string, - vals: readonly unknown[] - ) => void; - } - ).whereIn( - propKey, - tuples.map(t => t[0]) - ); - return await ( - proxy as unknown as { execute: () => Promise } - ).execute(); - } - // Composite PK — emit OR-grouped predicates. We must use - // COLUMN names (not property names) here because the inner - // knex `apply()` callback bypasses SchemaQueryBuilder's - // property-to-column translation. - const columnNames = pkInfo.columnNames; - ( - sqb as unknown as { - apply: (fn: (qb: Knex.QueryBuilder) => void) => void; - } - ).apply(qb => { - qb.andWhere(function (this: Knex.QueryBuilder) { - for (const pk of pks) { - const tuple = normalisePkTuple(pk, true, 'findMany'); - this.orWhere(function (this: Knex.QueryBuilder) { - for (let i = 0; i < columnNames.length; i++) { - this.andWhere(columnNames[i], tuple[i] as any); - } - }); - } - }); - }); - return await ( - proxy as unknown as { execute: () => Promise } - ).execute(); + if (!pks.length) return []; + const tuples = pks.map(tupleFor); + if (!isComposite) + return (proxy as any) + .whereIn( + propertyKeys[0], + tuples.map(tuple => tuple[0]) + ) + .execute(); + return (proxy as any) + .where((group: any) => + tuples.reduce( + (outer, tuple) => + outer.orWhere((inner: any) => + propertyKeys.reduce( + (query, key, i) => + query.where(key, tuple[i]), + inner + ) + ), + group + ) + ) + .execute(); } - - // find / findOrFail - applyPkFilter(args[0]); - const row = await ( - proxy as unknown as { - first: () => Promise; - } - ).first(); + const tuple = tupleFor(args[0]); + const filtered = propertyKeys.reduce( + (query, key, i) => query.andWhere(key, '=', tuple[i]), + proxy as any + ); + const row = await filtered.first(); if (row === undefined && method === 'findOrFail') { throw new EntityNotFoundError(entityLabel, args[0]); } @@ -700,9 +683,9 @@ export function makeDbSet>( entity.schema as EntitySchema ); return wrapQuery( - sqb as SchemaQueryBuilder< + sqb as unknown as SchemaQueryBuilder< EntitySchema, - EntityResult + EntityRowSchema> >, entity, knex, @@ -754,9 +737,9 @@ export function makeDbSet>( entity.schema as EntitySchema ); const query = wrapQuery( - fresh as SchemaQueryBuilder< + fresh as unknown as SchemaQueryBuilder< EntitySchema, - EntityResult + EntityRowSchema> >, entity, knex, @@ -789,7 +772,10 @@ function wrapVariantQuery< TEntity extends Entity, K extends string >( - sqb: SchemaQueryBuilder, VariantResult>, + sqb: SchemaQueryBuilder< + EntitySchema, + EntityRowSchema> + >, entity: TEntity, variantKey: K, knexInst: Knex, @@ -799,47 +785,6 @@ function wrapVariantQuery< sqb as unknown as object, { get(target, prop, receiver) { - // --- Typed include override (same as wrapQuery) --- - if (prop === 'include') { - return ( - sel: (t: Record) => string, - customize?: (q: SchemaQueryBuilder) => void - ) => { - const name = sel(getEntityKeyTree(entity)); - ( - sqb as unknown as { - include: ( - n: string, - c?: ( - q: SchemaQueryBuilder - ) => void - ) => void; - } - ).include(name, customize); - return proxy; - }; - } - if (prop === 'includeVariant') { - return ( - vk: string, - relationName: string, - customize?: (q: SchemaQueryBuilder) => void - ) => { - ( - sqb as unknown as { - includeVariant: ( - v: string, - r: string, - c?: ( - q: SchemaQueryBuilder - ) => void - ) => void; - } - ).includeVariant(vk, relationName, customize); - return proxy; - }; - } - if (prop === '_sqb') return sqb; if (prop === '_entity') return entity; @@ -963,8 +908,32 @@ function wrapVariantQuery< const value = Reflect.get(target, prop, receiver); if (typeof value !== 'function') return value; return function (this: unknown, ...args: unknown[]) { + if (prop === 'then') { + const [resolve, reject] = args; + return sqb + .execute() + .then(rows => { + if (!onResults || !sqb.returnsEntityRows) + return rows; + return onResults(rows) ?? rows; + }) + .then(resolve as any, reject as any); + } const result = (value as Function).apply(sqb, args); if (result === sqb) return proxy; + if ( + result && + typeof result.execute === 'function' && + typeof result.sameSource === 'function' && + sqb.sameSource(result) + ) + return wrapVariantQuery( + result, + entity, + variantKey, + knexInst, + onResults + ); if ( onResults != null && sqb.returnsEntityRows && @@ -974,6 +943,21 @@ function wrapVariantQuery< ) { return (result as Promise).then( (resolved: unknown) => { + if ( + (prop === 'paginate' || + prop === 'paginateAfter') && + resolved && + typeof resolved === 'object' && + 'data' in resolved && + Array.isArray(resolved.data) + ) { + return { + ...resolved, + data: + onResults(resolved.data) ?? + resolved.data + }; + } if (Array.isArray(resolved)) { const entities = resolved.filter( r => @@ -1055,19 +1039,13 @@ function makeVariantDbSet< } // Allocate a fresh SQB with the variant filter baked in, then // wrap it in the variant-aware query proxy. - const fresh = schemaQuery( - knex, - entity.schema as EntitySchema - ); - ( - fresh as unknown as { - selectVariants?: (keys: string[]) => void; - } - ).selectVariants?.([variantKey]); + const fresh = ( + schemaQuery(knex, entity.schema as any) as any + ).selectVariants([variantKey]); const query = wrapVariantQuery( - fresh as SchemaQueryBuilder< + fresh as unknown as SchemaQueryBuilder< EntitySchema, - VariantResult + EntityRowSchema> >, entity, variantKey, diff --git a/libs/orm/src/index.ts b/libs/orm/src/index.ts index e58fda81..ca290237 100644 --- a/libs/orm/src/index.ts +++ b/libs/orm/src/index.ts @@ -18,7 +18,14 @@ export type { TrackedDbContext } from './dbcontext.js'; export { createDb } from './dbcontext.js'; -export type { DbSet, EntityQuery, VariantDbSet } from './dbset.js'; +export type { + DbSet, + DbSetOperations, + EntityQuery, + PolymorphicEntityQuery, + TableEntityQuery, + VariantDbSet +} from './dbset.js'; export { ConcurrencyError, EntityNotFoundError, diff --git a/libs/orm/src/orm.test.ts b/libs/orm/src/orm.test.ts index 6e0149fe..ae5d3fe1 100644 --- a/libs/orm/src/orm.test.ts +++ b/libs/orm/src/orm.test.ts @@ -324,16 +324,16 @@ describe('EntityQuery proxy', () => { expect(typeof chain.toQuery).toBe('function'); }); - it('.include(selector) forwards the relation name and emits a JOIN', () => { + it('.include(selector) emits a correlated nested row', () => { const db = createDb(mock.knex, { todos: TodoEntity }); const sql = db.todos.include(t => t.author).toQuery(); - expect(sql.toLowerCase()).toContain('join'); + expect(sql.toLowerCase()).toContain('to_jsonb'); expect(sql).toContain('users'); }); it('.include(selector) accepts a customize callback', () => { const db = createDb(mock.knex, { todos: TodoEntity }); - const customize = vi.fn(); + const customize = vi.fn(q => q); db.todos.include(t => t.author, customize); expect(customize).toHaveBeenCalledOnce(); }); @@ -356,7 +356,7 @@ describe('EntityQuery proxy', () => { // than swallowing the call. const db = createDb(mock.knex, { todos: TodoEntity }); expect(() => db.todos.includeVariant('foo', 'author')).toThrow( - /not polymorphic/i + /includeVariant is not a function/i ); }); }); @@ -377,10 +377,12 @@ describe('DbSet.find / findOrFail / findMany', () => { // ---- single-PK happy paths --------------------------------------------- it('find(scalar) emits WHERE id = ? and returns the first row', async () => { - mock.responses.push([{ id: 42, email: 'a@b', name: 'A' }]); + mock.responses.push([ + { id: 42, email: 'a@b', name: 'A', createdAt: null } + ]); const db = createDb(mock.knex, { users: UserEntity }); const u = await db.users.find(42); - expect(u).toEqual({ id: 42, email: 'a@b', name: 'A' }); + expect(u).toEqual({ id: 42, email: 'a@b', name: 'A', createdAt: null }); expect(mock.captured).toHaveLength(1); expect(mock.captured[0].sql).toContain('"id" = $1'); expect(mock.captured[0].bindings).toContain(42); @@ -394,10 +396,12 @@ describe('DbSet.find / findOrFail / findMany', () => { }); it('findOrFail returns the row when present', async () => { - mock.responses.push([{ id: 1, email: 'x', name: 'Y' }]); + mock.responses.push([ + { id: 1, email: 'x', name: 'Y', createdAt: null } + ]); const db = createDb(mock.knex, { users: UserEntity }); const u = await db.users.findOrFail(1); - expect(u).toEqual({ id: 1, email: 'x', name: 'Y' }); + expect(u).toEqual({ id: 1, email: 'x', name: 'Y', createdAt: null }); }); it('findOrFail throws EntityNotFoundError when no row matches', async () => { @@ -427,8 +431,8 @@ describe('DbSet.find / findOrFail / findMany', () => { it('findMany on single-PK emits WHERE id IN (...)', async () => { mock.responses.push([ - { id: 1, email: 'a', name: 'A' }, - { id: 2, email: 'b', name: 'B' } + { id: 1, email: 'a', name: 'A', createdAt: null }, + { id: 2, email: 'b', name: 'B', createdAt: null } ]); const db = createDb(mock.knex, { users: UserEntity }); const rows = await db.users.findMany([1, 2]); @@ -440,10 +444,10 @@ describe('DbSet.find / findOrFail / findMany', () => { // ---- composite-PK paths ----------------------------------------------- it('find on composite-PK accepts a tuple', async () => { - mock.responses.push([{ postId: 1, tagId: 9 }]); + mock.responses.push([{ postId: 1, tagId: 9, addedAt: null }]); const db = createDb(mock.knex, { postTags: PostTagEntity }); const r = await db.postTags.find([1, 9]); - expect(r).toEqual({ postId: 1, tagId: 9 }); + expect(r).toEqual({ postId: 1, tagId: 9, addedAt: null }); expect(mock.captured[0].sql).toContain('"post_id"'); expect(mock.captured[0].sql).toContain('"tag_id"'); expect(mock.captured[0].bindings).toEqual( @@ -468,8 +472,8 @@ describe('DbSet.find / findOrFail / findMany', () => { it('findMany on composite-PK emits OR-grouped predicates', async () => { mock.responses.push([ - { postId: 1, tagId: 9 }, - { postId: 2, tagId: 9 } + { postId: 1, tagId: 9, addedAt: null }, + { postId: 2, tagId: 9, addedAt: null } ]); const db = createDb(mock.knex, { postTags: PostTagEntity }); const rows = await db.postTags.findMany([ @@ -636,7 +640,9 @@ describe('DbSet.save — graph persistence', () => { it('update path: PK present → emits UPDATE, no INSERT for root', async () => { stubTransaction(); // The update returns the updated row. - mock.responses.push([{ id: 5, name: 'X', email: 'x@y' }]); + mock.responses.push([ + { id: 5, name: 'X', email: 'x@y', createdAt: null } + ]); const db = createDb(mock.knex, { users: UserEntity }); const out = await db.users.save({ id: 5, @@ -657,7 +663,7 @@ describe('DbSet.save — graph persistence', () => { stubTransaction(); // Root todo insert. mock.responses.push([ - { id: 21, title: 'T', userId: null, completed: false } + { id: 21, title: 'T', userId: 0, completed: false } ]); // Pivot insert (todo_tags) returns []; we don't read it. mock.responses.push([]); @@ -687,7 +693,9 @@ describe('DbSet.save — graph persistence', () => { (mock.knex as any).isTransaction = true; const txSpy = vi.spyOn(mock.knex, 'transaction'); - mock.responses.push([{ id: 9, email: 'x', name: 'Y' }]); + mock.responses.push([ + { id: 9, email: 'x', name: 'Y', createdAt: null } + ]); const db = createDb(mock.knex, { users: UserEntity }); await db.users .withTransaction(mock.knex as unknown as KnexT.Transaction) @@ -748,7 +756,7 @@ describe('DbSet.save — graph persistence', () => { stubTransaction(); // Root todo insert. mock.responses.push([ - { id: 41, title: 'T', userId: null, completed: false } + { id: 41, title: 'T', userId: 0, completed: false } ]); // Tag insert (because PK was not supplied → create new row). mock.responses.push([{ id: 77, name: 'urgent' }]); @@ -885,8 +893,18 @@ describe('DbSet.ofVariant — insert', () => { stubTransaction(); // Base row insert returns generated PK. mock.responses.push([{ id: 5, type: 'assigned', todo_id: 42 }]); - // Variant row insert. + // Variant row insert, then read-back of the completed branch. mock.responses.push([]); + mock.responses.push([ + { + __read_poly: { + id: 5, + type: 'assigned', + todoId: 42, + assigneeId: 9 + } + } + ]); const db = createDb(mock.knex, { activities: ActivityEntityCTI }); const result = await db.activities.ofVariant('assigned').insert({ @@ -914,6 +932,9 @@ describe('DbSet.ofVariant — insert', () => { stubTransaction(); mock.responses.push([{ id: 7, type: 'commented', todo_id: 1 }]); mock.responses.push([]); + mock.responses.push([ + { __read_poly: { id: 7, type: 'commented', todoId: 1, body: 'hi' } } + ]); const db = createDb(mock.knex, { activities: ActivityEntityCTI }); await db.activities.ofVariant('commented').insert({ @@ -939,9 +960,9 @@ describe('DbSet.ofVariant — insert', () => { it('throws when the variant key is unknown', async () => { stubTransaction(); const db = createDb(mock.knex, { activities: ActivityEntitySTI }); - await expect( + expect(() => db.activities.ofVariant('nonexistent' as any).insert({}) - ).rejects.toThrow(/unknown/i); + ).toThrow(/declared variants/i); }); }); @@ -967,7 +988,15 @@ describe('VariantDbSet.update', () => { it('STI: emits an UPDATE on the base table filtered by discriminator', async () => { // First query: execute() to collect PKs → returns matching rows. mock.responses.push([ - { id: 3, type: 'assigned', todo_id: 10, user_id: 1, assignee_id: 4 } + { + __read_poly: { + id: 3, + type: 'assigned', + todoId: 10, + userId: 1, + assigneeId: 4 + } + } ]); // Second query: the UPDATE itself. mock.responses.push([]); @@ -987,7 +1016,16 @@ describe('VariantDbSet.update', () => { it('CTI: emits an UPDATE on the variant table', async () => { stubTransaction(); // execute() returns matched base-table rows. - mock.responses.push([{ id: 5, type: 'assigned', todo_id: 1 }]); + mock.responses.push([ + { + __read_poly: { + id: 5, + type: 'assigned', + todoId: 1, + assigneeId: 4 + } + } + ]); // UPDATE on the variant table. mock.responses.push([]); @@ -1040,7 +1078,17 @@ describe('VariantDbSet.delete', () => { it('STI: emits a DELETE on the base table with discriminator filter', async () => { stubTransaction(); // execute() to collect PKs. - mock.responses.push([{ id: 2, type: 'commented', todo_id: 1 }]); + mock.responses.push([ + { + __read_poly: { + id: 2, + type: 'commented', + todoId: 1, + userId: 7, + body: 'hi' + } + } + ]); // The DELETE. mock.responses.push([]); @@ -1058,7 +1106,16 @@ describe('VariantDbSet.delete', () => { it('CTI: deletes variant row first then base row', async () => { stubTransaction(); // execute() → matched base rows. - mock.responses.push([{ id: 7, type: 'assigned', todo_id: 3 }]); + mock.responses.push([ + { + __read_poly: { + id: 7, + type: 'assigned', + todoId: 3, + assigneeId: 4 + } + } + ]); // DELETE from variant table. mock.responses.push([]); // DELETE from base table. @@ -1107,7 +1164,15 @@ describe('VariantDbSet.find', () => { it('returns the matched row', async () => { mock.responses.push([ - { id: 3, type: 'assigned', todo_id: 5, user_id: 1, assignee_id: 2 } + { + __read_poly: { + id: 3, + type: 'assigned', + todoId: 5, + userId: 1, + assigneeId: 2 + } + } ]); const db = createDb(mock.knex, { activities: ActivityEntitySTI }); @@ -1184,8 +1249,12 @@ describe('Tracked DbContext', () => { // ------------------------------------------------------------------------- it('querying the same PK twice returns the same object reference', async () => { - mock.responses.push([{ id: 1, email: 'a@b', name: 'A' }]); - mock.responses.push([{ id: 1, email: 'a@b', name: 'A' }]); + mock.responses.push([ + { id: 1, email: 'a@b', name: 'A', createdAt: null } + ]); + mock.responses.push([ + { id: 1, email: 'a@b', name: 'A', createdAt: null } + ]); const db = createDb( mock.knex, @@ -1200,8 +1269,8 @@ describe('Tracked DbContext', () => { it('rows returned from all() are attached to the tracker', async () => { mock.responses.push([ - { id: 1, email: 'a@b', name: 'A' }, - { id: 2, email: 'c@d', name: 'B' } + { id: 1, email: 'a@b', name: 'A', createdAt: null }, + { id: 2, email: 'c@d', name: 'B', createdAt: null } ]); const db = createDb( @@ -1212,7 +1281,9 @@ describe('Tracked DbContext', () => { const rows = (await db.users.execute()) as any[]; // Querying one of the same PKs should return the existing object. - mock.responses.push([{ id: 1, email: 'a@b', name: 'A' }]); + mock.responses.push([ + { id: 1, email: 'a@b', name: 'A', createdAt: null } + ]); const reloaded = await db.users.find(1); expect(reloaded).toBe(rows[0]); }); @@ -1227,7 +1298,7 @@ describe('Tracked DbContext', () => { { users: UserEntity }, { tracking: true } ); - const user = { id: 10, email: 'x@y', name: 'X' }; + const user = { id: 10, email: 'x@y', name: 'X', createdAt: null }; db.attach('users', user); const e = db.entry(user); expect(e.state).toBe('Unchanged'); @@ -1240,8 +1311,8 @@ describe('Tracked DbContext', () => { { users: UserEntity }, { tracking: true } ); - const u1 = { id: 5, email: 'a@b', name: 'A' }; - const u2 = { id: 5, email: 'c@d', name: 'C' }; // same PK, different object + const u1 = { id: 5, email: 'a@b', name: 'A', createdAt: null }; + const u2 = { id: 5, email: 'c@d', name: 'C', createdAt: null }; // same PK, different object db.attach('users', u1); const returned = db.attach('users', u2); expect(returned).toBe(u1); // identity-map: existing wins @@ -1253,7 +1324,12 @@ describe('Tracked DbContext', () => { { users: UserEntity }, { tracking: true } ); - const user = { id: 1, email: 'a@b.com', name: 'Alice' }; + const user = { + id: 1, + email: 'a@b.com', + name: 'Alice', + createdAt: null + }; db.attach('users', user); const original = db.entry(user).originalValues; @@ -1267,7 +1343,7 @@ describe('Tracked DbContext', () => { { users: UserEntity }, { tracking: true } ); - const user = { id: 1, email: 'a@b', name: 'A' }; + const user = { id: 1, email: 'a@b', name: 'A', createdAt: null }; db.attach('users', user); expect(db.entry(user).isModified()).toBe(false); }); @@ -1278,7 +1354,7 @@ describe('Tracked DbContext', () => { { users: UserEntity }, { tracking: true } ); - const user = { id: 1, email: 'a@b', name: 'A' }; + const user = { id: 1, email: 'a@b', name: 'A', createdAt: null }; db.attach('users', user); user.name = 'Changed'; expect(db.entry(user).isModified()).toBe(true); @@ -1292,7 +1368,7 @@ describe('Tracked DbContext', () => { { users: UserEntity }, { tracking: true } ); - const user = { id: 1, email: 'a@b', name: 'A' }; + const user = { id: 1, email: 'a@b', name: 'A', createdAt: null }; db.attach('users', user); user.name = 'Changed'; db.entry(user).reset(); @@ -1306,7 +1382,7 @@ describe('Tracked DbContext', () => { { users: UserEntity }, { tracking: true } ); - const user = { id: 99, email: 'x', name: 'X' }; + const user = { id: 99, email: 'x', name: 'X', createdAt: null }; expect(() => db.entry(user)).toThrow(/not tracked/i); }); @@ -1316,7 +1392,7 @@ describe('Tracked DbContext', () => { { users: UserEntity }, { tracking: true } ); - const user = { id: 1, email: 'a@b', name: 'A' }; + const user = { id: 1, email: 'a@b', name: 'A', createdAt: null }; db.attach('users', user); db.detach(user); expect(() => db.entry(user)).toThrow(/not tracked/i); @@ -1357,7 +1433,7 @@ describe('Tracked DbContext', () => { { users: UserEntity }, { tracking: true } ); - const user = { id: 1, email: 'a@b', name: 'A' }; + const user = { id: 1, email: 'a@b', name: 'A', createdAt: null }; db.attach('users', user); db.remove(user); expect(db.entry(user).state).toBe('Deleted'); @@ -1369,7 +1445,9 @@ describe('Tracked DbContext', () => { { users: UserEntity }, { tracking: true } ); - expect(() => db.remove({ id: 1, email: 'x', name: 'X' })).toThrow(); + expect(() => + db.remove({ id: 1, email: 'x', name: 'X', createdAt: null }) + ).toThrow(); }); // ------------------------------------------------------------------------- @@ -1378,14 +1456,16 @@ describe('Tracked DbContext', () => { it('saveChanges() detects silently mutated Unchanged entries and emits UPDATE', async () => { stubTransaction(); - mock.responses.push([{ id: 1, email_address: 'a@b', name: 'Updated' }]); + mock.responses.push([ + { id: 1, email_address: 'a@b', name: 'Updated', created_at: null } + ]); const db = createDb( mock.knex, { users: UserEntity }, { tracking: true } ); - const user = { id: 1, email: 'a@b', name: 'A' }; + const user = { id: 1, email: 'a@b', name: 'A', createdAt: null }; db.attach('users', user); user.name = 'Updated'; // mutate without calling any set-state method @@ -1406,7 +1486,7 @@ describe('Tracked DbContext', () => { { users: UserEntity }, { tracking: true } ); - const user = { id: 1, email: 'a@b', name: 'A' }; + const user = { id: 1, email: 'a@b', name: 'A', createdAt: null }; db.attach('users', user); const result = await db.saveChanges(); @@ -1420,7 +1500,9 @@ describe('Tracked DbContext', () => { it('saveChanges() inserts Added entities', async () => { stubTransaction(); - mock.responses.push([{ id: 42, email_address: 'new@e', name: 'New' }]); + mock.responses.push([ + { id: 42, email_address: 'new@e', name: 'New', created_at: null } + ]); const db = createDb( mock.knex, @@ -1452,7 +1534,7 @@ describe('Tracked DbContext', () => { { users: UserEntity }, { tracking: true } ); - const user = { id: 3, email: 'x@y', name: 'X' }; + const user = { id: 3, email: 'x@y', name: 'X', createdAt: null }; db.attach('users', user); db.remove(user); @@ -1474,7 +1556,7 @@ describe('Tracked DbContext', () => { { users: UserEntity }, { tracking: true } ); - const user = { id: 1, email: 'a@b', name: 'A' }; + const user = { id: 1, email: 'a@b', name: 'A', createdAt: null }; db.attach('users', user); user.name = 'B'; @@ -1494,7 +1576,7 @@ describe('Tracked DbContext', () => { { users: UserEntity }, { tracking: true } ); - const user = { id: 1, email: 'a@b', name: 'A' }; + const user = { id: 1, email: 'a@b', name: 'A', createdAt: null }; db.attach('users', user); (user as any).id = 99; // mutate PK @@ -1513,7 +1595,7 @@ describe('Tracked DbContext', () => { { users: UserEntity }, { tracking: true } ); - const user = { id: 1, email: 'a@b', name: 'A' }; + const user = { id: 1, email: 'a@b', name: 'A', createdAt: null }; db.attach('users', user); user.name = 'Changed'; @@ -1528,7 +1610,7 @@ describe('Tracked DbContext', () => { { users: UserEntity }, { tracking: true } ); - const user = { id: 1, email: 'a@b', name: 'A' }; + const user = { id: 1, email: 'a@b', name: 'A', createdAt: null }; db.attach('users', user); db.remove(user); expect(db.entry(user).state).toBe('Deleted'); @@ -1550,7 +1632,7 @@ describe('Tracked DbContext', () => { { users: UserEntity }, { tracking: true } ); - const user = { id: 1, email: 'a@b', name: 'A' }; + const user = { id: 1, email: 'a@b', name: 'A', createdAt: null }; db.attach('users', user); user.name = 'B'; @@ -1569,7 +1651,7 @@ describe('Tracked DbContext', () => { it('reload() refreshes entity values from DB', async () => { mock.responses.push([ - { id: 1, email_address: 'new@b', name: 'Refreshed' } + { id: 1, email: 'new@b', name: 'Refreshed', createdAt: null } ]); const db = createDb( @@ -1577,7 +1659,7 @@ describe('Tracked DbContext', () => { { users: UserEntity }, { tracking: true } ); - const user = { id: 1, email: 'a@b', name: 'A' }; + const user = { id: 1, email: 'a@b', name: 'A', createdAt: null }; db.attach('users', user); user.name = 'Dirty'; // simulate dirty state @@ -1616,7 +1698,7 @@ describe('Tracked DbContext', () => { { users: UserEntity }, { tracking: true } ); - const user = { id: 1, email: 'a@b', name: 'A' }; + const user = { id: 1, email: 'a@b', name: 'A', createdAt: null }; db.attach('users', user); // No mutations → dispose should not throw. await expect(db[Symbol.asyncDispose]()).resolves.toBeUndefined(); @@ -1628,7 +1710,7 @@ describe('Tracked DbContext', () => { { users: UserEntity }, { tracking: true } ); - const user = { id: 1, email: 'a@b', name: 'A' }; + const user = { id: 1, email: 'a@b', name: 'A', createdAt: null }; db.attach('users', user); user.name = 'Dirty'; @@ -1643,7 +1725,7 @@ describe('Tracked DbContext', () => { { users: UserEntity }, { tracking: true } ); - const user = { id: 1, email: 'a@b', name: 'A' }; + const user = { id: 1, email: 'a@b', name: 'A', createdAt: null }; db.attach('users', user); user.name = 'Dirty'; @@ -2022,7 +2104,9 @@ describe('Tracked DbContext — first() single result onResults (line 481)', () }); it('first() in a tracked context attaches the resolved single object', async () => { - mock.responses.push([{ id: 2, email_address: 'b@b', name: 'Bob' }]); + mock.responses.push([ + { id: 2, email: 'b@b', name: 'Bob', createdAt: null } + ]); const db = createDb( mock.knex, @@ -2061,7 +2145,12 @@ describe('Tracked DbContext — reload() early returns', () => { { users: UserEntity }, { tracking: true } ); - const untracked = { id: 99, email: 'x@y.com', name: 'X' }; + const untracked = { + id: 99, + email: 'x@y.com', + name: 'X', + createdAt: null + }; // Should not throw and should not emit any SQL. await db.reload(untracked); expect(mock.captured).toHaveLength(0); @@ -2100,7 +2189,12 @@ describe('Tracked DbContext — attach() same-object snapshot refresh', () => { { users: UserEntity }, { tracking: true } ); - const user = { id: 1, email: 'a@b.com', name: 'Alice' }; + const user = { + id: 1, + email: 'a@b.com', + name: 'Alice', + createdAt: null + }; db.attach('users', user); // Dirty the entity. @@ -2231,7 +2325,12 @@ describe('Tracked DbContext — pendingSummary() branch coverage', () => { { users: UserEntity }, { tracking: true } ); - const user = { id: 1, email: 'a@b.com', name: 'Alice' }; + const user = { + id: 1, + email: 'a@b.com', + name: 'Alice', + createdAt: null + }; db.attach('users', user); // Silently mutate (no explicit state change — isDirty triggers Modified count). @@ -2248,7 +2347,7 @@ describe('Tracked DbContext — pendingSummary() branch coverage', () => { { users: UserEntity }, { tracking: true } ); - const user = { id: 2, email: 'b@c.com', name: 'Bob' }; + const user = { id: 2, email: 'b@c.com', name: 'Bob', createdAt: null }; db.attach('users', user); db.remove(user); diff --git a/libs/orm/src/query-types.test-d.ts b/libs/orm/src/query-types.test-d.ts index a52747f4..d794583e 100644 --- a/libs/orm/src/query-types.test-d.ts +++ b/libs/orm/src/query-types.test-d.ts @@ -35,6 +35,7 @@ test('include customizers know their relation schema', () => { owners.where(t => t.name, 'Alice'); // @ts-expect-error field belongs to tasks, not users owners.where(t => t.ownerId, 1); + return owners.where(t => t.name, 'Alice'); } ); }); diff --git a/libs/orm/src/result-types.ts b/libs/orm/src/result-types.ts index 7029d7a3..94e67a4e 100644 --- a/libs/orm/src/result-types.ts +++ b/libs/orm/src/result-types.ts @@ -8,7 +8,8 @@ import type { Entity, EntityRelations, EntitySchema, - RelationInfo + RelationInfo, + SchemaAwareQuery } from '@cleverbrush/knex-schema'; import type { InferType, ObjectSchemaBuilder } from '@cleverbrush/schema'; @@ -28,12 +29,9 @@ import type { InferType, ObjectSchemaBuilder } from '@cleverbrush/schema'; * * @public */ -export type EntityResult> = - TEntity extends Entity - ? [U] extends [never] - ? InferType> - : U - : InferType>; +export type EntityResult> = InferType< + SchemaAwareQuery>['rowSchema'] +>; /** * Discriminated-union variant rows for a polymorphic entity. Resolves to @@ -45,7 +43,7 @@ export type EntityResultByVariant> = TEntity extends Entity ? [U] extends [never] ? never - : U + : EntityResult : never; /** diff --git a/libs/orm/src/save-graph.ts b/libs/orm/src/save-graph.ts index 7509a54d..146c2a5c 100644 --- a/libs/orm/src/save-graph.ts +++ b/libs/orm/src/save-graph.ts @@ -152,7 +152,7 @@ async function saveNode( // 2. Save self (insert vs update from PK presence). // --------------------------------------------------------------------- const isUpdate = hasFullPk(schema, ownFields); - const sqb = schemaQuery(trx, schema) as unknown as { + let sqb = schemaQuery(trx, schema) as unknown as { andWhere: (col: string, op: string, val: unknown) => unknown; update: (data: unknown) => Promise; insert: (data: unknown) => Promise; @@ -165,7 +165,7 @@ async function saveNode( const updateData: Record = { ...ownFields }; for (const k of pk.propertyKeys) delete updateData[k]; for (const k of pk.propertyKeys) { - sqb.andWhere(k, '=', ownFields[k]); + sqb = sqb.andWhere(k, '=', ownFields[k]) as typeof sqb; } // SchemaQueryBuilder.update returns the updated row(s). const result = (await sqb.update(updateData)) as unknown; diff --git a/libs/orm/src/variant-write.ts b/libs/orm/src/variant-write.ts index bf9dfd39..0f4eb8e6 100644 --- a/libs/orm/src/variant-write.ts +++ b/libs/orm/src/variant-write.ts @@ -9,14 +9,32 @@ import { buildColumnMap, getPrimaryKeyColumns, getVariants, + object, query as schemaQuery } from '@cleverbrush/knex-schema'; +import type { ObjectSchemaBuilder } from '@cleverbrush/schema'; import type { Knex } from 'knex'; // --------------------------------------------------------------------------- // Internal helpers // --------------------------------------------------------------------------- +/** Keep table metadata and hooks without constructing a polymorphic reader. */ +function storageSchema( + schema: any, + properties = schema.introspect().properties +): ObjectSchemaBuilder { + let stored: ObjectSchemaBuilder = + object(properties); + for (const [key, value] of Object.entries( + schema.introspect().extensions ?? {} + )) { + if (key !== 'variants' && key !== 'polymorphicVariants') + stored = stored.withExtension(key, value) as typeof stored; + } + return stored; +} + /** * Resolve the variant config for a schema, throwing if the schema is not * polymorphic or if the requested variant key is unknown. @@ -90,10 +108,13 @@ export async function insertVariant( if (spec.storage === 'sti') { // Single-table: insert into base table with discriminator column const row = { ...payload, [discKey]: variantKey }; - const sqb = schemaQuery(t, schema) as unknown as { - insert: (data: unknown) => Promise>; + const props = { + ...schema.introspect().properties, + ...spec.schema.introspect().properties }; - return (await sqb.insert(row)) ?? row; + const stored = storageSchema(schema, props); + const result = await schemaQuery(t, stored).insert(row as any); + return result as Record; } // CTI: two-table insert @@ -129,20 +150,11 @@ export async function insertVariant( // Keys that match neither schema are silently dropped } - // 1. Insert base row using raw knex (not SchemaQueryBuilder) to avoid - // polymorphic result-resolution running before the variant row exists. - const { propToCol: basePropToCol } = buildColumnMap(schema); - const baseRowForInsert: Record = {}; - for (const [propKey, val] of Object.entries(basePayload)) { - baseRowForInsert[basePropToCol.get(propKey) ?? propKey] = val; - } - const baseInsertResult = await (t as unknown as Knex)(baseTableName) - .insert(baseRowForInsert) - .returning('*'); - const baseRow: Record = - Array.isArray(baseInsertResult) && baseInsertResult.length > 0 - ? (baseInsertResult[0] as Record) - : baseRowForInsert; + // 1. Decode base RETURNING values before using the PK. In particular, + // bigint IDs must be text-cast in SQL before driver parsers can round them. + const baseRow = (await schemaQuery(t, storageSchema(schema)).insert( + basePayload as any + )) as Record; // Resolve the base PK value from the returned row const pkInfo = getPrimaryKeyColumns(schema); @@ -179,17 +191,17 @@ export async function insertVariant( } await (t as unknown as Knex)(variantTableName).insert(variantRow); - // 3. Merge and return - const { colToProp: baseColToProp } = buildColumnMap(schema); - const result: Record = {}; - for (const [col, val] of Object.entries(baseRow)) { - result[baseColToProp.get(col) ?? col] = val; - } - // Ensure discriminator and variant payload are in the result - result[discKey] = variantKey; - for (const [propKey, val] of Object.entries(variantPayload)) { - result[propKey] = val; - } + // Read the completed branch inside the same transaction for one consistent storage representation. + const result = await (schemaQuery(t, schema) as any) + .selectVariants([variantKey]) + .unscoped() + .withDeleted() + .where(pkPropKey, pkValue) + .first(); + if (!result) + throw new Error( + 'insertVariant: inserted row could not be read back' + ); return result; }; diff --git a/websites/docs/app/knex-schema/page.tsx b/websites/docs/app/knex-schema/page.tsx index 1be30d69..de0e6219 100644 --- a/websites/docs/app/knex-schema/page.tsx +++ b/websites/docs/app/knex-schema/page.tsx @@ -228,9 +228,10 @@ returning *`

.joinOne() and .joinMany(){' '} load related rows in a{' '} - single PostgreSQL query using CTEs and{' '} - jsonb_agg. The inferred TypeScript type is - updated automatically for each join you add. + single PostgreSQL query using + correlated subqueries and jsonb_agg. The + inferred TypeScript type is updated automatically for + each join you add.

                          t.id,
         foreignColumn: t => t.authorId,
         as:            'posts',
-        limit:         5,
-        orderBy:       { column: t => t.id, direction: 'desc' },
-    });
+    }, posts => posts.orderBy(t => t.id, 'desc').limit(5));
 // users[0].posts → Array<{ id: number; title: string; authorId: number }>
 
 // Many-to-one — attach the author to each post
@@ -298,22 +297,24 @@ const posts = await query(db, PostSchema)
                 

Escape Hatch

- Use .apply(fn) to call any Knex method not - exposed by this API — the raw{' '} - Knex.QueryBuilder is passed to your + Use .apply(fn, {'{ output }'}) with a + complete output schema for raw SQL. The independently + mutable Knex.QueryBuilder is passed to your callback:

                          t.id, id)
-    .apply(qb => qb.forUpdate().noWait());
+    .apply(qb => qb.clearSelect().select({ name: 'first_name' }), {
+        output: UserName,
+    });
 
-// Pre-scoped base query (e.g. soft-delete filter)
-const base = db('users').where('deleted_at', null);
-const activeUsers = await query(db, UserSchema, base)
-    .where(t => t.age, '>', 18);`)
+// Share an immutable Framework base query; retain each configured result.
+const base = query(db, UserSchema).whereNull(t => t.deletedAt);
+const activeUsers = await base.where(t => t.age, '>', 18);`)
                             }}
                         />
                     
@@ -373,7 +374,7 @@ const average = await query(knex, TaskSchema).avgValue(t => t.estimate, { }} />

- Existing APIs remain unchanged. Read the{' '} + Queries are immutable in this major release. Read the{' '} complete query guide {' '} @@ -382,18 +383,19 @@ const average = await query(knex, TaskSchema).avgValue(t => t.estimate, {

-

Opt-in projection-aware reads

+

Automatic projection-aware schemas

- Start with withRowSchema() before selecting or including - fields. The immutable PostgreSQL reader exposes the - actual decoded result schema: SQL null stays null, dates - are Date objects at every depth, and decimal/bigint - values are exact strings before JSON parsing. + Every query exposes rowSchema automatically; no extra + mode switch is needed. Immutable PostgreSQL queries + describe the actual decoded result schema: SQL null + stays null, dates are Date objects at every depth, and + decimal/bigint values are exact strings before JSON + parsing.

                          ({ title: t.title, amount: t.amount }));
 const Source = read.rowSchema;
 const rows = await read.where(t => t.id, taskId);`)
@@ -404,8 +406,8 @@ const rows = await read.where(t => t.id, taskId);`)
                         Typed aliases, aggregates, named projections and nested
                         graphs retain their selected shape. Polymorphic readers
                         expose a union rowSchema and per-variant object schemas.
-                        Raw shapes are rejected; existing query behavior is
-                        unchanged.
+                        Raw shapes require an explicit Framework output schema.
+                        Retain every returned builder when configuring a query.
                     

Read representation, pagination and migration details @@ -423,7 +425,7 @@ const rows = await read.where(t => t.id, taskId);`)
                          ({ id: t.id, title: t.title }));
 const read = base.where(t => t.projectId, projectId)
     .andWhere(group => group
@@ -441,8 +443,9 @@ const read = base.where(t => t.projectId, projectId)
                         predicates. Subquery SQL and bindings are captured on
                         attachment, with no database execution. Use ref() for
                         quoted columns and generated aliases; keep values in
-                        bindings and raw SQL fragments application-authored.
-                        Unrestricted apply() remains unavailable.
+                        bindings and raw SQL fragments application-authored. Raw
+                        apply() requires an explicit output schema. Return the
+                        configured group from every predicate callback.
                     

Multi-file examples and compatibility boundaries @@ -571,7 +574,7 @@ const read = base.where(t => t.projectId, projectId) Escape hatch - .apply(fn),{' '} + .apply(fn, {'{ output }'}),{' '} .toQuery(),{' '} .toString() diff --git a/websites/docs/app/mapper/page.tsx b/websites/docs/app/mapper/page.tsx index fdf8aed4..9df84e73 100644 --- a/websites/docs/app/mapper/page.tsx +++ b/websites/docs/app/mapper/page.tsx @@ -229,7 +229,7 @@ const registry = mapper()
                          ({ id: u.id, name: u.name }));
 const Source = read.rowSchema; // no SQL
 const toDto = mapper().configure(Source, UserDto, m => m)
diff --git a/websites/docs/app/orm/page.tsx b/websites/docs/app/orm/page.tsx
index 610c276b..58be4c79 100644
--- a/websites/docs/app/orm/page.tsx
+++ b/websites/docs/app/orm/page.tsx
@@ -244,16 +244,16 @@ try {
                 

Detached reads with projection schemas

- db.users.withRowSchema() returns an immutable read-only - query with runtime metadata matching its projection and - relation graph. Results stay detached even in a tracking - context, so partial selections cannot silently become - incomplete tracked entities. + Every DbSet query is immutable, with metadata matching + its decoded projection and relations. Full entities + retain identity tracking when enabled. Projected, + grouped, distinct and raw results remain detached, so + incomplete selections cannot replace tracked entities.

                          ({ id: p.id, name: p.name }))
     .include(r => r.tasks, tasks => tasks
         .select(t => ({ title: t.title })));
@@ -265,7 +265,9 @@ const projects = await read; // one SQL statement`)
                     

Return child queries from customizers. STI/CTI reads expose variantRowSchemas for explicit mapper dispatch. - Ordinary entity reads and writes remain unchanged. + Entity objects remain mutable. Reads, reloads and + returning writes share exact numeric, date and null + representations.

Projection-aware consumer guide diff --git a/websites/docs/public/llms.txt b/websites/docs/public/llms.txt index d1bc3fa1..209db7c0 100644 --- a/websites/docs/public/llms.txt +++ b/websites/docs/public/llms.txt @@ -177,10 +177,10 @@ belong to these packages. Knex is a peer dependency; PostgreSQL also needs `pg`. exposes typed DbSets. Ordinary entity queries support identity tracking, change persistence, optimistic concurrency and STI/CTI variants. Use `@cleverbrush/orm-cli` for migrations. [ORM guide](/orm). -- **Projection-aware reads:** enter `.withRowSchema()` before selecting or - including. It returns an immutable, read-only query. `rowSchema` describes the - decoded selection, not the full table, and accessing it never executes SQL. - Results are detached even in tracking contexts. SQL nulls stay `null`, dates +- **Immutable queries:** every Framework query exposes `rowSchema` automatically; + `.withRowSchema()` is removed. Retain returned builders. `rowSchema` describes + the decoded selection, and accessing it never executes SQL. Full ORM entities + remain tracked when enabled; projected, grouped, distinct and raw rows are detached. SQL nulls stay `null`, dates decode to `Date` throughout nested graphs, and declared decimal/bigint columns retain exact strings. Input defaults and preprocessors are not replayed. [Read schemas](/knex-schema#row-schemas), [detached ORM reads](/orm#detached-read-schemas). @@ -190,10 +190,11 @@ belong to these packages. Knex is a peer dependency; PostgreSQL also needs `pg`. `orWhereRaw` / `orderByRaw` with positional bindings and `ref(selector)` for quoted mapped columns, including generated child aliases. Group callbacks run synchronously once and receive only predicate methods; retained groups are - closed after the callback. Subquery SQL/bindings are captured without executing + immutable too. Return the configured group, never void or a Promise. Subquery SQL/bindings are captured without executing SQL. These operations retain rowSchema identity; assign their returned reader. Raw fragments are trusted application SQL, not a sandbox. Keep authorization - outside grouped search ORs. No unrestricted apply() exists in read mode. + outside grouped search ORs. Opaque SELECTs use `apply(configure, { output })` or + `selectRaw(sql, bindings, { output })` with a synchronous Framework object schema. Numbered pagination retains ordering; composite cursors replace it with their explicit orderBy specification. [Read predicates](/knex-schema#read-predicates). - **Nested and polymorphic reads:** child customizers return their configured From ff6a30ecc889da486f38c9f2bbea13900bfbb0ad Mon Sep 17 00:00:00 2001 From: Andrew Zolotukhin Date: Thu, 1 Oct 2026 05:27:58 +0000 Subject: [PATCH 17/41] docs: keep Framework guidance application-agnostic and current --- .changeset/immutable-query-major.md | 8 ++- .changeset/schema-boundaries.md | 2 +- AGENTS.md | 11 +++ demos/e2e/README.md | 2 +- docs/assets/immutable-query-docs.png | Bin 157494 -> 156320 bytes docs/cache-form-migration.md | 12 ++-- libs/client/CHANGELOG.md | 2 +- libs/deep/README.md | 9 +-- libs/env/CHANGELOG.md | 2 +- libs/knex-schema/CHANGELOG.md | 2 +- libs/knex-schema/MIGRATION-v5.md | 2 +- libs/knex-schema/README.md | 8 +-- libs/knex-schema/src/QuerySource.ts | 22 +++--- libs/knex-schema/src/expressions.ts | 2 +- libs/knex-schema/src/extension.ts | 68 +----------------- libs/knex-schema/src/types.ts | 2 +- libs/orm-cli/CHANGELOG.md | 2 +- libs/orm/CHANGELOG.md | 2 +- libs/orm/README.md | 8 +-- libs/schema/README.md | 25 +++---- .../src/builders/ObjectSchemaBuilder.ts | 4 +- libs/server/CHANGELOG.md | 2 +- .../docs/app/client/sections/cacheTags.tsx | 11 ++- websites/docs/app/knex-schema/page.tsx | 15 ++-- websites/docs/app/react-form/page.tsx | 4 +- websites/docs/public/llms.txt | 4 +- .../app/docs/sections/api-reference.tsx | 8 +-- .../app/docs/sections/schema-modifiers.tsx | 4 +- .../schema/app/docs/sections/validation.tsx | 7 +- .../app/playground/schemaDeclarations.ts | 4 +- 30 files changed, 95 insertions(+), 159 deletions(-) diff --git a/.changeset/immutable-query-major.md b/.changeset/immutable-query-major.md index d792313b..631bb9fe 100644 --- a/.changeset/immutable-query-major.md +++ b/.changeset/immutable-query-major.md @@ -22,6 +22,10 @@ Make Framework query builders immutable and infer row schemas automatically. -This breaking release requires consumers to retain returned query builders, return synchronous builders from scopes and grouped predicates, and supply an explicit Framework object output schema for opaque raw SELECTs. Remove withRowSchema() calls: ordinary, aliased, polymorphic and ORM queries now expose their row schemas directly. Projections replace scalar selections, and projected/aggregate/raw queries cannot perform entity writes. Reads and write-returning rows consistently preserve exact decimal/bigint strings, Date objects and SQL nulls. +Retain returned query builders, return synchronous builders from scopes and grouped predicates, and supply an explicit Framework object output schema for opaque raw SELECTs. Ordinary, aliased, polymorphic and ORM queries expose their row schemas directly. Projections replace scalar selections, and projected/aggregate/raw queries cannot perform entity writes. Reads and write-returning rows consistently preserve exact decimal/bigint strings, Date objects and SQL nulls. -All published Framework packages advance together to the next major version. See the knex-schema and ORM migration guides before upgrading; tracked entity objects remain mutable. +All published Framework packages advance together to the next major version. Tracked entity objects remain mutable. + +### Migrating from v4.x to v5 + +Remove `withRowSchema()` calls and retain each configured query instead of relying on mutation. Replace raw base-query overloads with explicit output contracts. See `libs/knex-schema/MIGRATION-v5.md` for the complete migration guide. diff --git a/.changeset/schema-boundaries.md b/.changeset/schema-boundaries.md index c4c0d255..199781d1 100644 --- a/.changeset/schema-boundaries.md +++ b/.changeset/schema-boundaries.md @@ -10,4 +10,4 @@ Shape, validation-rule, default, fallback and extension changes clear inherited names; apply schemaName after those edits to establish a new named definition. Preserve one canonical definition in JSON Schema, OpenAPI and AsyncAPI with strict name collision checks. Keep existing -type inference and legacy optional null acceptance unchanged. +type inference and optional null acceptance unchanged. diff --git a/AGENTS.md b/AGENTS.md index 4b8d890f..d93978be 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -135,6 +135,17 @@ The `demos/` directory is linted separately (see `demos/todo-backend/biome.json` - Target `ES2022`; use modern syntax freely - Type assertions with `as` are acceptable (the linter won't block them) +## Documentation and Project Boundaries + +- Framework is an independent, application-agnostic project. Use generic domain + examples in source, documentation, changesets and PR descriptions. Consumer + application references belong only in website showcase links. +- Describe the current supported API in READMEs, guides and JSDoc. Keep historical + API comparisons and upgrade instructions in explicitly labeled v4.x-to-v5 + migration documentation, and link to it from current guides where useful. +- Preserve accurate API contracts and deprecation annotations; do not change + runtime behavior just to simplify documentation. + --- ## Testing Conventions diff --git a/demos/e2e/README.md b/demos/e2e/README.md index 8fad4eb8..aab01e1f 100644 --- a/demos/e2e/README.md +++ b/demos/e2e/README.md @@ -116,7 +116,7 @@ src/ - **Todos** — full CRUD, list pagination, `getWithAuthor`, polymorphic events (`assigned` / `commented` / `completed`), optimistic concurrency on `complete` (200 / 409 with `If-Match`), cross-user 403, attachment - download, `legacyReplace` redirect. + download, PUT redirect. - **Import / Export** — 207 small batch, 202 large batch, idempotency header (contract-level), CSV export with quoting + content headers. - **Users (admin)** — list (admin only), delete user, self-delete blocked, diff --git a/docs/assets/immutable-query-docs.png b/docs/assets/immutable-query-docs.png index 37c23b6f722c86e6102d8d7c53bd0096763f11ea..fb6c4d841623789824974d0343e5dd11ba0a24e0 100644 GIT binary patch literal 156320 zcmbq)Wm_D}^Y-E%5}aVc9fG^N!@}YaAh-s1OOW91?y!ryO9<{BoZ#-R&z^IB|4;Dr zo7tVdrndgc001!LWF>(B00Q(UTsJZ-^s>__!2$rh2gpf^X?SEF zXCaB=$Pk6xp?2_ysWNG+O4|PMuBve_2xF7R=ISHh@}HHAnj-ib#&v6d+;L~9ii4w8 z6Ob=^_Hz1qW^b%h>G)|U_6|j-E5oj?PN42;oQH!kI!eKWKss5)62DAi_@n$^#m2l= z(>ON441B|IBT8l?)W}HV`?6efxK})O!*sJEHvISoa(Bu<{+>gX_bLa<^xXJ#Zo8Un zwV5x3fuEk{tMyQ8{ZMKvb#k@I-)}$TnZDrBHDXmS4@Mn-qOtLvXIac(XAfzL(Ullt zkxCp66?jW*^;VZYRnU>n$sSs9{4mH_Ieh{^SXS-VqaVzIa~XSA`)o^&z26+unw3PK zR3rlUgj8u*LOc!uF@O-$^l{}4Z-B=1M2mAH`XUXLn{)D9#On0#F4I{GaQez)Z8Ox= z^-(yVGgO4N-4o4by9|H3Q0h1q6!aT4(FTc=)220x>NI-9BQf~ZhVBGa3I@3&nHANs z=nleaj|J8v8@VZIl1L|K%{uAjQU&aUF?W%N`xEXIqXy|79WKI?B-a6>Q;+ky$(jO%`*wiYh$vHnh(c|-u6oXyKf14fGgZu#pJEDz2}~Ag}9npZkr_W zcJm`+&9ho}28f+Rx9Ni?u3X&C9%$dxFz17qa_F8ugBFd1%sYT++<8qBbM3Dds)lKN zYXSg3lu&XJuG|`uuleZII32Hc_%pf1@pr&jo@|j(KC&F zT!Fl=h3y3FCOW$1?Ac;=Fol*^9_g6yj%1ClO3s_t3h-K#z#VOyHN}~=IVX`3&mS>< z^&mA``}RIf^l1MJ05D0?!6E=J1>rIC@_YD4(te+InUu?|-4U+-ddHZxTP5GOro5@& zSk?mnyrt2*U{*s{H*)e0a2DK`hfP)5F2~sost&jTpqaKMsr(YcgUD+GXAcC>q;zS~Z1H`s)9=?65V3(ZApqo3K5A*>xJTv&!T@q}bMKiX ze$MgRHk7_o^36-KE&5t}?ml~JI`14V2Ds`4?Tu-E=+ei*&zflVE{UAlZ%(yF;ir42g{H##QU zr)NH*TO?OqdteulzVrgtSYYPyeuMgmf z;lwY+`Sqm_y0`It$2c_;wGnkVi3(VNXw46XO47W3IHnmvbnS#a%{jPHO9G8iy9p5* zb$o#uqc3SzylKWHY;X+V-54 ziQyR}{JC8HLI@B6K7u}j=-Ll=ht`V)gX_(;KKQHex1qZY$9Bv<)N0$G+r~EcSk0b0 zG<>B`ot8%N3NULK063G~o6SbT;C&-C%8uYYs*{aum8Lm^U&^-|1h55N4U-1tJHi@vB7oLGb9CGr; zq@E@kK_9#y1K8zf>S>pYKj;yX3vbHg!U5fx5cLsoGVYC-wMfc*F5 zH}%+=MU^pKzn@@?YvKw1Q*wbeK^dE5m9qMn`ti5l^R-{#s`8$Y}LQ(AW{*&31MN)E+t{J#y^dn@%7cp$_{ru06 zC&-dqHWvZ4UAY^c-=ZmY*Vr%k)+_J7 zuv9K)uVvnV7kc<@o!5V7PMNl6jQi_4-HvzYME3}MEI1wfA05^D?T>Jy!H2vBNxB+M zQwE4Bc-M_+E~h%Vb>5tNF22ccyGMUlN+vGRuMCKh0VY z;jSENxCdC_ZqWWCLx=J^-KT3sg{El}6#x5qtUh+{&&Kqi%%=rjw$ZT%rmcu2+q{e? zUC;mklC~kAtnhX3@Nkq2uDl-qe|+GO41WzEbQMaT*n)n8pM*WIV&pUKX#2 zRK8?_@oSx|)bw-Bf!&bCQqJLx7&$Ig-9>JTcfDbdI5?j@ptDV6=oAxKx>wS-s;v#t&~l=5k5!sQDiifgWR+v9d+RA8H)K5o5S>~3&o@bqT(G=0S3V5Of(ta%Bd04VkB1Ly_h%s% z5w~_9tCjmOGGeOMeSY=z8Q;yPDdy!%0TigFPkmER2zu_Y1>6p{^L7Y=DFVoZ!=HV7 z?AY;`El;$^B@+PVcS{|t_s_w|Qk$yq2s_6ZBLW#3j$C$AE4oa0mRQ{@4!G3i48G3! z+02e078-9N5dOsg68z_XcTI=N&Q85>Cge$asmze1#V2!XWn)Qa9v*rB8;9&IS20X- zggXQgG3rQ@gNx0?rN|V%y5AJ|bV4zAP&Hc#qF^!fTGl$elTD{LK0bk0A_}*j8(f@) zL=V9|~0fD;O9-}ATD$1N~ zT<-k@*q+k~qu8hf##64fAR(441v*ST2P=$56ZERF3;p7r$J@&zC3)dL6D1{S z9-nAeo3Tae{rMK;`*mbyzY#Z_5T%o%oIK*KLXWe51|0!P7=20AYK($xrS_UIFK2$T zUN8ly3;N{=zfQ=#q-Ug2(G->1i{_7v&i>T@?f(2DeI8*Jw$lqQ2!g5kVif>$`0{J!UssnZGV&Q* zmx5WUAJ~RT{ofAAlh|t<2`93tPX*3}*#*D$&flr~m0FrJh$J#qaU9la&S2;9Gvocc zOMs{h74YCf;cl9P-OJtbnV%^hzS=@btC;S>`;tMO;*9I~L`R7sp##~|!QR@`oWVVt zn!1Fhs1Q`98qM&4?;xb8FoBHhrQYR+D;+b%i;|4>aP#7nK}g8PwF(cTl2-jKt*UEw zRAXba&`_+yld)}&){~69;Ky7g`Rpmyo5c+&e??L7!*G$v(vmh%cI*(>?`hov(PZkN z&b=TX8)s@boVY2aYCYnHNF^jl+O$w%6`c5H3|t3;hpY*NC@FvRdcRuOW)`*h zXE$8+SJ1i&F|r!m6TS$#Y>$V{V6JyY6bl%PtUe5!wJ{2gj;6cr-H}||P3B(4!bE9R zbx`4;yy~fbtH&2xvm*=f`S~0i9Kqc4`MRee6}kj*3K<=BRqL`W2IG;D$>!$anOUit%)u<< zI(w)wv8%TqIx(@SX;5tK2%5mtk2mZX7=(z1>$UK>KAkbym}jdYXmTTif4nw;Rku;Z zCl!Rg)IvheM|lxhy7SJ=IY}QX?*;uH_j@dw$_gncEU{?!AUQqV&7bKfOw)U(Pdr(X)(}jnUaFXNF%U>etFt^i`+KI> zcYD$=YpH2`f-QATqLbj|Aa+fNpN&j_zU*M(6hT^gfVQMqCoN-XSr=&5H{A}u%j$W1 zd9oUiBH>kUBoAj%_0-{oU5WFjT6ylV0RlD9*1G+T5-EsxmR82*qlxcVc4nSdeh*Ie z54VSDVd&X77w>ysQe5Bu$km-=;JkGCdX3mnv*foAl-EVHAtLxmd{Ry{@912ew4f1_ zc}H*IFjr{r`YI;>8FUqq+!Vr~qsbCm-p=F-@w)Z$#(&TvNQrZDsF_A?X<4aUX=t23q?J1oVp!uzI`nXzYNf+X$ z*w2shEMGjc*;Cchp7|!mep3|7(Eh-SGFv#4B@>FXUuP`aWUyTQJ^Xdx|8fC}+Zrr; zyoFJ$>#?2aalmx1c`WWbJY792Y=tSdi>5O{8X226VY?ICihD?B&gXBJO+V_|vJ*_O z>35lv$xixDx^rHe3~8u)GzTU{T~0T9&q^wv+#iDGnT2>9x)PIFE?V$s!BTe8YB_E0 zZ`7W}%k^NTr^;my7sq@-WQ z#@I&gMv$`+g1@vAZy(z#u~x{$^!jCc+HR#A)6gLHONSKN<_JbLyY68moV0-Ur-|_^ zDLxHUwK;2b2llG;nHU$za~~YU>oxV-uhN88xECPq;5;E)tvl~YsAT$$k^a4$Lk44D zl7TOUlkae8d8+C5B+=Dd;^hjY=iSe!S8kLDCsjIkhm(S~N;a*ETG9slrE&0RJl}+G zP6Q4n#V*Tnuf=PnJ$r6)fX z^7{Km)hyR>h&v)c@KaK)24%q)?n_t9@p4&Mv4O1f+J%25LjddgyU(2On`{oPtc=rR z6OZu;d@jS!CbKK(CV4ib>by?*Q8$|YvR&WKsR8imeZ5@`K3nh;euz_hdY5&-8%l`e zUI95V%%aEmJwUA*W@}}YM_pK*yY#S@uyA6>w9Io?&&}hF|Ka5A`sQz)JL0XSy~c5l zX{ljf+H2~x#186?JorL^%!oCoU8TlRPUDieZGWcNkwnYFyZEQ)JyW6Umaf(rVtnds z&aR76jrCf0hg$=xsboLZivRQFtl7Glkgn3H%^6qW5D;3z6~TLNiTROo+^c zVH?QB1z0cqM|+q{gbSuxTJ1gFhmnuF#r@)Au3mAfM&>4&i4+dGB|H&Do^LQdI{!r|GbWsPl|f0A4PD3@ zYK}05!!mgHvah$iLXm3rKJUEtQ5e~v%N#ydDb~4`{r0zj|oqWBJPod zFJCPuy8$CgvP4-#{eX4s(X}qST0v`j__kz7iD=$EAE(prs$ydG4h6+ZasGPvGJ7nB zbYL{?AS;_(r|sh4>5g8jQU;wUfBH_8<}7!jbVGk_BU|*;LRoe&QP$LAoOU{}gDBl^ zdM1;?^~~?Fr&mrT#~cySe7>BX-#M8@Z9@|zSlab`o5fG*xk1b88$u`$;`#brP63-g zB?W^dGf&oe_gY5+Ye-HmQtGePUs0>z>pu-`fraD;2lwRF6Yi#lwr@k1n1xJt&bnRBg@yh&APBJ2B2y?TyOZn&5xZvTYP z;fEiWnkc_;3W7Kx&KN_ ztH_v{QqJ!Dw!Qr@JF8J6J6kT-J0Xp(5p@;W;{R~}c(!sMV& zyP;KF-Ey^2mK3bh#EtPMCrN*}g=VN?!vK(xxwc3IY>_N6XH9L}kf|E2M5#gj= z(E{B=)X<)&N=j47@{HD5X|hCM)S*VfsK z)-O~z(^0u1)}k$&*q;k!6yjtFa#G9FU#@(d2&CH9B4Y0-*!Y;?U5Y@A3|c3p7izg4 zs&L=eCRZ&+K>X4E8;st1j9zA{@|xdj9i}D?n6OTT{W`uU*eUt|)ANlAEkfj(i;-1{ z7^#o#n9{vK>#oPT9vb@DQ>qzY>nlnj((Nxr0|8F*)D}<0H`eUorsxqrKJs5Kw!ca+XdFzj! z6&XA(P3$~7DN--|JRt9IAzJ(97XE356esS9@9VfX5r+7s&AIT~>F*ZrRku8B&XyFX z-Y3K+`m!J~^GD613hk*FhOmdLP_ubOau4XkAWoucy7zvKg=d^)-LuCQmbT^5y5U-}vh$a$eL@<2d1l zvCMr#B>8zI1ziuV&KFX zw+=JESuHcadcJwGs9I~Z(+^#`FPoMC2F2k+E>{b-u#wzs46EFdK7ul#$&-Wo`h|;# zyW!>KNuk5VwI|QPHh|RkdqE#%1~bux-Hs)m{B5)FEPqW0^q9z{=d;ZpZxsr%iqGy_ zZm2%Q1e~t@XX{D?&ad|@XCXJ8IgdmwcZ(+p3F`em9IpG_YlVJg_MFbA6nE+N7SYH0 zymu*IX~#)Kd;{ZR{1@?_cgOw;9W7L7f4jdYTvC*c$`fN9P|keZDr9xH*A@PHSSTkl z?uC1qZvPuoWa8m9W9mqYMZabHZjbdlnUEj&;}98*AAOwZJ0c;rZC5&oAN{w>pc=&w zqDp*R40}$kKsA-`Q9iHNodRxuSka%J3$F-f@MV`<(KHO3Y5GjC%n;do@HeGpzl#i$A-d&$h zerV=ZJ&F2l7~_WFU2i8l=iW#!uiz+lVph*4bV%+%SsE3x^sQ>ebM_AeF^On(nKM_0 zMUX$5p2fC&^y6%$*F~|25K7ajNI@dijY86_jXRn5{I{a-zaW}PM0YvW6Cy<*Nk#ny z%^M_F8?oT!6C@RZhU~q5Q_rOl2cg+nb{9QL`imNDYf36SM=Y=W|!F zcP>S~0$k*IPOl;U`rj|{HDR+mD$DLW(S!&zOltxYO34Jp?I$lpZcNq3Th1b2MA%JmPizEaHPj{3v|r zIC*qxN2FS8xm-A2kh_2tmPl{Q*}+AZ?Q+MM+(fhlF{7NYUN}RjRVkm2hTFWY&0IvaGksqvLtko4!^za@j8>(&))4VmstPSGe8n#5<*=l&ZWm)E zr_;y#?yobojH#16zdC`bsi`jq-NZpw3kK@ZtW=P47M{!TZF%ywi;iU~6TkG~mFRSR zUTIv)jLT~_B1rKTCTtR)BfV5;W9mw>pr)d33UZ3 zRjV&wC*nS!TEgo zn#%mN&mjKx}o?%no_ zH8?O^qN?AuZ2}xJ^AuyqtubYsBgT3sf6bsIpNz>wUe?bYE3l}i?pp-Tmz!(J)UTs1 zE)?=5ly~#&Q(4N*PgtEvIZOAzbvn~TLXP`5FO>{XVqm7-6_qU^S3e@{(Q^z--T z{-57&O0~L^!;88#%q!7um+xf5hOACOjG4_oG3^Djf+~IlP2tMN)equS!t{%gT1?rU zx1Xpuzc(y%UAZtjsEEj!*6vYv4Fq!VH272otfgE(QVpPW+?2^>KU+0GK&oCT|Aamx z@AB~93M{HxK(o6_tOl?B8dAC32alvqUDyvpLnu(?iI!tV-u{&j#tQbHFO_7qD*hSv zGhEnZdp1IgoMdTGpi3#|8KViT_M?@@;VItndUi2+>|>LiHrgZU|K$Sc@r}Ot2`9c1 zNQp5e$1jD9L7Qz=T%4KJczNRDWC}kVvprLCDxQ)!eY(eO8}8|k z@7TINml>e0HT*=2bkvQnGbe_m$JmI()i9Nskro@8;G;vOzu4dwf~Qdxr84+Y%G}PX zKZ?tUjWf~xpk$x`457qDxGpJb&VBmjWl#$9bJpAhn65!Xse(ff1H8oHnFc6MogXSS z1OMJyt#iBl-CoWA6K_%yIoXx*3?5UA6h2$eUJbeY5QZ1;wj0j(RiF5TP9~N;A9mo+ zpV*tc#bsTmB^53TYx;2`F6D9t{4x<>)uRnva?TIdRv*!LZRkXBp_XcAO{aUAJvTtZnc3N{XyeTdPs=rWgU@@(S?q-yeV(uRB7RJ7Wrih^ws5edvs zqq9!VYNM&KzeJ4ka;Y_aWRZaIkr)`4TyF>|;PMO&dJ!NnK_v;ENI>4~TTF7K$xm}H z^W7h`Ro0qiq6aEbu!DyEeAQ?s-w?c%>$hoE%OHa! zrmE$#jJ1LKI)%)={EOx%+SjaJ2C{NVJPYBTLKE~D2Yh!J9`p-W4Pe#ITq4QrKLZmI zdR$=8){oFMTqdY%$uc zi2j*W*f*lxpQDC=BGXsT9_1X?k_wB|I2dNivYOp6?EEb7Exh4scsbNR<`dkG(F&74 z^q&N{RkZ)1H};@V|LrC3?e3sIKE>ZgTkRwFI%jRa!>Gl8PmJX`u;=OIt1!>8Q^uG76(_*ru*CdZbzn zNX%zr*XCA_8f5Akz`?sJ}CMKVfQau!-tmnigaYr#(rEF}S=T0ZJoOh3g zmp7`hM4_=B2klR0dHk~rUWy_`!{mO2#z;=& z5TO&L+uB#26c}%8{V=ozCm6-WWip(#I>c9O{_&Bl0!p*#$j;A)%Z!LJnKXx?;DBx? z@1~x;EQ<08ku;|k|0-#_oLJ)ym5Eoq2Rp0wQQzB9^~tcrRMZ~wNH4B?TGXNU#Xdu> zi>aD$JG^DZ?`#)-(%bGwWfaPa;#tRJ53VAHDD~0 zc3NirsZXs@;8b0+-I!4EG@}&t3%KzfcO3MBy$-(NpWgNRPou41ARn$me3D5^e6OZRK1GA?MEMcO{3 zkD;K*3AMRy!%i4Bw^}WecFDx39b**L$I z^js5I#F~GDs6uoR;2b-%96a;Q&_9<=e#Jinq8NdHG89ER1hhLl*t(sGRdyz-ub?3C zp^R+L63^1mL_p)nKP+ERtW650duRX1s^3~%dO4Navat<&5};#94z(y`gsK?M#PN_d zcLxh1j~*VDrD{;`xzt?f9N4C3dG&{fhKA>g<9F+tNX4QhzT%`%x>YwEPq+GYoVZqYJI0woReIhhZ++0Ja&idbP%|e(x1@#x%Wu|A%jG5K}*HAySqFMn(VvO^#%BoDQt> zisWq1A$JS{aWD-f6~EukXP%dqchb^$y%JLG{`g>75i&g^0Xb?$vsri_kKXB}=XAi| z;z>Q$E_HJ>xNhfERaM2r2Q}i<`;+qfYU-(bL2~s{d(lxbIqfZPlXEb>%Zbi|2Mat7 zf5#P4UXqu|7CTP-6&u|Xe`RIa>0nyU6rWb;d6bgY*+G`{-1IMe&%@zAzg*jEj4kOJ z>hmYpnLxIDg{_Q?vq5HYJDomhPTvP7?sx5!&kD|eQVmPqy6x)Nn6*qRDzb{tL!O0u z7Uk9qc=;KmtTetgfakAyEJdUC_h)@WvvY*8oi;TFHv;Df#l{Ki#>daQx~Vo~xR>uT zj{G|O5_aF{f}=NftmHQr=QYcDzklXdw*Hz$J@R#HJG8zDe`(3g*Oi_P^34bf%k&j< z$eRhG9$ND`g^&91DA>4zlV-ZjrcvC{R%QH!5|w*L#C9#EF&r&*HuTs zdFFQ_=ZOFiqs(JByG*~Q=S}W&LmrTlQ%|m9!xH}^sZxb7?#Lb+wcHqZT*a`xp_Y@f zOtF)-xZ2Ux>HNZ5*&eCk>(D3;E8iU7=XHANV0y8eBz$sXS8G#Wu0U(RtgK?gVQH#I zC!o{kh`i%I^d_F?ZOSp)pn1eH#J&>PixiO$jsw9K7UKL>q*|fU_JP(5`=P;5@9!E2 z-kY+>+iLUHqmn04U`NN;a?{zOU1{HAWmQg!3HrAjLjzqNhv$dpA*#HgohRPUmP?}# z0zAyLd(0It)|;Ge_>2k>K|$rp_h*#(+P!P@ns&s;C$==vZ<(*(v%50yx5^6(6KirX z)xA-+k%Vh4C<_SsM{x+Zn>>keOCe!YnF< zKH*Mv7Yx!`?B=@foFGjMvXZ>N4$)69M16++(&2N}sWl*7&g$N~=G;oA#KqQnbyQ>%&S~i=0xkNTkJP}zey^>18Hg*Bm`=kdBEEGxz7M7K z8f($lD^8aoHq~E=Diov8!~o}0Sd5x|jtNG%=q#WwT~QiiG4fSvK$~sfA|`3pEN)bU z*F&ZI2cp+&!9@3JV^mCL2aF=8A1hPoG4OQFLrTQgM%9!dbpBv@c{-fyeZ^P7mqgj|#@&Jl>Q!>vuB?)`UI%++fEqJ|-q6iK&U~ha(6A zclyXNKd&x)xouA8N3@=YKzuH$daV~uCyWj*@eXI&<4bkQW~jX1_Gyw*ahx{m&yF9w zn@*cYNvoA?fPLQwRMu9#&%-%M1>QLRu2zG~eEK=2Dp#8pW4Vr4UmEUb=WHf$R&#>G z-+~!F;H)(hW@fXHAN5zn{v0&r7hmPyshb}XP~1M=G*X$USrI$&eiLH0+PX^l!q{GZ zY4___JRVD{fYoL2eUQtem5t5HXq#XK7aJE&7>*3(p4(~9!r~LdfIQv8kodTNMmmEx zPHe5c1aB|_k$T4W_6fJKLuqsK%PNU49ofT;J`ZaXKO+*n3vCwItLxuue9M!z&g<$@ zq{wR&+}*YNn`8r<<4tjCv2y#tZrRvltJoy`6FIb4^; zq@XP5U6bJ~r>%06lo}uvaAlF0`T>zid6!bP>h%hIr8`}6zi%t+n$8HbT|i|i45Ib9 zS-eyCSCUuu!@B;}-#=Ut-afwPJaN|PFB+1ct<_aI5SL)V!Om`#fuZ;Ibz-hgFEm2S z{$3>B+m8xsXtc#2+G|0v-v>E;k)fv3#elScYMPoFrul0)&R7hZ3GUpkJvNmyo%;JUg`8;TtsK&`Ek3$ne zJPxV}_G!h(Ika;ON&b%viBWt>;@7h+{Ck3LVm)VcpobKdPW?wTjZ9gF1YwQH5m{w9 z{}+~$e3hG5&c4`Js9P@=rh{|aq+LG%?k+6`FFn)wNAWMlHRY&X{}%Rq@EdIVIWV!F z*?v4iTGC#C0lJPvzw)cuMT1%%d|H7x)${FO9}ihcm**)o_XMtbAnrZiL+r|Lv9jNt z7&!=`e2dFC$2gvy`(=|?m3mQcTI&Vix*tjrA*YJuVt2plq^Yr*dh&+9m|;f*Z5Q8y zL5t)4mv$cLS?MJH*MYozg92x&D7MDdK2JUB)~I1oDx2208t>KQaPKK*Y1_WGnBc#> z98;^)ks6&87O}m?6m`A=Wst-;9E_ECj63+nCzgI8VeYIM4S%*vM?3ODUTniApz3hd z!oy?X`ux7$mV$$Ao-T7(U~%m6p$@_SEIdp}xA7A2Qd6KUw{`PU_)sl&LJ-WVk<8VV zn5ovgr1D}mVz7??BjioW>)z_U8DGzHOYdUC9GD;Utp?MV=;eCR8xHOVH*+niI+0DC zUk>NW#roLl)2V(NVPZN%Sh#$B4cm*4=}39$wp)P04)$kM*^XuH44=0da%dk*H|<{> zX#d9*-WUUi&bur9)!0>=MLxc?F8`c%w;yK*b*yq1jh2QNn?**!4m#!z4wu_H8a_U| zi3eH+jM|eIIfz3tE%gptzewe2CQ#%t-C53Rro*pYfEOd||Cb9mC?w0S5w?)>x6RAT z`}XI(fVVf8dPGq%h-4{)lrP=o$?b7#AdRN~*SRdcoqAJr>Gz10oR!w3Z+rF!5Tl+; zP~uRqqvIu|%kif?er~?l_0Wj5E(>wPh~E@Cz*;&6T~lj{Qcb0*fu0{GA-bYfkAiF7 zmtNM^A=*rbiK{VM0<+^wojL|!!pRxsownc>E45~A9fm}AkK04Lx<{@*IhXbmurPcm zNi=c5;E#=EhL`+I;9@;B-}xe6=ZR1i@#pN$R>wCKzEWuMn#68LX#LNuv}g_ zi9A=S%Ge(KDXW<-84HPj~Y*jyThd6x&d;lsR}!|x9$yzJ^Mb|;?#5kfhC=| zlISdrAMM|ueIn2tbZ010*?z8;u|^j7$dI0$=5)|AN4dgjl|5L}v*Bg3D4V1mnoRZR z+q+2EtCEvf8_QEyctB?}JWU$9X?mG7^Sh-yxBSAr?G@kjXCUYNx(j zuijs*zqA`&fXmin-i~4j)nD(PwrIuN8s{T+$8fG5>84qld`{o4N67rgvpV0-FFJcW z>uYK&fn~q8<-X!GKQ+mlEwJTaWIXLnSNe)j^9%-639q}K^A-?LwVU=-UA^jxg;F3X zLwl2O#Q)~R5O6-l^j)CH{rwwvdOC-AeK4L#w+(YT*BR%~JyNhpvU@;tdomkzA~{)L z&D_k&W{w(`Ivou&B;uK9gRA4Q-!0%!|GfR)D3WUE1jDh=>Sv(=s^0>SKGx z?*(k488D7CI=0?2N!t@~JZUEyQMJNO`w+M=p;b1QgK^4f6c_l%g9{iIUgpwhnBr?& zjS_~riba?SjH70RE(~bEDYu%Qq@v&Hem=@blHD#Q30 zcV7kv6Px*$XA-0h3z~nM4hwIKt0>ArzO;cWK;-@(WS;a2yxT&cb$OA>mV z<)CJ=2>Qy z3uk&fw??etwV%yU>8m=rhkr#r@mBj$$SN^jc9vbB)I$44F-hghb{57pCkykcqrEHH zwh~QXREl_f3)R@1KJ4s}+fIwhj`s`35R)WS+nfc{s;p1u#N{>1EAwm{V7wqruP{hgCnD<;vw9k_zrBq9OaV)KqSxKQz;6 zU9VL~ZFd)1m7N|hG@V|qp$?tayZVM}HRt{uDk2{DonHl-9B9pzFvNAQ4YYry-*ir7 zOKVlyu2w1)T`J>sJ-Y>KTsB6nDk-9iOJFzJVz%!oj0tYTaF=bEoSvNg$*bT1$w8Z5 z)9&_sQNPr8w`KmQY1dOWI{q%T?f-uCsUf-mJJ?igZ?S{*_*dWlvEd{vT+L)(U#XK> z0nJ+R4l(+@9-^Rfn-do^gRb9*t*vBs_Ga;#?VM_-m@KmMK{zMBG)svABeI|nb&`G^ zYKnmHCK4w4CUy`-&E%5qp}rw-fn#hgrG^O=Kr+cBgF862v1Qu1fl@UdCU`d6Fhn_fEh_({iY*1zn zdU*lR)1B-OMF`VVpFpb~XA~x2Eyv1D;P_OJJQYqqZ82hKXV=|6b;Ea8hneoubFc4I zCB^I4zT&SZhz*bsseYh7FOBUfTbnN4x2cNn-T5iIR4tc@eH>(F29;G%!jq)VN zBQrj?Tfg$W`fWe@awds>y&ehDPh*P|G0by>&(0T=$+)f{iGheW%K!k2`lR{`i{S2d zl6MEc$5rUm_ZTdvhf^UJlfHFl+wzL!x3-6+8-X_ND(KlgX&a1;rH=n8Kot)mnP{JuD&VPBNqc*pC4>d|b_Vxl3D?%#TZGQX1u6Op?Jwi=REa&@(_9M-S z3HViN%7BP=G|tepvRpf~4+m=kcht~Ii%MpKelx?uTA9^lTD~3^E>}4tC&RWUYB;LB zHNDQ%IuAg!%;>F*=pu|B+P0GGHv+rbR`36TnEiA)hZ;)`!J~uA;{{(H8aA>K@`hj_0P){OUr{(RZ+uHoB>I#u z6npjGEjG37b(sIAp*OB!kd6ME007Kj|37|zkAHsm8IU{s_wBQ)od^A6X;UPOSE%Tn z5_~P}u?8T~jd}2ELYFV6Ewg&mPtl1Slan|`DKi8>?&rbbYuKGp*7wMqggVKh-7gsp z8rs8%GPf)`U4Pz!`EAo)BK+~VMph7ez1eD#MSF{Ev>|X0o__;<05JcE#*}=L*bp{f zy;w8ksOoWy!@RT?+RRPo_$dH-+2`xa%Rqf2CZkJthMvHATd=dN&}V!BU;mj+#DagA z3VfK-gUxCR44;8V{0H|yhbszzVh`wMET`&gR~Qv!Uy@<1!p0|{Q}Ss0uozIV$gG;B zm%LeG#bw;$dl;3?odO%@KyR@T`2?e&M<_^BH9P?6A9=@8&XmuZQqyc+ufCxD1IoyC zf%%8!+{j;69BDotj->KYT`-c+8VQuA03cGUD0JOP3)I3q;d9EK=fy^kjySVR6_MfQ z)rd7dz3{F(C=I|q?fY)%Wtelg^Gi`n@nTLNA6=6M24Eg`r3-rh`u)Fe@e>iub2@*Z zDHMsJD&Iq31f3BL#JkDpkVovIf&NiV{~#kR&7MmYYvzub;K+P13}Q`-#HULbn*FE~ zQEqlCveLyK@+L8)`Iv`1$euV4Ax(}VboXI-x2QIZ3)+cL>r}qS0?>K;bSDDahak27 zhhFF~y=2oP2)i+vGv-L!CGQi;L~0aIiuv|Qhr}7w)IP%jgaLt~xg#G>WyZS}&00l2 zZ9vhL-w@ll2L@jv?l2wTq@yZ!tI^j-aV5+spOW%9qiGi83HyH}65rmsS@-r?m8C73 z$S{l)`OfxkYf47)8~2M&)2SvPK2w<_x|Az=Vy7|5*=`$Y*S8c~O!SE7{rs=3f8(nd zLlUvjBbj=lWZ}pt`wW2@Mvk87p1r4;#u5Vj_6PD1fXj3z>Ko!gpHhMJ+x3)tJ2|| zKR;W4xLTNcR~SeilzeQp6VAMRr|`EN(R^E7g8|LR4em8BFK`aU$d4#6fQ)X#rRtLm z3fc~iYo%!Ce<&F;LMP_mIMm{Kk+14o2cSy;kju{~)a(#5<5u)s!bPgT^X?xbhBMOqh>&TSi`u1SIML(bq3VqR%yf?Xa($WM+xq zQH<;nsEyc=H_A1WfYGCq+MkkROp}XBP}n&L|D~-OlE=UT|E)~4+for5q*V>RHsc&I zQnJv%>(1QYDXgkRHzx>LFw>f8{-R8fVrB|^0-Ji3iALZmQAQt(&^L{cPXB_;K9i~l zBf(ChiRr`E6k0fimig2u^jVLhO*kz3#))Xi)X@Glv=R4?%5DN^e!PRoJ?=(6jR{?VqDjpQO0`X}m;$Z;#aNEg6pL~Z ze+{@oD*VUtKs8U5*dTWf&8R5HC#evqBZY72O8;r{PmX?W0s8z9T;|Lb_wugkXPZ*~ zz=r|QjU8&Pv0dhG7I>D(8{*=*iz=1#FC*J{z1CdS#m-il z@CtH>jLd|%FCniJ;L^wL2Vvu)#k!;r_&Rb}#qXf^=lB1LD$y$37|LZWU{^V7*=nft zU}XeNw2up|p*3YHkCL;XhrIki(uBGpi(@^BABse*ysDd?nz~Apcw(BACwm3)AVLL# zGeKaqODX0@O(*>?Q=(Jufq2!hyhkOq%Iaw(>1qOq1Y8TY^;FTKMU$|>oExc z{sbg@Y-F zOOIE;7x|o^hhif>ieC?#6xVI-EqrCr1LoeCR0E87G#2*mT?&Z<@NpW#K27pdY0I#c)RocGDN^MOwIJWF z$kv)p>nv!3LUZ2!TaRFOpD+sEm71qAuGEMB)*t4kz9WHp1mAy97?l5CE}$Ud8dTdr z)vWs)tgg4Cl>*@p;)22a=0{J8c`g(1kD}tC;n+L>D*`~cH~MGz>UaBo9iH#d=Myg# z4K1czv6w(@fNr?*6w-~Dzr|1;G)+5jLW^Sh_mNx=;UDmr-{RDapx{L)g505S9&@xQ zAtAxa%ETm}o`GzC%Phvh+IkoVqv-U$ZwH3ug;0edhlA+}Y52oG6as3MFFXR&)q#WD zY+TF~F#5&Uamllji7v+%W22*&g0M2m_?8B4@6Uyi%N0g1p^+GAig?K^Nmuj#aB2WD z+&;>HwBtwr4=5WkdSp9C?XXEL5CV*Wi8i$QWL6^j9_u4Pvx?J#?{lPG`*gkotX?qa zzR;5$I)vG4XRW5PCHzo9>tFw(Zm{RaxY#1AV*Dlh;th1(engK4W0|AQlID87SN$A5 z0Edq8j}!9GbDvR?Ukjdgj{YFEY(TxTCq9VZH8Ktyl$HP4(!l`0yg#bjgD1^bQiI$i zZXgt5+o4|XM#lPk841V)OK^w$FDV~W-C^|ewHbH^Pvj(pfu}hCkGi*v zs-tPzMu89r5JG}WfZ*=#1b252?hxE1BoN%)Wuw8}3GVJraCc|JnS|WWdq3}4>#Xzr z{AR6ecJ|EF^i)?@S69_l9S@7i_J>6f9!mTW-po6*PwJwb5-qwk0fKZpzw-XYfVXY< zBrg+aCE?2Va+BOx_PyNcuhITc2R^iKPW&O3!aqzKZGZ6`#_(W2`EBt4haAKz%M0GwBg7A5RsxRrA(8p(*PtGcl3aHiCeg#EC z!pOE!G19)A^nOjToYz(cdc?hA2G6&UW3NKOn7@N}p@;CG-*_|{pV(Z2h8DQgG&H7% zfnkIJKeG)2;+sG1yvhQm9=d}I%L{sOA`(VD;zV;5gl}in$Z#6J z5$nGXbBZ#x-bMsw2QfH>*J-y|oWf3dZ!f6|)P*fST%#3zU}8m!f{_Wz13!;Qh%?#p z$*i%L4N8QD0Pxr_B#w8OG4SiVwYg{hL7-B-OoT@8;f|DrreTc`2L%le7Vd8neeFa1 zk&7k8@R9kCjRri}M*vobU5>bSTw&9bQ%VX;k;$W!MuDHH3)JUU{y5s0l5!kBhug&N`=b67&yD*1*tY@IUj;<6bRd{u^dVit*WUkK0-&Q;{ZD2Ml{}`y}IQ;2PCje#! zKRp~exs;(mW?N^-e2*a(mXvXBQZ6IBxa<@&x7spY(&K2`-xiZYtwK&a->f4BwbN=r zD-=+3h{q*-_z+tp(-U=pW@rrfJbxdkJi@B+-TA8u@Z4>8Z*)b_ziIFEHaDKEKC_1> zV`pz16HQCP7q-s9=XU@3rcvCZM7}CJU z7y0%af{cu8VtjHkh63BxLs??!kC_eJcJVa}@5O7d!d@5>lI<>pm)^ff#XY$C1j{t8 z-^}~s|0TCXk#@&)Az8r1`@5<0CC^urV`9E|9n(fVdiTcTw_y()sINU>G07p3%38AL z+dGkNPi&um=j9D5d3=pzTL6Qn=P6qKEfD`~ZSDD#hX<-Q7z=Mz0r5BO?tjKPJw41b zAwPz;=L=C^hd{ze080HhKa81tk>vSTe0*W;U=i(x7^vS5niEZA)z;oM9B0m(V6jO4y@zcC*yOWWx)nKvM3Z4GXz153OhZ^lKUQa?n{y0W; zEK*Lcp)q8nV0=b7-@J;TFrBC&`Pc2r_C@o#(g?5go}d1Xe`bwT;ZDijjET<`}L znrKL2Kl75+0NWY`^j|oqga#NW1X$*p3Gh@8yOrBZjflOy5gE7$e{PS_$#1aG`_SOA zDdbAlLs-nGc+<$-O~~|3v&b;tpJ^|pJKqa~?*w9>C5B{HE3am#psd|O$@w09jipck zeW><_NJfl+vU=g@<7p4I3K-oCoQMDmdh<%pGtWhY?ls=x@%?enfZ=G{^R*X03v~-e z-@KpAbJ-iQU5-=u&9in~P=?WM2NKG3iMFw^u>c76neY4*zJ;YqflGCtyRKKfJ5UY4 ziI5;*P1)?fuluu_39VoWBpEPa@}|mWMS^lDMgo+8i~Z*@I|LQfIq-}HcWzq;Ki}Za zqspcx+W0BJlK!L=P?{p*6N(ovL+&Kq47Ce|rcK*CT;QE4S!(fKp<}<1R#S7avtxX2 zfRC4+x%uA4#_FC%xtHh2)=)CD)t>fXwULH@t{4qTL1DBu95B^-y@1sEiW&sr#47T4 z!0@-aBvW=!kAmJg_yWRYasd^mrXNW1&qv}43Atn23$3sDTku}5OsI?qS~Bl&^=8XH zb@(IVuv!9N;_E_>A>tJP{bB)4xdQpm&%e*tq|Ihb0#?$ytR$)%f|Ma6;wjrlOg+}T z0v?3+cVV_)iQcch5@iRzp8R^!lbm5QU2H2C`1!}3Sw_Oy(@e6+}vCsJ24Vh zmqqnNkX@4k;S@3C-%r&)o94EMW%oo4ap4v)eW+>vH_kLyoxDrba z9#Ds`AF8WwMS*B&89&}mng zk9s&fMZDNP&*Lv#y$_X@qFg-3hlf z6tUS*^zgvHrqn)72hSv#*~gjB@!nKFG~n@iseCz2xxa3m*rNU!m>q_oMG~dtYj|f4?>Ya0nPVrj6%YPW8I`!LQh{YW zcCW|Y0!jN^*?gU;>at;lN{!e|a0A+9HLA;8sY%Z~OCkEXtKUjfGKY6p99pZzO4K!X zKE=00qtxp>pdU;@p zOVN5 z2pdS!H=pYsA5RH#b9dL|5nn*2Sa4KFUs}TFblO|7&tvD}%rCK;s`4_<6}o@7MSC~X z_%U_ZDtWh#Cr&MHlLX+v+cr1p(~V^+w&TdVRCZ(2+Ax~Ah;Bq~u4;=bFdYI0^}@;V zO6Aw~_CWC=^Vp>#)v*NyOR<%bF7IWN5kD;4J${WeSf?r2xTQBv(>i!8^$|5RO<0hX z+b4-@FWgXnT^5F#s0k@)d1TS57LG{buD?enELfK(ous3op)myCVS4KYeIBU$Duk?U zrO9kAS9>KIEdjbPvzcg$yt1+^F6PCZRP-LN5$bo+juUpc?#R~9mz%1p(H`h_#Ut1; z63f2BYp@9?i8FGcFapFLN^RxciO4(DF}t4Sb?aCvhvUg0ZxI}-fwdP6PtA7w;DB%( zH`fCW2evc|D7-wJT|?h8 zuEMCUK-!zw?5m9DMS^;NcQR|?6=c6JW)W&!*ayJaTdb4c;{1s6k!0UJK za5UObuxEd^@>4O7PAmL-Q0A+Ps&7eHG#qXiAWi?e9Z*`yeLCL~_ zgQ;WNkJ%=40y~Lj^Z7^lKbu2BL&>>0NMf<&@VMP1%$AEJEv(%i&mKG4cJ1RL!Cg7( zp*WMbR(mssIN!T^MzlBp#j(?PB64Z&ecmM}iQsC!?}Bf3+a_D_q-QSlbuwuyz49Ml zK$q}jb>*jQe;BQs%#MOj#~@?lFW6IEey~`Y>ir$w2~o4f!D9oeiQ!O;R#x8*7qF&J z>D5{Zc9qLIyESI-QHYL3&WNZr)1)vy_B1(C@zCmQX~;8sBm`OrXDVPD8@{Tsl7)LU zC?ye9&yEoA1_&}!W}TF;qnOq^y6>fV7Ccdx6LYPW8y-JSmeCi~*JqUEx!lO1WXcWk zG!UR;#W6~=nW%2?`Y21*dymku@=c| z3#~O?=PcL7ezNRjwzk~S(&?2g=bl(Q^7GN%>SG#v0O6n)&)T^(J|xbSAF~^gPzLYF z+ssuxe)r|s?aMs*Y2cMrK}F4d)>&_%sXAOq&$gMDH=id)7#Rj$tCc|OA4y>hTe90b zAUTB#9N2!6;*eJ?;kMh$qJ7zQu3Aball*k%Q(OYjf3DkAplB4sRP)@{eJ!ch4?_PqN##cXzRXG`%EtCrn%w zt2@)aCAQ-`tNG90CGaGQAk!Vpr>cCL$TctMgw1{q9{1)pwcd}K^*`23$5opvf%S!S z6i5=IXD6qh@8z`HckX;*q4#(7?(C4pzKAFrN%EUjJdmK=H9-3l3w)OK?MZ{mcQfKNJrZ5&>6#B2`EGohuou7(=Vu%l-p~= zT&;Mc3@dJ1W4$crsJw3+YU=v5rg$joa`%8XCCy`@yil_j-nSBxqcMMW**L4Lgzt%V zcGW(`h0^+7BhSfE`zq_^;bMP^7Z%u*NoK~;+8Z|CGAnWtVloi%VQwvetE0Yn@SvPUQaGS89kiT8kI!Zg3tG5Z`8YZR)B>A^g_W9 z5a|T-fCbf&yuIT+X?I$k#tzh1h1ED%SQUG!12nnoHVgKX1KBWB$M@HJwzu6&R_@{D zMfp0HH@gG3Of6um`5CY9w5677xl8KHy*fpj=n%xGLE|a9&l5f2<0+Jp6Rr1OD1*7K z@l84$o5DxF5L2m;L}%e}bx#(RxD3ssrZ=8#2S5{iV>34_+mRix=}wG_(`=v)ToNYM zmr0i{k{5jF(Ly*IwO)#Auv1oOtnv3AthBX9v6_#HN=mAp8;Fm(aG0A+AM{QZMw8o0 zM-wmX@K!06_QH(d@cOa);EFy~82EI@MM0>rEFdKj8%HFXP_`GJvp((}Wub&Zmtw7Vwm%>aRfX_NRD&WAF=NzLDX?8OSV$;e)4G>onS(GZO<*juE{V6>A;5j z90Ng85|TxB2U$7HU#Hr+_&)lz8?oADqw5Sop+fj=)k=x?Q;tW~aqrwv;~OA72=lvm zDX^9qdN`$0L@@vf7I+4U%{|@><>T;r5r>#17u6oUf;@C^A-7^gg7mcL!8|pZ>jd( z8%njg_mk=Tn-GIkG=> zV1dH$eyQr2sH8Zj$Ns}a#g_S&JET%hmYuLN5IzTI>(h#Wz5RrD{Gi5N4|BQN!-S3G zFJxpE5`?8vd=uI%)CBIw3ErgzTn^Vj_&&F^Bc)dpr}aZ6%V#9TGP0?;>!uXfI|Z}u z8&a;K0aL-o4-5v#ePgNj6%zE?K|&&%Xd=#gjpoP{7Jd%I!2>PoN1lB3Wrm6t&>6 zeVHs(Sj=a*-aXd~;%nB=uZ~ZXLaq%eio<}lU_IU)E1#N1JMRwJsog%oGS4w~a2EsO z)Cs;2wEJ?GVLC3G2Ug0eKm`Uh^(0Y|E>k|JTYkz0b}tt54^x;sQOJcRPy)gOq;`?-sjVVWzk2dsb55mo&Ti(kQ zuW!7<9W6p>j_m_wyD7NcEAXuEkHE@zFjZSA;>OIUA-(6x183z&eN6L(-^8`3Q??#& zi}t{XZpAaQu~^@fue3hImPG@{si&m&U+zpMJ#eGK-l-Rf#HtKoM_K3WiD_tXYQM>5 znx_j&Q6hr9&QYtj9QP??QBrSmVTrE;)%a<{$~f-NRwyPLPuh;wYoD{yU>|bYM)i>? zc@hUaB?hzgWe)k9)^`mx?bGO8n!+FdolR66%qC55KpoE9+xUDZ?hoR)Zj@v6( zC1oO=_p8g%N3R^d&Z^B-njk;UiId#jo4mo%m+DVk9Poq1jxJiiz+##4+AvLu&bIB< zGeAzMUhHb-V`%Xr@>^_@NKWNSH`Z^DsGJ{El531hFyzR7F^`0YMFDn8S(KNu&Y3QL zeSBjmR(Wp=q_UgNck+ubc6axs@kYyyM^Ys>jjp#ahX(fP=9SuSPw?!2PiAAvu-F|P zj!4<&6j7#u3+!_bPr>RdF!=DoSd_i{(odp(fq-=ozZK zSh!4aT=CM!P!$W-Ly&0F`*tavdWGvRU!aNWlPGFp7@GGcn;eEjceAQCDgwg&$hnv= z&N7IQ4ri=R7b$9LrloY)xj3pU=4J;czY?B{&#=ze@b&i6irwyJZ#EH^?9Di)-)xo{ zFY9#NIg@3^Cd3T#y%ZiC9rc+n>`j)ilRvUNm=LDGo}`zrb#jDfV`Cy&p%%~HE?th; zGoBfTY`x!86outF+jlZwxG=KKH@7FtCI`DYS!<8Y1xn1*@!|5n5vjRYaJ~sqqD(y- zGPz=%-W-^dO`{K5T*@2Korxjs8PUnLvm36m$&bmkbDxZmojp0i)r{KLNlHZod||R- z(wSSVc+#7A!G5VUOQb=R+H|)O;unm!)X2A`Wd>eKm#>Au^fD9_YDnu zEpQlzDrYICJ}76#YmE#S*U5ZP`j*u%F&g}~<{WcZu%;GBKP(SD^`>2!ECD$KOF#1| z+ic~+#)&ZA79|d>J8QXmfAo~M70<+;)6__+2E{Kg}rvLdGj&Wx-jY=GeN+Qe1>FBrYsWJ-oT#mx+LY3Jis+jHzCPBQzP=E$gSXC~OwHsOw!t zIFKR_o!@~=zwE_ctPo4uh^}FcnN_D_nw>L-B(ap(_pe_Gy(>>_DY~R%JYlYrIML?k zk&aeB5EqP;m`}`~oJ2D7JxPssM9MQtM3i<@T38185q4D&elqQy%%}CjFDZh_9VemG zn6D~;#89a8zj^eN(#|SGw^JTdlxB=VAfVeUXHq51GU%V{TR0Ol$X}AbS7df`S;29} zlS;V?NG-l>ljXEuFdd2IL`R*XRNb&d9^9}}2}+LBn$9S>f6U%q78PQ#+EJg$Hoh#3 z#l&3=BE7{*#T5sO2z8aM3*G!4U%n$ccEx&~@#$BpoZsS2h6alh`3BX*tlnFxbQQ5QhJ>EdO+KaaY2|ZGUXg~mSMnz@0zPEybuOi1i*~g!g$P&D>X!}pem8Q~_ zB07jo=H+avH0JhSpVmJ-Qo5Do%3w>2G&Hcj5{aCz`mwGPicqkAv~_<1cU_5oOudy$ zdJ3=FM2iFm#AJY!AR}B03s)N{x6PuGtT>l(n@yHhMXYZ#kx3_gr()g@Cp!u3)AVdi zeKR^R`lnH@ihy||W{b%#c`wq{zC{O3NzR={nuN~Ix~M=T7f?ARG^G(zTDduyRc^KtrN1$6edXH$+6%}o@Z=c@&f>&ZttV(DpCZ1outK%MLg{(!NSiKsRI%<- zy{>06}#k}83Lk|d* z-N?AELWNy8OyLvNH!@10)L7+5e_!JBu!tDK+E~;A(6>cl?$cx~Wz9&j3~X5_S;K65b{9YSqY<{0cRyTsetV#~!22h|p@ZY_vn!cdmQ+Ny`;x;3ZgDN1(2z zeC7`aI`gWIWA2oMghAC~z#a*4cq#1jr~}hl@3LgF5?NV7D+8DSgFRSiHT6Nv<90e4 z!e+51HN^mYqgFTc#%{ys{?Qj$=saAGOlhh-3>TAt3LPR2xQzNXP^v-cu^?fEBb~Xb zM2nYX(y*CCwDhdJpZ3!XbR5lw@!4;QH`K`R1 zAimH6rEdkqi4@_4Jy|@JCEo0~aK(0B(sM`7yhP0?HfZn3yN--(vwUfy%_$>e_YUvo z;#+{ezOtJgR2p~fgOA}1n3t0)IPIlTluaPG-dVR0s0jB;I!xNjWfjF0V=)NrYzFm= zR!U-iL|}~W&hdMbfqlJQeVAP4mx!h$nN49<74XEx>Ti(R_>8D3>@Yl1ATot*4IL%p&e*BUlpw`H$`q-uTrNub`n>Pq{$+@iIhsp z=%z9%vi;cVN>sc-$%n$?&Epx@SA&a5mC{#0q5dTfnM}v%hSoL2(h{0ZcT4EFZ({I^ zFpEX}*=Fy%J^YiwN|otJH^60)l$f-kePHStq+&g*Jl3`Az2bcf#2Mm$EMN76*d#un zvdp{Qu;&{^Q%8!E@Vk<2%3vkgVTp&Gt6DoAjz-y`ccnk#@p)ohoH?eMBnL5u9$OV=zTgJJHCUk)zft&a% z)dH@MAMwcD230m4N2cGETu83PdMRtA%BD1m44c<1h#5KzE|h)8qvY{t-w6U-`TbVj zr}L>37}kSeS3-`5UCMmrFB<%5&94%94smE0#uT3AdMN{lrIe=^7zln@X|n%JDcYSV z$yTUZtW=-HR4|&Bx)8y1HTexEWLU{57KzpMVuJ$*G-J~dS3LKK$dYNk!=OZRef3qh zjfrLmkva)4iu;}f5`ursSG){@Dc{+oFpOHacK=veb6BUr^*-$>O)#(LiG7BjI_=?- z+$p&*mQoB<@uFvB>@00%9o*Cx(1N+VJFsdhA`QU8OJiJ0c{`a)^e4 z)9P|r!;*ac)&E*NLZ%j;N>>Ar!(i%>*cbU0ZX&djs zL)sU|(HZediocD}+KKIZ9=CQ>BGiR86S^1a%^CgIefFxJN3gadfJAIp9L?f8Zg!fjTUM^Y){maVhsBH;f@P$7B5^QVp8lbr<=`MX)-nYO28(E zVL;0m8yFtXe=2ooR=Tp?D^3h$k>z};B%1oLYa9u6>-dwhFm}8ED2R4w^}}K+UjQ!< zh;1lT&}lYmPt2%y{g;m<2{1U6GUN1gJAAzAP$+gfCrLgFg8qQWC;_5`CtG zM5mfF@dA${aYS3}$x{cJss<6UZ;jdoHR6;#0u`1iqxBRwJ%q_*^VAicSiPFmb-f!k zc6WJWd2GWFaG3Q)%2)XGBx2BQOQo!9d?b!$0BrTKGkJbeZHiin9=}St<_2M=4kFPB zF}O;>jM%bTG^IjfPES%AVj-`!q8ZYKSwm2AYG{O3T}&Erm!KeMe>yLpM<5#p<`IeM z`cPI{Dkilx;_=tF96fm>0>0&l7HubdPS5=kT?eg)`QrQh<&|2|du}d!bJw8!MWUG% z=k*Qk;8y%6im7>uQifX!^D04Xv;8BWV-+zw0jE&DaA`H^ax^0SX zbaKDm^LUyaM^^qg`jw%@XEN4`N)m(_YqM~T>+EDFhs>Jo?{T&|HsL8cJbGG?7^}nV z$YVZ=@U0I?K$sBlSnb-DTM(L zY)3k+p6L=w2nb9^$(pGPEDJT;rqM8tYM+ZJT&rW;HE2Ix6Uvher;d+L#6LEs>U_UQ z%E%QDQWmOeB5R+MtlfI3-rCaUlhEu($fH{}-BAu6tCu60DGz8|cp%x|ZHbV*Pp{_c zATrR>PRS>j0!)`9FofH|ZRr^hLp8exS=8`(UvjcvECHUo{CeL#r1|yIO@h7|O~BNK zf9K)@X<%ttwQ-#umfGTRnlu91cNV`L9Vpcdi1T!JScRdODwMz6AM<;Y-Xz2VGW`r{G)s&rHA8 zlnU#W71?HuOZE}_$)Crf(aca9R_~Kt4 z8J7-b1FO7eNaF3^zQHkHtf?lz;a&IMB9qC*z1J-)FVFbs>F4|6Y#YY}6-9Td$fE3% z0pmUHYT!yjfqBU>X<}MyLW{k#xmveg#Z_L1wAky)qQylaK^Pp}x`>uzer)aC zc-@2tUcSK8UX>m{d**z)TvUrOt##B1-7to^3KFBocH*-{=RMP%?f6@bHCs~Ury&=` zpti3z>*8=oIQmghgwchsR}bep*m*xXUAlGmP3$Tc1;HRP>(ml}fPsJOAV+t$HI^+? zG5T{ku3}`BR~rjg?jBWM`V2=;)-&KNKV zx3+QtgYcm6CV~!Mx<2G_>yg_xi_LY5(2gkz3W!aMT~XBm5p1Lv>0~5D$6fQqg2A<) z)}l=wgoWLBWUo)NVT+ceB#*3jl-+^)qk!d@a~2c?29g-$eA`x>Oo!BDcYancv4GF* z6=p5eo9w*tHtlp>4QV+=&3x=EVq?D;@Irn2{x{2RZ?YfAO)^FVrT>Wh!1|e$c3Rf5 zr?V>@lPz^wjR@unNbKcS`5_@A6DOT$*&Xv9F0caMOA3>#TgYtm02Zk0zBjah75rE= zx*RqMvev7@TwT&)MdNP!>;u)|y8(2_E6gGyR zc@pcBLsYF``R0=aWM@Von128w!H_JhjWKj423G1Ig>U+Jvwlp4+Hea77qK0R%ZR5kfpMzS*Iq(+yr%|>E_YOlvSrs;y{@)o zHLij)TUEBGXz+77(DR^W`S6b~U^brs+7?dmFct{6bo(F~Z{bsc7w$0J#~=WeBLI7i{XRa(j=pS&`J$fjH-8x-2JR04@6XBq{(i;=r&96D&m}ik_;MHF zJ^r6dAmlWByeJ%d0{$T9e*eUu2vG?Xdw6P1;=wY_$WYA zo`7EcOsoS0I%f z_Jw}haQ zU@0W3ki@qu(7BI6Y z8z=O=D(-}OXZIJbARHpp-D$*#95~3#6k6HnsI_4tV7z+3(x5zTX~1s%ZNyv z7$TKKV`?;?=Lt|CfkwpvlAYhpH~*ZocnL3P9+7C>Mvv@Eu2}N*WlkW7u|E9oD3^oS zP&OA4p(V+bGNz7wRoT=MQh2A_%4KL}1_4#KAz$QP&mUWz0uu)tWQhDpgciR=1FqPf z&f=Me3E?=^63P^EUGY>C4XnrOFL)pY#Ux>*>jm7=f0^)kWhh`ER5w#k`v2{0kx?a* zX@%5jC9sOStw@JBR)#E)Jp6vcB)5qBs{hR(uyx{6!jPG{vntQKhmJqbSTzt3oh$Hk zDABkq@^lsnP!vRtrv~x`ebFh3TwkzYC-fB?*Dr#!e-Wbm0U`KQ2zoW}Qx&az3Dn8p z%Rq2oARr&zut{P}j@u%ac13P}R;K)k!tS1R5PNK`v93$kP{O|f4PQvfY;~OC@DtYR zU8}jgsy8?SeO7@@oln57@e!Q6n$o>U5~-pTpTjOffXi458+f zQd54lhmi`pL;-Sbkv{U~wU3V>4W1a5k*<^~$oSzs6EuST$lJ1#+=JPHbb2iS-h1)3 zjU;66U?^#_fPX(_WNs-FYZ~XrB!$MM++VF`grmGWu=B&K8V~-`3j7iZPyk(UKm10A zDzIWdw{l|*p5V5>ZfbdMMt)>2qjZtOlX@9kIe#Doq}G|KYS+AWCzNCQlTl18eKxWG zEkEX;PVosxD*mDvw;gwj+%bRs((NVbPfEx$E*zCKzQiw5-rp>NH3D$-L*3$_C2ZFQ z!)JsN1YW`ds^X=#R%6l~9}@tX7GX&ta(}_@^+(Y8)d^(bG$8osvy<-tdceTQ7!cE| zPBv5Rdf09sQ_daOf@#UY*!J*S9vn$^At#gZ0|qUwe?6t zauV;?1&6s|?x_Nhy=gj!v06?}uXC2Azls4Lt6>mo!0Mc!L=Q%w_5yfYebe#u2Cjg_ z#rj$Zb9Ah~5G~S1+SKiy&@+&i{M@u4@W`kKb3IbN)Wp~`oRsEg#+hP(3K7 zwgF~X`1<+{JMaJe!T12>YMo&KYla&RC-L^9xd!Qr3kVuF<=hMiu05}}&n@P4W4^VU zvQ{ti;|K3?0D~SODWyTnLNRUSa>)MCWJBc7WpdqP%i#*n0k$pOa4*0gdm)-XI!^kI zqaJG5#mx6DK6eSk{McvIOa&{gYHt$CH4qfg#|Xm{MN7fSx+Zj-e9vRJEo(q%G{oBa z(=giWOHB=+Lqr{BiV{QUQ{PFvgenM$WPln%RQW5k{0K@$=3P!dmb$)-zn92Vk>NuYPmhhjv|L64e8DtqWtH7+> zR06bINnr|w`q!*6;$Nkf@nPdW!o(xfBUIsK3ZL4+&@e)0DTx@;8V`c|2^jk)PC~Zobr|BM%B9QH)=pMJ&nnEfF)G1s;O@jSy7#u$fS#PFTQguWoPj0TKJO z1V;E&H(vkA*8kK&%dwz9i~_$IYwr*1{X)C_V;^vFV5WgeB%>6!f!uJ!&pO>_`H?^e zJdsi+)CsRiLMKmrs8D-!w33O+?lptRelR_Akz0VJ3Z zTyz=%%cl(qiN2o*WMyeDkZeC^H{OwuO9m!Z%$E57HxPmOEqw|`B%&en!zA)63Bbw; z#+k~~l@#MP&@<`%&H(vWkGKiu#so^lt21I9$ST8@(h_6{0U%7ZG0Q2q@0fYwq8ed_5f=J=I?9eJ&$4qV!XQPVTQX+ss7AI5PuLfm3>zbl^YzGm@;~v z5O}M3c179jh@P{B_3%y}n@#%%KRYp26+e+md z!+_paa|B#M*!x0N)&7fYG3?cX5*Dyi@G3N|GJr^N?wy1)V9op26^NSnmb`@o{5Alj zg31ONIyOpHnpE6$`5 z^W)(BYb4wmGSz=lEy%(yF_V zTlOEu0Vhl2I90ZMTOwN-+WPwXs+d_=jDq~b&u%K38hCnvpb5JlAB-AHE5U#36}m`U z01Bk}#Ky#A&{2;FU5{45FHB$Lpa1d?9tcuvqbJ@BtgvWOpZ*$@Cu2V5tzJ<7wP4Yz+L@gtn&5u-S2+3kC~R5qs=>fw|G{9^orlDze(Vw-MRXqpdFgsQq3ulIs9CXbxy-UIdT3ln`J; z#IYz#_)llDS_196_Nti8AA#0Yjo;(E{U@t73<)VoI2OxId^)Ke&J7>@L2}lr<3GLt7BODpYVTv~;4N@C zqQ^CFllr}vVU^{y=|TeuQMZTlr9aYB8L-I}>tR4?->dMTJI|kX$Wt~e-=YI5o1z8x zw?e%WZb(uimnsyGWz%0aI~4DDoZgfe6|tr@I;Wba3?b8L{h>z}%I?IH;apYMf3w`>bG1XrsVdX&@c0bsmc?4Cg z*#kcD-k&|W>Fne5Q7uEA`Q;k`!^; za(31>tD+seFp727yn8$-i&R?l9{+1mSvN1i9Os(!#jwO+`lS!*ibdkw|| zS6f>3Cf6Q!5EU0wQ?YX);@omZLfp{>Xubef@~rv^of$_sjG16+lhO z4%ka;HNKu6+E|JBr^e06Imwvzs?VY3%Dod@hHYf}<)(m0ZQO6_3cR30vU|G1xteN* z4d2=JOD6k4O+BmJc#RLXSs4QoD)kN4ad8iK?Q%W1rUxon8?R1InWA$aM7rDSCvaF# zv|8NGm+p~JkfZk8T_3nNaccWZLX5Kv3~Ha8Px>#p=yd#nJvi%>izlC=ODtcvCUT$8 z_MLB}T(>$ZkjK;x0XyNW?H`*&e6qB>IGHw^_dghzu?~IDl^7E1J#w@R0#|O+)gE%X z%*;F~_u?=yDK>1-iM+91D5P+2AR-%?a5-4? zOh~JW|5<9FzfRTIFj=(EU}vg(jXhOo^}FEn`L^A>&rv~TG!e-wo`6_wsxpiE950vq zi{%$RGU=_quIWeXn+#TTQd_ZkQkploj~V$+ci(B(JM9l~T~nzR^2a|M-i$;?Mek-d zc%56%-hb~7Z8Da5s>!my^A=o#K3KfLy;0vP;0K@Qj zX`PXrtXKMnyBh=-&;!C!Gh26~ThRlB24TBRyjjrKbh& zi)~$uig>|M$~z*gUHg&ni^_S-@$T%_$KCNMO~dF_aT$p@?;BLGbTYTs;?7z~R@X+b zjaLH@xvUKiFXaPAKI&E*(q=R90SJqy6Y(Q55FB`^X}wYJirM@|Z=<&Ft2WvltL55w z_1Zi28R4YRBr@8R**-Wk5;1+m`v=XM_>Ua0Kw(rYD_QSJQpV$%^dz?#B1kEu?)AKn zlgl3$7VA92ml#-B4v#!rNkjLd4~s@4go2Hi!=cjOfGrg~1PH+nMZYA1Qlas{G--U< zHl?(vrcs^3QOXA907S-~CFZRMXAj)Vs)u!+)OnzhPYLWKxZPo~JV3A;(WPWDG#y^9T* zP-!UCf!xIf_Z{e&IUt3+sC1=?tHp*$+~Sa;bp7R@naTq?1A)2s*RNO{AgRUhVu#Y1 z`)X%AEDqIf?JV@+y*~ljNz_Xw^Cqh|P^!2VNgM5}Sle(Pj9vCk{^uv@C#9yvGMWtCdEb-!zzoV6iboJ_X$W_8;QZPY0V$9?E_R+JkP&1 z7fVk`l-Qd*s`X8Mij7J{R^R4mb`GUVo9)dMr_RLX0v=50dOgWrlX z;NJv?m`x(S|E*P)Ou5o|zrVrJTwd&)G<24CDkZExn(er~cSc$SC~&Cjm1JsRwUlL+ z{Un{pA5|bc;qUbrUVWfhWL(|S+z|EA%kC_$()R~ls^9wri?~N#2fgFmWyBveG{C+9 zegfnVjW!~R_I{vx4%gYo6sFWAm#KzBbJ;4Vb6O1zO?4Set|*?RC$FS7@*IrYwtB?x zeA_am2O60o)rI!PGP#l&tr&EIm`iHqPE;1uV0+^irJTfLT-7$0hc5LpL@NimR_?br zsOZ=j$__Di7 zk$nXHa+&$3>*2#4^axSrkxnH-Zo(jzK`H570tN<#T*>7YFN*rc8S2y?a$^hwx~3H} zZP=^Bk9kBG7qz3?wyN8s$l(% z)w8foue38n9D&50yyF(Tq63NlhqSj0i>mG0zEuQ7KvYUvM7pJ0MY_8|x*LWVLO?)T zy1ToZVUX_bl+K|WhIy8r*Lgkn{d{=8yliZ2v#}=DTC|$yPLutHzmLpI!a=R?xFFWJp^1B8PE$;zM^v;AKBXK>Epc`W;}e4R zaCsi)=bKiD4fpmMdHOZI#5oV;{i*xlzs*0MEDeYpC_EVV%XXZ|ms3%7vdj7%}@)5o7KR>$T-Uld{xt6VS z(YiT&W8)PrMH|7fry$?kT^;rZPnKokIL5gqL#CP6VYj;T%b1N=eZYG zx?FQ~9Mp{o*_jL@be%3#iC+3v!)sZQ<`Ku59Wa`{H#T2q(>(_WTV~lKLW5af202Hl zmmZXSs!ETFja_l(uUcDI2(g)C6=f>jTw*$vzTs#78_+a;3rf8pd-nD1cH62_PDbyw zZMw%L#RJ`QA&-N>eBoPGvbN@mXVVpxbsK@v8w2ydJ)a6KcD}dV$!lyRuvFLFqOn6q zcPuKbejdHpwIY|CyAY^VvxnHB^4bJ108C1(Reqc zIVKm|G2NZ?l!Yg-BRi{P(2<0b;T?UzMu1AvL`WoG$BKU|I{h)FU5jV@CI=;BCsuu3 zRe!KsU5im=Z!2G@K^olyogx%EJTSI=$gwE?NDu1l(!Qaw0W)GB&56WE`~8jjQ_Qo2 zN5AuyFM#s&Oo6I@4cBh{X#MHH`%kl9#+cnE zv4Se}&1ph)!W@Jt&luV$H@*xO5?g)|*;bTPcy7wKsyMpP`C&8Otpp{RYrh9%ofPlF zP_Ms#2rL!tiP%-Hop*QLk6C`thc%!6>~_dpD6vO+-NtpaXu9+uLpYV)eE*Jn zPW9jcI}j8LED;mW_d+F{_eaNL)#+v1Ol)ELnOsEj=S*fO`|)CaO%w2T(;FkJat`U% z^XBn|S_}n{;4`hXfD!tmA!<`as&xaG+9#;$&^Uk{kaT`W%TSf85~?lEoXIXgH#1CzZv zrDA_amvr>mi2RfKuesf!1(sXzm0$|ai|n28`_1p>In)w!QC~JVqra}cN4Laqbr(=?R^uGVOGpp{v7^P5Zk*n`lmG+ny-ZZLShvw3-og2 zsn0<-TQEK#*4co}i4F8P%ORW}H%ic^{VHEk9`nfBJGQu06~?j5JfEOB)fC{M%ZHy9`e0UCrDV-w%S%7 zw{Oi?L**v)&LPTm)uiDSdMC`Ma zhB~K3rJh zaGJ#HHX+&DsL5VnzGqVK&@BMa{|B5<_|Y9O{3DYiC*n3b-us9N0a6k5T-jpXCEok9 z8Cxm*;iU8R@^ax7%xm@;wIB1fHo)bAo#;CbSe;PPbB;Eumacf+-p2wxEEoKiVPtFu zQ%%yw9&`Iam*7J%2njkO&AYLX|svy8DBZ$a`z0 zTry?XhhJRQxiFEa@(vWNBKhi~*e*E#3|AVW7we9mPr2I1S%Maq1ZVm@7I6kd?~{9D zdHY|1d6~R?g(*$Q@V4AL3Zw%yt}oYXyTwIMVn5C5tv;qPI&8xTY4w4LV?B8J#GJKY=WfI{y6CD z(sKiyg!5L*0;%Y?Vww@-U7I)GgCjP!;jI??(YAz=S9bCKEWH|6u*L+mwvY5nD)miR z0@F^^DdKLI2=+hjM*DpCg&V=`t#+HD4QqEy7$z*1e{)nbv0=JtO0sGd8z1 zHe=uEc4{tX3(=W%A$2t@>FhR>1^V##@;TyH1gTL`{fAnGSp)rDj;asMu{h|v79bB> zcoV7V3)_Xu6(6Gd!=)>%irPvllG$vjg-dHqv!usb@rjiZ5=PKKsE>qDXqeBuP7|yHEus2$x6L>PnsX#z602*jdsr$*^pd?TWdMNCRJ%= zV%D}c%%IM&mEvjJX3uRPvTwe$PV$6ricinwp=meI`tI=dR>H}%KF45pT0&aDOi{Ou?NGf#2YSoUW_uLsST;oz38{XK2 zqPKI+`b&VfsXd+Sg!75QU5gCjgvjASuh~BS+rTO}FkscW^;4fnO*TZl{2Mh_SWNFSgEGaEK?^Lg=D^wRkEq}7>EwVd3n z^Kn|ud2W}H)qYWSEIv@_@%*@QXhE$w9b@C9U_rrIA$P?;p+TEstJI&In5YXm?8v(> zF^?_)=5boL=@v?>ex(T%uuqJ=u7AraligtNuk^4t1)FK@|G>A5|M0GWifi7X7Bzi0 zO;S?Q2aygjkVj&$SM+9C?CF17NuELhqHh{DeCFN`t=VydUXyP-EFW z?m(0p{=Lh56FlKmF^No!%1Sto*+Znf|I=+(RG0UX@^29Vpoj6w7pDNQw4r>vh@)hI z+63#%EAY>)|01|<4gC})AAtU_R8Y@JZFb@AGk{Cx@%-dk0L9~B=Y;K&`i>-{T|n@^ zg_Q%W8jTD+$)%H3fb2Nht;%WLUYm86px`G&#QDhl$-m{A(sTeZwqc9G(u-f@CTu;d z|L4#E+S%W|ezZe=@aF3$l2i=I*T~O`=^Cw`# z?{{A~Z2xlMC{8e^k)%;(xS#%eDgfr&!Rz{!TvlL*MgQ#ZYzox?Uf+Me0^k9Yee&bn zKb;*fIRnj}uUaut6b792JUVkE{O@@O9!QOL{|l?bu(tXiuisC^{GWTS4N}DHdGkMM zc^ChE<%{GABQsmS|I4A%vb6&Gs5&u5ZD&*dSAkP~ZzSsPPFS-wRAI0C3+xRnO~!fHNV#zZqQsn2&u-kfR8+BmVPc03{^s zzX1QgSH=Io$3F<5~H7^I9JIQ&$QBT#mmk>$uU&>`G&4+ z7zylBwsVkUTz(@p6DTH%5HNj?8|y%+0GKUjBL7VA`s8L&l+Y`E@R;!3Cn*I#UvmU^1 ze4_?z*fcbflv>Zqj>huAU>l@FY0%bM7|_#=DhQ^HW{nY8V7HwFxId9J#m->FShZ#S z;ROZAXzKNZR`J~Et@BcVM9;nher1Z~u z-%YXPegx!eC^6P`hdfo5h`zkAy%)O+Q+;C(I_jM#)oS^Jx8VIEHhm`M)hEOo zQRu+~&ijGp1qXHC;{y6RSB(^Ro*-UD~G^o2LeArK7VjDOr zqpLlYgeM9+ax~1E040!HFjsESgF*Pszgw};e@%+G)=A&*XbkreSKR` zj{vlXZM(cgqf{~ea;R9P@Xae+M?l{5Ttm=1NefpkPdWDM?{y@={F8h{4#Ing@u;!U z?m`xz%29hJPH-z0i%#hwv@g!xD#T>CwzAhf-$Np?6AgUEe^yI4HO8B`9g{zWV34!6 z;qcvmE>Ft`Z(j}tdhuMeRXR>Ui8?mYvs@hx1)qtFOKU=Q@U<-IIdcHY#RdkN>#Z+t z8{Z{ycGLP=qtYUsnh}@TQi=Zht+Usyb>BSWT`SoYZ8p~*3DB?f-p!E9xM* zm%;2sESQ11ofajT3l~aXtajXI4!Dw$8@V=JlC{{#*3{e#9@dK>-Oz>5Q5=o9=>uv- zHm`dNfJF#gdEO6uVVOR^TJ#*6REKpNcMF*q-pUHsJ z&o=@L&;H}bOC9YLfTV3YTdCO4wCrH1LYx7w5|zjG{=Uij&ZP{lRA`!!7oyqXz7G`W zW|-290h1sh7ZUEu{kB4m5R*|8?EE3bO*8WgVj;vkZlFAr<2lfsjtLv;UcFeT*tB#J z1i$*cUAngS!QGYY^nx|mMyLip7s4gn(N53H$625ivOvjC=iXOj4M^(8nE?3JgMGWH z)e!?@vt5N}@k0XZ?r~6va+gNsZ`0>30M6wf=2m?TOYyoc4B*|(t7|Bp2`zQLLIRJY zoCHbuK@-Na>>+wo5yla0P6v~%0`pjVOO#Zc%e|vNy`PVpH%~wG!CTyBY$w8nkJ>3{ zOHn+=gS1tw8q^ss!RJmhzoH+@=_;4+@g7$DEE361z_VyD|G(gQXS*3`=N3j0cJN_1 zwrRN_+H<_1?`gF~-kc@%)!9hdPjb75;nV;=OBi#6V~GwEwi1TRFP9Fzz1$XxAHFLL z&@u)Mj8G51XLgAWaLyai5ET-WOPOo*Ku zhalnKbVR%oK#DnVic|0dk5SYBimMngGwb?adfqqYLQOBdppr6$MVIoSyqpM^>$b|X zCjMiKL;!rLY+R_?xHiTH(5(QL+H(4fhwoKq0EO$E7+_l(oU^!zHUH!~YE9xdy{swU z+$FvbAe{lwRT3X4i#cIlM0g6divB@*FO2zcuLy3Ijvtm#FAoPv5rF1!rkaUFEEk(b?7k5PZ-(ptb}T}8j^_?7R2qC!ELf&#Q<UU%ZY(Ar9WqGT`gjTOovwe3 zTxr=q?r3}4kAFT-GTF>FW9$yd^-P(Uf~CYu)(P zrXEZN<@Cx>(ZvH z&I1^0Q%|0AvAoRB%e9@ixBFNg4r!``&9`>>iOCtPt<6#79d;{%36!46~*JX0gkW-oeGzBksAJWfzzb56H+H0NzxJGqHe3 ze(wOAAtKnd%R^|NVV?`TVOk4^4_!Qv3NgBBIwCW(G!!WY>hQ0E!lVF!VX{>b zDG8vB?6^dd^VL-}ijlqA={s9_(1xuZa$1j@6&Vd`wH)>jfe+{uhn3T_&mL|kxB;ub z`J`?5>!2_Hg6d9r!uG%n8r7bc?HmGpwOQ%4mdd#l@+z^M;5$KIO;M{7#@#2tI*bSx zyZP%biYRh0tfgx|+i(rVYutRVbA;r;+6(T;arLsupAM9>xq)^)Vx?+gwe0-Eg40kC zCYF?*v(!pqS|}P-KC9aTGF?c^2I#K^K{?*#FXC+%m+G$G_)m=8UhRoj@}8_n=DJ7Z zDNi}k)Se$KiuR!DGM+0d>7;y_KSiD>ED|GdT&ocxCb2^3@P{Nl68BXM&l~z4tgi{E zgb7(IP-`*AbO9Zf#lRuON(51*!z$tfWt0k$i>1(5W~r3<%~HdwlGmeNVakRmh%)?B>C2`s9x2aNs4!sX_tGEV{p&8WwwQoyDil6CV*`p&}=j zds2b*h|OsnveSm)6lhgzKA%ADiU;d=P16U>%ETrAdG|CFWF@bhZT|D6I{=8PSY#0- zL>?<)I;6L&+Sq=zE+!wctw&!cpI8VVzorp5llGC664VU-;$GyP()fe4v2R@nHUU|R zjE)D?Z`rpE7FmySX<(<&6$C3gyL$b(ntO6IZ*cg~ye=^7gi&W-ko2p(i9_%#bH*W@I}L9S`0^b?*4Xu4%>GX9K=|%TYG<;hF?0fW0=@1wng8Qc{Aw9UA(;H_IO_Z6zMH=V+2WivQ>r{n&XOl z8fP81)xoI?U?YF(mH|HN;s*+EgI0r?WL4-?G91z^NRN6LMqLN8#l{H!<^dRwYin7LJsST}>M9&gNhsC9+>n#^P4# zd2|xY6h5gaUK)C?n~yR8h+9)*k% z-`K`NazF?%H(P2rfVuEOe&6{jytIKtqM!oy3lJVdU6%kEKAC3o(J_HTg51p(TV1Bp z>34;W9$7xm2VRbv=#ET)dUenRvX}_fEl}opdpDanFxdvEV0S^B4o96=>w<8r_RxJ7 z4=qmf40C)HGhB}JYECpxi#C(HBZUqg$TdQ}Ds2z-yj{1^o(tkdv$WGoqREw6|5hcZ z*Y;!UGkPhs5Bg`zk7M`-31O;=oa2HcB>FLr;dkb_|3@_nqzA1Yn&ok;EK1io#H8<8kh zPPE^WkhgR;qsB^JVNf5S41WKfG7>c+{n_L=|MoUow`f2~;ICrYAwZ=+fgYQfx6G z#l~^COB32f2zkTPE?B&QfG}1hP)_%}OiwJ{N*oKS*H#TEp1%%!PlqBLuGJ>2tVKTCL^vJ0$ed*hS61eK$OM`vxGw0uY;-lKDbww%`DH8gCyw1GGG> zkIK!Ab!lNeelzP_T5WM; z)f%WgRzNgnc^{_frq|$*jN3M2vqarkuo09+p%gjasuE5|HJ2CiD9_#E42{UDYO{h64;vScc%yc6uA?LjN^7Z*%}m5m8T4a5%(&D%>?Fu zcIyGip++qjZd#Bcdf>q54u@r5kZ0-}Ma!9Y-6FOaG$%?T)sV_HwOu&e4X5mijpB9G z@_En8|~^|j-cw6J&_V2tES)*;qS&#AI4hO&D; zIjI)~xEqH&FS?SKfdi0G-PToMnK$LY{d0Gw3n1gEFSej(cFTej7VZvlHt!vk6$G_{$$sItx#3BA#Aw24qSgh8)JK$-A<+&@j5ju6yoWZe zSevr8I#sI+E~mjHGkTFxk&@M1!EGhIXZ@5g9$$;Bb9_QPuk*=G>QBrrWc(s93ZYO$ z%wD7h7Bm=3+kW%ZU%bE)tGuG(85N%dfr#4KJjc>Xex=B`CdaEDL z{lQeW&wRQ>dn~bzIR)em zBuBQRrWSfhs;rik$H)EEeILs|di%|Xm@)dR0xV2Zx*WhfK1pDI&67Plt@PUG{PnGo zYgt6z?82NKr#A|elthb!&(ohcbW+vxtPC+3lunyU$)lpX%EC58aHOwq)4hSrVXf#< z;2iyMy*kEfU!ref(vBPzm7iyC5tO4UF^&Y&;!uFC$8U>Z!e*RL2Swgfz+4}QbFl#u z+Spw{B$VfM|EA4SPDrpy13t|Q0PNbAUt_k3ce|_6d>cyEqv+|c{aBe?{t#Mk?nApYwkPd|cQP#c5`PV2T#ln)A;~;6TuSYo0Tq?ecHI2t5QdWIu zAAK+H>?sy4l{1rT^?N>9yf9_&po*OTcc^^L>6ogd$@LRIi~BPg9GB3$qDNHvHBJYi z9@nK_PNq6K{f=1HR@zUNo;-|lhz!Th+&T9JoCF_?kfq7QinKo33J&3Sd>Rs>!~@!S zi<{}qpaBK#Kd8zO0V4f{C(D6i_DV+fEoz}gRE2FjC`9^f*j^{eE|%_Tg+sVsJOnF# zOuSZMJjpa^-8{>mh};dzau-^tca;CEWTY|j0_6*9UnuA=tvKLC<#6oUZdQn@A zmM7QqnaKp*g63PKWkR8Emg~X!swGOw6XJLeele8qs^JAfBXBYE_2UAwy0AhTT_Z_( zHp&G>H-!H0mM&#qSTdXEXY#nOk8mD6`}&j1I+-i!?rMIg;kvlqqp))ElfvO2A{_3` zA0nJq6_SAp?~(NJzqx=y#lj~X@HD7L2q+)YvJa-S{%T<*ZJj95$CLeKmd;Ci-q~1Nf08+(3O*bHQu1OPRz)=Is)O>9<&F-o&ZrCC zB40?%)aCf3w?513RO59`+t~LqUkg9Vc6YX@(oqRI?tN36ymSGUKDszb$21Y5zGmXr z9$@X0DI_#2wd16EUznGMo6Ytg+TGdg7qcCko=i%WGcb(~>2=gQMm}`<%s-c4$om_J ze38X=vHbY>o~gBQrW5+kv?E;hY%sv8G-<_CZ6dUJ-tj4JW0Z6dlANNVzw>YERBFy-Vyp?cdsbL>#p){kD;Yzk6g|_>mSXmA_2kk7q^$i zuk^x+?N)^Bwtb?Z4~^~v!7ICFH*~)oWc!I6KZ$(>TUkJB?z6z=g}LH6VhXz?Ip~Xw z!)mnssjRHD{$%Zt{@R>~JXZ_%K#M{aGl_Z+6*dR44=WLId!Hs-jcY!JO#;jf;`wqu zNM1xrON|G-%tA#+18Vu%>yY-YDV^J-z|k#m5kEG9nhk18COTFcQG|`7-^%dbQq z*&W^$ud7 zN7U4-tZXd-fd+s_BIN-_n~14JgUZs!I}s8gdPLeCfTh1A7KAu-cmpI*d&;|x9-fXY z8uv|H#(0%~2xpk%R?SxbA)E!z;g4uHDP&tv2BS2_`O!FNyL1W>T{-*~YGfI?IoYqT1Bg5d(K27&|6e{<*&b17gkj1X) z{;l8@*+ZS(P&(9W1oPGyrxc5|@}%T*UhgqhtNz{NAm#p}XQfpBXO7Ux&r|rV@420I zJ^9#G+IKQH)7T$OsGeUbIDj~4n8+iO^ZX-19C=>f18KO1fh(oK$YQY7?jB9!j>vH8 z&X$gMcFQeNvCPy+z$H^#=BdZ;5X}B|D`qUbez5?Qe%o~Z=zV9iH^@~tktAk4CYa&( zc#=sODFZYn6zi=QoA}3})=lG-L{)%aG$KKu`r68IJEkxmpp6efuFvA#UGITU zS(=+3{^By`gY)82cuLb3XHTwWt63n4!wtTf2J-CA2*vv7td{2NObx=#BUXM`vli+>q9oxCuLLk^ReJ*AncJm7 zhJjBi;kP87f?2DHmdr~j`Zv6Balkw(IS6E+9gZ?WW)4$Y?FeZ!ai_r2N zKsg@1x&akf-pBj(+Sq=7m+Zj00fvhrvzzD1%!u=QZ2W{VI|#6yKz%BBv{=T&S6VMN zWC00~%lKUG7JYkP|C;gwu?3%~tZng*%M(_3u0)Rlg)nmp`hX@qeK&m}y=&Of-7;yy zRf(zmzJAKAe3=*mHU27pRt2LSq`eX{GEl%UeK#U?Csv^$D#;BDcR6Y@q$naq)G)jn} zdt63ospLkX!!bNAeRV%mkLX-9lC_oI8n~uQ&3L>Z6_T^g0+KIY2rw)QSF6{#@Dhhf zb`$9Jsk1(+l(kMOTKYI3GDaUpoTC?hAXXlx4{uT;I!lrPH-JS^Qa89-#|IVJEfN9Gwb7$Je?Xgi(YC#6tLv7fdO+q7~BNPl2aE2zq}H=2db%R z#TJjg$k)2@Y?x$zAw1_u)BRjKtMo(lU*zJ z;t;q{&w(7g&B__D4jEsjFx5FNf^F`575cy1-Di%#=*tBBeku(F`9C*)YObhyouW(Q50?~bqW?lrt4Py-ZSc6YKKv)~+SV)Julf1sQ*}BJ7hLPr6i-+b}^?ExH z!>j=W^1RFWfujWmI(mA&YpEY33^0rCdu1pDlOvBdeQ=)Gew_Sx#%dXGdC+&rtf(C+ z7sKM@{BY~lt(WXV(&Tmbkh?DkBp6dp_g5wbIgX=;@2mOU??d(KCPYqV<`>jwiWH0& zme;qLR&t!QE{{N>fnc?Y$%nRg;bD6qrXowntRf&D=N{5HKRRJkqe)q&_y=D1)`i!t zW=C{HuPW^n`KIAPqd9spA6F-(M(>Gv6kz4_Q#;?+bA4DihjN}yFeGDh{Q5ZE4JMKv zo|_x@uF|_a{QN}{r)gg-k;^VxrkR#{0-FDmhxLB5)-Fv+1sV2>%XgJcU*|+6O%ek@q68X(P>8q(hn&<1@?^mVqUb8R3)(7Ra$_ zDk$HukYMy5U(`lak)dn|my;bX*qqOE1NpN)a#U8 zE%wys+zPeSq{y+#Sl2W5V}kj5EoG;JzO$JJKG)zPZs23JDj$SEDl4QU6z>d87}asp zf970sZ&07b+x+a`U}OEc;&78Lbj0I&8zND?vm}ifyb^(!Z2P$Gw^X8_W1(j?Q&gFU z$*wcmZcMbx(J`DY-h;3?INo)Pk1YGTVxbpCTyfP)a9Wp`oD4WqMB?6T^jy1~lmJE* z(n*5pgh9aNm&WSGuyDW&TNv{$Up!q%FD~S$&k8Zzt{a-&72Un4a~}&`LX{i&OBI8t zUeHzNdv?ek7ntM2fVl%=@XJZjo{#GOvr1r`%zgyva=ebQiGgCNWEbF-wPyt8wwx)D zWIk|D({ObCIiAd6%nv!(WYZ<(8wsxms_*0Xi7ToK;%2fc{K4CY ziBFIndjY4lcW#Nq2i9U32doWpYE(kfh{F&dIWL!Ri@GG~o>N#Pxg7h;Ft0@G)N)5cY)s<%Ozu2^--c`YGxgIiHDaRskz z6=Ahf#JY*^)f*F(&a43m!+Gll=B=}lME2LKbCe!{(0{b>c6}wL0N+L&q#~>1%Ha3l z)1rMsqy41t9=Tbovia}N!pz|zUUM^TE;7=~PkI6dQM1!%yjM`9v!0T^An9qlVEJ!Nf)qwvxgago z;YIIrz}`SiWlA}-z{PSVCVH>zG)esz!+e#!b)s>1)d$n@mjznuCS~6f^YpGbXL;U- z=sD$l6jY}-j#K(Y7>wz+L+Z1C6`2W;@R9({vjgRP+|eOW*HkmH*x!afItnB*|^Jl`2D(mydU zQSSw$-eHj{wOL9L;f#%g8DC8T2;ikDEA+m0(xDjIHUip>=6d1?(Y4=Aa zrgkXN%NgOMix7n+3*t}rk0mSZgNP#q#1W#oECE>6-#W$ct~0arlZ3Jl^N3#@WJ3Z+ zc9t5Ai>V0QF*jkTBY36DUS8uL43>V)rg&bdC5r5GCRW)ZQITyR} z>|J2wCP`ZFvt#D2?yk!CTpv>5e2w^u-f7jZ*i@jt_89{N=YBnj2kh2szdw=q)5|ZH z(Y0)|EAMGIb3YnjlvheU%~_{xKQ;Jq5WwH|rS6P!BRRevu`9*3DqxdxnH3I|R+bJe zZl3YWFNZ%73?mu$qxj)XxOa@uiz{6qczNyib>xyVSc_P|nP3^~I;r6xN3-jLXn?z& z@aktf5YN1Z6x71!?X!2LpV{7=#FHZ@^nw7xvYNZmxp#S@A*SJqBgf3XCX5e{(@mI` z)jw)EZhil>yUhIMWh2R-51|U(K_YQo4lX?~T-ds>RHf}PrlzComokZ1YB}rmRasDu ziM_JY{&^C=`10wed+$tw(CdLw#?iTFOHX8g|NQwyymvx(V)D0PdHc-wKfk9>a~@&; zvlaO3_C)a;+P|BA@IR()`|qYNY2R?Z{=4bfJGqa~S^mD~pC?38zeVQGr#Op`rjgcv zu9VP@lgHvu3p_-ubbKlE^Frk&iXRPKCX zPR{@N;Y!@50YTcRv~4^jZlc);+gYx+6%zTGWu&^#Mzku8Pg|yVs#6j%T@JYP5tV1p z(pz028u6=%L#FULKfmswf%emTz4q!jt1s(o<>uS^ODJ-`dZM?>Dc`?;(CcTj?V6Tw zR2z_HbGgC0R5^s%BI1vMPN^}4YC5^|pE`lE2sgn*%s|ACFNhZSZ;hs11r6n!tFp~~ z=A@nFCdf$C2SZi!Wx(MhqvvPg6)EIp4_3U}A;7Cnawf>*_J)3YtJ*6>t7X!WK=&ur z>ry7N8V>I^)bF3RtSoyNh6|gF2zXzBRwCK7Ktze2#^BR6My&|DPFMYtSCI`K@*dZ~P|MdK|8JsdQwp*37G z#AteH{qUn7#S?8CKgt2J5pD3KS%>cpX*^nKCU^F)27rwv`Frf#|l4T$VQv$DR3Z*z=jRiMUO|2x~Q_z*%UB7Is znEUfi(Ld-C8N2aRw@mX?+g7j7jItxEZAd5&FGy%wcRS}*y&6M}UHIZe?+Vt*ZlLAQU?&>rmG+aVlyhN>9 zQA4cxfIidav2}?U3;i+cua)-YMz9RwT%aEEx8UH@&HbzOb?nJWW#LwTc>UG;&>ZZ5 ztG;;VT3?w|OQ1)}4Sp#sn`4EXqvhth6ux zaVMn_5iy~OQkGdfNTy;EP+NjX*c%Ot19TQRj2kJbsa^JjDit6W@aB5Y(=}M+gjz-4 zD1CvU)_9e7MBQw@q_*cne<}C87QPVp1`l*V^C%^eG6cV?-r7CvQ!W5#?o}*XtU*=N zt9O0Q$F<~+7NIc4%EAM6-_{shtP#o9ytn#cYdnp9a2Pq}%iE zA^NdTdgY)R(-C)$oS3n(ai=%NZPndqV*Mf6OHmHK8mn)(noSs2q|gQ@SlS&}j{$M~ z`h0hKKBwaGnw(C9*Um;R!8&T`3TU*ib>pXC>e|{`<)x4}?2_U`k=d(geK_x&x`yOT z2(~(xMrc~u@Tee3K9jo3*d}N{?_zW6a8v7w_H25svz5X`l}^oKI44s)2=EeI7mOm< z!?&1OYz%V5OpNllKA%dX*p@d=eWF>=m9b3nd=KaAsj}+u)j{k&P(xZ;zEjssz=SPC z)~>hUYEfio#Satuv2f}G%N-*XVJ(c^iC@D_PX~D3?wl3L+>JsMzPWSIgDjS=Ym4*0 z@W6$<<{hsYm@S<6!O5@3H$9Her~Hdu_#yWS@5P#ut0TIM-Y;olZM^t>8eD^wy_(O$ICz4 zPI(MTtV-2i2ztFkbf-uN)5SXC!~u7NO(GELQ&0Pv>h^E_)H}JS8(W)1EC#1*h1qwh zEp|%_%<@`N*}7qp^2jR<5PVh8WheQwVj6m32K@3R%v)mZ)|#c`$2#a{=5%R}8(}Y$ z-9{VS(DTB$J@&>?(;tQ1?={#QF_oTf4g}iTE_pZIjcTyF=Q_MdooA2Z`ivVYi41>g zTDn|y6t;i2v4PXuVp~7G_@-)d0i(Lg6-V#R_9(~^ zb(-RyV`HHS@uJ1~iq61dGE1M)$&U|9&q_;xDERU7MyF{rG4MWHybWOWYTsYrmFz+W zKj)cksQ8r68MZfF@ICQq_2XpMI~QA|hExW!vr<`4!e0Iop&cu0yrp3m|V6hbtAQZ+;Ptr07ce&dCSn3{y%hA=`yez`W339+=+OLdN9vS6m3&$GZcZJSh^qvj zkoWj(hJ1Z1drXU~G>}~#6^xmzTQ4dSsv5_}{Pa9*IaRBuxVUnWRKUA>zsJnw&j?WBY&UTRgac#`pfr#gG>&iV<|vnqN7TSyQ^@n2D{;8-sVJQMd^Ht zoJrzltPsU%Px#!>gy~7Bf+H1{C;Sk;zHK|Fak}SUEqkQn_cR;TCGc_}$OGAHR`?^^ zT)o>^gT6qe*j&YW1x;XQ4qCMuT`>)F0`H#y2f2nLQdrx=_X|OVr*@N#TBa{=HmY;S zFyLQ%Olb+Ku+>NIxwN10QG#i4*PCghvZAZmc8v3R9(-FO+7gaWV|N+a{ymCu8C@j{ zl9xex0;MS+aY|^64t)13+}SY`^_?Bi?I{pA0=VS3BI3I241mTx9Nti;hgq~Cjk;V= z?Q_&RrZiTYjN<&OQ2+fK)o-9+PsP+dT$C#dERwIoRYUhh9b}m)$0~khAKaETtt4Jy zN%eo%pjS~*>Bih0YXTN-@wV9*uQ$IdvfB^SWfqt+&fze7ZE3jT8Z{WfWFeoMvQa?( z1;QPz%sS23C*!qvX_V!j`>N${h={K4W9idRm)GNC`{R5s_jfn>498GbX<4+6t=-2q znJ@_0da#PLm(il|!y}s`bTh)}V(eeWk(0B<(FMm>vu`c~*2?fAq>@C61a4gX}%G z>*?#s1SBoItAp9KYo7Q4u0tv1IGxQgwouu0ChKHrf+Z|n8L!KqF3K#tr?eq)?+=cX zxC&}r)<5H1?<5vur9-wl<(jgJg)h2tQ!UkgrD-ici{+xjoy1>Rqo>hK$oQ&{c7JZ% z-@=jdhzeVpHXRyJqW1yWJUqRb)8OrPUP>??};%r-h+wa+HE$!|U0m zW#Zd)K+>mYWaZbdA5_JO7W*6?SKm$7+0EfR0UANRNWoV9g}4>6MYRDogV*kCH&^*nZMok>Y3--)t9$i zgUXI^HlPYdRyQNP0y}gy>y9@u>g(_OD-1eFgN$F1QEH-|;U+h+eq?b*&!sE(jQyf{ zn|r2qbiO<9e$gJZ^Cp3f=Y+SnPb0**Zax5(HD@lq68>g)XH^~tw}xVnE3l4H#2w?F z?QZ7XCXnyWod5OSa|fFHvm?lHCSzg1iW#{&CF-*f5qdn0NoIL|^C8qvo>_k_M)y@l zNnBO+T4}-ktMHZAU4weiv)^am8BN4jWLc;`xd-3XwP+}u6vUg!;7B+4_>9>BsgtN| z^@l@|PxPinB>9FQ;vntkKy;TH13ks?%WNgRET2zGs#sHF(0aZghQ>!jy@{{#vLoDf zNl>|1IWHv|;-gFMnxHn6E?@Ao?2Ehf;#uB{bWYGCjBz_c48V|{D8|J=Ogs9P<2P2P z#V^HW@cDRAgMVWoYgLyGDFNXQZs!wz@c2tB7eyn1*vI~ElNpDi0k_9LI17}zdYE56 z&vE)QSLxhzumjUS`nAPx(QlaG&TnP*CnpCC$QMz)Ziq_sEfdlI!`oX1)zJoTpGgRA z!5xCTyF+jf?(Xgq%raK-QC^YdFQeJ?pAGWy;ZxlRry5b+;h)4Gt=F_ zzPcO2t2S7;rP^OEDsp6_yFF;vczo|Xq(9-ORbqKHm6aWjnE?7Y*9W)>&P)Kh|xBz`X zgB?c10Ta~TpI>(D9O)Fp>G&ZYs+8)sd~kM=+>Ve#^`5qnphrZ!7CPo_@fPf?>aK)) zB4l}3n)NCMI#%uG|8;9o7hHqX;K60V6JjgSkc~#rGXXE6xuL$d9_zb->_?-;Lgkjt^;H5o`eBdctA{QbzIp{pHq)PjJ7Jj2 z!f5T(!BHc4vy;=q$S>SmFWbL^_iZ_mIMnC_sHq#w^LNkniOq*C=NDJ&uQW6m(V=<+ z%T7`<#ln)X<#1L6xyT~W+VcaHf)AGx=#YeKEcJ-;s*zV;;XDh;tw>J8=%BpZXE9L9 zl(Mda$dwiQq<8R{y$#|59=;Eq4}W_-v~}S?uPFx+hm%kM1}(Vh3`n5d-`?;l(8^pr z*3e}CWD=xHWyL&-bg^@Yq)%qYl~?gzs?k**`eUY`*SrP(fCfcoru#?3+q*L>HW6p&favkW2D__i$;Ht!3Qzcahiw_X+y$!uw2 zPsbJl)~Z0@ODK2DL^v0mD^bGyV$eXq2STCQKY!I7f2jCgYpa(*q;vTwILk=JpuhND zUNEiFY1MInk(#6`skc#l4KS=WS_vRxJ%pL3L{6UZydenmaW^+<^2w1?S&U_43- z6)7kG9%?c^{|(?5!2~+@m{3#+K~CxU^fm>-)XeN-=!#^AkYj=g#MrV^Crd2mVm;Y< z^C>nE{yj*)5vRB!T%KP}bfDZA;k1$?-@v5NGFjT0&OE+-ex}-$*hE1)yqgkn(EQ$5ifKOuJ;$68t0c%0m3 zqwxv6R!c3Xa=G=glz^GCzeIo6Bd$^rll?h=mK6E4&pC0W9QYWhq4 z)n(^R>iADZ4MVzBjjCd89rgQMUB?zOr{3MxZ(S+Fv7|-1)Y>+I6aX093lBr>Y5xf>O_FfM?Q5(6!*uNxzJNvvm@`|~9d265O9_I<+W4S`$ zWp8T@h9EMmbxZ91j4&NP8-p6VK#(e;VF=cfOTszUl3B?4R9cLn9X>qIID4nG(TO|9}}CcX7dGebxxW7v`~ z;ITD0x?Ml8PIjd;vl|SKeu(PdcX^80d^M&lAic&x&{oX$MHEx+{2eo!Xk#*{(@~)E zb&b=GD4?>3&}Xv073NuzmN1-?mAWK-Hu0;n?hjvBQU)EJQNSb2XVeAYSLGp7d9qmp zF|Dl6@ceZZfnew%B!*wlwz|6i$bL4Lk`~e}hnnRiS`GW#aBZ{Rpu3oNKw-42Sa+A3 z!|vrsqCMaGoj9dvL|G&UfFsd9)G;Wk2#%au>de3MP1k#6FOCC$oqa#r`#@XwWsXLD zG1B+5GD+R|_}RIer}sHLtlZ2kadO5>H&0E=dPQ)MTDFtss}9FZ=J5VI)GZV-zl*pY zp$?(wUxLR-_b{dQ)6?YVk+qg;$hZ_TXn0uew}bSs#O2Ed)D|;2NEvV62~W7*vv>(4 z^Z@MB7xAGtLF}6CR2?)c|BN0aYbjI57zwy!og}^ag(_v!;hd+^aC1fn&%g0O0?_bi zlUrD4=yloWIxdRCCmId+`0IGV)Wl@RO`=}Z>3@YesHQ=d9sr*Z{PTxVzX`qyX4rS0 zUWhe-SzgLJ7?M&=9(_#AJAGw|v&r+SV-zBPJwCoQfvII!lX*pPtd3%-JtDP1#}lF} zx6VtrO?7>yZS<@~}M;jZ{bhG(xr#8a>B>Hc0bacJ($ z_}h03=jnDk)Ni2k+tem+YqY(?u1B}dUDSt~eGb1jOi(CLf0CMgiur-%UQB`s8Ly|Dv)4@ZZ`KUT!CYIUu??hZ6L8 zaO?f^vs0@*e=zr3uY=8kZO-`@C?n_ZF20{`-@o3obH%kpQTo^T#}oW0yqa@tyJWw{ z^OEK!KUt7D#;&emyQj4ZpL;r6^DV#Dc=eUmXwLXPOGcO9T$CH~V&)kLH&{ZdFRzLb zuL@70*X+4>-IFRi{nA(y4N`l!?m7B&6Y^enFwyaQ-}-~~+yOi%)hRvPBG%e$spdiZ zMfiMcJM#Ax?V7OM3e8}u?cbdrw6t)&U(eGGAwH@b?l?u(oeBo_L4iy|Sq#?8?Wp&2 z3%yt%onl)Pf`WLi?4*|3lDSFga}l^D@uyA%tt!PC$|5^P`>e6XW2l`Wvz3H>E-+#S z((oRN9X6>0(T4E~>Rkqb=gb_ev+)(9H`^Y5Xm}c=H(H_xkk&UF9|GH~4|Fyt06{vS zh3i6PFICPaY23V;vvXKq^SS;YPHTG6vTt1*LimKwTHjP!L+(=g8(KjhW$iqf#GGF8 z!Bre%ZEk%oXX4FL&3g-UzMZ=u z!+Ew)E+qHtW)%7$DK#ifi6ZW)R_JoXKww7eqasU3guI3o8@1_qVK`548LoGwT#@HN zJ8W!b6krd3fWALbAvWhWqQl=Zs?*$H*tZcw9@dGZ=j(8D{)qZqYTc9vb5 v<+y_U`%_0;SVu|3`E};@+g8j!@t;~ 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 Y?*(}nBERbX4yE9v#TCTL-x~z{ABSSYS^xk5 literal 157494 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%0Dutj9raD3%WEuLGGrn(c@Lb+y)0S3cOjP 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

9gSsbr(mw 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 false (opaque objects compare by identity) ``` -**Breaking comparison corrections:** previous versions could throw for object/null -pairs, consider Dates equal to unrelated objects, compare distinct opaque objects -by enumerable shape, and reject equivalent cycles or repeated references. Signed -zero, invalid Dates, symbol keys and sparse arrays now follow the rules above. -Audit consumers relying on those outcomes. To compare Maps/Sets/custom instances -by content, explicitly project their relevant state into plain data first. +To compare Maps/Sets/custom instances by content, explicitly project their +relevant state into plain data first. For upgrade considerations, see the +[v4.x-to-v5 migration guide](../../docs/cache-form-migration.md#shared-data-snapshots-and-equality-breaking). ### `deepExtend(...objects)` diff --git a/libs/env/CHANGELOG.md b/libs/env/CHANGELOG.md index 0fb62f33..2b34e186 100644 --- a/libs/env/CHANGELOG.md +++ b/libs/env/CHANGELOG.md @@ -24,7 +24,7 @@ ### Minor Changes -- c75bff4: Add framework affordances discovered while reviewing Xpenser: +- c75bff4: Add reusable environment, HTTP, cache, database and migration capabilities: - `@cleverbrush/env`: add `envBoolean()` for environment-style boolean values such as `1`, `0`, `yes`, `no`, `on`, and `off`. diff --git a/libs/knex-schema/CHANGELOG.md b/libs/knex-schema/CHANGELOG.md index c7f59edc..68cc4bf1 100644 --- a/libs/knex-schema/CHANGELOG.md +++ b/libs/knex-schema/CHANGELOG.md @@ -22,7 +22,7 @@ ### Minor Changes -- c75bff4: Add framework affordances discovered while reviewing Xpenser: +- c75bff4: Add reusable environment, HTTP, cache, database and migration capabilities: - `@cleverbrush/env`: add `envBoolean()` for environment-style boolean values such as `1`, `0`, `yes`, `no`, `on`, and `off`. diff --git a/libs/knex-schema/MIGRATION-v5.md b/libs/knex-schema/MIGRATION-v5.md index b5184eb9..1f188b49 100644 --- a/libs/knex-schema/MIGRATION-v5.md +++ b/libs/knex-schema/MIGRATION-v5.md @@ -1,4 +1,4 @@ -# Migrating to immutable queries (Framework v5) +# Migrating from Framework v4.x to v5: immutable queries This is a coordinated **major release of all 19 published Framework packages**. Upgrade them together. Prerelease snapshots still use beta versions; the stable diff --git a/libs/knex-schema/README.md b/libs/knex-schema/README.md index d820d92c..26fa1779 100644 --- a/libs/knex-schema/README.md +++ b/libs/knex-schema/README.md @@ -2,8 +2,8 @@ Type-safe, schema-driven query builder for [Knex](https://knexjs.org/). Use `@cleverbrush/schema` object builders to describe your PostgreSQL tables — column name mapping, eager loading, and full CRUD are handled automatically with complete TypeScript inference. -This major release makes every Framework query immutable and exposes `.rowSchema` automatically. -See the [migration guide](./MIGRATION-v5.md) before upgrading from v4 or an opt-in read beta. +Every Framework query is immutable and exposes `.rowSchema` automatically. +Upgrading? See [Migrating from v4.x to v5](./MIGRATION-v5.md). ## Installation @@ -538,7 +538,7 @@ nested related objects instead. For reusable connection/transaction handling, ordinary and aliased schemas retain the same inference through `createQuery(knex)`, `withTransaction(trx)`, and -`transaction(callback)`. Custom Knex base-query overloads are removed; use `rawQuery(knex, Output, sql)` +`transaction(callback)`. Use `rawQuery(knex, Output, sql)` or `.apply(configure, { output })` for an explicit raw output contract. These APIs and their JSDoc are also available through `@cleverbrush/orm`. ### Aggregates with optional output schemas @@ -665,7 +665,7 @@ URL is missing. CI runs PostgreSQL 16 integration tests alongside unit/type test ## Projection-aware reads Every Framework query is immutable and exposes its decoded `.rowSchema` -automatically. There is no `.withRowSchema()` call or mutable compatibility mode. +automatically. Capture returned queries when adding filters, projections or includes. Inspecting metadata never runs SQL. Ordinary table queries also support writes; projected results are detached, while full ORM entities can still use identity tracking. diff --git a/libs/knex-schema/src/QuerySource.ts b/libs/knex-schema/src/QuerySource.ts index 2d14ae23..ff5788aa 100644 --- a/libs/knex-schema/src/QuerySource.ts +++ b/libs/knex-schema/src/QuerySource.ts @@ -237,7 +237,7 @@ export class QuerySource< } /** - * Append a legacy SQL COUNT selection without executing the query. + * Append a internal SQL COUNT selection without executing the query. * The driver controls the result shape/value type. Prefer countValue() for a * checked scalar number, or aggregate.count() in a typed object projection. */ @@ -246,16 +246,16 @@ export class QuerySource< } /** - * Append a legacy COUNT(DISTINCT column) selection. + * Append a internal COUNT(DISTINCT column) selection. * Prefer countDistinctValue() for a checked scalar or aggregate.countDistinct() - * for an inferred grouped result; this legacy method retains the builder type. + * for an inferred grouped result; this planner method retains the builder type. */ countDistinct(column?: ColumnRef | Knex.Raw): this { return (countDistinctImpl as any)(this, column); } /** - * Append a legacy MIN selection without changing the result type. + * Append a internal MIN selection without changing the result type. * Use minValue() for a scalar with explicit decoding, or aggregate.min() in a * typed projection. SQL returns null for an empty/all-null input. */ @@ -264,7 +264,7 @@ export class QuerySource< } /** - * Append a legacy MAX selection without changing the result type. + * Append a internal MAX selection without changing the result type. * Use maxValue() for a scalar with explicit decoding, or aggregate.max() in a * typed projection. SQL returns null for an empty/all-null input. */ @@ -273,7 +273,7 @@ export class QuerySource< } /** - * Append a legacy SUM selection, leaving numeric conversion to the driver. + * Append a internal SUM selection, leaving numeric conversion to the driver. * Prefer sumValue() or aggregate.sum() to preserve exact numeric text by default. */ sum(column: ColumnRef | Knex.Raw): this { @@ -281,7 +281,7 @@ export class QuerySource< } /** - * Append a legacy AVG selection, leaving numeric conversion to the driver. + * Append a internal AVG selection, leaving numeric conversion to the driver. * Prefer avgValue() or aggregate.avg() for a typed, precision-preserving result. */ avg(column: ColumnRef | Knex.Raw): this { @@ -874,7 +874,7 @@ export class QuerySource< /** * Read a cursor page without running a total-count query. * The orderBy form clones the source and preserves exact composite sort values; - * its non-null sort must contain a declared unique key. The legacy column form + * its non-null sort must contain a declared unique key. The single-column form * mutates this builder and defaults to id descending. Reapply access filters on * every request: cursors are positions, not authorization or snapshots. * @returns Mapped data, hasMore, and a nextCursor that is null on the last page. @@ -886,7 +886,7 @@ export class QuerySource< /** * Read a cursor page without running a total-count query. * The orderBy form clones the source and preserves exact composite sort values; - * its non-null sort must contain a declared unique key. The legacy column form + * its non-null sort must contain a declared unique key. The single-column form * mutates this builder and defaults to id descending. Reapply access filters on * every request: cursors are positions, not authorization or snapshots. * @returns Mapped data, hasMore, and a nextCursor that is null on the last page. @@ -897,7 +897,7 @@ export class QuerySource< cursor?: any; /** Maximum parent rows to return; one extra row determines hasMore. */ limit: number; - /** Unique sort property; defaults to id in the legacy API. */ + /** Unique sort property; defaults to id for single-column paging. */ column?: ColumnRef; /** Sort/continuation direction; defaults to descending. */ direction?: 'asc' | 'desc'; @@ -905,7 +905,7 @@ export class QuerySource< /** * Read a cursor page without running a total-count query. * The orderBy form clones the source and preserves exact composite sort values; - * its non-null sort must contain a declared unique key. The legacy column form + * its non-null sort must contain a declared unique key. The single-column form * mutates this builder and defaults to id descending. Reapply access filters on * every request: cursors are positions, not authorization or snapshots. * @returns Mapped data, hasMore, and a nextCursor that is null on the last page. diff --git a/libs/knex-schema/src/expressions.ts b/libs/knex-schema/src/expressions.ts index 1b198372..7b19cf45 100644 --- a/libs/knex-schema/src/expressions.ts +++ b/libs/knex-schema/src/expressions.ts @@ -46,7 +46,7 @@ export interface AliasedColumn { * Type-only marker carrying column nullability and value type; not a runtime row value. */ readonly __value?: T; - /** Type-only original schema used by opt-in projection metadata. */ + /** Type-only source schema used by projection metadata. */ readonly __readSource?: S; /** Type-only join nullability, independent of the stored column schema. */ readonly __leftJoined?: Nullable; diff --git a/libs/knex-schema/src/extension.ts b/libs/knex-schema/src/extension.ts index f24b14d5..5f75d00d 100644 --- a/libs/knex-schema/src/extension.ts +++ b/libs/knex-schema/src/extension.ts @@ -943,72 +943,8 @@ export const ddlExtension = defineExtension({ return this.withExtension('beforeDelete', [...existing, fn]); } - /** - * Declare polymorphic variants for this schema. - * - * Turns a base schema into a **polymorphic schema** where a discriminator - * column determines which variant each row belongs to. Variants can store - * their extra fields either in a separate table (CTI — Class Table - * Inheritance) or as nullable columns on the base table (STI — Single - * Table Inheritance). - * - * The return type carries a phantom brand - * (`[POLYMORPHIC_TYPE_BRAND]`) so that `query(db, schema)` automatically - * infers the full discriminated-union result type. - * - * @param config.discriminator - Property key (or accessor) of the - * discriminator column on the base table (e.g. `'type'` or `t => t.type`). - * @param config.variants - Map from discriminator value to - * `{ schema, storage, foreignKey?, allowOrphan?, enforceCheck? }`. - * - `storage: 'cti'` — variant fields are in a separate table; - * `foreignKey` (the FK column on the variant table) is required. - * - `storage: 'sti'` — variant fields are nullable columns on the base table. - * - * @example - * ```ts - * const FileBase = object({ id: number().primaryKey(), name: string(), type: string() }) - * .hasTableName('files'); - * - * const ImageExtras = object({ width: number(), height: number(), format: string() }) - * .hasTableName('image_file'); - * - * const DocumentExtras = object({ size: number(), issueDate: date() }) - * .hasTableName('document_file'); - * - * const ImageExtras = object({ - * fileId: number().hasColumnName('file_id'), - * type: string('image'), - * width: number(), height: number(), format: string() - * }).hasTableName('image_file'); - * - * const DocumentExtras = object({ - * fileId: number().hasColumnName('file_id'), - * type: string('document'), - * size: number(), issueDate: date() - * }).hasTableName('document_file'); - * - * const FileSchema = FileBase.withVariants({ - * discriminator: t => t.type, - * variants: { - * image: { schema: ImageExtras, storage: 'cti', foreignKey: t => t.fileId }, - * document: { schema: DocumentExtras, storage: 'cti', foreignKey: t => t.fileId }, - * }, - * }); - * - * // query(db, FileSchema) returns: - * // Array< - * // | { id: number; name: string; type: 'image'; width: number; height: number; format: string } - * // | { id: number; name: string; type: 'document'; size: number; issueDate: Date } - * // > - * ``` - */ - // NOTE: the public `.withVariants()` schema-level method has been - // removed. Variants are now declared on the {@link Entity} chain via - // `defineEntity(...).discriminator(...).ctiVariant(...).stiVariant(...)`. - // The internal worker {@link applyVariantsToSchema} (below this - // `defineExtension` block) is invoked by the Entity layer and stores - // the same `'variants'` / `'polymorphicVariants'` extensions that - // `QuerySource` reads at runtime. + // Entity declarations use applyVariantsToSchema to store the variant + // metadata consumed by polymorphic queries. } }); diff --git a/libs/knex-schema/src/types.ts b/libs/knex-schema/src/types.ts index 2b74183d..8eef5663 100644 --- a/libs/knex-schema/src/types.ts +++ b/libs/knex-schema/src/types.ts @@ -542,7 +542,7 @@ export interface RelationSpec { name: string; schema: any; foreignKey?: any; - /** Explicit schema property names retained for opt-in read correlation. */ + /** Explicit schema property names used for read correlation. */ localKey?: string; remoteKey?: string; /** Nullable belongs-to relations do not filter out their parent rows. */ diff --git a/libs/orm-cli/CHANGELOG.md b/libs/orm-cli/CHANGELOG.md index 7a77319d..d39807ef 100644 --- a/libs/orm-cli/CHANGELOG.md +++ b/libs/orm-cli/CHANGELOG.md @@ -22,7 +22,7 @@ ### Minor Changes -- c75bff4: Add framework affordances discovered while reviewing Xpenser: +- c75bff4: Add reusable environment, HTTP, cache, database and migration capabilities: - `@cleverbrush/env`: add `envBoolean()` for environment-style boolean values such as `1`, `0`, `yes`, `no`, `on`, and `off`. diff --git a/libs/orm/CHANGELOG.md b/libs/orm/CHANGELOG.md index b5a7f006..a06ebe63 100644 --- a/libs/orm/CHANGELOG.md +++ b/libs/orm/CHANGELOG.md @@ -25,7 +25,7 @@ ### Minor Changes -- c75bff4: Add framework affordances discovered while reviewing Xpenser: +- c75bff4: Add reusable environment, HTTP, cache, database and migration capabilities: - `@cleverbrush/env`: add `envBoolean()` for environment-style boolean values such as `1`, `0`, `yes`, `no`, `on`, and `off`. diff --git a/libs/orm/README.md b/libs/orm/README.md index 3037edee..aebbc37c 100644 --- a/libs/orm/README.md +++ b/libs/orm/README.md @@ -13,7 +13,7 @@ EF-Core-like typed ORM layer on top of [`@cleverbrush/knex-schema`](../knex-sche --- -For the breaking immutable-query release, read the [v5 migration guide](../knex-schema/MIGRATION-v5.md). All published Framework packages advance together. +Upgrading? See [Migrating from v4.x to v5](../knex-schema/MIGRATION-v5.md). ## Installation @@ -395,7 +395,7 @@ const tasks = await db.tasks .orderBy(t => t.createdAt, 'desc') .orderBy(t => t.id, 'desc') .include(t => t.owner, owners => { - owners.where(t => t.name, 'Alice'); // foreign schema, not any + return owners.where(t => t.name, 'Alice'); // foreign schema, not any }) .limit(20); ``` @@ -405,9 +405,9 @@ does not necessarily filter parents. Callback types infer the declared foreign schema, including variant queries when the relation schema is known. `paginateAfter({ limit, cursor, orderBy: [...] })` supports non-null scalar sorts -with a declared unique tie-breaker; single-column cursor calls are unchanged. +with a declared unique tie-breaker. Use `column` for a single-column cursor. See the [complete query guide](../knex-schema/README.md#composable-read-queries) for defaults, -precision policy, grouped aggregates, cursor restrictions, and migration examples. +precision policy, grouped aggregates, cursor restrictions, and examples. ## Related packages diff --git a/libs/schema/README.md b/libs/schema/README.md index 36bf1af8..8ae25fa6 100644 --- a/libs/schema/README.md +++ b/libs/schema/README.md @@ -122,10 +122,6 @@ if (result.valid) { const nameErrors = result.getErrorsFor((p) => p.name); console.log(nameErrors.isValid); // false console.log(nameErrors.errors); // ['Name must be at least 2 characters'] - - // result.errors on object schemas is deprecated — use getErrorsFor() instead - console.log('Errors:', result.errors); - // Array of { message: string } } ``` @@ -865,8 +861,7 @@ const result = UserSchema.validate(someObject); if (result.valid) { console.log(result.object); // typed as InferType } else { - // For object schemas, prefer getErrorsFor() for per-property error inspection (see below) - console.log(result.errors); // deprecated for object schemas — Array of { message: string } + console.log(result.getErrorsFor(t => t.name).errors); // field error strings } // Async validation (use when validators/preprocessors are async) @@ -883,12 +878,12 @@ const result = UserSchema.validate( { doNotStopOnFirstError: true } ); -console.log(result.errors); -// [ -// { message: 'Name must be at least 2 characters' }, -// { message: 'Please enter a valid email' }, -// { message: 'Age cannot be negative' } -// ] +console.log(result.getErrorsFor(t => t.name).errors); +// ['Name must be at least 2 characters'] +console.log(result.getErrorsFor(t => t.email).errors); +// ['Please enter a valid email'] +console.log(result.getErrorsFor(t => t.age).errors); +// ['Age cannot be negative'] ``` ### Custom Error Messages @@ -979,11 +974,11 @@ result.getErrorsFor((t) => t.password).errors; // → [] ``` -You can target multiple properties from a single validator by returning multiple errors with different `property` selectors. Errors without a `property` selector are attached to the root object as before. +You can target multiple properties from a single validator by returning multiple errors with different `property` selectors. Errors without a `property` selector are attached to the root object. ### Per-Property Errors with `getErrorsFor()` (Recommended) -`ObjectSchemaBuilder.validate()` returns an extended result with a `getErrorsFor()` method for inspecting errors on individual properties — perfect for showing inline form errors. **This is the recommended way to inspect validation errors on object schemas** and replaces the deprecated `errors` array on `ObjectSchemaValidationResult`: +`ObjectSchemaBuilder.validate()` returns a result with a `getErrorsFor()` method for inspecting errors on individual properties — useful for showing inline form errors: ```typescript const PersonSchema = object({ @@ -1167,7 +1162,7 @@ array(optionalText).parse(['ok', 42]); // ['ok', undefined] — no entries dropp Fallbacks are opt-in: a fallback on a property does not make a malformed required root object valid. A fallback factory runs only when validation fails. -**Null compatibility:** legacy optional schemas accept `null` at runtime even +**Null handling:** optional schemas accept `null` at runtime even though their inferred type does not include it. `.optional().catch(undefined)` therefore leaves `null` unchanged. Normalize it explicitly when needed: diff --git a/libs/schema/src/builders/ObjectSchemaBuilder.ts b/libs/schema/src/builders/ObjectSchemaBuilder.ts index 3be56a3c..5473c8d2 100644 --- a/libs/schema/src/builders/ObjectSchemaBuilder.ts +++ b/libs/schema/src/builders/ObjectSchemaBuilder.ts @@ -224,7 +224,7 @@ export type ObjectSchemaValidationResult< * This is the **recommended** way to inspect validation errors — it provides type-safe, * per-property error details including `isValid`, `errors`, and `seenValue`. * - * Prefer this over the deprecated `errors` array. + * Inspect root or property-specific validation errors with a selector. * * @param selector a callback function to select property from the schema. */ @@ -324,7 +324,7 @@ export type ObjectSchemaValidationResult< * }); * * // result.valid === false - * // result.errors is deprecated — use result.getErrorsFor() instead + * // Inspect property errors using result.getErrorsFor(). * // result.getErrorsFor((p) => p.age).errors // ["is expected to have property 'age'"] * ``` * diff --git a/libs/server/CHANGELOG.md b/libs/server/CHANGELOG.md index 387aa733..347477f2 100644 --- a/libs/server/CHANGELOG.md +++ b/libs/server/CHANGELOG.md @@ -30,7 +30,7 @@ ### Minor Changes -- c75bff4: Add framework affordances discovered while reviewing Xpenser: +- c75bff4: Add reusable environment, HTTP, cache, database and migration capabilities: - `@cleverbrush/env`: add `envBoolean()` for environment-style boolean values such as `1`, `0`, `yes`, `no`, `on`, and `off`. diff --git a/websites/docs/app/client/sections/cacheTags.tsx b/websites/docs/app/client/sections/cacheTags.tsx index 73993976..3fdb1b1f 100644 --- a/websites/docs/app/client/sections/cacheTags.tsx +++ b/websites/docs/app/client/sections/cacheTags.tsx @@ -130,7 +130,7 @@ externalCacheTags({ invalidateTag: revalidateTag });

-

Versioned keys: breaking migration

+

Deterministic cache keys

Server and client helpers, response caches and external invalidation share the deterministic ct2:{' '} @@ -141,11 +141,10 @@ externalCacheTags({ invalidateTag: revalidateTag }); values throw TypeError.

- Upgrade external cache writers and invalidators together and - flush or expire old entries. There is no legacy fallback. - Base invalidation labels remain literal names; TTLs are - unchanged. External invalidators send both base labels and - computed keys by default, including property-free tags. + External cache writers and invalidators must use the same + key format. Base invalidation labels are literal names. + External invalidators send both base labels and computed + keys by default, including property-free tags.

Response shape and auth/tenant isolation remain diff --git a/websites/docs/app/knex-schema/page.tsx b/websites/docs/app/knex-schema/page.tsx index de0e6219..715456f0 100644 --- a/websites/docs/app/knex-schema/page.tsx +++ b/websites/docs/app/knex-schema/page.tsx @@ -374,7 +374,7 @@ const average = await query(knex, TaskSchema).avgValue(t => t.estimate, { }} />

- Queries are immutable in this major release. Read the{' '} + Queries are immutable. Read the{' '} complete query guide {' '} @@ -385,12 +385,11 @@ const average = await query(knex, TaskSchema).avgValue(t => t.estimate, {

Automatic projection-aware schemas

- Every query exposes rowSchema automatically; no extra - mode switch is needed. Immutable PostgreSQL queries - describe the actual decoded result schema: SQL null - stays null, dates are Date objects at every depth, and - decimal/bigint values are exact strings before JSON - parsing. + Every query exposes rowSchema automatically. Immutable + PostgreSQL queries describe the actual decoded result + schema: SQL null stays null, dates are Date objects at + every depth, and decimal/bigint values are exact strings + before JSON parsing.

                          t.id, taskId);`)
                         Retain every returned builder when configuring a query.
                     

- Read representation, pagination and migration details + Read representation and pagination details
diff --git a/websites/docs/app/react-form/page.tsx b/websites/docs/app/react-form/page.tsx index 00f57c52..469b7519 100644 --- a/websites/docs/app/react-form/page.tsx +++ b/websites/docs/app/react-form/page.tsx @@ -307,8 +307,8 @@ function App() { createFormSystem. Its Field{' '} checks the selected value, variant and custom props. Extend it by spreading system.renderers. - Its optional Provider also configures - legacy fields. + Its optional Provider supplies renderers to + descendant fields.

                         
                                     Result of .validate(). Contains{' '}
                                     valid, errors, and{' '}
-                                    object. For object schemas,
-                                    also includes getErrorsFor() (
-                                    errors is{' '}
-                                    deprecated on object schema
-                                    results).
+                                    object. For object schemas, use{' '}
+                                    getErrorsFor() for per-property
+                                    errors.
                                 
                             
                             
diff --git a/websites/schema/app/docs/sections/schema-modifiers.tsx b/websites/schema/app/docs/sections/schema-modifiers.tsx
index 71c123dd..511d1668 100644
--- a/websites/schema/app/docs/sections/schema-modifiers.tsx
+++ b/websites/schema/app/docs/sections/schema-modifiers.tsx
@@ -140,8 +140,8 @@ array(text).parse(['ok', 42]); // ['ok', undefined] — no entries dropped`}
                 

- Legacy optional schemas accept null at runtime - even when their inferred type omits it. A fallback does not + Optional schemas accept null at runtime even + when their inferred type omits it. A fallback does not replace a value that passed validation, so normalize null explicitly when your application requires undefined:

diff --git a/websites/schema/app/docs/sections/validation.tsx b/websites/schema/app/docs/sections/validation.tsx index 7be966a3..bdc98d3f 100644 --- a/websites/schema/app/docs/sections/validation.tsx +++ b/websites/schema/app/docs/sections/validation.tsx @@ -19,9 +19,7 @@ export default function ValidationSection() { only when your schema includes async validators or preprocessors. For object schemas, the result also includes a{' '} getErrorsFor() method for per-property error - inspection — the flat errors array is{' '} - deprecated on object schema results and will be - removed in a future major version. + inspection.

                 {' '}
-                and replaces the deprecated errors array on object
-                schema validation results. It returns an object with{' '}
+                using property selectors. It returns an object with{' '}
                 isValid (boolean), errors (array of
                 error strings), and seenValue (the value that was
                 validated).
diff --git a/websites/schema/app/playground/schemaDeclarations.ts b/websites/schema/app/playground/schemaDeclarations.ts
index 11108581..aaff6960 100644
--- a/websites/schema/app/playground/schemaDeclarations.ts
+++ b/websites/schema/app/playground/schemaDeclarations.ts
@@ -2495,7 +2495,7 @@ export type ObjectSchemaValidationResult p.age).errors // ["is expected to have property 'age'"]
  * \`\`\`
  *

From 30f83aaa387e438c0e52b3cecdad5f4806da40d9 Mon Sep 17 00:00:00 2001
From: Andrew Zolotukhin 
Date: Thu, 1 Oct 2026 14:34:56 +0000
Subject: [PATCH 18/41] feat(scheduler)!: add durable jobs, progress and
 PostgreSQL storage

---
 .changeset/config.json                        |   1 +
 .changeset/durable-job-execution.md           |  14 +
 .github/pr-evidence/durable-scheduler.png     | Bin 0 -> 650668 bytes
 .github/workflows/ci.yml                      |   3 +
 AGENTS.md                                     |   3 +-
 README.md                                     |   3 +-
 demos/durable-jobs/README.md                  |   9 +
 demos/durable-jobs/contracts.ts               |   9 +
 demos/durable-jobs/crash-worker.mjs           |  14 +
 demos/durable-jobs/demo.ts                    |  16 +
 demos/durable-jobs/handler.ts                 |   9 +
 demos/durable-jobs/thread-handler.mjs         |  12 +
 demos/todo-backend/Dockerfile                 |   1 +
 demos/todo-frontend/Dockerfile                |   1 +
 libs/scheduler-postgres/README.md             |  91 +++
 .../integration/repository.test.ts            | 142 +++++
 libs/scheduler-postgres/package.json          |  36 ++
 libs/scheduler-postgres/src/index.ts          |   3 +
 libs/scheduler-postgres/src/migrations.ts     |  74 +++
 libs/scheduler-postgres/src/schema.test.ts    |  19 +
 libs/scheduler-postgres/src/schema.ts         | 113 ++++
 libs/scheduler-postgres/src/storage.ts        | 328 ++++++++++
 libs/scheduler-postgres/tsconfig.build.json   |  16 +
 libs/scheduler-postgres/tsconfig.json         |   4 +
 libs/scheduler-postgres/tsup.config.ts        |   9 +
 libs/scheduler-postgres/typedoc.json          |   6 +
 libs/scheduler-postgres/vitest.config.mts     |   2 +
 libs/scheduler/MIGRATION-v5.md                |  50 ++
 libs/scheduler/README.md                      | 356 ++++++-----
 libs/scheduler/package.json                   |   3 +-
 libs/scheduler/src/ScheduleCalculator.test.ts | 579 -----------------
 libs/scheduler/src/ScheduleCalculator.ts      | 404 ------------
 libs/scheduler/src/contracts.test-d.ts        |  30 +
 libs/scheduler/src/contracts.ts               | 167 +++++
 libs/scheduler/src/definition.test.ts         |  60 ++
 libs/scheduler/src/definition.ts              | 260 ++++++++
 libs/scheduler/src/index.ts                   | 583 +-----------------
 libs/scheduler/src/jobRepository.test.ts      | 162 -----
 libs/scheduler/src/jobRepository.ts           | 147 -----
 libs/scheduler/src/memory.ts                  | 228 +++++++
 libs/scheduler/src/recurrence.test.ts         | 117 ++++
 libs/scheduler/src/recurrence.ts              | 256 ++++++++
 libs/scheduler/src/repository.test.ts         |  79 +++
 libs/scheduler/src/repository.ts              | 480 ++++++++++++++
 libs/scheduler/src/scheduler.ts               | 258 ++++++++
 libs/scheduler/src/storage.ts                 |  65 ++
 libs/scheduler/src/thread-entry.ts            |  77 +++
 libs/scheduler/src/thread.test.ts             |  69 +++
 libs/scheduler/src/types.ts                   | 268 --------
 libs/scheduler/src/wait.ts                    |  13 +
 libs/scheduler/src/worker.test.ts             | 212 +++++++
 libs/scheduler/src/worker.ts                  | 410 ++++++++++++
 libs/scheduler/testing/repository-contract.ts | 303 +++++++++
 libs/scheduler/tsconfig.build.json            |   2 +-
 libs/scheduler/tsconfig.typecheck.json        |   6 +
 libs/scheduler/tsup.config.ts                 |   2 +-
 libs/scheduler/vitest.config.mts              |  11 +
 libs/schema/README.md                         |   2 +-
 package-lock.json                             | 136 ++--
 package.json                                  |   3 +-
 typedoc.json                                  |   3 +-
 vitest.scheduler.config.mts                   |   5 +
 websites/docs/Dockerfile                      |   3 +
 websites/docs/app/scheduler/page.tsx          | 448 ++++++--------
 websites/docs/app/site.ts                     |   2 +-
 65 files changed, 4603 insertions(+), 2594 deletions(-)
 create mode 100644 .changeset/durable-job-execution.md
 create mode 100644 .github/pr-evidence/durable-scheduler.png
 create mode 100644 demos/durable-jobs/README.md
 create mode 100644 demos/durable-jobs/contracts.ts
 create mode 100644 demos/durable-jobs/crash-worker.mjs
 create mode 100644 demos/durable-jobs/demo.ts
 create mode 100644 demos/durable-jobs/handler.ts
 create mode 100644 demos/durable-jobs/thread-handler.mjs
 create mode 100644 libs/scheduler-postgres/README.md
 create mode 100644 libs/scheduler-postgres/integration/repository.test.ts
 create mode 100644 libs/scheduler-postgres/package.json
 create mode 100644 libs/scheduler-postgres/src/index.ts
 create mode 100644 libs/scheduler-postgres/src/migrations.ts
 create mode 100644 libs/scheduler-postgres/src/schema.test.ts
 create mode 100644 libs/scheduler-postgres/src/schema.ts
 create mode 100644 libs/scheduler-postgres/src/storage.ts
 create mode 100644 libs/scheduler-postgres/tsconfig.build.json
 create mode 100644 libs/scheduler-postgres/tsconfig.json
 create mode 100644 libs/scheduler-postgres/tsup.config.ts
 create mode 100644 libs/scheduler-postgres/typedoc.json
 create mode 100644 libs/scheduler-postgres/vitest.config.mts
 create mode 100644 libs/scheduler/MIGRATION-v5.md
 delete mode 100644 libs/scheduler/src/ScheduleCalculator.test.ts
 delete mode 100644 libs/scheduler/src/ScheduleCalculator.ts
 create mode 100644 libs/scheduler/src/contracts.test-d.ts
 create mode 100644 libs/scheduler/src/contracts.ts
 create mode 100644 libs/scheduler/src/definition.test.ts
 create mode 100644 libs/scheduler/src/definition.ts
 delete mode 100644 libs/scheduler/src/jobRepository.test.ts
 delete mode 100644 libs/scheduler/src/jobRepository.ts
 create mode 100644 libs/scheduler/src/memory.ts
 create mode 100644 libs/scheduler/src/recurrence.test.ts
 create mode 100644 libs/scheduler/src/recurrence.ts
 create mode 100644 libs/scheduler/src/repository.test.ts
 create mode 100644 libs/scheduler/src/repository.ts
 create mode 100644 libs/scheduler/src/scheduler.ts
 create mode 100644 libs/scheduler/src/storage.ts
 create mode 100644 libs/scheduler/src/thread-entry.ts
 create mode 100644 libs/scheduler/src/thread.test.ts
 delete mode 100644 libs/scheduler/src/types.ts
 create mode 100644 libs/scheduler/src/wait.ts
 create mode 100644 libs/scheduler/src/worker.test.ts
 create mode 100644 libs/scheduler/src/worker.ts
 create mode 100644 libs/scheduler/testing/repository-contract.ts
 create mode 100644 libs/scheduler/tsconfig.typecheck.json
 create mode 100644 libs/scheduler/vitest.config.mts
 create mode 100644 vitest.scheduler.config.mts

diff --git a/.changeset/config.json b/.changeset/config.json
index f6700320..4f96e85b 100644
--- a/.changeset/config.json
+++ b/.changeset/config.json
@@ -9,6 +9,7 @@
             "@cleverbrush/deep",
             "@cleverbrush/async",
             "@cleverbrush/scheduler",
+            "@cleverbrush/scheduler-postgres",
             "@cleverbrush/mapper",
             "@cleverbrush/knex-clickhouse",
             "@cleverbrush/react-form",
diff --git a/.changeset/durable-job-execution.md b/.changeset/durable-job-execution.md
new file mode 100644
index 00000000..36ad0208
--- /dev/null
+++ b/.changeset/durable-job-execution.md
@@ -0,0 +1,14 @@
+---
+"@cleverbrush/scheduler": major
+"@cleverbrush/scheduler-postgres": major
+---
+
+Redesign the scheduler for versioned immediate, delayed and recurring jobs,
+typed separate handlers, durable ordered progress and fenced worker leases.
+Add an independently installed PostgreSQL adapter using Framework ORM and
+knex-schema, explicit migrations, transactional enqueue and restart recovery.
+
+Retries are opt-in and rerun whole handlers. Calendar triggers use explicit UTC
+or IANA zones with persisted cursors and missed/overlap policies. See the
+scheduler v4.x-to-v5 migration guide for the breaking API and rollout steps.
+The adapter joins the fixed Framework release group.
diff --git a/.github/pr-evidence/durable-scheduler.png b/.github/pr-evidence/durable-scheduler.png
new file mode 100644
index 0000000000000000000000000000000000000000..9d7dc7ae8729d9a69fdcf1d016f65c34b8691574
GIT binary patch
literal 650668
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

ZK=@wn9m(T=?Z%O>c+BVVLtRV&Ro_-pE>qBY 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%0A~QZK14x_gS5@KK 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 -KC{xC8n7l*XC;EgjNLd1r{>;CT{%|8K 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

c@RsODnbNw6mp6qKCmz8X3X(K=dIHU=mG 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�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