diff --git a/packages/types/engines.d.ts b/packages/types/engines.d.ts index 27efb0b64..b53e06e8b 100644 --- a/packages/types/engines.d.ts +++ b/packages/types/engines.d.ts @@ -38,7 +38,10 @@ export interface EngineDriver { title: string; defaultPort?: number; supportsDatabaseUrl?: boolean; - isFileDatabase?: boolean; + isElectronOnly?: boolean; + showConnectionField?: (field: string, values: any) => boolean; + showConnectionTab?: (tab: 'ssl' | 'sshTunnel', values: any) => boolean; + beforeConnectionSave?: (values: any) => any; databaseUrlPlaceholder?: string; connect({ server, port, user, password, database }): any; query(pool: any, sql: string): Promise; diff --git a/packages/web/src/modals/ConnectionModal.svelte b/packages/web/src/modals/ConnectionModal.svelte index 120b03f7f..6331302db 100644 --- a/packages/web/src/modals/ConnectionModal.svelte +++ b/packages/web/src/modals/ConnectionModal.svelte @@ -51,19 +51,29 @@ } async function handleSubmit(e) { - const connection = driver?.isFileDatabase - ? { - ..._.omit(e.detail, ['server', 'port', 'defaultDatabase']), - singleDatabase: true, - defaultDatabase: getDatabaseFileLabel(e.detail.databaseFile), - } - : { - ..._.omit(e.detail, ['databaseFile']), - singleDatabase: e.detail.defaultDatabase ? e.detail.singleDatabase : false, - }; + const allProps = [ + 'databaseFile', + 'useDatabaseUrl', + 'databaseUrl', + 'authType', + 'server', + 'port', + 'user', + 'password', + 'defaultDatabase', + 'singleDatabase', + ]; + const visibleProps = allProps.filter(x => !driver?.showConnectionField || driver.showConnectionField(x, $values)); + const omitProps = _.difference(allProps, visibleProps); + if (!$values.defaultDatabase) omitProps.push('singleDatabase'); + + let connection = _.omit(e.detail, omitProps); + if (driver?.beforeConnectionSave) connection = driver?.beforeConnectionSave(connection); + axiosInstance.post('connections/save', connection); closeCurrentModal(); } + @@ -77,11 +87,11 @@ label: 'Main', component: ConnectionModalDriverFields, }, - !driver?.isFileDatabase && { + (!driver?.showConnectionTab || driver?.showConnectionTab('sshTunnel', $values)) && { label: 'SSH Tunnel', component: ConnectionModalSshTunnelFields, }, - !driver?.isFileDatabase && { + (!driver?.showConnectionTab || driver?.showConnectionTab('ssl', $values)) && { label: 'SSL', component: ConnectionModalSslFields, }, @@ -146,4 +156,5 @@ .error-result { white-space: normal; } + diff --git a/packages/web/src/modals/ConnectionModalDriverFields.svelte b/packages/web/src/modals/ConnectionModalDriverFields.svelte index cd91a55ad..7696e54e6 100644 --- a/packages/web/src/modals/ConnectionModalDriverFields.svelte +++ b/packages/web/src/modals/ConnectionModalDriverFields.svelte @@ -24,6 +24,7 @@ $: disabledFields = (currentAuthType ? currentAuthType.disabledFields : null) || []; $: driver = $extensions.drivers.find(x => x.engine == engine); $: defaultDatabase = $values.defaultDatabase; + !driver.isFileDatabase || electron) + .filter(driver => !driver.isElectronOnly || electron) .map(driver => ({ value: driver.engine, label: driver.title, @@ -41,44 +42,48 @@ ]} /> -{#if driver?.isFileDatabase} +{#if !driver?.showConnectionField || driver.showConnectionField('databaseFile', $values)} -{:else} - {#if driver?.supportsDatabaseUrl} -
- + +
+{/if} + +{#if !driver?.showConnectionField || driver.showConnectionField('databaseUrl', $values)} + +{/if} + +{#if $authTypes && (!driver?.showConnectionField || driver.showConnectionField('authType', $values))} + ({ + value: auth.name, + label: auth.title, + }))} + /> +{/if} + +{#if !driver?.showConnectionField || driver.showConnectionField('server', $values)} +
+
+
- {/if} - - {#if driver?.supportsDatabaseUrl && useDatabaseUrl} - - {:else} - {#if $authTypes} - ({ - value: auth.name, - label: auth.title, - }))} - /> - {/if} - -
-
- -
+ {#if !driver?.showConnectionField || driver.showConnectionField('port', $values)}
-
+ {/if} +
+{/if} -
-
- -
+{#if !driver?.showConnectionField || driver.showConnectionField('user', $values)} +
+
+ +
+ {#if !driver?.showConnectionField || driver.showConnectionField('password', $values)}
-
- - {#if !disabledFields.includes('password')} - {/if} - {/if} +
+{/if} +{#if !disabledFields.includes('password') && (!driver?.showConnectionField || driver.showConnectionField('password', $values))} + +{/if} + +{#if !driver?.showConnectionField || driver.showConnectionField('defaultDatabase', $values)} +{/if} - {#if defaultDatabase} - - {/if} +{#if defaultDatabase && (!driver?.showConnectionField || driver.showConnectionField('singleDatabase', $values))} + {/if} @@ -143,4 +154,5 @@ .radio :global(label) { margin-right: 10px; } + diff --git a/packages/web/src/utility/getConnectionLabel.ts b/packages/web/src/utility/getConnectionLabel.ts index f2b578ddd..e028acadb 100644 --- a/packages/web/src/utility/getConnectionLabel.ts +++ b/packages/web/src/utility/getConnectionLabel.ts @@ -21,5 +21,9 @@ export default function getConnectionLabel(connection, { allowExplicitDatabase = if (connection.server) { return connection.server; } + if (connection.singleDatabase && connection.defaultDatabase) { + return `${connection.defaultDatabase}`; + } + return ''; } diff --git a/plugins/dbgate-plugin-mongo/src/frontend/driver.js b/plugins/dbgate-plugin-mongo/src/frontend/driver.js index 9dfd38cd4..aa905f1c6 100644 --- a/plugins/dbgate-plugin-mongo/src/frontend/driver.js +++ b/plugins/dbgate-plugin-mongo/src/frontend/driver.js @@ -34,6 +34,14 @@ const driver = { supportsDatabaseUrl: true, databaseUrlPlaceholder: 'e.g. mongodb://username:password@mongodb.mydomain.net/dbname', + showConnectionField: (field, values) => { + if (field == 'useDatabaseUrl') return true; + if (values.useDatabaseUrl) { + return ['databaseUrl', 'defaultDatabase', 'singleDatabase'].includes(field); + } + return ['server', 'port', 'user', 'password', 'defaultDatabase', 'singleDatabase'].includes(field); + }, + getCollectionUpdateScript(changeSet) { let res = ''; for (const insert of changeSet.inserts) { diff --git a/plugins/dbgate-plugin-mssql/src/frontend/driver.js b/plugins/dbgate-plugin-mssql/src/frontend/driver.js index cbdf9d263..19ecd6fd9 100644 --- a/plugins/dbgate-plugin-mssql/src/frontend/driver.js +++ b/plugins/dbgate-plugin-mssql/src/frontend/driver.js @@ -32,6 +32,9 @@ const driver = { } return dialect; }, + showConnectionField: (field, values) => + ['authType', 'server', 'port', 'user', 'password', 'defaultDatabase', 'singleDatabase'].includes(field), + engine: 'mssql@dbgate-plugin-mssql', title: 'Microsoft SQL Server', defaultPort: 1433, diff --git a/plugins/dbgate-plugin-mysql/src/frontend/drivers.js b/plugins/dbgate-plugin-mysql/src/frontend/drivers.js index aa8c48cec..4aa2df0e6 100644 --- a/plugins/dbgate-plugin-mysql/src/frontend/drivers.js +++ b/plugins/dbgate-plugin-mysql/src/frontend/drivers.js @@ -14,24 +14,27 @@ const dialect = { }, }; -/** @type {import('dbgate-types').EngineDriver} */ -const mysqlDriver = { +const mysqlDriverBase = { ...driverBase, + showConnectionField: (field, values) => + ['server', 'port', 'user', 'password', 'defaultDatabase', 'singleDatabase'].includes(field), dumperClass: Dumper, dialect, + defaultPort: 3306, +}; + +/** @type {import('dbgate-types').EngineDriver} */ +const mysqlDriver = { + ...mysqlDriverBase, engine: 'mysql@dbgate-plugin-mysql', title: 'MySQL', - defaultPort: 3306, }; /** @type {import('dbgate-types').EngineDriver} */ const mariaDriver = { - ...driverBase, - dumperClass: Dumper, - dialect, + ...mysqlDriverBase, engine: 'mariadb@dbgate-plugin-mysql', title: 'MariaDB', - defaultPort: 3306, }; module.exports = [mysqlDriver, mariaDriver]; diff --git a/plugins/dbgate-plugin-postgres/src/backend/drivers.js b/plugins/dbgate-plugin-postgres/src/backend/drivers.js index c863b3b32..95733a320 100644 --- a/plugins/dbgate-plugin-postgres/src/backend/drivers.js +++ b/plugins/dbgate-plugin-postgres/src/backend/drivers.js @@ -97,16 +97,38 @@ const drivers = driverBases.map(driverBase => ({ ...driverBase, analyserClass: Analyser, - async connect({ server, port, user, password, database, ssl }) { - const client = new pg.Client({ - // connectionString: 'postgres://root@localhost:26257/postgres?sslmode=disabke' - host: server, - port, - user, - password, - database: database || 'postgres', - ssl, - }); + async connect({ engine, server, port, user, password, database, databaseUrl, ssl }) { + let options = null; + + if (engine == 'redshift@dbgate-plugin-postgres') { + let url = databaseUrl; + if (url && url.startsWith('jdbc:redshift://')) { + url = url.substring('jdbc:redshift://'.length); + } + if (user && password) { + url = `postgres://${user}:${password}@${url}`; + } else if (user) { + url = `postgres://${user}@${url}`; + } else { + url = `postgres://${url}`; + } + + options = { + connectionString: url, + }; + } else { + options = { + // connectionString: 'postgres://root@localhost:26257/postgres?sslmode=disabke' + host: server, + port, + user, + password, + database: database || 'postgres', + ssl, + }; + } + + const client = new pg.Client(options); await client.connect(); return client; }, diff --git a/plugins/dbgate-plugin-postgres/src/frontend/drivers.js b/plugins/dbgate-plugin-postgres/src/frontend/drivers.js index 040cb936f..0eb99b4cc 100644 --- a/plugins/dbgate-plugin-postgres/src/frontend/drivers.js +++ b/plugins/dbgate-plugin-postgres/src/frontend/drivers.js @@ -15,11 +15,17 @@ const dialect = { stringAgg: true, }; -/** @type {import('dbgate-types').EngineDriver} */ -const postgresDriver = { +const postgresDriverBase = { ...driverBase, dumperClass: Dumper, dialect, + showConnectionField: (field, values) => + ['server', 'port', 'user', 'password', 'defaultDatabase', 'singleDatabase'].includes(field), +}; + +/** @type {import('dbgate-types').EngineDriver} */ +const postgresDriver = { + ...postgresDriverBase, engine: 'postgres@dbgate-plugin-postgres', title: 'Postgre SQL', defaultPort: 5432, @@ -27,9 +33,7 @@ const postgresDriver = { /** @type {import('dbgate-types').EngineDriver} */ const cockroachDriver = { - ...driverBase, - dumperClass: Dumper, - dialect, + ...postgresDriverBase, engine: 'cockroach@dbgate-plugin-postgres', title: 'CockroachDB', defaultPort: 26257, @@ -37,15 +41,30 @@ const cockroachDriver = { /** @type {import('dbgate-types').EngineDriver} */ const redshiftDriver = { - ...driverBase, - dumperClass: Dumper, + ...postgresDriverBase, dialect: { ...dialect, stringAgg: false, }, - engine: 'red@dbgate-plugin-postgres', + engine: 'redshift@dbgate-plugin-postgres', title: 'Amazon Redshift', defaultPort: 5439, + showConnectionField: (field, values) => ['databaseUrl', 'user', 'password'].includes(field), + beforeConnectionSave: connection => { + const { databaseUrl } = connection; + if (databaseUrl) { + const m = databaseUrl.match(/\/([^/]+)$/); + if (m) { + return { + ...connection, + singleDatabase: true, + defaultDatabase: m[1], + // displayName: connection.displayName || `${m[1]} on Amazon Redshift`, + }; + } + } + return connection; + }, }; module.exports = [postgresDriver, cockroachDriver, redshiftDriver]; diff --git a/plugins/dbgate-plugin-sqlite/src/frontend/driver.js b/plugins/dbgate-plugin-sqlite/src/frontend/driver.js index 8bfb95bfb..1d614be4e 100644 --- a/plugins/dbgate-plugin-sqlite/src/frontend/driver.js +++ b/plugins/dbgate-plugin-sqlite/src/frontend/driver.js @@ -1,6 +1,13 @@ const { driverBase } = require('dbgate-tools'); const Dumper = require('./Dumper'); +function getDatabaseFileLabel(databaseFile) { + if (!databaseFile) return databaseFile; + const m = databaseFile.match(/[\/]([^\/]+)$/); + if (m) return m[1]; + return databaseFile; +} + /** @type {import('dbgate-types').SqlDialect} */ const dialect = { limitSelect: true, @@ -13,7 +20,6 @@ const dialect = { }, }; - /** @type {import('dbgate-types').EngineDriver} */ const driver = { ...driverBase, @@ -21,7 +27,15 @@ const driver = { dialect, engine: 'sqlite@dbgate-plugin-sqlite', title: 'SQLite', - isFileDatabase: true, + showConnectionField: (field, values) => field == 'databaseFile', + showConnectionTab: (field) => false, + beforeConnectionSave: (connection) => ({ + ...connection, + singleDatabase: true, + defaultDatabase: getDatabaseFileLabel(connection.databaseFile), + }), + // isFileDatabase: true, + isElectronOnly: true, }; module.exports = driver;