diff --git a/packages/datalib/src/PerspectiveConfig.ts b/packages/datalib/src/PerspectiveConfig.ts index aafebbcd2..40c0726e7 100644 --- a/packages/datalib/src/PerspectiveConfig.ts +++ b/packages/datalib/src/PerspectiveConfig.ts @@ -1,4 +1,4 @@ -import { ForeignKeyInfo } from "dbgate-types"; +import { DatabaseInfo, ForeignKeyInfo } from 'dbgate-types'; export interface PerspectiveConfigColumns { expandedColumns: string[]; @@ -55,3 +55,27 @@ export type ChangePerspectiveConfigFunc = ( changeFunc: (config: PerspectiveConfig) => PerspectiveConfig, reload?: boolean ) => void; + +export function extractPerspectiveDatabases( + { conid, database }, + cfg: PerspectiveConfig +): { conid: string; database: string }[] { + const res: { conid: string; database: string }[] = []; + res.push({ conid, database }); + + function add(conid, database) { + if (res.find(x => x.conid == conid && x.database == database)) return; + res.push({ conid, database }); + } + + for (const custom of cfg.customJoins) { + add(custom.conid || conid, custom.database || database); + } + return res; +} + +export interface MultipleDatabaseInfo { + [conid: string]: { + [database: string]: DatabaseInfo; + }; +} diff --git a/packages/datalib/src/PerspectiveTreeNode.ts b/packages/datalib/src/PerspectiveTreeNode.ts index 5b0a6096d..193c9fc7f 100644 --- a/packages/datalib/src/PerspectiveTreeNode.ts +++ b/packages/datalib/src/PerspectiveTreeNode.ts @@ -1,7 +1,7 @@ import { ColumnInfo, DatabaseInfo, ForeignKeyInfo, RangeDefinition, TableInfo, ViewInfo } from 'dbgate-types'; -import { clearConfigCache } from 'prettier'; import { ChangePerspectiveConfigFunc, + MultipleDatabaseInfo, PerspectiveConfig, PerspectiveConfigColumns, PerspectiveCustomJoinConfig, @@ -54,6 +54,7 @@ export interface PerspectiveDataLoadPropsWithNode { export abstract class PerspectiveTreeNode { constructor( + public dbs: MultipleDatabaseInfo, public config: PerspectiveConfig, public setConfig: ChangePerspectiveConfigFunc, public parentNode: PerspectiveTreeNode, @@ -118,6 +119,9 @@ export abstract class PerspectiveTreeNode { get customJoinConfig(): PerspectiveCustomJoinConfig { return null; } + get db(): DatabaseInfo { + return this.dbs?.[this.databaseConfig.conid]?.[this.databaseConfig.database]; + } getChildMatchColumns() { return []; @@ -256,20 +260,20 @@ export class PerspectiveTableColumnNode extends PerspectiveTreeNode { constructor( public column: ColumnInfo, public table: TableInfo | ViewInfo, - public db: DatabaseInfo, + dbs: MultipleDatabaseInfo, config: PerspectiveConfig, setConfig: ChangePerspectiveConfigFunc, dataProvider: PerspectiveDataProvider, databaseConfig: PerspectiveDatabaseConfig, parentNode: PerspectiveTreeNode ) { - super(config, setConfig, parentNode, dataProvider, databaseConfig); + super(dbs, config, setConfig, parentNode, dataProvider, databaseConfig); this.foreignKey = (table as TableInfo)?.foreignKeys?.find( fk => fk.columns.length == 1 && fk.columns[0].columnName == column.columnName ); - this.refTable = db.tables.find( + this.refTable = this.db.tables.find( x => x.pureName == this.foreignKey?.refTableName && x.schemaName == this.foreignKey?.refSchemaName ); } @@ -349,7 +353,7 @@ export class PerspectiveTableColumnNode extends PerspectiveTreeNode { return getTableChildPerspectiveNodes( tbl, - this.db, + this.dbs, this.config, this.setConfig, this.dataProvider, @@ -412,14 +416,14 @@ export class PerspectiveTableColumnNode extends PerspectiveTreeNode { export class PerspectiveTableNode extends PerspectiveTreeNode { constructor( public table: TableInfo, - public db: DatabaseInfo, + dbs: MultipleDatabaseInfo, config: PerspectiveConfig, setConfig: ChangePerspectiveConfigFunc, public dataProvider: PerspectiveDataProvider, databaseConfig: PerspectiveDatabaseConfig, parentNode: PerspectiveTreeNode ) { - super(config, setConfig, parentNode, dataProvider, databaseConfig); + super(dbs, config, setConfig, parentNode, dataProvider, databaseConfig); } getNodeLoadProps(parentRows: any[]): PerspectiveDataLoadProps { @@ -448,7 +452,7 @@ export class PerspectiveTableNode extends PerspectiveTreeNode { get childNodes(): PerspectiveTreeNode[] { return getTableChildPerspectiveNodes( this.table, - this.db, + this.dbs, this.config, this.setConfig, this.dataProvider, @@ -482,14 +486,14 @@ export class PerspectiveTableNode extends PerspectiveTreeNode { export class PerspectiveViewNode extends PerspectiveTreeNode { constructor( public view: ViewInfo, - public db: DatabaseInfo, + dbs: MultipleDatabaseInfo, config: PerspectiveConfig, setConfig: ChangePerspectiveConfigFunc, public dataProvider: PerspectiveDataProvider, databaseConfig: PerspectiveDatabaseConfig, parentNode: PerspectiveTreeNode ) { - super(config, setConfig, parentNode, dataProvider, databaseConfig); + super(dbs, config, setConfig, parentNode, dataProvider, databaseConfig); } getNodeLoadProps(parentRows: any[]): PerspectiveDataLoadProps { @@ -518,7 +522,7 @@ export class PerspectiveViewNode extends PerspectiveTreeNode { get childNodes(): PerspectiveTreeNode[] { return getTableChildPerspectiveNodes( this.view, - this.db, + this.dbs, this.config, this.setConfig, this.dataProvider, @@ -540,7 +544,7 @@ export class PerspectiveTableReferenceNode extends PerspectiveTableNode { constructor( public foreignKey: ForeignKeyInfo, table: TableInfo, - db: DatabaseInfo, + dbs: MultipleDatabaseInfo, config: PerspectiveConfig, setConfig: ChangePerspectiveConfigFunc, public dataProvider: PerspectiveDataProvider, @@ -548,7 +552,7 @@ export class PerspectiveTableReferenceNode extends PerspectiveTableNode { public isMultiple: boolean, parentNode: PerspectiveTreeNode ) { - super(table, db, config, setConfig, dataProvider, databaseConfig, parentNode); + super(table, dbs, config, setConfig, dataProvider, databaseConfig, parentNode); } matchChildRow(parentRow: any, childRow: any): boolean { @@ -605,22 +609,15 @@ export class PerspectiveTableReferenceNode extends PerspectiveTableNode { export class PerspectiveCustomJoinTreeNode extends PerspectiveTableNode { constructor( public customJoin: PerspectiveCustomJoinConfig, - db: DatabaseInfo, + table: TableInfo, + dbs: MultipleDatabaseInfo, config: PerspectiveConfig, setConfig: ChangePerspectiveConfigFunc, public dataProvider: PerspectiveDataProvider, databaseConfig: PerspectiveDatabaseConfig, parentNode: PerspectiveTreeNode ) { - super( - db.tables.find(x => x.pureName == customJoin.refTableName && x.schemaName == customJoin.refSchemaName), - db, - config, - setConfig, - dataProvider, - databaseConfig, - parentNode - ); + super(table, dbs, config, setConfig, dataProvider, databaseConfig, parentNode); } matchChildRow(parentRow: any, childRow: any): boolean { @@ -677,7 +674,7 @@ export class PerspectiveCustomJoinTreeNode extends PerspectiveTableNode { export function getTableChildPerspectiveNodes( table: TableInfo | ViewInfo, - db: DatabaseInfo, + dbs: MultipleDatabaseInfo, config: PerspectiveConfig, setConfig: ChangePerspectiveConfigFunc, dataProvider: PerspectiveDataProvider, @@ -685,9 +682,11 @@ export function getTableChildPerspectiveNodes( parentColumn: PerspectiveTreeNode ) { if (!table) return []; + const db = parentColumn.db; const columnNodes = table.columns.map( - col => new PerspectiveTableColumnNode(col, table, db, config, setConfig, dataProvider, databaseConfig, parentColumn) + col => + new PerspectiveTableColumnNode(col, table, dbs, config, setConfig, dataProvider, databaseConfig, parentColumn) ); const circularColumns = columnNodes.filter(x => x.isCircular).map(x => x.columnName); const defaultColumns = getPerspectiveDefaultColumns(table, db, circularColumns); @@ -709,7 +708,7 @@ export function getTableChildPerspectiveNodes( new PerspectiveTableReferenceNode( fk, tbl, - db, + dbs, config, setConfig, dataProvider, @@ -726,9 +725,17 @@ export function getTableChildPerspectiveNodes( const customs = []; for (const join of config.customJoins || []) { if (join.baseUniqueName == parentColumn.uniqueName) { - customs.push( - new PerspectiveCustomJoinTreeNode(join, db, config, setConfig, dataProvider, databaseConfig, parentColumn) - ); + const newConfig = { ...databaseConfig }; + if (join.conid) newConfig.conid = join.conid; + if (join.database) newConfig.database = join.database; + const db = dbs?.[newConfig.conid]?.[newConfig.database]; + const table = db?.tables?.find(x => x.pureName == join.refTableName && x.schemaName == join.refSchemaName); + + if (table) { + customs.push( + new PerspectiveCustomJoinTreeNode(join, table, dbs, config, setConfig, dataProvider, newConfig, parentColumn) + ); + } } } res.push(..._sortBy(customs, 'title')); diff --git a/packages/datalib/src/index.ts b/packages/datalib/src/index.ts index 9ec457219..589ad7929 100644 --- a/packages/datalib/src/index.ts +++ b/packages/datalib/src/index.ts @@ -17,3 +17,4 @@ export * from './deleteCascade'; export * from './PerspectiveDisplay'; export * from './PerspectiveDataProvider'; export * from './PerspectiveCache'; +export * from './PerspectiveConfig'; diff --git a/packages/datalib/src/tests/PerspectiveDisplay.test.ts b/packages/datalib/src/tests/PerspectiveDisplay.test.ts index f794348c5..798cfce90 100644 --- a/packages/datalib/src/tests/PerspectiveDisplay.test.ts +++ b/packages/datalib/src/tests/PerspectiveDisplay.test.ts @@ -9,7 +9,15 @@ import artistDataAlbumTrack from './artistDataAlbumTrack'; test('test flat view', () => { const artistTable = chinookDbInfo.tables.find(x => x.pureName == 'Artist'); - const root = new PerspectiveTableNode(artistTable, chinookDbInfo, createPerspectiveConfig(), null, null, null, null); + const root = new PerspectiveTableNode( + artistTable, + { conid: { db: chinookDbInfo } }, + createPerspectiveConfig(), + null, + null, + { conid: 'conid', database: 'db' }, + null + ); const display = new PerspectiveDisplay(root, artistDataFlat); // console.log(display.loadIndicatorsCounts); @@ -29,11 +37,11 @@ test('test one level nesting', () => { const artistTable = chinookDbInfo.tables.find(x => x.pureName == 'Artist'); const root = new PerspectiveTableNode( artistTable, - chinookDbInfo, + { conid: { db: chinookDbInfo } }, { ...createPerspectiveConfig(), checkedColumns: ['Artist.Album'] }, null, null, - null, + { conid: 'conid', database: 'db' }, null ); const display = new PerspectiveDisplay(root, artistDataAlbum); @@ -79,11 +87,11 @@ test('test two level nesting', () => { const artistTable = chinookDbInfo.tables.find(x => x.pureName == 'Artist'); const root = new PerspectiveTableNode( artistTable, - chinookDbInfo, + { conid: { db: chinookDbInfo } }, { ...createPerspectiveConfig(), checkedColumns: ['Artist.Album', 'Artist.Album.Track'] }, null, null, - null, + { conid: 'conid', database: 'db' }, null ); const display = new PerspectiveDisplay(root, artistDataAlbumTrack); diff --git a/packages/web/src/perspectives/CustomJoinModal.svelte b/packages/web/src/perspectives/CustomJoinModal.svelte index ae0ee531e..992fa029a 100644 --- a/packages/web/src/perspectives/CustomJoinModal.svelte +++ b/packages/web/src/perspectives/CustomJoinModal.svelte @@ -316,6 +316,8 @@ refTableName, refSchemaName, columns, + conid: conidOverride, + database: databaseOverride, }; setConfig(cfg => ({ ...cfg, diff --git a/packages/web/src/perspectives/PerspectiveTable.svelte b/packages/web/src/perspectives/PerspectiveTable.svelte index 1d61ac782..86ee4c89c 100644 --- a/packages/web/src/perspectives/PerspectiveTable.svelte +++ b/packages/web/src/perspectives/PerspectiveTable.svelte @@ -180,6 +180,8 @@ const pureName = td.getAttribute('data-pureName'); const schemaName = td.getAttribute('data-schemaName'); + const dataConid = td.getAttribute('data-conid'); + const dataDatabase = td.getAttribute('data-database'); if (pureName) { res.push({ text: `Open table ${pureName}`, @@ -191,8 +193,8 @@ props: { schemaName, pureName, - conid, - database, + conid: dataConid || conid, + database: dataDatabase || database, objectTypeField: 'tables', }, }); diff --git a/packages/web/src/perspectives/PerspectiveView.svelte b/packages/web/src/perspectives/PerspectiveView.svelte index 49fb925f0..c49103340 100644 --- a/packages/web/src/perspectives/PerspectiveView.svelte +++ b/packages/web/src/perspectives/PerspectiveView.svelte @@ -17,6 +17,7 @@ import { ChangeConfigFunc, ChangePerspectiveConfigFunc, + extractPerspectiveDatabases, getTableChildPerspectiveNodes, GridConfig, PerspectiveConfig, @@ -54,6 +55,7 @@ import SearchBoxWrapper from '../elements/SearchBoxWrapper.svelte'; import SearchInput from '../elements/SearchInput.svelte'; import CloseSearchButton from '../buttons/CloseSearchButton.svelte'; + import { useMultipleDatabaseInfo } from '../utility/useMultipleDatabaseInfo'; const dbg = debug('dbgate:PerspectiveView'); @@ -95,16 +97,16 @@ }); } - const dbInfo = useDatabaseInfo({ conid, database }); + const dbInfos = useMultipleDatabaseInfo(extractPerspectiveDatabases({ conid, database }, config)); const tableInfo = useTableInfo({ conid, database, schemaName, pureName }); const viewInfo = useViewInfo({ conid, database, schemaName, pureName }); $: dataProvider = new PerspectiveDataProvider(cache, loader); $: loader = new PerspectiveDataLoader(apiCall); $: root = $tableInfo - ? new PerspectiveTableNode($tableInfo, $dbInfo, config, setConfig, dataProvider, { conid, database }, null) + ? new PerspectiveTableNode($tableInfo, $dbInfos, config, setConfig, dataProvider, { conid, database }, null) : $viewInfo - ? new PerspectiveViewNode($viewInfo, $dbInfo, config, setConfig, dataProvider, { conid, database }, null) + ? new PerspectiveViewNode($viewInfo, $dbInfos, config, setConfig, dataProvider, { conid, database }, null) : null; // $: console.log('CONFIG', config); diff --git a/packages/web/src/utility/useMultipleDatabaseInfo.ts b/packages/web/src/utility/useMultipleDatabaseInfo.ts new file mode 100644 index 000000000..819963428 --- /dev/null +++ b/packages/web/src/utility/useMultipleDatabaseInfo.ts @@ -0,0 +1,19 @@ +import { Readable, writable } from 'svelte/store'; +import { getDatabaseInfo } from './metadataLoaders'; +import { MultipleDatabaseInfo } from 'dbgate-datalib'; + +export function useMultipleDatabaseInfo(dbs: { conid: string; database: string }[]): Readable { + const res = writable({}); + for (const { conid, database } of dbs) { + getDatabaseInfo({ conid, database }).then(dbInfo => { + res.update(old => ({ + ...old, + [conid]: { + ...old[conid], + [database]: dbInfo, + }, + })); + }); + } + return res; +}