diff --git a/packages/api/src/controllers/databaseConnections.js b/packages/api/src/controllers/databaseConnections.js index 47321775f..8b731c37e 100644 --- a/packages/api/src/controllers/databaseConnections.js +++ b/packages/api/src/controllers/databaseConnections.js @@ -182,6 +182,15 @@ module.exports = { return res; }, + runOperation_meta: true, + async runOperation({ conid, database, operation, useTransaction }, req) { + testConnectionPermission(conid, req); + logger.info({ conid, database, operation }, 'Processing operation'); + const opened = await this.ensureOpened(conid, database); + const res = await this.sendRequest(opened, { msgtype: 'runOperation', operation, useTransaction }); + return res; + }, + collectionData_meta: true, async collectionData({ conid, database, options }, req) { testConnectionPermission(conid, req); diff --git a/packages/api/src/proc/databaseConnectionProcess.js b/packages/api/src/proc/databaseConnectionProcess.js index 9a8756431..894fba18c 100644 --- a/packages/api/src/proc/databaseConnectionProcess.js +++ b/packages/api/src/proc/databaseConnectionProcess.js @@ -170,6 +170,18 @@ async function handleRunScript({ msgid, sql, useTransaction }, skipReadonlyCheck } } +async function handleRunOperation({ msgid, operation, useTransaction }, skipReadonlyCheck = false) { + await waitConnected(); + const driver = requireEngineDriver(storedConnection); + try { + if (!skipReadonlyCheck) ensureExecuteCustomScript(driver); + await driver.operation(systemConnection, operation, { useTransaction }); + process.send({ msgtype: 'response', msgid }); + } catch (err) { + process.send({ msgtype: 'response', msgid, errorMessage: err.message }); + } +} + async function handleQueryData({ msgid, sql }, skipReadonlyCheck = false) { await waitConnected(); const driver = requireEngineDriver(storedConnection); @@ -311,6 +323,7 @@ const messageHandlers = { connect: handleConnect, queryData: handleQueryData, runScript: handleRunScript, + runOperation: handleRunOperation, updateCollection: handleUpdateCollection, collectionData: handleCollectionData, loadKeys: handleLoadKeys, diff --git a/packages/tools/src/driverBase.ts b/packages/tools/src/driverBase.ts index 20044d7a5..e3ea86f91 100644 --- a/packages/tools/src/driverBase.ts +++ b/packages/tools/src/driverBase.ts @@ -81,6 +81,9 @@ export const driverBase = { runCommandOnDriver(pool, this, dmp => dmp.commitTransaction()); } }, + async operation(pool, operation, options: RunScriptOptions) { + throw new Error('Operation not defined in target driver'); + }, getNewObjectTemplates() { if (this.databaseEngineTypes.includes('sql')) { return [{ label: 'New view', sql: 'CREATE VIEW myview\nAS\nSELECT * FROM table1' }]; diff --git a/packages/types/engines.d.ts b/packages/types/engines.d.ts index 4262a4c33..b2f3afea6 100644 --- a/packages/types/engines.d.ts +++ b/packages/types/engines.d.ts @@ -142,6 +142,7 @@ export interface EngineDriver { dropDatabase(pool: any, name: string): Promise; getQuerySplitterOptions(usage: 'stream' | 'script' | 'editor'): any; script(pool: any, sql: string, options?: RunScriptOptions): Promise; + operation(pool: any, operation: {}, options?: RunScriptOptions): Promise; getNewObjectTemplates(): NewObjectTemplate[]; // direct call of pool method, only some methods could be supported, on only some drivers callMethod(pool, method, args); diff --git a/packages/web/src/appobj/DatabaseAppObject.svelte b/packages/web/src/appobj/DatabaseAppObject.svelte index 21c1ce657..57049e89f 100644 --- a/packages/web/src/appobj/DatabaseAppObject.svelte +++ b/packages/web/src/appobj/DatabaseAppObject.svelte @@ -1,5 +1,5 @@