@hedystia/db 2.0.6 → 2.0.8

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.
Files changed (67) hide show
  1. package/dist/cache/index.mjs +12 -0
  2. package/dist/cache/index.mjs.map +1 -0
  3. package/dist/cache/manager.mjs +156 -153
  4. package/dist/cache/manager.mjs.map +1 -1
  5. package/dist/cache/memory-store.mjs +113 -111
  6. package/dist/cache/memory-store.mjs.map +1 -1
  7. package/dist/cli/commands/migrate.cjs +78 -0
  8. package/dist/cli/commands/migrate.cjs.map +1 -0
  9. package/dist/cli/commands/migrate.mjs +83 -0
  10. package/dist/cli/commands/migrate.mjs.map +1 -0
  11. package/dist/cli/commands/migration.cjs +3 -2
  12. package/dist/cli/commands/migration.cjs.map +1 -1
  13. package/dist/cli/commands/migration.mjs +4 -3
  14. package/dist/cli/commands/migration.mjs.map +1 -1
  15. package/dist/cli.cjs +44 -5
  16. package/dist/cli.cjs.map +1 -1
  17. package/dist/cli.mjs +45 -5
  18. package/dist/cli.mjs.map +1 -1
  19. package/dist/core/database.cjs +75 -29
  20. package/dist/core/database.cjs.map +1 -1
  21. package/dist/core/database.d.cts +11 -0
  22. package/dist/core/database.d.mts +11 -0
  23. package/dist/core/database.mjs +91 -34
  24. package/dist/core/database.mjs.map +1 -1
  25. package/dist/core/repository.mjs +414 -410
  26. package/dist/core/repository.mjs.map +1 -1
  27. package/dist/drivers/driver.mjs +9 -7
  28. package/dist/drivers/driver.mjs.map +1 -1
  29. package/dist/drivers/file.mjs +315 -312
  30. package/dist/drivers/file.mjs.map +1 -1
  31. package/dist/drivers/index.mjs +15 -6
  32. package/dist/drivers/index.mjs.map +1 -1
  33. package/dist/drivers/mysql.mjs +261 -256
  34. package/dist/drivers/mysql.mjs.map +1 -1
  35. package/dist/drivers/sql-compiler.mjs +4 -1
  36. package/dist/drivers/sql-compiler.mjs.map +1 -1
  37. package/dist/drivers/sqlite.cjs +12 -1
  38. package/dist/drivers/sqlite.cjs.map +1 -1
  39. package/dist/drivers/sqlite.mjs +258 -242
  40. package/dist/drivers/sqlite.mjs.map +1 -1
  41. package/dist/errors.mjs +48 -64
  42. package/dist/errors.mjs.map +1 -1
  43. package/dist/index.mjs +21 -9
  44. package/dist/index.mjs.map +1 -1
  45. package/dist/migrations/templates.cjs +4 -3
  46. package/dist/migrations/templates.cjs.map +1 -1
  47. package/dist/migrations/templates.d.cts +3 -2
  48. package/dist/migrations/templates.d.mts +3 -2
  49. package/dist/migrations/templates.mjs +4 -3
  50. package/dist/migrations/templates.mjs.map +1 -1
  51. package/dist/schema/column.mjs +155 -157
  52. package/dist/schema/column.mjs.map +1 -1
  53. package/dist/schema/columns/index.mjs +103 -171
  54. package/dist/schema/columns/index.mjs.map +1 -1
  55. package/dist/schema/index.mjs +15 -0
  56. package/dist/schema/index.mjs.map +1 -0
  57. package/dist/schema/registry.mjs +122 -119
  58. package/dist/schema/registry.mjs.map +1 -1
  59. package/dist/schema/table.mjs +4 -1
  60. package/dist/schema/table.mjs.map +1 -1
  61. package/dist/sync/synchronizer.mjs +2 -1
  62. package/dist/sync/synchronizer.mjs.map +1 -1
  63. package/dist/utils/naming.cjs +9 -0
  64. package/dist/utils/naming.cjs.map +1 -1
  65. package/dist/utils/naming.mjs +9 -1
  66. package/dist/utils/naming.mjs.map +1 -1
  67. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"database.cjs","names":["SchemaRegistry","DatabaseError","createDriver","CacheManager","TableRepository","MIGRATIONS_TABLE"],"sources":["../../src/core/database.ts"],"sourcesContent":["import { CacheManager } from \"../cache\";\nimport { MIGRATIONS_TABLE } from \"../constants\";\nimport { createDriver } from \"../drivers\";\nimport { DatabaseError } from \"../errors\";\nimport { SchemaRegistry } from \"../schema\";\nimport type {\n AnyTableDef,\n ConnectionConfig,\n DatabaseConfig,\n DatabaseDriver,\n DeleteOptions,\n InferRow,\n InferSchemas,\n MigrationDefinition,\n QueryOptions,\n RelationQueryMap,\n ResolveResult,\n TableMetadata,\n UpdateOptions,\n WhereClause,\n} from \"../types\";\nimport { TableRepository } from \"./repository\";\n\ntype TypedTableRepository<S extends readonly AnyTableDef[], T extends AnyTableDef> = {\n /**\n * Find all rows matching the given options\n * @param options - Filter, sort, paginate, and eagerly load relations\n * @returns Array of matching rows\n */\n find<O extends QueryOptions<InferRow<T>, RelationQueryMap<S, T>> = {}>(\n options?: O,\n ): Promise<ResolveResult<S, T, O>[]>;\n\n /**\n * Find all rows matching the given options (alias for {@link find})\n * @param options - Filter, sort, paginate, and eagerly load relations\n * @returns Array of matching rows\n */\n findMany<O extends QueryOptions<InferRow<T>, RelationQueryMap<S, T>> = {}>(\n options?: O,\n ): Promise<ResolveResult<S, T, O>[]>;\n\n /**\n * Find the first row matching the given options\n * @param options - Filter, sort, and eagerly load relations\n * @returns The first matching row, or `null` if none found\n */\n findFirst<O extends QueryOptions<InferRow<T>, RelationQueryMap<S, T>> = {}>(\n options?: O,\n ): Promise<ResolveResult<S, T, O> | null>;\n\n /**\n * Insert one or more rows into the table\n * @param data - Row data (or array of row data) to insert\n * @returns The inserted row\n */\n insert(data: Partial<InferRow<T>> | Partial<InferRow<T>>[]): Promise<InferRow<T>>;\n\n /**\n * Insert multiple rows into the table\n * @param data - Array of row data to insert\n * @returns Array of inserted rows\n */\n insertMany(data: Partial<InferRow<T>>[]): Promise<InferRow<T>[]>;\n\n /**\n * Update rows matching the where clause\n * @param options - Where clause and partial data to apply\n * @returns Array of updated rows\n */\n update(options: UpdateOptions<InferRow<T>>): Promise<InferRow<T>[]>;\n\n /**\n * Delete rows matching the where clause\n * @param options - Where clause to select rows for deletion\n * @returns Number of deleted rows\n */\n delete(options: DeleteOptions<InferRow<T>>): Promise<number>;\n\n /**\n * Count rows matching the where clause\n * @param options - Optional where clause to filter rows\n * @returns Number of matching rows\n */\n count(options?: Pick<QueryOptions<InferRow<T>>, \"where\">): Promise<number>;\n\n /**\n * Check whether at least one row matches the where clause\n * @param options - Where clause to check\n * @returns `true` if a matching row exists, `false` otherwise\n */\n exists(options: Pick<QueryOptions<InferRow<T>>, \"where\">): Promise<boolean>;\n\n /**\n * Insert a row if it doesn't exist, or update it if it does\n * @param options - Where clause to check, data to create, and data to update\n * @returns The created or updated row\n */\n upsert(options: {\n where: WhereClause<InferRow<T>>;\n create: Partial<InferRow<T>>;\n update: Partial<InferRow<T>>;\n }): Promise<InferRow<T>>;\n\n /**\n * Remove all rows from the table\n * @returns Resolves when the table has been truncated\n */\n truncate(): Promise<void>;\n};\n\ntype ExtractRepos<S> = S extends readonly AnyTableDef[]\n ? { [T in S[number] as T[\"__name\"]]: TypedTableRepository<S, T> }\n : S extends Record<string, any>\n ? {\n [K in keyof S as S[K] extends AnyTableDef ? K : never]: TypedTableRepository<\n InferSchemas<S>,\n Extract<S[K], AnyTableDef>\n >;\n }\n : never;\n\ntype DatabaseInstance<S> = ExtractRepos<S> & {\n /**\n * Initialize the database connection, create tables and run migrations\n * @returns {Promise<void>}\n */\n initialize(): Promise<void>;\n /**\n * Close the database connection\n * @returns {Promise<void>}\n */\n close(): Promise<void>;\n /**\n * Get the underlying database driver\n * @returns {DatabaseDriver} The database driver\n */\n getDriver(): DatabaseDriver;\n /**\n * Get the schema registry\n * @returns {SchemaRegistry} The schema registry\n */\n getRegistry(): SchemaRegistry;\n /**\n * Get the cache manager\n * @returns {CacheManager} The cache manager\n */\n getCache(): CacheManager;\n /**\n * Execute a raw SQL query\n * @param {string} sql - SQL query\n * @param {unknown[]} [params] - Query parameters\n * @returns {Promise<any[]>} Query results\n */\n raw(sql: string, params?: unknown[]): Promise<any[]>;\n /**\n * Execute within a transaction\n * @param {() => Promise<T>} fn - Function to execute\n * @returns {Promise<T>} Result\n */\n transaction<T>(fn: () => Promise<T>): Promise<T>;\n};\n\n/**\n * Create a database instance with typed repositories for each schema\n * @param {DatabaseConfig} config - Database configuration\n * @returns {DatabaseInstance<S>} Database instance with table repositories\n */\nfunction normalizeMigrations(\n migrations: MigrationDefinition[] | Record<string, unknown>,\n): MigrationDefinition[] {\n if (Array.isArray(migrations)) {\n return migrations;\n }\n return Object.values(migrations).filter(\n (v): v is MigrationDefinition =>\n v != null && typeof v === \"object\" && \"name\" in v && \"up\" in v && \"down\" in v,\n );\n}\n\nfunction normalizeSchemas<S extends readonly AnyTableDef[]>(schemas: any): S {\n if (Array.isArray(schemas)) {\n return schemas as any as S;\n }\n return Object.values(schemas).filter(\n (v): v is AnyTableDef => v != null && typeof v === \"object\" && (v as any).__table === true,\n ) as any;\n}\n\nexport function database<const S extends readonly AnyTableDef[] | Record<string, any>>(\n config: DatabaseConfig & { schemas: S },\n): DatabaseInstance<S> {\n const schemas = normalizeSchemas(config.schemas) as any;\n const registry = new SchemaRegistry();\n registry.register(schemas);\n\n const connectionConfig = Array.isArray(config.connection)\n ? config.connection[0]\n : config.connection;\n\n if (!connectionConfig) {\n throw new DatabaseError(\"Connection config is required\");\n }\n\n const driver = createDriver(config.database, connectionConfig as ConnectionConfig);\n const cache = new CacheManager(config.cache);\n\n let initialized = false;\n let initPromise: Promise<void> | null = null;\n\n const ensureInitialized = async () => {\n if (initialized) {\n return;\n }\n if (initPromise) {\n return initPromise;\n }\n initPromise = doInit();\n await initPromise;\n initialized = true;\n };\n\n const doInit = async () => {\n await driver.connect();\n\n if (config.syncSchemas) {\n const allMetadata = driver.getAllTableColumns ? await driver.getAllTableColumns() : null;\n\n const syncPromises = Array.from(registry.getAllTables()).map(async ([, tableMeta]) => {\n const existingCols = allMetadata ? allMetadata[tableMeta.name] : null;\n const exists = allMetadata ? !!existingCols : await driver.tableExists(tableMeta.name);\n\n if (!exists) {\n await driver.createTable(tableMeta);\n } else {\n const cols = existingCols || (await driver.getTableColumns(tableMeta.name));\n const existingNames = new Set(cols.map((c) => c.name));\n const addColumnPromises = tableMeta.columns\n .filter((colMeta) => !existingNames.has(colMeta.name))\n .map((colMeta) => driver.addColumn(tableMeta.name, colMeta));\n await Promise.all(addColumnPromises);\n }\n });\n await Promise.all(syncPromises);\n }\n\n if (config.runMigrations && config.migrations) {\n const migrations = normalizeMigrations(config.migrations);\n if (migrations.length > 0) {\n await runMigrations(driver, registry, migrations);\n }\n }\n };\n\n const repos = new Map<string, TableRepository<any>>();\n for (const schema of schemas) {\n const repo = new TableRepository(schema.__name, driver, cache, registry, schema.__cache);\n repos.set(schema.__name, repo);\n }\n\n const instance: any = {\n initialize: async () => {\n await ensureInitialized();\n },\n close: async () => {\n await driver.disconnect();\n cache.clear();\n initialized = false;\n initPromise = null;\n },\n getDriver: () => driver,\n getRegistry: () => registry,\n getCache: () => cache,\n raw: async (sql: string, params?: unknown[]) => {\n await ensureInitialized();\n return driver.query(sql, params);\n },\n transaction: async <T>(fn: () => Promise<T>) => {\n await ensureInitialized();\n return driver.transaction(fn);\n },\n };\n\n for (const schema of schemas) {\n const repo = repos.get(schema.__name)!;\n const proxy = new Proxy(repo, {\n get(target, prop, receiver) {\n const original = Reflect.get(target, prop, receiver);\n if (typeof original === \"function\") {\n return async (...args: any[]) => {\n await ensureInitialized();\n return original.apply(target, args);\n };\n }\n return original;\n },\n });\n instance[schema.__name] = proxy;\n }\n\n return instance as any as DatabaseInstance<S>;\n}\n\nasync function runMigrations(\n driver: DatabaseDriver,\n registry: SchemaRegistry,\n migrations: MigrationDefinition[],\n): Promise<void> {\n const migrationsTableMeta: TableMetadata = {\n name: MIGRATIONS_TABLE,\n columns: [\n {\n name: \"id\",\n type: \"integer\",\n primaryKey: true,\n autoIncrement: true,\n notNull: true,\n unique: true,\n defaultValue: undefined,\n },\n {\n name: \"name\",\n type: \"varchar\",\n primaryKey: false,\n autoIncrement: false,\n notNull: true,\n unique: true,\n defaultValue: undefined,\n length: 255,\n },\n {\n name: \"executed_at\",\n type: \"datetime\",\n primaryKey: false,\n autoIncrement: false,\n notNull: true,\n unique: false,\n defaultValue: undefined,\n },\n ],\n };\n\n const exists = await driver.tableExists(MIGRATIONS_TABLE);\n if (!exists) {\n await driver.createTable(migrationsTableMeta);\n }\n\n const executed = await driver.query(`SELECT name FROM \\`${MIGRATIONS_TABLE}\\``);\n const executedNames = new Set(executed.map((r: any) => r.name));\n\n for (const migration of migrations) {\n if (executedNames.has(migration.name)) {\n continue;\n }\n\n const ctx = {\n schema: {\n createTable: async (tableDef: AnyTableDef) => {\n const meta = registry.getTable(tableDef.__name);\n if (meta) {\n await driver.createTable(meta);\n }\n },\n dropTable: async (name: string) => {\n await driver.dropTable(name);\n },\n addColumn: async (table: string, _name: string, column: any) => {\n await driver.addColumn(table, column);\n },\n dropColumn: async (table: string, name: string) => {\n await driver.dropColumn(table, name);\n },\n renameColumn: async (table: string, oldName: string, newName: string) => {\n await driver.renameColumn(table, oldName, newName);\n },\n addIndex: async () => {},\n dropIndex: async () => {},\n },\n sql: async (query: string, params?: unknown[]) => {\n return driver.execute(query, params);\n },\n };\n\n await migration.up(ctx);\n\n await driver.execute(\n `INSERT INTO \\`${MIGRATIONS_TABLE}\\` (\\`name\\`, \\`executed_at\\`) VALUES (?, ?)`,\n [migration.name, new Date()],\n );\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"database.cjs","names":["SchemaRegistry","DatabaseError","createDriver","CacheManager","TableRepository","MIGRATIONS_TABLE"],"sources":["../../src/core/database.ts"],"sourcesContent":["import { CacheManager } from \"../cache\";\nimport { MIGRATIONS_TABLE } from \"../constants\";\nimport { createDriver } from \"../drivers\";\nimport { DatabaseError } from \"../errors\";\nimport { SchemaRegistry } from \"../schema\";\nimport type {\n AnyTableDef,\n ConnectionConfig,\n DatabaseConfig,\n DatabaseDriver,\n DeleteOptions,\n InferRow,\n InferSchemas,\n MigrationDefinition,\n QueryOptions,\n RelationQueryMap,\n ResolveResult,\n TableMetadata,\n UpdateOptions,\n WhereClause,\n} from \"../types\";\nimport { TableRepository } from \"./repository\";\n\ntype TypedTableRepository<S extends readonly AnyTableDef[], T extends AnyTableDef> = {\n /**\n * Find all rows matching the given options\n * @param options - Filter, sort, paginate, and eagerly load relations\n * @returns Array of matching rows\n */\n find<O extends QueryOptions<InferRow<T>, RelationQueryMap<S, T>> = {}>(\n options?: O,\n ): Promise<ResolveResult<S, T, O>[]>;\n\n /**\n * Find all rows matching the given options (alias for {@link find})\n * @param options - Filter, sort, paginate, and eagerly load relations\n * @returns Array of matching rows\n */\n findMany<O extends QueryOptions<InferRow<T>, RelationQueryMap<S, T>> = {}>(\n options?: O,\n ): Promise<ResolveResult<S, T, O>[]>;\n\n /**\n * Find the first row matching the given options\n * @param options - Filter, sort, and eagerly load relations\n * @returns The first matching row, or `null` if none found\n */\n findFirst<O extends QueryOptions<InferRow<T>, RelationQueryMap<S, T>> = {}>(\n options?: O,\n ): Promise<ResolveResult<S, T, O> | null>;\n\n /**\n * Insert one or more rows into the table\n * @param data - Row data (or array of row data) to insert\n * @returns The inserted row\n */\n insert(data: Partial<InferRow<T>> | Partial<InferRow<T>>[]): Promise<InferRow<T>>;\n\n /**\n * Insert multiple rows into the table\n * @param data - Array of row data to insert\n * @returns Array of inserted rows\n */\n insertMany(data: Partial<InferRow<T>>[]): Promise<InferRow<T>[]>;\n\n /**\n * Update rows matching the where clause\n * @param options - Where clause and partial data to apply\n * @returns Array of updated rows\n */\n update(options: UpdateOptions<InferRow<T>>): Promise<InferRow<T>[]>;\n\n /**\n * Delete rows matching the where clause\n * @param options - Where clause to select rows for deletion\n * @returns Number of deleted rows\n */\n delete(options: DeleteOptions<InferRow<T>>): Promise<number>;\n\n /**\n * Count rows matching the where clause\n * @param options - Optional where clause to filter rows\n * @returns Number of matching rows\n */\n count(options?: Pick<QueryOptions<InferRow<T>>, \"where\">): Promise<number>;\n\n /**\n * Check whether at least one row matches the where clause\n * @param options - Where clause to check\n * @returns `true` if a matching row exists, `false` otherwise\n */\n exists(options: Pick<QueryOptions<InferRow<T>>, \"where\">): Promise<boolean>;\n\n /**\n * Insert a row if it doesn't exist, or update it if it does\n * @param options - Where clause to check, data to create, and data to update\n * @returns The created or updated row\n */\n upsert(options: {\n where: WhereClause<InferRow<T>>;\n create: Partial<InferRow<T>>;\n update: Partial<InferRow<T>>;\n }): Promise<InferRow<T>>;\n\n /**\n * Remove all rows from the table\n * @returns Resolves when the table has been truncated\n */\n truncate(): Promise<void>;\n};\n\ntype ExtractRepos<S> = S extends readonly AnyTableDef[]\n ? { [T in S[number] as T[\"__name\"]]: TypedTableRepository<S, T> }\n : S extends Record<string, any>\n ? {\n [K in keyof S as S[K] extends AnyTableDef ? K : never]: TypedTableRepository<\n InferSchemas<S>,\n Extract<S[K], AnyTableDef>\n >;\n }\n : never;\n\ntype DatabaseInstance<S> = ExtractRepos<S> & {\n /**\n * Initialize the database connection, create tables and run migrations\n * @returns {Promise<void>}\n */\n initialize(): Promise<void>;\n /**\n * Close the database connection\n * @returns {Promise<void>}\n */\n close(): Promise<void>;\n /**\n * Get the underlying database driver\n * @returns {DatabaseDriver} The database driver\n */\n getDriver(): DatabaseDriver;\n /**\n * Get the schema registry\n * @returns {SchemaRegistry} The schema registry\n */\n getRegistry(): SchemaRegistry;\n /**\n * Get the cache manager\n * @returns {CacheManager} The cache manager\n */\n getCache(): CacheManager;\n /**\n * Execute a raw SQL query\n * @param {string} sql - SQL query\n * @param {unknown[]} [params] - Query parameters\n * @returns {Promise<any[]>} Query results\n */\n raw(sql: string, params?: unknown[]): Promise<any[]>;\n /**\n * Execute within a transaction\n * @param {() => Promise<T>} fn - Function to execute\n * @returns {Promise<T>} Result\n */\n transaction<T>(fn: () => Promise<T>): Promise<T>;\n /**\n * Run pending migrations manually\n * @returns {Promise<void>}\n */\n migrateUp(): Promise<void>;\n /**\n * Rollback migrations\n * @param {number} [steps=1] - Number of migrations to rollback\n * @returns {Promise<string[]>} Names of rolled back migrations\n */\n migrateDown(steps?: number): Promise<string[]>;\n};\n\n/**\n * Create a database instance with typed repositories for each schema\n * @param {DatabaseConfig} config - Database configuration\n * @returns {DatabaseInstance<S>} Database instance with table repositories\n */\nfunction normalizeMigrations(\n migrations: MigrationDefinition[] | Record<string, unknown>,\n): MigrationDefinition[] {\n if (Array.isArray(migrations)) {\n return migrations;\n }\n return Object.values(migrations).filter(\n (v): v is MigrationDefinition =>\n v != null && typeof v === \"object\" && \"name\" in v && \"up\" in v && \"down\" in v,\n );\n}\n\nfunction normalizeSchemas<S extends readonly AnyTableDef[]>(schemas: any): S {\n if (Array.isArray(schemas)) {\n return schemas as any as S;\n }\n return Object.values(schemas).filter(\n (v): v is AnyTableDef => v != null && typeof v === \"object\" && (v as any).__table === true,\n ) as any;\n}\n\nexport function database<const S extends readonly AnyTableDef[] | Record<string, any>>(\n config: DatabaseConfig & { schemas: S },\n): DatabaseInstance<S> {\n const schemas = normalizeSchemas(config.schemas) as any;\n const registry = new SchemaRegistry();\n registry.register(schemas);\n\n const dbName = typeof config.database === \"string\" ? config.database : config.database.name;\n\n let connectionConfig: ConnectionConfig | undefined;\n if (Array.isArray(config.connection)) {\n if (dbName === \"sqlite\") {\n connectionConfig = config.connection.find((c) => \"filename\" in c) ?? config.connection[0];\n } else if (dbName === \"mysql\" || dbName === \"mariadb\") {\n connectionConfig = config.connection.find((c) => \"host\" in c) ?? config.connection[0];\n } else if (dbName === \"file\") {\n connectionConfig = config.connection.find((c) => \"directory\" in c) ?? config.connection[0];\n } else {\n connectionConfig = config.connection[0];\n }\n } else {\n connectionConfig = config.connection;\n }\n\n if (!connectionConfig) {\n throw new DatabaseError(\"Connection config is required\");\n }\n\n const driver = createDriver(config.database, connectionConfig as ConnectionConfig);\n const cache = new CacheManager(config.cache);\n\n let initialized = false;\n let initPromise: Promise<void> | null = null;\n\n const ensureInitialized = async () => {\n if (initialized) {\n return;\n }\n if (initPromise) {\n return initPromise;\n }\n initPromise = doInit();\n await initPromise;\n initialized = true;\n };\n\n const doInit = async () => {\n await driver.connect();\n\n if (config.syncSchemas) {\n const allMetadata = driver.getAllTableColumns ? await driver.getAllTableColumns() : null;\n\n const syncPromises = Array.from(registry.getAllTables()).map(async ([, tableMeta]) => {\n const existingCols = allMetadata ? allMetadata[tableMeta.name] : null;\n const exists = allMetadata ? !!existingCols : await driver.tableExists(tableMeta.name);\n\n if (!exists) {\n await driver.createTable(tableMeta);\n } else {\n const cols = existingCols || (await driver.getTableColumns(tableMeta.name));\n const existingNames = new Set(cols.map((c) => c.name));\n const addColumnPromises = tableMeta.columns\n .filter((colMeta) => !existingNames.has(colMeta.name))\n .map((colMeta) => driver.addColumn(tableMeta.name, colMeta));\n await Promise.all(addColumnPromises);\n }\n });\n await Promise.all(syncPromises);\n }\n\n if (config.runMigrations && config.migrations) {\n const migrations = normalizeMigrations(config.migrations);\n if (migrations.length > 0) {\n await runMigrations(driver, registry, migrations);\n }\n }\n };\n\n const repos = new Map<string, TableRepository<any>>();\n for (const schema of schemas) {\n const repo = new TableRepository(schema.__name, driver, cache, registry, schema.__cache);\n repos.set(schema.__name, repo);\n }\n\n const instance: any = {\n initialize: async () => {\n await ensureInitialized();\n },\n close: async () => {\n await driver.disconnect();\n cache.clear();\n initialized = false;\n initPromise = null;\n },\n getDriver: () => driver,\n getRegistry: () => registry,\n getCache: () => cache,\n raw: async (sql: string, params?: unknown[]) => {\n await ensureInitialized();\n return driver.query(sql, params);\n },\n transaction: async <T>(fn: () => Promise<T>) => {\n await ensureInitialized();\n return driver.transaction(fn);\n },\n migrateUp: async () => {\n await ensureInitialized();\n if (config.migrations) {\n const migrations = normalizeMigrations(config.migrations);\n if (migrations.length > 0) {\n await runMigrations(driver, registry, migrations);\n }\n }\n },\n migrateDown: async (steps = 1) => {\n await ensureInitialized();\n if (config.migrations) {\n const migrations = normalizeMigrations(config.migrations);\n return rollbackMigrations(driver, registry, migrations, steps);\n }\n return [];\n },\n };\n\n for (const schema of schemas) {\n const repo = repos.get(schema.__name)!;\n const proxy = new Proxy(repo, {\n get(target, prop, receiver) {\n const original = Reflect.get(target, prop, receiver);\n if (typeof original === \"function\") {\n return async (...args: any[]) => {\n await ensureInitialized();\n return original.apply(target, args);\n };\n }\n return original;\n },\n });\n instance[schema.__name] = proxy;\n }\n\n return instance as any as DatabaseInstance<S>;\n}\n\nfunction getMigrationsTableMeta(): TableMetadata {\n return {\n name: MIGRATIONS_TABLE,\n columns: [\n {\n name: \"id\",\n type: \"integer\",\n primaryKey: true,\n autoIncrement: true,\n notNull: true,\n unique: true,\n defaultValue: undefined,\n },\n {\n name: \"name\",\n type: \"varchar\",\n primaryKey: false,\n autoIncrement: false,\n notNull: true,\n unique: true,\n defaultValue: undefined,\n length: 255,\n },\n {\n name: \"executed_at\",\n type: \"datetime\",\n primaryKey: false,\n autoIncrement: false,\n notNull: true,\n unique: false,\n defaultValue: undefined,\n },\n ],\n };\n}\n\nfunction createMigrationContext(\n driver: DatabaseDriver,\n registry: SchemaRegistry,\n): MigrationDefinition[\"up\"] extends (ctx: infer C) => any ? C : never {\n return {\n schema: {\n createTable: async (tableDef: AnyTableDef) => {\n const meta = registry.getTable(tableDef.__name) ?? {\n name: tableDef.__name,\n columns: [...tableDef.__columns],\n };\n await driver.createTable(meta);\n },\n dropTable: async (name: string) => {\n await driver.dropTable(name);\n },\n addColumn: async (table: string, _name: string, column: any) => {\n await driver.addColumn(table, column);\n },\n dropColumn: async (table: string, name: string) => {\n await driver.dropColumn(table, name);\n },\n renameColumn: async (table: string, oldName: string, newName: string) => {\n await driver.renameColumn(table, oldName, newName);\n },\n addIndex: async () => {},\n dropIndex: async () => {},\n },\n sql: async (query: string, params?: unknown[]) => {\n return driver.execute(query, params);\n },\n };\n}\n\nasync function ensureMigrationsTable(driver: DatabaseDriver): Promise<void> {\n const exists = await driver.tableExists(MIGRATIONS_TABLE);\n if (!exists) {\n await driver.createTable(getMigrationsTableMeta());\n }\n}\n\nasync function runMigrations(\n driver: DatabaseDriver,\n registry: SchemaRegistry,\n migrations: MigrationDefinition[],\n): Promise<void> {\n await ensureMigrationsTable(driver);\n\n const executed = await driver.query(`SELECT name FROM \\`${MIGRATIONS_TABLE}\\``);\n const executedNames = new Set(executed.map((r: any) => r.name));\n\n const ctx = createMigrationContext(driver, registry);\n\n for (const migration of migrations) {\n if (executedNames.has(migration.name)) {\n continue;\n }\n\n await migration.up(ctx);\n\n await driver.execute(\n `INSERT INTO \\`${MIGRATIONS_TABLE}\\` (\\`name\\`, \\`executed_at\\`) VALUES (?, ?)`,\n [migration.name, new Date()],\n );\n }\n}\n\nasync function rollbackMigrations(\n driver: DatabaseDriver,\n registry: SchemaRegistry,\n migrations: MigrationDefinition[],\n steps = 1,\n): Promise<string[]> {\n await ensureMigrationsTable(driver);\n\n const executed = await driver.query(`SELECT name FROM \\`${MIGRATIONS_TABLE}\\` ORDER BY id DESC`);\n const executedNames = executed.map((r: any) => r.name as string);\n\n const ctx = createMigrationContext(driver, registry);\n const migrationMap = new Map(migrations.map((m) => [m.name, m]));\n const rolledBack: string[] = [];\n\n const toRollback = executedNames.slice(0, steps);\n\n for (const name of toRollback) {\n const migration = migrationMap.get(name);\n if (!migration) {\n continue;\n }\n\n await migration.down(ctx);\n\n await driver.execute(`DELETE FROM \\`${MIGRATIONS_TABLE}\\` WHERE \\`name\\` = ?`, [name]);\n rolledBack.push(name);\n }\n\n return rolledBack;\n}\n"],"mappings":"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"}
