diff --git a/src/drivers/common-sql-imp.ts b/src/drivers/common-sql-imp.ts new file mode 100644 index 00000000..a3a76759 --- /dev/null +++ b/src/drivers/common-sql-imp.ts @@ -0,0 +1,112 @@ +import { validateOperation } from "@/components/lib/validation"; +import { + BaseDriver, + DatabaseTableOperation, + DatabaseTableOperationReslt, + DatabaseTableSchema, +} from "./base-driver"; +import { + generateDeleteStatement, + generateInsertStatement, + generateSelectOneWithConditionStatement, + generateUpdateStatement, +} from "./sqlite/sql-helper"; + +export default abstract class CommonSQLImplement extends BaseDriver { + protected validateUpdateOperation( + ops: DatabaseTableOperation[], + validateSchema: DatabaseTableSchema + ) { + for (const op of ops) { + const { valid, reason } = validateOperation(op, validateSchema); + if (!valid) { + throw new Error(reason); + } + } + } + + async updateTableData( + tableName: string, + ops: DatabaseTableOperation[], + validateSchema?: DatabaseTableSchema + ): Promise { + if (validateSchema) { + this.validateUpdateOperation(ops, validateSchema); + } + + const sqls = ops.map((op) => { + if (op.operation === "INSERT") + return generateInsertStatement(tableName, op.values); + if (op.operation === "DELETE") + return generateDeleteStatement(tableName, op.where); + + return generateUpdateStatement(tableName, op.where, op.values); + }); + + const result = await this.transaction(sqls); + + const tmp: DatabaseTableOperationReslt[] = []; + + for (let i = 0; i < result.length; i++) { + const r = result[i]; + const op = ops[i]; + + if (!r || !op) { + tmp.push({}); + continue; + } + + if (op.operation === "UPDATE") { + const selectStatement = generateSelectOneWithConditionStatement( + tableName, + op.where + ); + + // This transform to make it friendly for sending via HTTP + const selectResult = await this.query(selectStatement); + + tmp.push({ + lastId: r.lastInsertRowid, + record: selectResult.rows[0], + }); + } else if (op.operation === "INSERT") { + if (op.autoIncrementPkColumn) { + const selectStatement = generateSelectOneWithConditionStatement( + tableName, + { [op.autoIncrementPkColumn]: r.lastInsertRowid } + ); + + // This transform to make it friendly for sending via HTTP + const selectResult = await this.query(selectStatement); + + tmp.push({ + record: selectResult.rows[0], + lastId: r.lastInsertRowid, + }); + } else if (op.pk && op.pk.length > 0) { + const selectStatement = generateSelectOneWithConditionStatement( + tableName, + op.pk.reduce>((a, b) => { + a[b] = op.values[b]; + return a; + }, {}) + ); + + // This transform to make it friendly for sending via HTTP + const selectResult = await this.query(selectStatement); + + tmp.push({ + record: selectResult.rows[0], + lastId: r.lastInsertRowid, + }); + } else { + tmp.push({}); + } + } else { + tmp.push({}); + } + } + + return tmp; + } +} diff --git a/src/drivers/iframe-driver.ts b/src/drivers/iframe-driver.ts index 993cfbab..6906268b 100644 --- a/src/drivers/iframe-driver.ts +++ b/src/drivers/iframe-driver.ts @@ -20,13 +20,10 @@ type PromiseResolveReject = { reject: (value: string) => void; }; -export default class IframeDriver extends SqliteLikeBaseDriver { +class IframeConnection { protected counter = 0; protected queryPromise: Record = {}; - /** - * This will listen to the parent window response - */ listen() { const handler = (e: MessageEvent) => { if (e.data.error) { @@ -73,8 +70,11 @@ export default class IframeDriver extends SqliteLikeBaseDriver { ); }); } +} - close(): void { - // do nothing - } +export default class IframeDriver extends SqliteLikeBaseDriver { + protected conn = new IframeConnection(); + listen = this.conn.listen; + query = this.conn.query; + transaction = this.conn.transaction; } diff --git a/src/drivers/mysql/mysql-driver.ts b/src/drivers/mysql/mysql-driver.ts new file mode 100644 index 00000000..7cc4e5c6 --- /dev/null +++ b/src/drivers/mysql/mysql-driver.ts @@ -0,0 +1,5 @@ +import CommonSQLImplement from "../common-sql-imp"; + +export default abstract class MySQLLikeDriver extends CommonSQLImplement { + +} diff --git a/src/drivers/sqlite-base-driver.ts b/src/drivers/sqlite-base-driver.ts index 92ea63e5..a5a2d2d1 100644 --- a/src/drivers/sqlite-base-driver.ts +++ b/src/drivers/sqlite-base-driver.ts @@ -1,38 +1,25 @@ -import { validateOperation } from "@/components/lib/validation"; import type { DatabaseResultSet, DatabaseSchemaItem, DatabaseSchemas, DatabaseTableColumn, - DatabaseTableOperation, - DatabaseTableOperationReslt, DatabaseTableSchema, DatabaseTriggerSchema, DatabaseValue, DriverFlags, SelectFromTableOptions, } from "./base-driver"; -import { BaseDriver } from "./base-driver"; - -import { - escapeSqlValue, - generateInsertStatement, - generateDeleteStatement, - generateUpdateStatement, - generateSelectOneWithConditionStatement, -} from "@/drivers/sqlite/sql-helper"; +import { escapeSqlValue } from "@/drivers/sqlite/sql-helper"; import { parseCreateTableScript } from "@/drivers/sqlite/sql-parse-table"; import { parseCreateTriggerScript } from "@/drivers/sqlite/sql-parse-trigger"; +import CommonSQLImplement from "./common-sql-imp"; -export abstract class SqliteLikeBaseDriver extends BaseDriver { +export abstract class SqliteLikeBaseDriver extends CommonSQLImplement { protected escapeId(id: string) { return `"${id.replace(/"/g, '""')}"`; } - abstract override query(stmt: string): Promise; - abstract override transaction(stmts: string[]): Promise; - getFlags(): DriverFlags { return { supportBigInt: false, @@ -191,102 +178,4 @@ export abstract class SqliteLikeBaseDriver extends BaseDriver { schema: await this.tableSchema(tableName), }; } - - protected validateUpdateOperation( - ops: DatabaseTableOperation[], - validateSchema: DatabaseTableSchema - ) { - for (const op of ops) { - const { valid, reason } = validateOperation(op, validateSchema); - if (!valid) { - throw new Error(reason); - } - } - } - - async updateTableData( - tableName: string, - ops: DatabaseTableOperation[], - validateSchema?: DatabaseTableSchema - ): Promise { - if (validateSchema) { - this.validateUpdateOperation(ops, validateSchema); - } - - const sqls = ops.map((op) => { - if (op.operation === "INSERT") - return generateInsertStatement(tableName, op.values); - if (op.operation === "DELETE") - return generateDeleteStatement(tableName, op.where); - - return generateUpdateStatement(tableName, op.where, op.values); - }); - - const result = await this.transaction(sqls); - console.log("result", result); - - const tmp: DatabaseTableOperationReslt[] = []; - - for (let i = 0; i < result.length; i++) { - const r = result[i]; - const op = ops[i]; - - if (!r || !op) { - tmp.push({}); - continue; - } - - if (op.operation === "UPDATE") { - const selectStatement = generateSelectOneWithConditionStatement( - tableName, - op.where - ); - - // This transform to make it friendly for sending via HTTP - const selectResult = await this.query(selectStatement); - - tmp.push({ - lastId: r.lastInsertRowid, - record: selectResult.rows[0], - }); - } else if (op.operation === "INSERT") { - if (op.autoIncrementPkColumn) { - const selectStatement = generateSelectOneWithConditionStatement( - tableName, - { [op.autoIncrementPkColumn]: r.lastInsertRowid } - ); - - // This transform to make it friendly for sending via HTTP - const selectResult = await this.query(selectStatement); - - tmp.push({ - record: selectResult.rows[0], - lastId: r.lastInsertRowid, - }); - } else if (op.pk && op.pk.length > 0) { - const selectStatement = generateSelectOneWithConditionStatement( - tableName, - op.pk.reduce>((a, b) => { - a[b] = op.values[b]; - return a; - }, {}) - ); - - // This transform to make it friendly for sending via HTTP - const selectResult = await this.query(selectStatement); - - tmp.push({ - record: selectResult.rows[0], - lastId: r.lastInsertRowid, - }); - } else { - tmp.push({}); - } - } else { - tmp.push({}); - } - } - - return tmp; - } }