mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-04-25 09:45:59 +00:00
Merge branch 'develop'
This commit is contained in:
@@ -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);
|
||||||
|
|||||||
@@ -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)) {
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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';
|
||||||
|
|||||||
22
packages/datalib/src/perspectiveTools.ts
Normal file
22
packages/datalib/src/perspectiveTools.ts
Normal 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;
|
||||||
|
}
|
||||||
@@ -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}
|
||||||
|
|||||||
@@ -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}
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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)}
|
||||||
|
|||||||
@@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
Reference in New Issue
Block a user