@hedystia/db 2.0.8 → 2.0.9
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/core/database.cjs
CHANGED
|
@@ -18,7 +18,14 @@ function normalizeSchemas(schemas) {
|
|
|
18
18
|
if (Array.isArray(schemas)) return schemas;
|
|
19
19
|
return Object.values(schemas).filter((v) => v != null && typeof v === "object" && v.__table === true);
|
|
20
20
|
}
|
|
21
|
+
function buildSchemaKeyMap(rawSchemas) {
|
|
22
|
+
const map = /* @__PURE__ */ new Map();
|
|
23
|
+
if (Array.isArray(rawSchemas)) return map;
|
|
24
|
+
for (const [key, value] of Object.entries(rawSchemas)) if (value != null && typeof value === "object" && value.__table === true) map.set(value.__name, key);
|
|
25
|
+
return map;
|
|
26
|
+
}
|
|
21
27
|
function database(config) {
|
|
28
|
+
const schemaKeyMap = buildSchemaKeyMap(config.schemas);
|
|
22
29
|
const schemas = normalizeSchemas(config.schemas);
|
|
23
30
|
const registry = new require_registry.SchemaRegistry();
|
|
24
31
|
registry.register(schemas);
|
|
@@ -111,7 +118,8 @@ function database(config) {
|
|
|
111
118
|
};
|
|
112
119
|
return original;
|
|
113
120
|
} });
|
|
114
|
-
|
|
121
|
+
const accessorKey = schemaKeyMap.get(schema.__name) ?? schema.__name;
|
|
122
|
+
instance[accessorKey] = proxy;
|
|
115
123
|
}
|
|
116
124
|
return instance;
|
|
117
125
|
}
|
|
@@ -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 * 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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"}
|
|
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\nfunction buildSchemaKeyMap(rawSchemas: any): Map<string, string> {\n const map = new Map<string, string>();\n if (Array.isArray(rawSchemas)) {\n return map;\n }\n for (const [key, value] of Object.entries(rawSchemas)) {\n if (value != null && typeof value === \"object\" && (value as any).__table === true) {\n map.set((value as any).__name, key);\n }\n }\n return map;\n}\n\nexport function database<const S extends readonly AnyTableDef[] | Record<string, any>>(\n config: DatabaseConfig & { schemas: S },\n): DatabaseInstance<S> {\n const schemaKeyMap = buildSchemaKeyMap(config.schemas);\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 const accessorKey = schemaKeyMap.get(schema.__name) ?? schema.__name;\n instance[accessorKey] = 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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"}
|
package/dist/core/database.mjs
CHANGED
|
@@ -21,7 +21,14 @@ function normalizeSchemas(schemas) {
|
|
|
21
21
|
if (Array.isArray(schemas)) return schemas;
|
|
22
22
|
return Object.values(schemas).filter((v) => v != null && typeof v === "object" && v.__table === true);
|
|
23
23
|
}
|
|
24
|
+
function buildSchemaKeyMap(rawSchemas) {
|
|
25
|
+
const map = /* @__PURE__ */ new Map();
|
|
26
|
+
if (Array.isArray(rawSchemas)) return map;
|
|
27
|
+
for (const [key, value] of Object.entries(rawSchemas)) if (value != null && typeof value === "object" && value.__table === true) map.set(value.__name, key);
|
|
28
|
+
return map;
|
|
29
|
+
}
|
|
24
30
|
function database(config) {
|
|
31
|
+
const schemaKeyMap = buildSchemaKeyMap(config.schemas);
|
|
25
32
|
const schemas = normalizeSchemas(config.schemas);
|
|
26
33
|
const registry = new SchemaRegistry();
|
|
27
34
|
registry.register(schemas);
|
|
@@ -114,7 +121,8 @@ function database(config) {
|
|
|
114
121
|
};
|
|
115
122
|
return original;
|
|
116
123
|
} });
|
|
117
|
-
|
|
124
|
+
const accessorKey = schemaKeyMap.get(schema.__name) ?? schema.__name;
|
|
125
|
+
instance[accessorKey] = proxy;
|
|
118
126
|
}
|
|
119
127
|
return instance;
|
|
120
128
|
}
|
|
@@ -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 * 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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"}
|
|
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\nfunction buildSchemaKeyMap(rawSchemas: any): Map<string, string> {\n const map = new Map<string, string>();\n if (Array.isArray(rawSchemas)) {\n return map;\n }\n for (const [key, value] of Object.entries(rawSchemas)) {\n if (value != null && typeof value === \"object\" && (value as any).__table === true) {\n map.set((value as any).__name, key);\n }\n }\n return map;\n}\n\nexport function database<const S extends readonly AnyTableDef[] | Record<string, any>>(\n config: DatabaseConfig & { schemas: S },\n): DatabaseInstance<S> {\n const schemaKeyMap = buildSchemaKeyMap(config.schemas);\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 const accessorKey = schemaKeyMap.get(schema.__name) ?? schema.__name;\n instance[accessorKey] = 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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"}
|