@danceroutine/tango-testing 1.11.10 → 1.11.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { n as anAdapter, t as aDBClient } from "./aDBClient-fMkIdR7p.js";
2
- import { a as aManyToManyRelatedManager, c as aQueryExecutor, i as aQuerySet, l as aQueryResult, n as aRelationMeta, o as aManager, r as aRequestContext, s as aModelQuerySet, t as mocks_exports } from "./mocks-JyZwO-W4.js";
2
+ import { a as aManyToManyRelatedManager, c as aQueryExecutor, i as aQuerySet, l as aQueryResult, n as aRelationMeta, o as aManager, r as aRequestContext, s as aModelQuerySet, t as mocks_exports } from "./mocks-Bf9TpwD7.js";
3
3
  import { n as ModelDataFactory, t as factories_exports } from "./factories-qAJouv1I.js";
4
4
  import { n as assertions, t as assertions_exports } from "./assertions-lsAd7fhA.js";
5
5
  import { C as Dialect, S as ResetMode, _ as migrations_exports, a as seedTable, b as assertMigrationPlan, c as anIntegrationHarness, d as runtime_exports, f as setupTestTangoRuntime, g as runDialectConformanceSuite, h as conformance_exports, i as createModelQuerySetFixture, l as smoke_exports, m as aTangoConfig, n as expectQueryResult, o as TestHarness, p as aTangoRuntime, r as createQuerySetFixture, s as HarnessStrategyRegistry, t as integration_exports, u as AppProcessHarness, v as introspectSchema, x as domain_exports, y as applyAndVerifyMigrations } from "./integration-CLzkacon.js";
@@ -1,3 +1,3 @@
1
1
  import { n as anAdapter, t as aDBClient } from "../aDBClient-fMkIdR7p.js";
2
- import { a as aManyToManyRelatedManager, c as aQueryExecutor, i as aQuerySet, l as aQueryResult, n as aRelationMeta, o as aManager, r as aRequestContext, s as aModelQuerySet } from "../mocks-JyZwO-W4.js";
2
+ import { a as aManyToManyRelatedManager, c as aQueryExecutor, i as aQuerySet, l as aQueryResult, n as aRelationMeta, o as aManager, r as aRequestContext, s as aModelQuerySet } from "../mocks-Bf9TpwD7.js";
3
3
  export { aDBClient, aManager, aManyToManyRelatedManager, aModelQuerySet, aQueryExecutor, aQueryResult, aQuerySet, aRelationMeta, aRequestContext, anAdapter };
@@ -152,7 +152,7 @@ function aManyToManyRelatedManager(overrides = {}) {
152
152
  ownerModelLabel: overrides.ownerModelLabel ?? "Post",
153
153
  targetPrimaryKeyField: overrides.targetPrimaryKeyField ?? "id",
154
154
  throughTableManager,
155
- targetExecutorProvider: () => overrides.targetExecutor === void 0 ? {} : overrides.targetExecutor,
155
+ targetExecutorProvider: () => overrides.targetExecutor === void 0 ? aQueryExecutor() : overrides.targetExecutor,
156
156
  createTarget,
157
157
  runAtomic: runAtomicSpy
158
158
  }),