@@ -114,6 +114,17 @@ type DatabaseInstance<S> = ExtractRepos<S> & {
114
114
  * @returns {Promise<T>} Result
115
115
  */
116
116
  transaction<T>(fn: () => Promise<T>): Promise<T>;
117
+ /**
118
+ * Run pending migrations manually
119
+ * @returns {Promise<void>}
120
+ */
121
+ migrateUp(): Promise<void>;
122
+ /**
123
+ * Rollback migrations
124
+ * @param {number} [steps=1] - Number of migrations to rollback
125
+ * @returns {Promise<string[]>} Names of rolled back migrations
126
+ */
127
+ migrateDown(steps?: number): Promise<string[]>;
117
128
  };
118
129
  declare function database<const S extends readonly AnyTableDef[] | Record<string, any>>(config: DatabaseConfig & {
119
130
  schemas: S;
@@ -114,6 +114,17 @@ type DatabaseInstance<S> = ExtractRepos<S> & {
114
114
  * @returns {Promise<T>} Result
115
115
  */
116
116
  transaction<T>(fn: () => Promise<T>): Promise<T>;
117
+ /**
118
+ * Run pending migrations manually
119
+ * @returns {Promise<void>}
120
+ */
121
+ migrateUp(): Promise<void>;
122
+ /**
123
+ * Rollback migrations
124
+ * @param {number} [steps=1] - Number of migrations to rollback
125
+ * @returns {Promise<string[]>} Names of rolled back migrations
126
+ */
127
+ migrateDown(steps?: number): Promise<string[]>;
117
128
  };
118
129
  declare function database<const S extends readonly AnyTableDef[] | Record<string, any>>(config: DatabaseConfig & {
119
130
  schemas: S;
@@ -1,11 +1,13 @@
1
+ import { __esmMin } from "../_virtual/_rolldown/runtime.mjs";
1
2
  import { MIGRATIONS_TABLE, init_constants } from "../constants.mjs";
2
3
  import { CacheManager } from "../cache/manager.mjs";
3
- import { DatabaseError } from "../errors.mjs";
4
- import { createDriver } from "../drivers/index.mjs";
4
+ import { init_cache } from "../cache/index.mjs";
5
+ import { DatabaseError, init_errors } from "../errors.mjs";
6
+ import { createDriver, init_drivers } from "../drivers/index.mjs";
5
7
  import { SchemaRegistry } from "../schema/registry.mjs";
6
- import { TableRepository } from "./repository.mjs";
8
+ import { init_schema } from "../schema/index.mjs";
9
+ import { TableRepository, init_repository } from "./repository.mjs";
7
10
  //#region src/core/database.ts
8
- init_constants();
9
11
  /**
10
12
  * Create a database instance with typed repositories for each schema
11
13
  * @param {DatabaseConfig} config - Database configuration
@@ -23,7 +25,13 @@ function database(config) {
23
25
  const schemas = normalizeSchemas(config.schemas);
24
26
  const registry = new SchemaRegistry();
25
27
  registry.register(schemas);
26
- const connectionConfig = Array.isArray(config.connection) ? config.connection[0] : config.connection;
28
+ const dbName = typeof config.database === "string" ? config.database : config.database.name;
29
+ let connectionConfig;
30
+ if (Array.isArray(config.connection)) if (dbName === "sqlite") connectionConfig = config.connection.find((c) => "filename" in c) ?? config.connection[0];
31
+ else if (dbName === "mysql" || dbName === "mariadb") connectionConfig = config.connection.find((c) => "host" in c) ?? config.connection[0];
32
+ else if (dbName === "file") connectionConfig = config.connection.find((c) => "directory" in c) ?? config.connection[0];
33
+ else connectionConfig = config.connection[0];
34
+ else connectionConfig = config.connection;
27
35
  if (!connectionConfig) throw new DatabaseError("Connection config is required");
28
36
  const driver = createDriver(config.database, connectionConfig);
29
37
  const cache = new CacheManager(config.cache);
@@ -82,6 +90,18 @@ function database(config) {
82
90
  transaction: async (fn) => {
83
91
  await ensureInitialized();
84
92
  return driver.transaction(fn);
93
+ },
94
+ migrateUp: async () => {
95
+ await ensureInitialized();
96
+ if (config.migrations) {
97
+ const migrations = normalizeMigrations(config.migrations);
98
+ if (migrations.length > 0) await runMigrations(driver, registry, migrations);
99
+ }
100
+ },
101
+ migrateDown: async (steps = 1) => {
102
+ await ensureInitialized();
103
+ if (config.migrations) return rollbackMigrations(driver, registry, normalizeMigrations(config.migrations), steps);
104
+ return [];
85
105
  }
86
106
  };
87
107
  for (const schema of schemas) {
@@ -98,8 +118,8 @@ function database(config) {
98
118
  }
99
119
  return instance;
100
120
  }
101
- async function runMigrations(driver, registry, migrations) {
102
- const migrationsTableMeta = {
121
+ function getMigrationsTableMeta() {
122
+ return {
103
123
  name: MIGRATIONS_TABLE,
104
124
  columns: [
105
125
  {
@@ -132,40 +152,77 @@ async function runMigrations(driver, registry, migrations) {
132
152
  }
133
153
  ]
134
154
  };
135
- if (!await driver.tableExists("__hedystia_migrations")) await driver.createTable(migrationsTableMeta);
155
+ }
156
+ function createMigrationContext(driver, registry) {
157
+ return {
158
+ schema: {
159
+ createTable: async (tableDef) => {
160
+ const meta = registry.getTable(tableDef.__name) ?? {
161
+ name: tableDef.__name,
162
+ columns: [...tableDef.__columns]
163
+ };
164
+ await driver.createTable(meta);
165
+ },
166
+ dropTable: async (name) => {
167
+ await driver.dropTable(name);
168
+ },
169
+ addColumn: async (table, _name, column) => {
170
+ await driver.addColumn(table, column);
171
+ },
172
+ dropColumn: async (table, name) => {
173
+ await driver.dropColumn(table, name);
174
+ },
175
+ renameColumn: async (table, oldName, newName) => {
176
+ await driver.renameColumn(table, oldName, newName);
177
+ },
178
+ addIndex: async () => {},
179
+ dropIndex: async () => {}
180
+ },
181
+ sql: async (query, params) => {
182
+ return driver.execute(query, params);
183
+ }
184
+ };
185
+ }
186
+ async function ensureMigrationsTable(driver) {
187
+ if (!await driver.tableExists("__hedystia_migrations")) await driver.createTable(getMigrationsTableMeta());
188
+ }
189
+ async function runMigrations(driver, registry, migrations) {
190
+ await ensureMigrationsTable(driver);
136
191
  const executed = await driver.query(`SELECT name FROM \`${MIGRATIONS_TABLE}\``);
137
192
  const executedNames = new Set(executed.map((r) => r.name));
193
+ const ctx = createMigrationContext(driver, registry);
138
194
  for (const migration of migrations) {
139
195
  if (executedNames.has(migration.name)) continue;
140
- await migration.up({
141
- schema: {
142
- createTable: async (tableDef) => {
143
- const meta = registry.getTable(tableDef.__name);
144
- if (meta) await driver.createTable(meta);
145
- },
146
- dropTable: async (name) => {
147
- await driver.dropTable(name);
148
- },
149
- addColumn: async (table, _name, column) => {
150
- await driver.addColumn(table, column);
151
- },
152
- dropColumn: async (table, name) => {
153
- await driver.dropColumn(table, name);
154
- },
155
- renameColumn: async (table, oldName, newName) => {
156
- await driver.renameColumn(table, oldName, newName);
157
- },
158
- addIndex: async () => {},
159
- dropIndex: async () => {}
160
- },
161
- sql: async (query, params) => {
162
- return driver.execute(query, params);
163
- }
164
- });
196
+ await migration.up(ctx);
165
197
  await driver.execute(`INSERT INTO \`${MIGRATIONS_TABLE}\` (\`name\`, \`executed_at\`) VALUES (?, ?)`, [migration.name, /* @__PURE__ */ new Date()]);
166
198
  }
167
199
  }
