mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-04-23 19:36:02 +00:00
perspective data pattern
This commit is contained in:
@@ -5,6 +5,7 @@ import _zip from 'lodash/zip';
|
||||
import _difference from 'lodash/difference';
|
||||
import debug from 'debug';
|
||||
import stableStringify from 'json-stable-stringify';
|
||||
import { PerspectiveDataPattern } from './PerspectiveDataPattern';
|
||||
|
||||
const dbg = debug('dbgate:PerspectiveCache');
|
||||
|
||||
@@ -86,6 +87,7 @@ export class PerspectiveCache {
|
||||
constructor() {}
|
||||
|
||||
tables: { [tableKey: string]: PerspectiveCacheTable } = {};
|
||||
dataPatterns: PerspectiveDataPattern[] = [];
|
||||
|
||||
getTableCache(props: PerspectiveDataLoadProps) {
|
||||
const tableKey = stableStringify(
|
||||
@@ -113,5 +115,6 @@ export class PerspectiveCache {
|
||||
|
||||
clear() {
|
||||
this.tables = {};
|
||||
this.dataPatterns = [];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,8 +93,8 @@ export class PerspectiveDataLoader {
|
||||
}));
|
||||
}
|
||||
|
||||
async loadData(props: PerspectiveDataLoadProps) {
|
||||
const { schemaName, pureName, bindingColumns, bindingValues, dataColumns, orderBy, condition } = props;
|
||||
async loadDataSqlDb(props: PerspectiveDataLoadProps) {
|
||||
const { schemaName, pureName, bindingColumns, bindingValues, dataColumns, orderBy, condition, engineType } = props;
|
||||
|
||||
if (dataColumns?.length == 0) {
|
||||
return [];
|
||||
@@ -143,7 +143,53 @@ export class PerspectiveDataLoader {
|
||||
return response.rows;
|
||||
}
|
||||
|
||||
async loadRowCount(props: PerspectiveDataLoadProps) {
|
||||
getDocDbLoadOptions(props: PerspectiveDataLoadProps) {
|
||||
const { pureName } = props;
|
||||
return {
|
||||
pureName,
|
||||
skip: props.range?.offset,
|
||||
limit: props.range?.limit,
|
||||
};
|
||||
}
|
||||
|
||||
async loadDataDocDb(props: PerspectiveDataLoadProps) {
|
||||
const { schemaName, pureName, bindingColumns, bindingValues, dataColumns, orderBy, condition, engineType } = props;
|
||||
|
||||
if (dataColumns?.length == 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (dbg?.enabled) {
|
||||
dbg(
|
||||
`LOAD DATA, collection=${props.pureName}, columns=${props.dataColumns?.join(',')}, range=${
|
||||
props.range?.offset
|
||||
},${props.range?.limit}`
|
||||
);
|
||||
}
|
||||
|
||||
const options = this.getDocDbLoadOptions(props);
|
||||
|
||||
const response = await this.apiCall('database-connections/collection-data', {
|
||||
conid: props.databaseConfig.conid,
|
||||
database: props.databaseConfig.database,
|
||||
options,
|
||||
});
|
||||
|
||||
if (response.errorMessage) return response;
|
||||
return response.rows;
|
||||
}
|
||||
|
||||
async loadData(props: PerspectiveDataLoadProps) {
|
||||
const { engineType } = props;
|
||||
switch (engineType) {
|
||||
case 'sqldb':
|
||||
return this.loadDataSqlDb(props);
|
||||
case 'docdb':
|
||||
return this.loadDataDocDb(props);
|
||||
}
|
||||
}
|
||||
|
||||
async loadRowCountSqlDb(props: PerspectiveDataLoadProps) {
|
||||
const { schemaName, pureName, bindingColumns, bindingValues, dataColumns, orderBy, condition } = props;
|
||||
|
||||
const select: Select = {
|
||||
@@ -170,4 +216,31 @@ export class PerspectiveDataLoader {
|
||||
if (response.errorMessage) return response;
|
||||
return response.rows[0];
|
||||
}
|
||||
|
||||
async loadRowCountDocDb(props: PerspectiveDataLoadProps) {
|
||||
const { schemaName, pureName, bindingColumns, bindingValues, dataColumns, orderBy, condition } = props;
|
||||
|
||||
const options = {
|
||||
...this.getDocDbLoadOptions(props),
|
||||
countDocuments: true,
|
||||
};
|
||||
|
||||
const response = await this.apiCall('database-connections/collection-data', {
|
||||
conid: props.databaseConfig.conid,
|
||||
database: props.databaseConfig.database,
|
||||
options,
|
||||
});
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
async loadRowCount(props: PerspectiveDataLoadProps) {
|
||||
const { engineType } = props;
|
||||
switch (engineType) {
|
||||
case 'sqldb':
|
||||
return this.loadRowCountSqlDb(props);
|
||||
case 'docdb':
|
||||
return this.loadRowCountDocDb(props);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
65
packages/datalib/src/PerspectiveDataPattern.ts
Normal file
65
packages/datalib/src/PerspectiveDataPattern.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
import { PerspectiveDataLoader } from './PerspectiveDataLoader';
|
||||
import { PerspectiveDataLoadProps } from './PerspectiveDataProvider';
|
||||
import _isString from 'lodash/isString';
|
||||
import _isPlainObject from 'lodash/isPlainObject';
|
||||
import _isNumber from 'lodash/isNumber';
|
||||
import _isBoolean from 'lodash/isBoolean';
|
||||
|
||||
export type PerspectiveDataPatternColumnType = 'null' | 'string' | 'number' | 'boolean' | 'object';
|
||||
|
||||
export interface PerspectiveDataPatternColumn {
|
||||
name: string;
|
||||
types: PerspectiveDataPatternColumnType[];
|
||||
columns: PerspectiveDataPatternColumn[];
|
||||
}
|
||||
|
||||
export interface PerspectiveDataPattern {
|
||||
conid: string;
|
||||
database: string;
|
||||
schemaName: string;
|
||||
pureName: string;
|
||||
columns: PerspectiveDataPatternColumn[];
|
||||
}
|
||||
|
||||
export type PerspectiveDataPatternDict = { [designerId: string]: PerspectiveDataPattern };
|
||||
|
||||
function detectValueType(value): PerspectiveDataPatternColumnType {
|
||||
if (_isString(value)) return 'string';
|
||||
if (_isNumber(value)) return 'number';
|
||||
if (_isBoolean(value)) return 'boolean';
|
||||
if (value == null) return 'null';
|
||||
}
|
||||
|
||||
function addObjectToColumns(columns: PerspectiveDataPatternColumn[], row) {
|
||||
if (_isPlainObject(row)) {
|
||||
for (const key of Object.keys(row)) {
|
||||
let column: PerspectiveDataPatternColumn = columns.find(x => x.name == key);
|
||||
if (!column) {
|
||||
column = {
|
||||
name: key,
|
||||
types: [],
|
||||
columns: [],
|
||||
};
|
||||
columns.push(column);
|
||||
}
|
||||
const type = detectValueType(row[key]);
|
||||
if (!column.types.includes(type)) {
|
||||
column.types.push(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function analyseDataPattern(
|
||||
patternBase: Omit<PerspectiveDataPattern, 'columns'>,
|
||||
rows: any[]
|
||||
): PerspectiveDataPattern {
|
||||
const res: PerspectiveDataPattern = {
|
||||
...patternBase,
|
||||
columns: [],
|
||||
};
|
||||
for (const row of rows) {
|
||||
addObjectToColumns(res.columns, row);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import { RangeDefinition } from 'dbgate-types';
|
||||
import { format } from 'path';
|
||||
import { PerspectiveBindingGroup, PerspectiveCache } from './PerspectiveCache';
|
||||
import { PerspectiveDataLoader } from './PerspectiveDataLoader';
|
||||
import { PerspectiveDataPatternDict } from './PerspectiveDataPattern';
|
||||
|
||||
export const PERSPECTIVE_PAGE_SIZE = 100;
|
||||
|
||||
@@ -28,10 +29,15 @@ export interface PerspectiveDataLoadProps {
|
||||
range?: RangeDefinition;
|
||||
topCount?: number;
|
||||
condition?: Condition;
|
||||
engineType: 'sqldb' | 'docdb';
|
||||
}
|
||||
|
||||
export class PerspectiveDataProvider {
|
||||
constructor(public cache: PerspectiveCache, public loader: PerspectiveDataLoader) {}
|
||||
constructor(
|
||||
public cache: PerspectiveCache,
|
||||
public loader: PerspectiveDataLoader,
|
||||
public dataPatterns: PerspectiveDataPatternDict
|
||||
) {}
|
||||
async loadData(props: PerspectiveDataLoadProps): Promise<{ rows: any[]; incomplete: boolean }> {
|
||||
dbg('load data', props);
|
||||
// console.log('LOAD DATA', props);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import {
|
||||
CollectionInfo,
|
||||
ColumnInfo,
|
||||
DatabaseInfo,
|
||||
ForeignKeyInfo,
|
||||
@@ -313,7 +314,7 @@ export abstract class PerspectiveTreeNode {
|
||||
};
|
||||
}
|
||||
|
||||
getOrderBy(table: TableInfo | ViewInfo): PerspectiveDataLoadProps['orderBy'] {
|
||||
getOrderBy(table: TableInfo | ViewInfo | CollectionInfo): PerspectiveDataLoadProps['orderBy'] {
|
||||
const res = _compact(
|
||||
this.childNodes.map(node => {
|
||||
const sort = this.nodeConfig?.sort?.find(x => x.columnName == node.columnName);
|
||||
@@ -325,11 +326,15 @@ export abstract class PerspectiveTreeNode {
|
||||
}
|
||||
})
|
||||
);
|
||||
return res.length > 0
|
||||
? res
|
||||
: (table as TableInfo)?.primaryKey?.columns.map(x => ({ columnName: x.columnName, order: 'ASC' })) || [
|
||||
{ columnName: table?.columns[0].columnName, order: 'ASC' },
|
||||
];
|
||||
if (res.length > 0) return res;
|
||||
const pkColumns = (table as TableInfo)?.primaryKey?.columns.map(x => ({
|
||||
columnName: x.columnName,
|
||||
order: 'ASC' as 'ASC',
|
||||
}));
|
||||
if (pkColumns) return pkColumns;
|
||||
const columns = (table as TableInfo | ViewInfo)?.columns;
|
||||
if (columns) return [{ columnName: columns[0].columnName, order: 'ASC' }];
|
||||
return [{ columnName: '_id', order: 'ASC' }];
|
||||
}
|
||||
|
||||
getBaseTables() {
|
||||
@@ -553,6 +558,7 @@ export class PerspectiveTableColumnNode extends PerspectiveTreeNode {
|
||||
databaseConfig: this.databaseConfig,
|
||||
orderBy: this.getOrderBy(this.refTable),
|
||||
condition: this.getChildrenCondition(),
|
||||
engineType: 'sqldb',
|
||||
};
|
||||
}
|
||||
|
||||
@@ -715,6 +721,7 @@ export class PerspectiveTableNode extends PerspectiveTreeNode {
|
||||
databaseConfig: this.databaseConfig,
|
||||
orderBy: this.getOrderBy(this.table),
|
||||
condition: this.getChildrenCondition(),
|
||||
engineType: 'sqldb',
|
||||
};
|
||||
}
|
||||
|
||||
@@ -771,6 +778,88 @@ export class PerspectiveTableNode extends PerspectiveTreeNode {
|
||||
}
|
||||
}
|
||||
|
||||
export class PerspectiveCollectionNode extends PerspectiveTreeNode {
|
||||
constructor(
|
||||
public collection: CollectionInfo,
|
||||
dbs: MultipleDatabaseInfo,
|
||||
config: PerspectiveConfig,
|
||||
setConfig: ChangePerspectiveConfigFunc,
|
||||
public dataProvider: PerspectiveDataProvider,
|
||||
databaseConfig: PerspectiveDatabaseConfig,
|
||||
parentNode: PerspectiveTreeNode,
|
||||
designerId: string
|
||||
) {
|
||||
super(dbs, config, setConfig, parentNode, dataProvider, databaseConfig, designerId);
|
||||
}
|
||||
|
||||
getNodeLoadProps(parentRows: any[]): PerspectiveDataLoadProps {
|
||||
return {
|
||||
schemaName: this.collection.schemaName,
|
||||
pureName: this.collection.pureName,
|
||||
dataColumns: this.getDataLoadColumns(),
|
||||
databaseConfig: this.databaseConfig,
|
||||
orderBy: this.getOrderBy(this.collection),
|
||||
condition: this.getChildrenCondition(),
|
||||
engineType: 'docdb',
|
||||
};
|
||||
}
|
||||
|
||||
get codeName() {
|
||||
return this.collection.schemaName
|
||||
? `${this.collection.schemaName}:${this.collection.pureName}`
|
||||
: this.collection.pureName;
|
||||
}
|
||||
|
||||
get title() {
|
||||
return this.nodeConfig?.alias || this.collection.pureName;
|
||||
}
|
||||
|
||||
get isExpandable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
generateChildNodes(): PerspectiveTreeNode[] {
|
||||
return [];
|
||||
// return getTableChildPerspectiveNodes(
|
||||
// this.table,
|
||||
// this.dbs,
|
||||
// this.config,
|
||||
// this.setConfig,
|
||||
// this.dataProvider,
|
||||
// this.databaseConfig,
|
||||
// this
|
||||
// );
|
||||
}
|
||||
|
||||
get icon() {
|
||||
return 'img collection';
|
||||
}
|
||||
|
||||
getBaseTableFromThis() {
|
||||
return this.collection;
|
||||
}
|
||||
|
||||
get headerTableAttributes() {
|
||||
return {
|
||||
schemaName: this.collection.schemaName,
|
||||
pureName: this.collection.pureName,
|
||||
conid: this.databaseConfig.conid,
|
||||
database: this.databaseConfig.database,
|
||||
};
|
||||
}
|
||||
|
||||
get tableCode() {
|
||||
return `${this.collection.schemaName}|${this.collection.pureName}`;
|
||||
}
|
||||
|
||||
get namedObject(): NamedObjectInfo {
|
||||
return {
|
||||
schemaName: this.collection.schemaName,
|
||||
pureName: this.collection.pureName,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// export class PerspectiveViewNode extends PerspectiveTreeNode {
|
||||
// constructor(
|
||||
// public view: ViewInfo,
|
||||
@@ -873,6 +962,7 @@ export class PerspectiveTableReferenceNode extends PerspectiveTableNode {
|
||||
databaseConfig: this.databaseConfig,
|
||||
orderBy: this.getOrderBy(this.table),
|
||||
condition: this.getChildrenCondition(),
|
||||
engineType: 'sqldb',
|
||||
};
|
||||
}
|
||||
|
||||
@@ -978,6 +1068,7 @@ export class PerspectiveCustomJoinTreeNode extends PerspectiveTableNode {
|
||||
databaseConfig: this.databaseConfig,
|
||||
orderBy: this.getOrderBy(this.table),
|
||||
condition: this.getChildrenCondition(),
|
||||
engineType: 'sqldb',
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -19,3 +19,4 @@ export * from './PerspectiveDataProvider';
|
||||
export * from './PerspectiveCache';
|
||||
export * from './PerspectiveConfig';
|
||||
export * from './processPerspectiveDefaultColunns';
|
||||
export * from './PerspectiveDataPattern';
|
||||
|
||||
Reference in New Issue
Block a user