diff --git a/packages/tools/src/schemaInfoTools.ts b/packages/tools/src/schemaInfoTools.ts index ad82ab046..941410b8e 100644 --- a/packages/tools/src/schemaInfoTools.ts +++ b/packages/tools/src/schemaInfoTools.ts @@ -1,14 +1,19 @@ import { SchemaInfo, SqlDialect } from 'dbgate-types'; -export function findDefaultSchema(schemaList: SchemaInfo[], dialect: SqlDialect) { +export function findDefaultSchema(schemaList: SchemaInfo[], dialect: SqlDialect, schemaInStorage: string = null) { if (!schemaList) { return null; } + + if (schemaInStorage && schemaList.find(x => x.schemaName == schemaInStorage)) { + return schemaInStorage; + } + const dynamicDefaultSchema = schemaList.find(x => x.isDefault); if (dynamicDefaultSchema) { return dynamicDefaultSchema.schemaName; } - if (dialect.defaultSchemaName && schemaList.find(x => x.schemaName == dialect.defaultSchemaName)) { + if (dialect?.defaultSchemaName && schemaList.find(x => x.schemaName == dialect.defaultSchemaName)) { return dialect.defaultSchemaName; } return schemaList[0]?.schemaName; @@ -26,3 +31,7 @@ export function splitCompositeDbName(name: string) { export function extractDbNameFromComposite(name: string) { return isCompositeDbName(name) ? splitCompositeDbName(name).database : name; } + +export function extractSchemaNameFromComposite(name: string) { + return splitCompositeDbName(name)?.schema; +} diff --git a/packages/web/src/appobj/ConnectionAppObject.svelte b/packages/web/src/appobj/ConnectionAppObject.svelte index 8c3020e5b..88a71f67a 100644 --- a/packages/web/src/appobj/ConnectionAppObject.svelte +++ b/packages/web/src/appobj/ConnectionAppObject.svelte @@ -14,7 +14,7 @@ export function openConnection(connection) { const config = getCurrentConfig(); if (connection.singleDatabase) { - currentDatabase.set({ connection, name: connection.defaultDatabase }); + switchCurrentDatabase({ connection, name: connection.defaultDatabase }); apiCall('database-connections/refresh', { conid: connection._id, database: connection.defaultDatabase, @@ -60,7 +60,7 @@ if (electron) { apiCall('database-connections/disconnect', { conid, database: currentDb.name }); } - currentDatabase.set(null); + switchCurrentDatabase(null); } closeMultipleTabs(closeCondition); // if (data.unsaved) { @@ -107,6 +107,7 @@ import { tick } from 'svelte'; import { getConnectionLabel } from 'dbgate-tools'; import hasPermission from '../utility/hasPermission'; + import { switchCurrentDatabase } from '../utility/common'; export let data; export let passProps; @@ -142,7 +143,7 @@ return; } if ($openedSingleDatabaseConnections.includes(data._id)) { - currentDatabase.set({ connection: data, name: data.defaultDatabase }); + switchCurrentDatabase({ connection: data, name: data.defaultDatabase }); return; } if ($openedConnections.includes(data._id)) { diff --git a/packages/web/src/appobj/DatabaseAppObject.svelte b/packages/web/src/appobj/DatabaseAppObject.svelte index b817f6974..120577e74 100644 --- a/packages/web/src/appobj/DatabaseAppObject.svelte +++ b/packages/web/src/appobj/DatabaseAppObject.svelte @@ -26,7 +26,7 @@ apiCall('database-connections/disconnect', { conid, database }); } if (getCurrentDatabase()?.connection?._id == conid && getCurrentDatabase()?.name == database) { - currentDatabase.set(null); + switchCurrentDatabase(null); } openedSingleDatabaseConnections.update(list => list.filter(x => x != conid)); closeMultipleTabs(closeCondition); @@ -374,7 +374,7 @@ import openNewTab from '../utility/openNewTab'; import AppObjectCore from './AppObjectCore.svelte'; import { showSnackbarError, showSnackbarSuccess } from '../utility/snackbar'; - import { findEngineDriver, getConnectionLabel } from 'dbgate-tools'; + import { extractDbNameFromComposite, findEngineDriver, getConnectionLabel } from 'dbgate-tools'; import InputTextModal from '../modals/InputTextModal.svelte'; import { getDatabaseInfo, useUsedApps } from '../utility/metadataLoaders'; import { openJsonDocument } from '../tabs/JsonTab.svelte'; @@ -391,6 +391,7 @@ import hasPermission from '../utility/hasPermission'; import { openImportExportTab } from '../utility/importExportTools'; import newTable from '../tableeditor/newTable'; + import { switchCurrentDatabase } from '../utility/common'; export let data; export let passProps; @@ -419,8 +420,8 @@ colorMark={passProps?.connectionColorFactory && passProps?.connectionColorFactory({ conid: _.get(data.connection, '_id'), database: data.name }, null, null, false)} isBold={_.get($currentDatabase, 'connection._id') == _.get(data.connection, '_id') && - _.get($currentDatabase, 'name') == data.name} - on:click={() => ($currentDatabase = data)} + extractDbNameFromComposite(_.get($currentDatabase, 'name')) == data.name} + on:click={() => switchCurrentDatabase(data)} on:dragstart on:dragenter on:dragend diff --git a/packages/web/src/commands/CommandPalette.svelte b/packages/web/src/commands/CommandPalette.svelte index fc8c96ce1..aea16a20a 100644 --- a/packages/web/src/commands/CommandPalette.svelte +++ b/packages/web/src/commands/CommandPalette.svelte @@ -46,7 +46,7 @@ databaseList.push({ text: `${db.name} on ${getConnectionLabel(connection)}`, icon: 'img database', - onClick: () => currentDatabase.set({ connection, name: db.name }), + onClick: () => switchCurrentDatabase({ connection, name: db.name }), }); } } @@ -80,7 +80,7 @@ import { useConnectionList, useDatabaseInfo } from '../utility/metadataLoaders'; import { getLocalStorage } from '../utility/storageCache'; import registerCommand from './registerCommand'; - import { formatKeyText } from '../utility/common'; + import { formatKeyText, switchCurrentDatabase } from '../utility/common'; let domInput; let filter = ''; diff --git a/packages/web/src/commands/changeDatabaseStatusCommand.ts b/packages/web/src/commands/changeDatabaseStatusCommand.ts index 0d71a7ef7..d2d3b00bc 100644 --- a/packages/web/src/commands/changeDatabaseStatusCommand.ts +++ b/packages/web/src/commands/changeDatabaseStatusCommand.ts @@ -3,6 +3,7 @@ import { currentDatabase, getCurrentDatabase } from '../stores'; import getElectron from '../utility/getElectron'; import registerCommand from './registerCommand'; import { apiCall } from '../utility/api'; +import { switchCurrentDatabase } from '../utility/common'; registerCommand({ id: 'database.changeState', @@ -40,7 +41,7 @@ registerCommand({ onClick: () => { const electron = getElectron(); if (electron) apiCall('database-connections/disconnect', dbid); - currentDatabase.set(null); + switchCurrentDatabase(null); }, }, ]; diff --git a/packages/web/src/commands/recentDatabaseSwitch.ts b/packages/web/src/commands/recentDatabaseSwitch.ts index ee550b933..2e64b22f4 100644 --- a/packages/web/src/commands/recentDatabaseSwitch.ts +++ b/packages/web/src/commands/recentDatabaseSwitch.ts @@ -2,6 +2,7 @@ import _ from 'lodash'; import { recentDatabases, currentDatabase, getRecentDatabases } from '../stores'; import registerCommand from './registerCommand'; import { getConnectionLabel } from 'dbgate-tools'; +import { switchCurrentDatabase } from '../utility/common'; currentDatabase.subscribe(value => { if (!value) return; @@ -17,7 +18,7 @@ currentDatabase.subscribe(value => { function switchDatabaseCommand(db) { return { text: `${db.name} on ${getConnectionLabel(db?.connection, { allowExplicitDatabase: false })}`, - onClick: () => currentDatabase.set(db), + onClick: () => switchCurrentDatabase(db), }; } diff --git a/packages/web/src/commands/stdCommands.ts b/packages/web/src/commands/stdCommands.ts index 70282233d..78423b620 100644 --- a/packages/web/src/commands/stdCommands.ts +++ b/packages/web/src/commands/stdCommands.ts @@ -35,7 +35,7 @@ import { apiCall } from '../utility/api'; import runCommand from './runCommand'; import { openWebLink } from '../utility/exportFileTools'; import { getSettings } from '../utility/metadataLoaders'; -import { isMac } from '../utility/common'; +import { isMac, switchCurrentDatabase } from '../utility/common'; import { doLogout, internalRedirectTo } from '../clientAuth'; import { disconnectServerConnection } from '../appobj/ConnectionAppObject.svelte'; import UploadErrorModal from '../modals/UploadErrorModal.svelte'; @@ -347,7 +347,7 @@ registerCommand({ onConfirm: async file => { const resp = await apiCall('connections/new-sqlite-database', { file }); const connection = resp; - currentDatabase.set({ connection, name: `${file}.sqlite` }); + switchCurrentDatabase({ connection, name: `${file}.sqlite` }); }, }); }, diff --git a/packages/web/src/stores.ts b/packages/web/src/stores.ts index 5f33b9104..ae7fe1b0e 100644 --- a/packages/web/src/stores.ts +++ b/packages/web/src/stores.ts @@ -8,6 +8,7 @@ import _ from 'lodash'; import { safeJsonParse } from 'dbgate-tools'; import { apiCall } from './utility/api'; import { getOpenedTabsStorageName, isAdminPage } from './utility/pageDefs'; +import { switchCurrentDatabase } from './utility/common'; export interface TabDefinition { title: string; @@ -296,7 +297,7 @@ export function subscribeApiDependendStores() { currentConfigValue = value; invalidateCommands(); if (value.singleDbConnection) { - currentDatabase.set(value.singleDbConnection); + switchCurrentDatabase(value.singleDbConnection); } }); } diff --git a/packages/web/src/tabpanel/TabsPanel.svelte b/packages/web/src/tabpanel/TabsPanel.svelte index d859fd2eb..707522f6b 100644 --- a/packages/web/src/tabpanel/TabsPanel.svelte +++ b/packages/web/src/tabpanel/TabsPanel.svelte @@ -285,7 +285,7 @@ draggingTabTarget, } from '../stores'; import tabs from '../tabs'; - import { setSelectedTab } from '../utility/common'; + import { setSelectedTab, switchCurrentDatabase } from '../utility/common'; import contextMenu from '../utility/contextMenu'; import { isElectronAvailable } from '../utility/getElectron'; import { getConnectionInfo, useConnectionList } from '../utility/metadataLoaders'; @@ -420,11 +420,11 @@ if (conid) { const connection = await getConnectionInfo({ conid, database }); if (connection) { - $currentDatabase = { connection, name: database }; + switchCurrentDatabase({ connection, name: database }); return; } } - $currentDatabase = null; + switchCurrentDatabase(null); }; async function scrollInViewTab(tabid) { diff --git a/packages/web/src/utility/changeCurrentDbByTab.ts b/packages/web/src/utility/changeCurrentDbByTab.ts index 86fcc4c88..7a8183643 100644 --- a/packages/web/src/utility/changeCurrentDbByTab.ts +++ b/packages/web/src/utility/changeCurrentDbByTab.ts @@ -3,6 +3,7 @@ import { currentDatabase, getCurrentDatabase, getLockedDatabaseMode, openedTabs import { shouldShowTab } from '../tabpanel/TabsPanel.svelte'; import { callWhenAppLoaded, getAppLoaded } from './appLoadManager'; import { getConnectionInfo } from './metadataLoaders'; +import { switchCurrentDatabase } from './common'; let lastCurrentTab = null; @@ -20,7 +21,7 @@ openedTabs.subscribe(value => { if (conid && database && (conid != lastTab?.props?.conid || database != lastTab?.props?.database)) { const doWork = async () => { const connection = await getConnectionInfo({ conid }); - currentDatabase.set({ + switchCurrentDatabase({ connection, name: database, }); diff --git a/packages/web/src/utility/common.ts b/packages/web/src/utility/common.ts index 3951e41df..41df84b15 100644 --- a/packages/web/src/utility/common.ts +++ b/packages/web/src/utility/common.ts @@ -1,5 +1,7 @@ -import { getOpenedTabs, openedTabs } from '../stores'; +import { findDefaultSchema, findEngineDriver, isCompositeDbName } from 'dbgate-tools'; +import { currentDatabase, getExtensions, getOpenedTabs, openedTabs } from '../stores'; import _ from 'lodash'; +import { getSchemaList } from './metadataLoaders'; export class LoadingToken { isCanceled = false; @@ -82,3 +84,21 @@ export function isCtrlOrCommandKey(event) { } return event.ctrlKey; } + +export async function switchCurrentDatabase(data) { + if (data?.connection?.useSeparateSchemas && !isCompositeDbName(data.name)) { + const conid = data.connection._id; + const database = data.name; + const storageKey = `selected-schema-${conid}-${database}`; + const schemaInStorage = localStorage.getItem(storageKey); + const schemas = await getSchemaList({ conid, database }); + const driver = findEngineDriver(data.connection, getExtensions()); + const defaultSchema = findDefaultSchema(schemas, driver?.dialect, schemaInStorage); + currentDatabase.set({ + ...data, + name: `${data.name}::${defaultSchema}`, + }); + } else { + currentDatabase.set(data); + } +} diff --git a/packages/web/src/utility/openElectronFile.ts b/packages/web/src/utility/openElectronFile.ts index c4e0b09d0..cbfa8d501 100644 --- a/packages/web/src/utility/openElectronFile.ts +++ b/packages/web/src/utility/openElectronFile.ts @@ -12,6 +12,7 @@ import { SAVED_FILE_HANDLERS } from '../appobj/SavedFileAppObject.svelte'; import _ from 'lodash'; import ErrorMessageModal from '../modals/ErrorMessageModal.svelte'; import { openImportExportTab } from './importExportTools'; +import { switchCurrentDatabase } from './common'; export function canOpenByElectron(file, extensions) { if (!file) return false; @@ -38,7 +39,7 @@ export async function openSqliteFile(filePath) { singleDatabase: true, defaultDatabase, }); - currentDatabase.set({ + switchCurrentDatabase({ connection: resp, name: getDatabaseFileLabel(filePath), }); diff --git a/packages/web/src/widgets/SchemaSelector.svelte b/packages/web/src/widgets/SchemaSelector.svelte index eef13f511..98d1d2cb5 100644 --- a/packages/web/src/widgets/SchemaSelector.svelte +++ b/packages/web/src/widgets/SchemaSelector.svelte @@ -8,16 +8,22 @@ import ConfirmModal from '../modals/ConfirmModal.svelte'; import { runOperationOnDatabase } from '../modals/ConfirmSqlModal.svelte'; import InputTextModal from '../modals/InputTextModal.svelte'; - import { appliedCurrentSchema } from '../stores'; + import { appliedCurrentSchema, currentDatabase } from '../stores'; + import { switchCurrentDatabase } from '../utility/common'; + import { extractDbNameFromComposite, extractSchemaNameFromComposite, findDefaultSchema } from 'dbgate-tools'; export let schemaList; - export let selectedSchema; export let objectList; - export let valueStorageKey; - export let conid; export let database; + export let connection; + + export let driver; + + let selectedSchema = null; + + $: valueStorageKey = `selected-schema-${conid}-${database}`; $: { if (selectedSchema != null) { @@ -86,7 +92,12 @@ }); } - $: selectedSchema = localStorage.getItem(valueStorageKey ?? ''); + $: if (connection?.useSeparateSchemas) { + selectedSchema = + extractSchemaNameFromComposite($currentDatabase?.name) ?? findDefaultSchema(schemaList, driver?.dialect); + } else { + selectedSchema = localStorage.getItem(valueStorageKey ?? ''); + } {#if realSchemaList.length > 0} @@ -94,15 +105,22 @@
Schema:
({ label: `${x} (${countBySchema[x] ?? 0})`, value: x })), - // ...schemaList.filter(x => countBySchema[x]).map(x => ({ label: `${x} (${countBySchema[x] ?? 0})`, value: x })), - // ...schemaList.filter(x => !countBySchema[x]).map(x => ({ label: `${x} (${countBySchema[x] ?? 0})`, value: x })), - ]} + options={connection?.useSeparateSchemas + ? (schemaList?.map(x => ({ label: x.schemaName, value: x.schemaName })) ?? []) + : [ + { label: `All schemas (${objectList?.length ?? 0})`, value: '' }, + ...realSchemaList.map(x => ({ label: `${x} (${countBySchema[x] ?? 0})`, value: x })), + ]} value={selectedSchema ?? $appliedCurrentSchema ?? ''} on:change={e => { - selectedSchema = e.detail; + if (connection?.useSeparateSchemas) { + switchCurrentDatabase({ + connection, + name: `${extractDbNameFromComposite(database)}::${e.detail}`, + }); + } else { + selectedSchema = e.detail; + } localStorage.setItem(valueStorageKey, e.detail); }} selectClass="schema-select" diff --git a/packages/web/src/widgets/SqlObjectList.svelte b/packages/web/src/widgets/SqlObjectList.svelte index 99dba0016..e03840207 100644 --- a/packages/web/src/widgets/SqlObjectList.svelte +++ b/packages/web/src/widgets/SqlObjectList.svelte @@ -48,7 +48,6 @@ export let database; let filter = ''; - let selectedSchema = null; $: objects = useDatabaseInfo({ conid, database }); $: status = useDatabaseStatus({ conid, database }); @@ -153,11 +152,11 @@