@hedystia/db 2.0.9 → 2.0.11
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 +6 -2
- package/dist/core/database.cjs.map +1 -1
- package/dist/core/database.d.cts +3 -3
- package/dist/core/database.d.mts +3 -3
- package/dist/core/database.mjs +6 -2
- package/dist/core/database.mjs.map +1 -1
- package/dist/core/repository.cjs +32 -16
- package/dist/core/repository.cjs.map +1 -1
- package/dist/core/repository.d.cts +2 -0
- package/dist/core/repository.d.mts +2 -0
- package/dist/core/repository.mjs +33 -16
- package/dist/core/repository.mjs.map +1 -1
- package/dist/drivers/index.cjs +2 -0
- package/dist/drivers/index.cjs.map +1 -1
- package/dist/drivers/index.mjs +3 -0
- package/dist/drivers/index.mjs.map +1 -1
- package/dist/drivers/mysql.cjs +2 -1
- package/dist/drivers/mysql.cjs.map +1 -1
- package/dist/drivers/mysql.mjs +2 -1
- package/dist/drivers/mysql.mjs.map +1 -1
- package/dist/drivers/s3.cjs +282 -0
- package/dist/drivers/s3.cjs.map +1 -0
- package/dist/drivers/s3.mjs +286 -0
- package/dist/drivers/s3.mjs.map +1 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs.map +1 -1
- package/dist/schema/registry.cjs +2 -2
- package/dist/schema/registry.cjs.map +1 -1
- package/dist/schema/registry.d.cts +1 -1
- package/dist/schema/registry.d.mts +1 -1
- package/dist/schema/registry.mjs +2 -2
- package/dist/schema/registry.mjs.map +1 -1
- package/dist/types.d.cts +31 -11
- package/dist/types.d.mts +31 -11
- package/package.json +6 -2
- package/readme.md +62 -70
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mysql.cjs","names":["BaseDriver","DriverError","compileCreateTable","compileColumnDef"],"sources":["../../src/drivers/mysql.ts"],"sourcesContent":["import { DriverError } from \"../errors\";\nimport type { ColumnMetadata, MySQLConnectionConfig, TableMetadata } from \"../types\";\nimport { BaseDriver } from \"./driver\";\nimport { compileColumnDef, compileCreateTable } from \"./sql-compiler\";\n\ninterface MySQLPool {\n query(sql: string, params?: any[]): Promise<[any, any]>;\n execute(sql: string, params?: any[]): Promise<[any, any]>;\n getConnection(): Promise<MySQLConnection>;\n end(): Promise<void>;\n}\n\ninterface MySQLConnection {\n beginTransaction(): Promise<void>;\n commit(): Promise<void>;\n rollback(): Promise<void>;\n release(): void;\n query(sql: string, params?: any[]): Promise<[any, any]>;\n execute(sql: string, params?: any[]): Promise<[any, any]>;\n}\n\n/**\n * MySQL database driver supporting mysql2 and mysql\n */\nexport class MySQLDriver extends BaseDriver {\n private pool: MySQLPool | null = null;\n private config: MySQLConnectionConfig;\n private provider?: \"mysql\" | \"mysql2\";\n\n constructor(config: MySQLConnectionConfig, provider?: \"mysql\" | \"mysql2\") {\n super();\n this.config = config;\n this.provider = provider;\n }\n\n /**\n * Connect to the MySQL/MariaDB database\n */\n async connect(): Promise<void> {\n if (this.connected) {\n return;\n }\n\n const provider = this.provider;\n\n try {\n if (!provider || provider === \"mysql2\") {\n try {\n const mysql2 = await import(\"mysql2/promise\");\n this.pool = mysql2.createPool({\n host: this.config.host,\n port: this.config.port ?? 3306,\n user: this.config.user,\n password: this.config.password,\n database: this.config.database,\n waitForConnections: true,\n connectionLimit: 10,\n enableKeepAlive: true,\n keepAliveInitialDelay: 10000,\n });\n this.connected = true;\n return;\n } catch (err) {\n if (provider === \"mysql2\") {\n throw err;\n }\n }\n }\n\n if (!provider || provider === \"mysql\") {\n try {\n const mysql = await import(\"mysql\");\n const pool = mysql.createPool({\n host: this.config.host,\n port: this.config.port ?? 3306,\n user: this.config.user,\n password: this.config.password,\n database: this.config.database,\n connectionLimit: 10,\n waitForConnections: true,\n acquireTimeout: 10000,\n });\n\n this.pool = {\n execute: (sql: string, params: any[]) =>\n new Promise((resolve, reject) => {\n pool.query(sql, params, (err, results, fields) => {\n if (err) {\n return reject(err);\n }\n resolve([results, fields]);\n });\n }),\n query: (sql: string, params: any[]) =>\n new Promise((resolve, reject) => {\n pool.query(sql, params, (err, results, fields) => {\n if (err) {\n return reject(err);\n }\n resolve([results, fields]);\n });\n }),\n getConnection: () =>\n new Promise((resolve, reject) => {\n pool.getConnection((err, conn) => {\n if (err) {\n return reject(err);\n }\n const wrappedConn: MySQLConnection = {\n beginTransaction: () =>\n new Promise<void>((res, rej) =>\n conn.beginTransaction((e) => (e ? rej(e) : res())),\n ),\n commit: () =>\n new Promise<void>((res, rej) => conn.commit((e) => (e ? rej(e) : res()))),\n rollback: () =>\n new Promise<void>((res, rej) => conn.rollback((e) => (e ? rej(e) : res()))),\n release: () => conn.release(),\n query: (sql: string, params: any[]) =>\n new Promise((res, rej) => {\n conn.query(sql, params, (e, results, fields) =>\n e ? rej(e) : res([results, fields]),\n );\n }),\n execute: (sql: string, params: any[]) =>\n new Promise((res, rej) => {\n conn.query(sql, params, (e, results, fields) =>\n e ? rej(e) : res([results, fields]),\n );\n }),\n };\n resolve(wrappedConn);\n });\n }),\n end: () => new Promise<void>((res, rej) => pool.end((e) => (e ? rej(e) : res()))),\n };\n this.connected = true;\n } catch (err) {\n if (provider === \"mysql\") {\n throw err;\n }\n throw new Error(\"No MySQL driver found. Please install mysql2 or mysql.\");\n }\n }\n } catch (err: any) {\n throw new DriverError(`Failed to connect to MySQL database: ${err.message}`);\n }\n }\n\n async disconnect(): Promise<void> {\n if (this.pool) {\n await this.pool.end();\n this.pool = null;\n this.connected = false;\n }\n }\n\n private getPool(): MySQLPool {\n if (!this.pool) {\n throw new DriverError(\"Database not connected\");\n }\n return this.pool;\n }\n\n /**\n * Execute a SQL statement\n * @param {string} sql - SQL statement\n * @param {unknown[]} [params] - Query parameters\n * @returns {Promise<any>} Execution result\n */\n async execute(sql: string, params: unknown[] = []): Promise<any> {\n try {\n const [result] = await this.getPool().query(sql, this.formatParams(params));\n return {\n insertId: result.insertId,\n affectedRows: result.affectedRows,\n };\n } catch (err: any) {\n throw new DriverError(`MySQL execute error: ${err.message}`);\n }\n }\n\n /**\n * Execute a SQL query\n * @param {string} sql - SQL query\n * @param {unknown[]} [params] - Query parameters\n * @returns {Promise<any[]>} Query results\n */\n async query(sql: string, params: unknown[] = []): Promise<any[]> {\n try {\n const [rows] = await this.getPool().query(sql, this.formatParams(params));\n return rows as any[];\n } catch (err: any) {\n throw new DriverError(`MySQL query error: ${err.message}`);\n }\n }\n\n private formatParams(params: unknown[]): unknown[] {\n return params.map((p) => {\n if (p instanceof Date) {\n return p.toISOString().slice(0, 19).replace(\"T\", \" \");\n }\n return p;\n });\n }\n\n /**\n * Check if a table exists\n * @param {string} name - Table name\n * @returns {Promise<boolean>} Whether the table exists\n */\n async tableExists(name: string): Promise<boolean> {\n const rows = await this.query(\n \"SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ?\",\n [this.config.database, name],\n );\n return rows.length > 0;\n }\n\n /**\n * Get column metadata for a table\n * @param {string} name - Table name\n * @returns {Promise<ColumnMetadata[]>} Column metadata\n */\n async getTableColumns(name: string): Promise<ColumnMetadata[]> {\n const rows = await this.query(\n \"SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_KEY, EXTRA, COLUMN_DEFAULT FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ? ORDER BY ORDINAL_POSITION\",\n [this.config.database, name],\n );\n return rows.map((row: any) => ({\n name: row.COLUMN_NAME,\n type: this.mapMySQLType(row.DATA_TYPE),\n primaryKey: row.COLUMN_KEY === \"PRI\",\n autoIncrement: row.EXTRA?.includes(\"auto_increment\") ?? false,\n notNull: row.IS_NULLABLE === \"NO\",\n unique: row.COLUMN_KEY === \"UNI\",\n defaultValue: row.COLUMN_DEFAULT,\n }));\n }\n\n /**\n * Create a table from metadata\n * @param {TableMetadata} meta - Table metadata\n */\n async createTable(meta: TableMetadata): Promise<void> {\n const sql = compileCreateTable(meta, \"mysql\");\n await this.execute(sql);\n }\n\n /**\n * Drop a table\n * @param {string} name - Table name\n */\n async dropTable(name: string): Promise<void> {\n await this.execute(`DROP TABLE IF EXISTS \\`${name}\\``);\n }\n\n /**\n * Add a column to a table\n * @param {string} table - Table name\n * @param {ColumnMetadata} column - Column metadata\n */\n async addColumn(table: string, column: ColumnMetadata): Promise<void> {\n const colDef = compileColumnDef(column, \"mysql\");\n await this.execute(`ALTER TABLE \\`${table}\\` ADD COLUMN ${colDef}`);\n }\n\n /**\n * Drop a column from a table\n * @param {string} table - Table name\n * @param {string} name - Column name\n */\n async dropColumn(table: string, name: string): Promise<void> {\n await this.execute(`ALTER TABLE \\`${table}\\` DROP COLUMN \\`${name}\\``);\n }\n\n /**\n * Rename a column\n * @param {string} table - Table name\n * @param {string} oldName - Current name\n * @param {string} newName - New name\n */\n async renameColumn(table: string, oldName: string, newName: string): Promise<void> {\n await this.execute(`ALTER TABLE \\`${table}\\` RENAME COLUMN \\`${oldName}\\` TO \\`${newName}\\``);\n }\n\n /**\n * Execute within a transaction\n * @param {() => Promise<T>} fn - Function to execute\n * @returns {Promise<T>} Result\n */\n async transaction<T>(fn: () => Promise<T>): Promise<T> {\n const conn = await this.getPool().getConnection();\n try {\n await conn.beginTransaction();\n const result = await fn();\n await conn.commit();\n return result;\n } catch (err) {\n await conn.rollback();\n throw err;\n } finally {\n conn.release();\n }\n }\n\n /**\n * Fetch all column metadata for all tables in the database in a single query\n * @returns {Promise<Record<string, ColumnMetadata[]>>} Columns grouped by table name\n */\n async getAllTableColumns(): Promise<Record<string, ColumnMetadata[]>> {\n try {\n const rows = await this.query(\n \"SELECT TABLE_NAME, COLUMN_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_KEY, EXTRA, COLUMN_DEFAULT FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = ? ORDER BY TABLE_NAME, ORDINAL_POSITION\",\n [this.config.database],\n );\n\n const result: Record<string, ColumnMetadata[]> = {};\n for (let i = 0; i < rows.length; i++) {\n const row = rows[i] as any;\n if (!row || !row.TABLE_NAME) {\n continue;\n }\n const tableName = row.TABLE_NAME;\n if (!result[tableName]) {\n result[tableName] = [];\n }\n result[tableName].push({\n name: row.COLUMN_NAME,\n type: this.mapMySQLType(row.DATA_TYPE),\n primaryKey: row.COLUMN_KEY === \"PRI\",\n autoIncrement: row.EXTRA?.includes(\"auto_increment\") ?? false,\n notNull: row.IS_NULLABLE === \"NO\",\n unique: row.COLUMN_KEY === \"UNI\",\n defaultValue: row.COLUMN_DEFAULT,\n });\n }\n return result;\n } catch (err: any) {\n throw new DriverError(`Failed to fetch all table columns: ${err.message}`);\n }\n }\n\n private mapMySQLType(type: string): ColumnMetadata[\"type\"] {\n const lower = type.toLowerCase();\n if (\n lower === \"int\" ||\n lower === \"integer\" ||\n lower === \"tinyint\" ||\n lower === \"smallint\" ||\n lower === \"mediumint\"\n ) {\n return \"integer\";\n }\n if (lower === \"bigint\") {\n return \"bigint\";\n }\n if (lower === \"varchar\") {\n return \"varchar\";\n }\n if (lower === \"char\") {\n return \"char\";\n }\n if (lower === \"text\" || lower === \"mediumtext\" || lower === \"longtext\") {\n return \"text\";\n }\n if (lower === \"json\") {\n return \"json\";\n }\n if (lower === \"datetime\") {\n return \"datetime\";\n }\n if (lower === \"timestamp\") {\n return \"timestamp\";\n }\n if (lower === \"decimal\" || lower === \"numeric\") {\n return \"decimal\";\n }\n if (lower === \"float\" || lower === \"double\" || lower === \"real\") {\n return \"float\";\n }\n if (lower === \"blob\" || lower === \"mediumblob\" || lower === \"longblob\") {\n return \"blob\";\n }\n return \"text\";\n }\n}\n"],"mappings":";;;;;;;AAwBA,IAAa,cAAb,cAAiCA,eAAAA,WAAW;CAC1C,OAAiC;CACjC;CACA;CAEA,YAAY,QAA+B,UAA+B;AACxE,SAAO;AACP,OAAK,SAAS;AACd,OAAK,WAAW;;;;;CAMlB,MAAM,UAAyB;AAC7B,MAAI,KAAK,UACP;EAGF,MAAM,WAAW,KAAK;AAEtB,MAAI;AACF,OAAI,CAAC,YAAY,aAAa,SAC5B,KAAI;AAEF,SAAK,QADU,MAAM,OAAO,mBACT,WAAW;KAC5B,MAAM,KAAK,OAAO;KAClB,MAAM,KAAK,OAAO,QAAQ;KAC1B,MAAM,KAAK,OAAO;KAClB,UAAU,KAAK,OAAO;KACtB,UAAU,KAAK,OAAO;KACtB,oBAAoB;KACpB,iBAAiB;KACjB,iBAAiB;KACjB,uBAAuB;KACxB,CAAC;AACF,SAAK,YAAY;AACjB;YACO,KAAK;AACZ,QAAI,aAAa,SACf,OAAM;;AAKZ,OAAI,CAAC,YAAY,aAAa,QAC5B,KAAI;IAEF,MAAM,QADQ,MAAM,OAAO,UACR,WAAW;KAC5B,MAAM,KAAK,OAAO;KAClB,MAAM,KAAK,OAAO,QAAQ;KAC1B,MAAM,KAAK,OAAO;KAClB,UAAU,KAAK,OAAO;KACtB,UAAU,KAAK,OAAO;KACtB,iBAAiB;KACjB,oBAAoB;KACpB,gBAAgB;KACjB,CAAC;AAEF,SAAK,OAAO;KACV,UAAU,KAAa,WACrB,IAAI,SAAS,SAAS,WAAW;AAC/B,WAAK,MAAM,KAAK,SAAS,KAAK,SAAS,WAAW;AAChD,WAAI,IACF,QAAO,OAAO,IAAI;AAEpB,eAAQ,CAAC,SAAS,OAAO,CAAC;QAC1B;OACF;KACJ,QAAQ,KAAa,WACnB,IAAI,SAAS,SAAS,WAAW;AAC/B,WAAK,MAAM,KAAK,SAAS,KAAK,SAAS,WAAW;AAChD,WAAI,IACF,QAAO,OAAO,IAAI;AAEpB,eAAQ,CAAC,SAAS,OAAO,CAAC;QAC1B;OACF;KACJ,qBACE,IAAI,SAAS,SAAS,WAAW;AAC/B,WAAK,eAAe,KAAK,SAAS;AAChC,WAAI,IACF,QAAO,OAAO,IAAI;AAyBpB,eAvBqC;QACnC,wBACE,IAAI,SAAe,KAAK,QACtB,KAAK,kBAAkB,MAAO,IAAI,IAAI,EAAE,GAAG,KAAK,CAAE,CACnD;QACH,cACE,IAAI,SAAe,KAAK,QAAQ,KAAK,QAAQ,MAAO,IAAI,IAAI,EAAE,GAAG,KAAK,CAAE,CAAC;QAC3E,gBACE,IAAI,SAAe,KAAK,QAAQ,KAAK,UAAU,MAAO,IAAI,IAAI,EAAE,GAAG,KAAK,CAAE,CAAC;QAC7E,eAAe,KAAK,SAAS;QAC7B,QAAQ,KAAa,WACnB,IAAI,SAAS,KAAK,QAAQ;AACxB,cAAK,MAAM,KAAK,SAAS,GAAG,SAAS,WACnC,IAAI,IAAI,EAAE,GAAG,IAAI,CAAC,SAAS,OAAO,CAAC,CACpC;UACD;QACJ,UAAU,KAAa,WACrB,IAAI,SAAS,KAAK,QAAQ;AACxB,cAAK,MAAM,KAAK,SAAS,GAAG,SAAS,WACnC,IAAI,IAAI,EAAE,GAAG,IAAI,CAAC,SAAS,OAAO,CAAC,CACpC;UACD;QACL,CACmB;QACpB;OACF;KACJ,WAAW,IAAI,SAAe,KAAK,QAAQ,KAAK,KAAK,MAAO,IAAI,IAAI,EAAE,GAAG,KAAK,CAAE,CAAC;KAClF;AACD,SAAK,YAAY;YACV,KAAK;AACZ,QAAI,aAAa,QACf,OAAM;AAER,UAAM,IAAI,MAAM,yDAAyD;;WAGtE,KAAU;AACjB,SAAM,IAAIC,eAAAA,YAAY,wCAAwC,IAAI,UAAU;;;CAIhF,MAAM,aAA4B;AAChC,MAAI,KAAK,MAAM;AACb,SAAM,KAAK,KAAK,KAAK;AACrB,QAAK,OAAO;AACZ,QAAK,YAAY;;;CAIrB,UAA6B;AAC3B,MAAI,CAAC,KAAK,KACR,OAAM,IAAIA,eAAAA,YAAY,yBAAyB;AAEjD,SAAO,KAAK;;;;;;;;CASd,MAAM,QAAQ,KAAa,SAAoB,EAAE,EAAgB;AAC/D,MAAI;GACF,MAAM,CAAC,UAAU,MAAM,KAAK,SAAS,CAAC,MAAM,KAAK,KAAK,aAAa,OAAO,CAAC;AAC3E,UAAO;IACL,UAAU,OAAO;IACjB,cAAc,OAAO;IACtB;WACM,KAAU;AACjB,SAAM,IAAIA,eAAAA,YAAY,wBAAwB,IAAI,UAAU;;;;;;;;;CAUhE,MAAM,MAAM,KAAa,SAAoB,EAAE,EAAkB;AAC/D,MAAI;GACF,MAAM,CAAC,QAAQ,MAAM,KAAK,SAAS,CAAC,MAAM,KAAK,KAAK,aAAa,OAAO,CAAC;AACzE,UAAO;WACA,KAAU;AACjB,SAAM,IAAIA,eAAAA,YAAY,sBAAsB,IAAI,UAAU;;;CAI9D,aAAqB,QAA8B;AACjD,SAAO,OAAO,KAAK,MAAM;AACvB,OAAI,aAAa,KACf,QAAO,EAAE,aAAa,CAAC,MAAM,GAAG,GAAG,CAAC,QAAQ,KAAK,IAAI;AAEvD,UAAO;IACP;;;;;;;CAQJ,MAAM,YAAY,MAAgC;AAKhD,UAJa,MAAM,KAAK,MACtB,8FACA,CAAC,KAAK,OAAO,UAAU,KAAK,CAC7B,EACW,SAAS;;;;;;;CAQvB,MAAM,gBAAgB,MAAyC;AAK7D,UAJa,MAAM,KAAK,MACtB,qLACA,CAAC,KAAK,OAAO,UAAU,KAAK,CAC7B,EACW,KAAK,SAAc;GAC7B,MAAM,IAAI;GACV,MAAM,KAAK,aAAa,IAAI,UAAU;GACtC,YAAY,IAAI,eAAe;GAC/B,eAAe,IAAI,OAAO,SAAS,iBAAiB,IAAI;GACxD,SAAS,IAAI,gBAAgB;GAC7B,QAAQ,IAAI,eAAe;GAC3B,cAAc,IAAI;GACnB,EAAE;;;;;;CAOL,MAAM,YAAY,MAAoC;EACpD,MAAM,MAAMC,qBAAAA,mBAAmB,MAAM,QAAQ;AAC7C,QAAM,KAAK,QAAQ,IAAI;;;;;;CAOzB,MAAM,UAAU,MAA6B;AAC3C,QAAM,KAAK,QAAQ,0BAA0B,KAAK,IAAI;;;;;;;CAQxD,MAAM,UAAU,OAAe,QAAuC;EACpE,MAAM,SAASC,qBAAAA,iBAAiB,QAAQ,QAAQ;AAChD,QAAM,KAAK,QAAQ,iBAAiB,MAAM,gBAAgB,SAAS;;;;;;;CAQrE,MAAM,WAAW,OAAe,MAA6B;AAC3D,QAAM,KAAK,QAAQ,iBAAiB,MAAM,mBAAmB,KAAK,IAAI;;;;;;;;CASxE,MAAM,aAAa,OAAe,SAAiB,SAAgC;AACjF,QAAM,KAAK,QAAQ,iBAAiB,MAAM,qBAAqB,QAAQ,UAAU,QAAQ,IAAI;;;;;;;CAQ/F,MAAM,YAAe,IAAkC;EACrD,MAAM,OAAO,MAAM,KAAK,SAAS,CAAC,eAAe;AACjD,MAAI;AACF,SAAM,KAAK,kBAAkB;GAC7B,MAAM,SAAS,MAAM,IAAI;AACzB,SAAM,KAAK,QAAQ;AACnB,UAAO;WACA,KAAK;AACZ,SAAM,KAAK,UAAU;AACrB,SAAM;YACE;AACR,QAAK,SAAS;;;;;;;CAQlB,MAAM,qBAAgE;AACpE,MAAI;GACF,MAAM,OAAO,MAAM,KAAK,MACtB,0LACA,CAAC,KAAK,OAAO,SAAS,CACvB;GAED,MAAM,SAA2C,EAAE;AACnD,QAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;IACpC,MAAM,MAAM,KAAK;AACjB,QAAI,CAAC,OAAO,CAAC,IAAI,WACf;IAEF,MAAM,YAAY,IAAI;AACtB,QAAI,CAAC,OAAO,WACV,QAAO,aAAa,EAAE;AAExB,WAAO,WAAW,KAAK;KACrB,MAAM,IAAI;KACV,MAAM,KAAK,aAAa,IAAI,UAAU;KACtC,YAAY,IAAI,eAAe;KAC/B,eAAe,IAAI,OAAO,SAAS,iBAAiB,IAAI;KACxD,SAAS,IAAI,gBAAgB;KAC7B,QAAQ,IAAI,eAAe;KAC3B,cAAc,IAAI;KACnB,CAAC;;AAEJ,UAAO;WACA,KAAU;AACjB,SAAM,IAAIF,eAAAA,YAAY,sCAAsC,IAAI,UAAU;;;CAI9E,aAAqB,MAAsC;EACzD,MAAM,QAAQ,KAAK,aAAa;AAChC,MACE,UAAU,SACV,UAAU,aACV,UAAU,aACV,UAAU,cACV,UAAU,YAEV,QAAO;AAET,MAAI,UAAU,SACZ,QAAO;AAET,MAAI,UAAU,UACZ,QAAO;AAET,MAAI,UAAU,OACZ,QAAO;AAET,MAAI,UAAU,UAAU,UAAU,gBAAgB,UAAU,WAC1D,QAAO;AAET,MAAI,UAAU,OACZ,QAAO;AAET,MAAI,UAAU,WACZ,QAAO;AAET,MAAI,UAAU,YACZ,QAAO;AAET,MAAI,UAAU,aAAa,UAAU,UACnC,QAAO;AAET,MAAI,UAAU,WAAW,UAAU,YAAY,UAAU,OACvD,QAAO;AAET,MAAI,UAAU,UAAU,UAAU,gBAAgB,UAAU,WAC1D,QAAO;AAET,SAAO"}
|
|
1
|
+
{"version":3,"file":"mysql.cjs","names":["BaseDriver","DriverError","compileCreateTable","compileColumnDef"],"sources":["../../src/drivers/mysql.ts"],"sourcesContent":["import { DriverError } from \"../errors\";\nimport type { ColumnMetadata, MySQLConnectionConfig, TableMetadata } from \"../types\";\nimport { BaseDriver } from \"./driver\";\nimport { compileColumnDef, compileCreateTable } from \"./sql-compiler\";\n\ninterface MySQLPool {\n query(sql: string, params?: any[]): Promise<[any, any]>;\n execute(sql: string, params?: any[]): Promise<[any, any]>;\n getConnection(): Promise<MySQLConnection>;\n end(): Promise<void>;\n}\n\ninterface MySQLConnection {\n beginTransaction(): Promise<void>;\n commit(): Promise<void>;\n rollback(): Promise<void>;\n release(): void;\n query(sql: string, params?: any[]): Promise<[any, any]>;\n execute(sql: string, params?: any[]): Promise<[any, any]>;\n}\n\n/**\n * MySQL database driver supporting mysql2 and mysql\n */\nexport class MySQLDriver extends BaseDriver {\n private pool: MySQLPool | null = null;\n private config: MySQLConnectionConfig;\n private provider?: \"mysql\" | \"mysql2\";\n\n constructor(config: MySQLConnectionConfig, provider?: \"mysql\" | \"mysql2\") {\n super();\n this.config = config;\n this.provider = provider;\n }\n\n /**\n * Connect to the MySQL/MariaDB database\n */\n async connect(): Promise<void> {\n if (this.connected) {\n return;\n }\n\n const provider = this.provider;\n\n try {\n if (!provider || provider === \"mysql2\") {\n try {\n const mysql2 = await import(\"mysql2/promise\");\n this.pool = mysql2.createPool({\n host: this.config.host,\n port: this.config.port ?? 3306,\n user: this.config.user,\n password: this.config.password,\n database: this.config.database,\n waitForConnections: true,\n connectionLimit: 10,\n enableKeepAlive: true,\n keepAliveInitialDelay: 10000,\n decimalNumbers: true,\n });\n this.connected = true;\n return;\n } catch (err) {\n if (provider === \"mysql2\") {\n throw err;\n }\n }\n }\n\n if (!provider || provider === \"mysql\") {\n try {\n const mysql = await import(\"mysql\");\n const pool = mysql.createPool({\n host: this.config.host,\n port: this.config.port ?? 3306,\n user: this.config.user,\n password: this.config.password,\n database: this.config.database,\n connectionLimit: 10,\n waitForConnections: true,\n acquireTimeout: 10000,\n });\n\n this.pool = {\n execute: (sql: string, params: any[]) =>\n new Promise((resolve, reject) => {\n pool.query(sql, params, (err, results, fields) => {\n if (err) {\n return reject(err);\n }\n resolve([results, fields]);\n });\n }),\n query: (sql: string, params: any[]) =>\n new Promise((resolve, reject) => {\n pool.query(sql, params, (err, results, fields) => {\n if (err) {\n return reject(err);\n }\n resolve([results, fields]);\n });\n }),\n getConnection: () =>\n new Promise((resolve, reject) => {\n pool.getConnection((err, conn) => {\n if (err) {\n return reject(err);\n }\n const wrappedConn: MySQLConnection = {\n beginTransaction: () =>\n new Promise<void>((res, rej) =>\n conn.beginTransaction((e) => (e ? rej(e) : res())),\n ),\n commit: () =>\n new Promise<void>((res, rej) => conn.commit((e) => (e ? rej(e) : res()))),\n rollback: () =>\n new Promise<void>((res, rej) => conn.rollback((e) => (e ? rej(e) : res()))),\n release: () => conn.release(),\n query: (sql: string, params: any[]) =>\n new Promise((res, rej) => {\n conn.query(sql, params, (e, results, fields) =>\n e ? rej(e) : res([results, fields]),\n );\n }),\n execute: (sql: string, params: any[]) =>\n new Promise((res, rej) => {\n conn.query(sql, params, (e, results, fields) =>\n e ? rej(e) : res([results, fields]),\n );\n }),\n };\n resolve(wrappedConn);\n });\n }),\n end: () => new Promise<void>((res, rej) => pool.end((e) => (e ? rej(e) : res()))),\n };\n this.connected = true;\n } catch (err) {\n if (provider === \"mysql\") {\n throw err;\n }\n throw new Error(\"No MySQL driver found. Please install mysql2 or mysql.\");\n }\n }\n } catch (err: any) {\n throw new DriverError(`Failed to connect to MySQL database: ${err.message}`);\n }\n }\n\n async disconnect(): Promise<void> {\n if (this.pool) {\n await this.pool.end();\n this.pool = null;\n this.connected = false;\n }\n }\n\n private getPool(): MySQLPool {\n if (!this.pool) {\n throw new DriverError(\"Database not connected\");\n }\n return this.pool;\n }\n\n /**\n * Execute a SQL statement\n * @param {string} sql - SQL statement\n * @param {unknown[]} [params] - Query parameters\n * @returns {Promise<any>} Execution result\n */\n async execute(sql: string, params: unknown[] = []): Promise<any> {\n try {\n const [result] = await this.getPool().query(sql, this.formatParams(params));\n return {\n insertId: result.insertId,\n affectedRows: result.affectedRows,\n };\n } catch (err: any) {\n throw new DriverError(`MySQL execute error: ${err.message}`);\n }\n }\n\n /**\n * Execute a SQL query\n * @param {string} sql - SQL query\n * @param {unknown[]} [params] - Query parameters\n * @returns {Promise<any[]>} Query results\n */\n async query(sql: string, params: unknown[] = []): Promise<any[]> {\n try {\n const [rows] = await this.getPool().query(sql, this.formatParams(params));\n return rows as any[];\n } catch (err: any) {\n throw new DriverError(`MySQL query error: ${err.message}`);\n }\n }\n\n private formatParams(params: unknown[]): unknown[] {\n return params.map((p) => {\n if (p instanceof Date) {\n return p.toISOString().slice(0, 19).replace(\"T\", \" \");\n }\n return p;\n });\n }\n\n /**\n * Check if a table exists\n * @param {string} name - Table name\n * @returns {Promise<boolean>} Whether the table exists\n */\n async tableExists(name: string): Promise<boolean> {\n const rows = await this.query(\n \"SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ?\",\n [this.config.database, name],\n );\n return rows.length > 0;\n }\n\n /**\n * Get column metadata for a table\n * @param {string} name - Table name\n * @returns {Promise<ColumnMetadata[]>} Column metadata\n */\n async getTableColumns(name: string): Promise<ColumnMetadata[]> {\n const rows = await this.query(\n \"SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_KEY, EXTRA, COLUMN_DEFAULT FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ? ORDER BY ORDINAL_POSITION\",\n [this.config.database, name],\n );\n return rows.map((row: any) => ({\n name: row.COLUMN_NAME,\n type: this.mapMySQLType(row.DATA_TYPE),\n primaryKey: row.COLUMN_KEY === \"PRI\",\n autoIncrement: row.EXTRA?.includes(\"auto_increment\") ?? false,\n notNull: row.IS_NULLABLE === \"NO\",\n unique: row.COLUMN_KEY === \"UNI\",\n defaultValue: row.COLUMN_DEFAULT,\n }));\n }\n\n /**\n * Create a table from metadata\n * @param {TableMetadata} meta - Table metadata\n */\n async createTable(meta: TableMetadata): Promise<void> {\n const sql = compileCreateTable(meta, \"mysql\");\n await this.execute(sql);\n }\n\n /**\n * Drop a table\n * @param {string} name - Table name\n */\n async dropTable(name: string): Promise<void> {\n await this.execute(`DROP TABLE IF EXISTS \\`${name}\\``);\n }\n\n /**\n * Add a column to a table\n * @param {string} table - Table name\n * @param {ColumnMetadata} column - Column metadata\n */\n async addColumn(table: string, column: ColumnMetadata): Promise<void> {\n const colDef = compileColumnDef(column, \"mysql\");\n await this.execute(`ALTER TABLE \\`${table}\\` ADD COLUMN ${colDef}`);\n }\n\n /**\n * Drop a column from a table\n * @param {string} table - Table name\n * @param {string} name - Column name\n */\n async dropColumn(table: string, name: string): Promise<void> {\n await this.execute(`ALTER TABLE \\`${table}\\` DROP COLUMN \\`${name}\\``);\n }\n\n /**\n * Rename a column\n * @param {string} table - Table name\n * @param {string} oldName - Current name\n * @param {string} newName - New name\n */\n async renameColumn(table: string, oldName: string, newName: string): Promise<void> {\n await this.execute(`ALTER TABLE \\`${table}\\` RENAME COLUMN \\`${oldName}\\` TO \\`${newName}\\``);\n }\n\n /**\n * Execute within a transaction\n * @param {() => Promise<T>} fn - Function to execute\n * @returns {Promise<T>} Result\n */\n async transaction<T>(fn: () => Promise<T>): Promise<T> {\n const conn = await this.getPool().getConnection();\n try {\n await conn.beginTransaction();\n const result = await fn();\n await conn.commit();\n return result;\n } catch (err) {\n await conn.rollback();\n throw err;\n } finally {\n conn.release();\n }\n }\n\n /**\n * Fetch all column metadata for all tables in the database in a single query\n * @returns {Promise<Record<string, ColumnMetadata[]>>} Columns grouped by table name\n */\n async getAllTableColumns(): Promise<Record<string, ColumnMetadata[]>> {\n try {\n const rows = await this.query(\n \"SELECT TABLE_NAME, COLUMN_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_KEY, EXTRA, COLUMN_DEFAULT FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = ? ORDER BY TABLE_NAME, ORDINAL_POSITION\",\n [this.config.database],\n );\n\n const result: Record<string, ColumnMetadata[]> = {};\n for (let i = 0; i < rows.length; i++) {\n const row = rows[i] as any;\n if (!row || !row.TABLE_NAME) {\n continue;\n }\n const tableName = row.TABLE_NAME;\n if (!result[tableName]) {\n result[tableName] = [];\n }\n result[tableName].push({\n name: row.COLUMN_NAME,\n type: this.mapMySQLType(row.DATA_TYPE),\n primaryKey: row.COLUMN_KEY === \"PRI\",\n autoIncrement: row.EXTRA?.includes(\"auto_increment\") ?? false,\n notNull: row.IS_NULLABLE === \"NO\",\n unique: row.COLUMN_KEY === \"UNI\",\n defaultValue: row.COLUMN_DEFAULT,\n });\n }\n return result;\n } catch (err: any) {\n throw new DriverError(`Failed to fetch all table columns: ${err.message}`);\n }\n }\n\n private mapMySQLType(type: string): ColumnMetadata[\"type\"] {\n const lower = type.toLowerCase();\n if (\n lower === \"int\" ||\n lower === \"integer\" ||\n lower === \"tinyint\" ||\n lower === \"smallint\" ||\n lower === \"mediumint\"\n ) {\n return \"integer\";\n }\n if (lower === \"bigint\") {\n return \"bigint\";\n }\n if (lower === \"varchar\") {\n return \"varchar\";\n }\n if (lower === \"char\") {\n return \"char\";\n }\n if (lower === \"text\" || lower === \"mediumtext\" || lower === \"longtext\") {\n return \"text\";\n }\n if (lower === \"json\") {\n return \"json\";\n }\n if (lower === \"datetime\") {\n return \"datetime\";\n }\n if (lower === \"timestamp\") {\n return \"timestamp\";\n }\n if (lower === \"decimal\" || lower === \"numeric\") {\n return \"decimal\";\n }\n if (lower === \"float\" || lower === \"double\" || lower === \"real\") {\n return \"float\";\n }\n if (lower === \"blob\" || lower === \"mediumblob\" || lower === \"longblob\") {\n return \"blob\";\n }\n return \"text\";\n }\n}\n"],"mappings":"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"}
|
package/dist/drivers/mysql.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mysql.mjs","names":[],"sources":["../../src/drivers/mysql.ts"],"sourcesContent":["import { DriverError } from \"../errors\";\nimport type { ColumnMetadata, MySQLConnectionConfig, TableMetadata } from \"../types\";\nimport { BaseDriver } from \"./driver\";\nimport { compileColumnDef, compileCreateTable } from \"./sql-compiler\";\n\ninterface MySQLPool {\n query(sql: string, params?: any[]): Promise<[any, any]>;\n execute(sql: string, params?: any[]): Promise<[any, any]>;\n getConnection(): Promise<MySQLConnection>;\n end(): Promise<void>;\n}\n\ninterface MySQLConnection {\n beginTransaction(): Promise<void>;\n commit(): Promise<void>;\n rollback(): Promise<void>;\n release(): void;\n query(sql: string, params?: any[]): Promise<[any, any]>;\n execute(sql: string, params?: any[]): Promise<[any, any]>;\n}\n\n/**\n * MySQL database driver supporting mysql2 and mysql\n */\nexport class MySQLDriver extends BaseDriver {\n private pool: MySQLPool | null = null;\n private config: MySQLConnectionConfig;\n private provider?: \"mysql\" | \"mysql2\";\n\n constructor(config: MySQLConnectionConfig, provider?: \"mysql\" | \"mysql2\") {\n super();\n this.config = config;\n this.provider = provider;\n }\n\n /**\n * Connect to the MySQL/MariaDB database\n */\n async connect(): Promise<void> {\n if (this.connected) {\n return;\n }\n\n const provider = this.provider;\n\n try {\n if (!provider || provider === \"mysql2\") {\n try {\n const mysql2 = await import(\"mysql2/promise\");\n this.pool = mysql2.createPool({\n host: this.config.host,\n port: this.config.port ?? 3306,\n user: this.config.user,\n password: this.config.password,\n database: this.config.database,\n waitForConnections: true,\n connectionLimit: 10,\n enableKeepAlive: true,\n keepAliveInitialDelay: 10000,\n });\n this.connected = true;\n return;\n } catch (err) {\n if (provider === \"mysql2\") {\n throw err;\n }\n }\n }\n\n if (!provider || provider === \"mysql\") {\n try {\n const mysql = await import(\"mysql\");\n const pool = mysql.createPool({\n host: this.config.host,\n port: this.config.port ?? 3306,\n user: this.config.user,\n password: this.config.password,\n database: this.config.database,\n connectionLimit: 10,\n waitForConnections: true,\n acquireTimeout: 10000,\n });\n\n this.pool = {\n execute: (sql: string, params: any[]) =>\n new Promise((resolve, reject) => {\n pool.query(sql, params, (err, results, fields) => {\n if (err) {\n return reject(err);\n }\n resolve([results, fields]);\n });\n }),\n query: (sql: string, params: any[]) =>\n new Promise((resolve, reject) => {\n pool.query(sql, params, (err, results, fields) => {\n if (err) {\n return reject(err);\n }\n resolve([results, fields]);\n });\n }),\n getConnection: () =>\n new Promise((resolve, reject) => {\n pool.getConnection((err, conn) => {\n if (err) {\n return reject(err);\n }\n const wrappedConn: MySQLConnection = {\n beginTransaction: () =>\n new Promise<void>((res, rej) =>\n conn.beginTransaction((e) => (e ? rej(e) : res())),\n ),\n commit: () =>\n new Promise<void>((res, rej) => conn.commit((e) => (e ? rej(e) : res()))),\n rollback: () =>\n new Promise<void>((res, rej) => conn.rollback((e) => (e ? rej(e) : res()))),\n release: () => conn.release(),\n query: (sql: string, params: any[]) =>\n new Promise((res, rej) => {\n conn.query(sql, params, (e, results, fields) =>\n e ? rej(e) : res([results, fields]),\n );\n }),\n execute: (sql: string, params: any[]) =>\n new Promise((res, rej) => {\n conn.query(sql, params, (e, results, fields) =>\n e ? rej(e) : res([results, fields]),\n );\n }),\n };\n resolve(wrappedConn);\n });\n }),\n end: () => new Promise<void>((res, rej) => pool.end((e) => (e ? rej(e) : res()))),\n };\n this.connected = true;\n } catch (err) {\n if (provider === \"mysql\") {\n throw err;\n }\n throw new Error(\"No MySQL driver found. Please install mysql2 or mysql.\");\n }\n }\n } catch (err: any) {\n throw new DriverError(`Failed to connect to MySQL database: ${err.message}`);\n }\n }\n\n async disconnect(): Promise<void> {\n if (this.pool) {\n await this.pool.end();\n this.pool = null;\n this.connected = false;\n }\n }\n\n private getPool(): MySQLPool {\n if (!this.pool) {\n throw new DriverError(\"Database not connected\");\n }\n return this.pool;\n }\n\n /**\n * Execute a SQL statement\n * @param {string} sql - SQL statement\n * @param {unknown[]} [params] - Query parameters\n * @returns {Promise<any>} Execution result\n */\n async execute(sql: string, params: unknown[] = []): Promise<any> {\n try {\n const [result] = await this.getPool().query(sql, this.formatParams(params));\n return {\n insertId: result.insertId,\n affectedRows: result.affectedRows,\n };\n } catch (err: any) {\n throw new DriverError(`MySQL execute error: ${err.message}`);\n }\n }\n\n /**\n * Execute a SQL query\n * @param {string} sql - SQL query\n * @param {unknown[]} [params] - Query parameters\n * @returns {Promise<any[]>} Query results\n */\n async query(sql: string, params: unknown[] = []): Promise<any[]> {\n try {\n const [rows] = await this.getPool().query(sql, this.formatParams(params));\n return rows as any[];\n } catch (err: any) {\n throw new DriverError(`MySQL query error: ${err.message}`);\n }\n }\n\n private formatParams(params: unknown[]): unknown[] {\n return params.map((p) => {\n if (p instanceof Date) {\n return p.toISOString().slice(0, 19).replace(\"T\", \" \");\n }\n return p;\n });\n }\n\n /**\n * Check if a table exists\n * @param {string} name - Table name\n * @returns {Promise<boolean>} Whether the table exists\n */\n async tableExists(name: string): Promise<boolean> {\n const rows = await this.query(\n \"SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ?\",\n [this.config.database, name],\n );\n return rows.length > 0;\n }\n\n /**\n * Get column metadata for a table\n * @param {string} name - Table name\n * @returns {Promise<ColumnMetadata[]>} Column metadata\n */\n async getTableColumns(name: string): Promise<ColumnMetadata[]> {\n const rows = await this.query(\n \"SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_KEY, EXTRA, COLUMN_DEFAULT FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ? ORDER BY ORDINAL_POSITION\",\n [this.config.database, name],\n );\n return rows.map((row: any) => ({\n name: row.COLUMN_NAME,\n type: this.mapMySQLType(row.DATA_TYPE),\n primaryKey: row.COLUMN_KEY === \"PRI\",\n autoIncrement: row.EXTRA?.includes(\"auto_increment\") ?? false,\n notNull: row.IS_NULLABLE === \"NO\",\n unique: row.COLUMN_KEY === \"UNI\",\n defaultValue: row.COLUMN_DEFAULT,\n }));\n }\n\n /**\n * Create a table from metadata\n * @param {TableMetadata} meta - Table metadata\n */\n async createTable(meta: TableMetadata): Promise<void> {\n const sql = compileCreateTable(meta, \"mysql\");\n await this.execute(sql);\n }\n\n /**\n * Drop a table\n * @param {string} name - Table name\n */\n async dropTable(name: string): Promise<void> {\n await this.execute(`DROP TABLE IF EXISTS \\`${name}\\``);\n }\n\n /**\n * Add a column to a table\n * @param {string} table - Table name\n * @param {ColumnMetadata} column - Column metadata\n */\n async addColumn(table: string, column: ColumnMetadata): Promise<void> {\n const colDef = compileColumnDef(column, \"mysql\");\n await this.execute(`ALTER TABLE \\`${table}\\` ADD COLUMN ${colDef}`);\n }\n\n /**\n * Drop a column from a table\n * @param {string} table - Table name\n * @param {string} name - Column name\n */\n async dropColumn(table: string, name: string): Promise<void> {\n await this.execute(`ALTER TABLE \\`${table}\\` DROP COLUMN \\`${name}\\``);\n }\n\n /**\n * Rename a column\n * @param {string} table - Table name\n * @param {string} oldName - Current name\n * @param {string} newName - New name\n */\n async renameColumn(table: string, oldName: string, newName: string): Promise<void> {\n await this.execute(`ALTER TABLE \\`${table}\\` RENAME COLUMN \\`${oldName}\\` TO \\`${newName}\\``);\n }\n\n /**\n * Execute within a transaction\n * @param {() => Promise<T>} fn - Function to execute\n * @returns {Promise<T>} Result\n */\n async transaction<T>(fn: () => Promise<T>): Promise<T> {\n const conn = await this.getPool().getConnection();\n try {\n await conn.beginTransaction();\n const result = await fn();\n await conn.commit();\n return result;\n } catch (err) {\n await conn.rollback();\n throw err;\n } finally {\n conn.release();\n }\n }\n\n /**\n * Fetch all column metadata for all tables in the database in a single query\n * @returns {Promise<Record<string, ColumnMetadata[]>>} Columns grouped by table name\n */\n async getAllTableColumns(): Promise<Record<string, ColumnMetadata[]>> {\n try {\n const rows = await this.query(\n \"SELECT TABLE_NAME, COLUMN_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_KEY, EXTRA, COLUMN_DEFAULT FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = ? ORDER BY TABLE_NAME, ORDINAL_POSITION\",\n [this.config.database],\n );\n\n const result: Record<string, ColumnMetadata[]> = {};\n for (let i = 0; i < rows.length; i++) {\n const row = rows[i] as any;\n if (!row || !row.TABLE_NAME) {\n continue;\n }\n const tableName = row.TABLE_NAME;\n if (!result[tableName]) {\n result[tableName] = [];\n }\n result[tableName].push({\n name: row.COLUMN_NAME,\n type: this.mapMySQLType(row.DATA_TYPE),\n primaryKey: row.COLUMN_KEY === \"PRI\",\n autoIncrement: row.EXTRA?.includes(\"auto_increment\") ?? false,\n notNull: row.IS_NULLABLE === \"NO\",\n unique: row.COLUMN_KEY === \"UNI\",\n defaultValue: row.COLUMN_DEFAULT,\n });\n }\n return result;\n } catch (err: any) {\n throw new DriverError(`Failed to fetch all table columns: ${err.message}`);\n }\n }\n\n private mapMySQLType(type: string): ColumnMetadata[\"type\"] {\n const lower = type.toLowerCase();\n if (\n lower === \"int\" ||\n lower === \"integer\" ||\n lower === \"tinyint\" ||\n lower === \"smallint\" ||\n lower === \"mediumint\"\n ) {\n return \"integer\";\n }\n if (lower === \"bigint\") {\n return \"bigint\";\n }\n if (lower === \"varchar\") {\n return \"varchar\";\n }\n if (lower === \"char\") {\n return \"char\";\n }\n if (lower === \"text\" || lower === \"mediumtext\" || lower === \"longtext\") {\n return \"text\";\n }\n if (lower === \"json\") {\n return \"json\";\n }\n if (lower === \"datetime\") {\n return \"datetime\";\n }\n if (lower === \"timestamp\") {\n return \"timestamp\";\n }\n if (lower === \"decimal\" || lower === \"numeric\") {\n return \"decimal\";\n }\n if (lower === \"float\" || lower === \"double\" || lower === \"real\") {\n return \"float\";\n }\n if (lower === \"blob\" || lower === \"mediumblob\" || lower === \"longblob\") {\n return \"blob\";\n }\n return \"text\";\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"mysql.mjs","names":[],"sources":["../../src/drivers/mysql.ts"],"sourcesContent":["import { DriverError } from \"../errors\";\nimport type { ColumnMetadata, MySQLConnectionConfig, TableMetadata } from \"../types\";\nimport { BaseDriver } from \"./driver\";\nimport { compileColumnDef, compileCreateTable } from \"./sql-compiler\";\n\ninterface MySQLPool {\n query(sql: string, params?: any[]): Promise<[any, any]>;\n execute(sql: string, params?: any[]): Promise<[any, any]>;\n getConnection(): Promise<MySQLConnection>;\n end(): Promise<void>;\n}\n\ninterface MySQLConnection {\n beginTransaction(): Promise<void>;\n commit(): Promise<void>;\n rollback(): Promise<void>;\n release(): void;\n query(sql: string, params?: any[]): Promise<[any, any]>;\n execute(sql: string, params?: any[]): Promise<[any, any]>;\n}\n\n/**\n * MySQL database driver supporting mysql2 and mysql\n */\nexport class MySQLDriver extends BaseDriver {\n private pool: MySQLPool | null = null;\n private config: MySQLConnectionConfig;\n private provider?: \"mysql\" | \"mysql2\";\n\n constructor(config: MySQLConnectionConfig, provider?: \"mysql\" | \"mysql2\") {\n super();\n this.config = config;\n this.provider = provider;\n }\n\n /**\n * Connect to the MySQL/MariaDB database\n */\n async connect(): Promise<void> {\n if (this.connected) {\n return;\n }\n\n const provider = this.provider;\n\n try {\n if (!provider || provider === \"mysql2\") {\n try {\n const mysql2 = await import(\"mysql2/promise\");\n this.pool = mysql2.createPool({\n host: this.config.host,\n port: this.config.port ?? 3306,\n user: this.config.user,\n password: this.config.password,\n database: this.config.database,\n waitForConnections: true,\n connectionLimit: 10,\n enableKeepAlive: true,\n keepAliveInitialDelay: 10000,\n decimalNumbers: true,\n });\n this.connected = true;\n return;\n } catch (err) {\n if (provider === \"mysql2\") {\n throw err;\n }\n }\n }\n\n if (!provider || provider === \"mysql\") {\n try {\n const mysql = await import(\"mysql\");\n const pool = mysql.createPool({\n host: this.config.host,\n port: this.config.port ?? 3306,\n user: this.config.user,\n password: this.config.password,\n database: this.config.database,\n connectionLimit: 10,\n waitForConnections: true,\n acquireTimeout: 10000,\n });\n\n this.pool = {\n execute: (sql: string, params: any[]) =>\n new Promise((resolve, reject) => {\n pool.query(sql, params, (err, results, fields) => {\n if (err) {\n return reject(err);\n }\n resolve([results, fields]);\n });\n }),\n query: (sql: string, params: any[]) =>\n new Promise((resolve, reject) => {\n pool.query(sql, params, (err, results, fields) => {\n if (err) {\n return reject(err);\n }\n resolve([results, fields]);\n });\n }),\n getConnection: () =>\n new Promise((resolve, reject) => {\n pool.getConnection((err, conn) => {\n if (err) {\n return reject(err);\n }\n const wrappedConn: MySQLConnection = {\n beginTransaction: () =>\n new Promise<void>((res, rej) =>\n conn.beginTransaction((e) => (e ? rej(e) : res())),\n ),\n commit: () =>\n new Promise<void>((res, rej) => conn.commit((e) => (e ? rej(e) : res()))),\n rollback: () =>\n new Promise<void>((res, rej) => conn.rollback((e) => (e ? rej(e) : res()))),\n release: () => conn.release(),\n query: (sql: string, params: any[]) =>\n new Promise((res, rej) => {\n conn.query(sql, params, (e, results, fields) =>\n e ? rej(e) : res([results, fields]),\n );\n }),\n execute: (sql: string, params: any[]) =>\n new Promise((res, rej) => {\n conn.query(sql, params, (e, results, fields) =>\n e ? rej(e) : res([results, fields]),\n );\n }),\n };\n resolve(wrappedConn);\n });\n }),\n end: () => new Promise<void>((res, rej) => pool.end((e) => (e ? rej(e) : res()))),\n };\n this.connected = true;\n } catch (err) {\n if (provider === \"mysql\") {\n throw err;\n }\n throw new Error(\"No MySQL driver found. Please install mysql2 or mysql.\");\n }\n }\n } catch (err: any) {\n throw new DriverError(`Failed to connect to MySQL database: ${err.message}`);\n }\n }\n\n async disconnect(): Promise<void> {\n if (this.pool) {\n await this.pool.end();\n this.pool = null;\n this.connected = false;\n }\n }\n\n private getPool(): MySQLPool {\n if (!this.pool) {\n throw new DriverError(\"Database not connected\");\n }\n return this.pool;\n }\n\n /**\n * Execute a SQL statement\n * @param {string} sql - SQL statement\n * @param {unknown[]} [params] - Query parameters\n * @returns {Promise<any>} Execution result\n */\n async execute(sql: string, params: unknown[] = []): Promise<any> {\n try {\n const [result] = await this.getPool().query(sql, this.formatParams(params));\n return {\n insertId: result.insertId,\n affectedRows: result.affectedRows,\n };\n } catch (err: any) {\n throw new DriverError(`MySQL execute error: ${err.message}`);\n }\n }\n\n /**\n * Execute a SQL query\n * @param {string} sql - SQL query\n * @param {unknown[]} [params] - Query parameters\n * @returns {Promise<any[]>} Query results\n */\n async query(sql: string, params: unknown[] = []): Promise<any[]> {\n try {\n const [rows] = await this.getPool().query(sql, this.formatParams(params));\n return rows as any[];\n } catch (err: any) {\n throw new DriverError(`MySQL query error: ${err.message}`);\n }\n }\n\n private formatParams(params: unknown[]): unknown[] {\n return params.map((p) => {\n if (p instanceof Date) {\n return p.toISOString().slice(0, 19).replace(\"T\", \" \");\n }\n return p;\n });\n }\n\n /**\n * Check if a table exists\n * @param {string} name - Table name\n * @returns {Promise<boolean>} Whether the table exists\n */\n async tableExists(name: string): Promise<boolean> {\n const rows = await this.query(\n \"SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ?\",\n [this.config.database, name],\n );\n return rows.length > 0;\n }\n\n /**\n * Get column metadata for a table\n * @param {string} name - Table name\n * @returns {Promise<ColumnMetadata[]>} Column metadata\n */\n async getTableColumns(name: string): Promise<ColumnMetadata[]> {\n const rows = await this.query(\n \"SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_KEY, EXTRA, COLUMN_DEFAULT FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ? ORDER BY ORDINAL_POSITION\",\n [this.config.database, name],\n );\n return rows.map((row: any) => ({\n name: row.COLUMN_NAME,\n type: this.mapMySQLType(row.DATA_TYPE),\n primaryKey: row.COLUMN_KEY === \"PRI\",\n autoIncrement: row.EXTRA?.includes(\"auto_increment\") ?? false,\n notNull: row.IS_NULLABLE === \"NO\",\n unique: row.COLUMN_KEY === \"UNI\",\n defaultValue: row.COLUMN_DEFAULT,\n }));\n }\n\n /**\n * Create a table from metadata\n * @param {TableMetadata} meta - Table metadata\n */\n async createTable(meta: TableMetadata): Promise<void> {\n const sql = compileCreateTable(meta, \"mysql\");\n await this.execute(sql);\n }\n\n /**\n * Drop a table\n * @param {string} name - Table name\n */\n async dropTable(name: string): Promise<void> {\n await this.execute(`DROP TABLE IF EXISTS \\`${name}\\``);\n }\n\n /**\n * Add a column to a table\n * @param {string} table - Table name\n * @param {ColumnMetadata} column - Column metadata\n */\n async addColumn(table: string, column: ColumnMetadata): Promise<void> {\n const colDef = compileColumnDef(column, \"mysql\");\n await this.execute(`ALTER TABLE \\`${table}\\` ADD COLUMN ${colDef}`);\n }\n\n /**\n * Drop a column from a table\n * @param {string} table - Table name\n * @param {string} name - Column name\n */\n async dropColumn(table: string, name: string): Promise<void> {\n await this.execute(`ALTER TABLE \\`${table}\\` DROP COLUMN \\`${name}\\``);\n }\n\n /**\n * Rename a column\n * @param {string} table - Table name\n * @param {string} oldName - Current name\n * @param {string} newName - New name\n */\n async renameColumn(table: string, oldName: string, newName: string): Promise<void> {\n await this.execute(`ALTER TABLE \\`${table}\\` RENAME COLUMN \\`${oldName}\\` TO \\`${newName}\\``);\n }\n\n /**\n * Execute within a transaction\n * @param {() => Promise<T>} fn - Function to execute\n * @returns {Promise<T>} Result\n */\n async transaction<T>(fn: () => Promise<T>): Promise<T> {\n const conn = await this.getPool().getConnection();\n try {\n await conn.beginTransaction();\n const result = await fn();\n await conn.commit();\n return result;\n } catch (err) {\n await conn.rollback();\n throw err;\n } finally {\n conn.release();\n }\n }\n\n /**\n * Fetch all column metadata for all tables in the database in a single query\n * @returns {Promise<Record<string, ColumnMetadata[]>>} Columns grouped by table name\n */\n async getAllTableColumns(): Promise<Record<string, ColumnMetadata[]>> {\n try {\n const rows = await this.query(\n \"SELECT TABLE_NAME, COLUMN_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_KEY, EXTRA, COLUMN_DEFAULT FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = ? ORDER BY TABLE_NAME, ORDINAL_POSITION\",\n [this.config.database],\n );\n\n const result: Record<string, ColumnMetadata[]> = {};\n for (let i = 0; i < rows.length; i++) {\n const row = rows[i] as any;\n if (!row || !row.TABLE_NAME) {\n continue;\n }\n const tableName = row.TABLE_NAME;\n if (!result[tableName]) {\n result[tableName] = [];\n }\n result[tableName].push({\n name: row.COLUMN_NAME,\n type: this.mapMySQLType(row.DATA_TYPE),\n primaryKey: row.COLUMN_KEY === \"PRI\",\n autoIncrement: row.EXTRA?.includes(\"auto_increment\") ?? false,\n notNull: row.IS_NULLABLE === \"NO\",\n unique: row.COLUMN_KEY === \"UNI\",\n defaultValue: row.COLUMN_DEFAULT,\n });\n }\n return result;\n } catch (err: any) {\n throw new DriverError(`Failed to fetch all table columns: ${err.message}`);\n }\n }\n\n private mapMySQLType(type: string): ColumnMetadata[\"type\"] {\n const lower = type.toLowerCase();\n if (\n lower === \"int\" ||\n lower === \"integer\" ||\n lower === \"tinyint\" ||\n lower === \"smallint\" ||\n lower === \"mediumint\"\n ) {\n return \"integer\";\n }\n if (lower === \"bigint\") {\n return \"bigint\";\n }\n if (lower === \"varchar\") {\n return \"varchar\";\n }\n if (lower === \"char\") {\n return \"char\";\n }\n if (lower === \"text\" || lower === \"mediumtext\" || lower === \"longtext\") {\n return \"text\";\n }\n if (lower === \"json\") {\n return \"json\";\n }\n if (lower === \"datetime\") {\n return \"datetime\";\n }\n if (lower === \"timestamp\") {\n return \"timestamp\";\n }\n if (lower === \"decimal\" || lower === \"numeric\") {\n return \"decimal\";\n }\n if (lower === \"float\" || lower === \"double\" || lower === \"real\") {\n return \"float\";\n }\n if (lower === \"blob\" || lower === \"mediumblob\" || lower === \"longblob\") {\n return \"blob\";\n }\n return \"text\";\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
const require_errors = require("../errors.cjs");
|
|
2
|
+
const require_driver = require("./driver.cjs");
|
|
3
|
+
//#region src/drivers/s3.ts
|
|
4
|
+
/**
|
|
5
|
+
* S3-based database driver using JSON objects for storage
|
|
6
|
+
*/
|
|
7
|
+
var S3Driver = class extends require_driver.BaseDriver {
|
|
8
|
+
config;
|
|
9
|
+
data = /* @__PURE__ */ new Map();
|
|
10
|
+
client = null;
|
|
11
|
+
constructor(config) {
|
|
12
|
+
super();
|
|
13
|
+
this.config = config;
|
|
14
|
+
}
|
|
15
|
+
getKey(tableName) {
|
|
16
|
+
return `${this.config.prefix ? `${this.config.prefix}/` : ""}${tableName}.json`;
|
|
17
|
+
}
|
|
18
|
+
async connect() {
|
|
19
|
+
if (this.connected) return;
|
|
20
|
+
try {
|
|
21
|
+
const { S3Client, HeadBucketCommand } = await import("@aws-sdk/client-s3");
|
|
22
|
+
const clientConfig = {};
|
|
23
|
+
if (this.config.region) clientConfig.region = this.config.region;
|
|
24
|
+
if (this.config.endpoint) {
|
|
25
|
+
clientConfig.endpoint = this.config.endpoint;
|
|
26
|
+
clientConfig.forcePathStyle = true;
|
|
27
|
+
}
|
|
28
|
+
if (this.config.accessKeyId && this.config.secretAccessKey) clientConfig.credentials = {
|
|
29
|
+
accessKeyId: this.config.accessKeyId,
|
|
30
|
+
secretAccessKey: this.config.secretAccessKey
|
|
31
|
+
};
|
|
32
|
+
this.client = new S3Client(clientConfig);
|
|
33
|
+
try {
|
|
34
|
+
await this.client.send(new HeadBucketCommand({ Bucket: this.config.bucket }));
|
|
35
|
+
} catch (err) {
|
|
36
|
+
if (err.name === "NotFound" || err.$metadata?.httpStatusCode === 404) {
|
|
37
|
+
const { CreateBucketCommand } = await import("@aws-sdk/client-s3");
|
|
38
|
+
await this.client.send(new CreateBucketCommand({ Bucket: this.config.bucket }));
|
|
39
|
+
} else if (err.$metadata?.httpStatusCode !== 200) throw err;
|
|
40
|
+
}
|
|
41
|
+
await this.loadAll();
|
|
42
|
+
this.connected = true;
|
|
43
|
+
} catch (err) {
|
|
44
|
+
throw new require_errors.DriverError(`Failed to connect to S3: ${err.message}`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
async disconnect() {
|
|
48
|
+
await this.flushAll();
|
|
49
|
+
this.data.clear();
|
|
50
|
+
this.client = null;
|
|
51
|
+
this.connected = false;
|
|
52
|
+
}
|
|
53
|
+
async execute(sql, params = []) {
|
|
54
|
+
return this.executeParsed(sql, params);
|
|
55
|
+
}
|
|
56
|
+
async query(sql, params = []) {
|
|
57
|
+
const result = this.executeParsed(sql, params);
|
|
58
|
+
return Array.isArray(result) ? result : [];
|
|
59
|
+
}
|
|
60
|
+
async tableExists(name) {
|
|
61
|
+
return this.data.has(name);
|
|
62
|
+
}
|
|
63
|
+
async getTableColumns(name) {
|
|
64
|
+
const table = this.data.get(name);
|
|
65
|
+
if (!table) return [];
|
|
66
|
+
return Object.values(table.meta.columns);
|
|
67
|
+
}
|
|
68
|
+
async createTable(meta) {
|
|
69
|
+
if (this.data.has(meta.name)) return;
|
|
70
|
+
this.data.set(meta.name, {
|
|
71
|
+
rows: [],
|
|
72
|
+
autoIncrementId: 0,
|
|
73
|
+
meta: { columns: [...meta.columns] }
|
|
74
|
+
});
|
|
75
|
+
await this.flush(meta.name);
|
|
76
|
+
}
|
|
77
|
+
async dropTable(name) {
|
|
78
|
+
this.data.delete(name);
|
|
79
|
+
try {
|
|
80
|
+
const { DeleteObjectCommand } = await import("@aws-sdk/client-s3");
|
|
81
|
+
await this.client.send(new DeleteObjectCommand({
|
|
82
|
+
Bucket: this.config.bucket,
|
|
83
|
+
Key: this.getKey(name)
|
|
84
|
+
}));
|
|
85
|
+
} catch {}
|
|
86
|
+
}
|
|
87
|
+
async addColumn(table, column) {
|
|
88
|
+
const tableData = this.data.get(table);
|
|
89
|
+
if (!tableData) throw new require_errors.DriverError(`Table "${table}" does not exist`);
|
|
90
|
+
tableData.meta.columns.push(column);
|
|
91
|
+
for (const row of tableData.rows) row[column.name] = column.defaultValue ?? null;
|
|
92
|
+
await this.flush(table);
|
|
93
|
+
}
|
|
94
|
+
async dropColumn(table, name) {
|
|
95
|
+
const tableData = this.data.get(table);
|
|
96
|
+
if (!tableData) throw new require_errors.DriverError(`Table "${table}" does not exist`);
|
|
97
|
+
tableData.meta.columns = tableData.meta.columns.filter((c) => c.name !== name);
|
|
98
|
+
for (const row of tableData.rows) delete row[name];
|
|
99
|
+
await this.flush(table);
|
|
100
|
+
}
|
|
101
|
+
async renameColumn(table, oldName, newName) {
|
|
102
|
+
const tableData = this.data.get(table);
|
|
103
|
+
if (!tableData) throw new require_errors.DriverError(`Table "${table}" does not exist`);
|
|
104
|
+
const col = tableData.meta.columns.find((c) => c.name === oldName);
|
|
105
|
+
if (col) col.name = newName;
|
|
106
|
+
for (const row of tableData.rows) {
|
|
107
|
+
row[newName] = row[oldName];
|
|
108
|
+
delete row[oldName];
|
|
109
|
+
}
|
|
110
|
+
await this.flush(table);
|
|
111
|
+
}
|
|
112
|
+
async transaction(fn) {
|
|
113
|
+
const snapshot = /* @__PURE__ */ new Map();
|
|
114
|
+
for (const [name, tableData] of this.data) snapshot.set(name, JSON.stringify(tableData));
|
|
115
|
+
try {
|
|
116
|
+
const result = await fn();
|
|
117
|
+
await this.flushAll();
|
|
118
|
+
return result;
|
|
119
|
+
} catch (err) {
|
|
120
|
+
for (const [name, json] of snapshot) this.data.set(name, JSON.parse(json));
|
|
121
|
+
throw err;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
async getAllTableColumns() {
|
|
125
|
+
const result = {};
|
|
126
|
+
for (const [name, tableData] of this.data) result[name] = [...tableData.meta.columns];
|
|
127
|
+
return result;
|
|
128
|
+
}
|
|
129
|
+
getTableData(tableName) {
|
|
130
|
+
return this.data.get(tableName);
|
|
131
|
+
}
|
|
132
|
+
insertRow(tableName, row) {
|
|
133
|
+
const tableData = this.data.get(tableName);
|
|
134
|
+
if (!tableData) throw new require_errors.DriverError(`Table "${tableName}" does not exist`);
|
|
135
|
+
let pkCol = null;
|
|
136
|
+
for (const col of tableData.meta.columns) if (col.autoIncrement) {
|
|
137
|
+
pkCol = col.name;
|
|
138
|
+
break;
|
|
139
|
+
}
|
|
140
|
+
if (pkCol && row[pkCol] === void 0) {
|
|
141
|
+
tableData.autoIncrementId++;
|
|
142
|
+
row[pkCol] = tableData.autoIncrementId;
|
|
143
|
+
}
|
|
144
|
+
tableData.rows.push({ ...row });
|
|
145
|
+
this.flush(tableName);
|
|
146
|
+
return pkCol ? row[pkCol] : 0;
|
|
147
|
+
}
|
|
148
|
+
findRows(tableName, filter) {
|
|
149
|
+
const tableData = this.data.get(tableName);
|
|
150
|
+
if (!tableData) return [];
|
|
151
|
+
if (!filter) return tableData.rows.map((r) => ({ ...r }));
|
|
152
|
+
return tableData.rows.filter(filter).map((r) => ({ ...r }));
|
|
153
|
+
}
|
|
154
|
+
updateRows(tableName, filter, data) {
|
|
155
|
+
const tableData = this.data.get(tableName);
|
|
156
|
+
if (!tableData) return 0;
|
|
157
|
+
let count = 0;
|
|
158
|
+
for (const row of tableData.rows) if (filter(row)) {
|
|
159
|
+
Object.assign(row, data);
|
|
160
|
+
count++;
|
|
161
|
+
}
|
|
162
|
+
if (count > 0) this.flush(tableName);
|
|
163
|
+
return count;
|
|
164
|
+
}
|
|
165
|
+
deleteRows(tableName, filter) {
|
|
166
|
+
const tableData = this.data.get(tableName);
|
|
167
|
+
if (!tableData) return 0;
|
|
168
|
+
const before = tableData.rows.length;
|
|
169
|
+
tableData.rows = tableData.rows.filter((r) => !filter(r));
|
|
170
|
+
const deleted = before - tableData.rows.length;
|
|
171
|
+
if (deleted > 0) this.flush(tableName);
|
|
172
|
+
return deleted;
|
|
173
|
+
}
|
|
174
|
+
truncateTable(tableName) {
|
|
175
|
+
const tableData = this.data.get(tableName);
|
|
176
|
+
if (tableData) {
|
|
177
|
+
tableData.rows = [];
|
|
178
|
+
tableData.autoIncrementId = 0;
|
|
179
|
+
this.flush(tableName);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
countRows(tableName, filter) {
|
|
183
|
+
const tableData = this.data.get(tableName);
|
|
184
|
+
if (!tableData) return 0;
|
|
185
|
+
if (!filter) return tableData.rows.length;
|
|
186
|
+
return tableData.rows.filter(filter).length;
|
|
187
|
+
}
|
|
188
|
+
async loadAll() {
|
|
189
|
+
try {
|
|
190
|
+
const { ListObjectsV2Command, GetObjectCommand } = await import("@aws-sdk/client-s3");
|
|
191
|
+
const prefix = this.config.prefix ? `${this.config.prefix}/` : "";
|
|
192
|
+
const response = await this.client.send(new ListObjectsV2Command({
|
|
193
|
+
Bucket: this.config.bucket,
|
|
194
|
+
Prefix: prefix
|
|
195
|
+
}));
|
|
196
|
+
if (response.Contents) {
|
|
197
|
+
for (const obj of response.Contents) if (obj.Key?.endsWith(".json")) {
|
|
198
|
+
const tableName = obj.Key.replace(prefix, "").replace(".json", "");
|
|
199
|
+
try {
|
|
200
|
+
const body = await (await this.client.send(new GetObjectCommand({
|
|
201
|
+
Bucket: this.config.bucket,
|
|
202
|
+
Key: obj.Key
|
|
203
|
+
}))).Body?.transformToString();
|
|
204
|
+
if (body) this.data.set(tableName, JSON.parse(body));
|
|
205
|
+
} catch {}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
} catch {}
|
|
209
|
+
}
|
|
210
|
+
async flush(tableName) {
|
|
211
|
+
const tableData = this.data.get(tableName);
|
|
212
|
+
if (!tableData || !this.client) return;
|
|
213
|
+
try {
|
|
214
|
+
const { PutObjectCommand } = await import("@aws-sdk/client-s3");
|
|
215
|
+
await this.client.send(new PutObjectCommand({
|
|
216
|
+
Bucket: this.config.bucket,
|
|
217
|
+
Key: this.getKey(tableName),
|
|
218
|
+
Body: JSON.stringify(tableData),
|
|
219
|
+
ContentType: "application/json"
|
|
220
|
+
}));
|
|
221
|
+
} catch {}
|
|
222
|
+
}
|
|
223
|
+
async flushAll() {
|
|
224
|
+
for (const [name] of this.data) await this.flush(name);
|
|
225
|
+
}
|
|
226
|
+
executeParsed(sql, params) {
|
|
227
|
+
const trimmed = sql.trim().toUpperCase();
|
|
228
|
+
if (trimmed.startsWith("CREATE TABLE")) return {
|
|
229
|
+
insertId: 0,
|
|
230
|
+
affectedRows: 0
|
|
231
|
+
};
|
|
232
|
+
if (trimmed.startsWith("DROP TABLE")) {
|
|
233
|
+
const match = sql.match(/DROP\s+TABLE\s+(?:IF\s+EXISTS\s+)?`?(\w+)`?/i);
|
|
234
|
+
if (match?.[1]) this.data.delete(match[1]);
|
|
235
|
+
return {
|
|
236
|
+
insertId: 0,
|
|
237
|
+
affectedRows: 0
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
if (trimmed.startsWith("SELECT")) {
|
|
241
|
+
const tableMatch = sql.match(/FROM\s+`?(\w+)`?/i);
|
|
242
|
+
if (!tableMatch) return [];
|
|
243
|
+
const tableName = tableMatch[1];
|
|
244
|
+
if (!tableName) return [];
|
|
245
|
+
return this.findRows(tableName);
|
|
246
|
+
}
|
|
247
|
+
if (trimmed.startsWith("INSERT")) {
|
|
248
|
+
const tableMatch = sql.match(/INTO\s+`?(\w+)`?/i);
|
|
249
|
+
if (!tableMatch) return {
|
|
250
|
+
insertId: 0,
|
|
251
|
+
affectedRows: 0
|
|
252
|
+
};
|
|
253
|
+
const colMatch = sql.match(/\(([^)]+)\)\s+VALUES/i);
|
|
254
|
+
if (!colMatch) return {
|
|
255
|
+
insertId: 0,
|
|
256
|
+
affectedRows: 0
|
|
257
|
+
};
|
|
258
|
+
const cols = colMatch[1]?.split(",").map((c) => c.trim().replace(/`/g, ""));
|
|
259
|
+
if (!cols) return {
|
|
260
|
+
insertId: 0,
|
|
261
|
+
affectedRows: 0
|
|
262
|
+
};
|
|
263
|
+
const row = {};
|
|
264
|
+
for (let i = 0; i < cols.length; i++) {
|
|
265
|
+
const col = cols[i];
|
|
266
|
+
if (col) row[col] = params[i];
|
|
267
|
+
}
|
|
268
|
+
return {
|
|
269
|
+
insertId: this.insertRow(tableMatch[1], row),
|
|
270
|
+
affectedRows: 1
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
return {
|
|
274
|
+
insertId: 0,
|
|
275
|
+
affectedRows: 0
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
};
|
|
279
|
+
//#endregion
|
|
280
|
+
exports.S3Driver = S3Driver;
|
|
281
|
+
|
|
282
|
+
//# sourceMappingURL=s3.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"s3.cjs","names":["BaseDriver","DriverError"],"sources":["../../src/drivers/s3.ts"],"sourcesContent":["import { DriverError } from \"../errors\";\nimport type { ColumnMetadata, S3ConnectionConfig, TableMetadata } from \"../types\";\nimport { BaseDriver } from \"./driver\";\n\ninterface S3TableData {\n rows: Record<string, unknown>[];\n autoIncrementId: number;\n meta: {\n columns: ColumnMetadata[];\n };\n}\n\n/**\n * S3-based database driver using JSON objects for storage\n */\nexport class S3Driver extends BaseDriver {\n private config: S3ConnectionConfig;\n private data = new Map<string, S3TableData>();\n private client: any = null;\n\n constructor(config: S3ConnectionConfig) {\n super();\n this.config = config;\n }\n\n private getKey(tableName: string): string {\n const prefix = this.config.prefix ? `${this.config.prefix}/` : \"\";\n return `${prefix}${tableName}.json`;\n }\n\n async connect(): Promise<void> {\n if (this.connected) {\n return;\n }\n\n try {\n const { S3Client, HeadBucketCommand } = await import(\"@aws-sdk/client-s3\");\n const clientConfig: any = {};\n if (this.config.region) {\n clientConfig.region = this.config.region;\n }\n if (this.config.endpoint) {\n clientConfig.endpoint = this.config.endpoint;\n clientConfig.forcePathStyle = true;\n }\n if (this.config.accessKeyId && this.config.secretAccessKey) {\n clientConfig.credentials = {\n accessKeyId: this.config.accessKeyId,\n secretAccessKey: this.config.secretAccessKey,\n };\n }\n this.client = new S3Client(clientConfig);\n\n try {\n await this.client.send(new HeadBucketCommand({ Bucket: this.config.bucket }));\n } catch (err: any) {\n if (err.name === \"NotFound\" || err.$metadata?.httpStatusCode === 404) {\n const { CreateBucketCommand } = await import(\"@aws-sdk/client-s3\");\n await this.client.send(new CreateBucketCommand({ Bucket: this.config.bucket }));\n } else if (err.$metadata?.httpStatusCode !== 200) {\n throw err;\n }\n }\n\n await this.loadAll();\n this.connected = true;\n } catch (err: any) {\n throw new DriverError(`Failed to connect to S3: ${err.message}`);\n }\n }\n\n async disconnect(): Promise<void> {\n await this.flushAll();\n this.data.clear();\n this.client = null;\n this.connected = false;\n }\n\n async execute(sql: string, params: unknown[] = []): Promise<any> {\n return this.executeParsed(sql, params);\n }\n\n async query(sql: string, params: unknown[] = []): Promise<any[]> {\n const result = this.executeParsed(sql, params);\n return Array.isArray(result) ? result : [];\n }\n\n async tableExists(name: string): Promise<boolean> {\n return this.data.has(name);\n }\n\n async getTableColumns(name: string): Promise<ColumnMetadata[]> {\n const table = this.data.get(name);\n if (!table) {\n return [];\n }\n return Object.values(table.meta.columns);\n }\n\n async createTable(meta: TableMetadata): Promise<void> {\n if (this.data.has(meta.name)) {\n return;\n }\n this.data.set(meta.name, {\n rows: [],\n autoIncrementId: 0,\n meta: { columns: [...meta.columns] },\n });\n await this.flush(meta.name);\n }\n\n async dropTable(name: string): Promise<void> {\n this.data.delete(name);\n try {\n const { DeleteObjectCommand } = await import(\"@aws-sdk/client-s3\");\n await this.client.send(\n new DeleteObjectCommand({\n Bucket: this.config.bucket,\n Key: this.getKey(name),\n }),\n );\n } catch {}\n }\n\n async addColumn(table: string, column: ColumnMetadata): Promise<void> {\n const tableData = this.data.get(table);\n if (!tableData) {\n throw new DriverError(`Table \"${table}\" does not exist`);\n }\n tableData.meta.columns.push(column);\n for (const row of tableData.rows) {\n row[column.name] = column.defaultValue ?? null;\n }\n await this.flush(table);\n }\n\n async dropColumn(table: string, name: string): Promise<void> {\n const tableData = this.data.get(table);\n if (!tableData) {\n throw new DriverError(`Table \"${table}\" does not exist`);\n }\n tableData.meta.columns = tableData.meta.columns.filter((c) => c.name !== name);\n for (const row of tableData.rows) {\n delete row[name];\n }\n await this.flush(table);\n }\n\n async renameColumn(table: string, oldName: string, newName: string): Promise<void> {\n const tableData = this.data.get(table);\n if (!tableData) {\n throw new DriverError(`Table \"${table}\" does not exist`);\n }\n const col = tableData.meta.columns.find((c) => c.name === oldName);\n if (col) {\n col.name = newName;\n }\n for (const row of tableData.rows) {\n row[newName] = row[oldName];\n delete row[oldName];\n }\n await this.flush(table);\n }\n\n async transaction<T>(fn: () => Promise<T>): Promise<T> {\n const snapshot = new Map<string, string>();\n for (const [name, tableData] of this.data) {\n snapshot.set(name, JSON.stringify(tableData));\n }\n try {\n const result = await fn();\n await this.flushAll();\n return result;\n } catch (err) {\n for (const [name, json] of snapshot) {\n this.data.set(name, JSON.parse(json));\n }\n throw err;\n }\n }\n\n async getAllTableColumns(): Promise<Record<string, ColumnMetadata[]>> {\n const result: Record<string, ColumnMetadata[]> = {};\n for (const [name, tableData] of this.data) {\n result[name] = [...tableData.meta.columns];\n }\n return result;\n }\n\n getTableData(tableName: string): S3TableData | undefined {\n return this.data.get(tableName);\n }\n\n insertRow(tableName: string, row: Record<string, unknown>): number {\n const tableData = this.data.get(tableName);\n if (!tableData) {\n throw new DriverError(`Table \"${tableName}\" does not exist`);\n }\n let pkCol: string | null = null;\n for (const col of tableData.meta.columns) {\n if (col.autoIncrement) {\n pkCol = col.name;\n break;\n }\n }\n if (pkCol && row[pkCol] === undefined) {\n tableData.autoIncrementId++;\n row[pkCol] = tableData.autoIncrementId;\n }\n tableData.rows.push({ ...row });\n this.flush(tableName);\n return pkCol ? (row[pkCol] as number) : 0;\n }\n\n findRows(\n tableName: string,\n filter?: (row: Record<string, unknown>) => boolean,\n ): Record<string, unknown>[] {\n const tableData = this.data.get(tableName);\n if (!tableData) {\n return [];\n }\n if (!filter) {\n return tableData.rows.map((r) => ({ ...r }));\n }\n return tableData.rows.filter(filter).map((r) => ({ ...r }));\n }\n\n updateRows(\n tableName: string,\n filter: (row: Record<string, unknown>) => boolean,\n data: Record<string, unknown>,\n ): number {\n const tableData = this.data.get(tableName);\n if (!tableData) {\n return 0;\n }\n let count = 0;\n for (const row of tableData.rows) {\n if (filter(row)) {\n Object.assign(row, data);\n count++;\n }\n }\n if (count > 0) {\n this.flush(tableName);\n }\n return count;\n }\n\n deleteRows(tableName: string, filter: (row: Record<string, unknown>) => boolean): number {\n const tableData = this.data.get(tableName);\n if (!tableData) {\n return 0;\n }\n const before = tableData.rows.length;\n tableData.rows = tableData.rows.filter((r) => !filter(r));\n const deleted = before - tableData.rows.length;\n if (deleted > 0) {\n this.flush(tableName);\n }\n return deleted;\n }\n\n truncateTable(tableName: string): void {\n const tableData = this.data.get(tableName);\n if (tableData) {\n tableData.rows = [];\n tableData.autoIncrementId = 0;\n this.flush(tableName);\n }\n }\n\n countRows(tableName: string, filter?: (row: Record<string, unknown>) => boolean): number {\n const tableData = this.data.get(tableName);\n if (!tableData) {\n return 0;\n }\n if (!filter) {\n return tableData.rows.length;\n }\n return tableData.rows.filter(filter).length;\n }\n\n private async loadAll(): Promise<void> {\n try {\n const { ListObjectsV2Command, GetObjectCommand } = await import(\"@aws-sdk/client-s3\");\n const prefix = this.config.prefix ? `${this.config.prefix}/` : \"\";\n const response = await this.client.send(\n new ListObjectsV2Command({\n Bucket: this.config.bucket,\n Prefix: prefix,\n }),\n );\n\n if (response.Contents) {\n for (const obj of response.Contents) {\n if (obj.Key?.endsWith(\".json\")) {\n const tableName = obj.Key.replace(prefix, \"\").replace(\".json\", \"\");\n try {\n const getResponse = await this.client.send(\n new GetObjectCommand({\n Bucket: this.config.bucket,\n Key: obj.Key,\n }),\n );\n const body = await getResponse.Body?.transformToString();\n if (body) {\n this.data.set(tableName, JSON.parse(body));\n }\n } catch {}\n }\n }\n }\n } catch {}\n }\n\n private async flush(tableName: string): Promise<void> {\n const tableData = this.data.get(tableName);\n if (!tableData || !this.client) {\n return;\n }\n try {\n const { PutObjectCommand } = await import(\"@aws-sdk/client-s3\");\n await this.client.send(\n new PutObjectCommand({\n Bucket: this.config.bucket,\n Key: this.getKey(tableName),\n Body: JSON.stringify(tableData),\n ContentType: \"application/json\",\n }),\n );\n } catch {}\n }\n\n private async flushAll(): Promise<void> {\n for (const [name] of this.data) {\n await this.flush(name);\n }\n }\n\n private executeParsed(sql: string, params: unknown[]): any {\n const trimmed = sql.trim().toUpperCase();\n if (trimmed.startsWith(\"CREATE TABLE\")) {\n return { insertId: 0, affectedRows: 0 };\n }\n if (trimmed.startsWith(\"DROP TABLE\")) {\n const match = sql.match(/DROP\\s+TABLE\\s+(?:IF\\s+EXISTS\\s+)?`?(\\w+)`?/i);\n if (match?.[1]) {\n this.data.delete(match[1]);\n }\n return { insertId: 0, affectedRows: 0 };\n }\n if (trimmed.startsWith(\"SELECT\")) {\n const tableMatch = sql.match(/FROM\\s+`?(\\w+)`?/i);\n if (!tableMatch) {\n return [];\n }\n const tableName = tableMatch[1];\n if (!tableName) {\n return [];\n }\n return this.findRows(tableName);\n }\n if (trimmed.startsWith(\"INSERT\")) {\n const tableMatch = sql.match(/INTO\\s+`?(\\w+)`?/i);\n if (!tableMatch) {\n return { insertId: 0, affectedRows: 0 };\n }\n const colMatch = sql.match(/\\(([^)]+)\\)\\s+VALUES/i);\n if (!colMatch) {\n return { insertId: 0, affectedRows: 0 };\n }\n const cols = colMatch[1]?.split(\",\").map((c) => c.trim().replace(/`/g, \"\"));\n if (!cols) {\n return { insertId: 0, affectedRows: 0 };\n }\n const row: Record<string, unknown> = {};\n for (let i = 0; i < cols.length; i++) {\n const col = cols[i];\n if (col) {\n row[col] = params[i];\n }\n }\n const id = this.insertRow(tableMatch[1]!, row);\n return { insertId: id, affectedRows: 1 };\n }\n return { insertId: 0, affectedRows: 0 };\n }\n}\n"],"mappings":"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"}
|