/** * Universal Database Adapter Layer (UDA-Layer) * Provides a unified interface for any database system */ export type DatabaseDriver = | "sqlite" | "postgres" | "turso" | "cockroachdb" | "mysql" | "mariadb" | "mongodb" | "redis" | "firestore" | "dynamodb" | "neo4j" | "cassandra" | "scylladb" | "surrealdb" | "custom"; export interface DatabaseConfig { driver: DatabaseDriver; url: string; authToken?: string; user?: string; password?: string; database?: string; host?: string; port?: number; ssl?: boolean; poolSize?: number; options?: Record; } export interface QueryResult { rows: T[]; rowCount: number; lastInsertId?: string | number; affectedRows?: number; } export interface WhereClause { field: string; operator: | "=" | "!=" | ">" | "<" | ">=" | "<=" | "in" | "not in" | "like" | "ilike" | "is null" | "is not null" | "eq" | "ne" | "lt" | "lte" | "gt" | "gte" | "isNull" | "isNotNull"; value: unknown; } export interface OrderByClause { field: string; direction: "asc" | "desc"; } export interface QueryOptions { where?: WhereClause[]; orderBy?: OrderByClause[]; limit?: number; offset?: number; select?: string[]; include?: string[]; } export interface DatabaseAdapter { // Connection management connect(): Promise; disconnect(): Promise; isConnected(): boolean; // CRUD operations findOne(table: string, options?: QueryOptions): Promise; findMany(table: string, options?: QueryOptions): Promise; findById(table: string, id: string | number): Promise; create(table: string, data: Partial): Promise; createMany(table: string, data: Partial[]): Promise; update( table: string, id: string | number, data: Partial, ): Promise; updateMany( table: string, options: QueryOptions, data: Partial, ): Promise; delete(table: string, id: string | number): Promise; deleteMany(table: string, options?: QueryOptions): Promise; // Advanced queries count(table: string, options?: QueryOptions): Promise; exists(table: string, options?: QueryOptions): Promise; // Raw queries (for complex operations) rawQuery(query: string, params?: unknown[]): Promise>; // Transaction support beginTransaction(): Promise; commitTransaction(): Promise; rollbackTransaction(): Promise; transaction(fn: () => Promise): Promise; // Schema management tableExists(table: string): Promise; createTable(table: string, schema: TableSchema): Promise; dropTable(table: string): Promise; alterTable(table: string, changes: TableAlterCommand[]): Promise; // Migrations runMigration(migration: Migration): Promise; getMigrationStatus(): Promise; } export interface TableSchema { columns: ColumnDefinition[]; primaryKey?: string | string[]; indexes?: IndexDefinition[]; foreignKeys?: ForeignKeyDefinition[]; } export interface ColumnDefinition { name: string; type: ColumnType; nullable?: boolean; defaultValue?: unknown; unique?: boolean; autoIncrement?: boolean; references?: { table: string; column: string; }; } export type ColumnType = | "string" | "text" | "integer" | "bigint" | "float" | "decimal" | "boolean" | "date" | "datetime" | "timestamp" | "json" | "blob" | "uuid"; export interface IndexDefinition { name: string; columns: string[]; unique?: boolean; } export interface ForeignKeyDefinition { columns: string[]; references: { table: string; columns: string[]; }; onDelete?: "cascade" | "set null" | "restrict" | "no action"; onUpdate?: "cascade" | "set null" | "restrict" | "no action"; } export interface TableAlterCommand { type: | "add_column" | "drop_column" | "modify_column" | "add_index" | "drop_index"; column?: ColumnDefinition; columnName?: string; index?: IndexDefinition; indexName?: string; } export interface Migration { id: string; name: string; timestamp: number; up: (adapter: DatabaseAdapter) => Promise; down: (adapter: DatabaseAdapter) => Promise; } export interface MigrationStatus { id: string; name: string; executedAt: Date | null; status: "pending" | "executed" | "failed"; } // Abstract base class with common functionality export abstract class BaseDatabaseAdapter implements DatabaseAdapter { protected config: DatabaseConfig; protected connected: boolean = false; constructor(config: DatabaseConfig) { this.config = config; } abstract connect(): Promise; abstract disconnect(): Promise; isConnected(): boolean { return this.connected; } abstract findOne(table: string, options?: QueryOptions): Promise; abstract findMany(table: string, options?: QueryOptions): Promise; async findById(table: string, id: string | number): Promise { return this.findOne(table, { where: [{ field: "id", operator: "=", value: id }], }); } abstract create(table: string, data: Partial): Promise; abstract createMany(table: string, data: Partial[]): Promise; abstract update( table: string, id: string | number, data: Partial, ): Promise; abstract updateMany( table: string, options: QueryOptions, data: Partial, ): Promise; abstract delete(table: string, id: string | number): Promise; abstract deleteMany(table: string, options?: QueryOptions): Promise; abstract count(table: string, options?: QueryOptions): Promise; async exists(table: string, options?: QueryOptions): Promise { const count = await this.count(table, options); return count > 0; } abstract rawQuery( query: string, params?: unknown[], ): Promise>; abstract beginTransaction(): Promise; abstract commitTransaction(): Promise; abstract rollbackTransaction(): Promise; async transaction(fn: () => Promise): Promise { await this.beginTransaction(); try { const result = await fn(); await this.commitTransaction(); return result; } catch (error) { await this.rollbackTransaction(); throw error; } } abstract tableExists(table: string): Promise; abstract createTable(table: string, schema: TableSchema): Promise; abstract dropTable(table: string): Promise; abstract alterTable( table: string, changes: TableAlterCommand[], ): Promise; abstract runMigration(migration: Migration): Promise; abstract getMigrationStatus(): Promise; // Helper method to build where clause conditions protected buildWhereConditions(where: WhereClause[]): { sql: string; params: unknown[]; } { if (!where || where.length === 0) { return { sql: "", params: [] }; } const conditions: string[] = []; const params: unknown[] = []; for (const clause of where) { switch (clause.operator) { case "is null": conditions.push(`${clause.field} IS NULL`); break; case "is not null": conditions.push(`${clause.field} IS NOT NULL`); break; case "in": case "not in": const values = clause.value as unknown[]; const placeholders = values.map(() => "?").join(", "); conditions.push( `${clause.field} ${clause.operator.toUpperCase()} (${placeholders})`, ); params.push(...values); break; default: conditions.push(`${clause.field} ${clause.operator} ?`); params.push(clause.value); } } return { sql: `WHERE ${conditions.join(" AND ")}`, params, }; } // Helper to map abstract column types to database-specific types protected abstract mapColumnType(type: ColumnType): string; }