import { Entity, ValueObject } from "../core/index.js"; /** * Type of collection relationship. * - 'owned': Parent owns the children (1:N). Delete parent = delete children. * - 'reference': Parent references existing entities (N:N). Delete parent = unlink only. */ export type CollectionType = "owned" | "reference"; /** * Configuration for a collection (1:N or N:N relationship). */ export interface CollectionConfig { /** * Type of relationship. * - 'owned': Children are created/deleted with the parent (default for 1:N) * - 'reference': Only the link is created/removed (for N:N) * @default 'owned' */ type: CollectionType; /** * Target entity name (required for 'reference' type). * @example 'Tag' */ entity?: string; /** * ORM relation field name when it differs from the domain property name. * Used by ORM adapters for connect/disconnect operations. * If not provided, the domain property name (the key in `collections`) is used. * @example * // Domain property: "tags", Prisma field: "user_tags" * collections: { * tags: { type: 'reference', entity: 'Tag', relationName: 'user_tags' } * } */ relationName?: string; /** * Junction table configuration (optional, for ORMs that need it like Drizzle). * Prisma handles this automatically, so it's optional. */ junction?: { /** Junction table name (e.g., 'post_tags', '_PostToTag') */ table: string; /** FK field pointing to the source entity (e.g., 'post_id') */ sourceKey: string; /** FK field pointing to the target entity (e.g., 'tag_id') */ targetKey: string; }; } /** * Mapping schema for a domain entity. */ export interface EntitySchema { /** Entity name in the domain (e.g., 'User', 'Post') */ entity: string; /** Table name in the database (e.g., 'users', 'blog_posts') */ table: string; /** * Field mapping: domain → database. * Only include fields with different names. * @example { email: 'user_email', createdAt: 'created_at' } */ fields?: Record; /** * FK configuration for parent relation (1:N owned). */ parentFk?: { /** Name of the FK field in the database (e.g., 'author_id') */ field: string; /** Name of the parent entity (e.g., 'User') */ parentEntity: string; }; /** * Collection configurations for this entity's relations. * Key is the property name in the domain entity. * @example * ```typescript * collections: { * comments: { type: 'owned' }, * tags: { type: 'reference', entity: 'Tag' } * } * ``` */ collections?: Record; /** * Database primary key **column** name (persistence layer only). * Defaults to `'id'` when omitted. * * This does **not** refer to a domain property. Adapters always take the * identity value from `entity.id` and write/query it under this column name. * For example, `primaryKey: "otherKeyToPk"` produces * `where: { otherKeyToPk: entity.id.value }`, not `{ otherKeyToPk: entity.factoryId }`. * * For 1:1 child tables that share the parent's PK (e.g. `factoryProfile.otherKeyToPk`), * set `Profile.id` to the same value as the parent aggregate (`Factory.id`). * * @example * ```typescript * .register({ * entity: "Profile", * table: "factoryProfile", * primaryKey: "otherKeyToPk" * }) * // Domain: profile.id.value === factory.id.value * // DB update: WHERE otherKeyToPk = profile.id.value * ``` */ primaryKey?: string; } /** * Result of entity mapping. */ export interface MappedEntityData { [key: string]: any; } /** * Registry for mapping domain entities to database tables and fields. * * @example * ```typescript * const registry = new EntitySchemaRegistry() * .register({ * entity: 'User', * table: 'users', * fields: { email: 'user_email', name: 'user_name' }, * }) * .register({ * entity: 'Post', * table: 'blog_posts', * fields: { content: 'post_content' }, * parentFk: { field: 'author_id', parentEntity: 'User' }, * collections: { * comments: { type: 'owned' }, * tags: { type: 'reference', entity: 'Tag' } * } * }); * * const table = registry.getTable('Post'); // 'blog_posts' * const tagConfig = registry.getCollectionConfig('Post', 'tags'); * // { type: 'reference', entity: 'Tag' } * ``` */ export declare class EntitySchemaRegistry { private schemas; /** * Registers an entity schema. * @param schema - Schema to be registered. * @returns this (for chaining) */ register(schema: EntitySchema): this; /** * Registers multiple schemas at once. * @param schemas - Array of schemas. * @returns this (for chaining) */ registerAll(schemas: EntitySchema[]): this; /** * Gets the schema of an entity. * @param entity - Entity name. * @throws Error if the entity is not registered. */ getSchema(entity: string): EntitySchema; /** * Gets all registered schemas. */ getAllSchemas(): EntitySchema[]; /** * Tries to get the schema of an entity, returns null if not found. * @param entity - Entity name. */ tryGetSchema(entity: string): EntitySchema | null; /** * Checks if an entity is registered. * @param entity - Entity name. */ has(entity: string): boolean; /** * Gets the table name for an entity. * @param entity - Entity name. */ getTable(entity: string): string; /** * Gets the field mapping for an entity. * @param entity - Entity name. */ getFieldsMap(entity: string): Record; /** * Gets the database primary key column name for an entity. * @param entity - Entity name. * @returns Primary key column name (defaults to `'id'`) */ getPrimaryKeyField(entity: string): string; /** * Builds a Prisma/ORM where clause for a single record by domain ID. * @param entity - Entity name. * @param id - Domain entity ID value. */ buildWhereById(entity: string, id: string): Record; /** * Builds a Prisma/ORM where clause for multiple records by domain IDs. * @param entity - Entity name. * @param ids - Domain entity ID values. */ buildWhereByIds(entity: string, ids: string[]): Record; /** * Maps a domain field name to the database field name. * @param entity - Entity name. * @param fieldName - Domain field name. */ mapFieldName(entity: string, fieldName: string): string; /** * Maps fields of a domain object to database field names. * Ignores Entity, ValueObject, and entity collections. * Primitive arrays (e.g. `photoIds: string[]`) are persisted as scalar columns. * * @param entity - Entity name. * @param data - Data to be mapped. */ mapFields(entity: string, data: Record): MappedEntityData; /** * Maps a complete domain entity to database data. * Used for CREATE operations. * * @param entity - Entity name. * @param domainEntity - Domain entity instance. */ mapEntity(entity: string, domainEntity: Entity | ValueObject): MappedEntityData; /** * Gets the FK object to relate with the parent. * * @param entity - Entity name. * @param parentId - Parent ID. * @returns Object with the FK field or null if there is no parent. */ getParentFk(entity: string, parentId: string): Record | null; /** * Gets the name of the parent entity. * @param entity - Entity name. */ getParentEntity(entity: string): string | null; /** * Gets the FK field name. * @param entity - Entity name. */ getParentFkField(entity: string): string | null; /** * Gets the collection configuration for a specific field. * * @param entity - Parent entity name (e.g., 'Post') * @param fieldName - Collection field name (e.g., 'tags') * @returns CollectionConfig or null if not configured * * @example * ```typescript * const config = registry.getCollectionConfig('Post', 'tags'); * if (config?.type === 'reference') { * // Handle N:N relation - use connect/disconnect * } else { * // Handle 1:N relation - use create/delete * } * ``` */ getCollectionConfig(entity: string, fieldName: string): CollectionConfig | null; /** * Checks if a collection is a reference type (N:N). * * @param entity - Parent entity name * @param fieldName - Collection field name * @returns true if the collection is a reference (N:N), false otherwise * * @example * ```typescript * if (registry.isReferenceCollection('Post', 'tags')) { * // Use connect/disconnect instead of create/delete * } * ``` */ isReferenceCollection(entity: string, fieldName: string): boolean; /** * Checks if a collection is owned (1:N). * Returns true if explicitly configured as 'owned' or if not configured at all. * * @param entity - Parent entity name * @param fieldName - Collection field name * @returns true if the collection is owned (1:N), false if reference */ isOwnedCollection(entity: string, fieldName: string): boolean; /** * Gets all collections configured for an entity. * * @param entity - Entity name * @returns Record of field names to collection configs, or empty object */ getCollections(entity: string): Record; /** * Gets all reference (N:N) collections for an entity. * * @param entity - Entity name * @returns Array of field names that are reference collections */ getReferenceCollections(entity: string): string[]; /** * Gets the junction table configuration for a reference collection. * * @param entity - Parent entity name * @param fieldName - Collection field name * @returns Junction config or null */ getJunctionConfig(entity: string, fieldName: string): CollectionConfig["junction"] | null; /** * Resolves the ORM relation field name for a collection. * Returns `relationName` if configured, otherwise falls back to the domain field name. * * @param entity - Parent entity name * @param domainFieldName - Domain property name (e.g., 'tags') * @returns The field name to use in ORM operations */ getRelationFieldName(entity: string, domainFieldName: string): string; /** * Lists all registered entities. */ getRegisteredEntities(): string[]; /** * Clears all registered schemas. */ clear(): void; /** * Skips values that must not be written as scalar columns during partial updates. * `changedFields` only carries primitive arrays for scalar columns. */ private shouldSkipPartialFieldValue; /** * Skips nested relations and entity collections during full entity mapping. */ private shouldSkipEntityFieldValue; private isNestedDomainValue; private isPrimitiveValue; private isPrimitiveArray; /** * Normalizes a value for persistence. */ private normalizeValue; /** * Validates that a relation field exists in the entity's collections. * * @param entity - Parent entity name * @param relationField - Relation field to validate * @throws ConfigurationError if the field doesn't exist * */ validateRelationField(entity: string, relationField: string): void; private findSimilarNames; } //# sourceMappingURL=entity-schema-registry.d.ts.map