diff --git a/packages/api/src/controllers/databaseConnections.js b/packages/api/src/controllers/databaseConnections.js index 1503e735e..85e90d89d 100644 --- a/packages/api/src/controllers/databaseConnections.js +++ b/packages/api/src/controllers/databaseConnections.js @@ -159,7 +159,7 @@ module.exports = { async collectionData({ conid, database, options }) { const opened = await this.ensureOpened(conid, database); const res = await this.sendRequest(opened, { msgtype: 'collectionData', options }); - return res.result; + return res.result || null; }, async loadDataCore(msgtype, { conid, database, ...args }) { @@ -167,6 +167,10 @@ module.exports = { const res = await this.sendRequest(opened, { msgtype, ...args }); if (res.errorMessage) { console.error(res.errorMessage); + + return { + errorMessage: res.errorMessage, + }; } return res.result || null; }, @@ -193,19 +197,26 @@ module.exports = { callMethod_meta: true, async callMethod({ conid, database, method, args }) { - const opened = await this.ensureOpened(conid, database); - const res = await this.sendRequest(opened, { msgtype: 'callMethod', method, args }); - if (res.errorMessage) { - console.error(res.errorMessage); - } - return res.result || null; + return this.loadDataCore('callMethod', { conid, database, method, args }); + + // const opened = await this.ensureOpened(conid, database); + // const res = await this.sendRequest(opened, { msgtype: 'callMethod', method, args }); + // if (res.errorMessage) { + // console.error(res.errorMessage); + // } + // return res.result || null; }, updateCollection_meta: true, async updateCollection({ conid, database, changeSet }) { const opened = await this.ensureOpened(conid, database); const res = await this.sendRequest(opened, { msgtype: 'updateCollection', changeSet }); - return res.result; + if (res.errorMessage) { + return { + errorMessage: res.errorMessage, + }; + } + return res.result || null; }, status_meta: true, diff --git a/packages/api/src/proc/databaseConnectionProcess.js b/packages/api/src/proc/databaseConnectionProcess.js index 1f721239a..f10ac1874 100644 --- a/packages/api/src/proc/databaseConnectionProcess.js +++ b/packages/api/src/proc/databaseConnectionProcess.js @@ -155,6 +155,7 @@ async function handleRunScript({ msgid, sql }) { await waitConnected(); const driver = requireEngineDriver(storedConnection); try { + ensureExecuteCustomScript(driver); await driver.script(systemConnection, sql); process.send({ msgtype: 'response', msgid }); } catch (err) { @@ -166,6 +167,7 @@ async function handleQueryData({ msgid, sql }) { await waitConnected(); const driver = requireEngineDriver(storedConnection); try { + ensureExecuteCustomScript(driver); const res = await driver.query(systemConnection, sql); process.send({ msgtype: 'response', msgid, ...res }); } catch (err) { @@ -204,7 +206,10 @@ async function handleLoadKeyInfo({ msgid, key }) { } async function handleCallMethod({ msgid, method, args }) { - return handleDriverDataCore(msgid, driver => driver.callMethod(systemConnection, method, args)); + return handleDriverDataCore(msgid, driver => { + ensureExecuteCustomScript(driver); + return driver.callMethod(systemConnection, method, args); + }); } async function handleLoadKeyTableRange({ msgid, key, cursor, count }) { @@ -217,10 +222,20 @@ async function handleLoadFieldValues({ msgid, schemaName, pureName, field, searc ); } +function ensureExecuteCustomScript(driver) { + if (driver.readOnlySessions) { + return; + } + if (storedConnection.isReadOnly) { + throw new Error('Connection is read only'); + } +} + async function handleUpdateCollection({ msgid, changeSet }) { await waitConnected(); const driver = requireEngineDriver(storedConnection); try { + ensureExecuteCustomScript(driver); const result = await driver.updateCollection(systemConnection, changeSet); process.send({ msgtype: 'response', msgid, result }); } catch (err) { diff --git a/packages/api/src/proc/sessionProcess.js b/packages/api/src/proc/sessionProcess.js index e11323f2d..6e8355de9 100644 --- a/packages/api/src/proc/sessionProcess.js +++ b/packages/api/src/proc/sessionProcess.js @@ -135,10 +135,20 @@ function handleStream(driver, resultIndexHolder, sql) { }); } +function ensureExecuteCustomScript(driver) { + if (driver.readOnlySessions) { + return; + } + if (storedConnection.isReadOnly) { + throw new Error('Connection is read only'); + } +} + async function handleConnect(connection) { storedConnection = connection; const driver = requireEngineDriver(storedConnection); + ensureExecuteCustomScript(driver); systemConnection = await connectUtility(driver, storedConnection); for (const [resolve] of afterConnectCallbacks) { resolve(); diff --git a/packages/types/engines.d.ts b/packages/types/engines.d.ts index d5529be5c..22de715f9 100644 --- a/packages/types/engines.d.ts +++ b/packages/types/engines.d.ts @@ -47,6 +47,7 @@ export interface EngineDriver { title: string; defaultPort?: number; databaseEngineTypes: string[]; + readOnlySessions: boolean, supportedKeyTypes: { name: string; label: string }[]; supportsDatabaseUrl?: boolean; isElectronOnly?: boolean; diff --git a/packages/web/src/tabs/CollectionDataTab.svelte b/packages/web/src/tabs/CollectionDataTab.svelte index db7ab7728..a48703afb 100644 --- a/packages/web/src/tabs/CollectionDataTab.svelte +++ b/packages/web/src/tabs/CollectionDataTab.svelte @@ -173,6 +173,6 @@ - + diff --git a/packages/web/src/tabs/QueryTab.svelte b/packages/web/src/tabs/QueryTab.svelte index 94f50a8b4..dc11c89ee 100644 --- a/packages/web/src/tabs/QueryTab.svelte +++ b/packages/web/src/tabs/QueryTab.svelte @@ -140,7 +140,7 @@ } export function hasConnection() { - return !!conid; + return !!conid && (!$connection.isReadOnly || driver.readOnlySessions); } async function executeCore(sql) { diff --git a/plugins/dbgate-plugin-mongo/src/frontend/driver.js b/plugins/dbgate-plugin-mongo/src/frontend/driver.js index 146762712..9a06164bf 100644 --- a/plugins/dbgate-plugin-mongo/src/frontend/driver.js +++ b/plugins/dbgate-plugin-mongo/src/frontend/driver.js @@ -38,9 +38,9 @@ const driver = { showConnectionField: (field, values) => { if (field == 'useDatabaseUrl') return true; if (values.useDatabaseUrl) { - return ['databaseUrl', 'defaultDatabase', 'singleDatabase'].includes(field); + return ['databaseUrl', 'defaultDatabase', 'singleDatabase', 'isReadOnly'].includes(field); } - return ['server', 'port', 'user', 'password', 'defaultDatabase', 'singleDatabase'].includes(field); + return ['server', 'port', 'user', 'password', 'defaultDatabase', 'singleDatabase', 'isReadOnly'].includes(field); }, importExportArgs: [ diff --git a/plugins/dbgate-plugin-mysql/src/frontend/drivers.js b/plugins/dbgate-plugin-mysql/src/frontend/drivers.js index 7b889f014..77c27ba30 100644 --- a/plugins/dbgate-plugin-mysql/src/frontend/drivers.js +++ b/plugins/dbgate-plugin-mysql/src/frontend/drivers.js @@ -46,6 +46,7 @@ const mysqlDriverBase = { dialect, defaultPort: 3306, getQuerySplitterOptions: () => mysqlSplitterOptions, + readOnlySessions: true, getNewObjectTemplates() { return [