@@ -254,4 +254,4 @@ var mocks_exports = /* @__PURE__ */ __exportAll({
254
254
  //#endregion
255
255
  export { aManyToManyRelatedManager as a, aQueryExecutor as c, aQuerySet as i, aQueryResult as l, aRelationMeta as n, aManager as o, aRequestContext as r, aModelQuerySet as s, mocks_exports as t };
256
256
 
257
- //# sourceMappingURL=mocks-JyZwO-W4.js.map
257
+ //# sourceMappingURL=mocks-Bf9TpwD7.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mocks-Bf9TpwD7.js","names":["QueryResultClass","QuerySetClass"],"sources":["../src/mocks/aQueryResult.ts","../src/mocks/aQueryExecutor.ts","../src/mocks/aModelQuerySet.ts","../src/mocks/aManager.ts","../src/mocks/aManyToManyRelatedManager.ts","../src/mocks/aQuerySet.ts","../src/mocks/aRequestContext.ts","../src/mocks/aRelationMeta.ts","../src/mocks/index.ts"],"sourcesContent":["import type { QueryResult } from '@danceroutine/tango-orm/query';\nimport { QueryResult as QueryResultClass } from '@danceroutine/tango-orm/query';\n\nexport type AQueryResultOverrides<TModel> = {\n items?: readonly TModel[];\n results?: readonly TModel[];\n};\n\n/**\n * Create a query-result test value with optional overrides.\n */\nexport function aQueryResult<TModel>(overrides: AQueryResultOverrides<TModel> = {}): QueryResult<TModel> {\n const items = overrides.items ?? overrides.results ?? ([] as TModel[]);\n return new QueryResultClass(items);\n}\n","import { vi } from 'vitest';\nimport type { Adapter, QueryExecutor } from '@danceroutine/tango-orm';\nimport type { Dialect, TableMeta } from '@danceroutine/tango-orm/query';\nimport { anAdapter } from './anAdapter';\nimport { aDBClient } from './aDBClient';\n\nexport type QueryExecutorOverrides<TModel extends Record<string, unknown>> = {\n dialect?: Dialect;\n adapter?: Adapter;\n meta?: TableMeta;\n query?: (sql: string, params?: readonly unknown[]) => Promise<{ rows: unknown[] }>;\n run?: QueryExecutor<TModel>['run'];\n attachPersistedRecordAccessors?: QueryExecutor<TModel>['attachPersistedRecordAccessors'];\n};\n\n/**\n * Create a minimal `QueryExecutor` test double for `QuerySet` tests.\n */\nexport function aQueryExecutor<TModel extends Record<string, unknown>>(\n overrides: QueryExecutorOverrides<TModel> = {}\n): QueryExecutor<TModel> {\n const adapter = overrides.adapter ?? anAdapter({ dialect: overrides.dialect ?? 'postgres' });\n const meta: TableMeta = overrides.meta ?? { table: 'mock_table', pk: 'id', columns: {} };\n const run = overrides.run ?? vi.fn(async () => [] as TModel[]);\n const client = aDBClient(overrides.query ? { query: overrides.query } : {});\n\n return {\n meta,\n client,\n adapter,\n run,\n ...(overrides.attachPersistedRecordAccessors\n ? { attachPersistedRecordAccessors: overrides.attachPersistedRecordAccessors }\n : {}),\n };\n}\n","import { vi } from 'vitest';\nimport type { QuerySet } from '@danceroutine/tango-orm';\nimport { ModelQuerySet as QuerySetClass } from '@danceroutine/tango-orm';\nimport { aQueryResult } from './aQueryResult';\nimport { aQueryExecutor } from './aQueryExecutor';\n\n/**\n * Create a chainable model-queryset test double with optional behavior overrides.\n *\n * All methods are wrapped in `vi.fn()` so they can be asserted on directly\n * without an additional `vi.mocked()` call.\n */\nexport function aModelQuerySet<\n TModel extends Record<string, unknown>,\n TResult extends Record<string, unknown> = TModel,\n>(overrides: Partial<QuerySet<TModel, TResult>> = {}): QuerySet<TModel, TResult> {\n const queryset = new QuerySetClass<TModel, TResult>(aQueryExecutor<TModel>());\n const filterImpl: QuerySet<TModel, TResult>['filter'] = overrides.filter ?? ((_input) => queryset);\n const excludeImpl: QuerySet<TModel, TResult>['exclude'] = overrides.exclude ?? ((_input) => queryset);\n const orderByImpl: QuerySet<TModel, TResult>['orderBy'] = overrides.orderBy ?? ((..._tokens) => queryset);\n const limitImpl: QuerySet<TModel, TResult>['limit'] = overrides.limit ?? ((_n) => queryset);\n const offsetImpl: QuerySet<TModel, TResult>['offset'] = overrides.offset ?? ((_n) => queryset);\n const defaultSelect = ((_cols: readonly (keyof TModel)[]) => queryset) as unknown as QuerySet<\n TModel,\n TResult\n >['select'];\n const selectImpl = overrides.select ?? defaultSelect;\n const selectRelatedImpl =\n (overrides.selectRelated as ((...rels: readonly string[]) => QuerySet<TModel, TResult>) | undefined) ??\n ((..._rels: readonly string[]) => queryset);\n const prefetchRelatedImpl =\n (overrides.prefetchRelated as ((...rels: readonly string[]) => QuerySet<TModel, TResult>) | undefined) ??\n ((..._rels: readonly string[]) => queryset);\n const fetchImpl: QuerySet<TModel, TResult>['fetch'] =\n overrides.fetch ??\n (async <Out = TResult>(_shape?: ((r: TResult) => Out) | { parse: (r: TResult) => Out }) => aQueryResult<Out>());\n const fetchOneImpl: QuerySet<TModel, TResult>['fetchOne'] =\n overrides.fetchOne ??\n (async <Out = TResult>(_shape?: ((r: TResult) => Out) | { parse: (r: TResult) => Out }) => null as Out | null);\n const countImpl: QuerySet<TModel, TResult>['count'] = overrides.count ?? (async () => 0);\n const existsImpl: QuerySet<TModel, TResult>['exists'] = overrides.exists ?? (async () => false);\n\n queryset.filter = vi.fn((input: Parameters<QuerySet<TModel, TResult>['filter']>[0]) =>\n filterImpl(input)\n ) as QuerySet<TModel, TResult>['filter'];\n queryset.exclude = vi.fn((input: Parameters<QuerySet<TModel, TResult>['exclude']>[0]) =>\n excludeImpl(input)\n ) as QuerySet<TModel, TResult>['exclude'];\n queryset.orderBy = vi.fn((...tokens: Parameters<QuerySet<TModel, TResult>['orderBy']>) =>\n orderByImpl(...tokens)\n ) as QuerySet<TModel, TResult>['orderBy'];\n queryset.limit = vi.fn((n: number) => limitImpl(n)) as QuerySet<TModel, TResult>['limit'];\n queryset.offset = vi.fn((n: number) => offsetImpl(n)) as QuerySet<TModel, TResult>['offset'];\n queryset.select = vi.fn((cols: Parameters<QuerySet<TModel, TResult>['select']>[0]) =>\n selectImpl(cols)\n ) as unknown as QuerySet<TModel, TResult>['select'];\n queryset.selectRelated = vi.fn((...rels: readonly string[]) => selectRelatedImpl(...rels)) as unknown as QuerySet<\n TModel,\n TResult\n >['selectRelated'];\n queryset.prefetchRelated = vi.fn((...rels: readonly string[]) =>\n prefetchRelatedImpl(...rels)\n ) as unknown as QuerySet<TModel, TResult>['prefetchRelated'];\n queryset.fetch = vi.fn(fetchImpl) as unknown as QuerySet<TModel, TResult>['fetch'];\n queryset.fetchOne = vi.fn(fetchOneImpl) as unknown as QuerySet<TModel, TResult>['fetchOne'];\n queryset.count = vi.fn(() => countImpl()) as QuerySet<TModel, TResult>['count'];\n queryset.exists = vi.fn(() => existsImpl()) as QuerySet<TModel, TResult>['exists'];\n\n return queryset;\n}\n","import { vi } from 'vitest';\nimport type { ManagerLike, QuerySet } from '@danceroutine/tango-orm';\nimport type { TableMeta } from '@danceroutine/tango-orm/query';\nimport { aModelQuerySet } from './aModelQuerySet';\n\nexport type ManagerOverrides<TModel extends Record<string, unknown>> = {\n meta?: TableMeta;\n querySet?: QuerySet<TModel>;\n query?: ManagerLike<TModel>['query'];\n all?: ManagerLike<TModel>['all'];\n getOrCreate?: ManagerLike<TModel>['getOrCreate'];\n updateOrCreate?: ManagerLike<TModel>['updateOrCreate'];\n findById?: ManagerLike<TModel>['findById'];\n getOrThrow?: ManagerLike<TModel>['getOrThrow'];\n create?: ManagerLike<TModel>['create'];\n update?: ManagerLike<TModel>['update'];\n delete?: ManagerLike<TModel>['delete'];\n bulkCreate?: ManagerLike<TModel>['bulkCreate'];\n};\n\n/**\n * Create a manager-shaped test double for resource and service tests.\n */\nexport function aManager<TModel extends Record<string, unknown>>(\n overrides: ManagerOverrides<TModel> = {}\n): ManagerLike<TModel> {\n const meta = overrides.meta ?? { table: 'mock_table', pk: 'id', columns: {} };\n const querySet = overrides.querySet ?? aModelQuerySet<TModel>();\n type ModelId = TModel[keyof TModel];\n\n const queryImpl = overrides.query ?? (() => querySet);\n const allImpl = overrides.all ?? (() => queryImpl());\n const findByIdImpl = overrides.findById ?? (async () => null as TModel | null);\n const getOrThrowImpl =\n overrides.getOrThrow ??\n (async (id: ModelId) => {\n const record = await findByIdImpl(id);\n if (!record) {\n throw new Error(`No ${meta.table} record found for ${String(meta.pk)}=${String(id)}.`);\n }\n return record;\n });\n const createImpl = overrides.create ?? (async (input: Partial<TModel>) => input as TModel);\n const updateImpl = overrides.update ?? (async (_id: ModelId, patch: Partial<TModel>) => patch as TModel);\n const deleteImpl = overrides.delete ?? (async (_id: ModelId) => {});\n const bulkCreateImpl = overrides.bulkCreate ?? (async (inputs: Partial<TModel>[]) => inputs as TModel[]);\n const getOrCreateImpl =\n overrides.getOrCreate ??\n (async ({ defaults }: Parameters<ManagerLike<TModel>['getOrCreate']>[0]) => ({\n record: { ...defaults } as TModel,\n created: true,\n }));\n const updateOrCreateImpl =\n overrides.updateOrCreate ??\n (async ({ defaults }: Parameters<ManagerLike<TModel>['updateOrCreate']>[0]) => ({\n record: { ...defaults } as TModel,\n created: true,\n updated: false,\n }));\n\n return {\n meta,\n query: vi.fn(() => queryImpl()),\n all: vi.fn(() => allImpl()),\n getOrCreate: vi.fn((args: Parameters<ManagerLike<TModel>['getOrCreate']>[0]) => getOrCreateImpl(args)),\n updateOrCreate: vi.fn((args: Parameters<ManagerLike<TModel>['updateOrCreate']>[0]) => updateOrCreateImpl(args)),\n findById: vi.fn((id: ModelId) => findByIdImpl(id)),\n getOrThrow: vi.fn((id: ModelId) => getOrThrowImpl(id)),\n create: vi.fn((input: Partial<TModel>) => createImpl(input)),\n update: vi.fn((id: ModelId, patch: Partial<TModel>) => updateImpl(id, patch)),\n delete: vi.fn((id: ModelId) => deleteImpl(id)),\n bulkCreate: vi.fn((inputs: Partial<TModel>[]) => bulkCreateImpl(inputs)),\n };\n}\n","import { vi } from 'vitest';\nimport type { QueryExecutor } from '@danceroutine/tango-orm';\nimport { ManyToManyRelatedManager } from '@danceroutine/tango-orm';\nimport { aQueryExecutor } from './aQueryExecutor';\n\ntype ManagerConstructorInputs = ConstructorParameters<typeof ManyToManyRelatedManager>[0];\n\n/**\n * Overrides accepted by the {@link aManyToManyRelatedManager} fixture. All\n * fields are optional; defaults produce a manager bound to owner primary key\n * `7`, relation name `'tags'`, owner label `'Post'`, and target primary-key\n * field `'id'`.\n */\nexport interface ManyToManyRelatedManagerFixtureOverrides<TTarget extends Record<string, unknown>> {\n ownerPrimaryKey?: unknown;\n relationName?: string;\n ownerModelLabel?: string;\n targetPrimaryKeyField?: string;\n /**\n * Resolver returned by the manager's `targetExecutorProvider`. Pass `null`\n * to simulate the registry not yet knowing about the target model; omit to\n * return a minimal executor stub.\n */\n targetExecutor?: QueryExecutor<TTarget> | null;\n insertLink?: (ownerPrimaryKey: unknown, targetPrimaryKey: unknown) => Promise<void>;\n insertLinks?: (ownerPrimaryKey: unknown, targetPrimaryKeys: readonly unknown[]) => Promise<void>;\n deleteLink?: (ownerPrimaryKey: unknown, targetPrimaryKey: unknown) => Promise<void>;\n deleteLinks?: (ownerPrimaryKey: unknown, targetPrimaryKeys: readonly unknown[]) => Promise<void>;\n deleteAllLinksForOwner?: (ownerPrimaryKey: unknown) => Promise<void>;\n selectTargetIdsForOwner?: (ownerPrimaryKey: unknown) => Promise<readonly (string | number)[]>;\n createTarget?: (input: Partial<TTarget>) => Promise<TTarget>;\n runAtomic?: <T>(work: () => Promise<T>) => Promise<T>;\n}\n\n/**\n * Return shape of the {@link aManyToManyRelatedManager} fixture. The spy\n * references are returned alongside the manager so tests can assert against\n * the join-table calls without reaching into private fields.\n */\nexport interface ManyToManyRelatedManagerFixture<TTarget extends Record<string, unknown>> {\n manager: ManyToManyRelatedManager<TTarget>;\n insertLink: ReturnType<typeof vi.fn>;\n insertLinks: ReturnType<typeof vi.fn>;\n deleteLink: ReturnType<typeof vi.fn>;\n deleteLinks: ReturnType<typeof vi.fn>;\n deleteAllLinksForOwner: ReturnType<typeof vi.fn>;\n selectTargetIdsForOwner: ReturnType<typeof vi.fn>;\n createTarget: ReturnType<typeof vi.fn>;\n runAtomic: ReturnType<typeof vi.fn>;\n}\n\n/**\n * Build a {@link ManyToManyRelatedManager} instance wired to lightweight spies\n * for its underlying join-table operations. The fixture skips the\n * relation-metadata and registry plumbing exercised by `ModelManager`, so\n * tests can focus on manager behavior in isolation.\n */\nexport function aManyToManyRelatedManager<TTarget extends Record<string, unknown>>(\n overrides: ManyToManyRelatedManagerFixtureOverrides<TTarget> = {}\n): ManyToManyRelatedManagerFixture<TTarget> {\n const insertLink = vi.fn(overrides.insertLink ?? (async () => {}));\n const insertLinks = vi.fn(overrides.insertLinks ?? (async () => {}));\n const deleteLink = vi.fn(overrides.deleteLink ?? (async () => {}));\n const deleteLinks = vi.fn(overrides.deleteLinks ?? (async () => {}));\n const deleteAllLinksForOwner = vi.fn(overrides.deleteAllLinksForOwner ?? (async () => {}));\n const selectTargetIdsForOwner = vi.fn(\n overrides.selectTargetIdsForOwner ?? (async (): Promise<readonly (string | number)[]> => [])\n );\n const createTarget = vi.fn(\n overrides.createTarget ??\n (async (input: Partial<TTarget>) => {\n return input as TTarget;\n })\n );\n const runAtomicImpl: ManagerConstructorInputs['runAtomic'] =\n overrides.runAtomic ?? (async <T>(work: () => Promise<T>) => work());\n const runAtomicSpy = vi.fn(async <T>(work: () => Promise<T>) => runAtomicImpl(work));\n\n const throughTableManager = {\n insertLink,\n insertLinks,\n deleteLink,\n deleteLinks,\n deleteAllLinksForOwner,\n selectTargetIdsForOwner,\n } as unknown as ManagerConstructorInputs['throughTableManager'];\n\n const manager = new ManyToManyRelatedManager<TTarget>({\n ownerPrimaryKey: overrides.ownerPrimaryKey ?? 7,\n relationName: overrides.relationName ?? 'tags',\n ownerModelLabel: overrides.ownerModelLabel ?? 'Post',\n targetPrimaryKeyField: overrides.targetPrimaryKeyField ?? 'id',\n throughTableManager,\n targetExecutorProvider: () =>\n overrides.targetExecutor === undefined ? aQueryExecutor<TTarget>() : overrides.targetExecutor,\n createTarget,\n runAtomic: runAtomicSpy as ManagerConstructorInputs['runAtomic'],\n });\n\n return {\n manager,\n insertLink,\n insertLinks,\n deleteLink,\n deleteLinks,\n deleteAllLinksForOwner,\n selectTargetIdsForOwner,\n createTarget,\n runAtomic: runAtomicSpy,\n };\n}\n","import { getLogger } from '@danceroutine/tango-core';\nimport type { QuerySet } from '@danceroutine/tango-orm';\nimport { aModelQuerySet } from './aModelQuerySet';\n\nconst logger = getLogger('tango.testing.mocks');\n// TODO this pattern keeps showing up, perhaps we should implement logger.warnOnce\nlet hasWarned = false;\n\n/**\n * @deprecated Use `aModelQuerySet(...)` instead.\n */\nexport function aQuerySet<TModel extends Record<string, unknown>, TResult extends Record<string, unknown> = TModel>(\n overrides: Partial<QuerySet<TModel, TResult>> = {}\n): QuerySet<TModel, TResult> {\n if (!hasWarned) {\n hasWarned = true;\n logger.warn('`aQuerySet(...)` is deprecated. Use `aModelQuerySet(...)` instead.');\n }\n\n return aModelQuerySet(overrides);\n}\n","// Import through the package subpath so fixtures stay aligned with the public nominal type.\nimport { RequestContext, type BaseUser } from '@danceroutine/tango-resources/context';\n\ntype RequestContextFactory<TUser, TContext extends RequestContextLike<TUser>> = (\n request: Request,\n user: TUser | null\n) => TContext;\n\ntype RequestContextLike<TUser> = {\n request: Request;\n user: TUser | null;\n params: Record<string, string>;\n};\n\nexport type RequestContextFixtureOptions<\n TUser = BaseUser,\n TContext extends RequestContextLike<TUser> = RequestContext<TUser>,\n> = {\n method?: string;\n url?: string;\n body?: unknown;\n user?: TUser | null;\n params?: Record<string, string>;\n headers?: HeadersInit;\n contextFactory?: RequestContextFactory<TUser, TContext>;\n};\n\n/**\n * Create a RequestContext fixture with optional method/url/body/user/params.\n */\nexport function aRequestContext<TUser = BaseUser, TContext extends RequestContextLike<TUser> = RequestContext<TUser>>(\n method: string,\n url: string,\n body?: unknown\n): TContext;\nexport function aRequestContext<TUser = BaseUser, TContext extends RequestContextLike<TUser> = RequestContext<TUser>>(\n options?: RequestContextFixtureOptions<TUser, TContext>\n): TContext;\nexport function aRequestContext<TUser = BaseUser, TContext extends RequestContextLike<TUser> = RequestContext<TUser>>(\n optionsOrMethod: RequestContextFixtureOptions<TUser, TContext> | string = {},\n urlArg?: string,\n bodyArg?: unknown\n): TContext {\n const resolvedOptions: RequestContextFixtureOptions<TUser, TContext> =\n typeof optionsOrMethod === 'string'\n ? {\n method: optionsOrMethod,\n url: urlArg,\n body: bodyArg,\n }\n : optionsOrMethod;\n const {\n method = 'GET',\n url = 'https://example.test',\n body,\n user = null,\n params = {},\n headers,\n contextFactory,\n } = resolvedOptions;\n\n const resolvedHeaders: HeadersInit | undefined =\n body === undefined ? headers : { 'content-type': 'application/json', ...headers };\n\n const request = new Request(url, {\n method,\n headers: resolvedHeaders,\n body: body === undefined ? undefined : JSON.stringify(body),\n });\n const createContext =\n contextFactory ?? ((req: Request, currentUser: TUser | null) => RequestContext.create<TUser>(req, currentUser));\n const context = createContext(request, user) as TContext;\n context.params = params;\n return context;\n}\n","import type { RelationMeta, TableMeta } from '@danceroutine/tango-orm/query';\n\ntype RelationMetaInput = {\n kind: RelationMeta['kind'];\n table: string;\n sourceKey: string;\n targetKey: string;\n targetColumns: Record<string, string>;\n alias: string;\n edgeId?: string;\n sourceModelKey?: string;\n targetModelKey?: string;\n targetPrimaryKey?: string;\n targetMeta?: TableMeta;\n capabilities?: Partial<RelationMeta['capabilities']>;\n};\n\n/**\n * Build recursive relation metadata fixtures for planner/compiler/query tests.\n */\nexport function aRelationMeta(input: RelationMetaInput): RelationMeta {\n const cardinality = input.kind === 'belongsTo' || input.kind === 'hasOne' ? 'single' : 'many';\n const defaultHydratable = input.kind !== ('manyToMany' as RelationMeta['kind']);\n\n const targetMeta =\n input.targetMeta ??\n ({\n modelKey: input.targetModelKey ?? `${input.alias}:target`,\n table: input.table,\n pk: input.targetPrimaryKey ?? 'id',\n columns: input.targetColumns,\n } satisfies TableMeta);\n\n return {\n edgeId: input.edgeId ?? `${input.alias}:${input.sourceKey}:${input.targetKey}`,\n sourceModelKey: input.sourceModelKey ?? `${input.alias}:source`,\n targetModelKey: input.targetModelKey ?? `${input.alias}:target`,\n kind: input.kind,\n cardinality,\n capabilities: {\n queryable: true,\n hydratable: defaultHydratable,\n joinable: cardinality === 'single' && defaultHydratable,\n prefetchable: defaultHydratable,\n ...input.capabilities,\n },\n table: input.table,\n sourceKey: input.sourceKey,\n targetKey: input.targetKey,\n targetPrimaryKey: input.targetPrimaryKey ?? 'id',\n targetColumns: input.targetColumns,\n alias: input.alias,\n targetMeta,\n };\n}\n","/**\n * Domain boundary barrel: centralizes this subdomain's public contract.\n */\n\nexport { anAdapter } from './anAdapter';\nexport { aDBClient } from './aDBClient';\nexport { aManager } from './aManager';\nexport { aManyToManyRelatedManager } from './aManyToManyRelatedManager';\nexport { aModelQuerySet } from './aModelQuerySet';\nexport { aQueryResult } from './aQueryResult';\nexport { aQuerySet } from './aQuerySet';\nexport { aRequestContext } from './aRequestContext';\nexport { aQueryExecutor } from './aQueryExecutor';\nexport { aRelationMeta } from './aRelationMeta';\nexport type { AdapterOverrides } from './anAdapter';\nexport type { QueryExecutorOverrides } from './aQueryExecutor';\nexport type { ManagerOverrides } from './aManager';\nexport type {\n ManyToManyRelatedManagerFixture,\n ManyToManyRelatedManagerFixtureOverrides,\n} from './aManyToManyRelatedManager';\nexport type { DBClient } from './DBClient';\nexport type { MockQuerySetResult } from './MockQuerySetResult';\nexport type { RequestContextFixtureOptions } from './aRequestContext';\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@danceroutine/tango-testing",
3
- "version": "1.11.10",
3
+ "version": "1.11.12",
4
4
  "description": "Testing utilities for Tango",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -52,11 +52,11 @@
52
52
  "directory": "packages/testing"
53
53
  },
54
54
  "dependencies": {
55
- "@danceroutine/tango-config": "1.11.10",
56
- "@danceroutine/tango-core": "1.11.10",
57
- "@danceroutine/tango-migrations": "1.11.10",
58
- "@danceroutine/tango-orm": "1.11.10",
59
- "@danceroutine/tango-resources": "1.11.10"
55
+ "@danceroutine/tango-config": "1.11.12",
56
+ "@danceroutine/tango-core": "1.11.12",
57
+ "@danceroutine/tango-migrations": "1.11.12",
58
+ "@danceroutine/tango-orm": "1.11.12",
59
+ "@danceroutine/tango-resources": "1.11.12"
60
60
  },
61
61
  "peerDependencies": {
62
62
  "@types/express": "^5.0.0",
@@ -1 +0,0 @@
1
- {"version":3,"file":"mocks-JyZwO-W4.js","names":["QueryResultClass","QuerySetClass"],"sources":["../src/mocks/aQueryResult.ts","../src/mocks/aQueryExecutor.ts","../src/mocks/aModelQuerySet.ts","../src/mocks/aManager.ts","../src/mocks/aManyToManyRelatedManager.ts","../src/mocks/aQuerySet.ts","../src/mocks/aRequestContext.ts","../src/mocks/aRelationMeta.ts","../src/mocks/index.ts"],"sourcesContent":["import type { QueryResult } from '@danceroutine/tango-orm/query';\nimport { QueryResult as QueryResultClass } from '@danceroutine/tango-orm/query';\n\nexport type AQueryResultOverrides<TModel> = {\n items?: readonly TModel[];\n results?: readonly TModel[];\n};\n\n/**\n * Create a query-result test value with optional overrides.\n */\nexport function aQueryResult<TModel>(overrides: AQueryResultOverrides<TModel> = {}): QueryResult<TModel> {\n const items = overrides.items ?? overrides.results ?? ([] as TModel[]);\n return new QueryResultClass(items);\n}\n","import { vi } from 'vitest';\nimport type { Adapter, QueryExecutor } from '@danceroutine/tango-orm';\nimport type { Dialect, TableMeta } from '@danceroutine/tango-orm/query';\nimport { anAdapter } from './anAdapter';\nimport { aDBClient } from './aDBClient';\n\nexport type QueryExecutorOverrides<TModel extends Record<string, unknown>> = {\n dialect?: Dialect;\n adapter?: Adapter;\n meta?: TableMeta;\n query?: (sql: string, params?: readonly unknown[]) => Promise<{ rows: unknown[] }>;\n run?: QueryExecutor<TModel>['run'];\n attachPersistedRecordAccessors?: QueryExecutor<TModel>['attachPersistedRecordAccessors'];\n};\n\n/**\n * Create a minimal `QueryExecutor` test double for `QuerySet` tests.\n */\nexport function aQueryExecutor<TModel extends Record<string, unknown>>(\n overrides: QueryExecutorOverrides<TModel> = {}\n): QueryExecutor<TModel> {\n const adapter = overrides.adapter ?? anAdapter({ dialect: overrides.dialect ?? 'postgres' });\n const meta: TableMeta = overrides.meta ?? { table: 'mock_table', pk: 'id', columns: {} };\n const run = overrides.run ?? vi.fn(async () => [] as TModel[]);\n const client = aDBClient(overrides.query ? { query: overrides.query } : {});\n\n return {\n meta,\n client,\n adapter,\n run,\n ...(overrides.attachPersistedRecordAccessors\n ? { attachPersistedRecordAccessors: overrides.attachPersistedRecordAccessors }\n : {}),\n };\n}\n","import { vi } from 'vitest';\nimport type { QuerySet } from '@danceroutine/tango-orm';\nimport { ModelQuerySet as QuerySetClass } from '@danceroutine/tango-orm';\nimport { aQueryResult } from './aQueryResult';\nimport { aQueryExecutor } from './aQueryExecutor';\n\n/**\n * Create a chainable model-queryset test double with optional behavior overrides.\n *\n * All methods are wrapped in `vi.fn()` so they can be asserted on directly\n * without an additional `vi.mocked()` call.\n */\nexport function aModelQuerySet<\n TModel extends Record<string, unknown>,\n TResult extends Record<string, unknown> = TModel,\n>(overrides: Partial<QuerySet<TModel, TResult>> = {}): QuerySet<TModel, TResult> {\n const queryset = new QuerySetClass<TModel, TResult>(aQueryExecutor<TModel>());\n const filterImpl: QuerySet<TModel, TResult>['filter'] = overrides.filter ?? ((_input) => queryset);\n const excludeImpl: QuerySet<TModel, TResult>['exclude'] = overrides.exclude ?? ((_input) => queryset);\n const orderByImpl: QuerySet<TModel, TResult>['orderBy'] = overrides.orderBy ?? ((..._tokens) => queryset);\n const limitImpl: QuerySet<TModel, TResult>['limit'] = overrides.limit ?? ((_n) => queryset);\n const offsetImpl: QuerySet<TModel, TResult>['offset'] = overrides.offset ?? ((_n) => queryset);\n const defaultSelect = ((_cols: readonly (keyof TModel)[]) => queryset) as unknown as QuerySet<\n TModel,\n TResult\n >['select'];\n const selectImpl = overrides.select ?? defaultSelect;\n const selectRelatedImpl =\n (overrides.selectRelated as ((...rels: readonly string[]) => QuerySet<TModel, TResult>) | undefined) ??\n ((..._rels: readonly string[]) => queryset);\n const prefetchRelatedImpl =\n (overrides.prefetchRelated as ((...rels: readonly string[]) => QuerySet<TModel, TResult>) | undefined) ??\n ((..._rels: readonly string[]) => queryset);\n const fetchImpl: QuerySet<TModel, TResult>['fetch'] =\n overrides.fetch ??\n (async <Out = TResult>(_shape?: ((r: TResult) => Out) | { parse: (r: TResult) => Out }) => aQueryResult<Out>());\n const fetchOneImpl: QuerySet<TModel, TResult>['fetchOne'] =\n overrides.fetchOne ??\n (async <Out = TResult>(_shape?: ((r: TResult) => Out) | { parse: (r: TResult) => Out }) => null as Out | null);\n const countImpl: QuerySet<TModel, TResult>['count'] = overrides.count ?? (async () => 0);\n const existsImpl: QuerySet<TModel, TResult>['exists'] = overrides.exists ?? (async () => false);\n\n queryset.filter = vi.fn((input: Parameters<QuerySet<TModel, TResult>['filter']>[0]) =>\n filterImpl(input)\n ) as QuerySet<TModel, TResult>['filter'];\n queryset.exclude = vi.fn((input: Parameters<QuerySet<TModel, TResult>['exclude']>[0]) =>\n excludeImpl(input)\n ) as QuerySet<TModel, TResult>['exclude'];\n queryset.orderBy = vi.fn((...tokens: Parameters<QuerySet<TModel, TResult>['orderBy']>) =>\n orderByImpl(...tokens)\n ) as QuerySet<TModel, TResult>['orderBy'];\n queryset.limit = vi.fn((n: number) => limitImpl(n)) as QuerySet<TModel, TResult>['limit'];\n queryset.offset = vi.fn((n: number) => offsetImpl(n)) as QuerySet<TModel, TResult>['offset'];\n queryset.select = vi.fn((cols: Parameters<QuerySet<TModel, TResult>['select']>[0]) =>\n selectImpl(cols)\n ) as unknown as QuerySet<TModel, TResult>['select'];\n queryset.selectRelated = vi.fn((...rels: readonly string[]) => selectRelatedImpl(...rels)) as unknown as QuerySet<\n TModel,\n TResult\n >['selectRelated'];\n queryset.prefetchRelated = vi.fn((...rels: readonly string[]) =>\n prefetchRelatedImpl(...rels)\n ) as unknown as QuerySet<TModel, TResult>['prefetchRelated'];\n queryset.fetch = vi.fn(fetchImpl) as unknown as QuerySet<TModel, TResult>['fetch'];\n queryset.fetchOne = vi.fn(fetchOneImpl) as unknown as QuerySet<TModel, TResult>['fetchOne'];\n queryset.count = vi.fn(() => countImpl()) as QuerySet<TModel, TResult>['count'];\n queryset.exists = vi.fn(() => existsImpl()) as QuerySet<TModel, TResult>['exists'];\n\n return queryset;\n}\n","import { vi } from 'vitest';\nimport type { ManagerLike, QuerySet } from '@danceroutine/tango-orm';\nimport type { TableMeta } from '@danceroutine/tango-orm/query';\nimport { aModelQuerySet } from './aModelQuerySet';\n\nexport type ManagerOverrides<TModel extends Record<string, unknown>> = {\n meta?: TableMeta;\n querySet?: QuerySet<TModel>;\n query?: ManagerLike<TModel>['query'];\n all?: ManagerLike<TModel>['all'];\n getOrCreate?: ManagerLike<TModel>['getOrCreate'];\n updateOrCreate?: ManagerLike<TModel>['updateOrCreate'];\n findById?: ManagerLike<TModel>['findById'];\n getOrThrow?: ManagerLike<TModel>['getOrThrow'];\n create?: ManagerLike<TModel>['create'];\n update?: ManagerLike<TModel>['update'];\n delete?: ManagerLike<TModel>['delete'];\n bulkCreate?: ManagerLike<TModel>['bulkCreate'];\n};\n\n/**\n * Create a manager-shaped test double for resource and service tests.\n */\nexport function aManager<TModel extends Record<string, unknown>>(\n overrides: ManagerOverrides<TModel> = {}\n): ManagerLike<TModel> {\n const meta = overrides.meta ?? { table: 'mock_table', pk: 'id', columns: {} };\n const querySet = overrides.querySet ?? aModelQuerySet<TModel>();\n type ModelId = TModel[keyof TModel];\n\n const queryImpl = overrides.query ?? (() => querySet);\n const allImpl = overrides.all ?? (() => queryImpl());\n const findByIdImpl = overrides.findById ?? (async () => null as TModel | null);\n const getOrThrowImpl =\n overrides.getOrThrow ??\n (async (id: ModelId) => {\n const record = await findByIdImpl(id);\n if (!record) {\n throw new Error(`No ${meta.table} record found for ${String(meta.pk)}=${String(id)}.`);\n }\n return record;\n });\n const createImpl = overrides.create ?? (async (input: Partial<TModel>) => input as TModel);\n const updateImpl = overrides.update ?? (async (_id: ModelId, patch: Partial<TModel>) => patch as TModel);\n const deleteImpl = overrides.delete ?? (async (_id: ModelId) => {});\n const bulkCreateImpl = overrides.bulkCreate ?? (async (inputs: Partial<TModel>[]) => inputs as TModel[]);\n const getOrCreateImpl =\n overrides.getOrCreate ??\n (async ({ defaults }: Parameters<ManagerLike<TModel>['getOrCreate']>[0]) => ({\n record: { ...defaults } as TModel,\n created: true,\n }));\n const updateOrCreateImpl =\n overrides.updateOrCreate ??\n (async ({ defaults }: Parameters<ManagerLike<TModel>['updateOrCreate']>[0]) => ({\n record: { ...defaults } as TModel,\n created: true,\n updated: false,\n }));\n\n return {\n meta,\n query: vi.fn(() => queryImpl()),\n all: vi.fn(() => allImpl()),\n getOrCreate: vi.fn((args: Parameters<ManagerLike<TModel>['getOrCreate']>[0]) => getOrCreateImpl(args)),\n updateOrCreate: vi.fn((args: Parameters<ManagerLike<TModel>['updateOrCreate']>[0]) => updateOrCreateImpl(args)),\n findById: vi.fn((id: ModelId) => findByIdImpl(id)),\n getOrThrow: vi.fn((id: ModelId) => getOrThrowImpl(id)),\n create: vi.fn((input: Partial<TModel>) => createImpl(input)),\n update: vi.fn((id: ModelId, patch: Partial<TModel>) => updateImpl(id, patch)),\n delete: vi.fn((id: ModelId) => deleteImpl(id)),\n bulkCreate: vi.fn((inputs: Partial<TModel>[]) => bulkCreateImpl(inputs)),\n };\n}\n","import { vi } from 'vitest';\nimport type { QueryExecutor } from '@danceroutine/tango-orm';\nimport { ManyToManyRelatedManager } from '@danceroutine/tango-orm';\n\ntype ManagerConstructorInputs = ConstructorParameters<typeof ManyToManyRelatedManager>[0];\n\n/**\n * Overrides accepted by the {@link aManyToManyRelatedManager} fixture. All\n * fields are optional; defaults produce a manager bound to owner primary key\n * `7`, relation name `'tags'`, owner label `'Post'`, and target primary-key\n * field `'id'`.\n */\nexport interface ManyToManyRelatedManagerFixtureOverrides<TTarget extends Record<string, unknown>> {\n ownerPrimaryKey?: unknown;\n relationName?: string;\n ownerModelLabel?: string;\n targetPrimaryKeyField?: string;\n /**\n * Resolver returned by the manager's `targetExecutorProvider`. Pass `null`\n * to simulate the registry not yet knowing about the target model; omit to\n * return a minimal executor stub.\n */\n targetExecutor?: QueryExecutor<TTarget> | null;\n insertLink?: (ownerPrimaryKey: unknown, targetPrimaryKey: unknown) => Promise<void>;\n insertLinks?: (ownerPrimaryKey: unknown, targetPrimaryKeys: readonly unknown[]) => Promise<void>;\n deleteLink?: (ownerPrimaryKey: unknown, targetPrimaryKey: unknown) => Promise<void>;\n deleteLinks?: (ownerPrimaryKey: unknown, targetPrimaryKeys: readonly unknown[]) => Promise<void>;\n deleteAllLinksForOwner?: (ownerPrimaryKey: unknown) => Promise<void>;\n selectTargetIdsForOwner?: (ownerPrimaryKey: unknown) => Promise<readonly (string | number)[]>;\n createTarget?: (input: Partial<TTarget>) => Promise<TTarget>;\n runAtomic?: <T>(work: () => Promise<T>) => Promise<T>;\n}\n\n/**\n * Return shape of the {@link aManyToManyRelatedManager} fixture. The spy\n * references are returned alongside the manager so tests can assert against\n * the join-table calls without reaching into private fields.\n */\nexport interface ManyToManyRelatedManagerFixture<TTarget extends Record<string, unknown>> {\n manager: ManyToManyRelatedManager<TTarget>;\n insertLink: ReturnType<typeof vi.fn>;\n insertLinks: ReturnType<typeof vi.fn>;\n deleteLink: ReturnType<typeof vi.fn>;\n deleteLinks: ReturnType<typeof vi.fn>;\n deleteAllLinksForOwner: ReturnType<typeof vi.fn>;\n selectTargetIdsForOwner: ReturnType<typeof vi.fn>;\n createTarget: ReturnType<typeof vi.fn>;\n runAtomic: ReturnType<typeof vi.fn>;\n}\n\n/**\n * Build a {@link ManyToManyRelatedManager} instance wired to lightweight spies\n * for its underlying join-table operations. The fixture skips the\n * relation-metadata and registry plumbing exercised by `ModelManager`, so\n * tests can focus on manager behavior in isolation.\n */\nexport function aManyToManyRelatedManager<TTarget extends Record<string, unknown>>(\n overrides: ManyToManyRelatedManagerFixtureOverrides<TTarget> = {}\n): ManyToManyRelatedManagerFixture<TTarget> {\n const insertLink = vi.fn(overrides.insertLink ?? (async () => {}));\n const insertLinks = vi.fn(overrides.insertLinks ?? (async () => {}));\n const deleteLink = vi.fn(overrides.deleteLink ?? (async () => {}));\n const deleteLinks = vi.fn(overrides.deleteLinks ?? (async () => {}));\n const deleteAllLinksForOwner = vi.fn(overrides.deleteAllLinksForOwner ?? (async () => {}));\n const selectTargetIdsForOwner = vi.fn(\n overrides.selectTargetIdsForOwner ?? (async (): Promise<readonly (string | number)[]> => [])\n );\n const createTarget = vi.fn(\n overrides.createTarget ??\n (async (input: Partial<TTarget>) => {\n return input as TTarget;\n })\n );\n const runAtomicImpl: ManagerConstructorInputs['runAtomic'] =\n overrides.runAtomic ?? (async <T>(work: () => Promise<T>) => work());\n const runAtomicSpy = vi.fn(async <T>(work: () => Promise<T>) => runAtomicImpl(work));\n\n const throughTableManager = {\n insertLink,\n insertLinks,\n deleteLink,\n deleteLinks,\n deleteAllLinksForOwner,\n selectTargetIdsForOwner,\n } as unknown as ManagerConstructorInputs['throughTableManager'];\n\n const manager = new ManyToManyRelatedManager<TTarget>({\n ownerPrimaryKey: overrides.ownerPrimaryKey ?? 7,\n relationName: overrides.relationName ?? 'tags',\n ownerModelLabel: overrides.ownerModelLabel ?? 'Post',\n targetPrimaryKeyField: overrides.targetPrimaryKeyField ?? 'id',\n throughTableManager,\n targetExecutorProvider: () =>\n overrides.targetExecutor === undefined ? ({} as QueryExecutor<TTarget>) : overrides.targetExecutor,\n createTarget,\n runAtomic: runAtomicSpy as ManagerConstructorInputs['runAtomic'],\n });\n\n return {\n manager,\n insertLink,\n insertLinks,\n deleteLink,\n deleteLinks,\n deleteAllLinksForOwner,\n selectTargetIdsForOwner,\n createTarget,\n runAtomic: runAtomicSpy,\n };\n}\n","import { getLogger } from '@danceroutine/tango-core';\nimport type { QuerySet } from '@danceroutine/tango-orm';\nimport { aModelQuerySet } from './aModelQuerySet';\n\nconst logger = getLogger('tango.testing.mocks');\n// TODO this pattern keeps showing up, perhaps we should implement logger.warnOnce\nlet hasWarned = false;\n\n/**\n * @deprecated Use `aModelQuerySet(...)` instead.\n */\nexport function aQuerySet<TModel extends Record<string, unknown>, TResult extends Record<string, unknown> = TModel>(\n overrides: Partial<QuerySet<TModel, TResult>> = {}\n): QuerySet<TModel, TResult> {\n if (!hasWarned) {\n hasWarned = true;\n logger.warn('`aQuerySet(...)` is deprecated. Use `aModelQuerySet(...)` instead.');\n }\n\n return aModelQuerySet(overrides);\n}\n","// Import through the package subpath so fixtures stay aligned with the public nominal type.\nimport { RequestContext, type BaseUser } from '@danceroutine/tango-resources/context';\n\ntype RequestContextFactory<TUser, TContext extends RequestContextLike<TUser>> = (\n request: Request,\n user: TUser | null\n) => TContext;\n\ntype RequestContextLike<TUser> = {\n request: Request;\n user: TUser | null;\n params: Record<string, string>;\n};\n\nexport type RequestContextFixtureOptions<\n TUser = BaseUser,\n TContext extends RequestContextLike<TUser> = RequestContext<TUser>,\n> = {\n method?: string;\n url?: string;\n body?: unknown;\n user?: TUser | null;\n params?: Record<string, string>;\n headers?: HeadersInit;\n contextFactory?: RequestContextFactory<TUser, TContext>;\n};\n\n/**\n * Create a RequestContext fixture with optional method/url/body/user/params.\n */\nexport function aRequestContext<TUser = BaseUser, TContext extends RequestContextLike<TUser> = RequestContext<TUser>>(\n method: string,\n url: string,\n body?: unknown\n): TContext;\nexport function aRequestContext<TUser = BaseUser, TContext extends RequestContextLike<TUser> = RequestContext<TUser>>(\n options?: RequestContextFixtureOptions<TUser, TContext>\n): TContext;\nexport function aRequestContext<TUser = BaseUser, TContext extends RequestContextLike<TUser> = RequestContext<TUser>>(\n optionsOrMethod: RequestContextFixtureOptions<TUser, TContext> | string = {},\n urlArg?: string,\n bodyArg?: unknown\n): TContext {\n const resolvedOptions: RequestContextFixtureOptions<TUser, TContext> =\n typeof optionsOrMethod === 'string'\n ? {\n method: optionsOrMethod,\n url: urlArg,\n body: bodyArg,\n }\n : optionsOrMethod;\n const {\n method = 'GET',\n url = 'https://example.test',\n body,\n user = null,\n params = {},\n headers,\n contextFactory,\n } = resolvedOptions;\n\n const resolvedHeaders: HeadersInit | undefined =\n body === undefined ? headers : { 'content-type': 'application/json', ...headers };\n\n const request = new Request(url, {\n method,\n headers: resolvedHeaders,\n body: body === undefined ? undefined : JSON.stringify(body),\n });\n const createContext =\n contextFactory ?? ((req: Request, currentUser: TUser | null) => RequestContext.create<TUser>(req, currentUser));\n const context = createContext(request, user) as TContext;\n context.params = params;\n return context;\n}\n","import type { RelationMeta, TableMeta } from '@danceroutine/tango-orm/query';\n\ntype RelationMetaInput = {\n kind: RelationMeta['kind'];\n table: string;\n sourceKey: string;\n targetKey: string;\n targetColumns: Record<string, string>;\n alias: string;\n edgeId?: string;\n sourceModelKey?: string;\n targetModelKey?: string;\n targetPrimaryKey?: string;\n targetMeta?: TableMeta;\n capabilities?: Partial<RelationMeta['capabilities']>;\n};\n\n/**\n * Build recursive relation metadata fixtures for planner/compiler/query tests.\n */\nexport function aRelationMeta(input: RelationMetaInput): RelationMeta {\n const cardinality = input.kind === 'belongsTo' || input.kind === 'hasOne' ? 'single' : 'many';\n const defaultHydratable = input.kind !== ('manyToMany' as RelationMeta['kind']);\n\n const targetMeta =\n input.targetMeta ??\n ({\n modelKey: input.targetModelKey ?? `${input.alias}:target`,\n table: input.table,\n pk: input.targetPrimaryKey ?? 'id',\n columns: input.targetColumns,\n } satisfies TableMeta);\n\n return {\n edgeId: input.edgeId ?? `${input.alias}:${input.sourceKey}:${input.targetKey}`,\n sourceModelKey: input.sourceModelKey ?? `${input.alias}:source`,\n targetModelKey: input.targetModelKey ?? `${input.alias}:target`,\n kind: input.kind,\n cardinality,\n capabilities: {\n queryable: true,\n hydratable: defaultHydratable,\n joinable: cardinality === 'single' && defaultHydratable,\n prefetchable: defaultHydratable,\n ...input.capabilities,\n },\n table: input.table,\n sourceKey: input.sourceKey,\n targetKey: input.targetKey,\n targetPrimaryKey: input.targetPrimaryKey ?? 'id',\n targetColumns: input.targetColumns,\n alias: input.alias,\n targetMeta,\n };\n}\n","/**\n * Domain boundary barrel: centralizes this subdomain's public contract.\n */\n\nexport { anAdapter } from './anAdapter';\nexport { aDBClient } from './aDBClient';\nexport { aManager } from './aManager';\nexport { aManyToManyRelatedManager } from './aManyToManyRelatedManager';\nexport { aModelQuerySet } from './aModelQuerySet';\nexport { aQueryResult } from './aQueryResult';\nexport { aQuerySet } from './aQuerySet';\nexport { aRequestContext } from './aRequestContext';\nexport { aQueryExecutor } from './aQueryExecutor';\nexport { aRelationMeta } from './aRelationMeta';\nexport type { AdapterOverrides } from './anAdapter';\nexport type { QueryExecutorOverrides } from './aQueryExecutor';\nexport type { ManagerOverrides } from './aManager';\nexport type {\n ManyToManyRelatedManagerFixture,\n ManyToManyRelatedManagerFixtureOverrides,\n} from './aManyToManyRelatedManager';\nexport type { DBClient } from './DBClient';\nexport type { MockQuerySetResult } from './MockQuerySetResult';\nexport type { RequestContextFixtureOptions } from './aRequestContext';\n"],"mappings":"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"}