From 2adca6415941329f33832683e9538bb75caea65b Mon Sep 17 00:00:00 2001 From: Jan Prochazka Date: Tue, 4 Oct 2022 20:58:10 +0200 Subject: [PATCH 1/8] socketPath configurable with env variables #358 --- packages/api/src/controllers/connections.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/api/src/controllers/connections.js b/packages/api/src/controllers/connections.js index 7aad6ebb..63b3c872 100644 --- a/packages/api/src/controllers/connections.js +++ b/packages/api/src/controllers/connections.js @@ -53,6 +53,8 @@ function getPortalCollections() { databaseUrl: process.env[`URL_${id}`], useDatabaseUrl: !!process.env[`URL_${id}`], databaseFile: process.env[`FILE_${id}`], + socketPath: process.env[`SOCKET_PATH_${id}`], + authType: process.env[`AUTH_TYPE_${id}`] || (process.env[`SOCKET_PATH_${id}`] ? 'socket' : undefined), defaultDatabase: process.env[`DATABASE_${id}`] || (process.env[`FILE_${id}`] ? getDatabaseFileLabel(process.env[`FILE_${id}`]) : null), From 13d4d3445345b2e900f5ae27843208b7c519cdd2 Mon Sep 17 00:00:00 2001 From: Jan Prochazka Date: Sat, 8 Oct 2022 08:09:45 +0200 Subject: [PATCH 2/8] cond-disable ER diagram and query design #386 --- packages/web/src/commands/stdCommands.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/web/src/commands/stdCommands.ts b/packages/web/src/commands/stdCommands.ts index 951a6759..d5d7834f 100644 --- a/packages/web/src/commands/stdCommands.ts +++ b/packages/web/src/commands/stdCommands.ts @@ -127,6 +127,9 @@ registerCommand({ name: 'Query design', menuName: 'New query design', onClick: () => newQueryDesign(), + testEnabled: () => + getCurrentDatabase() && + findEngineDriver(getCurrentDatabase()?.connection, getExtensions())?.databaseEngineTypes?.includes('sql'), }); registerCommand({ @@ -144,6 +147,9 @@ registerCommand({ icon: 'img diagram', name: 'ER Diagram', menuName: 'New ER diagram', + testEnabled: () => + getCurrentDatabase() && + findEngineDriver(getCurrentDatabase()?.connection, getExtensions())?.databaseEngineTypes?.includes('sql'), onClick: () => newDiagram(), }); From 23cb3a4b12231af0658f85eb571346c5f3788a5f Mon Sep 17 00:00:00 2001 From: Jan Prochazka Date: Sat, 8 Oct 2022 08:34:31 +0200 Subject: [PATCH 3/8] table&database ctx menu improvement --- .../web/src/appobj/DatabaseAppObject.svelte | 37 +++++++++++++++++-- .../src/appobj/DatabaseObjectAppObject.svelte | 22 +++++------ 2 files changed, 44 insertions(+), 15 deletions(-) diff --git a/packages/web/src/appobj/DatabaseAppObject.svelte b/packages/web/src/appobj/DatabaseAppObject.svelte index fba48176..4f9cec01 100644 --- a/packages/web/src/appobj/DatabaseAppObject.svelte +++ b/packages/web/src/appobj/DatabaseAppObject.svelte @@ -229,6 +229,30 @@ }); }; + const handleQueryDesigner = () => { + openNewTab({ + title: 'Query #', + icon: 'img query-design', + tabComponent: 'QueryDesignTab', + props: { + conid: connection._id, + database: name, + }, + }); + }; + + const handleNewPerspective = () => { + openNewTab({ + title: 'Perspective #', + icon: 'img perspective', + tabComponent: 'PerspectiveTab', + props: { + conid: connection._id, + database: name, + }, + }); + }; + async function handleConfirmSql(sql) { saveScriptToDatabase({ conid: connection._id, database: name }, sql, false); } @@ -244,16 +268,21 @@ { onClick: handleNewQuery, text: 'New query', isNewQuery: true }, driver?.databaseEngineTypes?.includes('sql') && { onClick: handleNewTable, text: 'New table' }, driver?.databaseEngineTypes?.includes('document') && { onClick: handleNewCollection, text: 'New collection' }, - isSqlOrDoc && - !connection.isReadOnly && - !connection.singleDatabase && { onClick: handleDropDatabase, text: 'Drop database' }, + driver?.databaseEngineTypes?.includes('sql') && { onClick: handleQueryDesigner, text: 'Design query' }, + driver?.databaseEngineTypes?.includes('sql') && { + onClick: handleNewPerspective, + text: 'Design perspective query', + }, { divider: true }, isSqlOrDoc && !connection.isReadOnly && { onClick: handleImport, text: 'Import wizard' }, isSqlOrDoc && { onClick: handleExport, text: 'Export wizard' }, driver?.databaseEngineTypes?.includes('sql') && { onClick: handleSqlRestore, text: 'Restore/import SQL dump' }, driver?.supportsDatabaseDump && { onClick: handleSqlDump, text: 'Backup/export SQL dump' }, + isSqlOrDoc && + !connection.isReadOnly && + !connection.singleDatabase && { onClick: handleDropDatabase, text: 'Drop database' }, { divider: true }, - isSqlOrDoc && { onClick: handleShowDiagram, text: 'Show diagram' }, + driver?.databaseEngineTypes?.includes('sql') && { onClick: handleShowDiagram, text: 'Show diagram' }, isSqlOrDoc && { onClick: handleSqlGenerator, text: 'SQL Generator' }, isSqlOrDoc && { onClick: handleOpenJsonModel, text: 'Open model as JSON' }, isSqlOrDoc && { onClick: handleExportModel, text: 'Export DB model - experimental' }, diff --git a/packages/web/src/appobj/DatabaseObjectAppObject.svelte b/packages/web/src/appobj/DatabaseObjectAppObject.svelte index a6cceab6..d5d0fac8 100644 --- a/packages/web/src/appobj/DatabaseObjectAppObject.svelte +++ b/packages/web/src/appobj/DatabaseObjectAppObject.svelte @@ -52,7 +52,12 @@ icon: 'img table-structure', }, { - label: 'Open perspective', + label: 'Design query', + isQueryDesigner: true, + requiresWriteAccess: true, + }, + { + label: 'Design perspective query', tab: 'PerspectiveTab', forceNewTab: true, icon: 'img perspective', @@ -80,11 +85,6 @@ isDuplicateTable: true, requiresWriteAccess: true, }, - { - label: 'Query designer', - isQueryDesigner: true, - requiresWriteAccess: true, - }, { label: 'Show diagram', isDiagram: true, @@ -155,7 +155,11 @@ icon: 'img view-structure', }, { - label: 'Open perspective', + label: 'Design query', + isQueryDesigner: true, + }, + { + label: 'Design perspective query', tab: 'PerspectiveTab', forceNewTab: true, icon: 'img perspective', @@ -164,10 +168,6 @@ label: 'Drop view', isDrop: true, }, - { - label: 'Query designer', - isQueryDesigner: true, - }, { divider: true, }, From 2a2debbb882d016183469a7deb69313d847d0925 Mon Sep 17 00:00:00 2001 From: Jan Prochazka Date: Sat, 8 Oct 2022 09:00:19 +0200 Subject: [PATCH 4/8] fix nested mongo id as $oid #387 --- plugins/dbgate-plugin-mongo/src/backend/driver.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/plugins/dbgate-plugin-mongo/src/backend/driver.js b/plugins/dbgate-plugin-mongo/src/backend/driver.js index 756c6a5a..3d6c5a01 100644 --- a/plugins/dbgate-plugin-mongo/src/backend/driver.js +++ b/plugins/dbgate-plugin-mongo/src/backend/driver.js @@ -9,7 +9,9 @@ const AbstractCursor = require('mongodb').AbstractCursor; const createBulkInsertStream = require('./createBulkInsertStream'); function transformMongoData(row) { - return _.mapValues(row, (v) => (v && v.constructor == ObjectId ? { $oid: v.toString() } : v)); + return _.cloneDeepWith(row, (x) => { + if (x && x.constructor == ObjectId) return { $oid: x.toString() }; + }); } async function readCursor(cursor, options) { From f19835203fea16af9bb264f05bdebafa519a1699 Mon Sep 17 00:00:00 2001 From: Jan Prochazka Date: Sat, 8 Oct 2022 09:08:42 +0200 Subject: [PATCH 5/8] fixed pager component #388 --- packages/web/src/elements/Pager.svelte | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/web/src/elements/Pager.svelte b/packages/web/src/elements/Pager.svelte index 0f3af138..d2db8556 100644 --- a/packages/web/src/elements/Pager.svelte +++ b/packages/web/src/elements/Pager.svelte @@ -22,7 +22,7 @@
{ - skip -= limit; + skip = parseInt(skip) - parseInt(limit); if (skip < 0) skip = 0; dispatch('load'); }} @@ -35,7 +35,7 @@ dispatch('load')} on:keydown={handleKeyDown} /> { - skip += limit; + skip = parseInt(skip) + parseInt(limit); dispatch('load'); }} > From dc0001a8cd78129d22208755c560ff583c05de77 Mon Sep 17 00:00:00 2001 From: Jan Prochazka Date: Sat, 8 Oct 2022 21:14:18 +0200 Subject: [PATCH 6/8] sql case configuration #389 --- packages/tools/src/SqlDumper.ts | 16 +++++++++---- packages/web/src/App.svelte | 2 ++ .../web/src/modals/InsertJoinModal.svelte | 7 ++++-- packages/web/src/query/codeCompletion.ts | 23 +++++++++++++------ .../web/src/settings/SettingsModal.svelte | 13 +++++++++++ packages/web/src/settings/settingsTools.ts | 7 ++++++ .../web/src/utility/SettingsListener.svelte | 8 +++++++ 7 files changed, 62 insertions(+), 14 deletions(-) create mode 100644 packages/web/src/utility/SettingsListener.svelte diff --git a/packages/tools/src/SqlDumper.ts b/packages/tools/src/SqlDumper.ts index 3a6de60c..c8bb5c6a 100644 --- a/packages/tools/src/SqlDumper.ts +++ b/packages/tools/src/SqlDumper.ts @@ -32,6 +32,12 @@ export class SqlDumper implements AlterProcessor { dialect: SqlDialect; indentLevel = 0; + static keywordsCase = 'upperCase'; + static convertKeywordCase(keyword: any): string { + if (this.keywordsCase == 'lowerCase') return keyword?.toString()?.toLowerCase(); + return keyword?.toString()?.toUpperCase(); + } + constructor(driver: EngineDriver) { this.driver = driver; this.dialect = driver.dialect; @@ -60,10 +66,10 @@ export class SqlDumper implements AlterProcessor { this.putRaw("'"); } putByteArrayValue(value) { - this.putRaw('NULL'); + this.put('^null'); } putValue(value) { - if (value === null) this.putRaw('NULL'); + if (value === null) this.put('^null'); else if (value === true) this.putRaw('1'); else if (value === false) this.putRaw('0'); else if (_isString(value)) this.putStringValue(value); @@ -71,7 +77,7 @@ export class SqlDumper implements AlterProcessor { else if (_isDate(value)) this.putStringValue(new Date(value).toISOString()); else if (value?.type == 'Buffer' && _isArray(value?.data)) this.putByteArrayValue(value?.data); else if (_isPlainObject(value) || _isArray(value)) this.putStringValue(JSON.stringify(value)); - else this.putRaw('NULL'); + else this.put('^null'); } putCmd(format, ...args) { this.put(format, ...args); @@ -92,7 +98,7 @@ export class SqlDumper implements AlterProcessor { case 'k': { if (value) { - this.putRaw(value.toUpperCase()); + this.putRaw(SqlDumper.convertKeywordCase(value)); } } break; @@ -128,7 +134,7 @@ export class SqlDumper implements AlterProcessor { switch (c) { case '^': while (i < length && format[i].match(/[a-z0-9_]/i)) { - this.putRaw(format[i].toUpperCase()); + this.putRaw(SqlDumper.convertKeywordCase(format[i])); i++; } break; diff --git a/packages/web/src/App.svelte b/packages/web/src/App.svelte index 67c6b22c..6938737e 100644 --- a/packages/web/src/App.svelte +++ b/packages/web/src/App.svelte @@ -19,6 +19,7 @@ import AppTitleProvider from './utility/AppTitleProvider.svelte'; import getElectron from './utility/getElectron'; import AppStartInfo from './widgets/AppStartInfo.svelte'; + import SettingsListener from './utility/SettingsListener.svelte'; let loadedApi = false; let loadedPlugins = false; @@ -79,6 +80,7 @@ {#if loadedPlugins} + {:else} + import { SqlDumper } from 'dbgate-tools'; import FormStyledButton from '../buttons/FormStyledButton.svelte'; import TableControl from '../elements/TableControl.svelte'; import TextField from '../forms/TextField.svelte'; @@ -63,9 +64,11 @@ const source = sources[sourceIndex]; const target = targets[targetIndex]; if (source && target) { - return `${JOIN_TYPES[joinIndex]} ${target.refTable}${alias ? ` ${alias}` : ''} ON ${target.columnMap + return `${SqlDumper.convertKeywordCase(JOIN_TYPES[joinIndex])} ${target.refTable}${ + alias ? ` ${alias}` : '' + } ${SqlDumper.convertKeywordCase('ON')} ${target.columnMap .map(col => `${source.name}.${col.columnName} = ${alias || target.refTable}.${col.refColumnName}`) - .join(' AND ')}`; + .join(SqlDumper.convertKeywordCase(' AND '))}`; } return ''; } diff --git a/packages/web/src/query/codeCompletion.ts b/packages/web/src/query/codeCompletion.ts index e59503b5..ddb66209 100644 --- a/packages/web/src/query/codeCompletion.ts +++ b/packages/web/src/query/codeCompletion.ts @@ -2,6 +2,7 @@ import _ from 'lodash'; import { addCompleter, setCompleters } from 'ace-builds/src-noconflict/ext-language_tools'; import { getDatabaseInfo } from '../utility/metadataLoaders'; import analyseQuerySources from './analyseQuerySources'; +import { getStringSettingsValue } from '../settings/settingsTools'; const COMMON_KEYWORDS = [ 'select', @@ -78,13 +79,21 @@ export function mountCodeCompletion({ conid, database, editor, getText }) { const line = session.getLine(cursor.row).slice(0, cursor.column); const dbinfo = await getDatabaseInfo({ conid, database }); - let list = COMMON_KEYWORDS.map(word => ({ - name: word, - value: word, - caption: word, - meta: 'keyword', - score: 800, - })); + const convertUpper = getStringSettingsValue('sqlEditor.sqlCommandsCase', 'upperCase') == 'upperCase'; + + let list = COMMON_KEYWORDS.map(word => { + if (convertUpper) { + word = word.toUpperCase(); + } + + return { + name: word, + value: word, + caption: word, + meta: 'keyword', + score: 800, + }; + }); if (dbinfo) { const colMatch = line.match(/([a-zA-Z0-9_]+)\.([a-zA-Z0-9_]*)?$/); diff --git a/packages/web/src/settings/SettingsModal.svelte b/packages/web/src/settings/SettingsModal.svelte index 99e0ca35..ebf2d9a1 100644 --- a/packages/web/src/settings/SettingsModal.svelte +++ b/packages/web/src/settings/SettingsModal.svelte @@ -111,6 +111,19 @@ ORDER BY defaultValue="30" disabled={values['connection.autoRefresh'] === false} /> + +
SQL editor
+ +
Application theme
diff --git a/packages/web/src/settings/settingsTools.ts b/packages/web/src/settings/settingsTools.ts index 7c27ad20..dbf739ee 100644 --- a/packages/web/src/settings/settingsTools.ts +++ b/packages/web/src/settings/settingsTools.ts @@ -21,3 +21,10 @@ export function getBoolSettingsValue(name, defaultValue) { if (res == null) return defaultValue; return !!res; } + +export function getStringSettingsValue(name, defaultValue) { + const settings = getCurrentSettings(); + const res = settings[name]; + if (res == null) return defaultValue; + return res; +} diff --git a/packages/web/src/utility/SettingsListener.svelte b/packages/web/src/utility/SettingsListener.svelte new file mode 100644 index 00000000..7dedd6a8 --- /dev/null +++ b/packages/web/src/utility/SettingsListener.svelte @@ -0,0 +1,8 @@ + From f5906587db0568cdf91211c311a2bc2acfaef43c Mon Sep 17 00:00:00 2001 From: Jan Prochazka Date: Thu, 13 Oct 2022 10:52:10 +0200 Subject: [PATCH 7/8] perspectives: prevent multi-load --- packages/web/src/perspectives/PerspectiveTable.svelte | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/packages/web/src/perspectives/PerspectiveTable.svelte b/packages/web/src/perspectives/PerspectiveTable.svelte index 4f7990c4..32a9b97d 100644 --- a/packages/web/src/perspectives/PerspectiveTable.svelte +++ b/packages/web/src/perspectives/PerspectiveTable.svelte @@ -57,6 +57,7 @@ let errorMessage; let rowCount; let isLoading = false; + let isLoadQueued = false; const lastVisibleRowIndexRef = createRef(0); const disableLoadNextRef = createRef(false); @@ -121,6 +122,12 @@ } async function loadData(node: PerspectiveTreeNode, counts) { + if (isLoading) { + isLoadQueued = true; + return; + } else { + isLoadQueued = false; + } // console.log('LOADING', node); if (!node) return; const rows = []; @@ -147,6 +154,10 @@ // loadProps.push(child.getNodeLoadProps()); // } // } + + if (isLoadQueued) { + loadData(root, $loadedCounts); + } } export function openJson() { From a240681d6d468cd1eae55e7e168fc2184ad81568 Mon Sep 17 00:00:00 2001 From: Jan Prochazka Date: Thu, 13 Oct 2022 11:02:25 +0200 Subject: [PATCH 8/8] auto view json #395 --- packages/web/src/perspectives/PerspectiveCell.svelte | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/web/src/perspectives/PerspectiveCell.svelte b/packages/web/src/perspectives/PerspectiveCell.svelte index 2a470890..e4750dfd 100644 --- a/packages/web/src/perspectives/PerspectiveCell.svelte +++ b/packages/web/src/perspectives/PerspectiveCell.svelte @@ -1,6 +1,6 @@ - + {#if value !== undefined} {#if displayType == 'json'} @@ -23,6 +23,8 @@ {:else} (no image) {/if} + {:else if _.isArray(value) || _.isPlainObject(value)} + {:else} {/if}