200
+ async function rollbackMigrations(driver, registry, migrations, steps = 1) {
201
+ await ensureMigrationsTable(driver);
202
+ const executedNames = (await driver.query(`SELECT name FROM \`${MIGRATIONS_TABLE}\` ORDER BY id DESC`)).map((r) => r.name);
203
+ const ctx = createMigrationContext(driver, registry);
204
+ const migrationMap = new Map(migrations.map((m) => [m.name, m]));
205
+ const rolledBack = [];
206
+ const toRollback = executedNames.slice(0, steps);
207
+ for (const name of toRollback) {
208
+ const migration = migrationMap.get(name);
209
+ if (!migration) continue;
210
+ await migration.down(ctx);
211
+ await driver.execute(`DELETE FROM \`${MIGRATIONS_TABLE}\` WHERE \`name\` = ?`, [name]);
212
+ rolledBack.push(name);
213
+ }
214
+ return rolledBack;
215
+ }
216
+ var init_database = __esmMin((() => {
217
+ init_cache();
218
+ init_constants();
219
+ init_drivers();
220
+ init_errors();
221
+ init_schema();
222
+ init_repository();
223
+ }));
168
224
  //#endregion
169
- export { database };
225
+ init_database();
226
+ export { database, init_database };
170
227
 
171
228
  //# sourceMappingURL=database.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"database.mjs","names":[],"sources":["../../src/core/database.ts"],"sourcesContent":["import { CacheManager } from \"../cache\";\nimport { MIGRATIONS_TABLE } from \"../constants\";\nimport { createDriver } from \"../drivers\";\nimport { DatabaseError } from \"../errors\";\nimport { SchemaRegistry } from \"../schema\";\nimport type {\n AnyTableDef,\n ConnectionConfig,\n DatabaseConfig,\n DatabaseDriver,\n DeleteOptions,\n InferRow,\n InferSchemas,\n MigrationDefinition,\n QueryOptions,\n RelationQueryMap,\n ResolveResult,\n TableMetadata,\n UpdateOptions,\n WhereClause,\n} from \"../types\";\nimport { TableRepository } from \"./repository\";\n\ntype TypedTableRepository<S extends readonly AnyTableDef[], T extends AnyTableDef> = {\n /**\n * Find all rows matching the given options\n * @param options - Filter, sort, paginate, and eagerly load relations\n * @returns Array of matching rows\n */\n find<O extends QueryOptions<InferRow<T>, RelationQueryMap<S, T>> = {}>(\n options?: O,\n ): Promise<ResolveResult<S, T, O>[]>;\n\n /**\n * Find all rows matching the given options (alias for {@link find})\n * @param options - Filter, sort, paginate, and eagerly load relations\n * @returns Array of matching rows\n */\n findMany<O extends QueryOptions<InferRow<T>, RelationQueryMap<S, T>> = {}>(\n options?: O,\n ): Promise<ResolveResult<S, T, O>[]>;\n\n /**\n * Find the first row matching the given options\n * @param options - Filter, sort, and eagerly load relations\n * @returns The first matching row, or `null` if none found\n */\n findFirst<O extends QueryOptions<InferRow<T>, RelationQueryMap<S, T>> = {}>(\n options?: O,\n ): Promise<ResolveResult<S, T, O> | null>;\n\n /**\n * Insert one or more rows into the table\n * @param data - Row data (or array of row data) to insert\n * @returns The inserted row\n */\n insert(data: Partial<InferRow<T>> | Partial<InferRow<T>>[]): Promise<InferRow<T>>;\n\n /**\n * Insert multiple rows into the table\n * @param data - Array of row data to insert\n * @returns Array of inserted rows\n */\n insertMany(data: Partial<InferRow<T>>[]): Promise<InferRow<T>[]>;\n\n /**\n * Update rows matching the where clause\n * @param options - Where clause and partial data to apply\n * @returns Array of updated rows\n */\n update(options: UpdateOptions<InferRow<T>>): Promise<InferRow<T>[]>;\n\n /**\n * Delete rows matching the where clause\n * @param options - Where clause to select rows for deletion\n * @returns Number of deleted rows\n */\n delete(options: DeleteOptions<InferRow<T>>): Promise<number>;\n\n /**\n * Count rows matching the where clause\n * @param options - Optional where clause to filter rows\n * @returns Number of matching rows\n */\n count(options?: Pick<QueryOptions<InferRow<T>>, \"where\">): Promise<number>;\n\n /**\n * Check whether at least one row matches the where clause\n * @param options - Where clause to check\n * @returns `true` if a matching row exists, `false` otherwise\n */\n exists(options: Pick<QueryOptions<InferRow<T>>, \"where\">): Promise<boolean>;\n\n /**\n * Insert a row if it doesn't exist, or update it if it does\n * @param options - Where clause to check, data to create, and data to update\n * @returns The created or updated row\n */\n upsert(options: {\n where: WhereClause<InferRow<T>>;\n create: Partial<InferRow<T>>;\n update: Partial<InferRow<T>>;\n }): Promise<InferRow<T>>;\n\n /**\n * Remove all rows from the table\n * @returns Resolves when the table has been truncated\n */\n truncate(): Promise<void>;\n};\n\ntype ExtractRepos<S> = S extends readonly AnyTableDef[]\n ? { [T in S[number] as T[\"__name\"]]: TypedTableRepository<S, T> }\n : S extends Record<string, any>\n ? {\n [K in keyof S as S[K] extends AnyTableDef ? K : never]: TypedTableRepository<\n InferSchemas<S>,\n Extract<S[K], AnyTableDef>\n >;\n }\n : never;\n\ntype DatabaseInstance<S> = ExtractRepos<S> & {\n /**\n * Initialize the database connection, create tables and run migrations\n * @returns {Promise<void>}\n */\n initialize(): Promise<void>;\n /**\n * Close the database connection\n * @returns {Promise<void>}\n */\n close(): Promise<void>;\n /**\n * Get the underlying database driver\n * @returns {DatabaseDriver} The database driver\n */\n getDriver(): DatabaseDriver;\n /**\n * Get the schema registry\n * @returns {SchemaRegistry} The schema registry\n */\n getRegistry(): SchemaRegistry;\n /**\n * Get the cache manager\n * @returns {CacheManager} The cache manager\n */\n getCache(): CacheManager;\n /**\n * Execute a raw SQL query\n * @param {string} sql - SQL query\n * @param {unknown[]} [params] - Query parameters\n * @returns {Promise<any[]>} Query results\n */\n raw(sql: string, params?: unknown[]): Promise<any[]>;\n /**\n * Execute within a transaction\n * @param {() => Promise<T>} fn - Function to execute\n * @returns {Promise<T>} Result\n */\n transaction<T>(fn: () => Promise<T>): Promise<T>;\n};\n\n/**\n * Create a database instance with typed repositories for each schema\n * @param {DatabaseConfig} config - Database configuration\n * @returns {DatabaseInstance<S>} Database instance with table repositories\n */\nfunction normalizeMigrations(\n migrations: MigrationDefinition[] | Record<string, unknown>,\n): MigrationDefinition[] {\n if (Array.isArray(migrations)) {\n return migrations;\n }\n return Object.values(migrations).filter(\n (v): v is MigrationDefinition =>\n v != null && typeof v === \"object\" && \"name\" in v && \"up\" in v && \"down\" in v,\n );\n}\n\nfunction normalizeSchemas<S extends readonly AnyTableDef[]>(schemas: any): S {\n if (Array.isArray(schemas)) {\n return schemas as any as S;\n }\n return Object.values(schemas).filter(\n (v): v is AnyTableDef => v != null && typeof v === \"object\" && (v as any).__table === true,\n ) as any;\n}\n\nexport function database<const S extends readonly AnyTableDef[] | Record<string, any>>(\n config: DatabaseConfig & { schemas: S },\n): DatabaseInstance<S> {\n const schemas = normalizeSchemas(config.schemas) as any;\n const registry = new SchemaRegistry();\n registry.register(schemas);\n\n const connectionConfig = Array.isArray(config.connection)\n ? config.connection[0]\n : config.connection;\n\n if (!connectionConfig) {\n throw new DatabaseError(\"Connection config is required\");\n }\n\n const driver = createDriver(config.database, connectionConfig as ConnectionConfig);\n const cache = new CacheManager(config.cache);\n\n let initialized = false;\n let initPromise: Promise<void> | null = null;\n\n const ensureInitialized = async () => {\n if (initialized) {\n return;\n }\n if (initPromise) {\n return initPromise;\n }\n initPromise = doInit();\n await initPromise;\n initialized = true;\n };\n\n const doInit = async () => {\n await driver.connect();\n\n if (config.syncSchemas) {\n const allMetadata = driver.getAllTableColumns ? await driver.getAllTableColumns() : null;\n\n const syncPromises = Array.from(registry.getAllTables()).map(async ([, tableMeta]) => {\n const existingCols = allMetadata ? allMetadata[tableMeta.name] : null;\n const exists = allMetadata ? !!existingCols : await driver.tableExists(tableMeta.name);\n\n if (!exists) {\n await driver.createTable(tableMeta);\n } else {\n const cols = existingCols || (await driver.getTableColumns(tableMeta.name));\n const existingNames = new Set(cols.map((c) => c.name));\n const addColumnPromises = tableMeta.columns\n .filter((colMeta) => !existingNames.has(colMeta.name))\n .map((colMeta) => driver.addColumn(tableMeta.name, colMeta));\n await Promise.all(addColumnPromises);\n }\n });\n await Promise.all(syncPromises);\n }\n\n if (config.runMigrations && config.migrations) {\n const migrations = normalizeMigrations(config.migrations);\n if (migrations.length > 0) {\n await runMigrations(driver, registry, migrations);\n }\n }\n };\n\n const repos = new Map<string, TableRepository<any>>();\n for (const schema of schemas) {\n const repo = new TableRepository(schema.__name, driver, cache, registry, schema.__cache);\n repos.set(schema.__name, repo);\n }\n\n const instance: any = {\n initialize: async () => {\n await ensureInitialized();\n },\n close: async () => {\n await driver.disconnect();\n cache.clear();\n initialized = false;\n initPromise = null;\n },\n getDriver: () => driver,\n getRegistry: () => registry,\n getCache: () => cache,\n raw: async (sql: string, params?: unknown[]) => {\n await ensureInitialized();\n return driver.query(sql, params);\n },\n transaction: async <T>(fn: () => Promise<T>) => {\n await ensureInitialized();\n return driver.transaction(fn);\n },\n };\n\n for (const schema of schemas) {\n const repo = repos.get(schema.__name)!;\n const proxy = new Proxy(repo, {\n get(target, prop, receiver) {\n const original = Reflect.get(target, prop, receiver);\n if (typeof original === \"function\") {\n return async (...args: any[]) => {\n await ensureInitialized();\n return original.apply(target, args);\n };\n }\n return original;\n },\n });\n instance[schema.__name] = proxy;\n }\n\n return instance as any as DatabaseInstance<S>;\n}\n\nasync function runMigrations(\n driver: DatabaseDriver,\n registry: SchemaRegistry,\n migrations: MigrationDefinition[],\n): Promise<void> {\n const migrationsTableMeta: TableMetadata = {\n name: MIGRATIONS_TABLE,\n columns: [\n {\n name: \"id\",\n type: \"integer\",\n primaryKey: true,\n autoIncrement: true,\n notNull: true,\n unique: true,\n defaultValue: undefined,\n },\n {\n name: \"name\",\n type: \"varchar\",\n primaryKey: false,\n autoIncrement: false,\n notNull: true,\n unique: true,\n defaultValue: undefined,\n length: 255,\n },\n {\n name: \"executed_at\",\n type: \"datetime\",\n primaryKey: false,\n autoIncrement: false,\n notNull: true,\n unique: false,\n defaultValue: undefined,\n },\n ],\n };\n\n const exists = await driver.tableExists(MIGRATIONS_TABLE);\n if (!exists) {\n await driver.createTable(migrationsTableMeta);\n }\n\n const executed = await driver.query(`SELECT name FROM \\`${MIGRATIONS_TABLE}\\``);\n const executedNames = new Set(executed.map((r: any) => r.name));\n\n for (const migration of migrations) {\n if (executedNames.has(migration.name)) {\n continue;\n }\n\n const ctx = {\n schema: {\n createTable: async (tableDef: AnyTableDef) => {\n const meta = registry.getTable(tableDef.__name);\n if (meta) {\n await driver.createTable(meta);\n }\n },\n dropTable: async (name: string) => {\n await driver.dropTable(name);\n },\n addColumn: async (table: string, _name: string, column: any) => {\n await driver.addColumn(table, column);\n },\n dropColumn: async (table: string, name: string) => {\n await driver.dropColumn(table, name);\n },\n renameColumn: async (table: string, oldName: string, newName: string) => {\n await driver.renameColumn(table, oldName, newName);\n },\n addIndex: async () => {},\n dropIndex: async () => {},\n },\n sql: async (query: string, params?: unknown[]) => {\n return driver.execute(query, params);\n },\n };\n\n await migration.up(ctx);\n\n await driver.execute(\n `INSERT INTO \\`${MIGRATIONS_TABLE}\\` (\\`name\\`, \\`executed_at\\`) VALUES (?, ?)`,\n [migration.name, new Date()],\n );\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"database.mjs","names":[],"sources":["../../src/core/database.ts"],"sourcesContent":["import { CacheManager } from \"../cache\";\nimport { MIGRATIONS_TABLE } from \"../constants\";\nimport { createDriver } from \"../drivers\";\nimport { DatabaseError } from \"../errors\";\nimport { SchemaRegistry } from \"../schema\";\nimport type {\n AnyTableDef,\n ConnectionConfig,\n DatabaseConfig,\n DatabaseDriver,\n DeleteOptions,\n InferRow,\n InferSchemas,\n MigrationDefinition,\n QueryOptions,\n RelationQueryMap,\n ResolveResult,\n TableMetadata,\n UpdateOptions,\n WhereClause,\n} from \"../types\";\nimport { TableRepository } from \"./repository\";\n\ntype TypedTableRepository<S extends readonly AnyTableDef[], T extends AnyTableDef> = {\n /**\n * Find all rows matching the given options\n * @param options - Filter, sort, paginate, and eagerly load relations\n * @returns Array of matching rows\n */\n find<O extends QueryOptions<InferRow<T>, RelationQueryMap<S, T>> = {}>(\n options?: O,\n ): Promise<ResolveResult<S, T, O>[]>;\n\n /**\n * Find all rows matching the given options (alias for {@link find})\n * @param options - Filter, sort, paginate, and eagerly load relations\n * @returns Array of matching rows\n */\n findMany<O extends QueryOptions<InferRow<T>, RelationQueryMap<S, T>> = {}>(\n options?: O,\n ): Promise<ResolveResult<S, T, O>[]>;\n\n /**\n * Find the first row matching the given options\n * @param options - Filter, sort, and eagerly load relations\n * @returns The first matching row, or `null` if none found\n */\n findFirst<O extends QueryOptions<InferRow<T>, RelationQueryMap<S, T>> = {}>(\n options?: O,\n ): Promise<ResolveResult<S, T, O> | null>;\n\n /**\n * Insert one or more rows into the table\n * @param data - Row data (or array of row data) to insert\n * @returns The inserted row\n */\n insert(data: Partial<InferRow<T>> | Partial<InferRow<T>>[]): Promise<InferRow<T>>;\n\n /**\n * Insert multiple rows into the table\n * @param data - Array of row data to insert\n * @returns Array of inserted rows\n */\n insertMany(data: Partial<InferRow<T>>[]): Promise<InferRow<T>[]>;\n\n /**\n * Update rows matching the where clause\n * @param options - Where clause and partial data to apply\n * @returns Array of updated rows\n */\n update(options: UpdateOptions<InferRow<T>>): Promise<InferRow<T>[]>;\n\n /**\n * Delete rows matching the where clause\n * @param options - Where clause to select rows for deletion\n * @returns Number of deleted rows\n */\n delete(options: DeleteOptions<InferRow<T>>): Promise<number>;\n\n /**\n * Count rows matching the where clause\n * @param options - Optional where clause to filter rows\n * @returns Number of matching rows\n */\n count(options?: Pick<QueryOptions<InferRow<T>>, \"where\">): Promise<number>;\n\n /**\n * Check whether at least one row matches the where clause\n * @param options - Where clause to check\n * @returns `true` if a matching row exists, `false` otherwise\n */\n exists(options: Pick<QueryOptions<InferRow<T>>, \"where\">): Promise<boolean>;\n\n /**\n * Insert a row if it doesn't exist, or update it if it does\n * @param options - Where clause to check, data to create, and data to update\n * @returns The created or updated row\n */\n upsert(options: {\n where: WhereClause<InferRow<T>>;\n create: Partial<InferRow<T>>;\n update: Partial<InferRow<T>>;\n }): Promise<InferRow<T>>;\n\n /**\n * Remove all rows from the table\n * @returns Resolves when the table has been truncated\n */\n truncate(): Promise<void>;\n};\n\ntype ExtractRepos<S> = S extends readonly AnyTableDef[]\n ? { [T in S[number] as T[\"__name\"]]: TypedTableRepository<S, T> }\n : S extends Record<string, any>\n ? {\n [K in keyof S as S[K] extends AnyTableDef ? K : never]: TypedTableRepository<\n InferSchemas<S>,\n Extract<S[K], AnyTableDef>\n >;\n }\n : never;\n\ntype DatabaseInstance<S> = ExtractRepos<S> & {\n /**\n * Initialize the database connection, create tables and run migrations\n * @returns {Promise<void>}\n */\n initialize(): Promise<void>;\n /**\n * Close the database connection\n * @returns {Promise<void>}\n */\n close(): Promise<void>;\n /**\n * Get the underlying database driver\n * @returns {DatabaseDriver} The database driver\n */\n getDriver(): DatabaseDriver;\n /**\n * Get the schema registry\n * @returns {SchemaRegistry} The schema registry\n */\n getRegistry(): SchemaRegistry;\n /**\n * Get the cache manager\n * @returns {CacheManager} The cache manager\n */\n getCache(): CacheManager;\n /**\n * Execute a raw SQL query\n * @param {string} sql - SQL query\n * @param {unknown[]} [params] - Query parameters\n * @returns {Promise<any[]>} Query results\n */\n raw(sql: string, params?: unknown[]): Promise<any[]>;\n /**\n * Execute within a transaction\n * @param {() => Promise<T>} fn - Function to execute\n * @returns {Promise<T>} Result\n */\n transaction<T>(fn: () => Promise<T>): Promise<T>;\n /**\n * Run pending migrations manually\n * @returns {Promise<void>}\n */\n migrateUp(): Promise<void>;\n /**\n * Rollback migrations\n * @param {number} [steps=1] - Number of migrations to rollback\n * @returns {Promise<string[]>} Names of rolled back migrations\n */\n migrateDown(steps?: number): Promise<string[]>;\n};\n\n/**\n * Create a database instance with typed repositories for each schema\n * @param {DatabaseConfig} config - Database configuration\n * @returns {DatabaseInstance<S>} Database instance with table repositories\n */\nfunction normalizeMigrations(\n migrations: MigrationDefinition[] | Record<string, unknown>,\n): MigrationDefinition[] {\n if (Array.isArray(migrations)) {\n return migrations;\n }\n return Object.values(migrations).filter(\n (v): v is MigrationDefinition =>\n v != null && typeof v === \"object\" && \"name\" in v && \"up\" in v && \"down\" in v,\n );\n}\n\nfunction normalizeSchemas<S extends readonly AnyTableDef[]>(schemas: any): S {\n if (Array.isArray(schemas)) {\n return schemas as any as S;\n }\n return Object.values(schemas).filter(\n (v): v is AnyTableDef => v != null && typeof v === \"object\" && (v as any).__table === true,\n ) as any;\n}\n\nexport function database<const S extends readonly AnyTableDef[] | Record<string, any>>(\n config: DatabaseConfig & { schemas: S },\n): DatabaseInstance<S> {\n const schemas = normalizeSchemas(config.schemas) as any;\n const registry = new SchemaRegistry();\n registry.register(schemas);\n\n const dbName = typeof config.database === \"string\" ? config.database : config.database.name;\n\n let connectionConfig: ConnectionConfig | undefined;\n if (Array.isArray(config.connection)) {\n if (dbName === \"sqlite\") {\n connectionConfig = config.connection.find((c) => \"filename\" in c) ?? config.connection[0];\n } else if (dbName === \"mysql\" || dbName === \"mariadb\") {\n connectionConfig = config.connection.find((c) => \"host\" in c) ?? config.connection[0];\n } else if (dbName === \"file\") {\n connectionConfig = config.connection.find((c) => \"directory\" in c) ?? config.connection[0];\n } else {\n connectionConfig = config.connection[0];\n }\n } else {\n connectionConfig = config.connection;\n }\n\n if (!connectionConfig) {\n throw new DatabaseError(\"Connection config is required\");\n }\n\n const driver = createDriver(config.database, connectionConfig as ConnectionConfig);\n const cache = new CacheManager(config.cache);\n\n let initialized = false;\n let initPromise: Promise<void> | null = null;\n\n const ensureInitialized = async () => {\n if (initialized) {\n return;\n }\n if (initPromise) {\n return initPromise;\n }\n initPromise = doInit();\n await initPromise;\n initialized = true;\n };\n\n const doInit = async () => {\n await driver.connect();\n\n if (config.syncSchemas) {\n const allMetadata = driver.getAllTableColumns ? await driver.getAllTableColumns() : null;\n\n const syncPromises = Array.from(registry.getAllTables()).map(async ([, tableMeta]) => {\n const existingCols = allMetadata ? allMetadata[tableMeta.name] : null;\n const exists = allMetadata ? !!existingCols : await driver.tableExists(tableMeta.name);\n\n if (!exists) {\n await driver.createTable(tableMeta);\n } else {\n const cols = existingCols || (await driver.getTableColumns(tableMeta.name));\n const existingNames = new Set(cols.map((c) => c.name));\n const addColumnPromises = tableMeta.columns\n .filter((colMeta) => !existingNames.has(colMeta.name))\n .map((colMeta) => driver.addColumn(tableMeta.name, colMeta));\n await Promise.all(addColumnPromises);\n }\n });\n await Promise.all(syncPromises);\n }\n\n if (config.runMigrations && config.migrations) {\n const migrations = normalizeMigrations(config.migrations);\n if (migrations.length > 0) {\n await runMigrations(driver, registry, migrations);\n }\n }\n };\n\n const repos = new Map<string, TableRepository<any>>();\n for (const schema of schemas) {\n const repo = new TableRepository(schema.__name, driver, cache, registry, schema.__cache);\n repos.set(schema.__name, repo);\n }\n\n const instance: any = {\n initialize: async () => {\n await ensureInitialized();\n },\n close: async () => {\n await driver.disconnect();\n cache.clear();\n initialized = false;\n initPromise = null;\n },\n getDriver: () => driver,\n getRegistry: () => registry,\n getCache: () => cache,\n raw: async (sql: string, params?: unknown[]) => {\n await ensureInitialized();\n return driver.query(sql, params);\n },\n transaction: async <T>(fn: () => Promise<T>) => {\n await ensureInitialized();\n return driver.transaction(fn);\n },\n migrateUp: async () => {\n await ensureInitialized();\n if (config.migrations) {\n const migrations = normalizeMigrations(config.migrations);\n if (migrations.length > 0) {\n await runMigrations(driver, registry, migrations);\n }\n }\n },\n migrateDown: async (steps = 1) => {\n await ensureInitialized();\n if (config.migrations) {\n const migrations = normalizeMigrations(config.migrations);\n return rollbackMigrations(driver, registry, migrations, steps);\n }\n return [];\n },\n };\n\n for (const schema of schemas) {\n const repo = repos.get(schema.__name)!;\n const proxy = new Proxy(repo, {\n get(target, prop, receiver) {\n const original = Reflect.get(target, prop, receiver);\n if (typeof original === \"function\") {\n return async (...args: any[]) => {\n await ensureInitialized();\n return original.apply(target, args);\n };\n }\n return original;\n },\n });\n instance[schema.__name] = proxy;\n }\n\n return instance as any as DatabaseInstance<S>;\n}\n\nfunction getMigrationsTableMeta(): TableMetadata {\n return {\n name: MIGRATIONS_TABLE,\n columns: [\n {\n name: \"id\",\n type: \"integer\",\n primaryKey: true,\n autoIncrement: true,\n notNull: true,\n unique: true,\n defaultValue: undefined,\n },\n {\n name: \"name\",\n type: \"varchar\",\n primaryKey: false,\n autoIncrement: false,\n notNull: true,\n unique: true,\n defaultValue: undefined,\n length: 255,\n },\n {\n name: \"executed_at\",\n type: \"datetime\",\n primaryKey: false,\n autoIncrement: false,\n notNull: true,\n unique: false,\n defaultValue: undefined,\n },\n ],\n };\n}\n\nfunction createMigrationContext(\n driver: DatabaseDriver,\n registry: SchemaRegistry,\n): MigrationDefinition[\"up\"] extends (ctx: infer C) => any ? C : never {\n return {\n schema: {\n createTable: async (tableDef: AnyTableDef) => {\n const meta = registry.getTable(tableDef.__name) ?? {\n name: tableDef.__name,\n columns: [...tableDef.__columns],\n };\n await driver.createTable(meta);\n },\n dropTable: async (name: string) => {\n await driver.dropTable(name);\n },\n addColumn: async (table: string, _name: string, column: any) => {\n await driver.addColumn(table, column);\n },\n dropColumn: async (table: string, name: string) => {\n await driver.dropColumn(table, name);\n },\n renameColumn: async (table: string, oldName: string, newName: string) => {\n await driver.renameColumn(table, oldName, newName);\n },\n addIndex: async () => {},\n dropIndex: async () => {},\n },\n sql: async (query: string, params?: unknown[]) => {\n return driver.execute(query, params);\n },\n };\n}\n\nasync function ensureMigrationsTable(driver: DatabaseDriver): Promise<void> {\n const exists = await driver.tableExists(MIGRATIONS_TABLE);\n if (!exists) {\n await driver.createTable(getMigrationsTableMeta());\n }\n}\n\nasync function runMigrations(\n driver: DatabaseDriver,\n registry: SchemaRegistry,\n migrations: MigrationDefinition[],\n): Promise<void> {\n await ensureMigrationsTable(driver);\n\n const executed = await driver.query(`SELECT name FROM \\`${MIGRATIONS_TABLE}\\``);\n const executedNames = new Set(executed.map((r: any) => r.name));\n\n const ctx = createMigrationContext(driver, registry);\n\n for (const migration of migrations) {\n if (executedNames.has(migration.name)) {\n continue;\n }\n\n await migration.up(ctx);\n\n await driver.execute(\n `INSERT INTO \\`${MIGRATIONS_TABLE}\\` (\\`name\\`, \\`executed_at\\`) VALUES (?, ?)`,\n [migration.name, new Date()],\n );\n }\n}\n\nasync function rollbackMigrations(\n driver: DatabaseDriver,\n registry: SchemaRegistry,\n migrations: MigrationDefinition[],\n steps = 1,\n): Promise<string[]> {\n await ensureMigrationsTable(driver);\n\n const executed = await driver.query(`SELECT name FROM \\`${MIGRATIONS_TABLE}\\` ORDER BY id DESC`);\n const executedNames = executed.map((r: any) => r.name as string);\n\n const ctx = createMigrationContext(driver, registry);\n const migrationMap = new Map(migrations.map((m) => [m.name, m]));\n const rolledBack: string[] = [];\n\n const toRollback = executedNames.slice(0, steps);\n\n for (const name of toRollback) {\n const migration = migrationMap.get(name);\n if (!migration) {\n continue;\n }\n\n await migration.down(ctx);\n\n await driver.execute(`DELETE FROM \\`${MIGRATIONS_TABLE}\\` WHERE \\`name\\` = ?`, [name]);\n rolledBack.push(name);\n }\n\n return rolledBack;\n}\n"],"mappings":";;;;;;;;;;;;;;;AAmLA,SAAS,oBACP,YACuB;AACvB,KAAI,MAAM,QAAQ,WAAW,CAC3B,QAAO;AAET,QAAO,OAAO,OAAO,WAAW,CAAC,QAC9B,MACC,KAAK,QAAQ,OAAO,MAAM,YAAY,UAAU,KAAK,QAAQ,KAAK,UAAU,EAC/E;;AAGH,SAAS,iBAAmD,SAAiB;AAC3E,KAAI,MAAM,QAAQ,QAAQ,CACxB,QAAO;AAET,QAAO,OAAO,OAAO,QAAQ,CAAC,QAC3B,MAAwB,KAAK,QAAQ,OAAO,MAAM,YAAa,EAAU,YAAY,KACvF;;AAGH,SAAgB,SACd,QACqB;CACrB,MAAM,UAAU,iBAAiB,OAAO,QAAQ;CAChD,MAAM,WAAW,IAAI,gBAAgB;AACrC,UAAS,SAAS,QAAQ;CAE1B,MAAM,SAAS,OAAO,OAAO,aAAa,WAAW,OAAO,WAAW,OAAO,SAAS;CAEvF,IAAI;AACJ,KAAI,MAAM,QAAQ,OAAO,WAAW,CAClC,KAAI,WAAW,SACb,oBAAmB,OAAO,WAAW,MAAM,MAAM,cAAc,EAAE,IAAI,OAAO,WAAW;UAC9E,WAAW,WAAW,WAAW,UAC1C,oBAAmB,OAAO,WAAW,MAAM,MAAM,UAAU,EAAE,IAAI,OAAO,WAAW;UAC1E,WAAW,OACpB,oBAAmB,OAAO,WAAW,MAAM,MAAM,eAAe,EAAE,IAAI,OAAO,WAAW;KAExF,oBAAmB,OAAO,WAAW;KAGvC,oBAAmB,OAAO;AAG5B,KAAI,CAAC,iBACH,OAAM,IAAI,cAAc,gCAAgC;CAG1D,MAAM,SAAS,aAAa,OAAO,UAAU,iBAAqC;CAClF,MAAM,QAAQ,IAAI,aAAa,OAAO,MAAM;CAE5C,IAAI,cAAc;CAClB,IAAI,cAAoC;CAExC,MAAM,oBAAoB,YAAY;AACpC,MAAI,YACF;AAEF,MAAI,YACF,QAAO;AAET,gBAAc,QAAQ;AACtB,QAAM;AACN,gBAAc;;CAGhB,MAAM,SAAS,YAAY;AACzB,QAAM,OAAO,SAAS;AAEtB,MAAI,OAAO,aAAa;GACtB,MAAM,cAAc,OAAO,qBAAqB,MAAM,OAAO,oBAAoB,GAAG;GAEpF,MAAM,eAAe,MAAM,KAAK,SAAS,cAAc,CAAC,CAAC,IAAI,OAAO,GAAG,eAAe;IACpF,MAAM,eAAe,cAAc,YAAY,UAAU,QAAQ;AAGjE,QAAI,EAFW,cAAc,CAAC,CAAC,eAAe,MAAM,OAAO,YAAY,UAAU,KAAK,EAGpF,OAAM,OAAO,YAAY,UAAU;SAC9B;KACL,MAAM,OAAO,gBAAiB,MAAM,OAAO,gBAAgB,UAAU,KAAK;KAC1E,MAAM,gBAAgB,IAAI,IAAI,KAAK,KAAK,MAAM,EAAE,KAAK,CAAC;KACtD,MAAM,oBAAoB,UAAU,QACjC,QAAQ,YAAY,CAAC,cAAc,IAAI,QAAQ,KAAK,CAAC,CACrD,KAAK,YAAY,OAAO,UAAU,UAAU,MAAM,QAAQ,CAAC;AAC9D,WAAM,QAAQ,IAAI,kBAAkB;;KAEtC;AACF,SAAM,QAAQ,IAAI,aAAa;;AAGjC,MAAI,OAAO,iBAAiB,OAAO,YAAY;GAC7C,MAAM,aAAa,oBAAoB,OAAO,WAAW;AACzD,OAAI,WAAW,SAAS,EACtB,OAAM,cAAc,QAAQ,UAAU,WAAW;;;CAKvD,MAAM,wBAAQ,IAAI,KAAmC;AACrD,MAAK,MAAM,UAAU,SAAS;EAC5B,MAAM,OAAO,IAAI,gBAAgB,OAAO,QAAQ,QAAQ,OAAO,UAAU,OAAO,QAAQ;AACxF,QAAM,IAAI,OAAO,QAAQ,KAAK;;CAGhC,MAAM,WAAgB;EACpB,YAAY,YAAY;AACtB,SAAM,mBAAmB;;EAE3B,OAAO,YAAY;AACjB,SAAM,OAAO,YAAY;AACzB,SAAM,OAAO;AACb,iBAAc;AACd,iBAAc;;EAEhB,iBAAiB;EACjB,mBAAmB;EACnB,gBAAgB;EAChB,KAAK,OAAO,KAAa,WAAuB;AAC9C,SAAM,mBAAmB;AACzB,UAAO,OAAO,MAAM,KAAK,OAAO;;EAElC,aAAa,OAAU,OAAyB;AAC9C,SAAM,mBAAmB;AACzB,UAAO,OAAO,YAAY,GAAG;;EAE/B,WAAW,YAAY;AACrB,SAAM,mBAAmB;AACzB,OAAI,OAAO,YAAY;IACrB,MAAM,aAAa,oBAAoB,OAAO,WAAW;AACzD,QAAI,WAAW,SAAS,EACtB,OAAM,cAAc,QAAQ,UAAU,WAAW;;;EAIvD,aAAa,OAAO,QAAQ,MAAM;AAChC,SAAM,mBAAmB;AACzB,OAAI,OAAO,WAET,QAAO,mBAAmB,QAAQ,UADf,oBAAoB,OAAO,WAAW,EACD,MAAM;AAEhE,UAAO,EAAE;;EAEZ;AAED,MAAK,MAAM,UAAU,SAAS;EAC5B,MAAM,OAAO,MAAM,IAAI,OAAO,OAAO;EACrC,MAAM,QAAQ,IAAI,MAAM,MAAM,EAC5B,IAAI,QAAQ,MAAM,UAAU;GAC1B,MAAM,WAAW,QAAQ,IAAI,QAAQ,MAAM,SAAS;AACpD,OAAI,OAAO,aAAa,WACtB,QAAO,OAAO,GAAG,SAAgB;AAC/B,UAAM,mBAAmB;AACzB,WAAO,SAAS,MAAM,QAAQ,KAAK;;AAGvC,UAAO;KAEV,CAAC;AACF,WAAS,OAAO,UAAU;;AAG5B,QAAO;;AAGT,SAAS,yBAAwC;AAC/C,QAAO;EACL,MAAM;EACN,SAAS;GACP;IACE,MAAM;IACN,MAAM;IACN,YAAY;IACZ,eAAe;IACf,SAAS;IACT,QAAQ;IACR,cAAc,KAAA;IACf;GACD;IACE,MAAM;IACN,MAAM;IACN,YAAY;IACZ,eAAe;IACf,SAAS;IACT,QAAQ;IACR,cAAc,KAAA;IACd,QAAQ;IACT;GACD;IACE,MAAM;IACN,MAAM;IACN,YAAY;IACZ,eAAe;IACf,SAAS;IACT,QAAQ;IACR,cAAc,KAAA;IACf;GACF;EACF;;AAGH,SAAS,uBACP,QACA,UACqE;AACrE,QAAO;EACL,QAAQ;GACN,aAAa,OAAO,aAA0B;IAC5C,MAAM,OAAO,SAAS,SAAS,SAAS,OAAO,IAAI;KACjD,MAAM,SAAS;KACf,SAAS,CAAC,GAAG,SAAS,UAAU;KACjC;AACD,UAAM,OAAO,YAAY,KAAK;;GAEhC,WAAW,OAAO,SAAiB;AACjC,UAAM,OAAO,UAAU,KAAK;;GAE9B,WAAW,OAAO,OAAe,OAAe,WAAgB;AAC9D,UAAM,OAAO,UAAU,OAAO,OAAO;;GAEvC,YAAY,OAAO,OAAe,SAAiB;AACjD,UAAM,OAAO,WAAW,OAAO,KAAK;;GAEtC,cAAc,OAAO,OAAe,SAAiB,YAAoB;AACvE,UAAM,OAAO,aAAa,OAAO,SAAS,QAAQ;;GAEpD,UAAU,YAAY;GACtB,WAAW,YAAY;GACxB;EACD,KAAK,OAAO,OAAe,WAAuB;AAChD,UAAO,OAAO,QAAQ,OAAO,OAAO;;EAEvC;;AAGH,eAAe,sBAAsB,QAAuC;AAE1E,KAAI,CADW,MAAM,OAAO,YAAA,wBAA6B,CAEvD,OAAM,OAAO,YAAY,wBAAwB,CAAC;;AAItD,eAAe,cACb,QACA,UACA,YACe;AACf,OAAM,sBAAsB,OAAO;CAEnC,MAAM,WAAW,MAAM,OAAO,MAAM,sBAAsB,iBAAiB,IAAI;CAC/E,MAAM,gBAAgB,IAAI,IAAI,SAAS,KAAK,MAAW,EAAE,KAAK,CAAC;CAE/D,MAAM,MAAM,uBAAuB,QAAQ,SAAS;AAEpD,MAAK,MAAM,aAAa,YAAY;AAClC,MAAI,cAAc,IAAI,UAAU,KAAK,CACnC;AAGF,QAAM,UAAU,GAAG,IAAI;AAEvB,QAAM,OAAO,QACX,iBAAiB,iBAAiB,+CAClC,CAAC,UAAU,sBAAM,IAAI,MAAM,CAAC,CAC7B;;;AAIL,eAAe,mBACb,QACA,UACA,YACA,QAAQ,GACW;AACnB,OAAM,sBAAsB,OAAO;CAGnC,MAAM,iBADW,MAAM,OAAO,MAAM,sBAAsB,iBAAiB,qBAAqB,EACjE,KAAK,MAAW,EAAE,KAAe;CAEhE,MAAM,MAAM,uBAAuB,QAAQ,SAAS;CACpD,MAAM,eAAe,IAAI,IAAI,WAAW,KAAK,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;CAChE,MAAM,aAAuB,EAAE;CAE/B,MAAM,aAAa,cAAc,MAAM,GAAG,MAAM;AAEhD,MAAK,MAAM,QAAQ,YAAY;EAC7B,MAAM,YAAY,aAAa,IAAI,KAAK;AACxC,MAAI,CAAC,UACH;AAGF,QAAM,UAAU,KAAK,IAAI;AAEzB,QAAM,OAAO,QAAQ,iBAAiB,iBAAiB,wBAAwB,CAAC,KAAK,CAAC;AACtF,aAAW,KAAK,KAAK;;AAGvB,QAAO;;;aA5d+B;iBACQ;eACN;cACA;cACC;kBAiBI"}