@datrix/core 0.1.0 → 0.1.1

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.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/types/core/config.ts","../src/types/errors/datrix-error.ts","../src/types/errors/adapter/adapter-error.ts","../src/types/errors/adapter/adapter-helpers.ts","../src/types/errors/api/auth.ts","../src/types/errors/api/parser.ts","../src/types/errors/core/config.ts","../src/types/errors/core/crud.ts","../src/types/errors/core/query-builder.ts","../src/types/errors/core/validation.ts","../src/query-builder/error-helper.ts","../src/query-builder/where.ts","../src/query-builder/select.ts","../src/query-builder/populate.ts","../src/query-builder/data.ts","../src/query-builder/orderby.ts","../src/query-builder/builder.ts","../src/types/core/schema.ts","../src/validator/errors.ts","../src/validator/field-validator.ts","../src/validator/schema-validator.ts","../src/query-executor/error-helper.ts","../src/query-executor/validation.ts","../src/query-executor/relations.ts","../src/query-executor/executor.ts","../src/mixins/crud.ts","../src/plugin/schema-extension-context.ts","../src/types/utils/query.ts","../src/dispatcher/hook-errors.ts","../src/dispatcher/index.ts","../src/types/core/plugin.ts","../src/types/core/constants.ts","../src/schema/registry.ts","../src/migration/schema.ts","../src/types/core/migration.ts","../src/migration/differ.ts","../src/migration/generator.ts","../src/migration/history.ts","../src/migration/runner.ts","../src/migration/session.ts","../src/datrix.ts","../src/types/core/permission.ts","../src/types/adapter/index.ts","../src/types/api/parser.ts","../src/types/api/upload.ts","../src/types/api/config.ts","../src/types/cli/index.ts","../src/plugin/plugin.ts"],"sourcesContent":["/**\n * Core Module\n *\n * Exports all core functionality: Datrix singleton, schema, validation, query building, migrations, and configuration.\n */\n\n// Re-export Datrix singleton (main entry point)\nexport { Datrix, defineConfig } from \"./datrix\";\nexport type { DatrixInitOptions, ConfigFactory } from \"./datrix\";\n\nexport * from \"./types/core\";\nexport * from \"./types/adapter\";\nexport * from \"./types/api\";\nexport * from \"./types/cli\";\nexport * from \"./types/errors\";\nexport * from \"./types/utils\";\nexport * from \"./plugin/plugin\";\nexport * from \"./migration\";\n","/**\n * Core Configuration Types\n *\n * Datrix framework configuration types used in datrix.config.ts files.\n */\n\nimport type { DatabaseAdapter } from \"../adapter\";\nimport type { DatrixPlugin } from \"./plugin\";\nimport type { SchemaDefinition } from \"./schema\";\n\n/**\n * Main Datrix Configuration\n *\n * Users export this from their datrix.config.ts file\n *\n * @example\n * ```ts\n * // datrix.config.ts\n * import { PostgresAdapter } from 'datrix/adapters';\n * import { AuthPlugin } from 'datrix/plugins';\n *\n * export default {\n * adapter: new PostgresAdapter({ connectionString: process.env.DATABASE_URL! }),\n * schemas: { path: './schemas/**\\/*.schema.ts' },\n * plugins: [new AuthPlugin({ ... })],\n * } as const;\n * ```\n */\nexport interface DatrixConfig<\n\tTAdapter extends DatabaseAdapter = DatabaseAdapter,\n> {\n\t/**\n\t * Database adapter instance\n\t * Must be an initialized adapter (PostgresAdapter, MySQLAdapter, etc.)\n\t */\n\treadonly adapter: TAdapter;\n\n\t/**\n\t * Schema definitions\n\t * Import your schemas and add them to this array\n\t *\n\t * @example\n\t * ```ts\n\t * import { userSchema } from './schemas/user.schema';\n\t * import { postSchema } from './schemas/post.schema';\n\t *\n\t * export default {\n\t * schemas: [userSchema, postSchema],\n\t * }\n\t * ```\n\t */\n\treadonly schemas: readonly SchemaDefinition[];\n\n\t/**\n\t * Plugin instances (optional)\n\t * Order matters - plugins are initialized in the order they appear\n\t */\n\treadonly plugins?: readonly DatrixPlugin[];\n\n\t/**\n\t * Migration configuration (optional)\n\t * Controls database migration behavior\n\t */\n\treadonly migration?: MigrationConfig;\n\n\t/**\n\t * Development mode options (optional)\n\t * Enables additional debugging and validation features\n\t */\n\treadonly dev?: DevConfig;\n}\n\n/**\n * Migration Configuration\n */\nexport interface MigrationConfig {\n\t/**\n\t * Automatically run migrations on startup\n\t * @default false (true in development)\n\t */\n\treadonly auto?: boolean;\n\n\t/**\n\t * Directory to store migration files\n\t * @default './migrations'\n\t */\n\treadonly directory?: string;\n\n\t/**\n\t * Table name for storing migration history\n\t * @default '_datrix_migrations'\n\t */\n\treadonly modelName?: string;\n}\n\n/**\n * Development Configuration\n */\nexport interface DevConfig {\n\t/**\n\t * Enable detailed query logging\n\t * @default false (true in development)\n\t */\n\treadonly logging?: boolean;\n\n\t/**\n\t * Validate all queries before execution\n\t * @default false (true in development)\n\t */\n\treadonly validateQueries?: boolean;\n\n\t/**\n\t * Pretty-print errors with stack traces\n\t * @default false (true in development)\n\t */\n\treadonly prettyErrors?: boolean;\n}\n\n/**\n * Config file export format\n *\n * Supports both ESM default export and direct export\n */\nexport type ConfigFileExport<T extends DatrixConfig = DatrixConfig> =\n\t| T\n\t| { default: T };\n\n/**\n * Config loading options\n */\nexport interface LoadConfigOptions {\n\t/**\n\t * Path to config file\n\t * @default './datrix.config.ts' (with fallback to .js)\n\t */\n\treadonly configPath?: string;\n\n\t/**\n\t * Environment name\n\t * Used to load environment-specific config files\n\t * @default process.env.NODE_ENV ?? 'development'\n\t */\n\treadonly environment?: \"development\" | \"production\" | \"test\";\n\n\t/**\n\t * Current working directory\n\t * @default process.cwd()\n\t */\n\treadonly cwd?: string;\n}\n\n/**\n * Type guard for DatrixConfig\n */\nexport function isDatrixConfig(value: unknown): value is DatrixConfig {\n\tif (typeof value !== \"object\" || value === null) {\n\t\treturn false;\n\t}\n\n\tconst obj = value as Record<string, unknown>;\n\n\treturn (\n\t\t\"adapter\" in obj &&\n\t\ttypeof obj[\"adapter\"] === \"object\" &&\n\t\t\"schemas\" in obj &&\n\t\ttypeof obj[\"schemas\"] === \"object\"\n\t);\n}\n\n/**\n * Type guard for ESM default export\n */\nexport function hasDefaultExport<T>(value: unknown): value is { default: T } {\n\treturn typeof value === \"object\" && value !== null && \"default\" in value;\n}\n\n/**\n * Default migration configuration values\n */\nexport const DEFAULT_MIGRATION_CONFIG: Required<MigrationConfig> = {\n\tauto: false,\n\tdirectory: \"./migrations\",\n\tmodelName: \"_datrix_migration\",\n} as const;\n\n/**\n * Default dev configuration values\n */\nexport const DEFAULT_DEV_CONFIG: Required<DevConfig> = {\n\tlogging: false,\n\tvalidateQueries: false,\n\tprettyErrors: false,\n} as const;\n","/**\n * Base Datrix Error Class\n *\n * All Datrix errors extend this class OR use it directly.\n * Provides standard error structure across the framework.\n *\n * ## Usage Guidelines\n *\n * ### Option 1: Direct Usage (Simple Errors)\n * ```typescript\n * throw new DatrixError('Connection failed', {\n * code: 'CONNECTION_FAILED',\n * operation: 'database:connect',\n * context: { host: 'localhost', port: 5432 }\n * });\n * ```\n *\n * ### Option 2: Extend for Specialized Errors (Complex Errors)\n * ```typescript\n * class ParserError extends DatrixError {\n * readonly parser: ParserType;\n * readonly location: ErrorLocation;\n * // ... additional fields\n * }\n * ```\n *\n * ## When to Extend?\n *\n * **Extend when you need:**\n * - Additional fields (e.g., `location`, `field`, `parser`)\n * - Custom serialization logic\n * - Domain-specific error codes\n * - Client-facing errors with user guidance\n *\n * **Use directly when:**\n * - Simple internal errors\n * - Errors without special context needs\n * - Adapter/plugin errors (unless you need special fields)\n *\n * ## Client-Facing vs Internal Errors\n *\n * **Client-Facing** (API, Parser, Validation):\n * - Include: `suggestion`, `expected`, `received`\n * - User-friendly messages\n * - Detailed context\n *\n * **Internal** (Database, Plugin, Core):\n * - Skip: `suggestion`, `expected`, `received` (undefined)\n * - Technical messages\n * - Minimal context (just enough for debugging)\n *\n * @example\n * // Internal error (database adapter)\n * throw new DatrixError('Query execution failed', {\n * code: 'QUERY_FAILED',\n * operation: 'executeQuery',\n * context: { query: queryObject },\n * cause: originalError\n * });\n *\n * @example\n * // Client-facing error (validation)\n * throw new DatrixError('Field is required', {\n * code: 'REQUIRED',\n * operation: 'validate:field',\n * context: { field: 'email' },\n * suggestion: 'Provide a value for the email field',\n * expected: 'non-empty string',\n * received: undefined\n * });\n */\nexport class DatrixError<\n\tTContext extends Record<string, unknown> = Record<string, unknown>,\n> extends Error {\n\t/** Error code for programmatic handling */\n\treadonly code: string;\n\n\t/** When this error occurred */\n\treadonly timestamp: Date;\n\n\t/** Operation that caused the error (e.g., 'parseQuery', 'validateField') */\n\treadonly operation?: string | undefined;\n\n\t/** Additional error context (error-specific details) */\n\treadonly context?: TContext | undefined;\n\n\t/** Underlying error (for error chaining) */\n\toverride readonly cause?: Error | undefined;\n\n\t// Client-facing fields (optional)\n\n\t/** User guidance - how to fix this error */\n\treadonly suggestion?: string | undefined;\n\n\t/** Expected value/format */\n\treadonly expected?: string | undefined;\n\n\t/** Actual received value */\n\treadonly received?: unknown;\n\n\t/** Documentation link (optional, can be added later) */\n\treadonly documentation?: string | undefined;\n\n\tconstructor(message: string, options: DatrixErrorOptions<TContext>) {\n\t\tsuper(message, { cause: options.cause });\n\n\t\tthis.name = this.constructor.name;\n\t\tthis.code = options.code;\n\t\tthis.timestamp = new Date();\n\t\tthis.operation = options.operation;\n\t\tthis.context = options.context;\n\t\tthis.cause = options.cause;\n\n\t\t// Client-facing fields\n\t\tthis.suggestion = options.suggestion;\n\t\tthis.expected = options.expected;\n\t\tthis.received = options.received;\n\t\tthis.documentation = options.documentation;\n\n\t\t// Maintain proper stack trace\n\t\tif (Error.captureStackTrace) {\n\t\t\tError.captureStackTrace(this, this.constructor);\n\t\t}\n\t}\n\n\t/**\n\t * Serialize error for JSON responses\n\t * Automatically excludes undefined fields\n\t */\n\ttoJSON(): SerializedDatrixError {\n\t\tconst json: SerializedDatrixError = {\n\t\t\ttype: this.name,\n\t\t\tmessage: this.message,\n\t\t\tcode: this.code,\n\t\t\ttimestamp: this.timestamp.toISOString(),\n\t\t};\n\n\t\t// Add optional fields only if defined\n\t\tif (this.operation) json.operation = this.operation;\n\t\tif (this.context) json.context = this.context;\n\t\tif (this.suggestion) json.suggestion = this.suggestion;\n\t\tif (this.expected) json.expected = this.expected;\n\t\tif (this.received !== undefined) json.received = this.received;\n\t\tif (this.documentation) json.documentation = this.documentation;\n\n\t\tif (this.cause) {\n\t\t\tjson.cause = {\n\t\t\t\tmessage: this.cause.message,\n\t\t\t\tname: this.cause.name,\n\t\t\t};\n\t\t}\n\n\t\treturn json;\n\t}\n\n\t/**\n\t * Get detailed error message (for logging)\n\t */\n\ttoDetailedMessage(): string {\n\t\tconst parts = [\n\t\t\t`[${this.name}] ${this.message}`,\n\t\t\t` Code: ${this.code}`,\n\t\t\t` Timestamp: ${this.timestamp.toISOString()}`,\n\t\t];\n\n\t\tif (this.operation) {\n\t\t\tparts.push(` Operation: ${this.operation}`);\n\t\t}\n\n\t\tif (this.received !== undefined) {\n\t\t\tparts.push(` Received: ${JSON.stringify(this.received)}`);\n\t\t}\n\n\t\tif (this.expected) {\n\t\t\tparts.push(` Expected: ${this.expected}`);\n\t\t}\n\n\t\tif (this.suggestion) {\n\t\t\tparts.push(` Suggestion: ${this.suggestion}`);\n\t\t}\n\n\t\tif (this.documentation) {\n\t\t\tparts.push(` Documentation: ${this.documentation}`);\n\t\t}\n\n\t\tif (this.cause) {\n\t\t\tparts.push(` Caused by: ${this.cause.message}`);\n\t\t}\n\n\t\treturn parts.join(\"\\n\");\n\t}\n\n\t/**\n\t * Type guard - check if error is a DatrixError\n\t */\n\tstatic isDatrixError(error: unknown): error is DatrixError {\n\t\treturn error instanceof DatrixError;\n\t}\n}\n\n/**\n * Options for creating DatrixError\n */\nexport interface DatrixErrorOptions<\n\tTContext extends Record<string, unknown> = Record<string, unknown>,\n> {\n\t/**\n\t * Error code (machine-readable)\n\t * Each error type can define its own code constants\n\t */\n\treadonly code: string;\n\n\t/**\n\t * Operation that caused the error\n\t * Examples: 'parseQuery', 'validateField', 'executeQuery'\n\t */\n\treadonly operation?: string | undefined;\n\n\t/**\n\t * Additional error context\n\t * Include relevant details for debugging\n\t */\n\treadonly context?: TContext | undefined;\n\n\t/**\n\t * Underlying error (for error chaining)\n\t * Use when wrapping lower-level errors\n\t */\n\treadonly cause?: Error | undefined;\n\n\t// Client-facing fields (optional)\n\n\t/**\n\t * User guidance - how to fix this error\n\t * Only for client-facing errors\n\t */\n\treadonly suggestion?: string | undefined;\n\n\t/**\n\t * Expected value/format\n\t * Only for client-facing errors\n\t */\n\treadonly expected?: string | undefined;\n\n\t/**\n\t * Actual received value\n\t * Only for client-facing errors\n\t */\n\treadonly received?: unknown | undefined;\n\n\t/**\n\t * Documentation link\n\t * Can be added later\n\t */\n\treadonly documentation?: string | undefined;\n}\n\n/**\n * Serialized error for JSON responses\n * Only includes defined fields\n */\nexport interface SerializedDatrixError {\n\treadonly type: string;\n\treadonly message: string;\n\treadonly code: string;\n\treadonly timestamp: string;\n\toperation?: string;\n\tcontext?: Record<string, unknown>;\n\tsuggestion?: string;\n\texpected?: string;\n\treceived?: unknown;\n\tdocumentation?: string;\n\tcause?: {\n\t\treadonly message: string;\n\t\treadonly name: string;\n\t};\n}\n","/**\n * Datrix Adapter Error\n *\n * Single unified error class for all database adapters.\n * Replaces DatrixPostgresAdapterError, DatrixMySQLAdapterError, DatrixJsonAdapterError.\n */\n\nimport { DatrixError, type SerializedDatrixError } from \"../datrix-error\";\n\n// ============================================================================\n// Adapter Name\n// ============================================================================\n\nexport type AdapterName = \"postgres\" | \"mysql\" | \"mongodb\" | \"json\";\n\n// ============================================================================\n// Adapter Operation\n// ============================================================================\n\nexport type AdapterOperation =\n\t// Common\n\t| \"connect\"\n\t| \"disconnect\"\n\t| \"query\"\n\t| \"transaction\"\n\t| \"populate\"\n\t| \"join\"\n\t| \"aggregation\"\n\t| \"migration\"\n\t| \"introspection\"\n\t// JSON-specific\n\t| \"lock\"\n\t| \"read\"\n\t| \"write\"\n\t| \"validate\";\n\n// ============================================================================\n// Adapter Error Codes\n// ============================================================================\n\nexport type AdapterErrorCode =\n\t// --- Common ---\n\t| \"ADAPTER_CONNECTION_ERROR\"\n\t| \"ADAPTER_QUERY_ERROR\"\n\t| \"ADAPTER_TRANSACTION_ERROR\"\n\t| \"ADAPTER_MIGRATION_ERROR\"\n\t| \"ADAPTER_INTROSPECTION_ERROR\"\n\t| \"ADAPTER_AGGREGATION_ERROR\"\n\t| \"ADAPTER_POPULATE_ERROR\"\n\t| \"ADAPTER_JOIN_ERROR\"\n\t| \"ADAPTER_LATERAL_JOIN_ERROR\"\n\t| \"ADAPTER_JSON_AGGREGATION_ERROR\"\n\t| \"ADAPTER_RESULT_PROCESSING_ERROR\"\n\t| \"ADAPTER_INVALID_POPULATE_OPTIONS\"\n\t| \"ADAPTER_MODEL_NOT_FOUND\"\n\t| \"ADAPTER_SCHEMA_NOT_FOUND\"\n\t| \"ADAPTER_RELATION_NOT_FOUND\"\n\t| \"ADAPTER_INVALID_RELATION\"\n\t| \"ADAPTER_TARGET_MODEL_NOT_FOUND\"\n\t| \"ADAPTER_JUNCTION_TABLE_NOT_FOUND\"\n\t| \"ADAPTER_MAX_DEPTH_EXCEEDED\"\n\t// --- JSON-specific ---\n\t| \"ADAPTER_LOCK_TIMEOUT\"\n\t| \"ADAPTER_LOCK_ERROR\"\n\t| \"ADAPTER_FILE_READ_ERROR\"\n\t| \"ADAPTER_FILE_WRITE_ERROR\"\n\t| \"ADAPTER_FILE_NOT_FOUND\"\n\t| \"ADAPTER_INVALID_DATA\"\n\t| \"ADAPTER_QUERY_MISSING_DATA\"\n\t| \"ADAPTER_INVALID_WHERE_FIELD\"\n\t| \"ADAPTER_INVALID_RELATION_WHERE\"\n\t| \"ADAPTER_UNIQUE_CONSTRAINT\"\n\t| \"ADAPTER_FOREIGN_KEY_CONSTRAINT\"\n\t// --- Meta field operations ---\n\t| \"ADAPTER_META_FIELD_EXISTS\"\n\t| \"ADAPTER_META_FIELD_NOT_FOUND\";\n\n// ============================================================================\n// Error Context\n// ============================================================================\n\nexport interface AdapterErrorContext {\n\treadonly table?: string;\n\treadonly model?: string;\n\treadonly field?: string;\n\treadonly relationName?: string;\n\treadonly targetModel?: string;\n\treadonly junctionTable?: string;\n\treadonly query?: Record<string, unknown>;\n\treadonly sql?: string;\n\treadonly params?: readonly unknown[];\n\treadonly depth?: number;\n\treadonly maxDepth?: number;\n\treadonly relationPath?: string;\n\treadonly file?: string;\n\treadonly lockTimeout?: number;\n\treadonly [key: string]: unknown;\n}\n\n// ============================================================================\n// Error Options\n// ============================================================================\n\nexport interface DatrixAdapterErrorOptions {\n\treadonly adapter: AdapterName;\n\treadonly code: AdapterErrorCode;\n\treadonly operation?: AdapterOperation | undefined;\n\treadonly context?: AdapterErrorContext | undefined;\n\treadonly cause?: Error | undefined;\n\treadonly suggestion?: string | undefined;\n\treadonly expected?: string | undefined;\n\treadonly received?: unknown | undefined;\n}\n\n// ============================================================================\n// Serialized Error\n// ============================================================================\n\nexport interface SerializedDatrixAdapterError extends SerializedDatrixError {\n\treadonly adapter: AdapterName;\n\treadonly adapterOperation?: AdapterOperation;\n}\n\n// ============================================================================\n// Error Class\n// ============================================================================\n\n/**\n * Datrix Adapter Error Class\n *\n * Unified error class for all database adapters (postgres, mysql, json).\n * Use helper functions from adapter-helpers.ts instead of instantiating directly.\n *\n * @example\n * ```ts\n * throw new DatrixAdapterError('Model not found', {\n * adapter: 'postgres',\n * code: 'ADAPTER_MODEL_NOT_FOUND',\n * operation: 'populate',\n * context: { table: 'users' },\n * suggestion: 'Ensure model is registered in schema registry',\n * });\n * ```\n */\nexport class DatrixAdapterError extends DatrixError<AdapterErrorContext> {\n\treadonly adapter: AdapterName;\n\treadonly adapterOperation?: AdapterOperation | undefined;\n\n\tconstructor(message: string, options: DatrixAdapterErrorOptions) {\n\t\tconst operationString = options.operation\n\t\t\t? `adapter:${options.adapter}:${options.operation}`\n\t\t\t: `adapter:${options.adapter}`;\n\n\t\tsuper(message, {\n\t\t\tcode: options.code,\n\t\t\toperation: operationString,\n\t\t\tcontext: options.context,\n\t\t\tcause: options.cause,\n\t\t\tsuggestion: options.suggestion,\n\t\t\texpected: options.expected,\n\t\t\treceived: options.received,\n\t\t});\n\n\t\tthis.adapter = options.adapter;\n\t\tthis.adapterOperation = options.operation;\n\t}\n\n\toverride toJSON(): SerializedDatrixAdapterError {\n\t\tconst json = super.toJSON();\n\n\t\tif (this.adapterOperation) {\n\t\t\treturn {\n\t\t\t\t...json,\n\t\t\t\tadapter: this.adapter,\n\t\t\t\tadapterOperation: this.adapterOperation,\n\t\t\t};\n\t\t}\n\n\t\treturn { ...json, adapter: this.adapter };\n\t}\n\n\toverride toDetailedMessage(): string {\n\t\tconst baseMessage = super.toDetailedMessage();\n\t\tconst parts = baseMessage.split(\"\\n\");\n\n\t\tconst extraLines: string[] = [` Adapter: ${this.adapter}`];\n\n\t\tif (this.adapterOperation) {\n\t\t\textraLines.push(` Adapter Operation: ${this.adapterOperation}`);\n\t\t}\n\n\t\tparts.splice(3, 0, ...extraLines);\n\t\treturn parts.join(\"\\n\");\n\t}\n}\n","/**\n * Datrix Adapter Error Helpers\n *\n * Shared throw helpers for all database adapters.\n * Every helper accepts an object with at minimum { adapter }.\n */\n\nimport type { QueryObject } from \"../../core/query-builder\";\nimport type { DatrixEntry } from \"../../core/schema\";\nimport { DatrixAdapterError, type AdapterName } from \"./adapter-error\";\n\n// ============================================================================\n// SQL Truncation Utility\n// ============================================================================\n\nexport function truncateSqlForError(sql: string): string {\n\tif (process.env[\"NODE_ENV\"] === \"development\") {\n\t\treturn sql;\n\t}\n\treturn sql.length > 500 ? sql.substring(0, 500) + \"...\" : sql;\n}\n\n// ============================================================================\n// Connection Errors\n// ============================================================================\n\nexport function throwNotConnected(params: { adapter: AdapterName }): never {\n\tthrow new DatrixAdapterError(\"Not connected to database\", {\n\t\tadapter: params.adapter,\n\t\tcode: \"ADAPTER_CONNECTION_ERROR\",\n\t\toperation: \"connect\",\n\t\tsuggestion: \"Call adapter.connect() before executing queries\",\n\t});\n}\n\nexport function throwConnectionError(params: {\n\tadapter: AdapterName;\n\tmessage: string;\n\toperation?: \"connect\" | \"disconnect\";\n\tcause?: Error | undefined;\n}): never {\n\tthrow new DatrixAdapterError(params.message, {\n\t\tadapter: params.adapter,\n\t\tcode: \"ADAPTER_CONNECTION_ERROR\",\n\t\toperation: params.operation ?? \"connect\",\n\t\tcause: params.cause,\n\t});\n}\n\n// ============================================================================\n// Migration Errors\n// ============================================================================\n\nexport function throwMigrationError(params: {\n\tadapter: AdapterName;\n\tmessage: string;\n\ttable?: string | undefined;\n\tcause?: Error | undefined;\n\tsuggestion?: string | undefined;\n}): never {\n\tthrow new DatrixAdapterError(params.message, {\n\t\tadapter: params.adapter,\n\t\tcode: \"ADAPTER_MIGRATION_ERROR\",\n\t\toperation: \"migration\",\n\t\tcontext: params.table ? { table: params.table } : undefined,\n\t\tcause: params.cause,\n\t\tsuggestion: params.suggestion,\n\t});\n}\n\n// ============================================================================\n// Introspection Errors\n// ============================================================================\n\nexport function throwIntrospectionError(params: {\n\tadapter: AdapterName;\n\tmessage: string;\n\ttable?: string | undefined;\n\tcause?: Error | undefined;\n}): never {\n\tthrow new DatrixAdapterError(params.message, {\n\t\tadapter: params.adapter,\n\t\tcode: \"ADAPTER_INTROSPECTION_ERROR\",\n\t\toperation: \"introspection\",\n\t\tcontext: params.table ? { table: params.table } : undefined,\n\t\tcause: params.cause,\n\t});\n}\n\n// ============================================================================\n// Query Errors\n// ============================================================================\n\nexport function throwQueryError(params: {\n\tadapter: AdapterName;\n\tmessage: string;\n\tquery?: QueryObject | undefined;\n\tsql?: string | undefined;\n\tcause?: Error | undefined;\n\tsuggestion?: string | undefined;\n\texpected?: string | undefined;\n\treceived?: unknown;\n}): never {\n\tthrow new DatrixAdapterError(params.message, {\n\t\tadapter: params.adapter,\n\t\tcode: \"ADAPTER_QUERY_ERROR\",\n\t\toperation: \"query\",\n\t\tcontext: {\n\t\t\t...(params.query && {\n\t\t\t\tquery: { type: params.query.type, table: params.query.table },\n\t\t\t}),\n\t\t\t...(params.sql && { sql: truncateSqlForError(params.sql) }),\n\t\t},\n\t\tcause: params.cause,\n\t\tsuggestion: params.suggestion,\n\t\texpected: params.expected,\n\t\treceived: params.received,\n\t});\n}\n\nexport function throwQueryMissingData(params: {\n\tadapter: AdapterName;\n\tqueryType: string;\n\ttable: string;\n}): never {\n\tthrow new DatrixAdapterError(\n\t\t`${params.queryType} query missing data for table: ${params.table}`,\n\t\t{\n\t\t\tadapter: params.adapter,\n\t\t\tcode: \"ADAPTER_QUERY_MISSING_DATA\",\n\t\t\toperation: \"query\",\n\t\t\tcontext: { table: params.table, queryType: params.queryType },\n\t\t\tsuggestion: `Provide data field in ${params.queryType} query`,\n\t\t\texpected: \"query.data object\",\n\t\t},\n\t);\n}\n\n// ============================================================================\n// Transaction Errors\n// ============================================================================\n\nexport function throwTransactionError(params: {\n\tadapter: AdapterName;\n\tmessage: string;\n\tcause?: Error | undefined;\n}): never {\n\tthrow new DatrixAdapterError(params.message, {\n\t\tadapter: params.adapter,\n\t\tcode: \"ADAPTER_TRANSACTION_ERROR\",\n\t\toperation: \"transaction\",\n\t\tcause: params.cause,\n\t});\n}\n\nexport function throwTransactionAlreadyCommitted(params: {\n\tadapter: AdapterName;\n}): never {\n\tthrow new DatrixAdapterError(\"Transaction already committed\", {\n\t\tadapter: params.adapter,\n\t\tcode: \"ADAPTER_TRANSACTION_ERROR\",\n\t\toperation: \"transaction\",\n\t\tsuggestion: \"Start a new transaction instead of reusing a committed one\",\n\t});\n}\n\nexport function throwTransactionAlreadyRolledBack(params: {\n\tadapter: AdapterName;\n}): never {\n\tthrow new DatrixAdapterError(\"Transaction already rolled back\", {\n\t\tadapter: params.adapter,\n\t\tcode: \"ADAPTER_TRANSACTION_ERROR\",\n\t\toperation: \"transaction\",\n\t\tsuggestion: \"Start a new transaction instead of reusing a rolled back one\",\n\t});\n}\n\nexport function throwTransactionSavepointNotSupported(params: {\n\tadapter: AdapterName;\n}): never {\n\tthrow new DatrixAdapterError(\n\t\t`Savepoints are not supported by the ${params.adapter} adapter`,\n\t\t{\n\t\t\tadapter: params.adapter,\n\t\t\tcode: \"ADAPTER_TRANSACTION_ERROR\",\n\t\t\toperation: \"transaction\",\n\t\t\tsuggestion: \"Use nested transactions or restructure your logic\",\n\t\t},\n\t);\n}\n\nexport function throwRawQueryNotSupported(params: {\n\tadapter: AdapterName;\n}): never {\n\tthrow new DatrixAdapterError(\n\t\t`Raw SQL queries are not supported by the ${params.adapter} adapter`,\n\t\t{\n\t\t\tadapter: params.adapter,\n\t\t\tcode: \"ADAPTER_QUERY_ERROR\",\n\t\t\toperation: \"query\",\n\t\t\tsuggestion: \"Use the query builder API instead of raw SQL\",\n\t\t},\n\t);\n}\n\n// ============================================================================\n// Populate / Relation Errors\n// ============================================================================\n\nexport function throwModelNotFound(params: {\n\tadapter: AdapterName;\n\ttable: string;\n}): never {\n\tthrow new DatrixAdapterError(`Model not found for table: ${params.table}`, {\n\t\tadapter: params.adapter,\n\t\tcode: \"ADAPTER_MODEL_NOT_FOUND\",\n\t\toperation: \"populate\",\n\t\tcontext: { table: params.table },\n\t\tsuggestion: \"Ensure model is registered in schema registry\",\n\t\texpected: \"registered model\",\n\t});\n}\n\nexport function throwSchemaNotFound(params: {\n\tadapter: AdapterName;\n\tmodelName: string;\n}): never {\n\tthrow new DatrixAdapterError(\n\t\t`Schema not found for model: ${params.modelName}`,\n\t\t{\n\t\t\tadapter: params.adapter,\n\t\t\tcode: \"ADAPTER_SCHEMA_NOT_FOUND\",\n\t\t\toperation: \"populate\",\n\t\t\tcontext: { model: params.modelName },\n\t\t\tsuggestion: \"Ensure schema is registered in schema registry\",\n\t\t\texpected: \"registered schema\",\n\t\t},\n\t);\n}\n\nexport function throwRelationNotFound(params: {\n\tadapter: AdapterName;\n\trelationName: string;\n\tschemaName: string;\n}): never {\n\tthrow new DatrixAdapterError(\n\t\t`Relation field '${params.relationName}' not found in schema '${params.schemaName}'`,\n\t\t{\n\t\t\tadapter: params.adapter,\n\t\t\tcode: \"ADAPTER_RELATION_NOT_FOUND\",\n\t\t\toperation: \"populate\",\n\t\t\tcontext: { relationName: params.relationName, model: params.schemaName },\n\t\t\tsuggestion: `Add '${params.relationName}' relation to schema '${params.schemaName}' or check field name`,\n\t\t\texpected: `relation field '${params.relationName}'`,\n\t\t},\n\t);\n}\n\nexport function throwInvalidRelationType(params: {\n\tadapter: AdapterName;\n\trelationName: string;\n\tfieldType: string;\n\tschemaName: string;\n}): never {\n\tthrow new DatrixAdapterError(\n\t\t`Field '${params.relationName}' (type: ${params.fieldType}) is not a relation field in schema '${params.schemaName}'`,\n\t\t{\n\t\t\tadapter: params.adapter,\n\t\t\tcode: \"ADAPTER_INVALID_RELATION\",\n\t\t\toperation: \"populate\",\n\t\t\tcontext: {\n\t\t\t\trelationName: params.relationName,\n\t\t\t\tfield: params.fieldType,\n\t\t\t\tmodel: params.schemaName,\n\t\t\t},\n\t\t\tsuggestion: `Change field type to 'relation' for '${params.relationName}'`,\n\t\t\texpected: \"type: 'relation'\",\n\t\t\treceived: params.fieldType,\n\t\t},\n\t);\n}\n\nexport function throwTargetModelNotFound(params: {\n\tadapter: AdapterName;\n\ttargetModel: string;\n\trelationName: string;\n\tschemaName: string;\n}): never {\n\tthrow new DatrixAdapterError(\n\t\t`Target model '${params.targetModel}' not found for relation '${params.relationName}' in schema '${params.schemaName}'`,\n\t\t{\n\t\t\tadapter: params.adapter,\n\t\t\tcode: \"ADAPTER_TARGET_MODEL_NOT_FOUND\",\n\t\t\toperation: \"populate\",\n\t\t\tcontext: {\n\t\t\t\ttargetModel: params.targetModel,\n\t\t\t\trelationName: params.relationName,\n\t\t\t\tmodel: params.schemaName,\n\t\t\t},\n\t\t\tsuggestion: `Ensure model '${params.targetModel}' is registered in schema registry`,\n\t\t\texpected: `registered model '${params.targetModel}'`,\n\t\t},\n\t);\n}\n\nexport function throwJunctionTableNotFound(params: {\n\tadapter: AdapterName;\n\tjunctionTable: string;\n\trelationName: string;\n\tschemaName: string;\n}): never {\n\tthrow new DatrixAdapterError(\n\t\t`Junction table '${params.junctionTable}' not found for manyToMany relation '${params.relationName}' in schema '${params.schemaName}'`,\n\t\t{\n\t\t\tadapter: params.adapter,\n\t\t\tcode: \"ADAPTER_JUNCTION_TABLE_NOT_FOUND\",\n\t\t\toperation: \"populate\",\n\t\t\tcontext: {\n\t\t\t\tjunctionTable: params.junctionTable,\n\t\t\t\trelationName: params.relationName,\n\t\t\t\tmodel: params.schemaName,\n\t\t\t},\n\t\t\tsuggestion: `Create junction table '${params.junctionTable}' or check 'through' property in relation definition`,\n\t\t\texpected: `table '${params.junctionTable}' to exist`,\n\t\t},\n\t);\n}\n\nexport function throwMaxDepthExceeded(params: {\n\tadapter: AdapterName;\n\tcurrentDepth: number;\n\tmaxDepth: number;\n\trelationPath: string;\n}): never {\n\tthrow new DatrixAdapterError(\n\t\t`Populate depth exceeds maximum of ${params.maxDepth} at path: ${params.relationPath}`,\n\t\t{\n\t\t\tadapter: params.adapter,\n\t\t\tcode: \"ADAPTER_MAX_DEPTH_EXCEEDED\",\n\t\t\toperation: \"populate\",\n\t\t\tcontext: {\n\t\t\t\tdepth: params.currentDepth,\n\t\t\t\tmaxDepth: params.maxDepth,\n\t\t\t\trelationPath: params.relationPath,\n\t\t\t},\n\t\t\tsuggestion: `Reduce nesting level or increase MAX_POPULATE_DEPTH (current: ${params.maxDepth})`,\n\t\t\texpected: `depth <= ${params.maxDepth}`,\n\t\t\treceived: `depth: ${params.currentDepth}`,\n\t\t},\n\t);\n}\n\nexport function throwPopulateQueryError<T extends DatrixEntry>(params: {\n\tadapter: AdapterName;\n\tquery: QueryObject<T>;\n\tsql: string;\n\tcause: Error;\n\tstrategy?: string | undefined;\n\tqueryParams?: readonly unknown[] | undefined;\n}): never {\n\tconst strategyLabel = params.strategy\n\t\t? ` using ${params.strategy} strategy`\n\t\t: \"\";\n\tthrow new DatrixAdapterError(\n\t\t`Populate query execution failed for table '${params.query.table}'${strategyLabel}`,\n\t\t{\n\t\t\tadapter: params.adapter,\n\t\t\tcode: \"ADAPTER_POPULATE_ERROR\",\n\t\t\toperation: \"populate\",\n\t\t\tcontext: {\n\t\t\t\ttable: params.query.table,\n\t\t\t\tquery: { type: params.query.type },\n\t\t\t\tsql: truncateSqlForError(params.sql),\n\t\t\t\tparams: params.queryParams ?? [],\n\t\t\t\tstrategy: params.strategy,\n\t\t\t},\n\t\t\tcause: params.cause,\n\t\t\tsuggestion:\n\t\t\t\t\"Check SQL syntax, relation definitions, and database connection\",\n\t\t\texpected: \"successful query execution\",\n\t\t},\n\t);\n}\n\nexport function throwInvalidPopulateOptions(params: {\n\tadapter: AdapterName;\n\trelationName: string;\n\toptionName: string;\n\toptionValue: unknown;\n}): never {\n\tthrow new DatrixAdapterError(\n\t\t`Invalid populate option '${params.optionName}' for relation '${params.relationName}'`,\n\t\t{\n\t\t\tadapter: params.adapter,\n\t\t\tcode: \"ADAPTER_INVALID_POPULATE_OPTIONS\",\n\t\t\toperation: \"populate\",\n\t\t\tcontext: {\n\t\t\t\trelationName: params.relationName,\n\t\t\t\toptionName: params.optionName,\n\t\t\t\toptionValue: params.optionValue,\n\t\t\t},\n\t\t\tsuggestion:\n\t\t\t\t\"Check populate options syntax. Valid options: select, where, orderBy, limit, offset, populate\",\n\t\t\texpected: \"valid populate option\",\n\t\t\treceived: `${params.optionName}: ${JSON.stringify(params.optionValue)}`,\n\t\t},\n\t);\n}\n\n// ============================================================================\n// JOIN Errors\n// ============================================================================\n\nexport function throwJoinBuildError(params: {\n\tadapter: AdapterName;\n\trelationName: string;\n\trelationKind: string;\n\tcause?: Error | undefined;\n}): never {\n\tthrow new DatrixAdapterError(\n\t\t`Failed to generate JOIN for relation '${params.relationName}' (kind: ${params.relationKind})`,\n\t\t{\n\t\t\tadapter: params.adapter,\n\t\t\tcode: \"ADAPTER_JOIN_ERROR\",\n\t\t\toperation: \"join\",\n\t\t\tcontext: {\n\t\t\t\trelationName: params.relationName,\n\t\t\t\trelationKind: params.relationKind,\n\t\t\t},\n\t\t\tcause: params.cause,\n\t\t\tsuggestion: \"Check relation configuration and foreign key definitions\",\n\t\t\texpected: `valid ${params.relationKind} relation`,\n\t\t},\n\t);\n}\n\nexport function throwLateralJoinError(params: {\n\tadapter: AdapterName;\n\trelationName: string;\n\tcause?: Error | undefined;\n}): never {\n\tthrow new DatrixAdapterError(\n\t\t`Failed to generate LATERAL JOIN for relation '${params.relationName}'`,\n\t\t{\n\t\t\tadapter: params.adapter,\n\t\t\tcode: \"ADAPTER_LATERAL_JOIN_ERROR\",\n\t\t\toperation: \"join\",\n\t\t\tcontext: { relationName: params.relationName },\n\t\t\tcause: params.cause,\n\t\t\tsuggestion:\n\t\t\t\t\"Check populate options syntax and database version compatibility\",\n\t\t\texpected: \"valid LATERAL JOIN syntax\",\n\t\t},\n\t);\n}\n\n// ============================================================================\n// Aggregation Errors\n// ============================================================================\n\nexport function throwJsonAggregationError(params: {\n\tadapter: AdapterName;\n\trelationName: string;\n\tcause?: Error | undefined;\n}): never {\n\tthrow new DatrixAdapterError(\n\t\t`Failed to generate JSON aggregation for relation '${params.relationName}'`,\n\t\t{\n\t\t\tadapter: params.adapter,\n\t\t\tcode: \"ADAPTER_JSON_AGGREGATION_ERROR\",\n\t\t\toperation: \"aggregation\",\n\t\t\tcontext: { relationName: params.relationName },\n\t\t\tcause: params.cause,\n\t\t\tsuggestion: \"Check field selection and aggregation syntax\",\n\t\t\texpected: \"valid JSON aggregation syntax\",\n\t\t},\n\t);\n}\n\nexport function throwResultProcessingError(params: {\n\tadapter: AdapterName;\n\toperation: string;\n\tcause?: Error | undefined;\n}): never {\n\tthrow new DatrixAdapterError(\n\t\t`Failed to process query results: ${params.operation}`,\n\t\t{\n\t\t\tadapter: params.adapter,\n\t\t\tcode: \"ADAPTER_RESULT_PROCESSING_ERROR\",\n\t\t\toperation: \"populate\",\n\t\t\tcontext: { processingOperation: params.operation },\n\t\t\tcause: params.cause,\n\t\t\tsuggestion: \"Check result structure and populate configuration\",\n\t\t\texpected: \"valid result structure\",\n\t\t},\n\t);\n}\n\n// ============================================================================\n// Meta Field Errors (used by applyOperationsToMetaSchema in all adapters)\n// ============================================================================\n\nexport function throwMetaFieldAlreadyExists(params: {\n\tadapter: AdapterName;\n\tfield: string;\n\ttable: string;\n}): never {\n\tthrow new DatrixAdapterError(\n\t\t`Meta field '${params.field}' already exists in schema for table '${params.table}'`,\n\t\t{\n\t\t\tadapter: params.adapter,\n\t\t\tcode: \"ADAPTER_META_FIELD_EXISTS\",\n\t\t\toperation: \"migration\",\n\t\t\tcontext: { field: params.field, table: params.table },\n\t\t\tsuggestion: `Use 'modifyMetaField' to update existing field '${params.field}'`,\n\t\t},\n\t);\n}\n\nexport function throwMetaFieldNotFound(params: {\n\tadapter: AdapterName;\n\tfield: string;\n\ttable: string;\n}): never {\n\tthrow new DatrixAdapterError(\n\t\t`Meta field '${params.field}' not found in schema for table '${params.table}'`,\n\t\t{\n\t\t\tadapter: params.adapter,\n\t\t\tcode: \"ADAPTER_META_FIELD_NOT_FOUND\",\n\t\t\toperation: \"migration\",\n\t\t\tcontext: { field: params.field, table: params.table },\n\t\t\tsuggestion: `Use 'addMetaField' to add field '${params.field}' first`,\n\t\t},\n\t);\n}\n\n// ============================================================================\n// JSON Adapter — Lock Errors\n// ============================================================================\n\nexport function throwLockTimeout(params: {\n\tadapter: AdapterName;\n\tlockTimeout: number;\n}): never {\n\tthrow new DatrixAdapterError(\n\t\t`Could not acquire lock within ${params.lockTimeout}ms`,\n\t\t{\n\t\t\tadapter: params.adapter,\n\t\t\tcode: \"ADAPTER_LOCK_TIMEOUT\",\n\t\t\toperation: \"lock\",\n\t\t\tcontext: { lockTimeout: params.lockTimeout },\n\t\t\tsuggestion:\n\t\t\t\t\"Increase lockTimeout in adapter config or check for deadlocks\",\n\t\t\texpected: \"lock acquired within timeout\",\n\t\t},\n\t);\n}\n\nexport function throwLockError(params: {\n\tadapter: AdapterName;\n\tcause?: Error | undefined;\n}): never {\n\tthrow new DatrixAdapterError(\"Failed to acquire lock\", {\n\t\tadapter: params.adapter,\n\t\tcode: \"ADAPTER_LOCK_ERROR\",\n\t\toperation: \"lock\",\n\t\tcause: params.cause,\n\t\tsuggestion: \"Check file system permissions and lock file path\",\n\t});\n}\n\n// ============================================================================\n// JSON Adapter — File I/O Errors\n// ============================================================================\n\nexport function throwFileReadError(params: {\n\tadapter: AdapterName;\n\tfile: string;\n\tcause?: Error | undefined;\n}): never {\n\tthrow new DatrixAdapterError(`Failed to read file: ${params.file}`, {\n\t\tadapter: params.adapter,\n\t\tcode: \"ADAPTER_FILE_READ_ERROR\",\n\t\toperation: \"read\",\n\t\tcontext: { file: params.file },\n\t\tcause: params.cause,\n\t\tsuggestion: \"Check file exists and has correct permissions\",\n\t});\n}\n\nexport function throwFileWriteError(params: {\n\tadapter: AdapterName;\n\tfile: string;\n\tcause?: Error | undefined;\n}): never {\n\tthrow new DatrixAdapterError(`Failed to write file: ${params.file}`, {\n\t\tadapter: params.adapter,\n\t\tcode: \"ADAPTER_FILE_WRITE_ERROR\",\n\t\toperation: \"write\",\n\t\tcontext: { file: params.file },\n\t\tcause: params.cause,\n\t\tsuggestion: \"Check directory exists and has write permissions\",\n\t});\n}\n\nexport function throwFileNotFound(params: {\n\tadapter: AdapterName;\n\tfile: string;\n}): never {\n\tthrow new DatrixAdapterError(`File not found: ${params.file}`, {\n\t\tadapter: params.adapter,\n\t\tcode: \"ADAPTER_FILE_NOT_FOUND\",\n\t\toperation: \"read\",\n\t\tcontext: { file: params.file },\n\t\tsuggestion: \"Ensure the file exists or run migrations to create it\",\n\t});\n}\n\n// ============================================================================\n// JSON Adapter — Constraint Errors\n// ============================================================================\n\nexport function throwUniqueConstraintField(params: {\n\tadapter: AdapterName;\n\tfield: string;\n\tvalue: unknown;\n\ttable: string;\n}): never {\n\tthrow new DatrixAdapterError(\n\t\t`Duplicate value '${params.value}' for unique field '${params.field}'`,\n\t\t{\n\t\t\tadapter: params.adapter,\n\t\t\tcode: \"ADAPTER_UNIQUE_CONSTRAINT\",\n\t\t\toperation: \"query\",\n\t\t\tcontext: {\n\t\t\t\tfield: params.field,\n\t\t\t\tvalue: params.value,\n\t\t\t\ttable: params.table,\n\t\t\t},\n\t\t\tsuggestion: `Ensure '${params.field}' value is unique in table '${params.table}'`,\n\t\t\texpected: \"unique value\",\n\t\t\treceived: params.value,\n\t\t},\n\t);\n}\n\nexport function throwUniqueConstraintIndex(params: {\n\tadapter: AdapterName;\n\tfields: readonly string[];\n\ttable: string;\n}): never {\n\tthrow new DatrixAdapterError(\n\t\t`Duplicate value for unique index [${params.fields.join(\", \")}]`,\n\t\t{\n\t\t\tadapter: params.adapter,\n\t\t\tcode: \"ADAPTER_UNIQUE_CONSTRAINT\",\n\t\t\toperation: \"query\",\n\t\t\tcontext: { fields: params.fields.join(\", \"), table: params.table },\n\t\t\tsuggestion: `Ensure combination of [${params.fields.join(\", \")}] is unique in table '${params.table}'`,\n\t\t\texpected: \"unique combination\",\n\t\t},\n\t);\n}\n\nexport function throwForeignKeyConstraint(params: {\n\tadapter: AdapterName;\n\tforeignKey: string;\n\tvalue: unknown;\n\ttargetModel: string;\n\ttable: string;\n}): never {\n\tthrow new DatrixAdapterError(\n\t\t`Foreign key constraint failed: ${params.targetModel} with id '${params.value}' does not exist`,\n\t\t{\n\t\t\tadapter: params.adapter,\n\t\t\tcode: \"ADAPTER_FOREIGN_KEY_CONSTRAINT\",\n\t\t\toperation: \"query\",\n\t\t\tcontext: {\n\t\t\t\tforeignKey: params.foreignKey,\n\t\t\t\tvalue: params.value,\n\t\t\t\ttargetModel: params.targetModel,\n\t\t\t\ttable: params.table,\n\t\t\t},\n\t\t\tsuggestion: `Ensure ${params.targetModel} with id '${params.value}' exists before referencing it`,\n\t\t\texpected: `existing ${params.targetModel} id`,\n\t\t\treceived: params.value,\n\t\t},\n\t);\n}\n\n// ============================================================================\n// JSON Adapter — WHERE Errors\n// ============================================================================\n\nexport function throwInvalidWhereField(params: {\n\tadapter: AdapterName;\n\tfield: string;\n\tschemaName: string;\n\tavailableFields: readonly string[];\n}): never {\n\tthrow new DatrixAdapterError(\n\t\t`Invalid WHERE clause: Field '${params.field}' does not exist in schema '${params.schemaName}'`,\n\t\t{\n\t\t\tadapter: params.adapter,\n\t\t\tcode: \"ADAPTER_INVALID_WHERE_FIELD\",\n\t\t\toperation: \"query\",\n\t\t\tcontext: {\n\t\t\t\tfield: params.field,\n\t\t\t\tschemaName: params.schemaName,\n\t\t\t\tavailableFields: params.availableFields.join(\", \"),\n\t\t\t},\n\t\t\tsuggestion: `Use one of the available fields: ${params.availableFields.join(\", \")}`,\n\t\t\texpected: `valid field name from schema '${params.schemaName}'`,\n\t\t\treceived: params.field,\n\t\t},\n\t);\n}\n\nexport function throwInvalidRelationWhereSyntax(params: {\n\tadapter: AdapterName;\n\trelationName: string;\n\tschemaName: string;\n\tforeignKey: string;\n}): never {\n\tthrow new DatrixAdapterError(\n\t\t`Invalid WHERE clause: Cannot use comparison operators directly on relation field '${params.relationName}'`,\n\t\t{\n\t\t\tadapter: params.adapter,\n\t\t\tcode: \"ADAPTER_INVALID_RELATION_WHERE\",\n\t\t\toperation: \"query\",\n\t\t\tcontext: {\n\t\t\t\trelationName: params.relationName,\n\t\t\t\tschemaName: params.schemaName,\n\t\t\t\tforeignKey: params.foreignKey,\n\t\t\t},\n\t\t\tsuggestion:\n\t\t\t\t`Use nested WHERE syntax: { ${params.relationName}: { <field>: { $eq: <value> } } }\\n` +\n\t\t\t\t`Or filter by foreign key directly: { ${params.foreignKey}: { $eq: <value> } }`,\n\t\t\texpected:\n\t\t\t\t\"nested WHERE object with field names (e.g., { id: { $eq: 1 } })\",\n\t\t\treceived: \"comparison operators (e.g., { $eq: 1 })\",\n\t\t},\n\t);\n}\n","/**\n * Authentication Error\n *\n * Specialized error for authentication and authorization failures.\n * Extends DatrixError with auth-specific fields.\n */\n\nimport { DatrixError, type SerializedDatrixError } from \"../datrix-error\";\n\n/**\n * Auth strategy types\n */\nexport type AuthStrategy = \"jwt\" | \"session\" | \"password\" | \"permission\";\n\n/**\n * Auth error codes\n */\nexport type AuthErrorCode =\n\t| \"AUTH_INVALID_CREDENTIALS\"\n\t| \"AUTH_USER_NOT_FOUND\"\n\t| \"AUTH_USER_EXISTS\"\n\t| \"AUTH_WEAK_PASSWORD\"\n\t| \"AUTH_TOKEN_EXPIRED\"\n\t| \"AUTH_TOKEN_INVALID\"\n\t| \"AUTH_SESSION_NOT_FOUND\"\n\t| \"AUTH_SESSION_EXPIRED\"\n\t| \"AUTH_SESSION_INVALID\"\n\t| \"AUTH_UNAUTHORIZED\"\n\t| \"AUTH_FORBIDDEN\"\n\t| \"AUTH_CONFIG_INVALID\"\n\t| \"JWT_SIGN_ERROR\"\n\t| \"JWT_VERIFY_ERROR\"\n\t| \"JWT_DECODE_ERROR\"\n\t| \"JWT_EXPIRED\"\n\t| \"JWT_INVALID_FORMAT\"\n\t| \"JWT_INVALID_HEADER\"\n\t| \"JWT_INVALID_PAYLOAD\"\n\t| \"JWT_INVALID_SIGNATURE\"\n\t| \"JWT_INVALID_IAT\"\n\t| \"JWT_INVALID_ISSUER\"\n\t| \"JWT_INVALID_AUDIENCE\"\n\t| \"SESSION_CREATE_ERROR\"\n\t| \"SESSION_DELETE_ERROR\"\n\t| \"SESSION_NOT_CONFIGURED\"\n\t| \"PASSWORD_HASH_ERROR\"\n\t| \"PASSWORD_VERIFY_ERROR\"\n\t| \"PASSWORD_TOO_SHORT\"\n\t| \"PASSWORD_TOO_LONG\"\n\t| \"PERMISSION_DENIED\";\n\n/**\n * Auth error context\n */\nexport interface AuthErrorContext {\n\treadonly strategy?: AuthStrategy | undefined;\n\treadonly userId?: string | undefined;\n\treadonly role?: string | undefined;\n\treadonly sessionId?: string | undefined;\n\treadonly action?: string | undefined;\n\treadonly resource?: string | undefined;\n\treadonly field?: string | undefined;\n\treadonly exp?: number | undefined;\n\treadonly iat?: number | undefined;\n\treadonly now?: number | undefined;\n\treadonly minLength?: number | undefined;\n\treadonly maxLength?: number | undefined;\n\treadonly receivedType?: string | undefined;\n\treadonly expectedType?: string | undefined;\n\treadonly [key: string]: unknown;\n}\n\n/**\n * Options for creating DatrixAuthError\n */\nexport interface DatrixAuthErrorOptions {\n\treadonly code: AuthErrorCode;\n\treadonly strategy?: AuthStrategy;\n\treadonly context?: AuthErrorContext | undefined;\n\treadonly cause?: Error | undefined;\n\treadonly suggestion?: string | undefined;\n\treadonly expected?: string | undefined;\n\treadonly received?: unknown | undefined;\n}\n\n/**\n * Serialized auth error for API responses\n */\nexport interface SerializedDatrixAuthError extends SerializedDatrixError {\n\treadonly strategy?: AuthStrategy;\n}\n\n/**\n * Datrix Auth Error Class\n *\n * Specialized DatrixError for authentication and authorization failures.\n * Includes strategy type for better debugging.\n *\n * @example\n * ```ts\n * throw new DatrixAuthError('JWT token expired', {\n * code: 'JWT_EXPIRED',\n * strategy: 'jwt',\n * context: { exp: 1234567890, now: 1234567900 },\n * suggestion: 'Refresh your token or login again'\n * });\n * ```\n */\nexport class DatrixAuthError extends DatrixError<AuthErrorContext> {\n\treadonly strategy?: AuthStrategy | undefined;\n\n\tconstructor(message: string, options: DatrixAuthErrorOptions) {\n\t\tsuper(message, {\n\t\t\tcode: options.code,\n\t\t\toperation: options.strategy ? `auth:${options.strategy}` : \"auth\",\n\t\t\tcontext: options.context,\n\t\t\tcause: options.cause,\n\t\t\tsuggestion: options.suggestion,\n\t\t\texpected: options.expected,\n\t\t\treceived: options.received,\n\t\t});\n\n\t\tthis.strategy = options.strategy;\n\t}\n\n\t/**\n\t * Override toJSON to include auth-specific fields\n\t */\n\toverride toJSON(): SerializedDatrixAuthError {\n\t\tconst json = super.toJSON();\n\n\t\tif (this.strategy) {\n\t\t\treturn {\n\t\t\t\t...json,\n\t\t\t\tstrategy: this.strategy,\n\t\t\t};\n\t\t}\n\n\t\treturn json;\n\t}\n\n\t/**\n\t * Override toDetailedMessage to include auth-specific fields\n\t */\n\toverride toDetailedMessage(): string {\n\t\tconst baseMessage = super.toDetailedMessage();\n\n\t\tif (this.strategy) {\n\t\t\tconst parts = baseMessage.split(\"\\n\");\n\t\t\tparts.splice(3, 0, ` Strategy: ${this.strategy}`);\n\t\t\treturn parts.join(\"\\n\");\n\t\t}\n\n\t\treturn baseMessage;\n\t}\n}\n","/**\n * Parser Error\n *\n * Specialized error for query/URL parsing failures.\n * Extends DatrixError with parser-specific fields.\n */\n\nimport { DatrixError, type SerializedDatrixError } from \"../datrix-error\";\n\n/**\n * Which parser generated the error\n */\nexport type ParserType =\n\t| \"where\"\n\t| \"populate\"\n\t| \"fields\"\n\t| \"sort\"\n\t| \"pagination\"\n\t| \"query\";\n\n/**\n * Error location with full path tracking\n */\nexport interface ErrorLocation {\n\treadonly path: string;\n\treadonly parts: readonly string[];\n\treadonly queryParam?: string | undefined;\n\treadonly index?: number | undefined;\n\treadonly depth?: number | undefined;\n}\n\n/**\n * Base error context\n */\nexport interface BaseErrorContext {\n\treadonly [key: string]: unknown;\n}\n\n/**\n * Where parser specific context\n */\nexport interface WhereErrorContext extends BaseErrorContext {\n\treadonly operator?: string;\n\treadonly operatorPath?: string;\n\treadonly validOperators?: readonly string[];\n\treadonly arrayIndex?: number;\n\treadonly previousOperator?: string;\n\treadonly fieldValidationReason?: string;\n}\n\n/**\n * Populate parser specific context\n */\nexport interface PopulateErrorContext extends BaseErrorContext {\n\treadonly relation?: string;\n\treadonly relationPath?: string;\n\treadonly currentDepth?: number;\n\treadonly maxDepth?: number;\n\treadonly nestedRelations?: readonly string[];\n\treadonly fieldValidationReason?: string;\n}\n\n/**\n * Fields parser specific context\n */\nexport interface FieldsErrorContext extends BaseErrorContext {\n\treadonly fieldName?: string;\n\treadonly invalidFields?: readonly string[];\n\treadonly validationReasons?: readonly string[];\n\treadonly suspiciousParams?: readonly string[];\n\treadonly fieldValidationReason?: string;\n}\n\n/**\n * Pagination parser specific context\n */\nexport interface PaginationErrorContext extends BaseErrorContext {\n\treadonly parameter?: \"page\" | \"pageSize\" | \"limit\" | \"offset\";\n\treadonly minValue?: number;\n\treadonly maxValue?: number;\n}\n\n/**\n * Sort parser specific context\n */\nexport interface SortErrorContext extends BaseErrorContext {\n\treadonly sortField?: string;\n\treadonly sortDirection?: string;\n\treadonly invalidFields?: readonly string[];\n\treadonly fieldValidationReason?: string;\n}\n\n/**\n * Union of all parser context types\n */\nexport type ParserErrorContext =\n\t| WhereErrorContext\n\t| PopulateErrorContext\n\t| FieldsErrorContext\n\t| PaginationErrorContext\n\t| SortErrorContext\n\t| BaseErrorContext;\n\n/**\n * Comprehensive parser error codes\n */\nexport type ParserErrorCode =\n\t| \"INVALID_SYNTAX\"\n\t| \"INVALID_OPERATOR\"\n\t| \"INVALID_VALUE_TYPE\"\n\t| \"INVALID_VALUE_FORMAT\"\n\t| \"INVALID_FIELD_NAME\"\n\t| \"INVALID_PATH\"\n\t| \"MAX_DEPTH_EXCEEDED\"\n\t| \"MAX_LENGTH_EXCEEDED\"\n\t| \"MAX_SIZE_EXCEEDED\"\n\t| \"MIN_VALUE_VIOLATION\"\n\t| \"MAX_VALUE_VIOLATION\"\n\t| \"MISSING_REQUIRED\"\n\t| \"EMPTY_VALUE\"\n\t| \"ARRAY_INDEX_ERROR\"\n\t| \"CONSECUTIVE_INDEX_ERROR\"\n\t| \"UNKNOWN_PARAMETER\"\n\t| \"DUPLICATE_FIELD\"\n\t| \"INVALID_PAGINATION\"\n\t| \"PAGE_OUT_OF_RANGE\"\n\t| \"PARSER_INTERNAL_ERROR\";\n\n/**\n * Options for creating ParserError\n */\nexport interface ParserErrorOptions {\n\treadonly code: ParserErrorCode;\n\treadonly parser: ParserType;\n\treadonly location: ErrorLocation;\n\treadonly context?: ParserErrorContext;\n\treadonly suggestion?: string;\n\treadonly received?: unknown;\n\treadonly expected?: string;\n}\n\n/**\n * Serialized parser error for API responses\n */\nexport interface SerializedParserError extends SerializedDatrixError {\n\treadonly parser: ParserType;\n\treadonly location: ErrorLocation;\n}\n\n/**\n * Parser Error Class\n *\n * Specialized DatrixError for query/URL parsing errors.\n * Includes parser-specific fields: parser type and location tracking.\n */\nexport class ParserError extends DatrixError<ParserErrorContext> {\n\treadonly parser: ParserType;\n\treadonly location: ErrorLocation;\n\n\tconstructor(message: string, options: ParserErrorOptions) {\n\t\tsuper(message, {\n\t\t\tcode: options.code,\n\t\t\toperation: `parse:${options.parser}`,\n\t\t\tcontext: options.context,\n\t\t\tsuggestion: options.suggestion,\n\t\t\texpected: options.expected,\n\t\t\treceived: options.received,\n\t\t});\n\n\t\tthis.parser = options.parser;\n\t\tthis.location = options.location;\n\t}\n\n\t/**\n\t * Override toJSON to include parser-specific fields\n\t */\n\toverride toJSON(): SerializedParserError {\n\t\treturn {\n\t\t\t...super.toJSON(),\n\t\t\tparser: this.parser,\n\t\t\tlocation: this.location,\n\t\t};\n\t}\n\n\t/**\n\t * Override toDetailedMessage to include parser-specific info\n\t */\n\toverride toDetailedMessage(): string {\n\t\tconst baseMessage = super.toDetailedMessage();\n\t\tconst parserInfo = [\n\t\t\t` Parser: ${this.parser}`,\n\t\t\t` Location: ${this.location.path}`,\n\t\t];\n\n\t\tif (this.location.queryParam) {\n\t\t\tparserInfo.push(` Query Param: ${this.location.queryParam}`);\n\t\t}\n\n\t\tif (this.location.index !== undefined) {\n\t\t\tparserInfo.push(` Index: ${this.location.index}`);\n\t\t}\n\n\t\tif (this.location.depth !== undefined) {\n\t\t\tparserInfo.push(` Depth: ${this.location.depth}`);\n\t\t}\n\n\t\t// Insert parser info after the first line\n\t\tconst lines = baseMessage.split(\"\\n\");\n\t\tlines.splice(1, 0, ...parserInfo);\n\n\t\treturn lines.join(\"\\n\");\n\t}\n}\n\n/**\n * Helper to build error location\n */\nexport function buildErrorLocation(\n\tparts: string[],\n\toptions?: {\n\t\tqueryParam?: string | undefined;\n\t\tindex?: number | undefined;\n\t\tdepth?: number | undefined;\n\t},\n): ErrorLocation {\n\treturn {\n\t\tpath: parts.join(\".\"),\n\t\tparts,\n\t\tqueryParam: options?.queryParam,\n\t\tindex: options?.index,\n\t\tdepth: options?.depth,\n\t};\n}\n","/**\n * Config Error\n *\n * Specialized error for configuration validation failures.\n * Extends DatrixError with config-specific fields.\n */\n\nimport { DatrixError, type SerializedDatrixError } from \"../datrix-error\";\n\n/**\n * Config error codes\n */\nexport type ConfigErrorCode =\n\t| \"CONFIG_NOT_FOUND\"\n\t| \"CONFIG_INVALID_TYPE\"\n\t| \"CONFIG_REQUIRED_FIELD\"\n\t| \"CONFIG_INVALID_VALUE\"\n\t| \"CONFIG_EMPTY_VALUE\"\n\t| \"CONFIG_VALIDATION_FAILED\"\n\t| \"CONFIG_MULTIPLE_ERRORS\";\n\n/**\n * Config error context\n */\nexport interface ConfigErrorContext {\n\treadonly field?: string;\n\treadonly validOptions?: readonly string[];\n\treadonly receivedType?: string;\n\treadonly expectedType?: string;\n\treadonly index?: number;\n\treadonly configPath?: string;\n\treadonly [key: string]: unknown;\n}\n\n/**\n * Options for creating DatrixConfigError\n */\nexport interface DatrixConfigErrorOptions {\n\treadonly code: ConfigErrorCode;\n\treadonly field?: string | undefined;\n\treadonly context?: ConfigErrorContext | undefined;\n\treadonly cause?: Error | undefined;\n\treadonly suggestion?: string | undefined;\n\treadonly expected?: string | undefined;\n\treadonly received?: unknown | undefined;\n}\n\n/**\n * Serialized config error for API responses\n */\nexport interface SerializedDatrixConfigError extends SerializedDatrixError {\n\treadonly field?: string;\n}\n\n/**\n * Datrix Config Error Class\n *\n * Specialized DatrixError for configuration validation failures.\n * Includes field name for identifying which config property failed.\n */\nexport class DatrixConfigError extends DatrixError<ConfigErrorContext> {\n\treadonly field?: string | undefined;\n\n\tconstructor(message: string, options: DatrixConfigErrorOptions) {\n\t\tsuper(message, {\n\t\t\tcode: options.code,\n\t\t\toperation: \"config:validate\",\n\t\t\tcontext: options.context,\n\t\t\tcause: options.cause,\n\t\t\tsuggestion: options.suggestion,\n\t\t\texpected: options.expected,\n\t\t\treceived: options.received,\n\t\t});\n\n\t\tthis.field = options.field;\n\t}\n\n\t/**\n\t * Override toJSON to include config-specific fields\n\t */\n\toverride toJSON(): SerializedDatrixConfigError {\n\t\treturn {\n\t\t\t...super.toJSON(),\n\t\t\t...(this.field && { field: this.field }),\n\t\t};\n\t}\n\n\t/**\n\t * Override toDetailedMessage to include config-specific info\n\t */\n\toverride toDetailedMessage(): string {\n\t\tconst baseMessage = super.toDetailedMessage();\n\n\t\tif (this.field) {\n\t\t\tconst configInfo = [` Field: ${this.field}`];\n\t\t\tconst lines = baseMessage.split(\"\\n\");\n\t\t\tlines.splice(1, 0, ...configInfo);\n\t\t\treturn lines.join(\"\\n\");\n\t\t}\n\n\t\treturn baseMessage;\n\t}\n}\n\n/**\n * Multiple config validation errors\n */\nexport class DatrixConfigValidationError extends DatrixConfigError {\n\treadonly errors: readonly string[];\n\n\tconstructor(errors: readonly string[], suggestion?: string) {\n\t\tconst errorList = errors.map((e) => ` - ${e}`).join(\"\\n\");\n\n\t\tsuper(`Config validation failed:\\n${errorList}`, {\n\t\t\tcode: \"CONFIG_VALIDATION_FAILED\",\n\t\t\tcontext: { errors },\n\t\t\tsuggestion: suggestion ?? \"Fix the validation errors listed above\",\n\t\t});\n\n\t\tthis.errors = errors;\n\t}\n\n\t/**\n\t * Override toDetailedMessage to include all errors\n\t */\n\toverride toDetailedMessage(): string {\n\t\tconst baseMessage = super.toDetailedMessage();\n\t\tconst errorDetails = this.errors.map((err) => ` - ${err}`);\n\n\t\treturn `${baseMessage}\\n\\nValidation Errors:\\n${errorDetails.join(\"\\n\")}`;\n\t}\n}\n","/**\n * CRUD Operation Error\n *\n * Specialized error for database CRUD operation failures.\n * Extends DatrixError with CRUD-specific fields.\n */\n\nimport { DatrixError, type SerializedDatrixError } from \"../datrix-error\";\n\n/**\n * CRUD operation types\n */\nexport type CrudOperation =\n\t| \"findOne\"\n\t| \"findById\"\n\t| \"findMany\"\n\t| \"count\"\n\t| \"create\"\n\t| \"update\"\n\t| \"updateMany\"\n\t| \"delete\"\n\t| \"deleteMany\";\n\n/**\n * CRUD error codes\n */\nexport type CrudErrorCode =\n\t| \"QUERY_EXECUTION_FAILED\"\n\t| \"SCHEMA_NOT_FOUND\"\n\t| \"RECORD_NOT_FOUND\"\n\t| \"INVALID_POPULATE_VALUE\"\n\t| \"RESERVED_FIELD_WRITE\"\n\t| \"NOT_IMPLEMENTED\"\n\t| \"QUERY_FAILED\";\n\n/**\n * CRUD error context\n */\nexport interface CrudErrorContext {\n\treadonly model?: string;\n\treadonly query?: Record<string, unknown>;\n\treadonly recordId?: string | number;\n\treadonly where?: Record<string, unknown>;\n\treadonly adapterError?: string;\n\treadonly [key: string]: unknown;\n}\n\n/**\n * Options for creating DatrixCrudError\n */\nexport interface DatrixCrudErrorOptions {\n\treadonly code: CrudErrorCode;\n\treadonly operation: CrudOperation;\n\treadonly model: string;\n\treadonly context?: CrudErrorContext | undefined;\n\treadonly cause?: Error | undefined;\n\treadonly suggestion?: string | undefined;\n\treadonly expected?: string | undefined;\n\treadonly received?: unknown | undefined;\n}\n\n/**\n * Serialized CRUD error for API responses\n */\nexport interface SerializedDatrixCrudError extends SerializedDatrixError {\n\treadonly operation: CrudOperation;\n\treadonly model: string;\n}\n\n/**\n * Datrix CRUD Error Class\n *\n * Specialized DatrixError for CRUD operation failures.\n * Includes operation type and model name for better debugging.\n */\nexport class DatrixCrudError extends DatrixError<CrudErrorContext> {\n\toverride readonly operation: CrudOperation;\n\treadonly model: string;\n\n\tconstructor(message: string, options: DatrixCrudErrorOptions) {\n\t\tsuper(message, {\n\t\t\tcode: options.code,\n\t\t\toperation: `crud:${options.operation}`,\n\t\t\tcontext: options.context,\n\t\t\tcause: options.cause,\n\t\t\tsuggestion: options.suggestion,\n\t\t\texpected: options.expected,\n\t\t\treceived: options.received,\n\t\t});\n\n\t\tthis.operation = options.operation;\n\t\tthis.model = options.model;\n\t}\n\n\t/**\n\t * Override toJSON to include CRUD-specific fields\n\t */\n\toverride toJSON(): SerializedDatrixCrudError {\n\t\treturn {\n\t\t\t...super.toJSON(),\n\t\t\toperation: this.operation,\n\t\t\tmodel: this.model,\n\t\t};\n\t}\n\n\t/**\n\t * Override toDetailedMessage to include CRUD-specific info\n\t */\n\toverride toDetailedMessage(): string {\n\t\tconst baseMessage = super.toDetailedMessage();\n\t\tconst crudInfo = [\n\t\t\t` Operation: ${this.operation}`,\n\t\t\t` Model: ${this.model}`,\n\t\t];\n\n\t\tconst lines = baseMessage.split(\"\\n\");\n\t\tlines.splice(1, 0, ...crudInfo);\n\n\t\treturn lines.join(\"\\n\");\n\t}\n}\n","/**\n * Query Builder Error\n *\n * Specialized error for query builder failures.\n * Covers all query builder components: builder, where, select, populate, pagination.\n */\n\nimport { DatrixError, type SerializedDatrixError } from \"../datrix-error\";\n\n/**\n * Query builder component types\n */\nexport type QueryBuilderComponent =\n\t| \"builder\"\n\t| \"where\"\n\t| \"select\"\n\t| \"populate\"\n\t| \"data\"\n\t| \"pagination\";\n\n/**\n * Query builder error codes\n */\nexport type QueryBuilderErrorCode =\n\t| \"INVALID_QUERY_TYPE\"\n\t| \"MISSING_TABLE\"\n\t| \"INVALID_FIELD\"\n\t| \"INVALID_OPERATOR\"\n\t| \"INVALID_VALUE\"\n\t| \"MAX_DEPTH_EXCEEDED\"\n\t| \"EMPTY_CLAUSE\"\n\t| \"DUPLICATE_FIELD\"\n\t| \"COERCION_FAILED\"\n\t| \"DELETE_WITHOUT_WHERE\"\n\t| \"MISSING_DATA\"\n\t| \"RELATION_IN_SELECT\"\n\t| \"SCHEMA_NOT_FOUND\"\n\t| \"UNKNOWN_FIELD\";\n\n/**\n * Query builder error context\n */\nexport interface QueryBuilderErrorContext {\n\treadonly field?: string | undefined;\n\treadonly operator?: string | undefined;\n\treadonly value?: unknown | undefined;\n\treadonly availableFields?: readonly string[] | undefined;\n\treadonly validOperators?: readonly string[] | undefined;\n\treadonly depth?: number | undefined;\n\treadonly maxDepth?: number | undefined;\n\treadonly [key: string]: unknown;\n}\n\n/**\n * Options for creating DatrixQueryBuilderError\n */\nexport interface DatrixQueryBuilderErrorOptions {\n\treadonly code: QueryBuilderErrorCode;\n\treadonly component: QueryBuilderComponent;\n\treadonly field?: string | undefined;\n\treadonly context?: QueryBuilderErrorContext | undefined;\n\treadonly cause?: Error | undefined;\n\treadonly suggestion?: string | undefined;\n\treadonly expected?: string | undefined;\n\treadonly received?: unknown | undefined;\n}\n\n/**\n * Serialized query builder error\n */\nexport interface SerializedDatrixQueryBuilderError extends SerializedDatrixError {\n\treadonly component: QueryBuilderComponent;\n\treadonly field?: string;\n}\n\n/**\n * Datrix Query Builder Error Class\n *\n * Specialized DatrixError for query builder failures.\n * Includes component type to identify which part of query building failed.\n */\nexport class DatrixQueryBuilderError extends DatrixError<QueryBuilderErrorContext> {\n\treadonly component: QueryBuilderComponent;\n\treadonly field?: string | undefined;\n\n\tconstructor(\n\t\tmessage: string,\n\t\toptions?: DatrixQueryBuilderErrorOptions | string,\n\t) {\n\t\t// Backward compatibility: if options is string, it's the old 'code' parameter\n\t\tconst normalizedOptions: DatrixQueryBuilderErrorOptions =\n\t\t\ttypeof options === \"string\" || options === undefined\n\t\t\t\t? {\n\t\t\t\t\tcode: (options as QueryBuilderErrorCode) || \"INVALID_VALUE\",\n\t\t\t\t\tcomponent: \"builder\",\n\t\t\t\t}\n\t\t\t\t: options;\n\n\t\tsuper(message, {\n\t\t\tcode: normalizedOptions.code,\n\t\t\toperation: `query-builder:${normalizedOptions.component}`,\n\t\t\tcontext: normalizedOptions.context,\n\t\t\tcause: normalizedOptions.cause,\n\t\t\tsuggestion: normalizedOptions.suggestion,\n\t\t\texpected: normalizedOptions.expected,\n\t\t\treceived: normalizedOptions.received,\n\t\t});\n\n\t\tthis.component = normalizedOptions.component;\n\t\tthis.field = normalizedOptions.field;\n\t}\n\n\t/**\n\t * Override toJSON to include query builder-specific fields\n\t */\n\toverride toJSON(): SerializedDatrixQueryBuilderError {\n\t\treturn {\n\t\t\t...super.toJSON(),\n\t\t\tcomponent: this.component,\n\t\t\t...(this.field && { field: this.field }),\n\t\t};\n\t}\n\n\t/**\n\t * Override toDetailedMessage to include query builder-specific info\n\t */\n\toverride toDetailedMessage(): string {\n\t\tconst baseMessage = super.toDetailedMessage();\n\t\tconst builderInfo = [` Component: ${this.component}`];\n\n\t\tif (this.field) {\n\t\t\tbuilderInfo.push(` Field: ${this.field}`);\n\t\t}\n\n\t\tconst lines = baseMessage.split(\"\\n\");\n\t\tlines.splice(1, 0, ...builderInfo);\n\n\t\treturn lines.join(\"\\n\");\n\t}\n}\n","/**\n * Datrix Validation Error\n *\n * Specialized error for data validation failures.\n * Extends DatrixError with structured validation error details.\n */\n\nimport {\n\tDatrixError,\n\ttype DatrixErrorOptions,\n\ttype SerializedDatrixError,\n} from \"../datrix-error\";\nimport type { ValidationError } from \"../../core/validator\";\n\n/**\n * Options for creating DatrixValidationError\n */\nexport interface DatrixValidationErrorOptions extends Partial<DatrixErrorOptions> {\n\treadonly model: string;\n\treadonly errors: readonly ValidationError[];\n}\n\n/**\n * Serialized validation error for API responses\n */\nexport interface SerializedDatrixValidationError extends SerializedDatrixError {\n\treadonly model: string;\n\treadonly errors: readonly ValidationError[];\n}\n\n/**\n * Datrix Validation Error Class\n *\n * Specialized DatrixError for schema validation failures.\n * Includes the model name and a list of specific validation errors.\n */\nexport class DatrixValidationError extends DatrixError {\n\treadonly model: string;\n\treadonly errors: readonly ValidationError[];\n\n\tconstructor(message: string, options: DatrixValidationErrorOptions) {\n\t\tsuper(message, {\n\t\t\tcode: options.code || \"VALIDATION_FAILED\",\n\t\t\toperation: options.operation || \"validation\",\n\t\t\tcontext: {\n\t\t\t\tmodel: options.model,\n\t\t\t\terrors: options.errors,\n\t\t\t\t...options.context,\n\t\t\t},\n\t\t\t...(options.suggestion && { suggestion: options.suggestion }),\n\t\t\t...(options.expected && { expected: options.expected }),\n\t\t\t...(options.received !== undefined && { received: options.received }),\n\t\t});\n\n\t\tthis.model = options.model;\n\t\tthis.errors = options.errors;\n\t}\n\n\t/**\n\t * Override toJSON to include validation-specific fields\n\t */\n\toverride toJSON(): SerializedDatrixValidationError {\n\t\treturn {\n\t\t\t...super.toJSON(),\n\t\t\tmodel: this.model,\n\t\t\terrors: this.errors,\n\t\t};\n\t}\n\n\t/**\n\t * Override toDetailedMessage to include field-specific errors\n\t */\n\toverride toDetailedMessage(): string {\n\t\tconst baseMessage = super.toDetailedMessage();\n\t\tconst errorDetails = this.errors.map(\n\t\t\t(err) => ` - ${err.field}: ${err.message} (${err.code})`,\n\t\t);\n\n\t\treturn `${baseMessage}\\n\\nValidation Details:\\n${errorDetails.join(\"\\n\")}`;\n\t}\n}\n","/**\n * Query Builder Error Helpers\n *\n * Centralized error creation for query builder operations.\n * Covers: builder, where, select, populate, pagination components.\n */\n\nimport {\n\tDatrixQueryBuilderError,\n\ttype QueryBuilderComponent,\n} from \"../types/errors\";\n\n/**\n * Throw invalid field error\n *\n * @param component - Query builder component\n * @param field - Field name\n * @param availableFields - List of valid fields\n *\n * @example\n * ```ts\n * throwInvalidField('select', 'invalidField', ['id', 'name', 'email']);\n * ```\n */\nexport function throwInvalidField(\n\tcomponent: QueryBuilderComponent,\n\tfield: string,\n\tavailableFields?: readonly string[],\n): never {\n\tthrow new DatrixQueryBuilderError(\n\t\t`Invalid field '${field}' in ${component} clause`,\n\t\t{\n\t\t\tcode: \"INVALID_FIELD\",\n\t\t\tcomponent,\n\t\t\tfield,\n\t\t\tcontext: availableFields ? { availableFields } : undefined,\n\t\t\tsuggestion: availableFields\n\t\t\t\t? `Use one of: ${availableFields.join(\", \")}`\n\t\t\t\t: `Check that '${field}' exists in the schema`,\n\t\t\texpected: availableFields ? availableFields.join(\" | \") : undefined,\n\t\t\treceived: field,\n\t\t},\n\t);\n}\n\n/**\n * Throw invalid operator error\n *\n * @param field - Field name\n * @param operator - Invalid operator\n * @param validOperators - List of valid operators\n *\n * @example\n * ```ts\n * throwInvalidOperator('age', '$invalid', ['$eq', '$ne', '$gt', '$lt']);\n * ```\n */\nexport function throwInvalidOperator(\n\tfield: string,\n\toperator: string,\n\tvalidOperators: readonly string[],\n): never {\n\tthrow new DatrixQueryBuilderError(\n\t\t`Invalid operator '${operator}' for field '${field}'`,\n\t\t{\n\t\t\tcode: \"INVALID_OPERATOR\",\n\t\t\tcomponent: \"where\",\n\t\t\tfield,\n\t\t\tcontext: { operator, validOperators },\n\t\t\tsuggestion: `Use one of: ${validOperators.join(\", \")}`,\n\t\t\texpected: validOperators.join(\" | \"),\n\t\t\treceived: operator,\n\t\t},\n\t);\n}\n\n/**\n * Throw invalid value error\n *\n * @param component - Query builder component\n * @param field - Field name\n * @param value - Invalid value\n * @param expectedType - Expected type\n *\n * @example\n * ```ts\n * throwInvalidValue('where', 'age', 'invalid', 'number');\n * ```\n */\nexport function throwInvalidValue(\n\tcomponent: QueryBuilderComponent,\n\tfield: string,\n\tvalue: unknown,\n\texpectedType: string,\n): never {\n\tconst receivedType = Array.isArray(value)\n\t\t? \"array\"\n\t\t: value === null\n\t\t\t? \"null\"\n\t\t\t: typeof value;\n\n\tthrow new DatrixQueryBuilderError(\n\t\t`Invalid value for field '${field}'. Expected ${expectedType}, got ${receivedType}`,\n\t\t{\n\t\t\tcode: \"INVALID_VALUE\",\n\t\t\tcomponent,\n\t\t\tfield,\n\t\t\tcontext: { value, expectedType, receivedType },\n\t\t\tsuggestion: `Provide a ${expectedType} value for '${field}'`,\n\t\t\texpected: expectedType,\n\t\t\treceived: value,\n\t\t},\n\t);\n}\n\n/**\n * Throw max depth exceeded error\n *\n * @param component - Query builder component\n * @param currentDepth - Current nesting depth\n * @param maxDepth - Maximum allowed depth\n *\n * @example\n * ```ts\n * throwMaxDepthExceeded('where', 11, 10);\n * ```\n */\nexport function throwMaxDepthExceeded(\n\tcomponent: QueryBuilderComponent,\n\tcurrentDepth: number,\n\tmaxDepth: number,\n): never {\n\tthrow new DatrixQueryBuilderError(\n\t\t`Maximum nesting depth exceeded in ${component} clause. Depth: ${currentDepth}, Max: ${maxDepth}`,\n\t\t{\n\t\t\tcode: \"MAX_DEPTH_EXCEEDED\",\n\t\t\tcomponent,\n\t\t\tcontext: { depth: currentDepth, maxDepth },\n\t\t\tsuggestion: `Reduce nesting depth to ${maxDepth} or less`,\n\t\t\texpected: `depth <= ${maxDepth}`,\n\t\t\treceived: currentDepth,\n\t\t},\n\t);\n}\n\n/**\n * Throw empty clause error\n *\n * @param component - Query builder component\n *\n * @example\n * ```ts\n * throwEmptyClause('select');\n * ```\n */\nexport function throwEmptyClause(component: QueryBuilderComponent): never {\n\tthrow new DatrixQueryBuilderError(`Empty ${component} clause`, {\n\t\tcode: \"EMPTY_CLAUSE\",\n\t\tcomponent,\n\t\tsuggestion: `Provide at least one item in ${component} clause`,\n\t});\n}\n\n/**\n * Throw duplicate field error\n *\n * @param component - Query builder component\n * @param field - Duplicate field name\n *\n * @example\n * ```ts\n * throwDuplicateField('select', 'email');\n * ```\n */\nexport function throwDuplicateField(\n\tcomponent: QueryBuilderComponent,\n\tfield: string,\n): never {\n\tthrow new DatrixQueryBuilderError(\n\t\t`Duplicate field '${field}' in ${component} clause`,\n\t\t{\n\t\t\tcode: \"DUPLICATE_FIELD\",\n\t\t\tcomponent,\n\t\t\tfield,\n\t\t\tsuggestion: `Remove duplicate '${field}' field`,\n\t\t},\n\t);\n}\n\n/**\n * Throw missing table error\n *\n * @example\n * ```ts\n * throwMissingTable();\n * ```\n */\nexport function throwMissingTable(): never {\n\tthrow new DatrixQueryBuilderError(\"Query must have a table name\", {\n\t\tcode: \"MISSING_TABLE\",\n\t\tcomponent: \"builder\",\n\t\tsuggestion:\n\t\t\t\"Call .from('tableName') or .table('tableName') before building\",\n\t});\n}\n\n/**\n * Throw missing WHERE clause error for DELETE queries\n */\nexport function throwDeleteWithoutWhere(): never {\n\tthrow new DatrixQueryBuilderError(\n\t\t\"DELETE query requires a WHERE clause. Use deleteAll() to delete all records explicitly.\",\n\t\t{\n\t\t\tcode: \"DELETE_WITHOUT_WHERE\",\n\t\t\tcomponent: \"builder\",\n\t\t\tsuggestion:\n\t\t\t\t\"Add .where() clause or use deleteAll() for full table deletion\",\n\t\t},\n\t);\n}\n\n/**\n * Throw missing data error for INSERT/UPDATE queries\n */\nexport function throwMissingData(queryType: \"insert\" | \"update\"): never {\n\tthrow new DatrixQueryBuilderError(\n\t\t`${queryType.toUpperCase()} query requires data`,\n\t\t{\n\t\t\tcode: \"MISSING_DATA\",\n\t\t\tcomponent: \"builder\",\n\t\t\tsuggestion:\n\t\t\t\tqueryType === \"insert\"\n\t\t\t\t\t? \"Provide at least one data item to insert\"\n\t\t\t\t\t: \"Provide data object with fields to update\",\n\t\t},\n\t);\n}\n\n/**\n * Throw invalid query type error\n *\n * @param receivedType - Received query type\n *\n * @example\n * ```ts\n * throwInvalidQueryType('invalid');\n * ```\n */\nexport function throwInvalidQueryType(receivedType: unknown): never {\n\tthrow new DatrixQueryBuilderError(`Invalid query type: ${receivedType}`, {\n\t\tcode: \"INVALID_QUERY_TYPE\",\n\t\tcomponent: \"builder\",\n\t\tsuggestion: \"Use one of: select, insert, update, delete, count\",\n\t\texpected: \"select | insert | update | delete | count\",\n\t\treceived: receivedType,\n\t});\n}\n\n/**\n * Throw schema not found error\n *\n * @param modelName - Model name that was not found\n *\n * @example\n * ```ts\n * throwSchemaNotFound('InvalidModel');\n * ```\n */\nexport function throwSchemaNotFound(modelName: string): never {\n\tthrow new DatrixQueryBuilderError(`Schema not found for model: ${modelName}`, {\n\t\tcode: \"SCHEMA_NOT_FOUND\",\n\t\tcomponent: \"builder\",\n\t\tcontext: { modelName },\n\t\tsuggestion: `Check that '${modelName}' is registered in the schema registry`,\n\t\treceived: modelName,\n\t});\n}\n\n/**\n * Throw multiple invalid fields error\n *\n * @param component - Query builder component\n * @param invalidFields - List of invalid field names\n * @param availableFields - List of valid fields\n *\n * @example\n * ```ts\n * throwInvalidFields('select', ['field1', 'field2'], ['id', 'name', 'email']);\n * ```\n */\nexport function throwInvalidFields(\n\tcomponent: QueryBuilderComponent,\n\tinvalidFields: readonly string[],\n\tavailableFields?: readonly string[],\n): never {\n\tconst fieldList = invalidFields.join(\", \");\n\tthrow new DatrixQueryBuilderError(\n\t\t`Invalid field(s) in ${component} clause: ${fieldList}`,\n\t\t{\n\t\t\tcode: \"INVALID_FIELD\",\n\t\t\tcomponent,\n\t\t\tfield: invalidFields[0],\n\t\t\tcontext: { invalidFields, availableFields },\n\t\t\tsuggestion: availableFields\n\t\t\t\t? `Use one of: ${availableFields.join(\", \")}`\n\t\t\t\t: `Check that these fields exist in the schema`,\n\t\t\texpected: availableFields ? availableFields.join(\" | \") : undefined,\n\t\t\treceived: fieldList,\n\t\t},\n\t);\n}\n\n/**\n * Throw relation field in select error\n *\n * @param relationFields - List of relation field names\n * @param modelName - Model name\n *\n * @example\n * ```ts\n * throwRelationInSelect(['category', 'author'], 'Product');\n * ```\n */\nexport function throwRelationInSelect(\n\trelationFields: readonly string[],\n\tmodelName: string,\n): never {\n\tconst fieldList = relationFields.join(\", \");\n\tthrow new DatrixQueryBuilderError(\n\t\t`Cannot select relation field(s) in model '${modelName}': ${fieldList}. Use populate() to include relations.`,\n\t\t{\n\t\t\tcode: \"RELATION_IN_SELECT\",\n\t\t\tcomponent: \"select\",\n\t\t\tfield: relationFields[0],\n\t\t\tcontext: { relationFields, modelName },\n\t\t\tsuggestion: `Use .populate('${relationFields[0]}') instead of selecting it`,\n\t\t},\n\t);\n}\n\n/**\n * Throw type coercion failed error\n *\n * @param field - Field name\n * @param value - Value that failed coercion\n * @param expectedType - Expected type\n *\n * @example\n * ```ts\n * throwCoercionFailed('price', 'invalid', 'number');\n * // Error: Cannot convert value 'invalid' to number for field 'price'\n * ```\n */\nexport function throwCoercionFailed(\n\tfield: string,\n\tvalue: unknown,\n\texpectedType: string,\n): never {\n\tconst displayValue = typeof value === \"string\" ? `'${value}'` : String(value);\n\tthrow new DatrixQueryBuilderError(\n\t\t`Cannot convert value ${displayValue} to ${expectedType} for field '${field}'`,\n\t\t{\n\t\t\tcode: \"COERCION_FAILED\",\n\t\t\tcomponent: \"where\",\n\t\t\tfield,\n\t\t\tcontext: { value, expectedType, receivedType: typeof value },\n\t\t\tsuggestion: `Provide a valid ${expectedType} value for '${field}'`,\n\t\t\texpected: expectedType,\n\t\t\treceived: value,\n\t\t},\n\t);\n}\n","/**\n * WHERE Clause Builder\n *\n * All WHERE-related operations: merging, validation, normalization.\n * Handles comparison operators, logical operators, nested conditions, and relation shortcuts.\n */\n\nimport type {\n\tComparisonOperators,\n\tWhereClause,\n} from \"../types/core/query-builder\";\nimport type {\n\tFieldType,\n\tSchemaDefinition,\n\tRelationField,\n\tISchemaRegistry,\n\tDatrixEntry,\n\tFieldDefinition,\n} from \"../types/core/schema\";\nimport {\n\tthrowInvalidOperator,\n\tthrowInvalidValue,\n\tthrowMaxDepthExceeded,\n\tthrowInvalidField,\n\tthrowCoercionFailed,\n} from \"./error-helper\";\n\n/**\n * All supported comparison operators\n */\nexport const COMPARISON_OPERATORS = [\n\t\"$eq\",\n\t\"$ne\",\n\t\"$gt\",\n\t\"$gte\",\n\t\"$lt\",\n\t\"$lte\",\n\t\"$in\",\n\t\"$nin\",\n\t\"$like\",\n\t\"$ilike\",\n\t\"$startsWith\",\n\t\"$endsWith\",\n\t\"$contains\",\n\t\"$notContains\",\n\t\"$icontains\",\n\t\"$regex\",\n\t\"$exists\",\n\t\"$null\",\n\t\"$notNull\",\n] as const;\n\n/**\n * Operators that always expect boolean values\n */\nconst BOOLEAN_OPERATORS = [\"$exists\", \"$null\", \"$notNull\"] as const;\n\n/**\n * Operators that always expect string values (regardless of field type)\n */\nconst STRING_OPERATORS = [\n\t\"$like\",\n\t\"$ilike\",\n\t\"$startsWith\",\n\t\"$endsWith\",\n\t\"$contains\",\n\t\"$notContains\",\n\t\"$icontains\",\n\t\"$regex\",\n] as const;\n\n/**\n * Coerce a value to the expected field type\n *\n * API'den gelen string değerleri schema'daki field tipine göre dönüştürür.\n *\n * @param value - The value to coerce (often a string from API)\n * @param fieldDef - Field definition from schema\n * @param fieldName - Field name for error messages\n * @returns Coerced value in the correct type\n * @throws {DatrixQueryBuilderError} If coercion fails\n *\n * @example\n * ```ts\n * coerceValue(\"100\", { type: \"number\" }, \"price\") // → 100\n * coerceValue(\"true\", { type: \"boolean\" }, \"active\") // → true\n * coerceValue(\"2024-01-01\", { type: \"date\" }, \"createdAt\") // → Date object\n * coerceValue(\"hello\", { type: \"number\" }, \"price\") // → throws error\n * ```\n */\nexport function coerceValue(\n\tvalue: unknown,\n\tfieldDef: FieldDefinition,\n\tfieldName: string,\n): unknown {\n\t// null/undefined pass through\n\tif (value === null || value === undefined) {\n\t\treturn value;\n\t}\n\n\t// Already correct type - no coercion needed\n\tif (isCorrectType(value, fieldDef.type)) {\n\t\treturn value;\n\t}\n\n\t// String coercion based on field type\n\tif (typeof value === \"string\") {\n\t\treturn coerceString(value, fieldDef.type, fieldName);\n\t}\n\n\t// Array coercion (for $in, $nin operators)\n\tif (Array.isArray(value)) {\n\t\treturn value.map((item) => coerceValue(item, fieldDef, fieldName));\n\t}\n\n\t// Value is not string and not correct type - error\n\tthrowCoercionFailed(fieldName, value, fieldDef.type);\n}\n\n/**\n * Check if value is already the correct type\n *\n * Supports all FieldType values from schema.ts:\n * string, number, boolean, date, json, enum, array, relation, file\n */\nfunction isCorrectType(value: unknown, fieldType: FieldType): boolean {\n\tswitch (fieldType) {\n\t\tcase \"string\":\n\t\tcase \"enum\":\n\t\tcase \"file\":\n\t\t\treturn typeof value === \"string\";\n\t\tcase \"number\":\n\t\t\treturn typeof value === \"number\" && !Number.isNaN(value);\n\t\tcase \"boolean\":\n\t\t\treturn typeof value === \"boolean\";\n\t\tcase \"date\":\n\t\t\treturn value instanceof Date && !Number.isNaN(value.getTime());\n\t\tcase \"json\":\n\t\t\treturn typeof value === \"object\";\n\t\tcase \"array\":\n\t\t\treturn Array.isArray(value);\n\t\tcase \"relation\":\n\t\t\treturn typeof value === \"number\" || typeof value === \"string\";\n\t\tdefault:\n\t\t\treturn true;\n\t}\n}\n\n/**\n * Coerce string value to target type\n *\n * Supports all FieldType values from schema.ts:\n * string, number, boolean, date, json, enum, array, relation, file\n */\nfunction coerceString(\n\tvalue: string,\n\tfieldType: FieldType,\n\tfieldName: string,\n): unknown {\n\tswitch (fieldType) {\n\t\tcase \"string\":\n\t\tcase \"enum\":\n\t\tcase \"file\":\n\t\t\treturn value;\n\n\t\tcase \"number\": {\n\t\t\tconst num = Number(value);\n\t\t\tif (Number.isNaN(num)) {\n\t\t\t\tthrowCoercionFailed(fieldName, value, \"number\");\n\t\t\t}\n\t\t\treturn num;\n\t\t}\n\n\t\tcase \"boolean\": {\n\t\t\tconst lower = value.toLowerCase();\n\t\t\tif (lower === \"true\" || lower === \"1\") {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tif (lower === \"false\" || lower === \"0\") {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tthrowCoercionFailed(fieldName, value, \"boolean\");\n\t\t}\n\n\t\tcase \"date\": {\n\t\t\tconst date = new Date(value);\n\t\t\tif (Number.isNaN(date.getTime())) {\n\t\t\t\tthrowCoercionFailed(fieldName, value, \"date\");\n\t\t\t}\n\t\t\treturn date;\n\t\t}\n\n\t\tcase \"json\": {\n\t\t\ttry {\n\t\t\t\treturn JSON.parse(value);\n\t\t\t} catch {\n\t\t\t\tthrowCoercionFailed(fieldName, value, \"json\");\n\t\t\t}\n\t\t}\n\n\t\tcase \"array\": {\n\t\t\ttry {\n\t\t\t\tconst parsed = JSON.parse(value);\n\t\t\t\tif (!Array.isArray(parsed)) {\n\t\t\t\t\tthrowCoercionFailed(fieldName, value, \"array\");\n\t\t\t\t}\n\t\t\t\treturn parsed;\n\t\t\t} catch {\n\t\t\t\tthrowCoercionFailed(fieldName, value, \"array\");\n\t\t\t}\n\t\t}\n\n\t\tcase \"relation\": {\n\t\t\t// Try to parse as number first, otherwise keep as string ID\n\t\t\tconst num = Number(value);\n\t\t\treturn Number.isNaN(num) ? value : num;\n\t\t}\n\n\t\tdefault:\n\t\t\treturn value;\n\t}\n}\n\n/**\n * Maximum nesting depth for WHERE clauses to prevent stack overflow\n */\nconst MAX_WHERE_DEPTH = 10;\n\n/**\n * Check if value is a comparison operator object\n */\nexport function isComparisonOperators(\n\tvalue: unknown,\n): value is ComparisonOperators {\n\tif (typeof value !== \"object\" || value === null) {\n\t\treturn false;\n\t}\n\n\treturn Object.keys(value).some((key) =>\n\t\t(COMPARISON_OPERATORS as readonly string[]).includes(key),\n\t);\n}\n\n/**\n * Check if value is a logical operator\n */\nexport function isLogicalOperator(key: string): boolean {\n\treturn [\"$and\", \"$or\", \"$not\"].includes(key);\n}\n\n/**\n * Validate comparison operator value\n *\n * Note: This validation is lenient for string values because coercion\n * happens in normalizeWhereClause and will convert strings to proper types.\n * We only validate structural correctness here (e.g., $in must be array).\n *\n * @throws {DatrixQueryBuilderError} If operator or value is invalid\n */\nexport function validateComparisonOperator(\n\tfield: string,\n\toperator: string,\n\tvalue: unknown,\n\t_fieldType: FieldType,\n): void {\n\tswitch (operator) {\n\t\tcase \"$eq\":\n\t\tcase \"$ne\":\n\t\t\t// Any primitive is valid (strings will be coerced later)\n\t\t\tif (\n\t\t\t\ttypeof value !== \"string\" &&\n\t\t\t\ttypeof value !== \"number\" &&\n\t\t\t\ttypeof value !== \"boolean\" &&\n\t\t\t\tvalue !== null &&\n\t\t\t\t!(value instanceof Date)\n\t\t\t) {\n\t\t\t\tthrowInvalidValue(\"where\", field, value, \"primitive value\");\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase \"$gt\":\n\t\tcase \"$gte\":\n\t\tcase \"$lt\":\n\t\tcase \"$lte\":\n\t\t\t// Numbers, dates, or strings (strings will be coerced to number/date)\n\t\t\tif (\n\t\t\t\ttypeof value !== \"number\" &&\n\t\t\t\ttypeof value !== \"string\" &&\n\t\t\t\t!(value instanceof Date)\n\t\t\t) {\n\t\t\t\tthrowInvalidValue(\"where\", field, value, \"number, Date, or string\");\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase \"$in\":\n\t\tcase \"$nin\":\n\t\t\t// Array of primitives\n\t\t\tif (!Array.isArray(value)) {\n\t\t\t\tthrowInvalidValue(\"where\", field, value, \"array\");\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase \"$like\":\n\t\tcase \"$ilike\":\n\t\tcase \"$contains\":\n\t\tcase \"$icontains\":\n\t\tcase \"$notContains\":\n\t\tcase \"$startsWith\":\n\t\tcase \"$endsWith\":\n\t\t\t// String only\n\t\t\tif (typeof value !== \"string\") {\n\t\t\t\tthrowInvalidValue(\"where\", field, value, \"string\");\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase \"$regex\":\n\t\t\t// RegExp or string\n\t\t\tif (!(value instanceof RegExp) && typeof value !== \"string\") {\n\t\t\t\tthrowInvalidValue(\"where\", field, value, \"RegExp or string\");\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase \"$exists\":\n\t\tcase \"$null\":\n\t\tcase \"$notNull\":\n\t\t\t// Boolean or string (strings like \"true\"/\"false\" will be coerced)\n\t\t\tif (typeof value !== \"boolean\" && typeof value !== \"string\") {\n\t\t\t\tthrowInvalidValue(\"where\", field, value, \"boolean or string\");\n\t\t\t}\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tthrowInvalidOperator(field, operator, COMPARISON_OPERATORS);\n\t}\n}\n\n/**\n * Validate where clause against schema\n * @param where - WHERE clause to validate\n * @param schema - Schema definition\n * @param schemaRegistry - Schema registry for nested relation validation\n * @param depth - Current nesting depth\n * @throws {DatrixQueryBuilderError} If where clause is invalid\n */\nexport function validateWhereClause<T extends DatrixEntry>(\n\twhere: WhereClause<T>,\n\tschema: SchemaDefinition,\n\tschemaRegistry?: ISchemaRegistry,\n\tdepth = 0,\n): void {\n\t// Check depth limit\n\tif (depth > MAX_WHERE_DEPTH) {\n\t\tthrowMaxDepthExceeded(\"where\", depth, MAX_WHERE_DEPTH);\n\t}\n\n\tconst availableFields = Object.keys(schema.fields);\n\n\tfor (const [key, value] of Object.entries(where)) {\n\t\t// Handle logical operators\n\t\tif (isLogicalOperator(key)) {\n\t\t\tif (key === \"$and\" || key === \"$or\") {\n\t\t\t\tif (!Array.isArray(value)) {\n\t\t\t\t\tthrowInvalidValue(\"where\", key, value, \"array of conditions\");\n\t\t\t\t}\n\n\t\t\t\t// Recursively validate each condition\n\t\t\t\tfor (const condition of value as readonly WhereClause<T>[]) {\n\t\t\t\t\tvalidateWhereClause(condition, schema, schemaRegistry, depth + 1);\n\t\t\t\t}\n\t\t\t} else if (key === \"$not\") {\n\t\t\t\t// Recursively validate nested condition\n\t\t\t\tvalidateWhereClause(\n\t\t\t\t\tvalue as WhereClause<T>,\n\t\t\t\t\tschema,\n\t\t\t\t\tschemaRegistry,\n\t\t\t\t\tdepth + 1,\n\t\t\t\t);\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Check field exists in schema\n\t\tif (!availableFields.includes(key)) {\n\t\t\tthrowInvalidField(\"where\", key, availableFields);\n\t\t}\n\n\t\tconst fieldDef = schema.fields[key]!;\n\n\t\t// Handle relation fields\n\t\tif (fieldDef.type === \"relation\") {\n\t\t\tconst relationField = fieldDef as RelationField;\n\n\t\t\t// Primitive value shortcut: { category: 2 }\n\t\t\tif (typeof value === \"string\" || typeof value === \"number\") {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Object value - could be $null/$notNull or nested WHERE\n\t\t\tif (\n\t\t\t\ttypeof value === \"object\" &&\n\t\t\t\tvalue !== null &&\n\t\t\t\t!(value instanceof Date)\n\t\t\t) {\n\t\t\t\tconst valueObj = value as Record<string, unknown>;\n\t\t\t\tconst keys = Object.keys(valueObj);\n\n\t\t\t\t// Check for $null or $notNull operators on relation (FK null check)\n\t\t\t\t// { organization: { $null: true } } - valid for belongsTo/hasOne\n\t\t\t\tif (\n\t\t\t\t\tkeys.length === 1 &&\n\t\t\t\t\t(keys[0] === \"$null\" || keys[0] === \"$notNull\")\n\t\t\t\t) {\n\t\t\t\t\tconst opValue = valueObj[keys[0]];\n\t\t\t\t\t// Validate that the value is boolean or string that can be coerced\n\t\t\t\t\tif (typeof opValue !== \"boolean\" && typeof opValue !== \"string\") {\n\t\t\t\t\t\tthrowInvalidValue(\"where\", key, opValue, \"boolean or string\");\n\t\t\t\t\t}\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// Nested WHERE for relation - validate against target schema\n\t\t\t\tif (schemaRegistry) {\n\t\t\t\t\tconst targetSchema = schemaRegistry.get(relationField.model);\n\t\t\t\t\tif (targetSchema) {\n\t\t\t\t\t\tvalidateWhereClause(\n\t\t\t\t\t\t\tvalue as WhereClause<T>,\n\t\t\t\t\t\t\ttargetSchema,\n\t\t\t\t\t\t\tschemaRegistry,\n\t\t\t\t\t\t\tdepth + 1,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Handle comparison operators\n\t\tif (isComparisonOperators(value)) {\n\t\t\tconst ops = value as ComparisonOperators;\n\t\t\tfor (const [operator, opValue] of Object.entries(ops)) {\n\t\t\t\tvalidateComparisonOperator(key, operator, opValue, fieldDef.type);\n\t\t\t}\n\t\t}\n\t\t// Simple equality check\n\t\telse {\n\t\t\t// Validate primitive value\n\t\t\tif (\n\t\t\t\ttypeof value !== \"string\" &&\n\t\t\t\ttypeof value !== \"number\" &&\n\t\t\t\ttypeof value !== \"boolean\" &&\n\t\t\t\tvalue !== null &&\n\t\t\t\t!(value instanceof Date)\n\t\t\t) {\n\t\t\t\tthrowInvalidValue(\"where\", key, value, \"primitive value\");\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * Normalize and validate WHERE arrays\n *\n * Complete WHERE processing pipeline:\n * 1. Merge multiple .where() calls with $and\n * 2. Validate fields and operators (BEFORE normalization)\n * - Including nested relation WHERE validation\n * 3. Normalize relation shortcuts (category: 2 → categoryId: { $eq: 2 })\n * 4. Recursively process logical operators ($and, $or, $not)\n *\n * @param wheres - Array of where clauses from multiple .where() calls\n * @param schema - Schema definition for validation and normalization\n * @param registry - Schema registry for nested relation validation\n * @returns Normalized and validated WHERE clause\n *\n * @example\n * ```ts\n * // Multiple where calls\n * normalizeWhere([{ age: { $gte: 18 } }, { role: 'admin' }], schema, registry)\n * // → { $and: [{ age: { $gte: 18 } }, { role: 'admin' }] }\n *\n * // Relation shortcut normalization\n * normalizeWhere([{ category: 2 }], productSchema, registry)\n * // → { categoryId: { $eq: 2 } }\n *\n * // Nested relation WHERE validation\n * normalizeWhere([{ category: { invalidField: 'value' } }], productSchema, registry)\n * // → throws DatrixQueryBuilderError (invalidField doesn't exist in Category schema)\n *\n * // Validation errors caught first\n * normalizeWhere([{ invalidField: 'value' }], schema, registry)\n * // → throws DatrixQueryBuilderError (BEFORE normalization)\n * ```\n */\nexport function normalizeWhere<T extends DatrixEntry>(\n\twheres: WhereClause<T>[] | undefined,\n\tschema: SchemaDefinition,\n\tregistry: ISchemaRegistry,\n): WhereClause<T> | undefined {\n\tif (!wheres || wheres.length === 0) {\n\t\treturn undefined;\n\t}\n\n\t// 1. Merge multiple where clauses with $and\n\tlet mergedWhere: WhereClause<T>;\n\tif (wheres.length === 1) {\n\t\tmergedWhere = wheres[0]!;\n\t} else {\n\t\tmergedWhere = { $and: wheres } as WhereClause<T>;\n\t}\n\n\t// 2. Validate BEFORE normalization (catches errors early)\n\t// Including nested relation WHERE validation\n\tvalidateWhereClause(mergedWhere, schema, registry);\n\n\t// 3. Normalize relation shortcuts and logical operators\n\treturn normalizeWhereClause(mergedWhere, schema, registry);\n}\n\n/**\n * Normalize WHERE clause recursively\n *\n * Internal function that handles:\n * - Type coercion: \"100\" → 100 (based on field type)\n * - Relation shortcuts: { category: 2 } → { categoryId: { $eq: 2 } }\n * - Nested relation WHERE: Recursively normalize target schema\n * - Logical operators: Recursively process $and, $or, $not\n * - Comparison operators: Coerce values inside $eq, $gt, $in, etc.\n *\n * @param where - WHERE clause to normalize\n * @param schema - Schema definition\n * @param registry - Schema registry for nested relation schemas\n * @returns Normalized WHERE clause with coerced values\n */\nfunction normalizeWhereClause<T extends DatrixEntry>(\n\twhere: WhereClause<T>,\n\tschema: SchemaDefinition,\n\tregistry: ISchemaRegistry,\n): WhereClause<T> {\n\tconst normalized: Record<string, unknown> = {};\n\n\tfor (const [key, value] of Object.entries(where)) {\n\t\t// Handle logical operators recursively\n\t\tif (key === \"$and\" || key === \"$or\") {\n\t\t\tnormalized[key] = (value as WhereClause<T>[]).map((clause) =>\n\t\t\t\tnormalizeWhereClause(clause, schema, registry),\n\t\t\t);\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (key === \"$not\") {\n\t\t\tnormalized[key] = normalizeWhereClause(\n\t\t\t\tvalue as WhereClause<T>,\n\t\t\t\tschema,\n\t\t\t\tregistry,\n\t\t\t);\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Get field definition\n\t\tconst fieldDef = schema.fields[key];\n\t\tif (!fieldDef) {\n\t\t\t// Unknown field - keep as-is (validation will catch this)\n\t\t\tnormalized[key] = value;\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Handle relation fields\n\t\tif (fieldDef.type === \"relation\") {\n\t\t\tconst relationField = fieldDef as RelationField;\n\t\t\tconst kind = relationField.kind;\n\n\t\t\t// Only normalize for belongsTo/hasOne (they have FK in current table)\n\t\t\tif (kind === \"belongsTo\" || kind === \"hasOne\") {\n\t\t\t\tconst foreignKey = relationField.foreignKey!;\n\n\t\t\t\t// Primitive value shortcut: { category: 2 } → { categoryId: { $eq: 2 } }\n\t\t\t\tif (typeof value === \"string\" || typeof value === \"number\") {\n\t\t\t\t\tconst coercedValue = coerceValue(value, { type: \"number\" }, key);\n\t\t\t\t\tnormalized[foreignKey] = { $eq: coercedValue };\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// Object value - check if it's $null/$notNull operator for FK\n\t\t\t\tif (\n\t\t\t\t\ttypeof value === \"object\" &&\n\t\t\t\t\tvalue !== null &&\n\t\t\t\t\t!(value instanceof Date)\n\t\t\t\t) {\n\t\t\t\t\tconst valueObj = value as Record<string, unknown>;\n\t\t\t\t\tconst keys = Object.keys(valueObj);\n\n\t\t\t\t\t// Check for $null or $notNull operators on relation\n\t\t\t\t\t// { organization: { $null: true } } → { organizationId: { $null: true } }\n\t\t\t\t\tif (\n\t\t\t\t\t\tkeys.length === 1 &&\n\t\t\t\t\t\t(keys[0] === \"$null\" || keys[0] === \"$notNull\")\n\t\t\t\t\t) {\n\t\t\t\t\t\tconst operator = keys[0];\n\t\t\t\t\t\tconst operatorValue = valueObj[operator];\n\t\t\t\t\t\tconst coercedValue = coerceValue(\n\t\t\t\t\t\t\toperatorValue,\n\t\t\t\t\t\t\t{ type: \"boolean\" },\n\t\t\t\t\t\t\tkey,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tnormalized[foreignKey] = { [operator]: coercedValue };\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Nested WHERE - recursively normalize with target schema\n\t\t\t\t\tconst targetSchema = registry.get(relationField.model);\n\t\t\t\t\tif (targetSchema) {\n\t\t\t\t\t\tnormalized[key] = normalizeWhereClause(\n\t\t\t\t\t\t\tvalue as WhereClause<T>,\n\t\t\t\t\t\t\ttargetSchema,\n\t\t\t\t\t\t\tregistry,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// hasMany/manyToMany or fallback: keep as-is\n\t\t\tnormalized[key] = value;\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Handle comparison operators - coerce values inside\n\t\tif (isComparisonOperators(value)) {\n\t\t\tconst coercedOps: Record<string, unknown> = {};\n\t\t\tfor (const [operator, opValue] of Object.entries(\n\t\t\t\tvalue as ComparisonOperators,\n\t\t\t)) {\n\t\t\t\t// Boolean operators - $exists, $null, $notNull\n\t\t\t\tif ((BOOLEAN_OPERATORS as readonly string[]).includes(operator)) {\n\t\t\t\t\tcoercedOps[operator] = coerceValue(opValue, { type: \"boolean\" }, key);\n\t\t\t\t}\n\t\t\t\t// String operators - always keep as string regardless of field type\n\t\t\t\telse if ((STRING_OPERATORS as readonly string[]).includes(operator)) {\n\t\t\t\t\tcoercedOps[operator] = opValue; // Keep as string\n\t\t\t\t}\n\t\t\t\t// All other operators - coerce based on field type\n\t\t\t\telse {\n\t\t\t\t\tcoercedOps[operator] = coerceValue(opValue, fieldDef, key);\n\t\t\t\t}\n\t\t\t}\n\t\t\tnormalized[key] = coercedOps;\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Simple equality - coerce based on field type\n\t\tnormalized[key] = coerceValue(value, fieldDef, key);\n\t}\n\n\treturn normalized as WhereClause<T>;\n}\n","/**\n * SELECT Utilities\n *\n * All SELECT-related operations: merging, validation, normalization.\n */\n\nimport type { QuerySelect, SelectClause } from \"../types/core/query-builder\";\nimport type {\n\tDatrixEntry,\n\tSchemaDefinition,\n\tISchemaRegistry,\n} from \"../types/core/schema\";\nimport { throwInvalidFields, throwRelationInSelect } from \"./error-helper\";\n\n/**\n * Normalize and validate SELECT arrays\n *\n * Complete SELECT processing pipeline:\n * 1. Merge multiple .select() calls into one\n * 2. Deduplicate using Set\n * 3. If any is \"*\", expand to cached fields from registry\n * 4. Validate fields exist and are not relations\n * 5. Add reserved fields (id, createdAt, updatedAt)\n * 6. Always return array (never \"*\")\n *\n * @param selects - Array of select clauses from multiple .select() calls\n * @param schema - Schema definition for validation\n * @param modelName - Model name for error messages and cache lookup\n * @param registry - Schema registry for wildcard expansion\n * @returns Normalized, validated field array with reserved fields\n *\n * @example\n * ```ts\n * // Multiple selects\n * normalizeSelect([['name'], ['price'], ['name']], schema, 'Product', registry)\n * // → ['name', 'price', 'id', 'createdAt', 'updatedAt']\n *\n * // Wildcard expansion\n * normalizeSelect([['name'], '*'], schema, 'Product', registry)\n * // → ['id', 'name', 'price', 'stock', 'createdAt', 'updatedAt'] (from cache)\n *\n * // Validation errors\n * normalizeSelect([['invalidField']], schema, 'Product', registry)\n * // → throws DatrixQueryBuilderError\n *\n * normalizeSelect([['category']], schema, 'Product', registry)\n * // → throws DatrixQueryBuilderError (relation field)\n * ```\n */\nexport function normalizeSelect<T extends DatrixEntry>(\n\tselects: SelectClause<T>[] | undefined,\n\tschema: SchemaDefinition,\n\tregistry: ISchemaRegistry,\n): QuerySelect<T> {\n\t// If no selects provided, return cached fields for \"*\"\n\tif (!selects || selects.length === 0) {\n\t\treturn registry.getCachedSelectFields<T>(schema.name);\n\t}\n\n\t// 1. Flatten and deduplicate using Set (preserves insertion order)\n\tconst allFields = new Set<keyof T>();\n\tfor (const select of selects) {\n\t\tif (Array.isArray(select)) {\n\t\t\tselect.forEach((field) => allFields.add(field));\n\t\t}\n\t}\n\n\tconst fieldArray = Array.from(allFields);\n\n\t// 2. Validate fields (BEFORE wildcard check)\n\t// This ensures invalid fields are caught even if wildcard is present\n\tconst invalidFields: string[] = [];\n\tconst relationFields: string[] = [];\n\n\tfor (const fieldName of fieldArray) {\n\t\tconst field = schema.fields[fieldName as string];\n\n\t\t// Field doesn't exist in schema\n\t\tif (!field) {\n\t\t\tinvalidFields.push(fieldName as string);\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Field is a relation type\n\t\tif (field.type === \"relation\") {\n\t\t\trelationFields.push(fieldName as string);\n\t\t}\n\t}\n\n\t// Throw if validation failed\n\tif (invalidFields.length > 0) {\n\t\tconst availableFields = Object.keys(schema.fields).filter(\n\t\t\t(name) => schema.fields[name]?.type !== \"relation\",\n\t\t);\n\t\tthrowInvalidFields(\"select\", invalidFields, availableFields);\n\t}\n\n\tif (relationFields.length > 0) {\n\t\tthrowRelationInSelect(relationFields, schema.name);\n\t}\n\n\t// 3. Check for wildcard AFTER validation\n\t// If any select is \"*\", return cached fields\n\tif (selects.some((s) => s === \"*\")) {\n\t\treturn registry.getCachedSelectFields<T>(schema.name);\n\t}\n\n\t// 4. Add reserved fields\n\tallFields.add(\"id\" as keyof T);\n\tallFields.add(\"createdAt\" as keyof T);\n\tallFields.add(\"updatedAt\" as keyof T);\n\n\treturn Array.from(allFields) as QuerySelect<T>;\n}\n","/**\n * POPULATE Utilities\n *\n * All POPULATE-related operations: normalization, validation.\n * Handles relation loading, nested populates, dot notation, wildcard expansion.\n */\n\nimport type {\n\tPopulateClause,\n\tPopulateOptions,\n\tQueryPopulate,\n} from \"../types/core/query-builder\";\nimport type {\n\tDatrixEntry,\n\tRelationField,\n\tSchemaDefinition,\n\tISchemaRegistry,\n} from \"../types/core/schema\";\nimport { throwInvalidField, throwInvalidValue } from \"./error-helper\";\nimport { normalizeSelect } from \"./select\";\n\n/**\n * Maximum nesting depth for populate clauses to prevent stack overflow\n */\nconst MAX_POPULATE_DEPTH = 5;\n\n/**\n * Normalize and validate POPULATE clause\n *\n * Complete POPULATE processing pipeline:\n * 1. Handle wildcard '*' → expand to all relations\n * 2. Handle dot notation array → convert to nested object\n * 3. Handle object format → validate and normalize\n * 4. Recursively process nested populates\n * 5. Validate relation fields exist\n * 6. Check max depth limit\n *\n * @param populate - Raw POPULATE clause from user\n * @param modelName - Model name\n * @param registry - Schema registry for field expansion and validation\n * @returns Normalized POPULATE clause\n * @throws {Error} If validation fails\n *\n * @example\n * ```ts\n * // Wildcard or true - all relations (both are equivalent)\n * normalizePopulate('*', 'Post', registry)\n * normalizePopulate(true, 'Post', registry)\n * // → { author: { select: [...] }, category: { select: [...] } }\n *\n * // Dot notation array\n * normalizePopulate(['category', 'author.company'], 'Post', registry)\n * // → {\n * // category: { select: [...] },\n * // author: { populate: { company: { select: [...] } } }\n * // }\n *\n * // Object notation with true or '*' (both are equivalent)\n * normalizePopulate({ author: true }, 'Post', registry)\n * normalizePopulate({ author: '*' }, 'Post', registry)\n * // → { author: { select: ['id', 'name', ...] } }\n *\n * // Validation errors\n * normalizePopulate({ invalidField: true }, 'Post', registry)\n * // → throws Error: Field 'invalidField' does not exist\n *\n * normalizePopulate({ title: true }, 'Post', registry)\n * // → throws Error: Cannot populate non-relation field 'title'\n * ```\n */\nexport function normalizePopulate<T extends DatrixEntry>(\n\tpopulate: PopulateClause<T> | undefined,\n\tmodelName: string,\n\tregistry: ISchemaRegistry,\n\tdepth = 0,\n): PopulateClause<T> | undefined {\n\tif (!populate) {\n\t\treturn undefined;\n\t}\n\n\tif (depth > MAX_POPULATE_DEPTH) {\n\t\tthrowInvalidValue(\n\t\t\t\"populate\",\n\t\t\tmodelName,\n\t\t\tdepth,\n\t\t\t`maximum nesting depth of ${MAX_POPULATE_DEPTH}`,\n\t\t);\n\t}\n\n\tconst schema = registry.get(modelName);\n\tif (!schema) {\n\t\tthrowInvalidValue(\"populate\", \"modelName\", modelName, \"valid model name\");\n\t}\n\n\t// Handle wildcard '*' or true - populate all first-level relations\n\tif (populate === \"*\" || populate === true) {\n\t\tconst allRelations: Record<string, object> = {};\n\t\tfor (const [fieldName, field] of Object.entries(schema.fields)) {\n\t\t\tif (field.type === \"relation\") {\n\t\t\t\tconst relationField = field as RelationField;\n\t\t\t\tallRelations[fieldName] = {\n\t\t\t\t\tselect: registry.getCachedSelectFields(relationField.model),\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t\treturn allRelations as PopulateClause<T>;\n\t}\n\n\t// Handle array format - dot notation ['category', 'author.company']\n\tif (Array.isArray(populate)) {\n\t\treturn normalizePopulateDotNotation(populate, schema, modelName, registry);\n\t}\n\n\t// Handle object format\n\tconst result: Record<string, object> = {};\n\n\tfor (const [relationName, value] of Object.entries(populate)) {\n\t\tconst field = schema.fields[relationName];\n\n\t\t// Field doesn't exist - throw error (typo detection)\n\t\tif (!field) {\n\t\t\tconst availableRelations = Object.entries(schema.fields)\n\t\t\t\t.filter(([_, f]) => f.type === \"relation\")\n\t\t\t\t.map(([name]) => name);\n\n\t\t\tthrowInvalidField(\"populate\", relationName, availableRelations);\n\t\t}\n\n\t\t// Field exists but is not a relation - throw error\n\t\tif (field.type !== \"relation\") {\n\t\t\tthrowInvalidValue(\"populate\", relationName, field.type, \"relation\");\n\t\t}\n\n\t\tconst relationField = field as RelationField;\n\t\tconst targetModel = relationField.model;\n\n\t\tif (typeof value === \"boolean\" || value === \"*\") {\n\t\t\t// populate[category]=true or populate[category]='*' → convert to { select: [...] }\n\t\t\tresult[relationName] = {\n\t\t\t\tselect: registry.getCachedSelectFields(targetModel),\n\t\t\t};\n\t\t} else if (typeof value === \"object\" && value !== null) {\n\t\t\t// populate[category]={ select: [...], populate: {...} }\n\t\t\tresult[relationName] = {\n\t\t\t\t...value,\n\t\t\t\t// Normalize select for this level (if provided)\n\t\t\t\tselect: normalizeSelect(\n\t\t\t\t\tvalue.select !== undefined ? [value.select] : undefined,\n\t\t\t\t\tregistry.get(targetModel)!,\n\t\t\t\t\tregistry,\n\t\t\t\t),\n\t\t\t\t// Recursively process nested populate\n\t\t\t\tpopulate: value.populate\n\t\t\t\t\t? normalizePopulate(value.populate, targetModel, registry, depth + 1)\n\t\t\t\t\t: undefined,\n\t\t\t};\n\t\t} else {\n\t\t\tthrowInvalidValue(\n\t\t\t\t\"populate\",\n\t\t\t\trelationName,\n\t\t\t\tvalue,\n\t\t\t\t\"boolean | object | '*'\",\n\t\t\t);\n\t\t}\n\t}\n\n\treturn result as PopulateClause<T>;\n}\n\n/**\n * Normalize array-based populate with dot notation\n *\n * Internal helper for normalizePopulate.\n * Converts ['category', 'author.company', 'author.posts'] to nested object format.\n *\n * @param paths - Array of relation paths (dot notation)\n * @param schema - Current schema\n * @param modelName - Model name for error messages\n * @param registry - Schema registry\n * @returns Normalized populate object\n */\nfunction normalizePopulateDotNotation<T extends DatrixEntry>(\n\tpaths: readonly string[],\n\tschema: SchemaDefinition,\n\t_modelName: string,\n\tregistry: ISchemaRegistry,\n): PopulateClause<T> {\n\tconst result: Record<string, any> = {};\n\n\tfor (const path of paths) {\n\t\tconst parts = path.split(\".\");\n\t\tconst firstPart = parts[0]!;\n\n\t\t// Validate that first part is a relation field\n\t\tconst field = schema.fields[firstPart];\n\n\t\t// Field doesn't exist\n\t\tif (!field) {\n\t\t\tconst availableRelations = Object.entries(schema.fields)\n\t\t\t\t.filter(([_, f]) => f.type === \"relation\")\n\t\t\t\t.map(([name]) => name);\n\n\t\t\tthrowInvalidField(\"populate\", firstPart, availableRelations);\n\t\t}\n\n\t\t// Field exists but is not a relation\n\t\tif (field.type !== \"relation\") {\n\t\t\tthrowInvalidValue(\"populate\", firstPart, field.type, \"relation\");\n\t\t}\n\n\t\tconst relationField = field as RelationField;\n\t\tconst targetModel = relationField.model;\n\n\t\tif (parts.length === 1) {\n\t\t\t// Simple path: 'category' → { category: { select: [...] } }\n\t\t\tresult[firstPart] = {\n\t\t\t\tselect: registry.getCachedSelectFields(targetModel),\n\t\t\t};\n\t\t} else {\n\t\t\t// Nested path: 'author.company' → { author: { populate: { company: { select: [...] } } } }\n\t\t\tconst nestedPath = parts.slice(1).join(\".\");\n\n\t\t\tif (!result[firstPart]) {\n\t\t\t\tresult[firstPart] = {\n\t\t\t\t\tselect: registry.getCachedSelectFields(targetModel),\n\t\t\t\t\tpopulate: {},\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tif (!result[firstPart].populate) {\n\t\t\t\tresult[firstPart].populate = {};\n\t\t\t}\n\n\t\t\t// Recursively normalize the nested path\n\t\t\tconst targetSchema = registry.get(targetModel);\n\t\t\tif (targetSchema) {\n\t\t\t\tconst nested = normalizePopulateDotNotation(\n\t\t\t\t\t[nestedPath],\n\t\t\t\t\ttargetSchema,\n\t\t\t\t\ttargetModel,\n\t\t\t\t\tregistry,\n\t\t\t\t);\n\t\t\t\t// Merge nested populate\n\t\t\t\tObject.assign(result[firstPart].populate, nested);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn result;\n}\n\n/**\n * Normalize and merge POPULATE arrays\n *\n * Complete POPULATE processing pipeline for multiple .populate() calls:\n * 1. Normalize each populate clause (expand wildcards, validate, etc.)\n * 2. Merge all normalized results\n *\n * @param populates - Array of populate clauses from multiple .populate() calls\n * @param modelName - Model name for validation and normalization\n * @param registry - Schema registry\n * @returns Final normalized and merged populate clause\n *\n * @example\n * ```ts\n * // Multiple populate calls accumulated in array\n * const populates = [\n * { author: true },\n * { category: { select: ['name'] } }\n * ];\n *\n * const normalized = normalizePopulateArray(populates, 'Post', registry);\n * // → { author: { select: [...] }, category: { select: ['name'] } }\n * ```\n */\nexport function normalizePopulateArray<T extends DatrixEntry>(\n\tpopulates: PopulateClause<T>[] | undefined,\n\tmodelName: string,\n\tregistry: ISchemaRegistry,\n): QueryPopulate<T> | undefined {\n\tif (!populates || populates.length === 0) {\n\t\treturn undefined;\n\t}\n\n\t// Normalize each populate clause\n\tconst normalized: PopulateClause<T>[] = [];\n\tfor (const populate of populates) {\n\t\tconst result = normalizePopulate(populate, modelName, registry);\n\t\tif (result) {\n\t\t\tnormalized.push(result);\n\t\t}\n\t}\n\n\t// Merge all normalized populates\n\tif (normalized.length === 0) {\n\t\treturn undefined;\n\t}\n\n\treturn mergePopulateClauses(...normalized) as QueryPopulate<T>;\n}\n\n/**\n * Merge populate clauses\n *\n * Used internally by normalizePopulateArray when merging multiple .populate() calls.\n */\nexport function mergePopulateClauses<T extends DatrixEntry>(\n\t...clauses: readonly (PopulateClause<T> | undefined)[]\n): QueryPopulate<T> {\n\tconst merged: Record<string, PopulateOptions<T> | \"*\" | true> = {};\n\n\tfor (const clause of clauses) {\n\t\tif (!clause) continue;\n\n\t\tfor (const [relation, options] of Object.entries(clause)) {\n\t\t\t// If either is '*' or true, use it\n\t\t\tif (\n\t\t\t\toptions === \"*\" ||\n\t\t\t\toptions === true ||\n\t\t\t\tmerged[relation] === \"*\" ||\n\t\t\t\tmerged[relation] === true\n\t\t\t) {\n\t\t\t\tmerged[relation] = options === true ? true : \"*\";\n\t\t\t} else if (merged[relation]) {\n\t\t\t\t// Merge options (both are objects)\n\t\t\t\tconst existing = merged[relation] as PopulateOptions<T>;\n\t\t\t\tconst newOptions = options as PopulateOptions<T>;\n\t\t\t\tconst mergedOptions = {\n\t\t\t\t\t...(newOptions.select !== undefined || existing.select !== undefined\n\t\t\t\t\t\t? { select: newOptions.select || existing.select }\n\t\t\t\t\t\t: {}),\n\t\t\t\t\t...(newOptions.where !== undefined || existing.where !== undefined\n\t\t\t\t\t\t? { where: newOptions.where || existing.where }\n\t\t\t\t\t\t: {}),\n\t\t\t\t\t...(newOptions.populate !== undefined ||\n\t\t\t\t\t\texisting.populate !== undefined\n\t\t\t\t\t\t? {\n\t\t\t\t\t\t\tpopulate: newOptions.populate\n\t\t\t\t\t\t\t\t? mergePopulateClauses(existing.populate, newOptions.populate)\n\t\t\t\t\t\t\t\t: existing.populate,\n\t\t\t\t\t\t}\n\t\t\t\t\t\t: {}),\n\t\t\t\t\t...(newOptions.limit !== undefined || existing.limit !== undefined\n\t\t\t\t\t\t? { limit: newOptions.limit ?? existing.limit }\n\t\t\t\t\t\t: {}),\n\t\t\t\t\t...(newOptions.offset !== undefined || existing.offset !== undefined\n\t\t\t\t\t\t? { offset: newOptions.offset ?? existing.offset }\n\t\t\t\t\t\t: {}),\n\t\t\t\t\t...(newOptions.orderBy !== undefined || existing.orderBy !== undefined\n\t\t\t\t\t\t? { orderBy: newOptions.orderBy || existing.orderBy }\n\t\t\t\t\t\t: {}),\n\t\t\t\t};\n\t\t\t\tmerged[relation] = mergedOptions as PopulateOptions<T>;\n\t\t\t} else {\n\t\t\t\tmerged[relation] = options;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn merged as QueryPopulate<T>;\n}\n","/**\n * Data Normalization and Splitting for Query Builder\n *\n * This module handles:\n * 1. Single-pass field separation (scalars vs relations)\n * 2. Field existence validation\n * 3. Relation shortcut normalization (5 → { connect: [{ id: 5 }] })\n * 4. Foreign key inlining (belongsTo/hasOne)\n * 5. Recursive create/update normalization (with depth limit)\n *\n * These functions are used in QueryBuilder.build() to process INSERT/UPDATE data.\n */\n\nimport {\n\tSchemaDefinition,\n\tRelationField,\n\tDatrixEntry,\n\tISchemaRegistry,\n\tAnyRelationInputObject,\n} from \"../types/core/schema\";\nimport type {\n\tNormalizedNestedData,\n\tNormalizedRelationOperations,\n\tNormalizedRelationUpdate,\n\tQueryRelations,\n} from \"../types/core/query-builder\";\nimport { throwInvalidField, throwInvalidValue } from \"./error-helper\";\n\n/**\n * Maximum depth for nested create/update operations\n * Prevents infinite recursion and stack overflow\n */\nconst MAX_NESTED_DEPTH = 5;\n\n/**\n * Check if value is a RelationInput object (has connect/disconnect/set/etc)\n * vs a raw ID reference\n *\n * @param value - Value to check\n * @returns True if value is a RelationInput object\n *\n * @example\n * ```ts\n * isRelationInputObject({ connect: { id: 5 } }) // true\n * isRelationInputObject({ id: 5 }) // false (raw ref)\n * isRelationInputObject(5) // false\n * ```\n */\nfunction isRelationInputObject(value: unknown): boolean {\n\tif (typeof value !== \"object\" || value === null) {\n\t\treturn false;\n\t}\n\t// If it has 'id' property directly, it's a raw { id } ref, not RelationInput\n\tif (\"id\" in value && !(\"connect\" in value || \"set\" in value)) {\n\t\treturn false;\n\t}\n\t// Check for RelationInput keys\n\treturn (\n\t\t\"connect\" in value ||\n\t\t\"disconnect\" in value ||\n\t\t\"set\" in value ||\n\t\t\"create\" in value ||\n\t\t\"update\" in value ||\n\t\t\"delete\" in value\n\t);\n}\n\n/**\n * Extract IDs from various formats and convert to number array\n *\n * @param value - Input value (number, {id}, array of numbers/objects)\n * @returns Array of numbers\n *\n * @example\n * ```ts\n * extractIds(5) // [5]\n * extractIds([1, 2, 3]) // [1, 2, 3]\n * extractIds([{id: 1}, {id: 2}]) // [1, 2]\n * extractIds({id: 5}) // [5]\n * ```\n */\nfunction extractIds(value: unknown): number[] {\n\t// Single number\n\tif (typeof value === \"number\") {\n\t\treturn [value];\n\t}\n\n\t// Single string (convert to number)\n\tif (typeof value === \"string\") {\n\t\treturn [Number(value)];\n\t}\n\n\t// Single object with id\n\tif (typeof value === \"object\" && value !== null && \"id\" in value) {\n\t\tconst id = (value as { id: string | number }).id;\n\t\treturn [typeof id === \"number\" ? id : Number(id)];\n\t}\n\n\t// Array\n\tif (Array.isArray(value)) {\n\t\treturn value.map((item) => {\n\t\t\tif (typeof item === \"number\") {\n\t\t\t\treturn item;\n\t\t\t}\n\t\t\tif (typeof item === \"string\") {\n\t\t\t\treturn Number(item);\n\t\t\t}\n\t\t\tif (typeof item === \"object\" && item !== null && \"id\" in item) {\n\t\t\t\tconst id = (item as { id: string | number }).id;\n\t\t\t\treturn typeof id === \"number\" ? id : Number(id);\n\t\t\t}\n\t\t\treturn 0; // Fallback\n\t\t});\n\t}\n\n\treturn [];\n}\n\n/**\n * Process data for INSERT/UPDATE operations\n *\n * Single-pass optimized algorithm:\n * 1. Loop through data keys once\n * 2. Accumulate: scalars, relations, invalid fields\n * 3. Throw if any invalid fields found\n * 4. Normalize relations (shortcuts → RelationInput with number arrays)\n * 5. Recursively process create/update operations (with depth limit)\n * 6. Inline belongsTo/hasOne foreign keys into scalars\n * 7. Return separated data\n *\n * @param data - Raw data from user\n * @param schema - Schema definition\n * @param modelName - Model name (for error messages)\n * @param registry - Schema registry (for recursive processing of create/update)\n * @param depth - Current recursion depth (internal, default 0)\n * @returns Processed data with separated scalars and relations\n *\n * @example\n * ```ts\n * const result = processData(\n * { name: 'Post 1', author: 5, tags: [1, 2, 3], invalidField: 'x' },\n * postSchema,\n * 'Post',\n * registry\n * );\n * // Throws: Invalid field 'invalidField' in data clause\n *\n * const result2 = processData(\n * { name: 'Post 1', author: 5, tags: [1, 2, 3] },\n * postSchema,\n * 'Post',\n * registry\n * );\n * // Result:\n * // {\n * // data: { name: 'Post 1', authorId: 5 },\n * // relations: { tags: { set: [1, 2, 3] } }\n * // }\n *\n * const result3 = processData(\n * {\n * name: 'Post 1',\n * author: {\n * create: { name: 'John', company: { create: { name: 'Acme' } } }\n * }\n * },\n * postSchema,\n * 'Post',\n * registry\n * );\n * // Result (recursive processing):\n * // {\n * // data: { name: 'Post 1' },\n * // relations: {\n * // author: {\n * // create: {\n * // data: { name: 'John' },\n * // relations: {\n * // company: {\n * // create: { data: { name: 'Acme' }, relations: undefined }\n * // }\n * // }\n * // }\n * // }\n * // }\n * // }\n * ```\n */\nexport function processData<T extends DatrixEntry>(\n\tdata: Partial<T>,\n\tschema: SchemaDefinition,\n\tregistry: ISchemaRegistry,\n\tdepth: number = 0,\n\tvisitedModels: ReadonlySet<string> = new Set(),\n): NormalizedNestedData<T> {\n\t// Check max depth\n\tif (depth > MAX_NESTED_DEPTH) {\n\t\tthrowInvalidValue(\n\t\t\t\"data\",\n\t\t\t\"nested depth\",\n\t\t\tdepth,\n\t\t\t`maximum ${MAX_NESTED_DEPTH} levels of nesting`,\n\t\t);\n\t}\n\n\t// Check redundant nested creation (e.g. Author → Post → Author)\n\tif (visitedModels.has(schema.name)) {\n\t\tthrowInvalidValue(\n\t\t\t\"data\",\n\t\t\t\"redundant nested create/update\",\n\t\t\t`${[...visitedModels, schema.name].join(\" → \")}`,\n\t\t\t`use 'connect' instead of nesting back to '${schema.name}' — creating the same model in a nested chain is redundant`,\n\t\t);\n\t}\n\tconst scalars: Record<string, unknown> = {};\n\tconst rawRelations: Record<string, unknown> = {};\n\tconst invalidFields: string[] = [];\n\n\t// STEP 1: Single-pass separation (scalars vs relations) + collect invalid fields\n\tfor (const [key, value] of Object.entries(data)) {\n\t\tconst field = schema.fields[key];\n\n\t\t// Unknown field\n\t\tif (!field) {\n\t\t\tinvalidFields.push(key);\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Relation field\n\t\tif (field.type === \"relation\") {\n\t\t\trawRelations[key] = value;\n\t\t} else {\n\t\t\t// Scalar field\n\t\t\tscalars[key] = value;\n\t\t}\n\t}\n\n\t// STEP 2: Throw if any invalid fields found\n\tif (invalidFields.length > 0) {\n\t\tconst availableFields = Object.keys(schema.fields);\n\t\tthrowInvalidField(\"data\", invalidFields[0]!, availableFields);\n\t}\n\n\t// STEP 3: Normalize relations and inline foreign keys\n\tconst normalizedRelations: Record<\n\t\tstring,\n\t\tNormalizedRelationOperations<T>\n\t> = {};\n\n\tfor (const [key, value] of Object.entries(rawRelations)) {\n\t\tconst field = schema.fields[key] as RelationField;\n\n\t\t// Normalize relation shortcuts to NormalizedRelationOperations\n\t\tlet normalized: NormalizedRelationOperations<T>;\n\n\t\t// Case 0: null value - clear/disconnect relation\n\t\tif (value === null) {\n\t\t\tif (field.kind === \"belongsTo\") {\n\t\t\t\t// belongsTo: FK is on owner, disconnect triggers inlining FK = null\n\t\t\t\tnormalized = { disconnect: [] };\n\t\t\t} else if (field.kind === \"hasOne\") {\n\t\t\t\t// hasOne: FK is on target, use set: [] to clear the relation\n\t\t\t\tnormalized = { set: [] };\n\t\t\t} else {\n\t\t\t\t// hasMany/manyToMany: null is not allowed (prevent accidental mass deletion)\n\t\t\t\tthrowInvalidValue(\n\t\t\t\t\t\"data\",\n\t\t\t\t\t`relation ${key}`,\n\t\t\t\t\t\"null\",\n\t\t\t\t\t\"`[]` or `{ set: [] }` to clear all relations\",\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\t// Case 1: Direct ID shortcut (category: 5)\n\t\telse if (typeof value === \"number\" || typeof value === \"string\") {\n\t\t\tnormalized = { set: extractIds(value) };\n\t\t}\n\t\t// Case 2: Array shortcut (tags: [1, 2, 3] or [{id: 1}, {id: 2}])\n\t\telse if (Array.isArray(value)) {\n\t\t\tconst isRawIdArray =\n\t\t\t\tvalue.length === 0 || !isRelationInputObject(value[0]);\n\t\t\tif (isRawIdArray) {\n\t\t\t\tnormalized = { set: extractIds(value) };\n\t\t\t} else {\n\t\t\t\t// Already RelationInput array, needs processing\n\t\t\t\tnormalized = {};\n\t\t\t}\n\t\t}\n\t\t// Case 3: RelationInput object - normalize each operation to number arrays\n\t\telse if (typeof value === \"object\") {\n\t\t\tconst relInput = value as AnyRelationInputObject;\n\t\t\tnormalized = {};\n\n\t\t\t// Normalize connect to number array\n\t\t\tif (relInput.connect !== undefined) {\n\t\t\t\tnormalized = { ...normalized, connect: extractIds(relInput.connect) };\n\t\t\t}\n\n\t\t\t// Normalize disconnect to number array\n\t\t\t// Special case: disconnect: true for hasOne/belongsTo means \"clear this relation\"\n\t\t\tif (relInput.disconnect !== undefined) {\n\t\t\t\tif (relInput.disconnect === true) {\n\t\t\t\t\tif (field.kind === \"hasOne\") {\n\t\t\t\t\t\tnormalized = { ...normalized, set: [] };\n\t\t\t\t\t} else {\n\t\t\t\t\t\tnormalized = { ...normalized, disconnect: [] };\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tnormalized = {\n\t\t\t\t\t\t...normalized,\n\t\t\t\t\t\tdisconnect: extractIds(relInput.disconnect),\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Normalize set to number array\n\t\t\tif (relInput.set !== undefined) {\n\t\t\t\tnormalized = { ...normalized, set: extractIds(relInput.set) };\n\t\t\t}\n\n\t\t\t// Normalize delete to number array\n\t\t\tif (relInput.delete !== undefined) {\n\t\t\t\tnormalized = { ...normalized, delete: extractIds(relInput.delete) };\n\t\t\t}\n\n\t\t\t// Recursively process create operations\n\t\t\tif (relInput.create !== undefined) {\n\t\t\t\tconst targetSchema = registry.get(field.model);\n\t\t\t\tif (!targetSchema) {\n\t\t\t\t\tthrowInvalidValue(\n\t\t\t\t\t\t\"data\",\n\t\t\t\t\t\t`relation ${key}`,\n\t\t\t\t\t\tfield.model,\n\t\t\t\t\t\t\"valid model\",\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tconst nextVisited = new Set([...visitedModels, schema.name]);\n\n\t\t\t\t// Handle array of creates\n\t\t\t\tif (Array.isArray(relInput.create)) {\n\t\t\t\t\tnormalized = {\n\t\t\t\t\t\t...normalized,\n\t\t\t\t\t\tcreate: relInput.create.map((item) =>\n\t\t\t\t\t\t\tprocessData<T>(\n\t\t\t\t\t\t\t\titem as Partial<T>,\n\t\t\t\t\t\t\t\ttargetSchema,\n\t\t\t\t\t\t\t\tregistry,\n\t\t\t\t\t\t\t\tdepth + 1,\n\t\t\t\t\t\t\t\tnextVisited,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t),\n\t\t\t\t\t};\n\t\t\t\t} else {\n\t\t\t\t\t// Single create\n\t\t\t\t\tnormalized = {\n\t\t\t\t\t\t...normalized,\n\t\t\t\t\t\tcreate: [\n\t\t\t\t\t\t\tprocessData(\n\t\t\t\t\t\t\t\trelInput.create as Partial<T>,\n\t\t\t\t\t\t\t\ttargetSchema,\n\t\t\t\t\t\t\t\tregistry,\n\t\t\t\t\t\t\t\tdepth + 1,\n\t\t\t\t\t\t\t\tnextVisited,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t],\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Recursively process update operations\n\t\t\tif (relInput.update !== undefined) {\n\t\t\t\tconst targetSchema = registry.get(field.model);\n\t\t\t\tif (!targetSchema) {\n\t\t\t\t\tthrowInvalidValue(\n\t\t\t\t\t\t\"data\",\n\t\t\t\t\t\t`relation ${key}`,\n\t\t\t\t\t\tfield.model,\n\t\t\t\t\t\t\"valid model\",\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tconst nextVisited = new Set([...visitedModels, schema.name]);\n\n\t\t\t\t// Handle array of updates\n\t\t\t\tif (Array.isArray(relInput.update)) {\n\t\t\t\t\tnormalized = {\n\t\t\t\t\t\t...normalized,\n\t\t\t\t\t\tupdate: relInput.update.map((item) => {\n\t\t\t\t\t\t\tconst whereClause = item.where;\n\t\t\t\t\t\t\tconst updateData = item.data as Partial<T>;\n\t\t\t\t\t\t\tconst processed = processData<T>(\n\t\t\t\t\t\t\t\tupdateData,\n\t\t\t\t\t\t\t\ttargetSchema,\n\t\t\t\t\t\t\t\tregistry,\n\t\t\t\t\t\t\t\tdepth + 1,\n\t\t\t\t\t\t\t\tnextVisited,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\twhere: whereClause,\n\t\t\t\t\t\t\t\t...processed,\n\t\t\t\t\t\t\t} satisfies NormalizedRelationUpdate<T>;\n\t\t\t\t\t\t}),\n\t\t\t\t\t};\n\t\t\t\t} else {\n\t\t\t\t\t// Single update\n\t\t\t\t\tconst whereClause = relInput.update.where;\n\t\t\t\t\tconst updateData = relInput.update.data as Partial<T>;\n\t\t\t\t\tconst processed = processData<T>(\n\t\t\t\t\t\tupdateData,\n\t\t\t\t\t\ttargetSchema,\n\t\t\t\t\t\tregistry,\n\t\t\t\t\t\tdepth + 1,\n\t\t\t\t\t\tnextVisited,\n\t\t\t\t\t);\n\t\t\t\t\tnormalized = {\n\t\t\t\t\t\t...normalized,\n\t\t\t\t\t\tupdate: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\twhere: whereClause,\n\t\t\t\t\t\t\t\t...processed,\n\t\t\t\t\t\t\t} satisfies NormalizedRelationUpdate<T>,\n\t\t\t\t\t\t],\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\t// Fallback (shouldn't happen)\n\t\t\tnormalized = {};\n\t\t}\n\n\t\t// Inline foreign keys for belongsTo only\n\t\t// hasOne FK is on TARGET table, not on owner - cannot inline into owner's scalars\n\t\tif (field.kind === \"belongsTo\") {\n\t\t\t// Singular relations can only reference one record total\n\t\t\tconst totalRefs =\n\t\t\t\t(normalized.connect?.length ?? 0) +\n\t\t\t\t(normalized.set?.length ?? 0) +\n\t\t\t\t(normalized.create?.length ?? 0);\n\n\t\t\tif (totalRefs > 1) {\n\t\t\t\tthrowInvalidValue(\n\t\t\t\t\t\"data\",\n\t\t\t\t\t`relation ${key} (${field.kind})`,\n\t\t\t\t\t`${totalRefs} references`,\n\t\t\t\t\t\"a single reference — belongsTo can only reference one record\",\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst foreignKey = field.foreignKey!;\n\t\t\tlet inlinedId: number | null | undefined = undefined;\n\n\t\t\tif (normalized.connect) {\n\t\t\t\tconst ids = normalized.connect;\n\t\t\t\tinlinedId = ids[0] ?? null;\n\t\t\t} else if (normalized.set) {\n\t\t\t\tconst ids = normalized.set;\n\t\t\t\tinlinedId = ids[0] ?? null;\n\t\t\t} else if (normalized.disconnect) {\n\t\t\t\tinlinedId = null;\n\t\t\t}\n\n\t\t\tif (inlinedId !== undefined) {\n\t\t\t\t// Inline FK into scalars\n\t\t\t\tscalars[foreignKey] = inlinedId;\n\n\t\t\t\t// Keep in relations only if there are other operations (create/update/delete)\n\t\t\t\tconst hasOtherOps =\n\t\t\t\t\tnormalized.create || normalized.update || normalized.delete;\n\t\t\t\tif (hasOtherOps) {\n\t\t\t\t\tnormalizedRelations[key] = normalized;\n\t\t\t\t}\n\t\t\t\t// Otherwise, skip (FK already inlined, no async work needed)\n\t\t\t} else {\n\t\t\t\t// Cannot inline (e.g., only create/update/delete), keep as async relation\n\t\t\t\tnormalizedRelations[key] = normalized;\n\t\t\t}\n\t\t} else if (field.kind === \"hasOne\") {\n\t\t\t// hasOne: FK is on TARGET table\n\t\t\t// User cannot directly set the relation by passing ID to owner\n\t\t\t// Instead, target record must be created/updated with owner's ID\n\t\t\t// Keep as async relation for create/update operations\n\t\t\tnormalizedRelations[key] = normalized;\n\t\t} else {\n\t\t\t// hasMany or manyToMany - cannot inline, always async\n\t\t\tnormalizedRelations[key] = normalized;\n\t\t}\n\t}\n\n\treturn {\n\t\tdata: scalars as Partial<T>,\n\t\trelations:\n\t\t\tObject.keys(normalizedRelations).length > 0\n\t\t\t\t? (normalizedRelations as unknown as QueryRelations<T>)\n\t\t\t\t: undefined,\n\t};\n}\n","/**\n * OrderBy Normalizer\n *\n * Converts OrderByClause input formats to normalized QueryOrderBy.\n *\n * Supported input formats:\n * 1. Full format: [{ field: \"age\", direction: \"asc\", nulls: \"last\" }]\n * 2. Object shortcut: { age: \"asc\" }\n * 3. String array: [\"age\", \"-name\"] (- prefix = desc)\n */\n\nimport type {\n\tOrderByClause,\n\tQueryOrderBy,\n\tOrderByItem,\n\tOrderDirection,\n} from \"../types/core/query-builder\";\nimport type { DatrixEntry } from \"../types/core/schema\";\n\n/**\n * Check if input is already normalized (array of OrderByItem)\n */\nfunction isQueryOrderBy(input: unknown): boolean {\n\tif (!Array.isArray(input)) return false;\n\tif (input.length === 0) return true;\n\n\tconst first = input[0];\n\treturn (\n\t\ttypeof first === \"object\" &&\n\t\tfirst !== null &&\n\t\t\"field\" in first &&\n\t\t\"direction\" in first\n\t);\n}\n\n/**\n * Check if input is object shortcut format\n * { age: \"asc\", name: \"desc\" }\n */\nfunction isObjectShortcut(input: unknown): boolean {\n\tif (Array.isArray(input)) return false;\n\tif (typeof input !== \"object\" || input === null) return false;\n\n\tconst values = Object.values(input);\n\treturn values.every((v) => v === \"asc\" || v === \"desc\");\n}\n\n/**\n * Check if input is string array format\n * [\"age\", \"-name\"]\n */\nfunction isStringArray(input: unknown): boolean {\n\tif (!Array.isArray(input)) return false;\n\tif (input.length === 0) return false;\n\n\treturn input.every((item) => typeof item === \"string\");\n}\n\n/**\n * Normalize OrderByClause to QueryOrderBy\n *\n * @param input - OrderByClause in any supported format\n * @returns Normalized QueryOrderBy array\n *\n * @example\n * ```ts\n * // Full format (passthrough)\n * normalizeOrderBy([{ field: \"age\", direction: \"asc\" }])\n * // → [{ field: \"age\", direction: \"asc\" }]\n *\n * // Object shortcut\n * normalizeOrderBy({ age: \"asc\" })\n * // → [{ field: \"age\", direction: \"asc\" }]\n *\n * // String array\n * normalizeOrderBy([\"age\", \"-name\"])\n * // → [{ field: \"age\", direction: \"asc\" }, { field: \"name\", direction: \"desc\" }]\n * ```\n */\nexport function normalizeOrderBy<T extends DatrixEntry>(\n\tinput: OrderByClause<T> | undefined,\n): QueryOrderBy<T> | undefined {\n\tif (input === undefined || input === null) {\n\t\treturn undefined;\n\t}\n\n\t// Already normalized\n\tif (isQueryOrderBy(input)) {\n\t\treturn input as QueryOrderBy<T>;\n\t}\n\n\t// Object shortcut: { age: \"asc\" }\n\tif (isObjectShortcut(input)) {\n\t\tconst result: OrderByItem<T>[] = [];\n\t\tfor (const [field, direction] of Object.entries(input)) {\n\t\t\tresult.push({\n\t\t\t\tfield: field as keyof T,\n\t\t\t\tdirection: direction as OrderDirection,\n\t\t\t});\n\t\t}\n\t\treturn result as QueryOrderBy<T>;\n\t}\n\n\t// String array: [\"age\", \"-name\"]\n\tif (isStringArray(input)) {\n\t\treturn (input as string[]).map((item) => {\n\t\t\tconst str = item as string;\n\t\t\tif (str.startsWith(\"-\")) {\n\t\t\t\treturn {\n\t\t\t\t\tfield: str.slice(1) as keyof T,\n\t\t\t\t\tdirection: \"desc\" as OrderDirection,\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tfield: str as keyof T,\n\t\t\t\tdirection: \"asc\" as OrderDirection,\n\t\t\t};\n\t\t}) as QueryOrderBy<T>;\n\t}\n\n\t// Unknown format, return as-is (will fail validation later if invalid)\n\treturn input as QueryOrderBy<T>;\n}\n","/**\n * Query Builder Base Implementation (~150 LOC)\n *\n * Fluent API for building database-agnostic queries.\n * Produces QueryObject instances that adapters translate to SQL/NoSQL.\n */\n\nimport type {\n\tQueryObjectForType,\n\tQueryType,\n\tSelectClause,\n\tWhereClause,\n\tPopulateClause,\n\tOrderByItem,\n\tOrderDirection,\n\tOrderByClause,\n} from \"../types/core/query-builder\";\n\nimport { normalizeWhere } from \"./where\";\nimport { normalizePopulateArray } from \"./populate\";\nimport { normalizeSelect } from \"./select\";\nimport { processData } from \"./data\";\nimport { normalizeOrderBy } from \"./orderby\";\nimport {\n\tthrowSchemaNotFound,\n\tthrowInvalidQueryType,\n\tthrowMissingTable,\n\tthrowMissingData,\n\tthrowDeleteWithoutWhere,\n} from \"./error-helper\";\nimport type {\n\tDatrixEntry,\n\tISchemaRegistry as ISchemaRegistry,\n\tSchemaDefinition,\n} from \"../types/core/schema\";\n\n/**\n * Deep clone an object (safe for JSON-serializable data)\n */\nfunction deepClone<T>(obj: T): T {\n\tif (obj === null || typeof obj !== \"object\") {\n\t\treturn obj;\n\t}\n\n\tif (obj instanceof Date) {\n\t\treturn new Date(obj.getTime()) as T;\n\t}\n\n\tif (obj instanceof RegExp) {\n\t\treturn new RegExp(obj.source, obj.flags) as T;\n\t}\n\n\tif (Array.isArray(obj)) {\n\t\treturn obj.map((item) => deepClone(item)) as T;\n\t}\n\n\tconst cloned: Record<string, unknown> = {};\n\tfor (const key in obj) {\n\t\tif (Object.prototype.hasOwnProperty.call(obj, key)) {\n\t\t\tcloned[key] = deepClone(obj[key]);\n\t\t}\n\t}\n\n\treturn cloned as T;\n}\n\n/**\n * Mutable query state for building\n */\ninterface MutableQueryState<T extends DatrixEntry> {\n\ttype?: QueryType;\n\ttable?: string;\n\tselect?: SelectClause<T>[];\n\twhere?: WhereClause<T>[];\n\tpopulate?: PopulateClause<T>[];\n\torderBy?: OrderByClause<T>;\n\tlimit?: number;\n\toffset?: number;\n\tdata?: Partial<T>;\n\tdataItems?: Partial<T>[];\n\tdistinct?: boolean;\n\tgroupBy?: string[];\n\thaving?: WhereClause<T>;\n}\n\n/**\n * Query builder implementation\n */\nexport class DatrixQueryBuilder<\n\tTSchema extends DatrixEntry,\n\tTType extends QueryType = QueryType,\n> {\n\tprivate query: MutableQueryState<TSchema>;\n\tprivate readonly _modelName: string;\n\tprivate readonly _schema: SchemaDefinition;\n\tprivate readonly _registry: ISchemaRegistry;\n\n\t/**\n\t * Constructor for the query builder\n\t *\n\t * @param modelName - Model name (e.g., 'User', 'Post')\n\t * @param schemaRegistry - Schema registry for normalization and relation resolution\n\t *\n\t * This enables full normalization support:\n\t * - SELECT: \"*\" → expanded to field list, reserved fields added\n\t * - WHERE: relation shortcuts normalized (category: 2 → categoryId: { $eq: 2 })\n\t * - POPULATE: wildcards, dot notation, nested processing, relation traversal\n\t *\n\t * @throws {Error} If schema not found in registry\n\t *\n\t * @example\n\t * ```ts\n\t * const builder = new DatrixQueryBuilder('User', schemaRegistry);\n\t * builder.select('*').where({ role: 'admin' });\n\t * ```\n\t */\n\tconstructor(\n\t\tmodelName: string,\n\t\tschemaRegistry: ISchemaRegistry,\n\t\ttype: TType = \"select\" as TType,\n\t) {\n\t\tthis._modelName = modelName;\n\t\tthis._registry = schemaRegistry;\n\n\t\t// Get schema from registry\n\t\tconst schema = schemaRegistry.get(modelName)!;\n\t\tif (!schema) {\n\t\t\tthrowSchemaNotFound(modelName);\n\t\t}\n\n\t\tthis._schema = schema;\n\t\tthis.query = {\n\t\t\ttable: schema.tableName!,\n\t\t\ttype,\n\t\t};\n\t}\n\n\t/**\n\t * Select fields\n\t */\n\tselect(fields: SelectClause<TSchema>): this {\n\t\tif (this.query.select === undefined) {\n\t\t\tthis.query.select = [fields];\n\t\t} else {\n\t\t\tthis.query.select.push(fields);\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Add WHERE conditions\n\t */\n\twhere(conditions: WhereClause<TSchema>): this {\n\t\tif (this.query.where === undefined) {\n\t\t\tthis.query.where = [conditions];\n\t\t} else {\n\t\t\tthis.query.where.push(conditions);\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Populate relations\n\t *\n\t * Supports multiple formats:\n\t * - .populate('*') - all relations\n\t * - .populate(['author', 'category']) - array\n\t * - .populate({ author: true }) - object\n\t *\n\t * Multiple calls are accumulated and merged in build()\n\t */\n\tpopulate(relations: PopulateClause<TSchema>): this {\n\t\tif (this.query.populate === undefined) {\n\t\t\tthis.query.populate = [relations];\n\t\t} else {\n\t\t\tthis.query.populate.push(relations);\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Order by field(s)\n\t *\n\t * Supports multiple formats:\n\t * - Fluent: .orderBy(\"age\", \"asc\")\n\t * - Full: .orderBy([{ field: \"age\", direction: \"asc\" }])\n\t * - Object: .orderBy({ age: \"asc\" })\n\t * - Array: .orderBy([\"age\", \"-name\"])\n\t *\n\t * @example\n\t * ```ts\n\t * // Fluent API (single field)\n\t * builder.orderBy(\"age\", \"asc\").orderBy(\"name\", \"desc\");\n\t *\n\t * // Full format\n\t * builder.orderBy([{ field: \"age\", direction: \"asc\", nulls: \"last\" }]);\n\t *\n\t * // Object shortcut\n\t * builder.orderBy({ age: \"asc\" });\n\t *\n\t * // String array\n\t * builder.orderBy([\"age\", \"-name\"]);\n\t * ```\n\t */\n\torderBy(clause: OrderByClause<TSchema>): this;\n\torderBy(field: keyof TSchema, direction?: OrderDirection): this;\n\torderBy(\n\t\tfieldOrClause: keyof TSchema | OrderByClause<TSchema>,\n\t\tdirection: OrderDirection = \"asc\",\n\t): this {\n\t\t// Fluent API: orderBy(\"field\", \"asc\")\n\t\tif (typeof fieldOrClause === \"string\" && !Array.isArray(fieldOrClause)) {\n\t\t\tconst normalized = normalizeOrderBy(this.query.orderBy);\n\t\t\tconst newItem: OrderByItem<TSchema> = {\n\t\t\t\tfield: fieldOrClause as keyof TSchema,\n\t\t\t\tdirection,\n\t\t\t};\n\t\t\tthis.query.orderBy = [\n\t\t\t\t...(normalized || []),\n\t\t\t\tnewItem,\n\t\t\t] as OrderByClause<TSchema>;\n\t\t\treturn this;\n\t\t}\n\n\t\t// Clause format: orderBy([...]) or orderBy({...})\n\t\tthis.query.orderBy = fieldOrClause as OrderByClause<TSchema>;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Set limit\n\t */\n\tlimit(count: number): this {\n\t\tthis.query.limit = count;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Set offset\n\t */\n\toffset(count: number): this {\n\t\tthis.query.offset = count;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Set data for UPDATE (shallow merge, single object)\n\t *\n\t * Multiple calls are merged (shallow merge).\n\t * Only available for UPDATE queries.\n\t *\n\t * @param values - Data to update\n\t * @returns this\n\t *\n\t * @example\n\t * ```ts\n\t * builder\n\t * .data({ name: 'John' })\n\t * .data({ age: 25 }); // Merged: { name: 'John', age: 25 }\n\t * ```\n\t */\n\tdata(values: Partial<TSchema>): this {\n\t\tif (this.query.data === undefined) {\n\t\t\tthis.query.data = values;\n\t\t} else {\n\t\t\tthis.query.data = { ...this.query.data, ...values };\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Push a data item for INSERT (bulk insert support)\n\t *\n\t * Each call adds one item to the insert batch.\n\t * Only available for INSERT queries.\n\t *\n\t * @param item - Data item to insert\n\t * @returns this\n\t *\n\t * @example\n\t * ```ts\n\t * builder\n\t * .pushData({ name: 'John', age: 25 })\n\t * .pushData({ name: 'Jane', age: 30 });\n\t * // Inserts 2 rows\n\t * ```\n\t */\n\tpushData(item: Partial<TSchema>): this {\n\t\tif (this.query.dataItems === undefined) {\n\t\t\tthis.query.dataItems = [item];\n\t\t} else {\n\t\t\tthis.query.dataItems.push(item);\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Set DISTINCT\n\t */\n\tdistinct(enabled = true): this {\n\t\tthis.query.distinct = enabled;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Group by fields\n\t */\n\tgroupBy(fields: readonly string[]): this {\n\t\tthis.query.groupBy = [...(this.query.groupBy || []), ...fields];\n\t\treturn this;\n\t}\n\n\t/**\n\t * Having clause (for GROUP BY)\n\t */\n\thaving(conditions: WhereClause<TSchema>): this {\n\t\tthis.query.having = conditions;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Build final QueryObject\n\t * @throws {DatrixQueryBuilderError} If query is invalid\n\t */\n\tbuild(): QueryObjectForType<TSchema, TType> {\n\t\t// Validate required fields\n\t\tif (!this.query.type) {\n\t\t\tthrowInvalidQueryType(this.query.type);\n\t\t}\n\n\t\tif (!this.query.table) {\n\t\t\tthrowMissingTable();\n\t\t}\n\n\t\tconst type = this.query.type!;\n\t\tconst table = this.query.table!;\n\n\t\t// Normalize common clauses\n\t\tconst normalizedWhere = normalizeWhere(\n\t\t\tthis.query.where,\n\t\t\tthis._schema,\n\t\t\tthis._registry,\n\t\t);\n\t\tconst normalizedSelect = normalizeSelect(\n\t\t\tthis.query.select,\n\t\t\tthis._schema,\n\t\t\tthis._registry,\n\t\t);\n\t\tconst normalizedPopulate = normalizePopulateArray(\n\t\t\tthis.query.populate,\n\t\t\tthis._modelName,\n\t\t\tthis._registry,\n\t\t);\n\t\tconst normalizedOrderBy = normalizeOrderBy(this.query.orderBy);\n\n\t\t// Spread helpers for reuse\n\t\tconst selectSpread =\n\t\t\tnormalizedSelect !== undefined\n\t\t\t\t? { select: normalizedSelect }\n\t\t\t\t: { select: undefined };\n\t\tconst populateSpread =\n\t\t\tnormalizedPopulate !== undefined ? { populate: normalizedPopulate } : {};\n\t\tconst whereSpread =\n\t\t\tnormalizedWhere !== undefined ? { where: normalizedWhere } : {};\n\n\t\tswitch (type) {\n\t\t\tcase \"select\": {\n\t\t\t\treturn {\n\t\t\t\t\ttype,\n\t\t\t\t\ttable,\n\t\t\t\t\t...selectSpread,\n\t\t\t\t\t...whereSpread,\n\t\t\t\t\t...populateSpread,\n\t\t\t\t\t...(normalizedOrderBy !== undefined && {\n\t\t\t\t\t\torderBy: normalizedOrderBy,\n\t\t\t\t\t}),\n\t\t\t\t\t...(this.query.limit !== undefined && { limit: this.query.limit }),\n\t\t\t\t\t...(this.query.offset !== undefined && { offset: this.query.offset }),\n\t\t\t\t\t...(this.query.distinct !== undefined && {\n\t\t\t\t\t\tdistinct: this.query.distinct,\n\t\t\t\t\t}),\n\t\t\t\t\t...(this.query.groupBy !== undefined && {\n\t\t\t\t\t\tgroupBy: this.query.groupBy as readonly string[],\n\t\t\t\t\t}),\n\t\t\t\t\t...(this.query.having !== undefined && {\n\t\t\t\t\t\thaving: this.query.having,\n\t\t\t\t\t}),\n\t\t\t\t} as QueryObjectForType<TSchema, TType>;\n\t\t\t}\n\n\t\t\tcase \"count\": {\n\t\t\t\treturn {\n\t\t\t\t\ttype,\n\t\t\t\t\ttable,\n\t\t\t\t\t...whereSpread,\n\t\t\t\t\t...(this.query.groupBy !== undefined && {\n\t\t\t\t\t\tgroupBy: this.query.groupBy as readonly string[],\n\t\t\t\t\t}),\n\t\t\t\t\t...(this.query.having !== undefined && {\n\t\t\t\t\t\thaving: this.query.having,\n\t\t\t\t\t}),\n\t\t\t\t} as QueryObjectForType<TSchema, TType>;\n\t\t\t}\n\n\t\t\tcase \"insert\": {\n\t\t\t\tconst dataItems = this.query.dataItems ?? [];\n\t\t\t\tif (dataItems.length === 0) {\n\t\t\t\t\tthrowMissingData(\"insert\");\n\t\t\t\t}\n\t\t\t\tconst processedItems = dataItems.map((item) =>\n\t\t\t\t\tprocessData<TSchema>(item, this._schema, this._registry),\n\t\t\t\t);\n\t\t\t\tconst dataArray = processedItems.map(\n\t\t\t\t\t(p) => p.data,\n\t\t\t\t) as readonly Partial<TSchema>[];\n\t\t\t\tconst relations = processedItems[0]?.relations;\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"insert\" as const,\n\t\t\t\t\ttable,\n\t\t\t\t\tdata: dataArray,\n\t\t\t\t\t...(relations !== undefined && { relations }),\n\t\t\t\t\t...selectSpread,\n\t\t\t\t\t...populateSpread,\n\t\t\t\t} as unknown as QueryObjectForType<TSchema, TType>;\n\t\t\t}\n\n\t\t\tcase \"update\": {\n\t\t\t\tif (this.query.data === undefined) {\n\t\t\t\t\tthrowMissingData(\"update\");\n\t\t\t\t}\n\t\t\t\tconst processedData = processData<TSchema>(\n\t\t\t\t\tthis.query.data,\n\t\t\t\t\tthis._schema,\n\t\t\t\t\tthis._registry,\n\t\t\t\t);\n\t\t\t\treturn {\n\t\t\t\t\ttype,\n\t\t\t\t\ttable,\n\t\t\t\t\t...whereSpread,\n\t\t\t\t\tdata: processedData.data,\n\t\t\t\t\t...(processedData.relations !== undefined && {\n\t\t\t\t\t\trelations: processedData.relations,\n\t\t\t\t\t}),\n\t\t\t\t\t...selectSpread,\n\t\t\t\t\t...populateSpread,\n\t\t\t\t} as QueryObjectForType<TSchema, TType>;\n\t\t\t}\n\n\t\t\tcase \"delete\": {\n\t\t\t\tif (normalizedWhere === undefined) {\n\t\t\t\t\tthrowDeleteWithoutWhere();\n\t\t\t\t}\n\t\t\t\treturn {\n\t\t\t\t\ttype,\n\t\t\t\t\ttable,\n\t\t\t\t\twhere: normalizedWhere,\n\t\t\t\t\t...selectSpread,\n\t\t\t\t\t...populateSpread,\n\t\t\t\t} as QueryObjectForType<TSchema, TType>;\n\t\t\t}\n\n\t\t\tdefault:\n\t\t\t\tthrowInvalidQueryType(type);\n\t\t}\n\t}\n\n\t/**\n\t * Clone builder (for reusability)\n\t */\n\tclone(): DatrixQueryBuilder<TSchema, TType> {\n\t\tconst cloned = new DatrixQueryBuilder<TSchema, TType>(\n\t\t\tthis._modelName,\n\t\t\tthis._registry,\n\t\t\tthis.query.type as TType,\n\t\t);\n\n\t\t// Deep clone the query state to avoid shared references\n\t\tcloned.query = {\n\t\t\t...this.query,\n\t\t\t...(this.query.where !== undefined && {\n\t\t\t\twhere: deepClone(this.query.where),\n\t\t\t}),\n\t\t\t...(this.query.populate !== undefined && {\n\t\t\t\tpopulate: deepClone(this.query.populate),\n\t\t\t}),\n\t\t\t...(this.query.data !== undefined && {\n\t\t\t\tdata: deepClone(this.query.data),\n\t\t\t}),\n\t\t\t...(this.query.dataItems !== undefined && {\n\t\t\t\tdataItems: deepClone(this.query.dataItems),\n\t\t\t}),\n\t\t\t...(this.query.orderBy !== undefined && {\n\t\t\t\torderBy: deepClone(this.query.orderBy),\n\t\t\t}),\n\t\t\t...(this.query.groupBy !== undefined && {\n\t\t\t\tgroupBy: deepClone(this.query.groupBy),\n\t\t\t}),\n\t\t\t...(this.query.having !== undefined && {\n\t\t\t\thaving: deepClone(this.query.having),\n\t\t\t}),\n\t\t};\n\n\t\treturn cloned;\n\t}\n\n\t/**\n\t * Reset builder to initial state\n\t */\n\treset(): this {\n\t\tthis.query = {};\n\t\treturn this;\n\t}\n}\n\n/**\n * Create a new query builder\n *\n * @param modelName - Model name (e.g., 'User', 'Post')\n * @param schemaRegistry - Schema registry\n * @returns Query builder instance\n *\n * @example\n * ```ts\n * const builder = createQueryBuilder<User>('User', registry);\n * ```\n */\nexport function createQueryBuilder<\n\tTSchema extends DatrixEntry,\n\tTType extends QueryType = \"select\",\n>(\n\tmodelName: string,\n\tschemaRegistry: ISchemaRegistry,\n\ttype?: TType,\n): DatrixQueryBuilder<TSchema, TType> {\n\treturn new DatrixQueryBuilder<TSchema, TType>(\n\t\tmodelName,\n\t\tschemaRegistry,\n\t\t(type ?? \"select\") as TType,\n\t);\n}\n\nexport function selectFrom<TSchema extends DatrixEntry>(\n\tmodelName: string,\n\tschemaRegistry: ISchemaRegistry,\n): DatrixQueryBuilder<TSchema, \"select\"> {\n\treturn new DatrixQueryBuilder<TSchema, \"select\">(\n\t\tmodelName,\n\t\tschemaRegistry,\n\t\t\"select\",\n\t);\n}\n\n/**\n * Create INSERT query builder\n *\n * @param data - Single item or array of items to insert\n */\nexport function insertInto<TSchema extends DatrixEntry>(\n\tmodelName: string,\n\tdata: Partial<TSchema> | readonly Partial<TSchema>[],\n\tschemaRegistry: ISchemaRegistry,\n): DatrixQueryBuilder<TSchema, \"insert\"> {\n\tconst builder = new DatrixQueryBuilder<TSchema, \"insert\">(\n\t\tmodelName,\n\t\tschemaRegistry,\n\t\t\"insert\",\n\t);\n\tconst items = Array.isArray(data) ? data : [data];\n\tfor (const item of items) {\n\t\tbuilder.pushData(item);\n\t}\n\treturn builder;\n}\n\nexport function updateTable<TSchema extends DatrixEntry>(\n\tmodelName: string,\n\tdata: Partial<TSchema>,\n\tschemaRegistry: ISchemaRegistry,\n): DatrixQueryBuilder<TSchema, \"update\"> {\n\treturn new DatrixQueryBuilder<TSchema, \"update\">(\n\t\tmodelName,\n\t\tschemaRegistry,\n\t\t\"update\",\n\t).data(data);\n}\n\nexport function deleteFrom<TSchema extends DatrixEntry>(\n\tmodelName: string,\n\tschemaRegistry: ISchemaRegistry,\n): DatrixQueryBuilder<TSchema, \"delete\"> {\n\treturn new DatrixQueryBuilder<TSchema, \"delete\">(\n\t\tmodelName,\n\t\tschemaRegistry,\n\t\t\"delete\",\n\t);\n}\n\nexport function countFrom<TSchema extends DatrixEntry>(\n\tmodelName: string,\n\tschemaRegistry: ISchemaRegistry,\n): DatrixQueryBuilder<TSchema, \"count\"> {\n\treturn new DatrixQueryBuilder<TSchema, \"count\">(\n\t\tmodelName,\n\t\tschemaRegistry,\n\t\t\"count\",\n\t);\n}\n","/**\n * Schema Type Definitions\n *\n * This file defines the core schema types used throughout Datrix.\n * Schemas are defined as plain TypeScript objects with full type inference.\n */\n\nimport type { SchemaPermission, FieldPermission } from \"./permission\";\nimport { QuerySelect } from \"./query-builder\";\nimport type { DatrixEntry } from \"./entry\";\nimport type { LifecycleHooks } from \"./hooks\";\n\n/**\n * Reserved field names that are automatically added to all schemas\n * and cannot be defined manually by users\n */\nexport const RESERVED_FIELDS = [\"id\", \"createdAt\", \"updatedAt\"] as const;\n\n/**\n * Type for reserved field names\n */\nexport type ReservedFieldName = (typeof RESERVED_FIELDS)[number];\n\nexport type { DatrixEntry, DatrixRecord, FallbackValue } from \"./entry\";\n\n/**\n * Primitive field types\n */\nexport type FieldType =\n\t| \"string\"\n\t| \"number\"\n\t| \"boolean\"\n\t| \"date\"\n\t| \"json\"\n\t| \"enum\"\n\t| \"array\"\n\t| \"relation\"\n\t| \"file\";\n\n/**\n * Base field definition (common properties)\n *\n * @template TRoles - Union type of valid role names for permission checks\n */\ninterface BaseFieldDefinition<TRoles extends string = string> {\n\treadonly required?: boolean;\n\treadonly default?: unknown;\n\treadonly description?: string;\n\t/**\n\t * If true, field is excluded from SELECT queries by default\n\t * Used for auto-generated fields like foreign keys that shouldn't appear in responses\n\t * @internal\n\t */\n\treadonly hidden?: boolean;\n\t/**\n\t * Field-level permission configuration\n\t * - `read`: If denied, field is stripped from response\n\t * - `write`: If denied, returns 403 error\n\t */\n\treadonly permission?: FieldPermission<TRoles>;\n}\n\n/**\n * String field definition\n */\nexport interface StringField<\n\tTRoles extends string = string,\n> extends BaseFieldDefinition<TRoles> {\n\treadonly type: \"string\";\n\treadonly minLength?: number;\n\treadonly maxLength?: number;\n\treadonly pattern?: RegExp;\n\treadonly unique?: boolean;\n\treadonly validator?: (value: string) => true | string;\n\treadonly errorMessage?: string;\n}\n\n/**\n * Foreign key reference definition\n * Used by NumberField.references to generate FOREIGN KEY constraints in adapters\n */\nexport interface ForeignKeyReference {\n\treadonly table: string;\n\treadonly column?: string; // defaults to \"id\"\n\treadonly onDelete?: \"cascade\" | \"setNull\" | \"restrict\" | undefined;\n\treadonly onUpdate?: \"cascade\" | \"restrict\" | undefined;\n}\n\n/**\n * Number field definition\n */\nexport interface NumberField<\n\tTRoles extends string = string,\n> extends BaseFieldDefinition<TRoles> {\n\treadonly type: \"number\";\n\treadonly min?: number;\n\treadonly max?: number;\n\treadonly integer?: boolean;\n\treadonly unique?: boolean;\n\treadonly autoIncrement?: boolean;\n\treadonly validator?: (value: number) => true | string;\n\treadonly references?: ForeignKeyReference;\n}\n\n/**\n * Boolean field definition\n */\nexport interface BooleanField<\n\tTRoles extends string = string,\n> extends BaseFieldDefinition<TRoles> {\n\treadonly type: \"boolean\";\n}\n\n/**\n * Date field definition\n */\nexport interface DateField<\n\tTRoles extends string = string,\n> extends BaseFieldDefinition<TRoles> {\n\treadonly type: \"date\";\n\treadonly min?: Date;\n\treadonly max?: Date;\n}\n\n/**\n * JSON field definition\n */\nexport interface JsonField<\n\tTRoles extends string = string,\n> extends BaseFieldDefinition<TRoles> {\n\treadonly type: \"json\";\n\treadonly schema?: Record<string, unknown>; // JSON schema validation\n}\n\n/**\n * Enum field definition\n */\nexport interface EnumField<\n\tT extends readonly string[] = readonly string[],\n\tTRoles extends string = string,\n> extends BaseFieldDefinition<TRoles> {\n\treadonly type: \"enum\";\n\treadonly values: T;\n}\n\n/**\n * Array field definition\n */\nexport interface ArrayField<\n\tTRoles extends string = string,\n> extends BaseFieldDefinition<TRoles> {\n\treadonly type: \"array\";\n\treadonly items: FieldDefinition<TRoles>;\n\treadonly minItems?: number;\n\treadonly maxItems?: number;\n\treadonly unique?: boolean; // All items must be unique\n}\n\n/**\n * Relation kinds\n */\nexport type RelationKind = \"hasOne\" | \"hasMany\" | \"belongsTo\" | \"manyToMany\";\n\n/**\n * File options carried on a RelationField that was converted from a FileField.\n * When defined, the relation is a file upload relation.\n * Used by the upload handler — core ignores this.\n */\nexport interface FileFieldOptions {\n\treadonly allowedTypes?: readonly string[]; // MIME types e.g. [\"image/*\", \"application/pdf\"]\n\treadonly maxSize?: number; // In bytes\n}\n\n/**\n * Relation field definition\n */\nexport interface RelationField<\n\tTRoles extends string = string,\n> extends BaseFieldDefinition<TRoles> {\n\treadonly type: \"relation\";\n\treadonly model: string; // Target model name\n\treadonly kind: RelationKind;\n\treadonly foreignKey?: string; // Optional - defaults to fieldName + \"Id\"\n\treadonly through?: string; // Join table for manyToMany (optional - auto-generated)\n\treadonly onDelete?: \"cascade\" | \"setNull\" | \"restrict\";\n\treadonly onUpdate?: \"cascade\" | \"restrict\";\n\t/**\n\t * Present only when this relation was converted from a FileField.\n\t * Upload handler reads this to validate uploaded files.\n\t */\n\treadonly fileOptions?: FileFieldOptions;\n}\n\n/**\n * Flexible ID reference for relations\n * Accepts: number, string, or object with id property\n *\n * @example\n * ```ts\n * // All valid:\n * 5\n * \"uuid-123\"\n * { id: 5 }\n * { id: \"uuid-123\", name: \"Test\" } // extra fields ignored, id extracted\n * ```\n */\nexport type RelationIdRef = number | { id: number };\n\n/**\n * Flexible ID references (single or array)\n * Accepts any combination of RelationIdRef\n *\n * @example\n * ```ts\n * // All valid:\n * 5\n * [1, 2, 3]\n * { id: 5 }\n * [{ id: 1 }, { id: 2 }]\n * [1, { id: 2 }, \"uuid-3\"] // mixed\n * ```\n */\nexport type RelationIdRefs = RelationIdRef | RelationIdRef[];\n\n/**\n * belongsTo (N:1) and hasOne (1:1) relation input - write operations\n *\n * Singular relations: only one record can be referenced at a time.\n * Shortcuts: pass ID directly or null to disconnect.\n *\n * @example\n * ```ts\n * // Shortcuts\n * author: 5\n * author: { id: 5 }\n * author: null // disconnect\n *\n * // Explicit object form\n * author: { connect: 5 }\n * author: { connect: { id: 5 } }\n * author: { set: 5 }\n * author: { disconnect: true }\n * author: { create: { name: 'John' } }\n * author: { update: { where: { id: 5 }, data: { name: 'John' } } }\n * ```\n */\nexport type RelationBelongsTo<T extends DatrixEntry> =\n\t| RelationIdRef\n\t| null\n\t| {\n\t\tconnect?: RelationIdRef;\n\t\tset?: RelationIdRef;\n\t\tdisconnect?: true;\n\t\tcreate?: Partial<T>;\n\t\tupdate?: { where: { id: number }; data: Partial<T> };\n\t\tdelete?: RelationIdRef;\n\t};\n\n/**\n * hasOne (1:1) relation input - write operations\n * Same constraints as belongsTo (singular).\n */\nexport type RelationHasOne<T extends DatrixEntry> = RelationBelongsTo<T>;\n\n/**\n * hasMany (1:N) relation input - write operations\n *\n * Plural relations: multiple records can be referenced.\n * Shortcuts: single ID or array of IDs.\n *\n * @example\n * ```ts\n * // Shortcuts\n * tags: 5\n * tags: { id: 5 }\n * tags: [1, 2, 3]\n * tags: [{ id: 1 }, { id: 2 }]\n *\n * // Explicit object form\n * tags: { connect: [1, 2] }\n * tags: { disconnect: [3] }\n * tags: { set: [1, 2, 3] }\n * tags: { create: [{ name: 'Tag A' }, { name: 'Tag B' }] }\n * tags: { delete: [4, 5] }\n * ```\n */\nexport type RelationHasMany<T extends DatrixEntry> =\n\t| RelationIdRefs\n\t| {\n\t\tconnect?: RelationIdRefs;\n\t\tdisconnect?: RelationIdRefs;\n\t\tset?: RelationIdRefs;\n\t\tcreate?: Partial<T> | Partial<T>[];\n\t\tupdate?:\n\t\t| { where: { id: number }; data: Partial<T> }\n\t\t| { where: { id: number }; data: Partial<T> }[];\n\t\tdelete?: RelationIdRefs;\n\t};\n\n/**\n * manyToMany (N:N) relation input - write operations\n * Same constraints as hasMany (plural).\n */\nexport type RelationManyToMany<T extends DatrixEntry> = RelationHasMany<T>;\n\n/**\n * Union of all relation input types.\n * Used internally by the query builder and validator.\n */\nexport type RelationInput<T extends DatrixEntry> =\n\t| RelationBelongsTo<T>\n\t| RelationHasMany<T>;\n\n/**\n * Relation input without generic — for use in untyped/fallback contexts.\n * Covers ID-based operations only (no nested create/update).\n * Provides intellisense for connect/set/disconnect/delete without requiring a model type.\n *\n * @example\n * ```ts\n * // Shortcuts\n * author: 5\n * tags: [1, 2, 3]\n *\n * // Explicit\n * author: { connect: 5 }\n * tags: { set: [1, 2, 3] }\n * tags: { disconnect: [3] }\n * ```\n */\nexport type AnyRelationInput = RelationIdRefs | null | AnyRelationInputObject;\n\nexport type AnyRelationInputObject = {\n\tconnect?: RelationIdRefs;\n\tdisconnect?: RelationIdRefs | true;\n\tset?: RelationIdRefs;\n\tdelete?: RelationIdRefs;\n\tcreate?: Record<string, unknown> | Record<string, unknown>[];\n\tupdate?:\n\t| { where: { id: number }; data: Record<string, unknown> }\n\t| { where: { id: number }; data: Record<string, unknown> }[];\n};\n\n/**\n * Normalized relation ID (always { id } format)\n */\nexport type NormalizedRelationId = { id: string | number };\n\n/**\n * Normalize a single RelationIdRef to { id } format\n *\n * @param ref - ID reference (number, string, or object with id)\n * @returns Normalized { id } object\n *\n * @example\n * ```ts\n * normalizeRelationId(5) // { id: 5 }\n * normalizeRelationId(\"uuid\") // { id: \"uuid\" }\n * normalizeRelationId({ id: 5 }) // { id: 5 }\n * normalizeRelationId({ id: 5, name: \"Test\" }) // { id: 5 }\n * ```\n */\nexport function normalizeRelationId(ref: RelationIdRef): NormalizedRelationId {\n\tif (typeof ref === \"number\" || typeof ref === \"string\") {\n\t\treturn { id: ref };\n\t}\n\treturn { id: ref.id };\n}\n\n/**\n * Normalize RelationIdRefs to array of { id } format\n *\n * @param refs - Single or array of ID references\n * @returns Array of normalized { id } objects\n *\n * @example\n * ```ts\n * normalizeRelationIds(5) // [{ id: 5 }]\n * normalizeRelationIds([1, 2]) // [{ id: 1 }, { id: 2 }]\n * normalizeRelationIds({ id: 5 }) // [{ id: 5 }]\n * normalizeRelationIds([1, { id: 2 }]) // [{ id: 1 }, { id: 2 }]\n * ```\n */\nexport function normalizeRelationIds(\n\trefs: RelationIdRefs,\n): NormalizedRelationId[] {\n\tif (Array.isArray(refs)) {\n\t\treturn refs.map(normalizeRelationId);\n\t}\n\treturn [normalizeRelationId(refs)];\n}\n\n/**\n * Check if value is a valid RelationIdRef\n */\nexport function isRelationIdRef(value: unknown): value is RelationIdRef {\n\tif (typeof value === \"number\" || typeof value === \"string\") {\n\t\treturn true;\n\t}\n\tif (\n\t\ttypeof value === \"object\" &&\n\t\tvalue !== null &&\n\t\t\"id\" in value &&\n\t\t(typeof (value as { id: unknown }).id === \"number\" ||\n\t\t\ttypeof (value as { id: unknown }).id === \"string\")\n\t) {\n\t\treturn true;\n\t}\n\treturn false;\n}\n\n/**\n * Check if value is valid RelationIdRefs\n */\nexport function isRelationIdRefs(value: unknown): value is RelationIdRefs {\n\tif (isRelationIdRef(value)) {\n\t\treturn true;\n\t}\n\tif (Array.isArray(value) && value.every(isRelationIdRef)) {\n\t\treturn true;\n\t}\n\treturn false;\n}\n\n/**\n * File field definition\n */\nexport interface FileField<\n\tTRoles extends string = string,\n> extends BaseFieldDefinition<TRoles> {\n\treadonly type: \"file\";\n\treadonly allowedTypes?: readonly string[]; // MIME types\n\treadonly maxSize?: number; // In bytes\n\treadonly multiple?: boolean; // Allow multiple files\n}\n\n/**\n * Union of all field definitions\n *\n * @template TRoles - Union type of valid role names for permission checks\n */\nexport type FieldDefinition<TRoles extends string = string> =\n\t| StringField<TRoles>\n\t| NumberField<TRoles>\n\t| BooleanField<TRoles>\n\t| DateField<TRoles>\n\t| JsonField<TRoles>\n\t| EnumField<readonly string[], TRoles>\n\t| ArrayField<TRoles>\n\t| RelationField<TRoles>\n\t| FileField<TRoles>;\n\n/**\n * Index definition\n */\nexport interface IndexDefinition {\n\treadonly name?: string;\n\treadonly fields: readonly string[];\n\treadonly unique?: boolean;\n\treadonly type?: \"btree\" | \"hash\" | \"gist\" | \"gin\";\n}\n\nexport type { LifecycleHooks } from \"./hooks\";\n\n/**\n * Schema definition\n *\n * @template TRoles - Union type of valid role names for permission checks\n * @template TFields - Record of field names to field definitions\n *\n * @example\n * ```ts\n * const roles = ['admin', 'editor', 'user'] as const;\n * type Roles = typeof roles[number];\n *\n * const postSchema = defineSchema<Roles>()({\n * name: 'post',\n * fields: {\n * title: { type: 'string', required: true },\n * authorId: { type: 'string', required: true },\n * },\n * permission: {\n * create: ['admin', 'editor'],\n * read: true,\n * update: ['admin', (ctx) => ctx.user?.id === ctx.record?.authorId],\n * delete: ['admin'],\n * }\n * });\n * ```\n */\nexport interface SchemaDefinition<\n\tTRoles extends string = string,\n\tTFields extends Record<string, FieldDefinition<TRoles>> = Record<\n\t\tstring,\n\t\tFieldDefinition<TRoles>\n\t>,\n> {\n\treadonly name: string;\n\treadonly fields: TFields;\n\treadonly indexes?: readonly IndexDefinition[];\n\treadonly hooks?: LifecycleHooks;\n\treadonly timestamps?: boolean; // Auto-add createdAt, updatedAt\n\treadonly softDelete?: boolean; // Add deletedAt field\n\treadonly tableName?: string; // Custom table name (defaults to pluralized name)\n\t/**\n\t * Schema-level permission configuration\n\t * Defines who can perform CRUD operations on this schema\n\t */\n\treadonly permission?: SchemaPermission<TRoles>;\n\t/**\n\t * Internal flag - marks auto-generated junction tables for manyToMany relations\n\t * @internal\n\t */\n\treadonly _isJunctionTable?: boolean;\n}\n\n/**\n * Define a schema definition.\n * Returns the schema as-is with const inference preserved.\n *\n * @example\n * ```ts\n * const postSchema = defineSchema({\n * name: 'post',\n * fields: {\n * title: { type: 'string', required: true },\n * content: { type: 'string' },\n * },\n * permission: {\n * create: ['admin', 'editor'],\n * read: true,\n * }\n * });\n * ```\n */\nexport function defineSchema<const T extends SchemaDefinition>(schema: T): T {\n\treturn schema;\n}\n\n/**\n * Schema registry interface\n *\n * Defines the contract for schema storage and retrieval.\n * Implementation is in packages/core/src/schema/registry.ts\n */\nexport interface ISchemaRegistry {\n\t/** Register a schema */\n\tregister(schema: SchemaDefinition): SchemaDefinition;\n\t/** Get schema by name */\n\tget(name: string): SchemaDefinition | undefined;\n\t/** Get schema by model name with resolved table name */\n\tgetWithTableName(\n\t\tmodelName: string,\n\t): { schema: SchemaDefinition; tableName: string } | undefined;\n\t/** Get schema by table name with resolved table name */\n\tgetByTableName(\n\t\ttableName: string,\n\t): { schema: SchemaDefinition; tableName: string } | undefined;\n\t/** Check if schema exists */\n\thas(name: string): boolean;\n\t/** Get all schemas */\n\tgetAll(): readonly SchemaDefinition[];\n\t/** Get schema names */\n\tgetNames(): readonly string[];\n\t/** Get schema count */\n\treadonly size: number;\n\t/** Find model name by table name */\n\tfindModelByTableName(tableName: string | null): string | null;\n\t/** Get related schemas for a given schema */\n\tgetRelatedSchemas(schemaName: string): readonly string[];\n\t/** Check if registry is locked */\n\tisLocked(): boolean;\n\t/** Get select fields for a model */\n\tgetCachedSelectFields<T extends DatrixEntry>(\n\t\tmodelName: string,\n\t): QuerySelect<T>;\n}\n\n/**\n * Field metadata (runtime information)\n */\nexport interface FieldMetadata {\n\treadonly name: string;\n\treadonly type: FieldType;\n\treadonly required: boolean;\n\treadonly unique: boolean;\n\treadonly hasDefault: boolean;\n\treadonly isRelation: boolean;\n\treadonly isArray: boolean;\n}\n\n/**\n * Schema definition validation result\n */\nexport interface SchemaDefinitionValidationResult {\n\treadonly valid: boolean;\n\treadonly errors: readonly SchemaValidationError[];\n}\n\n/**\n * Schema validation error\n */\nexport interface SchemaValidationError {\n\treadonly field?: string;\n\treadonly message: string;\n\treadonly code: string;\n}\n\n/**\n * Validate schema definition\n */\nexport function validateSchemaDefinition(\n\tschema: SchemaDefinition,\n): SchemaDefinitionValidationResult {\n\tconst errors: SchemaValidationError[] = [];\n\n\t// Check name\n\tif (!schema.name || schema.name.trim() === \"\") {\n\t\terrors.push({\n\t\t\tmessage: \"Schema name is required\",\n\t\t\tcode: \"MISSING_NAME\",\n\t\t});\n\t}\n\n\t// Check fields\n\tif (!schema.fields || Object.keys(schema.fields).length === 0) {\n\t\terrors.push({\n\t\t\tmessage: \"Schema must have at least one field\",\n\t\t\tcode: \"NO_FIELDS\",\n\t\t});\n\t}\n\n\t// Validate each field\n\tfor (const [fieldName, fieldDef] of Object.entries(schema.fields)) {\n\t\t// Check field name\n\t\tif (!fieldName || fieldName.trim() === \"\") {\n\t\t\terrors.push({\n\t\t\t\tmessage: \"Field name cannot be empty\",\n\t\t\t\tcode: \"INVALID_FIELD_NAME\",\n\t\t\t});\n\t\t}\n\n\t\t// Check relation references\n\t\tif (fieldDef.type === \"relation\") {\n\t\t\tif (!fieldDef.model || fieldDef.model.trim() === \"\") {\n\t\t\t\terrors.push({\n\t\t\t\t\tfield: fieldName,\n\t\t\t\t\tmessage: \"Relation field must specify a model\",\n\t\t\t\t\tcode: \"MISSING_RELATION_MODEL\",\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\t// Check enum values\n\t\tif (fieldDef.type === \"enum\") {\n\t\t\tif (!fieldDef.values || fieldDef.values.length === 0) {\n\t\t\t\terrors.push({\n\t\t\t\t\tfield: fieldName,\n\t\t\t\t\tmessage: \"Enum field must have at least one value\",\n\t\t\t\t\tcode: \"EMPTY_ENUM\",\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\t// Check array items\n\t\tif (fieldDef.type === \"array\") {\n\t\t\tif (!fieldDef.items) {\n\t\t\t\terrors.push({\n\t\t\t\t\tfield: fieldName,\n\t\t\t\t\tmessage: \"Array field must specify items type\",\n\t\t\t\t\tcode: \"MISSING_ARRAY_ITEMS\",\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\treturn {\n\t\tvalid: errors.length === 0,\n\t\terrors,\n\t};\n}\n\n/**\n * Sort schemas by FK dependency order using Kahn's topological sort.\n * Referenced schemas (parents) come before schemas that reference them (children).\n * Circular/unresolved schemas are appended at the end unchanged.\n *\n * Used by SchemaRegistry.finalizeRegistry() and ZipExportWriter.finalize()\n * to guarantee consistent table creation order.\n */\nexport function sortSchemasByDependency(\n\tschemas: SchemaDefinition[],\n): SchemaDefinition[] {\n\tconst tableToSchema = new Map<string, SchemaDefinition>();\n\tfor (const schema of schemas) {\n\t\tif (schema.tableName) tableToSchema.set(schema.tableName, schema);\n\t}\n\n\tconst deps = new Map<string, Set<string>>();\n\tfor (const schema of schemas) {\n\t\tif (schema.tableName) deps.set(schema.tableName, new Set());\n\t}\n\n\tfor (const schema of schemas) {\n\t\tfor (const field of Object.values(schema.fields)) {\n\t\t\tconst ref = (field as { references?: { table: string } }).references;\n\t\t\tif (!ref) continue;\n\t\t\tconst depTable = ref.table;\n\t\t\tif (depTable !== schema.tableName && tableToSchema.has(depTable)) {\n\t\t\t\tdeps.get(schema.tableName!)!.add(depTable);\n\t\t\t}\n\t\t}\n\t}\n\n\tconst inDegree = new Map<string, number>();\n\tfor (const tableName of deps.keys()) {\n\t\tinDegree.set(tableName, 0);\n\t}\n\tfor (const depSet of deps.values()) {\n\t\tfor (const dep of depSet) {\n\t\t\tinDegree.set(dep, (inDegree.get(dep) ?? 0) + 1);\n\t\t}\n\t}\n\n\tconst queue: string[] = [];\n\tfor (const [tableName, degree] of inDegree) {\n\t\tif (degree === 0) queue.push(tableName);\n\t}\n\n\tconst sorted: string[] = [];\n\twhile (queue.length > 0) {\n\t\tconst current = queue.shift()!;\n\t\tsorted.push(current);\n\t\tfor (const dep of deps.get(current) ?? []) {\n\t\t\tconst newDegree = (inDegree.get(dep) ?? 1) - 1;\n\t\t\tinDegree.set(dep, newDegree);\n\t\t\tif (newDegree === 0) queue.push(dep);\n\t\t}\n\t}\n\n\t// Reverse: dependencies first (parents before children)\n\tsorted.reverse();\n\n\tconst result: SchemaDefinition[] = [];\n\tfor (const tableName of sorted) {\n\t\tconst schema = tableToSchema.get(tableName);\n\t\tif (schema) result.push(schema);\n\t}\n\t// Append any schemas without tableName or in circular deps\n\tfor (const schema of schemas) {\n\t\tif (!result.includes(schema)) result.push(schema);\n\t}\n\n\treturn result;\n}\n","/**\n * Validation Error Classes\n *\n * Custom error classes and utilities for validation errors.\n * Provides detailed error information for debugging.\n */\n\nimport { ValidationError, ValidationErrorCode } from \"../types/core/validator\";\nimport { DatrixValidationError } from \"../types/errors/core/validation\";\n\n/**\n * Create a validation error\n */\nexport function createValidationError(\n\tfield: string,\n\tcode: ValidationErrorCode,\n\tmessage: string,\n\toptions?: {\n\t\tvalue?: unknown;\n\t\texpected?: unknown;\n\t},\n): ValidationError {\n\treturn {\n\t\tfield,\n\t\tcode,\n\t\tmessage,\n\t\tvalue: options?.value,\n\t\texpected: options?.expected,\n\t};\n}\n\n/**\n * Format error message with context\n */\nexport function formatErrorMessage(\n\tcode: ValidationErrorCode,\n\tfield: string,\n\toptions?: {\n\t\tmin?: number;\n\t\tmax?: number;\n\t\texpected?: unknown;\n\t\tactual?: unknown;\n\t\tpattern?: RegExp;\n\t},\n): string {\n\tswitch (code) {\n\t\tcase \"REQUIRED\":\n\t\t\treturn `Field '${field}' is required`;\n\n\t\tcase \"TYPE_MISMATCH\":\n\t\t\treturn `Field '${field}' has incorrect type. Expected ${options?.expected}, got ${options?.actual}`;\n\n\t\tcase \"MIN_LENGTH\":\n\t\t\treturn `Field '${field}' must be at least ${options?.min} characters long`;\n\n\t\tcase \"MAX_LENGTH\":\n\t\t\treturn `Field '${field}' must be at most ${options?.max} characters long`;\n\n\t\tcase \"MIN_VALUE\":\n\t\t\treturn `Field '${field}' must be at least ${options?.min}`;\n\n\t\tcase \"MAX_VALUE\":\n\t\t\treturn `Field '${field}' must be at most ${options?.max}`;\n\n\t\tcase \"MIN_ITEMS\":\n\t\t\treturn `Field '${field}' must have at least ${options?.min} items`;\n\n\t\tcase \"MAX_ITEMS\":\n\t\t\treturn `Field '${field}' must have at most ${options?.max} items`;\n\n\t\tcase \"PATTERN\":\n\t\t\treturn `Field '${field}' does not match required pattern${options?.pattern ? `: ${options.pattern}` : \"\"\n\t\t\t\t}`;\n\n\t\tcase \"UNIQUE\":\n\t\t\treturn `Field '${field}' must be unique`;\n\n\t\tcase \"INVALID_ENUM\":\n\t\t\treturn `Field '${field}' must be one of: ${options?.expected}`;\n\n\t\tcase \"INVALID_FORMAT\":\n\t\t\treturn `Field '${field}' has invalid format`;\n\n\t\tcase \"INVALID_DATE\":\n\t\t\treturn `Field '${field}' is not a valid date`;\n\n\t\tcase \"CUSTOM\":\n\t\t\treturn `Field '${field}' validation failed`;\n\n\t\tdefault:\n\t\t\treturn `Field '${field}' validation failed`;\n\t}\n}\n\n/**\n * Combine multiple validation errors\n */\nexport function combineErrors(\n\t...errorArrays: readonly (readonly ValidationError[])[]\n): readonly ValidationError[] {\n\tconst combined: ValidationError[] = [];\n\n\tfor (const errors of errorArrays) {\n\t\tcombined.push(...errors);\n\t}\n\n\treturn combined;\n}\n\n/**\n * Group errors by field\n */\nexport function groupErrorsByField(\n\terrors: readonly ValidationError[],\n): Record<string, readonly ValidationError[]> {\n\tconst grouped: Record<string, ValidationError[]> = {};\n\n\tfor (const error of errors) {\n\t\tif (!grouped[error.field]) {\n\t\t\tgrouped[error.field] = [];\n\t\t}\n\t\tgrouped[error.field]!.push(error);\n\t}\n\n\treturn grouped;\n}\n\n/**\n * Get first error for each field\n */\nexport function getFirstErrorPerField(\n\terrors: readonly ValidationError[],\n): Record<string, ValidationError> {\n\tconst firstErrors: Record<string, ValidationError> = {};\n\n\tfor (const error of errors) {\n\t\tif (!firstErrors[error.field]) {\n\t\t\tfirstErrors[error.field] = error;\n\t\t}\n\t}\n\n\treturn firstErrors;\n}\n\n/**\n * Filter errors by code\n */\nexport function filterErrorsByCode(\n\terrors: readonly ValidationError[],\n\tcode: ValidationErrorCode,\n): readonly ValidationError[] {\n\treturn errors.filter((error) => error.code === code);\n}\n\n/**\n * Filter errors by field\n */\nexport function filterErrorsByField(\n\terrors: readonly ValidationError[],\n\tfield: string,\n): readonly ValidationError[] {\n\treturn errors.filter((error) => error.field === field);\n}\n\n/**\n * Check if errors contain specific code\n */\nexport function hasErrorCode(\n\terrors: readonly ValidationError[],\n\tcode: ValidationErrorCode,\n): boolean {\n\treturn errors.some((error) => error.code === code);\n}\n\n/**\n * Check if errors contain specific field\n */\nexport function hasErrorForField(\n\terrors: readonly ValidationError[],\n\tfield: string,\n): boolean {\n\treturn errors.some((error) => error.field === field);\n}\n\n/**\n * Format errors as human-readable string\n */\nexport function formatErrors(errors: readonly ValidationError[]): string {\n\tif (errors.length === 0) {\n\t\treturn \"No validation errors\";\n\t}\n\n\tconst messages = errors.map(\n\t\t(error) => ` - ${error.field}: ${error.message} (${error.code})`,\n\t);\n\n\treturn `Validation failed with ${errors.length} error(s):\\n${messages.join(\n\t\t\"\\n\",\n\t)}`;\n}\n\n/**\n * Format errors as JSON\n */\nexport function formatErrorsAsJSON(errors: readonly ValidationError[]): string {\n\treturn JSON.stringify(errors, null, 2);\n}\n\n/**\n * Convert errors to plain object (for API responses)\n */\nexport function errorsToPlainObject(\n\terrors: readonly ValidationError[],\n): Record<string, string[]> {\n\tconst plain: Record<string, string[]> = {};\n\n\tfor (const error of errors) {\n\t\tif (!plain[error.field]) {\n\t\t\tplain[error.field] = [];\n\t\t}\n\t\tplain[error.field]!.push(error.message);\n\t}\n\n\treturn plain;\n}\n\n/**\n * Validation error collection class (immutable)\n */\nexport class ValidationErrorCollection {\n\tprivate readonly errors: readonly ValidationError[];\n\n\tconstructor(errors: readonly ValidationError[] = []) {\n\t\tthis.errors = Object.freeze([...errors]);\n\t}\n\n\t/**\n\t * Add an error (returns new instance)\n\t */\n\tadd(error: ValidationError): ValidationErrorCollection {\n\t\treturn new ValidationErrorCollection([...this.errors, error]);\n\t}\n\n\t/**\n\t * Add multiple errors (returns new instance)\n\t */\n\taddMany(errors: readonly ValidationError[]): ValidationErrorCollection {\n\t\treturn new ValidationErrorCollection([...this.errors, ...errors]);\n\t}\n\n\t/**\n\t * Get all errors\n\t */\n\tgetAll(): readonly ValidationError[] {\n\t\treturn this.errors;\n\t}\n\n\t/**\n\t * Get errors by field\n\t */\n\tgetByField(field: string): readonly ValidationError[] {\n\t\treturn filterErrorsByField(this.errors, field);\n\t}\n\n\t/**\n\t * Get errors by code\n\t */\n\tgetByCode(code: ValidationErrorCode): readonly ValidationError[] {\n\t\treturn filterErrorsByCode(this.errors, code);\n\t}\n\n\t/**\n\t * Check if has errors\n\t */\n\thasErrors(): boolean {\n\t\treturn this.errors.length > 0;\n\t}\n\n\t/**\n\t * Get error count\n\t */\n\tcount(): number {\n\t\treturn this.errors.length;\n\t}\n\n\t/**\n\t * Format as string\n\t */\n\ttoString(): string {\n\t\treturn formatErrors(this.errors);\n\t}\n\n\t/**\n\t * Format as JSON\n\t */\n\ttoJSON(): readonly ValidationError[] {\n\t\treturn this.errors;\n\t}\n\n\t/**\n\t * Group by field\n\t */\n\tgroupByField(): Record<string, readonly ValidationError[]> {\n\t\treturn groupErrorsByField(this.errors);\n\t}\n\n\t/**\n\t * Get first error per field\n\t */\n\tgetFirstPerField(): Record<string, ValidationError> {\n\t\treturn getFirstErrorPerField(this.errors);\n\t}\n}\n\n/**\n * Centralized Validation Error Helpers\n *\n * Provides a clean API for throwing DatrixValidationError.\n * Similar pattern to CRUD error helpers for consistency.\n */\n\n/**\n * Throw multiple validation errors\n *\n * @param model - Model name\n * @param errors - Array of validation errors\n * @param suggestion - Optional user guidance\n *\n * @example\n * ```ts\n * throwValidationMultiple('User', [\n * { field: 'email', code: 'REQUIRED', message: 'Email required' },\n * { field: 'age', code: 'MIN_VALUE', message: 'Age must be 18+' }\n * ]);\n * ```\n */\nexport function throwValidationMultiple(\n\tmodel: string,\n\terrors: readonly ValidationError[],\n\tsuggestion?: string,\n): never {\n\tconst errorMessages = errors\n\t\t.map((e) => `${e.field}: ${e.message}`)\n\t\t.join(\", \");\n\n\tthrow new DatrixValidationError(\n\t\t`Validation failed for ${model}: ${errorMessages}`,\n\t\t{\n\t\t\tmodel,\n\t\t\terrors,\n\t\t\toperation: \"validation:data\",\n\t\t\tsuggestion,\n\t\t},\n\t);\n}\n\n/**\n * Throw a single field validation error\n *\n * @param model - Model name\n * @param field - Field name\n * @param code - Error code\n * @param message - Error message\n * @param options - Additional error details\n *\n * @example\n * ```ts\n * throwValidationSingle('User', 'email', 'REQUIRED', 'Email is required');\n * ```\n */\nexport function throwValidationSingle(\n\tmodel: string,\n\tfield: string,\n\tcode: ValidationErrorCode,\n\tmessage: string,\n\toptions?: {\n\t\tvalue?: unknown;\n\t\texpected?: unknown;\n\t\tsuggestion?: string;\n\t},\n): never {\n\tconst error = createValidationError(field, code, message, {\n\t\tvalue: options?.value,\n\t\texpected: options?.expected,\n\t});\n\n\tthrow new DatrixValidationError(`Validation failed for ${model}: ${message}`, {\n\t\tmodel,\n\t\terrors: [error],\n\t\toperation: \"validation:field\",\n\t\tsuggestion: options?.suggestion,\n\t});\n}\n\n/**\n * Throw required field error\n *\n * @param model - Model name\n * @param field - Field name\n *\n * @example\n * ```ts\n * throwValidationRequired('User', 'email');\n * ```\n */\nexport function throwValidationRequired(model: string, field: string): never {\n\tconst message = formatErrorMessage(\"REQUIRED\", field);\n\tthrowValidationSingle(model, field, \"REQUIRED\", message, {\n\t\tsuggestion: `Provide a value for the '${field}' field`,\n\t});\n}\n\n/**\n * Throw type mismatch error\n *\n * @param model - Model name\n * @param field - Field name\n * @param expected - Expected type\n * @param received - Received value\n *\n * @example\n * ```ts\n * throwValidationTypeMismatch('User', 'age', 'number', 'string');\n * ```\n */\nexport function throwValidationTypeMismatch(\n\tmodel: string,\n\tfield: string,\n\texpected: string,\n\treceived: unknown,\n): never {\n\tconst actualType = typeof received;\n\tconst message = formatErrorMessage(\"TYPE_MISMATCH\", field, {\n\t\texpected,\n\t\tactual: actualType,\n\t});\n\n\tthrowValidationSingle(model, field, \"TYPE_MISMATCH\", message, {\n\t\tvalue: received,\n\t\texpected,\n\t\tsuggestion: `Ensure '${field}' is of type ${expected}`,\n\t});\n}\n\n/**\n * Throw pattern validation error\n *\n * @param model - Model name\n * @param field - Field name\n * @param pattern - Expected pattern\n * @param received - Received value\n *\n * @example\n * ```ts\n * throwValidationPattern('User', 'email', /^.+@.+$/, 'invalid-email');\n * ```\n */\nexport function throwValidationPattern(\n\tmodel: string,\n\tfield: string,\n\tpattern: RegExp,\n\treceived: unknown,\n): never {\n\tconst message = formatErrorMessage(\"PATTERN\", field, { pattern });\n\n\tthrowValidationSingle(model, field, \"PATTERN\", message, {\n\t\tvalue: received,\n\t\texpected: pattern.toString(),\n\t\tsuggestion: `Ensure '${field}' matches the required pattern: ${pattern}`,\n\t});\n}\n\n/**\n * Throw min length validation error\n *\n * @param model - Model name\n * @param field - Field name\n * @param minLength - Minimum length\n * @param received - Received value\n *\n * @example\n * ```ts\n * throwValidationMinLength('User', 'password', 8, 'short');\n * ```\n */\nexport function throwValidationMinLength(\n\tmodel: string,\n\tfield: string,\n\tminLength: number,\n\treceived: unknown,\n): never {\n\tconst message = formatErrorMessage(\"MIN_LENGTH\", field, { min: minLength });\n\n\tthrowValidationSingle(model, field, \"MIN_LENGTH\", message, {\n\t\tvalue: received,\n\t\texpected: `at least ${minLength} characters`,\n\t\tsuggestion: `Provide a longer value for '${field}'`,\n\t});\n}\n\n/**\n * Throw max length validation error\n *\n * @param model - Model name\n * @param field - Field name\n * @param maxLength - Maximum length\n * @param received - Received value\n *\n * @example\n * ```ts\n * throwValidationMaxLength('User', 'bio', 500, longText);\n * ```\n */\nexport function throwValidationMaxLength(\n\tmodel: string,\n\tfield: string,\n\tmaxLength: number,\n\treceived: unknown,\n): never {\n\tconst message = formatErrorMessage(\"MAX_LENGTH\", field, { max: maxLength });\n\n\tthrowValidationSingle(model, field, \"MAX_LENGTH\", message, {\n\t\tvalue: received,\n\t\texpected: `at most ${maxLength} characters`,\n\t\tsuggestion: `Shorten the value for '${field}'`,\n\t});\n}\n\n/**\n * Throw min value validation error\n *\n * @param model - Model name\n * @param field - Field name\n * @param minValue - Minimum value\n * @param received - Received value\n *\n * @example\n * ```ts\n * throwValidationMinValue('User', 'age', 18, 15);\n * ```\n */\nexport function throwValidationMinValue(\n\tmodel: string,\n\tfield: string,\n\tminValue: number,\n\treceived: unknown,\n): never {\n\tconst message = formatErrorMessage(\"MIN_VALUE\", field, { min: minValue });\n\n\tthrowValidationSingle(model, field, \"MIN_VALUE\", message, {\n\t\tvalue: received,\n\t\texpected: `at least ${minValue}`,\n\t\tsuggestion: `Provide a value >= ${minValue} for '${field}'`,\n\t});\n}\n\n/**\n * Throw max value validation error\n *\n * @param model - Model name\n * @param field - Field name\n * @param maxValue - Maximum value\n * @param received - Received value\n *\n * @example\n * ```ts\n * throwValidationMaxValue('User', 'age', 120, 150);\n * ```\n */\nexport function throwValidationMaxValue(\n\tmodel: string,\n\tfield: string,\n\tmaxValue: number,\n\treceived: unknown,\n): never {\n\tconst message = formatErrorMessage(\"MAX_VALUE\", field, { max: maxValue });\n\n\tthrowValidationSingle(model, field, \"MAX_VALUE\", message, {\n\t\tvalue: received,\n\t\texpected: `at most ${maxValue}`,\n\t\tsuggestion: `Provide a value <= ${maxValue} for '${field}'`,\n\t});\n}\n\n/**\n * Throw invalid enum error\n *\n * @param model - Model name\n * @param field - Field name\n * @param validValues - Valid enum values\n * @param received - Received value\n *\n * @example\n * ```ts\n * throwValidationEnum('User', 'role', ['admin', 'user'], 'superuser');\n * ```\n */\nexport function throwValidationEnum(\n\tmodel: string,\n\tfield: string,\n\tvalidValues: readonly string[],\n\treceived: unknown,\n): never {\n\tconst message = formatErrorMessage(\"INVALID_ENUM\", field, {\n\t\texpected: validValues.join(\", \"),\n\t});\n\n\tthrowValidationSingle(model, field, \"INVALID_ENUM\", message, {\n\t\tvalue: received,\n\t\texpected: validValues.join(\" | \"),\n\t\tsuggestion: `Use one of: ${validValues.join(\", \")}`,\n\t});\n}\n\n/**\n * Throw min items validation error\n *\n * @param model - Model name\n * @param field - Field name\n * @param minItems - Minimum items\n * @param received - Received array\n *\n * @example\n * ```ts\n * throwValidationMinItems('Post', 'tags', 1, []);\n * ```\n */\nexport function throwValidationMinItems(\n\tmodel: string,\n\tfield: string,\n\tminItems: number,\n\treceived: unknown,\n): never {\n\tconst message = formatErrorMessage(\"MIN_ITEMS\", field, { min: minItems });\n\n\tthrowValidationSingle(model, field, \"MIN_ITEMS\", message, {\n\t\tvalue: received,\n\t\texpected: `at least ${minItems} items`,\n\t\tsuggestion: `Provide at least ${minItems} items for '${field}'`,\n\t});\n}\n\n/**\n * Throw max items validation error\n *\n * @param model - Model name\n * @param field - Field name\n * @param maxItems - Maximum items\n * @param received - Received array\n *\n * @example\n * ```ts\n * throwValidationMaxItems('Post', 'tags', 10, largeArray);\n * ```\n */\nexport function throwValidationMaxItems(\n\tmodel: string,\n\tfield: string,\n\tmaxItems: number,\n\treceived: unknown,\n): never {\n\tconst message = formatErrorMessage(\"MAX_ITEMS\", field, { max: maxItems });\n\n\tthrowValidationSingle(model, field, \"MAX_ITEMS\", message, {\n\t\tvalue: received,\n\t\texpected: `at most ${maxItems} items`,\n\t\tsuggestion: `Reduce items in '${field}' to ${maxItems} or less`,\n\t});\n}\n\n/**\n * Throw invalid date error\n *\n * @param model - Model name\n * @param field - Field name\n * @param received - Received value\n *\n * @example\n * ```ts\n * throwValidationDate('Event', 'startDate', 'invalid-date');\n * ```\n */\nexport function throwValidationDate(\n\tmodel: string,\n\tfield: string,\n\treceived: unknown,\n): never {\n\tconst message = formatErrorMessage(\"INVALID_DATE\", field);\n\n\tthrowValidationSingle(model, field, \"INVALID_DATE\", message, {\n\t\tvalue: received,\n\t\texpected: \"valid Date object\",\n\t\tsuggestion: `Provide a valid date for '${field}'`,\n\t});\n}\n\n/**\n * Throw custom validation error\n *\n * @param model - Model name\n * @param field - Field name\n * @param message - Custom error message\n * @param received - Received value\n *\n * @example\n * ```ts\n * throwValidationCustom('User', 'username', 'Username already taken', 'john');\n * ```\n */\nexport function throwValidationCustom(\n\tmodel: string,\n\tfield: string,\n\tmessage: string,\n\treceived?: unknown,\n): never {\n\tthrowValidationSingle(model, field, \"CUSTOM\", message, {\n\t\tvalue: received,\n\t});\n}\n\n/**\n * Legacy helper for backward compatibility\n * @deprecated Use throwValidationMultiple instead\n */\nexport const validationError = {\n\tthrow: throwValidationMultiple,\n};\n","/**\n * Field Validator Implementation (~150 LOC)\n *\n * Validates individual field values against their field definitions.\n * Zero external dependencies - all validation is custom.\n *\n * TODO: Add native 'email' field type for automatic email validation\n * Currently, email validation requires explicit pattern in schema:\n * { type: 'string', pattern: /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/ }\n * Future: { type: 'email', required: true }\n */\n\nimport type {\n\tFieldDefinition,\n\tStringField,\n\tNumberField,\n\tEnumField,\n\tArrayField,\n\tDateField,\n} from \"../types/core/schema\";\nimport { createValidationError, formatErrorMessage } from \"./errors\";\nimport { FieldValidationResult } from \"../types/core/validator\";\n\n/**\n * Type guards\n */\nconst isString = (value: unknown): value is string => typeof value === \"string\";\nconst isNumber = (value: unknown): value is number =>\n\ttypeof value === \"number\" && !isNaN(value);\nconst isBoolean = (value: unknown): value is boolean =>\n\ttypeof value === \"boolean\";\nconst isDate = (value: unknown): value is Date =>\n\tvalue instanceof Date && !isNaN(value.getTime());\nconst isArray = (value: unknown): value is readonly unknown[] =>\n\tArray.isArray(value);\nconst isNullOrUndefined = (value: unknown): value is null | undefined =>\n\tvalue === null || value === undefined;\n\n/**\n * Maximum nesting depth for array/object validation\n */\nconst MAX_VALIDATION_DEPTH = 10;\n\n/**\n * Main field validator function\n */\nexport function validateField<T = unknown>(\n\tvalue: unknown,\n\tfield: FieldDefinition,\n\tfieldName: string,\n\tdepth = 0,\n): FieldValidationResult<T> {\n\t// Check depth limit to prevent infinite recursion\n\tif (depth > MAX_VALIDATION_DEPTH) {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: [\n\t\t\t\tcreateValidationError(\n\t\t\t\t\tfieldName,\n\t\t\t\t\t\"CUSTOM\",\n\t\t\t\t\t`Maximum validation depth (${MAX_VALIDATION_DEPTH}) exceeded`,\n\t\t\t\t\t{ value: depth },\n\t\t\t\t),\n\t\t\t],\n\t\t};\n\t}\n\t// Check required\n\tif (field.required && isNullOrUndefined(value)) {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: [\n\t\t\t\tcreateValidationError(\n\t\t\t\t\tfieldName,\n\t\t\t\t\t\"REQUIRED\",\n\t\t\t\t\tformatErrorMessage(\"REQUIRED\", fieldName),\n\t\t\t\t),\n\t\t\t],\n\t\t};\n\t}\n\n\t// If optional and null/undefined, skip validation\n\tif (!field.required && isNullOrUndefined(value)) {\n\t\treturn { success: true, data: value as T };\n\t}\n\n\t// Type-specific validation\n\tswitch (field.type) {\n\t\tcase \"string\":\n\t\t\treturn validateString(\n\t\t\t\tvalue,\n\t\t\t\tfield as StringField,\n\t\t\t\tfieldName,\n\t\t\t) as FieldValidationResult<T>;\n\t\tcase \"number\":\n\t\t\treturn validateNumber(\n\t\t\t\tvalue,\n\t\t\t\tfield as NumberField,\n\t\t\t\tfieldName,\n\t\t\t) as FieldValidationResult<T>;\n\t\tcase \"boolean\":\n\t\t\treturn validateBoolean(value, fieldName) as FieldValidationResult<T>;\n\t\tcase \"date\":\n\t\t\treturn validateDate(\n\t\t\t\tvalue,\n\t\t\t\tfield as DateField,\n\t\t\t\tfieldName,\n\t\t\t) as FieldValidationResult<T>;\n\t\tcase \"enum\":\n\t\t\treturn validateEnum(\n\t\t\t\tvalue,\n\t\t\t\tfield as EnumField,\n\t\t\t\tfieldName,\n\t\t\t) as FieldValidationResult<T>;\n\t\tcase \"array\":\n\t\t\treturn validateArray(\n\t\t\t\tvalue,\n\t\t\t\tfield as ArrayField,\n\t\t\t\tfieldName,\n\t\t\t\tdepth,\n\t\t\t) as FieldValidationResult<T>;\n\t\tcase \"json\":\n\t\t\treturn validateJSON(value, fieldName) as FieldValidationResult<T>;\n\t\tcase \"relation\":\n\t\t\treturn validateRelation(value, fieldName) as FieldValidationResult<T>;\n\t\tdefault:\n\t\t\treturn { success: true, data: value as T };\n\t}\n}\n\n/**\n * Validate string field\n */\nfunction validateString(\n\tvalue: unknown,\n\tfield: StringField,\n\tfieldName: string,\n): FieldValidationResult<string> {\n\tif (!isString(value)) {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: [\n\t\t\t\tcreateValidationError(\n\t\t\t\t\tfieldName,\n\t\t\t\t\t\"TYPE_MISMATCH\",\n\t\t\t\t\tformatErrorMessage(\"TYPE_MISMATCH\", fieldName, {\n\t\t\t\t\t\texpected: \"string\",\n\t\t\t\t\t\tactual: typeof value,\n\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\t],\n\t\t};\n\t}\n\n\tconst errors = [];\n\n\t// Min length\n\tif (field.minLength !== undefined && value.length < field.minLength) {\n\t\terrors.push(\n\t\t\tcreateValidationError(\n\t\t\t\tfieldName,\n\t\t\t\t\"MIN_LENGTH\",\n\t\t\t\tformatErrorMessage(\"MIN_LENGTH\", fieldName, { min: field.minLength }),\n\t\t\t\t{ value: value.length, expected: field.minLength },\n\t\t\t),\n\t\t);\n\t}\n\n\t// Max length\n\tif (field.maxLength !== undefined && value.length > field.maxLength) {\n\t\terrors.push(\n\t\t\tcreateValidationError(\n\t\t\t\tfieldName,\n\t\t\t\t\"MAX_LENGTH\",\n\t\t\t\tformatErrorMessage(\"MAX_LENGTH\", fieldName, { max: field.maxLength }),\n\t\t\t\t{ value: value.length, expected: field.maxLength },\n\t\t\t),\n\t\t);\n\t}\n\n\t// Pattern\n\tif (field.pattern && !field.pattern.test(value)) {\n\t\terrors.push(\n\t\t\tcreateValidationError(\n\t\t\t\tfieldName,\n\t\t\t\t\"PATTERN\",\n\t\t\t\tformatErrorMessage(\"PATTERN\", fieldName, { pattern: field.pattern }),\n\t\t\t\t{ value },\n\t\t\t),\n\t\t);\n\t}\n\n\t// Custom validator\n\tif (field.validator) {\n\t\tconst result = field.validator(value);\n\t\tif (result !== true) {\n\t\t\terrors.push(\n\t\t\t\tcreateValidationError(fieldName, \"CUSTOM\", result, { value }),\n\t\t\t);\n\t\t}\n\t}\n\n\tif (errors.length > 0) {\n\t\treturn { success: false, error: errors };\n\t}\n\n\treturn { success: true, data: value };\n}\n\n/**\n * Validate number field\n */\nfunction validateNumber(\n\tvalue: unknown,\n\tfield: NumberField,\n\tfieldName: string,\n): FieldValidationResult<number> {\n\tif (!isNumber(value)) {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: [\n\t\t\t\tcreateValidationError(\n\t\t\t\t\tfieldName,\n\t\t\t\t\t\"TYPE_MISMATCH\",\n\t\t\t\t\tformatErrorMessage(\"TYPE_MISMATCH\", fieldName, {\n\t\t\t\t\t\texpected: \"number\",\n\t\t\t\t\t\tactual: typeof value,\n\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\t],\n\t\t};\n\t}\n\n\tconst errors = [];\n\n\t// Integer check\n\tif (field.integer && !Number.isInteger(value)) {\n\t\terrors.push(\n\t\t\tcreateValidationError(\n\t\t\t\tfieldName,\n\t\t\t\t\"INVALID_FORMAT\",\n\t\t\t\t`Field '${fieldName}' must be an integer`,\n\t\t\t\t{ value },\n\t\t\t),\n\t\t);\n\t}\n\n\t// Min value\n\tif (field.min !== undefined && value < field.min) {\n\t\terrors.push(\n\t\t\tcreateValidationError(\n\t\t\t\tfieldName,\n\t\t\t\t\"MIN_VALUE\",\n\t\t\t\tformatErrorMessage(\"MIN_VALUE\", fieldName, { min: field.min }),\n\t\t\t\t{ value, expected: field.min },\n\t\t\t),\n\t\t);\n\t}\n\n\t// Max value\n\tif (field.max !== undefined && value > field.max) {\n\t\terrors.push(\n\t\t\tcreateValidationError(\n\t\t\t\tfieldName,\n\t\t\t\t\"MAX_VALUE\",\n\t\t\t\tformatErrorMessage(\"MAX_VALUE\", fieldName, { max: field.max }),\n\t\t\t\t{ value, expected: field.max },\n\t\t\t),\n\t\t);\n\t}\n\n\t// Custom validator\n\tif (field.validator) {\n\t\tconst result = field.validator(value);\n\t\tif (result !== true) {\n\t\t\terrors.push(\n\t\t\t\tcreateValidationError(fieldName, \"CUSTOM\", result, { value }),\n\t\t\t);\n\t\t}\n\t}\n\n\tif (errors.length > 0) {\n\t\treturn { success: false, error: errors };\n\t}\n\n\treturn { success: true, data: value };\n}\n\n/**\n * Validate boolean field\n */\nfunction validateBoolean(\n\tvalue: unknown,\n\tfieldName: string,\n): FieldValidationResult<boolean> {\n\tif (!isBoolean(value)) {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: [\n\t\t\t\tcreateValidationError(\n\t\t\t\t\tfieldName,\n\t\t\t\t\t\"TYPE_MISMATCH\",\n\t\t\t\t\tformatErrorMessage(\"TYPE_MISMATCH\", fieldName, {\n\t\t\t\t\t\texpected: \"boolean\",\n\t\t\t\t\t\tactual: typeof value,\n\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\t],\n\t\t};\n\t}\n\n\treturn { success: true, data: value };\n}\n\n/**\n * Validate date field\n */\nfunction validateDate(\n\tvalue: unknown,\n\tfield: DateField,\n\tfieldName: string,\n): FieldValidationResult<Date> {\n\t// First check if it's a Date object at all (not string, not number)\n\tif (!(value instanceof Date)) {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: [\n\t\t\t\tcreateValidationError(\n\t\t\t\t\tfieldName,\n\t\t\t\t\t\"TYPE_MISMATCH\",\n\t\t\t\t\tformatErrorMessage(\"TYPE_MISMATCH\", fieldName, {\n\t\t\t\t\t\texpected: \"Date\",\n\t\t\t\t\t\tactual: typeof value,\n\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\t],\n\t\t};\n\t}\n\n\t// Then check if it's a valid Date (not NaN)\n\tif (!isDate(value)) {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: [\n\t\t\t\tcreateValidationError(\n\t\t\t\t\tfieldName,\n\t\t\t\t\t\"INVALID_DATE\",\n\t\t\t\t\tformatErrorMessage(\"INVALID_DATE\", fieldName),\n\t\t\t\t),\n\t\t\t],\n\t\t};\n\t}\n\n\tconst errors = [];\n\n\t// Min date\n\tif (field.min && value < field.min) {\n\t\terrors.push(\n\t\t\tcreateValidationError(\n\t\t\t\tfieldName,\n\t\t\t\t\"MIN_VALUE\",\n\t\t\t\t`Field '${fieldName}' must be after ${field.min.toISOString()}`,\n\t\t\t\t{ value, expected: field.min },\n\t\t\t),\n\t\t);\n\t}\n\n\t// Max date\n\tif (field.max && value > field.max) {\n\t\terrors.push(\n\t\t\tcreateValidationError(\n\t\t\t\tfieldName,\n\t\t\t\t\"MAX_VALUE\",\n\t\t\t\t`Field '${fieldName}' must be before ${field.max.toISOString()}`,\n\t\t\t\t{ value, expected: field.max },\n\t\t\t),\n\t\t);\n\t}\n\n\tif (errors.length > 0) {\n\t\treturn { success: false, error: errors };\n\t}\n\n\treturn { success: true, data: value };\n}\n\n/**\n * Validate enum field\n */\nfunction validateEnum(\n\tvalue: unknown,\n\tfield: EnumField,\n\tfieldName: string,\n): FieldValidationResult<string> {\n\tif (!isString(value)) {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: [\n\t\t\t\tcreateValidationError(\n\t\t\t\t\tfieldName,\n\t\t\t\t\t\"TYPE_MISMATCH\",\n\t\t\t\t\tformatErrorMessage(\"TYPE_MISMATCH\", fieldName, {\n\t\t\t\t\t\texpected: \"string\",\n\t\t\t\t\t\tactual: typeof value,\n\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\t],\n\t\t};\n\t}\n\n\tif (!field.values.includes(value)) {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: [\n\t\t\t\tcreateValidationError(\n\t\t\t\t\tfieldName,\n\t\t\t\t\t\"INVALID_ENUM\",\n\t\t\t\t\tformatErrorMessage(\"INVALID_ENUM\", fieldName, {\n\t\t\t\t\t\texpected: field.values.join(\", \"),\n\t\t\t\t\t}),\n\t\t\t\t\t{ value, expected: field.values },\n\t\t\t\t),\n\t\t\t],\n\t\t};\n\t}\n\n\treturn { success: true, data: value };\n}\n\n/**\n * Validate array field\n */\nfunction validateArray(\n\tvalue: unknown,\n\tfield: ArrayField,\n\tfieldName: string,\n\tdepth: number,\n): FieldValidationResult<readonly unknown[]> {\n\tif (!isArray(value)) {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: [\n\t\t\t\tcreateValidationError(\n\t\t\t\t\tfieldName,\n\t\t\t\t\t\"TYPE_MISMATCH\",\n\t\t\t\t\tformatErrorMessage(\"TYPE_MISMATCH\", fieldName, {\n\t\t\t\t\t\texpected: \"array\",\n\t\t\t\t\t\tactual: typeof value,\n\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\t],\n\t\t};\n\t}\n\n\tconst errors = [];\n\n\t// Min items\n\tif (field.minItems !== undefined && value.length < field.minItems) {\n\t\terrors.push(\n\t\t\tcreateValidationError(\n\t\t\t\tfieldName,\n\t\t\t\t\"MIN_ITEMS\",\n\t\t\t\tformatErrorMessage(\"MIN_ITEMS\", fieldName, { min: field.minItems }),\n\t\t\t\t{ value: value.length, expected: field.minItems },\n\t\t\t),\n\t\t);\n\t}\n\n\t// Max items\n\tif (field.maxItems !== undefined && value.length > field.maxItems) {\n\t\terrors.push(\n\t\t\tcreateValidationError(\n\t\t\t\tfieldName,\n\t\t\t\t\"MAX_ITEMS\",\n\t\t\t\tformatErrorMessage(\"MAX_ITEMS\", fieldName, { max: field.maxItems }),\n\t\t\t\t{ value: value.length, expected: field.maxItems },\n\t\t\t),\n\t\t);\n\t}\n\n\t// Unique items check\n\tif (field.unique) {\n\t\tconst seen = new Set<unknown>();\n\t\tconst duplicates = new Set<unknown>();\n\n\t\tfor (const item of value) {\n\t\t\t// Use JSON.stringify for deep comparison of objects/arrays\n\t\t\tconst itemKey =\n\t\t\t\ttypeof item === \"object\" && item !== null ? JSON.stringify(item) : item;\n\n\t\t\tif (seen.has(itemKey)) {\n\t\t\t\tduplicates.add(item);\n\t\t\t} else {\n\t\t\t\tseen.add(itemKey);\n\t\t\t}\n\t\t}\n\n\t\tif (duplicates.size > 0) {\n\t\t\terrors.push(\n\t\t\t\tcreateValidationError(\n\t\t\t\t\tfieldName,\n\t\t\t\t\t\"UNIQUE\",\n\t\t\t\t\tformatErrorMessage(\"UNIQUE\", fieldName),\n\t\t\t\t\t{ value: Array.from(duplicates) },\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t}\n\n\t// Validate each item\n\tfor (let i = 0; i < value.length; i++) {\n\t\tconst item = value[i];\n\t\tconst itemResult = validateField(\n\t\t\titem,\n\t\t\tfield.items,\n\t\t\t`${fieldName}[${i}]`,\n\t\t\tdepth + 1,\n\t\t);\n\t\tif (!itemResult.success) {\n\t\t\terrors.push(...itemResult.error);\n\t\t}\n\t}\n\n\tif (errors.length > 0) {\n\t\treturn { success: false, error: errors };\n\t}\n\n\treturn { success: true, data: value };\n}\n\n/**\n * Validate JSON field\n * JSON fields can be objects, arrays, or any valid JSON type\n */\nfunction validateJSON(\n\tvalue: unknown,\n\tfieldName: string,\n): FieldValidationResult<unknown> {\n\t// JSON field accepts: objects, arrays, strings, numbers, booleans, null\n\t// Reject: undefined, Date objects (should be serialized to string first)\n\tif (value === undefined || isDate(value)) {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: [\n\t\t\t\tcreateValidationError(\n\t\t\t\t\tfieldName,\n\t\t\t\t\t\"TYPE_MISMATCH\",\n\t\t\t\t\tformatErrorMessage(\"TYPE_MISMATCH\", fieldName, {\n\t\t\t\t\t\texpected:\n\t\t\t\t\t\t\t\"valid JSON type (object, array, string, number, boolean, null)\",\n\t\t\t\t\t\tactual: value === undefined ? \"undefined\" : \"Date\",\n\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\t],\n\t\t};\n\t}\n\n\treturn { success: true, data: value };\n}\n\n/**\n * Validate relation field\n * Supports both shortcut (ID) and RelationInput object\n */\nfunction validateRelation(\n\tvalue: unknown,\n\tfieldName: string,\n): FieldValidationResult<unknown> {\n\t// 1. Shortcut: ID (string or number)\n\tif (typeof value === \"string\" || typeof value === \"number\") {\n\t\treturn { success: true, data: value };\n\t}\n\n\t// 2. RelationInput object: { connect, disconnect, set, create, update, delete }\n\tif (typeof value === \"object\" && value !== null && !Array.isArray(value)) {\n\t\tconst input = value as Record<string, unknown>;\n\t\tconst validKeys = [\n\t\t\t\"connect\",\n\t\t\t\"disconnect\",\n\t\t\t\"set\",\n\t\t\t\"create\",\n\t\t\t\"update\",\n\t\t\t\"delete\",\n\t\t];\n\n\t\t// Check if at least one valid key exists\n\t\tconst hasValidKey = validKeys.some((key) => key in input);\n\t\tif (!hasValidKey) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: [\n\t\t\t\t\tcreateValidationError(\n\t\t\t\t\t\tfieldName,\n\t\t\t\t\t\t\"INVALID_FORMAT\",\n\t\t\t\t\t\t`Relation field '${fieldName}' must be an ID or a valid RelationInput object`,\n\t\t\t\t\t\t{ value },\n\t\t\t\t\t),\n\t\t\t\t],\n\t\t\t};\n\t\t}\n\n\t\t// Structural validation for common keys (shallow)\n\t\tif (input[\"connect\"]) {\n\t\t\tconst connect = input[\"connect\"];\n\t\t\tif (Array.isArray(connect)) {\n\t\t\t\tif (!connect.every((item) => typeof item === \"number\")) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tsuccess: false,\n\t\t\t\t\t\terror: [\n\t\t\t\t\t\t\tcreateValidationError(\n\t\t\t\t\t\t\t\tfieldName,\n\t\t\t\t\t\t\t\t\"INVALID_FORMAT\",\n\t\t\t\t\t\t\t\t\"connect must be a number or array of numbers\",\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t],\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t} else if (typeof connect !== \"number\") {\n\t\t\t\treturn {\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\terror: [\n\t\t\t\t\t\tcreateValidationError(\n\t\t\t\t\t\t\tfieldName,\n\t\t\t\t\t\t\t\"INVALID_FORMAT\",\n\t\t\t\t\t\t\t\"connect must be a number or array of numbers\",\n\t\t\t\t\t\t),\n\t\t\t\t\t],\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\t// If 'set' is provided, it must be an array of numbers\n\t\tif (input[\"set\"]) {\n\t\t\tif (\n\t\t\t\t!Array.isArray(input[\"set\"]) ||\n\t\t\t\t!(input[\"set\"] as unknown[]).every((item) => typeof item === \"number\")\n\t\t\t) {\n\t\t\t\treturn {\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\terror: [\n\t\t\t\t\t\tcreateValidationError(\n\t\t\t\t\t\t\tfieldName,\n\t\t\t\t\t\t\t\"INVALID_FORMAT\",\n\t\t\t\t\t\t\t\"set must be an array of numbers\",\n\t\t\t\t\t\t),\n\t\t\t\t\t],\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\treturn { success: true, data: value };\n\t}\n\n\treturn {\n\t\tsuccess: false,\n\t\terror: [\n\t\t\tcreateValidationError(\n\t\t\t\tfieldName,\n\t\t\t\t\"TYPE_MISMATCH\",\n\t\t\t\tformatErrorMessage(\"TYPE_MISMATCH\", fieldName, {\n\t\t\t\t\texpected: \"ID or RelationInput object\",\n\t\t\t\t\tactual: typeof value,\n\t\t\t\t}),\n\t\t\t),\n\t\t],\n\t};\n}\n","/**\n * Schema Validator Implementation\n *\n * Validates entire objects against schema definitions.\n * Orchestrates field-level validation for all fields.\n *\n * Architecture:\n * - validateSchema: Full validation - iterates ALL schema fields, checks required\n * - validatePartial: Partial validation - iterates ONLY data keys, still checks required\n * - Both use validateSingleField for actual field validation (no code duplication)\n */\n\nimport type {\n\tSchemaDefinition,\n\tFieldDefinition,\n\tDatrixEntry,\n\tRelationField,\n} from \"../types/core/schema\";\nimport type { ValidatorOptions } from \"../types/core/validator\";\nimport { validateField } from \"./field-validator\";\nimport {\n\tcreateValidationError,\n\tthrowValidationMultiple,\n\tValidationErrorCollection,\n} from \"./errors\";\n\n/**\n * Default validator options\n */\nconst DEFAULT_OPTIONS: Required<ValidatorOptions> = {\n\tstrict: true,\n\tcoerce: false,\n\tstripUnknown: false,\n\tabortEarly: false,\n};\n\n/**\n * Reserved field names that are auto-managed\n */\nconst RESERVED_FIELDS = [\"id\", \"createdAt\", \"updatedAt\"];\n\n/**\n * Check if a field is a relation with foreign key\n */\nfunction isRelationWithForeignKey(\n\tfieldDef: FieldDefinition,\n): fieldDef is RelationField {\n\treturn (\n\t\tfieldDef.type === \"relation\" &&\n\t\t(fieldDef.kind === \"belongsTo\" || fieldDef.kind === \"hasOne\")\n\t);\n}\n\n/**\n * Get value from input data, handling relation foreign key fallback\n */\nfunction getFieldValue(\n\tinputData: Record<string, unknown>,\n\tfieldName: string,\n\tfieldDef: FieldDefinition,\n): unknown {\n\tlet value = inputData[fieldName];\n\n\t// Fallback to foreign key for belongsTo/hasOne relations\n\tif (!value && isRelationWithForeignKey(fieldDef) && fieldDef.foreignKey) {\n\t\tvalue = inputData[fieldDef.foreignKey];\n\t}\n\n\treturn value;\n}\n\n/**\n * Validate a single field and collect errors\n *\n * This is the shared validation logic used by both validateSchema and validatePartial.\n * Uses the ORIGINAL field definition (required is NOT modified).\n */\nfunction validateSingleField(\n\tvalue: unknown,\n\tfieldDef: FieldDefinition,\n\tfieldName: string,\n\terrors: ValidationErrorCollection,\n\topts: Required<ValidatorOptions>,\n\tschemaName: string,\n): { errors: ValidationErrorCollection; validatedValue?: unknown } {\n\tconst result = validateField(value, fieldDef, fieldName);\n\n\tif (!result.success) {\n\t\terrors = errors.addMany(result.error);\n\n\t\tif (opts.abortEarly) {\n\t\t\tthrowValidationMultiple(schemaName, errors.getAll());\n\t\t}\n\n\t\treturn { errors };\n\t}\n\n\treturn { errors, validatedValue: result.data };\n}\n\n/**\n * Handle unknown fields based on options\n */\nfunction handleUnknownFields(\n\tinputData: Record<string, unknown>,\n\tschemaFields: Record<string, FieldDefinition>,\n\tvalidatedData: Record<string, unknown>,\n\terrors: ValidationErrorCollection,\n\topts: Required<ValidatorOptions>,\n\tschemaName: string,\n): ValidationErrorCollection {\n\tif (opts.strict) {\n\t\tfor (const key of Object.keys(inputData)) {\n\t\t\tif (!(key in schemaFields)) {\n\t\t\t\terrors = errors.add(\n\t\t\t\t\tcreateValidationError(\n\t\t\t\t\t\tkey,\n\t\t\t\t\t\t\"UNKNOWN\",\n\t\t\t\t\t\t`Unknown field '${key}' in schema '${schemaName}'`,\n\t\t\t\t\t),\n\t\t\t\t);\n\n\t\t\t\tif (opts.abortEarly) {\n\t\t\t\t\tthrowValidationMultiple(schemaName, errors.getAll());\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} else if (!opts.stripUnknown) {\n\t\t// Include unknown fields in validated data\n\t\tfor (const [key, value] of Object.entries(inputData)) {\n\t\t\tif (!(key in schemaFields)) {\n\t\t\t\tvalidatedData[key] = value;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn errors;\n}\n\n/**\n * Validate input is a valid object\n */\nfunction assertValidObject(\n\tdata: unknown,\n\tschemaName: string,\n): asserts data is Record<string, unknown> {\n\tif (typeof data !== \"object\" || data === null || Array.isArray(data)) {\n\t\tthrowValidationMultiple(schemaName, [\n\t\t\tcreateValidationError(\n\t\t\t\tschemaName,\n\t\t\t\t\"TYPE_MISMATCH\",\n\t\t\t\t`Expected object, got ${Array.isArray(data) ? \"array\" : typeof data}`,\n\t\t\t),\n\t\t]);\n\t}\n}\n\n/**\n * Validate data against schema (full validation for CREATE)\n *\n * Iterates ALL schema fields and validates each one.\n * Required fields that are missing will fail validation.\n */\nexport function validateSchema<T extends DatrixEntry>(\n\tdata: unknown,\n\tschema: SchemaDefinition,\n\toptions?: ValidatorOptions,\n): T {\n\tconst opts = { ...DEFAULT_OPTIONS, ...options };\n\tlet errors = new ValidationErrorCollection();\n\n\tassertValidObject(data, schema.name);\n\n\tconst inputData = data as Record<string, unknown>;\n\tconst validatedData: Record<string, unknown> = {};\n\n\t// Validate each field in schema\n\tfor (const [fieldName, fieldDef] of Object.entries(schema.fields)) {\n\t\t// Skip reserved fields - auto-generated by database/adapter\n\t\tif (RESERVED_FIELDS.includes(fieldName)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst value = getFieldValue(inputData, fieldName, fieldDef);\n\n\t\t// Skip hidden fields if not provided - these are typically auto-managed (like FKs)\n\t\t// and will be filled later in the CRUD flow or by the database.\n\t\tif (fieldDef.hidden && value === undefined) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Validate field with original definition (required check included)\n\t\tconst result = validateSingleField(\n\t\t\tvalue,\n\t\t\tfieldDef,\n\t\t\tfieldName,\n\t\t\terrors,\n\t\t\topts,\n\t\t\tschema.name,\n\t\t);\n\n\t\terrors = result.errors;\n\t\tif (result.validatedValue !== undefined) {\n\t\t\tvalidatedData[fieldName] = result.validatedValue;\n\t\t}\n\t}\n\n\t// Handle unknown fields\n\terrors = handleUnknownFields(\n\t\tinputData,\n\t\tschema.fields,\n\t\tvalidatedData,\n\t\terrors,\n\t\topts,\n\t\tschema.name,\n\t);\n\n\tif (errors.hasErrors()) {\n\t\tthrowValidationMultiple(schema.name, errors.getAll());\n\t}\n\n\treturn validatedData as T;\n}\n\n/**\n * Validate partial data (for UPDATE operations)\n *\n * Iterates ONLY the fields present in input data.\n * Each provided field is validated with its ORIGINAL definition (required check included).\n *\n * Key difference from validateSchema:\n * - validateSchema: Missing required field = ERROR (field not in data)\n * - validatePartial: Missing required field = OK (field not in data, not being updated)\n * - validatePartial: Required field set to null = ERROR (explicitly setting to null)\n */\nexport function validatePartial<T extends DatrixEntry>(\n\tdata: unknown,\n\tschema: SchemaDefinition,\n\toptions?: ValidatorOptions,\n): Partial<T> {\n\tconst opts = { ...DEFAULT_OPTIONS, ...options };\n\tlet errors = new ValidationErrorCollection();\n\n\tassertValidObject(data, schema.name);\n\n\tconst inputData = data as Record<string, unknown>;\n\tconst validatedData: Record<string, unknown> = {};\n\n\t// Validate ONLY fields that are present in input\n\tfor (const [fieldName, value] of Object.entries(inputData)) {\n\t\t// Skip reserved fields - cannot be modified\n\t\tif (RESERVED_FIELDS.includes(fieldName)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst fieldDef = schema.fields[fieldName];\n\n\t\t// Check if field exists in schema\n\t\tif (!fieldDef) {\n\t\t\tif (opts.strict) {\n\t\t\t\terrors = errors.add(\n\t\t\t\t\tcreateValidationError(\n\t\t\t\t\t\tfieldName,\n\t\t\t\t\t\t\"UNKNOWN\",\n\t\t\t\t\t\t`Unknown field '${fieldName}' in schema '${schema.name}'`,\n\t\t\t\t\t),\n\t\t\t\t);\n\n\t\t\t\tif (opts.abortEarly) {\n\t\t\t\t\tthrowValidationMultiple(schema.name, errors.getAll());\n\t\t\t\t}\n\t\t\t} else if (!opts.stripUnknown) {\n\t\t\t\tvalidatedData[fieldName] = value;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Validate field with ORIGINAL definition (required check included)\n\t\t// If user explicitly sets a required field to null, it will fail\n\t\tconst result = validateSingleField(\n\t\t\tvalue,\n\t\t\tfieldDef,\n\t\t\tfieldName,\n\t\t\terrors,\n\t\t\topts,\n\t\t\tschema.name,\n\t\t);\n\n\t\terrors = result.errors;\n\t\tif (result.validatedValue !== undefined) {\n\t\t\tvalidatedData[fieldName] = result.validatedValue;\n\t\t}\n\t}\n\n\tif (errors.hasErrors()) {\n\t\tthrowValidationMultiple(schema.name, errors.getAll());\n\t}\n\n\treturn validatedData as Partial<T>;\n}\n\n/**\n * Validate array of data (for bulk CREATE)\n */\nexport function validateMany<T extends DatrixEntry>(\n\tdataArray: unknown,\n\tschema: SchemaDefinition,\n\toptions?: ValidatorOptions,\n): readonly T[] {\n\tconst opts = { ...DEFAULT_OPTIONS, ...options };\n\n\tif (!Array.isArray(dataArray)) {\n\t\tthrowValidationMultiple(schema.name, [\n\t\t\tcreateValidationError(\n\t\t\t\tschema.name,\n\t\t\t\t\"TYPE_MISMATCH\",\n\t\t\t\t`Expected array, got ${typeof dataArray}`,\n\t\t\t),\n\t\t]);\n\t}\n\n\tconst validatedArray: T[] = [];\n\n\tfor (let i = 0; i < dataArray.length; i++) {\n\t\tconst item = dataArray[i];\n\t\tconst result = validateSchema<T>(item, schema, opts);\n\t\tvalidatedArray.push(result);\n\t}\n\n\treturn validatedArray;\n}\n\n/**\n * Check if data matches schema (returns boolean, does not throw)\n */\nexport function isValid(\n\tdata: unknown,\n\tschema: SchemaDefinition,\n\toptions?: ValidatorOptions,\n): boolean {\n\ttry {\n\t\tvalidateSchema(data, schema, options);\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n/**\n * Type guard for schema validation\n */\nexport function assertSchema<T>(\n\tdata: unknown,\n\tschema: SchemaDefinition,\n\toptions?: ValidatorOptions,\n): asserts data is T {\n\tvalidateSchema(data, schema, options);\n}\n","/**\n * Query Executor Error Helpers\n *\n * Centralized error creation for query executor operations.\n */\n\nimport {\n\tCrudErrorCode,\n\tCrudErrorContext,\n\tCrudOperation,\n\tDatrixCrudError,\n\tDatrixError,\n} from \"../types/errors\";\n\n/**\n * Options for throwing CRUD errors\n */\nexport interface ThrowCrudErrorOptions {\n\treadonly operation: CrudOperation;\n\treadonly model: string;\n\treadonly code: CrudErrorCode;\n\treadonly message?: string;\n\treadonly cause?: Error;\n\treadonly context?: CrudErrorContext;\n\treadonly suggestion?: string;\n\treadonly expected?: string;\n\treadonly received?: unknown;\n}\n\n/**\n * Throws a standardized CRUD error\n *\n * @param options - Error options\n * @throws DatrixCrudError\n *\n * @example\n * ```ts\n * throwCrudError({\n * operation: 'findOne',\n * model: 'User',\n * code: 'QUERY_EXECUTION_FAILED',\n * cause: dbError,\n * context: { query }\n * });\n * ```\n */\nexport function throwCrudError(options: ThrowCrudErrorOptions): never {\n\tconst {\n\t\toperation,\n\t\tmodel,\n\t\tcode,\n\t\tmessage,\n\t\tcause,\n\t\tcontext,\n\t\tsuggestion,\n\t\texpected,\n\t\treceived,\n\t} = options;\n\n\tconst defaultMessage = generateDefaultMessage(operation, model, code);\n\n\tthrow new DatrixCrudError(message ?? defaultMessage, {\n\t\tcode,\n\t\toperation,\n\t\tmodel,\n\t\tcontext: enhanceContext(context, cause),\n\t\tcause,\n\t\tsuggestion,\n\t\texpected,\n\t\treceived,\n\t});\n}\n\n/**\n * Enhance context with adapter error details if available\n */\nfunction enhanceContext(\n\tcontext: CrudErrorContext | undefined,\n\tcause: Error | undefined,\n): CrudErrorContext | undefined {\n\tif (!cause) {\n\t\treturn context;\n\t}\n\n\treturn {\n\t\t...context,\n\t\tadapterError: cause.message,\n\t};\n}\n\n/**\n * Generate a default error message based on operation and code\n */\nfunction generateDefaultMessage(\n\toperation: CrudOperation,\n\tmodel: string,\n\tcode: CrudErrorCode,\n): string {\n\tswitch (code) {\n\t\tcase \"QUERY_EXECUTION_FAILED\":\n\t\t\treturn `Failed to execute ${operation} query for ${model}`;\n\t\tcase \"SCHEMA_NOT_FOUND\":\n\t\t\treturn `Schema '${model}' not found`;\n\t\tcase \"RECORD_NOT_FOUND\":\n\t\t\treturn `${model} record not found`;\n\t\tcase \"INVALID_POPULATE_VALUE\":\n\t\t\treturn `Invalid populate value for ${model}`;\n\t\tcase \"RESERVED_FIELD_WRITE\":\n\t\t\treturn `Cannot write to reserved field in ${model}`;\n\t\tcase \"NOT_IMPLEMENTED\":\n\t\t\treturn `${operation} not implemented for ${model}`;\n\t\tcase \"QUERY_FAILED\":\n\t\t\treturn `Query failed for ${model}`;\n\t\tdefault:\n\t\t\treturn `CRUD operation failed for ${model}`;\n\t}\n}\n\n/**\n * Throw unsupported query type error\n *\n * @param queryType - The unsupported query type\n *\n * @example\n * ```ts\n * throwUnsupportedQueryType('invalid');\n * // Error: Unsupported query type: invalid\n * ```\n */\nexport function throwUnsupportedQueryType(queryType: unknown): never {\n\tthrow new DatrixError(`Unsupported query type: ${queryType}`, {\n\t\tcode: \"UNSUPPORTED_QUERY_TYPE\",\n\t\tcontext: { queryType },\n\t\tsuggestion: \"Use one of: select, insert, update, delete, count\",\n\t\texpected: \"select | insert | update | delete | count\",\n\t\treceived: queryType,\n\t});\n}\n\n/**\n * Helper for schema not found errors\n */\nexport function throwSchemaNotFoundError(model: string): never {\n\tthrowCrudError({\n\t\toperation: \"findOne\",\n\t\tmodel,\n\t\tcode: \"SCHEMA_NOT_FOUND\",\n\t\tsuggestion: `Make sure the schema '${model}' is registered in your Datrix instance`,\n\t});\n}\n\n/**\n * Helper for reserved field write errors\n */\nexport function throwReservedFieldError(field: string, model: string): never {\n\tthrowCrudError({\n\t\toperation: \"create\",\n\t\tmodel,\n\t\tcode: \"RESERVED_FIELD_WRITE\",\n\t\tmessage: `Cannot set reserved field '${field}'`,\n\t\tsuggestion: `Use datrix.raw.create() or datrix.raw.update() for manual control of '${field}'`,\n\t});\n}\n\n/**\n * Helper for record not found errors (single id operations)\n *\n * @param operation - The CRUD operation (update or delete)\n * @param model - Model name\n * @param id - The record ID that was not found\n *\n * @example\n * ```ts\n * throwRecordNotFound('update', 'User', 123);\n * // Error: User record with id 123 not found\n * ```\n */\nexport function throwRecordNotFound(\n\toperation: \"update\" | \"delete\",\n\tmodel: string,\n\tid: number,\n): never {\n\tthrowCrudError({\n\t\toperation,\n\t\tmodel,\n\t\tcode: \"RECORD_NOT_FOUND\",\n\t\tmessage: `${model} record with id ${id} not found`,\n\t\tcontext: { recordId: id },\n\t\tsuggestion: `Verify that the ${model} with id ${id} exists before attempting to ${operation}`,\n\t});\n}\n\n/**\n * Helper for relation target not found errors\n *\n * Thrown when connect/set references IDs that don't exist in the target table.\n *\n * @param parentModel - Parent model name (e.g., \"Post\")\n * @param relationField - Relation field name (e.g., \"tags\")\n * @param targetModel - Target model name (e.g., \"Tag\")\n * @param missingIds - Array of IDs that were not found\n *\n * @example\n * ```ts\n * throwRelationTargetNotFound('Post', 'tags', 'Tag', [999, 1000]);\n * // Error: Cannot connect Post.tags: Tag records with ids [999, 1000] not found\n * ```\n */\nexport function throwRelationTargetNotFound(\n\tparentModel: string,\n\trelationField: string,\n\ttargetModel: string,\n\tmissingIds: readonly number[],\n): never {\n\tconst idsStr =\n\t\tmissingIds.length === 1\n\t\t\t? `id ${missingIds[0]}`\n\t\t\t: `ids [${missingIds.join(\", \")}]`;\n\n\tthrowCrudError({\n\t\toperation: \"update\",\n\t\tmodel: parentModel,\n\t\tcode: \"RECORD_NOT_FOUND\",\n\t\tmessage: `Cannot connect ${parentModel}.${relationField}: ${targetModel} records with ${idsStr} not found`,\n\t\tcontext: {\n\t\t\trelationField,\n\t\t\ttargetModel,\n\t\t\tmissingIds: [...missingIds],\n\t\t},\n\t\tsuggestion: `Verify that all ${targetModel} IDs exist before connecting them to ${parentModel}.${relationField}`,\n\t});\n}\n","/**\n * Data Validation and Timestamp Management\n *\n * Handles:\n * 1. Reserved field checks\n * 2. Timestamp injection (before validation)\n * 3. Schema validation (min/max/regex/type/required)\n */\n\nimport {\n\tDatrixEntry,\n\tSchemaDefinition,\n\tRESERVED_FIELDS,\n} from \"../types/core/schema\";\nimport { validatePartial, validateSchema } from \"../validator\";\nimport { throwReservedFieldError } from \"./error-helper\";\nimport { QueryRelations } from \"../types/core/query-builder\";\n\n/**\n * Validation options\n */\nexport interface ValidationOptions {\n\t/** If true, use partial validation (for updates) */\n\tpartial: boolean;\n\t/** If true, this is a create operation (affects timestamp handling) */\n\tisCreate: boolean;\n\t/** If true, allow user to override timestamps (raw mode) */\n\tisRawMode: boolean;\n}\n\n/**\n * Check for reserved fields in user data\n *\n * Reserved fields (id, createdAt, updatedAt) are automatically managed\n * and cannot be set manually in normal mode.\n *\n * @param data - Data to check\n * @param isRawMode - If true, skip the check\n * @throws {DatrixError} If reserved field is found in normal mode\n *\n * @example\n * ```ts\n * // Normal mode\n * checkReservedFields({ id: 1, name: 'John' }, false);\n * // Throws: Cannot manually set reserved field 'id'\n *\n * // Raw mode\n * checkReservedFields({ id: 1, name: 'John' }, true);\n * // OK (raw mode allows override)\n * ```\n */\nfunction checkReservedFields<T extends DatrixEntry>(\n\tdata: Partial<T> | undefined,\n\tisRawMode: boolean,\n): void {\n\tif (isRawMode || !data) {\n\t\treturn;\n\t}\n\n\tfor (const field of RESERVED_FIELDS) {\n\t\tif (field in data) {\n\t\t\tthrowReservedFieldError(field, \"unknown\");\n\t\t}\n\t}\n}\n\n/**\n * Add timestamps to data before validation\n *\n * **Timestamp Rules:**\n *\n * **CREATE:**\n * - Normal mode: Always add createdAt + updatedAt (override user values)\n * - Raw mode: Add only if not provided (user can override)\n *\n * **UPDATE:**\n * - Normal mode: Always add updatedAt (override user value)\n * - Raw mode: Add only if not provided (user can override)\n *\n * @param data - Input data\n * @param options - Validation options\n * @returns Data with timestamps\n *\n * @example\n * ```ts\n * // CREATE (normal mode)\n * addTimestamps({ name: 'John' }, { isCreate: true, isRawMode: false });\n * // { name: 'John', createdAt: Date, updatedAt: Date }\n *\n * // CREATE (raw mode, user override)\n * addTimestamps(\n * { name: 'John', createdAt: new Date('2020-01-01') },\n * { isCreate: true, isRawMode: true }\n * );\n * // { name: 'John', createdAt: Date('2020-01-01'), updatedAt: Date('2020-01-01') }\n *\n * // UPDATE (normal mode)\n * addTimestamps({ name: 'Jane' }, { isCreate: false, isRawMode: false });\n * // { name: 'Jane', updatedAt: Date }\n * ```\n */\nfunction addTimestamps<T extends DatrixEntry>(\n\tdata: Partial<T> | undefined,\n\toptions: Pick<ValidationOptions, \"isCreate\" | \"isRawMode\">,\n): Partial<T> {\n\tconst { isCreate, isRawMode } = options;\n\tconst now = new Date();\n\tconst result: Partial<T> = !!data ? { ...data } : ({} as Partial<T>);\n\n\tif (isCreate) {\n\t\tif (isRawMode) {\n\t\t\t// Raw mode: Smart defaults (only if not provided)\n\t\t\tif (!result.createdAt) {\n\t\t\t\tresult.createdAt = now;\n\t\t\t}\n\t\t\tif (!result.updatedAt) {\n\t\t\t\tresult.updatedAt = result.createdAt;\n\t\t\t}\n\t\t} else {\n\t\t\t// Normal mode: Always add timestamps (override)\n\t\t\tresult.createdAt = now;\n\t\t\tresult.updatedAt = now;\n\t\t}\n\t} else {\n\t\t// Update operation\n\t\tif (isRawMode) {\n\t\t\t// Raw mode: Add updatedAt only if not provided\n\t\t\tif (!result.updatedAt) {\n\t\t\t\tresult.updatedAt = now;\n\t\t\t}\n\t\t} else {\n\t\t\t// Normal mode: Always update timestamp (override)\n\t\t\tresult.updatedAt = now;\n\t\t}\n\t}\n\n\treturn result;\n}\n\n/**\n * Validate data against schema with timestamp handling\n *\n * **Flow:**\n * 1. Check reserved fields (only in normal mode)\n * 2. Add timestamps BEFORE validation (so required fields pass)\n * 3. Schema validation (min/max/regex/type/required)\n *\n * @param data - Data to validate\n * @param schema - Schema definition\n * @param options - Validation options\n * @returns Validated data with timestamps\n * @throws {DatrixError} If validation fails or reserved field found\n *\n * @example\n * ```ts\n * // CREATE (normal mode)\n * validateData(\n * { name: 'John', age: 25 },\n * userSchema,\n * { partial: false, isCreate: true, isRawMode: false }\n * );\n * // { name: 'John', age: 25, createdAt: Date, updatedAt: Date }\n *\n * // UPDATE (partial)\n * validateData(\n * { age: 26 },\n * userSchema,\n * { partial: true, isCreate: false, isRawMode: false }\n * );\n * // { age: 26, updatedAt: Date }\n * ```\n */\nexport function validateData<\n\tT extends DatrixEntry = DatrixEntry,\n\tP extends boolean = false,\n>(\n\tdata: Partial<T> | undefined,\n\trelations: QueryRelations<T> | undefined,\n\tschema: SchemaDefinition,\n\toptions: ValidationOptions,\n): P extends true ? Partial<T> : T {\n\tconst { partial, isCreate, isRawMode } = options;\n\n\t// 1. Check for reserved fields (only in normal mode)\n\tcheckReservedFields(data, isRawMode);\n\n\t// 2. Add timestamps BEFORE validation (so required fields like createdAt pass)\n\tconst dataWithTimestamps = schema._isJunctionTable\n\t\t? data\n\t\t: addTimestamps(data, { isCreate, isRawMode });\n\n\t// 3. Schema validation (with timestamps already present)\n\tconst validationOptions = {\n\t\tstrict: true,\n\t\tstripUnknown: false,\n\t\tabortEarly: false,\n\t};\n\n\tconst combined = { ...(dataWithTimestamps ?? {}), ...(relations ?? {}) };\n\n\tif (partial) {\n\t\tvalidatePartial(combined, schema, validationOptions);\n\t} else {\n\t\tvalidateSchema(combined, schema, validationOptions);\n\t}\n\n\treturn dataWithTimestamps as P extends true ? Partial<T> : T;\n}\n","/**\n * Relation Processing for Query Executor\n *\n * Strategy: \"Resolve-then-link\"\n * 1. Execute create/update/delete first (recursive, via executor)\n * 2. Merge created IDs into connect/set arrays\n * 3. Process only ID-based operations (connect/disconnect/set)\n *\n * This prevents duplicate creation when updateMany targets multiple records.\n * create/update run ONCE, then each parent only does ID-based linking.\n */\n\nimport {\n\tQueryRelations,\n\tNormalizedRelationOperations,\n\tWhereClause,\n} from \"../types/core/query-builder\";\nimport { validateData } from \"./validation\";\nimport { DatrixEntry, DatrixRecord } from \"../types/core/entry\";\nimport { SchemaDefinition } from \"../types\";\nimport { QueryRunner } from \"../types/adapter\";\nimport { ISchemaRegistry } from \"../types/core/schema\";\n\n/**\n * Resolved relation operations (mutable, after CUD resolution)\n *\n * After resolveCUD runs, create/update/delete are consumed and\n * their resulting IDs are merged into connect/set.\n * Only ID-based operations remain for per-parent linking.\n */\ninterface ResolvedRelationOps {\n\tconnect: number[];\n\tdisconnect: number[];\n\tset: number[] | undefined;\n\tdeleteIds: number[];\n}\n\n/**\n * Process all relation operations for a single parent record\n *\n * Called per-parent from executor. By this point, CUD operations\n * should already be resolved via resolveRelationCUD.\n *\n * @param resolvedRelations - Pre-resolved relation ops (ID-based only)\n * @param parentId - Parent record ID\n * @param parentModel - Parent model name\n * @param schema - Parent schema definition\n * @param executor - Query executor\n * @param schemaRegistry - Schema registry\n */\nexport async function processRelations<T extends DatrixEntry>(\n\tresolvedRelations: Record<string, ResolvedRelationOps>,\n\tparentId: number,\n\tparentModel: string,\n\tschema: SchemaDefinition,\n\trunner: QueryRunner,\n\tschemaRegistry: ISchemaRegistry,\n): Promise<void> {\n\tfor (const [fieldName, ops] of Object.entries(resolvedRelations)) {\n\t\tawait processRelation<T>({\n\t\t\tparentId,\n\t\t\tparentModel,\n\t\t\tfieldName,\n\t\t\tops,\n\t\t\tschema,\n\t\t\trunner,\n\t\t\tschemaRegistry,\n\t\t});\n\t}\n}\n\n/**\n * Resolve CUD operations from relation data\n *\n * Executes create/update/delete ONCE, then merges resulting IDs\n * into connect arrays. Returns resolved ops ready for per-parent linking.\n *\n * This is called ONCE before the per-parent loop in executor,\n * preventing duplicate creation when updateMany targets N records.\n *\n * @param relations - Raw relation operations from QueryObject\n * @param schema - Parent schema definition\n * @param executor - Query executor\n * @param schemaRegistry - Schema registry\n * @returns Resolved relation ops per field (ID-based only)\n *\n * @example\n * ```ts\n * // Input: { tags: { create: [{ data: { name: 'New' } }], connect: [1] } }\n * // Output: { tags: { connect: [1, 42], disconnect: [], set: undefined, deleteIds: [] } }\n * // ↑ 42 = newly created tag ID\n * ```\n */\nexport async function resolveRelationCUD<T extends DatrixEntry>(\n\trelations: QueryRelations<T>,\n\tschema: SchemaDefinition,\n\trunner: QueryRunner,\n\tschemaRegistry: ISchemaRegistry,\n): Promise<Record<string, ResolvedRelationOps>> {\n\tconst resolved: Record<string, ResolvedRelationOps> = {};\n\n\tfor (const [fieldName, relationData] of Object.entries(relations)) {\n\t\tconst relData = relationData as NormalizedRelationOperations<DatrixEntry>;\n\t\tconst field = schema.fields[fieldName];\n\t\tif (!field || field.type !== \"relation\") {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst relatedModel = field.model;\n\t\tconst relSchema = schemaRegistry.get(relatedModel)!;\n\n\t\t// Start with existing ID-based ops (copy from readonly)\n\t\tconst ops: ResolvedRelationOps = {\n\t\t\tconnect: relData.connect ? [...relData.connect] : [],\n\t\t\tdisconnect: relData.disconnect ? [...relData.disconnect] : [],\n\t\t\tset: relData.set ? [...relData.set] : undefined,\n\t\t\tdeleteIds: relData.delete ? [...relData.delete] : [],\n\t\t};\n\n\t\t// --- Execute CREATE (once) and merge IDs ---\n\t\tif (relData.create) {\n\t\t\t// TODO: hasMany + updateMany guard\n\t\t\t// When parent query is updateMany (multiple parents), hasMany create\n\t\t\t// is semantically ambiguous: a child can only belong to one parent.\n\t\t\t// Guard implementation (commented out - enable when needed):\n\t\t\t//\n\t\t\t// if (field.kind === 'hasMany' && parentCount > 1) {\n\t\t\t// const count = await executor.executeCount(countQuery, parentSchema, { noDispatcher: true });\n\t\t\t// if (count > 1) {\n\t\t\t// throw new Error(\n\t\t\t// `Cannot use create in hasMany relation \"${fieldName}\" when updating multiple records. ` +\n\t\t\t// `A hasMany child can only belong to one parent. Use connect instead, ` +\n\t\t\t// `or narrow your where clause to target a single record.`\n\t\t\t// );\n\t\t\t// }\n\t\t\t// }\n\n\t\t\t// Separate items with nested relations from plain ones\n\t\t\tconst plainItems = relData.create.filter((item) => !item.relations);\n\t\t\tconst nestedItems = relData.create.filter((item) => item.relations);\n\n\t\t\t// Bulk insert plain items (no nested relations)\n\t\t\tif (plainItems.length > 0) {\n\t\t\t\tconst validatedBulkData = plainItems.map((item) =>\n\t\t\t\t\tvalidateData<DatrixEntry, false>(\n\t\t\t\t\t\titem.data,\n\t\t\t\t\t\titem.relations,\n\t\t\t\t\t\trelSchema,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tpartial: false,\n\t\t\t\t\t\t\tisCreate: true,\n\t\t\t\t\t\t\tisRawMode: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t\tconst bulkResult = await runner.executeQuery<DatrixEntry>({\n\t\t\t\t\ttype: \"insert\",\n\t\t\t\t\ttable: relSchema.tableName!,\n\t\t\t\t\tdata: validatedBulkData,\n\t\t\t\t});\n\n\t\t\t\tfor (const created of bulkResult.rows) {\n\t\t\t\t\tif (ops.set !== undefined) {\n\t\t\t\t\t\tops.set.push(created.id);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tops.connect.push(created.id);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Items with nested relations must be inserted individually\n\t\t\tfor (const createItem of nestedItems) {\n\t\t\t\tconst validatedData = validateData<DatrixEntry, false>(\n\t\t\t\t\tcreateItem.data,\n\t\t\t\t\tcreateItem.relations,\n\t\t\t\t\trelSchema,\n\t\t\t\t\t{\n\t\t\t\t\t\tpartial: false,\n\t\t\t\t\t\tisCreate: true,\n\t\t\t\t\t\tisRawMode: true,\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t\tconst createResult = await runner.executeQuery<DatrixEntry>({\n\t\t\t\t\ttype: \"insert\",\n\t\t\t\t\ttable: relSchema.tableName!,\n\t\t\t\t\tdata: [validatedData],\n\t\t\t\t});\n\t\t\t\tconst createdId = createResult.rows[0]!.id;\n\n\t\t\t\t// Recursively resolve nested relations\n\t\t\t\tif (createItem.relations) {\n\t\t\t\t\tconst nestedResolved = await resolveRelationCUD(\n\t\t\t\t\t\tcreateItem.relations,\n\t\t\t\t\t\trelSchema,\n\t\t\t\t\t\trunner,\n\t\t\t\t\t\tschemaRegistry,\n\t\t\t\t\t);\n\t\t\t\t\tawait processRelations(\n\t\t\t\t\t\tnestedResolved,\n\t\t\t\t\t\tcreatedId,\n\t\t\t\t\t\trelSchema.name,\n\t\t\t\t\t\trelSchema,\n\t\t\t\t\t\trunner,\n\t\t\t\t\t\tschemaRegistry,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tif (ops.set !== undefined) {\n\t\t\t\t\tops.set.push(createdId);\n\t\t\t\t} else {\n\t\t\t\t\tops.connect.push(createdId);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// --- Execute UPDATE (once) ---\n\t\tif (relData.update) {\n\t\t\tfor (const updateItem of relData.update) {\n\t\t\t\tconst { where, data, relations: nestedRelations } = updateItem;\n\n\t\t\t\tconst validatedData = validateData<DatrixEntry, true>(\n\t\t\t\t\tdata,\n\t\t\t\t\tnestedRelations,\n\t\t\t\t\trelSchema,\n\t\t\t\t\t{\n\t\t\t\t\t\tpartial: true,\n\t\t\t\t\t\tisCreate: false,\n\t\t\t\t\t\tisRawMode: true,\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t\tconst updateResult = await runner.executeQuery<DatrixEntry>({\n\t\t\t\t\ttype: \"update\",\n\t\t\t\t\ttable: relSchema.tableName!,\n\t\t\t\t\tdata: validatedData,\n\t\t\t\t\twhere: where as WhereClause<DatrixEntry>,\n\t\t\t\t});\n\n\t\t\t\t// Recursively resolve nested relations\n\t\t\t\tif (nestedRelations) {\n\t\t\t\t\tfor (const updated of updateResult.rows) {\n\t\t\t\t\t\tconst nestedResolved = await resolveRelationCUD(\n\t\t\t\t\t\t\tnestedRelations,\n\t\t\t\t\t\t\trelSchema,\n\t\t\t\t\t\t\trunner,\n\t\t\t\t\t\t\tschemaRegistry,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tawait processRelations(\n\t\t\t\t\t\t\tnestedResolved,\n\t\t\t\t\t\t\tupdated.id,\n\t\t\t\t\t\t\trelSchema.name,\n\t\t\t\t\t\t\trelSchema,\n\t\t\t\t\t\t\trunner,\n\t\t\t\t\t\t\tschemaRegistry,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// --- Execute DELETE (once) ---\n\t\tif (ops.deleteIds.length > 0) {\n\t\t\tawait runner.executeQuery<DatrixEntry>({\n\t\t\t\ttype: \"delete\",\n\t\t\t\ttable: relSchema.tableName!,\n\t\t\t\twhere: { id: { $in: ops.deleteIds } },\n\t\t\t});\n\t\t}\n\n\t\tresolved[fieldName] = ops;\n\t}\n\n\treturn resolved;\n}\n\n/**\n * Process a single relation field (ID-based operations only)\n *\n * At this point, create/update/delete are already resolved.\n * Only connect/disconnect/set remain as ID arrays.\n */\nasync function processRelation<T extends DatrixEntry>({\n\tparentId,\n\tparentModel,\n\tfieldName,\n\tops,\n\tschema,\n\trunner,\n\tschemaRegistry,\n}: {\n\tparentId: number;\n\tparentModel: string;\n\tfieldName: string;\n\tops: ResolvedRelationOps;\n\tschema: SchemaDefinition;\n\trunner: QueryRunner;\n\tschemaRegistry: ISchemaRegistry;\n}): Promise<void> {\n\tconst field = schema.fields[fieldName];\n\tif (!field || field.type !== \"relation\") {\n\t\treturn;\n\t}\n\n\tconst relation = field;\n\tconst foreignKey = relation.foreignKey ?? `${fieldName}Id`;\n\n\t// belongsTo → Update THIS record's foreign key (FK is on owner)\n\tif (relation.kind === \"belongsTo\") {\n\t\tconst updateData: Partial<DatrixRecord> = {};\n\n\t\tif (ops.connect.length > 0) {\n\t\t\tupdateData[foreignKey] = ops.connect[0];\n\t\t}\n\t\tif (ops.disconnect.length > 0) {\n\t\t\tupdateData[foreignKey] = null;\n\t\t}\n\t\tif (ops.set !== undefined) {\n\t\t\tupdateData[foreignKey] = ops.set.length > 0 ? ops.set[0] : null;\n\t\t}\n\n\t\tif (Object.keys(updateData).length > 0) {\n\t\t\tawait runner.executeQuery({\n\t\t\t\ttable: schema.tableName!,\n\t\t\t\ttype: \"update\",\n\t\t\t\twhere: { id: parentId },\n\t\t\t\tdata: updateData,\n\t\t\t});\n\t\t}\n\t}\n\n\t// hasOne → Update TARGET record's foreign key (FK is on target, singular)\n\tif (relation.kind === \"hasOne\") {\n\t\tconst reverseForeignKey = relation.foreignKey ?? `${parentModel}Id`;\n\t\tconst relationSchema = schemaRegistry.get(relation.model)!;\n\n\t\t// For hasOne, we need to ensure only one target is linked\n\t\tif (ops.connect.length > 0) {\n\t\t\t// First, disconnect any existing target\n\t\t\tawait runner.executeQuery({\n\t\t\t\ttable: relationSchema.tableName!,\n\t\t\t\ttype: \"update\",\n\t\t\t\tdata: { [reverseForeignKey]: null },\n\t\t\t\twhere: { [reverseForeignKey]: parentId },\n\t\t\t});\n\n\t\t\t// Then connect the new target (only first one for hasOne)\n\t\t\tawait runner.executeQuery({\n\t\t\t\ttable: relationSchema.tableName!,\n\t\t\t\ttype: \"update\",\n\t\t\t\tdata: { [reverseForeignKey]: parentId },\n\t\t\t\twhere: { id: ops.connect[0] },\n\t\t\t});\n\t\t}\n\n\t\tif (ops.disconnect.length > 0) {\n\t\t\tawait runner.executeQuery({\n\t\t\t\ttable: relationSchema.tableName!,\n\t\t\t\ttype: \"update\",\n\t\t\t\tdata: { [reverseForeignKey]: null },\n\t\t\t\twhere: { id: { $in: ops.disconnect } },\n\t\t\t});\n\t\t}\n\n\t\tif (ops.set !== undefined) {\n\t\t\t// 1. Disconnect current\n\t\t\tawait runner.executeQuery<T>({\n\t\t\t\ttable: relationSchema.tableName!,\n\t\t\t\ttype: \"update\",\n\t\t\t\tdata: { [reverseForeignKey]: null } as Partial<T>,\n\t\t\t\twhere: { [reverseForeignKey]: parentId } as WhereClause<T>,\n\t\t\t});\n\n\t\t\t// 2. Connect new one (if any)\n\t\t\tif (ops.set.length > 0) {\n\t\t\t\tawait runner.executeQuery<T>({\n\t\t\t\t\ttable: relationSchema.tableName!,\n\t\t\t\t\ttype: \"update\",\n\t\t\t\t\tdata: { [reverseForeignKey]: parentId } as Partial<T>,\n\t\t\t\t\twhere: { id: ops.set[0] } as WhereClause<T>,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\t// hasMany → Update TARGET records' foreign key (FK is on target, plural)\n\tif (relation.kind === \"hasMany\") {\n\t\tconst reverseForeignKey = relation.foreignKey ?? `${parentModel}Id`;\n\t\tconst relationSchema = schemaRegistry.get(relation.model)!;\n\n\t\tif (ops.connect.length > 0) {\n\t\t\tawait runner.executeQuery({\n\t\t\t\ttable: relationSchema.tableName!,\n\t\t\t\ttype: \"update\",\n\t\t\t\tdata: { [reverseForeignKey]: parentId },\n\t\t\t\twhere: { id: { $in: ops.connect } },\n\t\t\t});\n\t\t}\n\n\t\tif (ops.disconnect.length > 0) {\n\t\t\tawait runner.executeQuery({\n\t\t\t\ttable: relationSchema.tableName!,\n\t\t\t\ttype: \"update\",\n\t\t\t\tdata: { [reverseForeignKey]: null },\n\t\t\t\twhere: { id: { $in: ops.disconnect } },\n\t\t\t});\n\t\t}\n\n\t\tif (ops.set !== undefined) {\n\t\t\t// 1. Disconnect all current\n\t\t\tawait runner.executeQuery({\n\t\t\t\ttable: relationSchema.tableName!,\n\t\t\t\ttype: \"update\",\n\t\t\t\tdata: { [reverseForeignKey]: null },\n\t\t\t\twhere: {\n\t\t\t\t\t[reverseForeignKey]: parentId,\n\t\t\t\t},\n\t\t\t});\n\n\t\t\t// 2. Connect new ones\n\t\t\tif (ops.set.length > 0) {\n\t\t\t\tawait runner.executeQuery({\n\t\t\t\t\ttable: relationSchema.tableName!,\n\t\t\t\t\ttype: \"update\",\n\t\t\t\t\tdata: {\n\t\t\t\t\t\t[reverseForeignKey]: parentId,\n\t\t\t\t\t},\n\t\t\t\t\twhere: {\n\t\t\t\t\t\tid: { $in: ops.set },\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\t// manyToMany → Junction table operations\n\tif (relation.kind === \"manyToMany\") {\n\t\tconst junctionTable = relation.through!;\n\t\tconst sourceFK = `${parentModel}Id`;\n\t\tconst targetFK = `${relation.model}Id`;\n\n\t\t// Connect → INSERT INTO junction table (skip existing)\n\t\tif (ops.connect.length > 0) {\n\t\t\tconst existing = await runner.executeQuery({\n\t\t\t\ttable: junctionTable,\n\t\t\t\ttype: \"select\",\n\t\t\t\tselect: [targetFK],\n\t\t\t\twhere: {\n\t\t\t\t\t[sourceFK]: parentId,\n\t\t\t\t\t[targetFK]: { $in: ops.connect },\n\t\t\t\t},\n\t\t\t});\n\t\t\tconst existingIds = new Set(\n\t\t\t\texisting.rows.map((r) => r[targetFK as keyof DatrixEntry] as number),\n\t\t\t);\n\t\t\tconst newIds = ops.connect.filter((id) => !existingIds.has(id));\n\n\t\t\tif (newIds.length > 0) {\n\t\t\t\tconst rows = newIds.map((targetId) => ({\n\t\t\t\t\t[sourceFK]: parentId,\n\t\t\t\t\t[targetFK]: targetId,\n\t\t\t\t}));\n\t\t\t\tawait runner.executeQuery({\n\t\t\t\t\ttable: junctionTable,\n\t\t\t\t\ttype: \"insert\",\n\t\t\t\t\tdata: rows,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\t// Disconnect → DELETE FROM junction table\n\t\tif (ops.disconnect.length > 0) {\n\t\t\tawait runner.executeQuery<DatrixEntry>({\n\t\t\t\ttable: junctionTable,\n\t\t\t\ttype: \"delete\",\n\t\t\t\twhere: {\n\t\t\t\t\t[sourceFK]: parentId,\n\t\t\t\t\t[targetFK]: { $in: ops.disconnect },\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\n\t\t// Set → DELETE all + INSERT new\n\t\tif (ops.set !== undefined) {\n\t\t\t// 1. Delete all existing relations for this record\n\t\t\tawait runner.executeQuery<DatrixEntry>({\n\t\t\t\ttable: junctionTable,\n\t\t\t\ttype: \"delete\",\n\t\t\t\twhere: {\n\t\t\t\t\t[sourceFK]: parentId,\n\t\t\t\t},\n\t\t\t});\n\n\t\t\t// 2. Insert new relations (bulk)\n\t\t\tif (ops.set.length > 0) {\n\t\t\t\tconst rows = ops.set.map((targetId) => ({\n\t\t\t\t\t[sourceFK]: parentId,\n\t\t\t\t\t[targetFK]: targetId,\n\t\t\t\t}));\n\t\t\t\tawait runner.executeQuery<DatrixEntry>({\n\t\t\t\t\ttable: junctionTable,\n\t\t\t\t\ttype: \"insert\",\n\t\t\t\t\tdata: rows,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n}\n","/**\n * Query Executor\n *\n * Responsible for:\n * 1. Schema validation (min/max/regex/type/required)\n * 2. Timestamp injection\n * 3. Query execution via adapter\n * 4. Relation processing (async operations)\n * 5. Plugin hooks (via dispatcher)\n */\n\nimport {\n\tISchemaRegistry,\n\tSchemaDefinition,\n\tDatrixEntry,\n} from \"../types/core/schema\";\nimport {\n\tQueryObject,\n\tQuerySelectObject,\n\tQueryCountObject,\n\tQueryInsertObject,\n\tQueryUpdateObject,\n\tQueryDeleteObject,\n\tWhereClause,\n} from \"../types/core/query-builder\";\nimport { QueryAction } from \"../types/core/query-context\";\nimport { Dispatcher } from \"../dispatcher\";\nimport { validateData } from \"./validation\";\nimport { processRelations, resolveRelationCUD } from \"./relations\";\nimport {\n\tthrowSchemaNotFoundError,\n\tthrowUnsupportedQueryType,\n} from \"./error-helper\";\nimport { DatabaseAdapter, QueryRunner } from \"../types/adapter\";\n\n/**\n * Executor execution options\n */\nexport interface ExecutorOptions {\n\t/** If true, bypass dispatcher (no hooks) */\n\tnoDispatcher?: boolean;\n\t/** If true, return only ID/count instead of full record */\n\tnoReturning?: boolean;\n\t/** Query action override */\n\taction?: QueryAction;\n}\n\n/**\n * Query Executor Class\n *\n * Executes QueryObject instances with full validation, timestamp management,\n * and relation processing.\n */\nexport class QueryExecutor {\n\tconstructor(\n\t\tprivate readonly schemas: ISchemaRegistry,\n\t\tprivate readonly getAdapter: () => DatabaseAdapter,\n\t\tprivate readonly getDispatcher: () => Dispatcher,\n\t) { }\n\n\t/**\n\t * Execute a query\n\t *\n\t * @param query - Query object from QueryBuilder\n\t * @param options - Execution options (dispatcher, returning)\n\t * @returns Query result\n\t *\n\t * @example\n\t * ```ts\n\t * const query = insertInto('User', { name: 'John' }, registry).build();\n\t * const user = await executor.execute(query);\n\t *\n\t * // Raw mode (no hooks)\n\t * const result = await executor.execute(query, { noDispatcher: true });\n\t *\n\t * // ID only (no fetch)\n\t * const id = await executor.execute<User, number>(query, { noReturning: true });\n\t * ```\n\t */\n\tasync execute<T extends DatrixEntry, R>(\n\t\tquery: QueryObject<T>,\n\t\toptions: ExecutorOptions = {},\n\t): Promise<R> {\n\t\tconst schema = this.getSchema(query.table);\n\n\t\t// SELECT: Direct execution\n\t\tif (query.type === \"select\") {\n\t\t\treturn this.executeSelect<T>(query, schema, options) as R;\n\t\t}\n\n\t\t// COUNT: Direct execution\n\t\tif (query.type === \"count\") {\n\t\t\treturn this.executeCount<T>(query, schema, options) as R;\n\t\t}\n\n\t\t// DELETE: Fetch first (if returning), then delete\n\t\tif (query.type === \"delete\") {\n\t\t\treturn this.executeDelete<T>(query, schema, options) as R;\n\t\t}\n\n\t\t// INSERT/UPDATE: Validation + relations + fetch result\n\t\tif (query.type === \"insert\") {\n\t\t\treturn this.executeInsert<T>(query, schema, options) as R;\n\t\t}\n\n\t\t// INSERT/UPDATE: Validation + relations + fetch result\n\t\tif (query.type === \"update\") {\n\t\t\treturn this.executeUpdate<T>(query, schema, options) as R;\n\t\t}\n\n\t\tthrowUnsupportedQueryType((query as { type: string }).type);\n\t}\n\n\t/**\n\t * Execute SELECT query\n\t *\n\t * Always returns array (caller decides single vs multiple).\n\t * Can be reused for fetching after INSERT/UPDATE/DELETE.\n\t */\n\tasync executeSelect<T extends DatrixEntry>(\n\t\tquery: QuerySelectObject<T>,\n\t\tschema: SchemaDefinition,\n\t\toptions: ExecutorOptions,\n\t): Promise<T[]> {\n\t\treturn this.withLifecycle(\n\t\t\toptions.action ?? \"findMany\",\n\t\t\tschema,\n\t\t\toptions.noDispatcher ?? false,\n\t\t\tquery,\n\t\t\tasync (mq) => {\n\t\t\t\tconst result = await this.getAdapter().executeQuery<T>(mq);\n\t\t\t\treturn result.rows as T[];\n\t\t\t},\n\t\t);\n\t}\n\n\t/**\n\t * Execute COUNT query\n\t */\n\tasync executeCount<T extends DatrixEntry>(\n\t\tquery: QueryCountObject<T>,\n\t\tschema: SchemaDefinition,\n\t\toptions: ExecutorOptions,\n\t): Promise<number> {\n\t\treturn this.withLifecycle(\n\t\t\toptions.action ?? \"count\",\n\t\t\tschema,\n\t\t\toptions.noDispatcher ?? false,\n\t\t\tquery,\n\t\t\tasync (mq) => {\n\t\t\t\tconst result = await this.getAdapter().executeQuery<T>(mq);\n\t\t\t\treturn result.metadata.count ?? 0;\n\t\t\t},\n\t\t);\n\t}\n\n\t/**\n\t * Execute DELETE query (cascade junction tables, fetch first, then delete)\n\t *\n\t * Transaction flow: onBefore → BEGIN → SELECT (fetch) + junction cascade + DELETE → COMMIT → onAfter\n\t */\n\tasync executeDelete<T extends DatrixEntry>(\n\t\tquery: QueryDeleteObject<T>,\n\t\tschema: SchemaDefinition,\n\t\toptions: ExecutorOptions,\n\t): Promise<readonly T[]> {\n\t\treturn this.withLifecycle(\n\t\t\toptions.action ?? \"delete\",\n\t\t\tschema,\n\t\t\toptions.noDispatcher ?? false,\n\t\t\tquery,\n\t\t\tasync (mq) => {\n\t\t\t\t// 1. Begin transaction\n\t\t\t\tconst adapter = this.getAdapter();\n\t\t\t\tconst { runner, commit, rollback } =\n\t\t\t\t\tawait this.beginTransaction(adapter);\n\n\t\t\t\tlet deleteResult: readonly T[];\n\t\t\t\tlet returningResult: readonly T[];\n\n\t\t\t\ttry {\n\t\t\t\t\t// 2. Pre-fetch rows if caller needs select/populate results\n\t\t\t\t\tconst needsReturnSelect =\n\t\t\t\t\t\t!options.noReturning && (mq.select || mq.populate);\n\n\t\t\t\t\tlet prefetchedRows: readonly T[] | undefined;\n\n\t\t\t\t\tif (needsReturnSelect) {\n\t\t\t\t\t\tconst selectResult = await runner.executeQuery<T>({\n\t\t\t\t\t\t\ttype: \"select\",\n\t\t\t\t\t\t\ttable: mq.table,\n\t\t\t\t\t\t\twhere: mq.where,\n\t\t\t\t\t\t\tselect: mq.select ?? [\"id\"],\n\t\t\t\t\t\t\t...(mq.populate !== undefined && { populate: mq.populate }),\n\t\t\t\t\t\t});\n\t\t\t\t\t\tprefetchedRows = selectResult.rows;\n\t\t\t\t\t}\n\t\t\t\t\t// TODO: do we need transaction here?\n\t\t\t\t\t// 3. Execute DELETE (junction cleanup handled by DB via ON DELETE CASCADE)\n\t\t\t\t\tconst deleteQueryResult = await runner.executeQuery<T>(mq);\n\t\t\t\t\tdeleteResult = deleteQueryResult.rows;\n\n\t\t\t\t\t// 4. Commit transaction\n\t\t\t\t\tawait commit();\n\n\t\t\t\t\treturningResult = needsReturnSelect ? prefetchedRows! : deleteResult;\n\t\t\t\t} catch (error) {\n\t\t\t\t\tawait rollback();\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\n\t\t\t\treturn returningResult;\n\t\t\t},\n\t\t);\n\t}\n\n\t/**\n\t * Execute INSERT with validation and relations\n\t *\n\t * Transaction flow: onBefore → validate → BEGIN → INSERT + relations → COMMIT → SELECT → onAfter\n\t */\n\tasync executeInsert<T extends DatrixEntry>(\n\t\tquery: QueryInsertObject<T>,\n\t\tschema: SchemaDefinition,\n\t\toptions: ExecutorOptions,\n\t): Promise<readonly T[]> {\n\t\tconst noDispatcher = options.noDispatcher ?? false;\n\n\t\treturn this.withLifecycle(\n\t\t\toptions.action ?? \"create\",\n\t\t\tschema,\n\t\t\tnoDispatcher,\n\t\t\tquery,\n\t\t\tasync (mq) => {\n\t\t\t\tconst insertQuery = mq as QueryInsertObject<T>;\n\n\t\t\t\t// 1. Validate each data item against schema + add timestamps\n\t\t\t\tconst validatedItems = insertQuery.data.map((item) =>\n\t\t\t\t\tvalidateData<T, false>(item, insertQuery.relations, schema, {\n\t\t\t\t\t\tpartial: false,\n\t\t\t\t\t\tisCreate: true,\n\t\t\t\t\t\tisRawMode: noDispatcher,\n\t\t\t\t\t}),\n\t\t\t\t);\n\n\t\t\t\t// 2. Begin transaction\n\t\t\t\tconst adapter = this.getAdapter();\n\t\t\t\tconst { runner, commit, rollback } =\n\t\t\t\t\tawait this.beginTransaction(adapter);\n\n\t\t\t\tlet insertedIds: readonly T[];\n\n\t\t\t\ttry {\n\t\t\t\t\t// 3. Execute INSERT query (bulk)\n\t\t\t\t\tconst queryWithValidatedData: QueryInsertObject<T> = {\n\t\t\t\t\t\ttype: \"insert\",\n\t\t\t\t\t\ttable: insertQuery.table,\n\t\t\t\t\t\tdata: validatedItems,\n\t\t\t\t\t};\n\n\t\t\t\t\tconst insertResult = await runner.executeQuery<T>(\n\t\t\t\t\t\tqueryWithValidatedData,\n\t\t\t\t\t);\n\t\t\t\t\tinsertedIds = insertResult.rows;\n\n\t\t\t\t\t// 4. Process relations (if any) - resolve CUD once, then link per record\n\t\t\t\t\tif (insertQuery.relations) {\n\t\t\t\t\t\tconst resolvedOps = await resolveRelationCUD(\n\t\t\t\t\t\t\tinsertQuery.relations,\n\t\t\t\t\t\t\tschema,\n\t\t\t\t\t\t\trunner,\n\t\t\t\t\t\t\tthis.schemas,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tfor (const recordId of insertedIds) {\n\t\t\t\t\t\t\tawait processRelations(\n\t\t\t\t\t\t\t\tresolvedOps,\n\t\t\t\t\t\t\t\trecordId.id,\n\t\t\t\t\t\t\t\tschema.name,\n\t\t\t\t\t\t\t\tschema,\n\t\t\t\t\t\t\t\trunner,\n\t\t\t\t\t\t\t\tthis.schemas,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// 5. Commit transaction\n\t\t\t\t\tawait commit();\n\t\t\t\t} catch (error) {\n\t\t\t\t\tawait rollback();\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\n\t\t\t\t// 6. Fetch full records (if returning enabled)\n\t\t\t\tif (options.noReturning) {\n\t\t\t\t\treturn insertedIds;\n\t\t\t\t}\n\n\t\t\t\tconst selectQuery: QuerySelectObject<T> = {\n\t\t\t\t\ttype: \"select\",\n\t\t\t\t\ttable: insertQuery.table,\n\t\t\t\t\tselect: insertQuery.select!,\n\t\t\t\t\twhere: {\n\t\t\t\t\t\tid: { $in: insertedIds.map((r) => r.id) },\n\t\t\t\t\t} as unknown as WhereClause<T>,\n\t\t\t\t\t...(insertQuery.populate !== undefined && {\n\t\t\t\t\t\tpopulate: insertQuery.populate,\n\t\t\t\t\t}),\n\t\t\t\t};\n\n\t\t\t\treturn this.executeSelect<T>(selectQuery, schema, {\n\t\t\t\t\tnoDispatcher: true,\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\t}\n\n\t/**\n\t * Execute UPDATE with validation and relations\n\t *\n\t * Transaction flow: onBefore → validate → BEGIN → UPDATE + relations → COMMIT → SELECT → onAfter\n\t */\n\tasync executeUpdate<T extends DatrixEntry>(\n\t\tquery: QueryUpdateObject<T>,\n\t\tschema: SchemaDefinition,\n\t\toptions: ExecutorOptions,\n\t): Promise<readonly T[]> {\n\t\tconst noDispatcher = options.noDispatcher ?? false;\n\n\t\treturn this.withLifecycle(\n\t\t\toptions.action ?? \"update\",\n\t\t\tschema,\n\t\t\tnoDispatcher,\n\t\t\tquery,\n\t\t\tasync (mq) => {\n\t\t\t\tconst updateQuery = mq as QueryUpdateObject<T>;\n\n\t\t\t\t// 1. Validate data against schema (min/max/regex/type) + add timestamps\n\t\t\t\tconst validatedData = validateData<T, true>(\n\t\t\t\t\tupdateQuery.data,\n\t\t\t\t\tupdateQuery.relations,\n\t\t\t\t\tschema,\n\t\t\t\t\t{\n\t\t\t\t\t\tpartial: true,\n\t\t\t\t\t\tisCreate: false,\n\t\t\t\t\t\tisRawMode: noDispatcher,\n\t\t\t\t\t},\n\t\t\t\t);\n\n\t\t\t\t// 2. Begin transaction\n\t\t\t\tconst adapter = this.getAdapter();\n\t\t\t\tconst { runner, commit, rollback } =\n\t\t\t\t\tawait this.beginTransaction(adapter);\n\n\t\t\t\tlet recordIds: readonly T[];\n\n\t\t\t\ttry {\n\t\t\t\t\t// 3. Execute UPDATE query (scalars only)\n\t\t\t\t\tconst queryWithValidatedData: QueryUpdateObject<T> = {\n\t\t\t\t\t\ttype: \"update\",\n\t\t\t\t\t\ttable: updateQuery.table,\n\t\t\t\t\t\tdata: validatedData,\n\t\t\t\t\t\t...(updateQuery.where !== undefined && {\n\t\t\t\t\t\t\twhere: updateQuery.where,\n\t\t\t\t\t\t}),\n\t\t\t\t\t};\n\n\t\t\t\t\tconst updateResult = await runner.executeQuery<T>(\n\t\t\t\t\t\tqueryWithValidatedData,\n\t\t\t\t\t);\n\t\t\t\t\trecordIds = updateResult.rows;\n\n\t\t\t\t\t// 4. Process relations (if any) - resolve CUD ONCE, then link per parent\n\t\t\t\t\tif (updateQuery.relations) {\n\t\t\t\t\t\tconst resolvedOps = await resolveRelationCUD(\n\t\t\t\t\t\t\tupdateQuery.relations,\n\t\t\t\t\t\t\tschema,\n\t\t\t\t\t\t\trunner,\n\t\t\t\t\t\t\tthis.schemas,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tfor (const recordId of recordIds) {\n\t\t\t\t\t\t\tawait processRelations(\n\t\t\t\t\t\t\t\tresolvedOps,\n\t\t\t\t\t\t\t\trecordId.id,\n\t\t\t\t\t\t\t\tschema.name,\n\t\t\t\t\t\t\t\tschema,\n\t\t\t\t\t\t\t\trunner,\n\t\t\t\t\t\t\t\tthis.schemas,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// 5. Commit transaction\n\t\t\t\t\tawait commit();\n\t\t\t\t} catch (error) {\n\t\t\t\t\tawait rollback();\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\n\t\t\t\t// 6. Fetch full records (if returning enabled)\n\t\t\t\tif (options.noReturning) {\n\t\t\t\t\treturn recordIds;\n\t\t\t\t}\n\n\t\t\t\t// Use updated record IDs for select (not original where, which may no longer match)\n\t\t\t\tconst selectQuery: QuerySelectObject<T> = {\n\t\t\t\t\ttype: \"select\",\n\t\t\t\t\ttable: updateQuery.table,\n\t\t\t\t\tselect: updateQuery.select!,\n\t\t\t\t\twhere: {\n\t\t\t\t\t\tid: { $in: recordIds.map((r) => r.id) },\n\t\t\t\t\t} as unknown as WhereClause<T>,\n\t\t\t\t\t...(updateQuery.populate !== undefined && {\n\t\t\t\t\t\tpopulate: updateQuery.populate,\n\t\t\t\t\t}),\n\t\t\t\t};\n\n\t\t\t\treturn this.executeSelect<T>(selectQuery, schema, {\n\t\t\t\t\tnoDispatcher: true,\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\t}\n\n\t/**\n\t * Wraps a handler with dispatcher lifecycle: buildContext → onBefore → handler → onAfter.\n\t * If noDispatcher is true, skips all hooks and runs handler directly.\n\t * context.metadata is shared between before/after hooks for the same operation.\n\t */\n\tprivate async withLifecycle<TResult, TQuery>(\n\t\taction: QueryAction,\n\t\tschema: SchemaDefinition,\n\t\tnoDispatcher: boolean,\n\t\tquery: TQuery,\n\t\thandler: (modifiedQuery: TQuery) => Promise<TResult>,\n\t): Promise<TResult> {\n\t\tconst dispatcher = this.getDispatcher();\n\n\t\tif (noDispatcher) {\n\t\t\treturn handler(query);\n\t\t}\n\n\t\tconst context = await dispatcher.buildQueryContext(action);\n\n\t\tconst modifiedQuery = (await dispatcher.dispatchBeforeQuery(\n\t\t\tquery as QueryObject,\n\t\t\tschema,\n\t\t\tcontext,\n\t\t)) as TQuery;\n\n\t\tconst result = await handler(modifiedQuery);\n\n\t\treturn dispatcher.dispatchAfterQuery(\n\t\t\tresult as DatrixEntry,\n\t\t\tschema,\n\t\t\tcontext,\n\t\t) as Promise<TResult>;\n\t}\n\n\t/**\n\t * Begin transaction and return runner, commit, rollback helpers.\n\t */\n\tprivate async beginTransaction(adapter: DatabaseAdapter): Promise<{\n\t\trunner: QueryRunner;\n\t\tcommit: () => Promise<void>;\n\t\trollback: () => Promise<void>;\n\t}> {\n\t\tconst tx = await adapter.beginTransaction();\n\t\treturn {\n\t\t\trunner: tx,\n\t\t\tcommit: async () => {\n\t\t\t\tawait tx.commit();\n\t\t\t},\n\t\t\trollback: async () => {\n\t\t\t\tawait tx.rollback();\n\t\t\t},\n\t\t};\n\t}\n\n\t/**\n\t * Get schema by table name\n\t */\n\tprivate getSchema(tableName: string): SchemaDefinition {\n\t\tconst result = this.schemas.getByTableName(tableName);\n\t\tif (!result) {\n\t\t\tthrowSchemaNotFoundError(tableName);\n\t\t}\n\t\treturn result.schema;\n\t}\n}\n","/**\n * CRUD Operations Mixin\n *\n * Provides database CRUD (Create, Read, Update, Delete) operations.\n * This class encapsulates all data manipulation logic.\n */\n\nimport { DatabaseAdapter } from \"../types/adapter\";\nimport { ISchemaRegistry, DatrixEntry, DatrixRecord } from \"../types/core/schema\";\nimport { WhereClause } from \"../types/core/query-builder\";\nimport { Dispatcher } from \"../dispatcher\";\nimport {\n\tIRawCrud,\n\tRawCrudOptions,\n\tRawFindManyOptions,\n\tFallbackInput,\n} from \"../types/core\";\nimport {\n\tselectFrom,\n\tcountFrom,\n\tinsertInto,\n\tupdateTable,\n\tdeleteFrom,\n} from \"../query-builder\";\nimport { QueryExecutor } from \"../query-executor/executor\";\nimport { throwRecordNotFound } from \"../query-executor/error-helper\";\n\n/**\n * CRUD Operations Class\n *\n * Handles all database CRUD operations with type-safe query building.\n * Uses QueryExecutor for INSERT/UPDATE operations with relation processing.\n * Implements IRawCrud interface.\n */\nexport class CrudOperations implements IRawCrud {\n\tprivate readonly executor: QueryExecutor;\n\n\tconstructor(\n\t\tprivate readonly schemas: ISchemaRegistry,\n\t\treadonly getAdapter: () => DatabaseAdapter,\n\t\tprivate readonly getDispatcher: (() => Dispatcher) | null = null,\n\t) {\n\t\t// QueryExecutor handles validation, timestamps, and recursive relations\n\t\tthis.executor = new QueryExecutor(\n\t\t\tschemas,\n\t\t\tgetAdapter,\n\t\t\tgetDispatcher || (() => ({}) as Dispatcher), // Dummy dispatcher if null\n\t\t);\n\t}\n\n\t/**\n\t * Find one record by criteria\n\t *\n\t * **NEW:** Now supports type-safe nested relation WHERE queries!\n\t *\n\t * @param model - Model name (e.g., 'User')\n\t * @param where - Filter criteria (now supports nested relations)\n\t * @param options - Query options (select, populate)\n\t * @returns Record or null if not found\n\t *\n\t * @example\n\t * ```ts\n\t * // Basic WHERE\n\t * const user = await crud.findOne('User', { email: 'test@example.com' });\n\t *\n\t * // Nested relation WHERE\n\t * const post = await crud.findOne('Post', {\n\t * title: { $like: 'Hello%' },\n\t * author: { // ✅ NEW: Nested WHERE on relations!\n\t * verified: { $eq: true },\n\t * company: {\n\t * country: { name: { $eq: 'Turkey' } }\n\t * }\n\t * }\n\t * });\n\t *\n\t * // With type safety\n\t * type Post = { id: number; title: string; author: Relation<User>; };\n\t * const typedPost = await crud.findOne<Post>('Post', {\n\t * author: { name: { $like: 'John%' } } // ✅ Type-checked\n\t * });\n\t * ```\n\t */\n\tasync findOne<T extends DatrixEntry = DatrixEntry>(\n\t\tmodel: string,\n\t\twhere: WhereClause<T>,\n\t\toptions?: RawCrudOptions<T>,\n\t): Promise<T | null> {\n\t\tconst builder = selectFrom<T>(model, this.schemas).where(where).limit(1);\n\n\t\tif (options?.select) {\n\t\t\tbuilder.select(options.select);\n\t\t}\n\t\tif (options?.populate) {\n\t\t\tbuilder.populate(options.populate);\n\t\t}\n\n\t\tconst query = builder.build();\n\n\t\tconst results = await this.executor.execute<T, T[]>(query, {\n\t\t\tnoDispatcher: this.getDispatcher === null,\n\t\t\taction: \"findOne\",\n\t\t});\n\n\t\treturn results[0] || null;\n\t}\n\n\t/**\n\t * Find one record by ID\n\t *\n\t * @param model - Model name\n\t * @param id - Record ID\n\t * @param options - Query options\n\t * @returns Record or null\n\t *\n\t * @example\n\t * ```ts\n\t * const user = await crud.findById('User', '123');\n\t * ```\n\t */\n\tasync findById<T extends DatrixEntry = DatrixRecord>(\n\t\tmodel: string,\n\t\tid: number,\n\t\toptions?: RawCrudOptions<T>,\n\t): Promise<T | null> {\n\t\treturn this.findOne<T>(model, { id } as WhereClause<T>, options);\n\t}\n\n\t/**\n\t * Find multiple records\n\t *\n\t * **NEW:** Now supports type-safe nested relation WHERE queries!\n\t *\n\t * @param model - Model name\n\t * @param options - Query options (with nested relation WHERE support)\n\t * @returns Array of records\n\t *\n\t * @example\n\t * ```ts\n\t * // Basic query\n\t * const users = await crud.findMany('User', {\n\t * where: { role: 'admin' },\n\t * limit: 10,\n\t * orderBy: [{ field: 'createdAt', direction: 'desc' }]\n\t * });\n\t *\n\t * // With nested relation WHERE\n\t * const posts = await crud.findMany('Post', {\n\t * where: {\n\t * $and: [\n\t * { published: true },\n\t * { author: { verified: { $eq: true } } } // ✅ Nested relation\n\t * ]\n\t * }\n\t * });\n\t * ```\n\t */\n\tasync findMany<T extends DatrixEntry = DatrixRecord>(\n\t\tmodel: string,\n\t\toptions?: RawFindManyOptions<T>,\n\t): Promise<T[]> {\n\t\tconst builder = selectFrom<T>(model, this.schemas);\n\n\t\tif (options?.where) {\n\t\t\tbuilder.where(options.where);\n\t\t}\n\t\tif (options?.select) {\n\t\t\tbuilder.select(options.select);\n\t\t}\n\t\tif (options?.populate) {\n\t\t\tbuilder.populate(options.populate);\n\t\t}\n\t\tif (options?.orderBy) {\n\t\t\tbuilder.orderBy(options?.orderBy);\n\t\t}\n\t\tif (options?.limit !== undefined) {\n\t\t\tbuilder.limit(options.limit);\n\t\t}\n\t\tif (options?.offset !== undefined) {\n\t\t\tbuilder.offset(options.offset);\n\t\t}\n\n\t\tconst query = builder.build();\n\n\t\tconst results = await this.executor.execute<T, T[]>(query, {\n\t\t\tnoDispatcher: this.getDispatcher === null,\n\t\t\taction: \"findMany\",\n\t\t});\n\n\t\treturn results;\n\t}\n\n\t/**\n\t * Count records\n\t *\n\t * **NEW:** Now supports type-safe nested relation WHERE queries!\n\t *\n\t * @param model - Model name\n\t * @param where - Filter criteria (supports nested relations)\n\t * @returns Number of matching records\n\t *\n\t * @example\n\t * ```ts\n\t * const totalUsers = await crud.count('User');\n\t * const adminCount = await crud.count('User', { role: 'admin' });\n\t *\n\t * // With nested relation WHERE\n\t * const verifiedPosts = await crud.count('Post', {\n\t * author: { verified: { $eq: true } }\n\t * });\n\t * ```\n\t */\n\tasync count<T extends DatrixEntry = DatrixRecord>(\n\t\tmodel: string,\n\t\twhere?: WhereClause<T>,\n\t): Promise<number> {\n\t\tconst builder = countFrom<T>(model, this.schemas);\n\n\t\tif (where) {\n\t\t\tbuilder.where(where);\n\t\t}\n\n\t\tconst query = builder.build();\n\n\t\tconst result = await this.executor.execute<T, number>(query, {\n\t\t\tnoDispatcher: this.getDispatcher === null,\n\t\t\taction: \"count\",\n\t\t});\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Create a new record\n\t *\n\t * @param model - Model name\n\t * @param data - Record data\n\t * @returns Created record\n\t *\n\t * @example\n\t * ```ts\n\t * const user = await crud.create('User', {\n\t * email: 'john@example.com',\n\t * name: 'John Doe',\n\t * role: 'user'\n\t * });\n\t * ```\n\t */\n\tasync create<\n\t\tT extends DatrixEntry = DatrixRecord,\n\t\tTInput extends FallbackInput = FallbackInput,\n\t>(model: string, data: TInput, options?: RawCrudOptions<T>): Promise<T> {\n\t\tconst result = await this.createMany<T, TInput>(model, [data], {\n\t\t\t...options,\n\t\t\taction: \"create\", // pass this to avoid \"createMany\" action in dispatcher for single record creation\n\t\t});\n\n\t\treturn result[0]!;\n\t}\n\n\t/**\n\t * Create multiple new record\n\t *\n\t * @param model - Model name\n\t * @param data - Record data []\n\t * @returns Created records\n\t *\n\t * @example\n\t * ```ts\n\t * const user = await crud.create('User', [\n\t * { email: 'john@example.com', name: 'John Doe', role: 'user' },\n\t * { email: 'jane@example.com', name: 'Jane Doe', role: 'user' }\n\t * ]);\n\t * ```\n\t */\n\tasync createMany<\n\t\tT extends DatrixEntry = DatrixRecord,\n\t\tTInput extends FallbackInput = FallbackInput,\n\t>(model: string, data: TInput[], options?: RawCrudOptions<T>): Promise<T[]> {\n\t\tconst builder = insertInto<T>(\n\t\t\tmodel,\n\t\t\tdata as unknown as Partial<T>[],\n\t\t\tthis.schemas,\n\t\t);\n\n\t\tif (options?.select) {\n\t\t\tbuilder.select(options.select);\n\t\t}\n\t\tif (options?.populate) {\n\t\t\tbuilder.populate(options.populate);\n\t\t}\n\n\t\tconst query = builder.build();\n\n\t\tconst result = await this.executor.execute<T, T[]>(query, {\n\t\t\tnoDispatcher: this.getDispatcher === null,\n\t\t\taction: options?.action ?? \"createMany\",\n\t\t});\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Update a record by ID\n\t *\n\t * @param model - Model name\n\t * @param id - Record ID\n\t * @param data - Updated data\n\t * @returns Updated record\n\t *\n\t * @example\n\t * ```ts\n\t * const user = await crud.update('User', '123', {\n\t * name: 'Jane Doe'\n\t * });\n\t * ```\n\t */\n\tasync update<\n\t\tT extends DatrixEntry = DatrixRecord,\n\t\tTInput extends FallbackInput = FallbackInput,\n\t>(\n\t\tmodel: string,\n\t\tid: number,\n\t\tdata: TInput,\n\t\toptions?: RawCrudOptions<T>,\n\t): Promise<T> {\n\t\tconst result = await this.updateMany(\n\t\t\tmodel,\n\t\t\t{ id } as WhereClause<T>,\n\t\t\tdata,\n\t\t\t{\n\t\t\t\t...options,\n\t\t\t\taction: options?.action ?? \"update\",\n\t\t\t},\n\t\t);\n\n\t\tif (result.length === 0) {\n\t\t\tthrowRecordNotFound(\"update\", model, id);\n\t\t}\n\n\t\treturn result[0]!;\n\t}\n\n\t/**\n\t * Update multiple records\n\t *\n\t * **NEW:** Now supports type-safe nested relation WHERE queries!\n\t *\n\t * @param model - Model name\n\t * @param where - Filter criteria (supports nested relations)\n\t * @param data - Updated data\n\t * @returns Number of updated records\n\t *\n\t * @example\n\t * ```ts\n\t * // Basic WHERE\n\t * const count = await crud.updateMany('User',\n\t * { role: 'user' },\n\t * { verified: true }\n\t * );\n\t *\n\t * // With nested relation WHERE\n\t * const count2 = await crud.updateMany('Post',\n\t * { author: { verified: { $eq: true } } }, // ✅ NEW: Nested relation\n\t * { featured: true }\n\t * );\n\t * ```\n\t */\n\tasync updateMany<\n\t\tT extends DatrixEntry = DatrixRecord,\n\t\tTInput extends FallbackInput = FallbackInput,\n\t>(\n\t\tmodel: string,\n\t\twhere: WhereClause<T>,\n\t\tdata: TInput,\n\t\toptions?: RawCrudOptions<T>,\n\t): Promise<T[]> {\n\t\tconst builder = updateTable<T>(\n\t\t\tmodel,\n\t\t\tdata as unknown as Partial<T>,\n\t\t\tthis.schemas,\n\t\t).where(where);\n\n\t\tif (options?.select || !options?.noReturning) {\n\t\t\tbuilder.select(options?.select ?? \"*\");\n\t\t}\n\n\t\tif (options?.populate) {\n\t\t\tbuilder.populate(options.populate);\n\t\t}\n\n\t\tconst query = builder.build();\n\n\t\tconst result = await this.executor.execute<T, T[]>(query, {\n\t\t\tnoDispatcher: this.getDispatcher === null,\n\t\t\tnoReturning: options?.noReturning ?? false,\n\t\t\taction: options?.action || \"updateMany\",\n\t\t});\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Delete a record by ID\n\t *\n\t * @param model - Model name\n\t * @param id - Record ID\n\t * @returns True if deleted\n\t *\n\t * @example\n\t * ```ts\n\t * const deleted = await crud.delete('User', '123');\n\t * ```\n\t */\n\tasync delete<T extends DatrixEntry = DatrixRecord>(\n\t\tmodel: string,\n\t\tid: number,\n\t\toptions?: RawCrudOptions<T>,\n\t): Promise<T> {\n\t\tconst result = await this.deleteMany<T>(model, { id } as WhereClause<T>, {\n\t\t\t...options,\n\t\t\tnoReturning: options?.noReturning ?? false,\n\t\t\taction: options?.action ?? \"delete\",\n\t\t});\n\n\t\tif (result.length === 0) {\n\t\t\tthrowRecordNotFound(\"delete\", model, id);\n\t\t}\n\n\t\treturn result[0]!;\n\t}\n\n\t/**\n\t * Delete multiple records\n\t *\n\t * **NEW:** Now supports type-safe nested relation WHERE queries!\n\t *\n\t * @param model - Model name\n\t * @param where - Filter criteria (supports nested relations)\n\t * @returns Number of deleted records\n\t *\n\t * @example\n\t * ```ts\n\t * // Basic WHERE\n\t * const count = await crud.deleteMany('User', { verified: false });\n\t *\n\t * // With nested relation WHERE\n\t * const count2 = await crud.deleteMany('Post', {\n\t * author: { id: { $eq: userId } } // ✅ NEW: Use relation WHERE instead of authorId\n\t * });\n\t * ```\n\t */\n\tasync deleteMany<T extends DatrixEntry = DatrixRecord>(\n\t\tmodel: string,\n\t\twhere: WhereClause<T>,\n\t\toptions?: RawCrudOptions<T>,\n\t): Promise<T[]> {\n\t\tconst queryBuilder = deleteFrom<T>(model, this.schemas).where(where);\n\n\t\tif (options?.select || !options?.noReturning)\n\t\t\tqueryBuilder.select(options?.select ?? \"*\");\n\n\t\tif (options?.populate) queryBuilder.populate(options.populate);\n\n\t\tconst query = queryBuilder.build();\n\n\t\tconst result = await this.executor.execute<T, T[]>(query, {\n\t\t\tnoDispatcher: this.getDispatcher === null,\n\t\t\tnoReturning: options?.noReturning ?? !(query?.select || query?.populate),\n\t\t\taction: options?.action ?? \"deleteMany\",\n\t\t});\n\n\t\treturn result;\n\t}\n}\n","/**\n * Schema Extension Context Implementation\n *\n * Provides helper methods for plugins to extend schemas in bulk.\n */\n\nimport type {\n\tSchemaDefinition,\n\tSchemaExtension,\n\tSchemaExtensionContext,\n\tSchemaModifier,\n\tSchemaPattern,\n} from \"../types/core/plugin\";\n\nexport class SchemaExtensionContextImpl implements SchemaExtensionContext {\n\tconstructor(public readonly schemas: ReadonlyArray<SchemaDefinition>) {}\n\n\textendAll(modifier: SchemaModifier): SchemaExtension[] {\n\t\treturn this.schemas.map((schema) => ({\n\t\t\ttargetSchema: schema.name,\n\t\t\t...modifier(schema),\n\t\t}));\n\t}\n\n\textendWhere(\n\t\tpredicate: (schema: SchemaDefinition) => boolean,\n\t\tmodifier: SchemaModifier,\n\t): SchemaExtension[] {\n\t\treturn this.schemas.filter(predicate).map((schema) => ({\n\t\t\ttargetSchema: schema.name,\n\t\t\t...modifier(schema),\n\t\t}));\n\t}\n\n\textendByPattern(\n\t\tpattern: SchemaPattern,\n\t\tmodifier: SchemaModifier,\n\t): SchemaExtension[] {\n\t\treturn this.schemas\n\t\t\t.filter((schema) => this.matchesPattern(schema, pattern))\n\t\t\t.map((schema) => ({\n\t\t\t\ttargetSchema: schema.name,\n\t\t\t\t...modifier(schema),\n\t\t\t}));\n\t}\n\n\tprivate matchesPattern(\n\t\tschema: SchemaDefinition,\n\t\tpattern: SchemaPattern,\n\t): boolean {\n\t\tif (pattern.names && !pattern.names.includes(schema.name)) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (pattern.prefix && !schema.name.startsWith(pattern.prefix)) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (pattern.suffix && !schema.name.endsWith(pattern.suffix)) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (pattern.exclude?.includes(schema.name)) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (pattern.custom && !pattern.custom(schema)) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n}\n","/**\n * Query Utilities\n *\n * Provides runtime validation for QueryObject structure.\n */\n\nimport { DatrixEntry } from \"../core/schema\";\nimport { QueryObject } from \"../core/query-builder\";\nimport { DatrixError } from \"../errors\";\n\n/**\n * Valid keys for a QueryObject\n */\nconst VALID_QUERY_KEYS = new Set([\n\t\"type\",\n\t\"table\",\n\t\"select\",\n\t\"where\",\n\t\"populate\",\n\t\"orderBy\",\n\t\"limit\",\n\t\"offset\",\n\t\"data\",\n\t\"returning\",\n\t\"distinct\",\n\t\"groupBy\",\n\t\"having\",\n\t\"meta\",\n\t\"__meta__\",\n\t\"relations\",\n]);\n\n/**\n * Common mistakes to watch out for\n */\nconst FORBIDDEN_KEYS_MAPPING: Record<string, string> = {\n\tfields: \"select\",\n};\n\n/**\n * @deprecated Dont need it any more. query-builder creates perfectly validated QueryObjects\n * Validates that a QueryObject contains only allowed keys.\n * This is a runtime check to catch errors from plugins or dynamic query construction.\n */\nexport function validateQueryObject<T extends DatrixEntry>(\n\tquery: unknown,\n): void {\n\tif (typeof query !== \"object\" || query === null) {\n\t\tthrow new DatrixError(\"Query must be an object\", {\n\t\t\tcode: \"INVALID_QUERY_TYPE\",\n\t\t\toperation: \"query:validate\",\n\t\t\tcontext: { receivedType: typeof query },\n\t\t\tsuggestion: \"Provide a valid QueryObject\",\n\t\t\texpected: \"object\",\n\t\t\treceived: query,\n\t\t});\n\t}\n\n\tconst queryKeys = Object.keys(query);\n\tconst invalidKeys: string[] = [];\n\tconst suggestions: string[] = [];\n\n\tfor (const key of queryKeys) {\n\t\tif (!VALID_QUERY_KEYS.has(key)) {\n\t\t\tconst suggestion = FORBIDDEN_KEYS_MAPPING[key];\n\t\t\tif (suggestion) {\n\t\t\t\tinvalidKeys.push(key);\n\t\t\t\tsuggestions.push(`Use '${suggestion}' instead of '${key}'`);\n\t\t\t} else {\n\t\t\t\tinvalidKeys.push(key);\n\t\t\t}\n\t\t}\n\t}\n\n\tif (invalidKeys.length > 0) {\n\t\tconst keyList = invalidKeys\n\t\t\t.map((key) => {\n\t\t\t\tconst alt = FORBIDDEN_KEYS_MAPPING[key];\n\t\t\t\treturn alt ? `'${key}' (use '${alt}' instead)` : `'${key}'`;\n\t\t\t})\n\t\t\t.join(\", \");\n\n\t\tthrow new DatrixError(`Invalid keys found in QueryObject: ${keyList}`, {\n\t\t\tcode: \"INVALID_QUERY_KEYS\",\n\t\t\toperation: \"query:validate\",\n\t\t\tcontext: {\n\t\t\t\tinvalidKeys,\n\t\t\t\tvalidKeys: Array.from(VALID_QUERY_KEYS),\n\t\t\t\tquery,\n\t\t\t},\n\t\t\tsuggestion:\n\t\t\t\tsuggestions.length > 0\n\t\t\t\t\t? suggestions.join(\"; \")\n\t\t\t\t\t: \"Remove invalid keys from QueryObject\",\n\t\t\texpected: `Valid keys: ${Array.from(VALID_QUERY_KEYS).join(\", \")}`,\n\t\t});\n\t}\n\n\t// Basic structure check for required fields\n\tconst q = query as Partial<QueryObject<T>>;\n\tif (!q.type) {\n\t\tthrow new DatrixError(\"QueryObject is missing required field: type\", {\n\t\t\tcode: \"MISSING_QUERY_FIELD\",\n\t\t\toperation: \"query:validate\",\n\t\t\tcontext: { query },\n\t\t\tsuggestion:\n\t\t\t\t\"Add 'type' field to QueryObject (e.g., 'select', 'insert', 'update', 'delete')\",\n\t\t\texpected: \"type: 'select' | 'insert' | 'update' | 'delete'\",\n\t\t});\n\t}\n\tif (!q.table) {\n\t\tthrow new DatrixError(\"QueryObject is missing required field: table\", {\n\t\t\tcode: \"MISSING_QUERY_FIELD\",\n\t\t\toperation: \"query:validate\",\n\t\t\tcontext: { query },\n\t\t\tsuggestion: \"Add 'table' field to QueryObject with the target table name\",\n\t\t\texpected: \"table: string\",\n\t\t});\n\t}\n}\n","import { DatrixError } from \"../types/errors\";\n\ntype BeforeHookName =\n\t| \"beforeCreate\"\n\t| \"beforeUpdate\"\n\t| \"beforeDelete\"\n\t| \"beforeFind\";\n\ntype AfterHookName =\n\t| \"afterCreate\"\n\t| \"afterUpdate\"\n\t| \"afterDelete\"\n\t| \"afterFind\";\n\n/**\n * Thrown when a before hook returns undefined or null instead of data.\n * This is a programmer error — the hook must always return the (possibly modified) data.\n */\nexport function throwHookInvalidReturn(hookName: BeforeHookName): never {\n\tthrow new DatrixError(\n\t\t`${hookName} hook must return data. Did you forget to return?`,\n\t\t{\n\t\t\tcode: \"HOOK_INVALID_RETURN\",\n\t\t\toperation: `dispatcher:schema:${hookName}`,\n\t\t\tsuggestion: `Ensure your ${hookName} hook returns the data object (even if unmodified).`,\n\t\t},\n\t);\n}\n\n/**\n * Thrown when a plugin's before hook throws an error.\n * Re-throws DatrixErrors as-is; wraps unknown errors.\n */\nexport function throwHookPluginError(\n\tpluginName: string,\n\thookName: string,\n\tcause: unknown,\n): never {\n\tif (cause instanceof DatrixError) throw cause;\n\tthrow new DatrixError(\n\t\t`Plugin '${pluginName}' threw an error in ${hookName} hook.`,\n\t\t{\n\t\t\tcode: \"HOOK_PLUGIN_ERROR\",\n\t\t\toperation: `dispatcher:plugin:${hookName}`,\n\t\t\tcause: cause instanceof Error ? cause : new Error(String(cause)),\n\t\t},\n\t);\n}\n\n/**\n * Logs a warning when an after hook throws an error.\n * The operation result is still returned — after hook errors do not abort the response.\n * See docs: after hook errors are non-fatal by design.\n */\nexport function warnAfterHookError(\n\thookName: AfterHookName,\n\terror: unknown,\n): void {\n\tconsole.warn(\n\t\t`[Datrix] ${hookName} hook threw an error. The operation completed successfully but the hook failed.`,\n\t\terror,\n\t);\n}\n","/**\n * Plugin Hook Dispatcher\n *\n * Orchestrates the execution of plugin hooks (lifecycle and query hooks).\n * Ensures hooks are called in the correct order and provides error isolation.\n */\n\nimport {\n\tQueryObject,\n\tQuerySelectObject,\n\tQueryInsertObject,\n\tQueryUpdateObject,\n\tQueryDeleteObject,\n} from \"../types/core/query-builder\";\nimport { PluginRegistry } from \"../types/core/plugin\";\nimport { QueryAction, QueryContext } from \"../types/core/query-context\";\nimport {\n\tDatrixEntry,\n\tDatrixRecord,\n\tSchemaDefinition,\n\tLifecycleHooks,\n} from \"../types/core/schema\";\nimport type { Datrix } from \"../datrix\";\nimport { validateQueryObject } from \"../types/utils/query\";\nimport { SchemaRegistry } from \"../schema\";\nimport {\n\tthrowHookInvalidReturn,\n\tthrowHookPluginError,\n\twarnAfterHookError,\n} from \"./hook-errors\";\n\n/**\n * Create a new query context\n */\nfunction createQueryContext(action: QueryAction, datrix: Datrix): QueryContext {\n\treturn {\n\t\taction,\n\t\tdatrix,\n\t\tmetadata: {},\n\t};\n}\n\n/**\n * Dispatcher for plugin hooks\n */\nexport class Dispatcher {\n\tconstructor(\n\t\tprivate readonly registry: PluginRegistry,\n\t\tprivate readonly datrix: Datrix,\n\t) { }\n\n\t/**\n\t * Create and populate query context\n\t *\n\t * This allows plugins to enrich the context before query execution.\n\t */\n\tasync buildQueryContext(action: QueryAction): Promise<QueryContext> {\n\t\tlet context = createQueryContext(action, this.datrix);\n\n\t\tfor (const plugin of this.registry.getAll()) {\n\t\t\ttry {\n\t\t\t\tif (plugin.onCreateQueryContext) {\n\t\t\t\t\tconst result = await plugin.onCreateQueryContext(context);\n\t\t\t\t\tif (result) {\n\t\t\t\t\t\tcontext = result;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(\n\t\t\t\t\t`[Dispatcher] Error in plugin '${plugin.name}' onCreateQueryContext:`,\n\t\t\t\t\terror,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\treturn context;\n\t}\n\n\t/**\n\t * Dispatch onSchemaLoad hook to all plugins\n\t */\n\tasync dispatchSchemaLoad(schemas: SchemaRegistry): Promise<void> {\n\t\tfor (const plugin of this.registry.getAll()) {\n\t\t\ttry {\n\t\t\t\tif (plugin.onSchemaLoad) {\n\t\t\t\t\tawait plugin.onSchemaLoad(schemas);\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(\n\t\t\t\t\t`[Dispatcher] Error in plugin '${plugin.name}' onSchemaLoad:`,\n\t\t\t\t\terror,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Execute full query lifecycle:\n\t * 1. Create context + shared hookCtx (metadata shared between before/after)\n\t * 2. onBeforeQuery plugin hooks + schema before hook\n\t * 3. Execute query\n\t * 4. onAfterQuery plugin hooks + schema after hook\n\t */\n\tasync executeQuery<\n\t\tTResult extends DatrixEntry,\n\t\tR extends DatrixEntry = DatrixEntry,\n\t>(\n\t\taction: QueryAction,\n\t\tschema: SchemaDefinition,\n\t\tquery: QueryObject<TResult>,\n\t\texecutor: (query: QueryObject<TResult>) => Promise<R>,\n\t): Promise<R> {\n\t\tconst context = await this.buildQueryContext(action);\n\t\tconst modifiedQuery = await this.dispatchBeforeQuery(\n\t\t\tquery,\n\t\t\tschema,\n\t\t\tcontext,\n\t\t);\n\t\tconst result = await executor(modifiedQuery);\n\t\treturn this.dispatchAfterQuery<R>(result, schema, context);\n\t}\n\n\t/**\n\t * Dispatch onBeforeQuery hook to all plugins (serial execution),\n\t * then call the schema lifecycle hook if defined.\n\t * Both plugins and schema hooks can modify and return the query.\n\t * hookCtx is shared with dispatchAfterQuery so metadata persists.\n\t */\n\tasync dispatchBeforeQuery<TResult extends DatrixEntry = DatrixRecord>(\n\t\tquery: QueryObject<TResult>,\n\t\tschema: SchemaDefinition,\n\t\tcontext: QueryContext,\n\t): Promise<QueryObject<TResult>> {\n\t\tvalidateQueryObject(query);\n\n\t\tlet currentQuery = { ...query } as QueryObject<TResult>;\n\n\t\tfor (const plugin of this.registry.getAll()) {\n\t\t\ttry {\n\t\t\t\tif (plugin.onBeforeQuery) {\n\t\t\t\t\tcurrentQuery = await plugin.onBeforeQuery(currentQuery, context);\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tthrowHookPluginError(plugin.name, \"onBeforeQuery\", error);\n\t\t\t}\n\t\t}\n\n\t\tcurrentQuery = await this.dispatchSchemaBeforeHook(\n\t\t\tcurrentQuery,\n\t\t\tschema,\n\t\t\tcontext,\n\t\t);\n\n\t\treturn currentQuery;\n\t}\n\n\t/**\n\t * Dispatch onAfterQuery hook to all plugins (serial execution),\n\t * then call the schema lifecycle hook if defined.\n\t * Both plugins and schema hooks can modify and return the result.\n\t * hookCtx is the same instance as in dispatchBeforeQuery so metadata is shared.\n\t */\n\tasync dispatchAfterQuery<TResult extends DatrixEntry>(\n\t\tresult: TResult,\n\t\tschema: SchemaDefinition,\n\t\tcontext: QueryContext,\n\t): Promise<TResult> {\n\t\tlet currentResult = result;\n\n\t\tfor (const plugin of this.registry.getAll()) {\n\t\t\ttry {\n\t\t\t\tif (plugin.onAfterQuery) {\n\t\t\t\t\tcurrentResult = await plugin.onAfterQuery(currentResult, context);\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\twarnAfterHookError(\"afterFind\", error);\n\t\t\t}\n\t\t}\n\n\t\tcurrentResult = await this.dispatchSchemaAfterHook(\n\t\t\tcurrentResult,\n\t\t\tschema,\n\t\t\tcontext,\n\t\t);\n\n\t\treturn currentResult;\n\t}\n\n\tprivate async dispatchSchemaBeforeHook<TResult extends DatrixEntry>(\n\t\tquery: QueryObject<TResult>,\n\t\tschema: SchemaDefinition,\n\t\tcontext: QueryContext,\n\t): Promise<QueryObject<TResult>> {\n\t\tconst hooks = schema.hooks as LifecycleHooks<TResult> | undefined;\n\t\tif (!hooks) return query;\n\n\t\tconst { action } = context;\n\n\t\tif (\n\t\t\t(action === \"create\" || action === \"createMany\") &&\n\t\t\thooks.beforeCreate &&\n\t\t\tquery.type === \"insert\"\n\t\t) {\n\t\t\tconst modified = await hooks.beforeCreate(\n\t\t\t\tquery as QueryInsertObject<TResult>,\n\t\t\t\tcontext,\n\t\t\t);\n\t\t\tif (modified == null) throwHookInvalidReturn(\"beforeCreate\");\n\t\t\treturn modified as QueryObject<TResult>;\n\t\t}\n\n\t\tif (\n\t\t\t(action === \"update\" || action === \"updateMany\") &&\n\t\t\thooks.beforeUpdate &&\n\t\t\tquery.type === \"update\"\n\t\t) {\n\t\t\tconst modified = await hooks.beforeUpdate(\n\t\t\t\tquery as QueryUpdateObject<TResult>,\n\t\t\t\tcontext,\n\t\t\t);\n\t\t\tif (modified == null) throwHookInvalidReturn(\"beforeUpdate\");\n\t\t\treturn modified as QueryObject<TResult>;\n\t\t}\n\n\t\tif (\n\t\t\t(action === \"delete\" || action === \"deleteMany\") &&\n\t\t\thooks.beforeDelete &&\n\t\t\tquery.type === \"delete\"\n\t\t) {\n\t\t\tconst modified = await hooks.beforeDelete(\n\t\t\t\tquery as QueryDeleteObject<TResult>,\n\t\t\t\tcontext,\n\t\t\t);\n\t\t\tif (modified == null) throwHookInvalidReturn(\"beforeDelete\");\n\t\t\treturn modified as QueryObject<TResult>;\n\t\t}\n\n\t\tif (\n\t\t\t(action === \"findOne\" || action === \"findMany\" || action === \"count\") &&\n\t\t\thooks.beforeFind &&\n\t\t\tquery.type === \"select\"\n\t\t) {\n\t\t\tconst modified = await hooks.beforeFind(\n\t\t\t\tquery as QuerySelectObject<TResult>,\n\t\t\t\tcontext,\n\t\t\t);\n\t\t\tif (modified == null) throwHookInvalidReturn(\"beforeFind\");\n\t\t\treturn modified as QueryObject<TResult>;\n\t\t}\n\n\t\treturn query;\n\t}\n\n\tprivate async dispatchSchemaAfterHook<TResult extends DatrixEntry>(\n\t\tresult: TResult,\n\t\tschema: SchemaDefinition,\n\t\tcontext: QueryContext,\n\t): Promise<TResult> {\n\t\tconst hooks = schema.hooks;\n\t\tif (!hooks) return result;\n\n\t\tconst { action } = context;\n\t\tconst rows = result;\n\n\t\tif ((action === \"create\" || action === \"createMany\") && hooks.afterCreate) {\n\t\t\ttry {\n\t\t\t\treturn (await hooks.afterCreate(\n\t\t\t\t\trows as unknown as DatrixEntry[],\n\t\t\t\t\tcontext,\n\t\t\t\t)) as unknown as TResult;\n\t\t\t} catch (error) {\n\t\t\t\twarnAfterHookError(\"afterCreate\", error);\n\t\t\t}\n\t\t}\n\n\t\tif ((action === \"update\" || action === \"updateMany\") && hooks.afterUpdate) {\n\t\t\ttry {\n\t\t\t\treturn (await hooks.afterUpdate(\n\t\t\t\t\trows as unknown as DatrixEntry[],\n\t\t\t\t\tcontext,\n\t\t\t\t)) as unknown as TResult;\n\t\t\t} catch (error) {\n\t\t\t\twarnAfterHookError(\"afterUpdate\", error);\n\t\t\t}\n\t\t}\n\n\t\tif ((action === \"delete\" || action === \"deleteMany\") && hooks.afterDelete) {\n\t\t\ttry {\n\t\t\t\tawait hooks.afterDelete(rows as unknown as DatrixEntry[], context);\n\t\t\t} catch (error) {\n\t\t\t\twarnAfterHookError(\"afterDelete\", error);\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\n\t\tif ((action === \"findOne\" || action === \"findMany\") && hooks.afterFind) {\n\t\t\ttry {\n\t\t\t\treturn (await hooks.afterFind(\n\t\t\t\t\trows as unknown as DatrixEntry[],\n\t\t\t\t\tcontext,\n\t\t\t\t)) as unknown as TResult;\n\t\t\t} catch (error) {\n\t\t\t\twarnAfterHookError(\"afterFind\", error);\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n}\n\n/**\n * Create a new dispatcher\n */\nexport function createDispatcher(\n\tregistry: PluginRegistry,\n\tdatrix: Datrix,\n): Dispatcher {\n\treturn new Dispatcher(registry, datrix);\n}\n","/**\n * Plugin Interface\n *\n * This file defines the standard interface that ALL plugins must implement.\n * Plugins extend Datrix's core functionality with features like auth, upload, hooks, etc.\n */\n\nimport type {\n\tISchemaRegistry,\n\tSchemaDefinition,\n\tFieldDefinition,\n\tIndexDefinition,\n\tDatrixEntry,\n} from \"./schema\";\nimport type { DatabaseAdapter } from \"../adapter\";\nimport { QueryObject } from \"./query-builder\";\nimport { QueryContext } from \"./query-context\";\nimport { DatrixConfig } from \"./config\";\n\nexport type { SchemaDefinition } from \"./schema\";\n\n/**\n * Plugin context (provided during initialization)\n */\nexport interface PluginContext {\n\treadonly adapter: DatabaseAdapter;\n\treadonly schemas: ISchemaRegistry;\n\treadonly config: DatrixConfig;\n}\n\n/**\n * Plugin interface\n *\n * ALL plugins MUST implement this interface\n */\nexport interface DatrixPlugin<TOptions = Record<string, unknown>> {\n\t// Metadata\n\treadonly name: string;\n\treadonly version: string;\n\treadonly options: TOptions;\n\n\t// Lifecycle\n\tinit(context: PluginContext): Promise<void>;\n\tdestroy(): Promise<void>;\n\n\t// Schema hooks\n\tgetSchemas?(): Promise<SchemaDefinition[]>;\n\textendSchemas?(context: SchemaExtensionContext): Promise<SchemaExtension[]>;\n\n\t// Query hooks\n\tonSchemaLoad?(schemas: ISchemaRegistry): Promise<void>;\n\tonCreateQueryContext?(context: QueryContext): Promise<QueryContext>;\n\tonBeforeQuery?<T extends DatrixEntry>(\n\t\tquery: QueryObject<T>,\n\t\tcontext: QueryContext,\n\t): Promise<QueryObject<T>>;\n\tonAfterQuery?<TResult extends DatrixEntry>(\n\t\tresult: TResult,\n\t\tcontext: QueryContext,\n\t): Promise<TResult>;\n}\n\n/**\n * Base plugin error\n */\nexport class PluginError extends Error {\n\treadonly code: string;\n\treadonly pluginName: string | undefined;\n\treadonly details: unknown | undefined;\n\n\tconstructor(\n\t\tmessage: string,\n\t\toptions?: { code?: string; pluginName?: string; details?: unknown },\n\t) {\n\t\tsuper(message);\n\t\tthis.name = \"PluginError\";\n\t\tthis.code = options?.code ?? \"UNKNOWN\";\n\t\tthis.pluginName = options?.pluginName;\n\t\tthis.details = options?.details;\n\t}\n}\n\n/**\n * Type guard for DatrixPlugin\n */\nexport function isDatrixPlugin(value: unknown): value is DatrixPlugin {\n\tif (typeof value !== \"object\" || value === null) {\n\t\treturn false;\n\t}\n\n\tconst obj = value as Record<string, unknown>;\n\n\treturn (\n\t\t\"name\" in obj &&\n\t\t\"version\" in obj &&\n\t\t\"init\" in obj &&\n\t\t\"destroy\" in obj &&\n\t\ttypeof obj[\"name\"] === \"string\" &&\n\t\ttypeof obj[\"version\"] === \"string\" &&\n\t\ttypeof obj[\"init\"] === \"function\" &&\n\t\ttypeof obj[\"destroy\"] === \"function\"\n\t);\n}\n\n/**\n * Plugin factory type\n */\nexport type PluginFactory<TOptions = Record<string, unknown>> = (\n\toptions: TOptions,\n) => DatrixPlugin<TOptions>;\n\n/**\n * Upload error\n */\nexport class UploadError extends PluginError {\n\tconstructor(message: string, details?: unknown) {\n\t\tsuper(message, { code: \"UPLOAD_ERROR\", details });\n\t\tthis.name = \"UploadError\";\n\t}\n}\n\n/**\n * Plugin registry\n */\nexport class PluginRegistry {\n\tprivate readonly plugins: Map<string, DatrixPlugin> = new Map();\n\n\tregister(plugin: DatrixPlugin): void {\n\t\tif (this.plugins.has(plugin.name)) {\n\t\t\tthrow new PluginError(`Plugin already registered: ${plugin.name}`, {\n\t\t\t\tcode: \"DUPLICATE_PLUGIN\",\n\t\t\t});\n\t\t}\n\t\tthis.plugins.set(plugin.name, plugin);\n\t}\n\n\tget(name: string): DatrixPlugin | undefined {\n\t\treturn this.plugins.get(name);\n\t}\n\n\thas(name: string): boolean {\n\t\treturn this.plugins.has(name);\n\t}\n\n\tgetAll(): readonly DatrixPlugin[] {\n\t\treturn Array.from(this.plugins.values());\n\t}\n\n\tasync initAll(context: PluginContext): Promise<void> {\n\t\tfor (const plugin of this.plugins.values()) {\n\t\t\tawait plugin.init(context);\n\t\t}\n\t}\n\n\tasync destroyAll(): Promise<void> {\n\t\tfor (const plugin of this.plugins.values()) {\n\t\t\tawait plugin.destroy();\n\t\t}\n\t}\n}\n\n/**\n * Schema extension definition\n */\nexport interface SchemaExtension {\n\treadonly targetSchema: string;\n\treadonly fields?: Record<string, FieldDefinition>;\n\treadonly removeFields?: readonly string[];\n\treadonly modifyFields?: Record<string, Partial<FieldDefinition>>;\n\treadonly indexes?: readonly IndexDefinition[];\n}\n\n/**\n * Schema modifier function\n */\nexport type SchemaModifier = (schema: SchemaDefinition) => {\n\treadonly fields?: Record<string, FieldDefinition>;\n\treadonly indexes?: readonly IndexDefinition[];\n\treadonly removeFields?: readonly string[];\n\treadonly modifyFields?: Record<string, Partial<FieldDefinition>>;\n};\n\n/**\n * Schema pattern for filtering\n */\nexport interface SchemaPattern {\n\treadonly names?: readonly string[];\n\treadonly prefix?: string;\n\treadonly suffix?: string;\n\treadonly exclude?: readonly string[];\n\treadonly custom?: (schema: SchemaDefinition) => boolean;\n}\n\n/**\n * Schema extension context\n */\nexport interface SchemaExtensionContext {\n\treadonly schemas: ReadonlyArray<SchemaDefinition>;\n\n\textendAll(modifier: SchemaModifier): SchemaExtension[];\n\n\textendWhere(\n\t\tpredicate: (schema: SchemaDefinition) => boolean,\n\t\tmodifier: SchemaModifier,\n\t): SchemaExtension[];\n\n\textendByPattern(\n\t\tpattern: SchemaPattern,\n\t\tmodifier: SchemaModifier,\n\t): SchemaExtension[];\n}\n","/**\n * Core Constants\n *\n * Central location for all validation rules, limits, and operator definitions.\n * Used across parsers, query builders, and adapters.\n */\n\n/**\n * Maximum field/column name length\n * Based on PostgreSQL limit (most restrictive common database)\n */\nexport const MAX_FIELD_NAME_LENGTH = 63;\n\n/**\n * Maximum value length for WHERE clauses\n * Prevents DoS attacks with extremely large values\n */\nexport const MAX_WHERE_VALUE_LENGTH = 10000;\n\n/**\n * Maximum nesting depth for logical operators ($or, $and)\n * Prevents stack overflow attacks\n */\nexport const MAX_LOGICAL_NESTING_DEPTH = 10;\n\n/**\n * Maximum array index for indexed parameters (fields[N], populate[N])\n * Prevents DoS attacks with extremely large indices\n */\nexport const MAX_ARRAY_INDEX = 1000;\n\n/**\n * Comparison operators for WHERE clauses\n */\nexport const COMPARISON_OPERATORS = [\n\t\"$eq\", // Equal\n\t\"$ne\", // Not equal\n\t\"$gt\", // Greater than\n\t\"$gte\", // Greater than or equal\n\t\"$lt\", // Less than\n\t\"$lte\", // Less than or equal\n] as const;\n\n/**\n * String operators for WHERE clauses\n */\nexport const STRING_OPERATORS = [\n\t\"$contains\", // String contains\n\t\"$notContains\", // String does not contain\n\t\"$startsWith\", // String starts with\n\t\"$endsWith\", // String ends with\n\t\"$like\", // SQL LIKE pattern\n\t\"$ilike\", // Case-insensitive LIKE\n] as const;\n\n/**\n * Array membership operators for WHERE clauses\n */\nexport const ARRAY_OPERATORS = [\n\t\"$in\", // Value in array\n\t\"$nin\", // Value not in array\n] as const;\n\n/**\n * Null check operators for WHERE clauses\n */\nexport const NULL_OPERATORS = [\n\t\"$null\", // IS NULL\n\t\"$notNull\", // IS NOT NULL\n] as const;\n\n/**\n * Logical operators for WHERE clauses\n */\nexport const LOGICAL_OPERATORS = [\n\t\"$and\", // Logical AND\n\t\"$or\", // Logical OR\n\t\"$not\", // Logical NOT\n] as const;\n\n/**\n * All valid WHERE operators\n */\nexport const ALL_WHERE_OPERATORS = [\n\t...COMPARISON_OPERATORS,\n\t...STRING_OPERATORS,\n\t...ARRAY_OPERATORS,\n\t...NULL_OPERATORS,\n\t...LOGICAL_OPERATORS,\n] as const;\n\n/**\n * Type of operator value expectations\n */\nexport type OperatorValueType =\n\t| \"any\" // Any primitive value\n\t| \"array\" // Must be array\n\t| \"number\" // Must be number\n\t| \"string\" // Must be string\n\t| \"boolean\" // Must be boolean\n\t| \"conditions\"; // Array of WHERE conditions (for logical operators)\n\n/**\n * Operator validation rules\n * Defines what type of value each operator expects\n */\nexport const OPERATOR_VALUE_TYPES: Record<string, OperatorValueType> = {\n\t// Comparison operators - accept any value\n\t$eq: \"any\",\n\t$ne: \"any\",\n\t$gt: \"any\",\n\t$gte: \"any\",\n\t$lt: \"any\",\n\t$lte: \"any\",\n\n\t// String operators - must be string\n\t$contains: \"string\",\n\t$notContains: \"string\",\n\t$startsWith: \"string\",\n\t$endsWith: \"string\",\n\t$like: \"string\",\n\t$ilike: \"string\",\n\n\t// Array operators - must be array of values\n\t$in: \"array\",\n\t$nin: \"array\",\n\n\t// Null operators - boolean or no value needed\n\t$null: \"boolean\",\n\t$notNull: \"boolean\",\n\n\t// Logical operators - must be array of conditions\n\t$and: \"conditions\",\n\t$or: \"conditions\",\n\t$not: \"conditions\",\n} as const;\n\n/**\n * Check if a string is a valid WHERE operator\n */\nexport function isValidWhereOperator(\n\toperator: string,\n): operator is (typeof ALL_WHERE_OPERATORS)[number] {\n\treturn (ALL_WHERE_OPERATORS as readonly string[]).includes(operator);\n}\n\n/**\n * Check if an operator is a logical operator\n */\nexport function isLogicalOperator(\n\toperator: string,\n): operator is (typeof LOGICAL_OPERATORS)[number] {\n\treturn (LOGICAL_OPERATORS as readonly string[]).includes(operator);\n}\n\n/**\n * Check if an operator requires an array value\n */\nexport function requiresArrayValue(operator: string): boolean {\n\treturn OPERATOR_VALUE_TYPES[operator] === \"array\";\n}\n\n/**\n * Check if an operator requires conditions (for logical operators)\n */\nexport function requiresConditions(operator: string): boolean {\n\treturn OPERATOR_VALUE_TYPES[operator] === \"conditions\";\n}\n\n/**\n * Get expected value type for an operator\n */\nexport function getOperatorValueType(\n\toperator: string,\n): OperatorValueType | undefined {\n\treturn OPERATOR_VALUE_TYPES[operator];\n}\n\n/**\n * Internal metadata table name used by all adapters to store schema snapshots\n */\nexport const FORJA_META_MODEL = \"_datrix\";\n\n/**\n * Key prefix for schema entries stored in the _datrix metadata table\n */\nexport const FORJA_META_KEY_PREFIX = \"_schema_\";\n\n/**\n * Field name validation pattern\n * Must start with letter or underscore, contain only alphanumeric, underscores, and dots\n */\nexport const FIELD_NAME_PATTERN = /^[a-zA-Z_][a-zA-Z0-9_.]*$/;\n\n/**\n * Control characters pattern (dangerous in all contexts)\n */\nexport const CONTROL_CHARS_PATTERN = /[\\x00-\\x1F\\x7F]/;\n\n/**\n * Reserved field names (prototype pollution protection)\n */\nexport const RESERVED_FIELD_NAMES = [\n\t\"__proto__\",\n\t\"constructor\",\n\t\"prototype\",\n] as const;\n\n/**\n * Field validation failure reasons\n */\nexport type FieldInvalidReason =\n\t| \"EMPTY\"\n\t| \"TOO_LONG\"\n\t| \"RESERVED_FIELD\"\n\t| \"CONTROL_CHARS\"\n\t| \"INVALID_FORMAT\";\n\n/**\n * Field validation result with detailed reason\n */\nexport type FieldValidationResult =\n\t| { valid: true }\n\t| { valid: false; reason: FieldInvalidReason; detail?: string };\n\n/**\n * Validate field name with detailed reason on failure\n *\n * @param fieldName - Field name to validate\n * @returns Validation result with reason if invalid\n */\nexport function validateFieldName(fieldName: string): FieldValidationResult {\n\t// Empty or whitespace-only\n\tif (!fieldName || fieldName.trim() === \"\") {\n\t\treturn { valid: false, reason: \"EMPTY\" };\n\t}\n\n\t// Length check\n\tif (fieldName.length > MAX_FIELD_NAME_LENGTH) {\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\treason: \"TOO_LONG\",\n\t\t\tdetail: `Max ${MAX_FIELD_NAME_LENGTH} characters`,\n\t\t};\n\t}\n\n\t// Reserved fields check (prototype pollution protection)\n\tif (\n\t\tRESERVED_FIELD_NAMES.includes(\n\t\t\tfieldName as (typeof RESERVED_FIELD_NAMES)[number],\n\t\t)\n\t) {\n\t\treturn { valid: false, reason: \"RESERVED_FIELD\", detail: fieldName };\n\t}\n\n\t// Control characters check\n\tif (CONTROL_CHARS_PATTERN.test(fieldName)) {\n\t\treturn { valid: false, reason: \"CONTROL_CHARS\" };\n\t}\n\n\t// Format check\n\tif (!FIELD_NAME_PATTERN.test(fieldName)) {\n\t\treturn { valid: false, reason: \"INVALID_FORMAT\" };\n\t}\n\n\treturn { valid: true };\n}\n\n/**\n * Validate field name against universal rules (simple boolean)\n *\n * @param fieldName - Field name to validate\n * @returns True if valid, false otherwise\n */\nexport function isValidFieldName(fieldName: string): boolean {\n\treturn validateFieldName(fieldName).valid;\n}\n","/**\n * Schema Registry Implementation\n *\n * Manages schema registration, retrieval, and validation.\n * Central store for all schemas in the application.\n */\n\nimport type {\n\tFieldDefinition,\n\tFileField,\n\tFileFieldOptions,\n\tDatrixEntry,\n\tISchemaRegistry,\n\tRelationField,\n\tSchemaDefinition,\n\tSchemaValidationError,\n} from \"../types/core/schema\";\nimport {\n\tvalidateSchemaDefinition,\n\tsortSchemasByDependency,\n\tRESERVED_FIELDS,\n} from \"../types/core/schema\";\nimport { FORJA_META_MODEL } from \"../types/core/constants\";\nimport { QuerySelect } from \"../types/core/query-builder\";\n\n/**\n * Schema registry error\n */\nexport class SchemaRegistryError extends Error {\n\treadonly code: string;\n\treadonly schemaName: string | undefined;\n\treadonly details: unknown | undefined;\n\n\tconstructor(\n\t\tmessage: string,\n\t\toptions?: {\n\t\t\tcode?: string;\n\t\t\tschemaName?: string;\n\t\t\tdetails?: unknown;\n\t\t},\n\t) {\n\t\tsuper(message);\n\t\tthis.name = \"SchemaRegistryError\";\n\t\tthis.code = options?.code ?? \"UNKNOWN\";\n\t\tthis.schemaName = options?.schemaName;\n\t\tthis.details = options?.details;\n\t}\n}\n\n/**\n * Schema registry configuration\n */\nexport interface SchemaRegistryConfig {\n\treadonly strict: boolean | undefined;\n\treadonly allowOverwrite: boolean | undefined;\n\treadonly validateRelations: boolean | undefined;\n}\n\n/**\n * Performance cache for expensive operations\n */\ninterface RegistryCache {\n\trelatedSchemas: Map<string, readonly string[]>;\n\treferencingSchemas: Map<string, readonly string[]>;\n\tfieldTypeIndex: Map<string, readonly SchemaDefinition[]>;\n\tselectFields: Map<string, readonly string[]>;\n}\n\n/**\n * Schema registry implementation\n */\nexport class SchemaRegistry implements ISchemaRegistry {\n\tprivate readonly schemas: Map<string, SchemaDefinition> = new Map();\n\tprivate readonly config: Required<SchemaRegistryConfig>;\n\tprivate locked = false;\n\tprivate cache: RegistryCache = {\n\t\trelatedSchemas: new Map(),\n\t\treferencingSchemas: new Map(),\n\t\tfieldTypeIndex: new Map(),\n\t\tselectFields: new Map(),\n\t};\n\n\tconstructor(config?: SchemaRegistryConfig) {\n\t\tthis.config = {\n\t\t\tstrict: config?.strict ?? true,\n\t\t\tallowOverwrite: config?.allowOverwrite ?? false,\n\t\t\tvalidateRelations: config?.validateRelations ?? true,\n\t\t};\n\t}\n\n\t/**\n\t * Invalidate performance cache\n\t */\n\tprivate invalidateCache(): void {\n\t\tthis.cache.relatedSchemas.clear();\n\t\tthis.cache.referencingSchemas.clear();\n\t\tthis.cache.fieldTypeIndex.clear();\n\t\tthis.cache.selectFields.clear();\n\t}\n\n\t/**\n\t * Register a schema\n\t * Adds reserved fields (id, createdAt, updatedAt)\n\t * Does NOT process relations - call finalizeRegistry() after all schemas are registered\n\t */\n\tregister(schema: SchemaDefinition): SchemaDefinition {\n\t\tif (this.locked) {\n\t\t\tthrow new SchemaRegistryError(\"Registry is locked\", {\n\t\t\t\tcode: \"REGISTRY_LOCKED\",\n\t\t\t});\n\t\t}\n\n\t\tif (!schema.name || schema.name.trim() === \"\") {\n\t\t\tthrow new SchemaRegistryError(\"Schema name is required\", {\n\t\t\t\tcode: \"INVALID_SCHEMA_NAME\",\n\t\t\t});\n\t\t}\n\n\t\tif (this.schemas.has(schema.name) && !this.config.allowOverwrite) {\n\t\t\tthrow new SchemaRegistryError(\n\t\t\t\t`Schema already registered: ${schema.name}`,\n\t\t\t\t{\n\t\t\t\t\tcode: \"DUPLICATE_SCHEMA\",\n\t\t\t\t\tschemaName: schema.name,\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\n\t\tfor (const reservedField of RESERVED_FIELDS) {\n\t\t\tif (reservedField in schema.fields) {\n\t\t\t\tthrow new SchemaRegistryError(\n\t\t\t\t\t`Field '${reservedField}' is reserved and cannot be defined manually in schema '${schema.name}'`,\n\t\t\t\t\t{\n\t\t\t\t\t\tcode: \"RESERVED_FIELD_NAME\",\n\t\t\t\t\t\tschemaName: schema.name,\n\t\t\t\t\t\tdetails: { field: reservedField },\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tif (this.config.strict) {\n\t\t\tconst validation = validateSchemaDefinition(schema);\n\t\t\tif (!validation.valid) {\n\t\t\t\tthrow new SchemaRegistryError(\n\t\t\t\t\t`Schema validation failed: ${schema.name}`,\n\t\t\t\t\t{\n\t\t\t\t\t\tcode: \"VALIDATION_FAILED\",\n\t\t\t\t\t\tschemaName: schema.name,\n\t\t\t\t\t\tdetails: validation.errors,\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tconst transformedFields = this.transformFileFields(schema.fields);\n\n\t\tconst enhancedFields = {\n\t\t\tid: {\n\t\t\t\ttype: \"number\" as const,\n\t\t\t\tprimary: true,\n\t\t\t\tautoIncrement: true,\n\t\t\t\trequired: true,\n\t\t\t},\n\t\t\t...transformedFields,\n\t\t\tcreatedAt: {\n\t\t\t\ttype: \"date\" as const,\n\t\t\t\trequired: true,\n\t\t\t},\n\t\t\tupdatedAt: {\n\t\t\t\ttype: \"date\" as const,\n\t\t\t\trequired: true,\n\t\t\t},\n\t\t};\n\n\t\tconst storedSchema = {\n\t\t\t...schema,\n\t\t\ttableName: schema.tableName ?? this.pluralize(schema.name.toLowerCase()),\n\t\t\tfields: enhancedFields,\n\t\t};\n\n\t\tthis.schemas.set(schema.name, storedSchema);\n\t\tthis.invalidateCache();\n\n\t\treturn storedSchema;\n\t}\n\n\t/**\n\t * Register multiple schemas\n\t * Call finalizeRegistry() after all schemas are registered to process relations\n\t */\n\tregisterMany(schemas: readonly SchemaDefinition[]): void {\n\t\tfor (const schema of schemas) {\n\t\t\tthis.register(schema);\n\t\t}\n\t}\n\n\t/**\n\t * Finalize registry after all schemas are registered\n\t * Processes relations and creates junction tables\n\t * Call this after:\n\t * 1. User schemas registered\n\t * 2. Plugin schemas registered\n\t * 3. Plugin schema extensions applied\n\t */\n\tfinalizeRegistry(): void {\n\t\tthis.processRelations();\n\n\t\tif (this.config.validateRelations) {\n\t\t\tthis.validateRelations();\n\t\t}\n\n\t\tthis.sortByDependencies();\n\t}\n\n\t/**\n\t * Topological sort schemas by FK dependencies.\n\t * Schemas that are referenced by others come first.\n\t * Rebuilds the internal Map in dependency order.\n\t */\n\tprivate sortByDependencies(): void {\n\t\tconst allSchemas = Array.from(this.schemas.values());\n\t\tconst sorted = sortSchemasByDependency(allSchemas);\n\n\t\t// Rebuild Map in sorted order, _datrix always first\n\t\tconst entries = new Map<string, SchemaDefinition>();\n\n\t\tconst metaSchema = this.schemas.get(FORJA_META_MODEL);\n\t\tif (metaSchema) {\n\t\t\tentries.set(FORJA_META_MODEL, metaSchema);\n\t\t}\n\n\t\tfor (const schema of sorted) {\n\t\t\tif (schema.name === FORJA_META_MODEL) continue;\n\t\t\tentries.set(schema.name, schema);\n\t\t}\n\n\t\tthis.schemas.clear();\n\t\tfor (const [name, schema] of entries) {\n\t\t\tthis.schemas.set(name, schema);\n\t\t}\n\t}\n\n\t/**\n\t * Get schema by name\n\t */\n\tget(name: string): SchemaDefinition | undefined {\n\t\treturn this.schemas.get(name);\n\t}\n\n\t/**\n\t * Get schema by model name with resolved table name\n\t */\n\tgetWithTableName(\n\t\tmodelName: string,\n\t): { schema: SchemaDefinition; tableName: string } | undefined {\n\t\tconst schema = this.get(modelName);\n\t\tif (!schema) return undefined;\n\t\treturn {\n\t\t\tschema,\n\t\t\ttableName: schema.tableName ?? this.pluralize(modelName.toLowerCase()),\n\t\t};\n\t}\n\n\t/**\n\t * Get schema by table name\n\t */\n\tgetByTableName(\n\t\ttableName: string,\n\t): { schema: SchemaDefinition; tableName: string } | undefined {\n\t\tconst modelName = this.findModelByTableName(tableName);\n\t\tif (!modelName) return undefined;\n\t\treturn this.getWithTableName(modelName);\n\t}\n\n\t/**\n\t * Check if schema exists\n\t */\n\thas(name: string): boolean {\n\t\treturn this.schemas.has(name);\n\t}\n\n\t/**\n\t * Get all schemas\n\t */\n\tgetAll(): readonly SchemaDefinition[] {\n\t\treturn Array.from(this.schemas.values());\n\t}\n\n\t/**\n\t * Get schema names\n\t */\n\tgetNames(): readonly string[] {\n\t\treturn Array.from(this.schemas.keys());\n\t}\n\n\t/**\n\t * Get schema count\n\t */\n\tget size(): number {\n\t\treturn this.schemas.size;\n\t}\n\n\t/**\n\t * Find model name by table name\n\t */\n\tfindModelByTableName(tableName: string | null): string | null {\n\t\tif (!tableName) return null;\n\t\tfor (const [modelName, schema] of this.schemas.entries()) {\n\t\t\tconst schemaTableName =\n\t\t\t\tschema.tableName ?? this.pluralize(modelName.toLowerCase());\n\t\t\tif (schemaTableName === tableName) {\n\t\t\t\treturn modelName;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * Get schemas with relations\n\t */\n\tgetSchemasWithRelations(): readonly SchemaDefinition[] {\n\t\treturn this.getAll().filter((schema) =>\n\t\t\tObject.values(schema.fields).some((field) => field.type === \"relation\"),\n\t\t);\n\t}\n\n\t/**\n\t * Get related schemas for a given schema (cached)\n\t */\n\tgetRelatedSchemas(schemaName: string): readonly string[] {\n\t\tconst cached = this.cache.relatedSchemas.get(schemaName);\n\t\tif (cached) return cached;\n\n\t\tconst schema = this.get(schemaName);\n\t\tif (!schema) return [];\n\n\t\tconst related: string[] = [];\n\t\tfor (const field of Object.values(schema.fields)) {\n\t\t\tif (field.type === \"relation\") {\n\t\t\t\tconst relationField = field as RelationField;\n\t\t\t\tif (!related.includes(relationField.model)) {\n\t\t\t\t\trelated.push(relationField.model);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tthis.cache.relatedSchemas.set(schemaName, related);\n\t\treturn related;\n\t}\n\n\t/**\n\t * Get schemas that reference a given schema (cached)\n\t */\n\tgetReferencingSchemas(schemaName: string): readonly string[] {\n\t\tconst cached = this.cache.referencingSchemas.get(schemaName);\n\t\tif (cached) return cached;\n\n\t\tconst referencing: string[] = [];\n\t\tfor (const [name, schema] of this.schemas.entries()) {\n\t\t\tfor (const field of Object.values(schema.fields)) {\n\t\t\t\tif (field.type === \"relation\") {\n\t\t\t\t\tconst relationField = field as RelationField;\n\t\t\t\t\tif (relationField.model === schemaName) {\n\t\t\t\t\t\treferencing.push(name);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tthis.cache.referencingSchemas.set(schemaName, referencing);\n\t\treturn referencing;\n\t}\n\n\t/**\n\t * Find schemas by field type (cached)\n\t */\n\tfindByFieldType(fieldType: string): readonly SchemaDefinition[] {\n\t\tconst cached = this.cache.fieldTypeIndex.get(fieldType);\n\t\tif (cached) return cached;\n\n\t\tconst result = this.getAll().filter((schema) =>\n\t\t\tObject.values(schema.fields).some((field) => field.type === fieldType),\n\t\t);\n\n\t\tthis.cache.fieldTypeIndex.set(fieldType, result);\n\t\treturn result;\n\t}\n\n\t/**\n\t * Get cached SELECT fields for a model (wildcard \"*\" expansion)\n\t *\n\t * Returns all selectable fields for a model, excluding:\n\t * - Hidden fields (e.g., foreign keys)\n\t * - Relation fields (use populate for these)\n\t */\n\tgetCachedSelectFields<T extends DatrixEntry>(\n\t\tmodelName: string,\n\t): QuerySelect<T> {\n\t\tconst schema = this.get(modelName);\n\t\tif (!schema) {\n\t\t\tthrow new SchemaRegistryError(`Schema not found: ${modelName}`, {\n\t\t\t\tcode: \"SCHEMA_NOT_FOUND\",\n\t\t\t});\n\t\t}\n\n\t\tconst cached = this.cache.selectFields.get(modelName);\n\t\tif (cached) return cached as QuerySelect<T>;\n\n\t\tconst cleanFields: string[] = [];\n\t\tfor (const [fieldName, fieldDef] of Object.entries(schema.fields)) {\n\t\t\tif ((fieldDef as { hidden?: boolean }).hidden) continue;\n\t\t\tif (fieldDef.type === \"relation\") continue;\n\t\t\tcleanFields.push(fieldName);\n\t\t}\n\n\t\tthis.cache.selectFields.set(modelName, cleanFields);\n\t\treturn cleanFields as QuerySelect<T>;\n\t}\n\n\t/**\n\t * Validate all relations\n\t */\n\tvalidateRelations(): void {\n\t\tconst errors: SchemaValidationError[] = [];\n\n\t\tfor (const [, schema] of this.schemas.entries()) {\n\t\t\tfor (const [fieldName, field] of Object.entries(schema.fields)) {\n\t\t\t\tif (field.type === \"relation\") {\n\t\t\t\t\tconst relationField = field as RelationField;\n\t\t\t\t\tif (!this.has(relationField.model)) {\n\t\t\t\t\t\terrors.push({\n\t\t\t\t\t\t\tfield: fieldName,\n\t\t\t\t\t\t\tmessage: `Relation target not found: ${relationField.model}`,\n\t\t\t\t\t\t\tcode: \"INVALID_RELATION_TARGET\",\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (errors.length > 0) {\n\t\t\tthrow new SchemaRegistryError(\"Relation validation failed\", {\n\t\t\t\tcode: \"INVALID_RELATIONS\",\n\t\t\t\tdetails: errors,\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * Clear all schemas\n\t */\n\tclear(): void {\n\t\tif (this.locked) {\n\t\t\tthrow new SchemaRegistryError(\"Cannot clear locked registry\", {\n\t\t\t\tcode: \"REGISTRY_LOCKED\",\n\t\t\t});\n\t\t}\n\t\tthis.schemas.clear();\n\t\tthis.invalidateCache();\n\t}\n\n\t/**\n\t * Remove schema by name\n\t */\n\tremove(name: string): boolean {\n\t\tif (this.locked) {\n\t\t\tthrow new SchemaRegistryError(\"Cannot remove from locked registry\", {\n\t\t\t\tcode: \"REGISTRY_LOCKED\",\n\t\t\t});\n\t\t}\n\n\t\tconst removed = this.schemas.delete(name);\n\t\tif (removed) {\n\t\t\tthis.invalidateCache();\n\t\t}\n\t\treturn removed;\n\t}\n\n\t/**\n\t * Lock registry (prevent modifications)\n\t */\n\tlock(): void {\n\t\tthis.locked = true;\n\t}\n\n\t/**\n\t * Unlock registry\n\t */\n\tunlock(): void {\n\t\tthis.locked = false;\n\t}\n\n\t/**\n\t * Check if registry is locked\n\t */\n\tisLocked(): boolean {\n\t\treturn this.locked;\n\t}\n\n\t/**\n\t * Transform file fields into relation fields (Pass 0)\n\t * Called during register() before reserved fields are added.\n\t *\n\t * FileField { type: \"file\", multiple: false } → RelationField { kind: \"belongsTo\", model: \"media\", fileOptions: {...} }\n\t * FileField { type: \"file\", multiple: true } → RelationField { kind: \"hasMany\", model: \"media\", fileOptions: {...} }\n\t *\n\t * Upload config is NOT required here — that check is in ApiPlugin.\n\t * Core only transforms the type so adapters/migrations see a plain relation.\n\t */\n\tprivate transformFileFields(\n\t\tfields: Record<string, FieldDefinition>,\n\t): Record<string, FieldDefinition> {\n\t\tconst result: Record<string, FieldDefinition> = {};\n\n\t\tfor (const [fieldName, field] of Object.entries(fields)) {\n\t\t\tif (field.type !== \"file\") {\n\t\t\t\tresult[fieldName] = field;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst fileField = field as FileField;\n\n\t\t\tconst fileOptions: FileFieldOptions = {\n\t\t\t\t...(fileField.allowedTypes !== undefined && {\n\t\t\t\t\tallowedTypes: fileField.allowedTypes,\n\t\t\t\t}),\n\t\t\t\t...(fileField.maxSize !== undefined && {\n\t\t\t\t\tmaxSize: fileField.maxSize,\n\t\t\t\t}),\n\t\t\t};\n\n\t\t\tconst hasFileOptions = Object.keys(fileOptions).length > 0;\n\n\t\t\tconst relationField: RelationField = {\n\t\t\t\ttype: \"relation\",\n\t\t\t\tmodel: \"media\",\n\t\t\t\tkind: fileField.multiple ? \"hasMany\" : \"belongsTo\",\n\t\t\t\t...(fileField.required !== undefined && {\n\t\t\t\t\trequired: fileField.required,\n\t\t\t\t}),\n\t\t\t\t...(hasFileOptions && { fileOptions }),\n\t\t\t};\n\n\t\t\tresult[fieldName] = relationField;\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Process relations (Pass 2)\n\t * Add foreign keys for belongsTo/hasOne/hasMany\n\t * Create junction tables for manyToMany\n\t */\n\tprivate processRelations(): void {\n\t\tfor (const [schemaName, schema] of this.schemas.entries()) {\n\t\t\tconst enhancedFields = { ...schema.fields };\n\n\t\t\tfor (const [fieldName, field] of Object.entries(schema.fields)) {\n\t\t\t\tif (field.type !== \"relation\") continue;\n\n\t\t\t\tconst relation = field as RelationField;\n\t\t\t\tconst targetSchema = this.schemas.get(relation.model);\n\n\t\t\t\tif (!targetSchema) {\n\t\t\t\t\tthrow new SchemaRegistryError(\n\t\t\t\t\t\t`Relation target not found: ${relation.model} in schema ${schemaName}.${fieldName}`,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcode: \"INVALID_RELATION_TARGET\",\n\t\t\t\t\t\t\tschemaName,\n\t\t\t\t\t\t\tdetails: { field: fieldName, target: relation.model },\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tif (relation.kind === \"belongsTo\") {\n\t\t\t\t\tconst foreignKey = relation.foreignKey ?? `${fieldName}Id`;\n\n\t\t\t\t\tif (!(foreignKey in enhancedFields)) {\n\t\t\t\t\t\tconst targetTableName =\n\t\t\t\t\t\t\ttargetSchema.tableName ??\n\t\t\t\t\t\t\tthis.pluralize(relation.model.toLowerCase());\n\t\t\t\t\t\tconst isRequired = relation.required ?? false;\n\t\t\t\t\t\tconst defaultOnDelete = isRequired ? \"cascade\" : \"setNull\";\n\t\t\t\t\t\tenhancedFields[foreignKey] = {\n\t\t\t\t\t\t\ttype: \"number\",\n\t\t\t\t\t\t\trequired: isRequired,\n\t\t\t\t\t\t\thidden: true,\n\t\t\t\t\t\t\treferences: {\n\t\t\t\t\t\t\t\ttable: targetTableName,\n\t\t\t\t\t\t\t\tcolumn: \"id\",\n\t\t\t\t\t\t\t\tonDelete: relation.onDelete ?? defaultOnDelete,\n\t\t\t\t\t\t\t\tonUpdate: relation.onUpdate,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\n\t\t\t\t\tenhancedFields[fieldName] = {\n\t\t\t\t\t\t...relation,\n\t\t\t\t\t\tforeignKey,\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tif (relation.kind === \"hasOne\" || relation.kind === \"hasMany\") {\n\t\t\t\t\tconst foreignKey = relation.foreignKey ?? `${schemaName}Id`;\n\t\t\t\t\tconst targetFields = { ...targetSchema.fields };\n\n\t\t\t\t\tif (!(foreignKey in targetFields)) {\n\t\t\t\t\t\tconst sourceTableName =\n\t\t\t\t\t\t\tschema.tableName ?? this.pluralize(schemaName.toLowerCase());\n\t\t\t\t\t\ttargetFields[foreignKey] = {\n\t\t\t\t\t\t\ttype: \"number\",\n\t\t\t\t\t\t\trequired: false,\n\t\t\t\t\t\t\thidden: true,\n\t\t\t\t\t\t\treferences: {\n\t\t\t\t\t\t\t\ttable: sourceTableName,\n\t\t\t\t\t\t\t\tcolumn: \"id\",\n\t\t\t\t\t\t\t\tonDelete: relation.onDelete ?? \"setNull\",\n\t\t\t\t\t\t\t\tonUpdate: relation.onUpdate,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\n\t\t\t\t\tthis.schemas.set(relation.model, {\n\t\t\t\t\t\t...targetSchema,\n\t\t\t\t\t\tfields: targetFields,\n\t\t\t\t\t});\n\n\t\t\t\t\tenhancedFields[fieldName] = {\n\t\t\t\t\t\t...relation,\n\t\t\t\t\t\tforeignKey,\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tif (relation.kind === \"manyToMany\") {\n\t\t\t\t\tconst junctionTableName =\n\t\t\t\t\t\trelation.through ??\n\t\t\t\t\t\tthis.getJunctionTableName(schemaName, relation.model);\n\n\t\t\t\t\tthis.createJunctionTable(schemaName, relation, junctionTableName);\n\n\t\t\t\t\tenhancedFields[fieldName] = {\n\t\t\t\t\t\t...relation,\n\t\t\t\t\t\tthrough: junctionTableName,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.schemas.set(schemaName, {\n\t\t\t\t...schema,\n\t\t\t\tfields: enhancedFields,\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * Create junction table for manyToMany relation\n\t */\n\tprivate createJunctionTable(\n\t\tschemaName: string,\n\t\trelation: RelationField,\n\t\tjunctionTableName: string,\n\t): void {\n\t\tif (this.schemas.has(junctionTableName)) return;\n\n\t\tconst sourceFk = `${schemaName}Id`;\n\t\tconst targetFk = `${relation.model}Id`;\n\n\t\tconst junctionSchema: SchemaDefinition = {\n\t\t\tname: junctionTableName,\n\t\t\ttableName: junctionTableName,\n\t\t\tfields: {\n\t\t\t\tid: { type: \"number\", required: false, autoIncrement: true },\n\t\t\t\t[schemaName]: {\n\t\t\t\t\ttype: \"relation\",\n\t\t\t\t\tkind: \"belongsTo\",\n\t\t\t\t\tmodel: schemaName,\n\t\t\t\t\tforeignKey: sourceFk,\n\t\t\t\t\trequired: true,\n\t\t\t\t} as RelationField,\n\t\t\t\t[relation.model]: {\n\t\t\t\t\ttype: \"relation\",\n\t\t\t\t\tkind: \"belongsTo\",\n\t\t\t\t\tmodel: relation.model,\n\t\t\t\t\tforeignKey: targetFk,\n\t\t\t\t\trequired: true,\n\t\t\t\t} as RelationField,\n\t\t\t\t[sourceFk]: {\n\t\t\t\t\ttype: \"number\",\n\t\t\t\t\trequired: true,\n\t\t\t\t\thidden: true,\n\t\t\t\t\treferences: {\n\t\t\t\t\t\ttable: this.pluralize(schemaName.toLowerCase()),\n\t\t\t\t\t\tcolumn: \"id\",\n\t\t\t\t\t\tonDelete: \"cascade\" as const,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t[targetFk]: {\n\t\t\t\t\ttype: \"number\",\n\t\t\t\t\trequired: true,\n\t\t\t\t\thidden: true,\n\t\t\t\t\treferences: {\n\t\t\t\t\t\ttable: this.pluralize(relation.model.toLowerCase()),\n\t\t\t\t\t\tcolumn: \"id\",\n\t\t\t\t\t\tonDelete: \"cascade\" as const,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tindexes: [\n\t\t\t\t{\n\t\t\t\t\tfields: [sourceFk, targetFk],\n\t\t\t\t\tunique: true,\n\t\t\t\t},\n\t\t\t],\n\t\t\t_isJunctionTable: true,\n\t\t};\n\n\t\tthis.schemas.set(junctionTableName, junctionSchema);\n\t}\n\n\t/**\n\t * Get junction table name for manyToMany relation\n\t * Alphabetically sorted for consistency\n\t */\n\tprivate getJunctionTableName(schema1: string, schema2: string): string {\n\t\tconst sorted = [schema1, schema2].sort();\n\t\treturn `${sorted[0]}_${sorted[1]}`;\n\t}\n\n\t/**\n\t * Enhanced pluralization with common English rules\n\t */\n\tprivate pluralize(word: string): string {\n\t\tconst irregulars: Record<string, string> = {\n\t\t\tperson: \"people\",\n\t\t\tchild: \"children\",\n\t\t\tman: \"men\",\n\t\t\twoman: \"women\",\n\t\t\ttooth: \"teeth\",\n\t\t\tfoot: \"feet\",\n\t\t\tmouse: \"mice\",\n\t\t\tgoose: \"geese\",\n\t\t\tox: \"oxen\",\n\t\t\tdatum: \"data\",\n\t\t\tindex: \"indices\",\n\t\t\tvertex: \"vertices\",\n\t\t\tmatrix: \"matrices\",\n\t\t\tstatus: \"statuses\",\n\t\t\tquiz: \"quizzes\",\n\t\t};\n\n\t\tconst lower = word.toLowerCase();\n\t\tconst irregular = irregulars[lower];\n\t\tif (irregular) {\n\t\t\tconst firstChar = word.charAt(0);\n\t\t\treturn firstChar === firstChar.toUpperCase()\n\t\t\t\t? irregular.charAt(0).toUpperCase() + irregular.slice(1)\n\t\t\t\t: irregular;\n\t\t}\n\n\t\tif (\n\t\t\tword.endsWith(\"ss\") ||\n\t\t\tlower === \"data\" ||\n\t\t\tlower === \"information\" ||\n\t\t\tlower === \"equipment\"\n\t\t) {\n\t\t\treturn word;\n\t\t}\n\n\t\tif (word.endsWith(\"y\") && word.length > 1) {\n\t\t\tconst beforeY = word[word.length - 2];\n\t\t\tif (beforeY && !\"aeiou\".includes(beforeY.toLowerCase())) {\n\t\t\t\treturn word.slice(0, -1) + \"ies\";\n\t\t\t}\n\t\t}\n\n\t\tif (word.endsWith(\"f\")) {\n\t\t\treturn word.slice(0, -1) + \"ves\";\n\t\t}\n\t\tif (word.endsWith(\"fe\")) {\n\t\t\treturn word.slice(0, -2) + \"ves\";\n\t\t}\n\n\t\tif (word.endsWith(\"o\") && word.length > 1) {\n\t\t\tconst beforeO = word[word.length - 2];\n\t\t\tif (beforeO && !\"aeiou\".includes(beforeO.toLowerCase())) {\n\t\t\t\treturn word + \"es\";\n\t\t\t}\n\t\t}\n\n\t\tif (\n\t\t\tword.endsWith(\"ch\") ||\n\t\t\tword.endsWith(\"sh\") ||\n\t\t\tword.endsWith(\"s\") ||\n\t\t\tword.endsWith(\"ss\") ||\n\t\t\tword.endsWith(\"x\") ||\n\t\t\tword.endsWith(\"z\")\n\t\t) {\n\t\t\treturn word + \"es\";\n\t\t}\n\n\t\treturn word + \"s\";\n\t}\n\n\t/**\n\t * Export schemas as JSON\n\t */\n\ttoJSON(): Record<string, SchemaDefinition> {\n\t\tconst autoFields = new Set([\"id\", \"createdAt\", \"updatedAt\"]);\n\t\tconst result: Record<string, SchemaDefinition> = {};\n\n\t\tfor (const [name, schema] of this.schemas) {\n\t\t\tconst fields: Record<string, unknown> = {};\n\t\t\tfor (const [fieldName, fieldDef] of Object.entries(schema.fields)) {\n\t\t\t\tif (autoFields.has(fieldName)) continue;\n\t\t\t\tfields[fieldName] = fieldDef;\n\t\t\t}\n\t\t\tresult[name] = { ...schema, fields } as SchemaDefinition;\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Import schemas from JSON\n\t */\n\tfromJSON(data: Record<string, SchemaDefinition>): void {\n\t\tconst schemas = Object.values(data);\n\t\tthis.registerMany(schemas);\n\t}\n}\n\n/**\n * Global schema registry instance\n */\nlet globalRegistry: SchemaRegistry | undefined;\n\n/**\n * Get global registry instance\n */\nexport function getGlobalRegistry(): SchemaRegistry {\n\tif (!globalRegistry) {\n\t\tglobalRegistry = new SchemaRegistry();\n\t}\n\treturn globalRegistry;\n}\n\n/**\n * Set global registry instance\n */\nexport function setGlobalRegistry(registry: SchemaRegistry): void {\n\tglobalRegistry = registry;\n}\n\n/**\n * Reset global registry\n */\nexport function resetGlobalRegistry(): void {\n\tglobalRegistry = undefined;\n}\n","/**\n * Migration History Schema Definition\n *\n * Internal schema for tracking applied migrations.\n * This schema is automatically registered by Datrix during initialization.\n */\n\nimport { defineSchema } from \"../types/core/schema\";\nimport { FORJA_META_MODEL } from \"../types/core/constants\";\nexport { FORJA_META_MODEL };\n\n/**\n * Default model name for migration history\n */\nexport const DEFAULT_MIGRATION_MODEL = \"_datrix_migration\";\n\n/**\n * Get migration history schema definition\n *\n * @param modelName - Custom model name (default: '_datrix_migration')\n * @returns Schema definition for migration history table\n */\nexport function getMigrationSchema(\n\tmodelName: string = DEFAULT_MIGRATION_MODEL,\n) {\n\treturn defineSchema({\n\t\tname: modelName,\n\n\t\tfields: {\n\t\t\tname: {\n\t\t\t\ttype: \"string\",\n\t\t\t\trequired: true,\n\t\t\t\tmaxLength: 255,\n\t\t\t\tdescription: \"Migration name\",\n\t\t\t},\n\t\t\tversion: {\n\t\t\t\ttype: \"string\",\n\t\t\t\trequired: true,\n\t\t\t\tunique: true,\n\t\t\t\tmaxLength: 255,\n\t\t\t\tdescription: \"Migration version (timestamp-based)\",\n\t\t\t},\n\t\t\texecutionTime: {\n\t\t\t\ttype: \"number\",\n\t\t\t\trequired: true,\n\t\t\t\tmin: 0,\n\t\t\t\tdescription: \"Execution time in milliseconds\",\n\t\t\t},\n\t\t\tstatus: {\n\t\t\t\ttype: \"enum\",\n\t\t\t\trequired: true,\n\t\t\t\tvalues: [\"pending\", \"completed\", \"failed\", \"rolled_back\"] as const,\n\t\t\t\tdescription: \"Migration execution status\",\n\t\t\t},\n\t\t\tchecksum: {\n\t\t\t\ttype: \"string\",\n\t\t\t\tmaxLength: 64,\n\t\t\t\tdescription: \"SHA-256 checksum of migration content\",\n\t\t\t},\n\t\t\terror: {\n\t\t\t\ttype: \"string\",\n\t\t\t\tdescription: \"Error message if migration failed\",\n\t\t\t},\n\t\t\tappliedAt: {\n\t\t\t\ttype: \"date\",\n\t\t\t\trequired: true,\n\t\t\t\tdescription: \"When the migration was applied\",\n\t\t\t},\n\t\t},\n\n\t\tindexes: [\n\t\t\t{ fields: [\"version\"], unique: true },\n\t\t\t{ fields: [\"status\"] },\n\t\t\t{ fields: [\"appliedAt\"] },\n\t\t],\n\n\t\tpermission: {\n\t\t\tcreate: false,\n\t\t\tread: false,\n\t\t\tupdate: false,\n\t\t\tdelete: false,\n\t\t},\n\t} as const);\n}\n\n/**\n * Migration history schema type\n */\nexport type MigrationHistorySchema = ReturnType<typeof getMigrationSchema>;\n\n/**\n * Get internal Datrix metadata schema definition\n *\n * Stores per-table schema snapshots as JSON for migration diffing.\n * key: table name, value: full Datrix SchemaDefinition as JSON string\n */\nexport function getDatrixMetaSchema() {\n\treturn defineSchema({\n\t\tname: FORJA_META_MODEL,\n\t\ttableName: FORJA_META_MODEL,\n\n\t\tfields: {\n\t\t\tkey: {\n\t\t\t\ttype: \"string\",\n\t\t\t\trequired: true,\n\t\t\t\tunique: true,\n\t\t\t\tmaxLength: 255,\n\t\t\t\tdescription: \"Table name\",\n\t\t\t},\n\t\t\tvalue: {\n\t\t\t\ttype: \"string\",\n\t\t\t\trequired: true,\n\t\t\t\tdescription: \"Datrix SchemaDefinition as JSON string\",\n\t\t\t},\n\t\t},\n\n\t\tpermission: {\n\t\t\tcreate: false,\n\t\t\tread: false,\n\t\t\tupdate: false,\n\t\t\tdelete: false,\n\t\t},\n\t} as const);\n}\n\n/**\n * Datrix metadata schema type\n */\nexport type DatrixMetaSchema = ReturnType<typeof getDatrixMetaSchema>;\n","/**\n * Migration System Type Definitions (~200 LOC)\n *\n * Types for database schema migrations, diffing, and history tracking.\n */\n\nimport { AlterOperation, QueryRunner } from \"../adapter\";\n\nimport { FieldDefinition, IndexDefinition, SchemaDefinition } from \"./schema\";\n\n/**\n * Migration status\n */\nexport type MigrationStatus = \"pending\" | \"running\" | \"completed\" | \"failed\";\n\n/**\n * Migration metadata\n */\nexport interface MigrationMetadata {\n\treadonly name: string;\n\treadonly version: string;\n\treadonly timestamp: number;\n\treadonly description?: string;\n\treadonly author?: string;\n}\n\n/**\n * Migration context for execution\n */\nexport interface MigrationContext {\n\treadonly version: string;\n\treadonly dryRun?: boolean;\n}\n\n/**\n * Migration operation types\n */\nexport type MigrationOperationType =\n\t| \"createTable\"\n\t| \"dropTable\"\n\t| \"alterTable\"\n\t| \"createIndex\"\n\t| \"dropIndex\"\n\t| \"renameTable\"\n\t| \"raw\"\n\t| \"dataTransfer\";\n\n/**\n * Base migration operation\n */\nexport interface BaseMigrationOperation {\n\treadonly type: MigrationOperationType;\n}\n\n/**\n * Create table operation\n */\nexport interface CreateTableOperation extends BaseMigrationOperation {\n\treadonly type: \"createTable\";\n\treadonly schema: SchemaDefinition;\n}\n\n/**\n * Drop table operation\n */\nexport interface DropTableOperation extends BaseMigrationOperation {\n\treadonly type: \"dropTable\";\n\treadonly tableName: string;\n}\n\n/**\n * Alter table operation\n */\nexport interface AlterTableOperation extends BaseMigrationOperation {\n\treadonly type: \"alterTable\";\n\treadonly tableName: string;\n\treadonly operations: readonly AlterOperation[];\n}\n\n/**\n * Create index operation\n */\nexport interface CreateIndexOperation extends BaseMigrationOperation {\n\treadonly type: \"createIndex\";\n\treadonly tableName: string;\n\treadonly index: IndexDefinition;\n}\n\n/**\n * Drop index operation\n */\nexport interface DropIndexOperation extends BaseMigrationOperation {\n\treadonly type: \"dropIndex\";\n\treadonly tableName: string;\n\treadonly indexName: string;\n}\n\n/**\n * Rename table operation\n */\nexport interface RenameTableOperation extends BaseMigrationOperation {\n\treadonly type: \"renameTable\";\n\treadonly from: string;\n\treadonly to: string;\n}\n\n/**\n * Raw SQL operation (for custom migrations)\n */\nexport interface RawSQLOperation extends BaseMigrationOperation {\n\treadonly type: \"raw\";\n\treadonly sql: string;\n\treadonly params?: readonly unknown[];\n}\n\n/**\n * Data transfer operation — runs a callback with the transaction runner.\n * Used for migrating data between tables (e.g. FK → junction, junction → FK).\n */\nexport interface DataTransferOperation extends BaseMigrationOperation {\n\treadonly type: \"dataTransfer\";\n\treadonly description: string;\n\treadonly execute: (runner: QueryRunner) => Promise<void>;\n}\n\n/**\n * Union of all migration operations\n */\nexport type MigrationOperation =\n\t| CreateTableOperation\n\t| DropTableOperation\n\t| AlterTableOperation\n\t| CreateIndexOperation\n\t| DropIndexOperation\n\t| RenameTableOperation\n\t| RawSQLOperation\n\t| DataTransferOperation;\n\n/**\n * Migration definition\n */\nexport interface Migration {\n\treadonly metadata: MigrationMetadata;\n\treadonly operations: readonly MigrationOperation[];\n}\n\n/**\n * Schema difference types\n */\nexport type SchemaDiffType =\n\t| \"tableAdded\"\n\t| \"tableRemoved\"\n\t| \"tableRenamed\"\n\t| \"fieldAdded\"\n\t| \"fieldRemoved\"\n\t| \"fieldModified\"\n\t| \"fieldRenamed\"\n\t| \"indexAdded\"\n\t| \"indexRemoved\";\n\n/**\n * Base schema difference\n */\nexport interface BaseSchemaDiff {\n\treadonly type: SchemaDiffType;\n}\n\n/**\n * Table added difference\n */\nexport interface TableAddedDiff extends BaseSchemaDiff {\n\treadonly type: \"tableAdded\";\n\treadonly schema: SchemaDefinition;\n}\n\n/**\n * Table removed difference\n */\nexport interface TableRemovedDiff extends BaseSchemaDiff {\n\treadonly type: \"tableRemoved\";\n\treadonly tableName: string;\n}\n\n/**\n * Table renamed difference\n */\nexport interface TableRenamedDiff extends BaseSchemaDiff {\n\treadonly type: \"tableRenamed\";\n\treadonly from: string;\n\treadonly to: string;\n}\n\n/**\n * Field added difference\n */\nexport interface FieldAddedDiff extends BaseSchemaDiff {\n\treadonly type: \"fieldAdded\";\n\treadonly tableName: string;\n\treadonly fieldName: string;\n\treadonly definition: FieldDefinition;\n}\n\n/**\n * Field removed difference\n */\nexport interface FieldRemovedDiff extends BaseSchemaDiff {\n\treadonly type: \"fieldRemoved\";\n\treadonly tableName: string;\n\treadonly fieldName: string;\n\treadonly definition: FieldDefinition;\n}\n\n/**\n * Field modified difference\n */\nexport interface FieldModifiedDiff extends BaseSchemaDiff {\n\treadonly type: \"fieldModified\";\n\treadonly tableName: string;\n\treadonly fieldName: string;\n\treadonly oldDefinition: FieldDefinition;\n\treadonly newDefinition: FieldDefinition;\n}\n\n/**\n * Field renamed difference\n */\nexport interface FieldRenamedDiff extends BaseSchemaDiff {\n\treadonly type: \"fieldRenamed\";\n\treadonly tableName: string;\n\treadonly from: string;\n\treadonly to: string;\n}\n\n/**\n * Index added difference\n */\nexport interface IndexAddedDiff extends BaseSchemaDiff {\n\treadonly type: \"indexAdded\";\n\treadonly tableName: string;\n\treadonly index: IndexDefinition;\n}\n\n/**\n * Index removed difference\n */\nexport interface IndexRemovedDiff extends BaseSchemaDiff {\n\treadonly type: \"indexRemoved\";\n\treadonly tableName: string;\n\treadonly indexName: string;\n}\n\n/**\n * Union of all schema differences\n */\nexport type SchemaDiff =\n\t| TableAddedDiff\n\t| TableRemovedDiff\n\t| TableRenamedDiff\n\t| FieldAddedDiff\n\t| FieldRemovedDiff\n\t| FieldModifiedDiff\n\t| FieldRenamedDiff\n\t| IndexAddedDiff\n\t| IndexRemovedDiff;\n\n/**\n * Schema comparison result\n */\nexport interface SchemaComparison {\n\treadonly differences: readonly SchemaDiff[];\n\treadonly hasChanges: boolean;\n}\n\n/**\n * Migration history record (stored in database)\n */\nexport interface MigrationHistoryRecord {\n\treadonly id: number;\n\treadonly name: string;\n\treadonly version: string;\n\treadonly appliedAt: Date;\n\treadonly executionTime: number; // milliseconds\n\treadonly status: MigrationStatus;\n\treadonly checksum?: string;\n\treadonly error?: string;\n}\n\n/**\n * Migration execution result\n */\nexport interface MigrationExecutionResult {\n\treadonly migration: Migration;\n\treadonly status: MigrationStatus;\n\treadonly executionTime: number;\n\treadonly error?: Error;\n\treadonly warnings?: readonly string[];\n}\n\n/**\n * Migration plan (list of migrations to execute)\n */\nexport interface MigrationFilePlan {\n\treadonly migrations: readonly Migration[];\n\treadonly target?: string; // Target version (undefined = latest)\n}\n\n/**\n * Migration error\n */\nexport class MigrationSystemError extends Error {\n\tconstructor(\n\t\tmessage: string,\n\t\tpublic readonly code:\n\t\t\t| \"MIGRATION_ERROR\"\n\t\t\t| \"DIFF_ERROR\"\n\t\t\t| \"GENERATION_ERROR\"\n\t\t\t| \"VALIDATION_ERROR\",\n\t\tpublic readonly details?: unknown,\n\t) {\n\t\tsuper(message);\n\t\tthis.name = \"MigrationSystemError\";\n\t}\n}\n\n/**\n * Schema differ interface\n */\nexport interface SchemaDiffer {\n\t/**\n\t * Compare two schemas and return differences\n\t */\n\tcompare(\n\t\toldSchema: Record<string, SchemaDefinition>,\n\t\tnewSchema: Record<string, SchemaDefinition>,\n\t): SchemaComparison;\n\n\t/**\n\t * Detect field type changes\n\t */\n\tisFieldModified(\n\t\toldField: FieldDefinition,\n\t\tnewField: FieldDefinition,\n\t): boolean;\n}\n\n/**\n * Migration generator interface\n */\nexport interface MigrationGenerator {\n\t/**\n\t * Generate migration from schema differences\n\t */\n\tgenerate(\n\t\tdifferences: readonly SchemaDiff[],\n\t\tmetadata: Omit<MigrationMetadata, \"timestamp\">,\n\t): Migration;\n\n\t/**\n\t * Generate migration operations from differences\n\t */\n\tgenerateOperations(\n\t\tdifferences: readonly SchemaDiff[],\n\t): readonly MigrationOperation[];\n\n\t/**\n\t * Generate TypeScript migration file content\n\t */\n\tgenerateFile(migration: Migration): string;\n}\n\n/**\n * Migration runner interface\n */\nexport interface MigrationRunner {\n\t/**\n\t * Get pending migrations\n\t */\n\tgetPending(): Promise<readonly Migration[]>;\n\n\t/**\n\t * Get applied migrations\n\t */\n\tgetApplied(): Promise<readonly MigrationHistoryRecord[]>;\n\n\t/**\n\t * Run pending migrations\n\t */\n\trunPending(options?: {\n\t\treadonly target?: string;\n\t\treadonly dryRun?: boolean;\n\t}): Promise<readonly MigrationExecutionResult[]>;\n\n\t/**\n\t * Run specific migration\n\t */\n\trunOne(migration: Migration): Promise<MigrationExecutionResult>;\n\n\t/**\n\t * Get migration plan\n\t */\n\tgetPlan(options?: { readonly target?: string }): MigrationFilePlan;\n}\n\n/**\n * Migration history manager interface\n */\nexport interface MigrationHistory {\n\t/**\n\t * Initialize migrations table\n\t */\n\tinitialize(): Promise<void>;\n\n\t/**\n\t * Record migration execution\n\t */\n\trecord(\n\t\tmigration: Migration,\n\t\texecutionTime: number,\n\t\tstatus: MigrationStatus,\n\t\terror?: Error,\n\t): Promise<void>;\n\n\t/**\n\t * Get all migration records\n\t */\n\tgetAll(): Promise<readonly MigrationHistoryRecord[]>;\n\n\t/**\n\t * Get last applied migration\n\t */\n\tgetLast(): Promise<MigrationHistoryRecord | undefined>;\n\n\t/**\n\t * Check if migration was applied\n\t */\n\tisApplied(version: string): Promise<boolean>;\n\n\t/**\n\t * Calculate migration checksum\n\t */\n\tcalculateChecksum(migration: Migration): string;\n\n\t/**\n\t * Verify migration integrity\n\t */\n\tverifyChecksum(migration: Migration, record: MigrationHistoryRecord): boolean;\n}\n","/**\n * Schema Differ Implementation (~300 LOC)\n *\n * Compares two schema versions and detects differences.\n * Produces structured diff objects for migration generation.\n */\n\nimport {\n\tMigrationSystemError,\n\tSchemaComparison,\n\tSchemaDiff,\n\tSchemaDiffer,\n} from \"../types/core/migration\";\nimport { FieldDefinition, SchemaDefinition } from \"../types/core/schema\";\n\n/**\n * Type guard for SchemaDefinition\n */\nfunction isSchemaDefinition(value: unknown): value is SchemaDefinition {\n\treturn (\n\t\ttypeof value === \"object\" &&\n\t\tvalue !== null &&\n\t\t\"name\" in value &&\n\t\ttypeof (value as Record<string, unknown>)[\"name\"] === \"string\" &&\n\t\t\"fields\" in value &&\n\t\ttypeof (value as Record<string, unknown>)[\"fields\"] === \"object\"\n\t);\n}\n\n/**\n * Type guard for FieldDefinition\n */\nfunction isFieldDefinition(value: unknown): value is FieldDefinition {\n\treturn (\n\t\ttypeof value === \"object\" &&\n\t\tvalue !== null &&\n\t\t\"type\" in value &&\n\t\ttypeof (value as Record<string, unknown>)[\"type\"] === \"string\"\n\t);\n}\n\n/**\n * Type guard for valid index types\n */\nfunction isValidIndexType(\n\ttype: string,\n): type is \"btree\" | \"hash\" | \"gist\" | \"gin\" {\n\treturn [\"btree\", \"hash\", \"gist\", \"gin\"].includes(type);\n}\n\n/**\n * Schema differ implementation\n */\nexport class ForgeSchemaDiffer implements SchemaDiffer {\n\t/**\n\t * Compare two schema collections\n\t */\n\tcompare(\n\t\toldSchemas: Record<string, SchemaDefinition>,\n\t\tnewSchemas: Record<string, SchemaDefinition>,\n\t): SchemaComparison {\n\t\ttry {\n\t\t\tif (\n\t\t\t\ttypeof oldSchemas !== \"object\" ||\n\t\t\t\toldSchemas === null ||\n\t\t\t\tArray.isArray(oldSchemas)\n\t\t\t) {\n\t\t\t\tthrow new MigrationSystemError(\n\t\t\t\t\t\"oldSchemas must be a plain object\",\n\t\t\t\t\t\"DIFF_ERROR\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (\n\t\t\t\ttypeof newSchemas !== \"object\" ||\n\t\t\t\tnewSchemas === null ||\n\t\t\t\tArray.isArray(newSchemas)\n\t\t\t) {\n\t\t\t\tthrow new MigrationSystemError(\n\t\t\t\t\t\"newSchemas must be a plain object\",\n\t\t\t\t\t\"DIFF_ERROR\",\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst differences: SchemaDiff[] = [];\n\n\t\t\tconst oldTableNames = new Set(Object.keys(oldSchemas));\n\t\t\tconst newTableNames = new Set(Object.keys(newSchemas));\n\n\t\t\t// Find added tables\n\t\t\tfor (const tableName of newTableNames) {\n\t\t\t\tif (!oldTableNames.has(tableName)) {\n\t\t\t\t\tconst schema = newSchemas[tableName];\n\t\t\t\t\tif (!isSchemaDefinition(schema)) {\n\t\t\t\t\t\tthrow new MigrationSystemError(\n\t\t\t\t\t\t\t`Invalid schema definition for table '${tableName}'`,\n\t\t\t\t\t\t\t\"DIFF_ERROR\",\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tdifferences.push({\n\t\t\t\t\t\ttype: \"tableAdded\",\n\t\t\t\t\t\tschema,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Find removed tables\n\t\t\tfor (const tableName of oldTableNames) {\n\t\t\t\tif (!newTableNames.has(tableName)) {\n\t\t\t\t\tdifferences.push({\n\t\t\t\t\t\ttype: \"tableRemoved\",\n\t\t\t\t\t\ttableName,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Find modified tables\n\t\t\tfor (const tableName of newTableNames) {\n\t\t\t\tif (oldTableNames.has(tableName)) {\n\t\t\t\t\tconst oldSchema = oldSchemas[tableName];\n\t\t\t\t\tconst newSchema = newSchemas[tableName];\n\n\t\t\t\t\tif (\n\t\t\t\t\t\t!isSchemaDefinition(oldSchema) ||\n\t\t\t\t\t\t!isSchemaDefinition(newSchema)\n\t\t\t\t\t) {\n\t\t\t\t\t\tthrow new MigrationSystemError(\n\t\t\t\t\t\t\t`Invalid schema definition for table '${tableName}'`,\n\t\t\t\t\t\t\t\"DIFF_ERROR\",\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tconst tableDiffs = this.compareTable(oldSchema, newSchema);\n\t\t\t\t\tdifferences.push(...tableDiffs);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst resolvedDifferences = this.resolveCrossSchemaNoOps(\n\t\t\t\tdifferences,\n\t\t\t\toldSchemas,\n\t\t\t\tnewSchemas,\n\t\t\t);\n\n\t\t\treturn {\n\t\t\t\tdifferences: resolvedDifferences,\n\t\t\t\thasChanges: resolvedDifferences.length > 0,\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthrow new MigrationSystemError(\n\t\t\t\t`Failed to compare schemas: ${message}`,\n\t\t\t\t\"DIFF_ERROR\",\n\t\t\t\terror,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Resolve cross-schema no-ops after all per-table diffs are produced.\n\t *\n\t * Cases eliminated:\n\t * 1. hasOne/hasMany removed from table A + belongsTo added to table B\n\t * → same FK column on B, no DB change\n\t * 2. belongsTo removed from table B + hasOne/hasMany added to table A\n\t * → same FK column on B, no DB change\n\t * 3. manyToMany added to table B while table A already declares it\n\t * → junction table already exists, no DB change\n\t * 4. manyToMany removed from one side while other side still declares it\n\t * → junction table still needed, suppress tableRemoved\n\t */\n\tprivate resolveCrossSchemaNoOps(\n\t\tdifferences: SchemaDiff[],\n\t\toldSchemas: Record<string, SchemaDefinition>,\n\t\tnewSchemas: Record<string, SchemaDefinition>,\n\t): SchemaDiff[] {\n\t\tconst toRemove = new Set<number>();\n\n\t\t// Index diffs for fast lookup\n\t\tconst fieldAdded: Array<{\n\t\t\tindex: number;\n\t\t\tdiff: SchemaDiff & { type: \"fieldAdded\" };\n\t\t}> = [];\n\t\tconst fieldRemoved: Array<{\n\t\t\tindex: number;\n\t\t\tdiff: SchemaDiff & { type: \"fieldRemoved\" };\n\t\t}> = [];\n\t\tconst tableRemoved: Array<{\n\t\t\tindex: number;\n\t\t\tdiff: SchemaDiff & { type: \"tableRemoved\" };\n\t\t}> = [];\n\n\t\tfor (let i = 0; i < differences.length; i++) {\n\t\t\tconst diff = differences[i];\n\t\t\tif (diff === undefined) continue;\n\t\t\tif (diff.type === \"fieldAdded\") {\n\t\t\t\tfieldAdded.push({\n\t\t\t\t\tindex: i,\n\t\t\t\t\tdiff: diff as SchemaDiff & { type: \"fieldAdded\" },\n\t\t\t\t});\n\t\t\t} else if (diff.type === \"fieldRemoved\") {\n\t\t\t\tfieldRemoved.push({\n\t\t\t\t\tindex: i,\n\t\t\t\t\tdiff: diff as SchemaDiff & { type: \"fieldRemoved\" },\n\t\t\t\t});\n\t\t\t} else if (diff.type === \"tableRemoved\") {\n\t\t\t\ttableRemoved.push({\n\t\t\t\t\tindex: i,\n\t\t\t\t\tdiff: diff as SchemaDiff & { type: \"tableRemoved\" },\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\t// Build lookup maps by table name for both old and new schemas\n\t\tconst newSchemaByTable = new Map<string, SchemaDefinition>();\n\t\tfor (const schema of Object.values(newSchemas)) {\n\t\t\tnewSchemaByTable.set(schema.tableName ?? schema.name, schema);\n\t\t}\n\n\t\tconst oldSchemaByTable = new Map<string, SchemaDefinition>();\n\t\tfor (const schema of Object.values(oldSchemas)) {\n\t\t\toldSchemaByTable.set(schema.tableName ?? schema.name, schema);\n\t\t}\n\n\t\t// Case 1 & 2: hasOne/hasMany ↔ belongsTo cross-table flip\n\t\t// The FK column lives on the target table in both cases.\n\t\t// We match a removed relation on one side with an added relation on\n\t\t// the other side that resolves to the same physical FK column.\n\t\t// Removed fields must be looked up in oldSchemas since they no longer\n\t\t// exist in newSchemas.\n\t\tfor (const removed of fieldRemoved) {\n\t\t\tconst removedField = this.getFieldFromSchemas(\n\t\t\t\tremoved.diff.tableName,\n\t\t\t\tremoved.diff.fieldName,\n\t\t\t\toldSchemaByTable,\n\t\t\t\toldSchemas,\n\t\t\t);\n\n\t\t\tif (!removedField || removedField.type !== \"relation\") continue;\n\t\t\tif (removedField.kind === \"manyToMany\") continue;\n\n\t\t\tfor (const added of fieldAdded) {\n\t\t\t\tif (toRemove.has(added.index)) continue;\n\n\t\t\t\tconst addedDef = added.diff.definition;\n\t\t\t\tif (addedDef.type !== \"relation\") continue;\n\t\t\t\tif (addedDef.kind === \"manyToMany\") continue;\n\n\t\t\t\tconst match = this.isCrossSchemaFkNoOp(\n\t\t\t\t\tremoved.diff.tableName,\n\t\t\t\t\tremovedField,\n\t\t\t\t\tadded.diff.tableName,\n\t\t\t\t\taddedDef,\n\t\t\t\t\tnewSchemaByTable,\n\t\t\t\t\tnewSchemas,\n\t\t\t\t\toldSchemaByTable,\n\t\t\t\t\toldSchemas,\n\t\t\t\t);\n\n\t\t\t\tif (match) {\n\t\t\t\t\ttoRemove.add(removed.index);\n\t\t\t\t\ttoRemove.add(added.index);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Case 3: manyToMany added on second side — junction table already exists\n\t\t// If the junction table is not being created in this migration it means\n\t\t// it already exists in the DB → this fieldAdded is a no-op.\n\t\tfor (const added of fieldAdded) {\n\t\t\tif (toRemove.has(added.index)) continue;\n\n\t\t\tconst addedDef = added.diff.definition;\n\t\t\tif (addedDef.type !== \"relation\" || addedDef.kind !== \"manyToMany\")\n\t\t\t\tcontinue;\n\n\t\t\tconst ownerSchema =\n\t\t\t\tnewSchemaByTable.get(added.diff.tableName) ??\n\t\t\t\tnewSchemas[added.diff.tableName];\n\t\t\tconst ownerModelName = ownerSchema?.name ?? added.diff.tableName;\n\n\t\t\tconst junctionName = this.resolveJunctionTableName(\n\t\t\t\townerModelName,\n\t\t\t\taddedDef.model,\n\t\t\t\taddedDef.through,\n\t\t\t\tnewSchemaByTable,\n\t\t\t\tnewSchemas,\n\t\t\t);\n\n\t\t\tif (junctionName === undefined) continue;\n\n\t\t\tconst junctionBeingCreated = differences.some(\n\t\t\t\t(d) =>\n\t\t\t\t\td.type === \"tableAdded\" &&\n\t\t\t\t\t(d.schema.tableName ?? d.schema.name) === junctionName,\n\t\t\t);\n\n\t\t\tif (!junctionBeingCreated) {\n\t\t\t\ttoRemove.add(added.index);\n\t\t\t}\n\t\t}\n\n\t\t// Case 3b: hasOne/hasMany added — FK column already exists in DB\n\t\t// This happens when belongsTo already existed on the other side.\n\t\t// The FK column is already present so the fieldAdded is a no-op.\n\t\tfor (const added of fieldAdded) {\n\t\t\tif (toRemove.has(added.index)) continue;\n\n\t\t\tconst addedDef = added.diff.definition;\n\t\t\tif (addedDef.type !== \"relation\") continue;\n\t\t\tif (addedDef.kind !== \"hasOne\" && addedDef.kind !== \"hasMany\") continue;\n\n\t\t\tconst ownerSchema =\n\t\t\t\tnewSchemaByTable.get(added.diff.tableName) ??\n\t\t\t\tnewSchemas[added.diff.tableName];\n\t\t\tconst ownerModelName = ownerSchema?.name ?? added.diff.tableName;\n\n\t\t\tconst fkTable = this.resolveModelTableName(\n\t\t\t\taddedDef.model,\n\t\t\t\tnewSchemaByTable,\n\t\t\t\tnewSchemas,\n\t\t\t);\n\t\t\tconst fkColumn = addedDef.foreignKey ?? `${ownerModelName}Id`;\n\n\t\t\tif (fkTable === undefined) continue;\n\n\t\t\t// Check if this FK column already exists in old schemas (already in DB)\n\t\t\tconst fkTableOldSchema =\n\t\t\t\toldSchemaByTable.get(fkTable) ?? oldSchemas[fkTable];\n\t\t\tif (fkTableOldSchema && fkColumn in fkTableOldSchema.fields) {\n\t\t\t\ttoRemove.add(added.index);\n\t\t\t}\n\t\t}\n\n\t\t// Case 4: manyToMany removed from one side — other side still declares it\n\t\t// Suppress tableRemoved for the junction table if it is still referenced.\n\t\tfor (const removed of tableRemoved) {\n\t\t\tif (toRemove.has(removed.index)) continue;\n\n\t\t\tconst junctionName = removed.diff.tableName;\n\n\t\t\tconst stillReferenced = this.isJunctionTableStillReferenced(\n\t\t\t\tjunctionName,\n\t\t\t\tnewSchemas,\n\t\t\t\tnewSchemaByTable,\n\t\t\t);\n\n\t\t\tif (stillReferenced) {\n\t\t\t\ttoRemove.add(removed.index);\n\t\t\t}\n\t\t}\n\n\t\t// Case 4b: manyToMany fieldRemoved on one side — other side still declares it\n\t\t// The junction table still exists so this fieldRemoved is a no-op.\n\t\tfor (const removed of fieldRemoved) {\n\t\t\tif (toRemove.has(removed.index)) continue;\n\n\t\t\tconst removedField = this.getFieldFromSchemas(\n\t\t\t\tremoved.diff.tableName,\n\t\t\t\tremoved.diff.fieldName,\n\t\t\t\toldSchemaByTable,\n\t\t\t\toldSchemas,\n\t\t\t);\n\n\t\t\tif (\n\t\t\t\t!removedField ||\n\t\t\t\tremovedField.type !== \"relation\" ||\n\t\t\t\tremovedField.kind !== \"manyToMany\"\n\t\t\t)\n\t\t\t\tcontinue;\n\n\t\t\tconst ownerSchema =\n\t\t\t\toldSchemaByTable.get(removed.diff.tableName) ??\n\t\t\t\toldSchemas[removed.diff.tableName];\n\t\t\tconst ownerModelName = ownerSchema?.name ?? removed.diff.tableName;\n\n\t\t\tconst junctionName = this.resolveJunctionTableName(\n\t\t\t\townerModelName,\n\t\t\t\tremovedField.model,\n\t\t\t\tremovedField.through,\n\t\t\t\tnewSchemaByTable,\n\t\t\t\tnewSchemas,\n\t\t\t);\n\n\t\t\tif (junctionName === undefined) continue;\n\n\t\t\tconst stillReferenced = this.isJunctionTableStillReferenced(\n\t\t\t\tjunctionName,\n\t\t\t\tnewSchemas,\n\t\t\t\tnewSchemaByTable,\n\t\t\t);\n\n\t\t\tif (stillReferenced) {\n\t\t\t\ttoRemove.add(removed.index);\n\t\t\t}\n\t\t}\n\n\t\treturn differences.filter((_, i) => !toRemove.has(i));\n\t}\n\n\t/**\n\t * Get a field definition from schemas, trying by table name then schema name.\n\t */\n\tprivate getFieldFromSchemas(\n\t\ttableName: string,\n\t\tfieldName: string,\n\t\tschemaByTable: Map<string, SchemaDefinition>,\n\t\tschemas: Record<string, SchemaDefinition>,\n\t): FieldDefinition | undefined {\n\t\tconst byTable = schemaByTable.get(tableName);\n\t\tif (byTable) {\n\t\t\tconst field = byTable.fields[fieldName];\n\t\t\tif (isFieldDefinition(field)) return field;\n\t\t}\n\t\tconst byName = schemas[tableName];\n\t\tif (byName) {\n\t\t\tconst field = byName.fields[fieldName];\n\t\t\tif (isFieldDefinition(field)) return field;\n\t\t}\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Determine if a removed relation on tableA and an added relation on tableB\n\t * resolve to the same physical FK column — making both diffs a no-op.\n\t *\n\t * Removed fields are resolved against oldSchemas (they no longer exist in new).\n\t * Added fields are resolved against newSchemas.\n\t */\n\tprivate isCrossSchemaFkNoOp(\n\t\tremovedTableName: string,\n\t\tremovedField: FieldDefinition & { type: \"relation\" },\n\t\taddedTableName: string,\n\t\taddedField: FieldDefinition & { type: \"relation\" },\n\t\tnewSchemaByTable: Map<string, SchemaDefinition>,\n\t\tnewSchemas: Record<string, SchemaDefinition>,\n\t\toldSchemaByTable: Map<string, SchemaDefinition>,\n\t\toldSchemas: Record<string, SchemaDefinition>,\n\t): boolean {\n\t\t// Resolve FK location for the removed side using old schema context\n\t\tconst removedFkTable = this.resolveFkTable(\n\t\t\tremovedTableName,\n\t\t\tremovedField,\n\t\t\toldSchemaByTable,\n\t\t\toldSchemas,\n\t\t);\n\t\tconst removedFkColumn = this.resolveFkColumn(\n\t\t\tremovedTableName,\n\t\t\tremovedField,\n\t\t\toldSchemaByTable,\n\t\t\toldSchemas,\n\t\t);\n\n\t\t// Resolve FK location for the added side using new schema context\n\t\tconst addedFkTable = this.resolveFkTable(\n\t\t\taddedTableName,\n\t\t\taddedField,\n\t\t\tnewSchemaByTable,\n\t\t\tnewSchemas,\n\t\t);\n\t\tconst addedFkColumn = this.resolveFkColumn(\n\t\t\taddedTableName,\n\t\t\taddedField,\n\t\t\tnewSchemaByTable,\n\t\t\tnewSchemas,\n\t\t);\n\n\t\tif (removedFkTable === undefined || addedFkTable === undefined)\n\t\t\treturn false;\n\t\tif (removedFkColumn === undefined || addedFkColumn === undefined)\n\t\t\treturn false;\n\n\t\treturn removedFkTable === addedFkTable && removedFkColumn === addedFkColumn;\n\t}\n\n\t/**\n\t * Resolve which table the FK column physically lives on.\n\t * - belongsTo: FK is on the owner table (tableName itself)\n\t * - hasOne/hasMany: FK is on the target (model) table\n\t */\n\tprivate resolveFkTable(\n\t\ttableName: string,\n\t\tfield: FieldDefinition & { type: \"relation\" },\n\t\tschemaByTable: Map<string, SchemaDefinition>,\n\t\tschemas: Record<string, SchemaDefinition>,\n\t): string | undefined {\n\t\tif (field.kind === \"belongsTo\") {\n\t\t\treturn tableName;\n\t\t}\n\t\treturn this.resolveModelTableName(field.model, schemaByTable, schemas);\n\t}\n\n\t/**\n\t * Resolve the FK column name for a relation field.\n\t * - belongsTo: foreignKey ?? model + \"Id\"\n\t * - hasOne/hasMany: foreignKey ?? ownerModelName + \"Id\"\n\t */\n\tprivate resolveFkColumn(\n\t\ttableName: string,\n\t\tfield: FieldDefinition & { type: \"relation\" },\n\t\tschemaByTable: Map<string, SchemaDefinition>,\n\t\tschemas: Record<string, SchemaDefinition>,\n\t): string | undefined {\n\t\tif (field.foreignKey !== undefined) {\n\t\t\treturn field.foreignKey;\n\t\t}\n\t\tif (field.kind === \"belongsTo\") {\n\t\t\treturn `${field.model}Id`;\n\t\t}\n\t\t// hasOne / hasMany: default FK is ownerModelName + \"Id\"\n\t\tconst ownerSchema = schemaByTable.get(tableName) ?? schemas[tableName];\n\t\tconst ownerModelName = ownerSchema?.name ?? tableName;\n\t\treturn `${ownerModelName}Id`;\n\t}\n\n\t/**\n\t * Resolve a model name to its table name.\n\t */\n\tprivate resolveModelTableName(\n\t\tmodelName: string,\n\t\tschemaByTable: Map<string, SchemaDefinition>,\n\t\tschemas: Record<string, SchemaDefinition>,\n\t): string | undefined {\n\t\tconst byName = schemas[modelName];\n\t\tif (byName) return byName.tableName ?? byName.name;\n\n\t\tfor (const schema of Object.values(schemas)) {\n\t\t\tif (schema.name === modelName) return schema.tableName ?? schema.name;\n\t\t}\n\n\t\t// Also check by table name directly\n\t\tif (schemaByTable.has(modelName)) return modelName;\n\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Resolve the junction table name for a manyToMany relation.\n\t * ownerModelName is the schema name (not table name), same as registry logic.\n\t */\n\tprivate resolveJunctionTableName(\n\t\townerModelName: string,\n\t\ttargetModelName: string,\n\t\tthrough: string | undefined,\n\t\t_newSchemaByTable: Map<string, SchemaDefinition>,\n\t\t_newSchemas: Record<string, SchemaDefinition>,\n\t): string | undefined {\n\t\tif (through !== undefined) return through;\n\n\t\t// Alphabetical order by model name, same as registry\n\t\tconst parts = [ownerModelName, targetModelName].sort();\n\t\treturn `${parts[0]}_${parts[1]}`;\n\t}\n\n\t/**\n\t * Check if a junction table is still referenced by any manyToMany\n\t * relation in the new schemas.\n\t */\n\tprivate isJunctionTableStillReferenced(\n\t\tjunctionName: string,\n\t\tnewSchemas: Record<string, SchemaDefinition>,\n\t\tnewSchemaByTable: Map<string, SchemaDefinition>,\n\t): boolean {\n\t\tfor (const schema of Object.values(newSchemas)) {\n\t\t\tconst ownerModelName = schema.name;\n\t\t\tfor (const field of Object.values(schema.fields)) {\n\t\t\t\tif (!isFieldDefinition(field)) continue;\n\t\t\t\tif (field.type !== \"relation\" || field.kind !== \"manyToMany\") continue;\n\n\t\t\t\tconst resolved = this.resolveJunctionTableName(\n\t\t\t\t\townerModelName,\n\t\t\t\t\tfield.model,\n\t\t\t\t\tfield.through,\n\t\t\t\t\tnewSchemaByTable,\n\t\t\t\t\tnewSchemas,\n\t\t\t\t);\n\n\t\t\t\tif (resolved === junctionName) return true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\t/**\n\t * Check if two relation fields have the same DB structure.\n\t * hasOne and hasMany both place the FK on the target table,\n\t * so switching between them requires no DB change.\n\t */\n\tprivate isSameRelationDbStructure(\n\t\toldField: FieldDefinition,\n\t\tnewField: FieldDefinition,\n\t): boolean {\n\t\tif (oldField.type !== \"relation\" || newField.type !== \"relation\") {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst sameModel = oldField.model === newField.model;\n\t\tconst sameForeignKey = oldField.foreignKey === newField.foreignKey;\n\n\t\tconst oldKind = oldField.kind;\n\t\tconst newKind = newField.kind;\n\t\tconst isHasOneHasManySwap =\n\t\t\t(oldKind === \"hasOne\" && newKind === \"hasMany\") ||\n\t\t\t(oldKind === \"hasMany\" && newKind === \"hasOne\");\n\n\t\t// hasOne <-> hasMany: FK stays on target table, no DB change\n\t\tif (isHasOneHasManySwap && sameModel && sameForeignKey) {\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/**\n\t * Compare two versions of the same table\n\t */\n\tprivate compareTable(\n\t\toldSchema: SchemaDefinition,\n\t\tnewSchema: SchemaDefinition,\n\t): SchemaDiff[] {\n\t\tconst differences: SchemaDiff[] = [];\n\t\tconst tableName = newSchema.tableName ?? newSchema.name;\n\n\t\tconst oldFieldNames = new Set(Object.keys(oldSchema.fields));\n\t\tconst newFieldNames = new Set(Object.keys(newSchema.fields));\n\n\t\t// For relation fields not present by name: check if a same-DB-structure\n\t\t// relation exists under a different name (e.g. hasOne->hasMany rename).\n\t\t// If so, skip both the removed and added diff for those fields.\n\t\tconst skippedOldFields = new Set<string>();\n\t\tconst skippedNewFields = new Set<string>();\n\n\t\tfor (const newFieldName of newFieldNames) {\n\t\t\tif (oldFieldNames.has(newFieldName)) continue;\n\n\t\t\tconst newField = newSchema.fields[newFieldName];\n\t\t\tif (!isFieldDefinition(newField) || newField.type !== \"relation\")\n\t\t\t\tcontinue;\n\n\t\t\tfor (const oldFieldName of oldFieldNames) {\n\t\t\t\tif (newFieldNames.has(oldFieldName)) continue;\n\t\t\t\tif (skippedOldFields.has(oldFieldName)) continue;\n\n\t\t\t\tconst oldField = oldSchema.fields[oldFieldName];\n\t\t\t\tif (!isFieldDefinition(oldField) || oldField.type !== \"relation\")\n\t\t\t\t\tcontinue;\n\n\t\t\t\tif (this.isSameRelationDbStructure(oldField, newField)) {\n\t\t\t\t\tskippedOldFields.add(oldFieldName);\n\t\t\t\t\tskippedNewFields.add(newFieldName);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Find added fields\n\t\tfor (const fieldName of newFieldNames) {\n\t\t\tif (oldFieldNames.has(fieldName)) continue;\n\t\t\tif (skippedNewFields.has(fieldName)) continue;\n\n\t\t\tconst definition = newSchema.fields[fieldName];\n\t\t\tif (!isFieldDefinition(definition)) {\n\t\t\t\t// Skip invalid field definitions\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tdifferences.push({\n\t\t\t\ttype: \"fieldAdded\",\n\t\t\t\ttableName,\n\t\t\t\tfieldName,\n\t\t\t\tdefinition,\n\t\t\t});\n\t\t}\n\n\t\t// Find removed fields\n\t\tfor (const fieldName of oldFieldNames) {\n\t\t\tif (newFieldNames.has(fieldName)) continue;\n\t\t\tif (skippedOldFields.has(fieldName)) continue;\n\n\t\t\tconst definition = oldSchema.fields[fieldName];\n\t\t\tif (!isFieldDefinition(definition)) continue;\n\n\t\t\tdifferences.push({\n\t\t\t\ttype: \"fieldRemoved\",\n\t\t\t\ttableName,\n\t\t\t\tfieldName,\n\t\t\t\tdefinition,\n\t\t\t});\n\t\t}\n\n\t\t// Find modified fields\n\t\tfor (const fieldName of newFieldNames) {\n\t\t\tif (oldFieldNames.has(fieldName)) {\n\t\t\t\tconst oldField = oldSchema.fields[fieldName];\n\t\t\t\tconst newField = newSchema.fields[fieldName];\n\n\t\t\t\tif (!isFieldDefinition(oldField) || !isFieldDefinition(newField)) {\n\t\t\t\t\t// Skip invalid field definitions\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (this.isFieldModified(oldField, newField)) {\n\t\t\t\t\tdifferences.push({\n\t\t\t\t\t\ttype: \"fieldModified\",\n\t\t\t\t\t\ttableName,\n\t\t\t\t\t\tfieldName,\n\t\t\t\t\t\toldDefinition: oldField,\n\t\t\t\t\t\tnewDefinition: newField,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Compare indexes if present\n\t\tif (oldSchema.indexes || newSchema.indexes) {\n\t\t\tconst indexDiffs = this.compareIndexes(\n\t\t\t\ttableName,\n\t\t\t\toldSchema.indexes ?? [],\n\t\t\t\tnewSchema.indexes ?? [],\n\t\t\t);\n\t\t\tdifferences.push(...indexDiffs);\n\t\t}\n\n\t\treturn differences;\n\t}\n\n\t/**\n\t * Check if a field has been modified\n\t */\n\tisFieldModified(\n\t\toldField: FieldDefinition,\n\t\tnewField: FieldDefinition,\n\t): boolean {\n\t\t// Check type change\n\t\tif (oldField.type !== newField.type) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// Check required change\n\t\tif (oldField.required !== newField.required) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// Check unique constraint change\n\t\tconst oldUnique =\n\t\t\t\"unique\" in oldField\n\t\t\t\t? (oldField as { unique?: boolean }).unique\n\t\t\t\t: undefined;\n\t\tconst newUnique =\n\t\t\t\"unique\" in newField\n\t\t\t\t? (newField as { unique?: boolean }).unique\n\t\t\t\t: undefined;\n\t\tif (oldUnique !== newUnique) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// Check default value change\n\t\tif (oldField.default !== newField.default) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// Type-specific checks with proper type narrowing\n\t\tswitch (oldField.type) {\n\t\t\tcase \"string\":\n\t\t\t\t// Type narrowing\n\t\t\t\tif (newField.type !== \"string\") {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\tif (\n\t\t\t\t\toldField.maxLength !== newField.maxLength ||\n\t\t\t\t\toldField.minLength !== newField.minLength ||\n\t\t\t\t\toldField.pattern !== newField.pattern\n\t\t\t\t) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase \"number\":\n\t\t\t\t// Type narrowing\n\t\t\t\tif (newField.type !== \"number\") {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\tif (oldField.min !== newField.min || oldField.max !== newField.max) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase \"array\":\n\t\t\t\t// Type narrowing\n\t\t\t\tif (newField.type !== \"array\") {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\tif (\n\t\t\t\t\toldField.items !== newField.items ||\n\t\t\t\t\toldField.minItems !== newField.minItems ||\n\t\t\t\t\toldField.maxItems !== newField.maxItems ||\n\t\t\t\t\t(\"unique\" in oldField &&\n\t\t\t\t\t\t\"unique\" in newField &&\n\t\t\t\t\t\toldField.unique !== newField.unique)\n\t\t\t\t) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase \"enum\":\n\t\t\t\t// Type narrowing\n\t\t\t\tif (newField.type !== \"enum\") {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\t// Check if enum values changed\n\t\t\t\tif (oldField.values && newField.values) {\n\t\t\t\t\tconst oldValues = new Set(oldField.values);\n\t\t\t\t\tconst newValues = new Set(newField.values);\n\n\t\t\t\t\tif (oldValues.size !== newValues.size) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\n\t\t\t\t\tfor (const value of oldValues) {\n\t\t\t\t\t\tif (!newValues.has(value)) {\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase \"relation\":\n\t\t\t\t// Type narrowing\n\t\t\t\tif (newField.type !== \"relation\") {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\tif (\n\t\t\t\t\toldField.model !== newField.model ||\n\t\t\t\t\toldField.foreignKey !== newField.foreignKey ||\n\t\t\t\t\toldField.through !== newField.through ||\n\t\t\t\t\toldField.onDelete !== newField.onDelete ||\n\t\t\t\t\toldField.onUpdate !== newField.onUpdate\n\t\t\t\t) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\t// hasOne <-> hasMany does not change DB structure\n\t\t\t\tif (oldField.kind !== newField.kind) {\n\t\t\t\t\tconst isHasOneHasManySwap =\n\t\t\t\t\t\t(oldField.kind === \"hasOne\" && newField.kind === \"hasMany\") ||\n\t\t\t\t\t\t(oldField.kind === \"hasMany\" && newField.kind === \"hasOne\");\n\t\t\t\t\tif (!isHasOneHasManySwap) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/**\n\t * Compare indexes between two schema versions\n\t */\n\tprivate compareIndexes(\n\t\ttableName: string,\n\t\toldIndexes: readonly {\n\t\t\treadonly name?: string;\n\t\t\treadonly fields: readonly string[];\n\t\t\treadonly unique?: boolean;\n\t\t\treadonly type?: string;\n\t\t}[],\n\t\tnewIndexes: readonly {\n\t\t\treadonly name?: string;\n\t\t\treadonly fields: readonly string[];\n\t\t\treadonly unique?: boolean;\n\t\t\treadonly type?: string;\n\t\t}[],\n\t): SchemaDiff[] {\n\t\tconst differences: SchemaDiff[] = [];\n\n\t\t// Create index maps keyed by normalized signature\n\t\tconst oldIndexMap = new Map(\n\t\t\toldIndexes.map((idx) => [this.getIndexSignature(idx), idx]),\n\t\t);\n\t\tconst newIndexMap = new Map(\n\t\t\tnewIndexes.map((idx) => [this.getIndexSignature(idx), idx]),\n\t\t);\n\n\t\t// Find added indexes\n\t\tfor (const [signature, index] of newIndexMap) {\n\t\t\tif (!oldIndexMap.has(signature)) {\n\t\t\t\tdifferences.push({\n\t\t\t\t\ttype: \"indexAdded\",\n\t\t\t\t\ttableName,\n\t\t\t\t\tindex: {\n\t\t\t\t\t\t...(index.name !== undefined && { name: index.name }),\n\t\t\t\t\t\tfields: index.fields,\n\t\t\t\t\t\t...(index.unique !== undefined && { unique: index.unique }),\n\t\t\t\t\t\t...(index.type !== undefined &&\n\t\t\t\t\t\t\tisValidIndexType(index.type) && { type: index.type }),\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\t// Find removed indexes\n\t\tfor (const [signature, index] of oldIndexMap) {\n\t\t\tif (!newIndexMap.has(signature)) {\n\t\t\t\tconst indexName =\n\t\t\t\t\tindex.name ?? `idx_${tableName}_${index.fields.join(\"_\")}`;\n\t\t\t\tdifferences.push({\n\t\t\t\t\ttype: \"indexRemoved\",\n\t\t\t\t\ttableName,\n\t\t\t\t\tindexName,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\treturn differences;\n\t}\n\n\t/**\n\t * Get index signature for comparison\n\t */\n\tprivate getIndexSignature(index: {\n\t\treadonly fields: readonly string[];\n\t\treadonly unique?: boolean;\n\t\treadonly type?: string;\n\t}): string {\n\t\tconst fields = [...index.fields].sort().join(\",\");\n\t\tconst unique = index.unique ? \"unique\" : \"normal\";\n\t\tconst type = index.type ?? \"btree\";\n\t\treturn `${fields}:${unique}:${type}`;\n\t}\n}\n\n/**\n * Create schema differ instance\n */\nexport function createSchemaDiffer(): SchemaDiffer {\n\treturn new ForgeSchemaDiffer();\n}\n","/**\n * Migration Generator Implementation (~250 LOC)\n *\n * Generates migration operations and TypeScript migration files from schema differences.\n */\n\nimport {\n\tMigration,\n\tMigrationGenerator,\n\tMigrationMetadata,\n\tMigrationOperation,\n\tMigrationSystemError,\n\tSchemaDiff,\n} from \"../types/core/migration\";\n\n/**\n * Migration generator implementation\n */\nexport class ForgeMigrationGenerator implements MigrationGenerator {\n\t/**\n\t * Escape string for use in template literals\n\t */\n\tprivate escapeString(str: string): string {\n\t\treturn str\n\t\t\t.replace(/\\\\/g, \"\\\\\\\\\")\n\t\t\t.replace(/'/g, \"\\\\'\")\n\t\t\t.replace(/\"/g, '\\\\\"')\n\t\t\t.replace(/`/g, \"\\\\`\")\n\t\t\t.replace(/\\$/g, \"\\\\$\")\n\t\t\t.replace(/\\n/g, \"\\\\n\")\n\t\t\t.replace(/\\r/g, \"\\\\r\")\n\t\t\t.replace(/\\t/g, \"\\\\t\");\n\t}\n\n\t/**\n\t * Generate complete migration from differences\n\t */\n\tgenerate(\n\t\tdifferences: readonly SchemaDiff[],\n\t\tmetadata: Omit<MigrationMetadata, \"timestamp\">,\n\t): Migration {\n\t\ttry {\n\t\t\tconst operationsResult = this.generateOperations(differences);\n\n\t\t\tconst migration: Migration = {\n\t\t\t\tmetadata: {\n\t\t\t\t\t...metadata,\n\t\t\t\t\ttimestamp: Date.now(),\n\t\t\t\t},\n\t\t\t\toperations: operationsResult,\n\t\t\t};\n\n\t\t\treturn migration;\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthrow new MigrationSystemError(\n\t\t\t\t`Failed to generate migration: ${message}`,\n\t\t\t\t\"GENERATION_ERROR\",\n\t\t\t\terror,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Generate operations from differences\n\t */\n\tgenerateOperations(\n\t\tdifferences: readonly SchemaDiff[],\n\t): readonly MigrationOperation[] {\n\t\ttry {\n\t\t\tconst operations: MigrationOperation[] = [];\n\n\t\t\tfor (const diff of differences) {\n\t\t\t\tconst op = this.generateOperation(diff);\n\t\t\t\toperations.push(op);\n\t\t\t}\n\n\t\t\treturn operations;\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthrow new MigrationSystemError(\n\t\t\t\t`Failed to generate operations: ${message}`,\n\t\t\t\t\"GENERATION_ERROR\",\n\t\t\t\terror,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Generate operation for a single difference\n\t */\n\tprivate generateOperation(diff: SchemaDiff): MigrationOperation {\n\t\tswitch (diff.type) {\n\t\t\tcase \"tableAdded\":\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"createTable\",\n\t\t\t\t\tschema: diff.schema,\n\t\t\t\t};\n\n\t\t\tcase \"tableRemoved\":\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"dropTable\",\n\t\t\t\t\ttableName: diff.tableName,\n\t\t\t\t};\n\n\t\t\tcase \"tableRenamed\":\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"renameTable\",\n\t\t\t\t\tfrom: diff.from,\n\t\t\t\t\tto: diff.to,\n\t\t\t\t};\n\n\t\t\tcase \"fieldAdded\": {\n\t\t\t\t// Relation fields have no direct DB column — differ produces\n\t\t\t\t// separate diffs for the actual FK column (e.g. tagId).\n\t\t\t\t// But we still need to update _datrix meta schema.\n\t\t\t\tif (diff.definition.type === \"relation\") {\n\t\t\t\t\treturn {\n\t\t\t\t\t\ttype: \"alterTable\",\n\t\t\t\t\t\ttableName: diff.tableName,\n\t\t\t\t\t\toperations: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ttype: \"addMetaField\",\n\t\t\t\t\t\t\t\tfield: diff.fieldName,\n\t\t\t\t\t\t\t\tdefinition: diff.definition,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"alterTable\",\n\t\t\t\t\ttableName: diff.tableName,\n\t\t\t\t\toperations: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"addColumn\",\n\t\t\t\t\t\t\tcolumn: diff.fieldName,\n\t\t\t\t\t\t\tdefinition: diff.definition,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tcase \"fieldRemoved\": {\n\t\t\t\t// Relation fields have no direct DB column\n\t\t\t\t// But we still need to update _datrix meta schema.\n\t\t\t\tif (diff.definition.type === \"relation\") {\n\t\t\t\t\treturn {\n\t\t\t\t\t\ttype: \"alterTable\",\n\t\t\t\t\t\ttableName: diff.tableName,\n\t\t\t\t\t\toperations: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ttype: \"dropMetaField\",\n\t\t\t\t\t\t\t\tfield: diff.fieldName,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"alterTable\",\n\t\t\t\t\ttableName: diff.tableName,\n\t\t\t\t\toperations: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"dropColumn\",\n\t\t\t\t\t\t\tcolumn: diff.fieldName,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tcase \"fieldModified\": {\n\t\t\t\tconst operations = [];\n\n\t\t\t\t// Relation FK rename: foreignKey changed → rename the actual DB column\n\t\t\t\tif (\n\t\t\t\t\tdiff.oldDefinition.type === \"relation\" &&\n\t\t\t\t\tdiff.newDefinition.type === \"relation\" &&\n\t\t\t\t\tdiff.oldDefinition.foreignKey !== diff.newDefinition.foreignKey\n\t\t\t\t) {\n\t\t\t\t\tconst oldFK =\n\t\t\t\t\t\tdiff.oldDefinition.foreignKey ?? `${diff.oldDefinition.model}Id`;\n\t\t\t\t\tconst newFK =\n\t\t\t\t\t\tdiff.newDefinition.foreignKey ?? `${diff.newDefinition.model}Id`;\n\t\t\t\t\tif (oldFK !== newFK) {\n\t\t\t\t\t\toperations.push({\n\t\t\t\t\t\t\ttype: \"renameColumn\" as const,\n\t\t\t\t\t\t\tfrom: oldFK,\n\t\t\t\t\t\t\tto: newFK,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Relation field modified — update _datrix meta schema\n\t\t\t\tif (\n\t\t\t\t\tdiff.oldDefinition.type === \"relation\" ||\n\t\t\t\t\tdiff.newDefinition.type === \"relation\"\n\t\t\t\t) {\n\t\t\t\t\toperations.push({\n\t\t\t\t\t\ttype: \"modifyMetaField\" as const,\n\t\t\t\t\t\tfield: diff.fieldName,\n\t\t\t\t\t\tnewDefinition: diff.newDefinition,\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\t// If no special operation was generated, fall back to modifyColumn\n\t\t\t\tif (operations.length === 0) {\n\t\t\t\t\toperations.push({\n\t\t\t\t\t\ttype: \"modifyColumn\" as const,\n\t\t\t\t\t\tcolumn: diff.fieldName,\n\t\t\t\t\t\tnewDefinition: diff.newDefinition,\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"alterTable\",\n\t\t\t\t\ttableName: diff.tableName,\n\t\t\t\t\toperations,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tcase \"fieldRenamed\":\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"alterTable\",\n\t\t\t\t\ttableName: diff.tableName,\n\t\t\t\t\toperations: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"renameColumn\",\n\t\t\t\t\t\t\tfrom: diff.from,\n\t\t\t\t\t\t\tto: diff.to,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t};\n\n\t\t\tcase \"indexAdded\":\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"createIndex\",\n\t\t\t\t\ttableName: diff.tableName,\n\t\t\t\t\tindex: diff.index,\n\t\t\t\t};\n\n\t\t\tcase \"indexRemoved\":\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"dropIndex\",\n\t\t\t\t\ttableName: diff.tableName,\n\t\t\t\t\tindexName: diff.indexName,\n\t\t\t\t};\n\t\t}\n\t}\n\n\t/**\n\t * Generate TypeScript migration file content\n\t */\n\tgenerateFile(migration: Migration): string {\n\t\tconst { metadata, operations } = migration;\n\n\t\tconst operationsCode = this.generateOperationsCode(operations, 2);\n\n\t\t// Escape metadata strings to prevent injection\n\t\tconst escapedName = this.escapeString(metadata.name);\n\t\tconst escapedVersion = this.escapeString(metadata.version);\n\t\tconst escapedDescription = metadata.description\n\t\t\t? this.escapeString(metadata.description)\n\t\t\t: undefined;\n\t\tconst escapedAuthor = metadata.author\n\t\t\t? this.escapeString(metadata.author)\n\t\t\t: undefined;\n\n\t\treturn `/**\n * Migration: ${escapedName}\n * Version: ${escapedVersion}\n * Created: ${new Date(metadata.timestamp).toISOString()}\n ${escapedDescription ? `* Description: ${escapedDescription}` : \"\"}\n ${escapedAuthor ? `* Author: ${escapedAuthor}` : \"\"}\n */\n\nimport type { Migration } from '../types/core/migration';\n\nexport const migration: Migration = {\n metadata: {\n name: '${escapedName}',\n version: '${escapedVersion}',\n timestamp: ${metadata.timestamp},\n ${escapedDescription ? `description: '${escapedDescription}',` : \"\"}\n ${escapedAuthor ? `author: '${escapedAuthor}',` : \"\"}\n },\n\n operations: [\n${operationsCode}\n ]\n};\n\nexport default migration;\n`;\n\t}\n\n\t/**\n\t * Generate TypeScript code for operations array\n\t */\n\tprivate generateOperationsCode(\n\t\toperations: readonly MigrationOperation[],\n\t\tindent: number,\n\t): string {\n\t\tconst indentStr = \" \".repeat(indent);\n\n\t\treturn operations\n\t\t\t.map((op) => {\n\t\t\t\tswitch (op.type) {\n\t\t\t\t\tcase \"createTable\":\n\t\t\t\t\t\treturn `${indentStr}{\n${indentStr} type: 'createTable',\n${indentStr} schema: ${JSON.stringify(op.schema, null, 2).replace(/\\n/g, `\\n${indentStr} `)}\n${indentStr}}`;\n\n\t\t\t\t\tcase \"dropTable\":\n\t\t\t\t\t\treturn `${indentStr}{\n${indentStr} type: 'dropTable',\n${indentStr} tableName: '${op.tableName}'\n${indentStr}}`;\n\n\t\t\t\t\tcase \"alterTable\":\n\t\t\t\t\t\treturn `${indentStr}{\n${indentStr} type: 'alterTable',\n${indentStr} tableName: '${op.tableName}',\n${indentStr} operations: ${JSON.stringify(op.operations, null, 2).replace(/\\n/g, `\\n${indentStr} `)}\n${indentStr}}`;\n\n\t\t\t\t\tcase \"createIndex\":\n\t\t\t\t\t\treturn `${indentStr}{\n${indentStr} type: 'createIndex',\n${indentStr} tableName: '${op.tableName}',\n${indentStr} index: ${JSON.stringify(op.index, null, 2).replace(/\\n/g, `\\n${indentStr} `)}\n${indentStr}}`;\n\n\t\t\t\t\tcase \"dropIndex\":\n\t\t\t\t\t\treturn `${indentStr}{\n${indentStr} type: 'dropIndex',\n${indentStr} tableName: '${op.tableName}',\n${indentStr} indexName: '${op.indexName}'\n${indentStr}}`;\n\n\t\t\t\t\tcase \"renameTable\":\n\t\t\t\t\t\treturn `${indentStr}{\n${indentStr} type: 'renameTable',\n${indentStr} from: '${op.from}',\n${indentStr} to: '${op.to}'\n${indentStr}}`;\n\n\t\t\t\t\tcase \"raw\":\n\t\t\t\t\t\treturn `${indentStr}{\n${indentStr} type: 'raw',\n${indentStr} sql: \\`${op.sql}\\`,\n${indentStr} params: ${JSON.stringify(op.params ?? [])}\n${indentStr}}`;\n\n\t\t\t\t\tcase \"dataTransfer\":\n\t\t\t\t\t\treturn `${indentStr}{\n${indentStr} type: 'dataTransfer',\n${indentStr} description: '${op.description}'\n${indentStr}}`;\n\t\t\t\t}\n\t\t\t})\n\t\t\t.join(\",\\n\");\n\t}\n}\n\n/**\n * Create migration generator instance\n */\nexport function createMigrationGenerator(): MigrationGenerator {\n\treturn new ForgeMigrationGenerator();\n}\n","/**\n * Migration History Manager Implementation\n *\n * Manages migration execution history in the database.\n * Uses datrix.raw for all CRUD operations - no raw SQL.\n */\n\nimport { createHash } from \"crypto\";\nimport {\n\tMigration,\n\tMigrationHistory,\n\tMigrationHistoryRecord,\n\tMigrationStatus,\n\tMigrationSystemError,\n} from \"../types/core/migration\";\nimport { IDatrix } from \"../types/core\";\nimport { DatrixEntry } from \"../types/core/schema\";\nimport { DEFAULT_MIGRATION_MODEL, FORJA_META_MODEL } from \"./schema\";\n\n/**\n * Migration history entry type (matches the schema)\n */\ninterface MigrationEntry extends DatrixEntry {\n\tname: string;\n\tversion: string;\n\texecutionTime: number;\n\tstatus: MigrationStatus;\n\tchecksum?: string;\n\terror?: string;\n\tappliedAt: Date;\n}\n\n/**\n * Migration history manager implementation\n */\nexport class ForgeMigrationHistory implements MigrationHistory {\n\tprivate readonly datrix: IDatrix;\n\tprivate readonly modelName: string;\n\tprivate initialized = false;\n\n\tconstructor(datrix: IDatrix, modelName: string = DEFAULT_MIGRATION_MODEL) {\n\t\tthis.datrix = datrix;\n\t\tthis.modelName = modelName;\n\t}\n\n\t/**\n\t * Initialize migrations tracking table\n\t *\n\t * The table is created via adapter.createTable using the migration schema.\n\t * Schema is already registered in Datrix initialization.\n\t */\n\tasync initialize(): Promise<void> {\n\t\tif (this.initialized) {\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tconst schema = this.datrix.getSchemas().get(this.modelName);\n\t\t\tif (!schema) {\n\t\t\t\tthrow new MigrationSystemError(\n\t\t\t\t\t`Migration schema '${this.modelName}' not found in registry`,\n\t\t\t\t\t\"MIGRATION_ERROR\",\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst adapter = this.datrix.getAdapter();\n\n\t\t\t// Ensure _datrix metadata table exists before any other table operation\n\t\t\tconst metaExists = await adapter.tableExists(FORJA_META_MODEL);\n\t\t\tif (!metaExists) {\n\t\t\t\tconst metaSchema = this.datrix.getSchemas().get(FORJA_META_MODEL);\n\t\t\t\tif (!metaSchema) {\n\t\t\t\t\tthrow new MigrationSystemError(\n\t\t\t\t\t\t`Schema '${FORJA_META_MODEL}' not found in registry`,\n\t\t\t\t\t\t\"MIGRATION_ERROR\",\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\tawait adapter.createTable(metaSchema);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tthrow new MigrationSystemError(\n\t\t\t\t\t\t`Failed to create _datrix metadata table: ${(error as Error).message}`,\n\t\t\t\t\t\t\"MIGRATION_ERROR\",\n\t\t\t\t\t\terror,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst tableName = schema.tableName ?? schema.name;\n\t\t\tconst exists = await adapter.tableExists(tableName);\n\n\t\t\tif (!exists) {\n\t\t\t\ttry {\n\t\t\t\t\tawait adapter.createTable(schema);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tthrow new MigrationSystemError(\n\t\t\t\t\t\t`Failed to create migrations table: ${(error as Error).message}`,\n\t\t\t\t\t\t\"MIGRATION_ERROR\",\n\t\t\t\t\t\terror,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.initialized = true;\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthrow new MigrationSystemError(\n\t\t\t\t`Failed to initialize migration history: ${message}`,\n\t\t\t\t\"MIGRATION_ERROR\",\n\t\t\t\terror,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Record migration execution\n\t */\n\tasync record(\n\t\tmigration: Migration,\n\t\texecutionTime: number,\n\t\tstatus: MigrationStatus,\n\t\terror?: Error,\n\t): Promise<void> {\n\t\ttry {\n\t\t\tconst checksum = this.calculateChecksum(migration);\n\n\t\t\tawait this.datrix.raw.create<MigrationEntry>(this.modelName, {\n\t\t\t\tname: migration.metadata.name,\n\t\t\t\tversion: migration.metadata.version,\n\t\t\t\texecutionTime,\n\t\t\t\tstatus,\n\t\t\t\tchecksum,\n\t\t\t\terror: error?.message || \"\",\n\t\t\t\tappliedAt: new Date(),\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthrow new MigrationSystemError(\n\t\t\t\t`Failed to record migration: ${message}`,\n\t\t\t\t\"MIGRATION_ERROR\",\n\t\t\t\terror,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Get all migration records\n\t */\n\tasync getAll(): Promise<readonly MigrationHistoryRecord[]> {\n\t\ttry {\n\t\t\tconst entries = await this.datrix.raw.findMany<MigrationEntry>(\n\t\t\t\tthis.modelName,\n\t\t\t\t{\n\t\t\t\t\torderBy: { appliedAt: \"asc\" },\n\t\t\t\t},\n\t\t\t);\n\n\t\t\tconst records: MigrationHistoryRecord[] = entries.map((entry) => ({\n\t\t\t\tid: entry.id,\n\t\t\t\tname: entry.name,\n\t\t\t\tversion: entry.version,\n\t\t\t\tappliedAt: entry.appliedAt,\n\t\t\t\texecutionTime: entry.executionTime,\n\t\t\t\tstatus: entry.status,\n\t\t\t\t...(entry.checksum && { checksum: entry.checksum }),\n\t\t\t\t...(entry.error && { error: entry.error }),\n\t\t\t}));\n\n\t\t\treturn records;\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthrow new MigrationSystemError(\n\t\t\t\t`Failed to get migration history: ${message}`,\n\t\t\t\t\"MIGRATION_ERROR\",\n\t\t\t\terror,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Get last applied migration\n\t */\n\tasync getLast(): Promise<MigrationHistoryRecord | undefined> {\n\t\ttry {\n\t\t\tconst entries = await this.datrix.raw.findMany<MigrationEntry>(\n\t\t\t\tthis.modelName,\n\t\t\t\t{\n\t\t\t\t\twhere: { status: \"completed\" },\n\t\t\t\t\torderBy: { appliedAt: \"desc\" },\n\t\t\t\t\tlimit: 1,\n\t\t\t\t},\n\t\t\t);\n\n\t\t\tconst entry = entries[0];\n\t\t\tif (!entry) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\n\t\t\tconst record: MigrationHistoryRecord = {\n\t\t\t\tid: entry.id,\n\t\t\t\tname: entry.name,\n\t\t\t\tversion: entry.version,\n\t\t\t\tappliedAt: entry.appliedAt,\n\t\t\t\texecutionTime: entry.executionTime,\n\t\t\t\tstatus: entry.status,\n\t\t\t\t...(entry.checksum && { checksum: entry.checksum }),\n\t\t\t\t...(entry.error && { error: entry.error }),\n\t\t\t};\n\n\t\t\treturn record;\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthrow new MigrationSystemError(\n\t\t\t\t`Failed to get last migration: ${message}`,\n\t\t\t\t\"MIGRATION_ERROR\",\n\t\t\t\terror,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Check if migration was applied\n\t */\n\tasync isApplied(version: string): Promise<boolean> {\n\t\ttry {\n\t\t\tconst count = await this.datrix.raw.count<MigrationEntry>(this.modelName, {\n\t\t\t\tversion,\n\t\t\t\tstatus: \"completed\",\n\t\t\t});\n\n\t\t\treturn count > 0;\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthrow new MigrationSystemError(\n\t\t\t\t`Failed to check migration status: ${message}`,\n\t\t\t\t\"MIGRATION_ERROR\",\n\t\t\t\terror,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Calculate migration checksum\n\t */\n\tcalculateChecksum(migration: Migration): string {\n\t\tconst content = JSON.stringify({\n\t\t\toperations: migration.operations,\n\t\t});\n\n\t\treturn createHash(\"sha256\").update(content).digest(\"hex\");\n\t}\n\n\t/**\n\t * Verify migration integrity\n\t */\n\tverifyChecksum(\n\t\tmigration: Migration,\n\t\trecord: MigrationHistoryRecord,\n\t): boolean {\n\t\tif (!record.checksum) {\n\t\t\treturn true;\n\t\t}\n\n\t\tconst currentChecksum = this.calculateChecksum(migration);\n\t\treturn currentChecksum === record.checksum;\n\t}\n}\n\n/**\n * Create migration history manager\n */\nexport function createMigrationHistory(\n\tdatrix: IDatrix,\n\ttableName?: string,\n): MigrationHistory {\n\treturn new ForgeMigrationHistory(datrix, tableName);\n}\n","/**\n * Migration Runner Implementation\n *\n * Executes migrations and manages migration plans.\n */\n\nimport type {\n\tMigrationRunner,\n\tMigration,\n\tMigrationHistory,\n\tMigrationHistoryRecord,\n\tMigrationExecutionResult,\n\tMigrationOperation,\n\tMigrationFilePlan,\n} from \"../types/core/migration\";\nimport { MigrationSystemError } from \"../types/core/migration\";\nimport { DatabaseAdapter, Transaction } from \"../types/adapter\";\n\n/**\n * Migration runner implementation\n */\nexport class ForgeMigrationRunner implements MigrationRunner {\n\tprivate readonly adapter: DatabaseAdapter;\n\tprivate readonly history: MigrationHistory;\n\tprivate readonly migrations: readonly Migration[];\n\n\tconstructor(\n\t\tadapter: DatabaseAdapter,\n\t\thistory: MigrationHistory,\n\t\tmigrations: readonly Migration[],\n\t) {\n\t\tthis.adapter = adapter;\n\t\tthis.history = history;\n\t\tthis.migrations = migrations;\n\t}\n\n\t/**\n\t * Get pending migrations\n\t */\n\tasync getPending(): Promise<readonly Migration[]> {\n\t\ttry {\n\t\t\t// Initialize history table\n\t\t\tawait this.history.initialize();\n\n\t\t\t// Get applied migrations\n\t\t\tconst appliedResult = await this.history.getAll();\n\n\t\t\tconst appliedVersions = new Set(\n\t\t\t\tappliedResult\n\t\t\t\t\t.filter((record) => record.status === \"completed\")\n\t\t\t\t\t.map((record) => record.version),\n\t\t\t);\n\n\t\t\t// Filter pending migrations\n\t\t\tconst pending = this.migrations.filter(\n\t\t\t\t(migration) => !appliedVersions.has(migration.metadata.version),\n\t\t\t);\n\n\t\t\treturn pending;\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthrow new MigrationSystemError(\n\t\t\t\t`Failed to get pending migrations: ${message}`,\n\t\t\t\t\"MIGRATION_ERROR\",\n\t\t\t\terror,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Get applied migrations\n\t */\n\tasync getApplied(): Promise<readonly MigrationHistoryRecord[]> {\n\t\tawait this.history.initialize();\n\t\treturn await this.history.getAll();\n\t}\n\n\t/**\n\t * Run pending migrations\n\t */\n\tasync runPending(options?: {\n\t\treadonly target?: string;\n\t\treadonly dryRun?: boolean;\n\t}): Promise<readonly MigrationExecutionResult[]> {\n\t\ttry {\n\t\t\tlet migrationsToRun = await this.getPending();\n\n\t\t\t// Filter by target version if specified\n\t\t\tif (options?.target) {\n\t\t\t\tconst targetIndex = migrationsToRun.findIndex(\n\t\t\t\t\t(m) => m.metadata.version === options.target,\n\t\t\t\t);\n\n\t\t\t\tif (targetIndex === -1) {\n\t\t\t\t\tthrow new MigrationSystemError(\n\t\t\t\t\t\t`Target version ${options.target} not found`,\n\t\t\t\t\t\t\"MIGRATION_ERROR\",\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tmigrationsToRun = migrationsToRun.slice(0, targetIndex + 1);\n\t\t\t}\n\n\t\t\t// Handle dry run - simulate migrations without executing\n\t\t\tif (options?.dryRun) {\n\t\t\t\tconst simulatedResults: MigrationExecutionResult[] =\n\t\t\t\t\tmigrationsToRun.map(\n\t\t\t\t\t\t(migration): MigrationExecutionResult => ({\n\t\t\t\t\t\t\tmigration,\n\t\t\t\t\t\t\tstatus: \"pending\",\n\t\t\t\t\t\t\texecutionTime: 0,\n\t\t\t\t\t\t}),\n\t\t\t\t\t);\n\t\t\t\treturn simulatedResults;\n\t\t\t}\n\n\t\t\tconst results: MigrationExecutionResult[] = [];\n\n\t\t\tfor (const migration of migrationsToRun) {\n\t\t\t\tconst result = await this.runOne(migration);\n\n\t\t\t\tresults.push(result);\n\n\t\t\t\t// Stop on failure\n\t\t\t\tif (result.status === \"failed\") {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn results;\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthrow new MigrationSystemError(\n\t\t\t\t`Failed to run pending migrations: ${message}`,\n\t\t\t\t\"MIGRATION_ERROR\",\n\t\t\t\terror,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Run specific migration\n\t *\n\t * Operations are split into 3 phases for adapter compatibility:\n\t * - Phase 1 (pre-tx): createTable — run before transaction\n\t * - Phase 2 (tx): alterTable, dataTransfer, createIndex, dropIndex, renameTable, raw — inside transaction\n\t * - Phase 3 (post-tx): dropTable — run after successful commit\n\t *\n\t * This split is necessary because some adapters (e.g. MongoDB) cannot run\n\t * DDL operations (create/drop collection) inside a multi-document transaction.\n\t * For SQL adapters this is harmless since DDL is transaction-safe anyway.\n\t *\n\t * NOTE: On failure during phase 2, tables created in phase 1 may remain\n\t * as empty leftovers. This is acceptable — no data loss occurs.\n\t */\n\tasync runOne(migration: Migration): Promise<MigrationExecutionResult> {\n\t\tconst startTime = Date.now();\n\n\t\t// Split operations into 3 phases, preserving relative order within each phase\n\t\tconst { preOps, txOps, postOps } = this.splitOperationsByPhase(\n\t\t\tmigration.operations,\n\t\t);\n\n\t\ttry {\n\t\t\t// Phase 1: createTable operations (outside transaction)\n\t\t\tfor (const operation of preOps) {\n\t\t\t\ttry {\n\t\t\t\t\tawait this.executeOperationDirect(operation);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconst executionTime = Date.now() - startTime;\n\t\t\t\t\tconst err = error instanceof Error ? error : new Error(String(error));\n\t\t\t\t\tawait this.recordSafe(migration, executionTime, \"failed\", err);\n\t\t\t\t\treturn { migration, status: \"failed\", executionTime, error: err };\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Phase 2: DML and non-DDL operations (inside transaction)\n\t\t\tconst tx = await this.adapter.beginTransaction();\n\t\t\ttry {\n\t\t\t\tfor (const operation of txOps) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait this.executeOperation(tx, operation);\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tawait tx.rollback();\n\t\t\t\t\t\tconst executionTime = Date.now() - startTime;\n\t\t\t\t\t\tconst err =\n\t\t\t\t\t\t\terror instanceof Error ? error : new Error(String(error));\n\t\t\t\t\t\tawait this.recordSafe(migration, executionTime, \"failed\", err);\n\t\t\t\t\t\treturn { migration, status: \"failed\", executionTime, error: err };\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\tawait tx.commit();\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconst executionTime = Date.now() - startTime;\n\t\t\t\t\tconst err = error instanceof Error ? error : new Error(String(error));\n\t\t\t\t\treturn { migration, status: \"failed\", executionTime, error: err };\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tawait tx.rollback();\n\t\t\t\tconst executionTime = Date.now() - startTime;\n\t\t\t\tconst err = error instanceof Error ? error : new Error(String(error));\n\t\t\t\tawait this.recordSafe(migration, executionTime, \"failed\", err);\n\t\t\t\treturn { migration, status: \"failed\", executionTime, error: err };\n\t\t\t}\n\n\t\t\t// Phase 3: dropTable operations (after successful commit)\n\t\t\tfor (const operation of postOps) {\n\t\t\t\ttry {\n\t\t\t\t\tawait this.executeOperationDirect(operation);\n\t\t\t\t} catch (error) {\n\t\t\t\t\t// Drop failures after successful commit are warnings, not failures.\n\t\t\t\t\t// Data is already safely migrated — leftover tables can be cleaned manually.\n\t\t\t\t\tconst executionTime = Date.now() - startTime;\n\t\t\t\t\tconst warnings = [\n\t\t\t\t\t\t`Post-commit dropTable failed: ${(error as Error).message}`,\n\t\t\t\t\t];\n\t\t\t\t\tawait this.recordSafe(migration, executionTime, \"completed\");\n\t\t\t\t\treturn { migration, status: \"completed\", executionTime, warnings };\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst executionTime = Date.now() - startTime;\n\t\t\tconst warnings: string[] = [];\n\t\t\ttry {\n\t\t\t\tawait this.history.record(migration, executionTime, \"completed\");\n\t\t\t} catch (error) {\n\t\t\t\twarnings.push(\n\t\t\t\t\t`Failed to record migration history: ${(error as Error).message}`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tmigration,\n\t\t\t\tstatus: \"completed\",\n\t\t\t\texecutionTime,\n\t\t\t\t...(warnings.length > 0 && { warnings }),\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthrow new MigrationSystemError(\n\t\t\t\t`Failed to run migration: ${message}`,\n\t\t\t\t\"MIGRATION_ERROR\",\n\t\t\t\terror,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Split migration operations into 3 phases.\n\t * Preserves relative order within each phase.\n\t *\n\t * - pre: createTable (must exist before DML references them)\n\t * - tx: everything else except dropTable\n\t * - post: dropTable (safe to drop after data is committed)\n\t */\n\tprivate splitOperationsByPhase(operations: readonly MigrationOperation[]): {\n\t\treadonly preOps: readonly MigrationOperation[];\n\t\treadonly txOps: readonly MigrationOperation[];\n\t\treadonly postOps: readonly MigrationOperation[];\n\t} {\n\t\tconst preOps: MigrationOperation[] = [];\n\t\tconst txOps: MigrationOperation[] = [];\n\t\tconst postOps: MigrationOperation[] = [];\n\n\t\tfor (const op of operations) {\n\t\t\tif (op.type === \"createTable\") {\n\t\t\t\tpreOps.push(op);\n\t\t\t} else if (op.type === \"dropTable\" || op.type === \"renameTable\") {\n\t\t\t\tpostOps.push(op);\n\t\t\t} else {\n\t\t\t\ttxOps.push(op);\n\t\t\t}\n\t\t}\n\n\t\treturn { preOps, txOps, postOps };\n\t}\n\n\t/**\n\t * Execute a migration operation directly on the adapter (outside transaction)\n\t */\n\tprivate async executeOperationDirect(\n\t\toperation: MigrationOperation,\n\t): Promise<void> {\n\t\tswitch (operation.type) {\n\t\t\tcase \"createTable\":\n\t\t\t\treturn await this.adapter.createTable(operation.schema);\n\t\t\tcase \"dropTable\":\n\t\t\t\treturn await this.adapter.dropTable(operation.tableName);\n\t\t\tcase \"renameTable\":\n\t\t\t\treturn await this.adapter.renameTable(operation.from, operation.to);\n\t\t\tdefault:\n\t\t\t\tthrow new MigrationSystemError(\n\t\t\t\t\t`Operation type '${operation.type}' cannot run outside transaction`,\n\t\t\t\t\t\"MIGRATION_ERROR\",\n\t\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Record migration history safely (never throws)\n\t */\n\tprivate async recordSafe(\n\t\tmigration: Migration,\n\t\texecutionTime: number,\n\t\tstatus: \"completed\" | \"failed\",\n\t\terror?: Error,\n\t): Promise<void> {\n\t\ttry {\n\t\t\tawait this.history.record(migration, executionTime, status, error);\n\t\t} catch {\n\t\t\t// Swallow — recording failure should not mask the original error\n\t\t}\n\t}\n\n\t/**\n\t * Get migration plan\n\t */\n\tgetPlan(options?: { readonly target?: string }): MigrationFilePlan {\n\t\ttry {\n\t\t\tlet migrations = [...this.migrations];\n\n\t\t\tif (options?.target) {\n\t\t\t\tconst targetIndex = migrations.findIndex(\n\t\t\t\t\t(m) => m.metadata.version === options.target,\n\t\t\t\t);\n\n\t\t\t\tif (targetIndex === -1) {\n\t\t\t\t\tthrow new MigrationSystemError(\n\t\t\t\t\t\t`Target version ${options.target} not found`,\n\t\t\t\t\t\t\"MIGRATION_ERROR\",\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tmigrations = migrations.slice(0, targetIndex + 1);\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tmigrations,\n\t\t\t\t...(options?.target !== undefined && { target: options.target }),\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthrow new MigrationSystemError(\n\t\t\t\t`Failed to create migration plan: ${message}`,\n\t\t\t\t\"MIGRATION_ERROR\",\n\t\t\t\terror,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Execute a single migration operation within a transaction\n\t */\n\tprivate async executeOperation(\n\t\ttx: Transaction,\n\t\toperation: MigrationOperation,\n\t): Promise<void> {\n\t\tswitch (operation.type) {\n\t\t\tcase \"createTable\":\n\t\t\t\treturn await tx.createTable(operation.schema);\n\n\t\t\tcase \"dropTable\":\n\t\t\t\treturn await tx.dropTable(operation.tableName);\n\n\t\t\tcase \"alterTable\":\n\t\t\t\treturn await tx.alterTable(operation.tableName, operation.operations);\n\n\t\t\tcase \"createIndex\":\n\t\t\t\treturn await tx.addIndex(operation.tableName, operation.index);\n\n\t\t\tcase \"dropIndex\":\n\t\t\t\treturn await tx.dropIndex(operation.tableName, operation.indexName);\n\n\t\t\tcase \"renameTable\":\n\t\t\t\treturn await tx.renameTable(operation.from, operation.to);\n\n\t\t\tcase \"raw\":\n\t\t\t\tawait tx.executeRawQuery(operation.sql, operation.params ?? []);\n\t\t\t\treturn;\n\n\t\t\tcase \"dataTransfer\":\n\t\t\t\treturn await operation.execute(tx);\n\t\t}\n\t}\n}\n\n/**\n * Create migration runner\n */\nexport function createMigrationRunner(\n\tadapter: DatabaseAdapter,\n\thistory: MigrationHistory,\n\tmigrations: readonly Migration[],\n): MigrationRunner {\n\treturn new ForgeMigrationRunner(adapter, history, migrations);\n}\n","/**\n * Migration Session\n *\n * Provides a fluent API for managing database migrations.\n * Entry point: datrix.beginMigrate()\n *\n * Features:\n * - Compares current schemas with database state\n * - Detects ambiguous changes (rename vs drop+add)\n * - Interactive resolution for ambiguous cases\n * - Preview and apply migrations\n */\n\nimport { DatabaseAdapter, QueryRunner } from \"../types/adapter\";\nimport {\n\tSchemaDefinition,\n\tFieldDefinition,\n\tDatrixRecord,\n} from \"../types/core/schema\";\nimport {\n\tMigration,\n\tMigrationOperation,\n\tDataTransferOperation,\n\tMigrationSystemError,\n\tSchemaDiff,\n\tFieldAddedDiff,\n\tMigrationExecutionResult,\n} from \"../types/core/migration\";\nimport { IDatrix } from \"../types/core\";\nimport { ForgeSchemaDiffer } from \"./differ\";\nimport { ForgeMigrationGenerator } from \"./generator\";\nimport { ForgeMigrationHistory } from \"./history\";\nimport { ForgeMigrationRunner } from \"./runner\";\n\n/**\n * Ambiguous change types\n */\nexport type AmbiguousChangeType =\n\t| \"column_rename_or_replace\"\n\t| \"table_rename_or_replace\"\n\t| \"fk_column_drop\"\n\t| \"junction_table_drop\"\n\t| \"junction_table_rename_or_replace\"\n\t| \"relation_upgrade_single_to_many\"\n\t| \"relation_downgrade_many_to_single\"\n\t| \"fk_model_change\"\n\t| \"relation_direction_flip\";\n\n/**\n * Ambiguous action types\n */\nexport type AmbiguousActionType =\n\t| \"rename\"\n\t| \"drop_and_add\"\n\t| \"confirm_drop\"\n\t| \"migrate_to_junction\"\n\t| \"migrate_first\"\n\t| \"fresh_start\"\n\t| \"keep_column\"\n\t| \"drop_and_recreate\";\n\n/**\n * Ambiguous change that requires user input\n */\nexport interface AmbiguousChange {\n\treadonly id: string;\n\treadonly tableName: string;\n\treadonly type: AmbiguousChangeType;\n\treadonly removedName: string;\n\treadonly addedName: string;\n\treadonly removedDefinition?: FieldDefinition;\n\treadonly addedDefinition?: FieldDefinition;\n\treadonly possibleActions: readonly AmbiguousAction[];\n\treadonly warning?: string;\n\treadonly affectedRows?: number;\n\tresolved: boolean;\n\tresolvedAction?: AmbiguousAction;\n}\n\n/**\n * Possible action for ambiguous change\n */\nexport interface AmbiguousAction {\n\treadonly type: AmbiguousActionType;\n\treadonly description: string;\n}\n\n/**\n * Migration plan summary\n */\nexport interface MigrationPlan {\n\treadonly tablesToCreate: readonly SchemaDefinition[];\n\treadonly tablesToDrop: readonly string[];\n\treadonly tablesToAlter: readonly {\n\t\treadonly tableName: string;\n\t\treadonly changes: readonly SchemaDiff[];\n\t}[];\n\treadonly operations: readonly MigrationOperation[];\n\treadonly hasChanges: boolean;\n}\n\n/**\n * Migration Session class\n *\n * Created by datrix.beginMigrate()\n */\nexport class MigrationSession {\n\tprivate readonly datrix: IDatrix;\n\tprivate readonly adapter: DatabaseAdapter;\n\tprivate readonly differ: ForgeSchemaDiffer;\n\tprivate readonly generator: ForgeMigrationGenerator;\n\tprivate readonly history: ForgeMigrationHistory;\n\n\tprivate currentSchemas: Map<string, SchemaDefinition> = new Map();\n\tprivate databaseSchemas: Map<string, SchemaDefinition> = new Map();\n\tprivate differences: SchemaDiff[] = [];\n\tprivate _ambiguous: AmbiguousChange[] = [];\n\tprivate initialized = false;\n\n\tconstructor(datrix: IDatrix) {\n\t\tthis.datrix = datrix;\n\t\tthis.adapter = datrix.getAdapter();\n\t\tthis.differ = new ForgeSchemaDiffer();\n\t\tthis.generator = new ForgeMigrationGenerator();\n\n\t\tconst migrationConfig = datrix.getMigrationConfig();\n\t\tthis.history = new ForgeMigrationHistory(datrix, migrationConfig.modelName);\n\t}\n\n\t/**\n\t * Initialize session - load current state from database\n\t */\n\tasync initialize(): Promise<void> {\n\t\tif (this.initialized) {\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\t// Initialize history table\n\t\t\tawait this.history.initialize();\n\n\t\t\t// Load current schemas from Datrix\n\t\t\tconst registry = this.datrix.getSchemas();\n\t\t\tfor (const schema of registry.getAll()) {\n\t\t\t\t// Skip internal migration schema\n\t\t\t\tif (schema.name.startsWith(\"_datrix\")) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tthis.currentSchemas.set(schema.name, schema);\n\t\t\t}\n\n\t\t\t// Load existing schemas from database\n\t\t\tconst tablesResult = await this.adapter.getTables();\n\n\t\t\tfor (const tableName of tablesResult) {\n\t\t\t\t// Skip internal tables\n\t\t\t\tif (tableName.startsWith(\"_datrix\")) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst schemaResult = await this.adapter.getTableSchema(tableName);\n\t\t\t\tthis.databaseSchemas.set(tableName, schemaResult!);\n\t\t\t}\n\n\t\t\t// Compare schemas\n\t\t\tconst oldSchemas: Record<string, SchemaDefinition> = {};\n\t\t\tfor (const [name, schema] of this.databaseSchemas) {\n\t\t\t\toldSchemas[name] = schema;\n\t\t\t}\n\n\t\t\tconst newSchemas: Record<string, SchemaDefinition> = {};\n\t\t\tfor (const [name, schema] of this.currentSchemas) {\n\t\t\t\tnewSchemas[schema.tableName ?? name] = schema;\n\t\t\t}\n\n\t\t\tconst comparison = this.differ.compare(oldSchemas, newSchemas);\n\n\t\t\tthis.differences = [...comparison.differences];\n\n\t\t\t// Detect ambiguous changes\n\t\t\tthis.detectAmbiguousChanges();\n\n\t\t\tthis.initialized = true;\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthrow new MigrationSystemError(\n\t\t\t\t`Failed to initialize migration session: ${message}`,\n\t\t\t\t\"MIGRATION_ERROR\",\n\t\t\t\terror,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Detect ambiguous changes (potential renames, relation changes, etc.)\n\t */\n\tprivate detectAmbiguousChanges(): void {\n\t\t// Group diffs by type and table\n\t\tconst removedFields = new Map<string, SchemaDiff[]>();\n\t\tconst addedFields = new Map<string, SchemaDiff[]>();\n\t\tconst removedTables: SchemaDiff[] = [];\n\t\tconst addedTables: SchemaDiff[] = [];\n\n\t\tfor (const diff of this.differences) {\n\t\t\tif (diff.type === \"fieldRemoved\") {\n\t\t\t\tconst key = diff.tableName;\n\t\t\t\tif (!removedFields.has(key)) {\n\t\t\t\t\tremovedFields.set(key, []);\n\t\t\t\t}\n\t\t\t\tremovedFields.get(key)!.push(diff);\n\t\t\t} else if (diff.type === \"fieldAdded\") {\n\t\t\t\tconst key = diff.tableName;\n\t\t\t\tif (!addedFields.has(key)) {\n\t\t\t\t\taddedFields.set(key, []);\n\t\t\t\t}\n\t\t\t\taddedFields.get(key)!.push(diff);\n\t\t\t} else if (diff.type === \"tableRemoved\") {\n\t\t\t\tremovedTables.push(diff);\n\t\t\t} else if (diff.type === \"tableAdded\") {\n\t\t\t\taddedTables.push(diff);\n\t\t\t}\n\t\t}\n\n\t\t// Collect fieldModified diffs for relation-specific detection\n\t\tconst modifiedFields = new Map<string, SchemaDiff[]>();\n\t\tfor (const diff of this.differences) {\n\t\t\tif (diff.type === \"fieldModified\") {\n\t\t\t\tconst key = diff.tableName;\n\t\t\t\tif (!modifiedFields.has(key)) {\n\t\t\t\t\tmodifiedFields.set(key, []);\n\t\t\t\t}\n\t\t\t\tmodifiedFields.get(key)!.push(diff);\n\t\t\t}\n\t\t}\n\n\t\t// Track which diffs are handled by relation detection\n\t\tconst handledDiffs = new Set<string>();\n\n\t\t// 1. Detect relation type changes (belongsTo ↔ manyToMany)\n\t\tthis.detectRelationTypeChanges(\n\t\t\tremovedFields,\n\t\t\taddedFields,\n\t\t\tremovedTables,\n\t\t\taddedTables,\n\t\t\thandledDiffs,\n\t\t);\n\n\t\t// 2. Detect junction table renames (through name change) - must run before drops\n\t\tthis.detectJunctionTableRenames(removedTables, addedTables, handledDiffs);\n\n\t\t// 3. Detect junction table drops (manyToMany removal)\n\t\tthis.detectJunctionTableDrops(removedTables, handledDiffs);\n\n\t\t// 4. Detect relation direction flips (FK moves from one table to another) - before FK drop detection\n\t\tthis.detectRelationDirectionFlips(removedFields, addedFields, handledDiffs);\n\n\t\t// 5. Detect FK column changes (rename or drop)\n\t\tthis.detectFkColumnChanges(removedFields, addedFields, handledDiffs);\n\n\t\t// 6. Detect column renames (generic, non-FK columns)\n\t\tthis.detectColumnRenames(removedFields, addedFields, handledDiffs);\n\n\t\t// 7. Detect table renames\n\t\tthis.detectTableRenames(removedTables, addedTables, handledDiffs);\n\n\t\t// 8. Detect FK model changes (belongsTo pointing to different model)\n\t\tthis.detectFkModelChanges(modifiedFields, handledDiffs);\n\t}\n\n\t/**\n\t * Detect relation type changes (belongsTo ↔ manyToMany)\n\t */\n\tprivate detectRelationTypeChanges(\n\t\tremovedFields: Map<string, SchemaDiff[]>,\n\t\taddedFields: Map<string, SchemaDiff[]>,\n\t\tremovedTables: SchemaDiff[],\n\t\taddedTables: SchemaDiff[],\n\t\thandledDiffs: Set<string>,\n\t): void {\n\t\t// belongsTo → manyToMany: FK column removed + junction table added\n\t\tfor (const [tableName, removed] of removedFields) {\n\t\t\tfor (const removedDiff of removed) {\n\t\t\t\tif (removedDiff.type !== \"fieldRemoved\") continue;\n\n\t\t\t\t// Check if this looks like a FK column (ends with 'Id')\n\t\t\t\tif (!removedDiff.fieldName.endsWith(\"Id\")) continue;\n\n\t\t\t\tconst relationName = removedDiff.fieldName.slice(0, -2); // remove 'Id'\n\n\t\t\t\t// Look for a new junction table that involves this table\n\t\t\t\tfor (const addedTable of addedTables) {\n\t\t\t\t\tif (addedTable.type !== \"tableAdded\") continue;\n\n\t\t\t\t\tconst junctionName =\n\t\t\t\t\t\taddedTable.schema.tableName ?? addedTable.schema.name;\n\n\t\t\t\t\t// Check if junction table name contains both table names\n\t\t\t\t\tif (this.isJunctionTableFor(junctionName, tableName, relationName)) {\n\t\t\t\t\t\tconst diffKey = `${tableName}.${removedDiff.fieldName}`;\n\t\t\t\t\t\thandledDiffs.add(diffKey);\n\t\t\t\t\t\thandledDiffs.add(`table:${junctionName}`);\n\n\t\t\t\t\t\tthis._ambiguous.push({\n\t\t\t\t\t\t\tid: `relation_upgrade:${tableName}.${relationName}`,\n\t\t\t\t\t\t\ttableName,\n\t\t\t\t\t\t\ttype: \"relation_upgrade_single_to_many\",\n\t\t\t\t\t\t\tremovedName: removedDiff.fieldName,\n\t\t\t\t\t\t\taddedName: junctionName,\n\t\t\t\t\t\t\twarning:\n\t\t\t\t\t\t\t\t\"Existing single relations can be migrated to junction table.\",\n\t\t\t\t\t\t\tpossibleActions: [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\ttype: \"migrate_to_junction\",\n\t\t\t\t\t\t\t\t\tdescription: `Migrate existing ${removedDiff.fieldName} values to junction table '${junctionName}' (preserves data)`,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\ttype: \"fresh_start\",\n\t\t\t\t\t\t\t\t\tdescription: `Drop '${removedDiff.fieldName}' and create empty junction table (data loss)`,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\tresolved: false,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// manyToMany → belongsTo: junction table removed + FK column added\n\t\tfor (const removedTable of removedTables) {\n\t\t\tif (removedTable.type !== \"tableRemoved\") continue;\n\n\t\t\tconst junctionName = removedTable.tableName;\n\n\t\t\t// Check if this looks like a junction table\n\t\t\tif (!this.looksLikeJunctionTable(junctionName)) continue;\n\t\t\tif (handledDiffs.has(`table:${junctionName}`)) continue;\n\n\t\t\t// Look for a new FK column on one of the related tables\n\t\t\tfor (const [tableName, added] of addedFields) {\n\t\t\t\tfor (const addedDiff of added) {\n\t\t\t\t\tif (addedDiff.type !== \"fieldAdded\") continue;\n\n\t\t\t\t\t// Resolve relation name and FK column name\n\t\t\t\t\tlet relationName: string;\n\t\t\t\t\tlet fkColumnName: string;\n\n\t\t\t\t\tif (\n\t\t\t\t\t\taddedDiff.definition.type === \"relation\" &&\n\t\t\t\t\t\taddedDiff.definition.kind === \"belongsTo\"\n\t\t\t\t\t) {\n\t\t\t\t\t\t// Relation field: derive FK column from definition\n\t\t\t\t\t\trelationName = addedDiff.definition.model;\n\t\t\t\t\t\tfkColumnName =\n\t\t\t\t\t\t\taddedDiff.definition.foreignKey ??\n\t\t\t\t\t\t\t`${addedDiff.definition.model}Id`;\n\t\t\t\t\t} else if (addedDiff.fieldName.endsWith(\"Id\")) {\n\t\t\t\t\t\t// Plain FK column (e.g. \"tagId\")\n\t\t\t\t\t\trelationName = addedDiff.fieldName.slice(0, -2);\n\t\t\t\t\t\tfkColumnName = addedDiff.fieldName;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Check if junction table relates these\n\t\t\t\t\tif (this.isJunctionTableFor(junctionName, tableName, relationName)) {\n\t\t\t\t\t\tconst diffKey = `table:${junctionName}`;\n\t\t\t\t\t\tif (handledDiffs.has(diffKey)) continue;\n\t\t\t\t\t\thandledDiffs.add(diffKey);\n\t\t\t\t\t\thandledDiffs.add(`${tableName}.${addedDiff.fieldName}`);\n\n\t\t\t\t\t\t// Mark removed manyToMany relation fields as handled (no DB column)\n\t\t\t\t\t\tconst removedForTable = removedFields.get(tableName) ?? [];\n\t\t\t\t\t\tfor (const removedDiff of removedForTable) {\n\t\t\t\t\t\t\tif (removedDiff.type !== \"fieldRemoved\") continue;\n\t\t\t\t\t\t\thandledDiffs.add(`${tableName}.${removedDiff.fieldName}`);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Remove manyToMany field diffs from differences (no DB column to drop)\n\t\t\t\t\t\tthis.differences = this.differences.filter(\n\t\t\t\t\t\t\t(d) =>\n\t\t\t\t\t\t\t\t!(\n\t\t\t\t\t\t\t\t\td.type === \"fieldRemoved\" &&\n\t\t\t\t\t\t\t\t\td.tableName === tableName &&\n\t\t\t\t\t\t\t\t\t!d.fieldName.endsWith(\"Id\")\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tthis._ambiguous.push({\n\t\t\t\t\t\t\tid: `relation_downgrade:${tableName}.${relationName}`,\n\t\t\t\t\t\t\ttableName,\n\t\t\t\t\t\t\ttype: \"relation_downgrade_many_to_single\",\n\t\t\t\t\t\t\tremovedName: junctionName,\n\t\t\t\t\t\t\taddedName: fkColumnName,\n\t\t\t\t\t\t\twarning:\n\t\t\t\t\t\t\t\t\"Records with multiple relations will lose data! Only first relation will be kept.\",\n\t\t\t\t\t\t\tpossibleActions: [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\ttype: \"migrate_first\",\n\t\t\t\t\t\t\t\t\tdescription: `Migrate first relation from '${junctionName}' to '${fkColumnName}' (partial data loss)`,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\ttype: \"fresh_start\",\n\t\t\t\t\t\t\t\t\tdescription: `Drop junction table and create empty '${fkColumnName}' column (full data loss)`,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\tresolved: false,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Detect junction table drops (manyToMany relation removed)\n\t */\n\tprivate detectJunctionTableDrops(\n\t\tremovedTables: SchemaDiff[],\n\t\thandledDiffs: Set<string>,\n\t): void {\n\t\tfor (const removedTable of removedTables) {\n\t\t\tif (removedTable.type !== \"tableRemoved\") continue;\n\n\t\t\tconst tableName = removedTable.tableName;\n\t\t\tconst diffKey = `table:${tableName}`;\n\n\t\t\t// Skip if already handled by relation type change detection\n\t\t\tif (handledDiffs.has(diffKey)) continue;\n\n\t\t\t// Check if this looks like a junction table\n\t\t\tif (this.looksLikeJunctionTable(tableName)) {\n\t\t\t\thandledDiffs.add(diffKey);\n\n\t\t\t\tthis._ambiguous.push({\n\t\t\t\t\tid: `junction_drop:${tableName}`,\n\t\t\t\t\ttableName,\n\t\t\t\t\ttype: \"junction_table_drop\",\n\t\t\t\t\tremovedName: tableName,\n\t\t\t\t\taddedName: \"\",\n\t\t\t\t\twarning: \"All relations in this junction table will be lost.\",\n\t\t\t\t\tpossibleActions: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"confirm_drop\",\n\t\t\t\t\t\t\tdescription: `Confirm dropping junction table '${tableName}' (data loss)`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tresolved: false,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Detect junction table renames (through name change)\n\t */\n\tprivate detectJunctionTableRenames(\n\t\tremovedTables: SchemaDiff[],\n\t\taddedTables: SchemaDiff[],\n\t\thandledDiffs: Set<string>,\n\t): void {\n\t\tfor (const removedTable of removedTables) {\n\t\t\tif (removedTable.type !== \"tableRemoved\") continue;\n\n\t\t\tconst oldName = removedTable.tableName;\n\t\t\tconst oldDiffKey = `table:${oldName}`;\n\n\t\t\tif (handledDiffs.has(oldDiffKey)) continue;\n\t\t\tif (!this.looksLikeJunctionTable(oldName)) continue;\n\n\t\t\tfor (const addedTable of addedTables) {\n\t\t\t\tif (addedTable.type !== \"tableAdded\") continue;\n\n\t\t\t\tconst newName = addedTable.schema.tableName ?? addedTable.schema.name;\n\t\t\t\tconst newDiffKey = `table:${newName}`;\n\n\t\t\t\tif (handledDiffs.has(newDiffKey)) continue;\n\t\t\t\tif (!this.looksLikeJunctionTable(newName)) continue;\n\n\t\t\t\t// Check if they have similar structure (both junction tables for same models)\n\t\t\t\tif (this.couldBeJunctionRename(oldName, newName)) {\n\t\t\t\t\thandledDiffs.add(oldDiffKey);\n\t\t\t\t\thandledDiffs.add(newDiffKey);\n\n\t\t\t\t\tthis._ambiguous.push({\n\t\t\t\t\t\tid: `junction_rename:${oldName}->${newName}`,\n\t\t\t\t\t\ttableName: oldName,\n\t\t\t\t\t\ttype: \"junction_table_rename_or_replace\",\n\t\t\t\t\t\tremovedName: oldName,\n\t\t\t\t\t\taddedName: newName,\n\t\t\t\t\t\twarning:\n\t\t\t\t\t\t\t\"Renaming junction tables may cause issues if referenced elsewhere.\",\n\t\t\t\t\t\tpossibleActions: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ttype: \"rename\",\n\t\t\t\t\t\t\t\tdescription: `Rename junction table '${oldName}' to '${newName}' (preserves data)`,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ttype: \"drop_and_recreate\",\n\t\t\t\t\t\t\t\tdescription: `Drop '${oldName}' and create '${newName}' (data loss)`,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t\tresolved: false,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Detect FK column changes (rename or drop)\n\t *\n\t * Handles:\n\t * - FK rename: authorId removed + writerId added → column_rename_or_replace\n\t * - FK drop: authorId removed + no new FK added → fk_column_drop\n\t */\n\tprivate detectFkColumnChanges(\n\t\tremovedFields: Map<string, SchemaDiff[]>,\n\t\taddedFields: Map<string, SchemaDiff[]>,\n\t\thandledDiffs: Set<string>,\n\t): void {\n\t\tfor (const [tableName, removed] of removedFields) {\n\t\t\tconst added = addedFields.get(tableName) ?? [];\n\n\t\t\t// Get all added FK columns in this table (not yet handled)\n\t\t\tconst addedFkColumns = added.filter(\n\t\t\t\t(d): d is FieldAddedDiff =>\n\t\t\t\t\td.type === \"fieldAdded\" &&\n\t\t\t\t\td.fieldName.endsWith(\"Id\") &&\n\t\t\t\t\t!handledDiffs.has(`${tableName}.${d.fieldName}`),\n\t\t\t);\n\n\t\t\tfor (const removedDiff of removed) {\n\t\t\t\tif (removedDiff.type !== \"fieldRemoved\") continue;\n\t\t\t\tif (!removedDiff.fieldName.endsWith(\"Id\")) continue;\n\n\t\t\t\tconst removedKey = `${tableName}.${removedDiff.fieldName}`;\n\t\t\t\tif (handledDiffs.has(removedKey)) continue;\n\n\t\t\t\t// Check if there's a new FK column added - could be a rename\n\t\t\t\tif (addedFkColumns.length > 0) {\n\t\t\t\t\t// Find the first unhandled added FK column\n\t\t\t\t\tconst addedDiff = addedFkColumns.find(\n\t\t\t\t\t\t(d) => !handledDiffs.has(`${tableName}.${d.fieldName}`),\n\t\t\t\t\t);\n\n\t\t\t\t\tif (addedDiff && addedDiff.type === \"fieldAdded\") {\n\t\t\t\t\t\tconst addedKey = `${tableName}.${addedDiff.fieldName}`;\n\n\t\t\t\t\t\thandledDiffs.add(removedKey);\n\t\t\t\t\t\thandledDiffs.add(addedKey);\n\n\t\t\t\t\t\tthis._ambiguous.push({\n\t\t\t\t\t\t\tid: `${tableName}.${removedDiff.fieldName}->${addedDiff.fieldName}`,\n\t\t\t\t\t\t\ttableName,\n\t\t\t\t\t\t\ttype: \"column_rename_or_replace\",\n\t\t\t\t\t\t\tremovedName: removedDiff.fieldName,\n\t\t\t\t\t\t\taddedName: addedDiff.fieldName,\n\t\t\t\t\t\t\taddedDefinition: addedDiff.definition,\n\t\t\t\t\t\t\tpossibleActions: [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\ttype: \"rename\",\n\t\t\t\t\t\t\t\t\tdescription: `Rename column '${removedDiff.fieldName}' to '${addedDiff.fieldName}' (preserves data)`,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\ttype: \"drop_and_add\",\n\t\t\t\t\t\t\t\t\tdescription: `Drop '${removedDiff.fieldName}' and add '${addedDiff.fieldName}' (data loss)`,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\tresolved: false,\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// No matching added FK column - this is a pure FK drop\n\t\t\t\thandledDiffs.add(removedKey);\n\n\t\t\t\tthis._ambiguous.push({\n\t\t\t\t\tid: `fk_drop:${tableName}.${removedDiff.fieldName}`,\n\t\t\t\t\ttableName,\n\t\t\t\t\ttype: \"fk_column_drop\",\n\t\t\t\t\tremovedName: removedDiff.fieldName,\n\t\t\t\t\taddedName: \"\",\n\t\t\t\t\twarning: \"All foreign key references will be lost.\",\n\t\t\t\t\tpossibleActions: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"confirm_drop\",\n\t\t\t\t\t\t\tdescription: `Confirm dropping FK column '${removedDiff.fieldName}' from '${tableName}' (data loss)`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tresolved: false,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Detect potential column renames\n\t */\n\tprivate detectColumnRenames(\n\t\tremovedFields: Map<string, SchemaDiff[]>,\n\t\taddedFields: Map<string, SchemaDiff[]>,\n\t\thandledDiffs: Set<string>,\n\t): void {\n\t\tfor (const [tableName, removed] of removedFields) {\n\t\t\tconst added = addedFields.get(tableName);\n\t\t\tif (!added) continue;\n\n\t\t\tfor (const removedDiff of removed) {\n\t\t\t\tif (removedDiff.type !== \"fieldRemoved\") continue;\n\n\t\t\t\tconst removedKey = `${tableName}.${removedDiff.fieldName}`;\n\t\t\t\tif (handledDiffs.has(removedKey)) continue;\n\n\t\t\t\tfor (const addedDiff of added) {\n\t\t\t\t\tif (addedDiff.type !== \"fieldAdded\") continue;\n\n\t\t\t\t\tconst addedKey = `${tableName}.${addedDiff.fieldName}`;\n\t\t\t\t\tif (handledDiffs.has(addedKey)) continue;\n\n\t\t\t\t\t// Check if could be rename\n\t\t\t\t\tif (this.couldBeRename(undefined, addedDiff.definition)) {\n\t\t\t\t\t\thandledDiffs.add(removedKey);\n\t\t\t\t\t\thandledDiffs.add(addedKey);\n\n\t\t\t\t\t\tthis._ambiguous.push({\n\t\t\t\t\t\t\tid: `${tableName}.${removedDiff.fieldName}->${addedDiff.fieldName}`,\n\t\t\t\t\t\t\ttableName,\n\t\t\t\t\t\t\ttype: \"column_rename_or_replace\",\n\t\t\t\t\t\t\tremovedName: removedDiff.fieldName,\n\t\t\t\t\t\t\taddedName: addedDiff.fieldName,\n\t\t\t\t\t\t\taddedDefinition: addedDiff.definition,\n\t\t\t\t\t\t\tpossibleActions: [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\ttype: \"rename\",\n\t\t\t\t\t\t\t\t\tdescription: `Rename column '${removedDiff.fieldName}' to '${addedDiff.fieldName}' (preserves data)`,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\ttype: \"drop_and_add\",\n\t\t\t\t\t\t\t\t\tdescription: `Drop '${removedDiff.fieldName}' and add '${addedDiff.fieldName}' (data loss)`,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\tresolved: false,\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\t// Only match one pair per removed field\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Detect potential table renames\n\t */\n\tprivate detectTableRenames(\n\t\tremovedTables: SchemaDiff[],\n\t\taddedTables: SchemaDiff[],\n\t\thandledDiffs: Set<string>,\n\t): void {\n\t\tfor (const removedDiff of removedTables) {\n\t\t\tif (removedDiff.type !== \"tableRemoved\") continue;\n\n\t\t\tconst removedKey = `table:${removedDiff.tableName}`;\n\t\t\tif (handledDiffs.has(removedKey)) continue;\n\n\t\t\tfor (const addedDiff of addedTables) {\n\t\t\t\tif (addedDiff.type !== \"tableAdded\") continue;\n\n\t\t\t\tconst addedKey = `table:${addedDiff.schema.tableName ?? addedDiff.schema.name}`;\n\t\t\t\tif (handledDiffs.has(addedKey)) continue;\n\n\t\t\t\tif (this.couldBeTableRename(removedDiff.tableName, addedDiff.schema)) {\n\t\t\t\t\thandledDiffs.add(removedKey);\n\t\t\t\t\thandledDiffs.add(addedKey);\n\n\t\t\t\t\tthis._ambiguous.push({\n\t\t\t\t\t\tid: `table:${removedDiff.tableName}->${addedDiff.schema.name}`,\n\t\t\t\t\t\ttableName: removedDiff.tableName,\n\t\t\t\t\t\ttype: \"table_rename_or_replace\",\n\t\t\t\t\t\tremovedName: removedDiff.tableName,\n\t\t\t\t\t\taddedName: addedDiff.schema.name,\n\t\t\t\t\t\tpossibleActions: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ttype: \"rename\",\n\t\t\t\t\t\t\t\tdescription: `Rename table '${removedDiff.tableName}' to '${addedDiff.schema.name}' (preserves data)`,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ttype: \"drop_and_add\",\n\t\t\t\t\t\t\t\tdescription: `Drop '${removedDiff.tableName}' and create '${addedDiff.schema.name}' (data loss)`,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t\tresolved: false,\n\t\t\t\t\t});\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Detect FK model changes (belongsTo pointing to a different model).\n\t * The FK column name stays the same but the referenced model changes.\n\t */\n\tprivate detectFkModelChanges(\n\t\tmodifiedFields: Map<string, SchemaDiff[]>,\n\t\thandledDiffs: Set<string>,\n\t): void {\n\t\tfor (const [tableName, modified] of modifiedFields) {\n\t\t\tfor (const diff of modified) {\n\t\t\t\tif (diff.type !== \"fieldModified\") continue;\n\n\t\t\t\tconst oldDef = diff.oldDefinition;\n\t\t\t\tconst newDef = diff.newDefinition;\n\n\t\t\t\tif (oldDef.type !== \"relation\" || newDef.type !== \"relation\") continue;\n\t\t\t\tif (oldDef.kind !== \"belongsTo\" || newDef.kind !== \"belongsTo\")\n\t\t\t\t\tcontinue;\n\t\t\t\tif (oldDef.model === newDef.model) continue;\n\n\t\t\t\tconst diffKey = `${tableName}.${diff.fieldName}`;\n\t\t\t\tif (handledDiffs.has(diffKey)) continue;\n\t\t\t\thandledDiffs.add(diffKey);\n\n\t\t\t\tconst fkColumn = newDef.foreignKey ?? `${newDef.model}Id`;\n\n\t\t\t\tthis._ambiguous.push({\n\t\t\t\t\tid: `fk_model_change:${tableName}.${diff.fieldName}`,\n\t\t\t\t\ttableName,\n\t\t\t\t\ttype: \"fk_model_change\",\n\t\t\t\t\tremovedName: oldDef.model,\n\t\t\t\t\taddedName: newDef.model,\n\t\t\t\t\twarning: `Existing data in '${fkColumn}' will reference '${newDef.model}' instead of '${oldDef.model}'. Ensure data integrity before migrating.`,\n\t\t\t\t\tpossibleActions: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"keep_column\",\n\t\t\t\t\t\t\tdescription: `Keep column '${fkColumn}' as-is and change the referenced model (data may be inconsistent)`,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"drop_and_recreate\",\n\t\t\t\t\t\t\tdescription: `Drop '${fkColumn}' and recreate it (data loss)`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tresolved: false,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Detect relation direction flips.\n\t * A hasOne/hasMany FK is removed from one table and an equivalent FK\n\t * is added to another table — the relation ownership is flipping sides.\n\t *\n\t * Pattern: fieldRemoved (FK column on tableA) + fieldAdded (FK column on tableB)\n\t * where both columns represent the same logical relation but point in\n\t * opposite directions.\n\t */\n\tprivate detectRelationDirectionFlips(\n\t\tremovedFields: Map<string, SchemaDiff[]>,\n\t\taddedFields: Map<string, SchemaDiff[]>,\n\t\thandledDiffs: Set<string>,\n\t): void {\n\t\tfor (const [removedTable, removed] of removedFields) {\n\t\t\tfor (const removedDiff of removed) {\n\t\t\t\tif (removedDiff.type !== \"fieldRemoved\") continue;\n\t\t\t\tif (!removedDiff.fieldName.endsWith(\"Id\")) continue;\n\n\t\t\t\tconst removedKey = `${removedTable}.${removedDiff.fieldName}`;\n\t\t\t\tif (handledDiffs.has(removedKey)) continue;\n\n\t\t\t\t// Look for a new FK column on a different table\n\t\t\t\tfor (const [addedTable, added] of addedFields) {\n\t\t\t\t\tif (addedTable === removedTable) continue;\n\n\t\t\t\t\tfor (const addedDiff of added) {\n\t\t\t\t\t\tif (addedDiff.type !== \"fieldAdded\") continue;\n\t\t\t\t\t\tif (!addedDiff.fieldName.endsWith(\"Id\")) continue;\n\n\t\t\t\t\t\tconst addedKey = `${addedTable}.${addedDiff.fieldName}`;\n\t\t\t\t\t\tif (handledDiffs.has(addedKey)) continue;\n\n\t\t\t\t\t\t// Check if these two FK columns are related to the same models\n\t\t\t\t\t\t// removedTable has a FK pointing to some model (ends with Id)\n\t\t\t\t\t\t// addedTable has a new FK pointing to some model\n\t\t\t\t\t\t// They're a direction flip if one points to the other's table\n\t\t\t\t\t\tconst removedModelHint = removedDiff.fieldName.slice(0, -2);\n\t\t\t\t\t\tconst addedModelHint = addedDiff.fieldName.slice(0, -2);\n\n\t\t\t\t\t\tconst removedTableBase = this.singularize(removedTable);\n\t\t\t\t\t\tconst addedTableBase = this.singularize(addedTable);\n\n\t\t\t\t\t\tconst isFlip =\n\t\t\t\t\t\t\tremovedModelHint === addedTableBase ||\n\t\t\t\t\t\t\taddedModelHint === removedTableBase;\n\n\t\t\t\t\t\tif (isFlip) {\n\t\t\t\t\t\t\thandledDiffs.add(removedKey);\n\t\t\t\t\t\t\thandledDiffs.add(addedKey);\n\n\t\t\t\t\t\t\tthis._ambiguous.push({\n\t\t\t\t\t\t\t\tid: `direction_flip:${removedTable}.${removedDiff.fieldName}->${addedTable}.${addedDiff.fieldName}`,\n\t\t\t\t\t\t\t\ttableName: removedTable,\n\t\t\t\t\t\t\t\ttype: \"relation_direction_flip\",\n\t\t\t\t\t\t\t\tremovedName: `${removedTable}.${removedDiff.fieldName}`,\n\t\t\t\t\t\t\t\taddedName: `${addedTable}.${addedDiff.fieldName}`,\n\t\t\t\t\t\t\t\twarning: `Relation direction is changing. '${removedDiff.fieldName}' on '${removedTable}' will be replaced by '${addedDiff.fieldName}' on '${addedTable}'. Existing relation data will be lost.`,\n\t\t\t\t\t\t\t\tpossibleActions: [\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\ttype: \"drop_and_recreate\",\n\t\t\t\t\t\t\t\t\t\tdescription: `Drop '${removedDiff.fieldName}' from '${removedTable}' and add '${addedDiff.fieldName}' to '${addedTable}' (data loss)`,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\tresolved: false,\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Check if table name looks like a junction table\n\t */\n\tprivate looksLikeJunctionTable(tableName: string): boolean {\n\t\t// Junction tables typically have underscore: post_tag, category_post, etc.\n\t\treturn tableName.includes(\"_\") && !tableName.startsWith(\"_\");\n\t}\n\n\t/**\n\t * Check if junction table is for given table and relation\n\t */\n\tprivate isJunctionTableFor(\n\t\tjunctionName: string,\n\t\ttableName: string,\n\t\trelationName: string,\n\t): boolean {\n\t\tconst parts = junctionName.split(\"_\");\n\t\tif (parts.length !== 2) return false;\n\n\t\t// Junction table should contain both model names (singular form)\n\t\tconst singularTable = this.singularize(tableName);\n\t\tconst singularRelation = relationName.toLowerCase();\n\n\t\tconst containsTable = parts.some(\n\t\t\t(p) => p === singularTable || p === tableName.toLowerCase(),\n\t\t);\n\t\tconst containsRelation = parts.some(\n\t\t\t(p) => p === singularRelation || p === this.pluralize(singularRelation),\n\t\t);\n\n\t\treturn containsTable && containsRelation;\n\t}\n\n\t/**\n\t * Check if two junction tables could be a rename\n\t */\n\tprivate couldBeJunctionRename(oldName: string, newName: string): boolean {\n\t\tconst oldParts = new Set(oldName.split(\"_\"));\n\t\tconst newParts = new Set(newName.split(\"_\"));\n\n\t\t// At least one part should be common\n\t\tlet commonParts = 0;\n\t\tfor (const part of oldParts) {\n\t\t\tif (newParts.has(part)) commonParts++;\n\t\t}\n\n\t\treturn commonParts >= 1;\n\t}\n\n\t/**\n\t * Simple singularize helper\n\t */\n\tprivate singularize(word: string): string {\n\t\tif (word.endsWith(\"ies\")) {\n\t\t\treturn word.slice(0, -3) + \"y\";\n\t\t}\n\t\tif (word.endsWith(\"es\")) {\n\t\t\treturn word.slice(0, -2);\n\t\t}\n\t\tif (word.endsWith(\"s\") && !word.endsWith(\"ss\")) {\n\t\t\treturn word.slice(0, -1);\n\t\t}\n\t\treturn word;\n\t}\n\n\t/**\n\t * Simple pluralize helper\n\t */\n\tprivate pluralize(word: string): string {\n\t\tif (word.endsWith(\"y\")) {\n\t\t\treturn word.slice(0, -1) + \"ies\";\n\t\t}\n\t\tif (\n\t\t\tword.endsWith(\"s\") ||\n\t\t\tword.endsWith(\"x\") ||\n\t\t\tword.endsWith(\"ch\") ||\n\t\t\tword.endsWith(\"sh\")\n\t\t) {\n\t\t\treturn word + \"es\";\n\t\t}\n\t\treturn word + \"s\";\n\t}\n\n\t/**\n\t * Check if field change could be a rename\n\t */\n\tprivate couldBeRename(\n\t\t_oldDef: FieldDefinition | undefined,\n\t\t_newDef: FieldDefinition,\n\t): boolean {\n\t\t// Simple heuristic: if types match, could be rename\n\t\t// In real implementation, check more properties\n\t\treturn true; // For now, always offer rename option\n\t}\n\n\t/**\n\t * Check if table change could be a rename\n\t *\n\t * Excludes common system fields (id, createdAt, updatedAt) from comparison\n\t * to focus on user-defined fields only.\n\t */\n\tprivate couldBeTableRename(\n\t\toldTableName: string,\n\t\tnewSchema: SchemaDefinition,\n\t): boolean {\n\t\tconst oldSchema = this.databaseSchemas.get(oldTableName);\n\t\tif (!oldSchema) return false;\n\n\t\t// Exclude system fields from comparison\n\t\tconst systemFields = new Set([\"id\", \"createdAt\", \"updatedAt\"]);\n\n\t\tconst oldFields = new Set(\n\t\t\tObject.keys(oldSchema.fields).filter((f) => !systemFields.has(f)),\n\t\t);\n\t\tconst newFields = new Set(\n\t\t\tObject.keys(newSchema.fields).filter((f) => !systemFields.has(f)),\n\t\t);\n\n\t\t// Need at least 1 user-defined field to compare\n\t\tif (oldFields.size === 0 || newFields.size === 0) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Count common fields\n\t\tlet commonFields = 0;\n\t\tfor (const field of oldFields) {\n\t\t\tif (newFields.has(field)) {\n\t\t\t\tcommonFields++;\n\t\t\t}\n\t\t}\n\n\t\t// Need at least 70% of fields to match by name (stricter threshold)\n\t\tconst totalUniqueFields = new Set([...oldFields, ...newFields]).size;\n\t\tconst fieldNameSimilarity = commonFields / totalUniqueFields;\n\n\t\tif (fieldNameSimilarity < 0.7) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Also check field count similarity\n\t\tconst countSimilarity =\n\t\t\tMath.min(oldFields.size, newFields.size) /\n\t\t\tMath.max(oldFields.size, newFields.size);\n\n\t\treturn countSimilarity > 0.7;\n\t}\n\n\t/**\n\t * Get tables to create\n\t */\n\tget tablesToCreate(): readonly SchemaDefinition[] {\n\t\treturn this.differences\n\t\t\t.filter((d) => d.type === \"tableAdded\")\n\t\t\t.map(\n\t\t\t\t(d) => (d as { type: \"tableAdded\"; schema: SchemaDefinition }).schema,\n\t\t\t);\n\t}\n\n\t/**\n\t * Get tables to drop\n\t */\n\tget tablesToDrop(): readonly string[] {\n\t\treturn this.differences\n\t\t\t.filter((d) => d.type === \"tableRemoved\")\n\t\t\t.map((d) => (d as { type: \"tableRemoved\"; tableName: string }).tableName);\n\t}\n\n\t/**\n\t * Get tables to alter\n\t */\n\tget tablesToAlter(): readonly {\n\t\ttableName: string;\n\t\tchanges: readonly SchemaDiff[];\n\t}[] {\n\t\tconst alterations = new Map<string, SchemaDiff[]>();\n\n\t\tfor (const diff of this.differences) {\n\t\t\tif (\n\t\t\t\tdiff.type === \"fieldAdded\" ||\n\t\t\t\tdiff.type === \"fieldRemoved\" ||\n\t\t\t\tdiff.type === \"fieldModified\" ||\n\t\t\t\tdiff.type === \"indexAdded\" ||\n\t\t\t\tdiff.type === \"indexRemoved\"\n\t\t\t) {\n\t\t\t\tconst tableName = diff.tableName;\n\t\t\t\tif (!alterations.has(tableName)) {\n\t\t\t\t\talterations.set(tableName, []);\n\t\t\t\t}\n\t\t\t\talterations.get(tableName)!.push(diff);\n\t\t\t}\n\t\t}\n\n\t\treturn Array.from(alterations.entries()).map(([tableName, changes]) => ({\n\t\t\ttableName,\n\t\t\tchanges,\n\t\t}));\n\t}\n\n\t/**\n\t * Get ambiguous changes that need resolution\n\t */\n\tget ambiguous(): readonly AmbiguousChange[] {\n\t\treturn this._ambiguous.filter((a) => !a.resolved);\n\t}\n\n\t/**\n\t * Check if there are unresolved ambiguous changes\n\t */\n\thasUnresolvedAmbiguous(): boolean {\n\t\treturn this._ambiguous.some((a) => !a.resolved);\n\t}\n\n\t/**\n\t * Resolve an ambiguous change\n\t */\n\tresolveAmbiguous(id: string, action: AmbiguousActionType): void {\n\t\tconst ambiguous = this._ambiguous.find((a) => a.id === id);\n\t\tif (!ambiguous) {\n\t\t\tthrow new MigrationSystemError(\n\t\t\t\t`Ambiguous change '${id}' not found`,\n\t\t\t\t\"MIGRATION_ERROR\",\n\t\t\t);\n\t\t}\n\n\t\tconst selectedAction = ambiguous.possibleActions.find(\n\t\t\t(a) => a.type === action,\n\t\t);\n\t\tif (!selectedAction) {\n\t\t\tthrow new MigrationSystemError(\n\t\t\t\t`Invalid action '${action}' for ambiguous change '${id}'`,\n\t\t\t\t\"MIGRATION_ERROR\",\n\t\t\t);\n\t\t}\n\n\t\tambiguous.resolved = true;\n\t\tambiguous.resolvedAction = selectedAction;\n\n\t\t// Update differences based on resolution\n\t\tthis.applyResolution(ambiguous, action);\n\t}\n\n\t/**\n\t * Apply resolution - update differences based on chosen action\n\t */\n\tprivate applyResolution(\n\t\tambiguous: AmbiguousChange,\n\t\taction: AmbiguousActionType,\n\t): void {\n\t\tswitch (ambiguous.type) {\n\t\t\tcase \"column_rename_or_replace\":\n\t\t\t\tif (action === \"rename\") {\n\t\t\t\t\tthis.applyColumnRename(ambiguous);\n\t\t\t\t}\n\t\t\t\t// drop_and_add: keep original diffs\n\t\t\t\tbreak;\n\n\t\t\tcase \"table_rename_or_replace\":\n\t\t\t\tif (action === \"rename\") {\n\t\t\t\t\tthis.applyTableRename(ambiguous);\n\t\t\t\t}\n\t\t\t\t// drop_and_add: keep original diffs\n\t\t\t\tbreak;\n\n\t\t\tcase \"junction_table_rename_or_replace\":\n\t\t\t\tif (action === \"rename\") {\n\t\t\t\t\tthis.applyTableRename(ambiguous);\n\t\t\t\t}\n\t\t\t\t// drop_and_recreate: keep original diffs\n\t\t\t\tbreak;\n\n\t\t\tcase \"fk_column_drop\":\n\t\t\tcase \"junction_table_drop\":\n\t\t\t\t// confirm_drop: keep original diffs (just confirming)\n\t\t\t\tbreak;\n\n\t\t\tcase \"relation_upgrade_single_to_many\":\n\t\t\t\tif (action === \"migrate_to_junction\") {\n\t\t\t\t\t// TODO: Add data migration operation\n\t\t\t\t\t// For now, keep original diffs but mark for data migration\n\t\t\t\t}\n\t\t\t\t// fresh_start: keep original diffs (no data migration)\n\t\t\t\tbreak;\n\n\t\t\tcase \"relation_downgrade_many_to_single\":\n\t\t\t\t// Diffs (addColumn FK + dropTable junction) are kept for operation generation.\n\t\t\t\t// Data transfer is injected by injectDataTransferOperations.\n\t\t\t\tbreak;\n\n\t\t\tcase \"fk_model_change\":\n\t\t\t\t// Both keep_column and drop_and_recreate: keep original diffs for now\n\t\t\t\tbreak;\n\n\t\t\tcase \"relation_direction_flip\":\n\t\t\t\t// drop_both_and_recreate: keep original diffs\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\t/**\n\t * Apply column rename - replace drop+add with rename\n\t */\n\tprivate applyColumnRename(ambiguous: AmbiguousChange): void {\n\t\t// Remove the fieldRemoved, fieldAdded, and related fieldModified diffs\n\t\tthis.differences = this.differences.filter((d) => {\n\t\t\tif (\n\t\t\t\td.type === \"fieldRemoved\" &&\n\t\t\t\td.tableName === ambiguous.tableName &&\n\t\t\t\td.fieldName === ambiguous.removedName\n\t\t\t) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (\n\t\t\t\td.type === \"fieldAdded\" &&\n\t\t\t\td.tableName === ambiguous.tableName &&\n\t\t\t\td.fieldName === ambiguous.addedName\n\t\t\t) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t// Remove relation fieldModified that references the same FK rename\n\t\t\tif (\n\t\t\t\td.type === \"fieldModified\" &&\n\t\t\t\td.tableName === ambiguous.tableName &&\n\t\t\t\td.oldDefinition.type === \"relation\" &&\n\t\t\t\td.newDefinition.type === \"relation\"\n\t\t\t) {\n\t\t\t\tconst oldFK =\n\t\t\t\t\td.oldDefinition.foreignKey ?? `${d.oldDefinition.model}Id`;\n\t\t\t\tconst newFK =\n\t\t\t\t\td.newDefinition.foreignKey ?? `${d.newDefinition.model}Id`;\n\t\t\t\tif (oldFK === ambiguous.removedName && newFK === ambiguous.addedName) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t});\n\n\t\t// Add fieldRenamed diff\n\t\tthis.differences.push({\n\t\t\ttype: \"fieldRenamed\",\n\t\t\ttableName: ambiguous.tableName,\n\t\t\tfrom: ambiguous.removedName,\n\t\t\tto: ambiguous.addedName,\n\t\t});\n\t}\n\n\t/**\n\t * Apply table rename - replace drop+add with rename\n\t */\n\tprivate applyTableRename(ambiguous: AmbiguousChange): void {\n\t\t// Remove tableRemoved and tableAdded diffs\n\t\tthis.differences = this.differences.filter((d) => {\n\t\t\tif (d.type === \"tableRemoved\" && d.tableName === ambiguous.removedName) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (d.type === \"tableAdded\" && d.schema.name === ambiguous.addedName) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn true;\n\t\t});\n\n\t\t// Add tableRenamed diff\n\t\tthis.differences.push({\n\t\t\ttype: \"tableRenamed\",\n\t\t\tfrom: ambiguous.removedName,\n\t\t\tto: ambiguous.addedName,\n\t\t});\n\t}\n\n\t/**\n\t * Check if there are any changes to apply\n\t */\n\thasChanges(): boolean {\n\t\treturn this.differences.length > 0;\n\t}\n\n\t/**\n\t * Get migration plan\n\t */\n\tgetPlan(): MigrationPlan {\n\t\tif (this.hasUnresolvedAmbiguous()) {\n\t\t\tthrow new MigrationSystemError(\n\t\t\t\t\"Cannot generate plan with unresolved ambiguous changes\",\n\t\t\t\t\"MIGRATION_ERROR\",\n\t\t\t);\n\t\t}\n\n\t\tconst operations = this.generator.generateOperations(this.differences);\n\n\t\treturn {\n\t\t\ttablesToCreate: this.tablesToCreate,\n\t\t\ttablesToDrop: this.tablesToDrop,\n\t\t\ttablesToAlter: this.tablesToAlter,\n\t\t\toperations,\n\t\t\thasChanges: this.hasChanges(),\n\t\t};\n\t}\n\n\t/**\n\t * Apply migrations\n\t */\n\tasync apply(): Promise<readonly MigrationExecutionResult[]> {\n\t\tif (this.hasUnresolvedAmbiguous()) {\n\t\t\tthrow new MigrationSystemError(\n\t\t\t\t\"Cannot apply migrations with unresolved ambiguous changes\",\n\t\t\t\t\"MIGRATION_ERROR\",\n\t\t\t);\n\t\t}\n\n\t\tif (!this.hasChanges()) {\n\t\t\treturn [];\n\t\t}\n\n\t\t// Generate migration\n\t\tconst baseMigration = this.generator.generate(this.differences, {\n\t\t\tname: `migration_${Date.now()}`,\n\t\t\tversion: Date.now().toString(),\n\t\t\tdescription: \"Auto-generated migration\",\n\t\t});\n\n\t\t// Inject data transfer operations for resolved migrate_to_junction / migrate_first\n\t\tconst enrichedOperations = this.injectDataTransferOperations(\n\t\t\tbaseMigration.operations,\n\t\t);\n\n\t\tconst migration: Migration = {\n\t\t\t...baseMigration,\n\t\t\toperations: enrichedOperations,\n\t\t};\n\n\t\t// Create runner and execute\n\t\tconst runner = new ForgeMigrationRunner(this.adapter, this.history, [\n\t\t\tmigration,\n\t\t]);\n\n\t\tconst results = await runner.runPending();\n\n\t\t// Throw on failure so callers don't silently ignore migration errors\n\t\tconst failed = results.find((r) => r.status === \"failed\");\n\t\tif (failed) {\n\t\t\tconst errorMessage =\n\t\t\t\tfailed.error instanceof Error\n\t\t\t\t\t? failed.error.message\n\t\t\t\t\t: String(failed.error ?? \"Unknown migration error\");\n\t\t\tthrow new MigrationSystemError(\n\t\t\t\t`Migration failed: ${errorMessage}`,\n\t\t\t\t\"MIGRATION_ERROR\",\n\t\t\t\tfailed.error,\n\t\t\t);\n\t\t}\n\n\t\treturn results;\n\t}\n\n\t/**\n\t * Inject data transfer operations into the migration operation list.\n\t *\n\t * For each resolved ambiguous change with a data migration action,\n\t * inserts a dataTransfer step at the correct position:\n\t * - migrate_to_junction: after createTable(junction), before dropColumn(fkCol)\n\t * - migrate_first: after addColumn(fkCol), before dropTable(junction)\n\t */\n\tprivate injectDataTransferOperations(\n\t\toperations: readonly MigrationOperation[],\n\t): readonly MigrationOperation[] {\n\t\tconst result: MigrationOperation[] = [...operations];\n\n\t\tfor (const ambiguous of this._ambiguous) {\n\t\t\tif (!ambiguous.resolved) continue;\n\n\t\t\tif (ambiguous.resolvedAction?.type === \"migrate_to_junction\") {\n\t\t\t\tconst sourceFkCol = ambiguous.removedName; // e.g. \"categoryId\"\n\t\t\t\tconst junctionTable = ambiguous.addedName; // e.g. \"category_post\"\n\t\t\t\tconst sourceTable = ambiguous.tableName; // e.g. \"posts\"\n\n\t\t\t\t// Find insert position: after createTable(junction)\n\t\t\t\tconst createIdx = result.findIndex(\n\t\t\t\t\t(op) =>\n\t\t\t\t\t\top.type === \"createTable\" &&\n\t\t\t\t\t\t(op.schema.tableName ?? op.schema.name) === junctionTable,\n\t\t\t\t);\n\n\t\t\t\t// Find drop position: before alterTable(sourceTable) that drops fkCol\n\t\t\t\tconst dropIdx = result.findIndex(\n\t\t\t\t\t(op) =>\n\t\t\t\t\t\top.type === \"alterTable\" &&\n\t\t\t\t\t\top.tableName === sourceTable &&\n\t\t\t\t\t\top.operations.some(\n\t\t\t\t\t\t\t(o) => o.type === \"dropColumn\" && o.column === sourceFkCol,\n\t\t\t\t\t\t),\n\t\t\t\t);\n\n\t\t\t\tif (createIdx === -1 || dropIdx === -1) continue;\n\n\t\t\t\tconst transferOp: DataTransferOperation = {\n\t\t\t\t\ttype: \"dataTransfer\",\n\t\t\t\t\tdescription: `Migrate '${sourceTable}.${sourceFkCol}' values to junction table '${junctionTable}'`,\n\t\t\t\t\texecute: async (runner: QueryRunner) => {\n\t\t\t\t\t\tconst selectResult = await runner.executeQuery<DatrixRecord>({\n\t\t\t\t\t\t\ttype: \"select\",\n\t\t\t\t\t\t\ttable: sourceTable,\n\t\t\t\t\t\t\tselect: [\"id\", sourceFkCol],\n\t\t\t\t\t\t});\n\t\t\t\t\t\tconst rows = selectResult.rows;\n\n\t\t\t\t\t\t// Junction FK col for source: derived from FK col on target (e.g. \"categoryId\" → target model \"category\")\n\t\t\t\t\t\t// Source FK col in junction: singular of sourceTable + \"Id\" (e.g. \"posts\" → \"postId\")\n\t\t\t\t\t\tconst sourceModelName = this.singularize(sourceTable);\n\t\t\t\t\t\tconst sourceJunctionFkCol = `${sourceModelName}Id`;\n\n\t\t\t\t\t\tconst junctionRows = rows\n\t\t\t\t\t\t\t.filter((row) => row[sourceFkCol] != null)\n\t\t\t\t\t\t\t.map((row) => ({\n\t\t\t\t\t\t\t\t[sourceJunctionFkCol]: row.id,\n\t\t\t\t\t\t\t\t[sourceFkCol]: row[sourceFkCol],\n\t\t\t\t\t\t\t}));\n\n\t\t\t\t\t\tif (junctionRows.length === 0) return;\n\n\t\t\t\t\t\tawait runner.executeQuery({\n\t\t\t\t\t\t\ttype: \"insert\",\n\t\t\t\t\t\t\ttable: junctionTable,\n\t\t\t\t\t\t\tdata: junctionRows,\n\t\t\t\t\t\t});\n\t\t\t\t\t},\n\t\t\t\t};\n\n\t\t\t\t// Insert after createTable, but before drop\n\t\t\t\tconst insertAt = Math.min(createIdx + 1, dropIdx);\n\t\t\t\tresult.splice(insertAt, 0, transferOp);\n\t\t\t} else if (ambiguous.resolvedAction?.type === \"migrate_first\") {\n\t\t\t\tconst junctionTable = ambiguous.removedName; // e.g. \"post_tag\"\n\t\t\t\tconst targetFkCol = ambiguous.addedName; // e.g. \"tagId\"\n\t\t\t\tconst targetTable = ambiguous.tableName; // e.g. \"posts\"\n\n\t\t\t\t// Find insert position: after addColumn(targetFkCol) on targetTable\n\t\t\t\tconst addColIdx = result.findIndex(\n\t\t\t\t\t(op) =>\n\t\t\t\t\t\top.type === \"alterTable\" &&\n\t\t\t\t\t\top.tableName === targetTable &&\n\t\t\t\t\t\top.operations.some(\n\t\t\t\t\t\t\t(o) => o.type === \"addColumn\" && o.column === targetFkCol,\n\t\t\t\t\t\t),\n\t\t\t\t);\n\n\t\t\t\t// Find drop position: before dropTable(junction)\n\t\t\t\tconst dropTableIdx = result.findIndex(\n\t\t\t\t\t(op) => op.type === \"dropTable\" && op.tableName === junctionTable,\n\t\t\t\t);\n\n\t\t\t\tif (addColIdx === -1 || dropTableIdx === -1) continue;\n\n\t\t\t\t// Junction FK col for target table: singular of targetTable + \"Id\" (e.g. \"posts\" → \"postId\")\n\t\t\t\tconst targetModelName = this.singularize(targetTable);\n\t\t\t\tconst sourceFkCol = `${targetModelName}Id`; // e.g. \"postId\"\n\t\t\t\tconst relatedFkCol = targetFkCol; // e.g. \"tagId\"\n\n\t\t\t\tconst transferOp: DataTransferOperation = {\n\t\t\t\t\ttype: \"dataTransfer\",\n\t\t\t\t\tdescription: `Migrate first relation from '${junctionTable}' to '${targetTable}.${targetFkCol}'`,\n\t\t\t\t\texecute: async (runner: QueryRunner) => {\n\t\t\t\t\t\tconst selectResult = await runner.executeQuery<DatrixRecord>({\n\t\t\t\t\t\t\ttype: \"select\",\n\t\t\t\t\t\t\ttable: junctionTable,\n\t\t\t\t\t\t\tselect: [sourceFkCol, relatedFkCol],\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\t// Group by sourceFk, keep first occurrence per source record\n\t\t\t\t\t\tconst firstBySource = new Map<number, unknown>();\n\t\t\t\t\t\tfor (const row of selectResult.rows) {\n\t\t\t\t\t\t\tconst sourceId = row[sourceFkCol] as number;\n\t\t\t\t\t\t\tif (!firstBySource.has(sourceId)) {\n\t\t\t\t\t\t\t\tfirstBySource.set(sourceId, row[relatedFkCol]);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Update each source record with its first related FK\n\t\t\t\t\t\tfor (const [sourceId, relatedId] of firstBySource) {\n\t\t\t\t\t\t\tawait runner.executeQuery({\n\t\t\t\t\t\t\t\ttype: \"update\",\n\t\t\t\t\t\t\t\ttable: targetTable,\n\t\t\t\t\t\t\t\twhere: { id: { $eq: sourceId } },\n\t\t\t\t\t\t\t\tdata: { [relatedFkCol]: relatedId },\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t};\n\n\t\t\t\t// Insert after addColumn (data transfer needs the column to exist)\n\t\t\t\t// Also move dropTable AFTER dataTransfer so junction table still exists during transfer\n\t\t\t\tresult.splice(addColIdx + 1, 0, transferOp);\n\n\t\t\t\t// Re-find dropTable index (may have shifted after splice)\n\t\t\t\tconst newDropIdx = result.findIndex(\n\t\t\t\t\t(op) => op.type === \"dropTable\" && op.tableName === junctionTable,\n\t\t\t\t);\n\t\t\t\tconst transferIdx = result.indexOf(transferOp);\n\t\t\t\tif (newDropIdx !== -1 && newDropIdx < transferIdx) {\n\t\t\t\t\t// Remove dropTable from its current position and place it after dataTransfer\n\t\t\t\t\tconst [dropOp] = result.splice(newDropIdx, 1);\n\t\t\t\t\tconst insertAfterTransfer = result.indexOf(transferOp) + 1;\n\t\t\t\t\tresult.splice(insertAfterTransfer, 0, dropOp!);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Get dry-run preview of what would be applied\n\t */\n\tasync preview(): Promise<readonly MigrationOperation[]> {\n\t\tconst plan = this.getPlan();\n\t\treturn plan.operations;\n\t}\n}\n\n/**\n * Create migration session\n */\nexport async function createMigrationSession(\n\tdatrix: IDatrix,\n): Promise<MigrationSession> {\n\tconst session = new MigrationSession(datrix);\n\tawait session.initialize();\n\treturn session;\n}\n","/**\n * Datrix - Main Class\n *\n * Central orchestrator for the Datrix framework.\n * Manages configuration, database adapter, plugins, and schemas.\n */\n\nimport {\n\tDatrixConfig,\n\tMigrationConfig,\n\tDevConfig,\n\tDEFAULT_MIGRATION_CONFIG,\n\tDEFAULT_DEV_CONFIG,\n} from \"./types/core/config\";\nimport { DatabaseAdapter } from \"./types/adapter\";\nimport {\n\tDatrixPlugin,\n\tPluginContext,\n\tSchemaExtension,\n} from \"./types/core/plugin\";\nimport { WhereClause } from \"./types/core/query-builder\";\nimport { CrudOperations } from \"./mixins/crud\";\nimport { SchemaExtensionContextImpl } from \"./plugin/schema-extension-context\";\nimport { Dispatcher, createDispatcher } from \"./dispatcher\";\nimport { PluginRegistry } from \"./types/core/plugin\";\nimport { SchemaRegistry } from \"./schema\";\nimport { DatrixEntry, DatrixRecord } from \"./types/core/schema\";\nimport {\n\tIDatrix,\n\tRawCrudOptions,\n\tRawFindManyOptions,\n\tFallbackInput,\n} from \"./types/core\";\nimport { DatrixError } from \"./types/errors\";\nimport {\n\tgetMigrationSchema,\n\tDEFAULT_MIGRATION_MODEL,\n\tgetDatrixMetaSchema,\n} from \"./migration/schema\";\nimport { MigrationSession, createMigrationSession } from \"./migration/session\";\n\n/**\n * Datrix initialization options\n */\nexport interface DatrixInitOptions {\n\treadonly skipConnection?: boolean;\n\treadonly skipPlugins?: boolean;\n\treadonly skipSchemas?: boolean;\n}\n\n/**\n * Config factory function type\n */\nexport type ConfigFactory = () => DatrixConfig;\n\n/**\n * Datrix Main Class\n */\nexport class Datrix implements IDatrix {\n\tprivate config: DatrixConfig | null = null;\n\tprivate adapter: DatabaseAdapter | null = null;\n\tprivate pluginRegistry: PluginRegistry = new PluginRegistry();\n\tprivate dispatcher: Dispatcher | null = null;\n\tprivate _schemas: SchemaRegistry = new SchemaRegistry();\n\tprivate initialized = false;\n\n\tprivate _crud!: CrudOperations;\n\tprivate _rawCrud!: CrudOperations;\n\n\t/**\n\t * Initialize with config object directly\n\t */\n\tasync initializeWithConfig(\n\t\tconfig: DatrixConfig,\n\t\toptions: DatrixInitOptions = {},\n\t): Promise<void> {\n\t\tif (this.initialized) {\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tthis.config = config;\n\t\t\tthis.adapter = config.adapter;\n\n\t\t\t// Register plugins\n\t\t\tif (!options.skipPlugins && config.plugins) {\n\t\t\t\tfor (const plugin of config.plugins) {\n\t\t\t\t\tthis.pluginRegistry.register(plugin);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Create dispatcher\n\t\t\tthis.dispatcher = createDispatcher(this.pluginRegistry, this);\n\n\t\t\t// Connect to database\n\t\t\tif (!options.skipConnection && this.adapter) {\n\t\t\t\tawait this.adapter.connect(this._schemas);\n\t\t\t}\n\n\t\t\t// 1. Register internal _datrix metadata schema\n\t\t\tconst datrixMetaSchema = getDatrixMetaSchema();\n\t\t\tthis._schemas.register(datrixMetaSchema);\n\n\t\t\t// 2. Register user schemas\n\t\t\tif (!options.skipSchemas && config.schemas.length > 0) {\n\t\t\t\tfor (const schema of config.schemas) {\n\t\t\t\t\tthis._schemas.register(schema);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// 3. Register plugin schemas\n\t\t\tif (!options.skipPlugins) {\n\t\t\t\tfor (const plugin of this.pluginRegistry.getAll()) {\n\t\t\t\t\tif (plugin.getSchemas) {\n\t\t\t\t\t\tconst pluginSchemas = await plugin.getSchemas();\n\t\t\t\t\t\tfor (const schema of pluginSchemas) {\n\t\t\t\t\t\t\tthis._schemas.register(schema);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// 4. Apply schema extensions\n\t\t\tif (!options.skipPlugins) {\n\t\t\t\tconst extensionContext = new SchemaExtensionContextImpl(\n\t\t\t\t\tthis._schemas.getAll(),\n\t\t\t\t);\n\n\t\t\t\tfor (const plugin of this.pluginRegistry.getAll()) {\n\t\t\t\t\tif (plugin.extendSchemas) {\n\t\t\t\t\t\tconst extensions = await plugin.extendSchemas(extensionContext);\n\t\t\t\t\t\tthis.applySchemaExtensions(extensions);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// 5. Register internal migration schema\n\t\t\tconst migrationModelName =\n\t\t\t\tconfig.migration?.modelName ?? DEFAULT_MIGRATION_MODEL;\n\t\t\tconst migrationSchema = getMigrationSchema(migrationModelName);\n\t\t\tthis._schemas.register(migrationSchema);\n\n\t\t\t// 5. Finalize registry (process relations, create junction tables)\n\t\t\tthis._schemas.finalizeRegistry();\n\n\t\t\t// Initialize mixins\n\t\t\tthis._crud = new CrudOperations(\n\t\t\t\tthis._schemas,\n\t\t\t\t() => this.adapter!,\n\t\t\t\t() => this.dispatcher!,\n\t\t\t);\n\t\t\tthis._rawCrud = new CrudOperations(\n\t\t\t\tthis._schemas,\n\t\t\t\t() => this.adapter!,\n\t\t\t\tnull, // No dispatcher = raw mode (bypasses plugin hooks)\n\t\t\t);\n\n\t\t\t// Initialize plugins\n\t\t\tif (!options.skipPlugins) {\n\t\t\t\tconst pluginContext: PluginContext = {\n\t\t\t\t\tadapter: this.adapter!,\n\t\t\t\t\tschemas: this._schemas,\n\t\t\t\t\tconfig: this.config,\n\t\t\t\t};\n\n\t\t\t\tawait this.pluginRegistry.initAll(pluginContext);\n\t\t\t}\n\n\t\t\t// Dispatch schema load event\n\t\t\tif (!options.skipPlugins) {\n\t\t\t\tawait this.dispatcher.dispatchSchemaLoad(this._schemas);\n\t\t\t}\n\n\t\t\tthis.initialized = true;\n\n\t\t\t// Auto-migrate if configured\n\t\t\tconst migrationConfig = this.getMigrationConfig();\n\t\t\tif (migrationConfig.auto) {\n\t\t\t\tconst session = await createMigrationSession(this);\n\n\t\t\t\tif (session.ambiguous.length > 0) {\n\t\t\t\t\tconst ambiguousIds = session.ambiguous.map((a) => a.id).join(\", \");\n\t\t\t\t\tthrow new DatrixError(\n\t\t\t\t\t\t`Auto-migration aborted: ambiguous schema changes detected (${ambiguousIds}). Run \"datrix migrate\" interactively to resolve.`,\n\t\t\t\t\t\t{ code: \"INIT_FAILED\" },\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tif (session.hasChanges()) {\n\t\t\t\t\tawait session.apply();\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tif (error instanceof DatrixError) {\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\tthrow new DatrixError(\n\t\t\t\t`Initialization failed: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t\t{\n\t\t\t\t\tcode: \"INIT_FAILED\",\n\t\t\t\t\tcause: error instanceof Error ? error : undefined,\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\t}\n\n\tasync shutdown(): Promise<void> {\n\t\tif (!this.initialized) {\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tawait this.pluginRegistry.destroyAll();\n\n\t\t\tif (this.adapter) {\n\t\t\t\tawait this.adapter.disconnect();\n\t\t\t}\n\n\t\t\tthis._schemas.clear();\n\t\t\tthis.dispatcher = null;\n\t\t\tthis.initialized = false;\n\t\t} catch (error) {\n\t\t\tthrow new DatrixError(\n\t\t\t\t`Shutdown failed: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t\t{\n\t\t\t\t\tcode: \"SHUTDOWN_FAILED\",\n\t\t\t\t\tcause: error instanceof Error ? error : undefined,\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\t}\n\n\tgetConfig(): DatrixConfig {\n\t\tthis.ensureInitialized();\n\t\treturn this.config!;\n\t}\n\n\tgetAdapter<T extends DatabaseAdapter = DatabaseAdapter>(): T {\n\t\tthis.ensureInitialized();\n\t\treturn this.adapter as T;\n\t}\n\n\tgetPlugins(): readonly DatrixPlugin[] {\n\t\tthis.ensureInitialized();\n\t\treturn this.pluginRegistry.getAll();\n\t}\n\n\tgetPlugin<T extends DatrixPlugin = DatrixPlugin>(name: string): T | null {\n\t\tthis.ensureInitialized();\n\t\treturn (this.pluginRegistry.get(name) as T) ?? null;\n\t}\n\n\thasPlugin(name: string): boolean {\n\t\tthis.ensureInitialized();\n\t\treturn this.pluginRegistry.has(name);\n\t}\n\n\tgetDispatcher(): Dispatcher {\n\t\tthis.ensureInitialized();\n\t\treturn this.dispatcher!;\n\t}\n\n\tgetSchemas(): SchemaRegistry {\n\t\tthis.ensureInitialized();\n\t\treturn this._schemas;\n\t}\n\n\tgetMigrationConfig(): Required<MigrationConfig> {\n\t\tthis.ensureInitialized();\n\t\tconst userConfig = this.config!.migration ?? {};\n\t\treturn { ...DEFAULT_MIGRATION_CONFIG, ...userConfig };\n\t}\n\n\tgetDevConfig(): Required<DevConfig> {\n\t\tthis.ensureInitialized();\n\t\tconst userConfig = this.config!.dev ?? {};\n\t\treturn { ...DEFAULT_DEV_CONFIG, ...userConfig };\n\t}\n\n\tisInitialized(): boolean {\n\t\treturn this.initialized;\n\t}\n\n\t/**\n\t * Begin a migration session\n\t *\n\t * Compares current schemas with database state and returns a session\n\t * for reviewing and applying changes.\n\t *\n\t * @example\n\t * ```ts\n\t * const session = await datrix.beginMigrate();\n\t *\n\t * // Check what will change\n\t * console.log(session.tablesToCreate);\n\t * console.log(session.tablesToDrop);\n\t * console.log(session.tablesToAlter);\n\t *\n\t * // Resolve ambiguous changes (e.g., rename vs drop+add)\n\t * if (session.ambiguous.length > 0) {\n\t * session.resolveAmbiguous('user.name->lastname', 'rename');\n\t * }\n\t *\n\t * // Preview operations\n\t * const plan = session.getPlan();\n\t *\n\t * // Apply migrations\n\t * await session.apply();\n\t * ```\n\t */\n\tasync beginMigrate(): Promise<MigrationSession> {\n\t\tthis.ensureInitialized();\n\n\t\treturn await createMigrationSession(this);\n\t}\n\n\tget crud(): CrudOperations {\n\t\tthis.ensureInitialized();\n\t\treturn this._crud;\n\t}\n\n\t/**\n\t * Raw CRUD operations (bypasses plugin hooks)\n\t *\n\t * Use this when you need direct database access without\n\t * triggering onBeforeQuery/onAfterQuery plugin hooks.\n\t *\n\t * @example\n\t * ```ts\n\t * // Normal (with hooks)\n\t * const user = await datrix.findOne('User', { id: 1 });\n\t *\n\t * // Raw (without hooks)\n\t * const user = await datrix.raw.findOne('User', { id: 1 });\n\t * ```\n\t */\n\tget raw(): CrudOperations {\n\t\tthis.ensureInitialized();\n\t\treturn this._rawCrud;\n\t}\n\n\tasync findOne<T extends DatrixEntry = DatrixRecord>(\n\t\tmodel: string,\n\t\twhere: WhereClause<T>,\n\t\toptions?: RawCrudOptions<T>,\n\t): Promise<T | null> {\n\t\tthis.ensureInitialized();\n\t\treturn this._crud.findOne<T>(model, where, options);\n\t}\n\n\tasync findById<T extends DatrixEntry = DatrixRecord>(\n\t\tmodel: string,\n\t\tid: number,\n\t\toptions?: RawCrudOptions<T>,\n\t): Promise<T | null> {\n\t\tthis.ensureInitialized();\n\t\treturn this._crud.findById<T>(model, id, options);\n\t}\n\n\tasync findMany<T extends DatrixEntry = DatrixRecord>(\n\t\tmodel: string,\n\t\toptions?: RawFindManyOptions<T>,\n\t): Promise<T[]> {\n\t\tthis.ensureInitialized();\n\t\treturn this._crud.findMany<T>(model, options);\n\t}\n\n\tasync count<T extends DatrixEntry = DatrixRecord>(\n\t\tmodel: string,\n\t\twhere?: WhereClause<T>,\n\t): Promise<number> {\n\t\tthis.ensureInitialized();\n\t\treturn this._crud.count(model, where);\n\t}\n\n\tasync create<\n\t\tT extends DatrixEntry = DatrixRecord,\n\t\tTInput extends FallbackInput = FallbackInput,\n\t>(model: string, data: TInput, options?: RawCrudOptions<T>): Promise<T> {\n\t\tthis.ensureInitialized();\n\t\treturn this._crud.create<T, TInput>(model, data, options);\n\t}\n\n\tasync createMany<\n\t\tT extends DatrixEntry = DatrixRecord,\n\t\tTInput extends FallbackInput = FallbackInput,\n\t>(model: string, data: TInput[], options?: RawCrudOptions<T>): Promise<T[]> {\n\t\tthis.ensureInitialized();\n\t\treturn this._crud.createMany<T, TInput>(model, data, options);\n\t}\n\n\tasync update<\n\t\tT extends DatrixEntry = DatrixRecord,\n\t\tTInput extends FallbackInput = FallbackInput,\n\t>(\n\t\tmodel: string,\n\t\tid: number,\n\t\tdata: TInput,\n\t\toptions?: RawCrudOptions<T>,\n\t): Promise<T> {\n\t\tthis.ensureInitialized();\n\t\treturn this._crud.update<T, TInput>(model, id, data, options);\n\t}\n\n\tasync updateMany<\n\t\tT extends DatrixEntry = DatrixRecord,\n\t\tTInput extends FallbackInput = FallbackInput,\n\t>(\n\t\tmodel: string,\n\t\twhere: WhereClause<T>,\n\t\tdata: TInput,\n\t\toptions?: RawCrudOptions<T>,\n\t): Promise<T[]> {\n\t\tthis.ensureInitialized();\n\t\treturn this._crud.updateMany<T, TInput>(model, where, data, options);\n\t}\n\n\tasync delete<T extends DatrixEntry = DatrixRecord>(\n\t\tmodel: string,\n\t\tid: number,\n\t\toptions?: RawCrudOptions<T>,\n\t): Promise<T> {\n\t\tthis.ensureInitialized();\n\t\treturn this._crud.delete(model, id, options);\n\t}\n\n\tasync deleteMany<T extends DatrixEntry = DatrixRecord>(\n\t\tmodel: string,\n\t\twhere: WhereClause<T>,\n\t\toptions?: RawCrudOptions<T>,\n\t): Promise<T[]> {\n\t\tthis.ensureInitialized();\n\t\treturn this._crud.deleteMany(model, where, options);\n\t}\n\n\tget schema(): SchemaRegistry {\n\t\tthis.ensureInitialized();\n\t\treturn this._schemas;\n\t}\n\n\tgetSchema(name: string) {\n\t\tthis.ensureInitialized();\n\t\treturn this._schemas.get(name);\n\t}\n\n\tgetAllSchemas() {\n\t\tthis.ensureInitialized();\n\t\treturn this._schemas.getAll();\n\t}\n\n\thasSchema(name: string): boolean {\n\t\tthis.ensureInitialized();\n\t\treturn this._schemas.has(name);\n\t}\n\n\treset(): void {\n\t\tthis.config = null;\n\t\tthis.adapter = null;\n\t\tthis.pluginRegistry = new PluginRegistry();\n\t\tthis.dispatcher = null;\n\t\tthis._schemas = new SchemaRegistry();\n\t\tthis.initialized = false;\n\t}\n\n\tprivate ensureInitialized(): void {\n\t\tif (!this.initialized) {\n\t\t\tthrow new DatrixError(\n\t\t\t\t\"Datrix not initialized. Use defineConfig() and call the returned function first.\",\n\t\t\t\t{ code: \"NOT_INITIALIZED\" },\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate applySchemaExtensions(extensions: SchemaExtension[]): void {\n\t\tfor (const extension of extensions) {\n\t\t\tconst schema = this._schemas.get(extension.targetSchema)!;\n\t\t\tconst extendedFields = { ...schema.fields };\n\t\t\tconst extendedIndexes = [...(schema.indexes || [])];\n\n\t\t\tif (extension.fields) {\n\t\t\t\tfor (const [fieldName, fieldDef] of Object.entries(extension.fields)) {\n\t\t\t\t\tif (extendedFields[fieldName]) {\n\t\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t\t`[Datrix] Field '${fieldName}' already exists in schema '${extension.targetSchema}'. Skipping.`,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\textendedFields[fieldName] = fieldDef;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (extension.removeFields) {\n\t\t\t\tfor (const fieldName of extension.removeFields) {\n\t\t\t\t\tdelete extendedFields[fieldName];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (extension.modifyFields) {\n\t\t\t\tfor (const [fieldName, modifications] of Object.entries(\n\t\t\t\t\textension.modifyFields,\n\t\t\t\t)) {\n\t\t\t\t\tif (!extendedFields[fieldName]) {\n\t\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t\t`[Datrix] Cannot modify field '${fieldName}' in schema '${extension.targetSchema}': field not found. Skipping.`,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\textendedFields[fieldName] = {\n\t\t\t\t\t\t...extendedFields[fieldName],\n\t\t\t\t\t\t...modifications,\n\t\t\t\t\t} as any;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (extension.indexes) {\n\t\t\t\textendedIndexes.push(...extension.indexes);\n\t\t\t}\n\n\t\t\tconst extendedSchema = {\n\t\t\t\t...schema,\n\t\t\t\tfields: extendedFields,\n\t\t\t\tindexes: extendedIndexes,\n\t\t\t};\n\n\t\t\tthis._schemas.register(extendedSchema);\n\t\t}\n\t}\n}\n\n/**\n * Define Datrix configuration\n *\n * Returns a function that when called, returns an initialized Datrix instance.\n * The config factory is only called once on first invocation.\n *\n * @example\n * ```ts\n * // datrix.config.ts\n * import { defineConfig } from '..';\n *\n * export default defineConfig(() => ({\n * adapter: new JsonAdapter({ root: './data' }),\n * schemas: [userSchema, topicSchema],\n * }));\n * ```\n *\n * @example\n * ```ts\n * // Usage anywhere\n * import datrix from './datrix.config';\n *\n * const users = await datrix().findMany('user');\n * ```\n */\nexport function defineConfig(factory: ConfigFactory): () => Promise<Datrix> {\n\tconst instance = new Datrix();\n\tlet initPromise: Promise<Datrix> | null = null;\n\n\treturn async function getDatrixInstance(): Promise<Datrix> {\n\t\t// Already initialized - return immediately\n\t\tif (instance.isInitialized()) {\n\t\t\treturn instance;\n\t\t}\n\n\t\t// Initialization in progress - wait for it\n\t\tif (initPromise) {\n\t\t\treturn initPromise;\n\t\t}\n\n\t\t// Start initialization\n\t\tinitPromise = (async () => {\n\t\t\tconst config = factory();\n\n\t\t\ttry {\n\t\t\t\tawait instance.initializeWithConfig(config);\n\t\t\t} finally {\n\t\t\t\tinitPromise = null;\n\t\t\t}\n\n\t\t\treturn instance;\n\t\t})();\n\n\t\treturn initPromise;\n\t};\n}\n","/**\n * Permission System Types\n *\n * Schema-based permission system with role validation, function-based checks,\n * and field-level access control.\n */\n\nimport { AuthUser } from \"../api\";\nimport { DatrixEntry } from \"./schema\";\n\n/**\n * Permission actions for schema-level access\n */\nexport type PermissionAction = \"create\" | \"read\" | \"update\" | \"delete\";\n\n/**\n * Permission actions for field-level access\n */\nexport type FieldPermissionAction = \"read\" | \"write\";\n\n/**\n * Permission evaluation context\n *\n * @template TRecord - The record type for the schema\n */\nexport interface PermissionContext<TRecord extends DatrixEntry = DatrixEntry> {\n\t/** Current authenticated user (undefined if not authenticated) */\n\treadonly user: AuthUser | undefined;\n\t/** Current record (for update/delete operations) */\n\treadonly record?: TRecord;\n\t/** Input data (for create/update operations) */\n\treadonly input?: Partial<TRecord>;\n\t/** Current action being performed */\n\treadonly action: PermissionAction;\n\n\treadonly id?: number | string | null;\n\t/**\n\t * Datrix instance for custom queries\n\t * User can perform additional checks if needed\n\t */\n\treadonly datrix: unknown; // Avoid circular dependency\n}\n\n/**\n * Permission function type\n * Returns boolean or Promise<boolean> for async checks\n *\n * @template TRecord - The record type for the schema\n */\nexport type PermissionFn<TRecord extends DatrixEntry = DatrixEntry> = (\n\tctx: PermissionContext<TRecord>,\n) => boolean | Promise<boolean>;\n\n/**\n * Permission value type - supports multiple formats:\n * - `true` = everyone allowed\n * - `false` = no one allowed\n * - `['admin', 'editor']` = only these roles\n * - `(ctx) => boolean` = custom function\n * - `['admin', (ctx) => ctx.user?.id === ctx.record?.authorId]` = role OR function (OR logic)\n *\n * @template TRoles - Union type of valid role names\n * @template TRecord - The record type for the schema\n */\nexport type PermissionValue<\n\tTRoles extends string = string,\n\tTRecord extends DatrixEntry = DatrixEntry,\n> =\n\t| boolean\n\t| readonly TRoles[]\n\t| PermissionFn<TRecord>\n\t| readonly (TRoles | PermissionFn<TRecord>)[];\n\n/**\n * Schema-level permission configuration\n *\n * @template TRoles - Union type of valid role names\n * @template TRecord - The record type for the schema\n *\n * @example\n * ```ts\n * const permission: SchemaPermission<'admin' | 'editor' | 'user'> = {\n * create: ['admin', 'editor'],\n * read: true,\n * update: ['admin', (ctx) => ctx.user?.id === ctx.record?.authorId],\n * delete: ['admin'],\n * };\n * ```\n */\nexport interface SchemaPermission<\n\tTRoles extends string = string,\n\tTRecord extends DatrixEntry = DatrixEntry,\n> {\n\treadonly create?: PermissionValue<TRoles, TRecord>;\n\treadonly read?: PermissionValue<TRoles, TRecord>;\n\treadonly update?: PermissionValue<TRoles, TRecord>;\n\treadonly delete?: PermissionValue<TRoles, TRecord>;\n}\n\n/**\n * Field-level permission configuration\n *\n * - `read`: If user doesn't have permission, field is removed from response\n * - `write`: If user doesn't have permission, returns 403 error\n *\n * @template TRoles - Union type of valid role names\n * @template TRecord - The record type for the schema\n *\n * @example\n * ```ts\n * const field = {\n * type: 'string',\n * permission: {\n * read: ['admin', 'hr'], // Only admin/hr can see this field\n * write: ['admin'], // Only admin can modify\n * }\n * };\n * ```\n */\nexport interface FieldPermission<\n\tTRoles extends string = string,\n\tTRecord extends DatrixEntry = DatrixEntry,\n> {\n\treadonly read?: PermissionValue<TRoles, TRecord>;\n\treadonly write?: PermissionValue<TRoles, TRecord>;\n}\n\n/**\n * Default permission configuration for API\n *\n * Applied to all schemas that don't have explicit permissions\n *\n * @template TRoles - Union type of valid role names\n */\nexport interface DefaultPermission<TRoles extends string = string> {\n\treadonly create?: PermissionValue<TRoles>;\n\treadonly read?: PermissionValue<TRoles>;\n\treadonly update?: PermissionValue<TRoles>;\n\treadonly delete?: PermissionValue<TRoles>;\n}\n\n/**\n * Permission check result\n */\nexport interface PermissionCheckResult {\n\treadonly allowed: boolean;\n\treadonly reason?: string | undefined;\n}\n\n/**\n * Field permission check result\n */\nexport interface FieldPermissionCheckResult {\n\treadonly allowed: boolean;\n\treadonly deniedFields?: readonly string[] | undefined;\n}\n\n/**\n * Type guard for PermissionFn\n */\nexport function isPermissionFn<TRecord extends DatrixEntry = DatrixEntry>(\n\tvalue: unknown,\n): value is PermissionFn<TRecord> {\n\treturn typeof value === \"function\";\n}\n","/**\n * Database Adapter Interface\n *\n * This file defines the standard interface that ALL database adapters must implement.\n * Adapters provide database-specific implementations for PostgreSQL, MySQL, MongoDB, etc.\n *\n * Error handling: All methods throw DatrixAdapterError on failure instead of returning Result.\n */\n\nimport { QueryObject, WhereClause } from \"../core/query-builder\";\nimport {\n\tFieldDefinition,\n\tDatrixEntry,\n\tIndexDefinition,\n\tISchemaRegistry,\n\tSchemaDefinition,\n} from \"../core/schema\";\nimport { DatrixAdapterError } from \"../errors/adapter\";\n\n/**\n * Export data metadata\n */\nexport interface ExportMeta {\n\treadonly version: number;\n\treadonly exportedAt: string;\n}\n\n/**\n * Writer interface for export operations.\n *\n * Adapter calls these methods to stream export data.\n * CLI provides the concrete implementation (zip, file, memory, etc.)\n */\nexport interface ExportWriter {\n\twriteMeta(meta: ExportMeta): Promise<void>;\n\twriteSchema(schema: SchemaDefinition): Promise<void>;\n\twriteChunk(tableName: string, rows: Record<string, unknown>[]): Promise<void>;\n\tfinalize(): Promise<void>;\n}\n\n/**\n * Reader interface for import operations.\n *\n * Adapter calls these methods to stream import data.\n * CLI provides the concrete implementation (zip, file, memory, etc.)\n */\nexport interface ImportReader {\n\treadMeta(): Promise<ExportMeta>;\n\treadSchemas(): AsyncIterable<SchemaDefinition>;\n\tgetTables(): Promise<readonly string[]>;\n\treadChunks(tableName: string): AsyncIterable<Record<string, unknown>[]>;\n}\n\nexport { DatrixAdapterError };\n\n/**\n * Query result metadata\n */\nexport interface QueryMetadata {\n\treadonly rowCount?: number;\n\treadonly affectedRows?: number;\n\treadonly insertIds?: readonly number[];\n\treadonly count?: number;\n}\n\n/**\n * Query result\n */\nexport interface QueryResult<T = unknown> {\n\treadonly rows: readonly T[];\n\treadonly metadata: QueryMetadata;\n}\n\n/**\n * Common query execution interface shared by DatabaseAdapter and Transaction.\n */\nexport interface QueryRunner {\n\texecuteQuery<TResult extends DatrixEntry>(\n\t\tquery: QueryObject<TResult>,\n\t): Promise<QueryResult<TResult>>;\n\n\texecuteRawQuery<TResult extends DatrixEntry>(\n\t\tsql: string,\n\t\tparams: readonly unknown[],\n\t): Promise<QueryResult<TResult>>;\n}\n\n/**\n * Schema operations interface - shared by DatabaseAdapter and Transaction.\n * Migrations should use Transaction for atomic DDL operations.\n */\nexport interface SchemaOperations {\n\tcreateTable(schema: SchemaDefinition): Promise<void>;\n\tdropTable(tableName: string): Promise<void>;\n\trenameTable(from: string, to: string): Promise<void>;\n\talterTable(\n\t\ttableName: string,\n\t\toperations: readonly AlterOperation[],\n\t): Promise<void>;\n\taddIndex(tableName: string, index: IndexDefinition): Promise<void>;\n\tdropIndex(tableName: string, indexName: string): Promise<void>;\n}\n\n/**\n * Transaction interface\n *\n * Extends both QueryRunner and SchemaOperations to support:\n * - Query execution within transaction\n * - Schema modifications within transaction (for atomic migrations)\n */\nexport interface Transaction extends QueryRunner, SchemaOperations {\n\treadonly id: string;\n\n\tcommit(): Promise<void>;\n\trollback(): Promise<void>;\n\n\t// Savepoints\n\tsavepoint(name: string): Promise<void>;\n\trollbackTo(name: string): Promise<void>;\n\trelease(name: string): Promise<void>;\n}\n\n/**\n * Alter table operations\n */\nexport type AlterOperation =\n\t| {\n\t\treadonly type: \"addColumn\";\n\t\treadonly column: string;\n\t\treadonly definition: FieldDefinition;\n\t}\n\t| { readonly type: \"dropColumn\"; readonly column: string }\n\t| {\n\t\treadonly type: \"modifyColumn\";\n\t\treadonly column: string;\n\t\treadonly newDefinition: FieldDefinition;\n\t}\n\t| {\n\t\treadonly type: \"renameColumn\";\n\t\treadonly from: string;\n\t\treadonly to: string;\n\t}\n\t| {\n\t\treadonly type: \"addMetaField\";\n\t\treadonly field: string;\n\t\treadonly definition: FieldDefinition;\n\t}\n\t| { readonly type: \"dropMetaField\"; readonly field: string }\n\t| {\n\t\treadonly type: \"modifyMetaField\";\n\t\treadonly field: string;\n\t\treadonly newDefinition: FieldDefinition;\n\t};\n\n/**\n * Connection state\n */\nexport type ConnectionState =\n\t| \"disconnected\"\n\t| \"connecting\"\n\t| \"connected\"\n\t| \"error\";\n\n/**\n * Database adapter interface\n *\n * ALL database adapters MUST implement this interface.\n * Extends QueryRunner for query execution and SchemaOperations for DDL.\n *\n * Note: For migrations, prefer using Transaction (from beginTransaction())\n * to ensure atomic DDL operations where supported by the database.\n */\nexport interface DatabaseAdapter<TConfig = object>\n\textends QueryRunner, SchemaOperations {\n\t// Metadata\n\treadonly name: string;\n\treadonly config: TConfig;\n\n\t// Connection management\n\tconnect(schemas: ISchemaRegistry): Promise<void>;\n\tdisconnect(): Promise<void>;\n\tisConnected(): boolean;\n\tgetConnectionState(): ConnectionState;\n\n\t// Transaction support\n\tbeginTransaction(): Promise<Transaction>;\n\n\t// Introspection\n\tgetTables(): Promise<readonly string[]>;\n\tgetTableSchema(tableName: string): Promise<SchemaDefinition | null>;\n\ttableExists(tableName: string): Promise<boolean>;\n\n\t// Export / Import\n\texportData(writer: ExportWriter): Promise<void>;\n\timportData(reader: ImportReader): Promise<void>;\n}\n\n/**\n * Type guard for DatabaseAdapter\n */\nexport function isDatabaseAdapter(\n\tvalue: unknown,\n): value is DatabaseAdapter<unknown> {\n\treturn (\n\t\ttypeof value === \"object\" &&\n\t\tvalue !== null &&\n\t\t\"name\" in value &&\n\t\t\"config\" in value &&\n\t\t\"connect\" in value &&\n\t\t\"disconnect\" in value &&\n\t\t\"executeQuery\" in value &&\n\t\t\"exportData\" in value &&\n\t\t\"importData\" in value &&\n\t\ttypeof (value as DatabaseAdapter).connect === \"function\" &&\n\t\ttypeof (value as DatabaseAdapter).disconnect === \"function\" &&\n\t\ttypeof (value as DatabaseAdapter).executeQuery === \"function\" &&\n\t\ttypeof (value as DatabaseAdapter).exportData === \"function\" &&\n\t\ttypeof (value as DatabaseAdapter).importData === \"function\"\n\t);\n}\n\n/**\n * SQL parameter placeholder style\n */\nexport type ParameterStyle =\n\t| \"numbered\" // PostgreSQL: $1, $2, $3\n\t| \"question\" // MySQL: ?, ?, ?\n\t| \"named\"; // Named: :param1, :param2\n\n/**\n * SQL dialect\n */\nexport type SqlDialect = \"postgres\" | \"mysql\" | \"sqlite\";\n\n/**\n * Query translator interface\n */\nexport interface QueryTranslator<T extends DatrixEntry = DatrixEntry> {\n\ttranslate(query: QueryObject<T>): {\n\t\treadonly sql: string;\n\t\treadonly params: readonly unknown[];\n\t};\n\n\ttranslateWhere(\n\t\twhere: WhereClause<T>,\n\t\tstartIndex: number,\n\t): {\n\t\treadonly sql: string;\n\t\treadonly params: readonly unknown[];\n\t};\n\n\tescapeIdentifier(identifier: string): string;\n\tescapeValue(value: unknown): string;\n\tgetParameterPlaceholder(index: number): string;\n}\n","/**\n * Parser Type Definitions\n *\n * Types for parsing URL query strings into QueryObject format.\n * Supports: populate, fields, where, pagination, sorting\n */\n\nimport { DatrixEntry, DatrixRecord } from \"../core/schema\";\nimport {\n\tOrderByClause,\n\tOrderByItem,\n\tPopulateClause,\n\tSelectClause,\n\tWhereClause,\n} from \"../core/query-builder\";\n\n/**\n * Raw query parameters from HTTP request\n * (framework-agnostic - works with URLSearchParams, Express req.query, etc.)\n */\nexport type RawQueryParams = Record<\n\tstring,\n\tstring | readonly string[] | undefined\n>;\n\n/**\n * Parsed query result\n */\n\nexport interface ParsedQuery<T extends DatrixEntry = DatrixEntry> {\n\treadonly select?: SelectClause<T>;\n\treadonly where?: WhereClause<T>;\n\treadonly populate?: PopulateClause<T>;\n\treadonly orderBy?: OrderByClause<T>;\n\treadonly page?: number;\n\treadonly pageSize?: number;\n}\n\n/**\n * Parser options\n */\nexport interface ParserOptions {\n\treadonly maxPageSize?: number; // Default: 100\n\treadonly defaultPageSize?: number; // Default: 25\n\treadonly maxPopulateDepth?: number; // Default: 5\n\treadonly allowedOperators?: readonly string[]; // Default: all\n\treadonly strictMode?: boolean; // Fail on unknown fields\n}\n\n// Re-export parser error types from errors module\nexport type {\n\tParserType,\n\tParserErrorCode,\n\tParserErrorContext,\n\tWhereErrorContext,\n\tPopulateErrorContext,\n\tFieldsErrorContext,\n\tPaginationErrorContext,\n\tSortErrorContext,\n\tBaseErrorContext,\n\tErrorLocation,\n\tParserErrorOptions,\n\tSerializedParserError,\n} from \"../errors/api/parser\";\n\nexport { ParserError, buildErrorLocation } from \"../errors/api/parser\";\n\n/**\n * Supported WHERE operators\n */\nexport const WHERE_OPERATORS = [\n\t\"$eq\",\n\t\"$ne\",\n\t\"$lt\",\n\t\"$lte\",\n\t\"$gt\",\n\t\"$gte\",\n\t\"$in\",\n\t\"$nin\",\n\t\"$contains\",\n\t\"$notContains\",\n\t\"$startsWith\",\n\t\"$endsWith\",\n\t\"$null\",\n\t\"$notNull\",\n\t\"$like\",\n\t\"$ilike\",\n\t\"$and\",\n\t\"$or\",\n\t\"$not\",\n] as const;\n\n/**\n * WHERE operator type\n */\nexport type WhereOperator = (typeof WHERE_OPERATORS)[number];\n\n/**\n * Check if string is a valid operator\n */\nexport function isWhereOperator(value: string): value is WhereOperator {\n\treturn WHERE_OPERATORS.includes(value as WhereOperator);\n}\n\n/**\n * Pagination parameters\n */\nexport interface PaginationParams {\n\treadonly page?: number;\n\treadonly pageSize?: number;\n}\n\n/**\n * Parse pagination result\n */\nexport interface ParsedPagination {\n\treadonly page: number;\n\treadonly pageSize: number;\n}\n\n/**\n * Sort parameters\n */\nexport type SortParam = string | readonly string[];\n\n/**\n * Parse sort result\n */\nexport type ParsedSort<T extends DatrixEntry = DatrixRecord> =\n\treadonly OrderByItem<T>[];\n","/**\n * Upload Types\n *\n * Storage provider interface and related types for the upload system.\n * Moved here from plugin-upload so api package can reference it directly.\n */\n\nimport { SchemaPermission } from \"../core/permission\";\nimport type { DatrixEntry, SchemaDefinition } from \"../core/schema\";\n\n/**\n * Raw file data received from multipart/form-data parsing\n */\nexport interface UploadFile {\n\treadonly filename: string;\n\treadonly originalName: string;\n\treadonly mimetype: string;\n\treadonly size: number;\n\treadonly buffer: Uint8Array;\n}\n\n/**\n * Result returned by a storage provider after a successful upload\n */\nexport interface UploadResult {\n\treadonly key: string;\n\treadonly size: number;\n\treadonly mimetype: string;\n\treadonly uploadedAt: Date;\n}\n\n/**\n * Storage provider interface.\n * Implement this to add a new storage backend (S3, local, GCS, etc.)\n */\nexport interface StorageProvider {\n\treadonly name: string;\n\tupload(file: UploadFile): Promise<UploadResult>;\n\tdelete(key: string): Promise<void>;\n\tgetUrl(key: string): string;\n\texists(key: string): Promise<boolean>;\n}\n\n/**\n * A single processed variant (thumbnail, small, medium, etc.)\n */\nexport interface MediaVariant {\n\treadonly key: string;\n\treadonly url: string;\n\treadonly width: number;\n\treadonly height: number;\n\treadonly size: number;\n\treadonly mimeType: string;\n}\n\n/**\n * Map of resolution name → variant data.\n * Keys are whatever the user defines in Upload config resolutions.\n *\n * @example\n * ```ts\n * const variants: MediaVariants<\"thumbnail\" | \"small\"> = {\n * thumbnail: { url: \"...\", width: 150, height: 150, size: 4200, mimeType: \"image/webp\" },\n * small: { url: \"...\", width: 640, height: 360, size: 32000, mimeType: \"image/webp\" },\n * }\n * ```\n */\nexport type MediaVariants<TResolutions extends string = string> = {\n\treadonly [K in TResolutions]?: MediaVariant;\n};\n\n/**\n * Shape of a media record stored in the database.\n * Injected as the \"media\" schema by ApiPlugin when upload is configured.\n * TResolutions narrows the variants field for type-safe access.\n */\nexport interface MediaEntry<\n\tTResolutions extends string = string,\n> extends DatrixEntry {\n\treadonly filename: string;\n\treadonly originalName: string;\n\treadonly mimeType: string;\n\treadonly size: number;\n\treadonly url: string;\n\treadonly key: string;\n\treadonly variants: MediaVariants<TResolutions> | null;\n}\n\n/**\n * Upload configuration inside ApiConfig\n */\nexport interface UploadConfig {\n\t/**\n\t * Storage provider instance (S3, Local, etc.)\n\t */\n\treadonly provider: StorageProvider;\n\n\t/**\n\t * Custom table/model name for media records\n\t * @default \"media\"\n\t */\n\treadonly modelName?: string;\n\n\t/**\n\t * Global max file size in bytes (can be overridden per FileField)\n\t */\n\treadonly maxSize?: number;\n\n\t/**\n\t * Global allowed MIME types (can be overridden per FileField)\n\t */\n\treadonly allowedMimeTypes?: readonly string[];\n\n\t/**\n\t * Permission config for the injected media schema\n\t */\n\treadonly permission?: SchemaPermission;\n}\n\n/**\n * Local provider options\n */\nexport interface LocalProviderOptions {\n\treadonly basePath: string;\n\treadonly baseUrl: string;\n\treadonly ensureDirectory?: boolean;\n}\n\n/**\n * S3 provider options\n */\nexport interface S3ProviderOptions {\n\treadonly bucket: string;\n\treadonly region: string;\n\treadonly accessKeyId: string;\n\treadonly secretAccessKey: string;\n\treadonly endpoint?: string;\n\treadonly pathPrefix?: string;\n}\n\n/**\n * Generate unique filename with timestamp and random suffix\n */\nexport function generateUniqueFilename(originalFilename: string): string {\n\tconst timestamp = Date.now();\n\tconst random = Math.random().toString(36).substring(2, 15);\n\tconst extension = getFileExtension(originalFilename);\n\treturn extension\n\t\t? `${timestamp}-${random}.${extension}`\n\t\t: `${timestamp}-${random}`;\n}\n\n/**\n * Get file extension (without dot)\n */\nexport function getFileExtension(filename: string): string {\n\tconst parts = filename.split(\".\");\n\tif (parts.length < 2) return \"\";\n\treturn parts[parts.length - 1] ?? \"\";\n}\n\n/**\n * Sanitize filename — removes path traversal and dangerous characters\n */\nexport function sanitizeFilename(filename: string): string {\n\treturn filename\n\t\t.replace(/\\.\\./g, \"\")\n\t\t.replace(/\\//g, \"\")\n\t\t.replace(/\\\\/g, \"\")\n\t\t.replace(/[<>:\"|?*]/g, \"\")\n\t\t.replace(/\\s+/g, \"-\")\n\t\t.toLowerCase();\n}\n\n/**\n * Interface that Upload implementations must satisfy.\n * ApiPlugin depends only on this — not on the concrete api-upload package.\n */\nexport interface IUpload {\n\tgetSchemas(): Promise<SchemaDefinition[]> | SchemaDefinition[];\n\thandleRequest(request: Request, datrix: unknown): Promise<Response>;\n\tgetModelName(): string;\n\t/**\n\t * Traverse any response data (including populated relations) and inject\n\t * url fields derived from key via the configured storage provider.\n\t */\n\tinjectUrls(data: unknown): Promise<unknown>;\n\t/**\n\t * Resolve a public URL for the given storage key via the configured provider.\n\t * Used by the CLI file exporter to download files during export.\n\t */\n\tgetUrl(key: string): string;\n\t/**\n\t * The underlying storage provider.\n\t * Used by the CLI file importer to upload files directly.\n\t */\n\treadonly provider: StorageProvider;\n}\n\n/**\n * Type guard for StorageProvider\n */\nexport function isStorageProvider(value: unknown): value is StorageProvider {\n\tif (typeof value !== \"object\" || value === null) {\n\t\treturn false;\n\t}\n\n\tconst obj = value as Record<string, unknown>;\n\n\treturn (\n\t\ttypeof obj[\"name\"] === \"string\" &&\n\t\ttypeof obj[\"upload\"] === \"function\" &&\n\t\ttypeof obj[\"delete\"] === \"function\" &&\n\t\ttypeof obj[\"getUrl\"] === \"function\" &&\n\t\ttypeof obj[\"exists\"] === \"function\"\n\t);\n}\n","/**\n * API Configuration Defaults\n */\n\nexport const DEFAULT_API_CONFIG = {\n\tenabled: true,\n\tprefix: \"/api\",\n\tdefaultPageSize: 25,\n\tmaxPageSize: 100,\n\tmaxPopulateDepth: 5,\n\tautoRoutes: true,\n\texcludeSchemas: [],\n} as const;\n\n/**\n * Default API Auth configuration values\n */\nexport const DEFAULT_API_AUTH_CONFIG = {\n\tenabled: true,\n\tuserSchema: {\n\t\tname: \"user\",\n\t\temail: \"email\",\n\t},\n\tjwt: {\n\t\texpiresIn: \"7d\",\n\t\talgorithm: \"HS256\" as const,\n\t},\n\tsession: {\n\t\tstore: \"memory\" as const,\n\t\tmaxAge: 86400,\n\t\tcheckPeriod: 3600,\n\t\tprefix: \"datrix:session:\",\n\t},\n\tpassword: {\n\t\titerations: 100000,\n\t\tkeyLength: 64,\n\t\tminLength: 8,\n\t},\n\tendpoints: {\n\t\tlogin: \"/auth/login\",\n\t\tregister: \"/auth/register\",\n\t\tlogout: \"/auth/logout\",\n\t\tme: \"/auth/me\",\n\t\tdisableRegister: false,\n\t},\n} as const;\n","/**\n * CLI Type Definitions\n *\n * Types for CLI command parsing, options, and errors.\n */\n\n/**\n * CLI Error class\n */\nexport class CLIError extends Error {\n\tconstructor(\n\t\tmessage: string,\n\t\tpublic readonly code:\n\t\t\t| \"INVALID_COMMAND\"\n\t\t\t| \"MISSING_ARGUMENT\"\n\t\t\t| \"FILE_ERROR\"\n\t\t\t| \"CONFIG_ERROR\"\n\t\t\t| \"EXECUTION_ERROR\",\n\t\tpublic readonly details?: unknown,\n\t) {\n\t\tsuper(message);\n\t\tthis.name = \"CLIError\";\n\t}\n}\n\n/**\n * Parsed command-line arguments\n */\nexport interface ParsedArgs {\n\treadonly command?: string | undefined;\n\treadonly subcommand?: string | undefined;\n\treadonly args: readonly string[];\n\treadonly options: Record<string, string | boolean>;\n}\n\n/**\n * Common command options\n */\nexport interface BaseCommandOptions {\n\treadonly config?: string | undefined;\n\treadonly verbose?: boolean | undefined;\n}\n\n/**\n * Migrate command options\n */\nexport interface MigrateCommandOptions extends BaseCommandOptions {\n\treadonly down?: boolean | undefined;\n\treadonly to?: string | undefined;\n\treadonly dryRun?: boolean | undefined;\n}\n\n/**\n * Generate command options\n */\nexport interface GenerateCommandOptions extends BaseCommandOptions {\n\treadonly output?: string | undefined;\n}\n\n/**\n * Dev command options\n */\nexport interface DevCommandOptions extends BaseCommandOptions {\n\treadonly watch?: boolean | undefined;\n}\n","/**\n * Abstract Base Plugin\n *\n * Provides a base implementation for plugins with common functionality.\n * Plugins can extend this class instead of implementing DatrixPlugin from scratch.\n */\n\nimport { QueryObject } from \"../types/core/query-builder\";\nimport {\n\tISchemaRegistry,\n\tSchemaDefinition,\n\tDatrixEntry,\n} from \"../types/core/schema\";\nimport {\n\tDatrixPlugin,\n\tPluginContext,\n\tPluginError,\n\tSchemaExtensionContext,\n\tSchemaExtension,\n} from \"../types/core/plugin\";\nimport { QueryContext } from \"../types/core/query-context\";\n\n/**\n * Abstract base plugin class\n *\n * Provides default implementations for optional hooks.\n * Subclasses must implement init() and destroy() methods.\n */\nexport abstract class BasePlugin<\n\tTOptions = Record<string, unknown>,\n> implements DatrixPlugin<TOptions> {\n\tabstract readonly name: string;\n\tabstract readonly version: string;\n\treadonly options: TOptions;\n\n\tprotected context: PluginContext | undefined;\n\n\tconstructor(options: TOptions) {\n\t\tthis.options = options;\n\t}\n\n\t/**\n\t * Initialize the plugin\n\t *\n\t * Must be implemented by subclasses\n\t */\n\tabstract init(context: PluginContext): Promise<void>;\n\n\t/**\n\t * Destroy the plugin and cleanup resources\n\t *\n\t * Must be implemented by subclasses\n\t */\n\tabstract destroy(): Promise<void>;\n\n\t/**\n\t * Get plugin schemas\n\t *\n\t * Default implementation returns empty array\n\t */\n\tasync getSchemas(): Promise<SchemaDefinition[]> {\n\t\treturn [];\n\t}\n\n\t/**\n\t * Extend existing schemas\n\t *\n\t * Default implementation returns empty array\n\t */\n\tasync extendSchemas(\n\t\t_context: SchemaExtensionContext,\n\t): Promise<SchemaExtension[]> {\n\t\treturn [];\n\t}\n\n\t/**\n\t * Hook called when schemas are loaded\n\t *\n\t * Default implementation does nothing\n\t */\n\tasync onSchemaLoad(_schemas: ISchemaRegistry): Promise<void> {\n\t\t// Default: no-op\n\t}\n\n\t/**\n\t * Hook called before query execution\n\t *\n\t * Default implementation returns query unchanged\n\t */\n\tasync onBeforeQuery<T extends DatrixEntry>(\n\t\tquery: QueryObject<T>,\n\t\t_context: QueryContext,\n\t): Promise<QueryObject<T>> {\n\t\treturn query;\n\t}\n\n\t/**\n\t * Hook called after query execution\n\t *\n\t * Default implementation returns result unchanged\n\t */\n\tasync onAfterQuery<TResult extends DatrixEntry>(\n\t\tresult: TResult,\n\t\t_context: QueryContext,\n\t): Promise<TResult> {\n\t\treturn result;\n\t}\n\n\t/**\n\t * Hook called when creating query context\n\t *\n\t * Default implementation returns context unchanged\n\t */\n\tasync onCreateQueryContext(context: QueryContext): Promise<QueryContext> {\n\t\treturn context;\n\t}\n\n\t/**\n\t * Validate plugin options\n\t *\n\t * Helper method for subclasses to implement options validation\n\t */\n\tprotected validateOptions(\n\t\tvalidator: (options: unknown) => options is TOptions,\n\t\terrorMessage: string,\n\t): TOptions {\n\t\tif (validator(this.options)) {\n\t\t\treturn this.options;\n\t\t}\n\n\t\tthrow new PluginError(errorMessage, {\n\t\t\tcode: \"INVALID_OPTIONS\",\n\t\t\tpluginName: this.name,\n\t\t\tdetails: this.options,\n\t\t});\n\t}\n\n\t/**\n\t * Check if plugin is initialized\n\t *\n\t * Helper method to ensure init() was called\n\t */\n\tprotected isInitialized(): this is this & {\n\t\tcontext: PluginContext;\n\t} {\n\t\treturn this.context !== undefined;\n\t}\n\n\t/**\n\t * Get context or return error\n\t *\n\t * Helper method to safely access context\n\t */\n\tprotected getContext(): PluginContext {\n\t\tif (this.context === undefined) {\n\t\t\tthrow new PluginError(`Plugin ${this.name} not initialized`, {\n\t\t\t\tcode: \"PLUGIN_NOT_INITIALIZED\",\n\t\t\t\tpluginName: this.name,\n\t\t\t});\n\t\t}\n\t\treturn this.context;\n\t}\n\n\t/**\n\t * Create a plugin error\n\t *\n\t * Helper method to create properly formatted errors\n\t */\n\tprotected createError(\n\t\tmessage: string,\n\t\tcode: string,\n\t\tdetails?: unknown,\n\t): PluginError {\n\t\treturn new PluginError(message, {\n\t\t\tcode,\n\t\t\tpluginName: this.name,\n\t\t\tdetails,\n\t\t});\n\t}\n}\n"],"mappings":"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","names":["COMPARISON_OPERATORS","STRING_OPERATORS","isLogicalOperator","throwMaxDepthExceeded","throwSchemaNotFound","throwMaxDepthExceeded","throwSchemaNotFound","RESERVED_FIELDS","COMPARISON_OPERATORS","STRING_OPERATORS","isLogicalOperator","error","executionTime","warnings"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/types/core/config.ts","../src/types/errors/datrix-error.ts","../src/types/errors/adapter/adapter-error.ts","../src/types/errors/adapter/adapter-helpers.ts","../src/types/errors/api/auth.ts","../src/types/errors/api/parser.ts","../src/types/errors/core/config.ts","../src/types/errors/core/crud.ts","../src/types/errors/core/query-builder.ts","../src/types/errors/core/validation.ts","../src/query-builder/error-helper.ts","../src/query-builder/where.ts","../src/query-builder/select.ts","../src/query-builder/populate.ts","../src/query-builder/data.ts","../src/query-builder/orderby.ts","../src/query-builder/builder.ts","../src/types/core/schema.ts","../src/validator/errors.ts","../src/validator/field-validator.ts","../src/validator/schema-validator.ts","../src/query-executor/error-helper.ts","../src/query-executor/validation.ts","../src/query-executor/relations.ts","../src/query-executor/executor.ts","../src/mixins/crud.ts","../src/plugin/schema-extension-context.ts","../src/types/utils/query.ts","../src/dispatcher/hook-errors.ts","../src/dispatcher/index.ts","../src/types/core/plugin.ts","../src/types/core/constants.ts","../src/schema/registry.ts","../src/migration/schema.ts","../src/types/core/migration.ts","../src/migration/differ.ts","../src/migration/generator.ts","../src/migration/history.ts","../src/migration/runner.ts","../src/migration/session.ts","../src/datrix.ts","../src/types/core/permission.ts","../src/types/adapter/index.ts","../src/types/api/parser.ts","../src/types/api/upload.ts","../src/types/api/config.ts","../src/types/cli/index.ts","../src/plugin/plugin.ts"],"sourcesContent":["/**\n * Core Module\n *\n * Exports all core functionality: Datrix singleton, schema, validation, query building, migrations, and configuration.\n */\n\n// Re-export Datrix singleton (main entry point)\nexport { Datrix, defineConfig } from \"./datrix\";\nexport type { DatrixInitOptions, ConfigFactory } from \"./datrix\";\n\n// Core constants\nexport { DATRIX_META_MODEL, DATRIX_META_KEY_PREFIX } from \"./types/core/constants\";\n\nexport * from \"./types/core\";\nexport * from \"./types/adapter\";\nexport * from \"./types/api\";\nexport * from \"./types/cli\";\nexport * from \"./types/errors\";\nexport * from \"./types/utils\";\nexport * from \"./plugin/plugin\";\nexport * from \"./migration\";\n","/**\n * Core Configuration Types\n *\n * Datrix framework configuration types used in datrix.config.ts files.\n */\n\nimport type { DatabaseAdapter } from \"../adapter\";\nimport type { DatrixPlugin } from \"./plugin\";\nimport type { SchemaDefinition } from \"./schema\";\n\n/**\n * Main Datrix Configuration\n *\n * Users export this from their datrix.config.ts file\n *\n * @example\n * ```ts\n * // datrix.config.ts\n * import { PostgresAdapter } from 'datrix/adapters';\n * import { AuthPlugin } from 'datrix/plugins';\n *\n * export default {\n * adapter: new PostgresAdapter({ connectionString: process.env.DATABASE_URL! }),\n * schemas: { path: './schemas/**\\/*.schema.ts' },\n * plugins: [new AuthPlugin({ ... })],\n * } as const;\n * ```\n */\nexport interface DatrixConfig<\n\tTAdapter extends DatabaseAdapter = DatabaseAdapter,\n> {\n\t/**\n\t * Database adapter instance\n\t * Must be an initialized adapter (PostgresAdapter, MySQLAdapter, etc.)\n\t */\n\treadonly adapter: TAdapter;\n\n\t/**\n\t * Schema definitions\n\t * Import your schemas and add them to this array\n\t *\n\t * @example\n\t * ```ts\n\t * import { userSchema } from './schemas/user.schema';\n\t * import { postSchema } from './schemas/post.schema';\n\t *\n\t * export default {\n\t * schemas: [userSchema, postSchema],\n\t * }\n\t * ```\n\t */\n\treadonly schemas: readonly SchemaDefinition[];\n\n\t/**\n\t * Plugin instances (optional)\n\t * Order matters - plugins are initialized in the order they appear\n\t */\n\treadonly plugins?: readonly DatrixPlugin[];\n\n\t/**\n\t * Migration configuration (optional)\n\t * Controls database migration behavior\n\t */\n\treadonly migration?: MigrationConfig;\n\n\t/**\n\t * Development mode options (optional)\n\t * Enables additional debugging and validation features\n\t */\n\treadonly dev?: DevConfig;\n}\n\n/**\n * Migration Configuration\n */\nexport interface MigrationConfig {\n\t/**\n\t * Automatically run migrations on startup\n\t * @default false (true in development)\n\t */\n\treadonly auto?: boolean;\n\n\t/**\n\t * Directory to store migration files\n\t * @default './migrations'\n\t */\n\treadonly directory?: string;\n\n\t/**\n\t * Table name for storing migration history\n\t * @default '_datrix_migrations'\n\t */\n\treadonly modelName?: string;\n}\n\n/**\n * Development Configuration\n */\nexport interface DevConfig {\n\t/**\n\t * Enable detailed query logging\n\t * @default false (true in development)\n\t */\n\treadonly logging?: boolean;\n\n\t/**\n\t * Validate all queries before execution\n\t * @default false (true in development)\n\t */\n\treadonly validateQueries?: boolean;\n\n\t/**\n\t * Pretty-print errors with stack traces\n\t * @default false (true in development)\n\t */\n\treadonly prettyErrors?: boolean;\n}\n\n/**\n * Config file export format\n *\n * Supports both ESM default export and direct export\n */\nexport type ConfigFileExport<T extends DatrixConfig = DatrixConfig> =\n\t| T\n\t| { default: T };\n\n/**\n * Config loading options\n */\nexport interface LoadConfigOptions {\n\t/**\n\t * Path to config file\n\t * @default './datrix.config.ts' (with fallback to .js)\n\t */\n\treadonly configPath?: string;\n\n\t/**\n\t * Environment name\n\t * Used to load environment-specific config files\n\t * @default process.env.NODE_ENV ?? 'development'\n\t */\n\treadonly environment?: \"development\" | \"production\" | \"test\";\n\n\t/**\n\t * Current working directory\n\t * @default process.cwd()\n\t */\n\treadonly cwd?: string;\n}\n\n/**\n * Type guard for DatrixConfig\n */\nexport function isDatrixConfig(value: unknown): value is DatrixConfig {\n\tif (typeof value !== \"object\" || value === null) {\n\t\treturn false;\n\t}\n\n\tconst obj = value as Record<string, unknown>;\n\n\treturn (\n\t\t\"adapter\" in obj &&\n\t\ttypeof obj[\"adapter\"] === \"object\" &&\n\t\t\"schemas\" in obj &&\n\t\ttypeof obj[\"schemas\"] === \"object\"\n\t);\n}\n\n/**\n * Type guard for ESM default export\n */\nexport function hasDefaultExport<T>(value: unknown): value is { default: T } {\n\treturn typeof value === \"object\" && value !== null && \"default\" in value;\n}\n\n/**\n * Default migration configuration values\n */\nexport const DEFAULT_MIGRATION_CONFIG: Required<MigrationConfig> = {\n\tauto: false,\n\tdirectory: \"./migrations\",\n\tmodelName: \"_datrix_migration\",\n} as const;\n\n/**\n * Default dev configuration values\n */\nexport const DEFAULT_DEV_CONFIG: Required<DevConfig> = {\n\tlogging: false,\n\tvalidateQueries: false,\n\tprettyErrors: false,\n} as const;\n","/**\n * Base Datrix Error Class\n *\n * All Datrix errors extend this class OR use it directly.\n * Provides standard error structure across the framework.\n *\n * ## Usage Guidelines\n *\n * ### Option 1: Direct Usage (Simple Errors)\n * ```typescript\n * throw new DatrixError('Connection failed', {\n * code: 'CONNECTION_FAILED',\n * operation: 'database:connect',\n * context: { host: 'localhost', port: 5432 }\n * });\n * ```\n *\n * ### Option 2: Extend for Specialized Errors (Complex Errors)\n * ```typescript\n * class ParserError extends DatrixError {\n * readonly parser: ParserType;\n * readonly location: ErrorLocation;\n * // ... additional fields\n * }\n * ```\n *\n * ## When to Extend?\n *\n * **Extend when you need:**\n * - Additional fields (e.g., `location`, `field`, `parser`)\n * - Custom serialization logic\n * - Domain-specific error codes\n * - Client-facing errors with user guidance\n *\n * **Use directly when:**\n * - Simple internal errors\n * - Errors without special context needs\n * - Adapter/plugin errors (unless you need special fields)\n *\n * ## Client-Facing vs Internal Errors\n *\n * **Client-Facing** (API, Parser, Validation):\n * - Include: `suggestion`, `expected`, `received`\n * - User-friendly messages\n * - Detailed context\n *\n * **Internal** (Database, Plugin, Core):\n * - Skip: `suggestion`, `expected`, `received` (undefined)\n * - Technical messages\n * - Minimal context (just enough for debugging)\n *\n * @example\n * // Internal error (database adapter)\n * throw new DatrixError('Query execution failed', {\n * code: 'QUERY_FAILED',\n * operation: 'executeQuery',\n * context: { query: queryObject },\n * cause: originalError\n * });\n *\n * @example\n * // Client-facing error (validation)\n * throw new DatrixError('Field is required', {\n * code: 'REQUIRED',\n * operation: 'validate:field',\n * context: { field: 'email' },\n * suggestion: 'Provide a value for the email field',\n * expected: 'non-empty string',\n * received: undefined\n * });\n */\nexport class DatrixError<\n\tTContext extends Record<string, unknown> = Record<string, unknown>,\n> extends Error {\n\t/** Error code for programmatic handling */\n\treadonly code: string;\n\n\t/** When this error occurred */\n\treadonly timestamp: Date;\n\n\t/** Operation that caused the error (e.g., 'parseQuery', 'validateField') */\n\treadonly operation?: string | undefined;\n\n\t/** Additional error context (error-specific details) */\n\treadonly context?: TContext | undefined;\n\n\t/** Underlying error (for error chaining) */\n\toverride readonly cause?: Error | undefined;\n\n\t// Client-facing fields (optional)\n\n\t/** User guidance - how to fix this error */\n\treadonly suggestion?: string | undefined;\n\n\t/** Expected value/format */\n\treadonly expected?: string | undefined;\n\n\t/** Actual received value */\n\treadonly received?: unknown;\n\n\t/** Documentation link (optional, can be added later) */\n\treadonly documentation?: string | undefined;\n\n\tconstructor(message: string, options: DatrixErrorOptions<TContext>) {\n\t\tsuper(message, { cause: options.cause });\n\n\t\tthis.name = this.constructor.name;\n\t\tthis.code = options.code;\n\t\tthis.timestamp = new Date();\n\t\tthis.operation = options.operation;\n\t\tthis.context = options.context;\n\t\tthis.cause = options.cause;\n\n\t\t// Client-facing fields\n\t\tthis.suggestion = options.suggestion;\n\t\tthis.expected = options.expected;\n\t\tthis.received = options.received;\n\t\tthis.documentation = options.documentation;\n\n\t\t// Maintain proper stack trace\n\t\tif (Error.captureStackTrace) {\n\t\t\tError.captureStackTrace(this, this.constructor);\n\t\t}\n\t}\n\n\t/**\n\t * Serialize error for JSON responses\n\t * Automatically excludes undefined fields\n\t */\n\ttoJSON(): SerializedDatrixError {\n\t\tconst json: SerializedDatrixError = {\n\t\t\ttype: this.name,\n\t\t\tmessage: this.message,\n\t\t\tcode: this.code,\n\t\t\ttimestamp: this.timestamp.toISOString(),\n\t\t};\n\n\t\t// Add optional fields only if defined\n\t\tif (this.operation) json.operation = this.operation;\n\t\tif (this.context) json.context = this.context;\n\t\tif (this.suggestion) json.suggestion = this.suggestion;\n\t\tif (this.expected) json.expected = this.expected;\n\t\tif (this.received !== undefined) json.received = this.received;\n\t\tif (this.documentation) json.documentation = this.documentation;\n\n\t\tif (this.cause) {\n\t\t\tjson.cause = {\n\t\t\t\tmessage: this.cause.message,\n\t\t\t\tname: this.cause.name,\n\t\t\t};\n\t\t}\n\n\t\treturn json;\n\t}\n\n\t/**\n\t * Get detailed error message (for logging)\n\t */\n\ttoDetailedMessage(): string {\n\t\tconst parts = [\n\t\t\t`[${this.name}] ${this.message}`,\n\t\t\t` Code: ${this.code}`,\n\t\t\t` Timestamp: ${this.timestamp.toISOString()}`,\n\t\t];\n\n\t\tif (this.operation) {\n\t\t\tparts.push(` Operation: ${this.operation}`);\n\t\t}\n\n\t\tif (this.received !== undefined) {\n\t\t\tparts.push(` Received: ${JSON.stringify(this.received)}`);\n\t\t}\n\n\t\tif (this.expected) {\n\t\t\tparts.push(` Expected: ${this.expected}`);\n\t\t}\n\n\t\tif (this.suggestion) {\n\t\t\tparts.push(` Suggestion: ${this.suggestion}`);\n\t\t}\n\n\t\tif (this.documentation) {\n\t\t\tparts.push(` Documentation: ${this.documentation}`);\n\t\t}\n\n\t\tif (this.cause) {\n\t\t\tparts.push(` Caused by: ${this.cause.message}`);\n\t\t}\n\n\t\treturn parts.join(\"\\n\");\n\t}\n\n\t/**\n\t * Type guard - check if error is a DatrixError\n\t */\n\tstatic isDatrixError(error: unknown): error is DatrixError {\n\t\treturn error instanceof DatrixError;\n\t}\n}\n\n/**\n * Options for creating DatrixError\n */\nexport interface DatrixErrorOptions<\n\tTContext extends Record<string, unknown> = Record<string, unknown>,\n> {\n\t/**\n\t * Error code (machine-readable)\n\t * Each error type can define its own code constants\n\t */\n\treadonly code: string;\n\n\t/**\n\t * Operation that caused the error\n\t * Examples: 'parseQuery', 'validateField', 'executeQuery'\n\t */\n\treadonly operation?: string | undefined;\n\n\t/**\n\t * Additional error context\n\t * Include relevant details for debugging\n\t */\n\treadonly context?: TContext | undefined;\n\n\t/**\n\t * Underlying error (for error chaining)\n\t * Use when wrapping lower-level errors\n\t */\n\treadonly cause?: Error | undefined;\n\n\t// Client-facing fields (optional)\n\n\t/**\n\t * User guidance - how to fix this error\n\t * Only for client-facing errors\n\t */\n\treadonly suggestion?: string | undefined;\n\n\t/**\n\t * Expected value/format\n\t * Only for client-facing errors\n\t */\n\treadonly expected?: string | undefined;\n\n\t/**\n\t * Actual received value\n\t * Only for client-facing errors\n\t */\n\treadonly received?: unknown | undefined;\n\n\t/**\n\t * Documentation link\n\t * Can be added later\n\t */\n\treadonly documentation?: string | undefined;\n}\n\n/**\n * Serialized error for JSON responses\n * Only includes defined fields\n */\nexport interface SerializedDatrixError {\n\treadonly type: string;\n\treadonly message: string;\n\treadonly code: string;\n\treadonly timestamp: string;\n\toperation?: string;\n\tcontext?: Record<string, unknown>;\n\tsuggestion?: string;\n\texpected?: string;\n\treceived?: unknown;\n\tdocumentation?: string;\n\tcause?: {\n\t\treadonly message: string;\n\t\treadonly name: string;\n\t};\n}\n","/**\n * Datrix Adapter Error\n *\n * Single unified error class for all database adapters.\n * Replaces DatrixPostgresAdapterError, DatrixMySQLAdapterError, DatrixJsonAdapterError.\n */\n\nimport { DatrixError, type SerializedDatrixError } from \"../datrix-error\";\n\n// ============================================================================\n// Adapter Name\n// ============================================================================\n\nexport type AdapterName = \"postgres\" | \"mysql\" | \"mongodb\" | \"json\";\n\n// ============================================================================\n// Adapter Operation\n// ============================================================================\n\nexport type AdapterOperation =\n\t// Common\n\t| \"connect\"\n\t| \"disconnect\"\n\t| \"query\"\n\t| \"transaction\"\n\t| \"populate\"\n\t| \"join\"\n\t| \"aggregation\"\n\t| \"migration\"\n\t| \"introspection\"\n\t// JSON-specific\n\t| \"lock\"\n\t| \"read\"\n\t| \"write\"\n\t| \"validate\";\n\n// ============================================================================\n// Adapter Error Codes\n// ============================================================================\n\nexport type AdapterErrorCode =\n\t// --- Common ---\n\t| \"ADAPTER_CONNECTION_ERROR\"\n\t| \"ADAPTER_QUERY_ERROR\"\n\t| \"ADAPTER_TRANSACTION_ERROR\"\n\t| \"ADAPTER_MIGRATION_ERROR\"\n\t| \"ADAPTER_INTROSPECTION_ERROR\"\n\t| \"ADAPTER_AGGREGATION_ERROR\"\n\t| \"ADAPTER_POPULATE_ERROR\"\n\t| \"ADAPTER_JOIN_ERROR\"\n\t| \"ADAPTER_LATERAL_JOIN_ERROR\"\n\t| \"ADAPTER_JSON_AGGREGATION_ERROR\"\n\t| \"ADAPTER_RESULT_PROCESSING_ERROR\"\n\t| \"ADAPTER_INVALID_POPULATE_OPTIONS\"\n\t| \"ADAPTER_MODEL_NOT_FOUND\"\n\t| \"ADAPTER_SCHEMA_NOT_FOUND\"\n\t| \"ADAPTER_RELATION_NOT_FOUND\"\n\t| \"ADAPTER_INVALID_RELATION\"\n\t| \"ADAPTER_TARGET_MODEL_NOT_FOUND\"\n\t| \"ADAPTER_JUNCTION_TABLE_NOT_FOUND\"\n\t| \"ADAPTER_MAX_DEPTH_EXCEEDED\"\n\t// --- JSON-specific ---\n\t| \"ADAPTER_LOCK_TIMEOUT\"\n\t| \"ADAPTER_LOCK_ERROR\"\n\t| \"ADAPTER_FILE_READ_ERROR\"\n\t| \"ADAPTER_FILE_WRITE_ERROR\"\n\t| \"ADAPTER_FILE_NOT_FOUND\"\n\t| \"ADAPTER_INVALID_DATA\"\n\t| \"ADAPTER_QUERY_MISSING_DATA\"\n\t| \"ADAPTER_INVALID_WHERE_FIELD\"\n\t| \"ADAPTER_INVALID_RELATION_WHERE\"\n\t| \"ADAPTER_UNIQUE_CONSTRAINT\"\n\t| \"ADAPTER_FOREIGN_KEY_CONSTRAINT\"\n\t// --- Meta field operations ---\n\t| \"ADAPTER_META_FIELD_EXISTS\"\n\t| \"ADAPTER_META_FIELD_NOT_FOUND\";\n\n// ============================================================================\n// Error Context\n// ============================================================================\n\nexport interface AdapterErrorContext {\n\treadonly table?: string;\n\treadonly model?: string;\n\treadonly field?: string;\n\treadonly relationName?: string;\n\treadonly targetModel?: string;\n\treadonly junctionTable?: string;\n\treadonly query?: Record<string, unknown>;\n\treadonly sql?: string;\n\treadonly params?: readonly unknown[];\n\treadonly depth?: number;\n\treadonly maxDepth?: number;\n\treadonly relationPath?: string;\n\treadonly file?: string;\n\treadonly lockTimeout?: number;\n\treadonly [key: string]: unknown;\n}\n\n// ============================================================================\n// Error Options\n// ============================================================================\n\nexport interface DatrixAdapterErrorOptions {\n\treadonly adapter: AdapterName;\n\treadonly code: AdapterErrorCode;\n\treadonly operation?: AdapterOperation | undefined;\n\treadonly context?: AdapterErrorContext | undefined;\n\treadonly cause?: Error | undefined;\n\treadonly suggestion?: string | undefined;\n\treadonly expected?: string | undefined;\n\treadonly received?: unknown | undefined;\n}\n\n// ============================================================================\n// Serialized Error\n// ============================================================================\n\nexport interface SerializedDatrixAdapterError extends SerializedDatrixError {\n\treadonly adapter: AdapterName;\n\treadonly adapterOperation?: AdapterOperation;\n}\n\n// ============================================================================\n// Error Class\n// ============================================================================\n\n/**\n * Datrix Adapter Error Class\n *\n * Unified error class for all database adapters (postgres, mysql, json).\n * Use helper functions from adapter-helpers.ts instead of instantiating directly.\n *\n * @example\n * ```ts\n * throw new DatrixAdapterError('Model not found', {\n * adapter: 'postgres',\n * code: 'ADAPTER_MODEL_NOT_FOUND',\n * operation: 'populate',\n * context: { table: 'users' },\n * suggestion: 'Ensure model is registered in schema registry',\n * });\n * ```\n */\nexport class DatrixAdapterError extends DatrixError<AdapterErrorContext> {\n\treadonly adapter: AdapterName;\n\treadonly adapterOperation?: AdapterOperation | undefined;\n\n\tconstructor(message: string, options: DatrixAdapterErrorOptions) {\n\t\tconst operationString = options.operation\n\t\t\t? `adapter:${options.adapter}:${options.operation}`\n\t\t\t: `adapter:${options.adapter}`;\n\n\t\tsuper(message, {\n\t\t\tcode: options.code,\n\t\t\toperation: operationString,\n\t\t\tcontext: options.context,\n\t\t\tcause: options.cause,\n\t\t\tsuggestion: options.suggestion,\n\t\t\texpected: options.expected,\n\t\t\treceived: options.received,\n\t\t});\n\n\t\tthis.adapter = options.adapter;\n\t\tthis.adapterOperation = options.operation;\n\t}\n\n\toverride toJSON(): SerializedDatrixAdapterError {\n\t\tconst json = super.toJSON();\n\n\t\tif (this.adapterOperation) {\n\t\t\treturn {\n\t\t\t\t...json,\n\t\t\t\tadapter: this.adapter,\n\t\t\t\tadapterOperation: this.adapterOperation,\n\t\t\t};\n\t\t}\n\n\t\treturn { ...json, adapter: this.adapter };\n\t}\n\n\toverride toDetailedMessage(): string {\n\t\tconst baseMessage = super.toDetailedMessage();\n\t\tconst parts = baseMessage.split(\"\\n\");\n\n\t\tconst extraLines: string[] = [` Adapter: ${this.adapter}`];\n\n\t\tif (this.adapterOperation) {\n\t\t\textraLines.push(` Adapter Operation: ${this.adapterOperation}`);\n\t\t}\n\n\t\tparts.splice(3, 0, ...extraLines);\n\t\treturn parts.join(\"\\n\");\n\t}\n}\n","/**\n * Datrix Adapter Error Helpers\n *\n * Shared throw helpers for all database adapters.\n * Every helper accepts an object with at minimum { adapter }.\n */\n\nimport type { QueryObject } from \"../../core/query-builder\";\nimport type { DatrixEntry } from \"../../core/schema\";\nimport { DatrixAdapterError, type AdapterName } from \"./adapter-error\";\n\n// ============================================================================\n// SQL Truncation Utility\n// ============================================================================\n\nexport function truncateSqlForError(sql: string): string {\n\tif (process.env[\"NODE_ENV\"] === \"development\") {\n\t\treturn sql;\n\t}\n\treturn sql.length > 500 ? sql.substring(0, 500) + \"...\" : sql;\n}\n\n// ============================================================================\n// Connection Errors\n// ============================================================================\n\nexport function throwNotConnected(params: { adapter: AdapterName }): never {\n\tthrow new DatrixAdapterError(\"Not connected to database\", {\n\t\tadapter: params.adapter,\n\t\tcode: \"ADAPTER_CONNECTION_ERROR\",\n\t\toperation: \"connect\",\n\t\tsuggestion: \"Call adapter.connect() before executing queries\",\n\t});\n}\n\nexport function throwConnectionError(params: {\n\tadapter: AdapterName;\n\tmessage: string;\n\toperation?: \"connect\" | \"disconnect\";\n\tcause?: Error | undefined;\n}): never {\n\tthrow new DatrixAdapterError(params.message, {\n\t\tadapter: params.adapter,\n\t\tcode: \"ADAPTER_CONNECTION_ERROR\",\n\t\toperation: params.operation ?? \"connect\",\n\t\tcause: params.cause,\n\t});\n}\n\n// ============================================================================\n// Migration Errors\n// ============================================================================\n\nexport function throwMigrationError(params: {\n\tadapter: AdapterName;\n\tmessage: string;\n\ttable?: string | undefined;\n\tcause?: Error | undefined;\n\tsuggestion?: string | undefined;\n}): never {\n\tthrow new DatrixAdapterError(params.message, {\n\t\tadapter: params.adapter,\n\t\tcode: \"ADAPTER_MIGRATION_ERROR\",\n\t\toperation: \"migration\",\n\t\tcontext: params.table ? { table: params.table } : undefined,\n\t\tcause: params.cause,\n\t\tsuggestion: params.suggestion,\n\t});\n}\n\n// ============================================================================\n// Introspection Errors\n// ============================================================================\n\nexport function throwIntrospectionError(params: {\n\tadapter: AdapterName;\n\tmessage: string;\n\ttable?: string | undefined;\n\tcause?: Error | undefined;\n}): never {\n\tthrow new DatrixAdapterError(params.message, {\n\t\tadapter: params.adapter,\n\t\tcode: \"ADAPTER_INTROSPECTION_ERROR\",\n\t\toperation: \"introspection\",\n\t\tcontext: params.table ? { table: params.table } : undefined,\n\t\tcause: params.cause,\n\t});\n}\n\n// ============================================================================\n// Query Errors\n// ============================================================================\n\nexport function throwQueryError(params: {\n\tadapter: AdapterName;\n\tmessage: string;\n\tquery?: QueryObject | undefined;\n\tsql?: string | undefined;\n\tcause?: Error | undefined;\n\tsuggestion?: string | undefined;\n\texpected?: string | undefined;\n\treceived?: unknown;\n}): never {\n\tthrow new DatrixAdapterError(params.message, {\n\t\tadapter: params.adapter,\n\t\tcode: \"ADAPTER_QUERY_ERROR\",\n\t\toperation: \"query\",\n\t\tcontext: {\n\t\t\t...(params.query && {\n\t\t\t\tquery: { type: params.query.type, table: params.query.table },\n\t\t\t}),\n\t\t\t...(params.sql && { sql: truncateSqlForError(params.sql) }),\n\t\t},\n\t\tcause: params.cause,\n\t\tsuggestion: params.suggestion,\n\t\texpected: params.expected,\n\t\treceived: params.received,\n\t});\n}\n\nexport function throwQueryMissingData(params: {\n\tadapter: AdapterName;\n\tqueryType: string;\n\ttable: string;\n}): never {\n\tthrow new DatrixAdapterError(\n\t\t`${params.queryType} query missing data for table: ${params.table}`,\n\t\t{\n\t\t\tadapter: params.adapter,\n\t\t\tcode: \"ADAPTER_QUERY_MISSING_DATA\",\n\t\t\toperation: \"query\",\n\t\t\tcontext: { table: params.table, queryType: params.queryType },\n\t\t\tsuggestion: `Provide data field in ${params.queryType} query`,\n\t\t\texpected: \"query.data object\",\n\t\t},\n\t);\n}\n\n// ============================================================================\n// Transaction Errors\n// ============================================================================\n\nexport function throwTransactionError(params: {\n\tadapter: AdapterName;\n\tmessage: string;\n\tcause?: Error | undefined;\n}): never {\n\tthrow new DatrixAdapterError(params.message, {\n\t\tadapter: params.adapter,\n\t\tcode: \"ADAPTER_TRANSACTION_ERROR\",\n\t\toperation: \"transaction\",\n\t\tcause: params.cause,\n\t});\n}\n\nexport function throwTransactionAlreadyCommitted(params: {\n\tadapter: AdapterName;\n}): never {\n\tthrow new DatrixAdapterError(\"Transaction already committed\", {\n\t\tadapter: params.adapter,\n\t\tcode: \"ADAPTER_TRANSACTION_ERROR\",\n\t\toperation: \"transaction\",\n\t\tsuggestion: \"Start a new transaction instead of reusing a committed one\",\n\t});\n}\n\nexport function throwTransactionAlreadyRolledBack(params: {\n\tadapter: AdapterName;\n}): never {\n\tthrow new DatrixAdapterError(\"Transaction already rolled back\", {\n\t\tadapter: params.adapter,\n\t\tcode: \"ADAPTER_TRANSACTION_ERROR\",\n\t\toperation: \"transaction\",\n\t\tsuggestion: \"Start a new transaction instead of reusing a rolled back one\",\n\t});\n}\n\nexport function throwTransactionSavepointNotSupported(params: {\n\tadapter: AdapterName;\n}): never {\n\tthrow new DatrixAdapterError(\n\t\t`Savepoints are not supported by the ${params.adapter} adapter`,\n\t\t{\n\t\t\tadapter: params.adapter,\n\t\t\tcode: \"ADAPTER_TRANSACTION_ERROR\",\n\t\t\toperation: \"transaction\",\n\t\t\tsuggestion: \"Use nested transactions or restructure your logic\",\n\t\t},\n\t);\n}\n\nexport function throwRawQueryNotSupported(params: {\n\tadapter: AdapterName;\n}): never {\n\tthrow new DatrixAdapterError(\n\t\t`Raw SQL queries are not supported by the ${params.adapter} adapter`,\n\t\t{\n\t\t\tadapter: params.adapter,\n\t\t\tcode: \"ADAPTER_QUERY_ERROR\",\n\t\t\toperation: \"query\",\n\t\t\tsuggestion: \"Use the query builder API instead of raw SQL\",\n\t\t},\n\t);\n}\n\n// ============================================================================\n// Populate / Relation Errors\n// ============================================================================\n\nexport function throwModelNotFound(params: {\n\tadapter: AdapterName;\n\ttable: string;\n}): never {\n\tthrow new DatrixAdapterError(`Model not found for table: ${params.table}`, {\n\t\tadapter: params.adapter,\n\t\tcode: \"ADAPTER_MODEL_NOT_FOUND\",\n\t\toperation: \"populate\",\n\t\tcontext: { table: params.table },\n\t\tsuggestion: \"Ensure model is registered in schema registry\",\n\t\texpected: \"registered model\",\n\t});\n}\n\nexport function throwSchemaNotFound(params: {\n\tadapter: AdapterName;\n\tmodelName: string;\n}): never {\n\tthrow new DatrixAdapterError(\n\t\t`Schema not found for model: ${params.modelName}`,\n\t\t{\n\t\t\tadapter: params.adapter,\n\t\t\tcode: \"ADAPTER_SCHEMA_NOT_FOUND\",\n\t\t\toperation: \"populate\",\n\t\t\tcontext: { model: params.modelName },\n\t\t\tsuggestion: \"Ensure schema is registered in schema registry\",\n\t\t\texpected: \"registered schema\",\n\t\t},\n\t);\n}\n\nexport function throwRelationNotFound(params: {\n\tadapter: AdapterName;\n\trelationName: string;\n\tschemaName: string;\n}): never {\n\tthrow new DatrixAdapterError(\n\t\t`Relation field '${params.relationName}' not found in schema '${params.schemaName}'`,\n\t\t{\n\t\t\tadapter: params.adapter,\n\t\t\tcode: \"ADAPTER_RELATION_NOT_FOUND\",\n\t\t\toperation: \"populate\",\n\t\t\tcontext: { relationName: params.relationName, model: params.schemaName },\n\t\t\tsuggestion: `Add '${params.relationName}' relation to schema '${params.schemaName}' or check field name`,\n\t\t\texpected: `relation field '${params.relationName}'`,\n\t\t},\n\t);\n}\n\nexport function throwInvalidRelationType(params: {\n\tadapter: AdapterName;\n\trelationName: string;\n\tfieldType: string;\n\tschemaName: string;\n}): never {\n\tthrow new DatrixAdapterError(\n\t\t`Field '${params.relationName}' (type: ${params.fieldType}) is not a relation field in schema '${params.schemaName}'`,\n\t\t{\n\t\t\tadapter: params.adapter,\n\t\t\tcode: \"ADAPTER_INVALID_RELATION\",\n\t\t\toperation: \"populate\",\n\t\t\tcontext: {\n\t\t\t\trelationName: params.relationName,\n\t\t\t\tfield: params.fieldType,\n\t\t\t\tmodel: params.schemaName,\n\t\t\t},\n\t\t\tsuggestion: `Change field type to 'relation' for '${params.relationName}'`,\n\t\t\texpected: \"type: 'relation'\",\n\t\t\treceived: params.fieldType,\n\t\t},\n\t);\n}\n\nexport function throwTargetModelNotFound(params: {\n\tadapter: AdapterName;\n\ttargetModel: string;\n\trelationName: string;\n\tschemaName: string;\n}): never {\n\tthrow new DatrixAdapterError(\n\t\t`Target model '${params.targetModel}' not found for relation '${params.relationName}' in schema '${params.schemaName}'`,\n\t\t{\n\t\t\tadapter: params.adapter,\n\t\t\tcode: \"ADAPTER_TARGET_MODEL_NOT_FOUND\",\n\t\t\toperation: \"populate\",\n\t\t\tcontext: {\n\t\t\t\ttargetModel: params.targetModel,\n\t\t\t\trelationName: params.relationName,\n\t\t\t\tmodel: params.schemaName,\n\t\t\t},\n\t\t\tsuggestion: `Ensure model '${params.targetModel}' is registered in schema registry`,\n\t\t\texpected: `registered model '${params.targetModel}'`,\n\t\t},\n\t);\n}\n\nexport function throwJunctionTableNotFound(params: {\n\tadapter: AdapterName;\n\tjunctionTable: string;\n\trelationName: string;\n\tschemaName: string;\n}): never {\n\tthrow new DatrixAdapterError(\n\t\t`Junction table '${params.junctionTable}' not found for manyToMany relation '${params.relationName}' in schema '${params.schemaName}'`,\n\t\t{\n\t\t\tadapter: params.adapter,\n\t\t\tcode: \"ADAPTER_JUNCTION_TABLE_NOT_FOUND\",\n\t\t\toperation: \"populate\",\n\t\t\tcontext: {\n\t\t\t\tjunctionTable: params.junctionTable,\n\t\t\t\trelationName: params.relationName,\n\t\t\t\tmodel: params.schemaName,\n\t\t\t},\n\t\t\tsuggestion: `Create junction table '${params.junctionTable}' or check 'through' property in relation definition`,\n\t\t\texpected: `table '${params.junctionTable}' to exist`,\n\t\t},\n\t);\n}\n\nexport function throwMaxDepthExceeded(params: {\n\tadapter: AdapterName;\n\tcurrentDepth: number;\n\tmaxDepth: number;\n\trelationPath: string;\n}): never {\n\tthrow new DatrixAdapterError(\n\t\t`Populate depth exceeds maximum of ${params.maxDepth} at path: ${params.relationPath}`,\n\t\t{\n\t\t\tadapter: params.adapter,\n\t\t\tcode: \"ADAPTER_MAX_DEPTH_EXCEEDED\",\n\t\t\toperation: \"populate\",\n\t\t\tcontext: {\n\t\t\t\tdepth: params.currentDepth,\n\t\t\t\tmaxDepth: params.maxDepth,\n\t\t\t\trelationPath: params.relationPath,\n\t\t\t},\n\t\t\tsuggestion: `Reduce nesting level or increase MAX_POPULATE_DEPTH (current: ${params.maxDepth})`,\n\t\t\texpected: `depth <= ${params.maxDepth}`,\n\t\t\treceived: `depth: ${params.currentDepth}`,\n\t\t},\n\t);\n}\n\nexport function throwPopulateQueryError<T extends DatrixEntry>(params: {\n\tadapter: AdapterName;\n\tquery: QueryObject<T>;\n\tsql: string;\n\tcause: Error;\n\tstrategy?: string | undefined;\n\tqueryParams?: readonly unknown[] | undefined;\n}): never {\n\tconst strategyLabel = params.strategy\n\t\t? ` using ${params.strategy} strategy`\n\t\t: \"\";\n\tthrow new DatrixAdapterError(\n\t\t`Populate query execution failed for table '${params.query.table}'${strategyLabel}`,\n\t\t{\n\t\t\tadapter: params.adapter,\n\t\t\tcode: \"ADAPTER_POPULATE_ERROR\",\n\t\t\toperation: \"populate\",\n\t\t\tcontext: {\n\t\t\t\ttable: params.query.table,\n\t\t\t\tquery: { type: params.query.type },\n\t\t\t\tsql: truncateSqlForError(params.sql),\n\t\t\t\tparams: params.queryParams ?? [],\n\t\t\t\tstrategy: params.strategy,\n\t\t\t},\n\t\t\tcause: params.cause,\n\t\t\tsuggestion:\n\t\t\t\t\"Check SQL syntax, relation definitions, and database connection\",\n\t\t\texpected: \"successful query execution\",\n\t\t},\n\t);\n}\n\nexport function throwInvalidPopulateOptions(params: {\n\tadapter: AdapterName;\n\trelationName: string;\n\toptionName: string;\n\toptionValue: unknown;\n}): never {\n\tthrow new DatrixAdapterError(\n\t\t`Invalid populate option '${params.optionName}' for relation '${params.relationName}'`,\n\t\t{\n\t\t\tadapter: params.adapter,\n\t\t\tcode: \"ADAPTER_INVALID_POPULATE_OPTIONS\",\n\t\t\toperation: \"populate\",\n\t\t\tcontext: {\n\t\t\t\trelationName: params.relationName,\n\t\t\t\toptionName: params.optionName,\n\t\t\t\toptionValue: params.optionValue,\n\t\t\t},\n\t\t\tsuggestion:\n\t\t\t\t\"Check populate options syntax. Valid options: select, where, orderBy, limit, offset, populate\",\n\t\t\texpected: \"valid populate option\",\n\t\t\treceived: `${params.optionName}: ${JSON.stringify(params.optionValue)}`,\n\t\t},\n\t);\n}\n\n// ============================================================================\n// JOIN Errors\n// ============================================================================\n\nexport function throwJoinBuildError(params: {\n\tadapter: AdapterName;\n\trelationName: string;\n\trelationKind: string;\n\tcause?: Error | undefined;\n}): never {\n\tthrow new DatrixAdapterError(\n\t\t`Failed to generate JOIN for relation '${params.relationName}' (kind: ${params.relationKind})`,\n\t\t{\n\t\t\tadapter: params.adapter,\n\t\t\tcode: \"ADAPTER_JOIN_ERROR\",\n\t\t\toperation: \"join\",\n\t\t\tcontext: {\n\t\t\t\trelationName: params.relationName,\n\t\t\t\trelationKind: params.relationKind,\n\t\t\t},\n\t\t\tcause: params.cause,\n\t\t\tsuggestion: \"Check relation configuration and foreign key definitions\",\n\t\t\texpected: `valid ${params.relationKind} relation`,\n\t\t},\n\t);\n}\n\nexport function throwLateralJoinError(params: {\n\tadapter: AdapterName;\n\trelationName: string;\n\tcause?: Error | undefined;\n}): never {\n\tthrow new DatrixAdapterError(\n\t\t`Failed to generate LATERAL JOIN for relation '${params.relationName}'`,\n\t\t{\n\t\t\tadapter: params.adapter,\n\t\t\tcode: \"ADAPTER_LATERAL_JOIN_ERROR\",\n\t\t\toperation: \"join\",\n\t\t\tcontext: { relationName: params.relationName },\n\t\t\tcause: params.cause,\n\t\t\tsuggestion:\n\t\t\t\t\"Check populate options syntax and database version compatibility\",\n\t\t\texpected: \"valid LATERAL JOIN syntax\",\n\t\t},\n\t);\n}\n\n// ============================================================================\n// Aggregation Errors\n// ============================================================================\n\nexport function throwJsonAggregationError(params: {\n\tadapter: AdapterName;\n\trelationName: string;\n\tcause?: Error | undefined;\n}): never {\n\tthrow new DatrixAdapterError(\n\t\t`Failed to generate JSON aggregation for relation '${params.relationName}'`,\n\t\t{\n\t\t\tadapter: params.adapter,\n\t\t\tcode: \"ADAPTER_JSON_AGGREGATION_ERROR\",\n\t\t\toperation: \"aggregation\",\n\t\t\tcontext: { relationName: params.relationName },\n\t\t\tcause: params.cause,\n\t\t\tsuggestion: \"Check field selection and aggregation syntax\",\n\t\t\texpected: \"valid JSON aggregation syntax\",\n\t\t},\n\t);\n}\n\nexport function throwResultProcessingError(params: {\n\tadapter: AdapterName;\n\toperation: string;\n\tcause?: Error | undefined;\n}): never {\n\tthrow new DatrixAdapterError(\n\t\t`Failed to process query results: ${params.operation}`,\n\t\t{\n\t\t\tadapter: params.adapter,\n\t\t\tcode: \"ADAPTER_RESULT_PROCESSING_ERROR\",\n\t\t\toperation: \"populate\",\n\t\t\tcontext: { processingOperation: params.operation },\n\t\t\tcause: params.cause,\n\t\t\tsuggestion: \"Check result structure and populate configuration\",\n\t\t\texpected: \"valid result structure\",\n\t\t},\n\t);\n}\n\n// ============================================================================\n// Meta Field Errors (used by applyOperationsToMetaSchema in all adapters)\n// ============================================================================\n\nexport function throwMetaFieldAlreadyExists(params: {\n\tadapter: AdapterName;\n\tfield: string;\n\ttable: string;\n}): never {\n\tthrow new DatrixAdapterError(\n\t\t`Meta field '${params.field}' already exists in schema for table '${params.table}'`,\n\t\t{\n\t\t\tadapter: params.adapter,\n\t\t\tcode: \"ADAPTER_META_FIELD_EXISTS\",\n\t\t\toperation: \"migration\",\n\t\t\tcontext: { field: params.field, table: params.table },\n\t\t\tsuggestion: `Use 'modifyMetaField' to update existing field '${params.field}'`,\n\t\t},\n\t);\n}\n\nexport function throwMetaFieldNotFound(params: {\n\tadapter: AdapterName;\n\tfield: string;\n\ttable: string;\n}): never {\n\tthrow new DatrixAdapterError(\n\t\t`Meta field '${params.field}' not found in schema for table '${params.table}'`,\n\t\t{\n\t\t\tadapter: params.adapter,\n\t\t\tcode: \"ADAPTER_META_FIELD_NOT_FOUND\",\n\t\t\toperation: \"migration\",\n\t\t\tcontext: { field: params.field, table: params.table },\n\t\t\tsuggestion: `Use 'addMetaField' to add field '${params.field}' first`,\n\t\t},\n\t);\n}\n\n// ============================================================================\n// JSON Adapter — Lock Errors\n// ============================================================================\n\nexport function throwLockTimeout(params: {\n\tadapter: AdapterName;\n\tlockTimeout: number;\n}): never {\n\tthrow new DatrixAdapterError(\n\t\t`Could not acquire lock within ${params.lockTimeout}ms`,\n\t\t{\n\t\t\tadapter: params.adapter,\n\t\t\tcode: \"ADAPTER_LOCK_TIMEOUT\",\n\t\t\toperation: \"lock\",\n\t\t\tcontext: { lockTimeout: params.lockTimeout },\n\t\t\tsuggestion:\n\t\t\t\t\"Increase lockTimeout in adapter config or check for deadlocks\",\n\t\t\texpected: \"lock acquired within timeout\",\n\t\t},\n\t);\n}\n\nexport function throwLockError(params: {\n\tadapter: AdapterName;\n\tcause?: Error | undefined;\n}): never {\n\tthrow new DatrixAdapterError(\"Failed to acquire lock\", {\n\t\tadapter: params.adapter,\n\t\tcode: \"ADAPTER_LOCK_ERROR\",\n\t\toperation: \"lock\",\n\t\tcause: params.cause,\n\t\tsuggestion: \"Check file system permissions and lock file path\",\n\t});\n}\n\n// ============================================================================\n// JSON Adapter — File I/O Errors\n// ============================================================================\n\nexport function throwFileReadError(params: {\n\tadapter: AdapterName;\n\tfile: string;\n\tcause?: Error | undefined;\n}): never {\n\tthrow new DatrixAdapterError(`Failed to read file: ${params.file}`, {\n\t\tadapter: params.adapter,\n\t\tcode: \"ADAPTER_FILE_READ_ERROR\",\n\t\toperation: \"read\",\n\t\tcontext: { file: params.file },\n\t\tcause: params.cause,\n\t\tsuggestion: \"Check file exists and has correct permissions\",\n\t});\n}\n\nexport function throwFileWriteError(params: {\n\tadapter: AdapterName;\n\tfile: string;\n\tcause?: Error | undefined;\n}): never {\n\tthrow new DatrixAdapterError(`Failed to write file: ${params.file}`, {\n\t\tadapter: params.adapter,\n\t\tcode: \"ADAPTER_FILE_WRITE_ERROR\",\n\t\toperation: \"write\",\n\t\tcontext: { file: params.file },\n\t\tcause: params.cause,\n\t\tsuggestion: \"Check directory exists and has write permissions\",\n\t});\n}\n\nexport function throwFileNotFound(params: {\n\tadapter: AdapterName;\n\tfile: string;\n}): never {\n\tthrow new DatrixAdapterError(`File not found: ${params.file}`, {\n\t\tadapter: params.adapter,\n\t\tcode: \"ADAPTER_FILE_NOT_FOUND\",\n\t\toperation: \"read\",\n\t\tcontext: { file: params.file },\n\t\tsuggestion: \"Ensure the file exists or run migrations to create it\",\n\t});\n}\n\n// ============================================================================\n// JSON Adapter — Constraint Errors\n// ============================================================================\n\nexport function throwUniqueConstraintField(params: {\n\tadapter: AdapterName;\n\tfield: string;\n\tvalue: unknown;\n\ttable: string;\n}): never {\n\tthrow new DatrixAdapterError(\n\t\t`Duplicate value '${params.value}' for unique field '${params.field}'`,\n\t\t{\n\t\t\tadapter: params.adapter,\n\t\t\tcode: \"ADAPTER_UNIQUE_CONSTRAINT\",\n\t\t\toperation: \"query\",\n\t\t\tcontext: {\n\t\t\t\tfield: params.field,\n\t\t\t\tvalue: params.value,\n\t\t\t\ttable: params.table,\n\t\t\t},\n\t\t\tsuggestion: `Ensure '${params.field}' value is unique in table '${params.table}'`,\n\t\t\texpected: \"unique value\",\n\t\t\treceived: params.value,\n\t\t},\n\t);\n}\n\nexport function throwUniqueConstraintIndex(params: {\n\tadapter: AdapterName;\n\tfields: readonly string[];\n\ttable: string;\n}): never {\n\tthrow new DatrixAdapterError(\n\t\t`Duplicate value for unique index [${params.fields.join(\", \")}]`,\n\t\t{\n\t\t\tadapter: params.adapter,\n\t\t\tcode: \"ADAPTER_UNIQUE_CONSTRAINT\",\n\t\t\toperation: \"query\",\n\t\t\tcontext: { fields: params.fields.join(\", \"), table: params.table },\n\t\t\tsuggestion: `Ensure combination of [${params.fields.join(\", \")}] is unique in table '${params.table}'`,\n\t\t\texpected: \"unique combination\",\n\t\t},\n\t);\n}\n\nexport function throwForeignKeyConstraint(params: {\n\tadapter: AdapterName;\n\tforeignKey: string;\n\tvalue: unknown;\n\ttargetModel: string;\n\ttable: string;\n}): never {\n\tthrow new DatrixAdapterError(\n\t\t`Foreign key constraint failed: ${params.targetModel} with id '${params.value}' does not exist`,\n\t\t{\n\t\t\tadapter: params.adapter,\n\t\t\tcode: \"ADAPTER_FOREIGN_KEY_CONSTRAINT\",\n\t\t\toperation: \"query\",\n\t\t\tcontext: {\n\t\t\t\tforeignKey: params.foreignKey,\n\t\t\t\tvalue: params.value,\n\t\t\t\ttargetModel: params.targetModel,\n\t\t\t\ttable: params.table,\n\t\t\t},\n\t\t\tsuggestion: `Ensure ${params.targetModel} with id '${params.value}' exists before referencing it`,\n\t\t\texpected: `existing ${params.targetModel} id`,\n\t\t\treceived: params.value,\n\t\t},\n\t);\n}\n\n// ============================================================================\n// JSON Adapter — WHERE Errors\n// ============================================================================\n\nexport function throwInvalidWhereField(params: {\n\tadapter: AdapterName;\n\tfield: string;\n\tschemaName: string;\n\tavailableFields: readonly string[];\n}): never {\n\tthrow new DatrixAdapterError(\n\t\t`Invalid WHERE clause: Field '${params.field}' does not exist in schema '${params.schemaName}'`,\n\t\t{\n\t\t\tadapter: params.adapter,\n\t\t\tcode: \"ADAPTER_INVALID_WHERE_FIELD\",\n\t\t\toperation: \"query\",\n\t\t\tcontext: {\n\t\t\t\tfield: params.field,\n\t\t\t\tschemaName: params.schemaName,\n\t\t\t\tavailableFields: params.availableFields.join(\", \"),\n\t\t\t},\n\t\t\tsuggestion: `Use one of the available fields: ${params.availableFields.join(\", \")}`,\n\t\t\texpected: `valid field name from schema '${params.schemaName}'`,\n\t\t\treceived: params.field,\n\t\t},\n\t);\n}\n\nexport function throwInvalidRelationWhereSyntax(params: {\n\tadapter: AdapterName;\n\trelationName: string;\n\tschemaName: string;\n\tforeignKey: string;\n}): never {\n\tthrow new DatrixAdapterError(\n\t\t`Invalid WHERE clause: Cannot use comparison operators directly on relation field '${params.relationName}'`,\n\t\t{\n\t\t\tadapter: params.adapter,\n\t\t\tcode: \"ADAPTER_INVALID_RELATION_WHERE\",\n\t\t\toperation: \"query\",\n\t\t\tcontext: {\n\t\t\t\trelationName: params.relationName,\n\t\t\t\tschemaName: params.schemaName,\n\t\t\t\tforeignKey: params.foreignKey,\n\t\t\t},\n\t\t\tsuggestion:\n\t\t\t\t`Use nested WHERE syntax: { ${params.relationName}: { <field>: { $eq: <value> } } }\\n` +\n\t\t\t\t`Or filter by foreign key directly: { ${params.foreignKey}: { $eq: <value> } }`,\n\t\t\texpected:\n\t\t\t\t\"nested WHERE object with field names (e.g., { id: { $eq: 1 } })\",\n\t\t\treceived: \"comparison operators (e.g., { $eq: 1 })\",\n\t\t},\n\t);\n}\n","/**\n * Authentication Error\n *\n * Specialized error for authentication and authorization failures.\n * Extends DatrixError with auth-specific fields.\n */\n\nimport { DatrixError, type SerializedDatrixError } from \"../datrix-error\";\n\n/**\n * Auth strategy types\n */\nexport type AuthStrategy = \"jwt\" | \"session\" | \"password\" | \"permission\";\n\n/**\n * Auth error codes\n */\nexport type AuthErrorCode =\n\t| \"AUTH_INVALID_CREDENTIALS\"\n\t| \"AUTH_USER_NOT_FOUND\"\n\t| \"AUTH_USER_EXISTS\"\n\t| \"AUTH_WEAK_PASSWORD\"\n\t| \"AUTH_TOKEN_EXPIRED\"\n\t| \"AUTH_TOKEN_INVALID\"\n\t| \"AUTH_SESSION_NOT_FOUND\"\n\t| \"AUTH_SESSION_EXPIRED\"\n\t| \"AUTH_SESSION_INVALID\"\n\t| \"AUTH_UNAUTHORIZED\"\n\t| \"AUTH_FORBIDDEN\"\n\t| \"AUTH_CONFIG_INVALID\"\n\t| \"JWT_SIGN_ERROR\"\n\t| \"JWT_VERIFY_ERROR\"\n\t| \"JWT_DECODE_ERROR\"\n\t| \"JWT_EXPIRED\"\n\t| \"JWT_INVALID_FORMAT\"\n\t| \"JWT_INVALID_HEADER\"\n\t| \"JWT_INVALID_PAYLOAD\"\n\t| \"JWT_INVALID_SIGNATURE\"\n\t| \"JWT_INVALID_IAT\"\n\t| \"JWT_INVALID_ISSUER\"\n\t| \"JWT_INVALID_AUDIENCE\"\n\t| \"SESSION_CREATE_ERROR\"\n\t| \"SESSION_DELETE_ERROR\"\n\t| \"SESSION_NOT_CONFIGURED\"\n\t| \"PASSWORD_HASH_ERROR\"\n\t| \"PASSWORD_VERIFY_ERROR\"\n\t| \"PASSWORD_TOO_SHORT\"\n\t| \"PASSWORD_TOO_LONG\"\n\t| \"PERMISSION_DENIED\";\n\n/**\n * Auth error context\n */\nexport interface AuthErrorContext {\n\treadonly strategy?: AuthStrategy | undefined;\n\treadonly userId?: string | undefined;\n\treadonly role?: string | undefined;\n\treadonly sessionId?: string | undefined;\n\treadonly action?: string | undefined;\n\treadonly resource?: string | undefined;\n\treadonly field?: string | undefined;\n\treadonly exp?: number | undefined;\n\treadonly iat?: number | undefined;\n\treadonly now?: number | undefined;\n\treadonly minLength?: number | undefined;\n\treadonly maxLength?: number | undefined;\n\treadonly receivedType?: string | undefined;\n\treadonly expectedType?: string | undefined;\n\treadonly [key: string]: unknown;\n}\n\n/**\n * Options for creating DatrixAuthError\n */\nexport interface DatrixAuthErrorOptions {\n\treadonly code: AuthErrorCode;\n\treadonly strategy?: AuthStrategy;\n\treadonly context?: AuthErrorContext | undefined;\n\treadonly cause?: Error | undefined;\n\treadonly suggestion?: string | undefined;\n\treadonly expected?: string | undefined;\n\treadonly received?: unknown | undefined;\n}\n\n/**\n * Serialized auth error for API responses\n */\nexport interface SerializedDatrixAuthError extends SerializedDatrixError {\n\treadonly strategy?: AuthStrategy;\n}\n\n/**\n * Datrix Auth Error Class\n *\n * Specialized DatrixError for authentication and authorization failures.\n * Includes strategy type for better debugging.\n *\n * @example\n * ```ts\n * throw new DatrixAuthError('JWT token expired', {\n * code: 'JWT_EXPIRED',\n * strategy: 'jwt',\n * context: { exp: 1234567890, now: 1234567900 },\n * suggestion: 'Refresh your token or login again'\n * });\n * ```\n */\nexport class DatrixAuthError extends DatrixError<AuthErrorContext> {\n\treadonly strategy?: AuthStrategy | undefined;\n\n\tconstructor(message: string, options: DatrixAuthErrorOptions) {\n\t\tsuper(message, {\n\t\t\tcode: options.code,\n\t\t\toperation: options.strategy ? `auth:${options.strategy}` : \"auth\",\n\t\t\tcontext: options.context,\n\t\t\tcause: options.cause,\n\t\t\tsuggestion: options.suggestion,\n\t\t\texpected: options.expected,\n\t\t\treceived: options.received,\n\t\t});\n\n\t\tthis.strategy = options.strategy;\n\t}\n\n\t/**\n\t * Override toJSON to include auth-specific fields\n\t */\n\toverride toJSON(): SerializedDatrixAuthError {\n\t\tconst json = super.toJSON();\n\n\t\tif (this.strategy) {\n\t\t\treturn {\n\t\t\t\t...json,\n\t\t\t\tstrategy: this.strategy,\n\t\t\t};\n\t\t}\n\n\t\treturn json;\n\t}\n\n\t/**\n\t * Override toDetailedMessage to include auth-specific fields\n\t */\n\toverride toDetailedMessage(): string {\n\t\tconst baseMessage = super.toDetailedMessage();\n\n\t\tif (this.strategy) {\n\t\t\tconst parts = baseMessage.split(\"\\n\");\n\t\t\tparts.splice(3, 0, ` Strategy: ${this.strategy}`);\n\t\t\treturn parts.join(\"\\n\");\n\t\t}\n\n\t\treturn baseMessage;\n\t}\n}\n","/**\n * Parser Error\n *\n * Specialized error for query/URL parsing failures.\n * Extends DatrixError with parser-specific fields.\n */\n\nimport { DatrixError, type SerializedDatrixError } from \"../datrix-error\";\n\n/**\n * Which parser generated the error\n */\nexport type ParserType =\n\t| \"where\"\n\t| \"populate\"\n\t| \"fields\"\n\t| \"sort\"\n\t| \"pagination\"\n\t| \"query\";\n\n/**\n * Error location with full path tracking\n */\nexport interface ErrorLocation {\n\treadonly path: string;\n\treadonly parts: readonly string[];\n\treadonly queryParam?: string | undefined;\n\treadonly index?: number | undefined;\n\treadonly depth?: number | undefined;\n}\n\n/**\n * Base error context\n */\nexport interface BaseErrorContext {\n\treadonly [key: string]: unknown;\n}\n\n/**\n * Where parser specific context\n */\nexport interface WhereErrorContext extends BaseErrorContext {\n\treadonly operator?: string;\n\treadonly operatorPath?: string;\n\treadonly validOperators?: readonly string[];\n\treadonly arrayIndex?: number;\n\treadonly previousOperator?: string;\n\treadonly fieldValidationReason?: string;\n}\n\n/**\n * Populate parser specific context\n */\nexport interface PopulateErrorContext extends BaseErrorContext {\n\treadonly relation?: string;\n\treadonly relationPath?: string;\n\treadonly currentDepth?: number;\n\treadonly maxDepth?: number;\n\treadonly nestedRelations?: readonly string[];\n\treadonly fieldValidationReason?: string;\n}\n\n/**\n * Fields parser specific context\n */\nexport interface FieldsErrorContext extends BaseErrorContext {\n\treadonly fieldName?: string;\n\treadonly invalidFields?: readonly string[];\n\treadonly validationReasons?: readonly string[];\n\treadonly suspiciousParams?: readonly string[];\n\treadonly fieldValidationReason?: string;\n}\n\n/**\n * Pagination parser specific context\n */\nexport interface PaginationErrorContext extends BaseErrorContext {\n\treadonly parameter?: \"page\" | \"pageSize\" | \"limit\" | \"offset\";\n\treadonly minValue?: number;\n\treadonly maxValue?: number;\n}\n\n/**\n * Sort parser specific context\n */\nexport interface SortErrorContext extends BaseErrorContext {\n\treadonly sortField?: string;\n\treadonly sortDirection?: string;\n\treadonly invalidFields?: readonly string[];\n\treadonly fieldValidationReason?: string;\n}\n\n/**\n * Union of all parser context types\n */\nexport type ParserErrorContext =\n\t| WhereErrorContext\n\t| PopulateErrorContext\n\t| FieldsErrorContext\n\t| PaginationErrorContext\n\t| SortErrorContext\n\t| BaseErrorContext;\n\n/**\n * Comprehensive parser error codes\n */\nexport type ParserErrorCode =\n\t| \"INVALID_SYNTAX\"\n\t| \"INVALID_OPERATOR\"\n\t| \"INVALID_VALUE_TYPE\"\n\t| \"INVALID_VALUE_FORMAT\"\n\t| \"INVALID_FIELD_NAME\"\n\t| \"INVALID_PATH\"\n\t| \"MAX_DEPTH_EXCEEDED\"\n\t| \"MAX_LENGTH_EXCEEDED\"\n\t| \"MAX_SIZE_EXCEEDED\"\n\t| \"MIN_VALUE_VIOLATION\"\n\t| \"MAX_VALUE_VIOLATION\"\n\t| \"MISSING_REQUIRED\"\n\t| \"EMPTY_VALUE\"\n\t| \"ARRAY_INDEX_ERROR\"\n\t| \"CONSECUTIVE_INDEX_ERROR\"\n\t| \"UNKNOWN_PARAMETER\"\n\t| \"DUPLICATE_FIELD\"\n\t| \"INVALID_PAGINATION\"\n\t| \"PAGE_OUT_OF_RANGE\"\n\t| \"PARSER_INTERNAL_ERROR\";\n\n/**\n * Options for creating ParserError\n */\nexport interface ParserErrorOptions {\n\treadonly code: ParserErrorCode;\n\treadonly parser: ParserType;\n\treadonly location: ErrorLocation;\n\treadonly context?: ParserErrorContext;\n\treadonly suggestion?: string;\n\treadonly received?: unknown;\n\treadonly expected?: string;\n}\n\n/**\n * Serialized parser error for API responses\n */\nexport interface SerializedParserError extends SerializedDatrixError {\n\treadonly parser: ParserType;\n\treadonly location: ErrorLocation;\n}\n\n/**\n * Parser Error Class\n *\n * Specialized DatrixError for query/URL parsing errors.\n * Includes parser-specific fields: parser type and location tracking.\n */\nexport class ParserError extends DatrixError<ParserErrorContext> {\n\treadonly parser: ParserType;\n\treadonly location: ErrorLocation;\n\n\tconstructor(message: string, options: ParserErrorOptions) {\n\t\tsuper(message, {\n\t\t\tcode: options.code,\n\t\t\toperation: `parse:${options.parser}`,\n\t\t\tcontext: options.context,\n\t\t\tsuggestion: options.suggestion,\n\t\t\texpected: options.expected,\n\t\t\treceived: options.received,\n\t\t});\n\n\t\tthis.parser = options.parser;\n\t\tthis.location = options.location;\n\t}\n\n\t/**\n\t * Override toJSON to include parser-specific fields\n\t */\n\toverride toJSON(): SerializedParserError {\n\t\treturn {\n\t\t\t...super.toJSON(),\n\t\t\tparser: this.parser,\n\t\t\tlocation: this.location,\n\t\t};\n\t}\n\n\t/**\n\t * Override toDetailedMessage to include parser-specific info\n\t */\n\toverride toDetailedMessage(): string {\n\t\tconst baseMessage = super.toDetailedMessage();\n\t\tconst parserInfo = [\n\t\t\t` Parser: ${this.parser}`,\n\t\t\t` Location: ${this.location.path}`,\n\t\t];\n\n\t\tif (this.location.queryParam) {\n\t\t\tparserInfo.push(` Query Param: ${this.location.queryParam}`);\n\t\t}\n\n\t\tif (this.location.index !== undefined) {\n\t\t\tparserInfo.push(` Index: ${this.location.index}`);\n\t\t}\n\n\t\tif (this.location.depth !== undefined) {\n\t\t\tparserInfo.push(` Depth: ${this.location.depth}`);\n\t\t}\n\n\t\t// Insert parser info after the first line\n\t\tconst lines = baseMessage.split(\"\\n\");\n\t\tlines.splice(1, 0, ...parserInfo);\n\n\t\treturn lines.join(\"\\n\");\n\t}\n}\n\n/**\n * Helper to build error location\n */\nexport function buildErrorLocation(\n\tparts: string[],\n\toptions?: {\n\t\tqueryParam?: string | undefined;\n\t\tindex?: number | undefined;\n\t\tdepth?: number | undefined;\n\t},\n): ErrorLocation {\n\treturn {\n\t\tpath: parts.join(\".\"),\n\t\tparts,\n\t\tqueryParam: options?.queryParam,\n\t\tindex: options?.index,\n\t\tdepth: options?.depth,\n\t};\n}\n","/**\n * Config Error\n *\n * Specialized error for configuration validation failures.\n * Extends DatrixError with config-specific fields.\n */\n\nimport { DatrixError, type SerializedDatrixError } from \"../datrix-error\";\n\n/**\n * Config error codes\n */\nexport type ConfigErrorCode =\n\t| \"CONFIG_NOT_FOUND\"\n\t| \"CONFIG_INVALID_TYPE\"\n\t| \"CONFIG_REQUIRED_FIELD\"\n\t| \"CONFIG_INVALID_VALUE\"\n\t| \"CONFIG_EMPTY_VALUE\"\n\t| \"CONFIG_VALIDATION_FAILED\"\n\t| \"CONFIG_MULTIPLE_ERRORS\";\n\n/**\n * Config error context\n */\nexport interface ConfigErrorContext {\n\treadonly field?: string;\n\treadonly validOptions?: readonly string[];\n\treadonly receivedType?: string;\n\treadonly expectedType?: string;\n\treadonly index?: number;\n\treadonly configPath?: string;\n\treadonly [key: string]: unknown;\n}\n\n/**\n * Options for creating DatrixConfigError\n */\nexport interface DatrixConfigErrorOptions {\n\treadonly code: ConfigErrorCode;\n\treadonly field?: string | undefined;\n\treadonly context?: ConfigErrorContext | undefined;\n\treadonly cause?: Error | undefined;\n\treadonly suggestion?: string | undefined;\n\treadonly expected?: string | undefined;\n\treadonly received?: unknown | undefined;\n}\n\n/**\n * Serialized config error for API responses\n */\nexport interface SerializedDatrixConfigError extends SerializedDatrixError {\n\treadonly field?: string;\n}\n\n/**\n * Datrix Config Error Class\n *\n * Specialized DatrixError for configuration validation failures.\n * Includes field name for identifying which config property failed.\n */\nexport class DatrixConfigError extends DatrixError<ConfigErrorContext> {\n\treadonly field?: string | undefined;\n\n\tconstructor(message: string, options: DatrixConfigErrorOptions) {\n\t\tsuper(message, {\n\t\t\tcode: options.code,\n\t\t\toperation: \"config:validate\",\n\t\t\tcontext: options.context,\n\t\t\tcause: options.cause,\n\t\t\tsuggestion: options.suggestion,\n\t\t\texpected: options.expected,\n\t\t\treceived: options.received,\n\t\t});\n\n\t\tthis.field = options.field;\n\t}\n\n\t/**\n\t * Override toJSON to include config-specific fields\n\t */\n\toverride toJSON(): SerializedDatrixConfigError {\n\t\treturn {\n\t\t\t...super.toJSON(),\n\t\t\t...(this.field && { field: this.field }),\n\t\t};\n\t}\n\n\t/**\n\t * Override toDetailedMessage to include config-specific info\n\t */\n\toverride toDetailedMessage(): string {\n\t\tconst baseMessage = super.toDetailedMessage();\n\n\t\tif (this.field) {\n\t\t\tconst configInfo = [` Field: ${this.field}`];\n\t\t\tconst lines = baseMessage.split(\"\\n\");\n\t\t\tlines.splice(1, 0, ...configInfo);\n\t\t\treturn lines.join(\"\\n\");\n\t\t}\n\n\t\treturn baseMessage;\n\t}\n}\n\n/**\n * Multiple config validation errors\n */\nexport class DatrixConfigValidationError extends DatrixConfigError {\n\treadonly errors: readonly string[];\n\n\tconstructor(errors: readonly string[], suggestion?: string) {\n\t\tconst errorList = errors.map((e) => ` - ${e}`).join(\"\\n\");\n\n\t\tsuper(`Config validation failed:\\n${errorList}`, {\n\t\t\tcode: \"CONFIG_VALIDATION_FAILED\",\n\t\t\tcontext: { errors },\n\t\t\tsuggestion: suggestion ?? \"Fix the validation errors listed above\",\n\t\t});\n\n\t\tthis.errors = errors;\n\t}\n\n\t/**\n\t * Override toDetailedMessage to include all errors\n\t */\n\toverride toDetailedMessage(): string {\n\t\tconst baseMessage = super.toDetailedMessage();\n\t\tconst errorDetails = this.errors.map((err) => ` - ${err}`);\n\n\t\treturn `${baseMessage}\\n\\nValidation Errors:\\n${errorDetails.join(\"\\n\")}`;\n\t}\n}\n","/**\n * CRUD Operation Error\n *\n * Specialized error for database CRUD operation failures.\n * Extends DatrixError with CRUD-specific fields.\n */\n\nimport { DatrixError, type SerializedDatrixError } from \"../datrix-error\";\n\n/**\n * CRUD operation types\n */\nexport type CrudOperation =\n\t| \"findOne\"\n\t| \"findById\"\n\t| \"findMany\"\n\t| \"count\"\n\t| \"create\"\n\t| \"update\"\n\t| \"updateMany\"\n\t| \"delete\"\n\t| \"deleteMany\";\n\n/**\n * CRUD error codes\n */\nexport type CrudErrorCode =\n\t| \"QUERY_EXECUTION_FAILED\"\n\t| \"SCHEMA_NOT_FOUND\"\n\t| \"RECORD_NOT_FOUND\"\n\t| \"INVALID_POPULATE_VALUE\"\n\t| \"RESERVED_FIELD_WRITE\"\n\t| \"NOT_IMPLEMENTED\"\n\t| \"QUERY_FAILED\";\n\n/**\n * CRUD error context\n */\nexport interface CrudErrorContext {\n\treadonly model?: string;\n\treadonly query?: Record<string, unknown>;\n\treadonly recordId?: string | number;\n\treadonly where?: Record<string, unknown>;\n\treadonly adapterError?: string;\n\treadonly [key: string]: unknown;\n}\n\n/**\n * Options for creating DatrixCrudError\n */\nexport interface DatrixCrudErrorOptions {\n\treadonly code: CrudErrorCode;\n\treadonly operation: CrudOperation;\n\treadonly model: string;\n\treadonly context?: CrudErrorContext | undefined;\n\treadonly cause?: Error | undefined;\n\treadonly suggestion?: string | undefined;\n\treadonly expected?: string | undefined;\n\treadonly received?: unknown | undefined;\n}\n\n/**\n * Serialized CRUD error for API responses\n */\nexport interface SerializedDatrixCrudError extends SerializedDatrixError {\n\treadonly operation: CrudOperation;\n\treadonly model: string;\n}\n\n/**\n * Datrix CRUD Error Class\n *\n * Specialized DatrixError for CRUD operation failures.\n * Includes operation type and model name for better debugging.\n */\nexport class DatrixCrudError extends DatrixError<CrudErrorContext> {\n\toverride readonly operation: CrudOperation;\n\treadonly model: string;\n\n\tconstructor(message: string, options: DatrixCrudErrorOptions) {\n\t\tsuper(message, {\n\t\t\tcode: options.code,\n\t\t\toperation: `crud:${options.operation}`,\n\t\t\tcontext: options.context,\n\t\t\tcause: options.cause,\n\t\t\tsuggestion: options.suggestion,\n\t\t\texpected: options.expected,\n\t\t\treceived: options.received,\n\t\t});\n\n\t\tthis.operation = options.operation;\n\t\tthis.model = options.model;\n\t}\n\n\t/**\n\t * Override toJSON to include CRUD-specific fields\n\t */\n\toverride toJSON(): SerializedDatrixCrudError {\n\t\treturn {\n\t\t\t...super.toJSON(),\n\t\t\toperation: this.operation,\n\t\t\tmodel: this.model,\n\t\t};\n\t}\n\n\t/**\n\t * Override toDetailedMessage to include CRUD-specific info\n\t */\n\toverride toDetailedMessage(): string {\n\t\tconst baseMessage = super.toDetailedMessage();\n\t\tconst crudInfo = [\n\t\t\t` Operation: ${this.operation}`,\n\t\t\t` Model: ${this.model}`,\n\t\t];\n\n\t\tconst lines = baseMessage.split(\"\\n\");\n\t\tlines.splice(1, 0, ...crudInfo);\n\n\t\treturn lines.join(\"\\n\");\n\t}\n}\n","/**\n * Query Builder Error\n *\n * Specialized error for query builder failures.\n * Covers all query builder components: builder, where, select, populate, pagination.\n */\n\nimport { DatrixError, type SerializedDatrixError } from \"../datrix-error\";\n\n/**\n * Query builder component types\n */\nexport type QueryBuilderComponent =\n\t| \"builder\"\n\t| \"where\"\n\t| \"select\"\n\t| \"populate\"\n\t| \"data\"\n\t| \"pagination\";\n\n/**\n * Query builder error codes\n */\nexport type QueryBuilderErrorCode =\n\t| \"INVALID_QUERY_TYPE\"\n\t| \"MISSING_TABLE\"\n\t| \"INVALID_FIELD\"\n\t| \"INVALID_OPERATOR\"\n\t| \"INVALID_VALUE\"\n\t| \"MAX_DEPTH_EXCEEDED\"\n\t| \"EMPTY_CLAUSE\"\n\t| \"DUPLICATE_FIELD\"\n\t| \"COERCION_FAILED\"\n\t| \"DELETE_WITHOUT_WHERE\"\n\t| \"MISSING_DATA\"\n\t| \"RELATION_IN_SELECT\"\n\t| \"SCHEMA_NOT_FOUND\"\n\t| \"UNKNOWN_FIELD\";\n\n/**\n * Query builder error context\n */\nexport interface QueryBuilderErrorContext {\n\treadonly field?: string | undefined;\n\treadonly operator?: string | undefined;\n\treadonly value?: unknown | undefined;\n\treadonly availableFields?: readonly string[] | undefined;\n\treadonly validOperators?: readonly string[] | undefined;\n\treadonly depth?: number | undefined;\n\treadonly maxDepth?: number | undefined;\n\treadonly [key: string]: unknown;\n}\n\n/**\n * Options for creating DatrixQueryBuilderError\n */\nexport interface DatrixQueryBuilderErrorOptions {\n\treadonly code: QueryBuilderErrorCode;\n\treadonly component: QueryBuilderComponent;\n\treadonly field?: string | undefined;\n\treadonly context?: QueryBuilderErrorContext | undefined;\n\treadonly cause?: Error | undefined;\n\treadonly suggestion?: string | undefined;\n\treadonly expected?: string | undefined;\n\treadonly received?: unknown | undefined;\n}\n\n/**\n * Serialized query builder error\n */\nexport interface SerializedDatrixQueryBuilderError extends SerializedDatrixError {\n\treadonly component: QueryBuilderComponent;\n\treadonly field?: string;\n}\n\n/**\n * Datrix Query Builder Error Class\n *\n * Specialized DatrixError for query builder failures.\n * Includes component type to identify which part of query building failed.\n */\nexport class DatrixQueryBuilderError extends DatrixError<QueryBuilderErrorContext> {\n\treadonly component: QueryBuilderComponent;\n\treadonly field?: string | undefined;\n\n\tconstructor(\n\t\tmessage: string,\n\t\toptions?: DatrixQueryBuilderErrorOptions | string,\n\t) {\n\t\t// Backward compatibility: if options is string, it's the old 'code' parameter\n\t\tconst normalizedOptions: DatrixQueryBuilderErrorOptions =\n\t\t\ttypeof options === \"string\" || options === undefined\n\t\t\t\t? {\n\t\t\t\t\tcode: (options as QueryBuilderErrorCode) || \"INVALID_VALUE\",\n\t\t\t\t\tcomponent: \"builder\",\n\t\t\t\t}\n\t\t\t\t: options;\n\n\t\tsuper(message, {\n\t\t\tcode: normalizedOptions.code,\n\t\t\toperation: `query-builder:${normalizedOptions.component}`,\n\t\t\tcontext: normalizedOptions.context,\n\t\t\tcause: normalizedOptions.cause,\n\t\t\tsuggestion: normalizedOptions.suggestion,\n\t\t\texpected: normalizedOptions.expected,\n\t\t\treceived: normalizedOptions.received,\n\t\t});\n\n\t\tthis.component = normalizedOptions.component;\n\t\tthis.field = normalizedOptions.field;\n\t}\n\n\t/**\n\t * Override toJSON to include query builder-specific fields\n\t */\n\toverride toJSON(): SerializedDatrixQueryBuilderError {\n\t\treturn {\n\t\t\t...super.toJSON(),\n\t\t\tcomponent: this.component,\n\t\t\t...(this.field && { field: this.field }),\n\t\t};\n\t}\n\n\t/**\n\t * Override toDetailedMessage to include query builder-specific info\n\t */\n\toverride toDetailedMessage(): string {\n\t\tconst baseMessage = super.toDetailedMessage();\n\t\tconst builderInfo = [` Component: ${this.component}`];\n\n\t\tif (this.field) {\n\t\t\tbuilderInfo.push(` Field: ${this.field}`);\n\t\t}\n\n\t\tconst lines = baseMessage.split(\"\\n\");\n\t\tlines.splice(1, 0, ...builderInfo);\n\n\t\treturn lines.join(\"\\n\");\n\t}\n}\n","/**\n * Datrix Validation Error\n *\n * Specialized error for data validation failures.\n * Extends DatrixError with structured validation error details.\n */\n\nimport {\n\tDatrixError,\n\ttype DatrixErrorOptions,\n\ttype SerializedDatrixError,\n} from \"../datrix-error\";\nimport type { ValidationError } from \"../../core/validator\";\n\n/**\n * Options for creating DatrixValidationError\n */\nexport interface DatrixValidationErrorOptions extends Partial<DatrixErrorOptions> {\n\treadonly model: string;\n\treadonly errors: readonly ValidationError[];\n}\n\n/**\n * Serialized validation error for API responses\n */\nexport interface SerializedDatrixValidationError extends SerializedDatrixError {\n\treadonly model: string;\n\treadonly errors: readonly ValidationError[];\n}\n\n/**\n * Datrix Validation Error Class\n *\n * Specialized DatrixError for schema validation failures.\n * Includes the model name and a list of specific validation errors.\n */\nexport class DatrixValidationError extends DatrixError {\n\treadonly model: string;\n\treadonly errors: readonly ValidationError[];\n\n\tconstructor(message: string, options: DatrixValidationErrorOptions) {\n\t\tsuper(message, {\n\t\t\tcode: options.code || \"VALIDATION_FAILED\",\n\t\t\toperation: options.operation || \"validation\",\n\t\t\tcontext: {\n\t\t\t\tmodel: options.model,\n\t\t\t\terrors: options.errors,\n\t\t\t\t...options.context,\n\t\t\t},\n\t\t\t...(options.suggestion && { suggestion: options.suggestion }),\n\t\t\t...(options.expected && { expected: options.expected }),\n\t\t\t...(options.received !== undefined && { received: options.received }),\n\t\t});\n\n\t\tthis.model = options.model;\n\t\tthis.errors = options.errors;\n\t}\n\n\t/**\n\t * Override toJSON to include validation-specific fields\n\t */\n\toverride toJSON(): SerializedDatrixValidationError {\n\t\treturn {\n\t\t\t...super.toJSON(),\n\t\t\tmodel: this.model,\n\t\t\terrors: this.errors,\n\t\t};\n\t}\n\n\t/**\n\t * Override toDetailedMessage to include field-specific errors\n\t */\n\toverride toDetailedMessage(): string {\n\t\tconst baseMessage = super.toDetailedMessage();\n\t\tconst errorDetails = this.errors.map(\n\t\t\t(err) => ` - ${err.field}: ${err.message} (${err.code})`,\n\t\t);\n\n\t\treturn `${baseMessage}\\n\\nValidation Details:\\n${errorDetails.join(\"\\n\")}`;\n\t}\n}\n","/**\n * Query Builder Error Helpers\n *\n * Centralized error creation for query builder operations.\n * Covers: builder, where, select, populate, pagination components.\n */\n\nimport {\n\tDatrixQueryBuilderError,\n\ttype QueryBuilderComponent,\n} from \"../types/errors\";\n\n/**\n * Throw invalid field error\n *\n * @param component - Query builder component\n * @param field - Field name\n * @param availableFields - List of valid fields\n *\n * @example\n * ```ts\n * throwInvalidField('select', 'invalidField', ['id', 'name', 'email']);\n * ```\n */\nexport function throwInvalidField(\n\tcomponent: QueryBuilderComponent,\n\tfield: string,\n\tavailableFields?: readonly string[],\n): never {\n\tthrow new DatrixQueryBuilderError(\n\t\t`Invalid field '${field}' in ${component} clause`,\n\t\t{\n\t\t\tcode: \"INVALID_FIELD\",\n\t\t\tcomponent,\n\t\t\tfield,\n\t\t\tcontext: availableFields ? { availableFields } : undefined,\n\t\t\tsuggestion: availableFields\n\t\t\t\t? `Use one of: ${availableFields.join(\", \")}`\n\t\t\t\t: `Check that '${field}' exists in the schema`,\n\t\t\texpected: availableFields ? availableFields.join(\" | \") : undefined,\n\t\t\treceived: field,\n\t\t},\n\t);\n}\n\n/**\n * Throw invalid operator error\n *\n * @param field - Field name\n * @param operator - Invalid operator\n * @param validOperators - List of valid operators\n *\n * @example\n * ```ts\n * throwInvalidOperator('age', '$invalid', ['$eq', '$ne', '$gt', '$lt']);\n * ```\n */\nexport function throwInvalidOperator(\n\tfield: string,\n\toperator: string,\n\tvalidOperators: readonly string[],\n): never {\n\tthrow new DatrixQueryBuilderError(\n\t\t`Invalid operator '${operator}' for field '${field}'`,\n\t\t{\n\t\t\tcode: \"INVALID_OPERATOR\",\n\t\t\tcomponent: \"where\",\n\t\t\tfield,\n\t\t\tcontext: { operator, validOperators },\n\t\t\tsuggestion: `Use one of: ${validOperators.join(\", \")}`,\n\t\t\texpected: validOperators.join(\" | \"),\n\t\t\treceived: operator,\n\t\t},\n\t);\n}\n\n/**\n * Throw invalid value error\n *\n * @param component - Query builder component\n * @param field - Field name\n * @param value - Invalid value\n * @param expectedType - Expected type\n *\n * @example\n * ```ts\n * throwInvalidValue('where', 'age', 'invalid', 'number');\n * ```\n */\nexport function throwInvalidValue(\n\tcomponent: QueryBuilderComponent,\n\tfield: string,\n\tvalue: unknown,\n\texpectedType: string,\n): never {\n\tconst receivedType = Array.isArray(value)\n\t\t? \"array\"\n\t\t: value === null\n\t\t\t? \"null\"\n\t\t\t: typeof value;\n\n\tthrow new DatrixQueryBuilderError(\n\t\t`Invalid value for field '${field}'. Expected ${expectedType}, got ${receivedType}`,\n\t\t{\n\t\t\tcode: \"INVALID_VALUE\",\n\t\t\tcomponent,\n\t\t\tfield,\n\t\t\tcontext: { value, expectedType, receivedType },\n\t\t\tsuggestion: `Provide a ${expectedType} value for '${field}'`,\n\t\t\texpected: expectedType,\n\t\t\treceived: value,\n\t\t},\n\t);\n}\n\n/**\n * Throw max depth exceeded error\n *\n * @param component - Query builder component\n * @param currentDepth - Current nesting depth\n * @param maxDepth - Maximum allowed depth\n *\n * @example\n * ```ts\n * throwMaxDepthExceeded('where', 11, 10);\n * ```\n */\nexport function throwMaxDepthExceeded(\n\tcomponent: QueryBuilderComponent,\n\tcurrentDepth: number,\n\tmaxDepth: number,\n): never {\n\tthrow new DatrixQueryBuilderError(\n\t\t`Maximum nesting depth exceeded in ${component} clause. Depth: ${currentDepth}, Max: ${maxDepth}`,\n\t\t{\n\t\t\tcode: \"MAX_DEPTH_EXCEEDED\",\n\t\t\tcomponent,\n\t\t\tcontext: { depth: currentDepth, maxDepth },\n\t\t\tsuggestion: `Reduce nesting depth to ${maxDepth} or less`,\n\t\t\texpected: `depth <= ${maxDepth}`,\n\t\t\treceived: currentDepth,\n\t\t},\n\t);\n}\n\n/**\n * Throw empty clause error\n *\n * @param component - Query builder component\n *\n * @example\n * ```ts\n * throwEmptyClause('select');\n * ```\n */\nexport function throwEmptyClause(component: QueryBuilderComponent): never {\n\tthrow new DatrixQueryBuilderError(`Empty ${component} clause`, {\n\t\tcode: \"EMPTY_CLAUSE\",\n\t\tcomponent,\n\t\tsuggestion: `Provide at least one item in ${component} clause`,\n\t});\n}\n\n/**\n * Throw duplicate field error\n *\n * @param component - Query builder component\n * @param field - Duplicate field name\n *\n * @example\n * ```ts\n * throwDuplicateField('select', 'email');\n * ```\n */\nexport function throwDuplicateField(\n\tcomponent: QueryBuilderComponent,\n\tfield: string,\n): never {\n\tthrow new DatrixQueryBuilderError(\n\t\t`Duplicate field '${field}' in ${component} clause`,\n\t\t{\n\t\t\tcode: \"DUPLICATE_FIELD\",\n\t\t\tcomponent,\n\t\t\tfield,\n\t\t\tsuggestion: `Remove duplicate '${field}' field`,\n\t\t},\n\t);\n}\n\n/**\n * Throw missing table error\n *\n * @example\n * ```ts\n * throwMissingTable();\n * ```\n */\nexport function throwMissingTable(): never {\n\tthrow new DatrixQueryBuilderError(\"Query must have a table name\", {\n\t\tcode: \"MISSING_TABLE\",\n\t\tcomponent: \"builder\",\n\t\tsuggestion:\n\t\t\t\"Call .from('tableName') or .table('tableName') before building\",\n\t});\n}\n\n/**\n * Throw missing WHERE clause error for DELETE queries\n */\nexport function throwDeleteWithoutWhere(): never {\n\tthrow new DatrixQueryBuilderError(\n\t\t\"DELETE query requires a WHERE clause. Use deleteAll() to delete all records explicitly.\",\n\t\t{\n\t\t\tcode: \"DELETE_WITHOUT_WHERE\",\n\t\t\tcomponent: \"builder\",\n\t\t\tsuggestion:\n\t\t\t\t\"Add .where() clause or use deleteAll() for full table deletion\",\n\t\t},\n\t);\n}\n\n/**\n * Throw missing data error for INSERT/UPDATE queries\n */\nexport function throwMissingData(queryType: \"insert\" | \"update\"): never {\n\tthrow new DatrixQueryBuilderError(\n\t\t`${queryType.toUpperCase()} query requires data`,\n\t\t{\n\t\t\tcode: \"MISSING_DATA\",\n\t\t\tcomponent: \"builder\",\n\t\t\tsuggestion:\n\t\t\t\tqueryType === \"insert\"\n\t\t\t\t\t? \"Provide at least one data item to insert\"\n\t\t\t\t\t: \"Provide data object with fields to update\",\n\t\t},\n\t);\n}\n\n/**\n * Throw invalid query type error\n *\n * @param receivedType - Received query type\n *\n * @example\n * ```ts\n * throwInvalidQueryType('invalid');\n * ```\n */\nexport function throwInvalidQueryType(receivedType: unknown): never {\n\tthrow new DatrixQueryBuilderError(`Invalid query type: ${receivedType}`, {\n\t\tcode: \"INVALID_QUERY_TYPE\",\n\t\tcomponent: \"builder\",\n\t\tsuggestion: \"Use one of: select, insert, update, delete, count\",\n\t\texpected: \"select | insert | update | delete | count\",\n\t\treceived: receivedType,\n\t});\n}\n\n/**\n * Throw schema not found error\n *\n * @param modelName - Model name that was not found\n *\n * @example\n * ```ts\n * throwSchemaNotFound('InvalidModel');\n * ```\n */\nexport function throwSchemaNotFound(modelName: string): never {\n\tthrow new DatrixQueryBuilderError(`Schema not found for model: ${modelName}`, {\n\t\tcode: \"SCHEMA_NOT_FOUND\",\n\t\tcomponent: \"builder\",\n\t\tcontext: { modelName },\n\t\tsuggestion: `Check that '${modelName}' is registered in the schema registry`,\n\t\treceived: modelName,\n\t});\n}\n\n/**\n * Throw multiple invalid fields error\n *\n * @param component - Query builder component\n * @param invalidFields - List of invalid field names\n * @param availableFields - List of valid fields\n *\n * @example\n * ```ts\n * throwInvalidFields('select', ['field1', 'field2'], ['id', 'name', 'email']);\n * ```\n */\nexport function throwInvalidFields(\n\tcomponent: QueryBuilderComponent,\n\tinvalidFields: readonly string[],\n\tavailableFields?: readonly string[],\n): never {\n\tconst fieldList = invalidFields.join(\", \");\n\tthrow new DatrixQueryBuilderError(\n\t\t`Invalid field(s) in ${component} clause: ${fieldList}`,\n\t\t{\n\t\t\tcode: \"INVALID_FIELD\",\n\t\t\tcomponent,\n\t\t\tfield: invalidFields[0],\n\t\t\tcontext: { invalidFields, availableFields },\n\t\t\tsuggestion: availableFields\n\t\t\t\t? `Use one of: ${availableFields.join(\", \")}`\n\t\t\t\t: `Check that these fields exist in the schema`,\n\t\t\texpected: availableFields ? availableFields.join(\" | \") : undefined,\n\t\t\treceived: fieldList,\n\t\t},\n\t);\n}\n\n/**\n * Throw relation field in select error\n *\n * @param relationFields - List of relation field names\n * @param modelName - Model name\n *\n * @example\n * ```ts\n * throwRelationInSelect(['category', 'author'], 'Product');\n * ```\n */\nexport function throwRelationInSelect(\n\trelationFields: readonly string[],\n\tmodelName: string,\n): never {\n\tconst fieldList = relationFields.join(\", \");\n\tthrow new DatrixQueryBuilderError(\n\t\t`Cannot select relation field(s) in model '${modelName}': ${fieldList}. Use populate() to include relations.`,\n\t\t{\n\t\t\tcode: \"RELATION_IN_SELECT\",\n\t\t\tcomponent: \"select\",\n\t\t\tfield: relationFields[0],\n\t\t\tcontext: { relationFields, modelName },\n\t\t\tsuggestion: `Use .populate('${relationFields[0]}') instead of selecting it`,\n\t\t},\n\t);\n}\n\n/**\n * Throw type coercion failed error\n *\n * @param field - Field name\n * @param value - Value that failed coercion\n * @param expectedType - Expected type\n *\n * @example\n * ```ts\n * throwCoercionFailed('price', 'invalid', 'number');\n * // Error: Cannot convert value 'invalid' to number for field 'price'\n * ```\n */\nexport function throwCoercionFailed(\n\tfield: string,\n\tvalue: unknown,\n\texpectedType: string,\n): never {\n\tconst displayValue = typeof value === \"string\" ? `'${value}'` : String(value);\n\tthrow new DatrixQueryBuilderError(\n\t\t`Cannot convert value ${displayValue} to ${expectedType} for field '${field}'`,\n\t\t{\n\t\t\tcode: \"COERCION_FAILED\",\n\t\t\tcomponent: \"where\",\n\t\t\tfield,\n\t\t\tcontext: { value, expectedType, receivedType: typeof value },\n\t\t\tsuggestion: `Provide a valid ${expectedType} value for '${field}'`,\n\t\t\texpected: expectedType,\n\t\t\treceived: value,\n\t\t},\n\t);\n}\n","/**\n * WHERE Clause Builder\n *\n * All WHERE-related operations: merging, validation, normalization.\n * Handles comparison operators, logical operators, nested conditions, and relation shortcuts.\n */\n\nimport type {\n\tComparisonOperators,\n\tWhereClause,\n} from \"../types/core/query-builder\";\nimport type {\n\tFieldType,\n\tSchemaDefinition,\n\tRelationField,\n\tISchemaRegistry,\n\tDatrixEntry,\n\tFieldDefinition,\n} from \"../types/core/schema\";\nimport {\n\tthrowInvalidOperator,\n\tthrowInvalidValue,\n\tthrowMaxDepthExceeded,\n\tthrowInvalidField,\n\tthrowCoercionFailed,\n} from \"./error-helper\";\n\n/**\n * All supported comparison operators\n */\nexport const COMPARISON_OPERATORS = [\n\t\"$eq\",\n\t\"$ne\",\n\t\"$gt\",\n\t\"$gte\",\n\t\"$lt\",\n\t\"$lte\",\n\t\"$in\",\n\t\"$nin\",\n\t\"$like\",\n\t\"$ilike\",\n\t\"$startsWith\",\n\t\"$endsWith\",\n\t\"$contains\",\n\t\"$notContains\",\n\t\"$icontains\",\n\t\"$regex\",\n\t\"$exists\",\n\t\"$null\",\n\t\"$notNull\",\n] as const;\n\n/**\n * Operators that always expect boolean values\n */\nconst BOOLEAN_OPERATORS = [\"$exists\", \"$null\", \"$notNull\"] as const;\n\n/**\n * Operators that always expect string values (regardless of field type)\n */\nconst STRING_OPERATORS = [\n\t\"$like\",\n\t\"$ilike\",\n\t\"$startsWith\",\n\t\"$endsWith\",\n\t\"$contains\",\n\t\"$notContains\",\n\t\"$icontains\",\n\t\"$regex\",\n] as const;\n\n/**\n * Coerce a value to the expected field type\n *\n * API'den gelen string değerleri schema'daki field tipine göre dönüştürür.\n *\n * @param value - The value to coerce (often a string from API)\n * @param fieldDef - Field definition from schema\n * @param fieldName - Field name for error messages\n * @returns Coerced value in the correct type\n * @throws {DatrixQueryBuilderError} If coercion fails\n *\n * @example\n * ```ts\n * coerceValue(\"100\", { type: \"number\" }, \"price\") // → 100\n * coerceValue(\"true\", { type: \"boolean\" }, \"active\") // → true\n * coerceValue(\"2024-01-01\", { type: \"date\" }, \"createdAt\") // → Date object\n * coerceValue(\"hello\", { type: \"number\" }, \"price\") // → throws error\n * ```\n */\nexport function coerceValue(\n\tvalue: unknown,\n\tfieldDef: FieldDefinition,\n\tfieldName: string,\n): unknown {\n\t// null/undefined pass through\n\tif (value === null || value === undefined) {\n\t\treturn value;\n\t}\n\n\t// Already correct type - no coercion needed\n\tif (isCorrectType(value, fieldDef.type)) {\n\t\treturn value;\n\t}\n\n\t// String coercion based on field type\n\tif (typeof value === \"string\") {\n\t\treturn coerceString(value, fieldDef.type, fieldName);\n\t}\n\n\t// Array coercion (for $in, $nin operators)\n\tif (Array.isArray(value)) {\n\t\treturn value.map((item) => coerceValue(item, fieldDef, fieldName));\n\t}\n\n\t// Value is not string and not correct type - error\n\tthrowCoercionFailed(fieldName, value, fieldDef.type);\n}\n\n/**\n * Check if value is already the correct type\n *\n * Supports all FieldType values from schema.ts:\n * string, number, boolean, date, json, enum, array, relation, file\n */\nfunction isCorrectType(value: unknown, fieldType: FieldType): boolean {\n\tswitch (fieldType) {\n\t\tcase \"string\":\n\t\tcase \"enum\":\n\t\tcase \"file\":\n\t\t\treturn typeof value === \"string\";\n\t\tcase \"number\":\n\t\t\treturn typeof value === \"number\" && !Number.isNaN(value);\n\t\tcase \"boolean\":\n\t\t\treturn typeof value === \"boolean\";\n\t\tcase \"date\":\n\t\t\treturn value instanceof Date && !Number.isNaN(value.getTime());\n\t\tcase \"json\":\n\t\t\treturn typeof value === \"object\";\n\t\tcase \"array\":\n\t\t\treturn Array.isArray(value);\n\t\tcase \"relation\":\n\t\t\treturn typeof value === \"number\" || typeof value === \"string\";\n\t\tdefault:\n\t\t\treturn true;\n\t}\n}\n\n/**\n * Coerce string value to target type\n *\n * Supports all FieldType values from schema.ts:\n * string, number, boolean, date, json, enum, array, relation, file\n */\nfunction coerceString(\n\tvalue: string,\n\tfieldType: FieldType,\n\tfieldName: string,\n): unknown {\n\tswitch (fieldType) {\n\t\tcase \"string\":\n\t\tcase \"enum\":\n\t\tcase \"file\":\n\t\t\treturn value;\n\n\t\tcase \"number\": {\n\t\t\tconst num = Number(value);\n\t\t\tif (Number.isNaN(num)) {\n\t\t\t\tthrowCoercionFailed(fieldName, value, \"number\");\n\t\t\t}\n\t\t\treturn num;\n\t\t}\n\n\t\tcase \"boolean\": {\n\t\t\tconst lower = value.toLowerCase();\n\t\t\tif (lower === \"true\" || lower === \"1\") {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tif (lower === \"false\" || lower === \"0\") {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tthrowCoercionFailed(fieldName, value, \"boolean\");\n\t\t}\n\n\t\tcase \"date\": {\n\t\t\tconst date = new Date(value);\n\t\t\tif (Number.isNaN(date.getTime())) {\n\t\t\t\tthrowCoercionFailed(fieldName, value, \"date\");\n\t\t\t}\n\t\t\treturn date;\n\t\t}\n\n\t\tcase \"json\": {\n\t\t\ttry {\n\t\t\t\treturn JSON.parse(value);\n\t\t\t} catch {\n\t\t\t\tthrowCoercionFailed(fieldName, value, \"json\");\n\t\t\t}\n\t\t}\n\n\t\tcase \"array\": {\n\t\t\ttry {\n\t\t\t\tconst parsed = JSON.parse(value);\n\t\t\t\tif (!Array.isArray(parsed)) {\n\t\t\t\t\tthrowCoercionFailed(fieldName, value, \"array\");\n\t\t\t\t}\n\t\t\t\treturn parsed;\n\t\t\t} catch {\n\t\t\t\tthrowCoercionFailed(fieldName, value, \"array\");\n\t\t\t}\n\t\t}\n\n\t\tcase \"relation\": {\n\t\t\t// Try to parse as number first, otherwise keep as string ID\n\t\t\tconst num = Number(value);\n\t\t\treturn Number.isNaN(num) ? value : num;\n\t\t}\n\n\t\tdefault:\n\t\t\treturn value;\n\t}\n}\n\n/**\n * Maximum nesting depth for WHERE clauses to prevent stack overflow\n */\nconst MAX_WHERE_DEPTH = 10;\n\n/**\n * Check if value is a comparison operator object\n */\nexport function isComparisonOperators(\n\tvalue: unknown,\n): value is ComparisonOperators {\n\tif (typeof value !== \"object\" || value === null) {\n\t\treturn false;\n\t}\n\n\treturn Object.keys(value).some((key) =>\n\t\t(COMPARISON_OPERATORS as readonly string[]).includes(key),\n\t);\n}\n\n/**\n * Check if value is a logical operator\n */\nexport function isLogicalOperator(key: string): boolean {\n\treturn [\"$and\", \"$or\", \"$not\"].includes(key);\n}\n\n/**\n * Validate comparison operator value\n *\n * Note: This validation is lenient for string values because coercion\n * happens in normalizeWhereClause and will convert strings to proper types.\n * We only validate structural correctness here (e.g., $in must be array).\n *\n * @throws {DatrixQueryBuilderError} If operator or value is invalid\n */\nexport function validateComparisonOperator(\n\tfield: string,\n\toperator: string,\n\tvalue: unknown,\n\t_fieldType: FieldType,\n): void {\n\tswitch (operator) {\n\t\tcase \"$eq\":\n\t\tcase \"$ne\":\n\t\t\t// Any primitive is valid (strings will be coerced later)\n\t\t\tif (\n\t\t\t\ttypeof value !== \"string\" &&\n\t\t\t\ttypeof value !== \"number\" &&\n\t\t\t\ttypeof value !== \"boolean\" &&\n\t\t\t\tvalue !== null &&\n\t\t\t\t!(value instanceof Date)\n\t\t\t) {\n\t\t\t\tthrowInvalidValue(\"where\", field, value, \"primitive value\");\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase \"$gt\":\n\t\tcase \"$gte\":\n\t\tcase \"$lt\":\n\t\tcase \"$lte\":\n\t\t\t// Numbers, dates, or strings (strings will be coerced to number/date)\n\t\t\tif (\n\t\t\t\ttypeof value !== \"number\" &&\n\t\t\t\ttypeof value !== \"string\" &&\n\t\t\t\t!(value instanceof Date)\n\t\t\t) {\n\t\t\t\tthrowInvalidValue(\"where\", field, value, \"number, Date, or string\");\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase \"$in\":\n\t\tcase \"$nin\":\n\t\t\t// Array of primitives\n\t\t\tif (!Array.isArray(value)) {\n\t\t\t\tthrowInvalidValue(\"where\", field, value, \"array\");\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase \"$like\":\n\t\tcase \"$ilike\":\n\t\tcase \"$contains\":\n\t\tcase \"$icontains\":\n\t\tcase \"$notContains\":\n\t\tcase \"$startsWith\":\n\t\tcase \"$endsWith\":\n\t\t\t// String only\n\t\t\tif (typeof value !== \"string\") {\n\t\t\t\tthrowInvalidValue(\"where\", field, value, \"string\");\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase \"$regex\":\n\t\t\t// RegExp or string\n\t\t\tif (!(value instanceof RegExp) && typeof value !== \"string\") {\n\t\t\t\tthrowInvalidValue(\"where\", field, value, \"RegExp or string\");\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase \"$exists\":\n\t\tcase \"$null\":\n\t\tcase \"$notNull\":\n\t\t\t// Boolean or string (strings like \"true\"/\"false\" will be coerced)\n\t\t\tif (typeof value !== \"boolean\" && typeof value !== \"string\") {\n\t\t\t\tthrowInvalidValue(\"where\", field, value, \"boolean or string\");\n\t\t\t}\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tthrowInvalidOperator(field, operator, COMPARISON_OPERATORS);\n\t}\n}\n\n/**\n * Validate where clause against schema\n * @param where - WHERE clause to validate\n * @param schema - Schema definition\n * @param schemaRegistry - Schema registry for nested relation validation\n * @param depth - Current nesting depth\n * @throws {DatrixQueryBuilderError} If where clause is invalid\n */\nexport function validateWhereClause<T extends DatrixEntry>(\n\twhere: WhereClause<T>,\n\tschema: SchemaDefinition,\n\tschemaRegistry?: ISchemaRegistry,\n\tdepth = 0,\n): void {\n\t// Check depth limit\n\tif (depth > MAX_WHERE_DEPTH) {\n\t\tthrowMaxDepthExceeded(\"where\", depth, MAX_WHERE_DEPTH);\n\t}\n\n\tconst availableFields = Object.keys(schema.fields);\n\n\tfor (const [key, value] of Object.entries(where)) {\n\t\t// Handle logical operators\n\t\tif (isLogicalOperator(key)) {\n\t\t\tif (key === \"$and\" || key === \"$or\") {\n\t\t\t\tif (!Array.isArray(value)) {\n\t\t\t\t\tthrowInvalidValue(\"where\", key, value, \"array of conditions\");\n\t\t\t\t}\n\n\t\t\t\t// Recursively validate each condition\n\t\t\t\tfor (const condition of value as readonly WhereClause<T>[]) {\n\t\t\t\t\tvalidateWhereClause(condition, schema, schemaRegistry, depth + 1);\n\t\t\t\t}\n\t\t\t} else if (key === \"$not\") {\n\t\t\t\t// Recursively validate nested condition\n\t\t\t\tvalidateWhereClause(\n\t\t\t\t\tvalue as WhereClause<T>,\n\t\t\t\t\tschema,\n\t\t\t\t\tschemaRegistry,\n\t\t\t\t\tdepth + 1,\n\t\t\t\t);\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Check field exists in schema\n\t\tif (!availableFields.includes(key)) {\n\t\t\tthrowInvalidField(\"where\", key, availableFields);\n\t\t}\n\n\t\tconst fieldDef = schema.fields[key]!;\n\n\t\t// Handle relation fields\n\t\tif (fieldDef.type === \"relation\") {\n\t\t\tconst relationField = fieldDef as RelationField;\n\n\t\t\t// Primitive value shortcut: { category: 2 }\n\t\t\tif (typeof value === \"string\" || typeof value === \"number\") {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Object value - could be $null/$notNull or nested WHERE\n\t\t\tif (\n\t\t\t\ttypeof value === \"object\" &&\n\t\t\t\tvalue !== null &&\n\t\t\t\t!(value instanceof Date)\n\t\t\t) {\n\t\t\t\tconst valueObj = value as Record<string, unknown>;\n\t\t\t\tconst keys = Object.keys(valueObj);\n\n\t\t\t\t// Check for $null or $notNull operators on relation (FK null check)\n\t\t\t\t// { organization: { $null: true } } - valid for belongsTo/hasOne\n\t\t\t\tif (\n\t\t\t\t\tkeys.length === 1 &&\n\t\t\t\t\t(keys[0] === \"$null\" || keys[0] === \"$notNull\")\n\t\t\t\t) {\n\t\t\t\t\tconst opValue = valueObj[keys[0]];\n\t\t\t\t\t// Validate that the value is boolean or string that can be coerced\n\t\t\t\t\tif (typeof opValue !== \"boolean\" && typeof opValue !== \"string\") {\n\t\t\t\t\t\tthrowInvalidValue(\"where\", key, opValue, \"boolean or string\");\n\t\t\t\t\t}\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// Nested WHERE for relation - validate against target schema\n\t\t\t\tif (schemaRegistry) {\n\t\t\t\t\tconst targetSchema = schemaRegistry.get(relationField.model);\n\t\t\t\t\tif (targetSchema) {\n\t\t\t\t\t\tvalidateWhereClause(\n\t\t\t\t\t\t\tvalue as WhereClause<T>,\n\t\t\t\t\t\t\ttargetSchema,\n\t\t\t\t\t\t\tschemaRegistry,\n\t\t\t\t\t\t\tdepth + 1,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Handle comparison operators\n\t\tif (isComparisonOperators(value)) {\n\t\t\tconst ops = value as ComparisonOperators;\n\t\t\tfor (const [operator, opValue] of Object.entries(ops)) {\n\t\t\t\tvalidateComparisonOperator(key, operator, opValue, fieldDef.type);\n\t\t\t}\n\t\t}\n\t\t// Simple equality check\n\t\telse {\n\t\t\t// Validate primitive value\n\t\t\tif (\n\t\t\t\ttypeof value !== \"string\" &&\n\t\t\t\ttypeof value !== \"number\" &&\n\t\t\t\ttypeof value !== \"boolean\" &&\n\t\t\t\tvalue !== null &&\n\t\t\t\t!(value instanceof Date)\n\t\t\t) {\n\t\t\t\tthrowInvalidValue(\"where\", key, value, \"primitive value\");\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * Normalize and validate WHERE arrays\n *\n * Complete WHERE processing pipeline:\n * 1. Merge multiple .where() calls with $and\n * 2. Validate fields and operators (BEFORE normalization)\n * - Including nested relation WHERE validation\n * 3. Normalize relation shortcuts (category: 2 → categoryId: { $eq: 2 })\n * 4. Recursively process logical operators ($and, $or, $not)\n *\n * @param wheres - Array of where clauses from multiple .where() calls\n * @param schema - Schema definition for validation and normalization\n * @param registry - Schema registry for nested relation validation\n * @returns Normalized and validated WHERE clause\n *\n * @example\n * ```ts\n * // Multiple where calls\n * normalizeWhere([{ age: { $gte: 18 } }, { role: 'admin' }], schema, registry)\n * // → { $and: [{ age: { $gte: 18 } }, { role: 'admin' }] }\n *\n * // Relation shortcut normalization\n * normalizeWhere([{ category: 2 }], productSchema, registry)\n * // → { categoryId: { $eq: 2 } }\n *\n * // Nested relation WHERE validation\n * normalizeWhere([{ category: { invalidField: 'value' } }], productSchema, registry)\n * // → throws DatrixQueryBuilderError (invalidField doesn't exist in Category schema)\n *\n * // Validation errors caught first\n * normalizeWhere([{ invalidField: 'value' }], schema, registry)\n * // → throws DatrixQueryBuilderError (BEFORE normalization)\n * ```\n */\nexport function normalizeWhere<T extends DatrixEntry>(\n\twheres: WhereClause<T>[] | undefined,\n\tschema: SchemaDefinition,\n\tregistry: ISchemaRegistry,\n): WhereClause<T> | undefined {\n\tif (!wheres || wheres.length === 0) {\n\t\treturn undefined;\n\t}\n\n\t// 1. Merge multiple where clauses with $and\n\tlet mergedWhere: WhereClause<T>;\n\tif (wheres.length === 1) {\n\t\tmergedWhere = wheres[0]!;\n\t} else {\n\t\tmergedWhere = { $and: wheres } as WhereClause<T>;\n\t}\n\n\t// 2. Validate BEFORE normalization (catches errors early)\n\t// Including nested relation WHERE validation\n\tvalidateWhereClause(mergedWhere, schema, registry);\n\n\t// 3. Normalize relation shortcuts and logical operators\n\treturn normalizeWhereClause(mergedWhere, schema, registry);\n}\n\n/**\n * Normalize WHERE clause recursively\n *\n * Internal function that handles:\n * - Type coercion: \"100\" → 100 (based on field type)\n * - Relation shortcuts: { category: 2 } → { categoryId: { $eq: 2 } }\n * - Nested relation WHERE: Recursively normalize target schema\n * - Logical operators: Recursively process $and, $or, $not\n * - Comparison operators: Coerce values inside $eq, $gt, $in, etc.\n *\n * @param where - WHERE clause to normalize\n * @param schema - Schema definition\n * @param registry - Schema registry for nested relation schemas\n * @returns Normalized WHERE clause with coerced values\n */\nfunction normalizeWhereClause<T extends DatrixEntry>(\n\twhere: WhereClause<T>,\n\tschema: SchemaDefinition,\n\tregistry: ISchemaRegistry,\n): WhereClause<T> {\n\tconst normalized: Record<string, unknown> = {};\n\n\tfor (const [key, value] of Object.entries(where)) {\n\t\t// Handle logical operators recursively\n\t\tif (key === \"$and\" || key === \"$or\") {\n\t\t\tnormalized[key] = (value as WhereClause<T>[]).map((clause) =>\n\t\t\t\tnormalizeWhereClause(clause, schema, registry),\n\t\t\t);\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (key === \"$not\") {\n\t\t\tnormalized[key] = normalizeWhereClause(\n\t\t\t\tvalue as WhereClause<T>,\n\t\t\t\tschema,\n\t\t\t\tregistry,\n\t\t\t);\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Get field definition\n\t\tconst fieldDef = schema.fields[key];\n\t\tif (!fieldDef) {\n\t\t\t// Unknown field - keep as-is (validation will catch this)\n\t\t\tnormalized[key] = value;\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Handle relation fields\n\t\tif (fieldDef.type === \"relation\") {\n\t\t\tconst relationField = fieldDef as RelationField;\n\t\t\tconst kind = relationField.kind;\n\n\t\t\t// Only normalize for belongsTo/hasOne (they have FK in current table)\n\t\t\tif (kind === \"belongsTo\" || kind === \"hasOne\") {\n\t\t\t\tconst foreignKey = relationField.foreignKey!;\n\n\t\t\t\t// Primitive value shortcut: { category: 2 } → { categoryId: { $eq: 2 } }\n\t\t\t\tif (typeof value === \"string\" || typeof value === \"number\") {\n\t\t\t\t\tconst coercedValue = coerceValue(value, { type: \"number\" }, key);\n\t\t\t\t\tnormalized[foreignKey] = { $eq: coercedValue };\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// Object value - check if it's $null/$notNull operator for FK\n\t\t\t\tif (\n\t\t\t\t\ttypeof value === \"object\" &&\n\t\t\t\t\tvalue !== null &&\n\t\t\t\t\t!(value instanceof Date)\n\t\t\t\t) {\n\t\t\t\t\tconst valueObj = value as Record<string, unknown>;\n\t\t\t\t\tconst keys = Object.keys(valueObj);\n\n\t\t\t\t\t// Check for $null or $notNull operators on relation\n\t\t\t\t\t// { organization: { $null: true } } → { organizationId: { $null: true } }\n\t\t\t\t\tif (\n\t\t\t\t\t\tkeys.length === 1 &&\n\t\t\t\t\t\t(keys[0] === \"$null\" || keys[0] === \"$notNull\")\n\t\t\t\t\t) {\n\t\t\t\t\t\tconst operator = keys[0];\n\t\t\t\t\t\tconst operatorValue = valueObj[operator];\n\t\t\t\t\t\tconst coercedValue = coerceValue(\n\t\t\t\t\t\t\toperatorValue,\n\t\t\t\t\t\t\t{ type: \"boolean\" },\n\t\t\t\t\t\t\tkey,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tnormalized[foreignKey] = { [operator]: coercedValue };\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Nested WHERE - recursively normalize with target schema\n\t\t\t\t\tconst targetSchema = registry.get(relationField.model);\n\t\t\t\t\tif (targetSchema) {\n\t\t\t\t\t\tnormalized[key] = normalizeWhereClause(\n\t\t\t\t\t\t\tvalue as WhereClause<T>,\n\t\t\t\t\t\t\ttargetSchema,\n\t\t\t\t\t\t\tregistry,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// hasMany/manyToMany or fallback: keep as-is\n\t\t\tnormalized[key] = value;\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Handle comparison operators - coerce values inside\n\t\tif (isComparisonOperators(value)) {\n\t\t\tconst coercedOps: Record<string, unknown> = {};\n\t\t\tfor (const [operator, opValue] of Object.entries(\n\t\t\t\tvalue as ComparisonOperators,\n\t\t\t)) {\n\t\t\t\t// Boolean operators - $exists, $null, $notNull\n\t\t\t\tif ((BOOLEAN_OPERATORS as readonly string[]).includes(operator)) {\n\t\t\t\t\tcoercedOps[operator] = coerceValue(opValue, { type: \"boolean\" }, key);\n\t\t\t\t}\n\t\t\t\t// String operators - always keep as string regardless of field type\n\t\t\t\telse if ((STRING_OPERATORS as readonly string[]).includes(operator)) {\n\t\t\t\t\tcoercedOps[operator] = opValue; // Keep as string\n\t\t\t\t}\n\t\t\t\t// All other operators - coerce based on field type\n\t\t\t\telse {\n\t\t\t\t\tcoercedOps[operator] = coerceValue(opValue, fieldDef, key);\n\t\t\t\t}\n\t\t\t}\n\t\t\tnormalized[key] = coercedOps;\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Simple equality - coerce based on field type\n\t\tnormalized[key] = coerceValue(value, fieldDef, key);\n\t}\n\n\treturn normalized as WhereClause<T>;\n}\n","/**\n * SELECT Utilities\n *\n * All SELECT-related operations: merging, validation, normalization.\n */\n\nimport type { QuerySelect, SelectClause } from \"../types/core/query-builder\";\nimport type {\n\tDatrixEntry,\n\tSchemaDefinition,\n\tISchemaRegistry,\n} from \"../types/core/schema\";\nimport { throwInvalidFields, throwRelationInSelect } from \"./error-helper\";\n\n/**\n * Normalize and validate SELECT arrays\n *\n * Complete SELECT processing pipeline:\n * 1. Merge multiple .select() calls into one\n * 2. Deduplicate using Set\n * 3. If any is \"*\", expand to cached fields from registry\n * 4. Validate fields exist and are not relations\n * 5. Add reserved fields (id, createdAt, updatedAt)\n * 6. Always return array (never \"*\")\n *\n * @param selects - Array of select clauses from multiple .select() calls\n * @param schema - Schema definition for validation\n * @param modelName - Model name for error messages and cache lookup\n * @param registry - Schema registry for wildcard expansion\n * @returns Normalized, validated field array with reserved fields\n *\n * @example\n * ```ts\n * // Multiple selects\n * normalizeSelect([['name'], ['price'], ['name']], schema, 'Product', registry)\n * // → ['name', 'price', 'id', 'createdAt', 'updatedAt']\n *\n * // Wildcard expansion\n * normalizeSelect([['name'], '*'], schema, 'Product', registry)\n * // → ['id', 'name', 'price', 'stock', 'createdAt', 'updatedAt'] (from cache)\n *\n * // Validation errors\n * normalizeSelect([['invalidField']], schema, 'Product', registry)\n * // → throws DatrixQueryBuilderError\n *\n * normalizeSelect([['category']], schema, 'Product', registry)\n * // → throws DatrixQueryBuilderError (relation field)\n * ```\n */\nexport function normalizeSelect<T extends DatrixEntry>(\n\tselects: SelectClause<T>[] | undefined,\n\tschema: SchemaDefinition,\n\tregistry: ISchemaRegistry,\n): QuerySelect<T> {\n\t// If no selects provided, return cached fields for \"*\"\n\tif (!selects || selects.length === 0) {\n\t\treturn registry.getCachedSelectFields<T>(schema.name);\n\t}\n\n\t// 1. Flatten and deduplicate using Set (preserves insertion order)\n\tconst allFields = new Set<keyof T>();\n\tfor (const select of selects) {\n\t\tif (Array.isArray(select)) {\n\t\t\tselect.forEach((field) => allFields.add(field));\n\t\t}\n\t}\n\n\tconst fieldArray = Array.from(allFields);\n\n\t// 2. Validate fields (BEFORE wildcard check)\n\t// This ensures invalid fields are caught even if wildcard is present\n\tconst invalidFields: string[] = [];\n\tconst relationFields: string[] = [];\n\n\tfor (const fieldName of fieldArray) {\n\t\tconst field = schema.fields[fieldName as string];\n\n\t\t// Field doesn't exist in schema\n\t\tif (!field) {\n\t\t\tinvalidFields.push(fieldName as string);\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Field is a relation type\n\t\tif (field.type === \"relation\") {\n\t\t\trelationFields.push(fieldName as string);\n\t\t}\n\t}\n\n\t// Throw if validation failed\n\tif (invalidFields.length > 0) {\n\t\tconst availableFields = Object.keys(schema.fields).filter(\n\t\t\t(name) => schema.fields[name]?.type !== \"relation\",\n\t\t);\n\t\tthrowInvalidFields(\"select\", invalidFields, availableFields);\n\t}\n\n\tif (relationFields.length > 0) {\n\t\tthrowRelationInSelect(relationFields, schema.name);\n\t}\n\n\t// 3. Check for wildcard AFTER validation\n\t// If any select is \"*\", return cached fields\n\tif (selects.some((s) => s === \"*\")) {\n\t\treturn registry.getCachedSelectFields<T>(schema.name);\n\t}\n\n\t// 4. Add reserved fields\n\tallFields.add(\"id\" as keyof T);\n\tallFields.add(\"createdAt\" as keyof T);\n\tallFields.add(\"updatedAt\" as keyof T);\n\n\treturn Array.from(allFields) as QuerySelect<T>;\n}\n","/**\n * POPULATE Utilities\n *\n * All POPULATE-related operations: normalization, validation.\n * Handles relation loading, nested populates, dot notation, wildcard expansion.\n */\n\nimport type {\n\tPopulateClause,\n\tPopulateOptions,\n\tQueryPopulate,\n} from \"../types/core/query-builder\";\nimport type {\n\tDatrixEntry,\n\tRelationField,\n\tSchemaDefinition,\n\tISchemaRegistry,\n} from \"../types/core/schema\";\nimport { throwInvalidField, throwInvalidValue } from \"./error-helper\";\nimport { normalizeSelect } from \"./select\";\n\n/**\n * Maximum nesting depth for populate clauses to prevent stack overflow\n */\nconst MAX_POPULATE_DEPTH = 5;\n\n/**\n * Normalize and validate POPULATE clause\n *\n * Complete POPULATE processing pipeline:\n * 1. Handle wildcard '*' → expand to all relations\n * 2. Handle dot notation array → convert to nested object\n * 3. Handle object format → validate and normalize\n * 4. Recursively process nested populates\n * 5. Validate relation fields exist\n * 6. Check max depth limit\n *\n * @param populate - Raw POPULATE clause from user\n * @param modelName - Model name\n * @param registry - Schema registry for field expansion and validation\n * @returns Normalized POPULATE clause\n * @throws {Error} If validation fails\n *\n * @example\n * ```ts\n * // Wildcard or true - all relations (both are equivalent)\n * normalizePopulate('*', 'Post', registry)\n * normalizePopulate(true, 'Post', registry)\n * // → { author: { select: [...] }, category: { select: [...] } }\n *\n * // Dot notation array\n * normalizePopulate(['category', 'author.company'], 'Post', registry)\n * // → {\n * // category: { select: [...] },\n * // author: { populate: { company: { select: [...] } } }\n * // }\n *\n * // Object notation with true or '*' (both are equivalent)\n * normalizePopulate({ author: true }, 'Post', registry)\n * normalizePopulate({ author: '*' }, 'Post', registry)\n * // → { author: { select: ['id', 'name', ...] } }\n *\n * // Validation errors\n * normalizePopulate({ invalidField: true }, 'Post', registry)\n * // → throws Error: Field 'invalidField' does not exist\n *\n * normalizePopulate({ title: true }, 'Post', registry)\n * // → throws Error: Cannot populate non-relation field 'title'\n * ```\n */\nexport function normalizePopulate<T extends DatrixEntry>(\n\tpopulate: PopulateClause<T> | undefined,\n\tmodelName: string,\n\tregistry: ISchemaRegistry,\n\tdepth = 0,\n): PopulateClause<T> | undefined {\n\tif (!populate) {\n\t\treturn undefined;\n\t}\n\n\tif (depth > MAX_POPULATE_DEPTH) {\n\t\tthrowInvalidValue(\n\t\t\t\"populate\",\n\t\t\tmodelName,\n\t\t\tdepth,\n\t\t\t`maximum nesting depth of ${MAX_POPULATE_DEPTH}`,\n\t\t);\n\t}\n\n\tconst schema = registry.get(modelName);\n\tif (!schema) {\n\t\tthrowInvalidValue(\"populate\", \"modelName\", modelName, \"valid model name\");\n\t}\n\n\t// Handle wildcard '*' or true - populate all first-level relations\n\tif (populate === \"*\" || populate === true) {\n\t\tconst allRelations: Record<string, object> = {};\n\t\tfor (const [fieldName, field] of Object.entries(schema.fields)) {\n\t\t\tif (field.type === \"relation\") {\n\t\t\t\tconst relationField = field as RelationField;\n\t\t\t\tallRelations[fieldName] = {\n\t\t\t\t\tselect: registry.getCachedSelectFields(relationField.model),\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t\treturn allRelations as PopulateClause<T>;\n\t}\n\n\t// Handle array format - dot notation ['category', 'author.company']\n\tif (Array.isArray(populate)) {\n\t\treturn normalizePopulateDotNotation(populate, schema, modelName, registry);\n\t}\n\n\t// Handle object format\n\tconst result: Record<string, object> = {};\n\n\tfor (const [relationName, value] of Object.entries(populate)) {\n\t\tconst field = schema.fields[relationName];\n\n\t\t// Field doesn't exist - throw error (typo detection)\n\t\tif (!field) {\n\t\t\tconst availableRelations = Object.entries(schema.fields)\n\t\t\t\t.filter(([_, f]) => f.type === \"relation\")\n\t\t\t\t.map(([name]) => name);\n\n\t\t\tthrowInvalidField(\"populate\", relationName, availableRelations);\n\t\t}\n\n\t\t// Field exists but is not a relation - throw error\n\t\tif (field.type !== \"relation\") {\n\t\t\tthrowInvalidValue(\"populate\", relationName, field.type, \"relation\");\n\t\t}\n\n\t\tconst relationField = field as RelationField;\n\t\tconst targetModel = relationField.model;\n\n\t\tif (typeof value === \"boolean\" || value === \"*\") {\n\t\t\t// populate[category]=true or populate[category]='*' → convert to { select: [...] }\n\t\t\tresult[relationName] = {\n\t\t\t\tselect: registry.getCachedSelectFields(targetModel),\n\t\t\t};\n\t\t} else if (typeof value === \"object\" && value !== null) {\n\t\t\t// populate[category]={ select: [...], populate: {...} }\n\t\t\tresult[relationName] = {\n\t\t\t\t...value,\n\t\t\t\t// Normalize select for this level (if provided)\n\t\t\t\tselect: normalizeSelect(\n\t\t\t\t\tvalue.select !== undefined ? [value.select] : undefined,\n\t\t\t\t\tregistry.get(targetModel)!,\n\t\t\t\t\tregistry,\n\t\t\t\t),\n\t\t\t\t// Recursively process nested populate\n\t\t\t\tpopulate: value.populate\n\t\t\t\t\t? normalizePopulate(value.populate, targetModel, registry, depth + 1)\n\t\t\t\t\t: undefined,\n\t\t\t};\n\t\t} else {\n\t\t\tthrowInvalidValue(\n\t\t\t\t\"populate\",\n\t\t\t\trelationName,\n\t\t\t\tvalue,\n\t\t\t\t\"boolean | object | '*'\",\n\t\t\t);\n\t\t}\n\t}\n\n\treturn result as PopulateClause<T>;\n}\n\n/**\n * Normalize array-based populate with dot notation\n *\n * Internal helper for normalizePopulate.\n * Converts ['category', 'author.company', 'author.posts'] to nested object format.\n *\n * @param paths - Array of relation paths (dot notation)\n * @param schema - Current schema\n * @param modelName - Model name for error messages\n * @param registry - Schema registry\n * @returns Normalized populate object\n */\nfunction normalizePopulateDotNotation<T extends DatrixEntry>(\n\tpaths: readonly string[],\n\tschema: SchemaDefinition,\n\t_modelName: string,\n\tregistry: ISchemaRegistry,\n): PopulateClause<T> {\n\tconst result: Record<string, any> = {};\n\n\tfor (const path of paths) {\n\t\tconst parts = path.split(\".\");\n\t\tconst firstPart = parts[0]!;\n\n\t\t// Validate that first part is a relation field\n\t\tconst field = schema.fields[firstPart];\n\n\t\t// Field doesn't exist\n\t\tif (!field) {\n\t\t\tconst availableRelations = Object.entries(schema.fields)\n\t\t\t\t.filter(([_, f]) => f.type === \"relation\")\n\t\t\t\t.map(([name]) => name);\n\n\t\t\tthrowInvalidField(\"populate\", firstPart, availableRelations);\n\t\t}\n\n\t\t// Field exists but is not a relation\n\t\tif (field.type !== \"relation\") {\n\t\t\tthrowInvalidValue(\"populate\", firstPart, field.type, \"relation\");\n\t\t}\n\n\t\tconst relationField = field as RelationField;\n\t\tconst targetModel = relationField.model;\n\n\t\tif (parts.length === 1) {\n\t\t\t// Simple path: 'category' → { category: { select: [...] } }\n\t\t\tresult[firstPart] = {\n\t\t\t\tselect: registry.getCachedSelectFields(targetModel),\n\t\t\t};\n\t\t} else {\n\t\t\t// Nested path: 'author.company' → { author: { populate: { company: { select: [...] } } } }\n\t\t\tconst nestedPath = parts.slice(1).join(\".\");\n\n\t\t\tif (!result[firstPart]) {\n\t\t\t\tresult[firstPart] = {\n\t\t\t\t\tselect: registry.getCachedSelectFields(targetModel),\n\t\t\t\t\tpopulate: {},\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tif (!result[firstPart].populate) {\n\t\t\t\tresult[firstPart].populate = {};\n\t\t\t}\n\n\t\t\t// Recursively normalize the nested path\n\t\t\tconst targetSchema = registry.get(targetModel);\n\t\t\tif (targetSchema) {\n\t\t\t\tconst nested = normalizePopulateDotNotation(\n\t\t\t\t\t[nestedPath],\n\t\t\t\t\ttargetSchema,\n\t\t\t\t\ttargetModel,\n\t\t\t\t\tregistry,\n\t\t\t\t);\n\t\t\t\t// Merge nested populate\n\t\t\t\tObject.assign(result[firstPart].populate, nested);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn result;\n}\n\n/**\n * Normalize and merge POPULATE arrays\n *\n * Complete POPULATE processing pipeline for multiple .populate() calls:\n * 1. Normalize each populate clause (expand wildcards, validate, etc.)\n * 2. Merge all normalized results\n *\n * @param populates - Array of populate clauses from multiple .populate() calls\n * @param modelName - Model name for validation and normalization\n * @param registry - Schema registry\n * @returns Final normalized and merged populate clause\n *\n * @example\n * ```ts\n * // Multiple populate calls accumulated in array\n * const populates = [\n * { author: true },\n * { category: { select: ['name'] } }\n * ];\n *\n * const normalized = normalizePopulateArray(populates, 'Post', registry);\n * // → { author: { select: [...] }, category: { select: ['name'] } }\n * ```\n */\nexport function normalizePopulateArray<T extends DatrixEntry>(\n\tpopulates: PopulateClause<T>[] | undefined,\n\tmodelName: string,\n\tregistry: ISchemaRegistry,\n): QueryPopulate<T> | undefined {\n\tif (!populates || populates.length === 0) {\n\t\treturn undefined;\n\t}\n\n\t// Normalize each populate clause\n\tconst normalized: PopulateClause<T>[] = [];\n\tfor (const populate of populates) {\n\t\tconst result = normalizePopulate(populate, modelName, registry);\n\t\tif (result) {\n\t\t\tnormalized.push(result);\n\t\t}\n\t}\n\n\t// Merge all normalized populates\n\tif (normalized.length === 0) {\n\t\treturn undefined;\n\t}\n\n\treturn mergePopulateClauses(...normalized) as QueryPopulate<T>;\n}\n\n/**\n * Merge populate clauses\n *\n * Used internally by normalizePopulateArray when merging multiple .populate() calls.\n */\nexport function mergePopulateClauses<T extends DatrixEntry>(\n\t...clauses: readonly (PopulateClause<T> | undefined)[]\n): QueryPopulate<T> {\n\tconst merged: Record<string, PopulateOptions<T> | \"*\" | true> = {};\n\n\tfor (const clause of clauses) {\n\t\tif (!clause) continue;\n\n\t\tfor (const [relation, options] of Object.entries(clause)) {\n\t\t\t// If either is '*' or true, use it\n\t\t\tif (\n\t\t\t\toptions === \"*\" ||\n\t\t\t\toptions === true ||\n\t\t\t\tmerged[relation] === \"*\" ||\n\t\t\t\tmerged[relation] === true\n\t\t\t) {\n\t\t\t\tmerged[relation] = options === true ? true : \"*\";\n\t\t\t} else if (merged[relation]) {\n\t\t\t\t// Merge options (both are objects)\n\t\t\t\tconst existing = merged[relation] as PopulateOptions<T>;\n\t\t\t\tconst newOptions = options as PopulateOptions<T>;\n\t\t\t\tconst mergedOptions = {\n\t\t\t\t\t...(newOptions.select !== undefined || existing.select !== undefined\n\t\t\t\t\t\t? { select: newOptions.select || existing.select }\n\t\t\t\t\t\t: {}),\n\t\t\t\t\t...(newOptions.where !== undefined || existing.where !== undefined\n\t\t\t\t\t\t? { where: newOptions.where || existing.where }\n\t\t\t\t\t\t: {}),\n\t\t\t\t\t...(newOptions.populate !== undefined ||\n\t\t\t\t\t\texisting.populate !== undefined\n\t\t\t\t\t\t? {\n\t\t\t\t\t\t\tpopulate: newOptions.populate\n\t\t\t\t\t\t\t\t? mergePopulateClauses(existing.populate, newOptions.populate)\n\t\t\t\t\t\t\t\t: existing.populate,\n\t\t\t\t\t\t}\n\t\t\t\t\t\t: {}),\n\t\t\t\t\t...(newOptions.limit !== undefined || existing.limit !== undefined\n\t\t\t\t\t\t? { limit: newOptions.limit ?? existing.limit }\n\t\t\t\t\t\t: {}),\n\t\t\t\t\t...(newOptions.offset !== undefined || existing.offset !== undefined\n\t\t\t\t\t\t? { offset: newOptions.offset ?? existing.offset }\n\t\t\t\t\t\t: {}),\n\t\t\t\t\t...(newOptions.orderBy !== undefined || existing.orderBy !== undefined\n\t\t\t\t\t\t? { orderBy: newOptions.orderBy || existing.orderBy }\n\t\t\t\t\t\t: {}),\n\t\t\t\t};\n\t\t\t\tmerged[relation] = mergedOptions as PopulateOptions<T>;\n\t\t\t} else {\n\t\t\t\tmerged[relation] = options;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn merged as QueryPopulate<T>;\n}\n","/**\n * Data Normalization and Splitting for Query Builder\n *\n * This module handles:\n * 1. Single-pass field separation (scalars vs relations)\n * 2. Field existence validation\n * 3. Relation shortcut normalization (5 → { connect: [{ id: 5 }] })\n * 4. Foreign key inlining (belongsTo/hasOne)\n * 5. Recursive create/update normalization (with depth limit)\n *\n * These functions are used in QueryBuilder.build() to process INSERT/UPDATE data.\n */\n\nimport {\n\tSchemaDefinition,\n\tRelationField,\n\tDatrixEntry,\n\tISchemaRegistry,\n\tAnyRelationInputObject,\n} from \"../types/core/schema\";\nimport type {\n\tNormalizedNestedData,\n\tNormalizedRelationOperations,\n\tNormalizedRelationUpdate,\n\tQueryRelations,\n} from \"../types/core/query-builder\";\nimport { throwInvalidField, throwInvalidValue } from \"./error-helper\";\n\n/**\n * Maximum depth for nested create/update operations\n * Prevents infinite recursion and stack overflow\n */\nconst MAX_NESTED_DEPTH = 5;\n\n/**\n * Check if value is a RelationInput object (has connect/disconnect/set/etc)\n * vs a raw ID reference\n *\n * @param value - Value to check\n * @returns True if value is a RelationInput object\n *\n * @example\n * ```ts\n * isRelationInputObject({ connect: { id: 5 } }) // true\n * isRelationInputObject({ id: 5 }) // false (raw ref)\n * isRelationInputObject(5) // false\n * ```\n */\nfunction isRelationInputObject(value: unknown): boolean {\n\tif (typeof value !== \"object\" || value === null) {\n\t\treturn false;\n\t}\n\t// If it has 'id' property directly, it's a raw { id } ref, not RelationInput\n\tif (\"id\" in value && !(\"connect\" in value || \"set\" in value)) {\n\t\treturn false;\n\t}\n\t// Check for RelationInput keys\n\treturn (\n\t\t\"connect\" in value ||\n\t\t\"disconnect\" in value ||\n\t\t\"set\" in value ||\n\t\t\"create\" in value ||\n\t\t\"update\" in value ||\n\t\t\"delete\" in value\n\t);\n}\n\n/**\n * Extract IDs from various formats and convert to number array\n *\n * @param value - Input value (number, {id}, array of numbers/objects)\n * @returns Array of numbers\n *\n * @example\n * ```ts\n * extractIds(5) // [5]\n * extractIds([1, 2, 3]) // [1, 2, 3]\n * extractIds([{id: 1}, {id: 2}]) // [1, 2]\n * extractIds({id: 5}) // [5]\n * ```\n */\nfunction extractIds(value: unknown): number[] {\n\t// Single number\n\tif (typeof value === \"number\") {\n\t\treturn [value];\n\t}\n\n\t// Single string (convert to number)\n\tif (typeof value === \"string\") {\n\t\treturn [Number(value)];\n\t}\n\n\t// Single object with id\n\tif (typeof value === \"object\" && value !== null && \"id\" in value) {\n\t\tconst id = (value as { id: string | number }).id;\n\t\treturn [typeof id === \"number\" ? id : Number(id)];\n\t}\n\n\t// Array\n\tif (Array.isArray(value)) {\n\t\treturn value.map((item) => {\n\t\t\tif (typeof item === \"number\") {\n\t\t\t\treturn item;\n\t\t\t}\n\t\t\tif (typeof item === \"string\") {\n\t\t\t\treturn Number(item);\n\t\t\t}\n\t\t\tif (typeof item === \"object\" && item !== null && \"id\" in item) {\n\t\t\t\tconst id = (item as { id: string | number }).id;\n\t\t\t\treturn typeof id === \"number\" ? id : Number(id);\n\t\t\t}\n\t\t\treturn 0; // Fallback\n\t\t});\n\t}\n\n\treturn [];\n}\n\n/**\n * Process data for INSERT/UPDATE operations\n *\n * Single-pass optimized algorithm:\n * 1. Loop through data keys once\n * 2. Accumulate: scalars, relations, invalid fields\n * 3. Throw if any invalid fields found\n * 4. Normalize relations (shortcuts → RelationInput with number arrays)\n * 5. Recursively process create/update operations (with depth limit)\n * 6. Inline belongsTo/hasOne foreign keys into scalars\n * 7. Return separated data\n *\n * @param data - Raw data from user\n * @param schema - Schema definition\n * @param modelName - Model name (for error messages)\n * @param registry - Schema registry (for recursive processing of create/update)\n * @param depth - Current recursion depth (internal, default 0)\n * @returns Processed data with separated scalars and relations\n *\n * @example\n * ```ts\n * const result = processData(\n * { name: 'Post 1', author: 5, tags: [1, 2, 3], invalidField: 'x' },\n * postSchema,\n * 'Post',\n * registry\n * );\n * // Throws: Invalid field 'invalidField' in data clause\n *\n * const result2 = processData(\n * { name: 'Post 1', author: 5, tags: [1, 2, 3] },\n * postSchema,\n * 'Post',\n * registry\n * );\n * // Result:\n * // {\n * // data: { name: 'Post 1', authorId: 5 },\n * // relations: { tags: { set: [1, 2, 3] } }\n * // }\n *\n * const result3 = processData(\n * {\n * name: 'Post 1',\n * author: {\n * create: { name: 'John', company: { create: { name: 'Acme' } } }\n * }\n * },\n * postSchema,\n * 'Post',\n * registry\n * );\n * // Result (recursive processing):\n * // {\n * // data: { name: 'Post 1' },\n * // relations: {\n * // author: {\n * // create: {\n * // data: { name: 'John' },\n * // relations: {\n * // company: {\n * // create: { data: { name: 'Acme' }, relations: undefined }\n * // }\n * // }\n * // }\n * // }\n * // }\n * // }\n * ```\n */\nexport function processData<T extends DatrixEntry>(\n\tdata: Partial<T>,\n\tschema: SchemaDefinition,\n\tregistry: ISchemaRegistry,\n\tdepth: number = 0,\n\tvisitedModels: ReadonlySet<string> = new Set(),\n): NormalizedNestedData<T> {\n\t// Check max depth\n\tif (depth > MAX_NESTED_DEPTH) {\n\t\tthrowInvalidValue(\n\t\t\t\"data\",\n\t\t\t\"nested depth\",\n\t\t\tdepth,\n\t\t\t`maximum ${MAX_NESTED_DEPTH} levels of nesting`,\n\t\t);\n\t}\n\n\t// Check redundant nested creation (e.g. Author → Post → Author)\n\tif (visitedModels.has(schema.name)) {\n\t\tthrowInvalidValue(\n\t\t\t\"data\",\n\t\t\t\"redundant nested create/update\",\n\t\t\t`${[...visitedModels, schema.name].join(\" → \")}`,\n\t\t\t`use 'connect' instead of nesting back to '${schema.name}' — creating the same model in a nested chain is redundant`,\n\t\t);\n\t}\n\tconst scalars: Record<string, unknown> = {};\n\tconst rawRelations: Record<string, unknown> = {};\n\tconst invalidFields: string[] = [];\n\n\t// STEP 1: Single-pass separation (scalars vs relations) + collect invalid fields\n\tfor (const [key, value] of Object.entries(data)) {\n\t\tconst field = schema.fields[key];\n\n\t\t// Unknown field\n\t\tif (!field) {\n\t\t\tinvalidFields.push(key);\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Relation field\n\t\tif (field.type === \"relation\") {\n\t\t\trawRelations[key] = value;\n\t\t} else {\n\t\t\t// Scalar field\n\t\t\tscalars[key] = value;\n\t\t}\n\t}\n\n\t// STEP 2: Throw if any invalid fields found\n\tif (invalidFields.length > 0) {\n\t\tconst availableFields = Object.keys(schema.fields);\n\t\tthrowInvalidField(\"data\", invalidFields[0]!, availableFields);\n\t}\n\n\t// STEP 3: Normalize relations and inline foreign keys\n\tconst normalizedRelations: Record<\n\t\tstring,\n\t\tNormalizedRelationOperations<T>\n\t> = {};\n\n\tfor (const [key, value] of Object.entries(rawRelations)) {\n\t\tconst field = schema.fields[key] as RelationField;\n\n\t\t// Normalize relation shortcuts to NormalizedRelationOperations\n\t\tlet normalized: NormalizedRelationOperations<T>;\n\n\t\t// Case 0: null value - clear/disconnect relation\n\t\tif (value === null) {\n\t\t\tif (field.kind === \"belongsTo\") {\n\t\t\t\t// belongsTo: FK is on owner, disconnect triggers inlining FK = null\n\t\t\t\tnormalized = { disconnect: [] };\n\t\t\t} else if (field.kind === \"hasOne\") {\n\t\t\t\t// hasOne: FK is on target, use set: [] to clear the relation\n\t\t\t\tnormalized = { set: [] };\n\t\t\t} else {\n\t\t\t\t// hasMany/manyToMany: null is not allowed (prevent accidental mass deletion)\n\t\t\t\tthrowInvalidValue(\n\t\t\t\t\t\"data\",\n\t\t\t\t\t`relation ${key}`,\n\t\t\t\t\t\"null\",\n\t\t\t\t\t\"`[]` or `{ set: [] }` to clear all relations\",\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\t// Case 1: Direct ID shortcut (category: 5)\n\t\telse if (typeof value === \"number\" || typeof value === \"string\") {\n\t\t\tnormalized = { set: extractIds(value) };\n\t\t}\n\t\t// Case 2: Array shortcut (tags: [1, 2, 3] or [{id: 1}, {id: 2}])\n\t\telse if (Array.isArray(value)) {\n\t\t\tconst isRawIdArray =\n\t\t\t\tvalue.length === 0 || !isRelationInputObject(value[0]);\n\t\t\tif (isRawIdArray) {\n\t\t\t\tnormalized = { set: extractIds(value) };\n\t\t\t} else {\n\t\t\t\t// Already RelationInput array, needs processing\n\t\t\t\tnormalized = {};\n\t\t\t}\n\t\t}\n\t\t// Case 3: RelationInput object - normalize each operation to number arrays\n\t\telse if (typeof value === \"object\") {\n\t\t\tconst relInput = value as AnyRelationInputObject;\n\t\t\tnormalized = {};\n\n\t\t\t// Normalize connect to number array\n\t\t\tif (relInput.connect !== undefined) {\n\t\t\t\tnormalized = { ...normalized, connect: extractIds(relInput.connect) };\n\t\t\t}\n\n\t\t\t// Normalize disconnect to number array\n\t\t\t// Special case: disconnect: true for hasOne/belongsTo means \"clear this relation\"\n\t\t\tif (relInput.disconnect !== undefined) {\n\t\t\t\tif (relInput.disconnect === true) {\n\t\t\t\t\tif (field.kind === \"hasOne\") {\n\t\t\t\t\t\tnormalized = { ...normalized, set: [] };\n\t\t\t\t\t} else {\n\t\t\t\t\t\tnormalized = { ...normalized, disconnect: [] };\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tnormalized = {\n\t\t\t\t\t\t...normalized,\n\t\t\t\t\t\tdisconnect: extractIds(relInput.disconnect),\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Normalize set to number array\n\t\t\tif (relInput.set !== undefined) {\n\t\t\t\tnormalized = { ...normalized, set: extractIds(relInput.set) };\n\t\t\t}\n\n\t\t\t// Normalize delete to number array\n\t\t\tif (relInput.delete !== undefined) {\n\t\t\t\tnormalized = { ...normalized, delete: extractIds(relInput.delete) };\n\t\t\t}\n\n\t\t\t// Recursively process create operations\n\t\t\tif (relInput.create !== undefined) {\n\t\t\t\tconst targetSchema = registry.get(field.model);\n\t\t\t\tif (!targetSchema) {\n\t\t\t\t\tthrowInvalidValue(\n\t\t\t\t\t\t\"data\",\n\t\t\t\t\t\t`relation ${key}`,\n\t\t\t\t\t\tfield.model,\n\t\t\t\t\t\t\"valid model\",\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tconst nextVisited = new Set([...visitedModels, schema.name]);\n\n\t\t\t\t// Handle array of creates\n\t\t\t\tif (Array.isArray(relInput.create)) {\n\t\t\t\t\tnormalized = {\n\t\t\t\t\t\t...normalized,\n\t\t\t\t\t\tcreate: relInput.create.map((item) =>\n\t\t\t\t\t\t\tprocessData<T>(\n\t\t\t\t\t\t\t\titem as Partial<T>,\n\t\t\t\t\t\t\t\ttargetSchema,\n\t\t\t\t\t\t\t\tregistry,\n\t\t\t\t\t\t\t\tdepth + 1,\n\t\t\t\t\t\t\t\tnextVisited,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t),\n\t\t\t\t\t};\n\t\t\t\t} else {\n\t\t\t\t\t// Single create\n\t\t\t\t\tnormalized = {\n\t\t\t\t\t\t...normalized,\n\t\t\t\t\t\tcreate: [\n\t\t\t\t\t\t\tprocessData(\n\t\t\t\t\t\t\t\trelInput.create as Partial<T>,\n\t\t\t\t\t\t\t\ttargetSchema,\n\t\t\t\t\t\t\t\tregistry,\n\t\t\t\t\t\t\t\tdepth + 1,\n\t\t\t\t\t\t\t\tnextVisited,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t],\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Recursively process update operations\n\t\t\tif (relInput.update !== undefined) {\n\t\t\t\tconst targetSchema = registry.get(field.model);\n\t\t\t\tif (!targetSchema) {\n\t\t\t\t\tthrowInvalidValue(\n\t\t\t\t\t\t\"data\",\n\t\t\t\t\t\t`relation ${key}`,\n\t\t\t\t\t\tfield.model,\n\t\t\t\t\t\t\"valid model\",\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tconst nextVisited = new Set([...visitedModels, schema.name]);\n\n\t\t\t\t// Handle array of updates\n\t\t\t\tif (Array.isArray(relInput.update)) {\n\t\t\t\t\tnormalized = {\n\t\t\t\t\t\t...normalized,\n\t\t\t\t\t\tupdate: relInput.update.map((item) => {\n\t\t\t\t\t\t\tconst whereClause = item.where;\n\t\t\t\t\t\t\tconst updateData = item.data as Partial<T>;\n\t\t\t\t\t\t\tconst processed = processData<T>(\n\t\t\t\t\t\t\t\tupdateData,\n\t\t\t\t\t\t\t\ttargetSchema,\n\t\t\t\t\t\t\t\tregistry,\n\t\t\t\t\t\t\t\tdepth + 1,\n\t\t\t\t\t\t\t\tnextVisited,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\twhere: whereClause,\n\t\t\t\t\t\t\t\t...processed,\n\t\t\t\t\t\t\t} satisfies NormalizedRelationUpdate<T>;\n\t\t\t\t\t\t}),\n\t\t\t\t\t};\n\t\t\t\t} else {\n\t\t\t\t\t// Single update\n\t\t\t\t\tconst whereClause = relInput.update.where;\n\t\t\t\t\tconst updateData = relInput.update.data as Partial<T>;\n\t\t\t\t\tconst processed = processData<T>(\n\t\t\t\t\t\tupdateData,\n\t\t\t\t\t\ttargetSchema,\n\t\t\t\t\t\tregistry,\n\t\t\t\t\t\tdepth + 1,\n\t\t\t\t\t\tnextVisited,\n\t\t\t\t\t);\n\t\t\t\t\tnormalized = {\n\t\t\t\t\t\t...normalized,\n\t\t\t\t\t\tupdate: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\twhere: whereClause,\n\t\t\t\t\t\t\t\t...processed,\n\t\t\t\t\t\t\t} satisfies NormalizedRelationUpdate<T>,\n\t\t\t\t\t\t],\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\t// Fallback (shouldn't happen)\n\t\t\tnormalized = {};\n\t\t}\n\n\t\t// Inline foreign keys for belongsTo only\n\t\t// hasOne FK is on TARGET table, not on owner - cannot inline into owner's scalars\n\t\tif (field.kind === \"belongsTo\") {\n\t\t\t// Singular relations can only reference one record total\n\t\t\tconst totalRefs =\n\t\t\t\t(normalized.connect?.length ?? 0) +\n\t\t\t\t(normalized.set?.length ?? 0) +\n\t\t\t\t(normalized.create?.length ?? 0);\n\n\t\t\tif (totalRefs > 1) {\n\t\t\t\tthrowInvalidValue(\n\t\t\t\t\t\"data\",\n\t\t\t\t\t`relation ${key} (${field.kind})`,\n\t\t\t\t\t`${totalRefs} references`,\n\t\t\t\t\t\"a single reference — belongsTo can only reference one record\",\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst foreignKey = field.foreignKey!;\n\t\t\tlet inlinedId: number | null | undefined = undefined;\n\n\t\t\tif (normalized.connect) {\n\t\t\t\tconst ids = normalized.connect;\n\t\t\t\tinlinedId = ids[0] ?? null;\n\t\t\t} else if (normalized.set) {\n\t\t\t\tconst ids = normalized.set;\n\t\t\t\tinlinedId = ids[0] ?? null;\n\t\t\t} else if (normalized.disconnect) {\n\t\t\t\tinlinedId = null;\n\t\t\t}\n\n\t\t\tif (inlinedId !== undefined) {\n\t\t\t\t// Inline FK into scalars\n\t\t\t\tscalars[foreignKey] = inlinedId;\n\n\t\t\t\t// Keep in relations only if there are other operations (create/update/delete)\n\t\t\t\tconst hasOtherOps =\n\t\t\t\t\tnormalized.create || normalized.update || normalized.delete;\n\t\t\t\tif (hasOtherOps) {\n\t\t\t\t\tnormalizedRelations[key] = normalized;\n\t\t\t\t}\n\t\t\t\t// Otherwise, skip (FK already inlined, no async work needed)\n\t\t\t} else {\n\t\t\t\t// Cannot inline (e.g., only create/update/delete), keep as async relation\n\t\t\t\tnormalizedRelations[key] = normalized;\n\t\t\t}\n\t\t} else if (field.kind === \"hasOne\") {\n\t\t\t// hasOne: FK is on TARGET table\n\t\t\t// User cannot directly set the relation by passing ID to owner\n\t\t\t// Instead, target record must be created/updated with owner's ID\n\t\t\t// Keep as async relation for create/update operations\n\t\t\tnormalizedRelations[key] = normalized;\n\t\t} else {\n\t\t\t// hasMany or manyToMany - cannot inline, always async\n\t\t\tnormalizedRelations[key] = normalized;\n\t\t}\n\t}\n\n\treturn {\n\t\tdata: scalars as Partial<T>,\n\t\trelations:\n\t\t\tObject.keys(normalizedRelations).length > 0\n\t\t\t\t? (normalizedRelations as unknown as QueryRelations<T>)\n\t\t\t\t: undefined,\n\t};\n}\n","/**\n * OrderBy Normalizer\n *\n * Converts OrderByClause input formats to normalized QueryOrderBy.\n *\n * Supported input formats:\n * 1. Full format: [{ field: \"age\", direction: \"asc\", nulls: \"last\" }]\n * 2. Object shortcut: { age: \"asc\" }\n * 3. String array: [\"age\", \"-name\"] (- prefix = desc)\n */\n\nimport type {\n\tOrderByClause,\n\tQueryOrderBy,\n\tOrderByItem,\n\tOrderDirection,\n} from \"../types/core/query-builder\";\nimport type { DatrixEntry } from \"../types/core/schema\";\n\n/**\n * Check if input is already normalized (array of OrderByItem)\n */\nfunction isQueryOrderBy(input: unknown): boolean {\n\tif (!Array.isArray(input)) return false;\n\tif (input.length === 0) return true;\n\n\tconst first = input[0];\n\treturn (\n\t\ttypeof first === \"object\" &&\n\t\tfirst !== null &&\n\t\t\"field\" in first &&\n\t\t\"direction\" in first\n\t);\n}\n\n/**\n * Check if input is object shortcut format\n * { age: \"asc\", name: \"desc\" }\n */\nfunction isObjectShortcut(input: unknown): boolean {\n\tif (Array.isArray(input)) return false;\n\tif (typeof input !== \"object\" || input === null) return false;\n\n\tconst values = Object.values(input);\n\treturn values.every((v) => v === \"asc\" || v === \"desc\");\n}\n\n/**\n * Check if input is string array format\n * [\"age\", \"-name\"]\n */\nfunction isStringArray(input: unknown): boolean {\n\tif (!Array.isArray(input)) return false;\n\tif (input.length === 0) return false;\n\n\treturn input.every((item) => typeof item === \"string\");\n}\n\n/**\n * Normalize OrderByClause to QueryOrderBy\n *\n * @param input - OrderByClause in any supported format\n * @returns Normalized QueryOrderBy array\n *\n * @example\n * ```ts\n * // Full format (passthrough)\n * normalizeOrderBy([{ field: \"age\", direction: \"asc\" }])\n * // → [{ field: \"age\", direction: \"asc\" }]\n *\n * // Object shortcut\n * normalizeOrderBy({ age: \"asc\" })\n * // → [{ field: \"age\", direction: \"asc\" }]\n *\n * // String array\n * normalizeOrderBy([\"age\", \"-name\"])\n * // → [{ field: \"age\", direction: \"asc\" }, { field: \"name\", direction: \"desc\" }]\n * ```\n */\nexport function normalizeOrderBy<T extends DatrixEntry>(\n\tinput: OrderByClause<T> | undefined,\n): QueryOrderBy<T> | undefined {\n\tif (input === undefined || input === null) {\n\t\treturn undefined;\n\t}\n\n\t// Already normalized\n\tif (isQueryOrderBy(input)) {\n\t\treturn input as QueryOrderBy<T>;\n\t}\n\n\t// Object shortcut: { age: \"asc\" }\n\tif (isObjectShortcut(input)) {\n\t\tconst result: OrderByItem<T>[] = [];\n\t\tfor (const [field, direction] of Object.entries(input)) {\n\t\t\tresult.push({\n\t\t\t\tfield: field as keyof T,\n\t\t\t\tdirection: direction as OrderDirection,\n\t\t\t});\n\t\t}\n\t\treturn result as QueryOrderBy<T>;\n\t}\n\n\t// String array: [\"age\", \"-name\"]\n\tif (isStringArray(input)) {\n\t\treturn (input as string[]).map((item) => {\n\t\t\tconst str = item as string;\n\t\t\tif (str.startsWith(\"-\")) {\n\t\t\t\treturn {\n\t\t\t\t\tfield: str.slice(1) as keyof T,\n\t\t\t\t\tdirection: \"desc\" as OrderDirection,\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tfield: str as keyof T,\n\t\t\t\tdirection: \"asc\" as OrderDirection,\n\t\t\t};\n\t\t}) as QueryOrderBy<T>;\n\t}\n\n\t// Unknown format, return as-is (will fail validation later if invalid)\n\treturn input as QueryOrderBy<T>;\n}\n","/**\n * Query Builder Base Implementation (~150 LOC)\n *\n * Fluent API for building database-agnostic queries.\n * Produces QueryObject instances that adapters translate to SQL/NoSQL.\n */\n\nimport type {\n\tQueryObjectForType,\n\tQueryType,\n\tSelectClause,\n\tWhereClause,\n\tPopulateClause,\n\tOrderByItem,\n\tOrderDirection,\n\tOrderByClause,\n} from \"../types/core/query-builder\";\n\nimport { normalizeWhere } from \"./where\";\nimport { normalizePopulateArray } from \"./populate\";\nimport { normalizeSelect } from \"./select\";\nimport { processData } from \"./data\";\nimport { normalizeOrderBy } from \"./orderby\";\nimport {\n\tthrowSchemaNotFound,\n\tthrowInvalidQueryType,\n\tthrowMissingTable,\n\tthrowMissingData,\n\tthrowDeleteWithoutWhere,\n} from \"./error-helper\";\nimport type {\n\tDatrixEntry,\n\tISchemaRegistry as ISchemaRegistry,\n\tSchemaDefinition,\n} from \"../types/core/schema\";\n\n/**\n * Deep clone an object (safe for JSON-serializable data)\n */\nfunction deepClone<T>(obj: T): T {\n\tif (obj === null || typeof obj !== \"object\") {\n\t\treturn obj;\n\t}\n\n\tif (obj instanceof Date) {\n\t\treturn new Date(obj.getTime()) as T;\n\t}\n\n\tif (obj instanceof RegExp) {\n\t\treturn new RegExp(obj.source, obj.flags) as T;\n\t}\n\n\tif (Array.isArray(obj)) {\n\t\treturn obj.map((item) => deepClone(item)) as T;\n\t}\n\n\tconst cloned: Record<string, unknown> = {};\n\tfor (const key in obj) {\n\t\tif (Object.prototype.hasOwnProperty.call(obj, key)) {\n\t\t\tcloned[key] = deepClone(obj[key]);\n\t\t}\n\t}\n\n\treturn cloned as T;\n}\n\n/**\n * Mutable query state for building\n */\ninterface MutableQueryState<T extends DatrixEntry> {\n\ttype?: QueryType;\n\ttable?: string;\n\tselect?: SelectClause<T>[];\n\twhere?: WhereClause<T>[];\n\tpopulate?: PopulateClause<T>[];\n\torderBy?: OrderByClause<T>;\n\tlimit?: number;\n\toffset?: number;\n\tdata?: Partial<T>;\n\tdataItems?: Partial<T>[];\n\tdistinct?: boolean;\n\tgroupBy?: string[];\n\thaving?: WhereClause<T>;\n}\n\n/**\n * Query builder implementation\n */\nexport class DatrixQueryBuilder<\n\tTSchema extends DatrixEntry,\n\tTType extends QueryType = QueryType,\n> {\n\tprivate query: MutableQueryState<TSchema>;\n\tprivate readonly _modelName: string;\n\tprivate readonly _schema: SchemaDefinition;\n\tprivate readonly _registry: ISchemaRegistry;\n\n\t/**\n\t * Constructor for the query builder\n\t *\n\t * @param modelName - Model name (e.g., 'User', 'Post')\n\t * @param schemaRegistry - Schema registry for normalization and relation resolution\n\t *\n\t * This enables full normalization support:\n\t * - SELECT: \"*\" → expanded to field list, reserved fields added\n\t * - WHERE: relation shortcuts normalized (category: 2 → categoryId: { $eq: 2 })\n\t * - POPULATE: wildcards, dot notation, nested processing, relation traversal\n\t *\n\t * @throws {Error} If schema not found in registry\n\t *\n\t * @example\n\t * ```ts\n\t * const builder = new DatrixQueryBuilder('User', schemaRegistry);\n\t * builder.select('*').where({ role: 'admin' });\n\t * ```\n\t */\n\tconstructor(\n\t\tmodelName: string,\n\t\tschemaRegistry: ISchemaRegistry,\n\t\ttype: TType = \"select\" as TType,\n\t) {\n\t\tthis._modelName = modelName;\n\t\tthis._registry = schemaRegistry;\n\n\t\t// Get schema from registry\n\t\tconst schema = schemaRegistry.get(modelName)!;\n\t\tif (!schema) {\n\t\t\tthrowSchemaNotFound(modelName);\n\t\t}\n\n\t\tthis._schema = schema;\n\t\tthis.query = {\n\t\t\ttable: schema.tableName!,\n\t\t\ttype,\n\t\t};\n\t}\n\n\t/**\n\t * Select fields\n\t */\n\tselect(fields: SelectClause<TSchema>): this {\n\t\tif (this.query.select === undefined) {\n\t\t\tthis.query.select = [fields];\n\t\t} else {\n\t\t\tthis.query.select.push(fields);\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Add WHERE conditions\n\t */\n\twhere(conditions: WhereClause<TSchema>): this {\n\t\tif (this.query.where === undefined) {\n\t\t\tthis.query.where = [conditions];\n\t\t} else {\n\t\t\tthis.query.where.push(conditions);\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Populate relations\n\t *\n\t * Supports multiple formats:\n\t * - .populate('*') - all relations\n\t * - .populate(['author', 'category']) - array\n\t * - .populate({ author: true }) - object\n\t *\n\t * Multiple calls are accumulated and merged in build()\n\t */\n\tpopulate(relations: PopulateClause<TSchema>): this {\n\t\tif (this.query.populate === undefined) {\n\t\t\tthis.query.populate = [relations];\n\t\t} else {\n\t\t\tthis.query.populate.push(relations);\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Order by field(s)\n\t *\n\t * Supports multiple formats:\n\t * - Fluent: .orderBy(\"age\", \"asc\")\n\t * - Full: .orderBy([{ field: \"age\", direction: \"asc\" }])\n\t * - Object: .orderBy({ age: \"asc\" })\n\t * - Array: .orderBy([\"age\", \"-name\"])\n\t *\n\t * @example\n\t * ```ts\n\t * // Fluent API (single field)\n\t * builder.orderBy(\"age\", \"asc\").orderBy(\"name\", \"desc\");\n\t *\n\t * // Full format\n\t * builder.orderBy([{ field: \"age\", direction: \"asc\", nulls: \"last\" }]);\n\t *\n\t * // Object shortcut\n\t * builder.orderBy({ age: \"asc\" });\n\t *\n\t * // String array\n\t * builder.orderBy([\"age\", \"-name\"]);\n\t * ```\n\t */\n\torderBy(clause: OrderByClause<TSchema>): this;\n\torderBy(field: keyof TSchema, direction?: OrderDirection): this;\n\torderBy(\n\t\tfieldOrClause: keyof TSchema | OrderByClause<TSchema>,\n\t\tdirection: OrderDirection = \"asc\",\n\t): this {\n\t\t// Fluent API: orderBy(\"field\", \"asc\")\n\t\tif (typeof fieldOrClause === \"string\" && !Array.isArray(fieldOrClause)) {\n\t\t\tconst normalized = normalizeOrderBy(this.query.orderBy);\n\t\t\tconst newItem: OrderByItem<TSchema> = {\n\t\t\t\tfield: fieldOrClause as keyof TSchema,\n\t\t\t\tdirection,\n\t\t\t};\n\t\t\tthis.query.orderBy = [\n\t\t\t\t...(normalized || []),\n\t\t\t\tnewItem,\n\t\t\t] as OrderByClause<TSchema>;\n\t\t\treturn this;\n\t\t}\n\n\t\t// Clause format: orderBy([...]) or orderBy({...})\n\t\tthis.query.orderBy = fieldOrClause as OrderByClause<TSchema>;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Set limit\n\t */\n\tlimit(count: number): this {\n\t\tthis.query.limit = count;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Set offset\n\t */\n\toffset(count: number): this {\n\t\tthis.query.offset = count;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Set data for UPDATE (shallow merge, single object)\n\t *\n\t * Multiple calls are merged (shallow merge).\n\t * Only available for UPDATE queries.\n\t *\n\t * @param values - Data to update\n\t * @returns this\n\t *\n\t * @example\n\t * ```ts\n\t * builder\n\t * .data({ name: 'John' })\n\t * .data({ age: 25 }); // Merged: { name: 'John', age: 25 }\n\t * ```\n\t */\n\tdata(values: Partial<TSchema>): this {\n\t\tif (this.query.data === undefined) {\n\t\t\tthis.query.data = values;\n\t\t} else {\n\t\t\tthis.query.data = { ...this.query.data, ...values };\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Push a data item for INSERT (bulk insert support)\n\t *\n\t * Each call adds one item to the insert batch.\n\t * Only available for INSERT queries.\n\t *\n\t * @param item - Data item to insert\n\t * @returns this\n\t *\n\t * @example\n\t * ```ts\n\t * builder\n\t * .pushData({ name: 'John', age: 25 })\n\t * .pushData({ name: 'Jane', age: 30 });\n\t * // Inserts 2 rows\n\t * ```\n\t */\n\tpushData(item: Partial<TSchema>): this {\n\t\tif (this.query.dataItems === undefined) {\n\t\t\tthis.query.dataItems = [item];\n\t\t} else {\n\t\t\tthis.query.dataItems.push(item);\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Set DISTINCT\n\t */\n\tdistinct(enabled = true): this {\n\t\tthis.query.distinct = enabled;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Group by fields\n\t */\n\tgroupBy(fields: readonly string[]): this {\n\t\tthis.query.groupBy = [...(this.query.groupBy || []), ...fields];\n\t\treturn this;\n\t}\n\n\t/**\n\t * Having clause (for GROUP BY)\n\t */\n\thaving(conditions: WhereClause<TSchema>): this {\n\t\tthis.query.having = conditions;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Build final QueryObject\n\t * @throws {DatrixQueryBuilderError} If query is invalid\n\t */\n\tbuild(): QueryObjectForType<TSchema, TType> {\n\t\t// Validate required fields\n\t\tif (!this.query.type) {\n\t\t\tthrowInvalidQueryType(this.query.type);\n\t\t}\n\n\t\tif (!this.query.table) {\n\t\t\tthrowMissingTable();\n\t\t}\n\n\t\tconst type = this.query.type!;\n\t\tconst table = this.query.table!;\n\n\t\t// Normalize common clauses\n\t\tconst normalizedWhere = normalizeWhere(\n\t\t\tthis.query.where,\n\t\t\tthis._schema,\n\t\t\tthis._registry,\n\t\t);\n\t\tconst normalizedSelect = normalizeSelect(\n\t\t\tthis.query.select,\n\t\t\tthis._schema,\n\t\t\tthis._registry,\n\t\t);\n\t\tconst normalizedPopulate = normalizePopulateArray(\n\t\t\tthis.query.populate,\n\t\t\tthis._modelName,\n\t\t\tthis._registry,\n\t\t);\n\t\tconst normalizedOrderBy = normalizeOrderBy(this.query.orderBy);\n\n\t\t// Spread helpers for reuse\n\t\tconst selectSpread =\n\t\t\tnormalizedSelect !== undefined\n\t\t\t\t? { select: normalizedSelect }\n\t\t\t\t: { select: undefined };\n\t\tconst populateSpread =\n\t\t\tnormalizedPopulate !== undefined ? { populate: normalizedPopulate } : {};\n\t\tconst whereSpread =\n\t\t\tnormalizedWhere !== undefined ? { where: normalizedWhere } : {};\n\n\t\tswitch (type) {\n\t\t\tcase \"select\": {\n\t\t\t\treturn {\n\t\t\t\t\ttype,\n\t\t\t\t\ttable,\n\t\t\t\t\t...selectSpread,\n\t\t\t\t\t...whereSpread,\n\t\t\t\t\t...populateSpread,\n\t\t\t\t\t...(normalizedOrderBy !== undefined && {\n\t\t\t\t\t\torderBy: normalizedOrderBy,\n\t\t\t\t\t}),\n\t\t\t\t\t...(this.query.limit !== undefined && { limit: this.query.limit }),\n\t\t\t\t\t...(this.query.offset !== undefined && { offset: this.query.offset }),\n\t\t\t\t\t...(this.query.distinct !== undefined && {\n\t\t\t\t\t\tdistinct: this.query.distinct,\n\t\t\t\t\t}),\n\t\t\t\t\t...(this.query.groupBy !== undefined && {\n\t\t\t\t\t\tgroupBy: this.query.groupBy as readonly string[],\n\t\t\t\t\t}),\n\t\t\t\t\t...(this.query.having !== undefined && {\n\t\t\t\t\t\thaving: this.query.having,\n\t\t\t\t\t}),\n\t\t\t\t} as QueryObjectForType<TSchema, TType>;\n\t\t\t}\n\n\t\t\tcase \"count\": {\n\t\t\t\treturn {\n\t\t\t\t\ttype,\n\t\t\t\t\ttable,\n\t\t\t\t\t...whereSpread,\n\t\t\t\t\t...(this.query.groupBy !== undefined && {\n\t\t\t\t\t\tgroupBy: this.query.groupBy as readonly string[],\n\t\t\t\t\t}),\n\t\t\t\t\t...(this.query.having !== undefined && {\n\t\t\t\t\t\thaving: this.query.having,\n\t\t\t\t\t}),\n\t\t\t\t} as QueryObjectForType<TSchema, TType>;\n\t\t\t}\n\n\t\t\tcase \"insert\": {\n\t\t\t\tconst dataItems = this.query.dataItems ?? [];\n\t\t\t\tif (dataItems.length === 0) {\n\t\t\t\t\tthrowMissingData(\"insert\");\n\t\t\t\t}\n\t\t\t\tconst processedItems = dataItems.map((item) =>\n\t\t\t\t\tprocessData<TSchema>(item, this._schema, this._registry),\n\t\t\t\t);\n\t\t\t\tconst dataArray = processedItems.map(\n\t\t\t\t\t(p) => p.data,\n\t\t\t\t) as readonly Partial<TSchema>[];\n\t\t\t\tconst relations = processedItems[0]?.relations;\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"insert\" as const,\n\t\t\t\t\ttable,\n\t\t\t\t\tdata: dataArray,\n\t\t\t\t\t...(relations !== undefined && { relations }),\n\t\t\t\t\t...selectSpread,\n\t\t\t\t\t...populateSpread,\n\t\t\t\t} as unknown as QueryObjectForType<TSchema, TType>;\n\t\t\t}\n\n\t\t\tcase \"update\": {\n\t\t\t\tif (this.query.data === undefined) {\n\t\t\t\t\tthrowMissingData(\"update\");\n\t\t\t\t}\n\t\t\t\tconst processedData = processData<TSchema>(\n\t\t\t\t\tthis.query.data,\n\t\t\t\t\tthis._schema,\n\t\t\t\t\tthis._registry,\n\t\t\t\t);\n\t\t\t\treturn {\n\t\t\t\t\ttype,\n\t\t\t\t\ttable,\n\t\t\t\t\t...whereSpread,\n\t\t\t\t\tdata: processedData.data,\n\t\t\t\t\t...(processedData.relations !== undefined && {\n\t\t\t\t\t\trelations: processedData.relations,\n\t\t\t\t\t}),\n\t\t\t\t\t...selectSpread,\n\t\t\t\t\t...populateSpread,\n\t\t\t\t} as QueryObjectForType<TSchema, TType>;\n\t\t\t}\n\n\t\t\tcase \"delete\": {\n\t\t\t\tif (normalizedWhere === undefined) {\n\t\t\t\t\tthrowDeleteWithoutWhere();\n\t\t\t\t}\n\t\t\t\treturn {\n\t\t\t\t\ttype,\n\t\t\t\t\ttable,\n\t\t\t\t\twhere: normalizedWhere,\n\t\t\t\t\t...selectSpread,\n\t\t\t\t\t...populateSpread,\n\t\t\t\t} as QueryObjectForType<TSchema, TType>;\n\t\t\t}\n\n\t\t\tdefault:\n\t\t\t\tthrowInvalidQueryType(type);\n\t\t}\n\t}\n\n\t/**\n\t * Clone builder (for reusability)\n\t */\n\tclone(): DatrixQueryBuilder<TSchema, TType> {\n\t\tconst cloned = new DatrixQueryBuilder<TSchema, TType>(\n\t\t\tthis._modelName,\n\t\t\tthis._registry,\n\t\t\tthis.query.type as TType,\n\t\t);\n\n\t\t// Deep clone the query state to avoid shared references\n\t\tcloned.query = {\n\t\t\t...this.query,\n\t\t\t...(this.query.where !== undefined && {\n\t\t\t\twhere: deepClone(this.query.where),\n\t\t\t}),\n\t\t\t...(this.query.populate !== undefined && {\n\t\t\t\tpopulate: deepClone(this.query.populate),\n\t\t\t}),\n\t\t\t...(this.query.data !== undefined && {\n\t\t\t\tdata: deepClone(this.query.data),\n\t\t\t}),\n\t\t\t...(this.query.dataItems !== undefined && {\n\t\t\t\tdataItems: deepClone(this.query.dataItems),\n\t\t\t}),\n\t\t\t...(this.query.orderBy !== undefined && {\n\t\t\t\torderBy: deepClone(this.query.orderBy),\n\t\t\t}),\n\t\t\t...(this.query.groupBy !== undefined && {\n\t\t\t\tgroupBy: deepClone(this.query.groupBy),\n\t\t\t}),\n\t\t\t...(this.query.having !== undefined && {\n\t\t\t\thaving: deepClone(this.query.having),\n\t\t\t}),\n\t\t};\n\n\t\treturn cloned;\n\t}\n\n\t/**\n\t * Reset builder to initial state\n\t */\n\treset(): this {\n\t\tthis.query = {};\n\t\treturn this;\n\t}\n}\n\n/**\n * Create a new query builder\n *\n * @param modelName - Model name (e.g., 'User', 'Post')\n * @param schemaRegistry - Schema registry\n * @returns Query builder instance\n *\n * @example\n * ```ts\n * const builder = createQueryBuilder<User>('User', registry);\n * ```\n */\nexport function createQueryBuilder<\n\tTSchema extends DatrixEntry,\n\tTType extends QueryType = \"select\",\n>(\n\tmodelName: string,\n\tschemaRegistry: ISchemaRegistry,\n\ttype?: TType,\n): DatrixQueryBuilder<TSchema, TType> {\n\treturn new DatrixQueryBuilder<TSchema, TType>(\n\t\tmodelName,\n\t\tschemaRegistry,\n\t\t(type ?? \"select\") as TType,\n\t);\n}\n\nexport function selectFrom<TSchema extends DatrixEntry>(\n\tmodelName: string,\n\tschemaRegistry: ISchemaRegistry,\n): DatrixQueryBuilder<TSchema, \"select\"> {\n\treturn new DatrixQueryBuilder<TSchema, \"select\">(\n\t\tmodelName,\n\t\tschemaRegistry,\n\t\t\"select\",\n\t);\n}\n\n/**\n * Create INSERT query builder\n *\n * @param data - Single item or array of items to insert\n */\nexport function insertInto<TSchema extends DatrixEntry>(\n\tmodelName: string,\n\tdata: Partial<TSchema> | readonly Partial<TSchema>[],\n\tschemaRegistry: ISchemaRegistry,\n): DatrixQueryBuilder<TSchema, \"insert\"> {\n\tconst builder = new DatrixQueryBuilder<TSchema, \"insert\">(\n\t\tmodelName,\n\t\tschemaRegistry,\n\t\t\"insert\",\n\t);\n\tconst items = Array.isArray(data) ? data : [data];\n\tfor (const item of items) {\n\t\tbuilder.pushData(item);\n\t}\n\treturn builder;\n}\n\nexport function updateTable<TSchema extends DatrixEntry>(\n\tmodelName: string,\n\tdata: Partial<TSchema>,\n\tschemaRegistry: ISchemaRegistry,\n): DatrixQueryBuilder<TSchema, \"update\"> {\n\treturn new DatrixQueryBuilder<TSchema, \"update\">(\n\t\tmodelName,\n\t\tschemaRegistry,\n\t\t\"update\",\n\t).data(data);\n}\n\nexport function deleteFrom<TSchema extends DatrixEntry>(\n\tmodelName: string,\n\tschemaRegistry: ISchemaRegistry,\n): DatrixQueryBuilder<TSchema, \"delete\"> {\n\treturn new DatrixQueryBuilder<TSchema, \"delete\">(\n\t\tmodelName,\n\t\tschemaRegistry,\n\t\t\"delete\",\n\t);\n}\n\nexport function countFrom<TSchema extends DatrixEntry>(\n\tmodelName: string,\n\tschemaRegistry: ISchemaRegistry,\n): DatrixQueryBuilder<TSchema, \"count\"> {\n\treturn new DatrixQueryBuilder<TSchema, \"count\">(\n\t\tmodelName,\n\t\tschemaRegistry,\n\t\t\"count\",\n\t);\n}\n","/**\n * Schema Type Definitions\n *\n * This file defines the core schema types used throughout Datrix.\n * Schemas are defined as plain TypeScript objects with full type inference.\n */\n\nimport type { SchemaPermission, FieldPermission } from \"./permission\";\nimport { QuerySelect } from \"./query-builder\";\nimport type { DatrixEntry } from \"./entry\";\nimport type { LifecycleHooks } from \"./hooks\";\n\n/**\n * Reserved field names that are automatically added to all schemas\n * and cannot be defined manually by users\n */\nexport const RESERVED_FIELDS = [\"id\", \"createdAt\", \"updatedAt\"] as const;\n\n/**\n * Type for reserved field names\n */\nexport type ReservedFieldName = (typeof RESERVED_FIELDS)[number];\n\nexport type { DatrixEntry, DatrixRecord, FallbackValue } from \"./entry\";\n\n/**\n * Primitive field types\n */\nexport type FieldType =\n\t| \"string\"\n\t| \"number\"\n\t| \"boolean\"\n\t| \"date\"\n\t| \"json\"\n\t| \"enum\"\n\t| \"array\"\n\t| \"relation\"\n\t| \"file\";\n\n/**\n * Base field definition (common properties)\n *\n * @template TRoles - Union type of valid role names for permission checks\n */\ninterface BaseFieldDefinition<TRoles extends string = string> {\n\treadonly required?: boolean;\n\treadonly default?: unknown;\n\treadonly description?: string;\n\t/**\n\t * If true, field is excluded from SELECT queries by default\n\t * Used for auto-generated fields like foreign keys that shouldn't appear in responses\n\t * @internal\n\t */\n\treadonly hidden?: boolean;\n\t/**\n\t * Field-level permission configuration\n\t * - `read`: If denied, field is stripped from response\n\t * - `write`: If denied, returns 403 error\n\t */\n\treadonly permission?: FieldPermission<TRoles>;\n}\n\n/**\n * String field definition\n */\nexport interface StringField<\n\tTRoles extends string = string,\n> extends BaseFieldDefinition<TRoles> {\n\treadonly type: \"string\";\n\treadonly minLength?: number;\n\treadonly maxLength?: number;\n\treadonly pattern?: RegExp;\n\treadonly unique?: boolean;\n\treadonly validator?: (value: string) => true | string;\n\treadonly errorMessage?: string;\n}\n\n/**\n * Foreign key reference definition\n * Used by NumberField.references to generate FOREIGN KEY constraints in adapters\n */\nexport interface ForeignKeyReference {\n\treadonly table: string;\n\treadonly column?: string; // defaults to \"id\"\n\treadonly onDelete?: \"cascade\" | \"setNull\" | \"restrict\" | undefined;\n\treadonly onUpdate?: \"cascade\" | \"restrict\" | undefined;\n}\n\n/**\n * Number field definition\n */\nexport interface NumberField<\n\tTRoles extends string = string,\n> extends BaseFieldDefinition<TRoles> {\n\treadonly type: \"number\";\n\treadonly min?: number;\n\treadonly max?: number;\n\treadonly integer?: boolean;\n\treadonly unique?: boolean;\n\treadonly autoIncrement?: boolean;\n\treadonly validator?: (value: number) => true | string;\n\treadonly references?: ForeignKeyReference;\n}\n\n/**\n * Boolean field definition\n */\nexport interface BooleanField<\n\tTRoles extends string = string,\n> extends BaseFieldDefinition<TRoles> {\n\treadonly type: \"boolean\";\n}\n\n/**\n * Date field definition\n */\nexport interface DateField<\n\tTRoles extends string = string,\n> extends BaseFieldDefinition<TRoles> {\n\treadonly type: \"date\";\n\treadonly min?: Date;\n\treadonly max?: Date;\n}\n\n/**\n * JSON field definition\n */\nexport interface JsonField<\n\tTRoles extends string = string,\n> extends BaseFieldDefinition<TRoles> {\n\treadonly type: \"json\";\n\treadonly schema?: Record<string, unknown>; // JSON schema validation\n}\n\n/**\n * Enum field definition\n */\nexport interface EnumField<\n\tT extends readonly string[] = readonly string[],\n\tTRoles extends string = string,\n> extends BaseFieldDefinition<TRoles> {\n\treadonly type: \"enum\";\n\treadonly values: T;\n}\n\n/**\n * Array field definition\n */\nexport interface ArrayField<\n\tTRoles extends string = string,\n> extends BaseFieldDefinition<TRoles> {\n\treadonly type: \"array\";\n\treadonly items: FieldDefinition<TRoles>;\n\treadonly minItems?: number;\n\treadonly maxItems?: number;\n\treadonly unique?: boolean; // All items must be unique\n}\n\n/**\n * Relation kinds\n */\nexport type RelationKind = \"hasOne\" | \"hasMany\" | \"belongsTo\" | \"manyToMany\";\n\n/**\n * File options carried on a RelationField that was converted from a FileField.\n * When defined, the relation is a file upload relation.\n * Used by the upload handler — core ignores this.\n */\nexport interface FileFieldOptions {\n\treadonly allowedTypes?: readonly string[]; // MIME types e.g. [\"image/*\", \"application/pdf\"]\n\treadonly maxSize?: number; // In bytes\n}\n\n/**\n * Relation field definition\n */\nexport interface RelationField<\n\tTRoles extends string = string,\n> extends BaseFieldDefinition<TRoles> {\n\treadonly type: \"relation\";\n\treadonly model: string; // Target model name\n\treadonly kind: RelationKind;\n\treadonly foreignKey?: string; // Optional - defaults to fieldName + \"Id\"\n\treadonly through?: string; // Join table for manyToMany (optional - auto-generated)\n\treadonly onDelete?: \"cascade\" | \"setNull\" | \"restrict\";\n\treadonly onUpdate?: \"cascade\" | \"restrict\";\n\t/**\n\t * Present only when this relation was converted from a FileField.\n\t * Upload handler reads this to validate uploaded files.\n\t */\n\treadonly fileOptions?: FileFieldOptions;\n}\n\n/**\n * Flexible ID reference for relations\n * Accepts: number, string, or object with id property\n *\n * @example\n * ```ts\n * // All valid:\n * 5\n * \"uuid-123\"\n * { id: 5 }\n * { id: \"uuid-123\", name: \"Test\" } // extra fields ignored, id extracted\n * ```\n */\nexport type RelationIdRef = number | { id: number };\n\n/**\n * Flexible ID references (single or array)\n * Accepts any combination of RelationIdRef\n *\n * @example\n * ```ts\n * // All valid:\n * 5\n * [1, 2, 3]\n * { id: 5 }\n * [{ id: 1 }, { id: 2 }]\n * [1, { id: 2 }, \"uuid-3\"] // mixed\n * ```\n */\nexport type RelationIdRefs = RelationIdRef | RelationIdRef[];\n\n/**\n * belongsTo (N:1) and hasOne (1:1) relation input - write operations\n *\n * Singular relations: only one record can be referenced at a time.\n * Shortcuts: pass ID directly or null to disconnect.\n *\n * @example\n * ```ts\n * // Shortcuts\n * author: 5\n * author: { id: 5 }\n * author: null // disconnect\n *\n * // Explicit object form\n * author: { connect: 5 }\n * author: { connect: { id: 5 } }\n * author: { set: 5 }\n * author: { disconnect: true }\n * author: { create: { name: 'John' } }\n * author: { update: { where: { id: 5 }, data: { name: 'John' } } }\n * ```\n */\nexport type RelationBelongsTo<T extends DatrixEntry> =\n\t| RelationIdRef\n\t| null\n\t| {\n\t\tconnect?: RelationIdRef;\n\t\tset?: RelationIdRef;\n\t\tdisconnect?: true;\n\t\tcreate?: Partial<T>;\n\t\tupdate?: { where: { id: number }; data: Partial<T> };\n\t\tdelete?: RelationIdRef;\n\t};\n\n/**\n * hasOne (1:1) relation input - write operations\n * Same constraints as belongsTo (singular).\n */\nexport type RelationHasOne<T extends DatrixEntry> = RelationBelongsTo<T>;\n\n/**\n * hasMany (1:N) relation input - write operations\n *\n * Plural relations: multiple records can be referenced.\n * Shortcuts: single ID or array of IDs.\n *\n * @example\n * ```ts\n * // Shortcuts\n * tags: 5\n * tags: { id: 5 }\n * tags: [1, 2, 3]\n * tags: [{ id: 1 }, { id: 2 }]\n *\n * // Explicit object form\n * tags: { connect: [1, 2] }\n * tags: { disconnect: [3] }\n * tags: { set: [1, 2, 3] }\n * tags: { create: [{ name: 'Tag A' }, { name: 'Tag B' }] }\n * tags: { delete: [4, 5] }\n * ```\n */\nexport type RelationHasMany<T extends DatrixEntry> =\n\t| RelationIdRefs\n\t| {\n\t\tconnect?: RelationIdRefs;\n\t\tdisconnect?: RelationIdRefs;\n\t\tset?: RelationIdRefs;\n\t\tcreate?: Partial<T> | Partial<T>[];\n\t\tupdate?:\n\t\t| { where: { id: number }; data: Partial<T> }\n\t\t| { where: { id: number }; data: Partial<T> }[];\n\t\tdelete?: RelationIdRefs;\n\t};\n\n/**\n * manyToMany (N:N) relation input - write operations\n * Same constraints as hasMany (plural).\n */\nexport type RelationManyToMany<T extends DatrixEntry> = RelationHasMany<T>;\n\n/**\n * Union of all relation input types.\n * Used internally by the query builder and validator.\n */\nexport type RelationInput<T extends DatrixEntry> =\n\t| RelationBelongsTo<T>\n\t| RelationHasMany<T>;\n\n/**\n * Relation input without generic — for use in untyped/fallback contexts.\n * Covers ID-based operations only (no nested create/update).\n * Provides intellisense for connect/set/disconnect/delete without requiring a model type.\n *\n * @example\n * ```ts\n * // Shortcuts\n * author: 5\n * tags: [1, 2, 3]\n *\n * // Explicit\n * author: { connect: 5 }\n * tags: { set: [1, 2, 3] }\n * tags: { disconnect: [3] }\n * ```\n */\nexport type AnyRelationInput = RelationIdRefs | null | AnyRelationInputObject;\n\nexport type AnyRelationInputObject = {\n\tconnect?: RelationIdRefs;\n\tdisconnect?: RelationIdRefs | true;\n\tset?: RelationIdRefs;\n\tdelete?: RelationIdRefs;\n\tcreate?: Record<string, unknown> | Record<string, unknown>[];\n\tupdate?:\n\t| { where: { id: number }; data: Record<string, unknown> }\n\t| { where: { id: number }; data: Record<string, unknown> }[];\n};\n\n/**\n * Normalized relation ID (always { id } format)\n */\nexport type NormalizedRelationId = { id: string | number };\n\n/**\n * Normalize a single RelationIdRef to { id } format\n *\n * @param ref - ID reference (number, string, or object with id)\n * @returns Normalized { id } object\n *\n * @example\n * ```ts\n * normalizeRelationId(5) // { id: 5 }\n * normalizeRelationId(\"uuid\") // { id: \"uuid\" }\n * normalizeRelationId({ id: 5 }) // { id: 5 }\n * normalizeRelationId({ id: 5, name: \"Test\" }) // { id: 5 }\n * ```\n */\nexport function normalizeRelationId(ref: RelationIdRef): NormalizedRelationId {\n\tif (typeof ref === \"number\" || typeof ref === \"string\") {\n\t\treturn { id: ref };\n\t}\n\treturn { id: ref.id };\n}\n\n/**\n * Normalize RelationIdRefs to array of { id } format\n *\n * @param refs - Single or array of ID references\n * @returns Array of normalized { id } objects\n *\n * @example\n * ```ts\n * normalizeRelationIds(5) // [{ id: 5 }]\n * normalizeRelationIds([1, 2]) // [{ id: 1 }, { id: 2 }]\n * normalizeRelationIds({ id: 5 }) // [{ id: 5 }]\n * normalizeRelationIds([1, { id: 2 }]) // [{ id: 1 }, { id: 2 }]\n * ```\n */\nexport function normalizeRelationIds(\n\trefs: RelationIdRefs,\n): NormalizedRelationId[] {\n\tif (Array.isArray(refs)) {\n\t\treturn refs.map(normalizeRelationId);\n\t}\n\treturn [normalizeRelationId(refs)];\n}\n\n/**\n * Check if value is a valid RelationIdRef\n */\nexport function isRelationIdRef(value: unknown): value is RelationIdRef {\n\tif (typeof value === \"number\" || typeof value === \"string\") {\n\t\treturn true;\n\t}\n\tif (\n\t\ttypeof value === \"object\" &&\n\t\tvalue !== null &&\n\t\t\"id\" in value &&\n\t\t(typeof (value as { id: unknown }).id === \"number\" ||\n\t\t\ttypeof (value as { id: unknown }).id === \"string\")\n\t) {\n\t\treturn true;\n\t}\n\treturn false;\n}\n\n/**\n * Check if value is valid RelationIdRefs\n */\nexport function isRelationIdRefs(value: unknown): value is RelationIdRefs {\n\tif (isRelationIdRef(value)) {\n\t\treturn true;\n\t}\n\tif (Array.isArray(value) && value.every(isRelationIdRef)) {\n\t\treturn true;\n\t}\n\treturn false;\n}\n\n/**\n * File field definition\n */\nexport interface FileField<\n\tTRoles extends string = string,\n> extends BaseFieldDefinition<TRoles> {\n\treadonly type: \"file\";\n\treadonly allowedTypes?: readonly string[]; // MIME types\n\treadonly maxSize?: number; // In bytes\n\treadonly multiple?: boolean; // Allow multiple files\n}\n\n/**\n * Union of all field definitions\n *\n * @template TRoles - Union type of valid role names for permission checks\n */\nexport type FieldDefinition<TRoles extends string = string> =\n\t| StringField<TRoles>\n\t| NumberField<TRoles>\n\t| BooleanField<TRoles>\n\t| DateField<TRoles>\n\t| JsonField<TRoles>\n\t| EnumField<readonly string[], TRoles>\n\t| ArrayField<TRoles>\n\t| RelationField<TRoles>\n\t| FileField<TRoles>;\n\n/**\n * Index definition\n */\nexport interface IndexDefinition {\n\treadonly name?: string;\n\treadonly fields: readonly string[];\n\treadonly unique?: boolean;\n\treadonly type?: \"btree\" | \"hash\" | \"gist\" | \"gin\";\n}\n\nexport type { LifecycleHooks } from \"./hooks\";\n\n/**\n * Schema definition\n *\n * @template TRoles - Union type of valid role names for permission checks\n * @template TFields - Record of field names to field definitions\n *\n * @example\n * ```ts\n * const roles = ['admin', 'editor', 'user'] as const;\n * type Roles = typeof roles[number];\n *\n * const postSchema = defineSchema<Roles>()({\n * name: 'post',\n * fields: {\n * title: { type: 'string', required: true },\n * authorId: { type: 'string', required: true },\n * },\n * permission: {\n * create: ['admin', 'editor'],\n * read: true,\n * update: ['admin', (ctx) => ctx.user?.id === ctx.record?.authorId],\n * delete: ['admin'],\n * }\n * });\n * ```\n */\nexport interface SchemaDefinition<\n\tTRoles extends string = string,\n\tTFields extends Record<string, FieldDefinition<TRoles>> = Record<\n\t\tstring,\n\t\tFieldDefinition<TRoles>\n\t>,\n> {\n\treadonly name: string;\n\treadonly fields: TFields;\n\treadonly indexes?: readonly IndexDefinition[];\n\treadonly hooks?: LifecycleHooks;\n\treadonly timestamps?: boolean; // Auto-add createdAt, updatedAt\n\treadonly softDelete?: boolean; // Add deletedAt field\n\treadonly tableName?: string; // Custom table name (defaults to pluralized name)\n\t/**\n\t * Schema-level permission configuration\n\t * Defines who can perform CRUD operations on this schema\n\t */\n\treadonly permission?: SchemaPermission<TRoles>;\n\t/**\n\t * Internal flag - marks auto-generated junction tables for manyToMany relations\n\t * @internal\n\t */\n\treadonly _isJunctionTable?: boolean;\n}\n\n/**\n * Define a schema definition.\n * Returns the schema as-is with const inference preserved.\n *\n * @example\n * ```ts\n * const postSchema = defineSchema({\n * name: 'post',\n * fields: {\n * title: { type: 'string', required: true },\n * content: { type: 'string' },\n * },\n * permission: {\n * create: ['admin', 'editor'],\n * read: true,\n * }\n * });\n * ```\n */\nexport function defineSchema<const T extends SchemaDefinition>(schema: T): T {\n\treturn schema;\n}\n\n/**\n * Schema registry interface\n *\n * Defines the contract for schema storage and retrieval.\n * Implementation is in packages/core/src/schema/registry.ts\n */\nexport interface ISchemaRegistry {\n\t/** Register a schema */\n\tregister(schema: SchemaDefinition): SchemaDefinition;\n\t/** Get schema by name */\n\tget(name: string): SchemaDefinition | undefined;\n\t/** Get schema by model name with resolved table name */\n\tgetWithTableName(\n\t\tmodelName: string,\n\t): { schema: SchemaDefinition; tableName: string } | undefined;\n\t/** Get schema by table name with resolved table name */\n\tgetByTableName(\n\t\ttableName: string,\n\t): { schema: SchemaDefinition; tableName: string } | undefined;\n\t/** Check if schema exists */\n\thas(name: string): boolean;\n\t/** Get all schemas */\n\tgetAll(): readonly SchemaDefinition[];\n\t/** Get schema names */\n\tgetNames(): readonly string[];\n\t/** Get schema count */\n\treadonly size: number;\n\t/** Find model name by table name */\n\tfindModelByTableName(tableName: string | null): string | null;\n\t/** Get related schemas for a given schema */\n\tgetRelatedSchemas(schemaName: string): readonly string[];\n\t/** Check if registry is locked */\n\tisLocked(): boolean;\n\t/** Get select fields for a model */\n\tgetCachedSelectFields<T extends DatrixEntry>(\n\t\tmodelName: string,\n\t): QuerySelect<T>;\n}\n\n/**\n * Field metadata (runtime information)\n */\nexport interface FieldMetadata {\n\treadonly name: string;\n\treadonly type: FieldType;\n\treadonly required: boolean;\n\treadonly unique: boolean;\n\treadonly hasDefault: boolean;\n\treadonly isRelation: boolean;\n\treadonly isArray: boolean;\n}\n\n/**\n * Schema definition validation result\n */\nexport interface SchemaDefinitionValidationResult {\n\treadonly valid: boolean;\n\treadonly errors: readonly SchemaValidationError[];\n}\n\n/**\n * Schema validation error\n */\nexport interface SchemaValidationError {\n\treadonly field?: string;\n\treadonly message: string;\n\treadonly code: string;\n}\n\n/**\n * Validate schema definition\n */\nexport function validateSchemaDefinition(\n\tschema: SchemaDefinition,\n): SchemaDefinitionValidationResult {\n\tconst errors: SchemaValidationError[] = [];\n\n\t// Check name\n\tif (!schema.name || schema.name.trim() === \"\") {\n\t\terrors.push({\n\t\t\tmessage: \"Schema name is required\",\n\t\t\tcode: \"MISSING_NAME\",\n\t\t});\n\t}\n\n\t// Check fields\n\tif (!schema.fields || Object.keys(schema.fields).length === 0) {\n\t\terrors.push({\n\t\t\tmessage: \"Schema must have at least one field\",\n\t\t\tcode: \"NO_FIELDS\",\n\t\t});\n\t}\n\n\t// Validate each field\n\tfor (const [fieldName, fieldDef] of Object.entries(schema.fields)) {\n\t\t// Check field name\n\t\tif (!fieldName || fieldName.trim() === \"\") {\n\t\t\terrors.push({\n\t\t\t\tmessage: \"Field name cannot be empty\",\n\t\t\t\tcode: \"INVALID_FIELD_NAME\",\n\t\t\t});\n\t\t}\n\n\t\t// Check relation references\n\t\tif (fieldDef.type === \"relation\") {\n\t\t\tif (!fieldDef.model || fieldDef.model.trim() === \"\") {\n\t\t\t\terrors.push({\n\t\t\t\t\tfield: fieldName,\n\t\t\t\t\tmessage: \"Relation field must specify a model\",\n\t\t\t\t\tcode: \"MISSING_RELATION_MODEL\",\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\t// Check enum values\n\t\tif (fieldDef.type === \"enum\") {\n\t\t\tif (!fieldDef.values || fieldDef.values.length === 0) {\n\t\t\t\terrors.push({\n\t\t\t\t\tfield: fieldName,\n\t\t\t\t\tmessage: \"Enum field must have at least one value\",\n\t\t\t\t\tcode: \"EMPTY_ENUM\",\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\t// Check array items\n\t\tif (fieldDef.type === \"array\") {\n\t\t\tif (!fieldDef.items) {\n\t\t\t\terrors.push({\n\t\t\t\t\tfield: fieldName,\n\t\t\t\t\tmessage: \"Array field must specify items type\",\n\t\t\t\t\tcode: \"MISSING_ARRAY_ITEMS\",\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\treturn {\n\t\tvalid: errors.length === 0,\n\t\terrors,\n\t};\n}\n\n/**\n * Sort schemas by FK dependency order using Kahn's topological sort.\n * Referenced schemas (parents) come before schemas that reference them (children).\n * Circular/unresolved schemas are appended at the end unchanged.\n *\n * Used by SchemaRegistry.finalizeRegistry() and ZipExportWriter.finalize()\n * to guarantee consistent table creation order.\n */\nexport function sortSchemasByDependency(\n\tschemas: SchemaDefinition[],\n): SchemaDefinition[] {\n\tconst tableToSchema = new Map<string, SchemaDefinition>();\n\tfor (const schema of schemas) {\n\t\tif (schema.tableName) tableToSchema.set(schema.tableName, schema);\n\t}\n\n\tconst deps = new Map<string, Set<string>>();\n\tfor (const schema of schemas) {\n\t\tif (schema.tableName) deps.set(schema.tableName, new Set());\n\t}\n\n\tfor (const schema of schemas) {\n\t\tfor (const field of Object.values(schema.fields)) {\n\t\t\tconst ref = (field as { references?: { table: string } }).references;\n\t\t\tif (!ref) continue;\n\t\t\tconst depTable = ref.table;\n\t\t\tif (depTable !== schema.tableName && tableToSchema.has(depTable)) {\n\t\t\t\tdeps.get(schema.tableName!)!.add(depTable);\n\t\t\t}\n\t\t}\n\t}\n\n\tconst inDegree = new Map<string, number>();\n\tfor (const tableName of deps.keys()) {\n\t\tinDegree.set(tableName, 0);\n\t}\n\tfor (const depSet of deps.values()) {\n\t\tfor (const dep of depSet) {\n\t\t\tinDegree.set(dep, (inDegree.get(dep) ?? 0) + 1);\n\t\t}\n\t}\n\n\tconst queue: string[] = [];\n\tfor (const [tableName, degree] of inDegree) {\n\t\tif (degree === 0) queue.push(tableName);\n\t}\n\n\tconst sorted: string[] = [];\n\twhile (queue.length > 0) {\n\t\tconst current = queue.shift()!;\n\t\tsorted.push(current);\n\t\tfor (const dep of deps.get(current) ?? []) {\n\t\t\tconst newDegree = (inDegree.get(dep) ?? 1) - 1;\n\t\t\tinDegree.set(dep, newDegree);\n\t\t\tif (newDegree === 0) queue.push(dep);\n\t\t}\n\t}\n\n\t// Reverse: dependencies first (parents before children)\n\tsorted.reverse();\n\n\tconst result: SchemaDefinition[] = [];\n\tfor (const tableName of sorted) {\n\t\tconst schema = tableToSchema.get(tableName);\n\t\tif (schema) result.push(schema);\n\t}\n\t// Append any schemas without tableName or in circular deps\n\tfor (const schema of schemas) {\n\t\tif (!result.includes(schema)) result.push(schema);\n\t}\n\n\treturn result;\n}\n","/**\n * Validation Error Classes\n *\n * Custom error classes and utilities for validation errors.\n * Provides detailed error information for debugging.\n */\n\nimport { ValidationError, ValidationErrorCode } from \"../types/core/validator\";\nimport { DatrixValidationError } from \"../types/errors/core/validation\";\n\n/**\n * Create a validation error\n */\nexport function createValidationError(\n\tfield: string,\n\tcode: ValidationErrorCode,\n\tmessage: string,\n\toptions?: {\n\t\tvalue?: unknown;\n\t\texpected?: unknown;\n\t},\n): ValidationError {\n\treturn {\n\t\tfield,\n\t\tcode,\n\t\tmessage,\n\t\tvalue: options?.value,\n\t\texpected: options?.expected,\n\t};\n}\n\n/**\n * Format error message with context\n */\nexport function formatErrorMessage(\n\tcode: ValidationErrorCode,\n\tfield: string,\n\toptions?: {\n\t\tmin?: number;\n\t\tmax?: number;\n\t\texpected?: unknown;\n\t\tactual?: unknown;\n\t\tpattern?: RegExp;\n\t},\n): string {\n\tswitch (code) {\n\t\tcase \"REQUIRED\":\n\t\t\treturn `Field '${field}' is required`;\n\n\t\tcase \"TYPE_MISMATCH\":\n\t\t\treturn `Field '${field}' has incorrect type. Expected ${options?.expected}, got ${options?.actual}`;\n\n\t\tcase \"MIN_LENGTH\":\n\t\t\treturn `Field '${field}' must be at least ${options?.min} characters long`;\n\n\t\tcase \"MAX_LENGTH\":\n\t\t\treturn `Field '${field}' must be at most ${options?.max} characters long`;\n\n\t\tcase \"MIN_VALUE\":\n\t\t\treturn `Field '${field}' must be at least ${options?.min}`;\n\n\t\tcase \"MAX_VALUE\":\n\t\t\treturn `Field '${field}' must be at most ${options?.max}`;\n\n\t\tcase \"MIN_ITEMS\":\n\t\t\treturn `Field '${field}' must have at least ${options?.min} items`;\n\n\t\tcase \"MAX_ITEMS\":\n\t\t\treturn `Field '${field}' must have at most ${options?.max} items`;\n\n\t\tcase \"PATTERN\":\n\t\t\treturn `Field '${field}' does not match required pattern${options?.pattern ? `: ${options.pattern}` : \"\"\n\t\t\t\t}`;\n\n\t\tcase \"UNIQUE\":\n\t\t\treturn `Field '${field}' must be unique`;\n\n\t\tcase \"INVALID_ENUM\":\n\t\t\treturn `Field '${field}' must be one of: ${options?.expected}`;\n\n\t\tcase \"INVALID_FORMAT\":\n\t\t\treturn `Field '${field}' has invalid format`;\n\n\t\tcase \"INVALID_DATE\":\n\t\t\treturn `Field '${field}' is not a valid date`;\n\n\t\tcase \"CUSTOM\":\n\t\t\treturn `Field '${field}' validation failed`;\n\n\t\tdefault:\n\t\t\treturn `Field '${field}' validation failed`;\n\t}\n}\n\n/**\n * Combine multiple validation errors\n */\nexport function combineErrors(\n\t...errorArrays: readonly (readonly ValidationError[])[]\n): readonly ValidationError[] {\n\tconst combined: ValidationError[] = [];\n\n\tfor (const errors of errorArrays) {\n\t\tcombined.push(...errors);\n\t}\n\n\treturn combined;\n}\n\n/**\n * Group errors by field\n */\nexport function groupErrorsByField(\n\terrors: readonly ValidationError[],\n): Record<string, readonly ValidationError[]> {\n\tconst grouped: Record<string, ValidationError[]> = {};\n\n\tfor (const error of errors) {\n\t\tif (!grouped[error.field]) {\n\t\t\tgrouped[error.field] = [];\n\t\t}\n\t\tgrouped[error.field]!.push(error);\n\t}\n\n\treturn grouped;\n}\n\n/**\n * Get first error for each field\n */\nexport function getFirstErrorPerField(\n\terrors: readonly ValidationError[],\n): Record<string, ValidationError> {\n\tconst firstErrors: Record<string, ValidationError> = {};\n\n\tfor (const error of errors) {\n\t\tif (!firstErrors[error.field]) {\n\t\t\tfirstErrors[error.field] = error;\n\t\t}\n\t}\n\n\treturn firstErrors;\n}\n\n/**\n * Filter errors by code\n */\nexport function filterErrorsByCode(\n\terrors: readonly ValidationError[],\n\tcode: ValidationErrorCode,\n): readonly ValidationError[] {\n\treturn errors.filter((error) => error.code === code);\n}\n\n/**\n * Filter errors by field\n */\nexport function filterErrorsByField(\n\terrors: readonly ValidationError[],\n\tfield: string,\n): readonly ValidationError[] {\n\treturn errors.filter((error) => error.field === field);\n}\n\n/**\n * Check if errors contain specific code\n */\nexport function hasErrorCode(\n\terrors: readonly ValidationError[],\n\tcode: ValidationErrorCode,\n): boolean {\n\treturn errors.some((error) => error.code === code);\n}\n\n/**\n * Check if errors contain specific field\n */\nexport function hasErrorForField(\n\terrors: readonly ValidationError[],\n\tfield: string,\n): boolean {\n\treturn errors.some((error) => error.field === field);\n}\n\n/**\n * Format errors as human-readable string\n */\nexport function formatErrors(errors: readonly ValidationError[]): string {\n\tif (errors.length === 0) {\n\t\treturn \"No validation errors\";\n\t}\n\n\tconst messages = errors.map(\n\t\t(error) => ` - ${error.field}: ${error.message} (${error.code})`,\n\t);\n\n\treturn `Validation failed with ${errors.length} error(s):\\n${messages.join(\n\t\t\"\\n\",\n\t)}`;\n}\n\n/**\n * Format errors as JSON\n */\nexport function formatErrorsAsJSON(errors: readonly ValidationError[]): string {\n\treturn JSON.stringify(errors, null, 2);\n}\n\n/**\n * Convert errors to plain object (for API responses)\n */\nexport function errorsToPlainObject(\n\terrors: readonly ValidationError[],\n): Record<string, string[]> {\n\tconst plain: Record<string, string[]> = {};\n\n\tfor (const error of errors) {\n\t\tif (!plain[error.field]) {\n\t\t\tplain[error.field] = [];\n\t\t}\n\t\tplain[error.field]!.push(error.message);\n\t}\n\n\treturn plain;\n}\n\n/**\n * Validation error collection class (immutable)\n */\nexport class ValidationErrorCollection {\n\tprivate readonly errors: readonly ValidationError[];\n\n\tconstructor(errors: readonly ValidationError[] = []) {\n\t\tthis.errors = Object.freeze([...errors]);\n\t}\n\n\t/**\n\t * Add an error (returns new instance)\n\t */\n\tadd(error: ValidationError): ValidationErrorCollection {\n\t\treturn new ValidationErrorCollection([...this.errors, error]);\n\t}\n\n\t/**\n\t * Add multiple errors (returns new instance)\n\t */\n\taddMany(errors: readonly ValidationError[]): ValidationErrorCollection {\n\t\treturn new ValidationErrorCollection([...this.errors, ...errors]);\n\t}\n\n\t/**\n\t * Get all errors\n\t */\n\tgetAll(): readonly ValidationError[] {\n\t\treturn this.errors;\n\t}\n\n\t/**\n\t * Get errors by field\n\t */\n\tgetByField(field: string): readonly ValidationError[] {\n\t\treturn filterErrorsByField(this.errors, field);\n\t}\n\n\t/**\n\t * Get errors by code\n\t */\n\tgetByCode(code: ValidationErrorCode): readonly ValidationError[] {\n\t\treturn filterErrorsByCode(this.errors, code);\n\t}\n\n\t/**\n\t * Check if has errors\n\t */\n\thasErrors(): boolean {\n\t\treturn this.errors.length > 0;\n\t}\n\n\t/**\n\t * Get error count\n\t */\n\tcount(): number {\n\t\treturn this.errors.length;\n\t}\n\n\t/**\n\t * Format as string\n\t */\n\ttoString(): string {\n\t\treturn formatErrors(this.errors);\n\t}\n\n\t/**\n\t * Format as JSON\n\t */\n\ttoJSON(): readonly ValidationError[] {\n\t\treturn this.errors;\n\t}\n\n\t/**\n\t * Group by field\n\t */\n\tgroupByField(): Record<string, readonly ValidationError[]> {\n\t\treturn groupErrorsByField(this.errors);\n\t}\n\n\t/**\n\t * Get first error per field\n\t */\n\tgetFirstPerField(): Record<string, ValidationError> {\n\t\treturn getFirstErrorPerField(this.errors);\n\t}\n}\n\n/**\n * Centralized Validation Error Helpers\n *\n * Provides a clean API for throwing DatrixValidationError.\n * Similar pattern to CRUD error helpers for consistency.\n */\n\n/**\n * Throw multiple validation errors\n *\n * @param model - Model name\n * @param errors - Array of validation errors\n * @param suggestion - Optional user guidance\n *\n * @example\n * ```ts\n * throwValidationMultiple('User', [\n * { field: 'email', code: 'REQUIRED', message: 'Email required' },\n * { field: 'age', code: 'MIN_VALUE', message: 'Age must be 18+' }\n * ]);\n * ```\n */\nexport function throwValidationMultiple(\n\tmodel: string,\n\terrors: readonly ValidationError[],\n\tsuggestion?: string,\n): never {\n\tconst errorMessages = errors\n\t\t.map((e) => `${e.field}: ${e.message}`)\n\t\t.join(\", \");\n\n\tthrow new DatrixValidationError(\n\t\t`Validation failed for ${model}: ${errorMessages}`,\n\t\t{\n\t\t\tmodel,\n\t\t\terrors,\n\t\t\toperation: \"validation:data\",\n\t\t\tsuggestion,\n\t\t},\n\t);\n}\n\n/**\n * Throw a single field validation error\n *\n * @param model - Model name\n * @param field - Field name\n * @param code - Error code\n * @param message - Error message\n * @param options - Additional error details\n *\n * @example\n * ```ts\n * throwValidationSingle('User', 'email', 'REQUIRED', 'Email is required');\n * ```\n */\nexport function throwValidationSingle(\n\tmodel: string,\n\tfield: string,\n\tcode: ValidationErrorCode,\n\tmessage: string,\n\toptions?: {\n\t\tvalue?: unknown;\n\t\texpected?: unknown;\n\t\tsuggestion?: string;\n\t},\n): never {\n\tconst error = createValidationError(field, code, message, {\n\t\tvalue: options?.value,\n\t\texpected: options?.expected,\n\t});\n\n\tthrow new DatrixValidationError(`Validation failed for ${model}: ${message}`, {\n\t\tmodel,\n\t\terrors: [error],\n\t\toperation: \"validation:field\",\n\t\tsuggestion: options?.suggestion,\n\t});\n}\n\n/**\n * Throw required field error\n *\n * @param model - Model name\n * @param field - Field name\n *\n * @example\n * ```ts\n * throwValidationRequired('User', 'email');\n * ```\n */\nexport function throwValidationRequired(model: string, field: string): never {\n\tconst message = formatErrorMessage(\"REQUIRED\", field);\n\tthrowValidationSingle(model, field, \"REQUIRED\", message, {\n\t\tsuggestion: `Provide a value for the '${field}' field`,\n\t});\n}\n\n/**\n * Throw type mismatch error\n *\n * @param model - Model name\n * @param field - Field name\n * @param expected - Expected type\n * @param received - Received value\n *\n * @example\n * ```ts\n * throwValidationTypeMismatch('User', 'age', 'number', 'string');\n * ```\n */\nexport function throwValidationTypeMismatch(\n\tmodel: string,\n\tfield: string,\n\texpected: string,\n\treceived: unknown,\n): never {\n\tconst actualType = typeof received;\n\tconst message = formatErrorMessage(\"TYPE_MISMATCH\", field, {\n\t\texpected,\n\t\tactual: actualType,\n\t});\n\n\tthrowValidationSingle(model, field, \"TYPE_MISMATCH\", message, {\n\t\tvalue: received,\n\t\texpected,\n\t\tsuggestion: `Ensure '${field}' is of type ${expected}`,\n\t});\n}\n\n/**\n * Throw pattern validation error\n *\n * @param model - Model name\n * @param field - Field name\n * @param pattern - Expected pattern\n * @param received - Received value\n *\n * @example\n * ```ts\n * throwValidationPattern('User', 'email', /^.+@.+$/, 'invalid-email');\n * ```\n */\nexport function throwValidationPattern(\n\tmodel: string,\n\tfield: string,\n\tpattern: RegExp,\n\treceived: unknown,\n): never {\n\tconst message = formatErrorMessage(\"PATTERN\", field, { pattern });\n\n\tthrowValidationSingle(model, field, \"PATTERN\", message, {\n\t\tvalue: received,\n\t\texpected: pattern.toString(),\n\t\tsuggestion: `Ensure '${field}' matches the required pattern: ${pattern}`,\n\t});\n}\n\n/**\n * Throw min length validation error\n *\n * @param model - Model name\n * @param field - Field name\n * @param minLength - Minimum length\n * @param received - Received value\n *\n * @example\n * ```ts\n * throwValidationMinLength('User', 'password', 8, 'short');\n * ```\n */\nexport function throwValidationMinLength(\n\tmodel: string,\n\tfield: string,\n\tminLength: number,\n\treceived: unknown,\n): never {\n\tconst message = formatErrorMessage(\"MIN_LENGTH\", field, { min: minLength });\n\n\tthrowValidationSingle(model, field, \"MIN_LENGTH\", message, {\n\t\tvalue: received,\n\t\texpected: `at least ${minLength} characters`,\n\t\tsuggestion: `Provide a longer value for '${field}'`,\n\t});\n}\n\n/**\n * Throw max length validation error\n *\n * @param model - Model name\n * @param field - Field name\n * @param maxLength - Maximum length\n * @param received - Received value\n *\n * @example\n * ```ts\n * throwValidationMaxLength('User', 'bio', 500, longText);\n * ```\n */\nexport function throwValidationMaxLength(\n\tmodel: string,\n\tfield: string,\n\tmaxLength: number,\n\treceived: unknown,\n): never {\n\tconst message = formatErrorMessage(\"MAX_LENGTH\", field, { max: maxLength });\n\n\tthrowValidationSingle(model, field, \"MAX_LENGTH\", message, {\n\t\tvalue: received,\n\t\texpected: `at most ${maxLength} characters`,\n\t\tsuggestion: `Shorten the value for '${field}'`,\n\t});\n}\n\n/**\n * Throw min value validation error\n *\n * @param model - Model name\n * @param field - Field name\n * @param minValue - Minimum value\n * @param received - Received value\n *\n * @example\n * ```ts\n * throwValidationMinValue('User', 'age', 18, 15);\n * ```\n */\nexport function throwValidationMinValue(\n\tmodel: string,\n\tfield: string,\n\tminValue: number,\n\treceived: unknown,\n): never {\n\tconst message = formatErrorMessage(\"MIN_VALUE\", field, { min: minValue });\n\n\tthrowValidationSingle(model, field, \"MIN_VALUE\", message, {\n\t\tvalue: received,\n\t\texpected: `at least ${minValue}`,\n\t\tsuggestion: `Provide a value >= ${minValue} for '${field}'`,\n\t});\n}\n\n/**\n * Throw max value validation error\n *\n * @param model - Model name\n * @param field - Field name\n * @param maxValue - Maximum value\n * @param received - Received value\n *\n * @example\n * ```ts\n * throwValidationMaxValue('User', 'age', 120, 150);\n * ```\n */\nexport function throwValidationMaxValue(\n\tmodel: string,\n\tfield: string,\n\tmaxValue: number,\n\treceived: unknown,\n): never {\n\tconst message = formatErrorMessage(\"MAX_VALUE\", field, { max: maxValue });\n\n\tthrowValidationSingle(model, field, \"MAX_VALUE\", message, {\n\t\tvalue: received,\n\t\texpected: `at most ${maxValue}`,\n\t\tsuggestion: `Provide a value <= ${maxValue} for '${field}'`,\n\t});\n}\n\n/**\n * Throw invalid enum error\n *\n * @param model - Model name\n * @param field - Field name\n * @param validValues - Valid enum values\n * @param received - Received value\n *\n * @example\n * ```ts\n * throwValidationEnum('User', 'role', ['admin', 'user'], 'superuser');\n * ```\n */\nexport function throwValidationEnum(\n\tmodel: string,\n\tfield: string,\n\tvalidValues: readonly string[],\n\treceived: unknown,\n): never {\n\tconst message = formatErrorMessage(\"INVALID_ENUM\", field, {\n\t\texpected: validValues.join(\", \"),\n\t});\n\n\tthrowValidationSingle(model, field, \"INVALID_ENUM\", message, {\n\t\tvalue: received,\n\t\texpected: validValues.join(\" | \"),\n\t\tsuggestion: `Use one of: ${validValues.join(\", \")}`,\n\t});\n}\n\n/**\n * Throw min items validation error\n *\n * @param model - Model name\n * @param field - Field name\n * @param minItems - Minimum items\n * @param received - Received array\n *\n * @example\n * ```ts\n * throwValidationMinItems('Post', 'tags', 1, []);\n * ```\n */\nexport function throwValidationMinItems(\n\tmodel: string,\n\tfield: string,\n\tminItems: number,\n\treceived: unknown,\n): never {\n\tconst message = formatErrorMessage(\"MIN_ITEMS\", field, { min: minItems });\n\n\tthrowValidationSingle(model, field, \"MIN_ITEMS\", message, {\n\t\tvalue: received,\n\t\texpected: `at least ${minItems} items`,\n\t\tsuggestion: `Provide at least ${minItems} items for '${field}'`,\n\t});\n}\n\n/**\n * Throw max items validation error\n *\n * @param model - Model name\n * @param field - Field name\n * @param maxItems - Maximum items\n * @param received - Received array\n *\n * @example\n * ```ts\n * throwValidationMaxItems('Post', 'tags', 10, largeArray);\n * ```\n */\nexport function throwValidationMaxItems(\n\tmodel: string,\n\tfield: string,\n\tmaxItems: number,\n\treceived: unknown,\n): never {\n\tconst message = formatErrorMessage(\"MAX_ITEMS\", field, { max: maxItems });\n\n\tthrowValidationSingle(model, field, \"MAX_ITEMS\", message, {\n\t\tvalue: received,\n\t\texpected: `at most ${maxItems} items`,\n\t\tsuggestion: `Reduce items in '${field}' to ${maxItems} or less`,\n\t});\n}\n\n/**\n * Throw invalid date error\n *\n * @param model - Model name\n * @param field - Field name\n * @param received - Received value\n *\n * @example\n * ```ts\n * throwValidationDate('Event', 'startDate', 'invalid-date');\n * ```\n */\nexport function throwValidationDate(\n\tmodel: string,\n\tfield: string,\n\treceived: unknown,\n): never {\n\tconst message = formatErrorMessage(\"INVALID_DATE\", field);\n\n\tthrowValidationSingle(model, field, \"INVALID_DATE\", message, {\n\t\tvalue: received,\n\t\texpected: \"valid Date object\",\n\t\tsuggestion: `Provide a valid date for '${field}'`,\n\t});\n}\n\n/**\n * Throw custom validation error\n *\n * @param model - Model name\n * @param field - Field name\n * @param message - Custom error message\n * @param received - Received value\n *\n * @example\n * ```ts\n * throwValidationCustom('User', 'username', 'Username already taken', 'john');\n * ```\n */\nexport function throwValidationCustom(\n\tmodel: string,\n\tfield: string,\n\tmessage: string,\n\treceived?: unknown,\n): never {\n\tthrowValidationSingle(model, field, \"CUSTOM\", message, {\n\t\tvalue: received,\n\t});\n}\n\n/**\n * Legacy helper for backward compatibility\n * @deprecated Use throwValidationMultiple instead\n */\nexport const validationError = {\n\tthrow: throwValidationMultiple,\n};\n","/**\n * Field Validator Implementation (~150 LOC)\n *\n * Validates individual field values against their field definitions.\n * Zero external dependencies - all validation is custom.\n *\n * TODO: Add native 'email' field type for automatic email validation\n * Currently, email validation requires explicit pattern in schema:\n * { type: 'string', pattern: /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/ }\n * Future: { type: 'email', required: true }\n */\n\nimport type {\n\tFieldDefinition,\n\tStringField,\n\tNumberField,\n\tEnumField,\n\tArrayField,\n\tDateField,\n} from \"../types/core/schema\";\nimport { createValidationError, formatErrorMessage } from \"./errors\";\nimport { FieldValidationResult } from \"../types/core/validator\";\n\n/**\n * Type guards\n */\nconst isString = (value: unknown): value is string => typeof value === \"string\";\nconst isNumber = (value: unknown): value is number =>\n\ttypeof value === \"number\" && !isNaN(value);\nconst isBoolean = (value: unknown): value is boolean =>\n\ttypeof value === \"boolean\";\nconst isDate = (value: unknown): value is Date =>\n\tvalue instanceof Date && !isNaN(value.getTime());\nconst isArray = (value: unknown): value is readonly unknown[] =>\n\tArray.isArray(value);\nconst isNullOrUndefined = (value: unknown): value is null | undefined =>\n\tvalue === null || value === undefined;\n\n/**\n * Maximum nesting depth for array/object validation\n */\nconst MAX_VALIDATION_DEPTH = 10;\n\n/**\n * Main field validator function\n */\nexport function validateField<T = unknown>(\n\tvalue: unknown,\n\tfield: FieldDefinition,\n\tfieldName: string,\n\tdepth = 0,\n): FieldValidationResult<T> {\n\t// Check depth limit to prevent infinite recursion\n\tif (depth > MAX_VALIDATION_DEPTH) {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: [\n\t\t\t\tcreateValidationError(\n\t\t\t\t\tfieldName,\n\t\t\t\t\t\"CUSTOM\",\n\t\t\t\t\t`Maximum validation depth (${MAX_VALIDATION_DEPTH}) exceeded`,\n\t\t\t\t\t{ value: depth },\n\t\t\t\t),\n\t\t\t],\n\t\t};\n\t}\n\t// Check required\n\tif (field.required && isNullOrUndefined(value)) {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: [\n\t\t\t\tcreateValidationError(\n\t\t\t\t\tfieldName,\n\t\t\t\t\t\"REQUIRED\",\n\t\t\t\t\tformatErrorMessage(\"REQUIRED\", fieldName),\n\t\t\t\t),\n\t\t\t],\n\t\t};\n\t}\n\n\t// If optional and null/undefined, skip validation\n\tif (!field.required && isNullOrUndefined(value)) {\n\t\treturn { success: true, data: value as T };\n\t}\n\n\t// Type-specific validation\n\tswitch (field.type) {\n\t\tcase \"string\":\n\t\t\treturn validateString(\n\t\t\t\tvalue,\n\t\t\t\tfield as StringField,\n\t\t\t\tfieldName,\n\t\t\t) as FieldValidationResult<T>;\n\t\tcase \"number\":\n\t\t\treturn validateNumber(\n\t\t\t\tvalue,\n\t\t\t\tfield as NumberField,\n\t\t\t\tfieldName,\n\t\t\t) as FieldValidationResult<T>;\n\t\tcase \"boolean\":\n\t\t\treturn validateBoolean(value, fieldName) as FieldValidationResult<T>;\n\t\tcase \"date\":\n\t\t\treturn validateDate(\n\t\t\t\tvalue,\n\t\t\t\tfield as DateField,\n\t\t\t\tfieldName,\n\t\t\t) as FieldValidationResult<T>;\n\t\tcase \"enum\":\n\t\t\treturn validateEnum(\n\t\t\t\tvalue,\n\t\t\t\tfield as EnumField,\n\t\t\t\tfieldName,\n\t\t\t) as FieldValidationResult<T>;\n\t\tcase \"array\":\n\t\t\treturn validateArray(\n\t\t\t\tvalue,\n\t\t\t\tfield as ArrayField,\n\t\t\t\tfieldName,\n\t\t\t\tdepth,\n\t\t\t) as FieldValidationResult<T>;\n\t\tcase \"json\":\n\t\t\treturn validateJSON(value, fieldName) as FieldValidationResult<T>;\n\t\tcase \"relation\":\n\t\t\treturn validateRelation(value, fieldName) as FieldValidationResult<T>;\n\t\tdefault:\n\t\t\treturn { success: true, data: value as T };\n\t}\n}\n\n/**\n * Validate string field\n */\nfunction validateString(\n\tvalue: unknown,\n\tfield: StringField,\n\tfieldName: string,\n): FieldValidationResult<string> {\n\tif (!isString(value)) {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: [\n\t\t\t\tcreateValidationError(\n\t\t\t\t\tfieldName,\n\t\t\t\t\t\"TYPE_MISMATCH\",\n\t\t\t\t\tformatErrorMessage(\"TYPE_MISMATCH\", fieldName, {\n\t\t\t\t\t\texpected: \"string\",\n\t\t\t\t\t\tactual: typeof value,\n\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\t],\n\t\t};\n\t}\n\n\tconst errors = [];\n\n\t// Min length\n\tif (field.minLength !== undefined && value.length < field.minLength) {\n\t\terrors.push(\n\t\t\tcreateValidationError(\n\t\t\t\tfieldName,\n\t\t\t\t\"MIN_LENGTH\",\n\t\t\t\tformatErrorMessage(\"MIN_LENGTH\", fieldName, { min: field.minLength }),\n\t\t\t\t{ value: value.length, expected: field.minLength },\n\t\t\t),\n\t\t);\n\t}\n\n\t// Max length\n\tif (field.maxLength !== undefined && value.length > field.maxLength) {\n\t\terrors.push(\n\t\t\tcreateValidationError(\n\t\t\t\tfieldName,\n\t\t\t\t\"MAX_LENGTH\",\n\t\t\t\tformatErrorMessage(\"MAX_LENGTH\", fieldName, { max: field.maxLength }),\n\t\t\t\t{ value: value.length, expected: field.maxLength },\n\t\t\t),\n\t\t);\n\t}\n\n\t// Pattern\n\tif (field.pattern && !field.pattern.test(value)) {\n\t\terrors.push(\n\t\t\tcreateValidationError(\n\t\t\t\tfieldName,\n\t\t\t\t\"PATTERN\",\n\t\t\t\tformatErrorMessage(\"PATTERN\", fieldName, { pattern: field.pattern }),\n\t\t\t\t{ value },\n\t\t\t),\n\t\t);\n\t}\n\n\t// Custom validator\n\tif (field.validator) {\n\t\tconst result = field.validator(value);\n\t\tif (result !== true) {\n\t\t\terrors.push(\n\t\t\t\tcreateValidationError(fieldName, \"CUSTOM\", result, { value }),\n\t\t\t);\n\t\t}\n\t}\n\n\tif (errors.length > 0) {\n\t\treturn { success: false, error: errors };\n\t}\n\n\treturn { success: true, data: value };\n}\n\n/**\n * Validate number field\n */\nfunction validateNumber(\n\tvalue: unknown,\n\tfield: NumberField,\n\tfieldName: string,\n): FieldValidationResult<number> {\n\tif (!isNumber(value)) {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: [\n\t\t\t\tcreateValidationError(\n\t\t\t\t\tfieldName,\n\t\t\t\t\t\"TYPE_MISMATCH\",\n\t\t\t\t\tformatErrorMessage(\"TYPE_MISMATCH\", fieldName, {\n\t\t\t\t\t\texpected: \"number\",\n\t\t\t\t\t\tactual: typeof value,\n\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\t],\n\t\t};\n\t}\n\n\tconst errors = [];\n\n\t// Integer check\n\tif (field.integer && !Number.isInteger(value)) {\n\t\terrors.push(\n\t\t\tcreateValidationError(\n\t\t\t\tfieldName,\n\t\t\t\t\"INVALID_FORMAT\",\n\t\t\t\t`Field '${fieldName}' must be an integer`,\n\t\t\t\t{ value },\n\t\t\t),\n\t\t);\n\t}\n\n\t// Min value\n\tif (field.min !== undefined && value < field.min) {\n\t\terrors.push(\n\t\t\tcreateValidationError(\n\t\t\t\tfieldName,\n\t\t\t\t\"MIN_VALUE\",\n\t\t\t\tformatErrorMessage(\"MIN_VALUE\", fieldName, { min: field.min }),\n\t\t\t\t{ value, expected: field.min },\n\t\t\t),\n\t\t);\n\t}\n\n\t// Max value\n\tif (field.max !== undefined && value > field.max) {\n\t\terrors.push(\n\t\t\tcreateValidationError(\n\t\t\t\tfieldName,\n\t\t\t\t\"MAX_VALUE\",\n\t\t\t\tformatErrorMessage(\"MAX_VALUE\", fieldName, { max: field.max }),\n\t\t\t\t{ value, expected: field.max },\n\t\t\t),\n\t\t);\n\t}\n\n\t// Custom validator\n\tif (field.validator) {\n\t\tconst result = field.validator(value);\n\t\tif (result !== true) {\n\t\t\terrors.push(\n\t\t\t\tcreateValidationError(fieldName, \"CUSTOM\", result, { value }),\n\t\t\t);\n\t\t}\n\t}\n\n\tif (errors.length > 0) {\n\t\treturn { success: false, error: errors };\n\t}\n\n\treturn { success: true, data: value };\n}\n\n/**\n * Validate boolean field\n */\nfunction validateBoolean(\n\tvalue: unknown,\n\tfieldName: string,\n): FieldValidationResult<boolean> {\n\tif (!isBoolean(value)) {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: [\n\t\t\t\tcreateValidationError(\n\t\t\t\t\tfieldName,\n\t\t\t\t\t\"TYPE_MISMATCH\",\n\t\t\t\t\tformatErrorMessage(\"TYPE_MISMATCH\", fieldName, {\n\t\t\t\t\t\texpected: \"boolean\",\n\t\t\t\t\t\tactual: typeof value,\n\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\t],\n\t\t};\n\t}\n\n\treturn { success: true, data: value };\n}\n\n/**\n * Validate date field\n */\nfunction validateDate(\n\tvalue: unknown,\n\tfield: DateField,\n\tfieldName: string,\n): FieldValidationResult<Date> {\n\t// First check if it's a Date object at all (not string, not number)\n\tif (!(value instanceof Date)) {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: [\n\t\t\t\tcreateValidationError(\n\t\t\t\t\tfieldName,\n\t\t\t\t\t\"TYPE_MISMATCH\",\n\t\t\t\t\tformatErrorMessage(\"TYPE_MISMATCH\", fieldName, {\n\t\t\t\t\t\texpected: \"Date\",\n\t\t\t\t\t\tactual: typeof value,\n\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\t],\n\t\t};\n\t}\n\n\t// Then check if it's a valid Date (not NaN)\n\tif (!isDate(value)) {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: [\n\t\t\t\tcreateValidationError(\n\t\t\t\t\tfieldName,\n\t\t\t\t\t\"INVALID_DATE\",\n\t\t\t\t\tformatErrorMessage(\"INVALID_DATE\", fieldName),\n\t\t\t\t),\n\t\t\t],\n\t\t};\n\t}\n\n\tconst errors = [];\n\n\t// Min date\n\tif (field.min && value < field.min) {\n\t\terrors.push(\n\t\t\tcreateValidationError(\n\t\t\t\tfieldName,\n\t\t\t\t\"MIN_VALUE\",\n\t\t\t\t`Field '${fieldName}' must be after ${field.min.toISOString()}`,\n\t\t\t\t{ value, expected: field.min },\n\t\t\t),\n\t\t);\n\t}\n\n\t// Max date\n\tif (field.max && value > field.max) {\n\t\terrors.push(\n\t\t\tcreateValidationError(\n\t\t\t\tfieldName,\n\t\t\t\t\"MAX_VALUE\",\n\t\t\t\t`Field '${fieldName}' must be before ${field.max.toISOString()}`,\n\t\t\t\t{ value, expected: field.max },\n\t\t\t),\n\t\t);\n\t}\n\n\tif (errors.length > 0) {\n\t\treturn { success: false, error: errors };\n\t}\n\n\treturn { success: true, data: value };\n}\n\n/**\n * Validate enum field\n */\nfunction validateEnum(\n\tvalue: unknown,\n\tfield: EnumField,\n\tfieldName: string,\n): FieldValidationResult<string> {\n\tif (!isString(value)) {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: [\n\t\t\t\tcreateValidationError(\n\t\t\t\t\tfieldName,\n\t\t\t\t\t\"TYPE_MISMATCH\",\n\t\t\t\t\tformatErrorMessage(\"TYPE_MISMATCH\", fieldName, {\n\t\t\t\t\t\texpected: \"string\",\n\t\t\t\t\t\tactual: typeof value,\n\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\t],\n\t\t};\n\t}\n\n\tif (!field.values.includes(value)) {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: [\n\t\t\t\tcreateValidationError(\n\t\t\t\t\tfieldName,\n\t\t\t\t\t\"INVALID_ENUM\",\n\t\t\t\t\tformatErrorMessage(\"INVALID_ENUM\", fieldName, {\n\t\t\t\t\t\texpected: field.values.join(\", \"),\n\t\t\t\t\t}),\n\t\t\t\t\t{ value, expected: field.values },\n\t\t\t\t),\n\t\t\t],\n\t\t};\n\t}\n\n\treturn { success: true, data: value };\n}\n\n/**\n * Validate array field\n */\nfunction validateArray(\n\tvalue: unknown,\n\tfield: ArrayField,\n\tfieldName: string,\n\tdepth: number,\n): FieldValidationResult<readonly unknown[]> {\n\tif (!isArray(value)) {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: [\n\t\t\t\tcreateValidationError(\n\t\t\t\t\tfieldName,\n\t\t\t\t\t\"TYPE_MISMATCH\",\n\t\t\t\t\tformatErrorMessage(\"TYPE_MISMATCH\", fieldName, {\n\t\t\t\t\t\texpected: \"array\",\n\t\t\t\t\t\tactual: typeof value,\n\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\t],\n\t\t};\n\t}\n\n\tconst errors = [];\n\n\t// Min items\n\tif (field.minItems !== undefined && value.length < field.minItems) {\n\t\terrors.push(\n\t\t\tcreateValidationError(\n\t\t\t\tfieldName,\n\t\t\t\t\"MIN_ITEMS\",\n\t\t\t\tformatErrorMessage(\"MIN_ITEMS\", fieldName, { min: field.minItems }),\n\t\t\t\t{ value: value.length, expected: field.minItems },\n\t\t\t),\n\t\t);\n\t}\n\n\t// Max items\n\tif (field.maxItems !== undefined && value.length > field.maxItems) {\n\t\terrors.push(\n\t\t\tcreateValidationError(\n\t\t\t\tfieldName,\n\t\t\t\t\"MAX_ITEMS\",\n\t\t\t\tformatErrorMessage(\"MAX_ITEMS\", fieldName, { max: field.maxItems }),\n\t\t\t\t{ value: value.length, expected: field.maxItems },\n\t\t\t),\n\t\t);\n\t}\n\n\t// Unique items check\n\tif (field.unique) {\n\t\tconst seen = new Set<unknown>();\n\t\tconst duplicates = new Set<unknown>();\n\n\t\tfor (const item of value) {\n\t\t\t// Use JSON.stringify for deep comparison of objects/arrays\n\t\t\tconst itemKey =\n\t\t\t\ttypeof item === \"object\" && item !== null ? JSON.stringify(item) : item;\n\n\t\t\tif (seen.has(itemKey)) {\n\t\t\t\tduplicates.add(item);\n\t\t\t} else {\n\t\t\t\tseen.add(itemKey);\n\t\t\t}\n\t\t}\n\n\t\tif (duplicates.size > 0) {\n\t\t\terrors.push(\n\t\t\t\tcreateValidationError(\n\t\t\t\t\tfieldName,\n\t\t\t\t\t\"UNIQUE\",\n\t\t\t\t\tformatErrorMessage(\"UNIQUE\", fieldName),\n\t\t\t\t\t{ value: Array.from(duplicates) },\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t}\n\n\t// Validate each item\n\tfor (let i = 0; i < value.length; i++) {\n\t\tconst item = value[i];\n\t\tconst itemResult = validateField(\n\t\t\titem,\n\t\t\tfield.items,\n\t\t\t`${fieldName}[${i}]`,\n\t\t\tdepth + 1,\n\t\t);\n\t\tif (!itemResult.success) {\n\t\t\terrors.push(...itemResult.error);\n\t\t}\n\t}\n\n\tif (errors.length > 0) {\n\t\treturn { success: false, error: errors };\n\t}\n\n\treturn { success: true, data: value };\n}\n\n/**\n * Validate JSON field\n * JSON fields can be objects, arrays, or any valid JSON type\n */\nfunction validateJSON(\n\tvalue: unknown,\n\tfieldName: string,\n): FieldValidationResult<unknown> {\n\t// JSON field accepts: objects, arrays, strings, numbers, booleans, null\n\t// Reject: undefined, Date objects (should be serialized to string first)\n\tif (value === undefined || isDate(value)) {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: [\n\t\t\t\tcreateValidationError(\n\t\t\t\t\tfieldName,\n\t\t\t\t\t\"TYPE_MISMATCH\",\n\t\t\t\t\tformatErrorMessage(\"TYPE_MISMATCH\", fieldName, {\n\t\t\t\t\t\texpected:\n\t\t\t\t\t\t\t\"valid JSON type (object, array, string, number, boolean, null)\",\n\t\t\t\t\t\tactual: value === undefined ? \"undefined\" : \"Date\",\n\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\t],\n\t\t};\n\t}\n\n\treturn { success: true, data: value };\n}\n\n/**\n * Validate relation field\n * Supports both shortcut (ID) and RelationInput object\n */\nfunction validateRelation(\n\tvalue: unknown,\n\tfieldName: string,\n): FieldValidationResult<unknown> {\n\t// 1. Shortcut: ID (string or number)\n\tif (typeof value === \"string\" || typeof value === \"number\") {\n\t\treturn { success: true, data: value };\n\t}\n\n\t// 2. RelationInput object: { connect, disconnect, set, create, update, delete }\n\tif (typeof value === \"object\" && value !== null && !Array.isArray(value)) {\n\t\tconst input = value as Record<string, unknown>;\n\t\tconst validKeys = [\n\t\t\t\"connect\",\n\t\t\t\"disconnect\",\n\t\t\t\"set\",\n\t\t\t\"create\",\n\t\t\t\"update\",\n\t\t\t\"delete\",\n\t\t];\n\n\t\t// Check if at least one valid key exists\n\t\tconst hasValidKey = validKeys.some((key) => key in input);\n\t\tif (!hasValidKey) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: [\n\t\t\t\t\tcreateValidationError(\n\t\t\t\t\t\tfieldName,\n\t\t\t\t\t\t\"INVALID_FORMAT\",\n\t\t\t\t\t\t`Relation field '${fieldName}' must be an ID or a valid RelationInput object`,\n\t\t\t\t\t\t{ value },\n\t\t\t\t\t),\n\t\t\t\t],\n\t\t\t};\n\t\t}\n\n\t\t// Structural validation for common keys (shallow)\n\t\tif (input[\"connect\"]) {\n\t\t\tconst connect = input[\"connect\"];\n\t\t\tif (Array.isArray(connect)) {\n\t\t\t\tif (!connect.every((item) => typeof item === \"number\")) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tsuccess: false,\n\t\t\t\t\t\terror: [\n\t\t\t\t\t\t\tcreateValidationError(\n\t\t\t\t\t\t\t\tfieldName,\n\t\t\t\t\t\t\t\t\"INVALID_FORMAT\",\n\t\t\t\t\t\t\t\t\"connect must be a number or array of numbers\",\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t],\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t} else if (typeof connect !== \"number\") {\n\t\t\t\treturn {\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\terror: [\n\t\t\t\t\t\tcreateValidationError(\n\t\t\t\t\t\t\tfieldName,\n\t\t\t\t\t\t\t\"INVALID_FORMAT\",\n\t\t\t\t\t\t\t\"connect must be a number or array of numbers\",\n\t\t\t\t\t\t),\n\t\t\t\t\t],\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\t// If 'set' is provided, it must be an array of numbers\n\t\tif (input[\"set\"]) {\n\t\t\tif (\n\t\t\t\t!Array.isArray(input[\"set\"]) ||\n\t\t\t\t!(input[\"set\"] as unknown[]).every((item) => typeof item === \"number\")\n\t\t\t) {\n\t\t\t\treturn {\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\terror: [\n\t\t\t\t\t\tcreateValidationError(\n\t\t\t\t\t\t\tfieldName,\n\t\t\t\t\t\t\t\"INVALID_FORMAT\",\n\t\t\t\t\t\t\t\"set must be an array of numbers\",\n\t\t\t\t\t\t),\n\t\t\t\t\t],\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\treturn { success: true, data: value };\n\t}\n\n\treturn {\n\t\tsuccess: false,\n\t\terror: [\n\t\t\tcreateValidationError(\n\t\t\t\tfieldName,\n\t\t\t\t\"TYPE_MISMATCH\",\n\t\t\t\tformatErrorMessage(\"TYPE_MISMATCH\", fieldName, {\n\t\t\t\t\texpected: \"ID or RelationInput object\",\n\t\t\t\t\tactual: typeof value,\n\t\t\t\t}),\n\t\t\t),\n\t\t],\n\t};\n}\n","/**\n * Schema Validator Implementation\n *\n * Validates entire objects against schema definitions.\n * Orchestrates field-level validation for all fields.\n *\n * Architecture:\n * - validateSchema: Full validation - iterates ALL schema fields, checks required\n * - validatePartial: Partial validation - iterates ONLY data keys, still checks required\n * - Both use validateSingleField for actual field validation (no code duplication)\n */\n\nimport type {\n\tSchemaDefinition,\n\tFieldDefinition,\n\tDatrixEntry,\n\tRelationField,\n} from \"../types/core/schema\";\nimport type { ValidatorOptions } from \"../types/core/validator\";\nimport { validateField } from \"./field-validator\";\nimport {\n\tcreateValidationError,\n\tthrowValidationMultiple,\n\tValidationErrorCollection,\n} from \"./errors\";\n\n/**\n * Default validator options\n */\nconst DEFAULT_OPTIONS: Required<ValidatorOptions> = {\n\tstrict: true,\n\tcoerce: false,\n\tstripUnknown: false,\n\tabortEarly: false,\n};\n\n/**\n * Reserved field names that are auto-managed\n */\nconst RESERVED_FIELDS = [\"id\", \"createdAt\", \"updatedAt\"];\n\n/**\n * Check if a field is a relation with foreign key\n */\nfunction isRelationWithForeignKey(\n\tfieldDef: FieldDefinition,\n): fieldDef is RelationField {\n\treturn (\n\t\tfieldDef.type === \"relation\" &&\n\t\t(fieldDef.kind === \"belongsTo\" || fieldDef.kind === \"hasOne\")\n\t);\n}\n\n/**\n * Get value from input data, handling relation foreign key fallback\n */\nfunction getFieldValue(\n\tinputData: Record<string, unknown>,\n\tfieldName: string,\n\tfieldDef: FieldDefinition,\n): unknown {\n\tlet value = inputData[fieldName];\n\n\t// Fallback to foreign key for belongsTo/hasOne relations\n\tif (!value && isRelationWithForeignKey(fieldDef) && fieldDef.foreignKey) {\n\t\tvalue = inputData[fieldDef.foreignKey];\n\t}\n\n\treturn value;\n}\n\n/**\n * Validate a single field and collect errors\n *\n * This is the shared validation logic used by both validateSchema and validatePartial.\n * Uses the ORIGINAL field definition (required is NOT modified).\n */\nfunction validateSingleField(\n\tvalue: unknown,\n\tfieldDef: FieldDefinition,\n\tfieldName: string,\n\terrors: ValidationErrorCollection,\n\topts: Required<ValidatorOptions>,\n\tschemaName: string,\n): { errors: ValidationErrorCollection; validatedValue?: unknown } {\n\tconst result = validateField(value, fieldDef, fieldName);\n\n\tif (!result.success) {\n\t\terrors = errors.addMany(result.error);\n\n\t\tif (opts.abortEarly) {\n\t\t\tthrowValidationMultiple(schemaName, errors.getAll());\n\t\t}\n\n\t\treturn { errors };\n\t}\n\n\treturn { errors, validatedValue: result.data };\n}\n\n/**\n * Handle unknown fields based on options\n */\nfunction handleUnknownFields(\n\tinputData: Record<string, unknown>,\n\tschemaFields: Record<string, FieldDefinition>,\n\tvalidatedData: Record<string, unknown>,\n\terrors: ValidationErrorCollection,\n\topts: Required<ValidatorOptions>,\n\tschemaName: string,\n): ValidationErrorCollection {\n\tif (opts.strict) {\n\t\tfor (const key of Object.keys(inputData)) {\n\t\t\tif (!(key in schemaFields)) {\n\t\t\t\terrors = errors.add(\n\t\t\t\t\tcreateValidationError(\n\t\t\t\t\t\tkey,\n\t\t\t\t\t\t\"UNKNOWN\",\n\t\t\t\t\t\t`Unknown field '${key}' in schema '${schemaName}'`,\n\t\t\t\t\t),\n\t\t\t\t);\n\n\t\t\t\tif (opts.abortEarly) {\n\t\t\t\t\tthrowValidationMultiple(schemaName, errors.getAll());\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} else if (!opts.stripUnknown) {\n\t\t// Include unknown fields in validated data\n\t\tfor (const [key, value] of Object.entries(inputData)) {\n\t\t\tif (!(key in schemaFields)) {\n\t\t\t\tvalidatedData[key] = value;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn errors;\n}\n\n/**\n * Validate input is a valid object\n */\nfunction assertValidObject(\n\tdata: unknown,\n\tschemaName: string,\n): asserts data is Record<string, unknown> {\n\tif (typeof data !== \"object\" || data === null || Array.isArray(data)) {\n\t\tthrowValidationMultiple(schemaName, [\n\t\t\tcreateValidationError(\n\t\t\t\tschemaName,\n\t\t\t\t\"TYPE_MISMATCH\",\n\t\t\t\t`Expected object, got ${Array.isArray(data) ? \"array\" : typeof data}`,\n\t\t\t),\n\t\t]);\n\t}\n}\n\n/**\n * Validate data against schema (full validation for CREATE)\n *\n * Iterates ALL schema fields and validates each one.\n * Required fields that are missing will fail validation.\n */\nexport function validateSchema<T extends DatrixEntry>(\n\tdata: unknown,\n\tschema: SchemaDefinition,\n\toptions?: ValidatorOptions,\n): T {\n\tconst opts = { ...DEFAULT_OPTIONS, ...options };\n\tlet errors = new ValidationErrorCollection();\n\n\tassertValidObject(data, schema.name);\n\n\tconst inputData = data as Record<string, unknown>;\n\tconst validatedData: Record<string, unknown> = {};\n\n\t// Validate each field in schema\n\tfor (const [fieldName, fieldDef] of Object.entries(schema.fields)) {\n\t\t// Skip reserved fields - auto-generated by database/adapter\n\t\tif (RESERVED_FIELDS.includes(fieldName)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst value = getFieldValue(inputData, fieldName, fieldDef);\n\n\t\t// Skip hidden fields if not provided - these are typically auto-managed (like FKs)\n\t\t// and will be filled later in the CRUD flow or by the database.\n\t\tif (fieldDef.hidden && value === undefined) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Validate field with original definition (required check included)\n\t\tconst result = validateSingleField(\n\t\t\tvalue,\n\t\t\tfieldDef,\n\t\t\tfieldName,\n\t\t\terrors,\n\t\t\topts,\n\t\t\tschema.name,\n\t\t);\n\n\t\terrors = result.errors;\n\t\tif (result.validatedValue !== undefined) {\n\t\t\tvalidatedData[fieldName] = result.validatedValue;\n\t\t}\n\t}\n\n\t// Handle unknown fields\n\terrors = handleUnknownFields(\n\t\tinputData,\n\t\tschema.fields,\n\t\tvalidatedData,\n\t\terrors,\n\t\topts,\n\t\tschema.name,\n\t);\n\n\tif (errors.hasErrors()) {\n\t\tthrowValidationMultiple(schema.name, errors.getAll());\n\t}\n\n\treturn validatedData as T;\n}\n\n/**\n * Validate partial data (for UPDATE operations)\n *\n * Iterates ONLY the fields present in input data.\n * Each provided field is validated with its ORIGINAL definition (required check included).\n *\n * Key difference from validateSchema:\n * - validateSchema: Missing required field = ERROR (field not in data)\n * - validatePartial: Missing required field = OK (field not in data, not being updated)\n * - validatePartial: Required field set to null = ERROR (explicitly setting to null)\n */\nexport function validatePartial<T extends DatrixEntry>(\n\tdata: unknown,\n\tschema: SchemaDefinition,\n\toptions?: ValidatorOptions,\n): Partial<T> {\n\tconst opts = { ...DEFAULT_OPTIONS, ...options };\n\tlet errors = new ValidationErrorCollection();\n\n\tassertValidObject(data, schema.name);\n\n\tconst inputData = data as Record<string, unknown>;\n\tconst validatedData: Record<string, unknown> = {};\n\n\t// Validate ONLY fields that are present in input\n\tfor (const [fieldName, value] of Object.entries(inputData)) {\n\t\t// Skip reserved fields - cannot be modified\n\t\tif (RESERVED_FIELDS.includes(fieldName)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst fieldDef = schema.fields[fieldName];\n\n\t\t// Check if field exists in schema\n\t\tif (!fieldDef) {\n\t\t\tif (opts.strict) {\n\t\t\t\terrors = errors.add(\n\t\t\t\t\tcreateValidationError(\n\t\t\t\t\t\tfieldName,\n\t\t\t\t\t\t\"UNKNOWN\",\n\t\t\t\t\t\t`Unknown field '${fieldName}' in schema '${schema.name}'`,\n\t\t\t\t\t),\n\t\t\t\t);\n\n\t\t\t\tif (opts.abortEarly) {\n\t\t\t\t\tthrowValidationMultiple(schema.name, errors.getAll());\n\t\t\t\t}\n\t\t\t} else if (!opts.stripUnknown) {\n\t\t\t\tvalidatedData[fieldName] = value;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Validate field with ORIGINAL definition (required check included)\n\t\t// If user explicitly sets a required field to null, it will fail\n\t\tconst result = validateSingleField(\n\t\t\tvalue,\n\t\t\tfieldDef,\n\t\t\tfieldName,\n\t\t\terrors,\n\t\t\topts,\n\t\t\tschema.name,\n\t\t);\n\n\t\terrors = result.errors;\n\t\tif (result.validatedValue !== undefined) {\n\t\t\tvalidatedData[fieldName] = result.validatedValue;\n\t\t}\n\t}\n\n\tif (errors.hasErrors()) {\n\t\tthrowValidationMultiple(schema.name, errors.getAll());\n\t}\n\n\treturn validatedData as Partial<T>;\n}\n\n/**\n * Validate array of data (for bulk CREATE)\n */\nexport function validateMany<T extends DatrixEntry>(\n\tdataArray: unknown,\n\tschema: SchemaDefinition,\n\toptions?: ValidatorOptions,\n): readonly T[] {\n\tconst opts = { ...DEFAULT_OPTIONS, ...options };\n\n\tif (!Array.isArray(dataArray)) {\n\t\tthrowValidationMultiple(schema.name, [\n\t\t\tcreateValidationError(\n\t\t\t\tschema.name,\n\t\t\t\t\"TYPE_MISMATCH\",\n\t\t\t\t`Expected array, got ${typeof dataArray}`,\n\t\t\t),\n\t\t]);\n\t}\n\n\tconst validatedArray: T[] = [];\n\n\tfor (let i = 0; i < dataArray.length; i++) {\n\t\tconst item = dataArray[i];\n\t\tconst result = validateSchema<T>(item, schema, opts);\n\t\tvalidatedArray.push(result);\n\t}\n\n\treturn validatedArray;\n}\n\n/**\n * Check if data matches schema (returns boolean, does not throw)\n */\nexport function isValid(\n\tdata: unknown,\n\tschema: SchemaDefinition,\n\toptions?: ValidatorOptions,\n): boolean {\n\ttry {\n\t\tvalidateSchema(data, schema, options);\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n/**\n * Type guard for schema validation\n */\nexport function assertSchema<T>(\n\tdata: unknown,\n\tschema: SchemaDefinition,\n\toptions?: ValidatorOptions,\n): asserts data is T {\n\tvalidateSchema(data, schema, options);\n}\n","/**\n * Query Executor Error Helpers\n *\n * Centralized error creation for query executor operations.\n */\n\nimport {\n\tCrudErrorCode,\n\tCrudErrorContext,\n\tCrudOperation,\n\tDatrixCrudError,\n\tDatrixError,\n} from \"../types/errors\";\n\n/**\n * Options for throwing CRUD errors\n */\nexport interface ThrowCrudErrorOptions {\n\treadonly operation: CrudOperation;\n\treadonly model: string;\n\treadonly code: CrudErrorCode;\n\treadonly message?: string;\n\treadonly cause?: Error;\n\treadonly context?: CrudErrorContext;\n\treadonly suggestion?: string;\n\treadonly expected?: string;\n\treadonly received?: unknown;\n}\n\n/**\n * Throws a standardized CRUD error\n *\n * @param options - Error options\n * @throws DatrixCrudError\n *\n * @example\n * ```ts\n * throwCrudError({\n * operation: 'findOne',\n * model: 'User',\n * code: 'QUERY_EXECUTION_FAILED',\n * cause: dbError,\n * context: { query }\n * });\n * ```\n */\nexport function throwCrudError(options: ThrowCrudErrorOptions): never {\n\tconst {\n\t\toperation,\n\t\tmodel,\n\t\tcode,\n\t\tmessage,\n\t\tcause,\n\t\tcontext,\n\t\tsuggestion,\n\t\texpected,\n\t\treceived,\n\t} = options;\n\n\tconst defaultMessage = generateDefaultMessage(operation, model, code);\n\n\tthrow new DatrixCrudError(message ?? defaultMessage, {\n\t\tcode,\n\t\toperation,\n\t\tmodel,\n\t\tcontext: enhanceContext(context, cause),\n\t\tcause,\n\t\tsuggestion,\n\t\texpected,\n\t\treceived,\n\t});\n}\n\n/**\n * Enhance context with adapter error details if available\n */\nfunction enhanceContext(\n\tcontext: CrudErrorContext | undefined,\n\tcause: Error | undefined,\n): CrudErrorContext | undefined {\n\tif (!cause) {\n\t\treturn context;\n\t}\n\n\treturn {\n\t\t...context,\n\t\tadapterError: cause.message,\n\t};\n}\n\n/**\n * Generate a default error message based on operation and code\n */\nfunction generateDefaultMessage(\n\toperation: CrudOperation,\n\tmodel: string,\n\tcode: CrudErrorCode,\n): string {\n\tswitch (code) {\n\t\tcase \"QUERY_EXECUTION_FAILED\":\n\t\t\treturn `Failed to execute ${operation} query for ${model}`;\n\t\tcase \"SCHEMA_NOT_FOUND\":\n\t\t\treturn `Schema '${model}' not found`;\n\t\tcase \"RECORD_NOT_FOUND\":\n\t\t\treturn `${model} record not found`;\n\t\tcase \"INVALID_POPULATE_VALUE\":\n\t\t\treturn `Invalid populate value for ${model}`;\n\t\tcase \"RESERVED_FIELD_WRITE\":\n\t\t\treturn `Cannot write to reserved field in ${model}`;\n\t\tcase \"NOT_IMPLEMENTED\":\n\t\t\treturn `${operation} not implemented for ${model}`;\n\t\tcase \"QUERY_FAILED\":\n\t\t\treturn `Query failed for ${model}`;\n\t\tdefault:\n\t\t\treturn `CRUD operation failed for ${model}`;\n\t}\n}\n\n/**\n * Throw unsupported query type error\n *\n * @param queryType - The unsupported query type\n *\n * @example\n * ```ts\n * throwUnsupportedQueryType('invalid');\n * // Error: Unsupported query type: invalid\n * ```\n */\nexport function throwUnsupportedQueryType(queryType: unknown): never {\n\tthrow new DatrixError(`Unsupported query type: ${queryType}`, {\n\t\tcode: \"UNSUPPORTED_QUERY_TYPE\",\n\t\tcontext: { queryType },\n\t\tsuggestion: \"Use one of: select, insert, update, delete, count\",\n\t\texpected: \"select | insert | update | delete | count\",\n\t\treceived: queryType,\n\t});\n}\n\n/**\n * Helper for schema not found errors\n */\nexport function throwSchemaNotFoundError(model: string): never {\n\tthrowCrudError({\n\t\toperation: \"findOne\",\n\t\tmodel,\n\t\tcode: \"SCHEMA_NOT_FOUND\",\n\t\tsuggestion: `Make sure the schema '${model}' is registered in your Datrix instance`,\n\t});\n}\n\n/**\n * Helper for reserved field write errors\n */\nexport function throwReservedFieldError(field: string, model: string): never {\n\tthrowCrudError({\n\t\toperation: \"create\",\n\t\tmodel,\n\t\tcode: \"RESERVED_FIELD_WRITE\",\n\t\tmessage: `Cannot set reserved field '${field}'`,\n\t\tsuggestion: `Use datrix.raw.create() or datrix.raw.update() for manual control of '${field}'`,\n\t});\n}\n\n/**\n * Helper for record not found errors (single id operations)\n *\n * @param operation - The CRUD operation (update or delete)\n * @param model - Model name\n * @param id - The record ID that was not found\n *\n * @example\n * ```ts\n * throwRecordNotFound('update', 'User', 123);\n * // Error: User record with id 123 not found\n * ```\n */\nexport function throwRecordNotFound(\n\toperation: \"update\" | \"delete\",\n\tmodel: string,\n\tid: number,\n): never {\n\tthrowCrudError({\n\t\toperation,\n\t\tmodel,\n\t\tcode: \"RECORD_NOT_FOUND\",\n\t\tmessage: `${model} record with id ${id} not found`,\n\t\tcontext: { recordId: id },\n\t\tsuggestion: `Verify that the ${model} with id ${id} exists before attempting to ${operation}`,\n\t});\n}\n\n/**\n * Helper for relation target not found errors\n *\n * Thrown when connect/set references IDs that don't exist in the target table.\n *\n * @param parentModel - Parent model name (e.g., \"Post\")\n * @param relationField - Relation field name (e.g., \"tags\")\n * @param targetModel - Target model name (e.g., \"Tag\")\n * @param missingIds - Array of IDs that were not found\n *\n * @example\n * ```ts\n * throwRelationTargetNotFound('Post', 'tags', 'Tag', [999, 1000]);\n * // Error: Cannot connect Post.tags: Tag records with ids [999, 1000] not found\n * ```\n */\nexport function throwRelationTargetNotFound(\n\tparentModel: string,\n\trelationField: string,\n\ttargetModel: string,\n\tmissingIds: readonly number[],\n): never {\n\tconst idsStr =\n\t\tmissingIds.length === 1\n\t\t\t? `id ${missingIds[0]}`\n\t\t\t: `ids [${missingIds.join(\", \")}]`;\n\n\tthrowCrudError({\n\t\toperation: \"update\",\n\t\tmodel: parentModel,\n\t\tcode: \"RECORD_NOT_FOUND\",\n\t\tmessage: `Cannot connect ${parentModel}.${relationField}: ${targetModel} records with ${idsStr} not found`,\n\t\tcontext: {\n\t\t\trelationField,\n\t\t\ttargetModel,\n\t\t\tmissingIds: [...missingIds],\n\t\t},\n\t\tsuggestion: `Verify that all ${targetModel} IDs exist before connecting them to ${parentModel}.${relationField}`,\n\t});\n}\n","/**\n * Data Validation and Timestamp Management\n *\n * Handles:\n * 1. Reserved field checks\n * 2. Timestamp injection (before validation)\n * 3. Schema validation (min/max/regex/type/required)\n */\n\nimport {\n\tDatrixEntry,\n\tSchemaDefinition,\n\tRESERVED_FIELDS,\n} from \"../types/core/schema\";\nimport { validatePartial, validateSchema } from \"../validator\";\nimport { throwReservedFieldError } from \"./error-helper\";\nimport { QueryRelations } from \"../types/core/query-builder\";\n\n/**\n * Validation options\n */\nexport interface ValidationOptions {\n\t/** If true, use partial validation (for updates) */\n\tpartial: boolean;\n\t/** If true, this is a create operation (affects timestamp handling) */\n\tisCreate: boolean;\n\t/** If true, allow user to override timestamps (raw mode) */\n\tisRawMode: boolean;\n}\n\n/**\n * Check for reserved fields in user data\n *\n * Reserved fields (id, createdAt, updatedAt) are automatically managed\n * and cannot be set manually in normal mode.\n *\n * @param data - Data to check\n * @param isRawMode - If true, skip the check\n * @throws {DatrixError} If reserved field is found in normal mode\n *\n * @example\n * ```ts\n * // Normal mode\n * checkReservedFields({ id: 1, name: 'John' }, false);\n * // Throws: Cannot manually set reserved field 'id'\n *\n * // Raw mode\n * checkReservedFields({ id: 1, name: 'John' }, true);\n * // OK (raw mode allows override)\n * ```\n */\nfunction checkReservedFields<T extends DatrixEntry>(\n\tdata: Partial<T> | undefined,\n\tisRawMode: boolean,\n): void {\n\tif (isRawMode || !data) {\n\t\treturn;\n\t}\n\n\tfor (const field of RESERVED_FIELDS) {\n\t\tif (field in data) {\n\t\t\tthrowReservedFieldError(field, \"unknown\");\n\t\t}\n\t}\n}\n\n/**\n * Add timestamps to data before validation\n *\n * **Timestamp Rules:**\n *\n * **CREATE:**\n * - Normal mode: Always add createdAt + updatedAt (override user values)\n * - Raw mode: Add only if not provided (user can override)\n *\n * **UPDATE:**\n * - Normal mode: Always add updatedAt (override user value)\n * - Raw mode: Add only if not provided (user can override)\n *\n * @param data - Input data\n * @param options - Validation options\n * @returns Data with timestamps\n *\n * @example\n * ```ts\n * // CREATE (normal mode)\n * addTimestamps({ name: 'John' }, { isCreate: true, isRawMode: false });\n * // { name: 'John', createdAt: Date, updatedAt: Date }\n *\n * // CREATE (raw mode, user override)\n * addTimestamps(\n * { name: 'John', createdAt: new Date('2020-01-01') },\n * { isCreate: true, isRawMode: true }\n * );\n * // { name: 'John', createdAt: Date('2020-01-01'), updatedAt: Date('2020-01-01') }\n *\n * // UPDATE (normal mode)\n * addTimestamps({ name: 'Jane' }, { isCreate: false, isRawMode: false });\n * // { name: 'Jane', updatedAt: Date }\n * ```\n */\nfunction addTimestamps<T extends DatrixEntry>(\n\tdata: Partial<T> | undefined,\n\toptions: Pick<ValidationOptions, \"isCreate\" | \"isRawMode\">,\n): Partial<T> {\n\tconst { isCreate, isRawMode } = options;\n\tconst now = new Date();\n\tconst result: Partial<T> = !!data ? { ...data } : ({} as Partial<T>);\n\n\tif (isCreate) {\n\t\tif (isRawMode) {\n\t\t\t// Raw mode: Smart defaults (only if not provided)\n\t\t\tif (!result.createdAt) {\n\t\t\t\tresult.createdAt = now;\n\t\t\t}\n\t\t\tif (!result.updatedAt) {\n\t\t\t\tresult.updatedAt = result.createdAt;\n\t\t\t}\n\t\t} else {\n\t\t\t// Normal mode: Always add timestamps (override)\n\t\t\tresult.createdAt = now;\n\t\t\tresult.updatedAt = now;\n\t\t}\n\t} else {\n\t\t// Update operation\n\t\tif (isRawMode) {\n\t\t\t// Raw mode: Add updatedAt only if not provided\n\t\t\tif (!result.updatedAt) {\n\t\t\t\tresult.updatedAt = now;\n\t\t\t}\n\t\t} else {\n\t\t\t// Normal mode: Always update timestamp (override)\n\t\t\tresult.updatedAt = now;\n\t\t}\n\t}\n\n\treturn result;\n}\n\n/**\n * Validate data against schema with timestamp handling\n *\n * **Flow:**\n * 1. Check reserved fields (only in normal mode)\n * 2. Add timestamps BEFORE validation (so required fields pass)\n * 3. Schema validation (min/max/regex/type/required)\n *\n * @param data - Data to validate\n * @param schema - Schema definition\n * @param options - Validation options\n * @returns Validated data with timestamps\n * @throws {DatrixError} If validation fails or reserved field found\n *\n * @example\n * ```ts\n * // CREATE (normal mode)\n * validateData(\n * { name: 'John', age: 25 },\n * userSchema,\n * { partial: false, isCreate: true, isRawMode: false }\n * );\n * // { name: 'John', age: 25, createdAt: Date, updatedAt: Date }\n *\n * // UPDATE (partial)\n * validateData(\n * { age: 26 },\n * userSchema,\n * { partial: true, isCreate: false, isRawMode: false }\n * );\n * // { age: 26, updatedAt: Date }\n * ```\n */\nexport function validateData<\n\tT extends DatrixEntry = DatrixEntry,\n\tP extends boolean = false,\n>(\n\tdata: Partial<T> | undefined,\n\trelations: QueryRelations<T> | undefined,\n\tschema: SchemaDefinition,\n\toptions: ValidationOptions,\n): P extends true ? Partial<T> : T {\n\tconst { partial, isCreate, isRawMode } = options;\n\n\t// 1. Check for reserved fields (only in normal mode)\n\tcheckReservedFields(data, isRawMode);\n\n\t// 2. Add timestamps BEFORE validation (so required fields like createdAt pass)\n\tconst dataWithTimestamps = schema._isJunctionTable\n\t\t? data\n\t\t: addTimestamps(data, { isCreate, isRawMode });\n\n\t// 3. Schema validation (with timestamps already present)\n\tconst validationOptions = {\n\t\tstrict: true,\n\t\tstripUnknown: false,\n\t\tabortEarly: false,\n\t};\n\n\tconst combined = { ...(dataWithTimestamps ?? {}), ...(relations ?? {}) };\n\n\tif (partial) {\n\t\tvalidatePartial(combined, schema, validationOptions);\n\t} else {\n\t\tvalidateSchema(combined, schema, validationOptions);\n\t}\n\n\treturn dataWithTimestamps as P extends true ? Partial<T> : T;\n}\n","/**\n * Relation Processing for Query Executor\n *\n * Strategy: \"Resolve-then-link\"\n * 1. Execute create/update/delete first (recursive, via executor)\n * 2. Merge created IDs into connect/set arrays\n * 3. Process only ID-based operations (connect/disconnect/set)\n *\n * This prevents duplicate creation when updateMany targets multiple records.\n * create/update run ONCE, then each parent only does ID-based linking.\n */\n\nimport {\n\tQueryRelations,\n\tNormalizedRelationOperations,\n\tWhereClause,\n} from \"../types/core/query-builder\";\nimport { validateData } from \"./validation\";\nimport { DatrixEntry, DatrixRecord } from \"../types/core/entry\";\nimport { SchemaDefinition } from \"../types\";\nimport { QueryRunner } from \"../types/adapter\";\nimport { ISchemaRegistry } from \"../types/core/schema\";\n\n/**\n * Resolved relation operations (mutable, after CUD resolution)\n *\n * After resolveCUD runs, create/update/delete are consumed and\n * their resulting IDs are merged into connect/set.\n * Only ID-based operations remain for per-parent linking.\n */\ninterface ResolvedRelationOps {\n\tconnect: number[];\n\tdisconnect: number[];\n\tset: number[] | undefined;\n\tdeleteIds: number[];\n}\n\n/**\n * Process all relation operations for a single parent record\n *\n * Called per-parent from executor. By this point, CUD operations\n * should already be resolved via resolveRelationCUD.\n *\n * @param resolvedRelations - Pre-resolved relation ops (ID-based only)\n * @param parentId - Parent record ID\n * @param parentModel - Parent model name\n * @param schema - Parent schema definition\n * @param executor - Query executor\n * @param schemaRegistry - Schema registry\n */\nexport async function processRelations<T extends DatrixEntry>(\n\tresolvedRelations: Record<string, ResolvedRelationOps>,\n\tparentId: number,\n\tparentModel: string,\n\tschema: SchemaDefinition,\n\trunner: QueryRunner,\n\tschemaRegistry: ISchemaRegistry,\n): Promise<void> {\n\tfor (const [fieldName, ops] of Object.entries(resolvedRelations)) {\n\t\tawait processRelation<T>({\n\t\t\tparentId,\n\t\t\tparentModel,\n\t\t\tfieldName,\n\t\t\tops,\n\t\t\tschema,\n\t\t\trunner,\n\t\t\tschemaRegistry,\n\t\t});\n\t}\n}\n\n/**\n * Resolve CUD operations from relation data\n *\n * Executes create/update/delete ONCE, then merges resulting IDs\n * into connect arrays. Returns resolved ops ready for per-parent linking.\n *\n * This is called ONCE before the per-parent loop in executor,\n * preventing duplicate creation when updateMany targets N records.\n *\n * @param relations - Raw relation operations from QueryObject\n * @param schema - Parent schema definition\n * @param executor - Query executor\n * @param schemaRegistry - Schema registry\n * @returns Resolved relation ops per field (ID-based only)\n *\n * @example\n * ```ts\n * // Input: { tags: { create: [{ data: { name: 'New' } }], connect: [1] } }\n * // Output: { tags: { connect: [1, 42], disconnect: [], set: undefined, deleteIds: [] } }\n * // ↑ 42 = newly created tag ID\n * ```\n */\nexport async function resolveRelationCUD<T extends DatrixEntry>(\n\trelations: QueryRelations<T>,\n\tschema: SchemaDefinition,\n\trunner: QueryRunner,\n\tschemaRegistry: ISchemaRegistry,\n): Promise<Record<string, ResolvedRelationOps>> {\n\tconst resolved: Record<string, ResolvedRelationOps> = {};\n\n\tfor (const [fieldName, relationData] of Object.entries(relations)) {\n\t\tconst relData = relationData as NormalizedRelationOperations<DatrixEntry>;\n\t\tconst field = schema.fields[fieldName];\n\t\tif (!field || field.type !== \"relation\") {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst relatedModel = field.model;\n\t\tconst relSchema = schemaRegistry.get(relatedModel)!;\n\n\t\t// Start with existing ID-based ops (copy from readonly)\n\t\tconst ops: ResolvedRelationOps = {\n\t\t\tconnect: relData.connect ? [...relData.connect] : [],\n\t\t\tdisconnect: relData.disconnect ? [...relData.disconnect] : [],\n\t\t\tset: relData.set ? [...relData.set] : undefined,\n\t\t\tdeleteIds: relData.delete ? [...relData.delete] : [],\n\t\t};\n\n\t\t// --- Execute CREATE (once) and merge IDs ---\n\t\tif (relData.create) {\n\t\t\t// TODO: hasMany + updateMany guard\n\t\t\t// When parent query is updateMany (multiple parents), hasMany create\n\t\t\t// is semantically ambiguous: a child can only belong to one parent.\n\t\t\t// Guard implementation (commented out - enable when needed):\n\t\t\t//\n\t\t\t// if (field.kind === 'hasMany' && parentCount > 1) {\n\t\t\t// const count = await executor.executeCount(countQuery, parentSchema, { noDispatcher: true });\n\t\t\t// if (count > 1) {\n\t\t\t// throw new Error(\n\t\t\t// `Cannot use create in hasMany relation \"${fieldName}\" when updating multiple records. ` +\n\t\t\t// `A hasMany child can only belong to one parent. Use connect instead, ` +\n\t\t\t// `or narrow your where clause to target a single record.`\n\t\t\t// );\n\t\t\t// }\n\t\t\t// }\n\n\t\t\t// Separate items with nested relations from plain ones\n\t\t\tconst plainItems = relData.create.filter((item) => !item.relations);\n\t\t\tconst nestedItems = relData.create.filter((item) => item.relations);\n\n\t\t\t// Bulk insert plain items (no nested relations)\n\t\t\tif (plainItems.length > 0) {\n\t\t\t\tconst validatedBulkData = plainItems.map((item) =>\n\t\t\t\t\tvalidateData<DatrixEntry, false>(\n\t\t\t\t\t\titem.data,\n\t\t\t\t\t\titem.relations,\n\t\t\t\t\t\trelSchema,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tpartial: false,\n\t\t\t\t\t\t\tisCreate: true,\n\t\t\t\t\t\t\tisRawMode: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t\tconst bulkResult = await runner.executeQuery<DatrixEntry>({\n\t\t\t\t\ttype: \"insert\",\n\t\t\t\t\ttable: relSchema.tableName!,\n\t\t\t\t\tdata: validatedBulkData,\n\t\t\t\t});\n\n\t\t\t\tfor (const created of bulkResult.rows) {\n\t\t\t\t\tif (ops.set !== undefined) {\n\t\t\t\t\t\tops.set.push(created.id);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tops.connect.push(created.id);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Items with nested relations must be inserted individually\n\t\t\tfor (const createItem of nestedItems) {\n\t\t\t\tconst validatedData = validateData<DatrixEntry, false>(\n\t\t\t\t\tcreateItem.data,\n\t\t\t\t\tcreateItem.relations,\n\t\t\t\t\trelSchema,\n\t\t\t\t\t{\n\t\t\t\t\t\tpartial: false,\n\t\t\t\t\t\tisCreate: true,\n\t\t\t\t\t\tisRawMode: true,\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t\tconst createResult = await runner.executeQuery<DatrixEntry>({\n\t\t\t\t\ttype: \"insert\",\n\t\t\t\t\ttable: relSchema.tableName!,\n\t\t\t\t\tdata: [validatedData],\n\t\t\t\t});\n\t\t\t\tconst createdId = createResult.rows[0]!.id;\n\n\t\t\t\t// Recursively resolve nested relations\n\t\t\t\tif (createItem.relations) {\n\t\t\t\t\tconst nestedResolved = await resolveRelationCUD(\n\t\t\t\t\t\tcreateItem.relations,\n\t\t\t\t\t\trelSchema,\n\t\t\t\t\t\trunner,\n\t\t\t\t\t\tschemaRegistry,\n\t\t\t\t\t);\n\t\t\t\t\tawait processRelations(\n\t\t\t\t\t\tnestedResolved,\n\t\t\t\t\t\tcreatedId,\n\t\t\t\t\t\trelSchema.name,\n\t\t\t\t\t\trelSchema,\n\t\t\t\t\t\trunner,\n\t\t\t\t\t\tschemaRegistry,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tif (ops.set !== undefined) {\n\t\t\t\t\tops.set.push(createdId);\n\t\t\t\t} else {\n\t\t\t\t\tops.connect.push(createdId);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// --- Execute UPDATE (once) ---\n\t\tif (relData.update) {\n\t\t\tfor (const updateItem of relData.update) {\n\t\t\t\tconst { where, data, relations: nestedRelations } = updateItem;\n\n\t\t\t\tconst validatedData = validateData<DatrixEntry, true>(\n\t\t\t\t\tdata,\n\t\t\t\t\tnestedRelations,\n\t\t\t\t\trelSchema,\n\t\t\t\t\t{\n\t\t\t\t\t\tpartial: true,\n\t\t\t\t\t\tisCreate: false,\n\t\t\t\t\t\tisRawMode: true,\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t\tconst updateResult = await runner.executeQuery<DatrixEntry>({\n\t\t\t\t\ttype: \"update\",\n\t\t\t\t\ttable: relSchema.tableName!,\n\t\t\t\t\tdata: validatedData,\n\t\t\t\t\twhere: where as WhereClause<DatrixEntry>,\n\t\t\t\t});\n\n\t\t\t\t// Recursively resolve nested relations\n\t\t\t\tif (nestedRelations) {\n\t\t\t\t\tfor (const updated of updateResult.rows) {\n\t\t\t\t\t\tconst nestedResolved = await resolveRelationCUD(\n\t\t\t\t\t\t\tnestedRelations,\n\t\t\t\t\t\t\trelSchema,\n\t\t\t\t\t\t\trunner,\n\t\t\t\t\t\t\tschemaRegistry,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tawait processRelations(\n\t\t\t\t\t\t\tnestedResolved,\n\t\t\t\t\t\t\tupdated.id,\n\t\t\t\t\t\t\trelSchema.name,\n\t\t\t\t\t\t\trelSchema,\n\t\t\t\t\t\t\trunner,\n\t\t\t\t\t\t\tschemaRegistry,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// --- Execute DELETE (once) ---\n\t\tif (ops.deleteIds.length > 0) {\n\t\t\tawait runner.executeQuery<DatrixEntry>({\n\t\t\t\ttype: \"delete\",\n\t\t\t\ttable: relSchema.tableName!,\n\t\t\t\twhere: { id: { $in: ops.deleteIds } },\n\t\t\t});\n\t\t}\n\n\t\tresolved[fieldName] = ops;\n\t}\n\n\treturn resolved;\n}\n\n/**\n * Process a single relation field (ID-based operations only)\n *\n * At this point, create/update/delete are already resolved.\n * Only connect/disconnect/set remain as ID arrays.\n */\nasync function processRelation<T extends DatrixEntry>({\n\tparentId,\n\tparentModel,\n\tfieldName,\n\tops,\n\tschema,\n\trunner,\n\tschemaRegistry,\n}: {\n\tparentId: number;\n\tparentModel: string;\n\tfieldName: string;\n\tops: ResolvedRelationOps;\n\tschema: SchemaDefinition;\n\trunner: QueryRunner;\n\tschemaRegistry: ISchemaRegistry;\n}): Promise<void> {\n\tconst field = schema.fields[fieldName];\n\tif (!field || field.type !== \"relation\") {\n\t\treturn;\n\t}\n\n\tconst relation = field;\n\tconst foreignKey = relation.foreignKey ?? `${fieldName}Id`;\n\n\t// belongsTo → Update THIS record's foreign key (FK is on owner)\n\tif (relation.kind === \"belongsTo\") {\n\t\tconst updateData: Partial<DatrixRecord> = {};\n\n\t\tif (ops.connect.length > 0) {\n\t\t\tupdateData[foreignKey] = ops.connect[0];\n\t\t}\n\t\tif (ops.disconnect.length > 0) {\n\t\t\tupdateData[foreignKey] = null;\n\t\t}\n\t\tif (ops.set !== undefined) {\n\t\t\tupdateData[foreignKey] = ops.set.length > 0 ? ops.set[0] : null;\n\t\t}\n\n\t\tif (Object.keys(updateData).length > 0) {\n\t\t\tawait runner.executeQuery({\n\t\t\t\ttable: schema.tableName!,\n\t\t\t\ttype: \"update\",\n\t\t\t\twhere: { id: parentId },\n\t\t\t\tdata: updateData,\n\t\t\t});\n\t\t}\n\t}\n\n\t// hasOne → Update TARGET record's foreign key (FK is on target, singular)\n\tif (relation.kind === \"hasOne\") {\n\t\tconst reverseForeignKey = relation.foreignKey ?? `${parentModel}Id`;\n\t\tconst relationSchema = schemaRegistry.get(relation.model)!;\n\n\t\t// For hasOne, we need to ensure only one target is linked\n\t\tif (ops.connect.length > 0) {\n\t\t\t// First, disconnect any existing target\n\t\t\tawait runner.executeQuery({\n\t\t\t\ttable: relationSchema.tableName!,\n\t\t\t\ttype: \"update\",\n\t\t\t\tdata: { [reverseForeignKey]: null },\n\t\t\t\twhere: { [reverseForeignKey]: parentId },\n\t\t\t});\n\n\t\t\t// Then connect the new target (only first one for hasOne)\n\t\t\tawait runner.executeQuery({\n\t\t\t\ttable: relationSchema.tableName!,\n\t\t\t\ttype: \"update\",\n\t\t\t\tdata: { [reverseForeignKey]: parentId },\n\t\t\t\twhere: { id: ops.connect[0] },\n\t\t\t});\n\t\t}\n\n\t\tif (ops.disconnect.length > 0) {\n\t\t\tawait runner.executeQuery({\n\t\t\t\ttable: relationSchema.tableName!,\n\t\t\t\ttype: \"update\",\n\t\t\t\tdata: { [reverseForeignKey]: null },\n\t\t\t\twhere: { id: { $in: ops.disconnect } },\n\t\t\t});\n\t\t}\n\n\t\tif (ops.set !== undefined) {\n\t\t\t// 1. Disconnect current\n\t\t\tawait runner.executeQuery<T>({\n\t\t\t\ttable: relationSchema.tableName!,\n\t\t\t\ttype: \"update\",\n\t\t\t\tdata: { [reverseForeignKey]: null } as Partial<T>,\n\t\t\t\twhere: { [reverseForeignKey]: parentId } as WhereClause<T>,\n\t\t\t});\n\n\t\t\t// 2. Connect new one (if any)\n\t\t\tif (ops.set.length > 0) {\n\t\t\t\tawait runner.executeQuery<T>({\n\t\t\t\t\ttable: relationSchema.tableName!,\n\t\t\t\t\ttype: \"update\",\n\t\t\t\t\tdata: { [reverseForeignKey]: parentId } as Partial<T>,\n\t\t\t\t\twhere: { id: ops.set[0] } as WhereClause<T>,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\t// hasMany → Update TARGET records' foreign key (FK is on target, plural)\n\tif (relation.kind === \"hasMany\") {\n\t\tconst reverseForeignKey = relation.foreignKey ?? `${parentModel}Id`;\n\t\tconst relationSchema = schemaRegistry.get(relation.model)!;\n\n\t\tif (ops.connect.length > 0) {\n\t\t\tawait runner.executeQuery({\n\t\t\t\ttable: relationSchema.tableName!,\n\t\t\t\ttype: \"update\",\n\t\t\t\tdata: { [reverseForeignKey]: parentId },\n\t\t\t\twhere: { id: { $in: ops.connect } },\n\t\t\t});\n\t\t}\n\n\t\tif (ops.disconnect.length > 0) {\n\t\t\tawait runner.executeQuery({\n\t\t\t\ttable: relationSchema.tableName!,\n\t\t\t\ttype: \"update\",\n\t\t\t\tdata: { [reverseForeignKey]: null },\n\t\t\t\twhere: { id: { $in: ops.disconnect } },\n\t\t\t});\n\t\t}\n\n\t\tif (ops.set !== undefined) {\n\t\t\t// 1. Disconnect all current\n\t\t\tawait runner.executeQuery({\n\t\t\t\ttable: relationSchema.tableName!,\n\t\t\t\ttype: \"update\",\n\t\t\t\tdata: { [reverseForeignKey]: null },\n\t\t\t\twhere: {\n\t\t\t\t\t[reverseForeignKey]: parentId,\n\t\t\t\t},\n\t\t\t});\n\n\t\t\t// 2. Connect new ones\n\t\t\tif (ops.set.length > 0) {\n\t\t\t\tawait runner.executeQuery({\n\t\t\t\t\ttable: relationSchema.tableName!,\n\t\t\t\t\ttype: \"update\",\n\t\t\t\t\tdata: {\n\t\t\t\t\t\t[reverseForeignKey]: parentId,\n\t\t\t\t\t},\n\t\t\t\t\twhere: {\n\t\t\t\t\t\tid: { $in: ops.set },\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\t// manyToMany → Junction table operations\n\tif (relation.kind === \"manyToMany\") {\n\t\tconst junctionTable = relation.through!;\n\t\tconst sourceFK = `${parentModel}Id`;\n\t\tconst targetFK = `${relation.model}Id`;\n\n\t\t// Connect → INSERT INTO junction table (skip existing)\n\t\tif (ops.connect.length > 0) {\n\t\t\tconst existing = await runner.executeQuery({\n\t\t\t\ttable: junctionTable,\n\t\t\t\ttype: \"select\",\n\t\t\t\tselect: [targetFK],\n\t\t\t\twhere: {\n\t\t\t\t\t[sourceFK]: parentId,\n\t\t\t\t\t[targetFK]: { $in: ops.connect },\n\t\t\t\t},\n\t\t\t});\n\t\t\tconst existingIds = new Set(\n\t\t\t\texisting.rows.map((r) => r[targetFK as keyof DatrixEntry] as number),\n\t\t\t);\n\t\t\tconst newIds = ops.connect.filter((id) => !existingIds.has(id));\n\n\t\t\tif (newIds.length > 0) {\n\t\t\t\tconst rows = newIds.map((targetId) => ({\n\t\t\t\t\t[sourceFK]: parentId,\n\t\t\t\t\t[targetFK]: targetId,\n\t\t\t\t}));\n\t\t\t\tawait runner.executeQuery({\n\t\t\t\t\ttable: junctionTable,\n\t\t\t\t\ttype: \"insert\",\n\t\t\t\t\tdata: rows,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\t// Disconnect → DELETE FROM junction table\n\t\tif (ops.disconnect.length > 0) {\n\t\t\tawait runner.executeQuery<DatrixEntry>({\n\t\t\t\ttable: junctionTable,\n\t\t\t\ttype: \"delete\",\n\t\t\t\twhere: {\n\t\t\t\t\t[sourceFK]: parentId,\n\t\t\t\t\t[targetFK]: { $in: ops.disconnect },\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\n\t\t// Set → DELETE all + INSERT new\n\t\tif (ops.set !== undefined) {\n\t\t\t// 1. Delete all existing relations for this record\n\t\t\tawait runner.executeQuery<DatrixEntry>({\n\t\t\t\ttable: junctionTable,\n\t\t\t\ttype: \"delete\",\n\t\t\t\twhere: {\n\t\t\t\t\t[sourceFK]: parentId,\n\t\t\t\t},\n\t\t\t});\n\n\t\t\t// 2. Insert new relations (bulk)\n\t\t\tif (ops.set.length > 0) {\n\t\t\t\tconst rows = ops.set.map((targetId) => ({\n\t\t\t\t\t[sourceFK]: parentId,\n\t\t\t\t\t[targetFK]: targetId,\n\t\t\t\t}));\n\t\t\t\tawait runner.executeQuery<DatrixEntry>({\n\t\t\t\t\ttable: junctionTable,\n\t\t\t\t\ttype: \"insert\",\n\t\t\t\t\tdata: rows,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n}\n","/**\n * Query Executor\n *\n * Responsible for:\n * 1. Schema validation (min/max/regex/type/required)\n * 2. Timestamp injection\n * 3. Query execution via adapter\n * 4. Relation processing (async operations)\n * 5. Plugin hooks (via dispatcher)\n */\n\nimport {\n\tISchemaRegistry,\n\tSchemaDefinition,\n\tDatrixEntry,\n} from \"../types/core/schema\";\nimport {\n\tQueryObject,\n\tQuerySelectObject,\n\tQueryCountObject,\n\tQueryInsertObject,\n\tQueryUpdateObject,\n\tQueryDeleteObject,\n\tWhereClause,\n} from \"../types/core/query-builder\";\nimport { QueryAction } from \"../types/core/query-context\";\nimport { Dispatcher } from \"../dispatcher\";\nimport { validateData } from \"./validation\";\nimport { processRelations, resolveRelationCUD } from \"./relations\";\nimport {\n\tthrowSchemaNotFoundError,\n\tthrowUnsupportedQueryType,\n} from \"./error-helper\";\nimport { DatabaseAdapter, QueryRunner } from \"../types/adapter\";\n\n/**\n * Executor execution options\n */\nexport interface ExecutorOptions {\n\t/** If true, bypass dispatcher (no hooks) */\n\tnoDispatcher?: boolean;\n\t/** If true, return only ID/count instead of full record */\n\tnoReturning?: boolean;\n\t/** Query action override */\n\taction?: QueryAction;\n}\n\n/**\n * Query Executor Class\n *\n * Executes QueryObject instances with full validation, timestamp management,\n * and relation processing.\n */\nexport class QueryExecutor {\n\tconstructor(\n\t\tprivate readonly schemas: ISchemaRegistry,\n\t\tprivate readonly getAdapter: () => DatabaseAdapter,\n\t\tprivate readonly getDispatcher: () => Dispatcher,\n\t) { }\n\n\t/**\n\t * Execute a query\n\t *\n\t * @param query - Query object from QueryBuilder\n\t * @param options - Execution options (dispatcher, returning)\n\t * @returns Query result\n\t *\n\t * @example\n\t * ```ts\n\t * const query = insertInto('User', { name: 'John' }, registry).build();\n\t * const user = await executor.execute(query);\n\t *\n\t * // Raw mode (no hooks)\n\t * const result = await executor.execute(query, { noDispatcher: true });\n\t *\n\t * // ID only (no fetch)\n\t * const id = await executor.execute<User, number>(query, { noReturning: true });\n\t * ```\n\t */\n\tasync execute<T extends DatrixEntry, R>(\n\t\tquery: QueryObject<T>,\n\t\toptions: ExecutorOptions = {},\n\t): Promise<R> {\n\t\tconst schema = this.getSchema(query.table);\n\n\t\t// SELECT: Direct execution\n\t\tif (query.type === \"select\") {\n\t\t\treturn this.executeSelect<T>(query, schema, options) as R;\n\t\t}\n\n\t\t// COUNT: Direct execution\n\t\tif (query.type === \"count\") {\n\t\t\treturn this.executeCount<T>(query, schema, options) as R;\n\t\t}\n\n\t\t// DELETE: Fetch first (if returning), then delete\n\t\tif (query.type === \"delete\") {\n\t\t\treturn this.executeDelete<T>(query, schema, options) as R;\n\t\t}\n\n\t\t// INSERT/UPDATE: Validation + relations + fetch result\n\t\tif (query.type === \"insert\") {\n\t\t\treturn this.executeInsert<T>(query, schema, options) as R;\n\t\t}\n\n\t\t// INSERT/UPDATE: Validation + relations + fetch result\n\t\tif (query.type === \"update\") {\n\t\t\treturn this.executeUpdate<T>(query, schema, options) as R;\n\t\t}\n\n\t\tthrowUnsupportedQueryType((query as { type: string }).type);\n\t}\n\n\t/**\n\t * Execute SELECT query\n\t *\n\t * Always returns array (caller decides single vs multiple).\n\t * Can be reused for fetching after INSERT/UPDATE/DELETE.\n\t */\n\tasync executeSelect<T extends DatrixEntry>(\n\t\tquery: QuerySelectObject<T>,\n\t\tschema: SchemaDefinition,\n\t\toptions: ExecutorOptions,\n\t): Promise<T[]> {\n\t\treturn this.withLifecycle(\n\t\t\toptions.action ?? \"findMany\",\n\t\t\tschema,\n\t\t\toptions.noDispatcher ?? false,\n\t\t\tquery,\n\t\t\tasync (mq) => {\n\t\t\t\tconst result = await this.getAdapter().executeQuery<T>(mq);\n\t\t\t\treturn result.rows as T[];\n\t\t\t},\n\t\t);\n\t}\n\n\t/**\n\t * Execute COUNT query\n\t */\n\tasync executeCount<T extends DatrixEntry>(\n\t\tquery: QueryCountObject<T>,\n\t\tschema: SchemaDefinition,\n\t\toptions: ExecutorOptions,\n\t): Promise<number> {\n\t\treturn this.withLifecycle(\n\t\t\toptions.action ?? \"count\",\n\t\t\tschema,\n\t\t\toptions.noDispatcher ?? false,\n\t\t\tquery,\n\t\t\tasync (mq) => {\n\t\t\t\tconst result = await this.getAdapter().executeQuery<T>(mq);\n\t\t\t\treturn result.metadata.count ?? 0;\n\t\t\t},\n\t\t);\n\t}\n\n\t/**\n\t * Execute DELETE query (cascade junction tables, fetch first, then delete)\n\t *\n\t * Transaction flow: onBefore → BEGIN → SELECT (fetch) + junction cascade + DELETE → COMMIT → onAfter\n\t */\n\tasync executeDelete<T extends DatrixEntry>(\n\t\tquery: QueryDeleteObject<T>,\n\t\tschema: SchemaDefinition,\n\t\toptions: ExecutorOptions,\n\t): Promise<readonly T[]> {\n\t\treturn this.withLifecycle(\n\t\t\toptions.action ?? \"delete\",\n\t\t\tschema,\n\t\t\toptions.noDispatcher ?? false,\n\t\t\tquery,\n\t\t\tasync (mq) => {\n\t\t\t\t// 1. Begin transaction\n\t\t\t\tconst adapter = this.getAdapter();\n\t\t\t\tconst { runner, commit, rollback } =\n\t\t\t\t\tawait this.beginTransaction(adapter);\n\n\t\t\t\tlet deleteResult: readonly T[];\n\t\t\t\tlet returningResult: readonly T[];\n\n\t\t\t\ttry {\n\t\t\t\t\t// 2. Pre-fetch rows if caller needs select/populate results\n\t\t\t\t\tconst needsReturnSelect =\n\t\t\t\t\t\t!options.noReturning && (mq.select || mq.populate);\n\n\t\t\t\t\tlet prefetchedRows: readonly T[] | undefined;\n\n\t\t\t\t\tif (needsReturnSelect) {\n\t\t\t\t\t\tconst selectResult = await runner.executeQuery<T>({\n\t\t\t\t\t\t\ttype: \"select\",\n\t\t\t\t\t\t\ttable: mq.table,\n\t\t\t\t\t\t\twhere: mq.where,\n\t\t\t\t\t\t\tselect: mq.select ?? [\"id\"],\n\t\t\t\t\t\t\t...(mq.populate !== undefined && { populate: mq.populate }),\n\t\t\t\t\t\t});\n\t\t\t\t\t\tprefetchedRows = selectResult.rows;\n\t\t\t\t\t}\n\t\t\t\t\t// TODO: do we need transaction here?\n\t\t\t\t\t// 3. Execute DELETE (junction cleanup handled by DB via ON DELETE CASCADE)\n\t\t\t\t\tconst deleteQueryResult = await runner.executeQuery<T>(mq);\n\t\t\t\t\tdeleteResult = deleteQueryResult.rows;\n\n\t\t\t\t\t// 4. Commit transaction\n\t\t\t\t\tawait commit();\n\n\t\t\t\t\treturningResult = needsReturnSelect ? prefetchedRows! : deleteResult;\n\t\t\t\t} catch (error) {\n\t\t\t\t\tawait rollback();\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\n\t\t\t\treturn returningResult;\n\t\t\t},\n\t\t);\n\t}\n\n\t/**\n\t * Execute INSERT with validation and relations\n\t *\n\t * Transaction flow: onBefore → validate → BEGIN → INSERT + relations → COMMIT → SELECT → onAfter\n\t */\n\tasync executeInsert<T extends DatrixEntry>(\n\t\tquery: QueryInsertObject<T>,\n\t\tschema: SchemaDefinition,\n\t\toptions: ExecutorOptions,\n\t): Promise<readonly T[]> {\n\t\tconst noDispatcher = options.noDispatcher ?? false;\n\n\t\treturn this.withLifecycle(\n\t\t\toptions.action ?? \"create\",\n\t\t\tschema,\n\t\t\tnoDispatcher,\n\t\t\tquery,\n\t\t\tasync (mq) => {\n\t\t\t\tconst insertQuery = mq as QueryInsertObject<T>;\n\n\t\t\t\t// 1. Validate each data item against schema + add timestamps\n\t\t\t\tconst validatedItems = insertQuery.data.map((item) =>\n\t\t\t\t\tvalidateData<T, false>(item, insertQuery.relations, schema, {\n\t\t\t\t\t\tpartial: false,\n\t\t\t\t\t\tisCreate: true,\n\t\t\t\t\t\tisRawMode: noDispatcher,\n\t\t\t\t\t}),\n\t\t\t\t);\n\n\t\t\t\t// 2. Begin transaction\n\t\t\t\tconst adapter = this.getAdapter();\n\t\t\t\tconst { runner, commit, rollback } =\n\t\t\t\t\tawait this.beginTransaction(adapter);\n\n\t\t\t\tlet insertedIds: readonly T[];\n\n\t\t\t\ttry {\n\t\t\t\t\t// 3. Execute INSERT query (bulk)\n\t\t\t\t\tconst queryWithValidatedData: QueryInsertObject<T> = {\n\t\t\t\t\t\ttype: \"insert\",\n\t\t\t\t\t\ttable: insertQuery.table,\n\t\t\t\t\t\tdata: validatedItems,\n\t\t\t\t\t};\n\n\t\t\t\t\tconst insertResult = await runner.executeQuery<T>(\n\t\t\t\t\t\tqueryWithValidatedData,\n\t\t\t\t\t);\n\t\t\t\t\tinsertedIds = insertResult.rows;\n\n\t\t\t\t\t// 4. Process relations (if any) - resolve CUD once, then link per record\n\t\t\t\t\tif (insertQuery.relations) {\n\t\t\t\t\t\tconst resolvedOps = await resolveRelationCUD(\n\t\t\t\t\t\t\tinsertQuery.relations,\n\t\t\t\t\t\t\tschema,\n\t\t\t\t\t\t\trunner,\n\t\t\t\t\t\t\tthis.schemas,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tfor (const recordId of insertedIds) {\n\t\t\t\t\t\t\tawait processRelations(\n\t\t\t\t\t\t\t\tresolvedOps,\n\t\t\t\t\t\t\t\trecordId.id,\n\t\t\t\t\t\t\t\tschema.name,\n\t\t\t\t\t\t\t\tschema,\n\t\t\t\t\t\t\t\trunner,\n\t\t\t\t\t\t\t\tthis.schemas,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// 5. Commit transaction\n\t\t\t\t\tawait commit();\n\t\t\t\t} catch (error) {\n\t\t\t\t\tawait rollback();\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\n\t\t\t\t// 6. Fetch full records (if returning enabled)\n\t\t\t\tif (options.noReturning) {\n\t\t\t\t\treturn insertedIds;\n\t\t\t\t}\n\n\t\t\t\tconst selectQuery: QuerySelectObject<T> = {\n\t\t\t\t\ttype: \"select\",\n\t\t\t\t\ttable: insertQuery.table,\n\t\t\t\t\tselect: insertQuery.select!,\n\t\t\t\t\twhere: {\n\t\t\t\t\t\tid: { $in: insertedIds.map((r) => r.id) },\n\t\t\t\t\t} as unknown as WhereClause<T>,\n\t\t\t\t\t...(insertQuery.populate !== undefined && {\n\t\t\t\t\t\tpopulate: insertQuery.populate,\n\t\t\t\t\t}),\n\t\t\t\t};\n\n\t\t\t\treturn this.executeSelect<T>(selectQuery, schema, {\n\t\t\t\t\tnoDispatcher: true,\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\t}\n\n\t/**\n\t * Execute UPDATE with validation and relations\n\t *\n\t * Transaction flow: onBefore → validate → BEGIN → UPDATE + relations → COMMIT → SELECT → onAfter\n\t */\n\tasync executeUpdate<T extends DatrixEntry>(\n\t\tquery: QueryUpdateObject<T>,\n\t\tschema: SchemaDefinition,\n\t\toptions: ExecutorOptions,\n\t): Promise<readonly T[]> {\n\t\tconst noDispatcher = options.noDispatcher ?? false;\n\n\t\treturn this.withLifecycle(\n\t\t\toptions.action ?? \"update\",\n\t\t\tschema,\n\t\t\tnoDispatcher,\n\t\t\tquery,\n\t\t\tasync (mq) => {\n\t\t\t\tconst updateQuery = mq as QueryUpdateObject<T>;\n\n\t\t\t\t// 1. Validate data against schema (min/max/regex/type) + add timestamps\n\t\t\t\tconst validatedData = validateData<T, true>(\n\t\t\t\t\tupdateQuery.data,\n\t\t\t\t\tupdateQuery.relations,\n\t\t\t\t\tschema,\n\t\t\t\t\t{\n\t\t\t\t\t\tpartial: true,\n\t\t\t\t\t\tisCreate: false,\n\t\t\t\t\t\tisRawMode: noDispatcher,\n\t\t\t\t\t},\n\t\t\t\t);\n\n\t\t\t\t// 2. Begin transaction\n\t\t\t\tconst adapter = this.getAdapter();\n\t\t\t\tconst { runner, commit, rollback } =\n\t\t\t\t\tawait this.beginTransaction(adapter);\n\n\t\t\t\tlet recordIds: readonly T[];\n\n\t\t\t\ttry {\n\t\t\t\t\t// 3. Execute UPDATE query (scalars only)\n\t\t\t\t\tconst queryWithValidatedData: QueryUpdateObject<T> = {\n\t\t\t\t\t\ttype: \"update\",\n\t\t\t\t\t\ttable: updateQuery.table,\n\t\t\t\t\t\tdata: validatedData,\n\t\t\t\t\t\t...(updateQuery.where !== undefined && {\n\t\t\t\t\t\t\twhere: updateQuery.where,\n\t\t\t\t\t\t}),\n\t\t\t\t\t};\n\n\t\t\t\t\tconst updateResult = await runner.executeQuery<T>(\n\t\t\t\t\t\tqueryWithValidatedData,\n\t\t\t\t\t);\n\t\t\t\t\trecordIds = updateResult.rows;\n\n\t\t\t\t\t// 4. Process relations (if any) - resolve CUD ONCE, then link per parent\n\t\t\t\t\tif (updateQuery.relations) {\n\t\t\t\t\t\tconst resolvedOps = await resolveRelationCUD(\n\t\t\t\t\t\t\tupdateQuery.relations,\n\t\t\t\t\t\t\tschema,\n\t\t\t\t\t\t\trunner,\n\t\t\t\t\t\t\tthis.schemas,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tfor (const recordId of recordIds) {\n\t\t\t\t\t\t\tawait processRelations(\n\t\t\t\t\t\t\t\tresolvedOps,\n\t\t\t\t\t\t\t\trecordId.id,\n\t\t\t\t\t\t\t\tschema.name,\n\t\t\t\t\t\t\t\tschema,\n\t\t\t\t\t\t\t\trunner,\n\t\t\t\t\t\t\t\tthis.schemas,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// 5. Commit transaction\n\t\t\t\t\tawait commit();\n\t\t\t\t} catch (error) {\n\t\t\t\t\tawait rollback();\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\n\t\t\t\t// 6. Fetch full records (if returning enabled)\n\t\t\t\tif (options.noReturning) {\n\t\t\t\t\treturn recordIds;\n\t\t\t\t}\n\n\t\t\t\t// Use updated record IDs for select (not original where, which may no longer match)\n\t\t\t\tconst selectQuery: QuerySelectObject<T> = {\n\t\t\t\t\ttype: \"select\",\n\t\t\t\t\ttable: updateQuery.table,\n\t\t\t\t\tselect: updateQuery.select!,\n\t\t\t\t\twhere: {\n\t\t\t\t\t\tid: { $in: recordIds.map((r) => r.id) },\n\t\t\t\t\t} as unknown as WhereClause<T>,\n\t\t\t\t\t...(updateQuery.populate !== undefined && {\n\t\t\t\t\t\tpopulate: updateQuery.populate,\n\t\t\t\t\t}),\n\t\t\t\t};\n\n\t\t\t\treturn this.executeSelect<T>(selectQuery, schema, {\n\t\t\t\t\tnoDispatcher: true,\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\t}\n\n\t/**\n\t * Wraps a handler with dispatcher lifecycle: buildContext → onBefore → handler → onAfter.\n\t * If noDispatcher is true, skips all hooks and runs handler directly.\n\t * context.metadata is shared between before/after hooks for the same operation.\n\t */\n\tprivate async withLifecycle<TResult, TQuery>(\n\t\taction: QueryAction,\n\t\tschema: SchemaDefinition,\n\t\tnoDispatcher: boolean,\n\t\tquery: TQuery,\n\t\thandler: (modifiedQuery: TQuery) => Promise<TResult>,\n\t): Promise<TResult> {\n\t\tconst dispatcher = this.getDispatcher();\n\n\t\tif (noDispatcher) {\n\t\t\treturn handler(query);\n\t\t}\n\n\t\tconst context = await dispatcher.buildQueryContext(action);\n\n\t\tconst modifiedQuery = (await dispatcher.dispatchBeforeQuery(\n\t\t\tquery as QueryObject,\n\t\t\tschema,\n\t\t\tcontext,\n\t\t)) as TQuery;\n\n\t\tconst result = await handler(modifiedQuery);\n\n\t\treturn dispatcher.dispatchAfterQuery(\n\t\t\tresult as DatrixEntry,\n\t\t\tschema,\n\t\t\tcontext,\n\t\t) as Promise<TResult>;\n\t}\n\n\t/**\n\t * Begin transaction and return runner, commit, rollback helpers.\n\t */\n\tprivate async beginTransaction(adapter: DatabaseAdapter): Promise<{\n\t\trunner: QueryRunner;\n\t\tcommit: () => Promise<void>;\n\t\trollback: () => Promise<void>;\n\t}> {\n\t\tconst tx = await adapter.beginTransaction();\n\t\treturn {\n\t\t\trunner: tx,\n\t\t\tcommit: async () => {\n\t\t\t\tawait tx.commit();\n\t\t\t},\n\t\t\trollback: async () => {\n\t\t\t\tawait tx.rollback();\n\t\t\t},\n\t\t};\n\t}\n\n\t/**\n\t * Get schema by table name\n\t */\n\tprivate getSchema(tableName: string): SchemaDefinition {\n\t\tconst result = this.schemas.getByTableName(tableName);\n\t\tif (!result) {\n\t\t\tthrowSchemaNotFoundError(tableName);\n\t\t}\n\t\treturn result.schema;\n\t}\n}\n","/**\n * CRUD Operations Mixin\n *\n * Provides database CRUD (Create, Read, Update, Delete) operations.\n * This class encapsulates all data manipulation logic.\n */\n\nimport { DatabaseAdapter } from \"../types/adapter\";\nimport { ISchemaRegistry, DatrixEntry, DatrixRecord } from \"../types/core/schema\";\nimport { WhereClause } from \"../types/core/query-builder\";\nimport { Dispatcher } from \"../dispatcher\";\nimport {\n\tIRawCrud,\n\tRawCrudOptions,\n\tRawFindManyOptions,\n\tFallbackInput,\n} from \"../types/core\";\nimport {\n\tselectFrom,\n\tcountFrom,\n\tinsertInto,\n\tupdateTable,\n\tdeleteFrom,\n} from \"../query-builder\";\nimport { QueryExecutor } from \"../query-executor/executor\";\nimport { throwRecordNotFound } from \"../query-executor/error-helper\";\n\n/**\n * CRUD Operations Class\n *\n * Handles all database CRUD operations with type-safe query building.\n * Uses QueryExecutor for INSERT/UPDATE operations with relation processing.\n * Implements IRawCrud interface.\n */\nexport class CrudOperations implements IRawCrud {\n\tprivate readonly executor: QueryExecutor;\n\n\tconstructor(\n\t\tprivate readonly schemas: ISchemaRegistry,\n\t\treadonly getAdapter: () => DatabaseAdapter,\n\t\tprivate readonly getDispatcher: (() => Dispatcher) | null = null,\n\t) {\n\t\t// QueryExecutor handles validation, timestamps, and recursive relations\n\t\tthis.executor = new QueryExecutor(\n\t\t\tschemas,\n\t\t\tgetAdapter,\n\t\t\tgetDispatcher || (() => ({}) as Dispatcher), // Dummy dispatcher if null\n\t\t);\n\t}\n\n\t/**\n\t * Find one record by criteria\n\t *\n\t * **NEW:** Now supports type-safe nested relation WHERE queries!\n\t *\n\t * @param model - Model name (e.g., 'User')\n\t * @param where - Filter criteria (now supports nested relations)\n\t * @param options - Query options (select, populate)\n\t * @returns Record or null if not found\n\t *\n\t * @example\n\t * ```ts\n\t * // Basic WHERE\n\t * const user = await crud.findOne('User', { email: 'test@example.com' });\n\t *\n\t * // Nested relation WHERE\n\t * const post = await crud.findOne('Post', {\n\t * title: { $like: 'Hello%' },\n\t * author: { // ✅ NEW: Nested WHERE on relations!\n\t * verified: { $eq: true },\n\t * company: {\n\t * country: { name: { $eq: 'Turkey' } }\n\t * }\n\t * }\n\t * });\n\t *\n\t * // With type safety\n\t * type Post = { id: number; title: string; author: Relation<User>; };\n\t * const typedPost = await crud.findOne<Post>('Post', {\n\t * author: { name: { $like: 'John%' } } // ✅ Type-checked\n\t * });\n\t * ```\n\t */\n\tasync findOne<T extends DatrixEntry = DatrixEntry>(\n\t\tmodel: string,\n\t\twhere: WhereClause<T>,\n\t\toptions?: RawCrudOptions<T>,\n\t): Promise<T | null> {\n\t\tconst builder = selectFrom<T>(model, this.schemas).where(where).limit(1);\n\n\t\tif (options?.select) {\n\t\t\tbuilder.select(options.select);\n\t\t}\n\t\tif (options?.populate) {\n\t\t\tbuilder.populate(options.populate);\n\t\t}\n\n\t\tconst query = builder.build();\n\n\t\tconst results = await this.executor.execute<T, T[]>(query, {\n\t\t\tnoDispatcher: this.getDispatcher === null,\n\t\t\taction: \"findOne\",\n\t\t});\n\n\t\treturn results[0] || null;\n\t}\n\n\t/**\n\t * Find one record by ID\n\t *\n\t * @param model - Model name\n\t * @param id - Record ID\n\t * @param options - Query options\n\t * @returns Record or null\n\t *\n\t * @example\n\t * ```ts\n\t * const user = await crud.findById('User', '123');\n\t * ```\n\t */\n\tasync findById<T extends DatrixEntry = DatrixRecord>(\n\t\tmodel: string,\n\t\tid: number,\n\t\toptions?: RawCrudOptions<T>,\n\t): Promise<T | null> {\n\t\treturn this.findOne<T>(model, { id } as WhereClause<T>, options);\n\t}\n\n\t/**\n\t * Find multiple records\n\t *\n\t * **NEW:** Now supports type-safe nested relation WHERE queries!\n\t *\n\t * @param model - Model name\n\t * @param options - Query options (with nested relation WHERE support)\n\t * @returns Array of records\n\t *\n\t * @example\n\t * ```ts\n\t * // Basic query\n\t * const users = await crud.findMany('User', {\n\t * where: { role: 'admin' },\n\t * limit: 10,\n\t * orderBy: [{ field: 'createdAt', direction: 'desc' }]\n\t * });\n\t *\n\t * // With nested relation WHERE\n\t * const posts = await crud.findMany('Post', {\n\t * where: {\n\t * $and: [\n\t * { published: true },\n\t * { author: { verified: { $eq: true } } } // ✅ Nested relation\n\t * ]\n\t * }\n\t * });\n\t * ```\n\t */\n\tasync findMany<T extends DatrixEntry = DatrixRecord>(\n\t\tmodel: string,\n\t\toptions?: RawFindManyOptions<T>,\n\t): Promise<T[]> {\n\t\tconst builder = selectFrom<T>(model, this.schemas);\n\n\t\tif (options?.where) {\n\t\t\tbuilder.where(options.where);\n\t\t}\n\t\tif (options?.select) {\n\t\t\tbuilder.select(options.select);\n\t\t}\n\t\tif (options?.populate) {\n\t\t\tbuilder.populate(options.populate);\n\t\t}\n\t\tif (options?.orderBy) {\n\t\t\tbuilder.orderBy(options?.orderBy);\n\t\t}\n\t\tif (options?.limit !== undefined) {\n\t\t\tbuilder.limit(options.limit);\n\t\t}\n\t\tif (options?.offset !== undefined) {\n\t\t\tbuilder.offset(options.offset);\n\t\t}\n\n\t\tconst query = builder.build();\n\n\t\tconst results = await this.executor.execute<T, T[]>(query, {\n\t\t\tnoDispatcher: this.getDispatcher === null,\n\t\t\taction: \"findMany\",\n\t\t});\n\n\t\treturn results;\n\t}\n\n\t/**\n\t * Count records\n\t *\n\t * **NEW:** Now supports type-safe nested relation WHERE queries!\n\t *\n\t * @param model - Model name\n\t * @param where - Filter criteria (supports nested relations)\n\t * @returns Number of matching records\n\t *\n\t * @example\n\t * ```ts\n\t * const totalUsers = await crud.count('User');\n\t * const adminCount = await crud.count('User', { role: 'admin' });\n\t *\n\t * // With nested relation WHERE\n\t * const verifiedPosts = await crud.count('Post', {\n\t * author: { verified: { $eq: true } }\n\t * });\n\t * ```\n\t */\n\tasync count<T extends DatrixEntry = DatrixRecord>(\n\t\tmodel: string,\n\t\twhere?: WhereClause<T>,\n\t): Promise<number> {\n\t\tconst builder = countFrom<T>(model, this.schemas);\n\n\t\tif (where) {\n\t\t\tbuilder.where(where);\n\t\t}\n\n\t\tconst query = builder.build();\n\n\t\tconst result = await this.executor.execute<T, number>(query, {\n\t\t\tnoDispatcher: this.getDispatcher === null,\n\t\t\taction: \"count\",\n\t\t});\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Create a new record\n\t *\n\t * @param model - Model name\n\t * @param data - Record data\n\t * @returns Created record\n\t *\n\t * @example\n\t * ```ts\n\t * const user = await crud.create('User', {\n\t * email: 'john@example.com',\n\t * name: 'John Doe',\n\t * role: 'user'\n\t * });\n\t * ```\n\t */\n\tasync create<\n\t\tT extends DatrixEntry = DatrixRecord,\n\t\tTInput extends FallbackInput = FallbackInput,\n\t>(model: string, data: TInput, options?: RawCrudOptions<T>): Promise<T> {\n\t\tconst result = await this.createMany<T, TInput>(model, [data], {\n\t\t\t...options,\n\t\t\taction: \"create\", // pass this to avoid \"createMany\" action in dispatcher for single record creation\n\t\t});\n\n\t\treturn result[0]!;\n\t}\n\n\t/**\n\t * Create multiple new record\n\t *\n\t * @param model - Model name\n\t * @param data - Record data []\n\t * @returns Created records\n\t *\n\t * @example\n\t * ```ts\n\t * const user = await crud.create('User', [\n\t * { email: 'john@example.com', name: 'John Doe', role: 'user' },\n\t * { email: 'jane@example.com', name: 'Jane Doe', role: 'user' }\n\t * ]);\n\t * ```\n\t */\n\tasync createMany<\n\t\tT extends DatrixEntry = DatrixRecord,\n\t\tTInput extends FallbackInput = FallbackInput,\n\t>(model: string, data: TInput[], options?: RawCrudOptions<T>): Promise<T[]> {\n\t\tconst builder = insertInto<T>(\n\t\t\tmodel,\n\t\t\tdata as unknown as Partial<T>[],\n\t\t\tthis.schemas,\n\t\t);\n\n\t\tif (options?.select) {\n\t\t\tbuilder.select(options.select);\n\t\t}\n\t\tif (options?.populate) {\n\t\t\tbuilder.populate(options.populate);\n\t\t}\n\n\t\tconst query = builder.build();\n\n\t\tconst result = await this.executor.execute<T, T[]>(query, {\n\t\t\tnoDispatcher: this.getDispatcher === null,\n\t\t\taction: options?.action ?? \"createMany\",\n\t\t});\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Update a record by ID\n\t *\n\t * @param model - Model name\n\t * @param id - Record ID\n\t * @param data - Updated data\n\t * @returns Updated record\n\t *\n\t * @example\n\t * ```ts\n\t * const user = await crud.update('User', '123', {\n\t * name: 'Jane Doe'\n\t * });\n\t * ```\n\t */\n\tasync update<\n\t\tT extends DatrixEntry = DatrixRecord,\n\t\tTInput extends FallbackInput = FallbackInput,\n\t>(\n\t\tmodel: string,\n\t\tid: number,\n\t\tdata: TInput,\n\t\toptions?: RawCrudOptions<T>,\n\t): Promise<T> {\n\t\tconst result = await this.updateMany(\n\t\t\tmodel,\n\t\t\t{ id } as WhereClause<T>,\n\t\t\tdata,\n\t\t\t{\n\t\t\t\t...options,\n\t\t\t\taction: options?.action ?? \"update\",\n\t\t\t},\n\t\t);\n\n\t\tif (result.length === 0) {\n\t\t\tthrowRecordNotFound(\"update\", model, id);\n\t\t}\n\n\t\treturn result[0]!;\n\t}\n\n\t/**\n\t * Update multiple records\n\t *\n\t * **NEW:** Now supports type-safe nested relation WHERE queries!\n\t *\n\t * @param model - Model name\n\t * @param where - Filter criteria (supports nested relations)\n\t * @param data - Updated data\n\t * @returns Number of updated records\n\t *\n\t * @example\n\t * ```ts\n\t * // Basic WHERE\n\t * const count = await crud.updateMany('User',\n\t * { role: 'user' },\n\t * { verified: true }\n\t * );\n\t *\n\t * // With nested relation WHERE\n\t * const count2 = await crud.updateMany('Post',\n\t * { author: { verified: { $eq: true } } }, // ✅ NEW: Nested relation\n\t * { featured: true }\n\t * );\n\t * ```\n\t */\n\tasync updateMany<\n\t\tT extends DatrixEntry = DatrixRecord,\n\t\tTInput extends FallbackInput = FallbackInput,\n\t>(\n\t\tmodel: string,\n\t\twhere: WhereClause<T>,\n\t\tdata: TInput,\n\t\toptions?: RawCrudOptions<T>,\n\t): Promise<T[]> {\n\t\tconst builder = updateTable<T>(\n\t\t\tmodel,\n\t\t\tdata as unknown as Partial<T>,\n\t\t\tthis.schemas,\n\t\t).where(where);\n\n\t\tif (options?.select || !options?.noReturning) {\n\t\t\tbuilder.select(options?.select ?? \"*\");\n\t\t}\n\n\t\tif (options?.populate) {\n\t\t\tbuilder.populate(options.populate);\n\t\t}\n\n\t\tconst query = builder.build();\n\n\t\tconst result = await this.executor.execute<T, T[]>(query, {\n\t\t\tnoDispatcher: this.getDispatcher === null,\n\t\t\tnoReturning: options?.noReturning ?? false,\n\t\t\taction: options?.action || \"updateMany\",\n\t\t});\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Delete a record by ID\n\t *\n\t * @param model - Model name\n\t * @param id - Record ID\n\t * @returns True if deleted\n\t *\n\t * @example\n\t * ```ts\n\t * const deleted = await crud.delete('User', '123');\n\t * ```\n\t */\n\tasync delete<T extends DatrixEntry = DatrixRecord>(\n\t\tmodel: string,\n\t\tid: number,\n\t\toptions?: RawCrudOptions<T>,\n\t): Promise<T> {\n\t\tconst result = await this.deleteMany<T>(model, { id } as WhereClause<T>, {\n\t\t\t...options,\n\t\t\tnoReturning: options?.noReturning ?? false,\n\t\t\taction: options?.action ?? \"delete\",\n\t\t});\n\n\t\tif (result.length === 0) {\n\t\t\tthrowRecordNotFound(\"delete\", model, id);\n\t\t}\n\n\t\treturn result[0]!;\n\t}\n\n\t/**\n\t * Delete multiple records\n\t *\n\t * **NEW:** Now supports type-safe nested relation WHERE queries!\n\t *\n\t * @param model - Model name\n\t * @param where - Filter criteria (supports nested relations)\n\t * @returns Number of deleted records\n\t *\n\t * @example\n\t * ```ts\n\t * // Basic WHERE\n\t * const count = await crud.deleteMany('User', { verified: false });\n\t *\n\t * // With nested relation WHERE\n\t * const count2 = await crud.deleteMany('Post', {\n\t * author: { id: { $eq: userId } } // ✅ NEW: Use relation WHERE instead of authorId\n\t * });\n\t * ```\n\t */\n\tasync deleteMany<T extends DatrixEntry = DatrixRecord>(\n\t\tmodel: string,\n\t\twhere: WhereClause<T>,\n\t\toptions?: RawCrudOptions<T>,\n\t): Promise<T[]> {\n\t\tconst queryBuilder = deleteFrom<T>(model, this.schemas).where(where);\n\n\t\tif (options?.select || !options?.noReturning)\n\t\t\tqueryBuilder.select(options?.select ?? \"*\");\n\n\t\tif (options?.populate) queryBuilder.populate(options.populate);\n\n\t\tconst query = queryBuilder.build();\n\n\t\tconst result = await this.executor.execute<T, T[]>(query, {\n\t\t\tnoDispatcher: this.getDispatcher === null,\n\t\t\tnoReturning: options?.noReturning ?? !(query?.select || query?.populate),\n\t\t\taction: options?.action ?? \"deleteMany\",\n\t\t});\n\n\t\treturn result;\n\t}\n}\n","/**\n * Schema Extension Context Implementation\n *\n * Provides helper methods for plugins to extend schemas in bulk.\n */\n\nimport type {\n\tSchemaDefinition,\n\tSchemaExtension,\n\tSchemaExtensionContext,\n\tSchemaModifier,\n\tSchemaPattern,\n} from \"../types/core/plugin\";\n\nexport class SchemaExtensionContextImpl implements SchemaExtensionContext {\n\tconstructor(public readonly schemas: ReadonlyArray<SchemaDefinition>) {}\n\n\textendAll(modifier: SchemaModifier): SchemaExtension[] {\n\t\treturn this.schemas.map((schema) => ({\n\t\t\ttargetSchema: schema.name,\n\t\t\t...modifier(schema),\n\t\t}));\n\t}\n\n\textendWhere(\n\t\tpredicate: (schema: SchemaDefinition) => boolean,\n\t\tmodifier: SchemaModifier,\n\t): SchemaExtension[] {\n\t\treturn this.schemas.filter(predicate).map((schema) => ({\n\t\t\ttargetSchema: schema.name,\n\t\t\t...modifier(schema),\n\t\t}));\n\t}\n\n\textendByPattern(\n\t\tpattern: SchemaPattern,\n\t\tmodifier: SchemaModifier,\n\t): SchemaExtension[] {\n\t\treturn this.schemas\n\t\t\t.filter((schema) => this.matchesPattern(schema, pattern))\n\t\t\t.map((schema) => ({\n\t\t\t\ttargetSchema: schema.name,\n\t\t\t\t...modifier(schema),\n\t\t\t}));\n\t}\n\n\tprivate matchesPattern(\n\t\tschema: SchemaDefinition,\n\t\tpattern: SchemaPattern,\n\t): boolean {\n\t\tif (pattern.names && !pattern.names.includes(schema.name)) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (pattern.prefix && !schema.name.startsWith(pattern.prefix)) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (pattern.suffix && !schema.name.endsWith(pattern.suffix)) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (pattern.exclude?.includes(schema.name)) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (pattern.custom && !pattern.custom(schema)) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n}\n","/**\n * Query Utilities\n *\n * Provides runtime validation for QueryObject structure.\n */\n\nimport { DatrixEntry } from \"../core/schema\";\nimport { QueryObject } from \"../core/query-builder\";\nimport { DatrixError } from \"../errors\";\n\n/**\n * Valid keys for a QueryObject\n */\nconst VALID_QUERY_KEYS = new Set([\n\t\"type\",\n\t\"table\",\n\t\"select\",\n\t\"where\",\n\t\"populate\",\n\t\"orderBy\",\n\t\"limit\",\n\t\"offset\",\n\t\"data\",\n\t\"returning\",\n\t\"distinct\",\n\t\"groupBy\",\n\t\"having\",\n\t\"meta\",\n\t\"__meta__\",\n\t\"relations\",\n]);\n\n/**\n * Common mistakes to watch out for\n */\nconst FORBIDDEN_KEYS_MAPPING: Record<string, string> = {\n\tfields: \"select\",\n};\n\n/**\n * @deprecated Dont need it any more. query-builder creates perfectly validated QueryObjects\n * Validates that a QueryObject contains only allowed keys.\n * This is a runtime check to catch errors from plugins or dynamic query construction.\n */\nexport function validateQueryObject<T extends DatrixEntry>(\n\tquery: unknown,\n): void {\n\tif (typeof query !== \"object\" || query === null) {\n\t\tthrow new DatrixError(\"Query must be an object\", {\n\t\t\tcode: \"INVALID_QUERY_TYPE\",\n\t\t\toperation: \"query:validate\",\n\t\t\tcontext: { receivedType: typeof query },\n\t\t\tsuggestion: \"Provide a valid QueryObject\",\n\t\t\texpected: \"object\",\n\t\t\treceived: query,\n\t\t});\n\t}\n\n\tconst queryKeys = Object.keys(query);\n\tconst invalidKeys: string[] = [];\n\tconst suggestions: string[] = [];\n\n\tfor (const key of queryKeys) {\n\t\tif (!VALID_QUERY_KEYS.has(key)) {\n\t\t\tconst suggestion = FORBIDDEN_KEYS_MAPPING[key];\n\t\t\tif (suggestion) {\n\t\t\t\tinvalidKeys.push(key);\n\t\t\t\tsuggestions.push(`Use '${suggestion}' instead of '${key}'`);\n\t\t\t} else {\n\t\t\t\tinvalidKeys.push(key);\n\t\t\t}\n\t\t}\n\t}\n\n\tif (invalidKeys.length > 0) {\n\t\tconst keyList = invalidKeys\n\t\t\t.map((key) => {\n\t\t\t\tconst alt = FORBIDDEN_KEYS_MAPPING[key];\n\t\t\t\treturn alt ? `'${key}' (use '${alt}' instead)` : `'${key}'`;\n\t\t\t})\n\t\t\t.join(\", \");\n\n\t\tthrow new DatrixError(`Invalid keys found in QueryObject: ${keyList}`, {\n\t\t\tcode: \"INVALID_QUERY_KEYS\",\n\t\t\toperation: \"query:validate\",\n\t\t\tcontext: {\n\t\t\t\tinvalidKeys,\n\t\t\t\tvalidKeys: Array.from(VALID_QUERY_KEYS),\n\t\t\t\tquery,\n\t\t\t},\n\t\t\tsuggestion:\n\t\t\t\tsuggestions.length > 0\n\t\t\t\t\t? suggestions.join(\"; \")\n\t\t\t\t\t: \"Remove invalid keys from QueryObject\",\n\t\t\texpected: `Valid keys: ${Array.from(VALID_QUERY_KEYS).join(\", \")}`,\n\t\t});\n\t}\n\n\t// Basic structure check for required fields\n\tconst q = query as Partial<QueryObject<T>>;\n\tif (!q.type) {\n\t\tthrow new DatrixError(\"QueryObject is missing required field: type\", {\n\t\t\tcode: \"MISSING_QUERY_FIELD\",\n\t\t\toperation: \"query:validate\",\n\t\t\tcontext: { query },\n\t\t\tsuggestion:\n\t\t\t\t\"Add 'type' field to QueryObject (e.g., 'select', 'insert', 'update', 'delete')\",\n\t\t\texpected: \"type: 'select' | 'insert' | 'update' | 'delete'\",\n\t\t});\n\t}\n\tif (!q.table) {\n\t\tthrow new DatrixError(\"QueryObject is missing required field: table\", {\n\t\t\tcode: \"MISSING_QUERY_FIELD\",\n\t\t\toperation: \"query:validate\",\n\t\t\tcontext: { query },\n\t\t\tsuggestion: \"Add 'table' field to QueryObject with the target table name\",\n\t\t\texpected: \"table: string\",\n\t\t});\n\t}\n}\n","import { DatrixError } from \"../types/errors\";\n\ntype BeforeHookName =\n\t| \"beforeCreate\"\n\t| \"beforeUpdate\"\n\t| \"beforeDelete\"\n\t| \"beforeFind\";\n\ntype AfterHookName =\n\t| \"afterCreate\"\n\t| \"afterUpdate\"\n\t| \"afterDelete\"\n\t| \"afterFind\";\n\n/**\n * Thrown when a before hook returns undefined or null instead of data.\n * This is a programmer error — the hook must always return the (possibly modified) data.\n */\nexport function throwHookInvalidReturn(hookName: BeforeHookName): never {\n\tthrow new DatrixError(\n\t\t`${hookName} hook must return data. Did you forget to return?`,\n\t\t{\n\t\t\tcode: \"HOOK_INVALID_RETURN\",\n\t\t\toperation: `dispatcher:schema:${hookName}`,\n\t\t\tsuggestion: `Ensure your ${hookName} hook returns the data object (even if unmodified).`,\n\t\t},\n\t);\n}\n\n/**\n * Thrown when a plugin's before hook throws an error.\n * Re-throws DatrixErrors as-is; wraps unknown errors.\n */\nexport function throwHookPluginError(\n\tpluginName: string,\n\thookName: string,\n\tcause: unknown,\n): never {\n\tif (cause instanceof DatrixError) throw cause;\n\tthrow new DatrixError(\n\t\t`Plugin '${pluginName}' threw an error in ${hookName} hook.`,\n\t\t{\n\t\t\tcode: \"HOOK_PLUGIN_ERROR\",\n\t\t\toperation: `dispatcher:plugin:${hookName}`,\n\t\t\tcause: cause instanceof Error ? cause : new Error(String(cause)),\n\t\t},\n\t);\n}\n\n/**\n * Logs a warning when an after hook throws an error.\n * The operation result is still returned — after hook errors do not abort the response.\n * See docs: after hook errors are non-fatal by design.\n */\nexport function warnAfterHookError(\n\thookName: AfterHookName,\n\terror: unknown,\n): void {\n\tconsole.warn(\n\t\t`[Datrix] ${hookName} hook threw an error. The operation completed successfully but the hook failed.`,\n\t\terror,\n\t);\n}\n","/**\n * Plugin Hook Dispatcher\n *\n * Orchestrates the execution of plugin hooks (lifecycle and query hooks).\n * Ensures hooks are called in the correct order and provides error isolation.\n */\n\nimport {\n\tQueryObject,\n\tQuerySelectObject,\n\tQueryInsertObject,\n\tQueryUpdateObject,\n\tQueryDeleteObject,\n} from \"../types/core/query-builder\";\nimport { PluginRegistry } from \"../types/core/plugin\";\nimport { QueryAction, QueryContext } from \"../types/core/query-context\";\nimport {\n\tDatrixEntry,\n\tDatrixRecord,\n\tSchemaDefinition,\n\tLifecycleHooks,\n} from \"../types/core/schema\";\nimport type { Datrix } from \"../datrix\";\nimport { validateQueryObject } from \"../types/utils/query\";\nimport { SchemaRegistry } from \"../schema\";\nimport {\n\tthrowHookInvalidReturn,\n\tthrowHookPluginError,\n\twarnAfterHookError,\n} from \"./hook-errors\";\n\n/**\n * Create a new query context\n */\nfunction createQueryContext(action: QueryAction, datrix: Datrix): QueryContext {\n\treturn {\n\t\taction,\n\t\tdatrix,\n\t\tmetadata: {},\n\t};\n}\n\n/**\n * Dispatcher for plugin hooks\n */\nexport class Dispatcher {\n\tconstructor(\n\t\tprivate readonly registry: PluginRegistry,\n\t\tprivate readonly datrix: Datrix,\n\t) { }\n\n\t/**\n\t * Create and populate query context\n\t *\n\t * This allows plugins to enrich the context before query execution.\n\t */\n\tasync buildQueryContext(action: QueryAction): Promise<QueryContext> {\n\t\tlet context = createQueryContext(action, this.datrix);\n\n\t\tfor (const plugin of this.registry.getAll()) {\n\t\t\ttry {\n\t\t\t\tif (plugin.onCreateQueryContext) {\n\t\t\t\t\tconst result = await plugin.onCreateQueryContext(context);\n\t\t\t\t\tif (result) {\n\t\t\t\t\t\tcontext = result;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(\n\t\t\t\t\t`[Dispatcher] Error in plugin '${plugin.name}' onCreateQueryContext:`,\n\t\t\t\t\terror,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\treturn context;\n\t}\n\n\t/**\n\t * Dispatch onSchemaLoad hook to all plugins\n\t */\n\tasync dispatchSchemaLoad(schemas: SchemaRegistry): Promise<void> {\n\t\tfor (const plugin of this.registry.getAll()) {\n\t\t\ttry {\n\t\t\t\tif (plugin.onSchemaLoad) {\n\t\t\t\t\tawait plugin.onSchemaLoad(schemas);\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(\n\t\t\t\t\t`[Dispatcher] Error in plugin '${plugin.name}' onSchemaLoad:`,\n\t\t\t\t\terror,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Execute full query lifecycle:\n\t * 1. Create context + shared hookCtx (metadata shared between before/after)\n\t * 2. onBeforeQuery plugin hooks + schema before hook\n\t * 3. Execute query\n\t * 4. onAfterQuery plugin hooks + schema after hook\n\t */\n\tasync executeQuery<\n\t\tTResult extends DatrixEntry,\n\t\tR extends DatrixEntry = DatrixEntry,\n\t>(\n\t\taction: QueryAction,\n\t\tschema: SchemaDefinition,\n\t\tquery: QueryObject<TResult>,\n\t\texecutor: (query: QueryObject<TResult>) => Promise<R>,\n\t): Promise<R> {\n\t\tconst context = await this.buildQueryContext(action);\n\t\tconst modifiedQuery = await this.dispatchBeforeQuery(\n\t\t\tquery,\n\t\t\tschema,\n\t\t\tcontext,\n\t\t);\n\t\tconst result = await executor(modifiedQuery);\n\t\treturn this.dispatchAfterQuery<R>(result, schema, context);\n\t}\n\n\t/**\n\t * Dispatch onBeforeQuery hook to all plugins (serial execution),\n\t * then call the schema lifecycle hook if defined.\n\t * Both plugins and schema hooks can modify and return the query.\n\t * hookCtx is shared with dispatchAfterQuery so metadata persists.\n\t */\n\tasync dispatchBeforeQuery<TResult extends DatrixEntry = DatrixRecord>(\n\t\tquery: QueryObject<TResult>,\n\t\tschema: SchemaDefinition,\n\t\tcontext: QueryContext,\n\t): Promise<QueryObject<TResult>> {\n\t\tvalidateQueryObject(query);\n\n\t\tlet currentQuery = { ...query } as QueryObject<TResult>;\n\n\t\tfor (const plugin of this.registry.getAll()) {\n\t\t\ttry {\n\t\t\t\tif (plugin.onBeforeQuery) {\n\t\t\t\t\tcurrentQuery = await plugin.onBeforeQuery(currentQuery, context);\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tthrowHookPluginError(plugin.name, \"onBeforeQuery\", error);\n\t\t\t}\n\t\t}\n\n\t\tcurrentQuery = await this.dispatchSchemaBeforeHook(\n\t\t\tcurrentQuery,\n\t\t\tschema,\n\t\t\tcontext,\n\t\t);\n\n\t\treturn currentQuery;\n\t}\n\n\t/**\n\t * Dispatch onAfterQuery hook to all plugins (serial execution),\n\t * then call the schema lifecycle hook if defined.\n\t * Both plugins and schema hooks can modify and return the result.\n\t * hookCtx is the same instance as in dispatchBeforeQuery so metadata is shared.\n\t */\n\tasync dispatchAfterQuery<TResult extends DatrixEntry>(\n\t\tresult: TResult,\n\t\tschema: SchemaDefinition,\n\t\tcontext: QueryContext,\n\t): Promise<TResult> {\n\t\tlet currentResult = result;\n\n\t\tfor (const plugin of this.registry.getAll()) {\n\t\t\ttry {\n\t\t\t\tif (plugin.onAfterQuery) {\n\t\t\t\t\tcurrentResult = await plugin.onAfterQuery(currentResult, context);\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\twarnAfterHookError(\"afterFind\", error);\n\t\t\t}\n\t\t}\n\n\t\tcurrentResult = await this.dispatchSchemaAfterHook(\n\t\t\tcurrentResult,\n\t\t\tschema,\n\t\t\tcontext,\n\t\t);\n\n\t\treturn currentResult;\n\t}\n\n\tprivate async dispatchSchemaBeforeHook<TResult extends DatrixEntry>(\n\t\tquery: QueryObject<TResult>,\n\t\tschema: SchemaDefinition,\n\t\tcontext: QueryContext,\n\t): Promise<QueryObject<TResult>> {\n\t\tconst hooks = schema.hooks as LifecycleHooks<TResult> | undefined;\n\t\tif (!hooks) return query;\n\n\t\tconst { action } = context;\n\n\t\tif (\n\t\t\t(action === \"create\" || action === \"createMany\") &&\n\t\t\thooks.beforeCreate &&\n\t\t\tquery.type === \"insert\"\n\t\t) {\n\t\t\tconst modified = await hooks.beforeCreate(\n\t\t\t\tquery as QueryInsertObject<TResult>,\n\t\t\t\tcontext,\n\t\t\t);\n\t\t\tif (modified == null) throwHookInvalidReturn(\"beforeCreate\");\n\t\t\treturn modified as QueryObject<TResult>;\n\t\t}\n\n\t\tif (\n\t\t\t(action === \"update\" || action === \"updateMany\") &&\n\t\t\thooks.beforeUpdate &&\n\t\t\tquery.type === \"update\"\n\t\t) {\n\t\t\tconst modified = await hooks.beforeUpdate(\n\t\t\t\tquery as QueryUpdateObject<TResult>,\n\t\t\t\tcontext,\n\t\t\t);\n\t\t\tif (modified == null) throwHookInvalidReturn(\"beforeUpdate\");\n\t\t\treturn modified as QueryObject<TResult>;\n\t\t}\n\n\t\tif (\n\t\t\t(action === \"delete\" || action === \"deleteMany\") &&\n\t\t\thooks.beforeDelete &&\n\t\t\tquery.type === \"delete\"\n\t\t) {\n\t\t\tconst modified = await hooks.beforeDelete(\n\t\t\t\tquery as QueryDeleteObject<TResult>,\n\t\t\t\tcontext,\n\t\t\t);\n\t\t\tif (modified == null) throwHookInvalidReturn(\"beforeDelete\");\n\t\t\treturn modified as QueryObject<TResult>;\n\t\t}\n\n\t\tif (\n\t\t\t(action === \"findOne\" || action === \"findMany\" || action === \"count\") &&\n\t\t\thooks.beforeFind &&\n\t\t\tquery.type === \"select\"\n\t\t) {\n\t\t\tconst modified = await hooks.beforeFind(\n\t\t\t\tquery as QuerySelectObject<TResult>,\n\t\t\t\tcontext,\n\t\t\t);\n\t\t\tif (modified == null) throwHookInvalidReturn(\"beforeFind\");\n\t\t\treturn modified as QueryObject<TResult>;\n\t\t}\n\n\t\treturn query;\n\t}\n\n\tprivate async dispatchSchemaAfterHook<TResult extends DatrixEntry>(\n\t\tresult: TResult,\n\t\tschema: SchemaDefinition,\n\t\tcontext: QueryContext,\n\t): Promise<TResult> {\n\t\tconst hooks = schema.hooks;\n\t\tif (!hooks) return result;\n\n\t\tconst { action } = context;\n\t\tconst rows = result;\n\n\t\tif ((action === \"create\" || action === \"createMany\") && hooks.afterCreate) {\n\t\t\ttry {\n\t\t\t\treturn (await hooks.afterCreate(\n\t\t\t\t\trows as unknown as DatrixEntry[],\n\t\t\t\t\tcontext,\n\t\t\t\t)) as unknown as TResult;\n\t\t\t} catch (error) {\n\t\t\t\twarnAfterHookError(\"afterCreate\", error);\n\t\t\t}\n\t\t}\n\n\t\tif ((action === \"update\" || action === \"updateMany\") && hooks.afterUpdate) {\n\t\t\ttry {\n\t\t\t\treturn (await hooks.afterUpdate(\n\t\t\t\t\trows as unknown as DatrixEntry[],\n\t\t\t\t\tcontext,\n\t\t\t\t)) as unknown as TResult;\n\t\t\t} catch (error) {\n\t\t\t\twarnAfterHookError(\"afterUpdate\", error);\n\t\t\t}\n\t\t}\n\n\t\tif ((action === \"delete\" || action === \"deleteMany\") && hooks.afterDelete) {\n\t\t\ttry {\n\t\t\t\tawait hooks.afterDelete(rows as unknown as DatrixEntry[], context);\n\t\t\t} catch (error) {\n\t\t\t\twarnAfterHookError(\"afterDelete\", error);\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\n\t\tif ((action === \"findOne\" || action === \"findMany\") && hooks.afterFind) {\n\t\t\ttry {\n\t\t\t\treturn (await hooks.afterFind(\n\t\t\t\t\trows as unknown as DatrixEntry[],\n\t\t\t\t\tcontext,\n\t\t\t\t)) as unknown as TResult;\n\t\t\t} catch (error) {\n\t\t\t\twarnAfterHookError(\"afterFind\", error);\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n}\n\n/**\n * Create a new dispatcher\n */\nexport function createDispatcher(\n\tregistry: PluginRegistry,\n\tdatrix: Datrix,\n): Dispatcher {\n\treturn new Dispatcher(registry, datrix);\n}\n","/**\n * Plugin Interface\n *\n * This file defines the standard interface that ALL plugins must implement.\n * Plugins extend Datrix's core functionality with features like auth, upload, hooks, etc.\n */\n\nimport type {\n\tISchemaRegistry,\n\tSchemaDefinition,\n\tFieldDefinition,\n\tIndexDefinition,\n\tDatrixEntry,\n} from \"./schema\";\nimport type { DatabaseAdapter } from \"../adapter\";\nimport { QueryObject } from \"./query-builder\";\nimport { QueryContext } from \"./query-context\";\nimport { DatrixConfig } from \"./config\";\n\nexport type { SchemaDefinition } from \"./schema\";\n\n/**\n * Plugin context (provided during initialization)\n */\nexport interface PluginContext {\n\treadonly adapter: DatabaseAdapter;\n\treadonly schemas: ISchemaRegistry;\n\treadonly config: DatrixConfig;\n}\n\n/**\n * Plugin interface\n *\n * ALL plugins MUST implement this interface\n */\nexport interface DatrixPlugin<TOptions = Record<string, unknown>> {\n\t// Metadata\n\treadonly name: string;\n\treadonly version: string;\n\treadonly options: TOptions;\n\n\t// Lifecycle\n\tinit(context: PluginContext): Promise<void>;\n\tdestroy(): Promise<void>;\n\n\t// Schema hooks\n\tgetSchemas?(): Promise<SchemaDefinition[]>;\n\textendSchemas?(context: SchemaExtensionContext): Promise<SchemaExtension[]>;\n\n\t// Query hooks\n\tonSchemaLoad?(schemas: ISchemaRegistry): Promise<void>;\n\tonCreateQueryContext?(context: QueryContext): Promise<QueryContext>;\n\tonBeforeQuery?<T extends DatrixEntry>(\n\t\tquery: QueryObject<T>,\n\t\tcontext: QueryContext,\n\t): Promise<QueryObject<T>>;\n\tonAfterQuery?<TResult extends DatrixEntry>(\n\t\tresult: TResult,\n\t\tcontext: QueryContext,\n\t): Promise<TResult>;\n}\n\n/**\n * Base plugin error\n */\nexport class PluginError extends Error {\n\treadonly code: string;\n\treadonly pluginName: string | undefined;\n\treadonly details: unknown | undefined;\n\n\tconstructor(\n\t\tmessage: string,\n\t\toptions?: { code?: string; pluginName?: string; details?: unknown },\n\t) {\n\t\tsuper(message);\n\t\tthis.name = \"PluginError\";\n\t\tthis.code = options?.code ?? \"UNKNOWN\";\n\t\tthis.pluginName = options?.pluginName;\n\t\tthis.details = options?.details;\n\t}\n}\n\n/**\n * Type guard for DatrixPlugin\n */\nexport function isDatrixPlugin(value: unknown): value is DatrixPlugin {\n\tif (typeof value !== \"object\" || value === null) {\n\t\treturn false;\n\t}\n\n\tconst obj = value as Record<string, unknown>;\n\n\treturn (\n\t\t\"name\" in obj &&\n\t\t\"version\" in obj &&\n\t\t\"init\" in obj &&\n\t\t\"destroy\" in obj &&\n\t\ttypeof obj[\"name\"] === \"string\" &&\n\t\ttypeof obj[\"version\"] === \"string\" &&\n\t\ttypeof obj[\"init\"] === \"function\" &&\n\t\ttypeof obj[\"destroy\"] === \"function\"\n\t);\n}\n\n/**\n * Plugin factory type\n */\nexport type PluginFactory<TOptions = Record<string, unknown>> = (\n\toptions: TOptions,\n) => DatrixPlugin<TOptions>;\n\n/**\n * Upload error\n */\nexport class UploadError extends PluginError {\n\tconstructor(message: string, details?: unknown) {\n\t\tsuper(message, { code: \"UPLOAD_ERROR\", details });\n\t\tthis.name = \"UploadError\";\n\t}\n}\n\n/**\n * Plugin registry\n */\nexport class PluginRegistry {\n\tprivate readonly plugins: Map<string, DatrixPlugin> = new Map();\n\n\tregister(plugin: DatrixPlugin): void {\n\t\tif (this.plugins.has(plugin.name)) {\n\t\t\tthrow new PluginError(`Plugin already registered: ${plugin.name}`, {\n\t\t\t\tcode: \"DUPLICATE_PLUGIN\",\n\t\t\t});\n\t\t}\n\t\tthis.plugins.set(plugin.name, plugin);\n\t}\n\n\tget(name: string): DatrixPlugin | undefined {\n\t\treturn this.plugins.get(name);\n\t}\n\n\thas(name: string): boolean {\n\t\treturn this.plugins.has(name);\n\t}\n\n\tgetAll(): readonly DatrixPlugin[] {\n\t\treturn Array.from(this.plugins.values());\n\t}\n\n\tasync initAll(context: PluginContext): Promise<void> {\n\t\tfor (const plugin of this.plugins.values()) {\n\t\t\tawait plugin.init(context);\n\t\t}\n\t}\n\n\tasync destroyAll(): Promise<void> {\n\t\tfor (const plugin of this.plugins.values()) {\n\t\t\tawait plugin.destroy();\n\t\t}\n\t}\n}\n\n/**\n * Schema extension definition\n */\nexport interface SchemaExtension {\n\treadonly targetSchema: string;\n\treadonly fields?: Record<string, FieldDefinition>;\n\treadonly removeFields?: readonly string[];\n\treadonly modifyFields?: Record<string, Partial<FieldDefinition>>;\n\treadonly indexes?: readonly IndexDefinition[];\n}\n\n/**\n * Schema modifier function\n */\nexport type SchemaModifier = (schema: SchemaDefinition) => {\n\treadonly fields?: Record<string, FieldDefinition>;\n\treadonly indexes?: readonly IndexDefinition[];\n\treadonly removeFields?: readonly string[];\n\treadonly modifyFields?: Record<string, Partial<FieldDefinition>>;\n};\n\n/**\n * Schema pattern for filtering\n */\nexport interface SchemaPattern {\n\treadonly names?: readonly string[];\n\treadonly prefix?: string;\n\treadonly suffix?: string;\n\treadonly exclude?: readonly string[];\n\treadonly custom?: (schema: SchemaDefinition) => boolean;\n}\n\n/**\n * Schema extension context\n */\nexport interface SchemaExtensionContext {\n\treadonly schemas: ReadonlyArray<SchemaDefinition>;\n\n\textendAll(modifier: SchemaModifier): SchemaExtension[];\n\n\textendWhere(\n\t\tpredicate: (schema: SchemaDefinition) => boolean,\n\t\tmodifier: SchemaModifier,\n\t): SchemaExtension[];\n\n\textendByPattern(\n\t\tpattern: SchemaPattern,\n\t\tmodifier: SchemaModifier,\n\t): SchemaExtension[];\n}\n","/**\n * Core Constants\n *\n * Central location for all validation rules, limits, and operator definitions.\n * Used across parsers, query builders, and adapters.\n */\n\n/**\n * Maximum field/column name length\n * Based on PostgreSQL limit (most restrictive common database)\n */\nexport const MAX_FIELD_NAME_LENGTH = 63;\n\n/**\n * Maximum value length for WHERE clauses\n * Prevents DoS attacks with extremely large values\n */\nexport const MAX_WHERE_VALUE_LENGTH = 10000;\n\n/**\n * Maximum nesting depth for logical operators ($or, $and)\n * Prevents stack overflow attacks\n */\nexport const MAX_LOGICAL_NESTING_DEPTH = 10;\n\n/**\n * Maximum array index for indexed parameters (fields[N], populate[N])\n * Prevents DoS attacks with extremely large indices\n */\nexport const MAX_ARRAY_INDEX = 1000;\n\n/**\n * Comparison operators for WHERE clauses\n */\nexport const COMPARISON_OPERATORS = [\n\t\"$eq\", // Equal\n\t\"$ne\", // Not equal\n\t\"$gt\", // Greater than\n\t\"$gte\", // Greater than or equal\n\t\"$lt\", // Less than\n\t\"$lte\", // Less than or equal\n] as const;\n\n/**\n * String operators for WHERE clauses\n */\nexport const STRING_OPERATORS = [\n\t\"$contains\", // String contains\n\t\"$notContains\", // String does not contain\n\t\"$startsWith\", // String starts with\n\t\"$endsWith\", // String ends with\n\t\"$like\", // SQL LIKE pattern\n\t\"$ilike\", // Case-insensitive LIKE\n] as const;\n\n/**\n * Array membership operators for WHERE clauses\n */\nexport const ARRAY_OPERATORS = [\n\t\"$in\", // Value in array\n\t\"$nin\", // Value not in array\n] as const;\n\n/**\n * Null check operators for WHERE clauses\n */\nexport const NULL_OPERATORS = [\n\t\"$null\", // IS NULL\n\t\"$notNull\", // IS NOT NULL\n] as const;\n\n/**\n * Logical operators for WHERE clauses\n */\nexport const LOGICAL_OPERATORS = [\n\t\"$and\", // Logical AND\n\t\"$or\", // Logical OR\n\t\"$not\", // Logical NOT\n] as const;\n\n/**\n * All valid WHERE operators\n */\nexport const ALL_WHERE_OPERATORS = [\n\t...COMPARISON_OPERATORS,\n\t...STRING_OPERATORS,\n\t...ARRAY_OPERATORS,\n\t...NULL_OPERATORS,\n\t...LOGICAL_OPERATORS,\n] as const;\n\n/**\n * Type of operator value expectations\n */\nexport type OperatorValueType =\n\t| \"any\" // Any primitive value\n\t| \"array\" // Must be array\n\t| \"number\" // Must be number\n\t| \"string\" // Must be string\n\t| \"boolean\" // Must be boolean\n\t| \"conditions\"; // Array of WHERE conditions (for logical operators)\n\n/**\n * Operator validation rules\n * Defines what type of value each operator expects\n */\nexport const OPERATOR_VALUE_TYPES: Record<string, OperatorValueType> = {\n\t// Comparison operators - accept any value\n\t$eq: \"any\",\n\t$ne: \"any\",\n\t$gt: \"any\",\n\t$gte: \"any\",\n\t$lt: \"any\",\n\t$lte: \"any\",\n\n\t// String operators - must be string\n\t$contains: \"string\",\n\t$notContains: \"string\",\n\t$startsWith: \"string\",\n\t$endsWith: \"string\",\n\t$like: \"string\",\n\t$ilike: \"string\",\n\n\t// Array operators - must be array of values\n\t$in: \"array\",\n\t$nin: \"array\",\n\n\t// Null operators - boolean or no value needed\n\t$null: \"boolean\",\n\t$notNull: \"boolean\",\n\n\t// Logical operators - must be array of conditions\n\t$and: \"conditions\",\n\t$or: \"conditions\",\n\t$not: \"conditions\",\n} as const;\n\n/**\n * Check if a string is a valid WHERE operator\n */\nexport function isValidWhereOperator(\n\toperator: string,\n): operator is (typeof ALL_WHERE_OPERATORS)[number] {\n\treturn (ALL_WHERE_OPERATORS as readonly string[]).includes(operator);\n}\n\n/**\n * Check if an operator is a logical operator\n */\nexport function isLogicalOperator(\n\toperator: string,\n): operator is (typeof LOGICAL_OPERATORS)[number] {\n\treturn (LOGICAL_OPERATORS as readonly string[]).includes(operator);\n}\n\n/**\n * Check if an operator requires an array value\n */\nexport function requiresArrayValue(operator: string): boolean {\n\treturn OPERATOR_VALUE_TYPES[operator] === \"array\";\n}\n\n/**\n * Check if an operator requires conditions (for logical operators)\n */\nexport function requiresConditions(operator: string): boolean {\n\treturn OPERATOR_VALUE_TYPES[operator] === \"conditions\";\n}\n\n/**\n * Get expected value type for an operator\n */\nexport function getOperatorValueType(\n\toperator: string,\n): OperatorValueType | undefined {\n\treturn OPERATOR_VALUE_TYPES[operator];\n}\n\n/**\n * Internal metadata table name used by all adapters to store schema snapshots\n */\nexport const DATRIX_META_MODEL = \"_datrix\";\n\n/**\n * Key prefix for schema entries stored in the _datrix metadata table\n */\nexport const DATRIX_META_KEY_PREFIX = \"_schema_\";\n\n/**\n * Field name validation pattern\n * Must start with letter or underscore, contain only alphanumeric, underscores, and dots\n */\nexport const FIELD_NAME_PATTERN = /^[a-zA-Z_][a-zA-Z0-9_.]*$/;\n\n/**\n * Control characters pattern (dangerous in all contexts)\n */\nexport const CONTROL_CHARS_PATTERN = /[\\x00-\\x1F\\x7F]/;\n\n/**\n * Reserved field names (prototype pollution protection)\n */\nexport const RESERVED_FIELD_NAMES = [\n\t\"__proto__\",\n\t\"constructor\",\n\t\"prototype\",\n] as const;\n\n/**\n * Field validation failure reasons\n */\nexport type FieldInvalidReason =\n\t| \"EMPTY\"\n\t| \"TOO_LONG\"\n\t| \"RESERVED_FIELD\"\n\t| \"CONTROL_CHARS\"\n\t| \"INVALID_FORMAT\";\n\n/**\n * Field validation result with detailed reason\n */\nexport type FieldValidationResult =\n\t| { valid: true }\n\t| { valid: false; reason: FieldInvalidReason; detail?: string };\n\n/**\n * Validate field name with detailed reason on failure\n *\n * @param fieldName - Field name to validate\n * @returns Validation result with reason if invalid\n */\nexport function validateFieldName(fieldName: string): FieldValidationResult {\n\t// Empty or whitespace-only\n\tif (!fieldName || fieldName.trim() === \"\") {\n\t\treturn { valid: false, reason: \"EMPTY\" };\n\t}\n\n\t// Length check\n\tif (fieldName.length > MAX_FIELD_NAME_LENGTH) {\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\treason: \"TOO_LONG\",\n\t\t\tdetail: `Max ${MAX_FIELD_NAME_LENGTH} characters`,\n\t\t};\n\t}\n\n\t// Reserved fields check (prototype pollution protection)\n\tif (\n\t\tRESERVED_FIELD_NAMES.includes(\n\t\t\tfieldName as (typeof RESERVED_FIELD_NAMES)[number],\n\t\t)\n\t) {\n\t\treturn { valid: false, reason: \"RESERVED_FIELD\", detail: fieldName };\n\t}\n\n\t// Control characters check\n\tif (CONTROL_CHARS_PATTERN.test(fieldName)) {\n\t\treturn { valid: false, reason: \"CONTROL_CHARS\" };\n\t}\n\n\t// Format check\n\tif (!FIELD_NAME_PATTERN.test(fieldName)) {\n\t\treturn { valid: false, reason: \"INVALID_FORMAT\" };\n\t}\n\n\treturn { valid: true };\n}\n\n/**\n * Validate field name against universal rules (simple boolean)\n *\n * @param fieldName - Field name to validate\n * @returns True if valid, false otherwise\n */\nexport function isValidFieldName(fieldName: string): boolean {\n\treturn validateFieldName(fieldName).valid;\n}\n","/**\n * Schema Registry Implementation\n *\n * Manages schema registration, retrieval, and validation.\n * Central store for all schemas in the application.\n */\n\nimport type {\n\tFieldDefinition,\n\tFileField,\n\tFileFieldOptions,\n\tDatrixEntry,\n\tISchemaRegistry,\n\tRelationField,\n\tSchemaDefinition,\n\tSchemaValidationError,\n} from \"../types/core/schema\";\nimport {\n\tvalidateSchemaDefinition,\n\tsortSchemasByDependency,\n\tRESERVED_FIELDS,\n} from \"../types/core/schema\";\nimport { DATRIX_META_MODEL } from \"../types/core/constants\";\nimport { QuerySelect } from \"../types/core/query-builder\";\n\n/**\n * Schema registry error\n */\nexport class SchemaRegistryError extends Error {\n\treadonly code: string;\n\treadonly schemaName: string | undefined;\n\treadonly details: unknown | undefined;\n\n\tconstructor(\n\t\tmessage: string,\n\t\toptions?: {\n\t\t\tcode?: string;\n\t\t\tschemaName?: string;\n\t\t\tdetails?: unknown;\n\t\t},\n\t) {\n\t\tsuper(message);\n\t\tthis.name = \"SchemaRegistryError\";\n\t\tthis.code = options?.code ?? \"UNKNOWN\";\n\t\tthis.schemaName = options?.schemaName;\n\t\tthis.details = options?.details;\n\t}\n}\n\n/**\n * Schema registry configuration\n */\nexport interface SchemaRegistryConfig {\n\treadonly strict: boolean | undefined;\n\treadonly allowOverwrite: boolean | undefined;\n\treadonly validateRelations: boolean | undefined;\n}\n\n/**\n * Performance cache for expensive operations\n */\ninterface RegistryCache {\n\trelatedSchemas: Map<string, readonly string[]>;\n\treferencingSchemas: Map<string, readonly string[]>;\n\tfieldTypeIndex: Map<string, readonly SchemaDefinition[]>;\n\tselectFields: Map<string, readonly string[]>;\n}\n\n/**\n * Schema registry implementation\n */\nexport class SchemaRegistry implements ISchemaRegistry {\n\tprivate readonly schemas: Map<string, SchemaDefinition> = new Map();\n\tprivate readonly config: Required<SchemaRegistryConfig>;\n\tprivate locked = false;\n\tprivate cache: RegistryCache = {\n\t\trelatedSchemas: new Map(),\n\t\treferencingSchemas: new Map(),\n\t\tfieldTypeIndex: new Map(),\n\t\tselectFields: new Map(),\n\t};\n\n\tconstructor(config?: SchemaRegistryConfig) {\n\t\tthis.config = {\n\t\t\tstrict: config?.strict ?? true,\n\t\t\tallowOverwrite: config?.allowOverwrite ?? false,\n\t\t\tvalidateRelations: config?.validateRelations ?? true,\n\t\t};\n\t}\n\n\t/**\n\t * Invalidate performance cache\n\t */\n\tprivate invalidateCache(): void {\n\t\tthis.cache.relatedSchemas.clear();\n\t\tthis.cache.referencingSchemas.clear();\n\t\tthis.cache.fieldTypeIndex.clear();\n\t\tthis.cache.selectFields.clear();\n\t}\n\n\t/**\n\t * Register a schema\n\t * Adds reserved fields (id, createdAt, updatedAt)\n\t * Does NOT process relations - call finalizeRegistry() after all schemas are registered\n\t */\n\tregister(schema: SchemaDefinition): SchemaDefinition {\n\t\tif (this.locked) {\n\t\t\tthrow new SchemaRegistryError(\"Registry is locked\", {\n\t\t\t\tcode: \"REGISTRY_LOCKED\",\n\t\t\t});\n\t\t}\n\n\t\tif (!schema.name || schema.name.trim() === \"\") {\n\t\t\tthrow new SchemaRegistryError(\"Schema name is required\", {\n\t\t\t\tcode: \"INVALID_SCHEMA_NAME\",\n\t\t\t});\n\t\t}\n\n\t\tif (this.schemas.has(schema.name) && !this.config.allowOverwrite) {\n\t\t\tthrow new SchemaRegistryError(\n\t\t\t\t`Schema already registered: ${schema.name}`,\n\t\t\t\t{\n\t\t\t\t\tcode: \"DUPLICATE_SCHEMA\",\n\t\t\t\t\tschemaName: schema.name,\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\n\t\tfor (const reservedField of RESERVED_FIELDS) {\n\t\t\tif (reservedField in schema.fields) {\n\t\t\t\tthrow new SchemaRegistryError(\n\t\t\t\t\t`Field '${reservedField}' is reserved and cannot be defined manually in schema '${schema.name}'`,\n\t\t\t\t\t{\n\t\t\t\t\t\tcode: \"RESERVED_FIELD_NAME\",\n\t\t\t\t\t\tschemaName: schema.name,\n\t\t\t\t\t\tdetails: { field: reservedField },\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tif (this.config.strict) {\n\t\t\tconst validation = validateSchemaDefinition(schema);\n\t\t\tif (!validation.valid) {\n\t\t\t\tthrow new SchemaRegistryError(\n\t\t\t\t\t`Schema validation failed: ${schema.name}`,\n\t\t\t\t\t{\n\t\t\t\t\t\tcode: \"VALIDATION_FAILED\",\n\t\t\t\t\t\tschemaName: schema.name,\n\t\t\t\t\t\tdetails: validation.errors,\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tconst transformedFields = this.transformFileFields(schema.fields);\n\n\t\tconst enhancedFields = {\n\t\t\tid: {\n\t\t\t\ttype: \"number\" as const,\n\t\t\t\tprimary: true,\n\t\t\t\tautoIncrement: true,\n\t\t\t\trequired: true,\n\t\t\t},\n\t\t\t...transformedFields,\n\t\t\tcreatedAt: {\n\t\t\t\ttype: \"date\" as const,\n\t\t\t\trequired: true,\n\t\t\t},\n\t\t\tupdatedAt: {\n\t\t\t\ttype: \"date\" as const,\n\t\t\t\trequired: true,\n\t\t\t},\n\t\t};\n\n\t\tconst storedSchema = {\n\t\t\t...schema,\n\t\t\ttableName: schema.tableName ?? this.pluralize(schema.name.toLowerCase()),\n\t\t\tfields: enhancedFields,\n\t\t};\n\n\t\tthis.schemas.set(schema.name, storedSchema);\n\t\tthis.invalidateCache();\n\n\t\treturn storedSchema;\n\t}\n\n\t/**\n\t * Register multiple schemas\n\t * Call finalizeRegistry() after all schemas are registered to process relations\n\t */\n\tregisterMany(schemas: readonly SchemaDefinition[]): void {\n\t\tfor (const schema of schemas) {\n\t\t\tthis.register(schema);\n\t\t}\n\t}\n\n\t/**\n\t * Finalize registry after all schemas are registered\n\t * Processes relations and creates junction tables\n\t * Call this after:\n\t * 1. User schemas registered\n\t * 2. Plugin schemas registered\n\t * 3. Plugin schema extensions applied\n\t */\n\tfinalizeRegistry(): void {\n\t\tthis.processRelations();\n\n\t\tif (this.config.validateRelations) {\n\t\t\tthis.validateRelations();\n\t\t}\n\n\t\tthis.sortByDependencies();\n\t}\n\n\t/**\n\t * Topological sort schemas by FK dependencies.\n\t * Schemas that are referenced by others come first.\n\t * Rebuilds the internal Map in dependency order.\n\t */\n\tprivate sortByDependencies(): void {\n\t\tconst allSchemas = Array.from(this.schemas.values());\n\t\tconst sorted = sortSchemasByDependency(allSchemas);\n\n\t\t// Rebuild Map in sorted order, _datrix always first\n\t\tconst entries = new Map<string, SchemaDefinition>();\n\n\t\tconst metaSchema = this.schemas.get(DATRIX_META_MODEL);\n\t\tif (metaSchema) {\n\t\t\tentries.set(DATRIX_META_MODEL, metaSchema);\n\t\t}\n\n\t\tfor (const schema of sorted) {\n\t\t\tif (schema.name === DATRIX_META_MODEL) continue;\n\t\t\tentries.set(schema.name, schema);\n\t\t}\n\n\t\tthis.schemas.clear();\n\t\tfor (const [name, schema] of entries) {\n\t\t\tthis.schemas.set(name, schema);\n\t\t}\n\t}\n\n\t/**\n\t * Get schema by name\n\t */\n\tget(name: string): SchemaDefinition | undefined {\n\t\treturn this.schemas.get(name);\n\t}\n\n\t/**\n\t * Get schema by model name with resolved table name\n\t */\n\tgetWithTableName(\n\t\tmodelName: string,\n\t): { schema: SchemaDefinition; tableName: string } | undefined {\n\t\tconst schema = this.get(modelName);\n\t\tif (!schema) return undefined;\n\t\treturn {\n\t\t\tschema,\n\t\t\ttableName: schema.tableName ?? this.pluralize(modelName.toLowerCase()),\n\t\t};\n\t}\n\n\t/**\n\t * Get schema by table name\n\t */\n\tgetByTableName(\n\t\ttableName: string,\n\t): { schema: SchemaDefinition; tableName: string } | undefined {\n\t\tconst modelName = this.findModelByTableName(tableName);\n\t\tif (!modelName) return undefined;\n\t\treturn this.getWithTableName(modelName);\n\t}\n\n\t/**\n\t * Check if schema exists\n\t */\n\thas(name: string): boolean {\n\t\treturn this.schemas.has(name);\n\t}\n\n\t/**\n\t * Get all schemas\n\t */\n\tgetAll(): readonly SchemaDefinition[] {\n\t\treturn Array.from(this.schemas.values());\n\t}\n\n\t/**\n\t * Get schema names\n\t */\n\tgetNames(): readonly string[] {\n\t\treturn Array.from(this.schemas.keys());\n\t}\n\n\t/**\n\t * Get schema count\n\t */\n\tget size(): number {\n\t\treturn this.schemas.size;\n\t}\n\n\t/**\n\t * Find model name by table name\n\t */\n\tfindModelByTableName(tableName: string | null): string | null {\n\t\tif (!tableName) return null;\n\t\tfor (const [modelName, schema] of this.schemas.entries()) {\n\t\t\tconst schemaTableName =\n\t\t\t\tschema.tableName ?? this.pluralize(modelName.toLowerCase());\n\t\t\tif (schemaTableName === tableName) {\n\t\t\t\treturn modelName;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * Get schemas with relations\n\t */\n\tgetSchemasWithRelations(): readonly SchemaDefinition[] {\n\t\treturn this.getAll().filter((schema) =>\n\t\t\tObject.values(schema.fields).some((field) => field.type === \"relation\"),\n\t\t);\n\t}\n\n\t/**\n\t * Get related schemas for a given schema (cached)\n\t */\n\tgetRelatedSchemas(schemaName: string): readonly string[] {\n\t\tconst cached = this.cache.relatedSchemas.get(schemaName);\n\t\tif (cached) return cached;\n\n\t\tconst schema = this.get(schemaName);\n\t\tif (!schema) return [];\n\n\t\tconst related: string[] = [];\n\t\tfor (const field of Object.values(schema.fields)) {\n\t\t\tif (field.type === \"relation\") {\n\t\t\t\tconst relationField = field as RelationField;\n\t\t\t\tif (!related.includes(relationField.model)) {\n\t\t\t\t\trelated.push(relationField.model);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tthis.cache.relatedSchemas.set(schemaName, related);\n\t\treturn related;\n\t}\n\n\t/**\n\t * Get schemas that reference a given schema (cached)\n\t */\n\tgetReferencingSchemas(schemaName: string): readonly string[] {\n\t\tconst cached = this.cache.referencingSchemas.get(schemaName);\n\t\tif (cached) return cached;\n\n\t\tconst referencing: string[] = [];\n\t\tfor (const [name, schema] of this.schemas.entries()) {\n\t\t\tfor (const field of Object.values(schema.fields)) {\n\t\t\t\tif (field.type === \"relation\") {\n\t\t\t\t\tconst relationField = field as RelationField;\n\t\t\t\t\tif (relationField.model === schemaName) {\n\t\t\t\t\t\treferencing.push(name);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tthis.cache.referencingSchemas.set(schemaName, referencing);\n\t\treturn referencing;\n\t}\n\n\t/**\n\t * Find schemas by field type (cached)\n\t */\n\tfindByFieldType(fieldType: string): readonly SchemaDefinition[] {\n\t\tconst cached = this.cache.fieldTypeIndex.get(fieldType);\n\t\tif (cached) return cached;\n\n\t\tconst result = this.getAll().filter((schema) =>\n\t\t\tObject.values(schema.fields).some((field) => field.type === fieldType),\n\t\t);\n\n\t\tthis.cache.fieldTypeIndex.set(fieldType, result);\n\t\treturn result;\n\t}\n\n\t/**\n\t * Get cached SELECT fields for a model (wildcard \"*\" expansion)\n\t *\n\t * Returns all selectable fields for a model, excluding:\n\t * - Hidden fields (e.g., foreign keys)\n\t * - Relation fields (use populate for these)\n\t */\n\tgetCachedSelectFields<T extends DatrixEntry>(\n\t\tmodelName: string,\n\t): QuerySelect<T> {\n\t\tconst schema = this.get(modelName);\n\t\tif (!schema) {\n\t\t\tthrow new SchemaRegistryError(`Schema not found: ${modelName}`, {\n\t\t\t\tcode: \"SCHEMA_NOT_FOUND\",\n\t\t\t});\n\t\t}\n\n\t\tconst cached = this.cache.selectFields.get(modelName);\n\t\tif (cached) return cached as QuerySelect<T>;\n\n\t\tconst cleanFields: string[] = [];\n\t\tfor (const [fieldName, fieldDef] of Object.entries(schema.fields)) {\n\t\t\tif ((fieldDef as { hidden?: boolean }).hidden) continue;\n\t\t\tif (fieldDef.type === \"relation\") continue;\n\t\t\tcleanFields.push(fieldName);\n\t\t}\n\n\t\tthis.cache.selectFields.set(modelName, cleanFields);\n\t\treturn cleanFields as QuerySelect<T>;\n\t}\n\n\t/**\n\t * Validate all relations\n\t */\n\tvalidateRelations(): void {\n\t\tconst errors: SchemaValidationError[] = [];\n\n\t\tfor (const [, schema] of this.schemas.entries()) {\n\t\t\tfor (const [fieldName, field] of Object.entries(schema.fields)) {\n\t\t\t\tif (field.type === \"relation\") {\n\t\t\t\t\tconst relationField = field as RelationField;\n\t\t\t\t\tif (!this.has(relationField.model)) {\n\t\t\t\t\t\terrors.push({\n\t\t\t\t\t\t\tfield: fieldName,\n\t\t\t\t\t\t\tmessage: `Relation target not found: ${relationField.model}`,\n\t\t\t\t\t\t\tcode: \"INVALID_RELATION_TARGET\",\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (errors.length > 0) {\n\t\t\tthrow new SchemaRegistryError(\"Relation validation failed\", {\n\t\t\t\tcode: \"INVALID_RELATIONS\",\n\t\t\t\tdetails: errors,\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * Clear all schemas\n\t */\n\tclear(): void {\n\t\tif (this.locked) {\n\t\t\tthrow new SchemaRegistryError(\"Cannot clear locked registry\", {\n\t\t\t\tcode: \"REGISTRY_LOCKED\",\n\t\t\t});\n\t\t}\n\t\tthis.schemas.clear();\n\t\tthis.invalidateCache();\n\t}\n\n\t/**\n\t * Remove schema by name\n\t */\n\tremove(name: string): boolean {\n\t\tif (this.locked) {\n\t\t\tthrow new SchemaRegistryError(\"Cannot remove from locked registry\", {\n\t\t\t\tcode: \"REGISTRY_LOCKED\",\n\t\t\t});\n\t\t}\n\n\t\tconst removed = this.schemas.delete(name);\n\t\tif (removed) {\n\t\t\tthis.invalidateCache();\n\t\t}\n\t\treturn removed;\n\t}\n\n\t/**\n\t * Lock registry (prevent modifications)\n\t */\n\tlock(): void {\n\t\tthis.locked = true;\n\t}\n\n\t/**\n\t * Unlock registry\n\t */\n\tunlock(): void {\n\t\tthis.locked = false;\n\t}\n\n\t/**\n\t * Check if registry is locked\n\t */\n\tisLocked(): boolean {\n\t\treturn this.locked;\n\t}\n\n\t/**\n\t * Transform file fields into relation fields (Pass 0)\n\t * Called during register() before reserved fields are added.\n\t *\n\t * FileField { type: \"file\", multiple: false } → RelationField { kind: \"belongsTo\", model: \"media\", fileOptions: {...} }\n\t * FileField { type: \"file\", multiple: true } → RelationField { kind: \"hasMany\", model: \"media\", fileOptions: {...} }\n\t *\n\t * Upload config is NOT required here — that check is in ApiPlugin.\n\t * Core only transforms the type so adapters/migrations see a plain relation.\n\t */\n\tprivate transformFileFields(\n\t\tfields: Record<string, FieldDefinition>,\n\t): Record<string, FieldDefinition> {\n\t\tconst result: Record<string, FieldDefinition> = {};\n\n\t\tfor (const [fieldName, field] of Object.entries(fields)) {\n\t\t\tif (field.type !== \"file\") {\n\t\t\t\tresult[fieldName] = field;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst fileField = field as FileField;\n\n\t\t\tconst fileOptions: FileFieldOptions = {\n\t\t\t\t...(fileField.allowedTypes !== undefined && {\n\t\t\t\t\tallowedTypes: fileField.allowedTypes,\n\t\t\t\t}),\n\t\t\t\t...(fileField.maxSize !== undefined && {\n\t\t\t\t\tmaxSize: fileField.maxSize,\n\t\t\t\t}),\n\t\t\t};\n\n\t\t\tconst hasFileOptions = Object.keys(fileOptions).length > 0;\n\n\t\t\tconst relationField: RelationField = {\n\t\t\t\ttype: \"relation\",\n\t\t\t\tmodel: \"media\",\n\t\t\t\tkind: fileField.multiple ? \"hasMany\" : \"belongsTo\",\n\t\t\t\t...(fileField.required !== undefined && {\n\t\t\t\t\trequired: fileField.required,\n\t\t\t\t}),\n\t\t\t\t...(hasFileOptions && { fileOptions }),\n\t\t\t};\n\n\t\t\tresult[fieldName] = relationField;\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Process relations (Pass 2)\n\t * Add foreign keys for belongsTo/hasOne/hasMany\n\t * Create junction tables for manyToMany\n\t */\n\tprivate processRelations(): void {\n\t\tfor (const [schemaName, schema] of this.schemas.entries()) {\n\t\t\tconst enhancedFields = { ...schema.fields };\n\n\t\t\tfor (const [fieldName, field] of Object.entries(schema.fields)) {\n\t\t\t\tif (field.type !== \"relation\") continue;\n\n\t\t\t\tconst relation = field as RelationField;\n\t\t\t\tconst targetSchema = this.schemas.get(relation.model);\n\n\t\t\t\tif (!targetSchema) {\n\t\t\t\t\tthrow new SchemaRegistryError(\n\t\t\t\t\t\t`Relation target not found: ${relation.model} in schema ${schemaName}.${fieldName}`,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcode: \"INVALID_RELATION_TARGET\",\n\t\t\t\t\t\t\tschemaName,\n\t\t\t\t\t\t\tdetails: { field: fieldName, target: relation.model },\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tif (relation.kind === \"belongsTo\") {\n\t\t\t\t\tconst foreignKey = relation.foreignKey ?? `${fieldName}Id`;\n\n\t\t\t\t\tif (!(foreignKey in enhancedFields)) {\n\t\t\t\t\t\tconst targetTableName =\n\t\t\t\t\t\t\ttargetSchema.tableName ??\n\t\t\t\t\t\t\tthis.pluralize(relation.model.toLowerCase());\n\t\t\t\t\t\tconst isRequired = relation.required ?? false;\n\t\t\t\t\t\tconst defaultOnDelete = isRequired ? \"cascade\" : \"setNull\";\n\t\t\t\t\t\tenhancedFields[foreignKey] = {\n\t\t\t\t\t\t\ttype: \"number\",\n\t\t\t\t\t\t\trequired: isRequired,\n\t\t\t\t\t\t\thidden: true,\n\t\t\t\t\t\t\treferences: {\n\t\t\t\t\t\t\t\ttable: targetTableName,\n\t\t\t\t\t\t\t\tcolumn: \"id\",\n\t\t\t\t\t\t\t\tonDelete: relation.onDelete ?? defaultOnDelete,\n\t\t\t\t\t\t\t\tonUpdate: relation.onUpdate,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\n\t\t\t\t\tenhancedFields[fieldName] = {\n\t\t\t\t\t\t...relation,\n\t\t\t\t\t\tforeignKey,\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tif (relation.kind === \"hasOne\" || relation.kind === \"hasMany\") {\n\t\t\t\t\tconst foreignKey = relation.foreignKey ?? `${schemaName}Id`;\n\t\t\t\t\tconst targetFields = { ...targetSchema.fields };\n\n\t\t\t\t\tif (!(foreignKey in targetFields)) {\n\t\t\t\t\t\tconst sourceTableName =\n\t\t\t\t\t\t\tschema.tableName ?? this.pluralize(schemaName.toLowerCase());\n\t\t\t\t\t\ttargetFields[foreignKey] = {\n\t\t\t\t\t\t\ttype: \"number\",\n\t\t\t\t\t\t\trequired: false,\n\t\t\t\t\t\t\thidden: true,\n\t\t\t\t\t\t\treferences: {\n\t\t\t\t\t\t\t\ttable: sourceTableName,\n\t\t\t\t\t\t\t\tcolumn: \"id\",\n\t\t\t\t\t\t\t\tonDelete: relation.onDelete ?? \"setNull\",\n\t\t\t\t\t\t\t\tonUpdate: relation.onUpdate,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\n\t\t\t\t\tthis.schemas.set(relation.model, {\n\t\t\t\t\t\t...targetSchema,\n\t\t\t\t\t\tfields: targetFields,\n\t\t\t\t\t});\n\n\t\t\t\t\tenhancedFields[fieldName] = {\n\t\t\t\t\t\t...relation,\n\t\t\t\t\t\tforeignKey,\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tif (relation.kind === \"manyToMany\") {\n\t\t\t\t\tconst junctionTableName =\n\t\t\t\t\t\trelation.through ??\n\t\t\t\t\t\tthis.getJunctionTableName(schemaName, relation.model);\n\n\t\t\t\t\tthis.createJunctionTable(schemaName, relation, junctionTableName);\n\n\t\t\t\t\tenhancedFields[fieldName] = {\n\t\t\t\t\t\t...relation,\n\t\t\t\t\t\tthrough: junctionTableName,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.schemas.set(schemaName, {\n\t\t\t\t...schema,\n\t\t\t\tfields: enhancedFields,\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * Create junction table for manyToMany relation\n\t */\n\tprivate createJunctionTable(\n\t\tschemaName: string,\n\t\trelation: RelationField,\n\t\tjunctionTableName: string,\n\t): void {\n\t\tif (this.schemas.has(junctionTableName)) return;\n\n\t\tconst sourceFk = `${schemaName}Id`;\n\t\tconst targetFk = `${relation.model}Id`;\n\n\t\tconst junctionSchema: SchemaDefinition = {\n\t\t\tname: junctionTableName,\n\t\t\ttableName: junctionTableName,\n\t\t\tfields: {\n\t\t\t\tid: { type: \"number\", required: false, autoIncrement: true },\n\t\t\t\t[schemaName]: {\n\t\t\t\t\ttype: \"relation\",\n\t\t\t\t\tkind: \"belongsTo\",\n\t\t\t\t\tmodel: schemaName,\n\t\t\t\t\tforeignKey: sourceFk,\n\t\t\t\t\trequired: true,\n\t\t\t\t} as RelationField,\n\t\t\t\t[relation.model]: {\n\t\t\t\t\ttype: \"relation\",\n\t\t\t\t\tkind: \"belongsTo\",\n\t\t\t\t\tmodel: relation.model,\n\t\t\t\t\tforeignKey: targetFk,\n\t\t\t\t\trequired: true,\n\t\t\t\t} as RelationField,\n\t\t\t\t[sourceFk]: {\n\t\t\t\t\ttype: \"number\",\n\t\t\t\t\trequired: true,\n\t\t\t\t\thidden: true,\n\t\t\t\t\treferences: {\n\t\t\t\t\t\ttable: this.pluralize(schemaName.toLowerCase()),\n\t\t\t\t\t\tcolumn: \"id\",\n\t\t\t\t\t\tonDelete: \"cascade\" as const,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t[targetFk]: {\n\t\t\t\t\ttype: \"number\",\n\t\t\t\t\trequired: true,\n\t\t\t\t\thidden: true,\n\t\t\t\t\treferences: {\n\t\t\t\t\t\ttable: this.pluralize(relation.model.toLowerCase()),\n\t\t\t\t\t\tcolumn: \"id\",\n\t\t\t\t\t\tonDelete: \"cascade\" as const,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tindexes: [\n\t\t\t\t{\n\t\t\t\t\tfields: [sourceFk, targetFk],\n\t\t\t\t\tunique: true,\n\t\t\t\t},\n\t\t\t],\n\t\t\t_isJunctionTable: true,\n\t\t};\n\n\t\tthis.schemas.set(junctionTableName, junctionSchema);\n\t}\n\n\t/**\n\t * Get junction table name for manyToMany relation\n\t * Alphabetically sorted for consistency\n\t */\n\tprivate getJunctionTableName(schema1: string, schema2: string): string {\n\t\tconst sorted = [schema1, schema2].sort();\n\t\treturn `${sorted[0]}_${sorted[1]}`;\n\t}\n\n\t/**\n\t * Enhanced pluralization with common English rules\n\t */\n\tprivate pluralize(word: string): string {\n\t\tconst irregulars: Record<string, string> = {\n\t\t\tperson: \"people\",\n\t\t\tchild: \"children\",\n\t\t\tman: \"men\",\n\t\t\twoman: \"women\",\n\t\t\ttooth: \"teeth\",\n\t\t\tfoot: \"feet\",\n\t\t\tmouse: \"mice\",\n\t\t\tgoose: \"geese\",\n\t\t\tox: \"oxen\",\n\t\t\tdatum: \"data\",\n\t\t\tindex: \"indices\",\n\t\t\tvertex: \"vertices\",\n\t\t\tmatrix: \"matrices\",\n\t\t\tstatus: \"statuses\",\n\t\t\tquiz: \"quizzes\",\n\t\t};\n\n\t\tconst lower = word.toLowerCase();\n\t\tconst irregular = irregulars[lower];\n\t\tif (irregular) {\n\t\t\tconst firstChar = word.charAt(0);\n\t\t\treturn firstChar === firstChar.toUpperCase()\n\t\t\t\t? irregular.charAt(0).toUpperCase() + irregular.slice(1)\n\t\t\t\t: irregular;\n\t\t}\n\n\t\tif (\n\t\t\tword.endsWith(\"ss\") ||\n\t\t\tlower === \"data\" ||\n\t\t\tlower === \"information\" ||\n\t\t\tlower === \"equipment\"\n\t\t) {\n\t\t\treturn word;\n\t\t}\n\n\t\tif (word.endsWith(\"y\") && word.length > 1) {\n\t\t\tconst beforeY = word[word.length - 2];\n\t\t\tif (beforeY && !\"aeiou\".includes(beforeY.toLowerCase())) {\n\t\t\t\treturn word.slice(0, -1) + \"ies\";\n\t\t\t}\n\t\t}\n\n\t\tif (word.endsWith(\"f\")) {\n\t\t\treturn word.slice(0, -1) + \"ves\";\n\t\t}\n\t\tif (word.endsWith(\"fe\")) {\n\t\t\treturn word.slice(0, -2) + \"ves\";\n\t\t}\n\n\t\tif (word.endsWith(\"o\") && word.length > 1) {\n\t\t\tconst beforeO = word[word.length - 2];\n\t\t\tif (beforeO && !\"aeiou\".includes(beforeO.toLowerCase())) {\n\t\t\t\treturn word + \"es\";\n\t\t\t}\n\t\t}\n\n\t\tif (\n\t\t\tword.endsWith(\"ch\") ||\n\t\t\tword.endsWith(\"sh\") ||\n\t\t\tword.endsWith(\"s\") ||\n\t\t\tword.endsWith(\"ss\") ||\n\t\t\tword.endsWith(\"x\") ||\n\t\t\tword.endsWith(\"z\")\n\t\t) {\n\t\t\treturn word + \"es\";\n\t\t}\n\n\t\treturn word + \"s\";\n\t}\n\n\t/**\n\t * Export schemas as JSON\n\t */\n\ttoJSON(): Record<string, SchemaDefinition> {\n\t\tconst autoFields = new Set([\"id\", \"createdAt\", \"updatedAt\"]);\n\t\tconst result: Record<string, SchemaDefinition> = {};\n\n\t\tfor (const [name, schema] of this.schemas) {\n\t\t\tconst fields: Record<string, unknown> = {};\n\t\t\tfor (const [fieldName, fieldDef] of Object.entries(schema.fields)) {\n\t\t\t\tif (autoFields.has(fieldName)) continue;\n\t\t\t\tfields[fieldName] = fieldDef;\n\t\t\t}\n\t\t\tresult[name] = { ...schema, fields } as SchemaDefinition;\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Import schemas from JSON\n\t */\n\tfromJSON(data: Record<string, SchemaDefinition>): void {\n\t\tconst schemas = Object.values(data);\n\t\tthis.registerMany(schemas);\n\t}\n}\n\n/**\n * Global schema registry instance\n */\nlet globalRegistry: SchemaRegistry | undefined;\n\n/**\n * Get global registry instance\n */\nexport function getGlobalRegistry(): SchemaRegistry {\n\tif (!globalRegistry) {\n\t\tglobalRegistry = new SchemaRegistry();\n\t}\n\treturn globalRegistry;\n}\n\n/**\n * Set global registry instance\n */\nexport function setGlobalRegistry(registry: SchemaRegistry): void {\n\tglobalRegistry = registry;\n}\n\n/**\n * Reset global registry\n */\nexport function resetGlobalRegistry(): void {\n\tglobalRegistry = undefined;\n}\n","/**\n * Migration History Schema Definition\n *\n * Internal schema for tracking applied migrations.\n * This schema is automatically registered by Datrix during initialization.\n */\n\nimport { defineSchema } from \"../types/core/schema\";\nimport { DATRIX_META_MODEL } from \"../types/core/constants\";\nexport { DATRIX_META_MODEL };\n\n/**\n * Default model name for migration history\n */\nexport const DEFAULT_MIGRATION_MODEL = \"_datrix_migration\";\n\n/**\n * Get migration history schema definition\n *\n * @param modelName - Custom model name (default: '_datrix_migration')\n * @returns Schema definition for migration history table\n */\nexport function getMigrationSchema(\n\tmodelName: string = DEFAULT_MIGRATION_MODEL,\n) {\n\treturn defineSchema({\n\t\tname: modelName,\n\n\t\tfields: {\n\t\t\tname: {\n\t\t\t\ttype: \"string\",\n\t\t\t\trequired: true,\n\t\t\t\tmaxLength: 255,\n\t\t\t\tdescription: \"Migration name\",\n\t\t\t},\n\t\t\tversion: {\n\t\t\t\ttype: \"string\",\n\t\t\t\trequired: true,\n\t\t\t\tunique: true,\n\t\t\t\tmaxLength: 255,\n\t\t\t\tdescription: \"Migration version (timestamp-based)\",\n\t\t\t},\n\t\t\texecutionTime: {\n\t\t\t\ttype: \"number\",\n\t\t\t\trequired: true,\n\t\t\t\tmin: 0,\n\t\t\t\tdescription: \"Execution time in milliseconds\",\n\t\t\t},\n\t\t\tstatus: {\n\t\t\t\ttype: \"enum\",\n\t\t\t\trequired: true,\n\t\t\t\tvalues: [\"pending\", \"completed\", \"failed\", \"rolled_back\"] as const,\n\t\t\t\tdescription: \"Migration execution status\",\n\t\t\t},\n\t\t\tchecksum: {\n\t\t\t\ttype: \"string\",\n\t\t\t\tmaxLength: 64,\n\t\t\t\tdescription: \"SHA-256 checksum of migration content\",\n\t\t\t},\n\t\t\terror: {\n\t\t\t\ttype: \"string\",\n\t\t\t\tdescription: \"Error message if migration failed\",\n\t\t\t},\n\t\t\tappliedAt: {\n\t\t\t\ttype: \"date\",\n\t\t\t\trequired: true,\n\t\t\t\tdescription: \"When the migration was applied\",\n\t\t\t},\n\t\t},\n\n\t\tindexes: [\n\t\t\t{ fields: [\"version\"], unique: true },\n\t\t\t{ fields: [\"status\"] },\n\t\t\t{ fields: [\"appliedAt\"] },\n\t\t],\n\n\t\tpermission: {\n\t\t\tcreate: false,\n\t\t\tread: false,\n\t\t\tupdate: false,\n\t\t\tdelete: false,\n\t\t},\n\t} as const);\n}\n\n/**\n * Migration history schema type\n */\nexport type MigrationHistorySchema = ReturnType<typeof getMigrationSchema>;\n\n/**\n * Get internal Datrix metadata schema definition\n *\n * Stores per-table schema snapshots as JSON for migration diffing.\n * key: table name, value: full Datrix SchemaDefinition as JSON string\n */\nexport function getDatrixMetaSchema() {\n\treturn defineSchema({\n\t\tname: DATRIX_META_MODEL,\n\t\ttableName: DATRIX_META_MODEL,\n\n\t\tfields: {\n\t\t\tkey: {\n\t\t\t\ttype: \"string\",\n\t\t\t\trequired: true,\n\t\t\t\tunique: true,\n\t\t\t\tmaxLength: 255,\n\t\t\t\tdescription: \"Table name\",\n\t\t\t},\n\t\t\tvalue: {\n\t\t\t\ttype: \"string\",\n\t\t\t\trequired: true,\n\t\t\t\tdescription: \"Datrix SchemaDefinition as JSON string\",\n\t\t\t},\n\t\t},\n\n\t\tpermission: {\n\t\t\tcreate: false,\n\t\t\tread: false,\n\t\t\tupdate: false,\n\t\t\tdelete: false,\n\t\t},\n\t} as const);\n}\n\n/**\n * Datrix metadata schema type\n */\nexport type DatrixMetaSchema = ReturnType<typeof getDatrixMetaSchema>;\n","/**\n * Migration System Type Definitions (~200 LOC)\n *\n * Types for database schema migrations, diffing, and history tracking.\n */\n\nimport { AlterOperation, QueryRunner } from \"../adapter\";\n\nimport { FieldDefinition, IndexDefinition, SchemaDefinition } from \"./schema\";\n\n/**\n * Migration status\n */\nexport type MigrationStatus = \"pending\" | \"running\" | \"completed\" | \"failed\";\n\n/**\n * Migration metadata\n */\nexport interface MigrationMetadata {\n\treadonly name: string;\n\treadonly version: string;\n\treadonly timestamp: number;\n\treadonly description?: string;\n\treadonly author?: string;\n}\n\n/**\n * Migration context for execution\n */\nexport interface MigrationContext {\n\treadonly version: string;\n\treadonly dryRun?: boolean;\n}\n\n/**\n * Migration operation types\n */\nexport type MigrationOperationType =\n\t| \"createTable\"\n\t| \"dropTable\"\n\t| \"alterTable\"\n\t| \"createIndex\"\n\t| \"dropIndex\"\n\t| \"renameTable\"\n\t| \"raw\"\n\t| \"dataTransfer\";\n\n/**\n * Base migration operation\n */\nexport interface BaseMigrationOperation {\n\treadonly type: MigrationOperationType;\n}\n\n/**\n * Create table operation\n */\nexport interface CreateTableOperation extends BaseMigrationOperation {\n\treadonly type: \"createTable\";\n\treadonly schema: SchemaDefinition;\n}\n\n/**\n * Drop table operation\n */\nexport interface DropTableOperation extends BaseMigrationOperation {\n\treadonly type: \"dropTable\";\n\treadonly tableName: string;\n}\n\n/**\n * Alter table operation\n */\nexport interface AlterTableOperation extends BaseMigrationOperation {\n\treadonly type: \"alterTable\";\n\treadonly tableName: string;\n\treadonly operations: readonly AlterOperation[];\n}\n\n/**\n * Create index operation\n */\nexport interface CreateIndexOperation extends BaseMigrationOperation {\n\treadonly type: \"createIndex\";\n\treadonly tableName: string;\n\treadonly index: IndexDefinition;\n}\n\n/**\n * Drop index operation\n */\nexport interface DropIndexOperation extends BaseMigrationOperation {\n\treadonly type: \"dropIndex\";\n\treadonly tableName: string;\n\treadonly indexName: string;\n}\n\n/**\n * Rename table operation\n */\nexport interface RenameTableOperation extends BaseMigrationOperation {\n\treadonly type: \"renameTable\";\n\treadonly from: string;\n\treadonly to: string;\n}\n\n/**\n * Raw SQL operation (for custom migrations)\n */\nexport interface RawSQLOperation extends BaseMigrationOperation {\n\treadonly type: \"raw\";\n\treadonly sql: string;\n\treadonly params?: readonly unknown[];\n}\n\n/**\n * Data transfer operation — runs a callback with the transaction runner.\n * Used for migrating data between tables (e.g. FK → junction, junction → FK).\n */\nexport interface DataTransferOperation extends BaseMigrationOperation {\n\treadonly type: \"dataTransfer\";\n\treadonly description: string;\n\treadonly execute: (runner: QueryRunner) => Promise<void>;\n}\n\n/**\n * Union of all migration operations\n */\nexport type MigrationOperation =\n\t| CreateTableOperation\n\t| DropTableOperation\n\t| AlterTableOperation\n\t| CreateIndexOperation\n\t| DropIndexOperation\n\t| RenameTableOperation\n\t| RawSQLOperation\n\t| DataTransferOperation;\n\n/**\n * Migration definition\n */\nexport interface Migration {\n\treadonly metadata: MigrationMetadata;\n\treadonly operations: readonly MigrationOperation[];\n}\n\n/**\n * Schema difference types\n */\nexport type SchemaDiffType =\n\t| \"tableAdded\"\n\t| \"tableRemoved\"\n\t| \"tableRenamed\"\n\t| \"fieldAdded\"\n\t| \"fieldRemoved\"\n\t| \"fieldModified\"\n\t| \"fieldRenamed\"\n\t| \"indexAdded\"\n\t| \"indexRemoved\";\n\n/**\n * Base schema difference\n */\nexport interface BaseSchemaDiff {\n\treadonly type: SchemaDiffType;\n}\n\n/**\n * Table added difference\n */\nexport interface TableAddedDiff extends BaseSchemaDiff {\n\treadonly type: \"tableAdded\";\n\treadonly schema: SchemaDefinition;\n}\n\n/**\n * Table removed difference\n */\nexport interface TableRemovedDiff extends BaseSchemaDiff {\n\treadonly type: \"tableRemoved\";\n\treadonly tableName: string;\n}\n\n/**\n * Table renamed difference\n */\nexport interface TableRenamedDiff extends BaseSchemaDiff {\n\treadonly type: \"tableRenamed\";\n\treadonly from: string;\n\treadonly to: string;\n}\n\n/**\n * Field added difference\n */\nexport interface FieldAddedDiff extends BaseSchemaDiff {\n\treadonly type: \"fieldAdded\";\n\treadonly tableName: string;\n\treadonly fieldName: string;\n\treadonly definition: FieldDefinition;\n}\n\n/**\n * Field removed difference\n */\nexport interface FieldRemovedDiff extends BaseSchemaDiff {\n\treadonly type: \"fieldRemoved\";\n\treadonly tableName: string;\n\treadonly fieldName: string;\n\treadonly definition: FieldDefinition;\n}\n\n/**\n * Field modified difference\n */\nexport interface FieldModifiedDiff extends BaseSchemaDiff {\n\treadonly type: \"fieldModified\";\n\treadonly tableName: string;\n\treadonly fieldName: string;\n\treadonly oldDefinition: FieldDefinition;\n\treadonly newDefinition: FieldDefinition;\n}\n\n/**\n * Field renamed difference\n */\nexport interface FieldRenamedDiff extends BaseSchemaDiff {\n\treadonly type: \"fieldRenamed\";\n\treadonly tableName: string;\n\treadonly from: string;\n\treadonly to: string;\n}\n\n/**\n * Index added difference\n */\nexport interface IndexAddedDiff extends BaseSchemaDiff {\n\treadonly type: \"indexAdded\";\n\treadonly tableName: string;\n\treadonly index: IndexDefinition;\n}\n\n/**\n * Index removed difference\n */\nexport interface IndexRemovedDiff extends BaseSchemaDiff {\n\treadonly type: \"indexRemoved\";\n\treadonly tableName: string;\n\treadonly indexName: string;\n}\n\n/**\n * Union of all schema differences\n */\nexport type SchemaDiff =\n\t| TableAddedDiff\n\t| TableRemovedDiff\n\t| TableRenamedDiff\n\t| FieldAddedDiff\n\t| FieldRemovedDiff\n\t| FieldModifiedDiff\n\t| FieldRenamedDiff\n\t| IndexAddedDiff\n\t| IndexRemovedDiff;\n\n/**\n * Schema comparison result\n */\nexport interface SchemaComparison {\n\treadonly differences: readonly SchemaDiff[];\n\treadonly hasChanges: boolean;\n}\n\n/**\n * Migration history record (stored in database)\n */\nexport interface MigrationHistoryRecord {\n\treadonly id: number;\n\treadonly name: string;\n\treadonly version: string;\n\treadonly appliedAt: Date;\n\treadonly executionTime: number; // milliseconds\n\treadonly status: MigrationStatus;\n\treadonly checksum?: string;\n\treadonly error?: string;\n}\n\n/**\n * Migration execution result\n */\nexport interface MigrationExecutionResult {\n\treadonly migration: Migration;\n\treadonly status: MigrationStatus;\n\treadonly executionTime: number;\n\treadonly error?: Error;\n\treadonly warnings?: readonly string[];\n}\n\n/**\n * Migration plan (list of migrations to execute)\n */\nexport interface MigrationFilePlan {\n\treadonly migrations: readonly Migration[];\n\treadonly target?: string; // Target version (undefined = latest)\n}\n\n/**\n * Migration error\n */\nexport class MigrationSystemError extends Error {\n\tconstructor(\n\t\tmessage: string,\n\t\tpublic readonly code:\n\t\t\t| \"MIGRATION_ERROR\"\n\t\t\t| \"DIFF_ERROR\"\n\t\t\t| \"GENERATION_ERROR\"\n\t\t\t| \"VALIDATION_ERROR\",\n\t\tpublic readonly details?: unknown,\n\t) {\n\t\tsuper(message);\n\t\tthis.name = \"MigrationSystemError\";\n\t}\n}\n\n/**\n * Schema differ interface\n */\nexport interface SchemaDiffer {\n\t/**\n\t * Compare two schemas and return differences\n\t */\n\tcompare(\n\t\toldSchema: Record<string, SchemaDefinition>,\n\t\tnewSchema: Record<string, SchemaDefinition>,\n\t): SchemaComparison;\n\n\t/**\n\t * Detect field type changes\n\t */\n\tisFieldModified(\n\t\toldField: FieldDefinition,\n\t\tnewField: FieldDefinition,\n\t): boolean;\n}\n\n/**\n * Migration generator interface\n */\nexport interface MigrationGenerator {\n\t/**\n\t * Generate migration from schema differences\n\t */\n\tgenerate(\n\t\tdifferences: readonly SchemaDiff[],\n\t\tmetadata: Omit<MigrationMetadata, \"timestamp\">,\n\t): Migration;\n\n\t/**\n\t * Generate migration operations from differences\n\t */\n\tgenerateOperations(\n\t\tdifferences: readonly SchemaDiff[],\n\t): readonly MigrationOperation[];\n\n\t/**\n\t * Generate TypeScript migration file content\n\t */\n\tgenerateFile(migration: Migration): string;\n}\n\n/**\n * Migration runner interface\n */\nexport interface MigrationRunner {\n\t/**\n\t * Get pending migrations\n\t */\n\tgetPending(): Promise<readonly Migration[]>;\n\n\t/**\n\t * Get applied migrations\n\t */\n\tgetApplied(): Promise<readonly MigrationHistoryRecord[]>;\n\n\t/**\n\t * Run pending migrations\n\t */\n\trunPending(options?: {\n\t\treadonly target?: string;\n\t\treadonly dryRun?: boolean;\n\t}): Promise<readonly MigrationExecutionResult[]>;\n\n\t/**\n\t * Run specific migration\n\t */\n\trunOne(migration: Migration): Promise<MigrationExecutionResult>;\n\n\t/**\n\t * Get migration plan\n\t */\n\tgetPlan(options?: { readonly target?: string }): MigrationFilePlan;\n}\n\n/**\n * Migration history manager interface\n */\nexport interface MigrationHistory {\n\t/**\n\t * Initialize migrations table\n\t */\n\tinitialize(): Promise<void>;\n\n\t/**\n\t * Record migration execution\n\t */\n\trecord(\n\t\tmigration: Migration,\n\t\texecutionTime: number,\n\t\tstatus: MigrationStatus,\n\t\terror?: Error,\n\t): Promise<void>;\n\n\t/**\n\t * Get all migration records\n\t */\n\tgetAll(): Promise<readonly MigrationHistoryRecord[]>;\n\n\t/**\n\t * Get last applied migration\n\t */\n\tgetLast(): Promise<MigrationHistoryRecord | undefined>;\n\n\t/**\n\t * Check if migration was applied\n\t */\n\tisApplied(version: string): Promise<boolean>;\n\n\t/**\n\t * Calculate migration checksum\n\t */\n\tcalculateChecksum(migration: Migration): string;\n\n\t/**\n\t * Verify migration integrity\n\t */\n\tverifyChecksum(migration: Migration, record: MigrationHistoryRecord): boolean;\n}\n","/**\n * Schema Differ Implementation (~300 LOC)\n *\n * Compares two schema versions and detects differences.\n * Produces structured diff objects for migration generation.\n */\n\nimport {\n\tMigrationSystemError,\n\tSchemaComparison,\n\tSchemaDiff,\n\tSchemaDiffer,\n} from \"../types/core/migration\";\nimport { FieldDefinition, SchemaDefinition } from \"../types/core/schema\";\n\n/**\n * Type guard for SchemaDefinition\n */\nfunction isSchemaDefinition(value: unknown): value is SchemaDefinition {\n\treturn (\n\t\ttypeof value === \"object\" &&\n\t\tvalue !== null &&\n\t\t\"name\" in value &&\n\t\ttypeof (value as Record<string, unknown>)[\"name\"] === \"string\" &&\n\t\t\"fields\" in value &&\n\t\ttypeof (value as Record<string, unknown>)[\"fields\"] === \"object\"\n\t);\n}\n\n/**\n * Type guard for FieldDefinition\n */\nfunction isFieldDefinition(value: unknown): value is FieldDefinition {\n\treturn (\n\t\ttypeof value === \"object\" &&\n\t\tvalue !== null &&\n\t\t\"type\" in value &&\n\t\ttypeof (value as Record<string, unknown>)[\"type\"] === \"string\"\n\t);\n}\n\n/**\n * Type guard for valid index types\n */\nfunction isValidIndexType(\n\ttype: string,\n): type is \"btree\" | \"hash\" | \"gist\" | \"gin\" {\n\treturn [\"btree\", \"hash\", \"gist\", \"gin\"].includes(type);\n}\n\n/**\n * Schema differ implementation\n */\nexport class ForgeSchemaDiffer implements SchemaDiffer {\n\t/**\n\t * Compare two schema collections\n\t */\n\tcompare(\n\t\toldSchemas: Record<string, SchemaDefinition>,\n\t\tnewSchemas: Record<string, SchemaDefinition>,\n\t): SchemaComparison {\n\t\ttry {\n\t\t\tif (\n\t\t\t\ttypeof oldSchemas !== \"object\" ||\n\t\t\t\toldSchemas === null ||\n\t\t\t\tArray.isArray(oldSchemas)\n\t\t\t) {\n\t\t\t\tthrow new MigrationSystemError(\n\t\t\t\t\t\"oldSchemas must be a plain object\",\n\t\t\t\t\t\"DIFF_ERROR\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (\n\t\t\t\ttypeof newSchemas !== \"object\" ||\n\t\t\t\tnewSchemas === null ||\n\t\t\t\tArray.isArray(newSchemas)\n\t\t\t) {\n\t\t\t\tthrow new MigrationSystemError(\n\t\t\t\t\t\"newSchemas must be a plain object\",\n\t\t\t\t\t\"DIFF_ERROR\",\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst differences: SchemaDiff[] = [];\n\n\t\t\tconst oldTableNames = new Set(Object.keys(oldSchemas));\n\t\t\tconst newTableNames = new Set(Object.keys(newSchemas));\n\n\t\t\t// Find added tables\n\t\t\tfor (const tableName of newTableNames) {\n\t\t\t\tif (!oldTableNames.has(tableName)) {\n\t\t\t\t\tconst schema = newSchemas[tableName];\n\t\t\t\t\tif (!isSchemaDefinition(schema)) {\n\t\t\t\t\t\tthrow new MigrationSystemError(\n\t\t\t\t\t\t\t`Invalid schema definition for table '${tableName}'`,\n\t\t\t\t\t\t\t\"DIFF_ERROR\",\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tdifferences.push({\n\t\t\t\t\t\ttype: \"tableAdded\",\n\t\t\t\t\t\tschema,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Find removed tables\n\t\t\tfor (const tableName of oldTableNames) {\n\t\t\t\tif (!newTableNames.has(tableName)) {\n\t\t\t\t\tdifferences.push({\n\t\t\t\t\t\ttype: \"tableRemoved\",\n\t\t\t\t\t\ttableName,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Find modified tables\n\t\t\tfor (const tableName of newTableNames) {\n\t\t\t\tif (oldTableNames.has(tableName)) {\n\t\t\t\t\tconst oldSchema = oldSchemas[tableName];\n\t\t\t\t\tconst newSchema = newSchemas[tableName];\n\n\t\t\t\t\tif (\n\t\t\t\t\t\t!isSchemaDefinition(oldSchema) ||\n\t\t\t\t\t\t!isSchemaDefinition(newSchema)\n\t\t\t\t\t) {\n\t\t\t\t\t\tthrow new MigrationSystemError(\n\t\t\t\t\t\t\t`Invalid schema definition for table '${tableName}'`,\n\t\t\t\t\t\t\t\"DIFF_ERROR\",\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tconst tableDiffs = this.compareTable(oldSchema, newSchema);\n\t\t\t\t\tdifferences.push(...tableDiffs);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst resolvedDifferences = this.resolveCrossSchemaNoOps(\n\t\t\t\tdifferences,\n\t\t\t\toldSchemas,\n\t\t\t\tnewSchemas,\n\t\t\t);\n\n\t\t\treturn {\n\t\t\t\tdifferences: resolvedDifferences,\n\t\t\t\thasChanges: resolvedDifferences.length > 0,\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthrow new MigrationSystemError(\n\t\t\t\t`Failed to compare schemas: ${message}`,\n\t\t\t\t\"DIFF_ERROR\",\n\t\t\t\terror,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Resolve cross-schema no-ops after all per-table diffs are produced.\n\t *\n\t * Cases eliminated:\n\t * 1. hasOne/hasMany removed from table A + belongsTo added to table B\n\t * → same FK column on B, no DB change\n\t * 2. belongsTo removed from table B + hasOne/hasMany added to table A\n\t * → same FK column on B, no DB change\n\t * 3. manyToMany added to table B while table A already declares it\n\t * → junction table already exists, no DB change\n\t * 4. manyToMany removed from one side while other side still declares it\n\t * → junction table still needed, suppress tableRemoved\n\t */\n\tprivate resolveCrossSchemaNoOps(\n\t\tdifferences: SchemaDiff[],\n\t\toldSchemas: Record<string, SchemaDefinition>,\n\t\tnewSchemas: Record<string, SchemaDefinition>,\n\t): SchemaDiff[] {\n\t\tconst toRemove = new Set<number>();\n\n\t\t// Index diffs for fast lookup\n\t\tconst fieldAdded: Array<{\n\t\t\tindex: number;\n\t\t\tdiff: SchemaDiff & { type: \"fieldAdded\" };\n\t\t}> = [];\n\t\tconst fieldRemoved: Array<{\n\t\t\tindex: number;\n\t\t\tdiff: SchemaDiff & { type: \"fieldRemoved\" };\n\t\t}> = [];\n\t\tconst tableRemoved: Array<{\n\t\t\tindex: number;\n\t\t\tdiff: SchemaDiff & { type: \"tableRemoved\" };\n\t\t}> = [];\n\n\t\tfor (let i = 0; i < differences.length; i++) {\n\t\t\tconst diff = differences[i];\n\t\t\tif (diff === undefined) continue;\n\t\t\tif (diff.type === \"fieldAdded\") {\n\t\t\t\tfieldAdded.push({\n\t\t\t\t\tindex: i,\n\t\t\t\t\tdiff: diff as SchemaDiff & { type: \"fieldAdded\" },\n\t\t\t\t});\n\t\t\t} else if (diff.type === \"fieldRemoved\") {\n\t\t\t\tfieldRemoved.push({\n\t\t\t\t\tindex: i,\n\t\t\t\t\tdiff: diff as SchemaDiff & { type: \"fieldRemoved\" },\n\t\t\t\t});\n\t\t\t} else if (diff.type === \"tableRemoved\") {\n\t\t\t\ttableRemoved.push({\n\t\t\t\t\tindex: i,\n\t\t\t\t\tdiff: diff as SchemaDiff & { type: \"tableRemoved\" },\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\t// Build lookup maps by table name for both old and new schemas\n\t\tconst newSchemaByTable = new Map<string, SchemaDefinition>();\n\t\tfor (const schema of Object.values(newSchemas)) {\n\t\t\tnewSchemaByTable.set(schema.tableName ?? schema.name, schema);\n\t\t}\n\n\t\tconst oldSchemaByTable = new Map<string, SchemaDefinition>();\n\t\tfor (const schema of Object.values(oldSchemas)) {\n\t\t\toldSchemaByTable.set(schema.tableName ?? schema.name, schema);\n\t\t}\n\n\t\t// Case 1 & 2: hasOne/hasMany ↔ belongsTo cross-table flip\n\t\t// The FK column lives on the target table in both cases.\n\t\t// We match a removed relation on one side with an added relation on\n\t\t// the other side that resolves to the same physical FK column.\n\t\t// Removed fields must be looked up in oldSchemas since they no longer\n\t\t// exist in newSchemas.\n\t\tfor (const removed of fieldRemoved) {\n\t\t\tconst removedField = this.getFieldFromSchemas(\n\t\t\t\tremoved.diff.tableName,\n\t\t\t\tremoved.diff.fieldName,\n\t\t\t\toldSchemaByTable,\n\t\t\t\toldSchemas,\n\t\t\t);\n\n\t\t\tif (!removedField || removedField.type !== \"relation\") continue;\n\t\t\tif (removedField.kind === \"manyToMany\") continue;\n\n\t\t\tfor (const added of fieldAdded) {\n\t\t\t\tif (toRemove.has(added.index)) continue;\n\n\t\t\t\tconst addedDef = added.diff.definition;\n\t\t\t\tif (addedDef.type !== \"relation\") continue;\n\t\t\t\tif (addedDef.kind === \"manyToMany\") continue;\n\n\t\t\t\tconst match = this.isCrossSchemaFkNoOp(\n\t\t\t\t\tremoved.diff.tableName,\n\t\t\t\t\tremovedField,\n\t\t\t\t\tadded.diff.tableName,\n\t\t\t\t\taddedDef,\n\t\t\t\t\tnewSchemaByTable,\n\t\t\t\t\tnewSchemas,\n\t\t\t\t\toldSchemaByTable,\n\t\t\t\t\toldSchemas,\n\t\t\t\t);\n\n\t\t\t\tif (match) {\n\t\t\t\t\ttoRemove.add(removed.index);\n\t\t\t\t\ttoRemove.add(added.index);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Case 3: manyToMany added on second side — junction table already exists\n\t\t// If the junction table is not being created in this migration it means\n\t\t// it already exists in the DB → this fieldAdded is a no-op.\n\t\tfor (const added of fieldAdded) {\n\t\t\tif (toRemove.has(added.index)) continue;\n\n\t\t\tconst addedDef = added.diff.definition;\n\t\t\tif (addedDef.type !== \"relation\" || addedDef.kind !== \"manyToMany\")\n\t\t\t\tcontinue;\n\n\t\t\tconst ownerSchema =\n\t\t\t\tnewSchemaByTable.get(added.diff.tableName) ??\n\t\t\t\tnewSchemas[added.diff.tableName];\n\t\t\tconst ownerModelName = ownerSchema?.name ?? added.diff.tableName;\n\n\t\t\tconst junctionName = this.resolveJunctionTableName(\n\t\t\t\townerModelName,\n\t\t\t\taddedDef.model,\n\t\t\t\taddedDef.through,\n\t\t\t\tnewSchemaByTable,\n\t\t\t\tnewSchemas,\n\t\t\t);\n\n\t\t\tif (junctionName === undefined) continue;\n\n\t\t\tconst junctionBeingCreated = differences.some(\n\t\t\t\t(d) =>\n\t\t\t\t\td.type === \"tableAdded\" &&\n\t\t\t\t\t(d.schema.tableName ?? d.schema.name) === junctionName,\n\t\t\t);\n\n\t\t\tif (!junctionBeingCreated) {\n\t\t\t\ttoRemove.add(added.index);\n\t\t\t}\n\t\t}\n\n\t\t// Case 3b: hasOne/hasMany added — FK column already exists in DB\n\t\t// This happens when belongsTo already existed on the other side.\n\t\t// The FK column is already present so the fieldAdded is a no-op.\n\t\tfor (const added of fieldAdded) {\n\t\t\tif (toRemove.has(added.index)) continue;\n\n\t\t\tconst addedDef = added.diff.definition;\n\t\t\tif (addedDef.type !== \"relation\") continue;\n\t\t\tif (addedDef.kind !== \"hasOne\" && addedDef.kind !== \"hasMany\") continue;\n\n\t\t\tconst ownerSchema =\n\t\t\t\tnewSchemaByTable.get(added.diff.tableName) ??\n\t\t\t\tnewSchemas[added.diff.tableName];\n\t\t\tconst ownerModelName = ownerSchema?.name ?? added.diff.tableName;\n\n\t\t\tconst fkTable = this.resolveModelTableName(\n\t\t\t\taddedDef.model,\n\t\t\t\tnewSchemaByTable,\n\t\t\t\tnewSchemas,\n\t\t\t);\n\t\t\tconst fkColumn = addedDef.foreignKey ?? `${ownerModelName}Id`;\n\n\t\t\tif (fkTable === undefined) continue;\n\n\t\t\t// Check if this FK column already exists in old schemas (already in DB)\n\t\t\tconst fkTableOldSchema =\n\t\t\t\toldSchemaByTable.get(fkTable) ?? oldSchemas[fkTable];\n\t\t\tif (fkTableOldSchema && fkColumn in fkTableOldSchema.fields) {\n\t\t\t\ttoRemove.add(added.index);\n\t\t\t}\n\t\t}\n\n\t\t// Case 4: manyToMany removed from one side — other side still declares it\n\t\t// Suppress tableRemoved for the junction table if it is still referenced.\n\t\tfor (const removed of tableRemoved) {\n\t\t\tif (toRemove.has(removed.index)) continue;\n\n\t\t\tconst junctionName = removed.diff.tableName;\n\n\t\t\tconst stillReferenced = this.isJunctionTableStillReferenced(\n\t\t\t\tjunctionName,\n\t\t\t\tnewSchemas,\n\t\t\t\tnewSchemaByTable,\n\t\t\t);\n\n\t\t\tif (stillReferenced) {\n\t\t\t\ttoRemove.add(removed.index);\n\t\t\t}\n\t\t}\n\n\t\t// Case 4b: manyToMany fieldRemoved on one side — other side still declares it\n\t\t// The junction table still exists so this fieldRemoved is a no-op.\n\t\tfor (const removed of fieldRemoved) {\n\t\t\tif (toRemove.has(removed.index)) continue;\n\n\t\t\tconst removedField = this.getFieldFromSchemas(\n\t\t\t\tremoved.diff.tableName,\n\t\t\t\tremoved.diff.fieldName,\n\t\t\t\toldSchemaByTable,\n\t\t\t\toldSchemas,\n\t\t\t);\n\n\t\t\tif (\n\t\t\t\t!removedField ||\n\t\t\t\tremovedField.type !== \"relation\" ||\n\t\t\t\tremovedField.kind !== \"manyToMany\"\n\t\t\t)\n\t\t\t\tcontinue;\n\n\t\t\tconst ownerSchema =\n\t\t\t\toldSchemaByTable.get(removed.diff.tableName) ??\n\t\t\t\toldSchemas[removed.diff.tableName];\n\t\t\tconst ownerModelName = ownerSchema?.name ?? removed.diff.tableName;\n\n\t\t\tconst junctionName = this.resolveJunctionTableName(\n\t\t\t\townerModelName,\n\t\t\t\tremovedField.model,\n\t\t\t\tremovedField.through,\n\t\t\t\tnewSchemaByTable,\n\t\t\t\tnewSchemas,\n\t\t\t);\n\n\t\t\tif (junctionName === undefined) continue;\n\n\t\t\tconst stillReferenced = this.isJunctionTableStillReferenced(\n\t\t\t\tjunctionName,\n\t\t\t\tnewSchemas,\n\t\t\t\tnewSchemaByTable,\n\t\t\t);\n\n\t\t\tif (stillReferenced) {\n\t\t\t\ttoRemove.add(removed.index);\n\t\t\t}\n\t\t}\n\n\t\treturn differences.filter((_, i) => !toRemove.has(i));\n\t}\n\n\t/**\n\t * Get a field definition from schemas, trying by table name then schema name.\n\t */\n\tprivate getFieldFromSchemas(\n\t\ttableName: string,\n\t\tfieldName: string,\n\t\tschemaByTable: Map<string, SchemaDefinition>,\n\t\tschemas: Record<string, SchemaDefinition>,\n\t): FieldDefinition | undefined {\n\t\tconst byTable = schemaByTable.get(tableName);\n\t\tif (byTable) {\n\t\t\tconst field = byTable.fields[fieldName];\n\t\t\tif (isFieldDefinition(field)) return field;\n\t\t}\n\t\tconst byName = schemas[tableName];\n\t\tif (byName) {\n\t\t\tconst field = byName.fields[fieldName];\n\t\t\tif (isFieldDefinition(field)) return field;\n\t\t}\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Determine if a removed relation on tableA and an added relation on tableB\n\t * resolve to the same physical FK column — making both diffs a no-op.\n\t *\n\t * Removed fields are resolved against oldSchemas (they no longer exist in new).\n\t * Added fields are resolved against newSchemas.\n\t */\n\tprivate isCrossSchemaFkNoOp(\n\t\tremovedTableName: string,\n\t\tremovedField: FieldDefinition & { type: \"relation\" },\n\t\taddedTableName: string,\n\t\taddedField: FieldDefinition & { type: \"relation\" },\n\t\tnewSchemaByTable: Map<string, SchemaDefinition>,\n\t\tnewSchemas: Record<string, SchemaDefinition>,\n\t\toldSchemaByTable: Map<string, SchemaDefinition>,\n\t\toldSchemas: Record<string, SchemaDefinition>,\n\t): boolean {\n\t\t// Resolve FK location for the removed side using old schema context\n\t\tconst removedFkTable = this.resolveFkTable(\n\t\t\tremovedTableName,\n\t\t\tremovedField,\n\t\t\toldSchemaByTable,\n\t\t\toldSchemas,\n\t\t);\n\t\tconst removedFkColumn = this.resolveFkColumn(\n\t\t\tremovedTableName,\n\t\t\tremovedField,\n\t\t\toldSchemaByTable,\n\t\t\toldSchemas,\n\t\t);\n\n\t\t// Resolve FK location for the added side using new schema context\n\t\tconst addedFkTable = this.resolveFkTable(\n\t\t\taddedTableName,\n\t\t\taddedField,\n\t\t\tnewSchemaByTable,\n\t\t\tnewSchemas,\n\t\t);\n\t\tconst addedFkColumn = this.resolveFkColumn(\n\t\t\taddedTableName,\n\t\t\taddedField,\n\t\t\tnewSchemaByTable,\n\t\t\tnewSchemas,\n\t\t);\n\n\t\tif (removedFkTable === undefined || addedFkTable === undefined)\n\t\t\treturn false;\n\t\tif (removedFkColumn === undefined || addedFkColumn === undefined)\n\t\t\treturn false;\n\n\t\treturn removedFkTable === addedFkTable && removedFkColumn === addedFkColumn;\n\t}\n\n\t/**\n\t * Resolve which table the FK column physically lives on.\n\t * - belongsTo: FK is on the owner table (tableName itself)\n\t * - hasOne/hasMany: FK is on the target (model) table\n\t */\n\tprivate resolveFkTable(\n\t\ttableName: string,\n\t\tfield: FieldDefinition & { type: \"relation\" },\n\t\tschemaByTable: Map<string, SchemaDefinition>,\n\t\tschemas: Record<string, SchemaDefinition>,\n\t): string | undefined {\n\t\tif (field.kind === \"belongsTo\") {\n\t\t\treturn tableName;\n\t\t}\n\t\treturn this.resolveModelTableName(field.model, schemaByTable, schemas);\n\t}\n\n\t/**\n\t * Resolve the FK column name for a relation field.\n\t * - belongsTo: foreignKey ?? model + \"Id\"\n\t * - hasOne/hasMany: foreignKey ?? ownerModelName + \"Id\"\n\t */\n\tprivate resolveFkColumn(\n\t\ttableName: string,\n\t\tfield: FieldDefinition & { type: \"relation\" },\n\t\tschemaByTable: Map<string, SchemaDefinition>,\n\t\tschemas: Record<string, SchemaDefinition>,\n\t): string | undefined {\n\t\tif (field.foreignKey !== undefined) {\n\t\t\treturn field.foreignKey;\n\t\t}\n\t\tif (field.kind === \"belongsTo\") {\n\t\t\treturn `${field.model}Id`;\n\t\t}\n\t\t// hasOne / hasMany: default FK is ownerModelName + \"Id\"\n\t\tconst ownerSchema = schemaByTable.get(tableName) ?? schemas[tableName];\n\t\tconst ownerModelName = ownerSchema?.name ?? tableName;\n\t\treturn `${ownerModelName}Id`;\n\t}\n\n\t/**\n\t * Resolve a model name to its table name.\n\t */\n\tprivate resolveModelTableName(\n\t\tmodelName: string,\n\t\tschemaByTable: Map<string, SchemaDefinition>,\n\t\tschemas: Record<string, SchemaDefinition>,\n\t): string | undefined {\n\t\tconst byName = schemas[modelName];\n\t\tif (byName) return byName.tableName ?? byName.name;\n\n\t\tfor (const schema of Object.values(schemas)) {\n\t\t\tif (schema.name === modelName) return schema.tableName ?? schema.name;\n\t\t}\n\n\t\t// Also check by table name directly\n\t\tif (schemaByTable.has(modelName)) return modelName;\n\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Resolve the junction table name for a manyToMany relation.\n\t * ownerModelName is the schema name (not table name), same as registry logic.\n\t */\n\tprivate resolveJunctionTableName(\n\t\townerModelName: string,\n\t\ttargetModelName: string,\n\t\tthrough: string | undefined,\n\t\t_newSchemaByTable: Map<string, SchemaDefinition>,\n\t\t_newSchemas: Record<string, SchemaDefinition>,\n\t): string | undefined {\n\t\tif (through !== undefined) return through;\n\n\t\t// Alphabetical order by model name, same as registry\n\t\tconst parts = [ownerModelName, targetModelName].sort();\n\t\treturn `${parts[0]}_${parts[1]}`;\n\t}\n\n\t/**\n\t * Check if a junction table is still referenced by any manyToMany\n\t * relation in the new schemas.\n\t */\n\tprivate isJunctionTableStillReferenced(\n\t\tjunctionName: string,\n\t\tnewSchemas: Record<string, SchemaDefinition>,\n\t\tnewSchemaByTable: Map<string, SchemaDefinition>,\n\t): boolean {\n\t\tfor (const schema of Object.values(newSchemas)) {\n\t\t\tconst ownerModelName = schema.name;\n\t\t\tfor (const field of Object.values(schema.fields)) {\n\t\t\t\tif (!isFieldDefinition(field)) continue;\n\t\t\t\tif (field.type !== \"relation\" || field.kind !== \"manyToMany\") continue;\n\n\t\t\t\tconst resolved = this.resolveJunctionTableName(\n\t\t\t\t\townerModelName,\n\t\t\t\t\tfield.model,\n\t\t\t\t\tfield.through,\n\t\t\t\t\tnewSchemaByTable,\n\t\t\t\t\tnewSchemas,\n\t\t\t\t);\n\n\t\t\t\tif (resolved === junctionName) return true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\t/**\n\t * Check if two relation fields have the same DB structure.\n\t * hasOne and hasMany both place the FK on the target table,\n\t * so switching between them requires no DB change.\n\t */\n\tprivate isSameRelationDbStructure(\n\t\toldField: FieldDefinition,\n\t\tnewField: FieldDefinition,\n\t): boolean {\n\t\tif (oldField.type !== \"relation\" || newField.type !== \"relation\") {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst sameModel = oldField.model === newField.model;\n\t\tconst sameForeignKey = oldField.foreignKey === newField.foreignKey;\n\n\t\tconst oldKind = oldField.kind;\n\t\tconst newKind = newField.kind;\n\t\tconst isHasOneHasManySwap =\n\t\t\t(oldKind === \"hasOne\" && newKind === \"hasMany\") ||\n\t\t\t(oldKind === \"hasMany\" && newKind === \"hasOne\");\n\n\t\t// hasOne <-> hasMany: FK stays on target table, no DB change\n\t\tif (isHasOneHasManySwap && sameModel && sameForeignKey) {\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/**\n\t * Compare two versions of the same table\n\t */\n\tprivate compareTable(\n\t\toldSchema: SchemaDefinition,\n\t\tnewSchema: SchemaDefinition,\n\t): SchemaDiff[] {\n\t\tconst differences: SchemaDiff[] = [];\n\t\tconst tableName = newSchema.tableName ?? newSchema.name;\n\n\t\tconst oldFieldNames = new Set(Object.keys(oldSchema.fields));\n\t\tconst newFieldNames = new Set(Object.keys(newSchema.fields));\n\n\t\t// For relation fields not present by name: check if a same-DB-structure\n\t\t// relation exists under a different name (e.g. hasOne->hasMany rename).\n\t\t// If so, skip both the removed and added diff for those fields.\n\t\tconst skippedOldFields = new Set<string>();\n\t\tconst skippedNewFields = new Set<string>();\n\n\t\tfor (const newFieldName of newFieldNames) {\n\t\t\tif (oldFieldNames.has(newFieldName)) continue;\n\n\t\t\tconst newField = newSchema.fields[newFieldName];\n\t\t\tif (!isFieldDefinition(newField) || newField.type !== \"relation\")\n\t\t\t\tcontinue;\n\n\t\t\tfor (const oldFieldName of oldFieldNames) {\n\t\t\t\tif (newFieldNames.has(oldFieldName)) continue;\n\t\t\t\tif (skippedOldFields.has(oldFieldName)) continue;\n\n\t\t\t\tconst oldField = oldSchema.fields[oldFieldName];\n\t\t\t\tif (!isFieldDefinition(oldField) || oldField.type !== \"relation\")\n\t\t\t\t\tcontinue;\n\n\t\t\t\tif (this.isSameRelationDbStructure(oldField, newField)) {\n\t\t\t\t\tskippedOldFields.add(oldFieldName);\n\t\t\t\t\tskippedNewFields.add(newFieldName);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Find added fields\n\t\tfor (const fieldName of newFieldNames) {\n\t\t\tif (oldFieldNames.has(fieldName)) continue;\n\t\t\tif (skippedNewFields.has(fieldName)) continue;\n\n\t\t\tconst definition = newSchema.fields[fieldName];\n\t\t\tif (!isFieldDefinition(definition)) {\n\t\t\t\t// Skip invalid field definitions\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tdifferences.push({\n\t\t\t\ttype: \"fieldAdded\",\n\t\t\t\ttableName,\n\t\t\t\tfieldName,\n\t\t\t\tdefinition,\n\t\t\t});\n\t\t}\n\n\t\t// Find removed fields\n\t\tfor (const fieldName of oldFieldNames) {\n\t\t\tif (newFieldNames.has(fieldName)) continue;\n\t\t\tif (skippedOldFields.has(fieldName)) continue;\n\n\t\t\tconst definition = oldSchema.fields[fieldName];\n\t\t\tif (!isFieldDefinition(definition)) continue;\n\n\t\t\tdifferences.push({\n\t\t\t\ttype: \"fieldRemoved\",\n\t\t\t\ttableName,\n\t\t\t\tfieldName,\n\t\t\t\tdefinition,\n\t\t\t});\n\t\t}\n\n\t\t// Find modified fields\n\t\tfor (const fieldName of newFieldNames) {\n\t\t\tif (oldFieldNames.has(fieldName)) {\n\t\t\t\tconst oldField = oldSchema.fields[fieldName];\n\t\t\t\tconst newField = newSchema.fields[fieldName];\n\n\t\t\t\tif (!isFieldDefinition(oldField) || !isFieldDefinition(newField)) {\n\t\t\t\t\t// Skip invalid field definitions\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (this.isFieldModified(oldField, newField)) {\n\t\t\t\t\tdifferences.push({\n\t\t\t\t\t\ttype: \"fieldModified\",\n\t\t\t\t\t\ttableName,\n\t\t\t\t\t\tfieldName,\n\t\t\t\t\t\toldDefinition: oldField,\n\t\t\t\t\t\tnewDefinition: newField,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Compare indexes if present\n\t\tif (oldSchema.indexes || newSchema.indexes) {\n\t\t\tconst indexDiffs = this.compareIndexes(\n\t\t\t\ttableName,\n\t\t\t\toldSchema.indexes ?? [],\n\t\t\t\tnewSchema.indexes ?? [],\n\t\t\t);\n\t\t\tdifferences.push(...indexDiffs);\n\t\t}\n\n\t\treturn differences;\n\t}\n\n\t/**\n\t * Check if a field has been modified\n\t */\n\tisFieldModified(\n\t\toldField: FieldDefinition,\n\t\tnewField: FieldDefinition,\n\t): boolean {\n\t\t// Check type change\n\t\tif (oldField.type !== newField.type) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// Check required change\n\t\tif (oldField.required !== newField.required) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// Check unique constraint change\n\t\tconst oldUnique =\n\t\t\t\"unique\" in oldField\n\t\t\t\t? (oldField as { unique?: boolean }).unique\n\t\t\t\t: undefined;\n\t\tconst newUnique =\n\t\t\t\"unique\" in newField\n\t\t\t\t? (newField as { unique?: boolean }).unique\n\t\t\t\t: undefined;\n\t\tif (oldUnique !== newUnique) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// Check default value change\n\t\tif (oldField.default !== newField.default) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// Type-specific checks with proper type narrowing\n\t\tswitch (oldField.type) {\n\t\t\tcase \"string\":\n\t\t\t\t// Type narrowing\n\t\t\t\tif (newField.type !== \"string\") {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\tif (\n\t\t\t\t\toldField.maxLength !== newField.maxLength ||\n\t\t\t\t\toldField.minLength !== newField.minLength ||\n\t\t\t\t\toldField.pattern !== newField.pattern\n\t\t\t\t) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase \"number\":\n\t\t\t\t// Type narrowing\n\t\t\t\tif (newField.type !== \"number\") {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\tif (oldField.min !== newField.min || oldField.max !== newField.max) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase \"array\":\n\t\t\t\t// Type narrowing\n\t\t\t\tif (newField.type !== \"array\") {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\tif (\n\t\t\t\t\toldField.items !== newField.items ||\n\t\t\t\t\toldField.minItems !== newField.minItems ||\n\t\t\t\t\toldField.maxItems !== newField.maxItems ||\n\t\t\t\t\t(\"unique\" in oldField &&\n\t\t\t\t\t\t\"unique\" in newField &&\n\t\t\t\t\t\toldField.unique !== newField.unique)\n\t\t\t\t) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase \"enum\":\n\t\t\t\t// Type narrowing\n\t\t\t\tif (newField.type !== \"enum\") {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\t// Check if enum values changed\n\t\t\t\tif (oldField.values && newField.values) {\n\t\t\t\t\tconst oldValues = new Set(oldField.values);\n\t\t\t\t\tconst newValues = new Set(newField.values);\n\n\t\t\t\t\tif (oldValues.size !== newValues.size) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\n\t\t\t\t\tfor (const value of oldValues) {\n\t\t\t\t\t\tif (!newValues.has(value)) {\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase \"relation\":\n\t\t\t\t// Type narrowing\n\t\t\t\tif (newField.type !== \"relation\") {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\tif (\n\t\t\t\t\toldField.model !== newField.model ||\n\t\t\t\t\toldField.foreignKey !== newField.foreignKey ||\n\t\t\t\t\toldField.through !== newField.through ||\n\t\t\t\t\toldField.onDelete !== newField.onDelete ||\n\t\t\t\t\toldField.onUpdate !== newField.onUpdate\n\t\t\t\t) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\t// hasOne <-> hasMany does not change DB structure\n\t\t\t\tif (oldField.kind !== newField.kind) {\n\t\t\t\t\tconst isHasOneHasManySwap =\n\t\t\t\t\t\t(oldField.kind === \"hasOne\" && newField.kind === \"hasMany\") ||\n\t\t\t\t\t\t(oldField.kind === \"hasMany\" && newField.kind === \"hasOne\");\n\t\t\t\t\tif (!isHasOneHasManySwap) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/**\n\t * Compare indexes between two schema versions\n\t */\n\tprivate compareIndexes(\n\t\ttableName: string,\n\t\toldIndexes: readonly {\n\t\t\treadonly name?: string;\n\t\t\treadonly fields: readonly string[];\n\t\t\treadonly unique?: boolean;\n\t\t\treadonly type?: string;\n\t\t}[],\n\t\tnewIndexes: readonly {\n\t\t\treadonly name?: string;\n\t\t\treadonly fields: readonly string[];\n\t\t\treadonly unique?: boolean;\n\t\t\treadonly type?: string;\n\t\t}[],\n\t): SchemaDiff[] {\n\t\tconst differences: SchemaDiff[] = [];\n\n\t\t// Create index maps keyed by normalized signature\n\t\tconst oldIndexMap = new Map(\n\t\t\toldIndexes.map((idx) => [this.getIndexSignature(idx), idx]),\n\t\t);\n\t\tconst newIndexMap = new Map(\n\t\t\tnewIndexes.map((idx) => [this.getIndexSignature(idx), idx]),\n\t\t);\n\n\t\t// Find added indexes\n\t\tfor (const [signature, index] of newIndexMap) {\n\t\t\tif (!oldIndexMap.has(signature)) {\n\t\t\t\tdifferences.push({\n\t\t\t\t\ttype: \"indexAdded\",\n\t\t\t\t\ttableName,\n\t\t\t\t\tindex: {\n\t\t\t\t\t\t...(index.name !== undefined && { name: index.name }),\n\t\t\t\t\t\tfields: index.fields,\n\t\t\t\t\t\t...(index.unique !== undefined && { unique: index.unique }),\n\t\t\t\t\t\t...(index.type !== undefined &&\n\t\t\t\t\t\t\tisValidIndexType(index.type) && { type: index.type }),\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\t// Find removed indexes\n\t\tfor (const [signature, index] of oldIndexMap) {\n\t\t\tif (!newIndexMap.has(signature)) {\n\t\t\t\tconst indexName =\n\t\t\t\t\tindex.name ?? `idx_${tableName}_${index.fields.join(\"_\")}`;\n\t\t\t\tdifferences.push({\n\t\t\t\t\ttype: \"indexRemoved\",\n\t\t\t\t\ttableName,\n\t\t\t\t\tindexName,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\treturn differences;\n\t}\n\n\t/**\n\t * Get index signature for comparison\n\t */\n\tprivate getIndexSignature(index: {\n\t\treadonly fields: readonly string[];\n\t\treadonly unique?: boolean;\n\t\treadonly type?: string;\n\t}): string {\n\t\tconst fields = [...index.fields].sort().join(\",\");\n\t\tconst unique = index.unique ? \"unique\" : \"normal\";\n\t\tconst type = index.type ?? \"btree\";\n\t\treturn `${fields}:${unique}:${type}`;\n\t}\n}\n\n/**\n * Create schema differ instance\n */\nexport function createSchemaDiffer(): SchemaDiffer {\n\treturn new ForgeSchemaDiffer();\n}\n","/**\n * Migration Generator Implementation (~250 LOC)\n *\n * Generates migration operations and TypeScript migration files from schema differences.\n */\n\nimport {\n\tMigration,\n\tMigrationGenerator,\n\tMigrationMetadata,\n\tMigrationOperation,\n\tMigrationSystemError,\n\tSchemaDiff,\n} from \"../types/core/migration\";\n\n/**\n * Migration generator implementation\n */\nexport class ForgeMigrationGenerator implements MigrationGenerator {\n\t/**\n\t * Escape string for use in template literals\n\t */\n\tprivate escapeString(str: string): string {\n\t\treturn str\n\t\t\t.replace(/\\\\/g, \"\\\\\\\\\")\n\t\t\t.replace(/'/g, \"\\\\'\")\n\t\t\t.replace(/\"/g, '\\\\\"')\n\t\t\t.replace(/`/g, \"\\\\`\")\n\t\t\t.replace(/\\$/g, \"\\\\$\")\n\t\t\t.replace(/\\n/g, \"\\\\n\")\n\t\t\t.replace(/\\r/g, \"\\\\r\")\n\t\t\t.replace(/\\t/g, \"\\\\t\");\n\t}\n\n\t/**\n\t * Generate complete migration from differences\n\t */\n\tgenerate(\n\t\tdifferences: readonly SchemaDiff[],\n\t\tmetadata: Omit<MigrationMetadata, \"timestamp\">,\n\t): Migration {\n\t\ttry {\n\t\t\tconst operationsResult = this.generateOperations(differences);\n\n\t\t\tconst migration: Migration = {\n\t\t\t\tmetadata: {\n\t\t\t\t\t...metadata,\n\t\t\t\t\ttimestamp: Date.now(),\n\t\t\t\t},\n\t\t\t\toperations: operationsResult,\n\t\t\t};\n\n\t\t\treturn migration;\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthrow new MigrationSystemError(\n\t\t\t\t`Failed to generate migration: ${message}`,\n\t\t\t\t\"GENERATION_ERROR\",\n\t\t\t\terror,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Generate operations from differences\n\t */\n\tgenerateOperations(\n\t\tdifferences: readonly SchemaDiff[],\n\t): readonly MigrationOperation[] {\n\t\ttry {\n\t\t\tconst operations: MigrationOperation[] = [];\n\n\t\t\tfor (const diff of differences) {\n\t\t\t\tconst op = this.generateOperation(diff);\n\t\t\t\toperations.push(op);\n\t\t\t}\n\n\t\t\treturn operations;\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthrow new MigrationSystemError(\n\t\t\t\t`Failed to generate operations: ${message}`,\n\t\t\t\t\"GENERATION_ERROR\",\n\t\t\t\terror,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Generate operation for a single difference\n\t */\n\tprivate generateOperation(diff: SchemaDiff): MigrationOperation {\n\t\tswitch (diff.type) {\n\t\t\tcase \"tableAdded\":\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"createTable\",\n\t\t\t\t\tschema: diff.schema,\n\t\t\t\t};\n\n\t\t\tcase \"tableRemoved\":\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"dropTable\",\n\t\t\t\t\ttableName: diff.tableName,\n\t\t\t\t};\n\n\t\t\tcase \"tableRenamed\":\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"renameTable\",\n\t\t\t\t\tfrom: diff.from,\n\t\t\t\t\tto: diff.to,\n\t\t\t\t};\n\n\t\t\tcase \"fieldAdded\": {\n\t\t\t\t// Relation fields have no direct DB column — differ produces\n\t\t\t\t// separate diffs for the actual FK column (e.g. tagId).\n\t\t\t\t// But we still need to update _datrix meta schema.\n\t\t\t\tif (diff.definition.type === \"relation\") {\n\t\t\t\t\treturn {\n\t\t\t\t\t\ttype: \"alterTable\",\n\t\t\t\t\t\ttableName: diff.tableName,\n\t\t\t\t\t\toperations: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ttype: \"addMetaField\",\n\t\t\t\t\t\t\t\tfield: diff.fieldName,\n\t\t\t\t\t\t\t\tdefinition: diff.definition,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"alterTable\",\n\t\t\t\t\ttableName: diff.tableName,\n\t\t\t\t\toperations: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"addColumn\",\n\t\t\t\t\t\t\tcolumn: diff.fieldName,\n\t\t\t\t\t\t\tdefinition: diff.definition,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tcase \"fieldRemoved\": {\n\t\t\t\t// Relation fields have no direct DB column\n\t\t\t\t// But we still need to update _datrix meta schema.\n\t\t\t\tif (diff.definition.type === \"relation\") {\n\t\t\t\t\treturn {\n\t\t\t\t\t\ttype: \"alterTable\",\n\t\t\t\t\t\ttableName: diff.tableName,\n\t\t\t\t\t\toperations: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ttype: \"dropMetaField\",\n\t\t\t\t\t\t\t\tfield: diff.fieldName,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"alterTable\",\n\t\t\t\t\ttableName: diff.tableName,\n\t\t\t\t\toperations: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"dropColumn\",\n\t\t\t\t\t\t\tcolumn: diff.fieldName,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tcase \"fieldModified\": {\n\t\t\t\tconst operations = [];\n\n\t\t\t\t// Relation FK rename: foreignKey changed → rename the actual DB column\n\t\t\t\tif (\n\t\t\t\t\tdiff.oldDefinition.type === \"relation\" &&\n\t\t\t\t\tdiff.newDefinition.type === \"relation\" &&\n\t\t\t\t\tdiff.oldDefinition.foreignKey !== diff.newDefinition.foreignKey\n\t\t\t\t) {\n\t\t\t\t\tconst oldFK =\n\t\t\t\t\t\tdiff.oldDefinition.foreignKey ?? `${diff.oldDefinition.model}Id`;\n\t\t\t\t\tconst newFK =\n\t\t\t\t\t\tdiff.newDefinition.foreignKey ?? `${diff.newDefinition.model}Id`;\n\t\t\t\t\tif (oldFK !== newFK) {\n\t\t\t\t\t\toperations.push({\n\t\t\t\t\t\t\ttype: \"renameColumn\" as const,\n\t\t\t\t\t\t\tfrom: oldFK,\n\t\t\t\t\t\t\tto: newFK,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Relation field modified — update _datrix meta schema\n\t\t\t\tif (\n\t\t\t\t\tdiff.oldDefinition.type === \"relation\" ||\n\t\t\t\t\tdiff.newDefinition.type === \"relation\"\n\t\t\t\t) {\n\t\t\t\t\toperations.push({\n\t\t\t\t\t\ttype: \"modifyMetaField\" as const,\n\t\t\t\t\t\tfield: diff.fieldName,\n\t\t\t\t\t\tnewDefinition: diff.newDefinition,\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\t// If no special operation was generated, fall back to modifyColumn\n\t\t\t\tif (operations.length === 0) {\n\t\t\t\t\toperations.push({\n\t\t\t\t\t\ttype: \"modifyColumn\" as const,\n\t\t\t\t\t\tcolumn: diff.fieldName,\n\t\t\t\t\t\tnewDefinition: diff.newDefinition,\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"alterTable\",\n\t\t\t\t\ttableName: diff.tableName,\n\t\t\t\t\toperations,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tcase \"fieldRenamed\":\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"alterTable\",\n\t\t\t\t\ttableName: diff.tableName,\n\t\t\t\t\toperations: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"renameColumn\",\n\t\t\t\t\t\t\tfrom: diff.from,\n\t\t\t\t\t\t\tto: diff.to,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t};\n\n\t\t\tcase \"indexAdded\":\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"createIndex\",\n\t\t\t\t\ttableName: diff.tableName,\n\t\t\t\t\tindex: diff.index,\n\t\t\t\t};\n\n\t\t\tcase \"indexRemoved\":\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"dropIndex\",\n\t\t\t\t\ttableName: diff.tableName,\n\t\t\t\t\tindexName: diff.indexName,\n\t\t\t\t};\n\t\t}\n\t}\n\n\t/**\n\t * Generate TypeScript migration file content\n\t */\n\tgenerateFile(migration: Migration): string {\n\t\tconst { metadata, operations } = migration;\n\n\t\tconst operationsCode = this.generateOperationsCode(operations, 2);\n\n\t\t// Escape metadata strings to prevent injection\n\t\tconst escapedName = this.escapeString(metadata.name);\n\t\tconst escapedVersion = this.escapeString(metadata.version);\n\t\tconst escapedDescription = metadata.description\n\t\t\t? this.escapeString(metadata.description)\n\t\t\t: undefined;\n\t\tconst escapedAuthor = metadata.author\n\t\t\t? this.escapeString(metadata.author)\n\t\t\t: undefined;\n\n\t\treturn `/**\n * Migration: ${escapedName}\n * Version: ${escapedVersion}\n * Created: ${new Date(metadata.timestamp).toISOString()}\n ${escapedDescription ? `* Description: ${escapedDescription}` : \"\"}\n ${escapedAuthor ? `* Author: ${escapedAuthor}` : \"\"}\n */\n\nimport type { Migration } from '../types/core/migration';\n\nexport const migration: Migration = {\n metadata: {\n name: '${escapedName}',\n version: '${escapedVersion}',\n timestamp: ${metadata.timestamp},\n ${escapedDescription ? `description: '${escapedDescription}',` : \"\"}\n ${escapedAuthor ? `author: '${escapedAuthor}',` : \"\"}\n },\n\n operations: [\n${operationsCode}\n ]\n};\n\nexport default migration;\n`;\n\t}\n\n\t/**\n\t * Generate TypeScript code for operations array\n\t */\n\tprivate generateOperationsCode(\n\t\toperations: readonly MigrationOperation[],\n\t\tindent: number,\n\t): string {\n\t\tconst indentStr = \" \".repeat(indent);\n\n\t\treturn operations\n\t\t\t.map((op) => {\n\t\t\t\tswitch (op.type) {\n\t\t\t\t\tcase \"createTable\":\n\t\t\t\t\t\treturn `${indentStr}{\n${indentStr} type: 'createTable',\n${indentStr} schema: ${JSON.stringify(op.schema, null, 2).replace(/\\n/g, `\\n${indentStr} `)}\n${indentStr}}`;\n\n\t\t\t\t\tcase \"dropTable\":\n\t\t\t\t\t\treturn `${indentStr}{\n${indentStr} type: 'dropTable',\n${indentStr} tableName: '${op.tableName}'\n${indentStr}}`;\n\n\t\t\t\t\tcase \"alterTable\":\n\t\t\t\t\t\treturn `${indentStr}{\n${indentStr} type: 'alterTable',\n${indentStr} tableName: '${op.tableName}',\n${indentStr} operations: ${JSON.stringify(op.operations, null, 2).replace(/\\n/g, `\\n${indentStr} `)}\n${indentStr}}`;\n\n\t\t\t\t\tcase \"createIndex\":\n\t\t\t\t\t\treturn `${indentStr}{\n${indentStr} type: 'createIndex',\n${indentStr} tableName: '${op.tableName}',\n${indentStr} index: ${JSON.stringify(op.index, null, 2).replace(/\\n/g, `\\n${indentStr} `)}\n${indentStr}}`;\n\n\t\t\t\t\tcase \"dropIndex\":\n\t\t\t\t\t\treturn `${indentStr}{\n${indentStr} type: 'dropIndex',\n${indentStr} tableName: '${op.tableName}',\n${indentStr} indexName: '${op.indexName}'\n${indentStr}}`;\n\n\t\t\t\t\tcase \"renameTable\":\n\t\t\t\t\t\treturn `${indentStr}{\n${indentStr} type: 'renameTable',\n${indentStr} from: '${op.from}',\n${indentStr} to: '${op.to}'\n${indentStr}}`;\n\n\t\t\t\t\tcase \"raw\":\n\t\t\t\t\t\treturn `${indentStr}{\n${indentStr} type: 'raw',\n${indentStr} sql: \\`${op.sql}\\`,\n${indentStr} params: ${JSON.stringify(op.params ?? [])}\n${indentStr}}`;\n\n\t\t\t\t\tcase \"dataTransfer\":\n\t\t\t\t\t\treturn `${indentStr}{\n${indentStr} type: 'dataTransfer',\n${indentStr} description: '${op.description}'\n${indentStr}}`;\n\t\t\t\t}\n\t\t\t})\n\t\t\t.join(\",\\n\");\n\t}\n}\n\n/**\n * Create migration generator instance\n */\nexport function createMigrationGenerator(): MigrationGenerator {\n\treturn new ForgeMigrationGenerator();\n}\n","/**\n * Migration History Manager Implementation\n *\n * Manages migration execution history in the database.\n * Uses datrix.raw for all CRUD operations - no raw SQL.\n */\n\nimport { createHash } from \"crypto\";\nimport {\n\tMigration,\n\tMigrationHistory,\n\tMigrationHistoryRecord,\n\tMigrationStatus,\n\tMigrationSystemError,\n} from \"../types/core/migration\";\nimport { IDatrix } from \"../types/core\";\nimport { DatrixEntry } from \"../types/core/schema\";\nimport { DEFAULT_MIGRATION_MODEL, DATRIX_META_MODEL } from \"./schema\";\n\n/**\n * Migration history entry type (matches the schema)\n */\ninterface MigrationEntry extends DatrixEntry {\n\tname: string;\n\tversion: string;\n\texecutionTime: number;\n\tstatus: MigrationStatus;\n\tchecksum?: string;\n\terror?: string;\n\tappliedAt: Date;\n}\n\n/**\n * Migration history manager implementation\n */\nexport class ForgeMigrationHistory implements MigrationHistory {\n\tprivate readonly datrix: IDatrix;\n\tprivate readonly modelName: string;\n\tprivate initialized = false;\n\n\tconstructor(datrix: IDatrix, modelName: string = DEFAULT_MIGRATION_MODEL) {\n\t\tthis.datrix = datrix;\n\t\tthis.modelName = modelName;\n\t}\n\n\t/**\n\t * Initialize migrations tracking table\n\t *\n\t * The table is created via adapter.createTable using the migration schema.\n\t * Schema is already registered in Datrix initialization.\n\t */\n\tasync initialize(): Promise<void> {\n\t\tif (this.initialized) {\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tconst schema = this.datrix.getSchemas().get(this.modelName);\n\t\t\tif (!schema) {\n\t\t\t\tthrow new MigrationSystemError(\n\t\t\t\t\t`Migration schema '${this.modelName}' not found in registry`,\n\t\t\t\t\t\"MIGRATION_ERROR\",\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst adapter = this.datrix.getAdapter();\n\n\t\t\t// Ensure _datrix metadata table exists before any other table operation\n\t\t\tconst metaExists = await adapter.tableExists(DATRIX_META_MODEL);\n\t\t\tif (!metaExists) {\n\t\t\t\tconst metaSchema = this.datrix.getSchemas().get(DATRIX_META_MODEL);\n\t\t\t\tif (!metaSchema) {\n\t\t\t\t\tthrow new MigrationSystemError(\n\t\t\t\t\t\t`Schema '${DATRIX_META_MODEL}' not found in registry`,\n\t\t\t\t\t\t\"MIGRATION_ERROR\",\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\tawait adapter.createTable(metaSchema);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tthrow new MigrationSystemError(\n\t\t\t\t\t\t`Failed to create _datrix metadata table: ${(error as Error).message}`,\n\t\t\t\t\t\t\"MIGRATION_ERROR\",\n\t\t\t\t\t\terror,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst tableName = schema.tableName ?? schema.name;\n\t\t\tconst exists = await adapter.tableExists(tableName);\n\n\t\t\tif (!exists) {\n\t\t\t\ttry {\n\t\t\t\t\tawait adapter.createTable(schema);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tthrow new MigrationSystemError(\n\t\t\t\t\t\t`Failed to create migrations table: ${(error as Error).message}`,\n\t\t\t\t\t\t\"MIGRATION_ERROR\",\n\t\t\t\t\t\terror,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.initialized = true;\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthrow new MigrationSystemError(\n\t\t\t\t`Failed to initialize migration history: ${message}`,\n\t\t\t\t\"MIGRATION_ERROR\",\n\t\t\t\terror,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Record migration execution\n\t */\n\tasync record(\n\t\tmigration: Migration,\n\t\texecutionTime: number,\n\t\tstatus: MigrationStatus,\n\t\terror?: Error,\n\t): Promise<void> {\n\t\ttry {\n\t\t\tconst checksum = this.calculateChecksum(migration);\n\n\t\t\tawait this.datrix.raw.create<MigrationEntry>(this.modelName, {\n\t\t\t\tname: migration.metadata.name,\n\t\t\t\tversion: migration.metadata.version,\n\t\t\t\texecutionTime,\n\t\t\t\tstatus,\n\t\t\t\tchecksum,\n\t\t\t\terror: error?.message || \"\",\n\t\t\t\tappliedAt: new Date(),\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthrow new MigrationSystemError(\n\t\t\t\t`Failed to record migration: ${message}`,\n\t\t\t\t\"MIGRATION_ERROR\",\n\t\t\t\terror,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Get all migration records\n\t */\n\tasync getAll(): Promise<readonly MigrationHistoryRecord[]> {\n\t\ttry {\n\t\t\tconst entries = await this.datrix.raw.findMany<MigrationEntry>(\n\t\t\t\tthis.modelName,\n\t\t\t\t{\n\t\t\t\t\torderBy: { appliedAt: \"asc\" },\n\t\t\t\t},\n\t\t\t);\n\n\t\t\tconst records: MigrationHistoryRecord[] = entries.map((entry) => ({\n\t\t\t\tid: entry.id,\n\t\t\t\tname: entry.name,\n\t\t\t\tversion: entry.version,\n\t\t\t\tappliedAt: entry.appliedAt,\n\t\t\t\texecutionTime: entry.executionTime,\n\t\t\t\tstatus: entry.status,\n\t\t\t\t...(entry.checksum && { checksum: entry.checksum }),\n\t\t\t\t...(entry.error && { error: entry.error }),\n\t\t\t}));\n\n\t\t\treturn records;\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthrow new MigrationSystemError(\n\t\t\t\t`Failed to get migration history: ${message}`,\n\t\t\t\t\"MIGRATION_ERROR\",\n\t\t\t\terror,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Get last applied migration\n\t */\n\tasync getLast(): Promise<MigrationHistoryRecord | undefined> {\n\t\ttry {\n\t\t\tconst entries = await this.datrix.raw.findMany<MigrationEntry>(\n\t\t\t\tthis.modelName,\n\t\t\t\t{\n\t\t\t\t\twhere: { status: \"completed\" },\n\t\t\t\t\torderBy: { appliedAt: \"desc\" },\n\t\t\t\t\tlimit: 1,\n\t\t\t\t},\n\t\t\t);\n\n\t\t\tconst entry = entries[0];\n\t\t\tif (!entry) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\n\t\t\tconst record: MigrationHistoryRecord = {\n\t\t\t\tid: entry.id,\n\t\t\t\tname: entry.name,\n\t\t\t\tversion: entry.version,\n\t\t\t\tappliedAt: entry.appliedAt,\n\t\t\t\texecutionTime: entry.executionTime,\n\t\t\t\tstatus: entry.status,\n\t\t\t\t...(entry.checksum && { checksum: entry.checksum }),\n\t\t\t\t...(entry.error && { error: entry.error }),\n\t\t\t};\n\n\t\t\treturn record;\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthrow new MigrationSystemError(\n\t\t\t\t`Failed to get last migration: ${message}`,\n\t\t\t\t\"MIGRATION_ERROR\",\n\t\t\t\terror,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Check if migration was applied\n\t */\n\tasync isApplied(version: string): Promise<boolean> {\n\t\ttry {\n\t\t\tconst count = await this.datrix.raw.count<MigrationEntry>(this.modelName, {\n\t\t\t\tversion,\n\t\t\t\tstatus: \"completed\",\n\t\t\t});\n\n\t\t\treturn count > 0;\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthrow new MigrationSystemError(\n\t\t\t\t`Failed to check migration status: ${message}`,\n\t\t\t\t\"MIGRATION_ERROR\",\n\t\t\t\terror,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Calculate migration checksum\n\t */\n\tcalculateChecksum(migration: Migration): string {\n\t\tconst content = JSON.stringify({\n\t\t\toperations: migration.operations,\n\t\t});\n\n\t\treturn createHash(\"sha256\").update(content).digest(\"hex\");\n\t}\n\n\t/**\n\t * Verify migration integrity\n\t */\n\tverifyChecksum(\n\t\tmigration: Migration,\n\t\trecord: MigrationHistoryRecord,\n\t): boolean {\n\t\tif (!record.checksum) {\n\t\t\treturn true;\n\t\t}\n\n\t\tconst currentChecksum = this.calculateChecksum(migration);\n\t\treturn currentChecksum === record.checksum;\n\t}\n}\n\n/**\n * Create migration history manager\n */\nexport function createMigrationHistory(\n\tdatrix: IDatrix,\n\ttableName?: string,\n): MigrationHistory {\n\treturn new ForgeMigrationHistory(datrix, tableName);\n}\n","/**\n * Migration Runner Implementation\n *\n * Executes migrations and manages migration plans.\n */\n\nimport type {\n\tMigrationRunner,\n\tMigration,\n\tMigrationHistory,\n\tMigrationHistoryRecord,\n\tMigrationExecutionResult,\n\tMigrationOperation,\n\tMigrationFilePlan,\n} from \"../types/core/migration\";\nimport { MigrationSystemError } from \"../types/core/migration\";\nimport { DatabaseAdapter, Transaction } from \"../types/adapter\";\n\n/**\n * Migration runner implementation\n */\nexport class ForgeMigrationRunner implements MigrationRunner {\n\tprivate readonly adapter: DatabaseAdapter;\n\tprivate readonly history: MigrationHistory;\n\tprivate readonly migrations: readonly Migration[];\n\n\tconstructor(\n\t\tadapter: DatabaseAdapter,\n\t\thistory: MigrationHistory,\n\t\tmigrations: readonly Migration[],\n\t) {\n\t\tthis.adapter = adapter;\n\t\tthis.history = history;\n\t\tthis.migrations = migrations;\n\t}\n\n\t/**\n\t * Get pending migrations\n\t */\n\tasync getPending(): Promise<readonly Migration[]> {\n\t\ttry {\n\t\t\t// Initialize history table\n\t\t\tawait this.history.initialize();\n\n\t\t\t// Get applied migrations\n\t\t\tconst appliedResult = await this.history.getAll();\n\n\t\t\tconst appliedVersions = new Set(\n\t\t\t\tappliedResult\n\t\t\t\t\t.filter((record) => record.status === \"completed\")\n\t\t\t\t\t.map((record) => record.version),\n\t\t\t);\n\n\t\t\t// Filter pending migrations\n\t\t\tconst pending = this.migrations.filter(\n\t\t\t\t(migration) => !appliedVersions.has(migration.metadata.version),\n\t\t\t);\n\n\t\t\treturn pending;\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthrow new MigrationSystemError(\n\t\t\t\t`Failed to get pending migrations: ${message}`,\n\t\t\t\t\"MIGRATION_ERROR\",\n\t\t\t\terror,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Get applied migrations\n\t */\n\tasync getApplied(): Promise<readonly MigrationHistoryRecord[]> {\n\t\tawait this.history.initialize();\n\t\treturn await this.history.getAll();\n\t}\n\n\t/**\n\t * Run pending migrations\n\t */\n\tasync runPending(options?: {\n\t\treadonly target?: string;\n\t\treadonly dryRun?: boolean;\n\t}): Promise<readonly MigrationExecutionResult[]> {\n\t\ttry {\n\t\t\tlet migrationsToRun = await this.getPending();\n\n\t\t\t// Filter by target version if specified\n\t\t\tif (options?.target) {\n\t\t\t\tconst targetIndex = migrationsToRun.findIndex(\n\t\t\t\t\t(m) => m.metadata.version === options.target,\n\t\t\t\t);\n\n\t\t\t\tif (targetIndex === -1) {\n\t\t\t\t\tthrow new MigrationSystemError(\n\t\t\t\t\t\t`Target version ${options.target} not found`,\n\t\t\t\t\t\t\"MIGRATION_ERROR\",\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tmigrationsToRun = migrationsToRun.slice(0, targetIndex + 1);\n\t\t\t}\n\n\t\t\t// Handle dry run - simulate migrations without executing\n\t\t\tif (options?.dryRun) {\n\t\t\t\tconst simulatedResults: MigrationExecutionResult[] =\n\t\t\t\t\tmigrationsToRun.map(\n\t\t\t\t\t\t(migration): MigrationExecutionResult => ({\n\t\t\t\t\t\t\tmigration,\n\t\t\t\t\t\t\tstatus: \"pending\",\n\t\t\t\t\t\t\texecutionTime: 0,\n\t\t\t\t\t\t}),\n\t\t\t\t\t);\n\t\t\t\treturn simulatedResults;\n\t\t\t}\n\n\t\t\tconst results: MigrationExecutionResult[] = [];\n\n\t\t\tfor (const migration of migrationsToRun) {\n\t\t\t\tconst result = await this.runOne(migration);\n\n\t\t\t\tresults.push(result);\n\n\t\t\t\t// Stop on failure\n\t\t\t\tif (result.status === \"failed\") {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn results;\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthrow new MigrationSystemError(\n\t\t\t\t`Failed to run pending migrations: ${message}`,\n\t\t\t\t\"MIGRATION_ERROR\",\n\t\t\t\terror,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Run specific migration\n\t *\n\t * Operations are split into 3 phases for adapter compatibility:\n\t * - Phase 1 (pre-tx): createTable — run before transaction\n\t * - Phase 2 (tx): alterTable, dataTransfer, createIndex, dropIndex, renameTable, raw — inside transaction\n\t * - Phase 3 (post-tx): dropTable — run after successful commit\n\t *\n\t * This split is necessary because some adapters (e.g. MongoDB) cannot run\n\t * DDL operations (create/drop collection) inside a multi-document transaction.\n\t * For SQL adapters this is harmless since DDL is transaction-safe anyway.\n\t *\n\t * NOTE: On failure during phase 2, tables created in phase 1 may remain\n\t * as empty leftovers. This is acceptable — no data loss occurs.\n\t */\n\tasync runOne(migration: Migration): Promise<MigrationExecutionResult> {\n\t\tconst startTime = Date.now();\n\n\t\t// Split operations into 3 phases, preserving relative order within each phase\n\t\tconst { preOps, txOps, postOps } = this.splitOperationsByPhase(\n\t\t\tmigration.operations,\n\t\t);\n\n\t\ttry {\n\t\t\t// Phase 1: createTable operations (outside transaction)\n\t\t\tfor (const operation of preOps) {\n\t\t\t\ttry {\n\t\t\t\t\tawait this.executeOperationDirect(operation);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconst executionTime = Date.now() - startTime;\n\t\t\t\t\tconst err = error instanceof Error ? error : new Error(String(error));\n\t\t\t\t\tawait this.recordSafe(migration, executionTime, \"failed\", err);\n\t\t\t\t\treturn { migration, status: \"failed\", executionTime, error: err };\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Phase 2: DML and non-DDL operations (inside transaction)\n\t\t\tconst tx = await this.adapter.beginTransaction();\n\t\t\ttry {\n\t\t\t\tfor (const operation of txOps) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait this.executeOperation(tx, operation);\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tawait tx.rollback();\n\t\t\t\t\t\tconst executionTime = Date.now() - startTime;\n\t\t\t\t\t\tconst err =\n\t\t\t\t\t\t\terror instanceof Error ? error : new Error(String(error));\n\t\t\t\t\t\tawait this.recordSafe(migration, executionTime, \"failed\", err);\n\t\t\t\t\t\treturn { migration, status: \"failed\", executionTime, error: err };\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\tawait tx.commit();\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconst executionTime = Date.now() - startTime;\n\t\t\t\t\tconst err = error instanceof Error ? error : new Error(String(error));\n\t\t\t\t\treturn { migration, status: \"failed\", executionTime, error: err };\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tawait tx.rollback();\n\t\t\t\tconst executionTime = Date.now() - startTime;\n\t\t\t\tconst err = error instanceof Error ? error : new Error(String(error));\n\t\t\t\tawait this.recordSafe(migration, executionTime, \"failed\", err);\n\t\t\t\treturn { migration, status: \"failed\", executionTime, error: err };\n\t\t\t}\n\n\t\t\t// Phase 3: dropTable operations (after successful commit)\n\t\t\tfor (const operation of postOps) {\n\t\t\t\ttry {\n\t\t\t\t\tawait this.executeOperationDirect(operation);\n\t\t\t\t} catch (error) {\n\t\t\t\t\t// Drop failures after successful commit are warnings, not failures.\n\t\t\t\t\t// Data is already safely migrated — leftover tables can be cleaned manually.\n\t\t\t\t\tconst executionTime = Date.now() - startTime;\n\t\t\t\t\tconst warnings = [\n\t\t\t\t\t\t`Post-commit dropTable failed: ${(error as Error).message}`,\n\t\t\t\t\t];\n\t\t\t\t\tawait this.recordSafe(migration, executionTime, \"completed\");\n\t\t\t\t\treturn { migration, status: \"completed\", executionTime, warnings };\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst executionTime = Date.now() - startTime;\n\t\t\tconst warnings: string[] = [];\n\t\t\ttry {\n\t\t\t\tawait this.history.record(migration, executionTime, \"completed\");\n\t\t\t} catch (error) {\n\t\t\t\twarnings.push(\n\t\t\t\t\t`Failed to record migration history: ${(error as Error).message}`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tmigration,\n\t\t\t\tstatus: \"completed\",\n\t\t\t\texecutionTime,\n\t\t\t\t...(warnings.length > 0 && { warnings }),\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthrow new MigrationSystemError(\n\t\t\t\t`Failed to run migration: ${message}`,\n\t\t\t\t\"MIGRATION_ERROR\",\n\t\t\t\terror,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Split migration operations into 3 phases.\n\t * Preserves relative order within each phase.\n\t *\n\t * - pre: createTable (must exist before DML references them)\n\t * - tx: everything else except dropTable\n\t * - post: dropTable (safe to drop after data is committed)\n\t */\n\tprivate splitOperationsByPhase(operations: readonly MigrationOperation[]): {\n\t\treadonly preOps: readonly MigrationOperation[];\n\t\treadonly txOps: readonly MigrationOperation[];\n\t\treadonly postOps: readonly MigrationOperation[];\n\t} {\n\t\tconst preOps: MigrationOperation[] = [];\n\t\tconst txOps: MigrationOperation[] = [];\n\t\tconst postOps: MigrationOperation[] = [];\n\n\t\tfor (const op of operations) {\n\t\t\tif (op.type === \"createTable\") {\n\t\t\t\tpreOps.push(op);\n\t\t\t} else if (op.type === \"dropTable\" || op.type === \"renameTable\") {\n\t\t\t\tpostOps.push(op);\n\t\t\t} else {\n\t\t\t\ttxOps.push(op);\n\t\t\t}\n\t\t}\n\n\t\treturn { preOps, txOps, postOps };\n\t}\n\n\t/**\n\t * Execute a migration operation directly on the adapter (outside transaction)\n\t */\n\tprivate async executeOperationDirect(\n\t\toperation: MigrationOperation,\n\t): Promise<void> {\n\t\tswitch (operation.type) {\n\t\t\tcase \"createTable\":\n\t\t\t\treturn await this.adapter.createTable(operation.schema);\n\t\t\tcase \"dropTable\":\n\t\t\t\treturn await this.adapter.dropTable(operation.tableName);\n\t\t\tcase \"renameTable\":\n\t\t\t\treturn await this.adapter.renameTable(operation.from, operation.to);\n\t\t\tdefault:\n\t\t\t\tthrow new MigrationSystemError(\n\t\t\t\t\t`Operation type '${operation.type}' cannot run outside transaction`,\n\t\t\t\t\t\"MIGRATION_ERROR\",\n\t\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Record migration history safely (never throws)\n\t */\n\tprivate async recordSafe(\n\t\tmigration: Migration,\n\t\texecutionTime: number,\n\t\tstatus: \"completed\" | \"failed\",\n\t\terror?: Error,\n\t): Promise<void> {\n\t\ttry {\n\t\t\tawait this.history.record(migration, executionTime, status, error);\n\t\t} catch {\n\t\t\t// Swallow — recording failure should not mask the original error\n\t\t}\n\t}\n\n\t/**\n\t * Get migration plan\n\t */\n\tgetPlan(options?: { readonly target?: string }): MigrationFilePlan {\n\t\ttry {\n\t\t\tlet migrations = [...this.migrations];\n\n\t\t\tif (options?.target) {\n\t\t\t\tconst targetIndex = migrations.findIndex(\n\t\t\t\t\t(m) => m.metadata.version === options.target,\n\t\t\t\t);\n\n\t\t\t\tif (targetIndex === -1) {\n\t\t\t\t\tthrow new MigrationSystemError(\n\t\t\t\t\t\t`Target version ${options.target} not found`,\n\t\t\t\t\t\t\"MIGRATION_ERROR\",\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tmigrations = migrations.slice(0, targetIndex + 1);\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tmigrations,\n\t\t\t\t...(options?.target !== undefined && { target: options.target }),\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthrow new MigrationSystemError(\n\t\t\t\t`Failed to create migration plan: ${message}`,\n\t\t\t\t\"MIGRATION_ERROR\",\n\t\t\t\terror,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Execute a single migration operation within a transaction\n\t */\n\tprivate async executeOperation(\n\t\ttx: Transaction,\n\t\toperation: MigrationOperation,\n\t): Promise<void> {\n\t\tswitch (operation.type) {\n\t\t\tcase \"createTable\":\n\t\t\t\treturn await tx.createTable(operation.schema);\n\n\t\t\tcase \"dropTable\":\n\t\t\t\treturn await tx.dropTable(operation.tableName);\n\n\t\t\tcase \"alterTable\":\n\t\t\t\treturn await tx.alterTable(operation.tableName, operation.operations);\n\n\t\t\tcase \"createIndex\":\n\t\t\t\treturn await tx.addIndex(operation.tableName, operation.index);\n\n\t\t\tcase \"dropIndex\":\n\t\t\t\treturn await tx.dropIndex(operation.tableName, operation.indexName);\n\n\t\t\tcase \"renameTable\":\n\t\t\t\treturn await tx.renameTable(operation.from, operation.to);\n\n\t\t\tcase \"raw\":\n\t\t\t\tawait tx.executeRawQuery(operation.sql, operation.params ?? []);\n\t\t\t\treturn;\n\n\t\t\tcase \"dataTransfer\":\n\t\t\t\treturn await operation.execute(tx);\n\t\t}\n\t}\n}\n\n/**\n * Create migration runner\n */\nexport function createMigrationRunner(\n\tadapter: DatabaseAdapter,\n\thistory: MigrationHistory,\n\tmigrations: readonly Migration[],\n): MigrationRunner {\n\treturn new ForgeMigrationRunner(adapter, history, migrations);\n}\n","/**\n * Migration Session\n *\n * Provides a fluent API for managing database migrations.\n * Entry point: datrix.beginMigrate()\n *\n * Features:\n * - Compares current schemas with database state\n * - Detects ambiguous changes (rename vs drop+add)\n * - Interactive resolution for ambiguous cases\n * - Preview and apply migrations\n */\n\nimport { DatabaseAdapter, QueryRunner } from \"../types/adapter\";\nimport {\n\tSchemaDefinition,\n\tFieldDefinition,\n\tDatrixRecord,\n} from \"../types/core/schema\";\nimport {\n\tMigration,\n\tMigrationOperation,\n\tDataTransferOperation,\n\tMigrationSystemError,\n\tSchemaDiff,\n\tFieldAddedDiff,\n\tMigrationExecutionResult,\n} from \"../types/core/migration\";\nimport { IDatrix } from \"../types/core\";\nimport { ForgeSchemaDiffer } from \"./differ\";\nimport { ForgeMigrationGenerator } from \"./generator\";\nimport { ForgeMigrationHistory } from \"./history\";\nimport { ForgeMigrationRunner } from \"./runner\";\n\n/**\n * Ambiguous change types\n */\nexport type AmbiguousChangeType =\n\t| \"column_rename_or_replace\"\n\t| \"table_rename_or_replace\"\n\t| \"fk_column_drop\"\n\t| \"junction_table_drop\"\n\t| \"junction_table_rename_or_replace\"\n\t| \"relation_upgrade_single_to_many\"\n\t| \"relation_downgrade_many_to_single\"\n\t| \"fk_model_change\"\n\t| \"relation_direction_flip\";\n\n/**\n * Ambiguous action types\n */\nexport type AmbiguousActionType =\n\t| \"rename\"\n\t| \"drop_and_add\"\n\t| \"confirm_drop\"\n\t| \"migrate_to_junction\"\n\t| \"migrate_first\"\n\t| \"fresh_start\"\n\t| \"keep_column\"\n\t| \"drop_and_recreate\";\n\n/**\n * Ambiguous change that requires user input\n */\nexport interface AmbiguousChange {\n\treadonly id: string;\n\treadonly tableName: string;\n\treadonly type: AmbiguousChangeType;\n\treadonly removedName: string;\n\treadonly addedName: string;\n\treadonly removedDefinition?: FieldDefinition;\n\treadonly addedDefinition?: FieldDefinition;\n\treadonly possibleActions: readonly AmbiguousAction[];\n\treadonly warning?: string;\n\treadonly affectedRows?: number;\n\tresolved: boolean;\n\tresolvedAction?: AmbiguousAction;\n}\n\n/**\n * Possible action for ambiguous change\n */\nexport interface AmbiguousAction {\n\treadonly type: AmbiguousActionType;\n\treadonly description: string;\n}\n\n/**\n * Migration plan summary\n */\nexport interface MigrationPlan {\n\treadonly tablesToCreate: readonly SchemaDefinition[];\n\treadonly tablesToDrop: readonly string[];\n\treadonly tablesToAlter: readonly {\n\t\treadonly tableName: string;\n\t\treadonly changes: readonly SchemaDiff[];\n\t}[];\n\treadonly operations: readonly MigrationOperation[];\n\treadonly hasChanges: boolean;\n}\n\n/**\n * Migration Session class\n *\n * Created by datrix.beginMigrate()\n */\nexport class MigrationSession {\n\tprivate readonly datrix: IDatrix;\n\tprivate readonly adapter: DatabaseAdapter;\n\tprivate readonly differ: ForgeSchemaDiffer;\n\tprivate readonly generator: ForgeMigrationGenerator;\n\tprivate readonly history: ForgeMigrationHistory;\n\n\tprivate currentSchemas: Map<string, SchemaDefinition> = new Map();\n\tprivate databaseSchemas: Map<string, SchemaDefinition> = new Map();\n\tprivate differences: SchemaDiff[] = [];\n\tprivate _ambiguous: AmbiguousChange[] = [];\n\tprivate initialized = false;\n\n\tconstructor(datrix: IDatrix) {\n\t\tthis.datrix = datrix;\n\t\tthis.adapter = datrix.getAdapter();\n\t\tthis.differ = new ForgeSchemaDiffer();\n\t\tthis.generator = new ForgeMigrationGenerator();\n\n\t\tconst migrationConfig = datrix.getMigrationConfig();\n\t\tthis.history = new ForgeMigrationHistory(datrix, migrationConfig.modelName);\n\t}\n\n\t/**\n\t * Initialize session - load current state from database\n\t */\n\tasync initialize(): Promise<void> {\n\t\tif (this.initialized) {\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\t// Initialize history table\n\t\t\tawait this.history.initialize();\n\n\t\t\t// Load current schemas from Datrix\n\t\t\tconst registry = this.datrix.getSchemas();\n\t\t\tfor (const schema of registry.getAll()) {\n\t\t\t\t// Skip internal migration schema\n\t\t\t\tif (schema.name.startsWith(\"_datrix\")) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tthis.currentSchemas.set(schema.name, schema);\n\t\t\t}\n\n\t\t\t// Load existing schemas from database\n\t\t\tconst tablesResult = await this.adapter.getTables();\n\n\t\t\tfor (const tableName of tablesResult) {\n\t\t\t\t// Skip internal tables\n\t\t\t\tif (tableName.startsWith(\"_datrix\")) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst schemaResult = await this.adapter.getTableSchema(tableName);\n\t\t\t\tthis.databaseSchemas.set(tableName, schemaResult!);\n\t\t\t}\n\n\t\t\t// Compare schemas\n\t\t\tconst oldSchemas: Record<string, SchemaDefinition> = {};\n\t\t\tfor (const [name, schema] of this.databaseSchemas) {\n\t\t\t\toldSchemas[name] = schema;\n\t\t\t}\n\n\t\t\tconst newSchemas: Record<string, SchemaDefinition> = {};\n\t\t\tfor (const [name, schema] of this.currentSchemas) {\n\t\t\t\tnewSchemas[schema.tableName ?? name] = schema;\n\t\t\t}\n\n\t\t\tconst comparison = this.differ.compare(oldSchemas, newSchemas);\n\n\t\t\tthis.differences = [...comparison.differences];\n\n\t\t\t// Detect ambiguous changes\n\t\t\tthis.detectAmbiguousChanges();\n\n\t\t\tthis.initialized = true;\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthrow new MigrationSystemError(\n\t\t\t\t`Failed to initialize migration session: ${message}`,\n\t\t\t\t\"MIGRATION_ERROR\",\n\t\t\t\terror,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Detect ambiguous changes (potential renames, relation changes, etc.)\n\t */\n\tprivate detectAmbiguousChanges(): void {\n\t\t// Group diffs by type and table\n\t\tconst removedFields = new Map<string, SchemaDiff[]>();\n\t\tconst addedFields = new Map<string, SchemaDiff[]>();\n\t\tconst removedTables: SchemaDiff[] = [];\n\t\tconst addedTables: SchemaDiff[] = [];\n\n\t\tfor (const diff of this.differences) {\n\t\t\tif (diff.type === \"fieldRemoved\") {\n\t\t\t\tconst key = diff.tableName;\n\t\t\t\tif (!removedFields.has(key)) {\n\t\t\t\t\tremovedFields.set(key, []);\n\t\t\t\t}\n\t\t\t\tremovedFields.get(key)!.push(diff);\n\t\t\t} else if (diff.type === \"fieldAdded\") {\n\t\t\t\tconst key = diff.tableName;\n\t\t\t\tif (!addedFields.has(key)) {\n\t\t\t\t\taddedFields.set(key, []);\n\t\t\t\t}\n\t\t\t\taddedFields.get(key)!.push(diff);\n\t\t\t} else if (diff.type === \"tableRemoved\") {\n\t\t\t\tremovedTables.push(diff);\n\t\t\t} else if (diff.type === \"tableAdded\") {\n\t\t\t\taddedTables.push(diff);\n\t\t\t}\n\t\t}\n\n\t\t// Collect fieldModified diffs for relation-specific detection\n\t\tconst modifiedFields = new Map<string, SchemaDiff[]>();\n\t\tfor (const diff of this.differences) {\n\t\t\tif (diff.type === \"fieldModified\") {\n\t\t\t\tconst key = diff.tableName;\n\t\t\t\tif (!modifiedFields.has(key)) {\n\t\t\t\t\tmodifiedFields.set(key, []);\n\t\t\t\t}\n\t\t\t\tmodifiedFields.get(key)!.push(diff);\n\t\t\t}\n\t\t}\n\n\t\t// Track which diffs are handled by relation detection\n\t\tconst handledDiffs = new Set<string>();\n\n\t\t// 1. Detect relation type changes (belongsTo ↔ manyToMany)\n\t\tthis.detectRelationTypeChanges(\n\t\t\tremovedFields,\n\t\t\taddedFields,\n\t\t\tremovedTables,\n\t\t\taddedTables,\n\t\t\thandledDiffs,\n\t\t);\n\n\t\t// 2. Detect junction table renames (through name change) - must run before drops\n\t\tthis.detectJunctionTableRenames(removedTables, addedTables, handledDiffs);\n\n\t\t// 3. Detect junction table drops (manyToMany removal)\n\t\tthis.detectJunctionTableDrops(removedTables, handledDiffs);\n\n\t\t// 4. Detect relation direction flips (FK moves from one table to another) - before FK drop detection\n\t\tthis.detectRelationDirectionFlips(removedFields, addedFields, handledDiffs);\n\n\t\t// 5. Detect FK column changes (rename or drop)\n\t\tthis.detectFkColumnChanges(removedFields, addedFields, handledDiffs);\n\n\t\t// 6. Detect column renames (generic, non-FK columns)\n\t\tthis.detectColumnRenames(removedFields, addedFields, handledDiffs);\n\n\t\t// 7. Detect table renames\n\t\tthis.detectTableRenames(removedTables, addedTables, handledDiffs);\n\n\t\t// 8. Detect FK model changes (belongsTo pointing to different model)\n\t\tthis.detectFkModelChanges(modifiedFields, handledDiffs);\n\t}\n\n\t/**\n\t * Detect relation type changes (belongsTo ↔ manyToMany)\n\t */\n\tprivate detectRelationTypeChanges(\n\t\tremovedFields: Map<string, SchemaDiff[]>,\n\t\taddedFields: Map<string, SchemaDiff[]>,\n\t\tremovedTables: SchemaDiff[],\n\t\taddedTables: SchemaDiff[],\n\t\thandledDiffs: Set<string>,\n\t): void {\n\t\t// belongsTo → manyToMany: FK column removed + junction table added\n\t\tfor (const [tableName, removed] of removedFields) {\n\t\t\tfor (const removedDiff of removed) {\n\t\t\t\tif (removedDiff.type !== \"fieldRemoved\") continue;\n\n\t\t\t\t// Check if this looks like a FK column (ends with 'Id')\n\t\t\t\tif (!removedDiff.fieldName.endsWith(\"Id\")) continue;\n\n\t\t\t\tconst relationName = removedDiff.fieldName.slice(0, -2); // remove 'Id'\n\n\t\t\t\t// Look for a new junction table that involves this table\n\t\t\t\tfor (const addedTable of addedTables) {\n\t\t\t\t\tif (addedTable.type !== \"tableAdded\") continue;\n\n\t\t\t\t\tconst junctionName =\n\t\t\t\t\t\taddedTable.schema.tableName ?? addedTable.schema.name;\n\n\t\t\t\t\t// Check if junction table name contains both table names\n\t\t\t\t\tif (this.isJunctionTableFor(junctionName, tableName, relationName)) {\n\t\t\t\t\t\tconst diffKey = `${tableName}.${removedDiff.fieldName}`;\n\t\t\t\t\t\thandledDiffs.add(diffKey);\n\t\t\t\t\t\thandledDiffs.add(`table:${junctionName}`);\n\n\t\t\t\t\t\tthis._ambiguous.push({\n\t\t\t\t\t\t\tid: `relation_upgrade:${tableName}.${relationName}`,\n\t\t\t\t\t\t\ttableName,\n\t\t\t\t\t\t\ttype: \"relation_upgrade_single_to_many\",\n\t\t\t\t\t\t\tremovedName: removedDiff.fieldName,\n\t\t\t\t\t\t\taddedName: junctionName,\n\t\t\t\t\t\t\twarning:\n\t\t\t\t\t\t\t\t\"Existing single relations can be migrated to junction table.\",\n\t\t\t\t\t\t\tpossibleActions: [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\ttype: \"migrate_to_junction\",\n\t\t\t\t\t\t\t\t\tdescription: `Migrate existing ${removedDiff.fieldName} values to junction table '${junctionName}' (preserves data)`,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\ttype: \"fresh_start\",\n\t\t\t\t\t\t\t\t\tdescription: `Drop '${removedDiff.fieldName}' and create empty junction table (data loss)`,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\tresolved: false,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// manyToMany → belongsTo: junction table removed + FK column added\n\t\tfor (const removedTable of removedTables) {\n\t\t\tif (removedTable.type !== \"tableRemoved\") continue;\n\n\t\t\tconst junctionName = removedTable.tableName;\n\n\t\t\t// Check if this looks like a junction table\n\t\t\tif (!this.looksLikeJunctionTable(junctionName)) continue;\n\t\t\tif (handledDiffs.has(`table:${junctionName}`)) continue;\n\n\t\t\t// Look for a new FK column on one of the related tables\n\t\t\tfor (const [tableName, added] of addedFields) {\n\t\t\t\tfor (const addedDiff of added) {\n\t\t\t\t\tif (addedDiff.type !== \"fieldAdded\") continue;\n\n\t\t\t\t\t// Resolve relation name and FK column name\n\t\t\t\t\tlet relationName: string;\n\t\t\t\t\tlet fkColumnName: string;\n\n\t\t\t\t\tif (\n\t\t\t\t\t\taddedDiff.definition.type === \"relation\" &&\n\t\t\t\t\t\taddedDiff.definition.kind === \"belongsTo\"\n\t\t\t\t\t) {\n\t\t\t\t\t\t// Relation field: derive FK column from definition\n\t\t\t\t\t\trelationName = addedDiff.definition.model;\n\t\t\t\t\t\tfkColumnName =\n\t\t\t\t\t\t\taddedDiff.definition.foreignKey ??\n\t\t\t\t\t\t\t`${addedDiff.definition.model}Id`;\n\t\t\t\t\t} else if (addedDiff.fieldName.endsWith(\"Id\")) {\n\t\t\t\t\t\t// Plain FK column (e.g. \"tagId\")\n\t\t\t\t\t\trelationName = addedDiff.fieldName.slice(0, -2);\n\t\t\t\t\t\tfkColumnName = addedDiff.fieldName;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Check if junction table relates these\n\t\t\t\t\tif (this.isJunctionTableFor(junctionName, tableName, relationName)) {\n\t\t\t\t\t\tconst diffKey = `table:${junctionName}`;\n\t\t\t\t\t\tif (handledDiffs.has(diffKey)) continue;\n\t\t\t\t\t\thandledDiffs.add(diffKey);\n\t\t\t\t\t\thandledDiffs.add(`${tableName}.${addedDiff.fieldName}`);\n\n\t\t\t\t\t\t// Mark removed manyToMany relation fields as handled (no DB column)\n\t\t\t\t\t\tconst removedForTable = removedFields.get(tableName) ?? [];\n\t\t\t\t\t\tfor (const removedDiff of removedForTable) {\n\t\t\t\t\t\t\tif (removedDiff.type !== \"fieldRemoved\") continue;\n\t\t\t\t\t\t\thandledDiffs.add(`${tableName}.${removedDiff.fieldName}`);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Remove manyToMany field diffs from differences (no DB column to drop)\n\t\t\t\t\t\tthis.differences = this.differences.filter(\n\t\t\t\t\t\t\t(d) =>\n\t\t\t\t\t\t\t\t!(\n\t\t\t\t\t\t\t\t\td.type === \"fieldRemoved\" &&\n\t\t\t\t\t\t\t\t\td.tableName === tableName &&\n\t\t\t\t\t\t\t\t\t!d.fieldName.endsWith(\"Id\")\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tthis._ambiguous.push({\n\t\t\t\t\t\t\tid: `relation_downgrade:${tableName}.${relationName}`,\n\t\t\t\t\t\t\ttableName,\n\t\t\t\t\t\t\ttype: \"relation_downgrade_many_to_single\",\n\t\t\t\t\t\t\tremovedName: junctionName,\n\t\t\t\t\t\t\taddedName: fkColumnName,\n\t\t\t\t\t\t\twarning:\n\t\t\t\t\t\t\t\t\"Records with multiple relations will lose data! Only first relation will be kept.\",\n\t\t\t\t\t\t\tpossibleActions: [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\ttype: \"migrate_first\",\n\t\t\t\t\t\t\t\t\tdescription: `Migrate first relation from '${junctionName}' to '${fkColumnName}' (partial data loss)`,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\ttype: \"fresh_start\",\n\t\t\t\t\t\t\t\t\tdescription: `Drop junction table and create empty '${fkColumnName}' column (full data loss)`,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\tresolved: false,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Detect junction table drops (manyToMany relation removed)\n\t */\n\tprivate detectJunctionTableDrops(\n\t\tremovedTables: SchemaDiff[],\n\t\thandledDiffs: Set<string>,\n\t): void {\n\t\tfor (const removedTable of removedTables) {\n\t\t\tif (removedTable.type !== \"tableRemoved\") continue;\n\n\t\t\tconst tableName = removedTable.tableName;\n\t\t\tconst diffKey = `table:${tableName}`;\n\n\t\t\t// Skip if already handled by relation type change detection\n\t\t\tif (handledDiffs.has(diffKey)) continue;\n\n\t\t\t// Check if this looks like a junction table\n\t\t\tif (this.looksLikeJunctionTable(tableName)) {\n\t\t\t\thandledDiffs.add(diffKey);\n\n\t\t\t\tthis._ambiguous.push({\n\t\t\t\t\tid: `junction_drop:${tableName}`,\n\t\t\t\t\ttableName,\n\t\t\t\t\ttype: \"junction_table_drop\",\n\t\t\t\t\tremovedName: tableName,\n\t\t\t\t\taddedName: \"\",\n\t\t\t\t\twarning: \"All relations in this junction table will be lost.\",\n\t\t\t\t\tpossibleActions: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"confirm_drop\",\n\t\t\t\t\t\t\tdescription: `Confirm dropping junction table '${tableName}' (data loss)`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tresolved: false,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Detect junction table renames (through name change)\n\t */\n\tprivate detectJunctionTableRenames(\n\t\tremovedTables: SchemaDiff[],\n\t\taddedTables: SchemaDiff[],\n\t\thandledDiffs: Set<string>,\n\t): void {\n\t\tfor (const removedTable of removedTables) {\n\t\t\tif (removedTable.type !== \"tableRemoved\") continue;\n\n\t\t\tconst oldName = removedTable.tableName;\n\t\t\tconst oldDiffKey = `table:${oldName}`;\n\n\t\t\tif (handledDiffs.has(oldDiffKey)) continue;\n\t\t\tif (!this.looksLikeJunctionTable(oldName)) continue;\n\n\t\t\tfor (const addedTable of addedTables) {\n\t\t\t\tif (addedTable.type !== \"tableAdded\") continue;\n\n\t\t\t\tconst newName = addedTable.schema.tableName ?? addedTable.schema.name;\n\t\t\t\tconst newDiffKey = `table:${newName}`;\n\n\t\t\t\tif (handledDiffs.has(newDiffKey)) continue;\n\t\t\t\tif (!this.looksLikeJunctionTable(newName)) continue;\n\n\t\t\t\t// Check if they have similar structure (both junction tables for same models)\n\t\t\t\tif (this.couldBeJunctionRename(oldName, newName)) {\n\t\t\t\t\thandledDiffs.add(oldDiffKey);\n\t\t\t\t\thandledDiffs.add(newDiffKey);\n\n\t\t\t\t\tthis._ambiguous.push({\n\t\t\t\t\t\tid: `junction_rename:${oldName}->${newName}`,\n\t\t\t\t\t\ttableName: oldName,\n\t\t\t\t\t\ttype: \"junction_table_rename_or_replace\",\n\t\t\t\t\t\tremovedName: oldName,\n\t\t\t\t\t\taddedName: newName,\n\t\t\t\t\t\twarning:\n\t\t\t\t\t\t\t\"Renaming junction tables may cause issues if referenced elsewhere.\",\n\t\t\t\t\t\tpossibleActions: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ttype: \"rename\",\n\t\t\t\t\t\t\t\tdescription: `Rename junction table '${oldName}' to '${newName}' (preserves data)`,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ttype: \"drop_and_recreate\",\n\t\t\t\t\t\t\t\tdescription: `Drop '${oldName}' and create '${newName}' (data loss)`,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t\tresolved: false,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Detect FK column changes (rename or drop)\n\t *\n\t * Handles:\n\t * - FK rename: authorId removed + writerId added → column_rename_or_replace\n\t * - FK drop: authorId removed + no new FK added → fk_column_drop\n\t */\n\tprivate detectFkColumnChanges(\n\t\tremovedFields: Map<string, SchemaDiff[]>,\n\t\taddedFields: Map<string, SchemaDiff[]>,\n\t\thandledDiffs: Set<string>,\n\t): void {\n\t\tfor (const [tableName, removed] of removedFields) {\n\t\t\tconst added = addedFields.get(tableName) ?? [];\n\n\t\t\t// Get all added FK columns in this table (not yet handled)\n\t\t\tconst addedFkColumns = added.filter(\n\t\t\t\t(d): d is FieldAddedDiff =>\n\t\t\t\t\td.type === \"fieldAdded\" &&\n\t\t\t\t\td.fieldName.endsWith(\"Id\") &&\n\t\t\t\t\t!handledDiffs.has(`${tableName}.${d.fieldName}`),\n\t\t\t);\n\n\t\t\tfor (const removedDiff of removed) {\n\t\t\t\tif (removedDiff.type !== \"fieldRemoved\") continue;\n\t\t\t\tif (!removedDiff.fieldName.endsWith(\"Id\")) continue;\n\n\t\t\t\tconst removedKey = `${tableName}.${removedDiff.fieldName}`;\n\t\t\t\tif (handledDiffs.has(removedKey)) continue;\n\n\t\t\t\t// Check if there's a new FK column added - could be a rename\n\t\t\t\tif (addedFkColumns.length > 0) {\n\t\t\t\t\t// Find the first unhandled added FK column\n\t\t\t\t\tconst addedDiff = addedFkColumns.find(\n\t\t\t\t\t\t(d) => !handledDiffs.has(`${tableName}.${d.fieldName}`),\n\t\t\t\t\t);\n\n\t\t\t\t\tif (addedDiff && addedDiff.type === \"fieldAdded\") {\n\t\t\t\t\t\tconst addedKey = `${tableName}.${addedDiff.fieldName}`;\n\n\t\t\t\t\t\thandledDiffs.add(removedKey);\n\t\t\t\t\t\thandledDiffs.add(addedKey);\n\n\t\t\t\t\t\tthis._ambiguous.push({\n\t\t\t\t\t\t\tid: `${tableName}.${removedDiff.fieldName}->${addedDiff.fieldName}`,\n\t\t\t\t\t\t\ttableName,\n\t\t\t\t\t\t\ttype: \"column_rename_or_replace\",\n\t\t\t\t\t\t\tremovedName: removedDiff.fieldName,\n\t\t\t\t\t\t\taddedName: addedDiff.fieldName,\n\t\t\t\t\t\t\taddedDefinition: addedDiff.definition,\n\t\t\t\t\t\t\tpossibleActions: [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\ttype: \"rename\",\n\t\t\t\t\t\t\t\t\tdescription: `Rename column '${removedDiff.fieldName}' to '${addedDiff.fieldName}' (preserves data)`,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\ttype: \"drop_and_add\",\n\t\t\t\t\t\t\t\t\tdescription: `Drop '${removedDiff.fieldName}' and add '${addedDiff.fieldName}' (data loss)`,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\tresolved: false,\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// No matching added FK column - this is a pure FK drop\n\t\t\t\thandledDiffs.add(removedKey);\n\n\t\t\t\tthis._ambiguous.push({\n\t\t\t\t\tid: `fk_drop:${tableName}.${removedDiff.fieldName}`,\n\t\t\t\t\ttableName,\n\t\t\t\t\ttype: \"fk_column_drop\",\n\t\t\t\t\tremovedName: removedDiff.fieldName,\n\t\t\t\t\taddedName: \"\",\n\t\t\t\t\twarning: \"All foreign key references will be lost.\",\n\t\t\t\t\tpossibleActions: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"confirm_drop\",\n\t\t\t\t\t\t\tdescription: `Confirm dropping FK column '${removedDiff.fieldName}' from '${tableName}' (data loss)`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tresolved: false,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Detect potential column renames\n\t */\n\tprivate detectColumnRenames(\n\t\tremovedFields: Map<string, SchemaDiff[]>,\n\t\taddedFields: Map<string, SchemaDiff[]>,\n\t\thandledDiffs: Set<string>,\n\t): void {\n\t\tfor (const [tableName, removed] of removedFields) {\n\t\t\tconst added = addedFields.get(tableName);\n\t\t\tif (!added) continue;\n\n\t\t\tfor (const removedDiff of removed) {\n\t\t\t\tif (removedDiff.type !== \"fieldRemoved\") continue;\n\n\t\t\t\tconst removedKey = `${tableName}.${removedDiff.fieldName}`;\n\t\t\t\tif (handledDiffs.has(removedKey)) continue;\n\n\t\t\t\tfor (const addedDiff of added) {\n\t\t\t\t\tif (addedDiff.type !== \"fieldAdded\") continue;\n\n\t\t\t\t\tconst addedKey = `${tableName}.${addedDiff.fieldName}`;\n\t\t\t\t\tif (handledDiffs.has(addedKey)) continue;\n\n\t\t\t\t\t// Check if could be rename\n\t\t\t\t\tif (this.couldBeRename(undefined, addedDiff.definition)) {\n\t\t\t\t\t\thandledDiffs.add(removedKey);\n\t\t\t\t\t\thandledDiffs.add(addedKey);\n\n\t\t\t\t\t\tthis._ambiguous.push({\n\t\t\t\t\t\t\tid: `${tableName}.${removedDiff.fieldName}->${addedDiff.fieldName}`,\n\t\t\t\t\t\t\ttableName,\n\t\t\t\t\t\t\ttype: \"column_rename_or_replace\",\n\t\t\t\t\t\t\tremovedName: removedDiff.fieldName,\n\t\t\t\t\t\t\taddedName: addedDiff.fieldName,\n\t\t\t\t\t\t\taddedDefinition: addedDiff.definition,\n\t\t\t\t\t\t\tpossibleActions: [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\ttype: \"rename\",\n\t\t\t\t\t\t\t\t\tdescription: `Rename column '${removedDiff.fieldName}' to '${addedDiff.fieldName}' (preserves data)`,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\ttype: \"drop_and_add\",\n\t\t\t\t\t\t\t\t\tdescription: `Drop '${removedDiff.fieldName}' and add '${addedDiff.fieldName}' (data loss)`,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\tresolved: false,\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\t// Only match one pair per removed field\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Detect potential table renames\n\t */\n\tprivate detectTableRenames(\n\t\tremovedTables: SchemaDiff[],\n\t\taddedTables: SchemaDiff[],\n\t\thandledDiffs: Set<string>,\n\t): void {\n\t\tfor (const removedDiff of removedTables) {\n\t\t\tif (removedDiff.type !== \"tableRemoved\") continue;\n\n\t\t\tconst removedKey = `table:${removedDiff.tableName}`;\n\t\t\tif (handledDiffs.has(removedKey)) continue;\n\n\t\t\tfor (const addedDiff of addedTables) {\n\t\t\t\tif (addedDiff.type !== \"tableAdded\") continue;\n\n\t\t\t\tconst addedKey = `table:${addedDiff.schema.tableName ?? addedDiff.schema.name}`;\n\t\t\t\tif (handledDiffs.has(addedKey)) continue;\n\n\t\t\t\tif (this.couldBeTableRename(removedDiff.tableName, addedDiff.schema)) {\n\t\t\t\t\thandledDiffs.add(removedKey);\n\t\t\t\t\thandledDiffs.add(addedKey);\n\n\t\t\t\t\tthis._ambiguous.push({\n\t\t\t\t\t\tid: `table:${removedDiff.tableName}->${addedDiff.schema.name}`,\n\t\t\t\t\t\ttableName: removedDiff.tableName,\n\t\t\t\t\t\ttype: \"table_rename_or_replace\",\n\t\t\t\t\t\tremovedName: removedDiff.tableName,\n\t\t\t\t\t\taddedName: addedDiff.schema.name,\n\t\t\t\t\t\tpossibleActions: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ttype: \"rename\",\n\t\t\t\t\t\t\t\tdescription: `Rename table '${removedDiff.tableName}' to '${addedDiff.schema.name}' (preserves data)`,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ttype: \"drop_and_add\",\n\t\t\t\t\t\t\t\tdescription: `Drop '${removedDiff.tableName}' and create '${addedDiff.schema.name}' (data loss)`,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t\tresolved: false,\n\t\t\t\t\t});\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Detect FK model changes (belongsTo pointing to a different model).\n\t * The FK column name stays the same but the referenced model changes.\n\t */\n\tprivate detectFkModelChanges(\n\t\tmodifiedFields: Map<string, SchemaDiff[]>,\n\t\thandledDiffs: Set<string>,\n\t): void {\n\t\tfor (const [tableName, modified] of modifiedFields) {\n\t\t\tfor (const diff of modified) {\n\t\t\t\tif (diff.type !== \"fieldModified\") continue;\n\n\t\t\t\tconst oldDef = diff.oldDefinition;\n\t\t\t\tconst newDef = diff.newDefinition;\n\n\t\t\t\tif (oldDef.type !== \"relation\" || newDef.type !== \"relation\") continue;\n\t\t\t\tif (oldDef.kind !== \"belongsTo\" || newDef.kind !== \"belongsTo\")\n\t\t\t\t\tcontinue;\n\t\t\t\tif (oldDef.model === newDef.model) continue;\n\n\t\t\t\tconst diffKey = `${tableName}.${diff.fieldName}`;\n\t\t\t\tif (handledDiffs.has(diffKey)) continue;\n\t\t\t\thandledDiffs.add(diffKey);\n\n\t\t\t\tconst fkColumn = newDef.foreignKey ?? `${newDef.model}Id`;\n\n\t\t\t\tthis._ambiguous.push({\n\t\t\t\t\tid: `fk_model_change:${tableName}.${diff.fieldName}`,\n\t\t\t\t\ttableName,\n\t\t\t\t\ttype: \"fk_model_change\",\n\t\t\t\t\tremovedName: oldDef.model,\n\t\t\t\t\taddedName: newDef.model,\n\t\t\t\t\twarning: `Existing data in '${fkColumn}' will reference '${newDef.model}' instead of '${oldDef.model}'. Ensure data integrity before migrating.`,\n\t\t\t\t\tpossibleActions: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"keep_column\",\n\t\t\t\t\t\t\tdescription: `Keep column '${fkColumn}' as-is and change the referenced model (data may be inconsistent)`,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"drop_and_recreate\",\n\t\t\t\t\t\t\tdescription: `Drop '${fkColumn}' and recreate it (data loss)`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tresolved: false,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Detect relation direction flips.\n\t * A hasOne/hasMany FK is removed from one table and an equivalent FK\n\t * is added to another table — the relation ownership is flipping sides.\n\t *\n\t * Pattern: fieldRemoved (FK column on tableA) + fieldAdded (FK column on tableB)\n\t * where both columns represent the same logical relation but point in\n\t * opposite directions.\n\t */\n\tprivate detectRelationDirectionFlips(\n\t\tremovedFields: Map<string, SchemaDiff[]>,\n\t\taddedFields: Map<string, SchemaDiff[]>,\n\t\thandledDiffs: Set<string>,\n\t): void {\n\t\tfor (const [removedTable, removed] of removedFields) {\n\t\t\tfor (const removedDiff of removed) {\n\t\t\t\tif (removedDiff.type !== \"fieldRemoved\") continue;\n\t\t\t\tif (!removedDiff.fieldName.endsWith(\"Id\")) continue;\n\n\t\t\t\tconst removedKey = `${removedTable}.${removedDiff.fieldName}`;\n\t\t\t\tif (handledDiffs.has(removedKey)) continue;\n\n\t\t\t\t// Look for a new FK column on a different table\n\t\t\t\tfor (const [addedTable, added] of addedFields) {\n\t\t\t\t\tif (addedTable === removedTable) continue;\n\n\t\t\t\t\tfor (const addedDiff of added) {\n\t\t\t\t\t\tif (addedDiff.type !== \"fieldAdded\") continue;\n\t\t\t\t\t\tif (!addedDiff.fieldName.endsWith(\"Id\")) continue;\n\n\t\t\t\t\t\tconst addedKey = `${addedTable}.${addedDiff.fieldName}`;\n\t\t\t\t\t\tif (handledDiffs.has(addedKey)) continue;\n\n\t\t\t\t\t\t// Check if these two FK columns are related to the same models\n\t\t\t\t\t\t// removedTable has a FK pointing to some model (ends with Id)\n\t\t\t\t\t\t// addedTable has a new FK pointing to some model\n\t\t\t\t\t\t// They're a direction flip if one points to the other's table\n\t\t\t\t\t\tconst removedModelHint = removedDiff.fieldName.slice(0, -2);\n\t\t\t\t\t\tconst addedModelHint = addedDiff.fieldName.slice(0, -2);\n\n\t\t\t\t\t\tconst removedTableBase = this.singularize(removedTable);\n\t\t\t\t\t\tconst addedTableBase = this.singularize(addedTable);\n\n\t\t\t\t\t\tconst isFlip =\n\t\t\t\t\t\t\tremovedModelHint === addedTableBase ||\n\t\t\t\t\t\t\taddedModelHint === removedTableBase;\n\n\t\t\t\t\t\tif (isFlip) {\n\t\t\t\t\t\t\thandledDiffs.add(removedKey);\n\t\t\t\t\t\t\thandledDiffs.add(addedKey);\n\n\t\t\t\t\t\t\tthis._ambiguous.push({\n\t\t\t\t\t\t\t\tid: `direction_flip:${removedTable}.${removedDiff.fieldName}->${addedTable}.${addedDiff.fieldName}`,\n\t\t\t\t\t\t\t\ttableName: removedTable,\n\t\t\t\t\t\t\t\ttype: \"relation_direction_flip\",\n\t\t\t\t\t\t\t\tremovedName: `${removedTable}.${removedDiff.fieldName}`,\n\t\t\t\t\t\t\t\taddedName: `${addedTable}.${addedDiff.fieldName}`,\n\t\t\t\t\t\t\t\twarning: `Relation direction is changing. '${removedDiff.fieldName}' on '${removedTable}' will be replaced by '${addedDiff.fieldName}' on '${addedTable}'. Existing relation data will be lost.`,\n\t\t\t\t\t\t\t\tpossibleActions: [\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\ttype: \"drop_and_recreate\",\n\t\t\t\t\t\t\t\t\t\tdescription: `Drop '${removedDiff.fieldName}' from '${removedTable}' and add '${addedDiff.fieldName}' to '${addedTable}' (data loss)`,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\tresolved: false,\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Check if table name looks like a junction table\n\t */\n\tprivate looksLikeJunctionTable(tableName: string): boolean {\n\t\t// Junction tables typically have underscore: post_tag, category_post, etc.\n\t\treturn tableName.includes(\"_\") && !tableName.startsWith(\"_\");\n\t}\n\n\t/**\n\t * Check if junction table is for given table and relation\n\t */\n\tprivate isJunctionTableFor(\n\t\tjunctionName: string,\n\t\ttableName: string,\n\t\trelationName: string,\n\t): boolean {\n\t\tconst parts = junctionName.split(\"_\");\n\t\tif (parts.length !== 2) return false;\n\n\t\t// Junction table should contain both model names (singular form)\n\t\tconst singularTable = this.singularize(tableName);\n\t\tconst singularRelation = relationName.toLowerCase();\n\n\t\tconst containsTable = parts.some(\n\t\t\t(p) => p === singularTable || p === tableName.toLowerCase(),\n\t\t);\n\t\tconst containsRelation = parts.some(\n\t\t\t(p) => p === singularRelation || p === this.pluralize(singularRelation),\n\t\t);\n\n\t\treturn containsTable && containsRelation;\n\t}\n\n\t/**\n\t * Check if two junction tables could be a rename\n\t */\n\tprivate couldBeJunctionRename(oldName: string, newName: string): boolean {\n\t\tconst oldParts = new Set(oldName.split(\"_\"));\n\t\tconst newParts = new Set(newName.split(\"_\"));\n\n\t\t// At least one part should be common\n\t\tlet commonParts = 0;\n\t\tfor (const part of oldParts) {\n\t\t\tif (newParts.has(part)) commonParts++;\n\t\t}\n\n\t\treturn commonParts >= 1;\n\t}\n\n\t/**\n\t * Simple singularize helper\n\t */\n\tprivate singularize(word: string): string {\n\t\tif (word.endsWith(\"ies\")) {\n\t\t\treturn word.slice(0, -3) + \"y\";\n\t\t}\n\t\tif (word.endsWith(\"es\")) {\n\t\t\treturn word.slice(0, -2);\n\t\t}\n\t\tif (word.endsWith(\"s\") && !word.endsWith(\"ss\")) {\n\t\t\treturn word.slice(0, -1);\n\t\t}\n\t\treturn word;\n\t}\n\n\t/**\n\t * Simple pluralize helper\n\t */\n\tprivate pluralize(word: string): string {\n\t\tif (word.endsWith(\"y\")) {\n\t\t\treturn word.slice(0, -1) + \"ies\";\n\t\t}\n\t\tif (\n\t\t\tword.endsWith(\"s\") ||\n\t\t\tword.endsWith(\"x\") ||\n\t\t\tword.endsWith(\"ch\") ||\n\t\t\tword.endsWith(\"sh\")\n\t\t) {\n\t\t\treturn word + \"es\";\n\t\t}\n\t\treturn word + \"s\";\n\t}\n\n\t/**\n\t * Check if field change could be a rename\n\t */\n\tprivate couldBeRename(\n\t\t_oldDef: FieldDefinition | undefined,\n\t\t_newDef: FieldDefinition,\n\t): boolean {\n\t\t// Simple heuristic: if types match, could be rename\n\t\t// In real implementation, check more properties\n\t\treturn true; // For now, always offer rename option\n\t}\n\n\t/**\n\t * Check if table change could be a rename\n\t *\n\t * Excludes common system fields (id, createdAt, updatedAt) from comparison\n\t * to focus on user-defined fields only.\n\t */\n\tprivate couldBeTableRename(\n\t\toldTableName: string,\n\t\tnewSchema: SchemaDefinition,\n\t): boolean {\n\t\tconst oldSchema = this.databaseSchemas.get(oldTableName);\n\t\tif (!oldSchema) return false;\n\n\t\t// Exclude system fields from comparison\n\t\tconst systemFields = new Set([\"id\", \"createdAt\", \"updatedAt\"]);\n\n\t\tconst oldFields = new Set(\n\t\t\tObject.keys(oldSchema.fields).filter((f) => !systemFields.has(f)),\n\t\t);\n\t\tconst newFields = new Set(\n\t\t\tObject.keys(newSchema.fields).filter((f) => !systemFields.has(f)),\n\t\t);\n\n\t\t// Need at least 1 user-defined field to compare\n\t\tif (oldFields.size === 0 || newFields.size === 0) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Count common fields\n\t\tlet commonFields = 0;\n\t\tfor (const field of oldFields) {\n\t\t\tif (newFields.has(field)) {\n\t\t\t\tcommonFields++;\n\t\t\t}\n\t\t}\n\n\t\t// Need at least 70% of fields to match by name (stricter threshold)\n\t\tconst totalUniqueFields = new Set([...oldFields, ...newFields]).size;\n\t\tconst fieldNameSimilarity = commonFields / totalUniqueFields;\n\n\t\tif (fieldNameSimilarity < 0.7) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Also check field count similarity\n\t\tconst countSimilarity =\n\t\t\tMath.min(oldFields.size, newFields.size) /\n\t\t\tMath.max(oldFields.size, newFields.size);\n\n\t\treturn countSimilarity > 0.7;\n\t}\n\n\t/**\n\t * Get tables to create\n\t */\n\tget tablesToCreate(): readonly SchemaDefinition[] {\n\t\treturn this.differences\n\t\t\t.filter((d) => d.type === \"tableAdded\")\n\t\t\t.map(\n\t\t\t\t(d) => (d as { type: \"tableAdded\"; schema: SchemaDefinition }).schema,\n\t\t\t);\n\t}\n\n\t/**\n\t * Get tables to drop\n\t */\n\tget tablesToDrop(): readonly string[] {\n\t\treturn this.differences\n\t\t\t.filter((d) => d.type === \"tableRemoved\")\n\t\t\t.map((d) => (d as { type: \"tableRemoved\"; tableName: string }).tableName);\n\t}\n\n\t/**\n\t * Get tables to alter\n\t */\n\tget tablesToAlter(): readonly {\n\t\ttableName: string;\n\t\tchanges: readonly SchemaDiff[];\n\t}[] {\n\t\tconst alterations = new Map<string, SchemaDiff[]>();\n\n\t\tfor (const diff of this.differences) {\n\t\t\tif (\n\t\t\t\tdiff.type === \"fieldAdded\" ||\n\t\t\t\tdiff.type === \"fieldRemoved\" ||\n\t\t\t\tdiff.type === \"fieldModified\" ||\n\t\t\t\tdiff.type === \"indexAdded\" ||\n\t\t\t\tdiff.type === \"indexRemoved\"\n\t\t\t) {\n\t\t\t\tconst tableName = diff.tableName;\n\t\t\t\tif (!alterations.has(tableName)) {\n\t\t\t\t\talterations.set(tableName, []);\n\t\t\t\t}\n\t\t\t\talterations.get(tableName)!.push(diff);\n\t\t\t}\n\t\t}\n\n\t\treturn Array.from(alterations.entries()).map(([tableName, changes]) => ({\n\t\t\ttableName,\n\t\t\tchanges,\n\t\t}));\n\t}\n\n\t/**\n\t * Get ambiguous changes that need resolution\n\t */\n\tget ambiguous(): readonly AmbiguousChange[] {\n\t\treturn this._ambiguous.filter((a) => !a.resolved);\n\t}\n\n\t/**\n\t * Check if there are unresolved ambiguous changes\n\t */\n\thasUnresolvedAmbiguous(): boolean {\n\t\treturn this._ambiguous.some((a) => !a.resolved);\n\t}\n\n\t/**\n\t * Resolve an ambiguous change\n\t */\n\tresolveAmbiguous(id: string, action: AmbiguousActionType): void {\n\t\tconst ambiguous = this._ambiguous.find((a) => a.id === id);\n\t\tif (!ambiguous) {\n\t\t\tthrow new MigrationSystemError(\n\t\t\t\t`Ambiguous change '${id}' not found`,\n\t\t\t\t\"MIGRATION_ERROR\",\n\t\t\t);\n\t\t}\n\n\t\tconst selectedAction = ambiguous.possibleActions.find(\n\t\t\t(a) => a.type === action,\n\t\t);\n\t\tif (!selectedAction) {\n\t\t\tthrow new MigrationSystemError(\n\t\t\t\t`Invalid action '${action}' for ambiguous change '${id}'`,\n\t\t\t\t\"MIGRATION_ERROR\",\n\t\t\t);\n\t\t}\n\n\t\tambiguous.resolved = true;\n\t\tambiguous.resolvedAction = selectedAction;\n\n\t\t// Update differences based on resolution\n\t\tthis.applyResolution(ambiguous, action);\n\t}\n\n\t/**\n\t * Apply resolution - update differences based on chosen action\n\t */\n\tprivate applyResolution(\n\t\tambiguous: AmbiguousChange,\n\t\taction: AmbiguousActionType,\n\t): void {\n\t\tswitch (ambiguous.type) {\n\t\t\tcase \"column_rename_or_replace\":\n\t\t\t\tif (action === \"rename\") {\n\t\t\t\t\tthis.applyColumnRename(ambiguous);\n\t\t\t\t}\n\t\t\t\t// drop_and_add: keep original diffs\n\t\t\t\tbreak;\n\n\t\t\tcase \"table_rename_or_replace\":\n\t\t\t\tif (action === \"rename\") {\n\t\t\t\t\tthis.applyTableRename(ambiguous);\n\t\t\t\t}\n\t\t\t\t// drop_and_add: keep original diffs\n\t\t\t\tbreak;\n\n\t\t\tcase \"junction_table_rename_or_replace\":\n\t\t\t\tif (action === \"rename\") {\n\t\t\t\t\tthis.applyTableRename(ambiguous);\n\t\t\t\t}\n\t\t\t\t// drop_and_recreate: keep original diffs\n\t\t\t\tbreak;\n\n\t\t\tcase \"fk_column_drop\":\n\t\t\tcase \"junction_table_drop\":\n\t\t\t\t// confirm_drop: keep original diffs (just confirming)\n\t\t\t\tbreak;\n\n\t\t\tcase \"relation_upgrade_single_to_many\":\n\t\t\t\tif (action === \"migrate_to_junction\") {\n\t\t\t\t\t// TODO: Add data migration operation\n\t\t\t\t\t// For now, keep original diffs but mark for data migration\n\t\t\t\t}\n\t\t\t\t// fresh_start: keep original diffs (no data migration)\n\t\t\t\tbreak;\n\n\t\t\tcase \"relation_downgrade_many_to_single\":\n\t\t\t\t// Diffs (addColumn FK + dropTable junction) are kept for operation generation.\n\t\t\t\t// Data transfer is injected by injectDataTransferOperations.\n\t\t\t\tbreak;\n\n\t\t\tcase \"fk_model_change\":\n\t\t\t\t// Both keep_column and drop_and_recreate: keep original diffs for now\n\t\t\t\tbreak;\n\n\t\t\tcase \"relation_direction_flip\":\n\t\t\t\t// drop_both_and_recreate: keep original diffs\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\t/**\n\t * Apply column rename - replace drop+add with rename\n\t */\n\tprivate applyColumnRename(ambiguous: AmbiguousChange): void {\n\t\t// Remove the fieldRemoved, fieldAdded, and related fieldModified diffs\n\t\tthis.differences = this.differences.filter((d) => {\n\t\t\tif (\n\t\t\t\td.type === \"fieldRemoved\" &&\n\t\t\t\td.tableName === ambiguous.tableName &&\n\t\t\t\td.fieldName === ambiguous.removedName\n\t\t\t) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (\n\t\t\t\td.type === \"fieldAdded\" &&\n\t\t\t\td.tableName === ambiguous.tableName &&\n\t\t\t\td.fieldName === ambiguous.addedName\n\t\t\t) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t// Remove relation fieldModified that references the same FK rename\n\t\t\tif (\n\t\t\t\td.type === \"fieldModified\" &&\n\t\t\t\td.tableName === ambiguous.tableName &&\n\t\t\t\td.oldDefinition.type === \"relation\" &&\n\t\t\t\td.newDefinition.type === \"relation\"\n\t\t\t) {\n\t\t\t\tconst oldFK =\n\t\t\t\t\td.oldDefinition.foreignKey ?? `${d.oldDefinition.model}Id`;\n\t\t\t\tconst newFK =\n\t\t\t\t\td.newDefinition.foreignKey ?? `${d.newDefinition.model}Id`;\n\t\t\t\tif (oldFK === ambiguous.removedName && newFK === ambiguous.addedName) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t});\n\n\t\t// Add fieldRenamed diff\n\t\tthis.differences.push({\n\t\t\ttype: \"fieldRenamed\",\n\t\t\ttableName: ambiguous.tableName,\n\t\t\tfrom: ambiguous.removedName,\n\t\t\tto: ambiguous.addedName,\n\t\t});\n\t}\n\n\t/**\n\t * Apply table rename - replace drop+add with rename\n\t */\n\tprivate applyTableRename(ambiguous: AmbiguousChange): void {\n\t\t// Remove tableRemoved and tableAdded diffs\n\t\tthis.differences = this.differences.filter((d) => {\n\t\t\tif (d.type === \"tableRemoved\" && d.tableName === ambiguous.removedName) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (d.type === \"tableAdded\" && d.schema.name === ambiguous.addedName) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn true;\n\t\t});\n\n\t\t// Add tableRenamed diff\n\t\tthis.differences.push({\n\t\t\ttype: \"tableRenamed\",\n\t\t\tfrom: ambiguous.removedName,\n\t\t\tto: ambiguous.addedName,\n\t\t});\n\t}\n\n\t/**\n\t * Check if there are any changes to apply\n\t */\n\thasChanges(): boolean {\n\t\treturn this.differences.length > 0;\n\t}\n\n\t/**\n\t * Get migration plan\n\t */\n\tgetPlan(): MigrationPlan {\n\t\tif (this.hasUnresolvedAmbiguous()) {\n\t\t\tthrow new MigrationSystemError(\n\t\t\t\t\"Cannot generate plan with unresolved ambiguous changes\",\n\t\t\t\t\"MIGRATION_ERROR\",\n\t\t\t);\n\t\t}\n\n\t\tconst operations = this.generator.generateOperations(this.differences);\n\n\t\treturn {\n\t\t\ttablesToCreate: this.tablesToCreate,\n\t\t\ttablesToDrop: this.tablesToDrop,\n\t\t\ttablesToAlter: this.tablesToAlter,\n\t\t\toperations,\n\t\t\thasChanges: this.hasChanges(),\n\t\t};\n\t}\n\n\t/**\n\t * Apply migrations\n\t */\n\tasync apply(): Promise<readonly MigrationExecutionResult[]> {\n\t\tif (this.hasUnresolvedAmbiguous()) {\n\t\t\tthrow new MigrationSystemError(\n\t\t\t\t\"Cannot apply migrations with unresolved ambiguous changes\",\n\t\t\t\t\"MIGRATION_ERROR\",\n\t\t\t);\n\t\t}\n\n\t\tif (!this.hasChanges()) {\n\t\t\treturn [];\n\t\t}\n\n\t\t// Generate migration\n\t\tconst baseMigration = this.generator.generate(this.differences, {\n\t\t\tname: `migration_${Date.now()}`,\n\t\t\tversion: Date.now().toString(),\n\t\t\tdescription: \"Auto-generated migration\",\n\t\t});\n\n\t\t// Inject data transfer operations for resolved migrate_to_junction / migrate_first\n\t\tconst enrichedOperations = this.injectDataTransferOperations(\n\t\t\tbaseMigration.operations,\n\t\t);\n\n\t\tconst migration: Migration = {\n\t\t\t...baseMigration,\n\t\t\toperations: enrichedOperations,\n\t\t};\n\n\t\t// Create runner and execute\n\t\tconst runner = new ForgeMigrationRunner(this.adapter, this.history, [\n\t\t\tmigration,\n\t\t]);\n\n\t\tconst results = await runner.runPending();\n\n\t\t// Throw on failure so callers don't silently ignore migration errors\n\t\tconst failed = results.find((r) => r.status === \"failed\");\n\t\tif (failed) {\n\t\t\tconst errorMessage =\n\t\t\t\tfailed.error instanceof Error\n\t\t\t\t\t? failed.error.message\n\t\t\t\t\t: String(failed.error ?? \"Unknown migration error\");\n\t\t\tthrow new MigrationSystemError(\n\t\t\t\t`Migration failed: ${errorMessage}`,\n\t\t\t\t\"MIGRATION_ERROR\",\n\t\t\t\tfailed.error,\n\t\t\t);\n\t\t}\n\n\t\treturn results;\n\t}\n\n\t/**\n\t * Inject data transfer operations into the migration operation list.\n\t *\n\t * For each resolved ambiguous change with a data migration action,\n\t * inserts a dataTransfer step at the correct position:\n\t * - migrate_to_junction: after createTable(junction), before dropColumn(fkCol)\n\t * - migrate_first: after addColumn(fkCol), before dropTable(junction)\n\t */\n\tprivate injectDataTransferOperations(\n\t\toperations: readonly MigrationOperation[],\n\t): readonly MigrationOperation[] {\n\t\tconst result: MigrationOperation[] = [...operations];\n\n\t\tfor (const ambiguous of this._ambiguous) {\n\t\t\tif (!ambiguous.resolved) continue;\n\n\t\t\tif (ambiguous.resolvedAction?.type === \"migrate_to_junction\") {\n\t\t\t\tconst sourceFkCol = ambiguous.removedName; // e.g. \"categoryId\"\n\t\t\t\tconst junctionTable = ambiguous.addedName; // e.g. \"category_post\"\n\t\t\t\tconst sourceTable = ambiguous.tableName; // e.g. \"posts\"\n\n\t\t\t\t// Find insert position: after createTable(junction)\n\t\t\t\tconst createIdx = result.findIndex(\n\t\t\t\t\t(op) =>\n\t\t\t\t\t\top.type === \"createTable\" &&\n\t\t\t\t\t\t(op.schema.tableName ?? op.schema.name) === junctionTable,\n\t\t\t\t);\n\n\t\t\t\t// Find drop position: before alterTable(sourceTable) that drops fkCol\n\t\t\t\tconst dropIdx = result.findIndex(\n\t\t\t\t\t(op) =>\n\t\t\t\t\t\top.type === \"alterTable\" &&\n\t\t\t\t\t\top.tableName === sourceTable &&\n\t\t\t\t\t\top.operations.some(\n\t\t\t\t\t\t\t(o) => o.type === \"dropColumn\" && o.column === sourceFkCol,\n\t\t\t\t\t\t),\n\t\t\t\t);\n\n\t\t\t\tif (createIdx === -1 || dropIdx === -1) continue;\n\n\t\t\t\tconst transferOp: DataTransferOperation = {\n\t\t\t\t\ttype: \"dataTransfer\",\n\t\t\t\t\tdescription: `Migrate '${sourceTable}.${sourceFkCol}' values to junction table '${junctionTable}'`,\n\t\t\t\t\texecute: async (runner: QueryRunner) => {\n\t\t\t\t\t\tconst selectResult = await runner.executeQuery<DatrixRecord>({\n\t\t\t\t\t\t\ttype: \"select\",\n\t\t\t\t\t\t\ttable: sourceTable,\n\t\t\t\t\t\t\tselect: [\"id\", sourceFkCol],\n\t\t\t\t\t\t});\n\t\t\t\t\t\tconst rows = selectResult.rows;\n\n\t\t\t\t\t\t// Junction FK col for source: derived from FK col on target (e.g. \"categoryId\" → target model \"category\")\n\t\t\t\t\t\t// Source FK col in junction: singular of sourceTable + \"Id\" (e.g. \"posts\" → \"postId\")\n\t\t\t\t\t\tconst sourceModelName = this.singularize(sourceTable);\n\t\t\t\t\t\tconst sourceJunctionFkCol = `${sourceModelName}Id`;\n\n\t\t\t\t\t\tconst junctionRows = rows\n\t\t\t\t\t\t\t.filter((row) => row[sourceFkCol] != null)\n\t\t\t\t\t\t\t.map((row) => ({\n\t\t\t\t\t\t\t\t[sourceJunctionFkCol]: row.id,\n\t\t\t\t\t\t\t\t[sourceFkCol]: row[sourceFkCol],\n\t\t\t\t\t\t\t}));\n\n\t\t\t\t\t\tif (junctionRows.length === 0) return;\n\n\t\t\t\t\t\tawait runner.executeQuery({\n\t\t\t\t\t\t\ttype: \"insert\",\n\t\t\t\t\t\t\ttable: junctionTable,\n\t\t\t\t\t\t\tdata: junctionRows,\n\t\t\t\t\t\t});\n\t\t\t\t\t},\n\t\t\t\t};\n\n\t\t\t\t// Insert after createTable, but before drop\n\t\t\t\tconst insertAt = Math.min(createIdx + 1, dropIdx);\n\t\t\t\tresult.splice(insertAt, 0, transferOp);\n\t\t\t} else if (ambiguous.resolvedAction?.type === \"migrate_first\") {\n\t\t\t\tconst junctionTable = ambiguous.removedName; // e.g. \"post_tag\"\n\t\t\t\tconst targetFkCol = ambiguous.addedName; // e.g. \"tagId\"\n\t\t\t\tconst targetTable = ambiguous.tableName; // e.g. \"posts\"\n\n\t\t\t\t// Find insert position: after addColumn(targetFkCol) on targetTable\n\t\t\t\tconst addColIdx = result.findIndex(\n\t\t\t\t\t(op) =>\n\t\t\t\t\t\top.type === \"alterTable\" &&\n\t\t\t\t\t\top.tableName === targetTable &&\n\t\t\t\t\t\top.operations.some(\n\t\t\t\t\t\t\t(o) => o.type === \"addColumn\" && o.column === targetFkCol,\n\t\t\t\t\t\t),\n\t\t\t\t);\n\n\t\t\t\t// Find drop position: before dropTable(junction)\n\t\t\t\tconst dropTableIdx = result.findIndex(\n\t\t\t\t\t(op) => op.type === \"dropTable\" && op.tableName === junctionTable,\n\t\t\t\t);\n\n\t\t\t\tif (addColIdx === -1 || dropTableIdx === -1) continue;\n\n\t\t\t\t// Junction FK col for target table: singular of targetTable + \"Id\" (e.g. \"posts\" → \"postId\")\n\t\t\t\tconst targetModelName = this.singularize(targetTable);\n\t\t\t\tconst sourceFkCol = `${targetModelName}Id`; // e.g. \"postId\"\n\t\t\t\tconst relatedFkCol = targetFkCol; // e.g. \"tagId\"\n\n\t\t\t\tconst transferOp: DataTransferOperation = {\n\t\t\t\t\ttype: \"dataTransfer\",\n\t\t\t\t\tdescription: `Migrate first relation from '${junctionTable}' to '${targetTable}.${targetFkCol}'`,\n\t\t\t\t\texecute: async (runner: QueryRunner) => {\n\t\t\t\t\t\tconst selectResult = await runner.executeQuery<DatrixRecord>({\n\t\t\t\t\t\t\ttype: \"select\",\n\t\t\t\t\t\t\ttable: junctionTable,\n\t\t\t\t\t\t\tselect: [sourceFkCol, relatedFkCol],\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\t// Group by sourceFk, keep first occurrence per source record\n\t\t\t\t\t\tconst firstBySource = new Map<number, unknown>();\n\t\t\t\t\t\tfor (const row of selectResult.rows) {\n\t\t\t\t\t\t\tconst sourceId = row[sourceFkCol] as number;\n\t\t\t\t\t\t\tif (!firstBySource.has(sourceId)) {\n\t\t\t\t\t\t\t\tfirstBySource.set(sourceId, row[relatedFkCol]);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Update each source record with its first related FK\n\t\t\t\t\t\tfor (const [sourceId, relatedId] of firstBySource) {\n\t\t\t\t\t\t\tawait runner.executeQuery({\n\t\t\t\t\t\t\t\ttype: \"update\",\n\t\t\t\t\t\t\t\ttable: targetTable,\n\t\t\t\t\t\t\t\twhere: { id: { $eq: sourceId } },\n\t\t\t\t\t\t\t\tdata: { [relatedFkCol]: relatedId },\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t};\n\n\t\t\t\t// Insert after addColumn (data transfer needs the column to exist)\n\t\t\t\t// Also move dropTable AFTER dataTransfer so junction table still exists during transfer\n\t\t\t\tresult.splice(addColIdx + 1, 0, transferOp);\n\n\t\t\t\t// Re-find dropTable index (may have shifted after splice)\n\t\t\t\tconst newDropIdx = result.findIndex(\n\t\t\t\t\t(op) => op.type === \"dropTable\" && op.tableName === junctionTable,\n\t\t\t\t);\n\t\t\t\tconst transferIdx = result.indexOf(transferOp);\n\t\t\t\tif (newDropIdx !== -1 && newDropIdx < transferIdx) {\n\t\t\t\t\t// Remove dropTable from its current position and place it after dataTransfer\n\t\t\t\t\tconst [dropOp] = result.splice(newDropIdx, 1);\n\t\t\t\t\tconst insertAfterTransfer = result.indexOf(transferOp) + 1;\n\t\t\t\t\tresult.splice(insertAfterTransfer, 0, dropOp!);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Get dry-run preview of what would be applied\n\t */\n\tasync preview(): Promise<readonly MigrationOperation[]> {\n\t\tconst plan = this.getPlan();\n\t\treturn plan.operations;\n\t}\n}\n\n/**\n * Create migration session\n */\nexport async function createMigrationSession(\n\tdatrix: IDatrix,\n): Promise<MigrationSession> {\n\tconst session = new MigrationSession(datrix);\n\tawait session.initialize();\n\treturn session;\n}\n","/**\n * Datrix - Main Class\n *\n * Central orchestrator for the Datrix framework.\n * Manages configuration, database adapter, plugins, and schemas.\n */\n\nimport {\n\tDatrixConfig,\n\tMigrationConfig,\n\tDevConfig,\n\tDEFAULT_MIGRATION_CONFIG,\n\tDEFAULT_DEV_CONFIG,\n} from \"./types/core/config\";\nimport { DatabaseAdapter } from \"./types/adapter\";\nimport {\n\tDatrixPlugin,\n\tPluginContext,\n\tSchemaExtension,\n} from \"./types/core/plugin\";\nimport { WhereClause } from \"./types/core/query-builder\";\nimport { CrudOperations } from \"./mixins/crud\";\nimport { SchemaExtensionContextImpl } from \"./plugin/schema-extension-context\";\nimport { Dispatcher, createDispatcher } from \"./dispatcher\";\nimport { PluginRegistry } from \"./types/core/plugin\";\nimport { SchemaRegistry } from \"./schema\";\nimport { DatrixEntry, DatrixRecord } from \"./types/core/schema\";\nimport {\n\tIDatrix,\n\tRawCrudOptions,\n\tRawFindManyOptions,\n\tFallbackInput,\n} from \"./types/core\";\nimport { DatrixError } from \"./types/errors\";\nimport {\n\tgetMigrationSchema,\n\tDEFAULT_MIGRATION_MODEL,\n\tgetDatrixMetaSchema,\n} from \"./migration/schema\";\nimport { MigrationSession, createMigrationSession } from \"./migration/session\";\n\n/**\n * Datrix initialization options\n */\nexport interface DatrixInitOptions {\n\treadonly skipConnection?: boolean;\n\treadonly skipPlugins?: boolean;\n\treadonly skipSchemas?: boolean;\n}\n\n/**\n * Config factory function type\n */\nexport type ConfigFactory = () => DatrixConfig;\n\n/**\n * Datrix Main Class\n */\nexport class Datrix implements IDatrix {\n\tprivate config: DatrixConfig | null = null;\n\tprivate adapter: DatabaseAdapter | null = null;\n\tprivate pluginRegistry: PluginRegistry = new PluginRegistry();\n\tprivate dispatcher: Dispatcher | null = null;\n\tprivate _schemas: SchemaRegistry = new SchemaRegistry();\n\tprivate initialized = false;\n\n\tprivate _crud!: CrudOperations;\n\tprivate _rawCrud!: CrudOperations;\n\n\t/**\n\t * Initialize with config object directly\n\t */\n\tasync initializeWithConfig(\n\t\tconfig: DatrixConfig,\n\t\toptions: DatrixInitOptions = {},\n\t): Promise<void> {\n\t\tif (this.initialized) {\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tthis.config = config;\n\t\t\tthis.adapter = config.adapter;\n\n\t\t\t// Register plugins\n\t\t\tif (!options.skipPlugins && config.plugins) {\n\t\t\t\tfor (const plugin of config.plugins) {\n\t\t\t\t\tthis.pluginRegistry.register(plugin);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Create dispatcher\n\t\t\tthis.dispatcher = createDispatcher(this.pluginRegistry, this);\n\n\t\t\t// Connect to database\n\t\t\tif (!options.skipConnection && this.adapter) {\n\t\t\t\tawait this.adapter.connect(this._schemas);\n\t\t\t}\n\n\t\t\t// 1. Register internal _datrix metadata schema\n\t\t\tconst datrixMetaSchema = getDatrixMetaSchema();\n\t\t\tthis._schemas.register(datrixMetaSchema);\n\n\t\t\t// 2. Register user schemas\n\t\t\tif (!options.skipSchemas && config.schemas.length > 0) {\n\t\t\t\tfor (const schema of config.schemas) {\n\t\t\t\t\tthis._schemas.register(schema);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// 3. Register plugin schemas\n\t\t\tif (!options.skipPlugins) {\n\t\t\t\tfor (const plugin of this.pluginRegistry.getAll()) {\n\t\t\t\t\tif (plugin.getSchemas) {\n\t\t\t\t\t\tconst pluginSchemas = await plugin.getSchemas();\n\t\t\t\t\t\tfor (const schema of pluginSchemas) {\n\t\t\t\t\t\t\tthis._schemas.register(schema);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// 4. Apply schema extensions\n\t\t\tif (!options.skipPlugins) {\n\t\t\t\tconst extensionContext = new SchemaExtensionContextImpl(\n\t\t\t\t\tthis._schemas.getAll(),\n\t\t\t\t);\n\n\t\t\t\tfor (const plugin of this.pluginRegistry.getAll()) {\n\t\t\t\t\tif (plugin.extendSchemas) {\n\t\t\t\t\t\tconst extensions = await plugin.extendSchemas(extensionContext);\n\t\t\t\t\t\tthis.applySchemaExtensions(extensions);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// 5. Register internal migration schema\n\t\t\tconst migrationModelName =\n\t\t\t\tconfig.migration?.modelName ?? DEFAULT_MIGRATION_MODEL;\n\t\t\tconst migrationSchema = getMigrationSchema(migrationModelName);\n\t\t\tthis._schemas.register(migrationSchema);\n\n\t\t\t// 5. Finalize registry (process relations, create junction tables)\n\t\t\tthis._schemas.finalizeRegistry();\n\n\t\t\t// Initialize mixins\n\t\t\tthis._crud = new CrudOperations(\n\t\t\t\tthis._schemas,\n\t\t\t\t() => this.adapter!,\n\t\t\t\t() => this.dispatcher!,\n\t\t\t);\n\t\t\tthis._rawCrud = new CrudOperations(\n\t\t\t\tthis._schemas,\n\t\t\t\t() => this.adapter!,\n\t\t\t\tnull, // No dispatcher = raw mode (bypasses plugin hooks)\n\t\t\t);\n\n\t\t\t// Initialize plugins\n\t\t\tif (!options.skipPlugins) {\n\t\t\t\tconst pluginContext: PluginContext = {\n\t\t\t\t\tadapter: this.adapter!,\n\t\t\t\t\tschemas: this._schemas,\n\t\t\t\t\tconfig: this.config,\n\t\t\t\t};\n\n\t\t\t\tawait this.pluginRegistry.initAll(pluginContext);\n\t\t\t}\n\n\t\t\t// Dispatch schema load event\n\t\t\tif (!options.skipPlugins) {\n\t\t\t\tawait this.dispatcher.dispatchSchemaLoad(this._schemas);\n\t\t\t}\n\n\t\t\tthis.initialized = true;\n\n\t\t\t// Auto-migrate if configured\n\t\t\tconst migrationConfig = this.getMigrationConfig();\n\t\t\tif (migrationConfig.auto) {\n\t\t\t\tconst session = await createMigrationSession(this);\n\n\t\t\t\tif (session.ambiguous.length > 0) {\n\t\t\t\t\tconst ambiguousIds = session.ambiguous.map((a) => a.id).join(\", \");\n\t\t\t\t\tthrow new DatrixError(\n\t\t\t\t\t\t`Auto-migration aborted: ambiguous schema changes detected (${ambiguousIds}). Run \"datrix migrate\" interactively to resolve.`,\n\t\t\t\t\t\t{ code: \"INIT_FAILED\" },\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tif (session.hasChanges()) {\n\t\t\t\t\tawait session.apply();\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tif (error instanceof DatrixError) {\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\tthrow new DatrixError(\n\t\t\t\t`Initialization failed: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t\t{\n\t\t\t\t\tcode: \"INIT_FAILED\",\n\t\t\t\t\tcause: error instanceof Error ? error : undefined,\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\t}\n\n\tasync shutdown(): Promise<void> {\n\t\tif (!this.initialized) {\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tawait this.pluginRegistry.destroyAll();\n\n\t\t\tif (this.adapter) {\n\t\t\t\tawait this.adapter.disconnect();\n\t\t\t}\n\n\t\t\tthis._schemas.clear();\n\t\t\tthis.dispatcher = null;\n\t\t\tthis.initialized = false;\n\t\t} catch (error) {\n\t\t\tthrow new DatrixError(\n\t\t\t\t`Shutdown failed: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t\t{\n\t\t\t\t\tcode: \"SHUTDOWN_FAILED\",\n\t\t\t\t\tcause: error instanceof Error ? error : undefined,\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\t}\n\n\tgetConfig(): DatrixConfig {\n\t\tthis.ensureInitialized();\n\t\treturn this.config!;\n\t}\n\n\tgetAdapter<T extends DatabaseAdapter = DatabaseAdapter>(): T {\n\t\tthis.ensureInitialized();\n\t\treturn this.adapter as T;\n\t}\n\n\tgetPlugins(): readonly DatrixPlugin[] {\n\t\tthis.ensureInitialized();\n\t\treturn this.pluginRegistry.getAll();\n\t}\n\n\tgetPlugin<T extends DatrixPlugin = DatrixPlugin>(name: string): T | null {\n\t\tthis.ensureInitialized();\n\t\treturn (this.pluginRegistry.get(name) as T) ?? null;\n\t}\n\n\thasPlugin(name: string): boolean {\n\t\tthis.ensureInitialized();\n\t\treturn this.pluginRegistry.has(name);\n\t}\n\n\tgetDispatcher(): Dispatcher {\n\t\tthis.ensureInitialized();\n\t\treturn this.dispatcher!;\n\t}\n\n\tgetSchemas(): SchemaRegistry {\n\t\tthis.ensureInitialized();\n\t\treturn this._schemas;\n\t}\n\n\tgetMigrationConfig(): Required<MigrationConfig> {\n\t\tthis.ensureInitialized();\n\t\tconst userConfig = this.config!.migration ?? {};\n\t\treturn { ...DEFAULT_MIGRATION_CONFIG, ...userConfig };\n\t}\n\n\tgetDevConfig(): Required<DevConfig> {\n\t\tthis.ensureInitialized();\n\t\tconst userConfig = this.config!.dev ?? {};\n\t\treturn { ...DEFAULT_DEV_CONFIG, ...userConfig };\n\t}\n\n\tisInitialized(): boolean {\n\t\treturn this.initialized;\n\t}\n\n\t/**\n\t * Begin a migration session\n\t *\n\t * Compares current schemas with database state and returns a session\n\t * for reviewing and applying changes.\n\t *\n\t * @example\n\t * ```ts\n\t * const session = await datrix.beginMigrate();\n\t *\n\t * // Check what will change\n\t * console.log(session.tablesToCreate);\n\t * console.log(session.tablesToDrop);\n\t * console.log(session.tablesToAlter);\n\t *\n\t * // Resolve ambiguous changes (e.g., rename vs drop+add)\n\t * if (session.ambiguous.length > 0) {\n\t * session.resolveAmbiguous('user.name->lastname', 'rename');\n\t * }\n\t *\n\t * // Preview operations\n\t * const plan = session.getPlan();\n\t *\n\t * // Apply migrations\n\t * await session.apply();\n\t * ```\n\t */\n\tasync beginMigrate(): Promise<MigrationSession> {\n\t\tthis.ensureInitialized();\n\n\t\treturn await createMigrationSession(this);\n\t}\n\n\tget crud(): CrudOperations {\n\t\tthis.ensureInitialized();\n\t\treturn this._crud;\n\t}\n\n\t/**\n\t * Raw CRUD operations (bypasses plugin hooks)\n\t *\n\t * Use this when you need direct database access without\n\t * triggering onBeforeQuery/onAfterQuery plugin hooks.\n\t *\n\t * @example\n\t * ```ts\n\t * // Normal (with hooks)\n\t * const user = await datrix.findOne('User', { id: 1 });\n\t *\n\t * // Raw (without hooks)\n\t * const user = await datrix.raw.findOne('User', { id: 1 });\n\t * ```\n\t */\n\tget raw(): CrudOperations {\n\t\tthis.ensureInitialized();\n\t\treturn this._rawCrud;\n\t}\n\n\tasync findOne<T extends DatrixEntry = DatrixRecord>(\n\t\tmodel: string,\n\t\twhere: WhereClause<T>,\n\t\toptions?: RawCrudOptions<T>,\n\t): Promise<T | null> {\n\t\tthis.ensureInitialized();\n\t\treturn this._crud.findOne<T>(model, where, options);\n\t}\n\n\tasync findById<T extends DatrixEntry = DatrixRecord>(\n\t\tmodel: string,\n\t\tid: number,\n\t\toptions?: RawCrudOptions<T>,\n\t): Promise<T | null> {\n\t\tthis.ensureInitialized();\n\t\treturn this._crud.findById<T>(model, id, options);\n\t}\n\n\tasync findMany<T extends DatrixEntry = DatrixRecord>(\n\t\tmodel: string,\n\t\toptions?: RawFindManyOptions<T>,\n\t): Promise<T[]> {\n\t\tthis.ensureInitialized();\n\t\treturn this._crud.findMany<T>(model, options);\n\t}\n\n\tasync count<T extends DatrixEntry = DatrixRecord>(\n\t\tmodel: string,\n\t\twhere?: WhereClause<T>,\n\t): Promise<number> {\n\t\tthis.ensureInitialized();\n\t\treturn this._crud.count(model, where);\n\t}\n\n\tasync create<\n\t\tT extends DatrixEntry = DatrixRecord,\n\t\tTInput extends FallbackInput = FallbackInput,\n\t>(model: string, data: TInput, options?: RawCrudOptions<T>): Promise<T> {\n\t\tthis.ensureInitialized();\n\t\treturn this._crud.create<T, TInput>(model, data, options);\n\t}\n\n\tasync createMany<\n\t\tT extends DatrixEntry = DatrixRecord,\n\t\tTInput extends FallbackInput = FallbackInput,\n\t>(model: string, data: TInput[], options?: RawCrudOptions<T>): Promise<T[]> {\n\t\tthis.ensureInitialized();\n\t\treturn this._crud.createMany<T, TInput>(model, data, options);\n\t}\n\n\tasync update<\n\t\tT extends DatrixEntry = DatrixRecord,\n\t\tTInput extends FallbackInput = FallbackInput,\n\t>(\n\t\tmodel: string,\n\t\tid: number,\n\t\tdata: TInput,\n\t\toptions?: RawCrudOptions<T>,\n\t): Promise<T> {\n\t\tthis.ensureInitialized();\n\t\treturn this._crud.update<T, TInput>(model, id, data, options);\n\t}\n\n\tasync updateMany<\n\t\tT extends DatrixEntry = DatrixRecord,\n\t\tTInput extends FallbackInput = FallbackInput,\n\t>(\n\t\tmodel: string,\n\t\twhere: WhereClause<T>,\n\t\tdata: TInput,\n\t\toptions?: RawCrudOptions<T>,\n\t): Promise<T[]> {\n\t\tthis.ensureInitialized();\n\t\treturn this._crud.updateMany<T, TInput>(model, where, data, options);\n\t}\n\n\tasync delete<T extends DatrixEntry = DatrixRecord>(\n\t\tmodel: string,\n\t\tid: number,\n\t\toptions?: RawCrudOptions<T>,\n\t): Promise<T> {\n\t\tthis.ensureInitialized();\n\t\treturn this._crud.delete(model, id, options);\n\t}\n\n\tasync deleteMany<T extends DatrixEntry = DatrixRecord>(\n\t\tmodel: string,\n\t\twhere: WhereClause<T>,\n\t\toptions?: RawCrudOptions<T>,\n\t): Promise<T[]> {\n\t\tthis.ensureInitialized();\n\t\treturn this._crud.deleteMany(model, where, options);\n\t}\n\n\tget schema(): SchemaRegistry {\n\t\tthis.ensureInitialized();\n\t\treturn this._schemas;\n\t}\n\n\tgetSchema(name: string) {\n\t\tthis.ensureInitialized();\n\t\treturn this._schemas.get(name);\n\t}\n\n\tgetAllSchemas() {\n\t\tthis.ensureInitialized();\n\t\treturn this._schemas.getAll();\n\t}\n\n\thasSchema(name: string): boolean {\n\t\tthis.ensureInitialized();\n\t\treturn this._schemas.has(name);\n\t}\n\n\treset(): void {\n\t\tthis.config = null;\n\t\tthis.adapter = null;\n\t\tthis.pluginRegistry = new PluginRegistry();\n\t\tthis.dispatcher = null;\n\t\tthis._schemas = new SchemaRegistry();\n\t\tthis.initialized = false;\n\t}\n\n\tprivate ensureInitialized(): void {\n\t\tif (!this.initialized) {\n\t\t\tthrow new DatrixError(\n\t\t\t\t\"Datrix not initialized. Use defineConfig() and call the returned function first.\",\n\t\t\t\t{ code: \"NOT_INITIALIZED\" },\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate applySchemaExtensions(extensions: SchemaExtension[]): void {\n\t\tfor (const extension of extensions) {\n\t\t\tconst schema = this._schemas.get(extension.targetSchema)!;\n\t\t\tconst extendedFields = { ...schema.fields };\n\t\t\tconst extendedIndexes = [...(schema.indexes || [])];\n\n\t\t\tif (extension.fields) {\n\t\t\t\tfor (const [fieldName, fieldDef] of Object.entries(extension.fields)) {\n\t\t\t\t\tif (extendedFields[fieldName]) {\n\t\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t\t`[Datrix] Field '${fieldName}' already exists in schema '${extension.targetSchema}'. Skipping.`,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\textendedFields[fieldName] = fieldDef;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (extension.removeFields) {\n\t\t\t\tfor (const fieldName of extension.removeFields) {\n\t\t\t\t\tdelete extendedFields[fieldName];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (extension.modifyFields) {\n\t\t\t\tfor (const [fieldName, modifications] of Object.entries(\n\t\t\t\t\textension.modifyFields,\n\t\t\t\t)) {\n\t\t\t\t\tif (!extendedFields[fieldName]) {\n\t\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t\t`[Datrix] Cannot modify field '${fieldName}' in schema '${extension.targetSchema}': field not found. Skipping.`,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\textendedFields[fieldName] = {\n\t\t\t\t\t\t...extendedFields[fieldName],\n\t\t\t\t\t\t...modifications,\n\t\t\t\t\t} as any;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (extension.indexes) {\n\t\t\t\textendedIndexes.push(...extension.indexes);\n\t\t\t}\n\n\t\t\tconst extendedSchema = {\n\t\t\t\t...schema,\n\t\t\t\tfields: extendedFields,\n\t\t\t\tindexes: extendedIndexes,\n\t\t\t};\n\n\t\t\tthis._schemas.register(extendedSchema);\n\t\t}\n\t}\n}\n\n/**\n * Define Datrix configuration\n *\n * Returns a function that when called, returns an initialized Datrix instance.\n * The config factory is only called once on first invocation.\n *\n * @example\n * ```ts\n * // datrix.config.ts\n * import { defineConfig } from '..';\n *\n * export default defineConfig(() => ({\n * adapter: new JsonAdapter({ root: './data' }),\n * schemas: [userSchema, topicSchema],\n * }));\n * ```\n *\n * @example\n * ```ts\n * // Usage anywhere\n * import datrix from './datrix.config';\n *\n * const users = await datrix().findMany('user');\n * ```\n */\nexport function defineConfig(factory: ConfigFactory): () => Promise<Datrix> {\n\tconst instance = new Datrix();\n\tlet initPromise: Promise<Datrix> | null = null;\n\n\treturn async function getDatrixInstance(): Promise<Datrix> {\n\t\t// Already initialized - return immediately\n\t\tif (instance.isInitialized()) {\n\t\t\treturn instance;\n\t\t}\n\n\t\t// Initialization in progress - wait for it\n\t\tif (initPromise) {\n\t\t\treturn initPromise;\n\t\t}\n\n\t\t// Start initialization\n\t\tinitPromise = (async () => {\n\t\t\tconst config = factory();\n\n\t\t\ttry {\n\t\t\t\tawait instance.initializeWithConfig(config);\n\t\t\t} finally {\n\t\t\t\tinitPromise = null;\n\t\t\t}\n\n\t\t\treturn instance;\n\t\t})();\n\n\t\treturn initPromise;\n\t};\n}\n","/**\n * Permission System Types\n *\n * Schema-based permission system with role validation, function-based checks,\n * and field-level access control.\n */\n\nimport { AuthUser } from \"../api\";\nimport { DatrixEntry } from \"./schema\";\n\n/**\n * Permission actions for schema-level access\n */\nexport type PermissionAction = \"create\" | \"read\" | \"update\" | \"delete\";\n\n/**\n * Permission actions for field-level access\n */\nexport type FieldPermissionAction = \"read\" | \"write\";\n\n/**\n * Permission evaluation context\n *\n * @template TRecord - The record type for the schema\n */\nexport interface PermissionContext<TRecord extends DatrixEntry = DatrixEntry> {\n\t/** Current authenticated user (undefined if not authenticated) */\n\treadonly user: AuthUser | undefined;\n\t/** Current record (for update/delete operations) */\n\treadonly record?: TRecord;\n\t/** Input data (for create/update operations) */\n\treadonly input?: Partial<TRecord>;\n\t/** Current action being performed */\n\treadonly action: PermissionAction;\n\n\treadonly id?: number | string | null;\n\t/**\n\t * Datrix instance for custom queries\n\t * User can perform additional checks if needed\n\t */\n\treadonly datrix: unknown; // Avoid circular dependency\n}\n\n/**\n * Permission function type\n * Returns boolean or Promise<boolean> for async checks\n *\n * @template TRecord - The record type for the schema\n */\nexport type PermissionFn<TRecord extends DatrixEntry = DatrixEntry> = (\n\tctx: PermissionContext<TRecord>,\n) => boolean | Promise<boolean>;\n\n/**\n * Permission value type - supports multiple formats:\n * - `true` = everyone allowed\n * - `false` = no one allowed\n * - `['admin', 'editor']` = only these roles\n * - `(ctx) => boolean` = custom function\n * - `['admin', (ctx) => ctx.user?.id === ctx.record?.authorId]` = role OR function (OR logic)\n *\n * @template TRoles - Union type of valid role names\n * @template TRecord - The record type for the schema\n */\nexport type PermissionValue<\n\tTRoles extends string = string,\n\tTRecord extends DatrixEntry = DatrixEntry,\n> =\n\t| boolean\n\t| readonly TRoles[]\n\t| PermissionFn<TRecord>\n\t| readonly (TRoles | PermissionFn<TRecord>)[];\n\n/**\n * Schema-level permission configuration\n *\n * @template TRoles - Union type of valid role names\n * @template TRecord - The record type for the schema\n *\n * @example\n * ```ts\n * const permission: SchemaPermission<'admin' | 'editor' | 'user'> = {\n * create: ['admin', 'editor'],\n * read: true,\n * update: ['admin', (ctx) => ctx.user?.id === ctx.record?.authorId],\n * delete: ['admin'],\n * };\n * ```\n */\nexport interface SchemaPermission<\n\tTRoles extends string = string,\n\tTRecord extends DatrixEntry = DatrixEntry,\n> {\n\treadonly create?: PermissionValue<TRoles, TRecord>;\n\treadonly read?: PermissionValue<TRoles, TRecord>;\n\treadonly update?: PermissionValue<TRoles, TRecord>;\n\treadonly delete?: PermissionValue<TRoles, TRecord>;\n}\n\n/**\n * Field-level permission configuration\n *\n * - `read`: If user doesn't have permission, field is removed from response\n * - `write`: If user doesn't have permission, returns 403 error\n *\n * @template TRoles - Union type of valid role names\n * @template TRecord - The record type for the schema\n *\n * @example\n * ```ts\n * const field = {\n * type: 'string',\n * permission: {\n * read: ['admin', 'hr'], // Only admin/hr can see this field\n * write: ['admin'], // Only admin can modify\n * }\n * };\n * ```\n */\nexport interface FieldPermission<\n\tTRoles extends string = string,\n\tTRecord extends DatrixEntry = DatrixEntry,\n> {\n\treadonly read?: PermissionValue<TRoles, TRecord>;\n\treadonly write?: PermissionValue<TRoles, TRecord>;\n}\n\n/**\n * Default permission configuration for API\n *\n * Applied to all schemas that don't have explicit permissions\n *\n * @template TRoles - Union type of valid role names\n */\nexport interface DefaultPermission<TRoles extends string = string> {\n\treadonly create?: PermissionValue<TRoles>;\n\treadonly read?: PermissionValue<TRoles>;\n\treadonly update?: PermissionValue<TRoles>;\n\treadonly delete?: PermissionValue<TRoles>;\n}\n\n/**\n * Permission check result\n */\nexport interface PermissionCheckResult {\n\treadonly allowed: boolean;\n\treadonly reason?: string | undefined;\n}\n\n/**\n * Field permission check result\n */\nexport interface FieldPermissionCheckResult {\n\treadonly allowed: boolean;\n\treadonly deniedFields?: readonly string[] | undefined;\n}\n\n/**\n * Type guard for PermissionFn\n */\nexport function isPermissionFn<TRecord extends DatrixEntry = DatrixEntry>(\n\tvalue: unknown,\n): value is PermissionFn<TRecord> {\n\treturn typeof value === \"function\";\n}\n","/**\n * Database Adapter Interface\n *\n * This file defines the standard interface that ALL database adapters must implement.\n * Adapters provide database-specific implementations for PostgreSQL, MySQL, MongoDB, etc.\n *\n * Error handling: All methods throw DatrixAdapterError on failure instead of returning Result.\n */\n\nimport { QueryObject, WhereClause } from \"../core/query-builder\";\nimport {\n\tFieldDefinition,\n\tDatrixEntry,\n\tIndexDefinition,\n\tISchemaRegistry,\n\tSchemaDefinition,\n} from \"../core/schema\";\nimport { DatrixAdapterError } from \"../errors/adapter\";\n\n/**\n * Export data metadata\n */\nexport interface ExportMeta {\n\treadonly version: number;\n\treadonly exportedAt: string;\n}\n\n/**\n * Writer interface for export operations.\n *\n * Adapter calls these methods to stream export data.\n * CLI provides the concrete implementation (zip, file, memory, etc.)\n */\nexport interface ExportWriter {\n\twriteMeta(meta: ExportMeta): Promise<void>;\n\twriteSchema(schema: SchemaDefinition): Promise<void>;\n\twriteChunk(tableName: string, rows: Record<string, unknown>[]): Promise<void>;\n\tfinalize(): Promise<void>;\n}\n\n/**\n * Reader interface for import operations.\n *\n * Adapter calls these methods to stream import data.\n * CLI provides the concrete implementation (zip, file, memory, etc.)\n */\nexport interface ImportReader {\n\treadMeta(): Promise<ExportMeta>;\n\treadSchemas(): AsyncIterable<SchemaDefinition>;\n\tgetTables(): Promise<readonly string[]>;\n\treadChunks(tableName: string): AsyncIterable<Record<string, unknown>[]>;\n}\n\nexport { DatrixAdapterError };\n\n/**\n * Query result metadata\n */\nexport interface QueryMetadata {\n\treadonly rowCount?: number;\n\treadonly affectedRows?: number;\n\treadonly insertIds?: readonly number[];\n\treadonly count?: number;\n}\n\n/**\n * Query result\n */\nexport interface QueryResult<T = unknown> {\n\treadonly rows: readonly T[];\n\treadonly metadata: QueryMetadata;\n}\n\n/**\n * Common query execution interface shared by DatabaseAdapter and Transaction.\n */\nexport interface QueryRunner {\n\texecuteQuery<TResult extends DatrixEntry>(\n\t\tquery: QueryObject<TResult>,\n\t): Promise<QueryResult<TResult>>;\n\n\texecuteRawQuery<TResult extends DatrixEntry>(\n\t\tsql: string,\n\t\tparams: readonly unknown[],\n\t): Promise<QueryResult<TResult>>;\n}\n\n/**\n * Schema operations interface - shared by DatabaseAdapter and Transaction.\n * Migrations should use Transaction for atomic DDL operations.\n */\nexport interface SchemaOperations {\n\tcreateTable(schema: SchemaDefinition): Promise<void>;\n\tdropTable(tableName: string): Promise<void>;\n\trenameTable(from: string, to: string): Promise<void>;\n\talterTable(\n\t\ttableName: string,\n\t\toperations: readonly AlterOperation[],\n\t): Promise<void>;\n\taddIndex(tableName: string, index: IndexDefinition): Promise<void>;\n\tdropIndex(tableName: string, indexName: string): Promise<void>;\n}\n\n/**\n * Transaction interface\n *\n * Extends both QueryRunner and SchemaOperations to support:\n * - Query execution within transaction\n * - Schema modifications within transaction (for atomic migrations)\n */\nexport interface Transaction extends QueryRunner, SchemaOperations {\n\treadonly id: string;\n\n\tcommit(): Promise<void>;\n\trollback(): Promise<void>;\n\n\t// Savepoints\n\tsavepoint(name: string): Promise<void>;\n\trollbackTo(name: string): Promise<void>;\n\trelease(name: string): Promise<void>;\n}\n\n/**\n * Alter table operations\n */\nexport type AlterOperation =\n\t| {\n\t\treadonly type: \"addColumn\";\n\t\treadonly column: string;\n\t\treadonly definition: FieldDefinition;\n\t}\n\t| { readonly type: \"dropColumn\"; readonly column: string }\n\t| {\n\t\treadonly type: \"modifyColumn\";\n\t\treadonly column: string;\n\t\treadonly newDefinition: FieldDefinition;\n\t}\n\t| {\n\t\treadonly type: \"renameColumn\";\n\t\treadonly from: string;\n\t\treadonly to: string;\n\t}\n\t| {\n\t\treadonly type: \"addMetaField\";\n\t\treadonly field: string;\n\t\treadonly definition: FieldDefinition;\n\t}\n\t| { readonly type: \"dropMetaField\"; readonly field: string }\n\t| {\n\t\treadonly type: \"modifyMetaField\";\n\t\treadonly field: string;\n\t\treadonly newDefinition: FieldDefinition;\n\t};\n\n/**\n * Connection state\n */\nexport type ConnectionState =\n\t| \"disconnected\"\n\t| \"connecting\"\n\t| \"connected\"\n\t| \"error\";\n\n/**\n * Database adapter interface\n *\n * ALL database adapters MUST implement this interface.\n * Extends QueryRunner for query execution and SchemaOperations for DDL.\n *\n * Note: For migrations, prefer using Transaction (from beginTransaction())\n * to ensure atomic DDL operations where supported by the database.\n */\nexport interface DatabaseAdapter<TConfig = object>\n\textends QueryRunner, SchemaOperations {\n\t// Metadata\n\treadonly name: string;\n\treadonly config: TConfig;\n\n\t// Connection management\n\tconnect(schemas: ISchemaRegistry): Promise<void>;\n\tdisconnect(): Promise<void>;\n\tisConnected(): boolean;\n\tgetConnectionState(): ConnectionState;\n\n\t// Transaction support\n\tbeginTransaction(): Promise<Transaction>;\n\n\t// Introspection\n\tgetTables(): Promise<readonly string[]>;\n\tgetTableSchema(tableName: string): Promise<SchemaDefinition | null>;\n\ttableExists(tableName: string): Promise<boolean>;\n\n\t// Export / Import\n\texportData(writer: ExportWriter): Promise<void>;\n\timportData(reader: ImportReader): Promise<void>;\n}\n\n/**\n * Type guard for DatabaseAdapter\n */\nexport function isDatabaseAdapter(\n\tvalue: unknown,\n): value is DatabaseAdapter<unknown> {\n\treturn (\n\t\ttypeof value === \"object\" &&\n\t\tvalue !== null &&\n\t\t\"name\" in value &&\n\t\t\"config\" in value &&\n\t\t\"connect\" in value &&\n\t\t\"disconnect\" in value &&\n\t\t\"executeQuery\" in value &&\n\t\t\"exportData\" in value &&\n\t\t\"importData\" in value &&\n\t\ttypeof (value as DatabaseAdapter).connect === \"function\" &&\n\t\ttypeof (value as DatabaseAdapter).disconnect === \"function\" &&\n\t\ttypeof (value as DatabaseAdapter).executeQuery === \"function\" &&\n\t\ttypeof (value as DatabaseAdapter).exportData === \"function\" &&\n\t\ttypeof (value as DatabaseAdapter).importData === \"function\"\n\t);\n}\n\n/**\n * SQL parameter placeholder style\n */\nexport type ParameterStyle =\n\t| \"numbered\" // PostgreSQL: $1, $2, $3\n\t| \"question\" // MySQL: ?, ?, ?\n\t| \"named\"; // Named: :param1, :param2\n\n/**\n * SQL dialect\n */\nexport type SqlDialect = \"postgres\" | \"mysql\" | \"sqlite\";\n\n/**\n * Query translator interface\n */\nexport interface QueryTranslator<T extends DatrixEntry = DatrixEntry> {\n\ttranslate(query: QueryObject<T>): {\n\t\treadonly sql: string;\n\t\treadonly params: readonly unknown[];\n\t};\n\n\ttranslateWhere(\n\t\twhere: WhereClause<T>,\n\t\tstartIndex: number,\n\t): {\n\t\treadonly sql: string;\n\t\treadonly params: readonly unknown[];\n\t};\n\n\tescapeIdentifier(identifier: string): string;\n\tescapeValue(value: unknown): string;\n\tgetParameterPlaceholder(index: number): string;\n}\n","/**\n * Parser Type Definitions\n *\n * Types for parsing URL query strings into QueryObject format.\n * Supports: populate, fields, where, pagination, sorting\n */\n\nimport { DatrixEntry, DatrixRecord } from \"../core/schema\";\nimport {\n\tOrderByClause,\n\tOrderByItem,\n\tPopulateClause,\n\tSelectClause,\n\tWhereClause,\n} from \"../core/query-builder\";\n\n/**\n * Raw query parameters from HTTP request\n * (framework-agnostic - works with URLSearchParams, Express req.query, etc.)\n */\nexport type RawQueryParams = Record<\n\tstring,\n\tstring | readonly string[] | undefined\n>;\n\n/**\n * Parsed query result\n */\n\nexport interface ParsedQuery<T extends DatrixEntry = DatrixEntry> {\n\treadonly select?: SelectClause<T>;\n\treadonly where?: WhereClause<T>;\n\treadonly populate?: PopulateClause<T>;\n\treadonly orderBy?: OrderByClause<T>;\n\treadonly page?: number;\n\treadonly pageSize?: number;\n}\n\n/**\n * Parser options\n */\nexport interface ParserOptions {\n\treadonly maxPageSize?: number; // Default: 100\n\treadonly defaultPageSize?: number; // Default: 25\n\treadonly maxPopulateDepth?: number; // Default: 5\n\treadonly allowedOperators?: readonly string[]; // Default: all\n\treadonly strictMode?: boolean; // Fail on unknown fields\n}\n\n// Re-export parser error types from errors module\nexport type {\n\tParserType,\n\tParserErrorCode,\n\tParserErrorContext,\n\tWhereErrorContext,\n\tPopulateErrorContext,\n\tFieldsErrorContext,\n\tPaginationErrorContext,\n\tSortErrorContext,\n\tBaseErrorContext,\n\tErrorLocation,\n\tParserErrorOptions,\n\tSerializedParserError,\n} from \"../errors/api/parser\";\n\nexport { ParserError, buildErrorLocation } from \"../errors/api/parser\";\n\n/**\n * Supported WHERE operators\n */\nexport const WHERE_OPERATORS = [\n\t\"$eq\",\n\t\"$ne\",\n\t\"$lt\",\n\t\"$lte\",\n\t\"$gt\",\n\t\"$gte\",\n\t\"$in\",\n\t\"$nin\",\n\t\"$contains\",\n\t\"$notContains\",\n\t\"$startsWith\",\n\t\"$endsWith\",\n\t\"$null\",\n\t\"$notNull\",\n\t\"$like\",\n\t\"$ilike\",\n\t\"$and\",\n\t\"$or\",\n\t\"$not\",\n] as const;\n\n/**\n * WHERE operator type\n */\nexport type WhereOperator = (typeof WHERE_OPERATORS)[number];\n\n/**\n * Check if string is a valid operator\n */\nexport function isWhereOperator(value: string): value is WhereOperator {\n\treturn WHERE_OPERATORS.includes(value as WhereOperator);\n}\n\n/**\n * Pagination parameters\n */\nexport interface PaginationParams {\n\treadonly page?: number;\n\treadonly pageSize?: number;\n}\n\n/**\n * Parse pagination result\n */\nexport interface ParsedPagination {\n\treadonly page: number;\n\treadonly pageSize: number;\n}\n\n/**\n * Sort parameters\n */\nexport type SortParam = string | readonly string[];\n\n/**\n * Parse sort result\n */\nexport type ParsedSort<T extends DatrixEntry = DatrixRecord> =\n\treadonly OrderByItem<T>[];\n","/**\n * Upload Types\n *\n * Storage provider interface and related types for the upload system.\n * Moved here from plugin-upload so api package can reference it directly.\n */\n\nimport { SchemaPermission } from \"../core/permission\";\nimport type { DatrixEntry, SchemaDefinition } from \"../core/schema\";\n\n/**\n * Raw file data received from multipart/form-data parsing\n */\nexport interface UploadFile {\n\treadonly filename: string;\n\treadonly originalName: string;\n\treadonly mimetype: string;\n\treadonly size: number;\n\treadonly buffer: Uint8Array;\n}\n\n/**\n * Result returned by a storage provider after a successful upload\n */\nexport interface UploadResult {\n\treadonly key: string;\n\treadonly size: number;\n\treadonly mimetype: string;\n\treadonly uploadedAt: Date;\n}\n\n/**\n * Storage provider interface.\n * Implement this to add a new storage backend (S3, local, GCS, etc.)\n */\nexport interface StorageProvider {\n\treadonly name: string;\n\tupload(file: UploadFile): Promise<UploadResult>;\n\tdelete(key: string): Promise<void>;\n\tgetUrl(key: string): string;\n\texists(key: string): Promise<boolean>;\n}\n\n/**\n * A single processed variant (thumbnail, small, medium, etc.)\n */\nexport interface MediaVariant {\n\treadonly key: string;\n\treadonly url: string;\n\treadonly width: number;\n\treadonly height: number;\n\treadonly size: number;\n\treadonly mimeType: string;\n}\n\n/**\n * Map of resolution name → variant data.\n * Keys are whatever the user defines in Upload config resolutions.\n *\n * @example\n * ```ts\n * const variants: MediaVariants<\"thumbnail\" | \"small\"> = {\n * thumbnail: { url: \"...\", width: 150, height: 150, size: 4200, mimeType: \"image/webp\" },\n * small: { url: \"...\", width: 640, height: 360, size: 32000, mimeType: \"image/webp\" },\n * }\n * ```\n */\nexport type MediaVariants<TResolutions extends string = string> = {\n\treadonly [K in TResolutions]?: MediaVariant;\n};\n\n/**\n * Shape of a media record stored in the database.\n * Injected as the \"media\" schema by ApiPlugin when upload is configured.\n * TResolutions narrows the variants field for type-safe access.\n */\nexport interface MediaEntry<\n\tTResolutions extends string = string,\n> extends DatrixEntry {\n\treadonly filename: string;\n\treadonly originalName: string;\n\treadonly mimeType: string;\n\treadonly size: number;\n\treadonly url: string;\n\treadonly key: string;\n\treadonly variants: MediaVariants<TResolutions> | null;\n}\n\n/**\n * Upload configuration inside ApiConfig\n */\nexport interface UploadConfig {\n\t/**\n\t * Storage provider instance (S3, Local, etc.)\n\t */\n\treadonly provider: StorageProvider;\n\n\t/**\n\t * Custom table/model name for media records\n\t * @default \"media\"\n\t */\n\treadonly modelName?: string;\n\n\t/**\n\t * Global max file size in bytes (can be overridden per FileField)\n\t */\n\treadonly maxSize?: number;\n\n\t/**\n\t * Global allowed MIME types (can be overridden per FileField)\n\t */\n\treadonly allowedMimeTypes?: readonly string[];\n\n\t/**\n\t * Permission config for the injected media schema\n\t */\n\treadonly permission?: SchemaPermission;\n}\n\n/**\n * Local provider options\n */\nexport interface LocalProviderOptions {\n\treadonly basePath: string;\n\treadonly baseUrl: string;\n\treadonly ensureDirectory?: boolean;\n}\n\n/**\n * S3 provider options\n */\nexport interface S3ProviderOptions {\n\treadonly bucket: string;\n\treadonly region: string;\n\treadonly accessKeyId: string;\n\treadonly secretAccessKey: string;\n\treadonly endpoint?: string;\n\treadonly pathPrefix?: string;\n}\n\n/**\n * Generate unique filename with timestamp and random suffix\n */\nexport function generateUniqueFilename(originalFilename: string): string {\n\tconst timestamp = Date.now();\n\tconst random = Math.random().toString(36).substring(2, 15);\n\tconst extension = getFileExtension(originalFilename);\n\treturn extension\n\t\t? `${timestamp}-${random}.${extension}`\n\t\t: `${timestamp}-${random}`;\n}\n\n/**\n * Get file extension (without dot)\n */\nexport function getFileExtension(filename: string): string {\n\tconst parts = filename.split(\".\");\n\tif (parts.length < 2) return \"\";\n\treturn parts[parts.length - 1] ?? \"\";\n}\n\n/**\n * Sanitize filename — removes path traversal and dangerous characters\n */\nexport function sanitizeFilename(filename: string): string {\n\treturn filename\n\t\t.replace(/\\.\\./g, \"\")\n\t\t.replace(/\\//g, \"\")\n\t\t.replace(/\\\\/g, \"\")\n\t\t.replace(/[<>:\"|?*]/g, \"\")\n\t\t.replace(/\\s+/g, \"-\")\n\t\t.toLowerCase();\n}\n\n/**\n * Interface that Upload implementations must satisfy.\n * ApiPlugin depends only on this — not on the concrete api-upload package.\n */\nexport interface IUpload {\n\tgetSchemas(): Promise<SchemaDefinition[]> | SchemaDefinition[];\n\thandleRequest(request: Request, datrix: unknown): Promise<Response>;\n\tgetModelName(): string;\n\t/**\n\t * Traverse any response data (including populated relations) and inject\n\t * url fields derived from key via the configured storage provider.\n\t */\n\tinjectUrls(data: unknown): Promise<unknown>;\n\t/**\n\t * Resolve a public URL for the given storage key via the configured provider.\n\t * Used by the CLI file exporter to download files during export.\n\t */\n\tgetUrl(key: string): string;\n\t/**\n\t * The underlying storage provider.\n\t * Used by the CLI file importer to upload files directly.\n\t */\n\treadonly provider: StorageProvider;\n}\n\n/**\n * Type guard for StorageProvider\n */\nexport function isStorageProvider(value: unknown): value is StorageProvider {\n\tif (typeof value !== \"object\" || value === null) {\n\t\treturn false;\n\t}\n\n\tconst obj = value as Record<string, unknown>;\n\n\treturn (\n\t\ttypeof obj[\"name\"] === \"string\" &&\n\t\ttypeof obj[\"upload\"] === \"function\" &&\n\t\ttypeof obj[\"delete\"] === \"function\" &&\n\t\ttypeof obj[\"getUrl\"] === \"function\" &&\n\t\ttypeof obj[\"exists\"] === \"function\"\n\t);\n}\n","/**\n * API Configuration Defaults\n */\n\nexport const DEFAULT_API_CONFIG = {\n\tenabled: true,\n\tprefix: \"/api\",\n\tdefaultPageSize: 25,\n\tmaxPageSize: 100,\n\tmaxPopulateDepth: 5,\n\tautoRoutes: true,\n\texcludeSchemas: [],\n} as const;\n\n/**\n * Default API Auth configuration values\n */\nexport const DEFAULT_API_AUTH_CONFIG = {\n\tenabled: true,\n\tuserSchema: {\n\t\tname: \"user\",\n\t\temail: \"email\",\n\t},\n\tjwt: {\n\t\texpiresIn: \"7d\",\n\t\talgorithm: \"HS256\" as const,\n\t},\n\tsession: {\n\t\tstore: \"memory\" as const,\n\t\tmaxAge: 86400,\n\t\tcheckPeriod: 3600,\n\t\tprefix: \"datrix:session:\",\n\t},\n\tpassword: {\n\t\titerations: 100000,\n\t\tkeyLength: 64,\n\t\tminLength: 8,\n\t},\n\tendpoints: {\n\t\tlogin: \"/auth/login\",\n\t\tregister: \"/auth/register\",\n\t\tlogout: \"/auth/logout\",\n\t\tme: \"/auth/me\",\n\t\tdisableRegister: false,\n\t},\n} as const;\n","/**\n * CLI Type Definitions\n *\n * Types for CLI command parsing, options, and errors.\n */\n\n/**\n * CLI Error class\n */\nexport class CLIError extends Error {\n\tconstructor(\n\t\tmessage: string,\n\t\tpublic readonly code:\n\t\t\t| \"INVALID_COMMAND\"\n\t\t\t| \"MISSING_ARGUMENT\"\n\t\t\t| \"FILE_ERROR\"\n\t\t\t| \"CONFIG_ERROR\"\n\t\t\t| \"EXECUTION_ERROR\",\n\t\tpublic readonly details?: unknown,\n\t) {\n\t\tsuper(message);\n\t\tthis.name = \"CLIError\";\n\t}\n}\n\n/**\n * Parsed command-line arguments\n */\nexport interface ParsedArgs {\n\treadonly command?: string | undefined;\n\treadonly subcommand?: string | undefined;\n\treadonly args: readonly string[];\n\treadonly options: Record<string, string | boolean>;\n}\n\n/**\n * Common command options\n */\nexport interface BaseCommandOptions {\n\treadonly config?: string | undefined;\n\treadonly verbose?: boolean | undefined;\n}\n\n/**\n * Migrate command options\n */\nexport interface MigrateCommandOptions extends BaseCommandOptions {\n\treadonly down?: boolean | undefined;\n\treadonly to?: string | undefined;\n\treadonly dryRun?: boolean | undefined;\n}\n\n/**\n * Generate command options\n */\nexport interface GenerateCommandOptions extends BaseCommandOptions {\n\treadonly output?: string | undefined;\n}\n\n/**\n * Dev command options\n */\nexport interface DevCommandOptions extends BaseCommandOptions {\n\treadonly watch?: boolean | undefined;\n}\n","/**\n * Abstract Base Plugin\n *\n * Provides a base implementation for plugins with common functionality.\n * Plugins can extend this class instead of implementing DatrixPlugin from scratch.\n */\n\nimport { QueryObject } from \"../types/core/query-builder\";\nimport {\n\tISchemaRegistry,\n\tSchemaDefinition,\n\tDatrixEntry,\n} from \"../types/core/schema\";\nimport {\n\tDatrixPlugin,\n\tPluginContext,\n\tPluginError,\n\tSchemaExtensionContext,\n\tSchemaExtension,\n} from \"../types/core/plugin\";\nimport { QueryContext } from \"../types/core/query-context\";\n\n/**\n * Abstract base plugin class\n *\n * Provides default implementations for optional hooks.\n * Subclasses must implement init() and destroy() methods.\n */\nexport abstract class BasePlugin<\n\tTOptions = Record<string, unknown>,\n> implements DatrixPlugin<TOptions> {\n\tabstract readonly name: string;\n\tabstract readonly version: string;\n\treadonly options: TOptions;\n\n\tprotected context: PluginContext | undefined;\n\n\tconstructor(options: TOptions) {\n\t\tthis.options = options;\n\t}\n\n\t/**\n\t * Initialize the plugin\n\t *\n\t * Must be implemented by subclasses\n\t */\n\tabstract init(context: PluginContext): Promise<void>;\n\n\t/**\n\t * Destroy the plugin and cleanup resources\n\t *\n\t * Must be implemented by subclasses\n\t */\n\tabstract destroy(): Promise<void>;\n\n\t/**\n\t * Get plugin schemas\n\t *\n\t * Default implementation returns empty array\n\t */\n\tasync getSchemas(): Promise<SchemaDefinition[]> {\n\t\treturn [];\n\t}\n\n\t/**\n\t * Extend existing schemas\n\t *\n\t * Default implementation returns empty array\n\t */\n\tasync extendSchemas(\n\t\t_context: SchemaExtensionContext,\n\t): Promise<SchemaExtension[]> {\n\t\treturn [];\n\t}\n\n\t/**\n\t * Hook called when schemas are loaded\n\t *\n\t * Default implementation does nothing\n\t */\n\tasync onSchemaLoad(_schemas: ISchemaRegistry): Promise<void> {\n\t\t// Default: no-op\n\t}\n\n\t/**\n\t * Hook called before query execution\n\t *\n\t * Default implementation returns query unchanged\n\t */\n\tasync onBeforeQuery<T extends DatrixEntry>(\n\t\tquery: QueryObject<T>,\n\t\t_context: QueryContext,\n\t): Promise<QueryObject<T>> {\n\t\treturn query;\n\t}\n\n\t/**\n\t * Hook called after query execution\n\t *\n\t * Default implementation returns result unchanged\n\t */\n\tasync onAfterQuery<TResult extends DatrixEntry>(\n\t\tresult: TResult,\n\t\t_context: QueryContext,\n\t): Promise<TResult> {\n\t\treturn result;\n\t}\n\n\t/**\n\t * Hook called when creating query context\n\t *\n\t * Default implementation returns context unchanged\n\t */\n\tasync onCreateQueryContext(context: QueryContext): Promise<QueryContext> {\n\t\treturn context;\n\t}\n\n\t/**\n\t * Validate plugin options\n\t *\n\t * Helper method for subclasses to implement options validation\n\t */\n\tprotected validateOptions(\n\t\tvalidator: (options: unknown) => options is TOptions,\n\t\terrorMessage: string,\n\t): TOptions {\n\t\tif (validator(this.options)) {\n\t\t\treturn this.options;\n\t\t}\n\n\t\tthrow new PluginError(errorMessage, {\n\t\t\tcode: \"INVALID_OPTIONS\",\n\t\t\tpluginName: this.name,\n\t\t\tdetails: this.options,\n\t\t});\n\t}\n\n\t/**\n\t * Check if plugin is initialized\n\t *\n\t * Helper method to ensure init() was called\n\t */\n\tprotected isInitialized(): this is this & {\n\t\tcontext: PluginContext;\n\t} {\n\t\treturn this.context !== undefined;\n\t}\n\n\t/**\n\t * Get context or return error\n\t *\n\t * Helper method to safely access context\n\t */\n\tprotected getContext(): PluginContext {\n\t\tif (this.context === undefined) {\n\t\t\tthrow new PluginError(`Plugin ${this.name} not initialized`, {\n\t\t\t\tcode: \"PLUGIN_NOT_INITIALIZED\",\n\t\t\t\tpluginName: this.name,\n\t\t\t});\n\t\t}\n\t\treturn this.context;\n\t}\n\n\t/**\n\t * Create a plugin error\n\t *\n\t * Helper method to create properly formatted errors\n\t */\n\tprotected createError(\n\t\tmessage: string,\n\t\tcode: string,\n\t\tdetails?: unknown,\n\t): PluginError {\n\t\treturn new PluginError(message, {\n\t\t\tcode,\n\t\t\tpluginName: this.name,\n\t\t\tdetails,\n\t\t});\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,8BAAAA;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,0BAAAC;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,2BAAAC;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;AC0JO,SAAS,eAAe,OAAuC;AACrE,MAAI,OAAO,UAAU,YAAY,UAAU,MAAM;AAChD,WAAO;AAAA,EACR;AAEA,QAAM,MAAM;AAEZ,SACC,aAAa,OACb,OAAO,IAAI,SAAS,MAAM,YAC1B,aAAa,OACb,OAAO,IAAI,SAAS,MAAM;AAE5B;AAKO,SAAS,iBAAoB,OAAyC;AAC5E,SAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,aAAa;AACpE;AAKO,IAAM,2BAAsD;AAAA,EAClE,MAAM;AAAA,EACN,WAAW;AAAA,EACX,WAAW;AACZ;AAKO,IAAM,qBAA0C;AAAA,EACtD,SAAS;AAAA,EACT,iBAAiB;AAAA,EACjB,cAAc;AACf;;;ACzHO,IAAM,cAAN,MAAM,qBAEH,MAAM;AAAA;AAAA,EAEN;AAAA;AAAA,EAGA;AAAA;AAAA,EAGA;AAAA;AAAA,EAGA;AAAA;AAAA,EAGS;AAAA;AAAA;AAAA,EAKT;AAAA;AAAA,EAGA;AAAA;AAAA,EAGA;AAAA;AAAA,EAGA;AAAA,EAET,YAAY,SAAiB,SAAuC;AACnE,UAAM,SAAS,EAAE,OAAO,QAAQ,MAAM,CAAC;AAEvC,SAAK,OAAO,KAAK,YAAY;AAC7B,SAAK,OAAO,QAAQ;AACpB,SAAK,YAAY,oBAAI,KAAK;AAC1B,SAAK,YAAY,QAAQ;AACzB,SAAK,UAAU,QAAQ;AACvB,SAAK,QAAQ,QAAQ;AAGrB,SAAK,aAAa,QAAQ;AAC1B,SAAK,WAAW,QAAQ;AACxB,SAAK,WAAW,QAAQ;AACxB,SAAK,gBAAgB,QAAQ;AAG7B,QAAI,MAAM,mBAAmB;AAC5B,YAAM,kBAAkB,MAAM,KAAK,WAAW;AAAA,IAC/C;AAAA,EACD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,SAAgC;AAC/B,UAAM,OAA8B;AAAA,MACnC,MAAM,KAAK;AAAA,MACX,SAAS,KAAK;AAAA,MACd,MAAM,KAAK;AAAA,MACX,WAAW,KAAK,UAAU,YAAY;AAAA,IACvC;AAGA,QAAI,KAAK,UAAW,MAAK,YAAY,KAAK;AAC1C,QAAI,KAAK,QAAS,MAAK,UAAU,KAAK;AACtC,QAAI,KAAK,WAAY,MAAK,aAAa,KAAK;AAC5C,QAAI,KAAK,SAAU,MAAK,WAAW,KAAK;AACxC,QAAI,KAAK,aAAa,OAAW,MAAK,WAAW,KAAK;AACtD,QAAI,KAAK,cAAe,MAAK,gBAAgB,KAAK;AAElD,QAAI,KAAK,OAAO;AACf,WAAK,QAAQ;AAAA,QACZ,SAAS,KAAK,MAAM;AAAA,QACpB,MAAM,KAAK,MAAM;AAAA,MAClB;AAAA,IACD;AAEA,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA,EAKA,oBAA4B;AAC3B,UAAM,QAAQ;AAAA,MACb,IAAI,KAAK,IAAI,KAAK,KAAK,OAAO;AAAA,MAC9B,WAAW,KAAK,IAAI;AAAA,MACpB,gBAAgB,KAAK,UAAU,YAAY,CAAC;AAAA,IAC7C;AAEA,QAAI,KAAK,WAAW;AACnB,YAAM,KAAK,gBAAgB,KAAK,SAAS,EAAE;AAAA,IAC5C;AAEA,QAAI,KAAK,aAAa,QAAW;AAChC,YAAM,KAAK,eAAe,KAAK,UAAU,KAAK,QAAQ,CAAC,EAAE;AAAA,IAC1D;AAEA,QAAI,KAAK,UAAU;AAClB,YAAM,KAAK,eAAe,KAAK,QAAQ,EAAE;AAAA,IAC1C;AAEA,QAAI,KAAK,YAAY;AACpB,YAAM,KAAK,iBAAiB,KAAK,UAAU,EAAE;AAAA,IAC9C;AAEA,QAAI,KAAK,eAAe;AACvB,YAAM,KAAK,oBAAoB,KAAK,aAAa,EAAE;AAAA,IACpD;AAEA,QAAI,KAAK,OAAO;AACf,YAAM,KAAK,gBAAgB,KAAK,MAAM,OAAO,EAAE;AAAA,IAChD;AAEA,WAAO,MAAM,KAAK,IAAI;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,cAAc,OAAsC;AAC1D,WAAO,iBAAiB;AAAA,EACzB;AACD;;;ACtDO,IAAM,qBAAN,cAAiC,YAAiC;AAAA,EAC/D;AAAA,EACA;AAAA,EAET,YAAY,SAAiB,SAAoC;AAChE,UAAM,kBAAkB,QAAQ,YAC7B,WAAW,QAAQ,OAAO,IAAI,QAAQ,SAAS,KAC/C,WAAW,QAAQ,OAAO;AAE7B,UAAM,SAAS;AAAA,MACd,MAAM,QAAQ;AAAA,MACd,WAAW;AAAA,MACX,SAAS,QAAQ;AAAA,MACjB,OAAO,QAAQ;AAAA,MACf,YAAY,QAAQ;AAAA,MACpB,UAAU,QAAQ;AAAA,MAClB,UAAU,QAAQ;AAAA,IACnB,CAAC;AAED,SAAK,UAAU,QAAQ;AACvB,SAAK,mBAAmB,QAAQ;AAAA,EACjC;AAAA,EAES,SAAuC;AAC/C,UAAM,OAAO,MAAM,OAAO;AAE1B,QAAI,KAAK,kBAAkB;AAC1B,aAAO;AAAA,QACN,GAAG;AAAA,QACH,SAAS,KAAK;AAAA,QACd,kBAAkB,KAAK;AAAA,MACxB;AAAA,IACD;AAEA,WAAO,EAAE,GAAG,MAAM,SAAS,KAAK,QAAQ;AAAA,EACzC;AAAA,EAES,oBAA4B;AACpC,UAAM,cAAc,MAAM,kBAAkB;AAC5C,UAAM,QAAQ,YAAY,MAAM,IAAI;AAEpC,UAAM,aAAuB,CAAC,cAAc,KAAK,OAAO,EAAE;AAE1D,QAAI,KAAK,kBAAkB;AAC1B,iBAAW,KAAK,wBAAwB,KAAK,gBAAgB,EAAE;AAAA,IAChE;AAEA,UAAM,OAAO,GAAG,GAAG,GAAG,UAAU;AAChC,WAAO,MAAM,KAAK,IAAI;AAAA,EACvB;AACD;;;ACnLO,SAAS,oBAAoB,KAAqB;AACxD,MAAI,QAAQ,IAAI,UAAU,MAAM,eAAe;AAC9C,WAAO;AAAA,EACR;AACA,SAAO,IAAI,SAAS,MAAM,IAAI,UAAU,GAAG,GAAG,IAAI,QAAQ;AAC3D;AAMO,SAAS,kBAAkB,QAAyC;AAC1E,QAAM,IAAI,mBAAmB,6BAA6B;AAAA,IACzD,SAAS,OAAO;AAAA,IAChB,MAAM;AAAA,IACN,WAAW;AAAA,IACX,YAAY;AAAA,EACb,CAAC;AACF;AAEO,SAAS,qBAAqB,QAK3B;AACT,QAAM,IAAI,mBAAmB,OAAO,SAAS;AAAA,IAC5C,SAAS,OAAO;AAAA,IAChB,MAAM;AAAA,IACN,WAAW,OAAO,aAAa;AAAA,IAC/B,OAAO,OAAO;AAAA,EACf,CAAC;AACF;AAMO,SAAS,oBAAoB,QAM1B;AACT,QAAM,IAAI,mBAAmB,OAAO,SAAS;AAAA,IAC5C,SAAS,OAAO;AAAA,IAChB,MAAM;AAAA,IACN,WAAW;AAAA,IACX,SAAS,OAAO,QAAQ,EAAE,OAAO,OAAO,MAAM,IAAI;AAAA,IAClD,OAAO,OAAO;AAAA,IACd,YAAY,OAAO;AAAA,EACpB,CAAC;AACF;AAMO,SAAS,wBAAwB,QAK9B;AACT,QAAM,IAAI,mBAAmB,OAAO,SAAS;AAAA,IAC5C,SAAS,OAAO;AAAA,IAChB,MAAM;AAAA,IACN,WAAW;AAAA,IACX,SAAS,OAAO,QAAQ,EAAE,OAAO,OAAO,MAAM,IAAI;AAAA,IAClD,OAAO,OAAO;AAAA,EACf,CAAC;AACF;AAMO,SAAS,gBAAgB,QAStB;AACT,QAAM,IAAI,mBAAmB,OAAO,SAAS;AAAA,IAC5C,SAAS,OAAO;AAAA,IAChB,MAAM;AAAA,IACN,WAAW;AAAA,IACX,SAAS;AAAA,MACR,GAAI,OAAO,SAAS;AAAA,QACnB,OAAO,EAAE,MAAM,OAAO,MAAM,MAAM,OAAO,OAAO,MAAM,MAAM;AAAA,MAC7D;AAAA,MACA,GAAI,OAAO,OAAO,EAAE,KAAK,oBAAoB,OAAO,GAAG,EAAE;AAAA,IAC1D;AAAA,IACA,OAAO,OAAO;AAAA,IACd,YAAY,OAAO;AAAA,IACnB,UAAU,OAAO;AAAA,IACjB,UAAU,OAAO;AAAA,EAClB,CAAC;AACF;AAEO,SAAS,sBAAsB,QAI5B;AACT,QAAM,IAAI;AAAA,IACT,GAAG,OAAO,SAAS,kCAAkC,OAAO,KAAK;AAAA,IACjE;AAAA,MACC,SAAS,OAAO;AAAA,MAChB,MAAM;AAAA,MACN,WAAW;AAAA,MACX,SAAS,EAAE,OAAO,OAAO,OAAO,WAAW,OAAO,UAAU;AAAA,MAC5D,YAAY,yBAAyB,OAAO,SAAS;AAAA,MACrD,UAAU;AAAA,IACX;AAAA,EACD;AACD;AAMO,SAAS,sBAAsB,QAI5B;AACT,QAAM,IAAI,mBAAmB,OAAO,SAAS;AAAA,IAC5C,SAAS,OAAO;AAAA,IAChB,MAAM;AAAA,IACN,WAAW;AAAA,IACX,OAAO,OAAO;AAAA,EACf,CAAC;AACF;AAEO,SAAS,iCAAiC,QAEvC;AACT,QAAM,IAAI,mBAAmB,iCAAiC;AAAA,IAC7D,SAAS,OAAO;AAAA,IAChB,MAAM;AAAA,IACN,WAAW;AAAA,IACX,YAAY;AAAA,EACb,CAAC;AACF;AAEO,SAAS,kCAAkC,QAExC;AACT,QAAM,IAAI,mBAAmB,mCAAmC;AAAA,IAC/D,SAAS,OAAO;AAAA,IAChB,MAAM;AAAA,IACN,WAAW;AAAA,IACX,YAAY;AAAA,EACb,CAAC;AACF;AAEO,SAAS,sCAAsC,QAE5C;AACT,QAAM,IAAI;AAAA,IACT,uCAAuC,OAAO,OAAO;AAAA,IACrD;AAAA,MACC,SAAS,OAAO;AAAA,MAChB,MAAM;AAAA,MACN,WAAW;AAAA,MACX,YAAY;AAAA,IACb;AAAA,EACD;AACD;AAEO,SAAS,0BAA0B,QAEhC;AACT,QAAM,IAAI;AAAA,IACT,4CAA4C,OAAO,OAAO;AAAA,IAC1D;AAAA,MACC,SAAS,OAAO;AAAA,MAChB,MAAM;AAAA,MACN,WAAW;AAAA,MACX,YAAY;AAAA,IACb;AAAA,EACD;AACD;AAMO,SAAS,mBAAmB,QAGzB;AACT,QAAM,IAAI,mBAAmB,8BAA8B,OAAO,KAAK,IAAI;AAAA,IAC1E,SAAS,OAAO;AAAA,IAChB,MAAM;AAAA,IACN,WAAW;AAAA,IACX,SAAS,EAAE,OAAO,OAAO,MAAM;AAAA,IAC/B,YAAY;AAAA,IACZ,UAAU;AAAA,EACX,CAAC;AACF;AAEO,SAAS,oBAAoB,QAG1B;AACT,QAAM,IAAI;AAAA,IACT,+BAA+B,OAAO,SAAS;AAAA,IAC/C;AAAA,MACC,SAAS,OAAO;AAAA,MAChB,MAAM;AAAA,MACN,WAAW;AAAA,MACX,SAAS,EAAE,OAAO,OAAO,UAAU;AAAA,MACnC,YAAY;AAAA,MACZ,UAAU;AAAA,IACX;AAAA,EACD;AACD;AAEO,SAAS,sBAAsB,QAI5B;AACT,QAAM,IAAI;AAAA,IACT,mBAAmB,OAAO,YAAY,0BAA0B,OAAO,UAAU;AAAA,IACjF;AAAA,MACC,SAAS,OAAO;AAAA,MAChB,MAAM;AAAA,MACN,WAAW;AAAA,MACX,SAAS,EAAE,cAAc,OAAO,cAAc,OAAO,OAAO,WAAW;AAAA,MACvE,YAAY,QAAQ,OAAO,YAAY,yBAAyB,OAAO,UAAU;AAAA,MACjF,UAAU,mBAAmB,OAAO,YAAY;AAAA,IACjD;AAAA,EACD;AACD;AAEO,SAAS,yBAAyB,QAK/B;AACT,QAAM,IAAI;AAAA,IACT,UAAU,OAAO,YAAY,YAAY,OAAO,SAAS,wCAAwC,OAAO,UAAU;AAAA,IAClH;AAAA,MACC,SAAS,OAAO;AAAA,MAChB,MAAM;AAAA,MACN,WAAW;AAAA,MACX,SAAS;AAAA,QACR,cAAc,OAAO;AAAA,QACrB,OAAO,OAAO;AAAA,QACd,OAAO,OAAO;AAAA,MACf;AAAA,MACA,YAAY,wCAAwC,OAAO,YAAY;AAAA,MACvE,UAAU;AAAA,MACV,UAAU,OAAO;AAAA,IAClB;AAAA,EACD;AACD;AAEO,SAAS,yBAAyB,QAK/B;AACT,QAAM,IAAI;AAAA,IACT,iBAAiB,OAAO,WAAW,6BAA6B,OAAO,YAAY,gBAAgB,OAAO,UAAU;AAAA,IACpH;AAAA,MACC,SAAS,OAAO;AAAA,MAChB,MAAM;AAAA,MACN,WAAW;AAAA,MACX,SAAS;AAAA,QACR,aAAa,OAAO;AAAA,QACpB,cAAc,OAAO;AAAA,QACrB,OAAO,OAAO;AAAA,MACf;AAAA,MACA,YAAY,iBAAiB,OAAO,WAAW;AAAA,MAC/C,UAAU,qBAAqB,OAAO,WAAW;AAAA,IAClD;AAAA,EACD;AACD;AAEO,SAAS,2BAA2B,QAKjC;AACT,QAAM,IAAI;AAAA,IACT,mBAAmB,OAAO,aAAa,wCAAwC,OAAO,YAAY,gBAAgB,OAAO,UAAU;AAAA,IACnI;AAAA,MACC,SAAS,OAAO;AAAA,MAChB,MAAM;AAAA,MACN,WAAW;AAAA,MACX,SAAS;AAAA,QACR,eAAe,OAAO;AAAA,QACtB,cAAc,OAAO;AAAA,QACrB,OAAO,OAAO;AAAA,MACf;AAAA,MACA,YAAY,0BAA0B,OAAO,aAAa;AAAA,MAC1D,UAAU,UAAU,OAAO,aAAa;AAAA,IACzC;AAAA,EACD;AACD;AAEO,SAAS,sBAAsB,QAK5B;AACT,QAAM,IAAI;AAAA,IACT,qCAAqC,OAAO,QAAQ,aAAa,OAAO,YAAY;AAAA,IACpF;AAAA,MACC,SAAS,OAAO;AAAA,MAChB,MAAM;AAAA,MACN,WAAW;AAAA,MACX,SAAS;AAAA,QACR,OAAO,OAAO;AAAA,QACd,UAAU,OAAO;AAAA,QACjB,cAAc,OAAO;AAAA,MACtB;AAAA,MACA,YAAY,iEAAiE,OAAO,QAAQ;AAAA,MAC5F,UAAU,YAAY,OAAO,QAAQ;AAAA,MACrC,UAAU,UAAU,OAAO,YAAY;AAAA,IACxC;AAAA,EACD;AACD;AAEO,SAAS,wBAA+C,QAOrD;AACT,QAAM,gBAAgB,OAAO,WAC1B,UAAU,OAAO,QAAQ,cACzB;AACH,QAAM,IAAI;AAAA,IACT,8CAA8C,OAAO,MAAM,KAAK,IAAI,aAAa;AAAA,IACjF;AAAA,MACC,SAAS,OAAO;AAAA,MAChB,MAAM;AAAA,MACN,WAAW;AAAA,MACX,SAAS;AAAA,QACR,OAAO,OAAO,MAAM;AAAA,QACpB,OAAO,EAAE,MAAM,OAAO,MAAM,KAAK;AAAA,QACjC,KAAK,oBAAoB,OAAO,GAAG;AAAA,QACnC,QAAQ,OAAO,eAAe,CAAC;AAAA,QAC/B,UAAU,OAAO;AAAA,MAClB;AAAA,MACA,OAAO,OAAO;AAAA,MACd,YACC;AAAA,MACD,UAAU;AAAA,IACX;AAAA,EACD;AACD;AAEO,SAAS,4BAA4B,QAKlC;AACT,QAAM,IAAI;AAAA,IACT,4BAA4B,OAAO,UAAU,mBAAmB,OAAO,YAAY;AAAA,IACnF;AAAA,MACC,SAAS,OAAO;AAAA,MAChB,MAAM;AAAA,MACN,WAAW;AAAA,MACX,SAAS;AAAA,QACR,cAAc,OAAO;AAAA,QACrB,YAAY,OAAO;AAAA,QACnB,aAAa,OAAO;AAAA,MACrB;AAAA,MACA,YACC;AAAA,MACD,UAAU;AAAA,MACV,UAAU,GAAG,OAAO,UAAU,KAAK,KAAK,UAAU,OAAO,WAAW,CAAC;AAAA,IACtE;AAAA,EACD;AACD;AAMO,SAAS,oBAAoB,QAK1B;AACT,QAAM,IAAI;AAAA,IACT,yCAAyC,OAAO,YAAY,YAAY,OAAO,YAAY;AAAA,IAC3F;AAAA,MACC,SAAS,OAAO;AAAA,MAChB,MAAM;AAAA,MACN,WAAW;AAAA,MACX,SAAS;AAAA,QACR,cAAc,OAAO;AAAA,QACrB,cAAc,OAAO;AAAA,MACtB;AAAA,MACA,OAAO,OAAO;AAAA,MACd,YAAY;AAAA,MACZ,UAAU,SAAS,OAAO,YAAY;AAAA,IACvC;AAAA,EACD;AACD;AAEO,SAAS,sBAAsB,QAI5B;AACT,QAAM,IAAI;AAAA,IACT,iDAAiD,OAAO,YAAY;AAAA,IACpE;AAAA,MACC,SAAS,OAAO;AAAA,MAChB,MAAM;AAAA,MACN,WAAW;AAAA,MACX,SAAS,EAAE,cAAc,OAAO,aAAa;AAAA,MAC7C,OAAO,OAAO;AAAA,MACd,YACC;AAAA,MACD,UAAU;AAAA,IACX;AAAA,EACD;AACD;AAMO,SAAS,0BAA0B,QAIhC;AACT,QAAM,IAAI;AAAA,IACT,qDAAqD,OAAO,YAAY;AAAA,IACxE;AAAA,MACC,SAAS,OAAO;AAAA,MAChB,MAAM;AAAA,MACN,WAAW;AAAA,MACX,SAAS,EAAE,cAAc,OAAO,aAAa;AAAA,MAC7C,OAAO,OAAO;AAAA,MACd,YAAY;AAAA,MACZ,UAAU;AAAA,IACX;AAAA,EACD;AACD;AAEO,SAAS,2BAA2B,QAIjC;AACT,QAAM,IAAI;AAAA,IACT,oCAAoC,OAAO,SAAS;AAAA,IACpD;AAAA,MACC,SAAS,OAAO;AAAA,MAChB,MAAM;AAAA,MACN,WAAW;AAAA,MACX,SAAS,EAAE,qBAAqB,OAAO,UAAU;AAAA,MACjD,OAAO,OAAO;AAAA,MACd,YAAY;AAAA,MACZ,UAAU;AAAA,IACX;AAAA,EACD;AACD;AAMO,SAAS,4BAA4B,QAIlC;AACT,QAAM,IAAI;AAAA,IACT,eAAe,OAAO,KAAK,yCAAyC,OAAO,KAAK;AAAA,IAChF;AAAA,MACC,SAAS,OAAO;AAAA,MAChB,MAAM;AAAA,MACN,WAAW;AAAA,MACX,SAAS,EAAE,OAAO,OAAO,OAAO,OAAO,OAAO,MAAM;AAAA,MACpD,YAAY,mDAAmD,OAAO,KAAK;AAAA,IAC5E;AAAA,EACD;AACD;AAEO,SAAS,uBAAuB,QAI7B;AACT,QAAM,IAAI;AAAA,IACT,eAAe,OAAO,KAAK,oCAAoC,OAAO,KAAK;AAAA,IAC3E;AAAA,MACC,SAAS,OAAO;AAAA,MAChB,MAAM;AAAA,MACN,WAAW;AAAA,MACX,SAAS,EAAE,OAAO,OAAO,OAAO,OAAO,OAAO,MAAM;AAAA,MACpD,YAAY,oCAAoC,OAAO,KAAK;AAAA,IAC7D;AAAA,EACD;AACD;AAMO,SAAS,iBAAiB,QAGvB;AACT,QAAM,IAAI;AAAA,IACT,iCAAiC,OAAO,WAAW;AAAA,IACnD;AAAA,MACC,SAAS,OAAO;AAAA,MAChB,MAAM;AAAA,MACN,WAAW;AAAA,MACX,SAAS,EAAE,aAAa,OAAO,YAAY;AAAA,MAC3C,YACC;AAAA,MACD,UAAU;AAAA,IACX;AAAA,EACD;AACD;AAEO,SAAS,eAAe,QAGrB;AACT,QAAM,IAAI,mBAAmB,0BAA0B;AAAA,IACtD,SAAS,OAAO;AAAA,IAChB,MAAM;AAAA,IACN,WAAW;AAAA,IACX,OAAO,OAAO;AAAA,IACd,YAAY;AAAA,EACb,CAAC;AACF;AAMO,SAAS,mBAAmB,QAIzB;AACT,QAAM,IAAI,mBAAmB,wBAAwB,OAAO,IAAI,IAAI;AAAA,IACnE,SAAS,OAAO;AAAA,IAChB,MAAM;AAAA,IACN,WAAW;AAAA,IACX,SAAS,EAAE,MAAM,OAAO,KAAK;AAAA,IAC7B,OAAO,OAAO;AAAA,IACd,YAAY;AAAA,EACb,CAAC;AACF;AAEO,SAAS,oBAAoB,QAI1B;AACT,QAAM,IAAI,mBAAmB,yBAAyB,OAAO,IAAI,IAAI;AAAA,IACpE,SAAS,OAAO;AAAA,IAChB,MAAM;AAAA,IACN,WAAW;AAAA,IACX,SAAS,EAAE,MAAM,OAAO,KAAK;AAAA,IAC7B,OAAO,OAAO;AAAA,IACd,YAAY;AAAA,EACb,CAAC;AACF;AAEO,SAAS,kBAAkB,QAGxB;AACT,QAAM,IAAI,mBAAmB,mBAAmB,OAAO,IAAI,IAAI;AAAA,IAC9D,SAAS,OAAO;AAAA,IAChB,MAAM;AAAA,IACN,WAAW;AAAA,IACX,SAAS,EAAE,MAAM,OAAO,KAAK;AAAA,IAC7B,YAAY;AAAA,EACb,CAAC;AACF;AAMO,SAAS,2BAA2B,QAKjC;AACT,QAAM,IAAI;AAAA,IACT,oBAAoB,OAAO,KAAK,uBAAuB,OAAO,KAAK;AAAA,IACnE;AAAA,MACC,SAAS,OAAO;AAAA,MAChB,MAAM;AAAA,MACN,WAAW;AAAA,MACX,SAAS;AAAA,QACR,OAAO,OAAO;AAAA,QACd,OAAO,OAAO;AAAA,QACd,OAAO,OAAO;AAAA,MACf;AAAA,MACA,YAAY,WAAW,OAAO,KAAK,+BAA+B,OAAO,KAAK;AAAA,MAC9E,UAAU;AAAA,MACV,UAAU,OAAO;AAAA,IAClB;AAAA,EACD;AACD;AAEO,SAAS,2BAA2B,QAIjC;AACT,QAAM,IAAI;AAAA,IACT,qCAAqC,OAAO,OAAO,KAAK,IAAI,CAAC;AAAA,IAC7D;AAAA,MACC,SAAS,OAAO;AAAA,MAChB,MAAM;AAAA,MACN,WAAW;AAAA,MACX,SAAS,EAAE,QAAQ,OAAO,OAAO,KAAK,IAAI,GAAG,OAAO,OAAO,MAAM;AAAA,MACjE,YAAY,0BAA0B,OAAO,OAAO,KAAK,IAAI,CAAC,yBAAyB,OAAO,KAAK;AAAA,MACnG,UAAU;AAAA,IACX;AAAA,EACD;AACD;AAEO,SAAS,0BAA0B,QAMhC;AACT,QAAM,IAAI;AAAA,IACT,kCAAkC,OAAO,WAAW,aAAa,OAAO,KAAK;AAAA,IAC7E;AAAA,MACC,SAAS,OAAO;AAAA,MAChB,MAAM;AAAA,MACN,WAAW;AAAA,MACX,SAAS;AAAA,QACR,YAAY,OAAO;AAAA,QACnB,OAAO,OAAO;AAAA,QACd,aAAa,OAAO;AAAA,QACpB,OAAO,OAAO;AAAA,MACf;AAAA,MACA,YAAY,UAAU,OAAO,WAAW,aAAa,OAAO,KAAK;AAAA,MACjE,UAAU,YAAY,OAAO,WAAW;AAAA,MACxC,UAAU,OAAO;AAAA,IAClB;AAAA,EACD;AACD;AAMO,SAAS,uBAAuB,QAK7B;AACT,QAAM,IAAI;AAAA,IACT,gCAAgC,OAAO,KAAK,+BAA+B,OAAO,UAAU;AAAA,IAC5F;AAAA,MACC,SAAS,OAAO;AAAA,MAChB,MAAM;AAAA,MACN,WAAW;AAAA,MACX,SAAS;AAAA,QACR,OAAO,OAAO;AAAA,QACd,YAAY,OAAO;AAAA,QACnB,iBAAiB,OAAO,gBAAgB,KAAK,IAAI;AAAA,MAClD;AAAA,MACA,YAAY,oCAAoC,OAAO,gBAAgB,KAAK,IAAI,CAAC;AAAA,MACjF,UAAU,iCAAiC,OAAO,UAAU;AAAA,MAC5D,UAAU,OAAO;AAAA,IAClB;AAAA,EACD;AACD;AAEO,SAAS,gCAAgC,QAKtC;AACT,QAAM,IAAI;AAAA,IACT,qFAAqF,OAAO,YAAY;AAAA,IACxG;AAAA,MACC,SAAS,OAAO;AAAA,MAChB,MAAM;AAAA,MACN,WAAW;AAAA,MACX,SAAS;AAAA,QACR,cAAc,OAAO;AAAA,QACrB,YAAY,OAAO;AAAA,QACnB,YAAY,OAAO;AAAA,MACpB;AAAA,MACA,YACC,8BAA8B,OAAO,YAAY;AAAA,uCACT,OAAO,UAAU;AAAA,MAC1D,UACC;AAAA,MACD,UAAU;AAAA,IACX;AAAA,EACD;AACD;;;AC5nBO,IAAM,kBAAN,cAA8B,YAA8B;AAAA,EACzD;AAAA,EAET,YAAY,SAAiB,SAAiC;AAC7D,UAAM,SAAS;AAAA,MACd,MAAM,QAAQ;AAAA,MACd,WAAW,QAAQ,WAAW,QAAQ,QAAQ,QAAQ,KAAK;AAAA,MAC3D,SAAS,QAAQ;AAAA,MACjB,OAAO,QAAQ;AAAA,MACf,YAAY,QAAQ;AAAA,MACpB,UAAU,QAAQ;AAAA,MAClB,UAAU,QAAQ;AAAA,IACnB,CAAC;AAED,SAAK,WAAW,QAAQ;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA,EAKS,SAAoC;AAC5C,UAAM,OAAO,MAAM,OAAO;AAE1B,QAAI,KAAK,UAAU;AAClB,aAAO;AAAA,QACN,GAAG;AAAA,QACH,UAAU,KAAK;AAAA,MAChB;AAAA,IACD;AAEA,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA,EAKS,oBAA4B;AACpC,UAAM,cAAc,MAAM,kBAAkB;AAE5C,QAAI,KAAK,UAAU;AAClB,YAAM,QAAQ,YAAY,MAAM,IAAI;AACpC,YAAM,OAAO,GAAG,GAAG,eAAe,KAAK,QAAQ,EAAE;AACjD,aAAO,MAAM,KAAK,IAAI;AAAA,IACvB;AAEA,WAAO;AAAA,EACR;AACD;;;ACCO,IAAM,cAAN,cAA0B,YAAgC;AAAA,EACvD;AAAA,EACA;AAAA,EAET,YAAY,SAAiB,SAA6B;AACzD,UAAM,SAAS;AAAA,MACd,MAAM,QAAQ;AAAA,MACd,WAAW,SAAS,QAAQ,MAAM;AAAA,MAClC,SAAS,QAAQ;AAAA,MACjB,YAAY,QAAQ;AAAA,MACpB,UAAU,QAAQ;AAAA,MAClB,UAAU,QAAQ;AAAA,IACnB,CAAC;AAED,SAAK,SAAS,QAAQ;AACtB,SAAK,WAAW,QAAQ;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA,EAKS,SAAgC;AACxC,WAAO;AAAA,MACN,GAAG,MAAM,OAAO;AAAA,MAChB,QAAQ,KAAK;AAAA,MACb,UAAU,KAAK;AAAA,IAChB;AAAA,EACD;AAAA;AAAA;AAAA;AAAA,EAKS,oBAA4B;AACpC,UAAM,cAAc,MAAM,kBAAkB;AAC5C,UAAM,aAAa;AAAA,MAClB,aAAa,KAAK,MAAM;AAAA,MACxB,eAAe,KAAK,SAAS,IAAI;AAAA,IAClC;AAEA,QAAI,KAAK,SAAS,YAAY;AAC7B,iBAAW,KAAK,kBAAkB,KAAK,SAAS,UAAU,EAAE;AAAA,IAC7D;AAEA,QAAI,KAAK,SAAS,UAAU,QAAW;AACtC,iBAAW,KAAK,YAAY,KAAK,SAAS,KAAK,EAAE;AAAA,IAClD;AAEA,QAAI,KAAK,SAAS,UAAU,QAAW;AACtC,iBAAW,KAAK,YAAY,KAAK,SAAS,KAAK,EAAE;AAAA,IAClD;AAGA,UAAM,QAAQ,YAAY,MAAM,IAAI;AACpC,UAAM,OAAO,GAAG,GAAG,GAAG,UAAU;AAEhC,WAAO,MAAM,KAAK,IAAI;AAAA,EACvB;AACD;AAKO,SAAS,mBACf,OACA,SAKgB;AAChB,SAAO;AAAA,IACN,MAAM,MAAM,KAAK,GAAG;AAAA,IACpB;AAAA,IACA,YAAY,SAAS;AAAA,IACrB,OAAO,SAAS;AAAA,IAChB,OAAO,SAAS;AAAA,EACjB;AACD;;;AC5KO,IAAM,oBAAN,cAAgC,YAAgC;AAAA,EAC7D;AAAA,EAET,YAAY,SAAiB,SAAmC;AAC/D,UAAM,SAAS;AAAA,MACd,MAAM,QAAQ;AAAA,MACd,WAAW;AAAA,MACX,SAAS,QAAQ;AAAA,MACjB,OAAO,QAAQ;AAAA,MACf,YAAY,QAAQ;AAAA,MACpB,UAAU,QAAQ;AAAA,MAClB,UAAU,QAAQ;AAAA,IACnB,CAAC;AAED,SAAK,QAAQ,QAAQ;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA,EAKS,SAAsC;AAC9C,WAAO;AAAA,MACN,GAAG,MAAM,OAAO;AAAA,MAChB,GAAI,KAAK,SAAS,EAAE,OAAO,KAAK,MAAM;AAAA,IACvC;AAAA,EACD;AAAA;AAAA;AAAA;AAAA,EAKS,oBAA4B;AACpC,UAAM,cAAc,MAAM,kBAAkB;AAE5C,QAAI,KAAK,OAAO;AACf,YAAM,aAAa,CAAC,YAAY,KAAK,KAAK,EAAE;AAC5C,YAAM,QAAQ,YAAY,MAAM,IAAI;AACpC,YAAM,OAAO,GAAG,GAAG,GAAG,UAAU;AAChC,aAAO,MAAM,KAAK,IAAI;AAAA,IACvB;AAEA,WAAO;AAAA,EACR;AACD;AAKO,IAAM,8BAAN,cAA0C,kBAAkB;AAAA,EACzD;AAAA,EAET,YAAY,QAA2B,YAAqB;AAC3D,UAAM,YAAY,OAAO,IAAI,CAAC,MAAM,OAAO,CAAC,EAAE,EAAE,KAAK,IAAI;AAEzD,UAAM;AAAA,EAA8B,SAAS,IAAI;AAAA,MAChD,MAAM;AAAA,MACN,SAAS,EAAE,OAAO;AAAA,MAClB,YAAY,cAAc;AAAA,IAC3B,CAAC;AAED,SAAK,SAAS;AAAA,EACf;AAAA;AAAA;AAAA;AAAA,EAKS,oBAA4B;AACpC,UAAM,cAAc,MAAM,kBAAkB;AAC5C,UAAM,eAAe,KAAK,OAAO,IAAI,CAAC,QAAQ,OAAO,GAAG,EAAE;AAE1D,WAAO,GAAG,WAAW;AAAA;AAAA;AAAA,EAA2B,aAAa,KAAK,IAAI,CAAC;AAAA,EACxE;AACD;;;ACxDO,IAAM,kBAAN,cAA8B,YAA8B;AAAA,EAChD;AAAA,EACT;AAAA,EAET,YAAY,SAAiB,SAAiC;AAC7D,UAAM,SAAS;AAAA,MACd,MAAM,QAAQ;AAAA,MACd,WAAW,QAAQ,QAAQ,SAAS;AAAA,MACpC,SAAS,QAAQ;AAAA,MACjB,OAAO,QAAQ;AAAA,MACf,YAAY,QAAQ;AAAA,MACpB,UAAU,QAAQ;AAAA,MAClB,UAAU,QAAQ;AAAA,IACnB,CAAC;AAED,SAAK,YAAY,QAAQ;AACzB,SAAK,QAAQ,QAAQ;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA,EAKS,SAAoC;AAC5C,WAAO;AAAA,MACN,GAAG,MAAM,OAAO;AAAA,MAChB,WAAW,KAAK;AAAA,MAChB,OAAO,KAAK;AAAA,IACb;AAAA,EACD;AAAA;AAAA;AAAA;AAAA,EAKS,oBAA4B;AACpC,UAAM,cAAc,MAAM,kBAAkB;AAC5C,UAAM,WAAW;AAAA,MAChB,gBAAgB,KAAK,SAAS;AAAA,MAC9B,YAAY,KAAK,KAAK;AAAA,IACvB;AAEA,UAAM,QAAQ,YAAY,MAAM,IAAI;AACpC,UAAM,OAAO,GAAG,GAAG,GAAG,QAAQ;AAE9B,WAAO,MAAM,KAAK,IAAI;AAAA,EACvB;AACD;;;ACvCO,IAAM,0BAAN,cAAsC,YAAsC;AAAA,EACzE;AAAA,EACA;AAAA,EAET,YACC,SACA,SACC;AAED,UAAM,oBACL,OAAO,YAAY,YAAY,YAAY,SACxC;AAAA,MACD,MAAO,WAAqC;AAAA,MAC5C,WAAW;AAAA,IACZ,IACE;AAEJ,UAAM,SAAS;AAAA,MACd,MAAM,kBAAkB;AAAA,MACxB,WAAW,iBAAiB,kBAAkB,SAAS;AAAA,MACvD,SAAS,kBAAkB;AAAA,MAC3B,OAAO,kBAAkB;AAAA,MACzB,YAAY,kBAAkB;AAAA,MAC9B,UAAU,kBAAkB;AAAA,MAC5B,UAAU,kBAAkB;AAAA,IAC7B,CAAC;AAED,SAAK,YAAY,kBAAkB;AACnC,SAAK,QAAQ,kBAAkB;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA,EAKS,SAA4C;AACpD,WAAO;AAAA,MACN,GAAG,MAAM,OAAO;AAAA,MAChB,WAAW,KAAK;AAAA,MAChB,GAAI,KAAK,SAAS,EAAE,OAAO,KAAK,MAAM;AAAA,IACvC;AAAA,EACD;AAAA;AAAA;AAAA;AAAA,EAKS,oBAA4B;AACpC,UAAM,cAAc,MAAM,kBAAkB;AAC5C,UAAM,cAAc,CAAC,gBAAgB,KAAK,SAAS,EAAE;AAErD,QAAI,KAAK,OAAO;AACf,kBAAY,KAAK,YAAY,KAAK,KAAK,EAAE;AAAA,IAC1C;AAEA,UAAM,QAAQ,YAAY,MAAM,IAAI;AACpC,UAAM,OAAO,GAAG,GAAG,GAAG,WAAW;AAEjC,WAAO,MAAM,KAAK,IAAI;AAAA,EACvB;AACD;;;ACvGO,IAAM,wBAAN,cAAoC,YAAY;AAAA,EAC7C;AAAA,EACA;AAAA,EAET,YAAY,SAAiB,SAAuC;AACnE,UAAM,SAAS;AAAA,MACd,MAAM,QAAQ,QAAQ;AAAA,MACtB,WAAW,QAAQ,aAAa;AAAA,MAChC,SAAS;AAAA,QACR,OAAO,QAAQ;AAAA,QACf,QAAQ,QAAQ;AAAA,QAChB,GAAG,QAAQ;AAAA,MACZ;AAAA,MACA,GAAI,QAAQ,cAAc,EAAE,YAAY,QAAQ,WAAW;AAAA,MAC3D,GAAI,QAAQ,YAAY,EAAE,UAAU,QAAQ,SAAS;AAAA,MACrD,GAAI,QAAQ,aAAa,UAAa,EAAE,UAAU,QAAQ,SAAS;AAAA,IACpE,CAAC;AAED,SAAK,QAAQ,QAAQ;AACrB,SAAK,SAAS,QAAQ;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA,EAKS,SAA0C;AAClD,WAAO;AAAA,MACN,GAAG,MAAM,OAAO;AAAA,MAChB,OAAO,KAAK;AAAA,MACZ,QAAQ,KAAK;AAAA,IACd;AAAA,EACD;AAAA;AAAA;AAAA;AAAA,EAKS,oBAA4B;AACpC,UAAM,cAAc,MAAM,kBAAkB;AAC5C,UAAM,eAAe,KAAK,OAAO;AAAA,MAChC,CAAC,QAAQ,OAAO,IAAI,KAAK,KAAK,IAAI,OAAO,KAAK,IAAI,IAAI;AAAA,IACvD;AAEA,WAAO,GAAG,WAAW;AAAA;AAAA;AAAA,EAA4B,aAAa,KAAK,IAAI,CAAC;AAAA,EACzE;AACD;;;ACxDO,SAAS,kBACf,WACA,OACA,iBACQ;AACR,QAAM,IAAI;AAAA,IACT,kBAAkB,KAAK,QAAQ,SAAS;AAAA,IACxC;AAAA,MACC,MAAM;AAAA,MACN;AAAA,MACA;AAAA,MACA,SAAS,kBAAkB,EAAE,gBAAgB,IAAI;AAAA,MACjD,YAAY,kBACT,eAAe,gBAAgB,KAAK,IAAI,CAAC,KACzC,eAAe,KAAK;AAAA,MACvB,UAAU,kBAAkB,gBAAgB,KAAK,KAAK,IAAI;AAAA,MAC1D,UAAU;AAAA,IACX;AAAA,EACD;AACD;AAcO,SAAS,qBACf,OACA,UACA,gBACQ;AACR,QAAM,IAAI;AAAA,IACT,qBAAqB,QAAQ,gBAAgB,KAAK;AAAA,IAClD;AAAA,MACC,MAAM;AAAA,MACN,WAAW;AAAA,MACX;AAAA,MACA,SAAS,EAAE,UAAU,eAAe;AAAA,MACpC,YAAY,eAAe,eAAe,KAAK,IAAI,CAAC;AAAA,MACpD,UAAU,eAAe,KAAK,KAAK;AAAA,MACnC,UAAU;AAAA,IACX;AAAA,EACD;AACD;AAeO,SAAS,kBACf,WACA,OACA,OACA,cACQ;AACR,QAAM,eAAe,MAAM,QAAQ,KAAK,IACrC,UACA,UAAU,OACT,SACA,OAAO;AAEX,QAAM,IAAI;AAAA,IACT,4BAA4B,KAAK,eAAe,YAAY,SAAS,YAAY;AAAA,IACjF;AAAA,MACC,MAAM;AAAA,MACN;AAAA,MACA;AAAA,MACA,SAAS,EAAE,OAAO,cAAc,aAAa;AAAA,MAC7C,YAAY,aAAa,YAAY,eAAe,KAAK;AAAA,MACzD,UAAU;AAAA,MACV,UAAU;AAAA,IACX;AAAA,EACD;AACD;AAcO,SAASC,uBACf,WACA,cACA,UACQ;AACR,QAAM,IAAI;AAAA,IACT,qCAAqC,SAAS,mBAAmB,YAAY,UAAU,QAAQ;AAAA,IAC/F;AAAA,MACC,MAAM;AAAA,MACN;AAAA,MACA,SAAS,EAAE,OAAO,cAAc,SAAS;AAAA,MACzC,YAAY,2BAA2B,QAAQ;AAAA,MAC/C,UAAU,YAAY,QAAQ;AAAA,MAC9B,UAAU;AAAA,IACX;AAAA,EACD;AACD;AAsDO,SAAS,oBAA2B;AAC1C,QAAM,IAAI,wBAAwB,gCAAgC;AAAA,IACjE,MAAM;AAAA,IACN,WAAW;AAAA,IACX,YACC;AAAA,EACF,CAAC;AACF;AAKO,SAAS,0BAAiC;AAChD,QAAM,IAAI;AAAA,IACT;AAAA,IACA;AAAA,MACC,MAAM;AAAA,MACN,WAAW;AAAA,MACX,YACC;AAAA,IACF;AAAA,EACD;AACD;AAKO,SAAS,iBAAiB,WAAuC;AACvE,QAAM,IAAI;AAAA,IACT,GAAG,UAAU,YAAY,CAAC;AAAA,IAC1B;AAAA,MACC,MAAM;AAAA,MACN,WAAW;AAAA,MACX,YACC,cAAc,WACX,6CACA;AAAA,IACL;AAAA,EACD;AACD;AAYO,SAAS,sBAAsB,cAA8B;AACnE,QAAM,IAAI,wBAAwB,uBAAuB,YAAY,IAAI;AAAA,IACxE,MAAM;AAAA,IACN,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,UAAU;AAAA,EACX,CAAC;AACF;AAYO,SAASC,qBAAoB,WAA0B;AAC7D,QAAM,IAAI,wBAAwB,+BAA+B,SAAS,IAAI;AAAA,IAC7E,MAAM;AAAA,IACN,WAAW;AAAA,IACX,SAAS,EAAE,UAAU;AAAA,IACrB,YAAY,eAAe,SAAS;AAAA,IACpC,UAAU;AAAA,EACX,CAAC;AACF;AAcO,SAAS,mBACf,WACA,eACA,iBACQ;AACR,QAAM,YAAY,cAAc,KAAK,IAAI;AACzC,QAAM,IAAI;AAAA,IACT,uBAAuB,SAAS,YAAY,SAAS;AAAA,IACrD;AAAA,MACC,MAAM;AAAA,MACN;AAAA,MACA,OAAO,cAAc,CAAC;AAAA,MACtB,SAAS,EAAE,eAAe,gBAAgB;AAAA,MAC1C,YAAY,kBACT,eAAe,gBAAgB,KAAK,IAAI,CAAC,KACzC;AAAA,MACH,UAAU,kBAAkB,gBAAgB,KAAK,KAAK,IAAI;AAAA,MAC1D,UAAU;AAAA,IACX;AAAA,EACD;AACD;AAaO,SAAS,sBACf,gBACA,WACQ;AACR,QAAM,YAAY,eAAe,KAAK,IAAI;AAC1C,QAAM,IAAI;AAAA,IACT,6CAA6C,SAAS,MAAM,SAAS;AAAA,IACrE;AAAA,MACC,MAAM;AAAA,MACN,WAAW;AAAA,MACX,OAAO,eAAe,CAAC;AAAA,MACvB,SAAS,EAAE,gBAAgB,UAAU;AAAA,MACrC,YAAY,kBAAkB,eAAe,CAAC,CAAC;AAAA,IAChD;AAAA,EACD;AACD;AAeO,SAAS,oBACf,OACA,OACA,cACQ;AACR,QAAM,eAAe,OAAO,UAAU,WAAW,IAAI,KAAK,MAAM,OAAO,KAAK;AAC5E,QAAM,IAAI;AAAA,IACT,wBAAwB,YAAY,OAAO,YAAY,eAAe,KAAK;AAAA,IAC3E;AAAA,MACC,MAAM;AAAA,MACN,WAAW;AAAA,MACX;AAAA,MACA,SAAS,EAAE,OAAO,cAAc,cAAc,OAAO,MAAM;AAAA,MAC3D,YAAY,mBAAmB,YAAY,eAAe,KAAK;AAAA,MAC/D,UAAU;AAAA,MACV,UAAU;AAAA,IACX;AAAA,EACD;AACD;;;ACrVO,IAAM,uBAAuB;AAAA,EACnC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD;AAKA,IAAM,oBAAoB,CAAC,WAAW,SAAS,UAAU;AAKzD,IAAM,mBAAmB;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD;AAqBO,SAAS,YACf,OACA,UACA,WACU;AAEV,MAAI,UAAU,QAAQ,UAAU,QAAW;AAC1C,WAAO;AAAA,EACR;AAGA,MAAI,cAAc,OAAO,SAAS,IAAI,GAAG;AACxC,WAAO;AAAA,EACR;AAGA,MAAI,OAAO,UAAU,UAAU;AAC9B,WAAO,aAAa,OAAO,SAAS,MAAM,SAAS;AAAA,EACpD;AAGA,MAAI,MAAM,QAAQ,KAAK,GAAG;AACzB,WAAO,MAAM,IAAI,CAAC,SAAS,YAAY,MAAM,UAAU,SAAS,CAAC;AAAA,EAClE;AAGA,sBAAoB,WAAW,OAAO,SAAS,IAAI;AACpD;AAQA,SAAS,cAAc,OAAgB,WAA+B;AACrE,UAAQ,WAAW;AAAA,IAClB,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACJ,aAAO,OAAO,UAAU;AAAA,IACzB,KAAK;AACJ,aAAO,OAAO,UAAU,YAAY,CAAC,OAAO,MAAM,KAAK;AAAA,IACxD,KAAK;AACJ,aAAO,OAAO,UAAU;AAAA,IACzB,KAAK;AACJ,aAAO,iBAAiB,QAAQ,CAAC,OAAO,MAAM,MAAM,QAAQ,CAAC;AAAA,IAC9D,KAAK;AACJ,aAAO,OAAO,UAAU;AAAA,IACzB,KAAK;AACJ,aAAO,MAAM,QAAQ,KAAK;AAAA,IAC3B,KAAK;AACJ,aAAO,OAAO,UAAU,YAAY,OAAO,UAAU;AAAA,IACtD;AACC,aAAO;AAAA,EACT;AACD;AAQA,SAAS,aACR,OACA,WACA,WACU;AACV,UAAQ,WAAW;AAAA,IAClB,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACJ,aAAO;AAAA,IAER,KAAK,UAAU;AACd,YAAM,MAAM,OAAO,KAAK;AACxB,UAAI,OAAO,MAAM,GAAG,GAAG;AACtB,4BAAoB,WAAW,OAAO,QAAQ;AAAA,MAC/C;AACA,aAAO;AAAA,IACR;AAAA,IAEA,KAAK,WAAW;AACf,YAAM,QAAQ,MAAM,YAAY;AAChC,UAAI,UAAU,UAAU,UAAU,KAAK;AACtC,eAAO;AAAA,MACR;AACA,UAAI,UAAU,WAAW,UAAU,KAAK;AACvC,eAAO;AAAA,MACR;AACA,0BAAoB,WAAW,OAAO,SAAS;AAAA,IAChD;AAAA,IAEA,KAAK,QAAQ;AACZ,YAAM,OAAO,IAAI,KAAK,KAAK;AAC3B,UAAI,OAAO,MAAM,KAAK,QAAQ,CAAC,GAAG;AACjC,4BAAoB,WAAW,OAAO,MAAM;AAAA,MAC7C;AACA,aAAO;AAAA,IACR;AAAA,IAEA,KAAK,QAAQ;AACZ,UAAI;AACH,eAAO,KAAK,MAAM,KAAK;AAAA,MACxB,QAAQ;AACP,4BAAoB,WAAW,OAAO,MAAM;AAAA,MAC7C;AAAA,IACD;AAAA,IAEA,KAAK,SAAS;AACb,UAAI;AACH,cAAM,SAAS,KAAK,MAAM,KAAK;AAC/B,YAAI,CAAC,MAAM,QAAQ,MAAM,GAAG;AAC3B,8BAAoB,WAAW,OAAO,OAAO;AAAA,QAC9C;AACA,eAAO;AAAA,MACR,QAAQ;AACP,4BAAoB,WAAW,OAAO,OAAO;AAAA,MAC9C;AAAA,IACD;AAAA,IAEA,KAAK,YAAY;AAEhB,YAAM,MAAM,OAAO,KAAK;AACxB,aAAO,OAAO,MAAM,GAAG,IAAI,QAAQ;AAAA,IACpC;AAAA,IAEA;AACC,aAAO;AAAA,EACT;AACD;AAKA,IAAM,kBAAkB;AAKjB,SAAS,sBACf,OAC+B;AAC/B,MAAI,OAAO,UAAU,YAAY,UAAU,MAAM;AAChD,WAAO;AAAA,EACR;AAEA,SAAO,OAAO,KAAK,KAAK,EAAE;AAAA,IAAK,CAAC,QAC9B,qBAA2C,SAAS,GAAG;AAAA,EACzD;AACD;AAKO,SAAS,kBAAkB,KAAsB;AACvD,SAAO,CAAC,QAAQ,OAAO,MAAM,EAAE,SAAS,GAAG;AAC5C;AAWO,SAAS,2BACf,OACA,UACA,OACA,YACO;AACP,UAAQ,UAAU;AAAA,IACjB,KAAK;AAAA,IACL,KAAK;AAEJ,UACC,OAAO,UAAU,YACjB,OAAO,UAAU,YACjB,OAAO,UAAU,aACjB,UAAU,QACV,EAAE,iBAAiB,OAClB;AACD,0BAAkB,SAAS,OAAO,OAAO,iBAAiB;AAAA,MAC3D;AACA;AAAA,IAED,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAEJ,UACC,OAAO,UAAU,YACjB,OAAO,UAAU,YACjB,EAAE,iBAAiB,OAClB;AACD,0BAAkB,SAAS,OAAO,OAAO,yBAAyB;AAAA,MACnE;AACA;AAAA,IAED,KAAK;AAAA,IACL,KAAK;AAEJ,UAAI,CAAC,MAAM,QAAQ,KAAK,GAAG;AAC1B,0BAAkB,SAAS,OAAO,OAAO,OAAO;AAAA,MACjD;AACA;AAAA,IAED,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAEJ,UAAI,OAAO,UAAU,UAAU;AAC9B,0BAAkB,SAAS,OAAO,OAAO,QAAQ;AAAA,MAClD;AACA;AAAA,IAED,KAAK;AAEJ,UAAI,EAAE,iBAAiB,WAAW,OAAO,UAAU,UAAU;AAC5D,0BAAkB,SAAS,OAAO,OAAO,kBAAkB;AAAA,MAC5D;AACA;AAAA,IAED,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAEJ,UAAI,OAAO,UAAU,aAAa,OAAO,UAAU,UAAU;AAC5D,0BAAkB,SAAS,OAAO,OAAO,mBAAmB;AAAA,MAC7D;AACA;AAAA,IAED;AACC,2BAAqB,OAAO,UAAU,oBAAoB;AAAA,EAC5D;AACD;AAUO,SAAS,oBACf,OACA,QACA,gBACA,QAAQ,GACD;AAEP,MAAI,QAAQ,iBAAiB;AAC5B,IAAAC,uBAAsB,SAAS,OAAO,eAAe;AAAA,EACtD;AAEA,QAAM,kBAAkB,OAAO,KAAK,OAAO,MAAM;AAEjD,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,KAAK,GAAG;AAEjD,QAAI,kBAAkB,GAAG,GAAG;AAC3B,UAAI,QAAQ,UAAU,QAAQ,OAAO;AACpC,YAAI,CAAC,MAAM,QAAQ,KAAK,GAAG;AAC1B,4BAAkB,SAAS,KAAK,OAAO,qBAAqB;AAAA,QAC7D;AAGA,mBAAW,aAAa,OAAoC;AAC3D,8BAAoB,WAAW,QAAQ,gBAAgB,QAAQ,CAAC;AAAA,QACjE;AAAA,MACD,WAAW,QAAQ,QAAQ;AAE1B;AAAA,UACC;AAAA,UACA;AAAA,UACA;AAAA,UACA,QAAQ;AAAA,QACT;AAAA,MACD;AACA;AAAA,IACD;AAGA,QAAI,CAAC,gBAAgB,SAAS,GAAG,GAAG;AACnC,wBAAkB,SAAS,KAAK,eAAe;AAAA,IAChD;AAEA,UAAM,WAAW,OAAO,OAAO,GAAG;AAGlC,QAAI,SAAS,SAAS,YAAY;AACjC,YAAM,gBAAgB;AAGtB,UAAI,OAAO,UAAU,YAAY,OAAO,UAAU,UAAU;AAC3D;AAAA,MACD;AAGA,UACC,OAAO,UAAU,YACjB,UAAU,QACV,EAAE,iBAAiB,OAClB;AACD,cAAM,WAAW;AACjB,cAAM,OAAO,OAAO,KAAK,QAAQ;AAIjC,YACC,KAAK,WAAW,MACf,KAAK,CAAC,MAAM,WAAW,KAAK,CAAC,MAAM,aACnC;AACD,gBAAM,UAAU,SAAS,KAAK,CAAC,CAAC;AAEhC,cAAI,OAAO,YAAY,aAAa,OAAO,YAAY,UAAU;AAChE,8BAAkB,SAAS,KAAK,SAAS,mBAAmB;AAAA,UAC7D;AACA;AAAA,QACD;AAGA,YAAI,gBAAgB;AACnB,gBAAM,eAAe,eAAe,IAAI,cAAc,KAAK;AAC3D,cAAI,cAAc;AACjB;AAAA,cACC;AAAA,cACA;AAAA,cACA;AAAA,cACA,QAAQ;AAAA,YACT;AAAA,UACD;AAAA,QACD;AAAA,MACD;AACA;AAAA,IACD;AAGA,QAAI,sBAAsB,KAAK,GAAG;AACjC,YAAM,MAAM;AACZ,iBAAW,CAAC,UAAU,OAAO,KAAK,OAAO,QAAQ,GAAG,GAAG;AACtD,mCAA2B,KAAK,UAAU,SAAS,SAAS,IAAI;AAAA,MACjE;AAAA,IACD,OAEK;AAEJ,UACC,OAAO,UAAU,YACjB,OAAO,UAAU,YACjB,OAAO,UAAU,aACjB,UAAU,QACV,EAAE,iBAAiB,OAClB;AACD,0BAAkB,SAAS,KAAK,OAAO,iBAAiB;AAAA,MACzD;AAAA,IACD;AAAA,EACD;AACD;AAoCO,SAAS,eACf,QACA,QACA,UAC6B;AAC7B,MAAI,CAAC,UAAU,OAAO,WAAW,GAAG;AACnC,WAAO;AAAA,EACR;AAGA,MAAI;AACJ,MAAI,OAAO,WAAW,GAAG;AACxB,kBAAc,OAAO,CAAC;AAAA,EACvB,OAAO;AACN,kBAAc,EAAE,MAAM,OAAO;AAAA,EAC9B;AAIA,sBAAoB,aAAa,QAAQ,QAAQ;AAGjD,SAAO,qBAAqB,aAAa,QAAQ,QAAQ;AAC1D;AAiBA,SAAS,qBACR,OACA,QACA,UACiB;AACjB,QAAM,aAAsC,CAAC;AAE7C,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,KAAK,GAAG;AAEjD,QAAI,QAAQ,UAAU,QAAQ,OAAO;AACpC,iBAAW,GAAG,IAAK,MAA2B;AAAA,QAAI,CAAC,WAClD,qBAAqB,QAAQ,QAAQ,QAAQ;AAAA,MAC9C;AACA;AAAA,IACD;AAEA,QAAI,QAAQ,QAAQ;AACnB,iBAAW,GAAG,IAAI;AAAA,QACjB;AAAA,QACA;AAAA,QACA;AAAA,MACD;AACA;AAAA,IACD;AAGA,UAAM,WAAW,OAAO,OAAO,GAAG;AAClC,QAAI,CAAC,UAAU;AAEd,iBAAW,GAAG,IAAI;AAClB;AAAA,IACD;AAGA,QAAI,SAAS,SAAS,YAAY;AACjC,YAAM,gBAAgB;AACtB,YAAM,OAAO,cAAc;AAG3B,UAAI,SAAS,eAAe,SAAS,UAAU;AAC9C,cAAM,aAAa,cAAc;AAGjC,YAAI,OAAO,UAAU,YAAY,OAAO,UAAU,UAAU;AAC3D,gBAAM,eAAe,YAAY,OAAO,EAAE,MAAM,SAAS,GAAG,GAAG;AAC/D,qBAAW,UAAU,IAAI,EAAE,KAAK,aAAa;AAC7C;AAAA,QACD;AAGA,YACC,OAAO,UAAU,YACjB,UAAU,QACV,EAAE,iBAAiB,OAClB;AACD,gBAAM,WAAW;AACjB,gBAAM,OAAO,OAAO,KAAK,QAAQ;AAIjC,cACC,KAAK,WAAW,MACf,KAAK,CAAC,MAAM,WAAW,KAAK,CAAC,MAAM,aACnC;AACD,kBAAM,WAAW,KAAK,CAAC;AACvB,kBAAM,gBAAgB,SAAS,QAAQ;AACvC,kBAAM,eAAe;AAAA,cACpB;AAAA,cACA,EAAE,MAAM,UAAU;AAAA,cAClB;AAAA,YACD;AACA,uBAAW,UAAU,IAAI,EAAE,CAAC,QAAQ,GAAG,aAAa;AACpD;AAAA,UACD;AAGA,gBAAM,eAAe,SAAS,IAAI,cAAc,KAAK;AACrD,cAAI,cAAc;AACjB,uBAAW,GAAG,IAAI;AAAA,cACjB;AAAA,cACA;AAAA,cACA;AAAA,YACD;AACA;AAAA,UACD;AAAA,QACD;AAAA,MACD;AAGA,iBAAW,GAAG,IAAI;AAClB;AAAA,IACD;AAGA,QAAI,sBAAsB,KAAK,GAAG;AACjC,YAAM,aAAsC,CAAC;AAC7C,iBAAW,CAAC,UAAU,OAAO,KAAK,OAAO;AAAA,QACxC;AAAA,MACD,GAAG;AAEF,YAAK,kBAAwC,SAAS,QAAQ,GAAG;AAChE,qBAAW,QAAQ,IAAI,YAAY,SAAS,EAAE,MAAM,UAAU,GAAG,GAAG;AAAA,QACrE,WAEU,iBAAuC,SAAS,QAAQ,GAAG;AACpE,qBAAW,QAAQ,IAAI;AAAA,QACxB,OAEK;AACJ,qBAAW,QAAQ,IAAI,YAAY,SAAS,UAAU,GAAG;AAAA,QAC1D;AAAA,MACD;AACA,iBAAW,GAAG,IAAI;AAClB;AAAA,IACD;AAGA,eAAW,GAAG,IAAI,YAAY,OAAO,UAAU,GAAG;AAAA,EACnD;AAEA,SAAO;AACR;;;AC7lBO,SAAS,gBACf,SACA,QACA,UACiB;AAEjB,MAAI,CAAC,WAAW,QAAQ,WAAW,GAAG;AACrC,WAAO,SAAS,sBAAyB,OAAO,IAAI;AAAA,EACrD;AAGA,QAAM,YAAY,oBAAI,IAAa;AACnC,aAAW,UAAU,SAAS;AAC7B,QAAI,MAAM,QAAQ,MAAM,GAAG;AAC1B,aAAO,QAAQ,CAAC,UAAU,UAAU,IAAI,KAAK,CAAC;AAAA,IAC/C;AAAA,EACD;AAEA,QAAM,aAAa,MAAM,KAAK,SAAS;AAIvC,QAAM,gBAA0B,CAAC;AACjC,QAAM,iBAA2B,CAAC;AAElC,aAAW,aAAa,YAAY;AACnC,UAAM,QAAQ,OAAO,OAAO,SAAmB;AAG/C,QAAI,CAAC,OAAO;AACX,oBAAc,KAAK,SAAmB;AACtC;AAAA,IACD;AAGA,QAAI,MAAM,SAAS,YAAY;AAC9B,qBAAe,KAAK,SAAmB;AAAA,IACxC;AAAA,EACD;AAGA,MAAI,cAAc,SAAS,GAAG;AAC7B,UAAM,kBAAkB,OAAO,KAAK,OAAO,MAAM,EAAE;AAAA,MAClD,CAAC,SAAS,OAAO,OAAO,IAAI,GAAG,SAAS;AAAA,IACzC;AACA,uBAAmB,UAAU,eAAe,eAAe;AAAA,EAC5D;AAEA,MAAI,eAAe,SAAS,GAAG;AAC9B,0BAAsB,gBAAgB,OAAO,IAAI;AAAA,EAClD;AAIA,MAAI,QAAQ,KAAK,CAAC,MAAM,MAAM,GAAG,GAAG;AACnC,WAAO,SAAS,sBAAyB,OAAO,IAAI;AAAA,EACrD;AAGA,YAAU,IAAI,IAAe;AAC7B,YAAU,IAAI,WAAsB;AACpC,YAAU,IAAI,WAAsB;AAEpC,SAAO,MAAM,KAAK,SAAS;AAC5B;;;ACzFA,IAAM,qBAAqB;AA8CpB,SAAS,kBACf,UACA,WACA,UACA,QAAQ,GACwB;AAChC,MAAI,CAAC,UAAU;AACd,WAAO;AAAA,EACR;AAEA,MAAI,QAAQ,oBAAoB;AAC/B;AAAA,MACC;AAAA,MACA;AAAA,MACA;AAAA,MACA,4BAA4B,kBAAkB;AAAA,IAC/C;AAAA,EACD;AAEA,QAAM,SAAS,SAAS,IAAI,SAAS;AACrC,MAAI,CAAC,QAAQ;AACZ,sBAAkB,YAAY,aAAa,WAAW,kBAAkB;AAAA,EACzE;AAGA,MAAI,aAAa,OAAO,aAAa,MAAM;AAC1C,UAAM,eAAuC,CAAC;AAC9C,eAAW,CAAC,WAAW,KAAK,KAAK,OAAO,QAAQ,OAAO,MAAM,GAAG;AAC/D,UAAI,MAAM,SAAS,YAAY;AAC9B,cAAM,gBAAgB;AACtB,qBAAa,SAAS,IAAI;AAAA,UACzB,QAAQ,SAAS,sBAAsB,cAAc,KAAK;AAAA,QAC3D;AAAA,MACD;AAAA,IACD;AACA,WAAO;AAAA,EACR;AAGA,MAAI,MAAM,QAAQ,QAAQ,GAAG;AAC5B,WAAO,6BAA6B,UAAU,QAAQ,WAAW,QAAQ;AAAA,EAC1E;AAGA,QAAM,SAAiC,CAAC;AAExC,aAAW,CAAC,cAAc,KAAK,KAAK,OAAO,QAAQ,QAAQ,GAAG;AAC7D,UAAM,QAAQ,OAAO,OAAO,YAAY;AAGxC,QAAI,CAAC,OAAO;AACX,YAAM,qBAAqB,OAAO,QAAQ,OAAO,MAAM,EACrD,OAAO,CAAC,CAAC,GAAG,CAAC,MAAM,EAAE,SAAS,UAAU,EACxC,IAAI,CAAC,CAAC,IAAI,MAAM,IAAI;AAEtB,wBAAkB,YAAY,cAAc,kBAAkB;AAAA,IAC/D;AAGA,QAAI,MAAM,SAAS,YAAY;AAC9B,wBAAkB,YAAY,cAAc,MAAM,MAAM,UAAU;AAAA,IACnE;AAEA,UAAM,gBAAgB;AACtB,UAAM,cAAc,cAAc;AAElC,QAAI,OAAO,UAAU,aAAa,UAAU,KAAK;AAEhD,aAAO,YAAY,IAAI;AAAA,QACtB,QAAQ,SAAS,sBAAsB,WAAW;AAAA,MACnD;AAAA,IACD,WAAW,OAAO,UAAU,YAAY,UAAU,MAAM;AAEvD,aAAO,YAAY,IAAI;AAAA,QACtB,GAAG;AAAA;AAAA,QAEH,QAAQ;AAAA,UACP,MAAM,WAAW,SAAY,CAAC,MAAM,MAAM,IAAI;AAAA,UAC9C,SAAS,IAAI,WAAW;AAAA,UACxB;AAAA,QACD;AAAA;AAAA,QAEA,UAAU,MAAM,WACb,kBAAkB,MAAM,UAAU,aAAa,UAAU,QAAQ,CAAC,IAClE;AAAA,MACJ;AAAA,IACD,OAAO;AACN;AAAA,QACC;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACD;AAAA,IACD;AAAA,EACD;AAEA,SAAO;AACR;AAcA,SAAS,6BACR,OACA,QACA,YACA,UACoB;AACpB,QAAM,SAA8B,CAAC;AAErC,aAAW,QAAQ,OAAO;AACzB,UAAM,QAAQ,KAAK,MAAM,GAAG;AAC5B,UAAM,YAAY,MAAM,CAAC;AAGzB,UAAM,QAAQ,OAAO,OAAO,SAAS;AAGrC,QAAI,CAAC,OAAO;AACX,YAAM,qBAAqB,OAAO,QAAQ,OAAO,MAAM,EACrD,OAAO,CAAC,CAAC,GAAG,CAAC,MAAM,EAAE,SAAS,UAAU,EACxC,IAAI,CAAC,CAAC,IAAI,MAAM,IAAI;AAEtB,wBAAkB,YAAY,WAAW,kBAAkB;AAAA,IAC5D;AAGA,QAAI,MAAM,SAAS,YAAY;AAC9B,wBAAkB,YAAY,WAAW,MAAM,MAAM,UAAU;AAAA,IAChE;AAEA,UAAM,gBAAgB;AACtB,UAAM,cAAc,cAAc;AAElC,QAAI,MAAM,WAAW,GAAG;AAEvB,aAAO,SAAS,IAAI;AAAA,QACnB,QAAQ,SAAS,sBAAsB,WAAW;AAAA,MACnD;AAAA,IACD,OAAO;AAEN,YAAM,aAAa,MAAM,MAAM,CAAC,EAAE,KAAK,GAAG;AAE1C,UAAI,CAAC,OAAO,SAAS,GAAG;AACvB,eAAO,SAAS,IAAI;AAAA,UACnB,QAAQ,SAAS,sBAAsB,WAAW;AAAA,UAClD,UAAU,CAAC;AAAA,QACZ;AAAA,MACD;AAEA,UAAI,CAAC,OAAO,SAAS,EAAE,UAAU;AAChC,eAAO,SAAS,EAAE,WAAW,CAAC;AAAA,MAC/B;AAGA,YAAM,eAAe,SAAS,IAAI,WAAW;AAC7C,UAAI,cAAc;AACjB,cAAM,SAAS;AAAA,UACd,CAAC,UAAU;AAAA,UACX;AAAA,UACA;AAAA,UACA;AAAA,QACD;AAEA,eAAO,OAAO,OAAO,SAAS,EAAE,UAAU,MAAM;AAAA,MACjD;AAAA,IACD;AAAA,EACD;AAEA,SAAO;AACR;AA0BO,SAAS,uBACf,WACA,WACA,UAC+B;AAC/B,MAAI,CAAC,aAAa,UAAU,WAAW,GAAG;AACzC,WAAO;AAAA,EACR;AAGA,QAAM,aAAkC,CAAC;AACzC,aAAW,YAAY,WAAW;AACjC,UAAM,SAAS,kBAAkB,UAAU,WAAW,QAAQ;AAC9D,QAAI,QAAQ;AACX,iBAAW,KAAK,MAAM;AAAA,IACvB;AAAA,EACD;AAGA,MAAI,WAAW,WAAW,GAAG;AAC5B,WAAO;AAAA,EACR;AAEA,SAAO,qBAAqB,GAAG,UAAU;AAC1C;AAOO,SAAS,wBACZ,SACgB;AACnB,QAAM,SAA0D,CAAC;AAEjE,aAAW,UAAU,SAAS;AAC7B,QAAI,CAAC,OAAQ;AAEb,eAAW,CAAC,UAAU,OAAO,KAAK,OAAO,QAAQ,MAAM,GAAG;AAEzD,UACC,YAAY,OACZ,YAAY,QACZ,OAAO,QAAQ,MAAM,OACrB,OAAO,QAAQ,MAAM,MACpB;AACD,eAAO,QAAQ,IAAI,YAAY,OAAO,OAAO;AAAA,MAC9C,WAAW,OAAO,QAAQ,GAAG;AAE5B,cAAM,WAAW,OAAO,QAAQ;AAChC,cAAM,aAAa;AACnB,cAAM,gBAAgB;AAAA,UACrB,GAAI,WAAW,WAAW,UAAa,SAAS,WAAW,SACxD,EAAE,QAAQ,WAAW,UAAU,SAAS,OAAO,IAC/C,CAAC;AAAA,UACJ,GAAI,WAAW,UAAU,UAAa,SAAS,UAAU,SACtD,EAAE,OAAO,WAAW,SAAS,SAAS,MAAM,IAC5C,CAAC;AAAA,UACJ,GAAI,WAAW,aAAa,UAC3B,SAAS,aAAa,SACpB;AAAA,YACD,UAAU,WAAW,WAClB,qBAAqB,SAAS,UAAU,WAAW,QAAQ,IAC3D,SAAS;AAAA,UACb,IACE,CAAC;AAAA,UACJ,GAAI,WAAW,UAAU,UAAa,SAAS,UAAU,SACtD,EAAE,OAAO,WAAW,SAAS,SAAS,MAAM,IAC5C,CAAC;AAAA,UACJ,GAAI,WAAW,WAAW,UAAa,SAAS,WAAW,SACxD,EAAE,QAAQ,WAAW,UAAU,SAAS,OAAO,IAC/C,CAAC;AAAA,UACJ,GAAI,WAAW,YAAY,UAAa,SAAS,YAAY,SAC1D,EAAE,SAAS,WAAW,WAAW,SAAS,QAAQ,IAClD,CAAC;AAAA,QACL;AACA,eAAO,QAAQ,IAAI;AAAA,MACpB,OAAO;AACN,eAAO,QAAQ,IAAI;AAAA,MACpB;AAAA,IACD;AAAA,EACD;AAEA,SAAO;AACR;;;ACxUA,IAAM,mBAAmB;AAgBzB,SAAS,sBAAsB,OAAyB;AACvD,MAAI,OAAO,UAAU,YAAY,UAAU,MAAM;AAChD,WAAO;AAAA,EACR;AAEA,MAAI,QAAQ,SAAS,EAAE,aAAa,SAAS,SAAS,QAAQ;AAC7D,WAAO;AAAA,EACR;AAEA,SACC,aAAa,SACb,gBAAgB,SAChB,SAAS,SACT,YAAY,SACZ,YAAY,SACZ,YAAY;AAEd;AAgBA,SAAS,WAAW,OAA0B;AAE7C,MAAI,OAAO,UAAU,UAAU;AAC9B,WAAO,CAAC,KAAK;AAAA,EACd;AAGA,MAAI,OAAO,UAAU,UAAU;AAC9B,WAAO,CAAC,OAAO,KAAK,CAAC;AAAA,EACtB;AAGA,MAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,QAAQ,OAAO;AACjE,UAAM,KAAM,MAAkC;AAC9C,WAAO,CAAC,OAAO,OAAO,WAAW,KAAK,OAAO,EAAE,CAAC;AAAA,EACjD;AAGA,MAAI,MAAM,QAAQ,KAAK,GAAG;AACzB,WAAO,MAAM,IAAI,CAAC,SAAS;AAC1B,UAAI,OAAO,SAAS,UAAU;AAC7B,eAAO;AAAA,MACR;AACA,UAAI,OAAO,SAAS,UAAU;AAC7B,eAAO,OAAO,IAAI;AAAA,MACnB;AACA,UAAI,OAAO,SAAS,YAAY,SAAS,QAAQ,QAAQ,MAAM;AAC9D,cAAM,KAAM,KAAiC;AAC7C,eAAO,OAAO,OAAO,WAAW,KAAK,OAAO,EAAE;AAAA,MAC/C;AACA,aAAO;AAAA,IACR,CAAC;AAAA,EACF;AAEA,SAAO,CAAC;AACT;AAwEO,SAAS,YACf,MACA,QACA,UACA,QAAgB,GAChB,gBAAqC,oBAAI,IAAI,GACnB;AAE1B,MAAI,QAAQ,kBAAkB;AAC7B;AAAA,MACC;AAAA,MACA;AAAA,MACA;AAAA,MACA,WAAW,gBAAgB;AAAA,IAC5B;AAAA,EACD;AAGA,MAAI,cAAc,IAAI,OAAO,IAAI,GAAG;AACnC;AAAA,MACC;AAAA,MACA;AAAA,MACA,GAAG,CAAC,GAAG,eAAe,OAAO,IAAI,EAAE,KAAK,UAAK,CAAC;AAAA,MAC9C,6CAA6C,OAAO,IAAI;AAAA,IACzD;AAAA,EACD;AACA,QAAM,UAAmC,CAAC;AAC1C,QAAM,eAAwC,CAAC;AAC/C,QAAM,gBAA0B,CAAC;AAGjC,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,IAAI,GAAG;AAChD,UAAM,QAAQ,OAAO,OAAO,GAAG;AAG/B,QAAI,CAAC,OAAO;AACX,oBAAc,KAAK,GAAG;AACtB;AAAA,IACD;AAGA,QAAI,MAAM,SAAS,YAAY;AAC9B,mBAAa,GAAG,IAAI;AAAA,IACrB,OAAO;AAEN,cAAQ,GAAG,IAAI;AAAA,IAChB;AAAA,EACD;AAGA,MAAI,cAAc,SAAS,GAAG;AAC7B,UAAM,kBAAkB,OAAO,KAAK,OAAO,MAAM;AACjD,sBAAkB,QAAQ,cAAc,CAAC,GAAI,eAAe;AAAA,EAC7D;AAGA,QAAM,sBAGF,CAAC;AAEL,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,YAAY,GAAG;AACxD,UAAM,QAAQ,OAAO,OAAO,GAAG;AAG/B,QAAI;AAGJ,QAAI,UAAU,MAAM;AACnB,UAAI,MAAM,SAAS,aAAa;AAE/B,qBAAa,EAAE,YAAY,CAAC,EAAE;AAAA,MAC/B,WAAW,MAAM,SAAS,UAAU;AAEnC,qBAAa,EAAE,KAAK,CAAC,EAAE;AAAA,MACxB,OAAO;AAEN;AAAA,UACC;AAAA,UACA,YAAY,GAAG;AAAA,UACf;AAAA,UACA;AAAA,QACD;AAAA,MACD;AAAA,IACD,WAES,OAAO,UAAU,YAAY,OAAO,UAAU,UAAU;AAChE,mBAAa,EAAE,KAAK,WAAW,KAAK,EAAE;AAAA,IACvC,WAES,MAAM,QAAQ,KAAK,GAAG;AAC9B,YAAM,eACL,MAAM,WAAW,KAAK,CAAC,sBAAsB,MAAM,CAAC,CAAC;AACtD,UAAI,cAAc;AACjB,qBAAa,EAAE,KAAK,WAAW,KAAK,EAAE;AAAA,MACvC,OAAO;AAEN,qBAAa,CAAC;AAAA,MACf;AAAA,IACD,WAES,OAAO,UAAU,UAAU;AACnC,YAAM,WAAW;AACjB,mBAAa,CAAC;AAGd,UAAI,SAAS,YAAY,QAAW;AACnC,qBAAa,EAAE,GAAG,YAAY,SAAS,WAAW,SAAS,OAAO,EAAE;AAAA,MACrE;AAIA,UAAI,SAAS,eAAe,QAAW;AACtC,YAAI,SAAS,eAAe,MAAM;AACjC,cAAI,MAAM,SAAS,UAAU;AAC5B,yBAAa,EAAE,GAAG,YAAY,KAAK,CAAC,EAAE;AAAA,UACvC,OAAO;AACN,yBAAa,EAAE,GAAG,YAAY,YAAY,CAAC,EAAE;AAAA,UAC9C;AAAA,QACD,OAAO;AACN,uBAAa;AAAA,YACZ,GAAG;AAAA,YACH,YAAY,WAAW,SAAS,UAAU;AAAA,UAC3C;AAAA,QACD;AAAA,MACD;AAGA,UAAI,SAAS,QAAQ,QAAW;AAC/B,qBAAa,EAAE,GAAG,YAAY,KAAK,WAAW,SAAS,GAAG,EAAE;AAAA,MAC7D;AAGA,UAAI,SAAS,WAAW,QAAW;AAClC,qBAAa,EAAE,GAAG,YAAY,QAAQ,WAAW,SAAS,MAAM,EAAE;AAAA,MACnE;AAGA,UAAI,SAAS,WAAW,QAAW;AAClC,cAAM,eAAe,SAAS,IAAI,MAAM,KAAK;AAC7C,YAAI,CAAC,cAAc;AAClB;AAAA,YACC;AAAA,YACA,YAAY,GAAG;AAAA,YACf,MAAM;AAAA,YACN;AAAA,UACD;AAAA,QACD;AAEA,cAAM,cAAc,oBAAI,IAAI,CAAC,GAAG,eAAe,OAAO,IAAI,CAAC;AAG3D,YAAI,MAAM,QAAQ,SAAS,MAAM,GAAG;AACnC,uBAAa;AAAA,YACZ,GAAG;AAAA,YACH,QAAQ,SAAS,OAAO;AAAA,cAAI,CAAC,SAC5B;AAAA,gBACC;AAAA,gBACA;AAAA,gBACA;AAAA,gBACA,QAAQ;AAAA,gBACR;AAAA,cACD;AAAA,YACD;AAAA,UACD;AAAA,QACD,OAAO;AAEN,uBAAa;AAAA,YACZ,GAAG;AAAA,YACH,QAAQ;AAAA,cACP;AAAA,gBACC,SAAS;AAAA,gBACT;AAAA,gBACA;AAAA,gBACA,QAAQ;AAAA,gBACR;AAAA,cACD;AAAA,YACD;AAAA,UACD;AAAA,QACD;AAAA,MACD;AAGA,UAAI,SAAS,WAAW,QAAW;AAClC,cAAM,eAAe,SAAS,IAAI,MAAM,KAAK;AAC7C,YAAI,CAAC,cAAc;AAClB;AAAA,YACC;AAAA,YACA,YAAY,GAAG;AAAA,YACf,MAAM;AAAA,YACN;AAAA,UACD;AAAA,QACD;AAEA,cAAM,cAAc,oBAAI,IAAI,CAAC,GAAG,eAAe,OAAO,IAAI,CAAC;AAG3D,YAAI,MAAM,QAAQ,SAAS,MAAM,GAAG;AACnC,uBAAa;AAAA,YACZ,GAAG;AAAA,YACH,QAAQ,SAAS,OAAO,IAAI,CAAC,SAAS;AACrC,oBAAM,cAAc,KAAK;AACzB,oBAAM,aAAa,KAAK;AACxB,oBAAM,YAAY;AAAA,gBACjB;AAAA,gBACA;AAAA,gBACA;AAAA,gBACA,QAAQ;AAAA,gBACR;AAAA,cACD;AACA,qBAAO;AAAA,gBACN,OAAO;AAAA,gBACP,GAAG;AAAA,cACJ;AAAA,YACD,CAAC;AAAA,UACF;AAAA,QACD,OAAO;AAEN,gBAAM,cAAc,SAAS,OAAO;AACpC,gBAAM,aAAa,SAAS,OAAO;AACnC,gBAAM,YAAY;AAAA,YACjB;AAAA,YACA;AAAA,YACA;AAAA,YACA,QAAQ;AAAA,YACR;AAAA,UACD;AACA,uBAAa;AAAA,YACZ,GAAG;AAAA,YACH,QAAQ;AAAA,cACP;AAAA,gBACC,OAAO;AAAA,gBACP,GAAG;AAAA,cACJ;AAAA,YACD;AAAA,UACD;AAAA,QACD;AAAA,MACD;AAAA,IACD,OAAO;AAEN,mBAAa,CAAC;AAAA,IACf;AAIA,QAAI,MAAM,SAAS,aAAa;AAE/B,YAAM,aACJ,WAAW,SAAS,UAAU,MAC9B,WAAW,KAAK,UAAU,MAC1B,WAAW,QAAQ,UAAU;AAE/B,UAAI,YAAY,GAAG;AAClB;AAAA,UACC;AAAA,UACA,YAAY,GAAG,KAAK,MAAM,IAAI;AAAA,UAC9B,GAAG,SAAS;AAAA,UACZ;AAAA,QACD;AAAA,MACD;AAEA,YAAM,aAAa,MAAM;AACzB,UAAI,YAAuC;AAE3C,UAAI,WAAW,SAAS;AACvB,cAAM,MAAM,WAAW;AACvB,oBAAY,IAAI,CAAC,KAAK;AAAA,MACvB,WAAW,WAAW,KAAK;AAC1B,cAAM,MAAM,WAAW;AACvB,oBAAY,IAAI,CAAC,KAAK;AAAA,MACvB,WAAW,WAAW,YAAY;AACjC,oBAAY;AAAA,MACb;AAEA,UAAI,cAAc,QAAW;AAE5B,gBAAQ,UAAU,IAAI;AAGtB,cAAM,cACL,WAAW,UAAU,WAAW,UAAU,WAAW;AACtD,YAAI,aAAa;AAChB,8BAAoB,GAAG,IAAI;AAAA,QAC5B;AAAA,MAED,OAAO;AAEN,4BAAoB,GAAG,IAAI;AAAA,MAC5B;AAAA,IACD,WAAW,MAAM,SAAS,UAAU;AAKnC,0BAAoB,GAAG,IAAI;AAAA,IAC5B,OAAO;AAEN,0BAAoB,GAAG,IAAI;AAAA,IAC5B;AAAA,EACD;AAEA,SAAO;AAAA,IACN,MAAM;AAAA,IACN,WACC,OAAO,KAAK,mBAAmB,EAAE,SAAS,IACtC,sBACD;AAAA,EACL;AACD;;;AC1dA,SAAS,eAAe,OAAyB;AAChD,MAAI,CAAC,MAAM,QAAQ,KAAK,EAAG,QAAO;AAClC,MAAI,MAAM,WAAW,EAAG,QAAO;AAE/B,QAAM,QAAQ,MAAM,CAAC;AACrB,SACC,OAAO,UAAU,YACjB,UAAU,QACV,WAAW,SACX,eAAe;AAEjB;AAMA,SAAS,iBAAiB,OAAyB;AAClD,MAAI,MAAM,QAAQ,KAAK,EAAG,QAAO;AACjC,MAAI,OAAO,UAAU,YAAY,UAAU,KAAM,QAAO;AAExD,QAAM,SAAS,OAAO,OAAO,KAAK;AAClC,SAAO,OAAO,MAAM,CAAC,MAAM,MAAM,SAAS,MAAM,MAAM;AACvD;AAMA,SAAS,cAAc,OAAyB;AAC/C,MAAI,CAAC,MAAM,QAAQ,KAAK,EAAG,QAAO;AAClC,MAAI,MAAM,WAAW,EAAG,QAAO;AAE/B,SAAO,MAAM,MAAM,CAAC,SAAS,OAAO,SAAS,QAAQ;AACtD;AAuBO,SAAS,iBACf,OAC8B;AAC9B,MAAI,UAAU,UAAa,UAAU,MAAM;AAC1C,WAAO;AAAA,EACR;AAGA,MAAI,eAAe,KAAK,GAAG;AAC1B,WAAO;AAAA,EACR;AAGA,MAAI,iBAAiB,KAAK,GAAG;AAC5B,UAAM,SAA2B,CAAC;AAClC,eAAW,CAAC,OAAO,SAAS,KAAK,OAAO,QAAQ,KAAK,GAAG;AACvD,aAAO,KAAK;AAAA,QACX;AAAA,QACA;AAAA,MACD,CAAC;AAAA,IACF;AACA,WAAO;AAAA,EACR;AAGA,MAAI,cAAc,KAAK,GAAG;AACzB,WAAQ,MAAmB,IAAI,CAAC,SAAS;AACxC,YAAM,MAAM;AACZ,UAAI,IAAI,WAAW,GAAG,GAAG;AACxB,eAAO;AAAA,UACN,OAAO,IAAI,MAAM,CAAC;AAAA,UAClB,WAAW;AAAA,QACZ;AAAA,MACD;AACA,aAAO;AAAA,QACN,OAAO;AAAA,QACP,WAAW;AAAA,MACZ;AAAA,IACD,CAAC;AAAA,EACF;AAGA,SAAO;AACR;;;ACnFA,SAAS,UAAa,KAAW;AAChC,MAAI,QAAQ,QAAQ,OAAO,QAAQ,UAAU;AAC5C,WAAO;AAAA,EACR;AAEA,MAAI,eAAe,MAAM;AACxB,WAAO,IAAI,KAAK,IAAI,QAAQ,CAAC;AAAA,EAC9B;AAEA,MAAI,eAAe,QAAQ;AAC1B,WAAO,IAAI,OAAO,IAAI,QAAQ,IAAI,KAAK;AAAA,EACxC;AAEA,MAAI,MAAM,QAAQ,GAAG,GAAG;AACvB,WAAO,IAAI,IAAI,CAAC,SAAS,UAAU,IAAI,CAAC;AAAA,EACzC;AAEA,QAAM,SAAkC,CAAC;AACzC,aAAW,OAAO,KAAK;AACtB,QAAI,OAAO,UAAU,eAAe,KAAK,KAAK,GAAG,GAAG;AACnD,aAAO,GAAG,IAAI,UAAU,IAAI,GAAG,CAAC;AAAA,IACjC;AAAA,EACD;AAEA,SAAO;AACR;AAwBO,IAAM,qBAAN,MAAM,oBAGX;AAAA,EACO;AAAA,EACS;AAAA,EACA;AAAA,EACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAqBjB,YACC,WACA,gBACA,OAAc,UACb;AACD,SAAK,aAAa;AAClB,SAAK,YAAY;AAGjB,UAAM,SAAS,eAAe,IAAI,SAAS;AAC3C,QAAI,CAAC,QAAQ;AACZ,MAAAC,qBAAoB,SAAS;AAAA,IAC9B;AAEA,SAAK,UAAU;AACf,SAAK,QAAQ;AAAA,MACZ,OAAO,OAAO;AAAA,MACd;AAAA,IACD;AAAA,EACD;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,QAAqC;AAC3C,QAAI,KAAK,MAAM,WAAW,QAAW;AACpC,WAAK,MAAM,SAAS,CAAC,MAAM;AAAA,IAC5B,OAAO;AACN,WAAK,MAAM,OAAO,KAAK,MAAM;AAAA,IAC9B;AACA,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,YAAwC;AAC7C,QAAI,KAAK,MAAM,UAAU,QAAW;AACnC,WAAK,MAAM,QAAQ,CAAC,UAAU;AAAA,IAC/B,OAAO;AACN,WAAK,MAAM,MAAM,KAAK,UAAU;AAAA,IACjC;AACA,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,SAAS,WAA0C;AAClD,QAAI,KAAK,MAAM,aAAa,QAAW;AACtC,WAAK,MAAM,WAAW,CAAC,SAAS;AAAA,IACjC,OAAO;AACN,WAAK,MAAM,SAAS,KAAK,SAAS;AAAA,IACnC;AACA,WAAO;AAAA,EACR;AAAA,EA4BA,QACC,eACA,YAA4B,OACrB;AAEP,QAAI,OAAO,kBAAkB,YAAY,CAAC,MAAM,QAAQ,aAAa,GAAG;AACvE,YAAM,aAAa,iBAAiB,KAAK,MAAM,OAAO;AACtD,YAAM,UAAgC;AAAA,QACrC,OAAO;AAAA,QACP;AAAA,MACD;AACA,WAAK,MAAM,UAAU;AAAA,QACpB,GAAI,cAAc,CAAC;AAAA,QACnB;AAAA,MACD;AACA,aAAO;AAAA,IACR;AAGA,SAAK,MAAM,UAAU;AACrB,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,OAAqB;AAC1B,SAAK,MAAM,QAAQ;AACnB,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,OAAqB;AAC3B,SAAK,MAAM,SAAS;AACpB,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAkBA,KAAK,QAAgC;AACpC,QAAI,KAAK,MAAM,SAAS,QAAW;AAClC,WAAK,MAAM,OAAO;AAAA,IACnB,OAAO;AACN,WAAK,MAAM,OAAO,EAAE,GAAG,KAAK,MAAM,MAAM,GAAG,OAAO;AAAA,IACnD;AACA,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAmBA,SAAS,MAA8B;AACtC,QAAI,KAAK,MAAM,cAAc,QAAW;AACvC,WAAK,MAAM,YAAY,CAAC,IAAI;AAAA,IAC7B,OAAO;AACN,WAAK,MAAM,UAAU,KAAK,IAAI;AAAA,IAC/B;AACA,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA,EAKA,SAAS,UAAU,MAAY;AAC9B,SAAK,MAAM,WAAW;AACtB,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA,EAKA,QAAQ,QAAiC;AACxC,SAAK,MAAM,UAAU,CAAC,GAAI,KAAK,MAAM,WAAW,CAAC,GAAI,GAAG,MAAM;AAC9D,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,YAAwC;AAC9C,SAAK,MAAM,SAAS;AACpB,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,QAA4C;AAE3C,QAAI,CAAC,KAAK,MAAM,MAAM;AACrB,4BAAsB,KAAK,MAAM,IAAI;AAAA,IACtC;AAEA,QAAI,CAAC,KAAK,MAAM,OAAO;AACtB,wBAAkB;AAAA,IACnB;AAEA,UAAM,OAAO,KAAK,MAAM;AACxB,UAAM,QAAQ,KAAK,MAAM;AAGzB,UAAM,kBAAkB;AAAA,MACvB,KAAK,MAAM;AAAA,MACX,KAAK;AAAA,MACL,KAAK;AAAA,IACN;AACA,UAAM,mBAAmB;AAAA,MACxB,KAAK,MAAM;AAAA,MACX,KAAK;AAAA,MACL,KAAK;AAAA,IACN;AACA,UAAM,qBAAqB;AAAA,MAC1B,KAAK,MAAM;AAAA,MACX,KAAK;AAAA,MACL,KAAK;AAAA,IACN;AACA,UAAM,oBAAoB,iBAAiB,KAAK,MAAM,OAAO;AAG7D,UAAM,eACL,qBAAqB,SAClB,EAAE,QAAQ,iBAAiB,IAC3B,EAAE,QAAQ,OAAU;AACxB,UAAM,iBACL,uBAAuB,SAAY,EAAE,UAAU,mBAAmB,IAAI,CAAC;AACxE,UAAM,cACL,oBAAoB,SAAY,EAAE,OAAO,gBAAgB,IAAI,CAAC;AAE/D,YAAQ,MAAM;AAAA,MACb,KAAK,UAAU;AACd,eAAO;AAAA,UACN;AAAA,UACA;AAAA,UACA,GAAG;AAAA,UACH,GAAG;AAAA,UACH,GAAG;AAAA,UACH,GAAI,sBAAsB,UAAa;AAAA,YACtC,SAAS;AAAA,UACV;AAAA,UACA,GAAI,KAAK,MAAM,UAAU,UAAa,EAAE,OAAO,KAAK,MAAM,MAAM;AAAA,UAChE,GAAI,KAAK,MAAM,WAAW,UAAa,EAAE,QAAQ,KAAK,MAAM,OAAO;AAAA,UACnE,GAAI,KAAK,MAAM,aAAa,UAAa;AAAA,YACxC,UAAU,KAAK,MAAM;AAAA,UACtB;AAAA,UACA,GAAI,KAAK,MAAM,YAAY,UAAa;AAAA,YACvC,SAAS,KAAK,MAAM;AAAA,UACrB;AAAA,UACA,GAAI,KAAK,MAAM,WAAW,UAAa;AAAA,YACtC,QAAQ,KAAK,MAAM;AAAA,UACpB;AAAA,QACD;AAAA,MACD;AAAA,MAEA,KAAK,SAAS;AACb,eAAO;AAAA,UACN;AAAA,UACA;AAAA,UACA,GAAG;AAAA,UACH,GAAI,KAAK,MAAM,YAAY,UAAa;AAAA,YACvC,SAAS,KAAK,MAAM;AAAA,UACrB;AAAA,UACA,GAAI,KAAK,MAAM,WAAW,UAAa;AAAA,YACtC,QAAQ,KAAK,MAAM;AAAA,UACpB;AAAA,QACD;AAAA,MACD;AAAA,MAEA,KAAK,UAAU;AACd,cAAM,YAAY,KAAK,MAAM,aAAa,CAAC;AAC3C,YAAI,UAAU,WAAW,GAAG;AAC3B,2BAAiB,QAAQ;AAAA,QAC1B;AACA,cAAM,iBAAiB,UAAU;AAAA,UAAI,CAAC,SACrC,YAAqB,MAAM,KAAK,SAAS,KAAK,SAAS;AAAA,QACxD;AACA,cAAM,YAAY,eAAe;AAAA,UAChC,CAAC,MAAM,EAAE;AAAA,QACV;AACA,cAAM,YAAY,eAAe,CAAC,GAAG;AACrC,eAAO;AAAA,UACN,MAAM;AAAA,UACN;AAAA,UACA,MAAM;AAAA,UACN,GAAI,cAAc,UAAa,EAAE,UAAU;AAAA,UAC3C,GAAG;AAAA,UACH,GAAG;AAAA,QACJ;AAAA,MACD;AAAA,MAEA,KAAK,UAAU;AACd,YAAI,KAAK,MAAM,SAAS,QAAW;AAClC,2BAAiB,QAAQ;AAAA,QAC1B;AACA,cAAM,gBAAgB;AAAA,UACrB,KAAK,MAAM;AAAA,UACX,KAAK;AAAA,UACL,KAAK;AAAA,QACN;AACA,eAAO;AAAA,UACN;AAAA,UACA;AAAA,UACA,GAAG;AAAA,UACH,MAAM,cAAc;AAAA,UACpB,GAAI,cAAc,cAAc,UAAa;AAAA,YAC5C,WAAW,cAAc;AAAA,UAC1B;AAAA,UACA,GAAG;AAAA,UACH,GAAG;AAAA,QACJ;AAAA,MACD;AAAA,MAEA,KAAK,UAAU;AACd,YAAI,oBAAoB,QAAW;AAClC,kCAAwB;AAAA,QACzB;AACA,eAAO;AAAA,UACN;AAAA,UACA;AAAA,UACA,OAAO;AAAA,UACP,GAAG;AAAA,UACH,GAAG;AAAA,QACJ;AAAA,MACD;AAAA,MAEA;AACC,8BAAsB,IAAI;AAAA,IAC5B;AAAA,EACD;AAAA;AAAA;AAAA;AAAA,EAKA,QAA4C;AAC3C,UAAM,SAAS,IAAI;AAAA,MAClB,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK,MAAM;AAAA,IACZ;AAGA,WAAO,QAAQ;AAAA,MACd,GAAG,KAAK;AAAA,MACR,GAAI,KAAK,MAAM,UAAU,UAAa;AAAA,QACrC,OAAO,UAAU,KAAK,MAAM,KAAK;AAAA,MAClC;AAAA,MACA,GAAI,KAAK,MAAM,aAAa,UAAa;AAAA,QACxC,UAAU,UAAU,KAAK,MAAM,QAAQ;AAAA,MACxC;AAAA,MACA,GAAI,KAAK,MAAM,SAAS,UAAa;AAAA,QACpC,MAAM,UAAU,KAAK,MAAM,IAAI;AAAA,MAChC;AAAA,MACA,GAAI,KAAK,MAAM,cAAc,UAAa;AAAA,QACzC,WAAW,UAAU,KAAK,MAAM,SAAS;AAAA,MAC1C;AAAA,MACA,GAAI,KAAK,MAAM,YAAY,UAAa;AAAA,QACvC,SAAS,UAAU,KAAK,MAAM,OAAO;AAAA,MACtC;AAAA,MACA,GAAI,KAAK,MAAM,YAAY,UAAa;AAAA,QACvC,SAAS,UAAU,KAAK,MAAM,OAAO;AAAA,MACtC;AAAA,MACA,GAAI,KAAK,MAAM,WAAW,UAAa;AAAA,QACtC,QAAQ,UAAU,KAAK,MAAM,MAAM;AAAA,MACpC;AAAA,IACD;AAEA,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA,EAKA,QAAc;AACb,SAAK,QAAQ,CAAC;AACd,WAAO;AAAA,EACR;AACD;AA6BO,SAAS,WACf,WACA,gBACwC;AACxC,SAAO,IAAI;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,EACD;AACD;AAOO,SAAS,WACf,WACA,MACA,gBACwC;AACxC,QAAM,UAAU,IAAI;AAAA,IACnB;AAAA,IACA;AAAA,IACA;AAAA,EACD;AACA,QAAM,QAAQ,MAAM,QAAQ,IAAI,IAAI,OAAO,CAAC,IAAI;AAChD,aAAW,QAAQ,OAAO;AACzB,YAAQ,SAAS,IAAI;AAAA,EACtB;AACA,SAAO;AACR;AAEO,SAAS,YACf,WACA,MACA,gBACwC;AACxC,SAAO,IAAI;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,EACD,EAAE,KAAK,IAAI;AACZ;AAEO,SAAS,WACf,WACA,gBACwC;AACxC,SAAO,IAAI;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,EACD;AACD;AAEO,SAAS,UACf,WACA,gBACuC;AACvC,SAAO,IAAI;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,EACD;AACD;;;AC9kBO,IAAM,kBAAkB,CAAC,MAAM,aAAa,WAAW;AA0VvD,SAAS,oBAAoB,KAA0C;AAC7E,MAAI,OAAO,QAAQ,YAAY,OAAO,QAAQ,UAAU;AACvD,WAAO,EAAE,IAAI,IAAI;AAAA,EAClB;AACA,SAAO,EAAE,IAAI,IAAI,GAAG;AACrB;AAgBO,SAAS,qBACf,MACyB;AACzB,MAAI,MAAM,QAAQ,IAAI,GAAG;AACxB,WAAO,KAAK,IAAI,mBAAmB;AAAA,EACpC;AACA,SAAO,CAAC,oBAAoB,IAAI,CAAC;AAClC;AAKO,SAAS,gBAAgB,OAAwC;AACvE,MAAI,OAAO,UAAU,YAAY,OAAO,UAAU,UAAU;AAC3D,WAAO;AAAA,EACR;AACA,MACC,OAAO,UAAU,YACjB,UAAU,QACV,QAAQ,UACP,OAAQ,MAA0B,OAAO,YACzC,OAAQ,MAA0B,OAAO,WACzC;AACD,WAAO;AAAA,EACR;AACA,SAAO;AACR;AAKO,SAAS,iBAAiB,OAAyC;AACzE,MAAI,gBAAgB,KAAK,GAAG;AAC3B,WAAO;AAAA,EACR;AACA,MAAI,MAAM,QAAQ,KAAK,KAAK,MAAM,MAAM,eAAe,GAAG;AACzD,WAAO;AAAA,EACR;AACA,SAAO;AACR;AAiHO,SAAS,aAA+C,QAAc;AAC5E,SAAO;AACR;AA0EO,SAAS,yBACf,QACmC;AACnC,QAAM,SAAkC,CAAC;AAGzC,MAAI,CAAC,OAAO,QAAQ,OAAO,KAAK,KAAK,MAAM,IAAI;AAC9C,WAAO,KAAK;AAAA,MACX,SAAS;AAAA,MACT,MAAM;AAAA,IACP,CAAC;AAAA,EACF;AAGA,MAAI,CAAC,OAAO,UAAU,OAAO,KAAK,OAAO,MAAM,EAAE,WAAW,GAAG;AAC9D,WAAO,KAAK;AAAA,MACX,SAAS;AAAA,MACT,MAAM;AAAA,IACP,CAAC;AAAA,EACF;AAGA,aAAW,CAAC,WAAW,QAAQ,KAAK,OAAO,QAAQ,OAAO,MAAM,GAAG;AAElE,QAAI,CAAC,aAAa,UAAU,KAAK,MAAM,IAAI;AAC1C,aAAO,KAAK;AAAA,QACX,SAAS;AAAA,QACT,MAAM;AAAA,MACP,CAAC;AAAA,IACF;AAGA,QAAI,SAAS,SAAS,YAAY;AACjC,UAAI,CAAC,SAAS,SAAS,SAAS,MAAM,KAAK,MAAM,IAAI;AACpD,eAAO,KAAK;AAAA,UACX,OAAO;AAAA,UACP,SAAS;AAAA,UACT,MAAM;AAAA,QACP,CAAC;AAAA,MACF;AAAA,IACD;AAGA,QAAI,SAAS,SAAS,QAAQ;AAC7B,UAAI,CAAC,SAAS,UAAU,SAAS,OAAO,WAAW,GAAG;AACrD,eAAO,KAAK;AAAA,UACX,OAAO;AAAA,UACP,SAAS;AAAA,UACT,MAAM;AAAA,QACP,CAAC;AAAA,MACF;AAAA,IACD;AAGA,QAAI,SAAS,SAAS,SAAS;AAC9B,UAAI,CAAC,SAAS,OAAO;AACpB,eAAO,KAAK;AAAA,UACX,OAAO;AAAA,UACP,SAAS;AAAA,UACT,MAAM;AAAA,QACP,CAAC;AAAA,MACF;AAAA,IACD;AAAA,EACD;AAEA,SAAO;AAAA,IACN,OAAO,OAAO,WAAW;AAAA,IACzB;AAAA,EACD;AACD;AAUO,SAAS,wBACf,SACqB;AACrB,QAAM,gBAAgB,oBAAI,IAA8B;AACxD,aAAW,UAAU,SAAS;AAC7B,QAAI,OAAO,UAAW,eAAc,IAAI,OAAO,WAAW,MAAM;AAAA,EACjE;AAEA,QAAM,OAAO,oBAAI,IAAyB;AAC1C,aAAW,UAAU,SAAS;AAC7B,QAAI,OAAO,UAAW,MAAK,IAAI,OAAO,WAAW,oBAAI,IAAI,CAAC;AAAA,EAC3D;AAEA,aAAW,UAAU,SAAS;AAC7B,eAAW,SAAS,OAAO,OAAO,OAAO,MAAM,GAAG;AACjD,YAAM,MAAO,MAA6C;AAC1D,UAAI,CAAC,IAAK;AACV,YAAM,WAAW,IAAI;AACrB,UAAI,aAAa,OAAO,aAAa,cAAc,IAAI,QAAQ,GAAG;AACjE,aAAK,IAAI,OAAO,SAAU,EAAG,IAAI,QAAQ;AAAA,MAC1C;AAAA,IACD;AAAA,EACD;AAEA,QAAM,WAAW,oBAAI,IAAoB;AACzC,aAAW,aAAa,KAAK,KAAK,GAAG;AACpC,aAAS,IAAI,WAAW,CAAC;AAAA,EAC1B;AACA,aAAW,UAAU,KAAK,OAAO,GAAG;AACnC,eAAW,OAAO,QAAQ;AACzB,eAAS,IAAI,MAAM,SAAS,IAAI,GAAG,KAAK,KAAK,CAAC;AAAA,IAC/C;AAAA,EACD;AAEA,QAAM,QAAkB,CAAC;AACzB,aAAW,CAAC,WAAW,MAAM,KAAK,UAAU;AAC3C,QAAI,WAAW,EAAG,OAAM,KAAK,SAAS;AAAA,EACvC;AAEA,QAAM,SAAmB,CAAC;AAC1B,SAAO,MAAM,SAAS,GAAG;AACxB,UAAM,UAAU,MAAM,MAAM;AAC5B,WAAO,KAAK,OAAO;AACnB,eAAW,OAAO,KAAK,IAAI,OAAO,KAAK,CAAC,GAAG;AAC1C,YAAM,aAAa,SAAS,IAAI,GAAG,KAAK,KAAK;AAC7C,eAAS,IAAI,KAAK,SAAS;AAC3B,UAAI,cAAc,EAAG,OAAM,KAAK,GAAG;AAAA,IACpC;AAAA,EACD;AAGA,SAAO,QAAQ;AAEf,QAAM,SAA6B,CAAC;AACpC,aAAW,aAAa,QAAQ;AAC/B,UAAM,SAAS,cAAc,IAAI,SAAS;AAC1C,QAAI,OAAQ,QAAO,KAAK,MAAM;AAAA,EAC/B;AAEA,aAAW,UAAU,SAAS;AAC7B,QAAI,CAAC,OAAO,SAAS,MAAM,EAAG,QAAO,KAAK,MAAM;AAAA,EACjD;AAEA,SAAO;AACR;;;ACruBO,SAAS,sBACf,OACA,MACA,SACA,SAIkB;AAClB,SAAO;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA,OAAO,SAAS;AAAA,IAChB,UAAU,SAAS;AAAA,EACpB;AACD;AAKO,SAAS,mBACf,MACA,OACA,SAOS;AACT,UAAQ,MAAM;AAAA,IACb,KAAK;AACJ,aAAO,UAAU,KAAK;AAAA,IAEvB,KAAK;AACJ,aAAO,UAAU,KAAK,kCAAkC,SAAS,QAAQ,SAAS,SAAS,MAAM;AAAA,IAElG,KAAK;AACJ,aAAO,UAAU,KAAK,sBAAsB,SAAS,GAAG;AAAA,IAEzD,KAAK;AACJ,aAAO,UAAU,KAAK,qBAAqB,SAAS,GAAG;AAAA,IAExD,KAAK;AACJ,aAAO,UAAU,KAAK,sBAAsB,SAAS,GAAG;AAAA,IAEzD,KAAK;AACJ,aAAO,UAAU,KAAK,qBAAqB,SAAS,GAAG;AAAA,IAExD,KAAK;AACJ,aAAO,UAAU,KAAK,wBAAwB,SAAS,GAAG;AAAA,IAE3D,KAAK;AACJ,aAAO,UAAU,KAAK,uBAAuB,SAAS,GAAG;AAAA,IAE1D,KAAK;AACJ,aAAO,UAAU,KAAK,oCAAoC,SAAS,UAAU,KAAK,QAAQ,OAAO,KAAK,EACrG;AAAA,IAEF,KAAK;AACJ,aAAO,UAAU,KAAK;AAAA,IAEvB,KAAK;AACJ,aAAO,UAAU,KAAK,qBAAqB,SAAS,QAAQ;AAAA,IAE7D,KAAK;AACJ,aAAO,UAAU,KAAK;AAAA,IAEvB,KAAK;AACJ,aAAO,UAAU,KAAK;AAAA,IAEvB,KAAK;AACJ,aAAO,UAAU,KAAK;AAAA,IAEvB;AACC,aAAO,UAAU,KAAK;AAAA,EACxB;AACD;AAoBO,SAAS,mBACf,QAC6C;AAC7C,QAAM,UAA6C,CAAC;AAEpD,aAAW,SAAS,QAAQ;AAC3B,QAAI,CAAC,QAAQ,MAAM,KAAK,GAAG;AAC1B,cAAQ,MAAM,KAAK,IAAI,CAAC;AAAA,IACzB;AACA,YAAQ,MAAM,KAAK,EAAG,KAAK,KAAK;AAAA,EACjC;AAEA,SAAO;AACR;AAKO,SAAS,sBACf,QACkC;AAClC,QAAM,cAA+C,CAAC;AAEtD,aAAW,SAAS,QAAQ;AAC3B,QAAI,CAAC,YAAY,MAAM,KAAK,GAAG;AAC9B,kBAAY,MAAM,KAAK,IAAI;AAAA,IAC5B;AAAA,EACD;AAEA,SAAO;AACR;AAKO,SAAS,mBACf,QACA,MAC6B;AAC7B,SAAO,OAAO,OAAO,CAAC,UAAU,MAAM,SAAS,IAAI;AACpD;AAKO,SAAS,oBACf,QACA,OAC6B;AAC7B,SAAO,OAAO,OAAO,CAAC,UAAU,MAAM,UAAU,KAAK;AACtD;AAyBO,SAAS,aAAa,QAA4C;AACxE,MAAI,OAAO,WAAW,GAAG;AACxB,WAAO;AAAA,EACR;AAEA,QAAM,WAAW,OAAO;AAAA,IACvB,CAAC,UAAU,OAAO,MAAM,KAAK,KAAK,MAAM,OAAO,KAAK,MAAM,IAAI;AAAA,EAC/D;AAEA,SAAO,0BAA0B,OAAO,MAAM;AAAA,EAAe,SAAS;AAAA,IACrE;AAAA,EACD,CAAC;AACF;AA8BO,IAAM,4BAAN,MAAM,2BAA0B;AAAA,EACrB;AAAA,EAEjB,YAAY,SAAqC,CAAC,GAAG;AACpD,SAAK,SAAS,OAAO,OAAO,CAAC,GAAG,MAAM,CAAC;AAAA,EACxC;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,OAAmD;AACtD,WAAO,IAAI,2BAA0B,CAAC,GAAG,KAAK,QAAQ,KAAK,CAAC;AAAA,EAC7D;AAAA;AAAA;AAAA;AAAA,EAKA,QAAQ,QAA+D;AACtE,WAAO,IAAI,2BAA0B,CAAC,GAAG,KAAK,QAAQ,GAAG,MAAM,CAAC;AAAA,EACjE;AAAA;AAAA;AAAA;AAAA,EAKA,SAAqC;AACpC,WAAO,KAAK;AAAA,EACb;AAAA;AAAA;AAAA;AAAA,EAKA,WAAW,OAA2C;AACrD,WAAO,oBAAoB,KAAK,QAAQ,KAAK;AAAA,EAC9C;AAAA;AAAA;AAAA;AAAA,EAKA,UAAU,MAAuD;AAChE,WAAO,mBAAmB,KAAK,QAAQ,IAAI;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA,EAKA,YAAqB;AACpB,WAAO,KAAK,OAAO,SAAS;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA,EAKA,QAAgB;AACf,WAAO,KAAK,OAAO;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA,EAKA,WAAmB;AAClB,WAAO,aAAa,KAAK,MAAM;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA,EAKA,SAAqC;AACpC,WAAO,KAAK;AAAA,EACb;AAAA;AAAA;AAAA;AAAA,EAKA,eAA2D;AAC1D,WAAO,mBAAmB,KAAK,MAAM;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA,EAKA,mBAAoD;AACnD,WAAO,sBAAsB,KAAK,MAAM;AAAA,EACzC;AACD;AAwBO,SAAS,wBACf,OACA,QACA,YACQ;AACR,QAAM,gBAAgB,OACpB,IAAI,CAAC,MAAM,GAAG,EAAE,KAAK,KAAK,EAAE,OAAO,EAAE,EACrC,KAAK,IAAI;AAEX,QAAM,IAAI;AAAA,IACT,yBAAyB,KAAK,KAAK,aAAa;AAAA,IAChD;AAAA,MACC;AAAA,MACA;AAAA,MACA,WAAW;AAAA,MACX;AAAA,IACD;AAAA,EACD;AACD;;;ACxUA,IAAM,WAAW,CAAC,UAAoC,OAAO,UAAU;AACvE,IAAM,WAAW,CAAC,UACjB,OAAO,UAAU,YAAY,CAAC,MAAM,KAAK;AAC1C,IAAM,YAAY,CAAC,UAClB,OAAO,UAAU;AAClB,IAAM,SAAS,CAAC,UACf,iBAAiB,QAAQ,CAAC,MAAM,MAAM,QAAQ,CAAC;AAChD,IAAM,UAAU,CAAC,UAChB,MAAM,QAAQ,KAAK;AACpB,IAAM,oBAAoB,CAAC,UAC1B,UAAU,QAAQ,UAAU;AAK7B,IAAM,uBAAuB;AAKtB,SAAS,cACf,OACA,OACA,WACA,QAAQ,GACmB;AAE3B,MAAI,QAAQ,sBAAsB;AACjC,WAAO;AAAA,MACN,SAAS;AAAA,MACT,OAAO;AAAA,QACN;AAAA,UACC;AAAA,UACA;AAAA,UACA,6BAA6B,oBAAoB;AAAA,UACjD,EAAE,OAAO,MAAM;AAAA,QAChB;AAAA,MACD;AAAA,IACD;AAAA,EACD;AAEA,MAAI,MAAM,YAAY,kBAAkB,KAAK,GAAG;AAC/C,WAAO;AAAA,MACN,SAAS;AAAA,MACT,OAAO;AAAA,QACN;AAAA,UACC;AAAA,UACA;AAAA,UACA,mBAAmB,YAAY,SAAS;AAAA,QACzC;AAAA,MACD;AAAA,IACD;AAAA,EACD;AAGA,MAAI,CAAC,MAAM,YAAY,kBAAkB,KAAK,GAAG;AAChD,WAAO,EAAE,SAAS,MAAM,MAAM,MAAW;AAAA,EAC1C;AAGA,UAAQ,MAAM,MAAM;AAAA,IACnB,KAAK;AACJ,aAAO;AAAA,QACN;AAAA,QACA;AAAA,QACA;AAAA,MACD;AAAA,IACD,KAAK;AACJ,aAAO;AAAA,QACN;AAAA,QACA;AAAA,QACA;AAAA,MACD;AAAA,IACD,KAAK;AACJ,aAAO,gBAAgB,OAAO,SAAS;AAAA,IACxC,KAAK;AACJ,aAAO;AAAA,QACN;AAAA,QACA;AAAA,QACA;AAAA,MACD;AAAA,IACD,KAAK;AACJ,aAAO;AAAA,QACN;AAAA,QACA;AAAA,QACA;AAAA,MACD;AAAA,IACD,KAAK;AACJ,aAAO;AAAA,QACN;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACD;AAAA,IACD,KAAK;AACJ,aAAO,aAAa,OAAO,SAAS;AAAA,IACrC,KAAK;AACJ,aAAO,iBAAiB,OAAO,SAAS;AAAA,IACzC;AACC,aAAO,EAAE,SAAS,MAAM,MAAM,MAAW;AAAA,EAC3C;AACD;AAKA,SAAS,eACR,OACA,OACA,WACgC;AAChC,MAAI,CAAC,SAAS,KAAK,GAAG;AACrB,WAAO;AAAA,MACN,SAAS;AAAA,MACT,OAAO;AAAA,QACN;AAAA,UACC;AAAA,UACA;AAAA,UACA,mBAAmB,iBAAiB,WAAW;AAAA,YAC9C,UAAU;AAAA,YACV,QAAQ,OAAO;AAAA,UAChB,CAAC;AAAA,QACF;AAAA,MACD;AAAA,IACD;AAAA,EACD;AAEA,QAAM,SAAS,CAAC;AAGhB,MAAI,MAAM,cAAc,UAAa,MAAM,SAAS,MAAM,WAAW;AACpE,WAAO;AAAA,MACN;AAAA,QACC;AAAA,QACA;AAAA,QACA,mBAAmB,cAAc,WAAW,EAAE,KAAK,MAAM,UAAU,CAAC;AAAA,QACpE,EAAE,OAAO,MAAM,QAAQ,UAAU,MAAM,UAAU;AAAA,MAClD;AAAA,IACD;AAAA,EACD;AAGA,MAAI,MAAM,cAAc,UAAa,MAAM,SAAS,MAAM,WAAW;AACpE,WAAO;AAAA,MACN;AAAA,QACC;AAAA,QACA;AAAA,QACA,mBAAmB,cAAc,WAAW,EAAE,KAAK,MAAM,UAAU,CAAC;AAAA,QACpE,EAAE,OAAO,MAAM,QAAQ,UAAU,MAAM,UAAU;AAAA,MAClD;AAAA,IACD;AAAA,EACD;AAGA,MAAI,MAAM,WAAW,CAAC,MAAM,QAAQ,KAAK,KAAK,GAAG;AAChD,WAAO;AAAA,MACN;AAAA,QACC;AAAA,QACA;AAAA,QACA,mBAAmB,WAAW,WAAW,EAAE,SAAS,MAAM,QAAQ,CAAC;AAAA,QACnE,EAAE,MAAM;AAAA,MACT;AAAA,IACD;AAAA,EACD;AAGA,MAAI,MAAM,WAAW;AACpB,UAAM,SAAS,MAAM,UAAU,KAAK;AACpC,QAAI,WAAW,MAAM;AACpB,aAAO;AAAA,QACN,sBAAsB,WAAW,UAAU,QAAQ,EAAE,MAAM,CAAC;AAAA,MAC7D;AAAA,IACD;AAAA,EACD;AAEA,MAAI,OAAO,SAAS,GAAG;AACtB,WAAO,EAAE,SAAS,OAAO,OAAO,OAAO;AAAA,EACxC;AAEA,SAAO,EAAE,SAAS,MAAM,MAAM,MAAM;AACrC;AAKA,SAAS,eACR,OACA,OACA,WACgC;AAChC,MAAI,CAAC,SAAS,KAAK,GAAG;AACrB,WAAO;AAAA,MACN,SAAS;AAAA,MACT,OAAO;AAAA,QACN;AAAA,UACC;AAAA,UACA;AAAA,UACA,mBAAmB,iBAAiB,WAAW;AAAA,YAC9C,UAAU;AAAA,YACV,QAAQ,OAAO;AAAA,UAChB,CAAC;AAAA,QACF;AAAA,MACD;AAAA,IACD;AAAA,EACD;AAEA,QAAM,SAAS,CAAC;AAGhB,MAAI,MAAM,WAAW,CAAC,OAAO,UAAU,KAAK,GAAG;AAC9C,WAAO;AAAA,MACN;AAAA,QACC;AAAA,QACA;AAAA,QACA,UAAU,SAAS;AAAA,QACnB,EAAE,MAAM;AAAA,MACT;AAAA,IACD;AAAA,EACD;AAGA,MAAI,MAAM,QAAQ,UAAa,QAAQ,MAAM,KAAK;AACjD,WAAO;AAAA,MACN;AAAA,QACC;AAAA,QACA;AAAA,QACA,mBAAmB,aAAa,WAAW,EAAE,KAAK,MAAM,IAAI,CAAC;AAAA,QAC7D,EAAE,OAAO,UAAU,MAAM,IAAI;AAAA,MAC9B;AAAA,IACD;AAAA,EACD;AAGA,MAAI,MAAM,QAAQ,UAAa,QAAQ,MAAM,KAAK;AACjD,WAAO;AAAA,MACN;AAAA,QACC;AAAA,QACA;AAAA,QACA,mBAAmB,aAAa,WAAW,EAAE,KAAK,MAAM,IAAI,CAAC;AAAA,QAC7D,EAAE,OAAO,UAAU,MAAM,IAAI;AAAA,MAC9B;AAAA,IACD;AAAA,EACD;AAGA,MAAI,MAAM,WAAW;AACpB,UAAM,SAAS,MAAM,UAAU,KAAK;AACpC,QAAI,WAAW,MAAM;AACpB,aAAO;AAAA,QACN,sBAAsB,WAAW,UAAU,QAAQ,EAAE,MAAM,CAAC;AAAA,MAC7D;AAAA,IACD;AAAA,EACD;AAEA,MAAI,OAAO,SAAS,GAAG;AACtB,WAAO,EAAE,SAAS,OAAO,OAAO,OAAO;AAAA,EACxC;AAEA,SAAO,EAAE,SAAS,MAAM,MAAM,MAAM;AACrC;AAKA,SAAS,gBACR,OACA,WACiC;AACjC,MAAI,CAAC,UAAU,KAAK,GAAG;AACtB,WAAO;AAAA,MACN,SAAS;AAAA,MACT,OAAO;AAAA,QACN;AAAA,UACC;AAAA,UACA;AAAA,UACA,mBAAmB,iBAAiB,WAAW;AAAA,YAC9C,UAAU;AAAA,YACV,QAAQ,OAAO;AAAA,UAChB,CAAC;AAAA,QACF;AAAA,MACD;AAAA,IACD;AAAA,EACD;AAEA,SAAO,EAAE,SAAS,MAAM,MAAM,MAAM;AACrC;AAKA,SAAS,aACR,OACA,OACA,WAC8B;AAE9B,MAAI,EAAE,iBAAiB,OAAO;AAC7B,WAAO;AAAA,MACN,SAAS;AAAA,MACT,OAAO;AAAA,QACN;AAAA,UACC;AAAA,UACA;AAAA,UACA,mBAAmB,iBAAiB,WAAW;AAAA,YAC9C,UAAU;AAAA,YACV,QAAQ,OAAO;AAAA,UAChB,CAAC;AAAA,QACF;AAAA,MACD;AAAA,IACD;AAAA,EACD;AAGA,MAAI,CAAC,OAAO,KAAK,GAAG;AACnB,WAAO;AAAA,MACN,SAAS;AAAA,MACT,OAAO;AAAA,QACN;AAAA,UACC;AAAA,UACA;AAAA,UACA,mBAAmB,gBAAgB,SAAS;AAAA,QAC7C;AAAA,MACD;AAAA,IACD;AAAA,EACD;AAEA,QAAM,SAAS,CAAC;AAGhB,MAAI,MAAM,OAAO,QAAQ,MAAM,KAAK;AACnC,WAAO;AAAA,MACN;AAAA,QACC;AAAA,QACA;AAAA,QACA,UAAU,SAAS,mBAAmB,MAAM,IAAI,YAAY,CAAC;AAAA,QAC7D,EAAE,OAAO,UAAU,MAAM,IAAI;AAAA,MAC9B;AAAA,IACD;AAAA,EACD;AAGA,MAAI,MAAM,OAAO,QAAQ,MAAM,KAAK;AACnC,WAAO;AAAA,MACN;AAAA,QACC;AAAA,QACA;AAAA,QACA,UAAU,SAAS,oBAAoB,MAAM,IAAI,YAAY,CAAC;AAAA,QAC9D,EAAE,OAAO,UAAU,MAAM,IAAI;AAAA,MAC9B;AAAA,IACD;AAAA,EACD;AAEA,MAAI,OAAO,SAAS,GAAG;AACtB,WAAO,EAAE,SAAS,OAAO,OAAO,OAAO;AAAA,EACxC;AAEA,SAAO,EAAE,SAAS,MAAM,MAAM,MAAM;AACrC;AAKA,SAAS,aACR,OACA,OACA,WACgC;AAChC,MAAI,CAAC,SAAS,KAAK,GAAG;AACrB,WAAO;AAAA,MACN,SAAS;AAAA,MACT,OAAO;AAAA,QACN;AAAA,UACC;AAAA,UACA;AAAA,UACA,mBAAmB,iBAAiB,WAAW;AAAA,YAC9C,UAAU;AAAA,YACV,QAAQ,OAAO;AAAA,UAChB,CAAC;AAAA,QACF;AAAA,MACD;AAAA,IACD;AAAA,EACD;AAEA,MAAI,CAAC,MAAM,OAAO,SAAS,KAAK,GAAG;AAClC,WAAO;AAAA,MACN,SAAS;AAAA,MACT,OAAO;AAAA,QACN;AAAA,UACC;AAAA,UACA;AAAA,UACA,mBAAmB,gBAAgB,WAAW;AAAA,YAC7C,UAAU,MAAM,OAAO,KAAK,IAAI;AAAA,UACjC,CAAC;AAAA,UACD,EAAE,OAAO,UAAU,MAAM,OAAO;AAAA,QACjC;AAAA,MACD;AAAA,IACD;AAAA,EACD;AAEA,SAAO,EAAE,SAAS,MAAM,MAAM,MAAM;AACrC;AAKA,SAAS,cACR,OACA,OACA,WACA,OAC4C;AAC5C,MAAI,CAAC,QAAQ,KAAK,GAAG;AACpB,WAAO;AAAA,MACN,SAAS;AAAA,MACT,OAAO;AAAA,QACN;AAAA,UACC;AAAA,UACA;AAAA,UACA,mBAAmB,iBAAiB,WAAW;AAAA,YAC9C,UAAU;AAAA,YACV,QAAQ,OAAO;AAAA,UAChB,CAAC;AAAA,QACF;AAAA,MACD;AAAA,IACD;AAAA,EACD;AAEA,QAAM,SAAS,CAAC;AAGhB,MAAI,MAAM,aAAa,UAAa,MAAM,SAAS,MAAM,UAAU;AAClE,WAAO;AAAA,MACN;AAAA,QACC;AAAA,QACA;AAAA,QACA,mBAAmB,aAAa,WAAW,EAAE,KAAK,MAAM,SAAS,CAAC;AAAA,QAClE,EAAE,OAAO,MAAM,QAAQ,UAAU,MAAM,SAAS;AAAA,MACjD;AAAA,IACD;AAAA,EACD;AAGA,MAAI,MAAM,aAAa,UAAa,MAAM,SAAS,MAAM,UAAU;AAClE,WAAO;AAAA,MACN;AAAA,QACC;AAAA,QACA;AAAA,QACA,mBAAmB,aAAa,WAAW,EAAE,KAAK,MAAM,SAAS,CAAC;AAAA,QAClE,EAAE,OAAO,MAAM,QAAQ,UAAU,MAAM,SAAS;AAAA,MACjD;AAAA,IACD;AAAA,EACD;AAGA,MAAI,MAAM,QAAQ;AACjB,UAAM,OAAO,oBAAI,IAAa;AAC9B,UAAM,aAAa,oBAAI,IAAa;AAEpC,eAAW,QAAQ,OAAO;AAEzB,YAAM,UACL,OAAO,SAAS,YAAY,SAAS,OAAO,KAAK,UAAU,IAAI,IAAI;AAEpE,UAAI,KAAK,IAAI,OAAO,GAAG;AACtB,mBAAW,IAAI,IAAI;AAAA,MACpB,OAAO;AACN,aAAK,IAAI,OAAO;AAAA,MACjB;AAAA,IACD;AAEA,QAAI,WAAW,OAAO,GAAG;AACxB,aAAO;AAAA,QACN;AAAA,UACC;AAAA,UACA;AAAA,UACA,mBAAmB,UAAU,SAAS;AAAA,UACtC,EAAE,OAAO,MAAM,KAAK,UAAU,EAAE;AAAA,QACjC;AAAA,MACD;AAAA,IACD;AAAA,EACD;AAGA,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACtC,UAAM,OAAO,MAAM,CAAC;AACpB,UAAM,aAAa;AAAA,MAClB;AAAA,MACA,MAAM;AAAA,MACN,GAAG,SAAS,IAAI,CAAC;AAAA,MACjB,QAAQ;AAAA,IACT;AACA,QAAI,CAAC,WAAW,SAAS;AACxB,aAAO,KAAK,GAAG,WAAW,KAAK;AAAA,IAChC;AAAA,EACD;AAEA,MAAI,OAAO,SAAS,GAAG;AACtB,WAAO,EAAE,SAAS,OAAO,OAAO,OAAO;AAAA,EACxC;AAEA,SAAO,EAAE,SAAS,MAAM,MAAM,MAAM;AACrC;AAMA,SAAS,aACR,OACA,WACiC;AAGjC,MAAI,UAAU,UAAa,OAAO,KAAK,GAAG;AACzC,WAAO;AAAA,MACN,SAAS;AAAA,MACT,OAAO;AAAA,QACN;AAAA,UACC;AAAA,UACA;AAAA,UACA,mBAAmB,iBAAiB,WAAW;AAAA,YAC9C,UACC;AAAA,YACD,QAAQ,UAAU,SAAY,cAAc;AAAA,UAC7C,CAAC;AAAA,QACF;AAAA,MACD;AAAA,IACD;AAAA,EACD;AAEA,SAAO,EAAE,SAAS,MAAM,MAAM,MAAM;AACrC;AAMA,SAAS,iBACR,OACA,WACiC;AAEjC,MAAI,OAAO,UAAU,YAAY,OAAO,UAAU,UAAU;AAC3D,WAAO,EAAE,SAAS,MAAM,MAAM,MAAM;AAAA,EACrC;AAGA,MAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK,GAAG;AACzE,UAAM,QAAQ;AACd,UAAM,YAAY;AAAA,MACjB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACD;AAGA,UAAM,cAAc,UAAU,KAAK,CAAC,QAAQ,OAAO,KAAK;AACxD,QAAI,CAAC,aAAa;AACjB,aAAO;AAAA,QACN,SAAS;AAAA,QACT,OAAO;AAAA,UACN;AAAA,YACC;AAAA,YACA;AAAA,YACA,mBAAmB,SAAS;AAAA,YAC5B,EAAE,MAAM;AAAA,UACT;AAAA,QACD;AAAA,MACD;AAAA,IACD;AAGA,QAAI,MAAM,SAAS,GAAG;AACrB,YAAM,UAAU,MAAM,SAAS;AAC/B,UAAI,MAAM,QAAQ,OAAO,GAAG;AAC3B,YAAI,CAAC,QAAQ,MAAM,CAAC,SAAS,OAAO,SAAS,QAAQ,GAAG;AACvD,iBAAO;AAAA,YACN,SAAS;AAAA,YACT,OAAO;AAAA,cACN;AAAA,gBACC;AAAA,gBACA;AAAA,gBACA;AAAA,cACD;AAAA,YACD;AAAA,UACD;AAAA,QACD;AAAA,MACD,WAAW,OAAO,YAAY,UAAU;AACvC,eAAO;AAAA,UACN,SAAS;AAAA,UACT,OAAO;AAAA,YACN;AAAA,cACC;AAAA,cACA;AAAA,cACA;AAAA,YACD;AAAA,UACD;AAAA,QACD;AAAA,MACD;AAAA,IACD;AAGA,QAAI,MAAM,KAAK,GAAG;AACjB,UACC,CAAC,MAAM,QAAQ,MAAM,KAAK,CAAC,KAC3B,CAAE,MAAM,KAAK,EAAgB,MAAM,CAAC,SAAS,OAAO,SAAS,QAAQ,GACpE;AACD,eAAO;AAAA,UACN,SAAS;AAAA,UACT,OAAO;AAAA,YACN;AAAA,cACC;AAAA,cACA;AAAA,cACA;AAAA,YACD;AAAA,UACD;AAAA,QACD;AAAA,MACD;AAAA,IACD;AAEA,WAAO,EAAE,SAAS,MAAM,MAAM,MAAM;AAAA,EACrC;AAEA,SAAO;AAAA,IACN,SAAS;AAAA,IACT,OAAO;AAAA,MACN;AAAA,QACC;AAAA,QACA;AAAA,QACA,mBAAmB,iBAAiB,WAAW;AAAA,UAC9C,UAAU;AAAA,UACV,QAAQ,OAAO;AAAA,QAChB,CAAC;AAAA,MACF;AAAA,IACD;AAAA,EACD;AACD;;;AC5nBA,IAAM,kBAA8C;AAAA,EACnD,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,cAAc;AAAA,EACd,YAAY;AACb;AAKA,IAAMC,mBAAkB,CAAC,MAAM,aAAa,WAAW;AAKvD,SAAS,yBACR,UAC4B;AAC5B,SACC,SAAS,SAAS,eACjB,SAAS,SAAS,eAAe,SAAS,SAAS;AAEtD;AAKA,SAAS,cACR,WACA,WACA,UACU;AACV,MAAI,QAAQ,UAAU,SAAS;AAG/B,MAAI,CAAC,SAAS,yBAAyB,QAAQ,KAAK,SAAS,YAAY;AACxE,YAAQ,UAAU,SAAS,UAAU;AAAA,EACtC;AAEA,SAAO;AACR;AAQA,SAAS,oBACR,OACA,UACA,WACA,QACA,MACA,YACkE;AAClE,QAAM,SAAS,cAAc,OAAO,UAAU,SAAS;AAEvD,MAAI,CAAC,OAAO,SAAS;AACpB,aAAS,OAAO,QAAQ,OAAO,KAAK;AAEpC,QAAI,KAAK,YAAY;AACpB,8BAAwB,YAAY,OAAO,OAAO,CAAC;AAAA,IACpD;AAEA,WAAO,EAAE,OAAO;AAAA,EACjB;AAEA,SAAO,EAAE,QAAQ,gBAAgB,OAAO,KAAK;AAC9C;AAKA,SAAS,oBACR,WACA,cACA,eACA,QACA,MACA,YAC4B;AAC5B,MAAI,KAAK,QAAQ;AAChB,eAAW,OAAO,OAAO,KAAK,SAAS,GAAG;AACzC,UAAI,EAAE,OAAO,eAAe;AAC3B,iBAAS,OAAO;AAAA,UACf;AAAA,YACC;AAAA,YACA;AAAA,YACA,kBAAkB,GAAG,gBAAgB,UAAU;AAAA,UAChD;AAAA,QACD;AAEA,YAAI,KAAK,YAAY;AACpB,kCAAwB,YAAY,OAAO,OAAO,CAAC;AAAA,QACpD;AAAA,MACD;AAAA,IACD;AAAA,EACD,WAAW,CAAC,KAAK,cAAc;AAE9B,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,SAAS,GAAG;AACrD,UAAI,EAAE,OAAO,eAAe;AAC3B,sBAAc,GAAG,IAAI;AAAA,MACtB;AAAA,IACD;AAAA,EACD;AAEA,SAAO;AACR;AAKA,SAAS,kBACR,MACA,YAC0C;AAC1C,MAAI,OAAO,SAAS,YAAY,SAAS,QAAQ,MAAM,QAAQ,IAAI,GAAG;AACrE,4BAAwB,YAAY;AAAA,MACnC;AAAA,QACC;AAAA,QACA;AAAA,QACA,wBAAwB,MAAM,QAAQ,IAAI,IAAI,UAAU,OAAO,IAAI;AAAA,MACpE;AAAA,IACD,CAAC;AAAA,EACF;AACD;AAQO,SAAS,eACf,MACA,QACA,SACI;AACJ,QAAM,OAAO,EAAE,GAAG,iBAAiB,GAAG,QAAQ;AAC9C,MAAI,SAAS,IAAI,0BAA0B;AAE3C,oBAAkB,MAAM,OAAO,IAAI;AAEnC,QAAM,YAAY;AAClB,QAAM,gBAAyC,CAAC;AAGhD,aAAW,CAAC,WAAW,QAAQ,KAAK,OAAO,QAAQ,OAAO,MAAM,GAAG;AAElE,QAAIA,iBAAgB,SAAS,SAAS,GAAG;AACxC;AAAA,IACD;AAEA,UAAM,QAAQ,cAAc,WAAW,WAAW,QAAQ;AAI1D,QAAI,SAAS,UAAU,UAAU,QAAW;AAC3C;AAAA,IACD;AAGA,UAAM,SAAS;AAAA,MACd;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,OAAO;AAAA,IACR;AAEA,aAAS,OAAO;AAChB,QAAI,OAAO,mBAAmB,QAAW;AACxC,oBAAc,SAAS,IAAI,OAAO;AAAA,IACnC;AAAA,EACD;AAGA,WAAS;AAAA,IACR;AAAA,IACA,OAAO;AAAA,IACP;AAAA,IACA;AAAA,IACA;AAAA,IACA,OAAO;AAAA,EACR;AAEA,MAAI,OAAO,UAAU,GAAG;AACvB,4BAAwB,OAAO,MAAM,OAAO,OAAO,CAAC;AAAA,EACrD;AAEA,SAAO;AACR;AAaO,SAAS,gBACf,MACA,QACA,SACa;AACb,QAAM,OAAO,EAAE,GAAG,iBAAiB,GAAG,QAAQ;AAC9C,MAAI,SAAS,IAAI,0BAA0B;AAE3C,oBAAkB,MAAM,OAAO,IAAI;AAEnC,QAAM,YAAY;AAClB,QAAM,gBAAyC,CAAC;AAGhD,aAAW,CAAC,WAAW,KAAK,KAAK,OAAO,QAAQ,SAAS,GAAG;AAE3D,QAAIA,iBAAgB,SAAS,SAAS,GAAG;AACxC;AAAA,IACD;AAEA,UAAM,WAAW,OAAO,OAAO,SAAS;AAGxC,QAAI,CAAC,UAAU;AACd,UAAI,KAAK,QAAQ;AAChB,iBAAS,OAAO;AAAA,UACf;AAAA,YACC;AAAA,YACA;AAAA,YACA,kBAAkB,SAAS,gBAAgB,OAAO,IAAI;AAAA,UACvD;AAAA,QACD;AAEA,YAAI,KAAK,YAAY;AACpB,kCAAwB,OAAO,MAAM,OAAO,OAAO,CAAC;AAAA,QACrD;AAAA,MACD,WAAW,CAAC,KAAK,cAAc;AAC9B,sBAAc,SAAS,IAAI;AAAA,MAC5B;AACA;AAAA,IACD;AAIA,UAAM,SAAS;AAAA,MACd;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,OAAO;AAAA,IACR;AAEA,aAAS,OAAO;AAChB,QAAI,OAAO,mBAAmB,QAAW;AACxC,oBAAc,SAAS,IAAI,OAAO;AAAA,IACnC;AAAA,EACD;AAEA,MAAI,OAAO,UAAU,GAAG;AACvB,4BAAwB,OAAO,MAAM,OAAO,OAAO,CAAC;AAAA,EACrD;AAEA,SAAO;AACR;;;AC7PO,SAAS,eAAe,SAAuC;AACrE,QAAM;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACD,IAAI;AAEJ,QAAM,iBAAiB,uBAAuB,WAAW,OAAO,IAAI;AAEpE,QAAM,IAAI,gBAAgB,WAAW,gBAAgB;AAAA,IACpD;AAAA,IACA;AAAA,IACA;AAAA,IACA,SAAS,eAAe,SAAS,KAAK;AAAA,IACtC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACD,CAAC;AACF;AAKA,SAAS,eACR,SACA,OAC+B;AAC/B,MAAI,CAAC,OAAO;AACX,WAAO;AAAA,EACR;AAEA,SAAO;AAAA,IACN,GAAG;AAAA,IACH,cAAc,MAAM;AAAA,EACrB;AACD;AAKA,SAAS,uBACR,WACA,OACA,MACS;AACT,UAAQ,MAAM;AAAA,IACb,KAAK;AACJ,aAAO,qBAAqB,SAAS,cAAc,KAAK;AAAA,IACzD,KAAK;AACJ,aAAO,WAAW,KAAK;AAAA,IACxB,KAAK;AACJ,aAAO,GAAG,KAAK;AAAA,IAChB,KAAK;AACJ,aAAO,8BAA8B,KAAK;AAAA,IAC3C,KAAK;AACJ,aAAO,qCAAqC,KAAK;AAAA,IAClD,KAAK;AACJ,aAAO,GAAG,SAAS,wBAAwB,KAAK;AAAA,IACjD,KAAK;AACJ,aAAO,oBAAoB,KAAK;AAAA,IACjC;AACC,aAAO,6BAA6B,KAAK;AAAA,EAC3C;AACD;AAaO,SAAS,0BAA0B,WAA2B;AACpE,QAAM,IAAI,YAAY,2BAA2B,SAAS,IAAI;AAAA,IAC7D,MAAM;AAAA,IACN,SAAS,EAAE,UAAU;AAAA,IACrB,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,UAAU;AAAA,EACX,CAAC;AACF;AAKO,SAAS,yBAAyB,OAAsB;AAC9D,iBAAe;AAAA,IACd,WAAW;AAAA,IACX;AAAA,IACA,MAAM;AAAA,IACN,YAAY,yBAAyB,KAAK;AAAA,EAC3C,CAAC;AACF;AAKO,SAAS,wBAAwB,OAAe,OAAsB;AAC5E,iBAAe;AAAA,IACd,WAAW;AAAA,IACX;AAAA,IACA,MAAM;AAAA,IACN,SAAS,8BAA8B,KAAK;AAAA,IAC5C,YAAY,yEAAyE,KAAK;AAAA,EAC3F,CAAC;AACF;AAeO,SAAS,oBACf,WACA,OACA,IACQ;AACR,iBAAe;AAAA,IACd;AAAA,IACA;AAAA,IACA,MAAM;AAAA,IACN,SAAS,GAAG,KAAK,mBAAmB,EAAE;AAAA,IACtC,SAAS,EAAE,UAAU,GAAG;AAAA,IACxB,YAAY,mBAAmB,KAAK,YAAY,EAAE,gCAAgC,SAAS;AAAA,EAC5F,CAAC;AACF;;;AC3IA,SAAS,oBACR,MACA,WACO;AACP,MAAI,aAAa,CAAC,MAAM;AACvB;AAAA,EACD;AAEA,aAAW,SAAS,iBAAiB;AACpC,QAAI,SAAS,MAAM;AAClB,8BAAwB,OAAO,SAAS;AAAA,IACzC;AAAA,EACD;AACD;AAqCA,SAAS,cACR,MACA,SACa;AACb,QAAM,EAAE,UAAU,UAAU,IAAI;AAChC,QAAM,MAAM,oBAAI,KAAK;AACrB,QAAM,SAAqB,CAAC,CAAC,OAAO,EAAE,GAAG,KAAK,IAAK,CAAC;AAEpD,MAAI,UAAU;AACb,QAAI,WAAW;AAEd,UAAI,CAAC,OAAO,WAAW;AACtB,eAAO,YAAY;AAAA,MACpB;AACA,UAAI,CAAC,OAAO,WAAW;AACtB,eAAO,YAAY,OAAO;AAAA,MAC3B;AAAA,IACD,OAAO;AAEN,aAAO,YAAY;AACnB,aAAO,YAAY;AAAA,IACpB;AAAA,EACD,OAAO;AAEN,QAAI,WAAW;AAEd,UAAI,CAAC,OAAO,WAAW;AACtB,eAAO,YAAY;AAAA,MACpB;AAAA,IACD,OAAO;AAEN,aAAO,YAAY;AAAA,IACpB;AAAA,EACD;AAEA,SAAO;AACR;AAmCO,SAAS,aAIf,MACA,WACA,QACA,SACkC;AAClC,QAAM,EAAE,SAAS,UAAU,UAAU,IAAI;AAGzC,sBAAoB,MAAM,SAAS;AAGnC,QAAM,qBAAqB,OAAO,mBAC/B,OACA,cAAc,MAAM,EAAE,UAAU,UAAU,CAAC;AAG9C,QAAM,oBAAoB;AAAA,IACzB,QAAQ;AAAA,IACR,cAAc;AAAA,IACd,YAAY;AAAA,EACb;AAEA,QAAM,WAAW,EAAE,GAAI,sBAAsB,CAAC,GAAI,GAAI,aAAa,CAAC,EAAG;AAEvE,MAAI,SAAS;AACZ,oBAAgB,UAAU,QAAQ,iBAAiB;AAAA,EACpD,OAAO;AACN,mBAAe,UAAU,QAAQ,iBAAiB;AAAA,EACnD;AAEA,SAAO;AACR;;;AC7JA,eAAsB,iBACrB,mBACA,UACA,aACA,QACA,QACA,gBACgB;AAChB,aAAW,CAAC,WAAW,GAAG,KAAK,OAAO,QAAQ,iBAAiB,GAAG;AACjE,UAAM,gBAAmB;AAAA,MACxB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACD,CAAC;AAAA,EACF;AACD;AAwBA,eAAsB,mBACrB,WACA,QACA,QACA,gBAC+C;AAC/C,QAAM,WAAgD,CAAC;AAEvD,aAAW,CAAC,WAAW,YAAY,KAAK,OAAO,QAAQ,SAAS,GAAG;AAClE,UAAM,UAAU;AAChB,UAAM,QAAQ,OAAO,OAAO,SAAS;AACrC,QAAI,CAAC,SAAS,MAAM,SAAS,YAAY;AACxC;AAAA,IACD;AAEA,UAAM,eAAe,MAAM;AAC3B,UAAM,YAAY,eAAe,IAAI,YAAY;AAGjD,UAAM,MAA2B;AAAA,MAChC,SAAS,QAAQ,UAAU,CAAC,GAAG,QAAQ,OAAO,IAAI,CAAC;AAAA,MACnD,YAAY,QAAQ,aAAa,CAAC,GAAG,QAAQ,UAAU,IAAI,CAAC;AAAA,MAC5D,KAAK,QAAQ,MAAM,CAAC,GAAG,QAAQ,GAAG,IAAI;AAAA,MACtC,WAAW,QAAQ,SAAS,CAAC,GAAG,QAAQ,MAAM,IAAI,CAAC;AAAA,IACpD;AAGA,QAAI,QAAQ,QAAQ;AAkBnB,YAAM,aAAa,QAAQ,OAAO,OAAO,CAAC,SAAS,CAAC,KAAK,SAAS;AAClE,YAAM,cAAc,QAAQ,OAAO,OAAO,CAAC,SAAS,KAAK,SAAS;AAGlE,UAAI,WAAW,SAAS,GAAG;AAC1B,cAAM,oBAAoB,WAAW;AAAA,UAAI,CAAC,SACzC;AAAA,YACC,KAAK;AAAA,YACL,KAAK;AAAA,YACL;AAAA,YACA;AAAA,cACC,SAAS;AAAA,cACT,UAAU;AAAA,cACV,WAAW;AAAA,YACZ;AAAA,UACD;AAAA,QACD;AACA,cAAM,aAAa,MAAM,OAAO,aAA0B;AAAA,UACzD,MAAM;AAAA,UACN,OAAO,UAAU;AAAA,UACjB,MAAM;AAAA,QACP,CAAC;AAED,mBAAW,WAAW,WAAW,MAAM;AACtC,cAAI,IAAI,QAAQ,QAAW;AAC1B,gBAAI,IAAI,KAAK,QAAQ,EAAE;AAAA,UACxB,OAAO;AACN,gBAAI,QAAQ,KAAK,QAAQ,EAAE;AAAA,UAC5B;AAAA,QACD;AAAA,MACD;AAGA,iBAAW,cAAc,aAAa;AACrC,cAAM,gBAAgB;AAAA,UACrB,WAAW;AAAA,UACX,WAAW;AAAA,UACX;AAAA,UACA;AAAA,YACC,SAAS;AAAA,YACT,UAAU;AAAA,YACV,WAAW;AAAA,UACZ;AAAA,QACD;AACA,cAAM,eAAe,MAAM,OAAO,aAA0B;AAAA,UAC3D,MAAM;AAAA,UACN,OAAO,UAAU;AAAA,UACjB,MAAM,CAAC,aAAa;AAAA,QACrB,CAAC;AACD,cAAM,YAAY,aAAa,KAAK,CAAC,EAAG;AAGxC,YAAI,WAAW,WAAW;AACzB,gBAAM,iBAAiB,MAAM;AAAA,YAC5B,WAAW;AAAA,YACX;AAAA,YACA;AAAA,YACA;AAAA,UACD;AACA,gBAAM;AAAA,YACL;AAAA,YACA;AAAA,YACA,UAAU;AAAA,YACV;AAAA,YACA;AAAA,YACA;AAAA,UACD;AAAA,QACD;AAEA,YAAI,IAAI,QAAQ,QAAW;AAC1B,cAAI,IAAI,KAAK,SAAS;AAAA,QACvB,OAAO;AACN,cAAI,QAAQ,KAAK,SAAS;AAAA,QAC3B;AAAA,MACD;AAAA,IACD;AAGA,QAAI,QAAQ,QAAQ;AACnB,iBAAW,cAAc,QAAQ,QAAQ;AACxC,cAAM,EAAE,OAAO,MAAM,WAAW,gBAAgB,IAAI;AAEpD,cAAM,gBAAgB;AAAA,UACrB;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,YACC,SAAS;AAAA,YACT,UAAU;AAAA,YACV,WAAW;AAAA,UACZ;AAAA,QACD;AACA,cAAM,eAAe,MAAM,OAAO,aAA0B;AAAA,UAC3D,MAAM;AAAA,UACN,OAAO,UAAU;AAAA,UACjB,MAAM;AAAA,UACN;AAAA,QACD,CAAC;AAGD,YAAI,iBAAiB;AACpB,qBAAW,WAAW,aAAa,MAAM;AACxC,kBAAM,iBAAiB,MAAM;AAAA,cAC5B;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,YACD;AACA,kBAAM;AAAA,cACL;AAAA,cACA,QAAQ;AAAA,cACR,UAAU;AAAA,cACV;AAAA,cACA;AAAA,cACA;AAAA,YACD;AAAA,UACD;AAAA,QACD;AAAA,MACD;AAAA,IACD;AAGA,QAAI,IAAI,UAAU,SAAS,GAAG;AAC7B,YAAM,OAAO,aAA0B;AAAA,QACtC,MAAM;AAAA,QACN,OAAO,UAAU;AAAA,QACjB,OAAO,EAAE,IAAI,EAAE,KAAK,IAAI,UAAU,EAAE;AAAA,MACrC,CAAC;AAAA,IACF;AAEA,aAAS,SAAS,IAAI;AAAA,EACvB;AAEA,SAAO;AACR;AAQA,eAAe,gBAAuC;AAAA,EACrD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,GAQkB;AACjB,QAAM,QAAQ,OAAO,OAAO,SAAS;AACrC,MAAI,CAAC,SAAS,MAAM,SAAS,YAAY;AACxC;AAAA,EACD;AAEA,QAAM,WAAW;AACjB,QAAM,aAAa,SAAS,cAAc,GAAG,SAAS;AAGtD,MAAI,SAAS,SAAS,aAAa;AAClC,UAAM,aAAoC,CAAC;AAE3C,QAAI,IAAI,QAAQ,SAAS,GAAG;AAC3B,iBAAW,UAAU,IAAI,IAAI,QAAQ,CAAC;AAAA,IACvC;AACA,QAAI,IAAI,WAAW,SAAS,GAAG;AAC9B,iBAAW,UAAU,IAAI;AAAA,IAC1B;AACA,QAAI,IAAI,QAAQ,QAAW;AAC1B,iBAAW,UAAU,IAAI,IAAI,IAAI,SAAS,IAAI,IAAI,IAAI,CAAC,IAAI;AAAA,IAC5D;AAEA,QAAI,OAAO,KAAK,UAAU,EAAE,SAAS,GAAG;AACvC,YAAM,OAAO,aAAa;AAAA,QACzB,OAAO,OAAO;AAAA,QACd,MAAM;AAAA,QACN,OAAO,EAAE,IAAI,SAAS;AAAA,QACtB,MAAM;AAAA,MACP,CAAC;AAAA,IACF;AAAA,EACD;AAGA,MAAI,SAAS,SAAS,UAAU;AAC/B,UAAM,oBAAoB,SAAS,cAAc,GAAG,WAAW;AAC/D,UAAM,iBAAiB,eAAe,IAAI,SAAS,KAAK;AAGxD,QAAI,IAAI,QAAQ,SAAS,GAAG;AAE3B,YAAM,OAAO,aAAa;AAAA,QACzB,OAAO,eAAe;AAAA,QACtB,MAAM;AAAA,QACN,MAAM,EAAE,CAAC,iBAAiB,GAAG,KAAK;AAAA,QAClC,OAAO,EAAE,CAAC,iBAAiB,GAAG,SAAS;AAAA,MACxC,CAAC;AAGD,YAAM,OAAO,aAAa;AAAA,QACzB,OAAO,eAAe;AAAA,QACtB,MAAM;AAAA,QACN,MAAM,EAAE,CAAC,iBAAiB,GAAG,SAAS;AAAA,QACtC,OAAO,EAAE,IAAI,IAAI,QAAQ,CAAC,EAAE;AAAA,MAC7B,CAAC;AAAA,IACF;AAEA,QAAI,IAAI,WAAW,SAAS,GAAG;AAC9B,YAAM,OAAO,aAAa;AAAA,QACzB,OAAO,eAAe;AAAA,QACtB,MAAM;AAAA,QACN,MAAM,EAAE,CAAC,iBAAiB,GAAG,KAAK;AAAA,QAClC,OAAO,EAAE,IAAI,EAAE,KAAK,IAAI,WAAW,EAAE;AAAA,MACtC,CAAC;AAAA,IACF;AAEA,QAAI,IAAI,QAAQ,QAAW;AAE1B,YAAM,OAAO,aAAgB;AAAA,QAC5B,OAAO,eAAe;AAAA,QACtB,MAAM;AAAA,QACN,MAAM,EAAE,CAAC,iBAAiB,GAAG,KAAK;AAAA,QAClC,OAAO,EAAE,CAAC,iBAAiB,GAAG,SAAS;AAAA,MACxC,CAAC;AAGD,UAAI,IAAI,IAAI,SAAS,GAAG;AACvB,cAAM,OAAO,aAAgB;AAAA,UAC5B,OAAO,eAAe;AAAA,UACtB,MAAM;AAAA,UACN,MAAM,EAAE,CAAC,iBAAiB,GAAG,SAAS;AAAA,UACtC,OAAO,EAAE,IAAI,IAAI,IAAI,CAAC,EAAE;AAAA,QACzB,CAAC;AAAA,MACF;AAAA,IACD;AAAA,EACD;AAGA,MAAI,SAAS,SAAS,WAAW;AAChC,UAAM,oBAAoB,SAAS,cAAc,GAAG,WAAW;AAC/D,UAAM,iBAAiB,eAAe,IAAI,SAAS,KAAK;AAExD,QAAI,IAAI,QAAQ,SAAS,GAAG;AAC3B,YAAM,OAAO,aAAa;AAAA,QACzB,OAAO,eAAe;AAAA,QACtB,MAAM;AAAA,QACN,MAAM,EAAE,CAAC,iBAAiB,GAAG,SAAS;AAAA,QACtC,OAAO,EAAE,IAAI,EAAE,KAAK,IAAI,QAAQ,EAAE;AAAA,MACnC,CAAC;AAAA,IACF;AAEA,QAAI,IAAI,WAAW,SAAS,GAAG;AAC9B,YAAM,OAAO,aAAa;AAAA,QACzB,OAAO,eAAe;AAAA,QACtB,MAAM;AAAA,QACN,MAAM,EAAE,CAAC,iBAAiB,GAAG,KAAK;AAAA,QAClC,OAAO,EAAE,IAAI,EAAE,KAAK,IAAI,WAAW,EAAE;AAAA,MACtC,CAAC;AAAA,IACF;AAEA,QAAI,IAAI,QAAQ,QAAW;AAE1B,YAAM,OAAO,aAAa;AAAA,QACzB,OAAO,eAAe;AAAA,QACtB,MAAM;AAAA,QACN,MAAM,EAAE,CAAC,iBAAiB,GAAG,KAAK;AAAA,QAClC,OAAO;AAAA,UACN,CAAC,iBAAiB,GAAG;AAAA,QACtB;AAAA,MACD,CAAC;AAGD,UAAI,IAAI,IAAI,SAAS,GAAG;AACvB,cAAM,OAAO,aAAa;AAAA,UACzB,OAAO,eAAe;AAAA,UACtB,MAAM;AAAA,UACN,MAAM;AAAA,YACL,CAAC,iBAAiB,GAAG;AAAA,UACtB;AAAA,UACA,OAAO;AAAA,YACN,IAAI,EAAE,KAAK,IAAI,IAAI;AAAA,UACpB;AAAA,QACD,CAAC;AAAA,MACF;AAAA,IACD;AAAA,EACD;AAGA,MAAI,SAAS,SAAS,cAAc;AACnC,UAAM,gBAAgB,SAAS;AAC/B,UAAM,WAAW,GAAG,WAAW;AAC/B,UAAM,WAAW,GAAG,SAAS,KAAK;AAGlC,QAAI,IAAI,QAAQ,SAAS,GAAG;AAC3B,YAAM,WAAW,MAAM,OAAO,aAAa;AAAA,QAC1C,OAAO;AAAA,QACP,MAAM;AAAA,QACN,QAAQ,CAAC,QAAQ;AAAA,QACjB,OAAO;AAAA,UACN,CAAC,QAAQ,GAAG;AAAA,UACZ,CAAC,QAAQ,GAAG,EAAE,KAAK,IAAI,QAAQ;AAAA,QAChC;AAAA,MACD,CAAC;AACD,YAAM,cAAc,IAAI;AAAA,QACvB,SAAS,KAAK,IAAI,CAAC,MAAM,EAAE,QAA6B,CAAW;AAAA,MACpE;AACA,YAAM,SAAS,IAAI,QAAQ,OAAO,CAAC,OAAO,CAAC,YAAY,IAAI,EAAE,CAAC;AAE9D,UAAI,OAAO,SAAS,GAAG;AACtB,cAAM,OAAO,OAAO,IAAI,CAAC,cAAc;AAAA,UACtC,CAAC,QAAQ,GAAG;AAAA,UACZ,CAAC,QAAQ,GAAG;AAAA,QACb,EAAE;AACF,cAAM,OAAO,aAAa;AAAA,UACzB,OAAO;AAAA,UACP,MAAM;AAAA,UACN,MAAM;AAAA,QACP,CAAC;AAAA,MACF;AAAA,IACD;AAGA,QAAI,IAAI,WAAW,SAAS,GAAG;AAC9B,YAAM,OAAO,aAA0B;AAAA,QACtC,OAAO;AAAA,QACP,MAAM;AAAA,QACN,OAAO;AAAA,UACN,CAAC,QAAQ,GAAG;AAAA,UACZ,CAAC,QAAQ,GAAG,EAAE,KAAK,IAAI,WAAW;AAAA,QACnC;AAAA,MACD,CAAC;AAAA,IACF;AAGA,QAAI,IAAI,QAAQ,QAAW;AAE1B,YAAM,OAAO,aAA0B;AAAA,QACtC,OAAO;AAAA,QACP,MAAM;AAAA,QACN,OAAO;AAAA,UACN,CAAC,QAAQ,GAAG;AAAA,QACb;AAAA,MACD,CAAC;AAGD,UAAI,IAAI,IAAI,SAAS,GAAG;AACvB,cAAM,OAAO,IAAI,IAAI,IAAI,CAAC,cAAc;AAAA,UACvC,CAAC,QAAQ,GAAG;AAAA,UACZ,CAAC,QAAQ,GAAG;AAAA,QACb,EAAE;AACF,cAAM,OAAO,aAA0B;AAAA,UACtC,OAAO;AAAA,UACP,MAAM;AAAA,UACN,MAAM;AAAA,QACP,CAAC;AAAA,MACF;AAAA,IACD;AAAA,EACD;AACD;;;ACpcO,IAAM,gBAAN,MAAoB;AAAA,EAC1B,YACkB,SACA,YACA,eAChB;AAHgB;AACA;AACA;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAqBJ,MAAM,QACL,OACA,UAA2B,CAAC,GACf;AACb,UAAM,SAAS,KAAK,UAAU,MAAM,KAAK;AAGzC,QAAI,MAAM,SAAS,UAAU;AAC5B,aAAO,KAAK,cAAiB,OAAO,QAAQ,OAAO;AAAA,IACpD;AAGA,QAAI,MAAM,SAAS,SAAS;AAC3B,aAAO,KAAK,aAAgB,OAAO,QAAQ,OAAO;AAAA,IACnD;AAGA,QAAI,MAAM,SAAS,UAAU;AAC5B,aAAO,KAAK,cAAiB,OAAO,QAAQ,OAAO;AAAA,IACpD;AAGA,QAAI,MAAM,SAAS,UAAU;AAC5B,aAAO,KAAK,cAAiB,OAAO,QAAQ,OAAO;AAAA,IACpD;AAGA,QAAI,MAAM,SAAS,UAAU;AAC5B,aAAO,KAAK,cAAiB,OAAO,QAAQ,OAAO;AAAA,IACpD;AAEA,8BAA2B,MAA2B,IAAI;AAAA,EAC3D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,cACL,OACA,QACA,SACe;AACf,WAAO,KAAK;AAAA,MACX,QAAQ,UAAU;AAAA,MAClB;AAAA,MACA,QAAQ,gBAAgB;AAAA,MACxB;AAAA,MACA,OAAO,OAAO;AACb,cAAM,SAAS,MAAM,KAAK,WAAW,EAAE,aAAgB,EAAE;AACzD,eAAO,OAAO;AAAA,MACf;AAAA,IACD;AAAA,EACD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,aACL,OACA,QACA,SACkB;AAClB,WAAO,KAAK;AAAA,MACX,QAAQ,UAAU;AAAA,MAClB;AAAA,MACA,QAAQ,gBAAgB;AAAA,MACxB;AAAA,MACA,OAAO,OAAO;AACb,cAAM,SAAS,MAAM,KAAK,WAAW,EAAE,aAAgB,EAAE;AACzD,eAAO,OAAO,SAAS,SAAS;AAAA,MACjC;AAAA,IACD;AAAA,EACD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,cACL,OACA,QACA,SACwB;AACxB,WAAO,KAAK;AAAA,MACX,QAAQ,UAAU;AAAA,MAClB;AAAA,MACA,QAAQ,gBAAgB;AAAA,MACxB;AAAA,MACA,OAAO,OAAO;AAEb,cAAM,UAAU,KAAK,WAAW;AAChC,cAAM,EAAE,QAAQ,QAAQ,SAAS,IAChC,MAAM,KAAK,iBAAiB,OAAO;AAEpC,YAAI;AACJ,YAAI;AAEJ,YAAI;AAEH,gBAAM,oBACL,CAAC,QAAQ,gBAAgB,GAAG,UAAU,GAAG;AAE1C,cAAI;AAEJ,cAAI,mBAAmB;AACtB,kBAAM,eAAe,MAAM,OAAO,aAAgB;AAAA,cACjD,MAAM;AAAA,cACN,OAAO,GAAG;AAAA,cACV,OAAO,GAAG;AAAA,cACV,QAAQ,GAAG,UAAU,CAAC,IAAI;AAAA,cAC1B,GAAI,GAAG,aAAa,UAAa,EAAE,UAAU,GAAG,SAAS;AAAA,YAC1D,CAAC;AACD,6BAAiB,aAAa;AAAA,UAC/B;AAGA,gBAAM,oBAAoB,MAAM,OAAO,aAAgB,EAAE;AACzD,yBAAe,kBAAkB;AAGjC,gBAAM,OAAO;AAEb,4BAAkB,oBAAoB,iBAAkB;AAAA,QACzD,SAAS,OAAO;AACf,gBAAM,SAAS;AACf,gBAAM;AAAA,QACP;AAEA,eAAO;AAAA,MACR;AAAA,IACD;AAAA,EACD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,cACL,OACA,QACA,SACwB;AACxB,UAAM,eAAe,QAAQ,gBAAgB;AAE7C,WAAO,KAAK;AAAA,MACX,QAAQ,UAAU;AAAA,MAClB;AAAA,MACA;AAAA,MACA;AAAA,MACA,OAAO,OAAO;AACb,cAAM,cAAc;AAGpB,cAAM,iBAAiB,YAAY,KAAK;AAAA,UAAI,CAAC,SAC5C,aAAuB,MAAM,YAAY,WAAW,QAAQ;AAAA,YAC3D,SAAS;AAAA,YACT,UAAU;AAAA,YACV,WAAW;AAAA,UACZ,CAAC;AAAA,QACF;AAGA,cAAM,UAAU,KAAK,WAAW;AAChC,cAAM,EAAE,QAAQ,QAAQ,SAAS,IAChC,MAAM,KAAK,iBAAiB,OAAO;AAEpC,YAAI;AAEJ,YAAI;AAEH,gBAAM,yBAA+C;AAAA,YACpD,MAAM;AAAA,YACN,OAAO,YAAY;AAAA,YACnB,MAAM;AAAA,UACP;AAEA,gBAAM,eAAe,MAAM,OAAO;AAAA,YACjC;AAAA,UACD;AACA,wBAAc,aAAa;AAG3B,cAAI,YAAY,WAAW;AAC1B,kBAAM,cAAc,MAAM;AAAA,cACzB,YAAY;AAAA,cACZ;AAAA,cACA;AAAA,cACA,KAAK;AAAA,YACN;AACA,uBAAW,YAAY,aAAa;AACnC,oBAAM;AAAA,gBACL;AAAA,gBACA,SAAS;AAAA,gBACT,OAAO;AAAA,gBACP;AAAA,gBACA;AAAA,gBACA,KAAK;AAAA,cACN;AAAA,YACD;AAAA,UACD;AAGA,gBAAM,OAAO;AAAA,QACd,SAAS,OAAO;AACf,gBAAM,SAAS;AACf,gBAAM;AAAA,QACP;AAGA,YAAI,QAAQ,aAAa;AACxB,iBAAO;AAAA,QACR;AAEA,cAAM,cAAoC;AAAA,UACzC,MAAM;AAAA,UACN,OAAO,YAAY;AAAA,UACnB,QAAQ,YAAY;AAAA,UACpB,OAAO;AAAA,YACN,IAAI,EAAE,KAAK,YAAY,IAAI,CAAC,MAAM,EAAE,EAAE,EAAE;AAAA,UACzC;AAAA,UACA,GAAI,YAAY,aAAa,UAAa;AAAA,YACzC,UAAU,YAAY;AAAA,UACvB;AAAA,QACD;AAEA,eAAO,KAAK,cAAiB,aAAa,QAAQ;AAAA,UACjD,cAAc;AAAA,QACf,CAAC;AAAA,MACF;AAAA,IACD;AAAA,EACD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,cACL,OACA,QACA,SACwB;AACxB,UAAM,eAAe,QAAQ,gBAAgB;AAE7C,WAAO,KAAK;AAAA,MACX,QAAQ,UAAU;AAAA,MAClB;AAAA,MACA;AAAA,MACA;AAAA,MACA,OAAO,OAAO;AACb,cAAM,cAAc;AAGpB,cAAM,gBAAgB;AAAA,UACrB,YAAY;AAAA,UACZ,YAAY;AAAA,UACZ;AAAA,UACA;AAAA,YACC,SAAS;AAAA,YACT,UAAU;AAAA,YACV,WAAW;AAAA,UACZ;AAAA,QACD;AAGA,cAAM,UAAU,KAAK,WAAW;AAChC,cAAM,EAAE,QAAQ,QAAQ,SAAS,IAChC,MAAM,KAAK,iBAAiB,OAAO;AAEpC,YAAI;AAEJ,YAAI;AAEH,gBAAM,yBAA+C;AAAA,YACpD,MAAM;AAAA,YACN,OAAO,YAAY;AAAA,YACnB,MAAM;AAAA,YACN,GAAI,YAAY,UAAU,UAAa;AAAA,cACtC,OAAO,YAAY;AAAA,YACpB;AAAA,UACD;AAEA,gBAAM,eAAe,MAAM,OAAO;AAAA,YACjC;AAAA,UACD;AACA,sBAAY,aAAa;AAGzB,cAAI,YAAY,WAAW;AAC1B,kBAAM,cAAc,MAAM;AAAA,cACzB,YAAY;AAAA,cACZ;AAAA,cACA;AAAA,cACA,KAAK;AAAA,YACN;AACA,uBAAW,YAAY,WAAW;AACjC,oBAAM;AAAA,gBACL;AAAA,gBACA,SAAS;AAAA,gBACT,OAAO;AAAA,gBACP;AAAA,gBACA;AAAA,gBACA,KAAK;AAAA,cACN;AAAA,YACD;AAAA,UACD;AAGA,gBAAM,OAAO;AAAA,QACd,SAAS,OAAO;AACf,gBAAM,SAAS;AACf,gBAAM;AAAA,QACP;AAGA,YAAI,QAAQ,aAAa;AACxB,iBAAO;AAAA,QACR;AAGA,cAAM,cAAoC;AAAA,UACzC,MAAM;AAAA,UACN,OAAO,YAAY;AAAA,UACnB,QAAQ,YAAY;AAAA,UACpB,OAAO;AAAA,YACN,IAAI,EAAE,KAAK,UAAU,IAAI,CAAC,MAAM,EAAE,EAAE,EAAE;AAAA,UACvC;AAAA,UACA,GAAI,YAAY,aAAa,UAAa;AAAA,YACzC,UAAU,YAAY;AAAA,UACvB;AAAA,QACD;AAEA,eAAO,KAAK,cAAiB,aAAa,QAAQ;AAAA,UACjD,cAAc;AAAA,QACf,CAAC;AAAA,MACF;AAAA,IACD;AAAA,EACD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAc,cACb,QACA,QACA,cACA,OACA,SACmB;AACnB,UAAM,aAAa,KAAK,cAAc;AAEtC,QAAI,cAAc;AACjB,aAAO,QAAQ,KAAK;AAAA,IACrB;AAEA,UAAM,UAAU,MAAM,WAAW,kBAAkB,MAAM;AAEzD,UAAM,gBAAiB,MAAM,WAAW;AAAA,MACvC;AAAA,MACA;AAAA,MACA;AAAA,IACD;AAEA,UAAM,SAAS,MAAM,QAAQ,aAAa;AAE1C,WAAO,WAAW;AAAA,MACjB;AAAA,MACA;AAAA,MACA;AAAA,IACD;AAAA,EACD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,iBAAiB,SAI5B;AACF,UAAM,KAAK,MAAM,QAAQ,iBAAiB;AAC1C,WAAO;AAAA,MACN,QAAQ;AAAA,MACR,QAAQ,YAAY;AACnB,cAAM,GAAG,OAAO;AAAA,MACjB;AAAA,MACA,UAAU,YAAY;AACrB,cAAM,GAAG,SAAS;AAAA,MACnB;AAAA,IACD;AAAA,EACD;AAAA;AAAA;AAAA;AAAA,EAKQ,UAAU,WAAqC;AACtD,UAAM,SAAS,KAAK,QAAQ,eAAe,SAAS;AACpD,QAAI,CAAC,QAAQ;AACZ,+BAAyB,SAAS;AAAA,IACnC;AACA,WAAO,OAAO;AAAA,EACf;AACD;;;ACtcO,IAAM,iBAAN,MAAyC;AAAA,EAG/C,YACkB,SACR,YACQ,gBAA2C,MAC3D;AAHgB;AACR;AACQ;AAGjB,SAAK,WAAW,IAAI;AAAA,MACnB;AAAA,MACA;AAAA,MACA,kBAAkB,OAAO,CAAC;AAAA;AAAA,IAC3B;AAAA,EACD;AAAA,EAbiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgDjB,MAAM,QACL,OACA,OACA,SACoB;AACpB,UAAM,UAAU,WAAc,OAAO,KAAK,OAAO,EAAE,MAAM,KAAK,EAAE,MAAM,CAAC;AAEvE,QAAI,SAAS,QAAQ;AACpB,cAAQ,OAAO,QAAQ,MAAM;AAAA,IAC9B;AACA,QAAI,SAAS,UAAU;AACtB,cAAQ,SAAS,QAAQ,QAAQ;AAAA,IAClC;AAEA,UAAM,QAAQ,QAAQ,MAAM;AAE5B,UAAM,UAAU,MAAM,KAAK,SAAS,QAAgB,OAAO;AAAA,MAC1D,cAAc,KAAK,kBAAkB;AAAA,MACrC,QAAQ;AAAA,IACT,CAAC;AAED,WAAO,QAAQ,CAAC,KAAK;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeA,MAAM,SACL,OACA,IACA,SACoB;AACpB,WAAO,KAAK,QAAW,OAAO,EAAE,GAAG,GAAqB,OAAO;AAAA,EAChE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA+BA,MAAM,SACL,OACA,SACe;AACf,UAAM,UAAU,WAAc,OAAO,KAAK,OAAO;AAEjD,QAAI,SAAS,OAAO;AACnB,cAAQ,MAAM,QAAQ,KAAK;AAAA,IAC5B;AACA,QAAI,SAAS,QAAQ;AACpB,cAAQ,OAAO,QAAQ,MAAM;AAAA,IAC9B;AACA,QAAI,SAAS,UAAU;AACtB,cAAQ,SAAS,QAAQ,QAAQ;AAAA,IAClC;AACA,QAAI,SAAS,SAAS;AACrB,cAAQ,QAAQ,SAAS,OAAO;AAAA,IACjC;AACA,QAAI,SAAS,UAAU,QAAW;AACjC,cAAQ,MAAM,QAAQ,KAAK;AAAA,IAC5B;AACA,QAAI,SAAS,WAAW,QAAW;AAClC,cAAQ,OAAO,QAAQ,MAAM;AAAA,IAC9B;AAEA,UAAM,QAAQ,QAAQ,MAAM;AAE5B,UAAM,UAAU,MAAM,KAAK,SAAS,QAAgB,OAAO;AAAA,MAC1D,cAAc,KAAK,kBAAkB;AAAA,MACrC,QAAQ;AAAA,IACT,CAAC;AAED,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAsBA,MAAM,MACL,OACA,OACkB;AAClB,UAAM,UAAU,UAAa,OAAO,KAAK,OAAO;AAEhD,QAAI,OAAO;AACV,cAAQ,MAAM,KAAK;AAAA,IACpB;AAEA,UAAM,QAAQ,QAAQ,MAAM;AAE5B,UAAM,SAAS,MAAM,KAAK,SAAS,QAAmB,OAAO;AAAA,MAC5D,cAAc,KAAK,kBAAkB;AAAA,MACrC,QAAQ;AAAA,IACT,CAAC;AAED,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAkBA,MAAM,OAGJ,OAAe,MAAc,SAAyC;AACvE,UAAM,SAAS,MAAM,KAAK,WAAsB,OAAO,CAAC,IAAI,GAAG;AAAA,MAC9D,GAAG;AAAA,MACH,QAAQ;AAAA;AAAA,IACT,CAAC;AAED,WAAO,OAAO,CAAC;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiBA,MAAM,WAGJ,OAAe,MAAgB,SAA2C;AAC3E,UAAM,UAAU;AAAA,MACf;AAAA,MACA;AAAA,MACA,KAAK;AAAA,IACN;AAEA,QAAI,SAAS,QAAQ;AACpB,cAAQ,OAAO,QAAQ,MAAM;AAAA,IAC9B;AACA,QAAI,SAAS,UAAU;AACtB,cAAQ,SAAS,QAAQ,QAAQ;AAAA,IAClC;AAEA,UAAM,QAAQ,QAAQ,MAAM;AAE5B,UAAM,SAAS,MAAM,KAAK,SAAS,QAAgB,OAAO;AAAA,MACzD,cAAc,KAAK,kBAAkB;AAAA,MACrC,QAAQ,SAAS,UAAU;AAAA,IAC5B,CAAC;AAED,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiBA,MAAM,OAIL,OACA,IACA,MACA,SACa;AACb,UAAM,SAAS,MAAM,KAAK;AAAA,MACzB;AAAA,MACA,EAAE,GAAG;AAAA,MACL;AAAA,MACA;AAAA,QACC,GAAG;AAAA,QACH,QAAQ,SAAS,UAAU;AAAA,MAC5B;AAAA,IACD;AAEA,QAAI,OAAO,WAAW,GAAG;AACxB,0BAAoB,UAAU,OAAO,EAAE;AAAA,IACxC;AAEA,WAAO,OAAO,CAAC;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA2BA,MAAM,WAIL,OACA,OACA,MACA,SACe;AACf,UAAM,UAAU;AAAA,MACf;AAAA,MACA;AAAA,MACA,KAAK;AAAA,IACN,EAAE,MAAM,KAAK;AAEb,QAAI,SAAS,UAAU,CAAC,SAAS,aAAa;AAC7C,cAAQ,OAAO,SAAS,UAAU,GAAG;AAAA,IACtC;AAEA,QAAI,SAAS,UAAU;AACtB,cAAQ,SAAS,QAAQ,QAAQ;AAAA,IAClC;AAEA,UAAM,QAAQ,QAAQ,MAAM;AAE5B,UAAM,SAAS,MAAM,KAAK,SAAS,QAAgB,OAAO;AAAA,MACzD,cAAc,KAAK,kBAAkB;AAAA,MACrC,aAAa,SAAS,eAAe;AAAA,MACrC,QAAQ,SAAS,UAAU;AAAA,IAC5B,CAAC;AAED,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcA,MAAM,OACL,OACA,IACA,SACa;AACb,UAAM,SAAS,MAAM,KAAK,WAAc,OAAO,EAAE,GAAG,GAAqB;AAAA,MACxE,GAAG;AAAA,MACH,aAAa,SAAS,eAAe;AAAA,MACrC,QAAQ,SAAS,UAAU;AAAA,IAC5B,CAAC;AAED,QAAI,OAAO,WAAW,GAAG;AACxB,0BAAoB,UAAU,OAAO,EAAE;AAAA,IACxC;AAEA,WAAO,OAAO,CAAC;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAsBA,MAAM,WACL,OACA,OACA,SACe;AACf,UAAM,eAAe,WAAc,OAAO,KAAK,OAAO,EAAE,MAAM,KAAK;AAEnE,QAAI,SAAS,UAAU,CAAC,SAAS;AAChC,mBAAa,OAAO,SAAS,UAAU,GAAG;AAE3C,QAAI,SAAS,SAAU,cAAa,SAAS,QAAQ,QAAQ;AAE7D,UAAM,QAAQ,aAAa,MAAM;AAEjC,UAAM,SAAS,MAAM,KAAK,SAAS,QAAgB,OAAO;AAAA,MACzD,cAAc,KAAK,kBAAkB;AAAA,MACrC,aAAa,SAAS,eAAe,EAAE,OAAO,UAAU,OAAO;AAAA,MAC/D,QAAQ,SAAS,UAAU;AAAA,IAC5B,CAAC;AAED,WAAO;AAAA,EACR;AACD;;;AC5cO,IAAM,6BAAN,MAAmE;AAAA,EACzE,YAA4B,SAA0C;AAA1C;AAAA,EAA2C;AAAA,EAEvE,UAAU,UAA6C;AACtD,WAAO,KAAK,QAAQ,IAAI,CAAC,YAAY;AAAA,MACpC,cAAc,OAAO;AAAA,MACrB,GAAG,SAAS,MAAM;AAAA,IACnB,EAAE;AAAA,EACH;AAAA,EAEA,YACC,WACA,UACoB;AACpB,WAAO,KAAK,QAAQ,OAAO,SAAS,EAAE,IAAI,CAAC,YAAY;AAAA,MACtD,cAAc,OAAO;AAAA,MACrB,GAAG,SAAS,MAAM;AAAA,IACnB,EAAE;AAAA,EACH;AAAA,EAEA,gBACC,SACA,UACoB;AACpB,WAAO,KAAK,QACV,OAAO,CAAC,WAAW,KAAK,eAAe,QAAQ,OAAO,CAAC,EACvD,IAAI,CAAC,YAAY;AAAA,MACjB,cAAc,OAAO;AAAA,MACrB,GAAG,SAAS,MAAM;AAAA,IACnB,EAAE;AAAA,EACJ;AAAA,EAEQ,eACP,QACA,SACU;AACV,QAAI,QAAQ,SAAS,CAAC,QAAQ,MAAM,SAAS,OAAO,IAAI,GAAG;AAC1D,aAAO;AAAA,IACR;AAEA,QAAI,QAAQ,UAAU,CAAC,OAAO,KAAK,WAAW,QAAQ,MAAM,GAAG;AAC9D,aAAO;AAAA,IACR;AAEA,QAAI,QAAQ,UAAU,CAAC,OAAO,KAAK,SAAS,QAAQ,MAAM,GAAG;AAC5D,aAAO;AAAA,IACR;AAEA,QAAI,QAAQ,SAAS,SAAS,OAAO,IAAI,GAAG;AAC3C,aAAO;AAAA,IACR;AAEA,QAAI,QAAQ,UAAU,CAAC,QAAQ,OAAO,MAAM,GAAG;AAC9C,aAAO;AAAA,IACR;AAEA,WAAO;AAAA,EACR;AACD;;;AC3DA,IAAM,mBAAmB,oBAAI,IAAI;AAAA,EAChC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,CAAC;AAKD,IAAM,yBAAiD;AAAA,EACtD,QAAQ;AACT;AAOO,SAAS,oBACf,OACO;AACP,MAAI,OAAO,UAAU,YAAY,UAAU,MAAM;AAChD,UAAM,IAAI,YAAY,2BAA2B;AAAA,MAChD,MAAM;AAAA,MACN,WAAW;AAAA,MACX,SAAS,EAAE,cAAc,OAAO,MAAM;AAAA,MACtC,YAAY;AAAA,MACZ,UAAU;AAAA,MACV,UAAU;AAAA,IACX,CAAC;AAAA,EACF;AAEA,QAAM,YAAY,OAAO,KAAK,KAAK;AACnC,QAAM,cAAwB,CAAC;AAC/B,QAAM,cAAwB,CAAC;AAE/B,aAAW,OAAO,WAAW;AAC5B,QAAI,CAAC,iBAAiB,IAAI,GAAG,GAAG;AAC/B,YAAM,aAAa,uBAAuB,GAAG;AAC7C,UAAI,YAAY;AACf,oBAAY,KAAK,GAAG;AACpB,oBAAY,KAAK,QAAQ,UAAU,iBAAiB,GAAG,GAAG;AAAA,MAC3D,OAAO;AACN,oBAAY,KAAK,GAAG;AAAA,MACrB;AAAA,IACD;AAAA,EACD;AAEA,MAAI,YAAY,SAAS,GAAG;AAC3B,UAAM,UAAU,YACd,IAAI,CAAC,QAAQ;AACb,YAAM,MAAM,uBAAuB,GAAG;AACtC,aAAO,MAAM,IAAI,GAAG,WAAW,GAAG,eAAe,IAAI,GAAG;AAAA,IACzD,CAAC,EACA,KAAK,IAAI;AAEX,UAAM,IAAI,YAAY,sCAAsC,OAAO,IAAI;AAAA,MACtE,MAAM;AAAA,MACN,WAAW;AAAA,MACX,SAAS;AAAA,QACR;AAAA,QACA,WAAW,MAAM,KAAK,gBAAgB;AAAA,QACtC;AAAA,MACD;AAAA,MACA,YACC,YAAY,SAAS,IAClB,YAAY,KAAK,IAAI,IACrB;AAAA,MACJ,UAAU,eAAe,MAAM,KAAK,gBAAgB,EAAE,KAAK,IAAI,CAAC;AAAA,IACjE,CAAC;AAAA,EACF;AAGA,QAAM,IAAI;AACV,MAAI,CAAC,EAAE,MAAM;AACZ,UAAM,IAAI,YAAY,+CAA+C;AAAA,MACpE,MAAM;AAAA,MACN,WAAW;AAAA,MACX,SAAS,EAAE,MAAM;AAAA,MACjB,YACC;AAAA,MACD,UAAU;AAAA,IACX,CAAC;AAAA,EACF;AACA,MAAI,CAAC,EAAE,OAAO;AACb,UAAM,IAAI,YAAY,gDAAgD;AAAA,MACrE,MAAM;AAAA,MACN,WAAW;AAAA,MACX,SAAS,EAAE,MAAM;AAAA,MACjB,YAAY;AAAA,MACZ,UAAU;AAAA,IACX,CAAC;AAAA,EACF;AACD;;;ACrGO,SAAS,uBAAuB,UAAiC;AACvE,QAAM,IAAI;AAAA,IACT,GAAG,QAAQ;AAAA,IACX;AAAA,MACC,MAAM;AAAA,MACN,WAAW,qBAAqB,QAAQ;AAAA,MACxC,YAAY,eAAe,QAAQ;AAAA,IACpC;AAAA,EACD;AACD;AAMO,SAAS,qBACf,YACA,UACA,OACQ;AACR,MAAI,iBAAiB,YAAa,OAAM;AACxC,QAAM,IAAI;AAAA,IACT,WAAW,UAAU,uBAAuB,QAAQ;AAAA,IACpD;AAAA,MACC,MAAM;AAAA,MACN,WAAW,qBAAqB,QAAQ;AAAA,MACxC,OAAO,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC;AAAA,IAChE;AAAA,EACD;AACD;AAOO,SAAS,mBACf,UACA,OACO;AACP,UAAQ;AAAA,IACP,YAAY,QAAQ;AAAA,IACpB;AAAA,EACD;AACD;;;AC5BA,SAAS,mBAAmB,QAAqB,QAA8B;AAC9E,SAAO;AAAA,IACN;AAAA,IACA;AAAA,IACA,UAAU,CAAC;AAAA,EACZ;AACD;AAKO,IAAM,aAAN,MAAiB;AAAA,EACvB,YACkB,UACA,QAChB;AAFgB;AACA;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOJ,MAAM,kBAAkB,QAA4C;AACnE,QAAI,UAAU,mBAAmB,QAAQ,KAAK,MAAM;AAEpD,eAAW,UAAU,KAAK,SAAS,OAAO,GAAG;AAC5C,UAAI;AACH,YAAI,OAAO,sBAAsB;AAChC,gBAAM,SAAS,MAAM,OAAO,qBAAqB,OAAO;AACxD,cAAI,QAAQ;AACX,sBAAU;AAAA,UACX;AAAA,QACD;AAAA,MACD,SAAS,OAAO;AACf,gBAAQ;AAAA,UACP,iCAAiC,OAAO,IAAI;AAAA,UAC5C;AAAA,QACD;AAAA,MACD;AAAA,IACD;AAEA,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,mBAAmB,SAAwC;AAChE,eAAW,UAAU,KAAK,SAAS,OAAO,GAAG;AAC5C,UAAI;AACH,YAAI,OAAO,cAAc;AACxB,gBAAM,OAAO,aAAa,OAAO;AAAA,QAClC;AAAA,MACD,SAAS,OAAO;AACf,gBAAQ;AAAA,UACP,iCAAiC,OAAO,IAAI;AAAA,UAC5C;AAAA,QACD;AAAA,MACD;AAAA,IACD;AAAA,EACD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,aAIL,QACA,QACA,OACA,UACa;AACb,UAAM,UAAU,MAAM,KAAK,kBAAkB,MAAM;AACnD,UAAM,gBAAgB,MAAM,KAAK;AAAA,MAChC;AAAA,MACA;AAAA,MACA;AAAA,IACD;AACA,UAAM,SAAS,MAAM,SAAS,aAAa;AAC3C,WAAO,KAAK,mBAAsB,QAAQ,QAAQ,OAAO;AAAA,EAC1D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,oBACL,OACA,QACA,SACgC;AAChC,wBAAoB,KAAK;AAEzB,QAAI,eAAe,EAAE,GAAG,MAAM;AAE9B,eAAW,UAAU,KAAK,SAAS,OAAO,GAAG;AAC5C,UAAI;AACH,YAAI,OAAO,eAAe;AACzB,yBAAe,MAAM,OAAO,cAAc,cAAc,OAAO;AAAA,QAChE;AAAA,MACD,SAAS,OAAO;AACf,6BAAqB,OAAO,MAAM,iBAAiB,KAAK;AAAA,MACzD;AAAA,IACD;AAEA,mBAAe,MAAM,KAAK;AAAA,MACzB;AAAA,MACA;AAAA,MACA;AAAA,IACD;AAEA,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,mBACL,QACA,QACA,SACmB;AACnB,QAAI,gBAAgB;AAEpB,eAAW,UAAU,KAAK,SAAS,OAAO,GAAG;AAC5C,UAAI;AACH,YAAI,OAAO,cAAc;AACxB,0BAAgB,MAAM,OAAO,aAAa,eAAe,OAAO;AAAA,QACjE;AAAA,MACD,SAAS,OAAO;AACf,2BAAmB,aAAa,KAAK;AAAA,MACtC;AAAA,IACD;AAEA,oBAAgB,MAAM,KAAK;AAAA,MAC1B;AAAA,MACA;AAAA,MACA;AAAA,IACD;AAEA,WAAO;AAAA,EACR;AAAA,EAEA,MAAc,yBACb,OACA,QACA,SACgC;AAChC,UAAM,QAAQ,OAAO;AACrB,QAAI,CAAC,MAAO,QAAO;AAEnB,UAAM,EAAE,OAAO,IAAI;AAEnB,SACE,WAAW,YAAY,WAAW,iBACnC,MAAM,gBACN,MAAM,SAAS,UACd;AACD,YAAM,WAAW,MAAM,MAAM;AAAA,QAC5B;AAAA,QACA;AAAA,MACD;AACA,UAAI,YAAY,KAAM,wBAAuB,cAAc;AAC3D,aAAO;AAAA,IACR;AAEA,SACE,WAAW,YAAY,WAAW,iBACnC,MAAM,gBACN,MAAM,SAAS,UACd;AACD,YAAM,WAAW,MAAM,MAAM;AAAA,QAC5B;AAAA,QACA;AAAA,MACD;AACA,UAAI,YAAY,KAAM,wBAAuB,cAAc;AAC3D,aAAO;AAAA,IACR;AAEA,SACE,WAAW,YAAY,WAAW,iBACnC,MAAM,gBACN,MAAM,SAAS,UACd;AACD,YAAM,WAAW,MAAM,MAAM;AAAA,QAC5B;AAAA,QACA;AAAA,MACD;AACA,UAAI,YAAY,KAAM,wBAAuB,cAAc;AAC3D,aAAO;AAAA,IACR;AAEA,SACE,WAAW,aAAa,WAAW,cAAc,WAAW,YAC7D,MAAM,cACN,MAAM,SAAS,UACd;AACD,YAAM,WAAW,MAAM,MAAM;AAAA,QAC5B;AAAA,QACA;AAAA,MACD;AACA,UAAI,YAAY,KAAM,wBAAuB,YAAY;AACzD,aAAO;AAAA,IACR;AAEA,WAAO;AAAA,EACR;AAAA,EAEA,MAAc,wBACb,QACA,QACA,SACmB;AACnB,UAAM,QAAQ,OAAO;AACrB,QAAI,CAAC,MAAO,QAAO;AAEnB,UAAM,EAAE,OAAO,IAAI;AACnB,UAAM,OAAO;AAEb,SAAK,WAAW,YAAY,WAAW,iBAAiB,MAAM,aAAa;AAC1E,UAAI;AACH,eAAQ,MAAM,MAAM;AAAA,UACnB;AAAA,UACA;AAAA,QACD;AAAA,MACD,SAAS,OAAO;AACf,2BAAmB,eAAe,KAAK;AAAA,MACxC;AAAA,IACD;AAEA,SAAK,WAAW,YAAY,WAAW,iBAAiB,MAAM,aAAa;AAC1E,UAAI;AACH,eAAQ,MAAM,MAAM;AAAA,UACnB;AAAA,UACA;AAAA,QACD;AAAA,MACD,SAAS,OAAO;AACf,2BAAmB,eAAe,KAAK;AAAA,MACxC;AAAA,IACD;AAEA,SAAK,WAAW,YAAY,WAAW,iBAAiB,MAAM,aAAa;AAC1E,UAAI;AACH,cAAM,MAAM,YAAY,MAAkC,OAAO;AAAA,MAClE,SAAS,OAAO;AACf,2BAAmB,eAAe,KAAK;AAAA,MACxC;AACA,aAAO;AAAA,IACR;AAEA,SAAK,WAAW,aAAa,WAAW,eAAe,MAAM,WAAW;AACvE,UAAI;AACH,eAAQ,MAAM,MAAM;AAAA,UACnB;AAAA,UACA;AAAA,QACD;AAAA,MACD,SAAS,OAAO;AACf,2BAAmB,aAAa,KAAK;AAAA,MACtC;AAAA,IACD;AAEA,WAAO;AAAA,EACR;AACD;AAKO,SAAS,iBACf,UACA,QACa;AACb,SAAO,IAAI,WAAW,UAAU,MAAM;AACvC;;;AC7PO,IAAM,cAAN,cAA0B,MAAM;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EAET,YACC,SACA,SACC;AACD,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,OAAO,SAAS,QAAQ;AAC7B,SAAK,aAAa,SAAS;AAC3B,SAAK,UAAU,SAAS;AAAA,EACzB;AACD;AAKO,SAAS,eAAe,OAAuC;AACrE,MAAI,OAAO,UAAU,YAAY,UAAU,MAAM;AAChD,WAAO;AAAA,EACR;AAEA,QAAM,MAAM;AAEZ,SACC,UAAU,OACV,aAAa,OACb,UAAU,OACV,aAAa,OACb,OAAO,IAAI,MAAM,MAAM,YACvB,OAAO,IAAI,SAAS,MAAM,YAC1B,OAAO,IAAI,MAAM,MAAM,cACvB,OAAO,IAAI,SAAS,MAAM;AAE5B;AAYO,IAAM,cAAN,cAA0B,YAAY;AAAA,EAC5C,YAAY,SAAiB,SAAmB;AAC/C,UAAM,SAAS,EAAE,MAAM,gBAAgB,QAAQ,CAAC;AAChD,SAAK,OAAO;AAAA,EACb;AACD;AAKO,IAAM,iBAAN,MAAqB;AAAA,EACV,UAAqC,oBAAI,IAAI;AAAA,EAE9D,SAAS,QAA4B;AACpC,QAAI,KAAK,QAAQ,IAAI,OAAO,IAAI,GAAG;AAClC,YAAM,IAAI,YAAY,8BAA8B,OAAO,IAAI,IAAI;AAAA,QAClE,MAAM;AAAA,MACP,CAAC;AAAA,IACF;AACA,SAAK,QAAQ,IAAI,OAAO,MAAM,MAAM;AAAA,EACrC;AAAA,EAEA,IAAI,MAAwC;AAC3C,WAAO,KAAK,QAAQ,IAAI,IAAI;AAAA,EAC7B;AAAA,EAEA,IAAI,MAAuB;AAC1B,WAAO,KAAK,QAAQ,IAAI,IAAI;AAAA,EAC7B;AAAA,EAEA,SAAkC;AACjC,WAAO,MAAM,KAAK,KAAK,QAAQ,OAAO,CAAC;AAAA,EACxC;AAAA,EAEA,MAAM,QAAQ,SAAuC;AACpD,eAAW,UAAU,KAAK,QAAQ,OAAO,GAAG;AAC3C,YAAM,OAAO,KAAK,OAAO;AAAA,IAC1B;AAAA,EACD;AAAA,EAEA,MAAM,aAA4B;AACjC,eAAW,UAAU,KAAK,QAAQ,OAAO,GAAG;AAC3C,YAAM,OAAO,QAAQ;AAAA,IACtB;AAAA,EACD;AACD;;;ACpJO,IAAM,wBAAwB;AAM9B,IAAM,yBAAyB;AAM/B,IAAM,4BAA4B;AAMlC,IAAM,kBAAkB;AAKxB,IAAMC,wBAAuB;AAAA,EACnC;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AACD;AAKO,IAAMC,oBAAmB;AAAA,EAC/B;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AACD;AAKO,IAAM,kBAAkB;AAAA,EAC9B;AAAA;AAAA,EACA;AAAA;AACD;AAKO,IAAM,iBAAiB;AAAA,EAC7B;AAAA;AAAA,EACA;AAAA;AACD;AAKO,IAAM,oBAAoB;AAAA,EAChC;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AACD;AAKO,IAAM,sBAAsB;AAAA,EAClC,GAAGD;AAAA,EACH,GAAGC;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AACJ;AAiBO,IAAM,uBAA0D;AAAA;AAAA,EAEtE,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,MAAM;AAAA,EACN,KAAK;AAAA,EACL,MAAM;AAAA;AAAA,EAGN,WAAW;AAAA,EACX,cAAc;AAAA,EACd,aAAa;AAAA,EACb,WAAW;AAAA,EACX,OAAO;AAAA,EACP,QAAQ;AAAA;AAAA,EAGR,KAAK;AAAA,EACL,MAAM;AAAA;AAAA,EAGN,OAAO;AAAA,EACP,UAAU;AAAA;AAAA,EAGV,MAAM;AAAA,EACN,KAAK;AAAA,EACL,MAAM;AACP;AAKO,SAAS,qBACf,UACmD;AACnD,SAAQ,oBAA0C,SAAS,QAAQ;AACpE;AAKO,SAASC,mBACf,UACiD;AACjD,SAAQ,kBAAwC,SAAS,QAAQ;AAClE;AAKO,SAAS,mBAAmB,UAA2B;AAC7D,SAAO,qBAAqB,QAAQ,MAAM;AAC3C;AAKO,SAAS,mBAAmB,UAA2B;AAC7D,SAAO,qBAAqB,QAAQ,MAAM;AAC3C;AAKO,SAAS,qBACf,UACgC;AAChC,SAAO,qBAAqB,QAAQ;AACrC;AAKO,IAAM,oBAAoB;AAK1B,IAAM,yBAAyB;AAM/B,IAAM,qBAAqB;AAK3B,IAAM,wBAAwB;AAK9B,IAAM,uBAAuB;AAAA,EACnC;AAAA,EACA;AAAA,EACA;AACD;AAyBO,SAAS,kBAAkB,WAA0C;AAE3E,MAAI,CAAC,aAAa,UAAU,KAAK,MAAM,IAAI;AAC1C,WAAO,EAAE,OAAO,OAAO,QAAQ,QAAQ;AAAA,EACxC;AAGA,MAAI,UAAU,SAAS,uBAAuB;AAC7C,WAAO;AAAA,MACN,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,QAAQ,OAAO,qBAAqB;AAAA,IACrC;AAAA,EACD;AAGA,MACC,qBAAqB;AAAA,IACpB;AAAA,EACD,GACC;AACD,WAAO,EAAE,OAAO,OAAO,QAAQ,kBAAkB,QAAQ,UAAU;AAAA,EACpE;AAGA,MAAI,sBAAsB,KAAK,SAAS,GAAG;AAC1C,WAAO,EAAE,OAAO,OAAO,QAAQ,gBAAgB;AAAA,EAChD;AAGA,MAAI,CAAC,mBAAmB,KAAK,SAAS,GAAG;AACxC,WAAO,EAAE,OAAO,OAAO,QAAQ,iBAAiB;AAAA,EACjD;AAEA,SAAO,EAAE,OAAO,KAAK;AACtB;AAQO,SAAS,iBAAiB,WAA4B;AAC5D,SAAO,kBAAkB,SAAS,EAAE;AACrC;;;ACxPO,IAAM,sBAAN,cAAkC,MAAM;AAAA,EACrC;AAAA,EACA;AAAA,EACA;AAAA,EAET,YACC,SACA,SAKC;AACD,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,OAAO,SAAS,QAAQ;AAC7B,SAAK,aAAa,SAAS;AAC3B,SAAK,UAAU,SAAS;AAAA,EACzB;AACD;AAwBO,IAAM,iBAAN,MAAgD;AAAA,EACrC,UAAyC,oBAAI,IAAI;AAAA,EACjD;AAAA,EACT,SAAS;AAAA,EACT,QAAuB;AAAA,IAC9B,gBAAgB,oBAAI,IAAI;AAAA,IACxB,oBAAoB,oBAAI,IAAI;AAAA,IAC5B,gBAAgB,oBAAI,IAAI;AAAA,IACxB,cAAc,oBAAI,IAAI;AAAA,EACvB;AAAA,EAEA,YAAY,QAA+B;AAC1C,SAAK,SAAS;AAAA,MACb,QAAQ,QAAQ,UAAU;AAAA,MAC1B,gBAAgB,QAAQ,kBAAkB;AAAA,MAC1C,mBAAmB,QAAQ,qBAAqB;AAAA,IACjD;AAAA,EACD;AAAA;AAAA;AAAA;AAAA,EAKQ,kBAAwB;AAC/B,SAAK,MAAM,eAAe,MAAM;AAChC,SAAK,MAAM,mBAAmB,MAAM;AACpC,SAAK,MAAM,eAAe,MAAM;AAChC,SAAK,MAAM,aAAa,MAAM;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,SAAS,QAA4C;AACpD,QAAI,KAAK,QAAQ;AAChB,YAAM,IAAI,oBAAoB,sBAAsB;AAAA,QACnD,MAAM;AAAA,MACP,CAAC;AAAA,IACF;AAEA,QAAI,CAAC,OAAO,QAAQ,OAAO,KAAK,KAAK,MAAM,IAAI;AAC9C,YAAM,IAAI,oBAAoB,2BAA2B;AAAA,QACxD,MAAM;AAAA,MACP,CAAC;AAAA,IACF;AAEA,QAAI,KAAK,QAAQ,IAAI,OAAO,IAAI,KAAK,CAAC,KAAK,OAAO,gBAAgB;AACjE,YAAM,IAAI;AAAA,QACT,8BAA8B,OAAO,IAAI;AAAA,QACzC;AAAA,UACC,MAAM;AAAA,UACN,YAAY,OAAO;AAAA,QACpB;AAAA,MACD;AAAA,IACD;AAEA,eAAW,iBAAiB,iBAAiB;AAC5C,UAAI,iBAAiB,OAAO,QAAQ;AACnC,cAAM,IAAI;AAAA,UACT,UAAU,aAAa,2DAA2D,OAAO,IAAI;AAAA,UAC7F;AAAA,YACC,MAAM;AAAA,YACN,YAAY,OAAO;AAAA,YACnB,SAAS,EAAE,OAAO,cAAc;AAAA,UACjC;AAAA,QACD;AAAA,MACD;AAAA,IACD;AAEA,QAAI,KAAK,OAAO,QAAQ;AACvB,YAAM,aAAa,yBAAyB,MAAM;AAClD,UAAI,CAAC,WAAW,OAAO;AACtB,cAAM,IAAI;AAAA,UACT,6BAA6B,OAAO,IAAI;AAAA,UACxC;AAAA,YACC,MAAM;AAAA,YACN,YAAY,OAAO;AAAA,YACnB,SAAS,WAAW;AAAA,UACrB;AAAA,QACD;AAAA,MACD;AAAA,IACD;AAEA,UAAM,oBAAoB,KAAK,oBAAoB,OAAO,MAAM;AAEhE,UAAM,iBAAiB;AAAA,MACtB,IAAI;AAAA,QACH,MAAM;AAAA,QACN,SAAS;AAAA,QACT,eAAe;AAAA,QACf,UAAU;AAAA,MACX;AAAA,MACA,GAAG;AAAA,MACH,WAAW;AAAA,QACV,MAAM;AAAA,QACN,UAAU;AAAA,MACX;AAAA,MACA,WAAW;AAAA,QACV,MAAM;AAAA,QACN,UAAU;AAAA,MACX;AAAA,IACD;AAEA,UAAM,eAAe;AAAA,MACpB,GAAG;AAAA,MACH,WAAW,OAAO,aAAa,KAAK,UAAU,OAAO,KAAK,YAAY,CAAC;AAAA,MACvE,QAAQ;AAAA,IACT;AAEA,SAAK,QAAQ,IAAI,OAAO,MAAM,YAAY;AAC1C,SAAK,gBAAgB;AAErB,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,aAAa,SAA4C;AACxD,eAAW,UAAU,SAAS;AAC7B,WAAK,SAAS,MAAM;AAAA,IACrB;AAAA,EACD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,mBAAyB;AACxB,SAAK,iBAAiB;AAEtB,QAAI,KAAK,OAAO,mBAAmB;AAClC,WAAK,kBAAkB;AAAA,IACxB;AAEA,SAAK,mBAAmB;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,qBAA2B;AAClC,UAAM,aAAa,MAAM,KAAK,KAAK,QAAQ,OAAO,CAAC;AACnD,UAAM,SAAS,wBAAwB,UAAU;AAGjD,UAAM,UAAU,oBAAI,IAA8B;AAElD,UAAM,aAAa,KAAK,QAAQ,IAAI,iBAAiB;AACrD,QAAI,YAAY;AACf,cAAQ,IAAI,mBAAmB,UAAU;AAAA,IAC1C;AAEA,eAAW,UAAU,QAAQ;AAC5B,UAAI,OAAO,SAAS,kBAAmB;AACvC,cAAQ,IAAI,OAAO,MAAM,MAAM;AAAA,IAChC;AAEA,SAAK,QAAQ,MAAM;AACnB,eAAW,CAAC,MAAM,MAAM,KAAK,SAAS;AACrC,WAAK,QAAQ,IAAI,MAAM,MAAM;AAAA,IAC9B;AAAA,EACD;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,MAA4C;AAC/C,WAAO,KAAK,QAAQ,IAAI,IAAI;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA,EAKA,iBACC,WAC8D;AAC9D,UAAM,SAAS,KAAK,IAAI,SAAS;AACjC,QAAI,CAAC,OAAQ,QAAO;AACpB,WAAO;AAAA,MACN;AAAA,MACA,WAAW,OAAO,aAAa,KAAK,UAAU,UAAU,YAAY,CAAC;AAAA,IACtE;AAAA,EACD;AAAA;AAAA;AAAA;AAAA,EAKA,eACC,WAC8D;AAC9D,UAAM,YAAY,KAAK,qBAAqB,SAAS;AACrD,QAAI,CAAC,UAAW,QAAO;AACvB,WAAO,KAAK,iBAAiB,SAAS;AAAA,EACvC;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,MAAuB;AAC1B,WAAO,KAAK,QAAQ,IAAI,IAAI;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA,EAKA,SAAsC;AACrC,WAAO,MAAM,KAAK,KAAK,QAAQ,OAAO,CAAC;AAAA,EACxC;AAAA;AAAA;AAAA;AAAA,EAKA,WAA8B;AAC7B,WAAO,MAAM,KAAK,KAAK,QAAQ,KAAK,CAAC;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,OAAe;AAClB,WAAO,KAAK,QAAQ;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA,EAKA,qBAAqB,WAAyC;AAC7D,QAAI,CAAC,UAAW,QAAO;AACvB,eAAW,CAAC,WAAW,MAAM,KAAK,KAAK,QAAQ,QAAQ,GAAG;AACzD,YAAM,kBACL,OAAO,aAAa,KAAK,UAAU,UAAU,YAAY,CAAC;AAC3D,UAAI,oBAAoB,WAAW;AAClC,eAAO;AAAA,MACR;AAAA,IACD;AACA,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA,EAKA,0BAAuD;AACtD,WAAO,KAAK,OAAO,EAAE;AAAA,MAAO,CAAC,WAC5B,OAAO,OAAO,OAAO,MAAM,EAAE,KAAK,CAAC,UAAU,MAAM,SAAS,UAAU;AAAA,IACvE;AAAA,EACD;AAAA;AAAA;AAAA;AAAA,EAKA,kBAAkB,YAAuC;AACxD,UAAM,SAAS,KAAK,MAAM,eAAe,IAAI,UAAU;AACvD,QAAI,OAAQ,QAAO;AAEnB,UAAM,SAAS,KAAK,IAAI,UAAU;AAClC,QAAI,CAAC,OAAQ,QAAO,CAAC;AAErB,UAAM,UAAoB,CAAC;AAC3B,eAAW,SAAS,OAAO,OAAO,OAAO,MAAM,GAAG;AACjD,UAAI,MAAM,SAAS,YAAY;AAC9B,cAAM,gBAAgB;AACtB,YAAI,CAAC,QAAQ,SAAS,cAAc,KAAK,GAAG;AAC3C,kBAAQ,KAAK,cAAc,KAAK;AAAA,QACjC;AAAA,MACD;AAAA,IACD;AAEA,SAAK,MAAM,eAAe,IAAI,YAAY,OAAO;AACjD,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA,EAKA,sBAAsB,YAAuC;AAC5D,UAAM,SAAS,KAAK,MAAM,mBAAmB,IAAI,UAAU;AAC3D,QAAI,OAAQ,QAAO;AAEnB,UAAM,cAAwB,CAAC;AAC/B,eAAW,CAAC,MAAM,MAAM,KAAK,KAAK,QAAQ,QAAQ,GAAG;AACpD,iBAAW,SAAS,OAAO,OAAO,OAAO,MAAM,GAAG;AACjD,YAAI,MAAM,SAAS,YAAY;AAC9B,gBAAM,gBAAgB;AACtB,cAAI,cAAc,UAAU,YAAY;AACvC,wBAAY,KAAK,IAAI;AACrB;AAAA,UACD;AAAA,QACD;AAAA,MACD;AAAA,IACD;AAEA,SAAK,MAAM,mBAAmB,IAAI,YAAY,WAAW;AACzD,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA,EAKA,gBAAgB,WAAgD;AAC/D,UAAM,SAAS,KAAK,MAAM,eAAe,IAAI,SAAS;AACtD,QAAI,OAAQ,QAAO;AAEnB,UAAM,SAAS,KAAK,OAAO,EAAE;AAAA,MAAO,CAAC,WACpC,OAAO,OAAO,OAAO,MAAM,EAAE,KAAK,CAAC,UAAU,MAAM,SAAS,SAAS;AAAA,IACtE;AAEA,SAAK,MAAM,eAAe,IAAI,WAAW,MAAM;AAC/C,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,sBACC,WACiB;AACjB,UAAM,SAAS,KAAK,IAAI,SAAS;AACjC,QAAI,CAAC,QAAQ;AACZ,YAAM,IAAI,oBAAoB,qBAAqB,SAAS,IAAI;AAAA,QAC/D,MAAM;AAAA,MACP,CAAC;AAAA,IACF;AAEA,UAAM,SAAS,KAAK,MAAM,aAAa,IAAI,SAAS;AACpD,QAAI,OAAQ,QAAO;AAEnB,UAAM,cAAwB,CAAC;AAC/B,eAAW,CAAC,WAAW,QAAQ,KAAK,OAAO,QAAQ,OAAO,MAAM,GAAG;AAClE,UAAK,SAAkC,OAAQ;AAC/C,UAAI,SAAS,SAAS,WAAY;AAClC,kBAAY,KAAK,SAAS;AAAA,IAC3B;AAEA,SAAK,MAAM,aAAa,IAAI,WAAW,WAAW;AAClD,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA,EAKA,oBAA0B;AACzB,UAAM,SAAkC,CAAC;AAEzC,eAAW,CAAC,EAAE,MAAM,KAAK,KAAK,QAAQ,QAAQ,GAAG;AAChD,iBAAW,CAAC,WAAW,KAAK,KAAK,OAAO,QAAQ,OAAO,MAAM,GAAG;AAC/D,YAAI,MAAM,SAAS,YAAY;AAC9B,gBAAM,gBAAgB;AACtB,cAAI,CAAC,KAAK,IAAI,cAAc,KAAK,GAAG;AACnC,mBAAO,KAAK;AAAA,cACX,OAAO;AAAA,cACP,SAAS,8BAA8B,cAAc,KAAK;AAAA,cAC1D,MAAM;AAAA,YACP,CAAC;AAAA,UACF;AAAA,QACD;AAAA,MACD;AAAA,IACD;AAEA,QAAI,OAAO,SAAS,GAAG;AACtB,YAAM,IAAI,oBAAoB,8BAA8B;AAAA,QAC3D,MAAM;AAAA,QACN,SAAS;AAAA,MACV,CAAC;AAAA,IACF;AAAA,EACD;AAAA;AAAA;AAAA;AAAA,EAKA,QAAc;AACb,QAAI,KAAK,QAAQ;AAChB,YAAM,IAAI,oBAAoB,gCAAgC;AAAA,QAC7D,MAAM;AAAA,MACP,CAAC;AAAA,IACF;AACA,SAAK,QAAQ,MAAM;AACnB,SAAK,gBAAgB;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,MAAuB;AAC7B,QAAI,KAAK,QAAQ;AAChB,YAAM,IAAI,oBAAoB,sCAAsC;AAAA,QACnE,MAAM;AAAA,MACP,CAAC;AAAA,IACF;AAEA,UAAM,UAAU,KAAK,QAAQ,OAAO,IAAI;AACxC,QAAI,SAAS;AACZ,WAAK,gBAAgB;AAAA,IACtB;AACA,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA,EAKA,OAAa;AACZ,SAAK,SAAS;AAAA,EACf;AAAA;AAAA;AAAA;AAAA,EAKA,SAAe;AACd,SAAK,SAAS;AAAA,EACf;AAAA;AAAA;AAAA;AAAA,EAKA,WAAoB;AACnB,WAAO,KAAK;AAAA,EACb;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYQ,oBACP,QACkC;AAClC,UAAM,SAA0C,CAAC;AAEjD,eAAW,CAAC,WAAW,KAAK,KAAK,OAAO,QAAQ,MAAM,GAAG;AACxD,UAAI,MAAM,SAAS,QAAQ;AAC1B,eAAO,SAAS,IAAI;AACpB;AAAA,MACD;AAEA,YAAM,YAAY;AAElB,YAAM,cAAgC;AAAA,QACrC,GAAI,UAAU,iBAAiB,UAAa;AAAA,UAC3C,cAAc,UAAU;AAAA,QACzB;AAAA,QACA,GAAI,UAAU,YAAY,UAAa;AAAA,UACtC,SAAS,UAAU;AAAA,QACpB;AAAA,MACD;AAEA,YAAM,iBAAiB,OAAO,KAAK,WAAW,EAAE,SAAS;AAEzD,YAAM,gBAA+B;AAAA,QACpC,MAAM;AAAA,QACN,OAAO;AAAA,QACP,MAAM,UAAU,WAAW,YAAY;AAAA,QACvC,GAAI,UAAU,aAAa,UAAa;AAAA,UACvC,UAAU,UAAU;AAAA,QACrB;AAAA,QACA,GAAI,kBAAkB,EAAE,YAAY;AAAA,MACrC;AAEA,aAAO,SAAS,IAAI;AAAA,IACrB;AAEA,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,mBAAyB;AAChC,eAAW,CAAC,YAAY,MAAM,KAAK,KAAK,QAAQ,QAAQ,GAAG;AAC1D,YAAM,iBAAiB,EAAE,GAAG,OAAO,OAAO;AAE1C,iBAAW,CAAC,WAAW,KAAK,KAAK,OAAO,QAAQ,OAAO,MAAM,GAAG;AAC/D,YAAI,MAAM,SAAS,WAAY;AAE/B,cAAM,WAAW;AACjB,cAAM,eAAe,KAAK,QAAQ,IAAI,SAAS,KAAK;AAEpD,YAAI,CAAC,cAAc;AAClB,gBAAM,IAAI;AAAA,YACT,8BAA8B,SAAS,KAAK,cAAc,UAAU,IAAI,SAAS;AAAA,YACjF;AAAA,cACC,MAAM;AAAA,cACN;AAAA,cACA,SAAS,EAAE,OAAO,WAAW,QAAQ,SAAS,MAAM;AAAA,YACrD;AAAA,UACD;AAAA,QACD;AAEA,YAAI,SAAS,SAAS,aAAa;AAClC,gBAAM,aAAa,SAAS,cAAc,GAAG,SAAS;AAEtD,cAAI,EAAE,cAAc,iBAAiB;AACpC,kBAAM,kBACL,aAAa,aACb,KAAK,UAAU,SAAS,MAAM,YAAY,CAAC;AAC5C,kBAAM,aAAa,SAAS,YAAY;AACxC,kBAAM,kBAAkB,aAAa,YAAY;AACjD,2BAAe,UAAU,IAAI;AAAA,cAC5B,MAAM;AAAA,cACN,UAAU;AAAA,cACV,QAAQ;AAAA,cACR,YAAY;AAAA,gBACX,OAAO;AAAA,gBACP,QAAQ;AAAA,gBACR,UAAU,SAAS,YAAY;AAAA,gBAC/B,UAAU,SAAS;AAAA,cACpB;AAAA,YACD;AAAA,UACD;AAEA,yBAAe,SAAS,IAAI;AAAA,YAC3B,GAAG;AAAA,YACH;AAAA,UACD;AAAA,QACD;AAEA,YAAI,SAAS,SAAS,YAAY,SAAS,SAAS,WAAW;AAC9D,gBAAM,aAAa,SAAS,cAAc,GAAG,UAAU;AACvD,gBAAM,eAAe,EAAE,GAAG,aAAa,OAAO;AAE9C,cAAI,EAAE,cAAc,eAAe;AAClC,kBAAM,kBACL,OAAO,aAAa,KAAK,UAAU,WAAW,YAAY,CAAC;AAC5D,yBAAa,UAAU,IAAI;AAAA,cAC1B,MAAM;AAAA,cACN,UAAU;AAAA,cACV,QAAQ;AAAA,cACR,YAAY;AAAA,gBACX,OAAO;AAAA,gBACP,QAAQ;AAAA,gBACR,UAAU,SAAS,YAAY;AAAA,gBAC/B,UAAU,SAAS;AAAA,cACpB;AAAA,YACD;AAAA,UACD;AAEA,eAAK,QAAQ,IAAI,SAAS,OAAO;AAAA,YAChC,GAAG;AAAA,YACH,QAAQ;AAAA,UACT,CAAC;AAED,yBAAe,SAAS,IAAI;AAAA,YAC3B,GAAG;AAAA,YACH;AAAA,UACD;AAAA,QACD;AAEA,YAAI,SAAS,SAAS,cAAc;AACnC,gBAAM,oBACL,SAAS,WACT,KAAK,qBAAqB,YAAY,SAAS,KAAK;AAErD,eAAK,oBAAoB,YAAY,UAAU,iBAAiB;AAEhE,yBAAe,SAAS,IAAI;AAAA,YAC3B,GAAG;AAAA,YACH,SAAS;AAAA,UACV;AAAA,QACD;AAAA,MACD;AAEA,WAAK,QAAQ,IAAI,YAAY;AAAA,QAC5B,GAAG;AAAA,QACH,QAAQ;AAAA,MACT,CAAC;AAAA,IACF;AAAA,EACD;AAAA;AAAA;AAAA;AAAA,EAKQ,oBACP,YACA,UACA,mBACO;AACP,QAAI,KAAK,QAAQ,IAAI,iBAAiB,EAAG;AAEzC,UAAM,WAAW,GAAG,UAAU;AAC9B,UAAM,WAAW,GAAG,SAAS,KAAK;AAElC,UAAM,iBAAmC;AAAA,MACxC,MAAM;AAAA,MACN,WAAW;AAAA,MACX,QAAQ;AAAA,QACP,IAAI,EAAE,MAAM,UAAU,UAAU,OAAO,eAAe,KAAK;AAAA,QAC3D,CAAC,UAAU,GAAG;AAAA,UACb,MAAM;AAAA,UACN,MAAM;AAAA,UACN,OAAO;AAAA,UACP,YAAY;AAAA,UACZ,UAAU;AAAA,QACX;AAAA,QACA,CAAC,SAAS,KAAK,GAAG;AAAA,UACjB,MAAM;AAAA,UACN,MAAM;AAAA,UACN,OAAO,SAAS;AAAA,UAChB,YAAY;AAAA,UACZ,UAAU;AAAA,QACX;AAAA,QACA,CAAC,QAAQ,GAAG;AAAA,UACX,MAAM;AAAA,UACN,UAAU;AAAA,UACV,QAAQ;AAAA,UACR,YAAY;AAAA,YACX,OAAO,KAAK,UAAU,WAAW,YAAY,CAAC;AAAA,YAC9C,QAAQ;AAAA,YACR,UAAU;AAAA,UACX;AAAA,QACD;AAAA,QACA,CAAC,QAAQ,GAAG;AAAA,UACX,MAAM;AAAA,UACN,UAAU;AAAA,UACV,QAAQ;AAAA,UACR,YAAY;AAAA,YACX,OAAO,KAAK,UAAU,SAAS,MAAM,YAAY,CAAC;AAAA,YAClD,QAAQ;AAAA,YACR,UAAU;AAAA,UACX;AAAA,QACD;AAAA,MACD;AAAA,MACA,SAAS;AAAA,QACR;AAAA,UACC,QAAQ,CAAC,UAAU,QAAQ;AAAA,UAC3B,QAAQ;AAAA,QACT;AAAA,MACD;AAAA,MACA,kBAAkB;AAAA,IACnB;AAEA,SAAK,QAAQ,IAAI,mBAAmB,cAAc;AAAA,EACnD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,qBAAqB,SAAiB,SAAyB;AACtE,UAAM,SAAS,CAAC,SAAS,OAAO,EAAE,KAAK;AACvC,WAAO,GAAG,OAAO,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA,EAKQ,UAAU,MAAsB;AACvC,UAAM,aAAqC;AAAA,MAC1C,QAAQ;AAAA,MACR,OAAO;AAAA,MACP,KAAK;AAAA,MACL,OAAO;AAAA,MACP,OAAO;AAAA,MACP,MAAM;AAAA,MACN,OAAO;AAAA,MACP,OAAO;AAAA,MACP,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,MAAM;AAAA,IACP;AAEA,UAAM,QAAQ,KAAK,YAAY;AAC/B,UAAM,YAAY,WAAW,KAAK;AAClC,QAAI,WAAW;AACd,YAAM,YAAY,KAAK,OAAO,CAAC;AAC/B,aAAO,cAAc,UAAU,YAAY,IACxC,UAAU,OAAO,CAAC,EAAE,YAAY,IAAI,UAAU,MAAM,CAAC,IACrD;AAAA,IACJ;AAEA,QACC,KAAK,SAAS,IAAI,KAClB,UAAU,UACV,UAAU,iBACV,UAAU,aACT;AACD,aAAO;AAAA,IACR;AAEA,QAAI,KAAK,SAAS,GAAG,KAAK,KAAK,SAAS,GAAG;AAC1C,YAAM,UAAU,KAAK,KAAK,SAAS,CAAC;AACpC,UAAI,WAAW,CAAC,QAAQ,SAAS,QAAQ,YAAY,CAAC,GAAG;AACxD,eAAO,KAAK,MAAM,GAAG,EAAE,IAAI;AAAA,MAC5B;AAAA,IACD;AAEA,QAAI,KAAK,SAAS,GAAG,GAAG;AACvB,aAAO,KAAK,MAAM,GAAG,EAAE,IAAI;AAAA,IAC5B;AACA,QAAI,KAAK,SAAS,IAAI,GAAG;AACxB,aAAO,KAAK,MAAM,GAAG,EAAE,IAAI;AAAA,IAC5B;AAEA,QAAI,KAAK,SAAS,GAAG,KAAK,KAAK,SAAS,GAAG;AAC1C,YAAM,UAAU,KAAK,KAAK,SAAS,CAAC;AACpC,UAAI,WAAW,CAAC,QAAQ,SAAS,QAAQ,YAAY,CAAC,GAAG;AACxD,eAAO,OAAO;AAAA,MACf;AAAA,IACD;AAEA,QACC,KAAK,SAAS,IAAI,KAClB,KAAK,SAAS,IAAI,KAClB,KAAK,SAAS,GAAG,KACjB,KAAK,SAAS,IAAI,KAClB,KAAK,SAAS,GAAG,KACjB,KAAK,SAAS,GAAG,GAChB;AACD,aAAO,OAAO;AAAA,IACf;AAEA,WAAO,OAAO;AAAA,EACf;AAAA;AAAA;AAAA;AAAA,EAKA,SAA2C;AAC1C,UAAM,aAAa,oBAAI,IAAI,CAAC,MAAM,aAAa,WAAW,CAAC;AAC3D,UAAM,SAA2C,CAAC;AAElD,eAAW,CAAC,MAAM,MAAM,KAAK,KAAK,SAAS;AAC1C,YAAM,SAAkC,CAAC;AACzC,iBAAW,CAAC,WAAW,QAAQ,KAAK,OAAO,QAAQ,OAAO,MAAM,GAAG;AAClE,YAAI,WAAW,IAAI,SAAS,EAAG;AAC/B,eAAO,SAAS,IAAI;AAAA,MACrB;AACA,aAAO,IAAI,IAAI,EAAE,GAAG,QAAQ,OAAO;AAAA,IACpC;AAEA,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA,EAKA,SAAS,MAA8C;AACtD,UAAM,UAAU,OAAO,OAAO,IAAI;AAClC,SAAK,aAAa,OAAO;AAAA,EAC1B;AACD;;;AClzBO,IAAM,0BAA0B;AAQhC,SAAS,mBACf,YAAoB,yBACnB;AACD,SAAO,aAAa;AAAA,IACnB,MAAM;AAAA,IAEN,QAAQ;AAAA,MACP,MAAM;AAAA,QACL,MAAM;AAAA,QACN,UAAU;AAAA,QACV,WAAW;AAAA,QACX,aAAa;AAAA,MACd;AAAA,MACA,SAAS;AAAA,QACR,MAAM;AAAA,QACN,UAAU;AAAA,QACV,QAAQ;AAAA,QACR,WAAW;AAAA,QACX,aAAa;AAAA,MACd;AAAA,MACA,eAAe;AAAA,QACd,MAAM;AAAA,QACN,UAAU;AAAA,QACV,KAAK;AAAA,QACL,aAAa;AAAA,MACd;AAAA,MACA,QAAQ;AAAA,QACP,MAAM;AAAA,QACN,UAAU;AAAA,QACV,QAAQ,CAAC,WAAW,aAAa,UAAU,aAAa;AAAA,QACxD,aAAa;AAAA,MACd;AAAA,MACA,UAAU;AAAA,QACT,MAAM;AAAA,QACN,WAAW;AAAA,QACX,aAAa;AAAA,MACd;AAAA,MACA,OAAO;AAAA,QACN,MAAM;AAAA,QACN,aAAa;AAAA,MACd;AAAA,MACA,WAAW;AAAA,QACV,MAAM;AAAA,QACN,UAAU;AAAA,QACV,aAAa;AAAA,MACd;AAAA,IACD;AAAA,IAEA,SAAS;AAAA,MACR,EAAE,QAAQ,CAAC,SAAS,GAAG,QAAQ,KAAK;AAAA,MACpC,EAAE,QAAQ,CAAC,QAAQ,EAAE;AAAA,MACrB,EAAE,QAAQ,CAAC,WAAW,EAAE;AAAA,IACzB;AAAA,IAEA,YAAY;AAAA,MACX,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,QAAQ;AAAA,IACT;AAAA,EACD,CAAU;AACX;AAaO,SAAS,sBAAsB;AACrC,SAAO,aAAa;AAAA,IACnB,MAAM;AAAA,IACN,WAAW;AAAA,IAEX,QAAQ;AAAA,MACP,KAAK;AAAA,QACJ,MAAM;AAAA,QACN,UAAU;AAAA,QACV,QAAQ;AAAA,QACR,WAAW;AAAA,QACX,aAAa;AAAA,MACd;AAAA,MACA,OAAO;AAAA,QACN,MAAM;AAAA,QACN,UAAU;AAAA,QACV,aAAa;AAAA,MACd;AAAA,IACD;AAAA,IAEA,YAAY;AAAA,MACX,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,QAAQ;AAAA,IACT;AAAA,EACD,CAAU;AACX;;;AC0LO,IAAM,uBAAN,cAAmC,MAAM;AAAA,EAC/C,YACC,SACgB,MAKA,SACf;AACD,UAAM,OAAO;AAPG;AAKA;AAGhB,SAAK,OAAO;AAAA,EACb;AACD;;;AChTA,SAAS,mBAAmB,OAA2C;AACtE,SACC,OAAO,UAAU,YACjB,UAAU,QACV,UAAU,SACV,OAAQ,MAAkC,MAAM,MAAM,YACtD,YAAY,SACZ,OAAQ,MAAkC,QAAQ,MAAM;AAE1D;AAKA,SAAS,kBAAkB,OAA0C;AACpE,SACC,OAAO,UAAU,YACjB,UAAU,QACV,UAAU,SACV,OAAQ,MAAkC,MAAM,MAAM;AAExD;AAKA,SAAS,iBACR,MAC4C;AAC5C,SAAO,CAAC,SAAS,QAAQ,QAAQ,KAAK,EAAE,SAAS,IAAI;AACtD;AAKO,IAAM,oBAAN,MAAgD;AAAA;AAAA;AAAA;AAAA,EAItD,QACC,YACA,YACmB;AACnB,QAAI;AACH,UACC,OAAO,eAAe,YACtB,eAAe,QACf,MAAM,QAAQ,UAAU,GACvB;AACD,cAAM,IAAI;AAAA,UACT;AAAA,UACA;AAAA,QACD;AAAA,MACD;AACA,UACC,OAAO,eAAe,YACtB,eAAe,QACf,MAAM,QAAQ,UAAU,GACvB;AACD,cAAM,IAAI;AAAA,UACT;AAAA,UACA;AAAA,QACD;AAAA,MACD;AAEA,YAAM,cAA4B,CAAC;AAEnC,YAAM,gBAAgB,IAAI,IAAI,OAAO,KAAK,UAAU,CAAC;AACrD,YAAM,gBAAgB,IAAI,IAAI,OAAO,KAAK,UAAU,CAAC;AAGrD,iBAAW,aAAa,eAAe;AACtC,YAAI,CAAC,cAAc,IAAI,SAAS,GAAG;AAClC,gBAAM,SAAS,WAAW,SAAS;AACnC,cAAI,CAAC,mBAAmB,MAAM,GAAG;AAChC,kBAAM,IAAI;AAAA,cACT,wCAAwC,SAAS;AAAA,cACjD;AAAA,YACD;AAAA,UACD;AAEA,sBAAY,KAAK;AAAA,YAChB,MAAM;AAAA,YACN;AAAA,UACD,CAAC;AAAA,QACF;AAAA,MACD;AAGA,iBAAW,aAAa,eAAe;AACtC,YAAI,CAAC,cAAc,IAAI,SAAS,GAAG;AAClC,sBAAY,KAAK;AAAA,YAChB,MAAM;AAAA,YACN;AAAA,UACD,CAAC;AAAA,QACF;AAAA,MACD;AAGA,iBAAW,aAAa,eAAe;AACtC,YAAI,cAAc,IAAI,SAAS,GAAG;AACjC,gBAAM,YAAY,WAAW,SAAS;AACtC,gBAAM,YAAY,WAAW,SAAS;AAEtC,cACC,CAAC,mBAAmB,SAAS,KAC7B,CAAC,mBAAmB,SAAS,GAC5B;AACD,kBAAM,IAAI;AAAA,cACT,wCAAwC,SAAS;AAAA,cACjD;AAAA,YACD;AAAA,UACD;AAEA,gBAAM,aAAa,KAAK,aAAa,WAAW,SAAS;AACzD,sBAAY,KAAK,GAAG,UAAU;AAAA,QAC/B;AAAA,MACD;AAEA,YAAM,sBAAsB,KAAK;AAAA,QAChC;AAAA,QACA;AAAA,QACA;AAAA,MACD;AAEA,aAAO;AAAA,QACN,aAAa;AAAA,QACb,YAAY,oBAAoB,SAAS;AAAA,MAC1C;AAAA,IACD,SAAS,OAAO;AACf,YAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,YAAM,IAAI;AAAA,QACT,8BAA8B,OAAO;AAAA,QACrC;AAAA,QACA;AAAA,MACD;AAAA,IACD;AAAA,EACD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeQ,wBACP,aACA,YACA,YACe;AACf,UAAM,WAAW,oBAAI,IAAY;AAGjC,UAAM,aAGD,CAAC;AACN,UAAM,eAGD,CAAC;AACN,UAAM,eAGD,CAAC;AAEN,aAAS,IAAI,GAAG,IAAI,YAAY,QAAQ,KAAK;AAC5C,YAAM,OAAO,YAAY,CAAC;AAC1B,UAAI,SAAS,OAAW;AACxB,UAAI,KAAK,SAAS,cAAc;AAC/B,mBAAW,KAAK;AAAA,UACf,OAAO;AAAA,UACP;AAAA,QACD,CAAC;AAAA,MACF,WAAW,KAAK,SAAS,gBAAgB;AACxC,qBAAa,KAAK;AAAA,UACjB,OAAO;AAAA,UACP;AAAA,QACD,CAAC;AAAA,MACF,WAAW,KAAK,SAAS,gBAAgB;AACxC,qBAAa,KAAK;AAAA,UACjB,OAAO;AAAA,UACP;AAAA,QACD,CAAC;AAAA,MACF;AAAA,IACD;AAGA,UAAM,mBAAmB,oBAAI,IAA8B;AAC3D,eAAW,UAAU,OAAO,OAAO,UAAU,GAAG;AAC/C,uBAAiB,IAAI,OAAO,aAAa,OAAO,MAAM,MAAM;AAAA,IAC7D;AAEA,UAAM,mBAAmB,oBAAI,IAA8B;AAC3D,eAAW,UAAU,OAAO,OAAO,UAAU,GAAG;AAC/C,uBAAiB,IAAI,OAAO,aAAa,OAAO,MAAM,MAAM;AAAA,IAC7D;AAQA,eAAW,WAAW,cAAc;AACnC,YAAM,eAAe,KAAK;AAAA,QACzB,QAAQ,KAAK;AAAA,QACb,QAAQ,KAAK;AAAA,QACb;AAAA,QACA;AAAA,MACD;AAEA,UAAI,CAAC,gBAAgB,aAAa,SAAS,WAAY;AACvD,UAAI,aAAa,SAAS,aAAc;AAExC,iBAAW,SAAS,YAAY;AAC/B,YAAI,SAAS,IAAI,MAAM,KAAK,EAAG;AAE/B,cAAM,WAAW,MAAM,KAAK;AAC5B,YAAI,SAAS,SAAS,WAAY;AAClC,YAAI,SAAS,SAAS,aAAc;AAEpC,cAAM,QAAQ,KAAK;AAAA,UAClB,QAAQ,KAAK;AAAA,UACb;AAAA,UACA,MAAM,KAAK;AAAA,UACX;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACD;AAEA,YAAI,OAAO;AACV,mBAAS,IAAI,QAAQ,KAAK;AAC1B,mBAAS,IAAI,MAAM,KAAK;AACxB;AAAA,QACD;AAAA,MACD;AAAA,IACD;AAKA,eAAW,SAAS,YAAY;AAC/B,UAAI,SAAS,IAAI,MAAM,KAAK,EAAG;AAE/B,YAAM,WAAW,MAAM,KAAK;AAC5B,UAAI,SAAS,SAAS,cAAc,SAAS,SAAS;AACrD;AAED,YAAM,cACL,iBAAiB,IAAI,MAAM,KAAK,SAAS,KACzC,WAAW,MAAM,KAAK,SAAS;AAChC,YAAM,iBAAiB,aAAa,QAAQ,MAAM,KAAK;AAEvD,YAAM,eAAe,KAAK;AAAA,QACzB;AAAA,QACA,SAAS;AAAA,QACT,SAAS;AAAA,QACT;AAAA,QACA;AAAA,MACD;AAEA,UAAI,iBAAiB,OAAW;AAEhC,YAAM,uBAAuB,YAAY;AAAA,QACxC,CAAC,MACA,EAAE,SAAS,iBACV,EAAE,OAAO,aAAa,EAAE,OAAO,UAAU;AAAA,MAC5C;AAEA,UAAI,CAAC,sBAAsB;AAC1B,iBAAS,IAAI,MAAM,KAAK;AAAA,MACzB;AAAA,IACD;AAKA,eAAW,SAAS,YAAY;AAC/B,UAAI,SAAS,IAAI,MAAM,KAAK,EAAG;AAE/B,YAAM,WAAW,MAAM,KAAK;AAC5B,UAAI,SAAS,SAAS,WAAY;AAClC,UAAI,SAAS,SAAS,YAAY,SAAS,SAAS,UAAW;AAE/D,YAAM,cACL,iBAAiB,IAAI,MAAM,KAAK,SAAS,KACzC,WAAW,MAAM,KAAK,SAAS;AAChC,YAAM,iBAAiB,aAAa,QAAQ,MAAM,KAAK;AAEvD,YAAM,UAAU,KAAK;AAAA,QACpB,SAAS;AAAA,QACT;AAAA,QACA;AAAA,MACD;AACA,YAAM,WAAW,SAAS,cAAc,GAAG,cAAc;AAEzD,UAAI,YAAY,OAAW;AAG3B,YAAM,mBACL,iBAAiB,IAAI,OAAO,KAAK,WAAW,OAAO;AACpD,UAAI,oBAAoB,YAAY,iBAAiB,QAAQ;AAC5D,iBAAS,IAAI,MAAM,KAAK;AAAA,MACzB;AAAA,IACD;AAIA,eAAW,WAAW,cAAc;AACnC,UAAI,SAAS,IAAI,QAAQ,KAAK,EAAG;AAEjC,YAAM,eAAe,QAAQ,KAAK;AAElC,YAAM,kBAAkB,KAAK;AAAA,QAC5B;AAAA,QACA;AAAA,QACA;AAAA,MACD;AAEA,UAAI,iBAAiB;AACpB,iBAAS,IAAI,QAAQ,KAAK;AAAA,MAC3B;AAAA,IACD;AAIA,eAAW,WAAW,cAAc;AACnC,UAAI,SAAS,IAAI,QAAQ,KAAK,EAAG;AAEjC,YAAM,eAAe,KAAK;AAAA,QACzB,QAAQ,KAAK;AAAA,QACb,QAAQ,KAAK;AAAA,QACb;AAAA,QACA;AAAA,MACD;AAEA,UACC,CAAC,gBACD,aAAa,SAAS,cACtB,aAAa,SAAS;AAEtB;AAED,YAAM,cACL,iBAAiB,IAAI,QAAQ,KAAK,SAAS,KAC3C,WAAW,QAAQ,KAAK,SAAS;AAClC,YAAM,iBAAiB,aAAa,QAAQ,QAAQ,KAAK;AAEzD,YAAM,eAAe,KAAK;AAAA,QACzB;AAAA,QACA,aAAa;AAAA,QACb,aAAa;AAAA,QACb;AAAA,QACA;AAAA,MACD;AAEA,UAAI,iBAAiB,OAAW;AAEhC,YAAM,kBAAkB,KAAK;AAAA,QAC5B;AAAA,QACA;AAAA,QACA;AAAA,MACD;AAEA,UAAI,iBAAiB;AACpB,iBAAS,IAAI,QAAQ,KAAK;AAAA,MAC3B;AAAA,IACD;AAEA,WAAO,YAAY,OAAO,CAAC,GAAG,MAAM,CAAC,SAAS,IAAI,CAAC,CAAC;AAAA,EACrD;AAAA;AAAA;AAAA;AAAA,EAKQ,oBACP,WACA,WACA,eACA,SAC8B;AAC9B,UAAM,UAAU,cAAc,IAAI,SAAS;AAC3C,QAAI,SAAS;AACZ,YAAM,QAAQ,QAAQ,OAAO,SAAS;AACtC,UAAI,kBAAkB,KAAK,EAAG,QAAO;AAAA,IACtC;AACA,UAAM,SAAS,QAAQ,SAAS;AAChC,QAAI,QAAQ;AACX,YAAM,QAAQ,OAAO,OAAO,SAAS;AACrC,UAAI,kBAAkB,KAAK,EAAG,QAAO;AAAA,IACtC;AACA,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASQ,oBACP,kBACA,cACA,gBACA,YACA,kBACA,YACA,kBACA,YACU;AAEV,UAAM,iBAAiB,KAAK;AAAA,MAC3B;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACD;AACA,UAAM,kBAAkB,KAAK;AAAA,MAC5B;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACD;AAGA,UAAM,eAAe,KAAK;AAAA,MACzB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACD;AACA,UAAM,gBAAgB,KAAK;AAAA,MAC1B;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACD;AAEA,QAAI,mBAAmB,UAAa,iBAAiB;AACpD,aAAO;AACR,QAAI,oBAAoB,UAAa,kBAAkB;AACtD,aAAO;AAER,WAAO,mBAAmB,gBAAgB,oBAAoB;AAAA,EAC/D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,eACP,WACA,OACA,eACA,SACqB;AACrB,QAAI,MAAM,SAAS,aAAa;AAC/B,aAAO;AAAA,IACR;AACA,WAAO,KAAK,sBAAsB,MAAM,OAAO,eAAe,OAAO;AAAA,EACtE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,gBACP,WACA,OACA,eACA,SACqB;AACrB,QAAI,MAAM,eAAe,QAAW;AACnC,aAAO,MAAM;AAAA,IACd;AACA,QAAI,MAAM,SAAS,aAAa;AAC/B,aAAO,GAAG,MAAM,KAAK;AAAA,IACtB;AAEA,UAAM,cAAc,cAAc,IAAI,SAAS,KAAK,QAAQ,SAAS;AACrE,UAAM,iBAAiB,aAAa,QAAQ;AAC5C,WAAO,GAAG,cAAc;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA,EAKQ,sBACP,WACA,eACA,SACqB;AACrB,UAAM,SAAS,QAAQ,SAAS;AAChC,QAAI,OAAQ,QAAO,OAAO,aAAa,OAAO;AAE9C,eAAW,UAAU,OAAO,OAAO,OAAO,GAAG;AAC5C,UAAI,OAAO,SAAS,UAAW,QAAO,OAAO,aAAa,OAAO;AAAA,IAClE;AAGA,QAAI,cAAc,IAAI,SAAS,EAAG,QAAO;AAEzC,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,yBACP,gBACA,iBACA,SACA,mBACA,aACqB;AACrB,QAAI,YAAY,OAAW,QAAO;AAGlC,UAAM,QAAQ,CAAC,gBAAgB,eAAe,EAAE,KAAK;AACrD,WAAO,GAAG,MAAM,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,+BACP,cACA,YACA,kBACU;AACV,eAAW,UAAU,OAAO,OAAO,UAAU,GAAG;AAC/C,YAAM,iBAAiB,OAAO;AAC9B,iBAAW,SAAS,OAAO,OAAO,OAAO,MAAM,GAAG;AACjD,YAAI,CAAC,kBAAkB,KAAK,EAAG;AAC/B,YAAI,MAAM,SAAS,cAAc,MAAM,SAAS,aAAc;AAE9D,cAAM,WAAW,KAAK;AAAA,UACrB;AAAA,UACA,MAAM;AAAA,UACN,MAAM;AAAA,UACN;AAAA,UACA;AAAA,QACD;AAEA,YAAI,aAAa,aAAc,QAAO;AAAA,MACvC;AAAA,IACD;AACA,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,0BACP,UACA,UACU;AACV,QAAI,SAAS,SAAS,cAAc,SAAS,SAAS,YAAY;AACjE,aAAO;AAAA,IACR;AAEA,UAAM,YAAY,SAAS,UAAU,SAAS;AAC9C,UAAM,iBAAiB,SAAS,eAAe,SAAS;AAExD,UAAM,UAAU,SAAS;AACzB,UAAM,UAAU,SAAS;AACzB,UAAM,sBACJ,YAAY,YAAY,YAAY,aACpC,YAAY,aAAa,YAAY;AAGvC,QAAI,uBAAuB,aAAa,gBAAgB;AACvD,aAAO;AAAA,IACR;AAEA,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA,EAKQ,aACP,WACA,WACe;AACf,UAAM,cAA4B,CAAC;AACnC,UAAM,YAAY,UAAU,aAAa,UAAU;AAEnD,UAAM,gBAAgB,IAAI,IAAI,OAAO,KAAK,UAAU,MAAM,CAAC;AAC3D,UAAM,gBAAgB,IAAI,IAAI,OAAO,KAAK,UAAU,MAAM,CAAC;AAK3D,UAAM,mBAAmB,oBAAI,IAAY;AACzC,UAAM,mBAAmB,oBAAI,IAAY;AAEzC,eAAW,gBAAgB,eAAe;AACzC,UAAI,cAAc,IAAI,YAAY,EAAG;AAErC,YAAM,WAAW,UAAU,OAAO,YAAY;AAC9C,UAAI,CAAC,kBAAkB,QAAQ,KAAK,SAAS,SAAS;AACrD;AAED,iBAAW,gBAAgB,eAAe;AACzC,YAAI,cAAc,IAAI,YAAY,EAAG;AACrC,YAAI,iBAAiB,IAAI,YAAY,EAAG;AAExC,cAAM,WAAW,UAAU,OAAO,YAAY;AAC9C,YAAI,CAAC,kBAAkB,QAAQ,KAAK,SAAS,SAAS;AACrD;AAED,YAAI,KAAK,0BAA0B,UAAU,QAAQ,GAAG;AACvD,2BAAiB,IAAI,YAAY;AACjC,2BAAiB,IAAI,YAAY;AACjC;AAAA,QACD;AAAA,MACD;AAAA,IACD;AAGA,eAAW,aAAa,eAAe;AACtC,UAAI,cAAc,IAAI,SAAS,EAAG;AAClC,UAAI,iBAAiB,IAAI,SAAS,EAAG;AAErC,YAAM,aAAa,UAAU,OAAO,SAAS;AAC7C,UAAI,CAAC,kBAAkB,UAAU,GAAG;AAEnC;AAAA,MACD;AAEA,kBAAY,KAAK;AAAA,QAChB,MAAM;AAAA,QACN;AAAA,QACA;AAAA,QACA;AAAA,MACD,CAAC;AAAA,IACF;AAGA,eAAW,aAAa,eAAe;AACtC,UAAI,cAAc,IAAI,SAAS,EAAG;AAClC,UAAI,iBAAiB,IAAI,SAAS,EAAG;AAErC,YAAM,aAAa,UAAU,OAAO,SAAS;AAC7C,UAAI,CAAC,kBAAkB,UAAU,EAAG;AAEpC,kBAAY,KAAK;AAAA,QAChB,MAAM;AAAA,QACN;AAAA,QACA;AAAA,QACA;AAAA,MACD,CAAC;AAAA,IACF;AAGA,eAAW,aAAa,eAAe;AACtC,UAAI,cAAc,IAAI,SAAS,GAAG;AACjC,cAAM,WAAW,UAAU,OAAO,SAAS;AAC3C,cAAM,WAAW,UAAU,OAAO,SAAS;AAE3C,YAAI,CAAC,kBAAkB,QAAQ,KAAK,CAAC,kBAAkB,QAAQ,GAAG;AAEjE;AAAA,QACD;AAEA,YAAI,KAAK,gBAAgB,UAAU,QAAQ,GAAG;AAC7C,sBAAY,KAAK;AAAA,YAChB,MAAM;AAAA,YACN;AAAA,YACA;AAAA,YACA,eAAe;AAAA,YACf,eAAe;AAAA,UAChB,CAAC;AAAA,QACF;AAAA,MACD;AAAA,IACD;AAGA,QAAI,UAAU,WAAW,UAAU,SAAS;AAC3C,YAAM,aAAa,KAAK;AAAA,QACvB;AAAA,QACA,UAAU,WAAW,CAAC;AAAA,QACtB,UAAU,WAAW,CAAC;AAAA,MACvB;AACA,kBAAY,KAAK,GAAG,UAAU;AAAA,IAC/B;AAEA,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA,EAKA,gBACC,UACA,UACU;AAEV,QAAI,SAAS,SAAS,SAAS,MAAM;AACpC,aAAO;AAAA,IACR;AAGA,QAAI,SAAS,aAAa,SAAS,UAAU;AAC5C,aAAO;AAAA,IACR;AAGA,UAAM,YACL,YAAY,WACR,SAAkC,SACnC;AACJ,UAAM,YACL,YAAY,WACR,SAAkC,SACnC;AACJ,QAAI,cAAc,WAAW;AAC5B,aAAO;AAAA,IACR;AAGA,QAAI,SAAS,YAAY,SAAS,SAAS;AAC1C,aAAO;AAAA,IACR;AAGA,YAAQ,SAAS,MAAM;AAAA,MACtB,KAAK;AAEJ,YAAI,SAAS,SAAS,UAAU;AAC/B,iBAAO;AAAA,QACR;AACA,YACC,SAAS,cAAc,SAAS,aAChC,SAAS,cAAc,SAAS,aAChC,SAAS,YAAY,SAAS,SAC7B;AACD,iBAAO;AAAA,QACR;AACA;AAAA,MAED,KAAK;AAEJ,YAAI,SAAS,SAAS,UAAU;AAC/B,iBAAO;AAAA,QACR;AACA,YAAI,SAAS,QAAQ,SAAS,OAAO,SAAS,QAAQ,SAAS,KAAK;AACnE,iBAAO;AAAA,QACR;AACA;AAAA,MAED,KAAK;AAEJ,YAAI,SAAS,SAAS,SAAS;AAC9B,iBAAO;AAAA,QACR;AACA,YACC,SAAS,UAAU,SAAS,SAC5B,SAAS,aAAa,SAAS,YAC/B,SAAS,aAAa,SAAS,YAC9B,YAAY,YACZ,YAAY,YACZ,SAAS,WAAW,SAAS,QAC7B;AACD,iBAAO;AAAA,QACR;AACA;AAAA,MAED,KAAK;AAEJ,YAAI,SAAS,SAAS,QAAQ;AAC7B,iBAAO;AAAA,QACR;AAEA,YAAI,SAAS,UAAU,SAAS,QAAQ;AACvC,gBAAM,YAAY,IAAI,IAAI,SAAS,MAAM;AACzC,gBAAM,YAAY,IAAI,IAAI,SAAS,MAAM;AAEzC,cAAI,UAAU,SAAS,UAAU,MAAM;AACtC,mBAAO;AAAA,UACR;AAEA,qBAAW,SAAS,WAAW;AAC9B,gBAAI,CAAC,UAAU,IAAI,KAAK,GAAG;AAC1B,qBAAO;AAAA,YACR;AAAA,UACD;AAAA,QACD;AACA;AAAA,MAED,KAAK;AAEJ,YAAI,SAAS,SAAS,YAAY;AACjC,iBAAO;AAAA,QACR;AACA,YACC,SAAS,UAAU,SAAS,SAC5B,SAAS,eAAe,SAAS,cACjC,SAAS,YAAY,SAAS,WAC9B,SAAS,aAAa,SAAS,YAC/B,SAAS,aAAa,SAAS,UAC9B;AACD,iBAAO;AAAA,QACR;AAEA,YAAI,SAAS,SAAS,SAAS,MAAM;AACpC,gBAAM,sBACJ,SAAS,SAAS,YAAY,SAAS,SAAS,aAChD,SAAS,SAAS,aAAa,SAAS,SAAS;AACnD,cAAI,CAAC,qBAAqB;AACzB,mBAAO;AAAA,UACR;AAAA,QACD;AACA;AAAA,IACF;AAEA,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA,EAKQ,eACP,WACA,YAMA,YAMe;AACf,UAAM,cAA4B,CAAC;AAGnC,UAAM,cAAc,IAAI;AAAA,MACvB,WAAW,IAAI,CAAC,QAAQ,CAAC,KAAK,kBAAkB,GAAG,GAAG,GAAG,CAAC;AAAA,IAC3D;AACA,UAAM,cAAc,IAAI;AAAA,MACvB,WAAW,IAAI,CAAC,QAAQ,CAAC,KAAK,kBAAkB,GAAG,GAAG,GAAG,CAAC;AAAA,IAC3D;AAGA,eAAW,CAAC,WAAW,KAAK,KAAK,aAAa;AAC7C,UAAI,CAAC,YAAY,IAAI,SAAS,GAAG;AAChC,oBAAY,KAAK;AAAA,UAChB,MAAM;AAAA,UACN;AAAA,UACA,OAAO;AAAA,YACN,GAAI,MAAM,SAAS,UAAa,EAAE,MAAM,MAAM,KAAK;AAAA,YACnD,QAAQ,MAAM;AAAA,YACd,GAAI,MAAM,WAAW,UAAa,EAAE,QAAQ,MAAM,OAAO;AAAA,YACzD,GAAI,MAAM,SAAS,UAClB,iBAAiB,MAAM,IAAI,KAAK,EAAE,MAAM,MAAM,KAAK;AAAA,UACrD;AAAA,QACD,CAAC;AAAA,MACF;AAAA,IACD;AAGA,eAAW,CAAC,WAAW,KAAK,KAAK,aAAa;AAC7C,UAAI,CAAC,YAAY,IAAI,SAAS,GAAG;AAChC,cAAM,YACL,MAAM,QAAQ,OAAO,SAAS,IAAI,MAAM,OAAO,KAAK,GAAG,CAAC;AACzD,oBAAY,KAAK;AAAA,UAChB,MAAM;AAAA,UACN;AAAA,UACA;AAAA,QACD,CAAC;AAAA,MACF;AAAA,IACD;AAEA,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA,EAKQ,kBAAkB,OAIf;AACV,UAAM,SAAS,CAAC,GAAG,MAAM,MAAM,EAAE,KAAK,EAAE,KAAK,GAAG;AAChD,UAAM,SAAS,MAAM,SAAS,WAAW;AACzC,UAAM,OAAO,MAAM,QAAQ;AAC3B,WAAO,GAAG,MAAM,IAAI,MAAM,IAAI,IAAI;AAAA,EACnC;AACD;;;AC/4BO,IAAM,0BAAN,MAA4D;AAAA;AAAA;AAAA;AAAA,EAI1D,aAAa,KAAqB;AACzC,WAAO,IACL,QAAQ,OAAO,MAAM,EACrB,QAAQ,MAAM,KAAK,EACnB,QAAQ,MAAM,KAAK,EACnB,QAAQ,MAAM,KAAK,EACnB,QAAQ,OAAO,KAAK,EACpB,QAAQ,OAAO,KAAK,EACpB,QAAQ,OAAO,KAAK,EACpB,QAAQ,OAAO,KAAK;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA,EAKA,SACC,aACA,UACY;AACZ,QAAI;AACH,YAAM,mBAAmB,KAAK,mBAAmB,WAAW;AAE5D,YAAM,YAAuB;AAAA,QAC5B,UAAU;AAAA,UACT,GAAG;AAAA,UACH,WAAW,KAAK,IAAI;AAAA,QACrB;AAAA,QACA,YAAY;AAAA,MACb;AAEA,aAAO;AAAA,IACR,SAAS,OAAO;AACf,YAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,YAAM,IAAI;AAAA,QACT,iCAAiC,OAAO;AAAA,QACxC;AAAA,QACA;AAAA,MACD;AAAA,IACD;AAAA,EACD;AAAA;AAAA;AAAA;AAAA,EAKA,mBACC,aACgC;AAChC,QAAI;AACH,YAAM,aAAmC,CAAC;AAE1C,iBAAW,QAAQ,aAAa;AAC/B,cAAM,KAAK,KAAK,kBAAkB,IAAI;AACtC,mBAAW,KAAK,EAAE;AAAA,MACnB;AAEA,aAAO;AAAA,IACR,SAAS,OAAO;AACf,YAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,YAAM,IAAI;AAAA,QACT,kCAAkC,OAAO;AAAA,QACzC;AAAA,QACA;AAAA,MACD;AAAA,IACD;AAAA,EACD;AAAA;AAAA;AAAA;AAAA,EAKQ,kBAAkB,MAAsC;AAC/D,YAAQ,KAAK,MAAM;AAAA,MAClB,KAAK;AACJ,eAAO;AAAA,UACN,MAAM;AAAA,UACN,QAAQ,KAAK;AAAA,QACd;AAAA,MAED,KAAK;AACJ,eAAO;AAAA,UACN,MAAM;AAAA,UACN,WAAW,KAAK;AAAA,QACjB;AAAA,MAED,KAAK;AACJ,eAAO;AAAA,UACN,MAAM;AAAA,UACN,MAAM,KAAK;AAAA,UACX,IAAI,KAAK;AAAA,QACV;AAAA,MAED,KAAK,cAAc;AAIlB,YAAI,KAAK,WAAW,SAAS,YAAY;AACxC,iBAAO;AAAA,YACN,MAAM;AAAA,YACN,WAAW,KAAK;AAAA,YAChB,YAAY;AAAA,cACX;AAAA,gBACC,MAAM;AAAA,gBACN,OAAO,KAAK;AAAA,gBACZ,YAAY,KAAK;AAAA,cAClB;AAAA,YACD;AAAA,UACD;AAAA,QACD;AAEA,eAAO;AAAA,UACN,MAAM;AAAA,UACN,WAAW,KAAK;AAAA,UAChB,YAAY;AAAA,YACX;AAAA,cACC,MAAM;AAAA,cACN,QAAQ,KAAK;AAAA,cACb,YAAY,KAAK;AAAA,YAClB;AAAA,UACD;AAAA,QACD;AAAA,MACD;AAAA,MAEA,KAAK,gBAAgB;AAGpB,YAAI,KAAK,WAAW,SAAS,YAAY;AACxC,iBAAO;AAAA,YACN,MAAM;AAAA,YACN,WAAW,KAAK;AAAA,YAChB,YAAY;AAAA,cACX;AAAA,gBACC,MAAM;AAAA,gBACN,OAAO,KAAK;AAAA,cACb;AAAA,YACD;AAAA,UACD;AAAA,QACD;AAEA,eAAO;AAAA,UACN,MAAM;AAAA,UACN,WAAW,KAAK;AAAA,UAChB,YAAY;AAAA,YACX;AAAA,cACC,MAAM;AAAA,cACN,QAAQ,KAAK;AAAA,YACd;AAAA,UACD;AAAA,QACD;AAAA,MACD;AAAA,MAEA,KAAK,iBAAiB;AACrB,cAAM,aAAa,CAAC;AAGpB,YACC,KAAK,cAAc,SAAS,cAC5B,KAAK,cAAc,SAAS,cAC5B,KAAK,cAAc,eAAe,KAAK,cAAc,YACpD;AACD,gBAAM,QACL,KAAK,cAAc,cAAc,GAAG,KAAK,cAAc,KAAK;AAC7D,gBAAM,QACL,KAAK,cAAc,cAAc,GAAG,KAAK,cAAc,KAAK;AAC7D,cAAI,UAAU,OAAO;AACpB,uBAAW,KAAK;AAAA,cACf,MAAM;AAAA,cACN,MAAM;AAAA,cACN,IAAI;AAAA,YACL,CAAC;AAAA,UACF;AAAA,QACD;AAGA,YACC,KAAK,cAAc,SAAS,cAC5B,KAAK,cAAc,SAAS,YAC3B;AACD,qBAAW,KAAK;AAAA,YACf,MAAM;AAAA,YACN,OAAO,KAAK;AAAA,YACZ,eAAe,KAAK;AAAA,UACrB,CAAC;AAAA,QACF;AAGA,YAAI,WAAW,WAAW,GAAG;AAC5B,qBAAW,KAAK;AAAA,YACf,MAAM;AAAA,YACN,QAAQ,KAAK;AAAA,YACb,eAAe,KAAK;AAAA,UACrB,CAAC;AAAA,QACF;AAEA,eAAO;AAAA,UACN,MAAM;AAAA,UACN,WAAW,KAAK;AAAA,UAChB;AAAA,QACD;AAAA,MACD;AAAA,MAEA,KAAK;AACJ,eAAO;AAAA,UACN,MAAM;AAAA,UACN,WAAW,KAAK;AAAA,UAChB,YAAY;AAAA,YACX;AAAA,cACC,MAAM;AAAA,cACN,MAAM,KAAK;AAAA,cACX,IAAI,KAAK;AAAA,YACV;AAAA,UACD;AAAA,QACD;AAAA,MAED,KAAK;AACJ,eAAO;AAAA,UACN,MAAM;AAAA,UACN,WAAW,KAAK;AAAA,UAChB,OAAO,KAAK;AAAA,QACb;AAAA,MAED,KAAK;AACJ,eAAO;AAAA,UACN,MAAM;AAAA,UACN,WAAW,KAAK;AAAA,UAChB,WAAW,KAAK;AAAA,QACjB;AAAA,IACF;AAAA,EACD;AAAA;AAAA;AAAA;AAAA,EAKA,aAAa,WAA8B;AAC1C,UAAM,EAAE,UAAU,WAAW,IAAI;AAEjC,UAAM,iBAAiB,KAAK,uBAAuB,YAAY,CAAC;AAGhE,UAAM,cAAc,KAAK,aAAa,SAAS,IAAI;AACnD,UAAM,iBAAiB,KAAK,aAAa,SAAS,OAAO;AACzD,UAAM,qBAAqB,SAAS,cACjC,KAAK,aAAa,SAAS,WAAW,IACtC;AACH,UAAM,gBAAgB,SAAS,SAC5B,KAAK,aAAa,SAAS,MAAM,IACjC;AAEH,WAAO;AAAA,gBACO,WAAW;AAAA,cACb,cAAc;AAAA,cACd,IAAI,KAAK,SAAS,SAAS,EAAE,YAAY,CAAC;AAAA,GACrD,qBAAqB,kBAAkB,kBAAkB,KAAK,EAAE;AAAA,GAChE,gBAAgB,aAAa,aAAa,KAAK,EAAE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,aAOvC,WAAW;AAAA,gBACR,cAAc;AAAA,iBACb,SAAS,SAAS;AAAA,MAC7B,qBAAqB,iBAAiB,kBAAkB,OAAO,EAAE;AAAA,MACjE,gBAAgB,YAAY,aAAa,OAAO,EAAE;AAAA;AAAA;AAAA;AAAA,EAItD,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMf;AAAA;AAAA;AAAA;AAAA,EAKQ,uBACP,YACA,QACS;AACT,UAAM,YAAY,KAAK,OAAO,MAAM;AAEpC,WAAO,WACL,IAAI,CAAC,OAAO;AACZ,cAAQ,GAAG,MAAM;AAAA,QAChB,KAAK;AACJ,iBAAO,GAAG,SAAS;AAAA,EACvB,SAAS;AAAA,EACT,SAAS,aAAa,KAAK,UAAU,GAAG,QAAQ,MAAM,CAAC,EAAE,QAAQ,OAAO;AAAA,EAAK,SAAS,IAAI,CAAC;AAAA,EAC3F,SAAS;AAAA,QAEN,KAAK;AACJ,iBAAO,GAAG,SAAS;AAAA,EACvB,SAAS;AAAA,EACT,SAAS,iBAAiB,GAAG,SAAS;AAAA,EACtC,SAAS;AAAA,QAEN,KAAK;AACJ,iBAAO,GAAG,SAAS;AAAA,EACvB,SAAS;AAAA,EACT,SAAS,iBAAiB,GAAG,SAAS;AAAA,EACtC,SAAS,iBAAiB,KAAK,UAAU,GAAG,YAAY,MAAM,CAAC,EAAE,QAAQ,OAAO;AAAA,EAAK,SAAS,IAAI,CAAC;AAAA,EACnG,SAAS;AAAA,QAEN,KAAK;AACJ,iBAAO,GAAG,SAAS;AAAA,EACvB,SAAS;AAAA,EACT,SAAS,iBAAiB,GAAG,SAAS;AAAA,EACtC,SAAS,YAAY,KAAK,UAAU,GAAG,OAAO,MAAM,CAAC,EAAE,QAAQ,OAAO;AAAA,EAAK,SAAS,IAAI,CAAC;AAAA,EACzF,SAAS;AAAA,QAEN,KAAK;AACJ,iBAAO,GAAG,SAAS;AAAA,EACvB,SAAS;AAAA,EACT,SAAS,iBAAiB,GAAG,SAAS;AAAA,EACtC,SAAS,iBAAiB,GAAG,SAAS;AAAA,EACtC,SAAS;AAAA,QAEN,KAAK;AACJ,iBAAO,GAAG,SAAS;AAAA,EACvB,SAAS;AAAA,EACT,SAAS,YAAY,GAAG,IAAI;AAAA,EAC5B,SAAS,UAAU,GAAG,EAAE;AAAA,EACxB,SAAS;AAAA,QAEN,KAAK;AACJ,iBAAO,GAAG,SAAS;AAAA,EACvB,SAAS;AAAA,EACT,SAAS,YAAY,GAAG,GAAG;AAAA,EAC3B,SAAS,aAAa,KAAK,UAAU,GAAG,UAAU,CAAC,CAAC,CAAC;AAAA,EACrD,SAAS;AAAA,QAEN,KAAK;AACJ,iBAAO,GAAG,SAAS;AAAA,EACvB,SAAS;AAAA,EACT,SAAS,mBAAmB,GAAG,WAAW;AAAA,EAC1C,SAAS;AAAA,MACP;AAAA,IACD,CAAC,EACA,KAAK,KAAK;AAAA,EACb;AACD;;;ACrWA,oBAA2B;AA4BpB,IAAM,wBAAN,MAAwD;AAAA,EAC7C;AAAA,EACA;AAAA,EACT,cAAc;AAAA,EAEtB,YAAY,QAAiB,YAAoB,yBAAyB;AACzE,SAAK,SAAS;AACd,SAAK,YAAY;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,aAA4B;AACjC,QAAI,KAAK,aAAa;AACrB;AAAA,IACD;AAEA,QAAI;AACH,YAAM,SAAS,KAAK,OAAO,WAAW,EAAE,IAAI,KAAK,SAAS;AAC1D,UAAI,CAAC,QAAQ;AACZ,cAAM,IAAI;AAAA,UACT,qBAAqB,KAAK,SAAS;AAAA,UACnC;AAAA,QACD;AAAA,MACD;AAEA,YAAM,UAAU,KAAK,OAAO,WAAW;AAGvC,YAAM,aAAa,MAAM,QAAQ,YAAY,iBAAiB;AAC9D,UAAI,CAAC,YAAY;AAChB,cAAM,aAAa,KAAK,OAAO,WAAW,EAAE,IAAI,iBAAiB;AACjE,YAAI,CAAC,YAAY;AAChB,gBAAM,IAAI;AAAA,YACT,WAAW,iBAAiB;AAAA,YAC5B;AAAA,UACD;AAAA,QACD;AACA,YAAI;AACH,gBAAM,QAAQ,YAAY,UAAU;AAAA,QACrC,SAAS,OAAO;AACf,gBAAM,IAAI;AAAA,YACT,4CAA6C,MAAgB,OAAO;AAAA,YACpE;AAAA,YACA;AAAA,UACD;AAAA,QACD;AAAA,MACD;AAEA,YAAM,YAAY,OAAO,aAAa,OAAO;AAC7C,YAAM,SAAS,MAAM,QAAQ,YAAY,SAAS;AAElD,UAAI,CAAC,QAAQ;AACZ,YAAI;AACH,gBAAM,QAAQ,YAAY,MAAM;AAAA,QACjC,SAAS,OAAO;AACf,gBAAM,IAAI;AAAA,YACT,sCAAuC,MAAgB,OAAO;AAAA,YAC9D;AAAA,YACA;AAAA,UACD;AAAA,QACD;AAAA,MACD;AAEA,WAAK,cAAc;AAAA,IACpB,SAAS,OAAO;AACf,YAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,YAAM,IAAI;AAAA,QACT,2CAA2C,OAAO;AAAA,QAClD;AAAA,QACA;AAAA,MACD;AAAA,IACD;AAAA,EACD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,OACL,WACA,eACA,QACA,OACgB;AAChB,QAAI;AACH,YAAM,WAAW,KAAK,kBAAkB,SAAS;AAEjD,YAAM,KAAK,OAAO,IAAI,OAAuB,KAAK,WAAW;AAAA,QAC5D,MAAM,UAAU,SAAS;AAAA,QACzB,SAAS,UAAU,SAAS;AAAA,QAC5B;AAAA,QACA;AAAA,QACA;AAAA,QACA,OAAO,OAAO,WAAW;AAAA,QACzB,WAAW,oBAAI,KAAK;AAAA,MACrB,CAAC;AAAA,IACF,SAASC,QAAO;AACf,YAAM,UAAUA,kBAAiB,QAAQA,OAAM,UAAU,OAAOA,MAAK;AACrE,YAAM,IAAI;AAAA,QACT,+BAA+B,OAAO;AAAA,QACtC;AAAA,QACAA;AAAA,MACD;AAAA,IACD;AAAA,EACD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,SAAqD;AAC1D,QAAI;AACH,YAAM,UAAU,MAAM,KAAK,OAAO,IAAI;AAAA,QACrC,KAAK;AAAA,QACL;AAAA,UACC,SAAS,EAAE,WAAW,MAAM;AAAA,QAC7B;AAAA,MACD;AAEA,YAAM,UAAoC,QAAQ,IAAI,CAAC,WAAW;AAAA,QACjE,IAAI,MAAM;AAAA,QACV,MAAM,MAAM;AAAA,QACZ,SAAS,MAAM;AAAA,QACf,WAAW,MAAM;AAAA,QACjB,eAAe,MAAM;AAAA,QACrB,QAAQ,MAAM;AAAA,QACd,GAAI,MAAM,YAAY,EAAE,UAAU,MAAM,SAAS;AAAA,QACjD,GAAI,MAAM,SAAS,EAAE,OAAO,MAAM,MAAM;AAAA,MACzC,EAAE;AAEF,aAAO;AAAA,IACR,SAAS,OAAO;AACf,YAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,YAAM,IAAI;AAAA,QACT,oCAAoC,OAAO;AAAA,QAC3C;AAAA,QACA;AAAA,MACD;AAAA,IACD;AAAA,EACD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,UAAuD;AAC5D,QAAI;AACH,YAAM,UAAU,MAAM,KAAK,OAAO,IAAI;AAAA,QACrC,KAAK;AAAA,QACL;AAAA,UACC,OAAO,EAAE,QAAQ,YAAY;AAAA,UAC7B,SAAS,EAAE,WAAW,OAAO;AAAA,UAC7B,OAAO;AAAA,QACR;AAAA,MACD;AAEA,YAAM,QAAQ,QAAQ,CAAC;AACvB,UAAI,CAAC,OAAO;AACX,eAAO;AAAA,MACR;AAEA,YAAM,SAAiC;AAAA,QACtC,IAAI,MAAM;AAAA,QACV,MAAM,MAAM;AAAA,QACZ,SAAS,MAAM;AAAA,QACf,WAAW,MAAM;AAAA,QACjB,eAAe,MAAM;AAAA,QACrB,QAAQ,MAAM;AAAA,QACd,GAAI,MAAM,YAAY,EAAE,UAAU,MAAM,SAAS;AAAA,QACjD,GAAI,MAAM,SAAS,EAAE,OAAO,MAAM,MAAM;AAAA,MACzC;AAEA,aAAO;AAAA,IACR,SAAS,OAAO;AACf,YAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,YAAM,IAAI;AAAA,QACT,iCAAiC,OAAO;AAAA,QACxC;AAAA,QACA;AAAA,MACD;AAAA,IACD;AAAA,EACD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,UAAU,SAAmC;AAClD,QAAI;AACH,YAAM,QAAQ,MAAM,KAAK,OAAO,IAAI,MAAsB,KAAK,WAAW;AAAA,QACzE;AAAA,QACA,QAAQ;AAAA,MACT,CAAC;AAED,aAAO,QAAQ;AAAA,IAChB,SAAS,OAAO;AACf,YAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,YAAM,IAAI;AAAA,QACT,qCAAqC,OAAO;AAAA,QAC5C;AAAA,QACA;AAAA,MACD;AAAA,IACD;AAAA,EACD;AAAA;AAAA;AAAA;AAAA,EAKA,kBAAkB,WAA8B;AAC/C,UAAM,UAAU,KAAK,UAAU;AAAA,MAC9B,YAAY,UAAU;AAAA,IACvB,CAAC;AAED,eAAO,0BAAW,QAAQ,EAAE,OAAO,OAAO,EAAE,OAAO,KAAK;AAAA,EACzD;AAAA;AAAA;AAAA;AAAA,EAKA,eACC,WACA,QACU;AACV,QAAI,CAAC,OAAO,UAAU;AACrB,aAAO;AAAA,IACR;AAEA,UAAM,kBAAkB,KAAK,kBAAkB,SAAS;AACxD,WAAO,oBAAoB,OAAO;AAAA,EACnC;AACD;;;ACrPO,IAAM,uBAAN,MAAsD;AAAA,EAC3C;AAAA,EACA;AAAA,EACA;AAAA,EAEjB,YACC,SACA,SACA,YACC;AACD,SAAK,UAAU;AACf,SAAK,UAAU;AACf,SAAK,aAAa;AAAA,EACnB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,aAA4C;AACjD,QAAI;AAEH,YAAM,KAAK,QAAQ,WAAW;AAG9B,YAAM,gBAAgB,MAAM,KAAK,QAAQ,OAAO;AAEhD,YAAM,kBAAkB,IAAI;AAAA,QAC3B,cACE,OAAO,CAAC,WAAW,OAAO,WAAW,WAAW,EAChD,IAAI,CAAC,WAAW,OAAO,OAAO;AAAA,MACjC;AAGA,YAAM,UAAU,KAAK,WAAW;AAAA,QAC/B,CAAC,cAAc,CAAC,gBAAgB,IAAI,UAAU,SAAS,OAAO;AAAA,MAC/D;AAEA,aAAO;AAAA,IACR,SAAS,OAAO;AACf,YAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,YAAM,IAAI;AAAA,QACT,qCAAqC,OAAO;AAAA,QAC5C;AAAA,QACA;AAAA,MACD;AAAA,IACD;AAAA,EACD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,aAAyD;AAC9D,UAAM,KAAK,QAAQ,WAAW;AAC9B,WAAO,MAAM,KAAK,QAAQ,OAAO;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,WAAW,SAGgC;AAChD,QAAI;AACH,UAAI,kBAAkB,MAAM,KAAK,WAAW;AAG5C,UAAI,SAAS,QAAQ;AACpB,cAAM,cAAc,gBAAgB;AAAA,UACnC,CAAC,MAAM,EAAE,SAAS,YAAY,QAAQ;AAAA,QACvC;AAEA,YAAI,gBAAgB,IAAI;AACvB,gBAAM,IAAI;AAAA,YACT,kBAAkB,QAAQ,MAAM;AAAA,YAChC;AAAA,UACD;AAAA,QACD;AAEA,0BAAkB,gBAAgB,MAAM,GAAG,cAAc,CAAC;AAAA,MAC3D;AAGA,UAAI,SAAS,QAAQ;AACpB,cAAM,mBACL,gBAAgB;AAAA,UACf,CAAC,eAAyC;AAAA,YACzC;AAAA,YACA,QAAQ;AAAA,YACR,eAAe;AAAA,UAChB;AAAA,QACD;AACD,eAAO;AAAA,MACR;AAEA,YAAM,UAAsC,CAAC;AAE7C,iBAAW,aAAa,iBAAiB;AACxC,cAAM,SAAS,MAAM,KAAK,OAAO,SAAS;AAE1C,gBAAQ,KAAK,MAAM;AAGnB,YAAI,OAAO,WAAW,UAAU;AAC/B;AAAA,QACD;AAAA,MACD;AAEA,aAAO;AAAA,IACR,SAAS,OAAO;AACf,YAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,YAAM,IAAI;AAAA,QACT,qCAAqC,OAAO;AAAA,QAC5C;AAAA,QACA;AAAA,MACD;AAAA,IACD;AAAA,EACD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiBA,MAAM,OAAO,WAAyD;AACrE,UAAM,YAAY,KAAK,IAAI;AAG3B,UAAM,EAAE,QAAQ,OAAO,QAAQ,IAAI,KAAK;AAAA,MACvC,UAAU;AAAA,IACX;AAEA,QAAI;AAEH,iBAAW,aAAa,QAAQ;AAC/B,YAAI;AACH,gBAAM,KAAK,uBAAuB,SAAS;AAAA,QAC5C,SAAS,OAAO;AACf,gBAAMC,iBAAgB,KAAK,IAAI,IAAI;AACnC,gBAAM,MAAM,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC;AACpE,gBAAM,KAAK,WAAW,WAAWA,gBAAe,UAAU,GAAG;AAC7D,iBAAO,EAAE,WAAW,QAAQ,UAAU,eAAAA,gBAAe,OAAO,IAAI;AAAA,QACjE;AAAA,MACD;AAGA,YAAM,KAAK,MAAM,KAAK,QAAQ,iBAAiB;AAC/C,UAAI;AACH,mBAAW,aAAa,OAAO;AAC9B,cAAI;AACH,kBAAM,KAAK,iBAAiB,IAAI,SAAS;AAAA,UAC1C,SAAS,OAAO;AACf,kBAAM,GAAG,SAAS;AAClB,kBAAMA,iBAAgB,KAAK,IAAI,IAAI;AACnC,kBAAM,MACL,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC;AACzD,kBAAM,KAAK,WAAW,WAAWA,gBAAe,UAAU,GAAG;AAC7D,mBAAO,EAAE,WAAW,QAAQ,UAAU,eAAAA,gBAAe,OAAO,IAAI;AAAA,UACjE;AAAA,QACD;AAEA,YAAI;AACH,gBAAM,GAAG,OAAO;AAAA,QACjB,SAAS,OAAO;AACf,gBAAMA,iBAAgB,KAAK,IAAI,IAAI;AACnC,gBAAM,MAAM,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC;AACpE,iBAAO,EAAE,WAAW,QAAQ,UAAU,eAAAA,gBAAe,OAAO,IAAI;AAAA,QACjE;AAAA,MACD,SAAS,OAAO;AACf,cAAM,GAAG,SAAS;AAClB,cAAMA,iBAAgB,KAAK,IAAI,IAAI;AACnC,cAAM,MAAM,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC;AACpE,cAAM,KAAK,WAAW,WAAWA,gBAAe,UAAU,GAAG;AAC7D,eAAO,EAAE,WAAW,QAAQ,UAAU,eAAAA,gBAAe,OAAO,IAAI;AAAA,MACjE;AAGA,iBAAW,aAAa,SAAS;AAChC,YAAI;AACH,gBAAM,KAAK,uBAAuB,SAAS;AAAA,QAC5C,SAAS,OAAO;AAGf,gBAAMA,iBAAgB,KAAK,IAAI,IAAI;AACnC,gBAAMC,YAAW;AAAA,YAChB,iCAAkC,MAAgB,OAAO;AAAA,UAC1D;AACA,gBAAM,KAAK,WAAW,WAAWD,gBAAe,WAAW;AAC3D,iBAAO,EAAE,WAAW,QAAQ,aAAa,eAAAA,gBAAe,UAAAC,UAAS;AAAA,QAClE;AAAA,MACD;AAEA,YAAM,gBAAgB,KAAK,IAAI,IAAI;AACnC,YAAM,WAAqB,CAAC;AAC5B,UAAI;AACH,cAAM,KAAK,QAAQ,OAAO,WAAW,eAAe,WAAW;AAAA,MAChE,SAAS,OAAO;AACf,iBAAS;AAAA,UACR,uCAAwC,MAAgB,OAAO;AAAA,QAChE;AAAA,MACD;AAEA,aAAO;AAAA,QACN;AAAA,QACA,QAAQ;AAAA,QACR;AAAA,QACA,GAAI,SAAS,SAAS,KAAK,EAAE,SAAS;AAAA,MACvC;AAAA,IACD,SAAS,OAAO;AACf,YAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,YAAM,IAAI;AAAA,QACT,4BAA4B,OAAO;AAAA,QACnC;AAAA,QACA;AAAA,MACD;AAAA,IACD;AAAA,EACD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUQ,uBAAuB,YAI7B;AACD,UAAM,SAA+B,CAAC;AACtC,UAAM,QAA8B,CAAC;AACrC,UAAM,UAAgC,CAAC;AAEvC,eAAW,MAAM,YAAY;AAC5B,UAAI,GAAG,SAAS,eAAe;AAC9B,eAAO,KAAK,EAAE;AAAA,MACf,WAAW,GAAG,SAAS,eAAe,GAAG,SAAS,eAAe;AAChE,gBAAQ,KAAK,EAAE;AAAA,MAChB,OAAO;AACN,cAAM,KAAK,EAAE;AAAA,MACd;AAAA,IACD;AAEA,WAAO,EAAE,QAAQ,OAAO,QAAQ;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,uBACb,WACgB;AAChB,YAAQ,UAAU,MAAM;AAAA,MACvB,KAAK;AACJ,eAAO,MAAM,KAAK,QAAQ,YAAY,UAAU,MAAM;AAAA,MACvD,KAAK;AACJ,eAAO,MAAM,KAAK,QAAQ,UAAU,UAAU,SAAS;AAAA,MACxD,KAAK;AACJ,eAAO,MAAM,KAAK,QAAQ,YAAY,UAAU,MAAM,UAAU,EAAE;AAAA,MACnE;AACC,cAAM,IAAI;AAAA,UACT,mBAAmB,UAAU,IAAI;AAAA,UACjC;AAAA,QACD;AAAA,IACF;AAAA,EACD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,WACb,WACA,eACA,QACA,OACgB;AAChB,QAAI;AACH,YAAM,KAAK,QAAQ,OAAO,WAAW,eAAe,QAAQ,KAAK;AAAA,IAClE,QAAQ;AAAA,IAER;AAAA,EACD;AAAA;AAAA;AAAA;AAAA,EAKA,QAAQ,SAA2D;AAClE,QAAI;AACH,UAAI,aAAa,CAAC,GAAG,KAAK,UAAU;AAEpC,UAAI,SAAS,QAAQ;AACpB,cAAM,cAAc,WAAW;AAAA,UAC9B,CAAC,MAAM,EAAE,SAAS,YAAY,QAAQ;AAAA,QACvC;AAEA,YAAI,gBAAgB,IAAI;AACvB,gBAAM,IAAI;AAAA,YACT,kBAAkB,QAAQ,MAAM;AAAA,YAChC;AAAA,UACD;AAAA,QACD;AAEA,qBAAa,WAAW,MAAM,GAAG,cAAc,CAAC;AAAA,MACjD;AAEA,aAAO;AAAA,QACN;AAAA,QACA,GAAI,SAAS,WAAW,UAAa,EAAE,QAAQ,QAAQ,OAAO;AAAA,MAC/D;AAAA,IACD,SAAS,OAAO;AACf,YAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,YAAM,IAAI;AAAA,QACT,oCAAoC,OAAO;AAAA,QAC3C;AAAA,QACA;AAAA,MACD;AAAA,IACD;AAAA,EACD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,iBACb,IACA,WACgB;AAChB,YAAQ,UAAU,MAAM;AAAA,MACvB,KAAK;AACJ,eAAO,MAAM,GAAG,YAAY,UAAU,MAAM;AAAA,MAE7C,KAAK;AACJ,eAAO,MAAM,GAAG,UAAU,UAAU,SAAS;AAAA,MAE9C,KAAK;AACJ,eAAO,MAAM,GAAG,WAAW,UAAU,WAAW,UAAU,UAAU;AAAA,MAErE,KAAK;AACJ,eAAO,MAAM,GAAG,SAAS,UAAU,WAAW,UAAU,KAAK;AAAA,MAE9D,KAAK;AACJ,eAAO,MAAM,GAAG,UAAU,UAAU,WAAW,UAAU,SAAS;AAAA,MAEnE,KAAK;AACJ,eAAO,MAAM,GAAG,YAAY,UAAU,MAAM,UAAU,EAAE;AAAA,MAEzD,KAAK;AACJ,cAAM,GAAG,gBAAgB,UAAU,KAAK,UAAU,UAAU,CAAC,CAAC;AAC9D;AAAA,MAED,KAAK;AACJ,eAAO,MAAM,UAAU,QAAQ,EAAE;AAAA,IACnC;AAAA,EACD;AACD;;;ACxRO,IAAM,mBAAN,MAAuB;AAAA,EACZ;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAET,iBAAgD,oBAAI,IAAI;AAAA,EACxD,kBAAiD,oBAAI,IAAI;AAAA,EACzD,cAA4B,CAAC;AAAA,EAC7B,aAAgC,CAAC;AAAA,EACjC,cAAc;AAAA,EAEtB,YAAY,QAAiB;AAC5B,SAAK,SAAS;AACd,SAAK,UAAU,OAAO,WAAW;AACjC,SAAK,SAAS,IAAI,kBAAkB;AACpC,SAAK,YAAY,IAAI,wBAAwB;AAE7C,UAAM,kBAAkB,OAAO,mBAAmB;AAClD,SAAK,UAAU,IAAI,sBAAsB,QAAQ,gBAAgB,SAAS;AAAA,EAC3E;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,aAA4B;AACjC,QAAI,KAAK,aAAa;AACrB;AAAA,IACD;AAEA,QAAI;AAEH,YAAM,KAAK,QAAQ,WAAW;AAG9B,YAAM,WAAW,KAAK,OAAO,WAAW;AACxC,iBAAW,UAAU,SAAS,OAAO,GAAG;AAEvC,YAAI,OAAO,KAAK,WAAW,SAAS,GAAG;AACtC;AAAA,QACD;AACA,aAAK,eAAe,IAAI,OAAO,MAAM,MAAM;AAAA,MAC5C;AAGA,YAAM,eAAe,MAAM,KAAK,QAAQ,UAAU;AAElD,iBAAW,aAAa,cAAc;AAErC,YAAI,UAAU,WAAW,SAAS,GAAG;AACpC;AAAA,QACD;AAEA,cAAM,eAAe,MAAM,KAAK,QAAQ,eAAe,SAAS;AAChE,aAAK,gBAAgB,IAAI,WAAW,YAAa;AAAA,MAClD;AAGA,YAAM,aAA+C,CAAC;AACtD,iBAAW,CAAC,MAAM,MAAM,KAAK,KAAK,iBAAiB;AAClD,mBAAW,IAAI,IAAI;AAAA,MACpB;AAEA,YAAM,aAA+C,CAAC;AACtD,iBAAW,CAAC,MAAM,MAAM,KAAK,KAAK,gBAAgB;AACjD,mBAAW,OAAO,aAAa,IAAI,IAAI;AAAA,MACxC;AAEA,YAAM,aAAa,KAAK,OAAO,QAAQ,YAAY,UAAU;AAE7D,WAAK,cAAc,CAAC,GAAG,WAAW,WAAW;AAG7C,WAAK,uBAAuB;AAE5B,WAAK,cAAc;AAAA,IACpB,SAAS,OAAO;AACf,YAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,YAAM,IAAI;AAAA,QACT,2CAA2C,OAAO;AAAA,QAClD;AAAA,QACA;AAAA,MACD;AAAA,IACD;AAAA,EACD;AAAA;AAAA;AAAA;AAAA,EAKQ,yBAA+B;AAEtC,UAAM,gBAAgB,oBAAI,IAA0B;AACpD,UAAM,cAAc,oBAAI,IAA0B;AAClD,UAAM,gBAA8B,CAAC;AACrC,UAAM,cAA4B,CAAC;AAEnC,eAAW,QAAQ,KAAK,aAAa;AACpC,UAAI,KAAK,SAAS,gBAAgB;AACjC,cAAM,MAAM,KAAK;AACjB,YAAI,CAAC,cAAc,IAAI,GAAG,GAAG;AAC5B,wBAAc,IAAI,KAAK,CAAC,CAAC;AAAA,QAC1B;AACA,sBAAc,IAAI,GAAG,EAAG,KAAK,IAAI;AAAA,MAClC,WAAW,KAAK,SAAS,cAAc;AACtC,cAAM,MAAM,KAAK;AACjB,YAAI,CAAC,YAAY,IAAI,GAAG,GAAG;AAC1B,sBAAY,IAAI,KAAK,CAAC,CAAC;AAAA,QACxB;AACA,oBAAY,IAAI,GAAG,EAAG,KAAK,IAAI;AAAA,MAChC,WAAW,KAAK,SAAS,gBAAgB;AACxC,sBAAc,KAAK,IAAI;AAAA,MACxB,WAAW,KAAK,SAAS,cAAc;AACtC,oBAAY,KAAK,IAAI;AAAA,MACtB;AAAA,IACD;AAGA,UAAM,iBAAiB,oBAAI,IAA0B;AACrD,eAAW,QAAQ,KAAK,aAAa;AACpC,UAAI,KAAK,SAAS,iBAAiB;AAClC,cAAM,MAAM,KAAK;AACjB,YAAI,CAAC,eAAe,IAAI,GAAG,GAAG;AAC7B,yBAAe,IAAI,KAAK,CAAC,CAAC;AAAA,QAC3B;AACA,uBAAe,IAAI,GAAG,EAAG,KAAK,IAAI;AAAA,MACnC;AAAA,IACD;AAGA,UAAM,eAAe,oBAAI,IAAY;AAGrC,SAAK;AAAA,MACJ;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACD;AAGA,SAAK,2BAA2B,eAAe,aAAa,YAAY;AAGxE,SAAK,yBAAyB,eAAe,YAAY;AAGzD,SAAK,6BAA6B,eAAe,aAAa,YAAY;AAG1E,SAAK,sBAAsB,eAAe,aAAa,YAAY;AAGnE,SAAK,oBAAoB,eAAe,aAAa,YAAY;AAGjE,SAAK,mBAAmB,eAAe,aAAa,YAAY;AAGhE,SAAK,qBAAqB,gBAAgB,YAAY;AAAA,EACvD;AAAA;AAAA;AAAA;AAAA,EAKQ,0BACP,eACA,aACA,eACA,aACA,cACO;AAEP,eAAW,CAAC,WAAW,OAAO,KAAK,eAAe;AACjD,iBAAW,eAAe,SAAS;AAClC,YAAI,YAAY,SAAS,eAAgB;AAGzC,YAAI,CAAC,YAAY,UAAU,SAAS,IAAI,EAAG;AAE3C,cAAM,eAAe,YAAY,UAAU,MAAM,GAAG,EAAE;AAGtD,mBAAW,cAAc,aAAa;AACrC,cAAI,WAAW,SAAS,aAAc;AAEtC,gBAAM,eACL,WAAW,OAAO,aAAa,WAAW,OAAO;AAGlD,cAAI,KAAK,mBAAmB,cAAc,WAAW,YAAY,GAAG;AACnE,kBAAM,UAAU,GAAG,SAAS,IAAI,YAAY,SAAS;AACrD,yBAAa,IAAI,OAAO;AACxB,yBAAa,IAAI,SAAS,YAAY,EAAE;AAExC,iBAAK,WAAW,KAAK;AAAA,cACpB,IAAI,oBAAoB,SAAS,IAAI,YAAY;AAAA,cACjD;AAAA,cACA,MAAM;AAAA,cACN,aAAa,YAAY;AAAA,cACzB,WAAW;AAAA,cACX,SACC;AAAA,cACD,iBAAiB;AAAA,gBAChB;AAAA,kBACC,MAAM;AAAA,kBACN,aAAa,oBAAoB,YAAY,SAAS,8BAA8B,YAAY;AAAA,gBACjG;AAAA,gBACA;AAAA,kBACC,MAAM;AAAA,kBACN,aAAa,SAAS,YAAY,SAAS;AAAA,gBAC5C;AAAA,cACD;AAAA,cACA,UAAU;AAAA,YACX,CAAC;AAAA,UACF;AAAA,QACD;AAAA,MACD;AAAA,IACD;AAGA,eAAW,gBAAgB,eAAe;AACzC,UAAI,aAAa,SAAS,eAAgB;AAE1C,YAAM,eAAe,aAAa;AAGlC,UAAI,CAAC,KAAK,uBAAuB,YAAY,EAAG;AAChD,UAAI,aAAa,IAAI,SAAS,YAAY,EAAE,EAAG;AAG/C,iBAAW,CAAC,WAAW,KAAK,KAAK,aAAa;AAC7C,mBAAW,aAAa,OAAO;AAC9B,cAAI,UAAU,SAAS,aAAc;AAGrC,cAAI;AACJ,cAAI;AAEJ,cACC,UAAU,WAAW,SAAS,cAC9B,UAAU,WAAW,SAAS,aAC7B;AAED,2BAAe,UAAU,WAAW;AACpC,2BACC,UAAU,WAAW,cACrB,GAAG,UAAU,WAAW,KAAK;AAAA,UAC/B,WAAW,UAAU,UAAU,SAAS,IAAI,GAAG;AAE9C,2BAAe,UAAU,UAAU,MAAM,GAAG,EAAE;AAC9C,2BAAe,UAAU;AAAA,UAC1B,OAAO;AACN;AAAA,UACD;AAGA,cAAI,KAAK,mBAAmB,cAAc,WAAW,YAAY,GAAG;AACnE,kBAAM,UAAU,SAAS,YAAY;AACrC,gBAAI,aAAa,IAAI,OAAO,EAAG;AAC/B,yBAAa,IAAI,OAAO;AACxB,yBAAa,IAAI,GAAG,SAAS,IAAI,UAAU,SAAS,EAAE;AAGtD,kBAAM,kBAAkB,cAAc,IAAI,SAAS,KAAK,CAAC;AACzD,uBAAW,eAAe,iBAAiB;AAC1C,kBAAI,YAAY,SAAS,eAAgB;AACzC,2BAAa,IAAI,GAAG,SAAS,IAAI,YAAY,SAAS,EAAE;AAAA,YACzD;AAGA,iBAAK,cAAc,KAAK,YAAY;AAAA,cACnC,CAAC,MACA,EACC,EAAE,SAAS,kBACX,EAAE,cAAc,aAChB,CAAC,EAAE,UAAU,SAAS,IAAI;AAAA,YAE7B;AAEA,iBAAK,WAAW,KAAK;AAAA,cACpB,IAAI,sBAAsB,SAAS,IAAI,YAAY;AAAA,cACnD;AAAA,cACA,MAAM;AAAA,cACN,aAAa;AAAA,cACb,WAAW;AAAA,cACX,SACC;AAAA,cACD,iBAAiB;AAAA,gBAChB;AAAA,kBACC,MAAM;AAAA,kBACN,aAAa,gCAAgC,YAAY,SAAS,YAAY;AAAA,gBAC/E;AAAA,gBACA;AAAA,kBACC,MAAM;AAAA,kBACN,aAAa,yCAAyC,YAAY;AAAA,gBACnE;AAAA,cACD;AAAA,cACA,UAAU;AAAA,YACX,CAAC;AAAA,UACF;AAAA,QACD;AAAA,MACD;AAAA,IACD;AAAA,EACD;AAAA;AAAA;AAAA;AAAA,EAKQ,yBACP,eACA,cACO;AACP,eAAW,gBAAgB,eAAe;AACzC,UAAI,aAAa,SAAS,eAAgB;AAE1C,YAAM,YAAY,aAAa;AAC/B,YAAM,UAAU,SAAS,SAAS;AAGlC,UAAI,aAAa,IAAI,OAAO,EAAG;AAG/B,UAAI,KAAK,uBAAuB,SAAS,GAAG;AAC3C,qBAAa,IAAI,OAAO;AAExB,aAAK,WAAW,KAAK;AAAA,UACpB,IAAI,iBAAiB,SAAS;AAAA,UAC9B;AAAA,UACA,MAAM;AAAA,UACN,aAAa;AAAA,UACb,WAAW;AAAA,UACX,SAAS;AAAA,UACT,iBAAiB;AAAA,YAChB;AAAA,cACC,MAAM;AAAA,cACN,aAAa,oCAAoC,SAAS;AAAA,YAC3D;AAAA,UACD;AAAA,UACA,UAAU;AAAA,QACX,CAAC;AAAA,MACF;AAAA,IACD;AAAA,EACD;AAAA;AAAA;AAAA;AAAA,EAKQ,2BACP,eACA,aACA,cACO;AACP,eAAW,gBAAgB,eAAe;AACzC,UAAI,aAAa,SAAS,eAAgB;AAE1C,YAAM,UAAU,aAAa;AAC7B,YAAM,aAAa,SAAS,OAAO;AAEnC,UAAI,aAAa,IAAI,UAAU,EAAG;AAClC,UAAI,CAAC,KAAK,uBAAuB,OAAO,EAAG;AAE3C,iBAAW,cAAc,aAAa;AACrC,YAAI,WAAW,SAAS,aAAc;AAEtC,cAAM,UAAU,WAAW,OAAO,aAAa,WAAW,OAAO;AACjE,cAAM,aAAa,SAAS,OAAO;AAEnC,YAAI,aAAa,IAAI,UAAU,EAAG;AAClC,YAAI,CAAC,KAAK,uBAAuB,OAAO,EAAG;AAG3C,YAAI,KAAK,sBAAsB,SAAS,OAAO,GAAG;AACjD,uBAAa,IAAI,UAAU;AAC3B,uBAAa,IAAI,UAAU;AAE3B,eAAK,WAAW,KAAK;AAAA,YACpB,IAAI,mBAAmB,OAAO,KAAK,OAAO;AAAA,YAC1C,WAAW;AAAA,YACX,MAAM;AAAA,YACN,aAAa;AAAA,YACb,WAAW;AAAA,YACX,SACC;AAAA,YACD,iBAAiB;AAAA,cAChB;AAAA,gBACC,MAAM;AAAA,gBACN,aAAa,0BAA0B,OAAO,SAAS,OAAO;AAAA,cAC/D;AAAA,cACA;AAAA,gBACC,MAAM;AAAA,gBACN,aAAa,SAAS,OAAO,iBAAiB,OAAO;AAAA,cACtD;AAAA,YACD;AAAA,YACA,UAAU;AAAA,UACX,CAAC;AAAA,QACF;AAAA,MACD;AAAA,IACD;AAAA,EACD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASQ,sBACP,eACA,aACA,cACO;AACP,eAAW,CAAC,WAAW,OAAO,KAAK,eAAe;AACjD,YAAM,QAAQ,YAAY,IAAI,SAAS,KAAK,CAAC;AAG7C,YAAM,iBAAiB,MAAM;AAAA,QAC5B,CAAC,MACA,EAAE,SAAS,gBACX,EAAE,UAAU,SAAS,IAAI,KACzB,CAAC,aAAa,IAAI,GAAG,SAAS,IAAI,EAAE,SAAS,EAAE;AAAA,MACjD;AAEA,iBAAW,eAAe,SAAS;AAClC,YAAI,YAAY,SAAS,eAAgB;AACzC,YAAI,CAAC,YAAY,UAAU,SAAS,IAAI,EAAG;AAE3C,cAAM,aAAa,GAAG,SAAS,IAAI,YAAY,SAAS;AACxD,YAAI,aAAa,IAAI,UAAU,EAAG;AAGlC,YAAI,eAAe,SAAS,GAAG;AAE9B,gBAAM,YAAY,eAAe;AAAA,YAChC,CAAC,MAAM,CAAC,aAAa,IAAI,GAAG,SAAS,IAAI,EAAE,SAAS,EAAE;AAAA,UACvD;AAEA,cAAI,aAAa,UAAU,SAAS,cAAc;AACjD,kBAAM,WAAW,GAAG,SAAS,IAAI,UAAU,SAAS;AAEpD,yBAAa,IAAI,UAAU;AAC3B,yBAAa,IAAI,QAAQ;AAEzB,iBAAK,WAAW,KAAK;AAAA,cACpB,IAAI,GAAG,SAAS,IAAI,YAAY,SAAS,KAAK,UAAU,SAAS;AAAA,cACjE;AAAA,cACA,MAAM;AAAA,cACN,aAAa,YAAY;AAAA,cACzB,WAAW,UAAU;AAAA,cACrB,iBAAiB,UAAU;AAAA,cAC3B,iBAAiB;AAAA,gBAChB;AAAA,kBACC,MAAM;AAAA,kBACN,aAAa,kBAAkB,YAAY,SAAS,SAAS,UAAU,SAAS;AAAA,gBACjF;AAAA,gBACA;AAAA,kBACC,MAAM;AAAA,kBACN,aAAa,SAAS,YAAY,SAAS,cAAc,UAAU,SAAS;AAAA,gBAC7E;AAAA,cACD;AAAA,cACA,UAAU;AAAA,YACX,CAAC;AAED;AAAA,UACD;AAAA,QACD;AAGA,qBAAa,IAAI,UAAU;AAE3B,aAAK,WAAW,KAAK;AAAA,UACpB,IAAI,WAAW,SAAS,IAAI,YAAY,SAAS;AAAA,UACjD;AAAA,UACA,MAAM;AAAA,UACN,aAAa,YAAY;AAAA,UACzB,WAAW;AAAA,UACX,SAAS;AAAA,UACT,iBAAiB;AAAA,YAChB;AAAA,cACC,MAAM;AAAA,cACN,aAAa,+BAA+B,YAAY,SAAS,WAAW,SAAS;AAAA,YACtF;AAAA,UACD;AAAA,UACA,UAAU;AAAA,QACX,CAAC;AAAA,MACF;AAAA,IACD;AAAA,EACD;AAAA;AAAA;AAAA;AAAA,EAKQ,oBACP,eACA,aACA,cACO;AACP,eAAW,CAAC,WAAW,OAAO,KAAK,eAAe;AACjD,YAAM,QAAQ,YAAY,IAAI,SAAS;AACvC,UAAI,CAAC,MAAO;AAEZ,iBAAW,eAAe,SAAS;AAClC,YAAI,YAAY,SAAS,eAAgB;AAEzC,cAAM,aAAa,GAAG,SAAS,IAAI,YAAY,SAAS;AACxD,YAAI,aAAa,IAAI,UAAU,EAAG;AAElC,mBAAW,aAAa,OAAO;AAC9B,cAAI,UAAU,SAAS,aAAc;AAErC,gBAAM,WAAW,GAAG,SAAS,IAAI,UAAU,SAAS;AACpD,cAAI,aAAa,IAAI,QAAQ,EAAG;AAGhC,cAAI,KAAK,cAAc,QAAW,UAAU,UAAU,GAAG;AACxD,yBAAa,IAAI,UAAU;AAC3B,yBAAa,IAAI,QAAQ;AAEzB,iBAAK,WAAW,KAAK;AAAA,cACpB,IAAI,GAAG,SAAS,IAAI,YAAY,SAAS,KAAK,UAAU,SAAS;AAAA,cACjE;AAAA,cACA,MAAM;AAAA,cACN,aAAa,YAAY;AAAA,cACzB,WAAW,UAAU;AAAA,cACrB,iBAAiB,UAAU;AAAA,cAC3B,iBAAiB;AAAA,gBAChB;AAAA,kBACC,MAAM;AAAA,kBACN,aAAa,kBAAkB,YAAY,SAAS,SAAS,UAAU,SAAS;AAAA,gBACjF;AAAA,gBACA;AAAA,kBACC,MAAM;AAAA,kBACN,aAAa,SAAS,YAAY,SAAS,cAAc,UAAU,SAAS;AAAA,gBAC7E;AAAA,cACD;AAAA,cACA,UAAU;AAAA,YACX,CAAC;AAGD;AAAA,UACD;AAAA,QACD;AAAA,MACD;AAAA,IACD;AAAA,EACD;AAAA;AAAA;AAAA;AAAA,EAKQ,mBACP,eACA,aACA,cACO;AACP,eAAW,eAAe,eAAe;AACxC,UAAI,YAAY,SAAS,eAAgB;AAEzC,YAAM,aAAa,SAAS,YAAY,SAAS;AACjD,UAAI,aAAa,IAAI,UAAU,EAAG;AAElC,iBAAW,aAAa,aAAa;AACpC,YAAI,UAAU,SAAS,aAAc;AAErC,cAAM,WAAW,SAAS,UAAU,OAAO,aAAa,UAAU,OAAO,IAAI;AAC7E,YAAI,aAAa,IAAI,QAAQ,EAAG;AAEhC,YAAI,KAAK,mBAAmB,YAAY,WAAW,UAAU,MAAM,GAAG;AACrE,uBAAa,IAAI,UAAU;AAC3B,uBAAa,IAAI,QAAQ;AAEzB,eAAK,WAAW,KAAK;AAAA,YACpB,IAAI,SAAS,YAAY,SAAS,KAAK,UAAU,OAAO,IAAI;AAAA,YAC5D,WAAW,YAAY;AAAA,YACvB,MAAM;AAAA,YACN,aAAa,YAAY;AAAA,YACzB,WAAW,UAAU,OAAO;AAAA,YAC5B,iBAAiB;AAAA,cAChB;AAAA,gBACC,MAAM;AAAA,gBACN,aAAa,iBAAiB,YAAY,SAAS,SAAS,UAAU,OAAO,IAAI;AAAA,cAClF;AAAA,cACA;AAAA,gBACC,MAAM;AAAA,gBACN,aAAa,SAAS,YAAY,SAAS,iBAAiB,UAAU,OAAO,IAAI;AAAA,cAClF;AAAA,YACD;AAAA,YACA,UAAU;AAAA,UACX,CAAC;AAED;AAAA,QACD;AAAA,MACD;AAAA,IACD;AAAA,EACD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,qBACP,gBACA,cACO;AACP,eAAW,CAAC,WAAW,QAAQ,KAAK,gBAAgB;AACnD,iBAAW,QAAQ,UAAU;AAC5B,YAAI,KAAK,SAAS,gBAAiB;AAEnC,cAAM,SAAS,KAAK;AACpB,cAAM,SAAS,KAAK;AAEpB,YAAI,OAAO,SAAS,cAAc,OAAO,SAAS,WAAY;AAC9D,YAAI,OAAO,SAAS,eAAe,OAAO,SAAS;AAClD;AACD,YAAI,OAAO,UAAU,OAAO,MAAO;AAEnC,cAAM,UAAU,GAAG,SAAS,IAAI,KAAK,SAAS;AAC9C,YAAI,aAAa,IAAI,OAAO,EAAG;AAC/B,qBAAa,IAAI,OAAO;AAExB,cAAM,WAAW,OAAO,cAAc,GAAG,OAAO,KAAK;AAErD,aAAK,WAAW,KAAK;AAAA,UACpB,IAAI,mBAAmB,SAAS,IAAI,KAAK,SAAS;AAAA,UAClD;AAAA,UACA,MAAM;AAAA,UACN,aAAa,OAAO;AAAA,UACpB,WAAW,OAAO;AAAA,UAClB,SAAS,qBAAqB,QAAQ,qBAAqB,OAAO,KAAK,iBAAiB,OAAO,KAAK;AAAA,UACpG,iBAAiB;AAAA,YAChB;AAAA,cACC,MAAM;AAAA,cACN,aAAa,gBAAgB,QAAQ;AAAA,YACtC;AAAA,YACA;AAAA,cACC,MAAM;AAAA,cACN,aAAa,SAAS,QAAQ;AAAA,YAC/B;AAAA,UACD;AAAA,UACA,UAAU;AAAA,QACX,CAAC;AAAA,MACF;AAAA,IACD;AAAA,EACD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWQ,6BACP,eACA,aACA,cACO;AACP,eAAW,CAAC,cAAc,OAAO,KAAK,eAAe;AACpD,iBAAW,eAAe,SAAS;AAClC,YAAI,YAAY,SAAS,eAAgB;AACzC,YAAI,CAAC,YAAY,UAAU,SAAS,IAAI,EAAG;AAE3C,cAAM,aAAa,GAAG,YAAY,IAAI,YAAY,SAAS;AAC3D,YAAI,aAAa,IAAI,UAAU,EAAG;AAGlC,mBAAW,CAAC,YAAY,KAAK,KAAK,aAAa;AAC9C,cAAI,eAAe,aAAc;AAEjC,qBAAW,aAAa,OAAO;AAC9B,gBAAI,UAAU,SAAS,aAAc;AACrC,gBAAI,CAAC,UAAU,UAAU,SAAS,IAAI,EAAG;AAEzC,kBAAM,WAAW,GAAG,UAAU,IAAI,UAAU,SAAS;AACrD,gBAAI,aAAa,IAAI,QAAQ,EAAG;AAMhC,kBAAM,mBAAmB,YAAY,UAAU,MAAM,GAAG,EAAE;AAC1D,kBAAM,iBAAiB,UAAU,UAAU,MAAM,GAAG,EAAE;AAEtD,kBAAM,mBAAmB,KAAK,YAAY,YAAY;AACtD,kBAAM,iBAAiB,KAAK,YAAY,UAAU;AAElD,kBAAM,SACL,qBAAqB,kBACrB,mBAAmB;AAEpB,gBAAI,QAAQ;AACX,2BAAa,IAAI,UAAU;AAC3B,2BAAa,IAAI,QAAQ;AAEzB,mBAAK,WAAW,KAAK;AAAA,gBACpB,IAAI,kBAAkB,YAAY,IAAI,YAAY,SAAS,KAAK,UAAU,IAAI,UAAU,SAAS;AAAA,gBACjG,WAAW;AAAA,gBACX,MAAM;AAAA,gBACN,aAAa,GAAG,YAAY,IAAI,YAAY,SAAS;AAAA,gBACrD,WAAW,GAAG,UAAU,IAAI,UAAU,SAAS;AAAA,gBAC/C,SAAS,oCAAoC,YAAY,SAAS,SAAS,YAAY,0BAA0B,UAAU,SAAS,SAAS,UAAU;AAAA,gBACvJ,iBAAiB;AAAA,kBAChB;AAAA,oBACC,MAAM;AAAA,oBACN,aAAa,SAAS,YAAY,SAAS,WAAW,YAAY,cAAc,UAAU,SAAS,SAAS,UAAU;AAAA,kBACvH;AAAA,gBACD;AAAA,gBACA,UAAU;AAAA,cACX,CAAC;AAED;AAAA,YACD;AAAA,UACD;AAAA,QACD;AAAA,MACD;AAAA,IACD;AAAA,EACD;AAAA;AAAA;AAAA;AAAA,EAKQ,uBAAuB,WAA4B;AAE1D,WAAO,UAAU,SAAS,GAAG,KAAK,CAAC,UAAU,WAAW,GAAG;AAAA,EAC5D;AAAA;AAAA;AAAA;AAAA,EAKQ,mBACP,cACA,WACA,cACU;AACV,UAAM,QAAQ,aAAa,MAAM,GAAG;AACpC,QAAI,MAAM,WAAW,EAAG,QAAO;AAG/B,UAAM,gBAAgB,KAAK,YAAY,SAAS;AAChD,UAAM,mBAAmB,aAAa,YAAY;AAElD,UAAM,gBAAgB,MAAM;AAAA,MAC3B,CAAC,MAAM,MAAM,iBAAiB,MAAM,UAAU,YAAY;AAAA,IAC3D;AACA,UAAM,mBAAmB,MAAM;AAAA,MAC9B,CAAC,MAAM,MAAM,oBAAoB,MAAM,KAAK,UAAU,gBAAgB;AAAA,IACvE;AAEA,WAAO,iBAAiB;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA,EAKQ,sBAAsB,SAAiB,SAA0B;AACxE,UAAM,WAAW,IAAI,IAAI,QAAQ,MAAM,GAAG,CAAC;AAC3C,UAAM,WAAW,IAAI,IAAI,QAAQ,MAAM,GAAG,CAAC;AAG3C,QAAI,cAAc;AAClB,eAAW,QAAQ,UAAU;AAC5B,UAAI,SAAS,IAAI,IAAI,EAAG;AAAA,IACzB;AAEA,WAAO,eAAe;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA,EAKQ,YAAY,MAAsB;AACzC,QAAI,KAAK,SAAS,KAAK,GAAG;AACzB,aAAO,KAAK,MAAM,GAAG,EAAE,IAAI;AAAA,IAC5B;AACA,QAAI,KAAK,SAAS,IAAI,GAAG;AACxB,aAAO,KAAK,MAAM,GAAG,EAAE;AAAA,IACxB;AACA,QAAI,KAAK,SAAS,GAAG,KAAK,CAAC,KAAK,SAAS,IAAI,GAAG;AAC/C,aAAO,KAAK,MAAM,GAAG,EAAE;AAAA,IACxB;AACA,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA,EAKQ,UAAU,MAAsB;AACvC,QAAI,KAAK,SAAS,GAAG,GAAG;AACvB,aAAO,KAAK,MAAM,GAAG,EAAE,IAAI;AAAA,IAC5B;AACA,QACC,KAAK,SAAS,GAAG,KACjB,KAAK,SAAS,GAAG,KACjB,KAAK,SAAS,IAAI,KAClB,KAAK,SAAS,IAAI,GACjB;AACD,aAAO,OAAO;AAAA,IACf;AACA,WAAO,OAAO;AAAA,EACf;AAAA;AAAA;AAAA;AAAA,EAKQ,cACP,SACA,SACU;AAGV,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQQ,mBACP,cACA,WACU;AACV,UAAM,YAAY,KAAK,gBAAgB,IAAI,YAAY;AACvD,QAAI,CAAC,UAAW,QAAO;AAGvB,UAAM,eAAe,oBAAI,IAAI,CAAC,MAAM,aAAa,WAAW,CAAC;AAE7D,UAAM,YAAY,IAAI;AAAA,MACrB,OAAO,KAAK,UAAU,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,aAAa,IAAI,CAAC,CAAC;AAAA,IACjE;AACA,UAAM,YAAY,IAAI;AAAA,MACrB,OAAO,KAAK,UAAU,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,aAAa,IAAI,CAAC,CAAC;AAAA,IACjE;AAGA,QAAI,UAAU,SAAS,KAAK,UAAU,SAAS,GAAG;AACjD,aAAO;AAAA,IACR;AAGA,QAAI,eAAe;AACnB,eAAW,SAAS,WAAW;AAC9B,UAAI,UAAU,IAAI,KAAK,GAAG;AACzB;AAAA,MACD;AAAA,IACD;AAGA,UAAM,qBAAoB,oBAAI,IAAI,CAAC,GAAG,WAAW,GAAG,SAAS,CAAC,GAAE;AAChE,UAAM,sBAAsB,eAAe;AAE3C,QAAI,sBAAsB,KAAK;AAC9B,aAAO;AAAA,IACR;AAGA,UAAM,kBACL,KAAK,IAAI,UAAU,MAAM,UAAU,IAAI,IACvC,KAAK,IAAI,UAAU,MAAM,UAAU,IAAI;AAExC,WAAO,kBAAkB;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,iBAA8C;AACjD,WAAO,KAAK,YACV,OAAO,CAAC,MAAM,EAAE,SAAS,YAAY,EACrC;AAAA,MACA,CAAC,MAAO,EAAuD;AAAA,IAChE;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,eAAkC;AACrC,WAAO,KAAK,YACV,OAAO,CAAC,MAAM,EAAE,SAAS,cAAc,EACvC,IAAI,CAAC,MAAO,EAAkD,SAAS;AAAA,EAC1E;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,gBAGA;AACH,UAAM,cAAc,oBAAI,IAA0B;AAElD,eAAW,QAAQ,KAAK,aAAa;AACpC,UACC,KAAK,SAAS,gBACd,KAAK,SAAS,kBACd,KAAK,SAAS,mBACd,KAAK,SAAS,gBACd,KAAK,SAAS,gBACb;AACD,cAAM,YAAY,KAAK;AACvB,YAAI,CAAC,YAAY,IAAI,SAAS,GAAG;AAChC,sBAAY,IAAI,WAAW,CAAC,CAAC;AAAA,QAC9B;AACA,oBAAY,IAAI,SAAS,EAAG,KAAK,IAAI;AAAA,MACtC;AAAA,IACD;AAEA,WAAO,MAAM,KAAK,YAAY,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC,WAAW,OAAO,OAAO;AAAA,MACvE;AAAA,MACA;AAAA,IACD,EAAE;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,YAAwC;AAC3C,WAAO,KAAK,WAAW,OAAO,CAAC,MAAM,CAAC,EAAE,QAAQ;AAAA,EACjD;AAAA;AAAA;AAAA;AAAA,EAKA,yBAAkC;AACjC,WAAO,KAAK,WAAW,KAAK,CAAC,MAAM,CAAC,EAAE,QAAQ;AAAA,EAC/C;AAAA;AAAA;AAAA;AAAA,EAKA,iBAAiB,IAAY,QAAmC;AAC/D,UAAM,YAAY,KAAK,WAAW,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE;AACzD,QAAI,CAAC,WAAW;AACf,YAAM,IAAI;AAAA,QACT,qBAAqB,EAAE;AAAA,QACvB;AAAA,MACD;AAAA,IACD;AAEA,UAAM,iBAAiB,UAAU,gBAAgB;AAAA,MAChD,CAAC,MAAM,EAAE,SAAS;AAAA,IACnB;AACA,QAAI,CAAC,gBAAgB;AACpB,YAAM,IAAI;AAAA,QACT,mBAAmB,MAAM,2BAA2B,EAAE;AAAA,QACtD;AAAA,MACD;AAAA,IACD;AAEA,cAAU,WAAW;AACrB,cAAU,iBAAiB;AAG3B,SAAK,gBAAgB,WAAW,MAAM;AAAA,EACvC;AAAA;AAAA;AAAA;AAAA,EAKQ,gBACP,WACA,QACO;AACP,YAAQ,UAAU,MAAM;AAAA,MACvB,KAAK;AACJ,YAAI,WAAW,UAAU;AACxB,eAAK,kBAAkB,SAAS;AAAA,QACjC;AAEA;AAAA,MAED,KAAK;AACJ,YAAI,WAAW,UAAU;AACxB,eAAK,iBAAiB,SAAS;AAAA,QAChC;AAEA;AAAA,MAED,KAAK;AACJ,YAAI,WAAW,UAAU;AACxB,eAAK,iBAAiB,SAAS;AAAA,QAChC;AAEA;AAAA,MAED,KAAK;AAAA,MACL,KAAK;AAEJ;AAAA,MAED,KAAK;AACJ,YAAI,WAAW,uBAAuB;AAAA,QAGtC;AAEA;AAAA,MAED,KAAK;AAGJ;AAAA,MAED,KAAK;AAEJ;AAAA,MAED,KAAK;AAEJ;AAAA,IACF;AAAA,EACD;AAAA;AAAA;AAAA;AAAA,EAKQ,kBAAkB,WAAkC;AAE3D,SAAK,cAAc,KAAK,YAAY,OAAO,CAAC,MAAM;AACjD,UACC,EAAE,SAAS,kBACX,EAAE,cAAc,UAAU,aAC1B,EAAE,cAAc,UAAU,aACzB;AACD,eAAO;AAAA,MACR;AACA,UACC,EAAE,SAAS,gBACX,EAAE,cAAc,UAAU,aAC1B,EAAE,cAAc,UAAU,WACzB;AACD,eAAO;AAAA,MACR;AAEA,UACC,EAAE,SAAS,mBACX,EAAE,cAAc,UAAU,aAC1B,EAAE,cAAc,SAAS,cACzB,EAAE,cAAc,SAAS,YACxB;AACD,cAAM,QACL,EAAE,cAAc,cAAc,GAAG,EAAE,cAAc,KAAK;AACvD,cAAM,QACL,EAAE,cAAc,cAAc,GAAG,EAAE,cAAc,KAAK;AACvD,YAAI,UAAU,UAAU,eAAe,UAAU,UAAU,WAAW;AACrE,iBAAO;AAAA,QACR;AAAA,MACD;AACA,aAAO;AAAA,IACR,CAAC;AAGD,SAAK,YAAY,KAAK;AAAA,MACrB,MAAM;AAAA,MACN,WAAW,UAAU;AAAA,MACrB,MAAM,UAAU;AAAA,MAChB,IAAI,UAAU;AAAA,IACf,CAAC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,iBAAiB,WAAkC;AAE1D,SAAK,cAAc,KAAK,YAAY,OAAO,CAAC,MAAM;AACjD,UAAI,EAAE,SAAS,kBAAkB,EAAE,cAAc,UAAU,aAAa;AACvE,eAAO;AAAA,MACR;AACA,UAAI,EAAE,SAAS,gBAAgB,EAAE,OAAO,SAAS,UAAU,WAAW;AACrE,eAAO;AAAA,MACR;AACA,aAAO;AAAA,IACR,CAAC;AAGD,SAAK,YAAY,KAAK;AAAA,MACrB,MAAM;AAAA,MACN,MAAM,UAAU;AAAA,MAChB,IAAI,UAAU;AAAA,IACf,CAAC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,aAAsB;AACrB,WAAO,KAAK,YAAY,SAAS;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA,EAKA,UAAyB;AACxB,QAAI,KAAK,uBAAuB,GAAG;AAClC,YAAM,IAAI;AAAA,QACT;AAAA,QACA;AAAA,MACD;AAAA,IACD;AAEA,UAAM,aAAa,KAAK,UAAU,mBAAmB,KAAK,WAAW;AAErE,WAAO;AAAA,MACN,gBAAgB,KAAK;AAAA,MACrB,cAAc,KAAK;AAAA,MACnB,eAAe,KAAK;AAAA,MACpB;AAAA,MACA,YAAY,KAAK,WAAW;AAAA,IAC7B;AAAA,EACD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,QAAsD;AAC3D,QAAI,KAAK,uBAAuB,GAAG;AAClC,YAAM,IAAI;AAAA,QACT;AAAA,QACA;AAAA,MACD;AAAA,IACD;AAEA,QAAI,CAAC,KAAK,WAAW,GAAG;AACvB,aAAO,CAAC;AAAA,IACT;AAGA,UAAM,gBAAgB,KAAK,UAAU,SAAS,KAAK,aAAa;AAAA,MAC/D,MAAM,aAAa,KAAK,IAAI,CAAC;AAAA,MAC7B,SAAS,KAAK,IAAI,EAAE,SAAS;AAAA,MAC7B,aAAa;AAAA,IACd,CAAC;AAGD,UAAM,qBAAqB,KAAK;AAAA,MAC/B,cAAc;AAAA,IACf;AAEA,UAAM,YAAuB;AAAA,MAC5B,GAAG;AAAA,MACH,YAAY;AAAA,IACb;AAGA,UAAM,SAAS,IAAI,qBAAqB,KAAK,SAAS,KAAK,SAAS;AAAA,MACnE;AAAA,IACD,CAAC;AAED,UAAM,UAAU,MAAM,OAAO,WAAW;AAGxC,UAAM,SAAS,QAAQ,KAAK,CAAC,MAAM,EAAE,WAAW,QAAQ;AACxD,QAAI,QAAQ;AACX,YAAM,eACL,OAAO,iBAAiB,QACrB,OAAO,MAAM,UACb,OAAO,OAAO,SAAS,yBAAyB;AACpD,YAAM,IAAI;AAAA,QACT,qBAAqB,YAAY;AAAA,QACjC;AAAA,QACA,OAAO;AAAA,MACR;AAAA,IACD;AAEA,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUQ,6BACP,YACgC;AAChC,UAAM,SAA+B,CAAC,GAAG,UAAU;AAEnD,eAAW,aAAa,KAAK,YAAY;AACxC,UAAI,CAAC,UAAU,SAAU;AAEzB,UAAI,UAAU,gBAAgB,SAAS,uBAAuB;AAC7D,cAAM,cAAc,UAAU;AAC9B,cAAM,gBAAgB,UAAU;AAChC,cAAM,cAAc,UAAU;AAG9B,cAAM,YAAY,OAAO;AAAA,UACxB,CAAC,OACA,GAAG,SAAS,kBACX,GAAG,OAAO,aAAa,GAAG,OAAO,UAAU;AAAA,QAC9C;AAGA,cAAM,UAAU,OAAO;AAAA,UACtB,CAAC,OACA,GAAG,SAAS,gBACZ,GAAG,cAAc,eACjB,GAAG,WAAW;AAAA,YACb,CAAC,MAAM,EAAE,SAAS,gBAAgB,EAAE,WAAW;AAAA,UAChD;AAAA,QACF;AAEA,YAAI,cAAc,MAAM,YAAY,GAAI;AAExC,cAAM,aAAoC;AAAA,UACzC,MAAM;AAAA,UACN,aAAa,YAAY,WAAW,IAAI,WAAW,+BAA+B,aAAa;AAAA,UAC/F,SAAS,OAAO,WAAwB;AACvC,kBAAM,eAAe,MAAM,OAAO,aAA2B;AAAA,cAC5D,MAAM;AAAA,cACN,OAAO;AAAA,cACP,QAAQ,CAAC,MAAM,WAAW;AAAA,YAC3B,CAAC;AACD,kBAAM,OAAO,aAAa;AAI1B,kBAAM,kBAAkB,KAAK,YAAY,WAAW;AACpD,kBAAM,sBAAsB,GAAG,eAAe;AAE9C,kBAAM,eAAe,KACnB,OAAO,CAAC,QAAQ,IAAI,WAAW,KAAK,IAAI,EACxC,IAAI,CAAC,SAAS;AAAA,cACd,CAAC,mBAAmB,GAAG,IAAI;AAAA,cAC3B,CAAC,WAAW,GAAG,IAAI,WAAW;AAAA,YAC/B,EAAE;AAEH,gBAAI,aAAa,WAAW,EAAG;AAE/B,kBAAM,OAAO,aAAa;AAAA,cACzB,MAAM;AAAA,cACN,OAAO;AAAA,cACP,MAAM;AAAA,YACP,CAAC;AAAA,UACF;AAAA,QACD;AAGA,cAAM,WAAW,KAAK,IAAI,YAAY,GAAG,OAAO;AAChD,eAAO,OAAO,UAAU,GAAG,UAAU;AAAA,MACtC,WAAW,UAAU,gBAAgB,SAAS,iBAAiB;AAC9D,cAAM,gBAAgB,UAAU;AAChC,cAAM,cAAc,UAAU;AAC9B,cAAM,cAAc,UAAU;AAG9B,cAAM,YAAY,OAAO;AAAA,UACxB,CAAC,OACA,GAAG,SAAS,gBACZ,GAAG,cAAc,eACjB,GAAG,WAAW;AAAA,YACb,CAAC,MAAM,EAAE,SAAS,eAAe,EAAE,WAAW;AAAA,UAC/C;AAAA,QACF;AAGA,cAAM,eAAe,OAAO;AAAA,UAC3B,CAAC,OAAO,GAAG,SAAS,eAAe,GAAG,cAAc;AAAA,QACrD;AAEA,YAAI,cAAc,MAAM,iBAAiB,GAAI;AAG7C,cAAM,kBAAkB,KAAK,YAAY,WAAW;AACpD,cAAM,cAAc,GAAG,eAAe;AACtC,cAAM,eAAe;AAErB,cAAM,aAAoC;AAAA,UACzC,MAAM;AAAA,UACN,aAAa,gCAAgC,aAAa,SAAS,WAAW,IAAI,WAAW;AAAA,UAC7F,SAAS,OAAO,WAAwB;AACvC,kBAAM,eAAe,MAAM,OAAO,aAA2B;AAAA,cAC5D,MAAM;AAAA,cACN,OAAO;AAAA,cACP,QAAQ,CAAC,aAAa,YAAY;AAAA,YACnC,CAAC;AAGD,kBAAM,gBAAgB,oBAAI,IAAqB;AAC/C,uBAAW,OAAO,aAAa,MAAM;AACpC,oBAAM,WAAW,IAAI,WAAW;AAChC,kBAAI,CAAC,cAAc,IAAI,QAAQ,GAAG;AACjC,8BAAc,IAAI,UAAU,IAAI,YAAY,CAAC;AAAA,cAC9C;AAAA,YACD;AAGA,uBAAW,CAAC,UAAU,SAAS,KAAK,eAAe;AAClD,oBAAM,OAAO,aAAa;AAAA,gBACzB,MAAM;AAAA,gBACN,OAAO;AAAA,gBACP,OAAO,EAAE,IAAI,EAAE,KAAK,SAAS,EAAE;AAAA,gBAC/B,MAAM,EAAE,CAAC,YAAY,GAAG,UAAU;AAAA,cACnC,CAAC;AAAA,YACF;AAAA,UACD;AAAA,QACD;AAIA,eAAO,OAAO,YAAY,GAAG,GAAG,UAAU;AAG1C,cAAM,aAAa,OAAO;AAAA,UACzB,CAAC,OAAO,GAAG,SAAS,eAAe,GAAG,cAAc;AAAA,QACrD;AACA,cAAM,cAAc,OAAO,QAAQ,UAAU;AAC7C,YAAI,eAAe,MAAM,aAAa,aAAa;AAElD,gBAAM,CAAC,MAAM,IAAI,OAAO,OAAO,YAAY,CAAC;AAC5C,gBAAM,sBAAsB,OAAO,QAAQ,UAAU,IAAI;AACzD,iBAAO,OAAO,qBAAqB,GAAG,MAAO;AAAA,QAC9C;AAAA,MACD;AAAA,IACD;AAEA,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,UAAkD;AACvD,UAAM,OAAO,KAAK,QAAQ;AAC1B,WAAO,KAAK;AAAA,EACb;AACD;AAKA,eAAsB,uBACrB,QAC4B;AAC5B,QAAM,UAAU,IAAI,iBAAiB,MAAM;AAC3C,QAAM,QAAQ,WAAW;AACzB,SAAO;AACR;;;ACn3CO,IAAM,SAAN,MAAgC;AAAA,EAC9B,SAA8B;AAAA,EAC9B,UAAkC;AAAA,EAClC,iBAAiC,IAAI,eAAe;AAAA,EACpD,aAAgC;AAAA,EAChC,WAA2B,IAAI,eAAe;AAAA,EAC9C,cAAc;AAAA,EAEd;AAAA,EACA;AAAA;AAAA;AAAA;AAAA,EAKR,MAAM,qBACL,QACA,UAA6B,CAAC,GACd;AAChB,QAAI,KAAK,aAAa;AACrB;AAAA,IACD;AAEA,QAAI;AACH,WAAK,SAAS;AACd,WAAK,UAAU,OAAO;AAGtB,UAAI,CAAC,QAAQ,eAAe,OAAO,SAAS;AAC3C,mBAAW,UAAU,OAAO,SAAS;AACpC,eAAK,eAAe,SAAS,MAAM;AAAA,QACpC;AAAA,MACD;AAGA,WAAK,aAAa,iBAAiB,KAAK,gBAAgB,IAAI;AAG5D,UAAI,CAAC,QAAQ,kBAAkB,KAAK,SAAS;AAC5C,cAAM,KAAK,QAAQ,QAAQ,KAAK,QAAQ;AAAA,MACzC;AAGA,YAAM,mBAAmB,oBAAoB;AAC7C,WAAK,SAAS,SAAS,gBAAgB;AAGvC,UAAI,CAAC,QAAQ,eAAe,OAAO,QAAQ,SAAS,GAAG;AACtD,mBAAW,UAAU,OAAO,SAAS;AACpC,eAAK,SAAS,SAAS,MAAM;AAAA,QAC9B;AAAA,MACD;AAGA,UAAI,CAAC,QAAQ,aAAa;AACzB,mBAAW,UAAU,KAAK,eAAe,OAAO,GAAG;AAClD,cAAI,OAAO,YAAY;AACtB,kBAAM,gBAAgB,MAAM,OAAO,WAAW;AAC9C,uBAAW,UAAU,eAAe;AACnC,mBAAK,SAAS,SAAS,MAAM;AAAA,YAC9B;AAAA,UACD;AAAA,QACD;AAAA,MACD;AAGA,UAAI,CAAC,QAAQ,aAAa;AACzB,cAAM,mBAAmB,IAAI;AAAA,UAC5B,KAAK,SAAS,OAAO;AAAA,QACtB;AAEA,mBAAW,UAAU,KAAK,eAAe,OAAO,GAAG;AAClD,cAAI,OAAO,eAAe;AACzB,kBAAM,aAAa,MAAM,OAAO,cAAc,gBAAgB;AAC9D,iBAAK,sBAAsB,UAAU;AAAA,UACtC;AAAA,QACD;AAAA,MACD;AAGA,YAAM,qBACL,OAAO,WAAW,aAAa;AAChC,YAAM,kBAAkB,mBAAmB,kBAAkB;AAC7D,WAAK,SAAS,SAAS,eAAe;AAGtC,WAAK,SAAS,iBAAiB;AAG/B,WAAK,QAAQ,IAAI;AAAA,QAChB,KAAK;AAAA,QACL,MAAM,KAAK;AAAA,QACX,MAAM,KAAK;AAAA,MACZ;AACA,WAAK,WAAW,IAAI;AAAA,QACnB,KAAK;AAAA,QACL,MAAM,KAAK;AAAA,QACX;AAAA;AAAA,MACD;AAGA,UAAI,CAAC,QAAQ,aAAa;AACzB,cAAM,gBAA+B;AAAA,UACpC,SAAS,KAAK;AAAA,UACd,SAAS,KAAK;AAAA,UACd,QAAQ,KAAK;AAAA,QACd;AAEA,cAAM,KAAK,eAAe,QAAQ,aAAa;AAAA,MAChD;AAGA,UAAI,CAAC,QAAQ,aAAa;AACzB,cAAM,KAAK,WAAW,mBAAmB,KAAK,QAAQ;AAAA,MACvD;AAEA,WAAK,cAAc;AAGnB,YAAM,kBAAkB,KAAK,mBAAmB;AAChD,UAAI,gBAAgB,MAAM;AACzB,cAAM,UAAU,MAAM,uBAAuB,IAAI;AAEjD,YAAI,QAAQ,UAAU,SAAS,GAAG;AACjC,gBAAM,eAAe,QAAQ,UAAU,IAAI,CAAC,MAAM,EAAE,EAAE,EAAE,KAAK,IAAI;AACjE,gBAAM,IAAI;AAAA,YACT,8DAA8D,YAAY;AAAA,YAC1E,EAAE,MAAM,cAAc;AAAA,UACvB;AAAA,QACD;AAEA,YAAI,QAAQ,WAAW,GAAG;AACzB,gBAAM,QAAQ,MAAM;AAAA,QACrB;AAAA,MACD;AAAA,IACD,SAAS,OAAO;AACf,UAAI,iBAAiB,aAAa;AACjC,cAAM;AAAA,MACP;AACA,YAAM,IAAI;AAAA,QACT,0BAA0B,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,QAChF;AAAA,UACC,MAAM;AAAA,UACN,OAAO,iBAAiB,QAAQ,QAAQ;AAAA,QACzC;AAAA,MACD;AAAA,IACD;AAAA,EACD;AAAA,EAEA,MAAM,WAA0B;AAC/B,QAAI,CAAC,KAAK,aAAa;AACtB;AAAA,IACD;AAEA,QAAI;AACH,YAAM,KAAK,eAAe,WAAW;AAErC,UAAI,KAAK,SAAS;AACjB,cAAM,KAAK,QAAQ,WAAW;AAAA,MAC/B;AAEA,WAAK,SAAS,MAAM;AACpB,WAAK,aAAa;AAClB,WAAK,cAAc;AAAA,IACpB,SAAS,OAAO;AACf,YAAM,IAAI;AAAA,QACT,oBAAoB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,QAC1E;AAAA,UACC,MAAM;AAAA,UACN,OAAO,iBAAiB,QAAQ,QAAQ;AAAA,QACzC;AAAA,MACD;AAAA,IACD;AAAA,EACD;AAAA,EAEA,YAA0B;AACzB,SAAK,kBAAkB;AACvB,WAAO,KAAK;AAAA,EACb;AAAA,EAEA,aAA6D;AAC5D,SAAK,kBAAkB;AACvB,WAAO,KAAK;AAAA,EACb;AAAA,EAEA,aAAsC;AACrC,SAAK,kBAAkB;AACvB,WAAO,KAAK,eAAe,OAAO;AAAA,EACnC;AAAA,EAEA,UAAiD,MAAwB;AACxE,SAAK,kBAAkB;AACvB,WAAQ,KAAK,eAAe,IAAI,IAAI,KAAW;AAAA,EAChD;AAAA,EAEA,UAAU,MAAuB;AAChC,SAAK,kBAAkB;AACvB,WAAO,KAAK,eAAe,IAAI,IAAI;AAAA,EACpC;AAAA,EAEA,gBAA4B;AAC3B,SAAK,kBAAkB;AACvB,WAAO,KAAK;AAAA,EACb;AAAA,EAEA,aAA6B;AAC5B,SAAK,kBAAkB;AACvB,WAAO,KAAK;AAAA,EACb;AAAA,EAEA,qBAAgD;AAC/C,SAAK,kBAAkB;AACvB,UAAM,aAAa,KAAK,OAAQ,aAAa,CAAC;AAC9C,WAAO,EAAE,GAAG,0BAA0B,GAAG,WAAW;AAAA,EACrD;AAAA,EAEA,eAAoC;AACnC,SAAK,kBAAkB;AACvB,UAAM,aAAa,KAAK,OAAQ,OAAO,CAAC;AACxC,WAAO,EAAE,GAAG,oBAAoB,GAAG,WAAW;AAAA,EAC/C;AAAA,EAEA,gBAAyB;AACxB,WAAO,KAAK;AAAA,EACb;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA6BA,MAAM,eAA0C;AAC/C,SAAK,kBAAkB;AAEvB,WAAO,MAAM,uBAAuB,IAAI;AAAA,EACzC;AAAA,EAEA,IAAI,OAAuB;AAC1B,SAAK,kBAAkB;AACvB,WAAO,KAAK;AAAA,EACb;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiBA,IAAI,MAAsB;AACzB,SAAK,kBAAkB;AACvB,WAAO,KAAK;AAAA,EACb;AAAA,EAEA,MAAM,QACL,OACA,OACA,SACoB;AACpB,SAAK,kBAAkB;AACvB,WAAO,KAAK,MAAM,QAAW,OAAO,OAAO,OAAO;AAAA,EACnD;AAAA,EAEA,MAAM,SACL,OACA,IACA,SACoB;AACpB,SAAK,kBAAkB;AACvB,WAAO,KAAK,MAAM,SAAY,OAAO,IAAI,OAAO;AAAA,EACjD;AAAA,EAEA,MAAM,SACL,OACA,SACe;AACf,SAAK,kBAAkB;AACvB,WAAO,KAAK,MAAM,SAAY,OAAO,OAAO;AAAA,EAC7C;AAAA,EAEA,MAAM,MACL,OACA,OACkB;AAClB,SAAK,kBAAkB;AACvB,WAAO,KAAK,MAAM,MAAM,OAAO,KAAK;AAAA,EACrC;AAAA,EAEA,MAAM,OAGJ,OAAe,MAAc,SAAyC;AACvE,SAAK,kBAAkB;AACvB,WAAO,KAAK,MAAM,OAAkB,OAAO,MAAM,OAAO;AAAA,EACzD;AAAA,EAEA,MAAM,WAGJ,OAAe,MAAgB,SAA2C;AAC3E,SAAK,kBAAkB;AACvB,WAAO,KAAK,MAAM,WAAsB,OAAO,MAAM,OAAO;AAAA,EAC7D;AAAA,EAEA,MAAM,OAIL,OACA,IACA,MACA,SACa;AACb,SAAK,kBAAkB;AACvB,WAAO,KAAK,MAAM,OAAkB,OAAO,IAAI,MAAM,OAAO;AAAA,EAC7D;AAAA,EAEA,MAAM,WAIL,OACA,OACA,MACA,SACe;AACf,SAAK,kBAAkB;AACvB,WAAO,KAAK,MAAM,WAAsB,OAAO,OAAO,MAAM,OAAO;AAAA,EACpE;AAAA,EAEA,MAAM,OACL,OACA,IACA,SACa;AACb,SAAK,kBAAkB;AACvB,WAAO,KAAK,MAAM,OAAO,OAAO,IAAI,OAAO;AAAA,EAC5C;AAAA,EAEA,MAAM,WACL,OACA,OACA,SACe;AACf,SAAK,kBAAkB;AACvB,WAAO,KAAK,MAAM,WAAW,OAAO,OAAO,OAAO;AAAA,EACnD;AAAA,EAEA,IAAI,SAAyB;AAC5B,SAAK,kBAAkB;AACvB,WAAO,KAAK;AAAA,EACb;AAAA,EAEA,UAAU,MAAc;AACvB,SAAK,kBAAkB;AACvB,WAAO,KAAK,SAAS,IAAI,IAAI;AAAA,EAC9B;AAAA,EAEA,gBAAgB;AACf,SAAK,kBAAkB;AACvB,WAAO,KAAK,SAAS,OAAO;AAAA,EAC7B;AAAA,EAEA,UAAU,MAAuB;AAChC,SAAK,kBAAkB;AACvB,WAAO,KAAK,SAAS,IAAI,IAAI;AAAA,EAC9B;AAAA,EAEA,QAAc;AACb,SAAK,SAAS;AACd,SAAK,UAAU;AACf,SAAK,iBAAiB,IAAI,eAAe;AACzC,SAAK,aAAa;AAClB,SAAK,WAAW,IAAI,eAAe;AACnC,SAAK,cAAc;AAAA,EACpB;AAAA,EAEQ,oBAA0B;AACjC,QAAI,CAAC,KAAK,aAAa;AACtB,YAAM,IAAI;AAAA,QACT;AAAA,QACA,EAAE,MAAM,kBAAkB;AAAA,MAC3B;AAAA,IACD;AAAA,EACD;AAAA,EAEQ,sBAAsB,YAAqC;AAClE,eAAW,aAAa,YAAY;AACnC,YAAM,SAAS,KAAK,SAAS,IAAI,UAAU,YAAY;AACvD,YAAM,iBAAiB,EAAE,GAAG,OAAO,OAAO;AAC1C,YAAM,kBAAkB,CAAC,GAAI,OAAO,WAAW,CAAC,CAAE;AAElD,UAAI,UAAU,QAAQ;AACrB,mBAAW,CAAC,WAAW,QAAQ,KAAK,OAAO,QAAQ,UAAU,MAAM,GAAG;AACrE,cAAI,eAAe,SAAS,GAAG;AAC9B,oBAAQ;AAAA,cACP,mBAAmB,SAAS,+BAA+B,UAAU,YAAY;AAAA,YAClF;AACA;AAAA,UACD;AACA,yBAAe,SAAS,IAAI;AAAA,QAC7B;AAAA,MACD;AAEA,UAAI,UAAU,cAAc;AAC3B,mBAAW,aAAa,UAAU,cAAc;AAC/C,iBAAO,eAAe,SAAS;AAAA,QAChC;AAAA,MACD;AAEA,UAAI,UAAU,cAAc;AAC3B,mBAAW,CAAC,WAAW,aAAa,KAAK,OAAO;AAAA,UAC/C,UAAU;AAAA,QACX,GAAG;AACF,cAAI,CAAC,eAAe,SAAS,GAAG;AAC/B,oBAAQ;AAAA,cACP,iCAAiC,SAAS,gBAAgB,UAAU,YAAY;AAAA,YACjF;AACA;AAAA,UACD;AAEA,yBAAe,SAAS,IAAI;AAAA,YAC3B,GAAG,eAAe,SAAS;AAAA,YAC3B,GAAG;AAAA,UACJ;AAAA,QACD;AAAA,MACD;AAEA,UAAI,UAAU,SAAS;AACtB,wBAAgB,KAAK,GAAG,UAAU,OAAO;AAAA,MAC1C;AAEA,YAAM,iBAAiB;AAAA,QACtB,GAAG;AAAA,QACH,QAAQ;AAAA,QACR,SAAS;AAAA,MACV;AAEA,WAAK,SAAS,SAAS,cAAc;AAAA,IACtC;AAAA,EACD;AACD;AA2BO,SAAS,aAAa,SAA+C;AAC3E,QAAM,WAAW,IAAI,OAAO;AAC5B,MAAI,cAAsC;AAE1C,SAAO,eAAe,oBAAqC;AAE1D,QAAI,SAAS,cAAc,GAAG;AAC7B,aAAO;AAAA,IACR;AAGA,QAAI,aAAa;AAChB,aAAO;AAAA,IACR;AAGA,mBAAe,YAAY;AAC1B,YAAM,SAAS,QAAQ;AAEvB,UAAI;AACH,cAAM,SAAS,qBAAqB,MAAM;AAAA,MAC3C,UAAE;AACD,sBAAc;AAAA,MACf;AAEA,aAAO;AAAA,IACR,GAAG;AAEH,WAAO;AAAA,EACR;AACD;;;ACzaO,SAAS,eACf,OACiC;AACjC,SAAO,OAAO,UAAU;AACzB;;;ACoCO,SAAS,kBACf,OACoC;AACpC,SACC,OAAO,UAAU,YACjB,UAAU,QACV,UAAU,SACV,YAAY,SACZ,aAAa,SACb,gBAAgB,SAChB,kBAAkB,SAClB,gBAAgB,SAChB,gBAAgB,SAChB,OAAQ,MAA0B,YAAY,cAC9C,OAAQ,MAA0B,eAAe,cACjD,OAAQ,MAA0B,iBAAiB,cACnD,OAAQ,MAA0B,eAAe,cACjD,OAAQ,MAA0B,eAAe;AAEnD;;;ACrJO,IAAM,kBAAkB;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD;AAUO,SAAS,gBAAgB,OAAuC;AACtE,SAAO,gBAAgB,SAAS,KAAsB;AACvD;;;ACyCO,SAAS,uBAAuB,kBAAkC;AACxE,QAAM,YAAY,KAAK,IAAI;AAC3B,QAAM,SAAS,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,UAAU,GAAG,EAAE;AACzD,QAAM,YAAY,iBAAiB,gBAAgB;AACnD,SAAO,YACJ,GAAG,SAAS,IAAI,MAAM,IAAI,SAAS,KACnC,GAAG,SAAS,IAAI,MAAM;AAC1B;AAKO,SAAS,iBAAiB,UAA0B;AAC1D,QAAM,QAAQ,SAAS,MAAM,GAAG;AAChC,MAAI,MAAM,SAAS,EAAG,QAAO;AAC7B,SAAO,MAAM,MAAM,SAAS,CAAC,KAAK;AACnC;AAKO,SAAS,iBAAiB,UAA0B;AAC1D,SAAO,SACL,QAAQ,SAAS,EAAE,EACnB,QAAQ,OAAO,EAAE,EACjB,QAAQ,OAAO,EAAE,EACjB,QAAQ,cAAc,EAAE,EACxB,QAAQ,QAAQ,GAAG,EACnB,YAAY;AACf;AA8BO,SAAS,kBAAkB,OAA0C;AAC3E,MAAI,OAAO,UAAU,YAAY,UAAU,MAAM;AAChD,WAAO;AAAA,EACR;AAEA,QAAM,MAAM;AAEZ,SACC,OAAO,IAAI,MAAM,MAAM,YACvB,OAAO,IAAI,QAAQ,MAAM,cACzB,OAAO,IAAI,QAAQ,MAAM,cACzB,OAAO,IAAI,QAAQ,MAAM,cACzB,OAAO,IAAI,QAAQ,MAAM;AAE3B;;;ACpNO,IAAM,qBAAqB;AAAA,EACjC,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,iBAAiB;AAAA,EACjB,aAAa;AAAA,EACb,kBAAkB;AAAA,EAClB,YAAY;AAAA,EACZ,gBAAgB,CAAC;AAClB;AAKO,IAAM,0BAA0B;AAAA,EACtC,SAAS;AAAA,EACT,YAAY;AAAA,IACX,MAAM;AAAA,IACN,OAAO;AAAA,EACR;AAAA,EACA,KAAK;AAAA,IACJ,WAAW;AAAA,IACX,WAAW;AAAA,EACZ;AAAA,EACA,SAAS;AAAA,IACR,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,aAAa;AAAA,IACb,QAAQ;AAAA,EACT;AAAA,EACA,UAAU;AAAA,IACT,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,WAAW;AAAA,EACZ;AAAA,EACA,WAAW;AAAA,IACV,OAAO;AAAA,IACP,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,IAAI;AAAA,IACJ,iBAAiB;AAAA,EAClB;AACD;;;ACpCO,IAAM,WAAN,cAAuB,MAAM;AAAA,EACnC,YACC,SACgB,MAMA,SACf;AACD,UAAM,OAAO;AARG;AAMA;AAGhB,SAAK,OAAO;AAAA,EACb;AACD;;;ACKO,IAAe,aAAf,MAE6B;AAAA,EAG1B;AAAA,EAEC;AAAA,EAEV,YAAY,SAAmB;AAC9B,SAAK,UAAU;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAqBA,MAAM,aAA0C;AAC/C,WAAO,CAAC;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,cACL,UAC6B;AAC7B,WAAO,CAAC;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,aAAa,UAA0C;AAAA,EAE7D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,cACL,OACA,UAC0B;AAC1B,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,aACL,QACA,UACmB;AACnB,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,qBAAqB,SAA8C;AACxE,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOU,gBACT,WACA,cACW;AACX,QAAI,UAAU,KAAK,OAAO,GAAG;AAC5B,aAAO,KAAK;AAAA,IACb;AAEA,UAAM,IAAI,YAAY,cAAc;AAAA,MACnC,MAAM;AAAA,MACN,YAAY,KAAK;AAAA,MACjB,SAAS,KAAK;AAAA,IACf,CAAC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOU,gBAER;AACD,WAAO,KAAK,YAAY;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOU,aAA4B;AACrC,QAAI,KAAK,YAAY,QAAW;AAC/B,YAAM,IAAI,YAAY,UAAU,KAAK,IAAI,oBAAoB;AAAA,QAC5D,MAAM;AAAA,QACN,YAAY,KAAK;AAAA,MAClB,CAAC;AAAA,IACF;AACA,WAAO,KAAK;AAAA,EACb;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOU,YACT,SACA,MACA,SACc;AACd,WAAO,IAAI,YAAY,SAAS;AAAA,MAC/B;AAAA,MACA,YAAY,KAAK;AAAA,MACjB;AAAA,IACD,CAAC;AAAA,EACF;AACD;","names":["COMPARISON_OPERATORS","STRING_OPERATORS","isLogicalOperator","throwMaxDepthExceeded","throwSchemaNotFound","throwMaxDepthExceeded","throwSchemaNotFound","RESERVED_FIELDS","COMPARISON_OPERATORS","STRING_OPERATORS","isLogicalOperator","error","executionTime","warnings"]}