diff --git a/packages/api/src/controllers/apps.js b/packages/api/src/controllers/apps.js index 5a124d57..7e057d80 100644 --- a/packages/api/src/controllers/apps.js +++ b/packages/api/src/controllers/apps.js @@ -186,13 +186,19 @@ module.exports = { } catch (err) { res.virtualReferences = []; } + try { + res.dictionaryDescriptions = JSON.parse( + await fs.readFile(path.join(dir, 'dictionary-descriptions.config.json'), { encoding: 'utf-8' }) + ); + } catch (err) { + res.dictionaryDescriptions = []; + } return res; }, - saveVfk_meta: true, - async saveVfk({ appFolder, schemaName, pureName, refSchemaName, refTableName, columns }) { - const file = path.join(appdir(), appFolder, 'virtual-references.config.json'); + async saveConfigFile(appFolder, filename, filterFunc, newItem) { + const file = path.join(appdir(), appFolder, filename); let json; try { @@ -201,33 +207,57 @@ module.exports = { json = []; } - if (columns.length == 1) { - json = json.filter( - x => - !( - x.schemaName == schemaName && - x.pureName == pureName && - x.columns.length == 1 && - x.columns[0].columnName == columns[0].columnName - ) - ); + if (filterFunc) { + json = json.filter(filterFunc); } - json = [ - ...json, + json = [...json, newItem]; + + await fs.writeFile(file, JSON.stringify(json, undefined, 2)); + + socket.emitChanged(`app-files-changed-${appFolder}`); + socket.emitChanged('used-apps-changed'); + }, + + saveVirtualReference_meta: true, + async saveVirtualReference({ appFolder, schemaName, pureName, refSchemaName, refTableName, columns }) { + await this.saveConfigFile( + appFolder, + 'virtual-references.config.json', + columns.length == 1 + ? x => + !( + x.schemaName == schemaName && + x.pureName == pureName && + x.columns.length == 1 && + x.columns[0].columnName == columns[0].columnName + ) + : null, { schemaName, pureName, refSchemaName, refTableName, columns, - }, - ]; + } + ); + return true; + }, - await fs.writeFile(file, JSON.stringify(json, undefined, 2)); - - socket.emitChanged(`app-files-changed-${appFolder}`); - socket.emitChanged('used-apps-changed'); + saveDictionaryDescription_meta: true, + async saveDictionaryDescription({ appFolder, pureName, schemaName, expresssion, columns, delimiter }) { + await this.saveConfigFile( + appFolder, + 'dictionary-descriptions.config.json', + x => !(x.schemaName == schemaName && x.pureName == pureName), + { + schemaName, + pureName, + expresssion, + columns, + delimiter, + } + ); return true; }, diff --git a/packages/tools/src/structureTools.ts b/packages/tools/src/structureTools.ts index a49f3a76..f3d08351 100644 --- a/packages/tools/src/structureTools.ts +++ b/packages/tools/src/structureTools.ts @@ -101,10 +101,10 @@ export function extendDatabaseInfoFromApps(db: DatabaseInfo, apps: ApplicationDe ...(table.foreignKeys || []), ..._flatten(apps.map(app => app.virtualReferences || [])) .filter(fk => fk.pureName == table.pureName && fk.schemaName == table.schemaName) - .map(fk => ({ ...fk, isVirtual: true })), + .map(fk => ({ ...fk, constraintType: 'foreignKey', isVirtual: true })), ], })), - }; + } as DatabaseInfo; return addTableDependencies(dbExt); } diff --git a/packages/types/appdefs.d.ts b/packages/types/appdefs.d.ts index 6fdd2822..d88559d7 100644 --- a/packages/types/appdefs.d.ts +++ b/packages/types/appdefs.d.ts @@ -19,10 +19,10 @@ interface VirtualReferenceDefinition { }[]; } -interface ColumnDescriptionDefinition { +interface DictionaryDescriptionDefinition { pureName: string; schemaName?: string; - expresssion?: string; + expresssion: string; columns: string[]; delimiter: string; } @@ -33,5 +33,5 @@ export interface ApplicationDefinition { queries: ApplicationQuery[]; commands: ApplicationCommand[]; virtualReferences: VirtualReferenceDefinition[]; - columnDescriptions: ColumnDescriptionDefinition[]; + dictionaryDescriptions: DictionaryDescriptionDefinition[]; } diff --git a/packages/web/src/App.svelte b/packages/web/src/App.svelte index b77d962c..a0527321 100644 --- a/packages/web/src/App.svelte +++ b/packages/web/src/App.svelte @@ -15,6 +15,7 @@ import { subscribeConnectionPingers } from './utility/connectionsPinger'; import { subscribePermissionCompiler } from './utility/hasPermission'; import { apiCall } from './utility/api'; + import { getUsedApps } from './utility/metadataLoaders'; let loadedApi = false; @@ -30,7 +31,8 @@ const settings = await apiCall('config/get-settings'); const connections = await apiCall('connections/list'); const config = await apiCall('config/get'); - loadedApi = settings && connections && config; + const apps = await getUsedApps(); + loadedApi = settings && connections && config && apps; if (loadedApi) { subscribeApiDependendStores(); diff --git a/packages/web/src/appobj/DatabaseAppObject.svelte b/packages/web/src/appobj/DatabaseAppObject.svelte index b483f315..7611f0fc 100644 --- a/packages/web/src/appobj/DatabaseAppObject.svelte +++ b/packages/web/src/appobj/DatabaseAppObject.svelte @@ -1,11 +1,6 @@ - - export async function saveDbToApp(conid, database, app) { - if (app == '#new') { - const folder = await apiCall('apps/create-folder', { folder: database }); - - await apiCall('connections/update-database', { - conid, - database, - values: { - [`useApp:${folder}`]: true, - }, - }); - - return folder; - } - - await apiCall('connections/update-database', { - conid, - database, - values: { - [`useApp:${app}`]: true, - }, - }); - - return app; - } - - @@ -75,7 +103,14 @@ - + + + { const appFolder = await saveDbToApp(conid, database, dstApp); - await apiCall('apps/save-vfk', { + await apiCall('apps/save-virtual-reference', { appFolder, schemaName, pureName, diff --git a/packages/web/src/utility/appTools.ts b/packages/web/src/utility/appTools.ts new file mode 100644 index 00000000..506e1aaa --- /dev/null +++ b/packages/web/src/utility/appTools.ts @@ -0,0 +1,33 @@ +import { ApplicationDefinition, StoredConnection } from 'dbgate-types'; +import { apiCall } from '../utility/api'; + +export async function saveDbToApp(conid: string, database: string, app: string) { + if (app == '#new') { + const folder = await apiCall('apps/create-folder', { folder: database }); + + await apiCall('connections/update-database', { + conid, + database, + values: { + [`useApp:${folder}`]: true, + }, + }); + + return folder; + } + + await apiCall('connections/update-database', { + conid, + database, + values: { + [`useApp:${app}`]: true, + }, + }); + + return app; +} + +export function filterAppsForDatabase(connection, database: string, $apps): ApplicationDefinition[] { + const db = (connection?.databases || []).find(x => x.name == database); + return $apps.filter(app => db && db[`useApp:${app.name}`]); +} diff --git a/packages/web/src/utility/dictionaryDescriptionTools.ts b/packages/web/src/utility/dictionaryDescriptionTools.ts index 0454ccc7..87cc9557 100644 --- a/packages/web/src/utility/dictionaryDescriptionTools.ts +++ b/packages/web/src/utility/dictionaryDescriptionTools.ts @@ -1,7 +1,8 @@ import { DictionaryDescription } from 'dbgate-datalib'; -import { TableInfo } from 'dbgate-types'; +import { ApplicationDefinition, TableInfo } from 'dbgate-types'; import _ from 'lodash'; -import { getLocalStorage, setLocalStorage, removeLocalStorage } from './storageCache'; +import { apiCall } from './api'; +import { filterAppsForDatabase, saveDbToApp } from './appTools'; function checkDescriptionColumns(columns: string[], table: TableInfo) { if (!columns?.length) return false; @@ -14,17 +15,20 @@ export function getDictionaryDescription( table: TableInfo, conid: string, database: string, + apps: ApplicationDefinition[], + connections, skipCheckSaved: boolean = false ): DictionaryDescription { - const keySpecific = `dictionary_spec_${table.schemaName}||${table.pureName}||${conid}||${database}`; - const keyCommon = `dictionary_spec_${table.schemaName}||${table.pureName}`; + const conn = connections.find(x => x._id == conid); + const dbApps = filterAppsForDatabase(conn, database, apps); - const cachedSpecific = getLocalStorage(keySpecific); - const cachedCommon = getLocalStorage(keyCommon); + const cached = _.flatten(dbApps.map(x => x.dictionaryDescriptions || [])).find( + x => x.pureName == table.pureName && x.schemaName == table.schemaName + ); - if (cachedSpecific && (skipCheckSaved || checkDescriptionColumns(cachedSpecific.columns, table))) - return cachedSpecific; - if (cachedCommon && (skipCheckSaved || checkDescriptionColumns(cachedCommon.columns, table))) return cachedCommon; + if (cached && (skipCheckSaved || checkDescriptionColumns(cached.columns, table))) { + return cached; + } const descColumn = table.columns.find(x => x?.dataType?.toLowerCase()?.includes('char')); if (descColumn) { @@ -57,29 +61,22 @@ export function changeDelimitedColumnList(columns, columnName, isChecked) { return parsed.join(','); } -export function saveDictionaryDescription( +export async function saveDictionaryDescription( table: TableInfo, conid: string, database: string, expression: string, delimiter: string, - useForAllDatabases: boolean + targetApplication: string ) { - const keySpecific = `dictionary_spec_${table.schemaName}||${table.pureName}||${conid}||${database}`; - const keyCommon = `dictionary_spec_${table.schemaName}||${table.pureName}`; + const appFolder = await saveDbToApp(conid, database, targetApplication); - removeLocalStorage(keySpecific); - if (useForAllDatabases) removeLocalStorage(keyCommon); - - const description = { + await apiCall('apps/save-dictionary-description', { + appFolder, + schemaName: table.schemaName, + pureName: table.pureName, columns: parseDelimitedColumnList(expression), expression, delimiter, - }; - - if (useForAllDatabases) { - setLocalStorage(keyCommon, description); - } else { - setLocalStorage(keySpecific, description); - } + }); }