{"version":3,"sources":["../../src/orm/errors/validation.ts","../../src/orm/fields.ts","../../src/orm/filter.ts","../../src/orm/orm-adapter.ts","../../src/orm/updates.ts"],"sourcesContent":["import { EquippedError } from '../../errors'\n\nexport type OrmValidationErrorKind = 'validation' | 'conflicting-ops' | 'empty-group' | 'undeclared-op' | 'upsert-filter-incompatible' | 'aggregate' | 'query-shape' | 'changes'\n\nexport type OrmValidationFailure = {\n\topIndex?: number\n\trowIndex?: number\n\tfield?: string\n\talias?: string\n\toption?: 'limit' | 'offset' | 'page' | 'batchSize'\n\tmigrationId?: string\n\tchangeIndex?: number\n\tcause: unknown\n}\n\nexport class OrmValidationError extends EquippedError {\n\tconstructor(\n\t\treadonly kind: OrmValidationErrorKind,\n\t\treadonly schema: string,\n\t\treadonly operation: string,\n\t\treadonly failures: OrmValidationFailure[],\n\t) {\n\t\tsuper(`ORM validation error (${kind}) on ${schema}.${operation}`, {\n\t\t\tkind,\n\t\t\tschema,\n\t\t\toperation,\n\t\t\tfailures,\n\t\t})\n\t}\n}\n\nif (import.meta.vitest) {\n\tconst { describe, test, expect } = import.meta.vitest\n\tconst { EquippedError } = await import('../../errors')\n\n\tdescribe('OrmValidationError', () => {\n\t\ttest('constructs with aggregate kind', () => {\n\t\t\tconst err = new OrmValidationError('aggregate', 'orders', 'aggregate', [])\n\t\t\texpect(err.kind).toBe('aggregate')\n\t\t\texpect(err.operation).toBe('aggregate')\n\t\t\texpect(err.message).toBe('ORM validation error (aggregate) on orders.aggregate')\n\t\t\texpect(err).toBeInstanceOf(OrmValidationError)\n\t\t\texpect(err).toBeInstanceOf(EquippedError)\n\t\t})\n\n\t\ttest('failure carries alias through to context', () => {\n\t\t\tconst failures: OrmValidationFailure[] = [\n\t\t\t\t{ alias: 'total_price', cause: 'alias collision' },\n\t\t\t]\n\t\t\tconst err = new OrmValidationError('aggregate', 'orders', 'aggregate', failures)\n\t\t\texpect(err.failures[0].alias).toBe('total_price')\n\t\t\texpect((err.context as any).failures[0].alias).toBe('total_price')\n\t\t})\n\n\t\ttest('failure without alias still works', () => {\n\t\t\tconst failures: OrmValidationFailure[] = [\n\t\t\t\t{ field: 'amount', cause: 'invalid field' },\n\t\t\t]\n\t\t\tconst err = new OrmValidationError('validation', 'orders', 'createOne', failures)\n\t\t\texpect(err.failures[0].alias).toBeUndefined()\n\t\t\texpect(err.failures[0].field).toBe('amount')\n\t\t})\n\n\t\ttest.each([\n\t\t\t'validation',\n\t\t\t'conflicting-ops',\n\t\t\t'empty-group',\n\t\t\t'undeclared-op',\n\t\t\t'upsert-filter-incompatible',\n\t\t\t'query-shape',\n\t\t\t'changes',\n\t\t] as const)('kind %s still works', (kind) => {\n\t\t\tconst err = new OrmValidationError(kind, 'users', 'createOne', [])\n\t\t\texpect(err.kind).toBe(kind)\n\t\t})\n\t})\n}\n","import { v, type Pipe, type PipeOutput } from 'valleyed'\n\nexport class Field<T = unknown, Name extends string = string, S = unknown> {\n\tdeclare readonly __valueType?: T\n\tdeclare readonly __schema?: S\n\treadonly name: Name\n\treadonly path: readonly string[]\n\n\tconstructor(name: Name, path?: readonly string[]) {\n\t\tthis.name = name\n\t\tthis.path = path ?? [name]\n\t}\n}\n\nexport type AnyField = Field<unknown, string, any>\n\nexport function toFieldName(field: string | AnyField): string {\n\tif (field instanceof Field) return field.path.join('.')\n\treturn field\n}\n\nexport class SchemaField<\n\tName extends string = string,\n\tP extends Pipe<any, any> = Pipe<any, any>,\n\tHasOnCreate extends boolean = false,\n> extends Field<PipeOutput<P>, Name> {\n\tdeclare readonly __hasOnCreate?: HasOnCreate\n\treadonly pipe: P\n\treadonly onCreate?: () => PipeOutput<P>\n\treadonly onUpdate?: () => PipeOutput<P>\n\n\tconstructor(name: Name, pipe: P, opts?: { onCreate?: () => PipeOutput<P>; onUpdate?: () => PipeOutput<P> }) {\n\t\tsuper(name)\n\t\tthis.pipe = pipe\n\t\tthis.onCreate = opts?.onCreate\n\t\tthis.onUpdate = opts?.onUpdate\n\t}\n}\n\nexport type AnySchemaField = SchemaField<string, Pipe<any, any>, boolean>\n\nexport class ComputedField<\n\tName extends string = string,\n\tP extends Pipe<any, any> = Pipe<any, any>,\n\tDeps extends readonly string[] = readonly string[],\n> {\n\tconstructor(\n\t\treadonly name: Name,\n\t\treadonly pipe: P,\n\t\treadonly deps: Deps,\n\t\treadonly compute: (data: Record<Deps[number], unknown>) => PipeOutput<P>,\n\t) {}\n}\n\nexport type AnyComputedField = ComputedField<string, Pipe<any, any>, readonly string[]>\n\nif (import.meta.vitest) {\n\tconst { describe, test, expect } = import.meta.vitest\n\n\tdescribe('Fields', () => {\n\t\tdescribe('Field', () => {\n\t\t\ttest('stores name and defaults path to [name]', () => {\n\t\t\t\tconst f = new Field('email')\n\t\t\t\texpect(f.name).toBe('email')\n\t\t\t\texpect(f.path).toEqual(['email'])\n\t\t\t})\n\n\t\t\ttest('stores provided custom path', () => {\n\t\t\t\tconst f = new Field('profile', ['profile', 'displayName'])\n\t\t\t\texpect(f.name).toBe('profile')\n\t\t\t\texpect(f.path).toEqual(['profile', 'displayName'])\n\t\t\t})\n\t\t})\n\n\t\tdescribe('toFieldName()', () => {\n\t\t\ttest('returns string input unchanged', () => {\n\t\t\t\texpect(toFieldName('createdAt')).toBe('createdAt')\n\t\t\t})\n\n\t\t\ttest('converts Field path into dot notation', () => {\n\t\t\t\tconst f = new Field('profile', ['profile', 'displayName'])\n\t\t\t\texpect(toFieldName(f)).toBe('profile.displayName')\n\t\t\t})\n\t\t})\n\n\t\tdescribe('SchemaField', () => {\n\t\t\ttest('extends Field and stores pipe', () => {\n\t\t\t\tconst mockPipe = v.string()\n\t\t\t\tconst f = new SchemaField('email', mockPipe)\n\t\t\t\texpect(f).toBeInstanceOf(Field)\n\t\t\t\texpect(f.name).toBe('email')\n\t\t\t\texpect(f.path).toEqual(['email'])\n\t\t\t\texpect(f.pipe).toBe(mockPipe)\n\t\t\t})\n\n\t\t\ttest('stores lifecycle hooks when provided', () => {\n\t\t\t\tconst mockPipe = v.number()\n\t\t\t\tconst f = new SchemaField('updatedAt', mockPipe, {\n\t\t\t\t\tonCreate: () => 1000,\n\t\t\t\t\tonUpdate: () => 2000,\n\t\t\t\t})\n\t\t\t\texpect(f.onCreate?.()).toBe(1000)\n\t\t\t\texpect(f.onUpdate?.()).toBe(2000)\n\t\t\t})\n\n\t\t\ttest('keeps lifecycle hooks undefined when omitted', () => {\n\t\t\t\tconst mockPipe = v.string()\n\t\t\t\tconst f = new SchemaField('name', mockPipe)\n\t\t\t\texpect(f.onCreate).toBeUndefined()\n\t\t\t\texpect(f.onUpdate).toBeUndefined()\n\t\t\t})\n\t\t})\n\t})\n}\n","import type { FilterOpName } from './adapter'\nimport { EquippedError } from '../errors'\nimport { OrmValidationError, type OrmValidationFailure } from './errors'\nimport { toFieldName, type AnyField, type Field } from './fields'\nimport type { AggregateSpec } from './orm-adapter'\nimport type { AnySchema } from './schema'\n\nexport class Filter {\n\treadonly field: string\n\tconstructor(\n\t\tfield: string | AnyField,\n\t\treadonly op: FilterOpName,\n\t\treadonly value: unknown,\n\t) {\n\t\tthis.field = toFieldName(field)\n\t}\n}\n\nexport type FilterChild = Filter | FilterGroup\n\nexport type FilterFactory = (q: FilterGroup) => FilterGroup\n\nexport type FilterGroupOp = 'and' | 'or'\n\nexport class FilterGroup {\n\treadonly children: readonly FilterChild[]\n\n\tprivate constructor(\n\t\treadonly op: FilterGroupOp = 'and',\n\t\tchildren?: readonly FilterChild[],\n\t) {\n\t\tthis.children = children ?? []\n\t}\n\n\t#withChild(child: FilterChild): FilterGroup {\n\t\treturn new FilterGroup(this.op, [...this.children, child])\n\t}\n\n\teq<T>(field: string | Field<T>, value: T): FilterGroup {\n\t\treturn this.#withChild(new Filter(field, 'eq', value))\n\t}\n\n\tne<T>(field: string | Field<T>, value: T): FilterGroup {\n\t\treturn this.#withChild(new Filter(field, 'ne', value))\n\t}\n\n\tgt<T>(field: string | Field<T>, value: T): FilterGroup {\n\t\treturn this.#withChild(new Filter(field, 'gt', value))\n\t}\n\n\tgte<T>(field: string | Field<T>, value: T): FilterGroup {\n\t\treturn this.#withChild(new Filter(field, 'gte', value))\n\t}\n\n\tlt<T>(field: string | Field<T>, value: T): FilterGroup {\n\t\treturn this.#withChild(new Filter(field, 'lt', value))\n\t}\n\n\tlte<T>(field: string | Field<T>, value: T): FilterGroup {\n\t\treturn this.#withChild(new Filter(field, 'lte', value))\n\t}\n\n\tin<T>(field: string | Field<T>, value: T[]): FilterGroup {\n\t\treturn this.#withChild(new Filter(field, 'in', value))\n\t}\n\n\tnotIn<T>(field: string | Field<T>, value: T[]): FilterGroup {\n\t\treturn this.#withChild(new Filter(field, 'notIn', value))\n\t}\n\n\tlike(field: string | Field<string>, value: string): FilterGroup {\n\t\treturn this.#withChild(new Filter(field, 'like', value))\n\t}\n\n\texists(field: string | Field<unknown>): FilterGroup {\n\t\treturn this.#withChild(new Filter(field, 'exists', true))\n\t}\n\n\tnotExists(field: string | Field<unknown>): FilterGroup {\n\t\treturn this.#withChild(new Filter(field, 'notExists', true))\n\t}\n\n\tcontains<T>(field: string | Field<T>, value: T[]): FilterGroup {\n\t\treturn this.#withChild(new Filter(field, 'contains', value))\n\t}\n\n\tnotContains<T>(field: string | Field<T>, value: T[]): FilterGroup {\n\t\treturn this.#withChild(new Filter(field, 'notContains', value))\n\t}\n\n\tand(facFns: FilterFactory[]): FilterGroup {\n\t\tif (facFns.length === 0) throw new EquippedError('and() requires at least one filter factory', { op: 'and' })\n\t\tconst group = new FilterGroup('and', facFns.map((fn) => fn(FilterGroup.create())))\n\t\treturn this.#withChild(group)\n\t}\n\n\tor(facFns: FilterFactory[]): FilterGroup {\n\t\tif (facFns.length === 0) throw new EquippedError('or() requires at least one filter factory', { op: 'or' })\n\t\tconst group = new FilterGroup('or', facFns.map((fn) => fn(FilterGroup.create())))\n\t\treturn this.#withChild(group)\n\t}\n\n\tclone(): FilterGroup {\n\t\treturn new FilterGroup(\n\t\t\tthis.op,\n\t\t\tthis.children.map((c) => {\n\t\t\t\tif (c instanceof Filter) return new Filter(c.field, c.op, structuredClone(c.value))\n\t\t\t\treturn c.clone()\n\t\t\t}),\n\t\t)\n\t}\n\n\tstatic create(): FilterGroup {\n\t\treturn new FilterGroup()\n\t}\n}\n\n\nexport type GatedFilterGroup<DeclaredOps extends readonly FilterOpName[]> = {\n\t[K in FilterOpName]: K extends DeclaredOps[number] ? FilterGroup[K] : never\n} & Pick<FilterGroup, 'and' | 'or' | 'clone' | 'children' | 'op'>\n\nexport type GatedFilterFactory<DeclaredOps extends readonly FilterOpName[]> = (\n\tq: GatedFilterGroup<DeclaredOps>,\n) => GatedFilterGroup<DeclaredOps>\n\nexport function assertNormalisedAggregate(schema: AnySchema, adapter: { aggregateOps: readonly string[] }, spec: AggregateSpec): void {\n\tconst failures: OrmValidationFailure[] = []\n\n\tif (spec.aggregates.length === 0) {\n\t\tfailures.push({ cause: 'At least one aggregator step is required' })\n\t}\n\n\tconst seenAliases = new Set<string>()\n\tfor (const agg of spec.aggregates) {\n\t\tif (seenAliases.has(agg.alias)) {\n\t\t\tfailures.push({ alias: agg.alias, cause: `Duplicate alias \"${agg.alias}\"` })\n\t\t}\n\t\tseenAliases.add(agg.alias)\n\n\t\tif (!adapter.aggregateOps.includes(agg.fn)) {\n\t\t\tfailures.push({ alias: agg.alias, cause: `Undeclared aggregate op \"${agg.fn}\"` })\n\t\t}\n\t}\n\n\tconst allFields = schema.fields as Record<string, unknown>\n\tconst fieldNames = new Set(Object.keys(allFields))\n\tfor (const field of spec.groupBy) {\n\t\tif (!fieldNames.has(field)) {\n\t\t\tfailures.push({ field, cause: `Unknown groupBy field \"${field}\" on schema \"${schema.name}\"` })\n\t\t}\n\t\tif (seenAliases.has(field)) {\n\t\t\tfailures.push({ alias: field, cause: `Alias \"${field}\" collides with groupBy field name` })\n\t\t}\n\t}\n\n\tif (failures.length > 0) {\n\t\tthrow new OrmValidationError('aggregate', schema.name, 'aggregate', failures)\n\t}\n\n\tif (spec.where) {\n\t\tassertNormalisedFilter(schema, spec.where)\n\t}\n\n\tif (spec.having) {\n\t\tconst validHavingFields = new Set([...seenAliases, ...spec.groupBy])\n\t\tconst havingErrors: OrmValidationFailure[] = []\n\n\t\tfunction walkHaving(node: FilterChild): void {\n\t\t\tif (node instanceof Filter) {\n\t\t\t\tif (!validHavingFields.has(node.field)) {\n\t\t\t\t\thavingErrors.push({ field: node.field, cause: `Unknown having field \"${node.field}\" — must be an aggregator alias or groupBy field` })\n\t\t\t\t}\n\t\t\t} else if (node instanceof FilterGroup) {\n\t\t\t\tfor (const child of node.children) walkHaving(child)\n\t\t\t}\n\t\t}\n\n\t\tfor (const child of spec.having.children) walkHaving(child)\n\n\t\tif (havingErrors.length > 0) {\n\t\t\tthrow new OrmValidationError('aggregate', schema.name, 'aggregate', havingErrors)\n\t\t}\n\t}\n}\n\nexport function assertNormalisedFilter(schema: AnySchema, group: FilterGroup): void {\n\tconst allFields = schema.fields as Record<string, unknown>\n\tconst fieldNames = new Set(Object.keys(allFields))\n\tconst errors: Array<{ field: string; cause: string }> = []\n\n\tfunction walk(node: FilterChild): void {\n\t\tif (node instanceof Filter) {\n\t\t\tif (!fieldNames.has(node.field)) {\n\t\t\t\terrors.push({ field: node.field, cause: `Unknown field \"${node.field}\" on schema \"${schema.name}\"` })\n\t\t\t}\n\t\t} else if (node instanceof FilterGroup) {\n\t\t\tfor (const child of node.children) walk(child)\n\t\t}\n\t}\n\n\tfor (const child of group.children) walk(child)\n\n\tif (errors.length > 0) {\n\t\tthrow new OrmValidationError(\n\t\t\t'validation',\n\t\t\tschema.name,\n\t\t\t'filter',\n\t\t\terrors.map((e) => ({ field: e.field, cause: e.cause })),\n\t\t)\n\t}\n}\n\nif (import.meta.vitest) {\n\tconst { describe, test, expect } = import.meta.vitest\n\tconst { v } = await import('valleyed')\n\tconst { Schema } = await import('./schema')\n\n\tconst UserSchema = Schema.from('users')\n\t\t.pk('id', v.string(), () => 'u1')\n\t\t.field('email', v.string())\n\t\t.field('age', v.number())\n\t\t.field('name', v.string())\n\t\t.field('tags', v.array(v.string()))\n\t\t.build()\n\n\tdescribe('FilterGroup', () => {\n\t\tdescribe('filter-op methods', () => {\n\t\t\ttest('eq adds a filter clause with op eq', () => {\n\t\t\t\tconst g = FilterGroup.create().eq(UserSchema.fields.age, 25)\n\t\t\t\texpect(g.children).toHaveLength(1)\n\t\t\t\tconst f = g.children[0] as Filter\n\t\t\t\texpect(f.field).toBe('age')\n\t\t\t\texpect(f.op).toBe('eq')\n\t\t\t\texpect(f.value).toBe(25)\n\t\t\t})\n\n\t\t\ttest('ne adds a filter clause with op ne', () => {\n\t\t\t\tconst g = FilterGroup.create().ne('name', 'Bob')\n\t\t\t\tconst f = g.children[0] as Filter\n\t\t\t\texpect(f.op).toBe('ne')\n\t\t\t\texpect(f.value).toBe('Bob')\n\t\t\t})\n\n\t\t\ttest('gt/gte/lt/lte produce correct ops', () => {\n\t\t\t\tconst g = FilterGroup.create()\n\t\t\t\t\t.gt(UserSchema.fields.age, 10)\n\t\t\t\t\t.gte(UserSchema.fields.age, 20)\n\t\t\t\t\t.lt(UserSchema.fields.age, 30)\n\t\t\t\t\t.lte(UserSchema.fields.age, 40)\n\t\t\t\texpect(g.children.map((c) => (c as Filter).op)).toEqual(['gt', 'gte', 'lt', 'lte'])\n\t\t\t})\n\n\t\t\ttest('in adds a filter clause with array value', () => {\n\t\t\t\tconst g = FilterGroup.create().in(UserSchema.fields.age, [1, 2, 3])\n\t\t\t\tconst f = g.children[0] as Filter\n\t\t\t\texpect(f.op).toBe('in')\n\t\t\t\texpect(f.value).toEqual([1, 2, 3])\n\t\t\t})\n\n\t\t\ttest('notIn adds a filter clause with op notIn', () => {\n\t\t\t\tconst g = FilterGroup.create().notIn(UserSchema.fields.age, [4, 5])\n\t\t\t\tconst f = g.children[0] as Filter\n\t\t\t\texpect(f.op).toBe('notIn')\n\t\t\t\texpect(f.value).toEqual([4, 5])\n\t\t\t})\n\n\t\t\ttest('like adds a filter clause with op like', () => {\n\t\t\t\tconst g = FilterGroup.create().like(UserSchema.fields.email, 'alice')\n\t\t\t\tconst f = g.children[0] as Filter\n\t\t\t\texpect(f.op).toBe('like')\n\t\t\t\texpect(f.value).toBe('alice')\n\t\t\t})\n\n\t\t\ttest('exists adds a filter clause with op exists', () => {\n\t\t\t\tconst g = FilterGroup.create().exists(UserSchema.fields.name)\n\t\t\t\tconst f = g.children[0] as Filter\n\t\t\t\texpect(f.op).toBe('exists')\n\t\t\t})\n\n\t\t\ttest('notExists is its own op, not a boolean form of exists', () => {\n\t\t\t\tconst g = FilterGroup.create().notExists(UserSchema.fields.name)\n\t\t\t\tconst f = g.children[0] as Filter\n\t\t\t\texpect(f.op).toBe('notExists')\n\t\t\t\texpect(f.op).not.toBe('exists')\n\t\t\t})\n\n\t\t\ttest('contains/notContains produce correct ops', () => {\n\t\t\t\tconst g = FilterGroup.create()\n\t\t\t\t\t.contains('tags', ['a'])\n\t\t\t\t\t.notContains('tags', ['b'])\n\t\t\t\texpect((g.children[0] as Filter).op).toBe('contains')\n\t\t\t\texpect((g.children[1] as Filter).op).toBe('notContains')\n\t\t\t})\n\n\t\t\ttest('all 13 filter ops produce matching Filter.op values (name-parity)', () => {\n\t\t\t\tconst g = FilterGroup.create()\n\t\t\t\t\t.eq('f', 1)\n\t\t\t\t\t.ne('f', 1)\n\t\t\t\t\t.gt('f', 1)\n\t\t\t\t\t.gte('f', 1)\n\t\t\t\t\t.lt('f', 1)\n\t\t\t\t\t.lte('f', 1)\n\t\t\t\t\t.in('f', [1])\n\t\t\t\t\t.notIn('f', [1])\n\t\t\t\t\t.like('f', 'x')\n\t\t\t\t\t.exists('f')\n\t\t\t\t\t.notExists('f')\n\t\t\t\t\t.contains('f', [1])\n\t\t\t\t\t.notContains('f', [1])\n\t\t\t\tconst ops = g.children.map((c) => (c as Filter).op)\n\t\t\t\texpect(ops).toEqual([\n\t\t\t\t\t'eq', 'ne', 'gt', 'gte', 'lt', 'lte',\n\t\t\t\t\t'in', 'notIn', 'like', 'exists', 'notExists',\n\t\t\t\t\t'contains', 'notContains',\n\t\t\t\t])\n\t\t\t})\n\t\t})\n\n\t\tdescribe('raw-string field overload', () => {\n\t\t\ttest('accepts raw string field name', () => {\n\t\t\t\tconst g = FilterGroup.create().eq('age', 18)\n\t\t\t\tconst f = g.children[0] as Filter\n\t\t\t\texpect(f.field).toBe('age')\n\t\t\t})\n\n\t\t\ttest('accepts typed Field ref and extracts field name', () => {\n\t\t\t\tconst g = FilterGroup.create().eq(UserSchema.fields.age, 18)\n\t\t\t\tconst f = g.children[0] as Filter\n\t\t\t\texpect(f.field).toBe('age')\n\t\t\t})\n\t\t})\n\n\t\tdescribe('structural combinators', () => {\n\t\t\ttest('and() creates a nested and-group', () => {\n\t\t\t\tconst g = FilterGroup.create().and([\n\t\t\t\t\t(q) => q.eq('age', 10),\n\t\t\t\t\t(q) => q.eq('name', 'Alice'),\n\t\t\t\t])\n\t\t\t\texpect(g.children).toHaveLength(1)\n\t\t\t\tconst nested = g.children[0] as FilterGroup\n\t\t\t\texpect(nested.op).toBe('and')\n\t\t\t\texpect(nested.children).toHaveLength(2)\n\t\t\t})\n\n\t\t\ttest('or() creates a nested or-group', () => {\n\t\t\t\tconst g = FilterGroup.create().or([\n\t\t\t\t\t(q) => q.eq('name', 'Alice'),\n\t\t\t\t\t(q) => q.eq('name', 'Bob'),\n\t\t\t\t])\n\t\t\t\tconst nested = g.children[0] as FilterGroup\n\t\t\t\texpect(nested.op).toBe('or')\n\t\t\t})\n\t\t})\n\n\t\tdescribe('empty-combinator rejection', () => {\n\t\t\ttest('and([]) throws at builder time', () => {\n\t\t\t\texpect(() => FilterGroup.create().and([])).toThrow()\n\t\t\t})\n\n\t\t\ttest('or([]) throws at builder time', () => {\n\t\t\t\texpect(() => FilterGroup.create().or([])).toThrow()\n\t\t\t})\n\n\t\t\ttest('thrown error has stack pointing at offending call', () => {\n\t\t\t\ttry {\n\t\t\t\t\tFilterGroup.create().and([])\n\t\t\t\t\texpect.unreachable()\n\t\t\t\t} catch (e) {\n\t\t\t\t\texpect((e as Error).stack).toContain('filter.ts')\n\t\t\t\t}\n\t\t\t})\n\t\t})\n\n\t\tdescribe('clone()', () => {\n\t\t\ttest('deep-clones the tree', () => {\n\t\t\t\tconst original = FilterGroup.create()\n\t\t\t\t\t.eq('name', 'Alice')\n\t\t\t\t\t.and([(q) => q.gt('age', 20)])\n\t\t\t\tconst cloned = original.clone()\n\n\t\t\t\texpect(cloned.children).toHaveLength(2)\n\t\t\t\texpect(cloned).not.toBe(original)\n\t\t\t\texpect(cloned.children[0]).not.toBe(original.children[0])\n\t\t\t})\n\n\t\t\ttest('structuredClone of values — mutations on clone do not leak', () => {\n\t\t\t\tconst arr = [1, 2, 3]\n\t\t\t\tconst original = FilterGroup.create().in('ids', arr)\n\t\t\t\tconst cloned = original.clone()\n\n\t\t\t\tconst clonedValue = (cloned.children[0] as Filter).value as number[]\n\t\t\t\tclonedValue.push(4)\n\n\t\t\t\texpect((original.children[0] as Filter).value).toEqual([1, 2, 3])\n\t\t\t\texpect(clonedValue).toEqual([1, 2, 3, 4])\n\t\t\t})\n\t\t})\n\t})\n\n\tdescribe('clone-on-step: fan-out independence', () => {\n\t\ttest('.eq() returns a new FilterGroup, not the same instance', () => {\n\t\t\tconst base = FilterGroup.create()\n\t\t\tconst a = base.eq('name', 'Alice')\n\t\t\texpect(a).not.toBe(base)\n\t\t})\n\n\t\ttest('fan-out from shared base does not pollute either branch', () => {\n\t\t\tconst base = FilterGroup.create().eq('name', 'Alice')\n\t\t\tconst branchA = base.gt('age', 20)\n\t\t\tconst branchB = base.lt('age', 40)\n\n\t\t\texpect(branchA.children).toHaveLength(2)\n\t\t\texpect(branchB.children).toHaveLength(2)\n\t\t\texpect(base.children).toHaveLength(1)\n\t\t\texpect((branchA.children[1] as Filter).op).toBe('gt')\n\t\t\texpect((branchB.children[1] as Filter).op).toBe('lt')\n\t\t})\n\n\t\ttest('.and() returns a new FilterGroup', () => {\n\t\t\tconst base = FilterGroup.create().eq('name', 'Alice')\n\t\t\tconst withAnd = base.and([(q) => q.gt('age', 20)])\n\t\t\texpect(withAnd).not.toBe(base)\n\t\t\texpect(base.children).toHaveLength(1)\n\t\t\texpect(withAnd.children).toHaveLength(2)\n\t\t})\n\n\t\ttest('.or() returns a new FilterGroup', () => {\n\t\t\tconst base = FilterGroup.create().eq('name', 'Alice')\n\t\t\tconst withOr = base.or([(q) => q.gt('age', 20)])\n\t\t\texpect(withOr).not.toBe(base)\n\t\t\texpect(base.children).toHaveLength(1)\n\t\t\texpect(withOr.children).toHaveLength(2)\n\t\t})\n\t})\n\n\tdescribe('assertNormalisedFilter', () => {\n\t\ttest('passes for valid filter referencing known fields', () => {\n\t\t\tconst g = FilterGroup.create().eq(UserSchema.fields.age, 25)\n\t\t\texpect(() => assertNormalisedFilter(UserSchema, g)).not.toThrow()\n\t\t})\n\n\t\ttest('passes for raw string field that exists on schema', () => {\n\t\t\tconst g = FilterGroup.create().eq('email', 'test@test.com')\n\t\t\texpect(() => assertNormalisedFilter(UserSchema, g)).not.toThrow()\n\t\t})\n\n\t\ttest('rejects unknown field name with OrmValidationError', () => {\n\t\t\tconst g = FilterGroup.create().eq('unknownField', 42)\n\t\t\texpect(() => assertNormalisedFilter(UserSchema, g)).toThrow(OrmValidationError)\n\t\t})\n\n\t\ttest('rejected error has kind validation', () => {\n\t\t\tconst g = FilterGroup.create().eq('badField', 42)\n\t\t\ttry {\n\t\t\t\tassertNormalisedFilter(UserSchema, g)\n\t\t\t\texpect.unreachable()\n\t\t\t} catch (e) {\n\t\t\t\texpect(e).toBeInstanceOf(OrmValidationError)\n\t\t\t\texpect((e as OrmValidationError).kind).toBe('validation')\n\t\t\t\texpect((e as OrmValidationError).failures).toHaveLength(1)\n\t\t\t\texpect((e as OrmValidationError).failures[0].field).toBe('badField')\n\t\t\t}\n\t\t})\n\n\t\ttest('preserves logical field names verbatim for Field refs', () => {\n\t\t\tconst g = FilterGroup.create().eq(UserSchema.fields.email, 'a@b.com')\n\t\t\tconst f = g.children[0] as Filter\n\t\t\texpect(f.field).toBe('email')\n\t\t\tassertNormalisedFilter(UserSchema, g)\n\t\t})\n\n\t\ttest('preserves logical field names verbatim for raw-string overloads', () => {\n\t\t\tconst g = FilterGroup.create().eq('age', 18)\n\t\t\tconst f = g.children[0] as Filter\n\t\t\texpect(f.field).toBe('age')\n\t\t\tassertNormalisedFilter(UserSchema, g)\n\t\t})\n\n\t\ttest('walks nested groups to detect unknown fields', () => {\n\t\t\tconst g = FilterGroup.create().and([\n\t\t\t\t(q) => q.eq('name', 'Alice'),\n\t\t\t\t(q) => q.or([(inner) => inner.eq('nonexistent', 'val')]),\n\t\t\t])\n\t\t\texpect(() => assertNormalisedFilter(UserSchema, g)).toThrow(OrmValidationError)\n\t\t})\n\t})\n\n\tdescribe('assertNormalisedAggregate', () => {\n\t\tconst adapter = { aggregateOps: ['count'] as readonly string[] }\n\n\t\ttest('passes for valid count aggregate', () => {\n\t\t\tconst spec = { aggregates: [{ fn: 'count' as const, alias: 'total' }], groupBy: [] }\n\t\t\texpect(() => assertNormalisedAggregate(UserSchema, adapter, spec)).not.toThrow()\n\t\t})\n\n\t\ttest('rejects empty aggregator list', () => {\n\t\t\tconst spec = { aggregates: [], groupBy: [] }\n\t\t\texpect(() => assertNormalisedAggregate(UserSchema, adapter, spec)).toThrow(OrmValidationError)\n\t\t\ttry {\n\t\t\t\tassertNormalisedAggregate(UserSchema, adapter, spec)\n\t\t\t\texpect.unreachable()\n\t\t\t} catch (e) {\n\t\t\t\texpect((e as OrmValidationError).kind).toBe('aggregate')\n\t\t\t}\n\t\t})\n\n\t\ttest('rejects undeclared aggregate op', () => {\n\t\t\tconst spec = { aggregates: [{ fn: 'sum' as const, alias: 'total', field: 'age' }], groupBy: [] }\n\t\t\texpect(() => assertNormalisedAggregate(UserSchema, adapter, spec)).toThrow(OrmValidationError)\n\t\t\ttry {\n\t\t\t\tassertNormalisedAggregate(UserSchema, adapter, spec)\n\t\t\t\texpect.unreachable()\n\t\t\t} catch (e) {\n\t\t\t\tconst err = e as OrmValidationError\n\t\t\t\texpect(err.kind).toBe('aggregate')\n\t\t\t\texpect(err.failures[0].alias).toBe('total')\n\t\t\t\texpect(err.failures[0].cause).toContain('Undeclared')\n\t\t\t}\n\t\t})\n\n\t\ttest('rejects duplicate aliases', () => {\n\t\t\tconst spec = {\n\t\t\t\taggregates: [\n\t\t\t\t\t{ fn: 'count' as const, alias: 'total' },\n\t\t\t\t\t{ fn: 'count' as const, alias: 'total' },\n\t\t\t\t],\n\t\t\t\tgroupBy: [],\n\t\t\t}\n\t\t\texpect(() => assertNormalisedAggregate(UserSchema, adapter, spec)).toThrow(OrmValidationError)\n\t\t\ttry {\n\t\t\t\tassertNormalisedAggregate(UserSchema, adapter, spec)\n\t\t\t\texpect.unreachable()\n\t\t\t} catch (e) {\n\t\t\t\tconst err = e as OrmValidationError\n\t\t\t\texpect(err.failures.some((f) => f.alias === 'total')).toBe(true)\n\t\t\t}\n\t\t})\n\n\t\ttest('validates where filter against schema', () => {\n\t\t\tconst spec = {\n\t\t\t\taggregates: [{ fn: 'count' as const, alias: 'total' }],\n\t\t\t\tgroupBy: [],\n\t\t\t\twhere: FilterGroup.create().eq('unknownField', 42),\n\t\t\t}\n\t\t\texpect(() => assertNormalisedAggregate(UserSchema, adapter, spec)).toThrow(OrmValidationError)\n\t\t})\n\n\t\ttest('collects multiple failures', () => {\n\t\t\tconst spec = {\n\t\t\t\taggregates: [\n\t\t\t\t\t{ fn: 'sum' as const, alias: 'x', field: 'age' },\n\t\t\t\t\t{ fn: 'avg' as const, alias: 'x', field: 'age' },\n\t\t\t\t],\n\t\t\t\tgroupBy: [],\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tassertNormalisedAggregate(UserSchema, adapter, spec)\n\t\t\t\texpect.unreachable()\n\t\t\t} catch (e) {\n\t\t\t\tconst err = e as OrmValidationError\n\t\t\t\texpect(err.failures.length).toBeGreaterThanOrEqual(2)\n\t\t\t}\n\t\t})\n\n\t\ttest('rejects unknown groupBy field', () => {\n\t\t\tconst allOps = { aggregateOps: ['count', 'sum'] as readonly string[] }\n\t\t\tconst spec = {\n\t\t\t\taggregates: [{ fn: 'count' as const, alias: 'total' }],\n\t\t\t\tgroupBy: ['nonexistent'],\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tassertNormalisedAggregate(UserSchema, allOps, spec)\n\t\t\t\texpect.unreachable()\n\t\t\t} catch (e) {\n\t\t\t\tconst err = e as OrmValidationError\n\t\t\t\texpect(err.kind).toBe('aggregate')\n\t\t\t\texpect(err.failures[0].cause).toContain('groupBy')\n\t\t\t\texpect(err.failures[0].field).toBe('nonexistent')\n\t\t\t}\n\t\t})\n\n\t\ttest('rejects alias colliding with groupBy field name', () => {\n\t\t\tconst allOps = { aggregateOps: ['count'] as readonly string[] }\n\t\t\tconst spec = {\n\t\t\t\taggregates: [{ fn: 'count' as const, alias: 'name' }],\n\t\t\t\tgroupBy: ['name'],\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tassertNormalisedAggregate(UserSchema, allOps, spec)\n\t\t\t\texpect.unreachable()\n\t\t\t} catch (e) {\n\t\t\t\tconst err = e as OrmValidationError\n\t\t\t\texpect(err.kind).toBe('aggregate')\n\t\t\t\texpect(err.failures.some((f) => String(f.cause).includes('collides'))).toBe(true)\n\t\t\t}\n\t\t})\n\n\t\ttest('rejects unknown having field', () => {\n\t\t\tconst allOps = { aggregateOps: ['count'] as readonly string[] }\n\t\t\tconst spec = {\n\t\t\t\taggregates: [{ fn: 'count' as const, alias: 'total' }],\n\t\t\t\tgroupBy: ['name'],\n\t\t\t\thaving: FilterGroup.create().gt('nonexistent', 0),\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tassertNormalisedAggregate(UserSchema, allOps, spec)\n\t\t\t\texpect.unreachable()\n\t\t\t} catch (e) {\n\t\t\t\tconst err = e as OrmValidationError\n\t\t\t\texpect(err.kind).toBe('aggregate')\n\t\t\t\texpect(err.failures[0].cause).toContain('having')\n\t\t\t}\n\t\t})\n\n\t\ttest('having accepts alias and groupBy field names', () => {\n\t\t\tconst allOps = { aggregateOps: ['count'] as readonly string[] }\n\t\t\tconst spec = {\n\t\t\t\taggregates: [{ fn: 'count' as const, alias: 'total' }],\n\t\t\t\tgroupBy: ['name'],\n\t\t\t\thaving: FilterGroup.create().gt('total', 0).eq('name', 'Alice'),\n\t\t\t}\n\t\t\texpect(() => assertNormalisedAggregate(UserSchema, allOps, spec)).not.toThrow()\n\t\t})\n\n\t\ttest('passes valid groupBy with known schema fields', () => {\n\t\t\tconst allOps = { aggregateOps: ['count'] as readonly string[] }\n\t\t\tconst spec = {\n\t\t\t\taggregates: [{ fn: 'count' as const, alias: 'total' }],\n\t\t\t\tgroupBy: ['name', 'age'],\n\t\t\t}\n\t\t\texpect(() => assertNormalisedAggregate(UserSchema, allOps, spec)).not.toThrow()\n\t\t})\n\t})\n}\n","import type { Pipe } from 'valleyed'\n\nimport { EquippedError } from '../errors'\nimport { Instance, type ClassRef } from '../instance'\nimport type { AggregateOpName, FieldTypeName, FilterOpName, UpdateOpName } from './adapter'\nimport type { OrmUse } from './adapters/base'\nimport { FilterGroup } from './filter'\nimport type { DiscoveredSchema } from './migrations/introspection-types'\nimport type { AddFieldChange, AddForeignKeyChange, AddIndexChange, CreateTableChange, DropFieldChange, DropForeignKeyChange, DropIndexChange, DropTableChange, ModifyFieldChange, RenameFieldChange, RenameTableChange } from './migrations/types'\nimport type { IterationQueryOptions, QueryOptions } from './query-options'\nimport type { AnySchema } from './schema'\nimport type { AnyUpdateOp } from './updates'\n\nexport type AggregateSpec = {\n\twhere?: FilterGroup\n\taggregates: ReadonlyArray<{\n\t\tfn: AggregateOpName\n\t\tfield?: string\n\t\talias: string\n\t}>\n\tgroupBy: readonly string[]\n\thaving?: FilterGroup\n}\n\nexport abstract class OrmAdapter {\n\treadonly queryableOps: readonly FilterOpName[] = []\n\treadonly updateOps: readonly UpdateOpName[] = []\n\treadonly aggregateOps: readonly AggregateOpName[] = []\n\treadonly supportedFieldTypes: readonly FieldTypeName[] = []\n\n\tabstract readonly schemaConfigPipe: Pipe<any, any>\n\n\tconnect?(): Promise<void>\n\tdisconnect?(): Promise<void>\n\tfindByPk?(schema: AnySchema, config: unknown, pk: unknown): Promise<Record<string, unknown> | null>\n\tcreateMany?(schema: AnySchema, config: unknown, data: Record<string, unknown>[]): Promise<Record<string, unknown>[]>\n\tupdateByPk?(schema: AnySchema, config: unknown, pk: unknown, ops: AnyUpdateOp[]): Promise<Record<string, unknown> | null>\n\tdeleteByPk?(schema: AnySchema, config: unknown, pk: unknown): Promise<Record<string, unknown> | null>\n\traw?(schema: AnySchema, config: unknown, ...args: any[]): Promise<any>\n\tfindMany?(schema: AnySchema, config: unknown, filter: FilterGroup, options?: QueryOptions): Promise<Record<string, unknown>[]>\n\tcount?(schema: AnySchema, config: unknown, filter: FilterGroup): Promise<number>\n\titerateMany?(schema: AnySchema, config: unknown, filter: FilterGroup, options?: IterationQueryOptions): AsyncGenerator<Record<string, unknown>, void, void>\n\tupdateMany?(schema: AnySchema, config: unknown, filter: FilterGroup, data: Record<string, unknown>): Promise<Record<string, unknown>[]>\n\tdeleteMany?(schema: AnySchema, config: unknown, filter: FilterGroup): Promise<Record<string, unknown>[]>\n\tupsertOne?(\n\t\tschema: AnySchema,\n\t\tconfig: unknown,\n\t\tfilter: FilterGroup,\n\t\tcreate: Record<string, unknown>,\n\t\tops: AnyUpdateOp[],\n\t): Promise<Record<string, unknown>>\n\taggregate?(schema: AnySchema, config: unknown, spec: AggregateSpec): Promise<Array<Record<string, unknown>>>\n\tsession?<T>(fn: () => Promise<T>): Promise<T>\n\n\tloadMigrations?(): Promise<{ id: string; appliedAt: number }[]>\n\trecordMigration?(id: string, appliedAt: number): Promise<void>\n\tacquireMigrationLock?<T>(fn: () => Promise<T>): Promise<T>\n\tapplyCreateTable?(change: CreateTableChange<any>): Promise<void>\n\tapplyDropTable?(change: DropTableChange): Promise<void>\n\tapplyAddField?(change: AddFieldChange<any>): Promise<void>\n\tapplyDropField?(change: DropFieldChange): Promise<void>\n\tapplyModifyField?(change: ModifyFieldChange<any>): Promise<void>\n\tapplyRenameTable?(change: RenameTableChange): Promise<void>\n\tapplyRenameField?(change: RenameFieldChange): Promise<void>\n\tapplyAddIndex?(change: AddIndexChange): Promise<void>\n\tapplyDropIndex?(change: DropIndexChange): Promise<void>\n\tapplyAddForeignKey?(change: AddForeignKeyChange): Promise<void>\n\tapplyDropForeignKey?(change: DropForeignKeyChange): Promise<void>\n\tintrospect?(): Promise<DiscoveredSchema[]>\n\n\tprotected onFatalError(err: unknown): never {\n\t\tconst wrapped = err instanceof EquippedError ? err : new EquippedError('OrmAdapter fatal error', {}, err)\n\t\tInstance.crash(wrapped)\n\t}\n\n\tconstructor() {\n\t\tconst self = this as any\n\t\tif (typeof self.connect === 'function') {\n\t\t\tInstance.on('start', () => self.connect(), { class: this.constructor as ClassRef })\n\t\t}\n\t\tif (typeof self.disconnect === 'function') {\n\t\t\tInstance.on('close', () => self.disconnect(), { class: this.constructor as ClassRef })\n\t\t}\n\t}\n\n\tuse(schema: AnySchema, config: unknown): OrmUse {\n\t\tconst self = this as any\n\t\tconst emptyIterator = async function* (): AsyncGenerator<Record<string, unknown>, void, void> {}\n\t\tconst use: OrmUse = {\n\t\t\tfindMany: (filter, opts) => self.findMany?.(schema, config, filter, opts) ?? Promise.resolve([]),\n\t\t\titerateMany: (filter, opts) => self.iterateMany?.(schema, config, filter, opts) ?? emptyIterator(),\n\t\t\tfindOne: async (filter) => {\n\t\t\t\tconst rows = await use.findMany(filter, { limit: 1 })\n\t\t\t\treturn rows[0] ?? null\n\t\t\t},\n\t\t\tcount: (filter) => self.count?.(schema, config, filter) ?? Promise.reject(new Error('count not implemented')),\n\t\t\tcreateOne: async (d) => {\n\t\t\t\tconst rows = await use.createMany([d])\n\t\t\t\treturn rows[0]\n\t\t\t},\n\t\t\tcreateMany: (d) => self.createMany?.(schema, config, d) ?? Promise.resolve([]),\n\t\t\tupdateMany: (filter, d) => self.updateMany?.(schema, config, filter, d) ?? Promise.resolve([]),\n\t\t\tupdateOne: async (filter, d) => {\n\t\t\t\tconst match = await use.findOne(filter)\n\t\t\t\tif (!match) return null\n\t\t\t\tconst pk = schema.pkField.name\n\t\t\t\tconst pkFilter = FilterGroup.create().eq(pk, match[pk])\n\t\t\t\tconst rows = await use.updateMany(pkFilter, d)\n\t\t\t\treturn rows[0] ?? null\n\t\t\t},\n\t\t\tupsertOne: (filter, create, ops) =>\n\t\t\t\tself.upsertOne?.(schema, config, filter, create, ops) ?? Promise.reject(new Error('upsertOne not implemented')),\n\t\t\tdeleteOne: async (filter) => {\n\t\t\t\tconst row = await use.findOne(filter)\n\t\t\t\tif (!row) return null\n\t\t\t\tconst pk = schema.pkField.name\n\t\t\t\tif (self.deleteByPk) {\n\t\t\t\t\tawait self.deleteByPk(schema, config, row[pk])\n\t\t\t\t} else if (self.deleteMany) {\n\t\t\t\t\tconst pkFilter = FilterGroup.create().eq(pk, row[pk])\n\t\t\t\t\tawait self.deleteMany(schema, config, pkFilter)\n\t\t\t\t}\n\t\t\t\treturn row\n\t\t\t},\n\t\t\tdeleteMany: (filter) => self.deleteMany?.(schema, config, filter) ?? Promise.resolve([]),\n\t\t\traw: (...args: any[]) => self.raw?.(schema, config, ...args) ?? Promise.reject(new Error('raw not implemented')),\n\t\t\taggregate: (spec) => self.aggregate?.(schema, config, spec) ?? Promise.reject(new Error('aggregate not implemented')),\n\t\t\taggregateOps: self.aggregateOps ?? [],\n\t\t}\n\t\treturn use\n\t}\n}\n\nif (import.meta.vitest) {\n\tconst { describe, test, expect, vi } = import.meta.vitest\n\tconst { v } = await import('valleyed')\n\n\tdescribe('OrmAdapter', () => {\n\t\ttest('subclass with connect/disconnect auto-registers Instance hooks', async () => {\n\t\t\tconst { Instance: Inst } = await import('../instance')\n\t\t\tconst onSpy = vi.spyOn(Inst, 'on').mockImplementation(() => {})\n\n\t\t\tclass TestAdapter extends OrmAdapter {\n\t\t\t\treadonly schemaConfigPipe = v.object({ table: v.string() })\n\t\t\t\treadonly supportedFieldTypes = ['string'] as const\n\t\t\t\tasync connect() {}\n\t\t\t\tasync disconnect() {}\n\t\t\t}\n\n\t\t\tnew (TestAdapter as any)()\n\n\t\t\texpect(onSpy).toHaveBeenCalledWith('start', expect.any(Function), expect.objectContaining({ class: TestAdapter }))\n\t\t\texpect(onSpy).toHaveBeenCalledWith('close', expect.any(Function), expect.objectContaining({ class: TestAdapter }))\n\n\t\t\tonSpy.mockRestore()\n\t\t})\n\n\t\ttest('subclass without connect/disconnect does not register hooks', async () => {\n\t\t\tconst { Instance: Inst } = await import('../instance')\n\t\t\tconst onSpy = vi.spyOn(Inst, 'on').mockImplementation(() => {})\n\n\t\t\tclass MinimalAdapter extends OrmAdapter {\n\t\t\t\treadonly schemaConfigPipe = v.object({ table: v.string() })\n\t\t\t}\n\n\t\t\tnew (MinimalAdapter as any)()\n\t\t\texpect(onSpy).not.toHaveBeenCalled()\n\n\t\t\tonSpy.mockRestore()\n\t\t})\n\n\t\ttest('capability declarations default to empty arrays', async () => {\n\t\t\tconst { Instance: Inst } = await import('../instance')\n\t\t\tvi.spyOn(Inst, 'on').mockImplementation(() => {})\n\n\t\t\tclass DefaultAdapter extends OrmAdapter {\n\t\t\t\treadonly schemaConfigPipe = v.object({ table: v.string() })\n\t\t\t}\n\t\t\tconst adapter = new (DefaultAdapter as any)() as DefaultAdapter\n\t\t\texpect(adapter.queryableOps).toEqual([])\n\t\t\texpect(adapter.updateOps).toEqual([])\n\t\t\texpect(adapter.aggregateOps).toEqual([])\n\t\t\texpect(adapter.supportedFieldTypes).toEqual([])\n\n\t\t\tvi.restoreAllMocks()\n\t\t})\n\n\t\ttest('onFatalError wraps non-EquippedError and calls Instance.crash', async () => {\n\t\t\tconst { Instance: Inst } = await import('../instance')\n\t\t\tvi.spyOn(Inst, 'on').mockImplementation(() => {})\n\t\t\tconst crashSpy = vi.spyOn(Inst, 'crash').mockImplementation((() => {\n\t\t\t\tthrow new Error('crash')\n\t\t\t}) as any)\n\n\t\t\tclass FatalAdapter extends OrmAdapter {\n\t\t\t\treadonly schemaConfigPipe = v.object({ table: v.string() })\n\t\t\t\ttriggerFatal() {\n\t\t\t\t\tthis.onFatalError(new Error('something broke'))\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst adapter = new (FatalAdapter as any)() as FatalAdapter\n\t\t\texpect(() => adapter.triggerFatal()).toThrow('crash')\n\t\t\texpect(crashSpy).toHaveBeenCalled()\n\n\t\t\tvi.restoreAllMocks()\n\t\t})\n\n\t\ttest('onFatalError passes through EquippedError directly', async () => {\n\t\t\tconst { Instance: Inst } = await import('../instance')\n\t\t\tvi.spyOn(Inst, 'on').mockImplementation(() => {})\n\t\t\tlet crashedWith: unknown\n\t\t\tvi.spyOn(Inst, 'crash').mockImplementation(((err: any) => {\n\t\t\t\tcrashedWith = err\n\t\t\t\tthrow err\n\t\t\t}) as any)\n\n\t\t\tclass FatalAdapter extends OrmAdapter {\n\t\t\t\treadonly schemaConfigPipe = v.object({ table: v.string() })\n\t\t\t\ttriggerFatal() {\n\t\t\t\t\tthis.onFatalError(new EquippedError('equipped error', { detail: 'test' }))\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst adapter = new (FatalAdapter as any)() as FatalAdapter\n\t\t\texpect(() => adapter.triggerFatal()).toThrow()\n\t\t\texpect(crashedWith).toBeInstanceOf(EquippedError)\n\t\t\texpect((crashedWith as EquippedError).message).toBe('equipped error')\n\n\t\t\tvi.restoreAllMocks()\n\t\t})\n\n\t\ttest('use() creates OrmUse bridge that delegates to flat methods', async () => {\n\t\t\tconst { Instance: Inst } = await import('../instance')\n\t\t\tconst { Schema } = await import('./schema')\n\t\t\tvi.spyOn(Inst, 'on').mockImplementation(() => {})\n\n\t\t\tclass BridgeAdapter extends OrmAdapter {\n\t\t\t\treadonly schemaConfigPipe = v.object({ table: v.string() })\n\t\t\t\treadonly supportedFieldTypes = ['string'] as const\n\t\t\t\treadonly queryableOps = ['eq'] as const\n\n\t\t\t\tasync findMany(_s: AnySchema, _c: unknown, _f: any, _o?: any) {\n\t\t\t\t\treturn [{ id: 'found' }]\n\t\t\t\t}\n\t\t\t\tasync count(_s: AnySchema, _c: unknown, _f: any) {\n\t\t\t\t\treturn 1\n\t\t\t\t}\n\t\t\t\tasync *iterateMany(_s: AnySchema, _c: unknown, _f: any, _o?: any) {\n\t\t\t\t\tyield { id: 'iterated' }\n\t\t\t\t}\n\t\t\t\tasync createMany(_s: AnySchema, _c: unknown, data: Record<string, unknown>[]) {\n\t\t\t\t\treturn data\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst TestSchema = Schema.from('bridge_test')\n\t\t\t\t.pk('id', v.string(), () => 'x')\n\t\t\t\t.build()\n\t\t\tconst adapter = new (BridgeAdapter as any)() as BridgeAdapter\n\t\t\tconst ormUse = adapter.use(TestSchema, { table: 'bridge_test' })\n\n\t\t\tconst rows = await ormUse.findMany(FilterGroup.create())\n\t\t\texpect(rows).toEqual([{ id: 'found' }])\n\t\t\tawait expect(ormUse.count(FilterGroup.create())).resolves.toBe(1)\n\n\t\t\tconst iterated: Record<string, unknown>[] = []\n\t\t\tfor await (const row of ormUse.iterateMany(FilterGroup.create())) iterated.push(row)\n\t\t\texpect(iterated).toEqual([{ id: 'iterated' }])\n\n\t\t\tconst created = await ormUse.createOne({ id: 'new' })\n\t\t\texpect(created).toEqual({ id: 'new' })\n\n\t\t\tvi.restoreAllMocks()\n\t\t})\n\n\t\ttest('use() bridge delegates updateMany to flat method', async () => {\n\t\t\tconst { Instance: Inst } = await import('../instance')\n\t\t\tconst { Schema } = await import('./schema')\n\t\t\tvi.spyOn(Inst, 'on').mockImplementation(() => {})\n\n\t\t\tclass UpdateAdapter extends OrmAdapter {\n\t\t\t\treadonly schemaConfigPipe = v.object({ table: v.string() })\n\t\t\t\treadonly supportedFieldTypes = ['string', 'number'] as const\n\t\t\t\treadonly updateOps = ['set'] as const\n\n\t\t\t\tasync findMany(_s: AnySchema, _c: unknown, _f: any) {\n\t\t\t\t\treturn [{ id: 'u1', name: 'old' }]\n\t\t\t\t}\n\t\t\t\tasync updateMany(_s: AnySchema, _c: unknown, _f: any, data: Record<string, unknown>) {\n\t\t\t\t\treturn [{ id: 'u1', ...data }]\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst TestSchema = Schema.from('upd_test')\n\t\t\t\t.pk('id', v.string(), () => 'x')\n\t\t\t\t.field('name', v.string())\n\t\t\t\t.build()\n\t\t\tconst adapter = new (UpdateAdapter as any)() as UpdateAdapter\n\t\t\tconst ormUse = adapter.use(TestSchema, { table: 'upd_test' })\n\n\t\t\tconst updated = await ormUse.updateOne(FilterGroup.create().eq('id', 'u1'), { name: 'new' })\n\t\t\texpect(updated).not.toBeNull()\n\t\t\texpect(updated!.name).toBe('new')\n\n\t\t\tvi.restoreAllMocks()\n\t\t})\n\n\t\ttest('use().iterateMany does not fall back to findMany when adapter omits iterateMany', async () => {\n\t\t\tconst { Instance: Inst } = await import('../instance')\n\t\t\tconst { Schema } = await import('./schema')\n\t\t\tvi.spyOn(Inst, 'on').mockImplementation(() => {})\n\n\t\t\tlet findManyCalls = 0\n\t\t\tclass FindOnlyAdapter extends OrmAdapter {\n\t\t\t\treadonly schemaConfigPipe = v.object({ table: v.string() })\n\t\t\t\treadonly supportedFieldTypes = ['string'] as const\n\t\t\t\tasync findMany() {\n\t\t\t\t\tfindManyCalls += 1\n\t\t\t\t\treturn [{ id: 'found' }]\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst TestSchema = Schema.from('iter_no_fallback')\n\t\t\t\t.pk('id', v.string(), () => 'x')\n\t\t\t\t.build()\n\t\t\tconst adapter = new (FindOnlyAdapter as any)() as FindOnlyAdapter\n\t\t\tconst rows: Record<string, unknown>[] = []\n\t\t\tfor await (const row of adapter.use(TestSchema, { table: 'iter_no_fallback' }).iterateMany(FilterGroup.create())) rows.push(row)\n\n\t\t\texpect(rows).toEqual([])\n\t\t\texpect(findManyCalls).toBe(0)\n\n\t\t\tvi.restoreAllMocks()\n\t\t})\n\n\t\ttest('use() bridge delegates deleteByPk via deleteOne', async () => {\n\t\t\tconst { Instance: Inst } = await import('../instance')\n\t\t\tconst { Schema } = await import('./schema')\n\t\t\tvi.spyOn(Inst, 'on').mockImplementation(() => {})\n\n\t\t\tlet deletedPk: unknown = null\n\t\t\tclass DeleteAdapter extends OrmAdapter {\n\t\t\t\treadonly schemaConfigPipe = v.object({ table: v.string() })\n\t\t\t\treadonly supportedFieldTypes = ['string'] as const\n\n\t\t\t\tasync findMany(_s: AnySchema, _c: unknown, _f: any) {\n\t\t\t\t\treturn [{ id: 'd1' }]\n\t\t\t\t}\n\t\t\t\tasync deleteByPk(_s: AnySchema, _c: unknown, pk: unknown) {\n\t\t\t\t\tdeletedPk = pk\n\t\t\t\t\treturn { id: String(pk) }\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst TestSchema = Schema.from('del_test')\n\t\t\t\t.pk('id', v.string(), () => 'x')\n\t\t\t\t.build()\n\t\t\tconst adapter = new (DeleteAdapter as any)() as DeleteAdapter\n\t\t\tconst ormUse = adapter.use(TestSchema, { table: 'del_test' })\n\n\t\t\tconst deleted = await ormUse.deleteOne(FilterGroup.create().eq('id', 'd1'))\n\t\t\texpect(deleted).toEqual({ id: 'd1' })\n\t\t\texpect(deletedPk).toBe('d1')\n\n\t\t\tvi.restoreAllMocks()\n\t\t})\n\n\t\ttest('use() bridge delegates session to flat method', async () => {\n\t\t\tconst { Instance: Inst } = await import('../instance')\n\t\t\tvi.spyOn(Inst, 'on').mockImplementation(() => {})\n\n\t\t\tlet sessionRan = false\n\t\t\tclass SessionAdapter extends OrmAdapter {\n\t\t\t\treadonly schemaConfigPipe = v.object({ table: v.string() })\n\t\t\t\tasync session<T>(fn: () => Promise<T>): Promise<T> {\n\t\t\t\t\tsessionRan = true\n\t\t\t\t\treturn fn()\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst adapter = new (SessionAdapter as any)() as SessionAdapter\n\t\t\tconst result = await adapter.session!(async () => 42)\n\t\t\texpect(result).toBe(42)\n\t\t\texpect(sessionRan).toBe(true)\n\n\t\t\tvi.restoreAllMocks()\n\t\t})\n\n\t\ttest('type-level: subclass method override enforces canonical signature', async () => {\n\t\t\tconst { Instance: Inst } = await import('../instance')\n\t\t\tvi.spyOn(Inst, 'on').mockImplementation(() => {})\n\n\t\t\tclass CorrectAdapter extends OrmAdapter {\n\t\t\t\treadonly schemaConfigPipe = v.object({ table: v.string() })\n\t\t\t\tasync findByPk(_s: AnySchema, _c: unknown, _pk: unknown) {\n\t\t\t\t\treturn null\n\t\t\t\t}\n\t\t\t\tasync createMany(_s: AnySchema, _c: unknown, _d: Record<string, unknown>[]) {\n\t\t\t\t\treturn []\n\t\t\t\t}\n\t\t\t\tasync raw(_s: AnySchema, _c: unknown, ..._args: any[]) {\n\t\t\t\t\treturn null\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst adapter = new (CorrectAdapter as any)() as CorrectAdapter\n\t\t\texpect(adapter.findByPk).toBeTypeOf('function')\n\t\t\texpect(adapter.createMany).toBeTypeOf('function')\n\t\t\texpect(adapter.raw).toBeTypeOf('function')\n\n\t\t\tvi.restoreAllMocks()\n\t\t})\n\t})\n}\n","import type { PipeInput, PipeOutput } from 'valleyed'\n\nimport type { AnyField, AnySchemaField, SchemaField } from './fields'\nimport { toFieldName } from './fields'\nimport type { AnySchema, SchemaFields } from './schema'\nimport type { Prettify } from './utils'\n\nexport type NumericFieldOf<S extends AnySchema> = {\n\t[K in keyof SchemaFields<S>]: SchemaFields<S>[K] extends SchemaField<any, infer P, any>\n\t\t? PipeOutput<P> extends number\n\t\t\t? SchemaFields<S>[K]\n\t\t\t: never\n\t\t: never\n}[keyof SchemaFields<S>]\n\nexport type ComparableFieldOf<S extends AnySchema> = {\n\t[K in keyof SchemaFields<S>]: SchemaFields<S>[K] extends SchemaField<any, infer P, any>\n\t\t? PipeOutput<P> extends number | string | Date\n\t\t\t? SchemaFields<S>[K]\n\t\t\t: never\n\t\t: never\n}[keyof SchemaFields<S>]\n\nexport type OptionalFieldOf<S extends AnySchema> = {\n\t[K in keyof SchemaFields<S>]: SchemaFields<S>[K] extends SchemaField<any, infer P, any>\n\t\t? undefined extends PipeOutput<P>\n\t\t\t? SchemaFields<S>[K]\n\t\t\t: never\n\t\t: never\n}[keyof SchemaFields<S>]\n\nexport type ArrayFieldOf<S extends AnySchema> = {\n\t[K in keyof SchemaFields<S>]: SchemaFields<S>[K] extends SchemaField<any, infer P, any>\n\t\t? PipeOutput<P> extends readonly any[]\n\t\t\t? SchemaFields<S>[K]\n\t\t\t: never\n\t\t: never\n}[keyof SchemaFields<S>]\n\nexport type ObjectFieldOf<S extends AnySchema> = {\n\t[K in keyof SchemaFields<S>]: SchemaFields<S>[K] extends SchemaField<any, infer P, any>\n\t\t? PipeOutput<P> extends Record<string, any>\n\t\t\t? PipeOutput<P> extends readonly any[]\n\t\t\t\t? never\n\t\t\t\t: SchemaFields<S>[K]\n\t\t\t: never\n\t\t: never\n}[keyof SchemaFields<S>]\n\nexport type SetValues<S extends AnySchema> = Prettify<\n\tPartial<{\n\t\t[K in keyof SchemaFields<S>]: SchemaFields<S>[K] extends AnySchemaField ? PipeInput<SchemaFields<S>[K]['pipe']> : never\n\t}>\n>\n\nexport class SetOp {\n\treadonly kind = 'set' as const\n\tconstructor(readonly values: Record<string, unknown>) {}\n}\nexport class IncOp {\n\treadonly kind = 'inc' as const\n\tconstructor(\n\t\treadonly field: string,\n\t\treadonly value: number,\n\t) {}\n}\nexport class MulOp {\n\treadonly kind = 'mul' as const\n\tconstructor(\n\t\treadonly field: string,\n\t\treadonly value: number,\n\t) {}\n}\nexport class MinOp<T = unknown> {\n\treadonly kind = 'min' as const\n\tconstructor(\n\t\treadonly field: string,\n\t\treadonly value: T,\n\t) {}\n}\nexport class MaxOp<T = unknown> {\n\treadonly kind = 'max' as const\n\tconstructor(\n\t\treadonly field: string,\n\t\treadonly value: T,\n\t) {}\n}\nexport class UnsetOp {\n\treadonly kind = 'unset' as const\n\tconstructor(readonly field: string) {}\n}\nexport class PushOp<T = unknown> {\n\treadonly kind = 'push' as const\n\tconstructor(\n\t\treadonly field: string,\n\t\treadonly value: T,\n\t) {}\n}\nexport class PullOp<T = unknown> {\n\treadonly kind = 'pull' as const\n\tconstructor(\n\t\treadonly field: string,\n\t\treadonly value: T,\n\t) {}\n}\nexport class PatchOp<T = unknown> {\n\treadonly kind = 'patch' as const\n\tconstructor(\n\t\treadonly field: string,\n\t\treadonly value: T,\n\t) {}\n}\n\nexport type AnyUpdateOp = SetOp | IncOp | MulOp | MinOp | MaxOp | UnsetOp | PushOp | PullOp | PatchOp\n\nexport function isUpdateOp(v: unknown): v is AnyUpdateOp {\n\treturn (\n\t\tv instanceof SetOp ||\n\t\tv instanceof IncOp ||\n\t\tv instanceof MulOp ||\n\t\tv instanceof MinOp ||\n\t\tv instanceof MaxOp ||\n\t\tv instanceof UnsetOp ||\n\t\tv instanceof PushOp ||\n\t\tv instanceof PullOp ||\n\t\tv instanceof PatchOp\n\t)\n}\n\nexport type HasOp<A, Op extends string> = A extends { updateOps: readonly (infer U)[] } ? (Op extends U ? true : false) : false\n\nexport type UpdateOp<_S extends AnySchema, A> =\n\t| (HasOp<A, 'set'> extends true ? SetOp : never)\n\t| (HasOp<A, 'inc'> extends true ? IncOp : never)\n\t| (HasOp<A, 'mul'> extends true ? MulOp : never)\n\t| (HasOp<A, 'min'> extends true ? MinOp : never)\n\t| (HasOp<A, 'max'> extends true ? MaxOp : never)\n\t| (HasOp<A, 'unset'> extends true ? UnsetOp : never)\n\t| (HasOp<A, 'push'> extends true ? PushOp : never)\n\t| (HasOp<A, 'pull'> extends true ? PullOp : never)\n\t| (HasOp<A, 'patch'> extends true ? PatchOp : never)\n\nexport function set<S extends AnySchema>(values: SetValues<S>): SetOp {\n\treturn new SetOp(values as Record<string, unknown>)\n}\n\nexport function inc<S extends AnySchema>(field: NumericFieldOf<S>, value: number): IncOp {\n\treturn new IncOp(toFieldName(field as AnyField), value)\n}\n\nexport function mul<S extends AnySchema>(field: NumericFieldOf<S>, value: number): MulOp {\n\treturn new MulOp(toFieldName(field as AnyField), value)\n}\n\nexport function min<S extends AnySchema>(field: ComparableFieldOf<S>, value: unknown): MinOp {\n\treturn new MinOp(toFieldName(field as AnyField), value)\n}\n\nexport function max<S extends AnySchema>(field: ComparableFieldOf<S>, value: unknown): MaxOp {\n\treturn new MaxOp(toFieldName(field as AnyField), value)\n}\n\nexport function unset<S extends AnySchema>(field: OptionalFieldOf<S>): UnsetOp {\n\treturn new UnsetOp(toFieldName(field as AnyField))\n}\n\nexport function push<S extends AnySchema>(field: ArrayFieldOf<S>, value: unknown): PushOp {\n\treturn new PushOp(toFieldName(field as AnyField), value)\n}\n\nexport function pull<S extends AnySchema>(field: ArrayFieldOf<S>, value: unknown): PullOp {\n\treturn new PullOp(toFieldName(field as AnyField), value)\n}\n\nexport function patch<S extends AnySchema>(field: ObjectFieldOf<S>, value: Record<string, unknown>): PatchOp {\n\treturn new PatchOp(toFieldName(field as AnyField), value)\n}\n\nexport function opTouchedFields(op: AnyUpdateOp): string[] {\n\tif (op instanceof SetOp) return Object.keys(op.values)\n\treturn [op.field]\n}\n\nexport function flattenOps(ops: AnyUpdateOp[]): Record<string, unknown> {\n\tconst data: Record<string, unknown> = {}\n\tfor (const op of ops) {\n\t\tif (op instanceof SetOp) Object.assign(data, op.values)\n\t\telse data[op.field] = op\n\t}\n\treturn data\n}\n\nif (import.meta.vitest) {\n\tconst { describe, test, expect, expectTypeOf } = import.meta.vitest\n\tconst { v } = await import('valleyed')\n\tconst { Schema } = await import('./schema')\n\n\tconst TestSchema = Schema.from('test')\n\t\t.pk('id', v.string(), () => 'x')\n\t\t.field('name', v.string())\n\t\t.field('age', v.number())\n\t\t.field('score', v.optional(v.number()))\n\t\t.field('tags', v.array(v.string()))\n\t\t.field('meta', v.object({ a: v.number() }))\n\t\t.field('createdAt', v.number(), { onCreate: () => 1000 })\n\t\t.field('updatedAt', v.number(), { onCreate: () => 1000, onUpdate: () => 2000 })\n\t\t.build()\n\n\tdescribe('op classes', () => {\n\t\ttest('SetOp has kind \"set\" and stores values', () => {\n\t\t\tconst op = new SetOp({ name: 'Alice' })\n\t\t\texpect(op.kind).toBe('set')\n\t\t\texpect(op.values).toEqual({ name: 'Alice' })\n\t\t})\n\t\ttest('IncOp has kind \"inc\" and stores field + value', () => {\n\t\t\tconst op = new IncOp('age', 5)\n\t\t\texpect(op.kind).toBe('inc')\n\t\t\texpect(op.field).toBe('age')\n\t\t\texpect(op.value).toBe(5)\n\t\t})\n\t\ttest('MulOp has kind \"mul\" and stores field + value', () => {\n\t\t\tconst op = new MulOp('score', 3)\n\t\t\texpect(op.kind).toBe('mul')\n\t\t\texpect(op.field).toBe('score')\n\t\t\texpect(op.value).toBe(3)\n\t\t})\n\t\ttest('MinOp has kind \"min\"', () => {\n\t\t\texpect(new MinOp('age', 10).kind).toBe('min')\n\t\t})\n\t\ttest('MaxOp has kind \"max\"', () => {\n\t\t\texpect(new MaxOp('age', 99).kind).toBe('max')\n\t\t})\n\t\ttest('UnsetOp has kind \"unset\"', () => {\n\t\t\texpect(new UnsetOp('score').kind).toBe('unset')\n\t\t})\n\t\ttest('PushOp has kind \"push\"', () => {\n\t\t\texpect(new PushOp('tags', 'x').kind).toBe('push')\n\t\t})\n\t\ttest('PullOp has kind \"pull\"', () => {\n\t\t\texpect(new PullOp('tags', 'x').kind).toBe('pull')\n\t\t})\n\t\ttest('PatchOp has kind \"patch\"', () => {\n\t\t\texpect(new PatchOp('meta', { a: 9 }).kind).toBe('patch')\n\t\t})\n\t})\n\n\tdescribe('isUpdateOp', () => {\n\t\ttest('returns true for every op class', () => {\n\t\t\texpect(isUpdateOp(new SetOp({}))).toBe(true)\n\t\t\texpect(isUpdateOp(new IncOp('f', 1))).toBe(true)\n\t\t\texpect(isUpdateOp(new MulOp('f', 2))).toBe(true)\n\t\t\texpect(isUpdateOp(new MinOp('f', 0))).toBe(true)\n\t\t\texpect(isUpdateOp(new MaxOp('f', 10))).toBe(true)\n\t\t\texpect(isUpdateOp(new UnsetOp('f'))).toBe(true)\n\t\t\texpect(isUpdateOp(new PushOp('f', 'v'))).toBe(true)\n\t\t\texpect(isUpdateOp(new PullOp('f', 'v'))).toBe(true)\n\t\t\texpect(isUpdateOp(new PatchOp('f', {}))).toBe(true)\n\t\t})\n\t\ttest('returns false for non-op values', () => {\n\t\t\texpect(isUpdateOp('string')).toBe(false)\n\t\t\texpect(isUpdateOp(42)).toBe(false)\n\t\t\texpect(isUpdateOp(null)).toBe(false)\n\t\t\texpect(isUpdateOp({})).toBe(false)\n\t\t})\n\t})\n\n\tdescribe('op helper functions', () => {\n\t\ttest('set() creates SetOp with values', () => {\n\t\t\tconst op = set<typeof TestSchema>({ name: 'Alice', age: 30 })\n\t\t\texpect(op).toBeInstanceOf(SetOp)\n\t\t\texpect(op.kind).toBe('set')\n\t\t\texpect(op.values).toEqual({ name: 'Alice', age: 30 })\n\t\t})\n\t\ttest('inc() creates IncOp from field ref', () => {\n\t\t\tconst op = inc<typeof TestSchema>(TestSchema.fields.age, 5)\n\t\t\texpect(op).toBeInstanceOf(IncOp)\n\t\t\texpect(op.field).toBe('age')\n\t\t\texpect(op.value).toBe(5)\n\t\t})\n\t\ttest('mul() creates MulOp from field ref', () => {\n\t\t\tconst op = mul<typeof TestSchema>(TestSchema.fields.age, 3)\n\t\t\texpect(op).toBeInstanceOf(MulOp)\n\t\t\texpect(op.field).toBe('age')\n\t\t\texpect(op.value).toBe(3)\n\t\t})\n\t\ttest('min() creates MinOp from field ref', () => {\n\t\t\tconst op = min<typeof TestSchema>(TestSchema.fields.age, 10)\n\t\t\texpect(op).toBeInstanceOf(MinOp)\n\t\t\texpect(op.field).toBe('age')\n\t\t})\n\t\ttest('max() creates MaxOp from field ref', () => {\n\t\t\tconst op = max<typeof TestSchema>(TestSchema.fields.age, 99)\n\t\t\texpect(op).toBeInstanceOf(MaxOp)\n\t\t\texpect(op.field).toBe('age')\n\t\t})\n\t\ttest('unset() creates UnsetOp from field ref', () => {\n\t\t\tconst op = unset<typeof TestSchema>(TestSchema.fields.score)\n\t\t\texpect(op).toBeInstanceOf(UnsetOp)\n\t\t\texpect(op.field).toBe('score')\n\t\t})\n\t\ttest('push() creates PushOp from field ref', () => {\n\t\t\tconst op = push<typeof TestSchema>(TestSchema.fields.tags, 'new-tag')\n\t\t\texpect(op).toBeInstanceOf(PushOp)\n\t\t\texpect(op.field).toBe('tags')\n\t\t\texpect(op.value).toBe('new-tag')\n\t\t})\n\t\ttest('pull() creates PullOp from field ref', () => {\n\t\t\tconst op = pull<typeof TestSchema>(TestSchema.fields.tags, 'old-tag')\n\t\t\texpect(op).toBeInstanceOf(PullOp)\n\t\t\texpect(op.field).toBe('tags')\n\t\t})\n\t\ttest('patch() creates PatchOp from field ref', () => {\n\t\t\tconst op = patch<typeof TestSchema>(TestSchema.fields.meta, { a: 9 })\n\t\t\texpect(op).toBeInstanceOf(PatchOp)\n\t\t\texpect(op.field).toBe('meta')\n\t\t\texpect(op.value).toEqual({ a: 9 })\n\t\t})\n\t})\n\n\tdescribe('opTouchedFields', () => {\n\t\ttest('SetOp returns all keys from values', () => {\n\t\t\texpect(opTouchedFields(new SetOp({ name: 'A', age: 1 }))).toEqual(['name', 'age'])\n\t\t})\n\t\ttest('IncOp returns the field', () => {\n\t\t\texpect(opTouchedFields(new IncOp('age', 1))).toEqual(['age'])\n\t\t})\n\t\ttest('UnsetOp returns the field', () => {\n\t\t\texpect(opTouchedFields(new UnsetOp('score'))).toEqual(['score'])\n\t\t})\n\t})\n\n\tdescribe('type-level: field-category helpers', () => {\n\t\ttest('NumericFieldOf only matches numeric fields (excludes optional numeric)', () => {\n\t\t\ttype Numeric = NumericFieldOf<typeof TestSchema>\n\t\t\texpectTypeOf<Numeric['name']>().toEqualTypeOf<'age' | 'createdAt' | 'updatedAt'>()\n\t\t})\n\t\ttest('ComparableFieldOf matches numeric and string fields (excludes optional)', () => {\n\t\t\ttype Comparable = ComparableFieldOf<typeof TestSchema>\n\t\t\texpectTypeOf<Comparable['name']>().toEqualTypeOf<'id' | 'name' | 'age' | 'createdAt' | 'updatedAt'>()\n\t\t})\n\t\ttest('OptionalFieldOf only matches optional fields', () => {\n\t\t\ttype Optional = OptionalFieldOf<typeof TestSchema>\n\t\t\texpectTypeOf<Optional['name']>().toEqualTypeOf<'score'>()\n\t\t})\n\t\ttest('ArrayFieldOf only matches array fields', () => {\n\t\t\ttype Arr = ArrayFieldOf<typeof TestSchema>\n\t\t\texpectTypeOf<Arr['name']>().toEqualTypeOf<'tags'>()\n\t\t})\n\t\ttest('ObjectFieldOf only matches object fields (not arrays)', () => {\n\t\t\ttype Obj = ObjectFieldOf<typeof TestSchema>\n\t\t\texpectTypeOf<Obj['name']>().toEqualTypeOf<'meta'>()\n\t\t})\n\t})\n\n\tdescribe('type-level: inc on a string field is a TS error', () => {\n\t\ttest('inc rejects non-numeric fields', () => {\n\t\t\t// @ts-expect-error — name is a string field, not numeric\n\t\t\tinc<typeof TestSchema>(TestSchema.fields.name, 1)\n\t\t})\n\t})\n\n\tdescribe('type-level: push on a non-array field is a TS error', () => {\n\t\ttest('push rejects non-array fields', () => {\n\t\t\t// @ts-expect-error — name is a string field, not array\n\t\t\tpush<typeof TestSchema>(TestSchema.fields.name, 'val')\n\t\t})\n\t})\n\n\tdescribe('type-level: per-op gating via UpdateOp<S, A>', () => {\n\t\ttest('undeclared ops resolve to never', async () => {\n\t\t\tconst { OrmAdapter } = await import('./orm-adapter')\n\t\t\tclass LimitedAdapter extends OrmAdapter {\n\t\t\t\treadonly schemaConfigPipe = v.object({})\n\t\t\t\treadonly supportedFieldTypes = ['string', 'number'] as const\n\t\t\t\treadonly updateOps = ['set', 'inc'] as const\n\t\t\t}\n\n\t\t\ttype Limited = UpdateOp<typeof TestSchema, LimitedAdapter>\n\t\t\texpectTypeOf<Limited>().toEqualTypeOf<SetOp | IncOp>()\n\t\t})\n\n\t\ttest('adapter with no updateOps resolves all variants to never', async () => {\n\t\t\tconst { OrmAdapter } = await import('./orm-adapter')\n\t\t\tclass NoOpsAdapter extends OrmAdapter {\n\t\t\t\treadonly schemaConfigPipe = v.object({})\n\t\t\t\treadonly supportedFieldTypes = ['string'] as const\n\t\t\t\treadonly updateOps = [] as const\n\t\t\t}\n\n\t\t\ttype NoOps = UpdateOp<typeof TestSchema, NoOpsAdapter>\n\t\t\texpectTypeOf<NoOps>().toBeNever()\n\t\t})\n\n\t\ttest('adapter with all updateOps includes all variants', async () => {\n\t\t\tconst { OrmAdapter } = await import('./orm-adapter')\n\t\t\tclass FullAdapter extends OrmAdapter {\n\t\t\t\treadonly schemaConfigPipe = v.object({})\n\t\t\t\treadonly supportedFieldTypes = ['string', 'number'] as const\n\t\t\t\treadonly updateOps = ['set', 'inc', 'mul', 'min', 'max', 'unset', 'push', 'pull', 'patch'] as const\n\t\t\t}\n\n\t\t\ttype Full = UpdateOp<typeof TestSchema, FullAdapter>\n\t\t\ttype Expected =\n\t\t\t\t| SetOp\n\t\t\t\t| IncOp\n\t\t\t\t| MulOp\n\t\t\t\t| MinOp\n\t\t\t\t| MaxOp\n\t\t\t\t| UnsetOp\n\t\t\t\t| PushOp\n\t\t\t\t| PullOp\n\t\t\t\t| PatchOp\n\t\t\texpectTypeOf<Full>().toEqualTypeOf<Expected>()\n\t\t})\n\t})\n}\n"],"mappings":"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","names":["OrmValidationError","EquippedError","kind","schema","operation","failures","Field","name","path","toFieldName","field","SchemaField","pipe","opts","ComputedField","deps","compute","Filter","field","op","value","toFieldName","FilterGroup","_FilterGroup","children","#withChild","child","facFns","EquippedError","group","fn","c","assertNormalisedAggregate","schema","adapter","spec","failures","seenAliases","agg","allFields","fieldNames","OrmValidationError","assertNormalisedFilter","walkHaving","node","validHavingFields","havingErrors","errors","walk","e","OrmAdapter","err","wrapped","EquippedError","Instance","self","schema","config","emptyIterator","use","filter","opts","d","match","pk","pkFilter","FilterGroup","create","ops","row","args","spec","SetOp","values","IncOp","field","value","MulOp","MinOp","MaxOp","UnsetOp","PushOp","PullOp","PatchOp","isUpdateOp","v","set","inc","toFieldName","mul","min","max","unset","push","pull","patch","opTouchedFields","op","flattenOps","ops","data"]}