Merge branch 'develop'

This commit is contained in:
Jan Prochazka
2022-12-30 19:10:46 +01:00
12 changed files with 377 additions and 38 deletions

View File

@@ -5,6 +5,7 @@ import _difference from 'lodash/difference';
import debug from 'debug'; import debug from 'debug';
import stableStringify from 'json-stable-stringify'; import stableStringify from 'json-stable-stringify';
import { PerspectiveDataPattern } from './PerspectiveDataPattern'; import { PerspectiveDataPattern } from './PerspectiveDataPattern';
import { perspectiveValueMatcher } from './perspectiveTools';
const dbg = debug('dbgate:PerspectiveCache'); const dbg = debug('dbgate:PerspectiveCache');
@@ -17,7 +18,9 @@ export class PerspectiveBindingGroup {
bindingValues: any[]; bindingValues: any[];
matchRow(row) { matchRow(row) {
return this.table.bindingColumns.every((column, index) => row[column] == this.bindingValues[index]); return this.table.bindingColumns.every((column, index) =>
perspectiveValueMatcher(row[column], this.bindingValues[index])
);
} }
} }
@@ -69,7 +72,11 @@ export class PerspectiveCacheTable {
} }
storeGroupSize(props: PerspectiveDataLoadProps, bindingValues: any[], count: number) { storeGroupSize(props: PerspectiveDataLoadProps, bindingValues: any[], count: number) {
const originalBindingValue = props.bindingValues.find(v => _zip(v, bindingValues).every(([x, y]) => x == y)); const originalBindingValue = props.bindingValues.find(v =>
_zip(v, bindingValues).every(([x, y]) => perspectiveValueMatcher(x, y))
);
// console.log('storeGroupSize NEW', bindingValues);
// console.log('storeGroupSize ORIGINAL', originalBindingValue);
if (originalBindingValue) { if (originalBindingValue) {
const key = stableStringify(originalBindingValue); const key = stableStringify(originalBindingValue);
// console.log('SET SIZE', originalBindingValue, bindingValues, key, count); // console.log('SET SIZE', originalBindingValue, bindingValues, key, count);

View File

@@ -51,7 +51,7 @@ function addObjectToColumns(columns: PerspectiveDataPatternColumn[], row) {
if (!column.types.includes(type)) { if (!column.types.includes(type)) {
column.types.push(type); column.types.push(type);
} }
if (_isPlainObject(value)) { if (_isPlainObject(value) && type != 'oid') {
addObjectToColumns(column.columns, value); addObjectToColumns(column.columns, value);
} }
if (_isArray(value)) { if (_isArray(value)) {

View File

@@ -47,6 +47,7 @@ export class PerspectiveDataProvider {
async loadDataNested(props: PerspectiveDataLoadProps): Promise<{ rows: any[]; incomplete: boolean }> { async loadDataNested(props: PerspectiveDataLoadProps): Promise<{ rows: any[]; incomplete: boolean }> {
const tableCache = this.cache.getTableCache(props); const tableCache = this.cache.getTableCache(props);
// console.log('loadDataNested', props);
const uncached = tableCache.getUncachedBindingGroups(props); const uncached = tableCache.getUncachedBindingGroups(props);
if (uncached.length > 0) { if (uncached.length > 0) {
@@ -54,7 +55,7 @@ export class PerspectiveDataProvider {
...props, ...props,
bindingValues: uncached, bindingValues: uncached,
}); });
// console.log('COUNTS', counts); // console.log('loadDataNested COUNTS', counts);
for (const resetItem of uncached) { for (const resetItem of uncached) {
tableCache.storeGroupSize(props, resetItem, 0); tableCache.storeGroupSize(props, resetItem, 0);
} }
@@ -196,6 +197,14 @@ export class PerspectiveDataProvider {
}, },
}); });
if (!nextRows) {
// return tableCache.getRowsResult(props);
return {
rows: [],
incomplete: false,
};
}
if (nextRows.errorMessage) { if (nextRows.errorMessage) {
throw new Error(nextRows.errorMessage); throw new Error(nextRows.errorMessage);
} }

View File

@@ -22,6 +22,7 @@ import {
PerspectiveReferenceConfig, PerspectiveReferenceConfig,
} from './PerspectiveConfig'; } from './PerspectiveConfig';
import _isEqual from 'lodash/isEqual'; import _isEqual from 'lodash/isEqual';
import _isArray from 'lodash/isArray';
import _cloneDeep from 'lodash/cloneDeep'; import _cloneDeep from 'lodash/cloneDeep';
import _compact from 'lodash/compact'; import _compact from 'lodash/compact';
import _uniq from 'lodash/uniq'; import _uniq from 'lodash/uniq';
@@ -38,6 +39,11 @@ import { Condition, Expression, Select } from 'dbgate-sqltree';
// import { getPerspectiveDefaultColumns } from './getPerspectiveDefaultColumns'; // import { getPerspectiveDefaultColumns } from './getPerspectiveDefaultColumns';
import uuidv1 from 'uuid/v1'; import uuidv1 from 'uuid/v1';
import { PerspectiveDataPatternColumn } from './PerspectiveDataPattern'; import { PerspectiveDataPatternColumn } from './PerspectiveDataPattern';
import {
getPerspectiveMostNestedChildColumnName,
getPerspectiveParentColumnName,
perspectiveValueMatcher,
} from './perspectiveTools';
export interface PerspectiveDataLoadPropsWithNode { export interface PerspectiveDataLoadPropsWithNode {
props: PerspectiveDataLoadProps; props: PerspectiveDataLoadProps;
@@ -137,6 +143,16 @@ export abstract class PerspectiveTreeNode {
get generatesDataGridColumn() { get generatesDataGridColumn() {
return this.isCheckedColumn; return this.isCheckedColumn;
} }
get validParentDesignerId() {
if (this.designerId) return this.designerId;
return this.parentNode?.validParentDesignerId;
}
get preloadedLevelData() {
return false;
}
get findByDesignerIdWithoutDesignerId() {
return false;
}
matchChildRow(parentRow: any, childRow: any): boolean { matchChildRow(parentRow: any, childRow: any): boolean {
return true; return true;
} }
@@ -210,7 +226,7 @@ export abstract class PerspectiveTreeNode {
get hasUncheckedNodeInPath() { get hasUncheckedNodeInPath() {
if (!this.parentNode) return false; if (!this.parentNode) return false;
if (!this.isCheckedNode) return true; if (this.designerId && !this.isCheckedNode) return true;
return this.parentNode.hasUncheckedNodeInPath; return this.parentNode.hasUncheckedNodeInPath;
} }
@@ -404,7 +420,7 @@ export abstract class PerspectiveTreeNode {
// } // }
findNodeByDesignerId(designerId: string): PerspectiveTreeNode { findNodeByDesignerId(designerId: string): PerspectiveTreeNode {
if (!this.designerId) { if (!this.designerId && !this.findByDesignerIdWithoutDesignerId) {
return null; return null;
} }
if (!designerId) { if (!designerId) {
@@ -758,15 +774,22 @@ export class PerspectivePatternColumnNode extends PerspectiveTreeNode {
) { ) {
super(dbs, config, setConfig, parentNode, dataProvider, databaseConfig, designerId); super(dbs, config, setConfig, parentNode, dataProvider, databaseConfig, designerId);
this.parentNodeConfig = this.tableNodeOrParent?.nodeConfig; this.parentNodeConfig = this.tableNodeOrParent?.nodeConfig;
// console.log('PATTERN COLUMN', column);
} }
get isChildColumn() { get isChildColumn() {
return this.parentNode instanceof PerspectivePatternColumnNode; return this.parentNode instanceof PerspectivePatternColumnNode;
} }
get findByDesignerIdWithoutDesignerId() {
return this.isExpandable;
}
// matchChildRow(parentRow: any, childRow: any): boolean { // matchChildRow(parentRow: any, childRow: any): boolean {
// if (!this.foreignKey) return false; // console.log('MATCH PATTENR ROW', parentRow, childRow);
// return parentRow[this.foreignKey.columns[0].columnName] == childRow[this.foreignKey.columns[0].refColumnName]; // return false;
// // if (!this.foreignKey) return false;
// // return parentRow[this.foreignKey.columns[0].columnName] == childRow[this.foreignKey.columns[0].refColumnName];
// } // }
// getChildMatchColumns() { // getChildMatchColumns() {
@@ -808,12 +831,19 @@ export class PerspectivePatternColumnNode extends PerspectiveTreeNode {
// } // }
getNodeLoadProps(parentRows: any[]): PerspectiveDataLoadProps { getNodeLoadProps(parentRows: any[]): PerspectiveDataLoadProps {
// console.log('GETTING PATTERN', parentRows);
return null; return null;
} }
get generatesHiearchicGridColumn() { get generatesHiearchicGridColumn(): boolean {
// return true;
// console.log('generatesHiearchicGridColumn', this.parentTableNode?.nodeConfig?.checkedColumns, this.codeName + '::'); // console.log('generatesHiearchicGridColumn', this.parentTableNode?.nodeConfig?.checkedColumns, this.codeName + '::');
return !!this.tableNodeOrParent?.nodeConfig?.checkedColumns?.find(x => x.startsWith(this.codeName + '::')); if (this.tableNodeOrParent?.nodeConfig?.checkedColumns?.find(x => x.startsWith(this.codeName + '::'))) {
return true;
}
// return false;
return this.hasCheckedJoinChild();
} }
// get generatesHiearchicGridColumn() { // get generatesHiearchicGridColumn() {
@@ -859,7 +889,11 @@ export class PerspectivePatternColumnNode extends PerspectiveTreeNode {
return 'mongo'; return 'mongo';
} }
generateChildNodes(): PerspectiveTreeNode[] { get preloadedLevelData() {
return true;
}
generatePatternChildNodes(): PerspectivePatternColumnNode[] {
return this.column.columns.map( return this.column.columns.map(
column => column =>
new PerspectivePatternColumnNode( new PerspectivePatternColumnNode(
@@ -875,7 +909,92 @@ export class PerspectivePatternColumnNode extends PerspectiveTreeNode {
null null
) )
); );
return []; }
hasCheckedJoinChild() {
for (const node of this.childNodes) {
if (node instanceof PerspectivePatternColumnNode) {
if (node.hasCheckedJoinChild()) return true;
}
if (node.isCheckedNode) return true;
}
return false;
}
generateChildNodes(): PerspectiveTreeNode[] {
const patternChildren = this.generatePatternChildNodes();
const customs = [];
// console.log('GETTING CHILDREN', this.config.nodes, this.config.references);
for (const node of this.config.nodes) {
for (const ref of this.config.references) {
const validDesignerId = this.validParentDesignerId;
if (
(ref.sourceId == validDesignerId && ref.targetId == node.designerId) ||
(ref.targetId == validDesignerId && ref.sourceId == node.designerId)
) {
// console.log('TESTING REF', ref, this.codeName);
if (ref.columns.length != 1) continue;
// console.log('CP1');
if (
ref.sourceId == validDesignerId &&
this.codeName == getPerspectiveParentColumnName(ref.columns[0].source)
) {
if (ref.columns[0].target.includes('::')) continue;
} else if (
ref.targetId == validDesignerId &&
this.codeName == getPerspectiveParentColumnName(ref.columns[0].target)
) {
if (ref.columns[0].source.includes('::')) continue;
} else {
continue;
}
// console.log('CP2');
const newConfig = { ...this.databaseConfig };
if (node.conid) newConfig.conid = node.conid;
if (node.database) newConfig.database = node.database;
const db = this.dbs?.[newConfig.conid]?.[newConfig.database];
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);
const join: PerspectiveCustomJoinConfig = {
refNodeDesignerId: node.designerId,
referenceDesignerId: ref.designerId,
baseDesignerId: validDesignerId,
joinName: node.alias,
refTableName: node.pureName,
refSchemaName: node.schemaName,
conid: node.conid,
database: node.database,
columns:
ref.sourceId == validDesignerId
? ref.columns.map(col => ({ baseColumnName: col.source, refColumnName: col.target }))
: ref.columns.map(col => ({ baseColumnName: col.target, refColumnName: col.source })),
};
if (table || view || collection) {
customs.push(
new PerspectiveCustomJoinTreeNode(
join,
table || view || collection,
this.dbs,
this.config,
this.setConfig,
this.dataProvider,
newConfig,
this,
node.designerId
)
);
}
}
}
}
return [...patternChildren, ...customs];
// return [];
// if (!this.foreignKey) return []; // if (!this.foreignKey) return [];
// const tbl = this?.db?.tables?.find( // const tbl = this?.db?.tables?.find(
// x => x.pureName == this.foreignKey?.refTableName && x.schemaName == this.foreignKey?.refSchemaName // x => x.pureName == this.foreignKey?.refTableName && x.schemaName == this.foreignKey?.refSchemaName
@@ -1153,8 +1272,14 @@ export class PerspectiveCustomJoinTreeNode extends PerspectiveTableNode {
} }
matchChildRow(parentRow: any, childRow: any): boolean { matchChildRow(parentRow: any, childRow: any): boolean {
// console.log('MATCH ROW', parentRow, childRow);
for (const column of this.customJoin.columns) { for (const column of this.customJoin.columns) {
if (parentRow[column.baseColumnName] != childRow[column.refColumnName]) { if (
!perspectiveValueMatcher(
parentRow[getPerspectiveMostNestedChildColumnName(column.baseColumnName)],
childRow[column.refColumnName]
)
) {
return false; return false;
} }
} }
@@ -1171,17 +1296,68 @@ export class PerspectiveCustomJoinTreeNode extends PerspectiveTableNode {
getNodeLoadProps(parentRows: any[]): PerspectiveDataLoadProps { getNodeLoadProps(parentRows: any[]): PerspectiveDataLoadProps {
// console.log('CUSTOM JOIN', this.customJoin); // console.log('CUSTOM JOIN', this.customJoin);
// console.log('PARENT ROWS', parentRows);
// console.log('this.getDataLoadColumns()', this.getDataLoadColumns()); // console.log('this.getDataLoadColumns()', this.getDataLoadColumns());
const isMongo = isCollectionInfo(this.table); const isMongo = isCollectionInfo(this.table);
// const bindingValues = [];
// for (const row of parentRows) {
// const rowBindingValueArrays = [];
// for (const col of this.customJoin.columns) {
// const path = col.baseColumnName.split('::');
// const values = [];
// function processSubpath(parent, subpath) {
// if (subpath.length == 0) {
// values.push(parent);
// return;
// }
// if (parent == null) {
// return;
// }
// const obj = parent[subpath[0]];
// if (_isArray(obj)) {
// for (const elem of obj) {
// processSubpath(elem, subpath.slice(1));
// }
// } else {
// processSubpath(obj, subpath.slice(1));
// }
// }
// processSubpath(row, path);
// rowBindingValueArrays.push(values);
// }
// const valueCount = Math.max(...rowBindingValueArrays.map(x => x.length));
// for (let i = 0; i < valueCount; i += 1) {
// const value = Array(this.customJoin.columns.length);
// for (let col = 0; col < this.customJoin.columns.length; col++) {
// value[col] = rowBindingValueArrays[col][i % rowBindingValueArrays[col].length];
// }
// bindingValues.push(value);
// }
// }
const bindingValues = parentRows.map(row =>
this.customJoin.columns.map(x => row[getPerspectiveMostNestedChildColumnName(x.baseColumnName)])
);
// console.log('bindingValues', bindingValues);
// console.log(
// 'bindingValues UNIQ',
// _uniqBy(bindingValues, x => JSON.stringify(x))
// );
return { return {
schemaName: this.table.schemaName, schemaName: this.table.schemaName,
pureName: this.table.pureName, pureName: this.table.pureName,
bindingColumns: this.getParentMatchColumns(), bindingColumns: this.getParentMatchColumns(),
bindingValues: _uniqBy( bindingValues: _uniqBy(bindingValues, x => JSON.stringify(x)),
parentRows.map(row => this.customJoin.columns.map(x => row[x.baseColumnName])),
stableStringify
),
dataColumns: this.getDataLoadColumns(), dataColumns: this.getDataLoadColumns(),
allColumns: isMongo, allColumns: isMongo,
databaseConfig: this.databaseConfig, databaseConfig: this.databaseConfig,
@@ -1412,6 +1588,9 @@ export function getTableChildPerspectiveNodes(
(ref.sourceId == parentNode.designerId && ref.targetId == node.designerId) || (ref.sourceId == parentNode.designerId && ref.targetId == node.designerId) ||
(ref.targetId == parentNode.designerId && ref.sourceId == node.designerId) (ref.targetId == parentNode.designerId && ref.sourceId == node.designerId)
) { ) {
if (ref.columns.find(x => x.source.includes('::') || x.target.includes('::'))) {
continue;
}
const newConfig = { ...databaseConfig }; const newConfig = { ...databaseConfig };
if (node.conid) newConfig.conid = node.conid; if (node.conid) newConfig.conid = node.conid;
if (node.database) newConfig.database = node.database; if (node.database) newConfig.database = node.database;

View File

@@ -21,3 +21,4 @@ export * from './PerspectiveConfig';
export * from './processPerspectiveDefaultColunns'; export * from './processPerspectiveDefaultColunns';
export * from './PerspectiveDataPattern'; export * from './PerspectiveDataPattern';
export * from './PerspectiveDataLoader'; export * from './PerspectiveDataLoader';
export * from './perspectiveTools';

View File

@@ -0,0 +1,22 @@
export function getPerspectiveParentColumnName(columnName: string) {
const path = columnName.split('::');
if (path.length >= 2) return path.slice(0, -1).join('::');
return null;
}
export function getPerspectiveMostNestedChildColumnName(columnName: string) {
const path = columnName.split('::');
return path[path.length - 1];
}
// export function perspectiveValueMatcher(value1, value2): boolean {
// if (value1?.$oid && value2?.$oid) return value1.$oid == value2.$oid;
// if (Array.isArray(value1)) return !!value1.find(x => perspectiveValueMatcher(x, value2));
// if (Array.isArray(value2)) return !!value2.find(x => perspectiveValueMatcher(value1, x));
// return value1 == value2;
// }
export function perspectiveValueMatcher(value1, value2): boolean {
if (value1?.$oid && value2?.$oid) return value1.$oid == value2.$oid;
return value1 == value2;
}

View File

@@ -6,6 +6,7 @@
import ColumnLabel from '../elements/ColumnLabel.svelte'; import ColumnLabel from '../elements/ColumnLabel.svelte';
import CheckboxField from '../forms/CheckboxField.svelte'; import CheckboxField from '../forms/CheckboxField.svelte';
import { plusExpandIcon } from '../icons/expandIcons';
import FontIcon from '../icons/FontIcon.svelte'; import FontIcon from '../icons/FontIcon.svelte';
import contextMenu from '../utility/contextMenu'; import contextMenu from '../utility/contextMenu';
import SortOrderIcon from './SortOrderIcon.svelte'; import SortOrderIcon from './SortOrderIcon.svelte';
@@ -21,6 +22,11 @@
export let onAddReferenceByColumn; export let onAddReferenceByColumn;
export let onSelectColumn; export let onSelectColumn;
export let settings; export let settings;
export let nestingSupported = null;
export let isExpandable = false;
export let isExpanded = false;
export let expandLevel = 0;
export let toggleExpanded = null;
$: designerColumn = (designer.columns || []).find( $: designerColumn = (designer.columns || []).find(
x => x.designerId == designerId && x.columnName == column.columnName x => x.designerId == designerId && x.columnName == column.columnName
@@ -115,16 +121,27 @@
})} })}
use:contextMenu={settings?.canSelectColumns ? createMenu : '__no_menu'} use:contextMenu={settings?.canSelectColumns ? createMenu : '__no_menu'}
> >
{#if nestingSupported}
<span class="expandColumnIcon" style={`margin-right: ${5 + expandLevel * 10}px`}>
<FontIcon
icon={isExpandable ? plusExpandIcon(isExpanded) : 'icon invisible-box'}
on:click={() => {
toggleExpanded(!isExpanded);
}}
/>
</span>
{/if}
{#if settings?.allowColumnOperations} {#if settings?.allowColumnOperations}
<CheckboxField <CheckboxField
checked={settings?.isColumnChecked checked={settings?.isColumnChecked
? settings?.isColumnChecked(designerId, column.columnName) ? settings?.isColumnChecked(designerId, column)
: !!(designer.columns || []).find( : !!(designer.columns || []).find(
x => x.designerId == designerId && x.columnName == column.columnName && x.isOutput x => x.designerId == designerId && x.columnName == column.columnName && x.isOutput
)} )}
on:change={e => { on:change={e => {
if (settings?.setColumnChecked) { if (settings?.setColumnChecked) {
settings?.setColumnChecked(designerId, column.columnName, e.target.checked); settings?.setColumnChecked(designerId, column, e.target.checked);
} else { } else {
if (e.target.checked) { if (e.target.checked) {
onChangeColumn( onChangeColumn(
@@ -147,7 +164,13 @@
}} }}
/> />
{/if} {/if}
<ColumnLabel {...column} {foreignKey} forceIcon {iconOverride} /> <ColumnLabel
{...column}
columnName={settings?.getColumnDisplayName ? settings?.getColumnDisplayName(column) : column.columnName}
{foreignKey}
forceIcon
{iconOverride}
/>
{#if designerColumn?.filter} {#if designerColumn?.filter}
<FontIcon icon="img filter" /> <FontIcon icon="img filter" />
{/if} {/if}

View File

@@ -1,6 +1,6 @@
<script lang="ts"> <script lang="ts">
import { presetDarkPalettes, presetPalettes } from '@ant-design/colors'; import { presetDarkPalettes, presetPalettes } from '@ant-design/colors';
import { computeDbDiffRows } from 'dbgate-tools'; import { filterName } from 'dbgate-tools';
import { tick } from 'svelte'; import { tick } from 'svelte';
import { createDatabaseObjectMenu } from '../appobj/DatabaseObjectAppObject.svelte'; import { createDatabaseObjectMenu } from '../appobj/DatabaseObjectAppObject.svelte';
@@ -68,6 +68,27 @@
$: specificDb = settings?.tableSpecificDb ? settings?.tableSpecificDb(designerId) : null; $: specificDb = settings?.tableSpecificDb ? settings?.tableSpecificDb(designerId) : null;
$: filterParentRows = settings?.hasFilterParentRowsFlag ? settings?.hasFilterParentRowsFlag(designerId) : false; $: filterParentRows = settings?.hasFilterParentRowsFlag ? settings?.hasFilterParentRowsFlag(designerId) : false;
$: isGrayed = settings?.isGrayedTable ? settings?.isGrayedTable(designerId) : false; $: isGrayed = settings?.isGrayedTable ? settings?.isGrayedTable(designerId) : false;
$: flatColumns = getFlatColumns(columns, '', 0);
function getFlatColumns(columns, filter, level) {
if (!columns) return [];
const res = [];
for (const col of columns) {
if (filterName(filter, col.columnName)) {
res.push({ ...col, expandLevel: level });
if (col.isExpanded) {
res.push(...getFlatColumns(col.getChildColumns ? col.getChildColumns() : null, filter, level + 1));
}
} else if (col.isExpanded) {
const children = getFlatColumns(col.getChildColumns ? col.getChildColumns() : null, filter, level + 1);
if (children.length > 0) {
res.push({ ...col, expandLevel: level });
res.push(...children);
}
}
}
return res;
}
export function isSelected() { export function isSelected() {
return table?.isSelectedTable; return table?.isSelectedTable;
@@ -156,7 +177,7 @@
export function getDomTable() { export function getDomTable() {
const domRefs = { ...columnRefs }; const domRefs = { ...columnRefs };
domRefs[''] = domWrapper; domRefs[''] = domWrapper;
return new DomTableRef(table, domRefs, domCanvas); return new DomTableRef(table, domRefs, domCanvas, settings);
} }
const handleSetTableAlias = () => { const handleSetTableAlias = () => {
@@ -214,7 +235,7 @@
]; ];
} }
// $: console.log('COLUMNS', columns); // $: console.log('COLUMNS', flatColumns);
</script> </script>
<div <div
@@ -279,8 +300,13 @@
{/if} {/if}
</div> </div>
<div class="columns" on:scroll={() => tick().then(onMoveReferences)} class:scroll={settings?.allowScrollColumns}> <div class="columns" on:scroll={() => tick().then(onMoveReferences)} class:scroll={settings?.allowScrollColumns}>
{#each columns || [] as column} {#each flatColumns || [] as column (column.columnName)}
<ColumnLine <ColumnLine
nestingSupported={!!settings?.isColumnExpandable && columns.find(x => settings?.isColumnExpandable(x))}
isExpandable={settings?.isColumnExpandable && settings?.isColumnExpandable(column)}
isExpanded={settings?.isColumnExpanded && settings?.isColumnExpanded(column)}
expandLevel={settings?.columnExpandLevel ? settings?.columnExpandLevel(column) : 0}
toggleExpanded={value => settings?.toggleExpandedColumn(column, value)}
{column} {column}
{table} {table}
{designer} {designer}

View File

@@ -6,13 +6,15 @@ export default class DomTableRef {
table: DesignerTableInfo; table: DesignerTableInfo;
designerId: string; designerId: string;
domRefs: { [column: string]: Element }; domRefs: { [column: string]: Element };
settings: any;
constructor(table: DesignerTableInfo, domRefs, domWrapper: Element) { constructor(table: DesignerTableInfo, domRefs, domWrapper: Element, settings) {
this.domTable = domRefs['']; this.domTable = domRefs[''];
this.domWrapper = domWrapper; this.domWrapper = domWrapper;
this.table = table; this.table = table;
this.designerId = table.designerId; this.designerId = table.designerId;
this.domRefs = domRefs; this.domRefs = domRefs;
this.settings = settings;
} }
getRect() { getRect() {
@@ -31,6 +33,10 @@ export default class DomTableRef {
getColumnY(columnName: string) { getColumnY(columnName: string) {
let col = this.domRefs[columnName]; let col = this.domRefs[columnName];
while (col == null && this.settings?.getParentColumnName && this.settings?.getParentColumnName(columnName)) {
columnName = this.settings?.getParentColumnName(columnName);
col = this.domRefs[columnName];
}
if (!col) return null; if (!col) return null;
const rect = col.getBoundingClientRect(); const rect = col.getBoundingClientRect();
const wrap = this.domWrapper.getBoundingClientRect(); const wrap = this.domWrapper.getBoundingClientRect();

View File

@@ -1,6 +1,10 @@
<script lang="ts"> <script lang="ts">
import { import {
ChangePerspectiveConfigFunc,
createPerspectiveNodeConfig, createPerspectiveNodeConfig,
getPerspectiveParentColumnName,
PerspectiveDataPatternColumn,
PerspectiveNodeConfig,
perspectiveNodesHaveStructure, perspectiveNodesHaveStructure,
PerspectiveTreeNode, PerspectiveTreeNode,
switchPerspectiveReferenceDirection, switchPerspectiveReferenceDirection,
@@ -28,6 +32,32 @@
export let onClickTableHeader = null; export let onClickTableHeader = null;
function mapDataPatternColumn(
column: PerspectiveDataPatternColumn,
node: PerspectiveNodeConfig,
codeNamePrefix: string
) {
return {
columnName: codeNamePrefix + column.name,
shortName: column.name,
getChildColumns:
column.columns?.length > 0
? () => column.columns.map(x => mapDataPatternColumn(x, node, codeNamePrefix + column.name + '::'))
: null,
isExpanded: node.expandedColumns.includes(codeNamePrefix + column.name),
toggleExpanded: value =>
setConfig(cfg => ({
...cfg,
nodes: cfg.nodes.map(node => ({
...node,
expandedColumns: value
? [...(node.expandedColumns || []), codeNamePrefix + column.name]
: (node.expandedColumns || []).filter(x => x != codeNamePrefix + column.name),
})),
})),
};
}
function createDesignerModel( function createDesignerModel(
config: PerspectiveConfig, config: PerspectiveConfig,
dbInfos: MultipleDatabaseInfo, dbInfos: MultipleDatabaseInfo,
@@ -49,10 +79,7 @@
if (!pattern) return null; if (!pattern) return null;
collection = { collection = {
...collection, ...collection,
columns: columns: pattern?.columns.map(x => mapDataPatternColumn(x, node, '')) || [],
pattern?.columns.map(x => ({
columnName: x.name,
})) || [],
}; };
} }
@@ -200,10 +227,10 @@
]; ];
}, },
createReferenceText: reference => (reference.isAutoGenerated ? 'FK' : 'Custom'), createReferenceText: reference => (reference.isAutoGenerated ? 'FK' : 'Custom'),
isColumnChecked: (designerId, columnName) => { isColumnChecked: (designerId, column) => {
return config.nodes.find(x => x.designerId == designerId)?.checkedColumns?.includes(columnName); return config.nodes.find(x => x.designerId == designerId)?.checkedColumns?.includes(column.columnName);
}, },
setColumnChecked: (designerId, columnName, value) => { setColumnChecked: (designerId, column, value) => {
setConfig(cfg => ({ setConfig(cfg => ({
...cfg, ...cfg,
nodes: cfg.nodes.map(node => nodes: cfg.nodes.map(node =>
@@ -211,8 +238,8 @@
? { ? {
...node, ...node,
checkedColumns: value checkedColumns: value
? [...(node.checkedColumns || []), columnName] ? [...(node.checkedColumns || []), column.columnName]
: (node.checkedColumns || []).filter(x => x != columnName), : (node.checkedColumns || []).filter(x => x != column.columnName),
} }
: node : node
), ),
@@ -301,6 +328,12 @@
return false; return false;
}, },
onClickTableHeader, onClickTableHeader,
isColumnExpandable: column => !!column.getChildColumns,
isColumnExpanded: column => column.isExpanded,
columnExpandLevel: column => column.expandLevel,
toggleExpandedColumn: (column, value) => column.toggleExpanded(value),
getColumnDisplayName: column => column.shortName || column.columnName,
getParentColumnName: getPerspectiveParentColumnName,
}} }}
referenceComponent={QueryDesignerReference} referenceComponent={QueryDesignerReference}
value={createDesignerModel(config, dbInfos, dataPatterns)} value={createDesignerModel(config, dbInfos, dataPatterns)}

View File

@@ -79,7 +79,12 @@
const lastVisibleRowIndexRef = createRef(0); const lastVisibleRowIndexRef = createRef(0);
const disableLoadNextRef = createRef(false); const disableLoadNextRef = createRef(false);
// Essential function !!
// Fills nested data into parentRows (assigns into array parentRows[i][node.fieldName])
// eg. when node is CustomJoinTreeNode, loads data from data provider
async function loadLevelData(node: PerspectiveTreeNode, parentRows: any[], counts) { async function loadLevelData(node: PerspectiveTreeNode, parentRows: any[], counts) {
// console.log('loadLevelData', node.codeName, node.fieldName, parentRows);
// console.log('COUNTS', node.codeName, counts);
dbg('load level data', counts); dbg('load level data', counts);
// const loadProps: PerspectiveDataLoadPropsWithNode[] = []; // const loadProps: PerspectiveDataLoadPropsWithNode[] = [];
const loadChildNodes = []; const loadChildNodes = [];
@@ -100,7 +105,8 @@
incompleteRowsIndicator: [node.designerId], incompleteRowsIndicator: [node.designerId],
}); });
} }
} else { } else if (!node.preloadedLevelData) {
// console.log('LOADED ROWS', rows);
let lastRowWithChildren = null; let lastRowWithChildren = null;
for (const parentRow of parentRows) { for (const parentRow of parentRows) {
const childRows = rows.filter(row => node.matchChildRow(parentRow, row)); const childRows = rows.filter(row => node.matchChildRow(parentRow, row));
@@ -114,11 +120,38 @@
incompleteRowsIndicator: [node.designerId], incompleteRowsIndicator: [node.designerId],
}); });
} }
} else {
// this is needed for nested call
rows = _.compact(_.flatten(parentRows.map(x => x[node.fieldName])));
} }
// console.log('TESTING NODE', node);
// console.log('ROWS', rows);
for (const child of node.childNodes) { for (const child of node.childNodes) {
if (child.isExpandable && child.isCheckedNode) { // console.log('TEST CHILD FOR LOAD', child);
await loadLevelData(child, rows, counts); // console.log(child.isExpandable, child.isCheckedNode, child.preloadedLevelData);
if (child.isExpandable && (child.isCheckedNode || child.preloadedLevelData)) {
// console.log('TESTED OK');
// if (child.preloadedLevelData) console.log('LOADING CHILD DATA', rows);
// console.log(child.preloadedLevelData, child);
// console.log('LOADING FOR CHILD', child.codeName, child.columnName, child);
// console.log('CALL CHILD', child.codeName, rows, parentRows);
await loadLevelData(
child,
rows,
// node.preloadedLevelData
// ? _.compact(_.flatten(parentRows.map(x => x[child.columnName])))
// : child.preloadedLevelData
// ? parentRows
// : rows,
// child.preloadedLevelData
// ? _.compact(_.flatten(parentRows.map(x => x[child.columnName])))
// : node.preloadedLevelData
// ? parentRows
// : rows,
counts
);
// loadProps.push(child.getNodeLoadProps()); // loadProps.push(child.getNodeLoadProps());
} }
} }

View File

@@ -258,7 +258,7 @@ const driver = {
const count = await collection.countDocuments(convertObjectId(options.condition) || {}); const count = await collection.countDocuments(convertObjectId(options.condition) || {});
return { count }; return { count };
} else if (options.aggregate) { } else if (options.aggregate) {
let cursor = await collection.aggregate(options.aggregate); let cursor = await collection.aggregate(convertObjectId(options.aggregate));
const rows = await cursor.toArray(); const rows = await cursor.toArray();
return { rows: rows.map(transformMongoData) }; return { rows: rows.map(transformMongoData) };
} else { } else {