diff --git a/packages/datalib/src/PerspectiveTreeNode.ts b/packages/datalib/src/PerspectiveTreeNode.ts index d571b8a0f..c3f4ae79e 100644 --- a/packages/datalib/src/PerspectiveTreeNode.ts +++ b/packages/datalib/src/PerspectiveTreeNode.ts @@ -39,6 +39,7 @@ import { FilterType } from 'dbgate-filterparser/lib/types'; import { Condition, Expression, Select } from 'dbgate-sqltree'; // import { getPerspectiveDefaultColumns } from './getPerspectiveDefaultColumns'; import uuidv1 from 'uuid/v1'; +import { PerspectiveDataPatternColumn } from './PerspectiveDataPattern'; export interface PerspectiveDataLoadPropsWithNode { props: PerspectiveDataLoadProps; @@ -699,6 +700,173 @@ export class PerspectiveTableColumnNode extends PerspectiveTreeNode { } } +export class PerspectivePatternColumnNode extends PerspectiveTreeNode { + foreignKey: ForeignKeyInfo; + refTable: TableInfo; + + constructor( + public column: PerspectiveDataPatternColumn, + dbs: MultipleDatabaseInfo, + config: PerspectiveConfig, + setConfig: ChangePerspectiveConfigFunc, + dataProvider: PerspectiveDataProvider, + databaseConfig: PerspectiveDatabaseConfig, + parentNode: PerspectiveTreeNode, + designerId: string + ) { + super(dbs, config, setConfig, parentNode, dataProvider, databaseConfig, designerId); + } + + // matchChildRow(parentRow: any, childRow: any): boolean { + // if (!this.foreignKey) return false; + // return parentRow[this.foreignKey.columns[0].columnName] == childRow[this.foreignKey.columns[0].refColumnName]; + // } + + // getChildMatchColumns() { + // if (!this.foreignKey) return []; + // return [this.foreignKey.columns[0].columnName]; + // } + + // getParentMatchColumns() { + // if (!this.foreignKey) return []; + // return [this.foreignKey.columns[0].refColumnName]; + // } + + // getParentJoinCondition(alias: string, parentAlias: string): Condition[] { + // if (!this.foreignKey) return []; + // return this.foreignKey.columns.map(column => { + // const res: Condition = { + // conditionType: 'binary', + // operator: '=', + // left: { + // exprType: 'column', + // columnName: column.columnName, + // source: { alias: parentAlias }, + // }, + // right: { + // exprType: 'column', + // columnName: column.refColumnName, + // source: { alias }, + // }, + // }; + // return res; + // }); + // } + + // createReferenceConfigColumns(): PerspectiveReferenceConfig['columns'] { + // return this.foreignKey?.columns?.map(col => ({ + // source: col.columnName, + // target: col.refColumnName, + // })); + // } + + getNodeLoadProps(parentRows: any[]): PerspectiveDataLoadProps { + return null; + } + + get icon() { + return 'img column'; + } + + get codeName() { + return this.column.name; + } + + get columnName() { + return this.column.name; + } + + get fieldName() { + return this.codeName + 'Ref'; + } + + get title() { + return this.column.name; + } + + get isExpandable() { + return !!this.foreignKey; + } + + get isSortable() { + return true; + } + + get filterType(): FilterType { + return 'mongo'; + } + + generateChildNodes(): PerspectiveTreeNode[] { + return []; + // if (!this.foreignKey) return []; + // const tbl = this?.db?.tables?.find( + // x => x.pureName == this.foreignKey?.refTableName && x.schemaName == this.foreignKey?.refSchemaName + // ); + + // return getTableChildPerspectiveNodes( + // tbl, + // this.dbs, + // this.config, + // this.setConfig, + // this.dataProvider, + // this.databaseConfig, + // this + // ); + } + + // get filterInfo(): PerspectiveFilterColumnInfo { + // return { + // columnName: this.columnName, + // filterType: this.filterType, + // pureName: this.column.pureName, + // schemaName: this.column.schemaName, + // foreignKey: this.foreignKey, + // }; + // } + + // parseFilterCondition(source = null): Condition { + // const filter = this.getFilter(); + // if (!filter) return null; + // const condition = parseFilter(filter, this.filterType); + // if (!condition) return null; + // return _cloneDeepWith(condition, (expr: Expression) => { + // if (expr.exprType == 'placeholder') { + // return { + // exprType: 'column', + // columnName: this.column.columnName, + // source, + // }; + // } + // }); + // } + + // get headerTableAttributes() { + // if (this.foreignKey) { + // return { + // schemaName: this.foreignKey.refSchemaName, + // pureName: this.foreignKey.refTableName, + // conid: this.databaseConfig.conid, + // database: this.databaseConfig.database, + // }; + // } + // return null; + // } + + // get tableCode() { + // return `${this.collection.schemaName}|${this.table.pureName}`; + // } + + // get namedObject(): NamedObjectInfo { + // if (this.foreignKey) { + // return { + // schemaName: this.foreignKey.refSchemaName, + // pureName: this.foreignKey.refTableName, + // }; + // } + // return null; + // } +} + export class PerspectiveTableNode extends PerspectiveTreeNode { constructor( public table: TableInfo | ViewInfo, @@ -819,16 +987,16 @@ export class PerspectiveCollectionNode extends PerspectiveTreeNode { } generateChildNodes(): PerspectiveTreeNode[] { - return []; - // return getTableChildPerspectiveNodes( - // this.table, - // this.dbs, - // this.config, - // this.setConfig, - // this.dataProvider, - // this.databaseConfig, - // this - // ); + return getCollectionChildPerspectiveNodes( + this.designerId, + this.collection, + this.dbs, + this.config, + this.setConfig, + this.dataProvider, + this.databaseConfig, + this + ); } get icon() { @@ -1172,6 +1340,43 @@ function findDesignerIdForNode( return node; } +export function getCollectionChildPerspectiveNodes( + designerId: string, + collection: CollectionInfo, + dbs: MultipleDatabaseInfo, + config: PerspectiveConfig, + setConfig: ChangePerspectiveConfigFunc, + dataProvider: PerspectiveDataProvider, + databaseConfig: PerspectiveDatabaseConfig, + parentNode: PerspectiveTreeNode +) { + if (!collection) return []; + const db = parentNode.db; + + const pattern = dataProvider.dataPatterns[designerId]; + if (!pattern) return []; + + const columnNodes = pattern.columns.map(col => + findDesignerIdForNode( + config, + parentNode, + designerId => + new PerspectivePatternColumnNode( + col, + dbs, + config, + setConfig, + dataProvider, + databaseConfig, + parentNode, + designerId + ) + ) + ); + + return columnNodes; +} + export function getTableChildPerspectiveNodes( table: TableInfo | ViewInfo, dbs: MultipleDatabaseInfo, diff --git a/packages/datalib/src/processPerspectiveDefaultColunns.ts b/packages/datalib/src/processPerspectiveDefaultColunns.ts index cd8e97479..2e106acf7 100644 --- a/packages/datalib/src/processPerspectiveDefaultColunns.ts +++ b/packages/datalib/src/processPerspectiveDefaultColunns.ts @@ -1,9 +1,17 @@ import { findForeignKeyForColumn } from 'dbgate-tools'; import { DatabaseInfo, TableInfo, ViewInfo } from 'dbgate-types'; import { createPerspectiveNodeConfig, MultipleDatabaseInfo, PerspectiveConfig } from './PerspectiveConfig'; -import { PerspectiveDataPatternDict } from './PerspectiveDataPattern'; +import { PerspectiveDataPattern, PerspectiveDataPatternDict } from './PerspectiveDataPattern'; import { PerspectiveTableNode } from './PerspectiveTreeNode'; +const namePredicates = [ + x => x.toLowerCase() == 'name', + x => x.toLowerCase() == 'title', + x => x.toLowerCase().includes('name'), + x => x.toLowerCase().includes('title'), + x => x.toLowerCase().includes('subject'), +]; + function getPerspectiveDefaultColumns( table: TableInfo | ViewInfo, db: DatabaseInfo, @@ -11,13 +19,7 @@ function getPerspectiveDefaultColumns( ): [string[], string[]] { const columns = table.columns.map(x => x.columnName); const predicates = [ - x => x.toLowerCase() == 'name', - x => x.toLowerCase() == 'title', - x => x.toLowerCase().includes('name'), - x => x.toLowerCase().includes('title'), - x => x.toLowerCase().includes('subject'), - // x => x.toLowerCase().includes('text'), - // x => x.toLowerCase().includes('desc'), + ...namePredicates, x => table.columns .find(y => y.columnName == x) @@ -45,6 +47,16 @@ function getPerspectiveDefaultColumns( return [[columns[0]], null]; } +function getPerspectiveDefaultCollectionColumns(pattern: PerspectiveDataPattern): string[] { + const columns = pattern.columns.map(x => x.name); + const predicates = [...namePredicates, x => pattern.columns.find(y => y.name == x)?.types?.includes('string')]; + + for (const predicate of predicates) { + const col = columns.find(predicate); + if (col) return [col]; + } +} + export function perspectiveNodesHaveStructure( config: PerspectiveConfig, dbInfos: MultipleDatabaseInfo, @@ -83,6 +95,7 @@ export function shouldProcessPerspectiveDefaultColunns( function processPerspectiveDefaultColunnsStep( config: PerspectiveConfig, dbInfos: MultipleDatabaseInfo, + dataPatterns: PerspectiveDataPatternDict, conid: string, database: string ) { @@ -112,6 +125,7 @@ function processPerspectiveDefaultColunnsStep( const table = db.tables.find(x => x.pureName == node.pureName && x.schemaName == node.schemaName); const view = db.views.find(x => x.pureName == node.pureName && x.schemaName == node.schemaName); + const collection = db.collections.find(x => x.pureName == node.pureName && x.schemaName == node.schemaName); if (table || view) { const treeNode = root.findNodeByDesignerId(node.designerId); @@ -186,6 +200,22 @@ function processPerspectiveDefaultColunnsStep( }; } } + + if (collection) { + const defaultColumns = getPerspectiveDefaultCollectionColumns(dataPatterns?.[node.designerId]); + return { + ...config, + nodes: config.nodes.map(n => + n.designerId == node.designerId + ? { + ...n, + defaultColumnsProcessed: true, + checkedColumns: defaultColumns, + } + : n + ), + }; + } } return null; @@ -204,11 +234,12 @@ function markAllProcessed(config: PerspectiveConfig): PerspectiveConfig { export function processPerspectiveDefaultColunns( config: PerspectiveConfig, dbInfos: MultipleDatabaseInfo, + dataPatterns: PerspectiveDataPatternDict, conid: string, database: string ): PerspectiveConfig { while (config.nodes.filter(x => !x.defaultColumnsProcessed).length > 0) { - const newConfig = processPerspectiveDefaultColunnsStep(config, dbInfos, conid, database); + const newConfig = processPerspectiveDefaultColunnsStep(config, dbInfos, dataPatterns, conid, database); if (!newConfig) { return markAllProcessed(config); } diff --git a/packages/datalib/src/tests/PerspectiveDisplay.test.ts b/packages/datalib/src/tests/PerspectiveDisplay.test.ts index d2c74f757..f86cc6b89 100644 --- a/packages/datalib/src/tests/PerspectiveDisplay.test.ts +++ b/packages/datalib/src/tests/PerspectiveDisplay.test.ts @@ -13,6 +13,7 @@ test('test flat view', () => { const configColumns = processPerspectiveDefaultColunns( createPerspectiveConfig({ pureName: 'Artist' }), { conid: { db: chinookDbInfo } }, + null, 'conid', 'db' ); @@ -47,7 +48,7 @@ test('test one level nesting', () => { columns: [{ source: 'ArtistId', target: 'ArtistId' }], }); - const configColumns = processPerspectiveDefaultColunns(config, { conid: { db: chinookDbInfo } }, 'conid', 'db'); + const configColumns = processPerspectiveDefaultColunns(config, { conid: { db: chinookDbInfo } }, null, 'conid', 'db'); // const config = createPerspectiveConfig({ pureName: 'Artist' }); // config.nodes[0].checkedColumns = ['Album']; @@ -107,7 +108,7 @@ test('test two level nesting', () => { designerId: '2', columns: [{ source: 'AlbumId', target: 'AlbumId' }], }); - const configColumns = processPerspectiveDefaultColunns(config, { conid: { db: chinookDbInfo } }, 'conid', 'db'); + const configColumns = processPerspectiveDefaultColunns(config, { conid: { db: chinookDbInfo } }, null, 'conid', 'db'); const root = new PerspectiveTableNode( artistTable, diff --git a/packages/web/src/perspectives/PerspectiveView.svelte b/packages/web/src/perspectives/PerspectiveView.svelte index 2caa237ed..db5e47184 100644 --- a/packages/web/src/perspectives/PerspectiveView.svelte +++ b/packages/web/src/perspectives/PerspectiveView.svelte @@ -169,7 +169,7 @@ $: { if (shouldProcessPerspectiveDefaultColunns(config, $dbInfos, $dataPatterns, conid, database)) { - setConfig(cfg => processPerspectiveDefaultColunns(cfg, $dbInfos, conid, database)); + setConfig(cfg => processPerspectiveDefaultColunns(cfg, $dbInfos, $dataPatterns, conid, database)); } }