dbgate-datalib 6.4.3-alpha.1 → 6.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/FreeTableGridDisplay.d.ts +2 -0
- package/lib/GridDisplay.d.ts +3 -1
- package/lib/GridDisplay.js +4 -2
- package/lib/TableGridDisplay.d.ts +4 -1
- package/lib/TableGridDisplay.js +4 -3
- package/lib/ViewGridDisplay.d.ts +2 -0
- package/lib/chartDefinitions.d.ts +80 -0
- package/lib/chartDefinitions.js +18 -0
- package/lib/chartProcessor.d.ts +23 -0
- package/lib/chartProcessor.js +296 -0
- package/lib/chartScoring.d.ts +3 -0
- package/lib/chartScoring.js +28 -0
- package/lib/chartTools.d.ts +19 -0
- package/lib/chartTools.js +471 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.js +2 -0
- package/lib/tests/chartProcessor.test.d.ts +1 -0
- package/lib/tests/chartProcessor.test.js +357 -0
- package/package.json +7 -5
|
@@ -32,6 +32,7 @@ export declare class FreeTableGridDisplay extends GridDisplay {
|
|
|
32
32
|
options?: [];
|
|
33
33
|
canSelectMultipleOptions?: boolean;
|
|
34
34
|
undropColumnName?: string;
|
|
35
|
+
hasAutoValue?: boolean;
|
|
35
36
|
contentHash?: string;
|
|
36
37
|
engine?: string;
|
|
37
38
|
}[];
|
|
@@ -61,6 +62,7 @@ export declare class FreeTableGridDisplay extends GridDisplay {
|
|
|
61
62
|
options?: [];
|
|
62
63
|
canSelectMultipleOptions?: boolean;
|
|
63
64
|
undropColumnName?: string;
|
|
65
|
+
hasAutoValue?: boolean;
|
|
64
66
|
contentHash?: string;
|
|
65
67
|
engine?: string;
|
|
66
68
|
};
|
package/lib/GridDisplay.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ export interface DisplayColumn {
|
|
|
12
12
|
notNull?: boolean;
|
|
13
13
|
autoIncrement?: boolean;
|
|
14
14
|
isPrimaryKey?: boolean;
|
|
15
|
+
hasAutoValue?: boolean;
|
|
15
16
|
isPartitionKey?: boolean;
|
|
16
17
|
isClusterKey?: boolean;
|
|
17
18
|
isUniqueKey?: boolean;
|
|
@@ -40,7 +41,8 @@ export declare abstract class GridDisplay {
|
|
|
40
41
|
driver?: EngineDriver;
|
|
41
42
|
dbinfo: DatabaseInfo;
|
|
42
43
|
serverVersion: any;
|
|
43
|
-
|
|
44
|
+
currentSettings: any;
|
|
45
|
+
constructor(config: GridConfig, setConfig: ChangeConfigFunc, cache: GridCache, setCache: ChangeCacheFunc, driver?: EngineDriver, dbinfo?: DatabaseInfo, serverVersion?: any, currentSettings?: any);
|
|
44
46
|
dialect: SqlDialect;
|
|
45
47
|
columns: DisplayColumn[];
|
|
46
48
|
formColumns: DisplayColumn[];
|
package/lib/GridDisplay.js
CHANGED
|
@@ -11,7 +11,7 @@ const dbgate_tools_1 = require("dbgate-tools");
|
|
|
11
11
|
const dbgate_sqltree_1 = require("dbgate-sqltree");
|
|
12
12
|
const dbgate_tools_2 = require("dbgate-tools");
|
|
13
13
|
class GridDisplay {
|
|
14
|
-
constructor(config, setConfig, cache, setCache, driver, dbinfo = null, serverVersion = null) {
|
|
14
|
+
constructor(config, setConfig, cache, setCache, driver, dbinfo = null, serverVersion = null, currentSettings = null) {
|
|
15
15
|
this.config = config;
|
|
16
16
|
this.setConfig = setConfig;
|
|
17
17
|
this.cache = cache;
|
|
@@ -19,6 +19,7 @@ class GridDisplay {
|
|
|
19
19
|
this.driver = driver;
|
|
20
20
|
this.dbinfo = dbinfo;
|
|
21
21
|
this.serverVersion = serverVersion;
|
|
22
|
+
this.currentSettings = currentSettings;
|
|
22
23
|
this.formColumns = [];
|
|
23
24
|
this.changeSetKeyFields = null;
|
|
24
25
|
this.editableStructure = null;
|
|
@@ -114,9 +115,10 @@ class GridDisplay {
|
|
|
114
115
|
this.setConfig(cfg => (Object.assign(Object.assign({}, cfg), { searchInColumns })));
|
|
115
116
|
}
|
|
116
117
|
get hiddenColumnIndexes() {
|
|
118
|
+
var _a;
|
|
117
119
|
// console.log('GridDisplay.hiddenColumn', this.config.hiddenColumns);
|
|
118
120
|
const res = (this.config.hiddenColumns || []).map(x => lodash_1.default.findIndex(this.allColumns, y => y.uniqueName == x));
|
|
119
|
-
if (this.config.searchInColumns) {
|
|
121
|
+
if (this.config.searchInColumns && !((_a = this.currentSettings) === null || _a === void 0 ? void 0 : _a['dataGrid.showAllColumnsWhenSearch'])) {
|
|
120
122
|
for (let i = 0; i < this.allColumns.length; i++) {
|
|
121
123
|
if (!(0, dbgate_tools_1.filterName)(this.config.searchInColumns, this.allColumns[i].columnName)) {
|
|
122
124
|
res.push(i);
|
|
@@ -13,10 +13,11 @@ export declare class TableGridDisplay extends GridDisplay {
|
|
|
13
13
|
displayOptions: any;
|
|
14
14
|
getDictionaryDescription: DictionaryDescriptionFunc;
|
|
15
15
|
isRawMode: boolean;
|
|
16
|
+
currentSettings: any;
|
|
16
17
|
table: TableInfo;
|
|
17
18
|
addAllExpandedColumnsToSelected: boolean;
|
|
18
19
|
hintBaseColumns: DisplayColumn[];
|
|
19
|
-
constructor(tableName: NamedObjectInfo, driver: EngineDriver, config: GridConfig, setConfig: ChangeConfigFunc, cache: GridCache, setCache: ChangeCacheFunc, dbinfo: DatabaseInfo, displayOptions: any, serverVersion: any, getDictionaryDescription?: DictionaryDescriptionFunc, isReadOnly?: boolean, isRawMode?: boolean);
|
|
20
|
+
constructor(tableName: NamedObjectInfo, driver: EngineDriver, config: GridConfig, setConfig: ChangeConfigFunc, cache: GridCache, setCache: ChangeCacheFunc, dbinfo: DatabaseInfo, displayOptions: any, serverVersion: any, getDictionaryDescription?: DictionaryDescriptionFunc, isReadOnly?: boolean, isRawMode?: boolean, currentSettings?: any);
|
|
20
21
|
addFormDisplayColumns(columns: any): void;
|
|
21
22
|
findTable({ schemaName, pureName }: {
|
|
22
23
|
schemaName?: any;
|
|
@@ -33,6 +34,7 @@ export declare class TableGridDisplay extends GridDisplay {
|
|
|
33
34
|
uniqueName: string;
|
|
34
35
|
uniquePath: string[];
|
|
35
36
|
isPrimaryKey: boolean;
|
|
37
|
+
hasAutoValue: boolean;
|
|
36
38
|
foreignKey: ForeignKeyInfo;
|
|
37
39
|
isForeignKeyUnique: boolean;
|
|
38
40
|
pairingId?: string;
|
|
@@ -75,6 +77,7 @@ export declare class TableGridDisplay extends GridDisplay {
|
|
|
75
77
|
uniqueName: string;
|
|
76
78
|
uniquePath: string[];
|
|
77
79
|
isPrimaryKey: boolean;
|
|
80
|
+
hasAutoValue: boolean;
|
|
78
81
|
foreignKey: ForeignKeyInfo;
|
|
79
82
|
isForeignKeyUnique: boolean;
|
|
80
83
|
pairingId?: string;
|
package/lib/TableGridDisplay.js
CHANGED
|
@@ -4,12 +4,13 @@ exports.TableGridDisplay = void 0;
|
|
|
4
4
|
const dbgate_tools_1 = require("dbgate-tools");
|
|
5
5
|
const GridDisplay_1 = require("./GridDisplay");
|
|
6
6
|
class TableGridDisplay extends GridDisplay_1.GridDisplay {
|
|
7
|
-
constructor(tableName, driver, config, setConfig, cache, setCache, dbinfo, displayOptions, serverVersion, getDictionaryDescription = null, isReadOnly = false, isRawMode = false) {
|
|
8
|
-
super(config, setConfig, cache, setCache, driver, dbinfo, serverVersion);
|
|
7
|
+
constructor(tableName, driver, config, setConfig, cache, setCache, dbinfo, displayOptions, serverVersion, getDictionaryDescription = null, isReadOnly = false, isRawMode = false, currentSettings = null) {
|
|
8
|
+
super(config, setConfig, cache, setCache, driver, dbinfo, serverVersion, currentSettings);
|
|
9
9
|
this.tableName = tableName;
|
|
10
10
|
this.displayOptions = displayOptions;
|
|
11
11
|
this.getDictionaryDescription = getDictionaryDescription;
|
|
12
12
|
this.isRawMode = isRawMode;
|
|
13
|
+
this.currentSettings = currentSettings;
|
|
13
14
|
this.addAllExpandedColumnsToSelected = false;
|
|
14
15
|
this.table = this.findTable(tableName);
|
|
15
16
|
if (!this.table) {
|
|
@@ -197,7 +198,7 @@ class TableGridDisplay extends GridDisplay_1.GridDisplay {
|
|
|
197
198
|
const uniqueName = uniquePath.join('.');
|
|
198
199
|
// console.log('this.config.addedColumns', this.config.addedColumns, uniquePath);
|
|
199
200
|
const res = Object.assign(Object.assign({}, col), { pureName: table.pureName, schemaName: table.schemaName, headerText: uniquePath.length == 1 ? col.columnName : `${table.pureName}.${col.columnName}`, uniqueName,
|
|
200
|
-
uniquePath, isPrimaryKey: table.primaryKey && !!table.primaryKey.columns.find(x => x.columnName == col.columnName), foreignKey: table.foreignKeys &&
|
|
201
|
+
uniquePath, isPrimaryKey: table.primaryKey && !!table.primaryKey.columns.find(x => x.columnName == col.columnName), hasAutoValue: col.hasAutoValue, foreignKey: table.foreignKeys &&
|
|
201
202
|
table.foreignKeys.find(fk => fk.columns.length == 1 && fk.columns[0].columnName == col.columnName), isForeignKeyUnique: false });
|
|
202
203
|
if (res.foreignKey) {
|
|
203
204
|
const refTableInfo = this.dbinfo.tables.find(x => x.schemaName == res.foreignKey.refSchemaName && x.pureName == res.foreignKey.refTableName);
|
package/lib/ViewGridDisplay.d.ts
CHANGED
|
@@ -31,6 +31,7 @@ export declare class ViewGridDisplay extends GridDisplay {
|
|
|
31
31
|
options?: [];
|
|
32
32
|
canSelectMultipleOptions?: boolean;
|
|
33
33
|
undropColumnName?: string;
|
|
34
|
+
hasAutoValue?: boolean;
|
|
34
35
|
contentHash?: string;
|
|
35
36
|
engine?: string;
|
|
36
37
|
}[];
|
|
@@ -60,6 +61,7 @@ export declare class ViewGridDisplay extends GridDisplay {
|
|
|
60
61
|
options?: [];
|
|
61
62
|
canSelectMultipleOptions?: boolean;
|
|
62
63
|
undropColumnName?: string;
|
|
64
|
+
hasAutoValue?: boolean;
|
|
63
65
|
contentHash?: string;
|
|
64
66
|
engine?: string;
|
|
65
67
|
};
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
export type ChartTypeEnum = 'bar' | 'line' | 'pie' | 'polarArea';
|
|
2
|
+
export type ChartXTransformFunction = 'identity' | 'date:minute' | 'date:hour' | 'date:day' | 'date:month' | 'date:year';
|
|
3
|
+
export type ChartYAggregateFunction = 'sum' | 'first' | 'last' | 'min' | 'max' | 'count' | 'avg';
|
|
4
|
+
export type ChartDataLabelFormatter = 'number' | 'size:bytes' | 'size:kb' | 'size:mb' | 'size:gb';
|
|
5
|
+
export declare const ChartConstDefaults: {
|
|
6
|
+
sortOrder: string;
|
|
7
|
+
windowAlign: string;
|
|
8
|
+
windowSize: number;
|
|
9
|
+
parentAggregateLimit: number;
|
|
10
|
+
};
|
|
11
|
+
export declare const ChartLimits: {
|
|
12
|
+
AUTODETECT_CHART_LIMIT: number;
|
|
13
|
+
AUTODETECT_MEASURES_LIMIT: number;
|
|
14
|
+
APPLY_LIMIT_AFTER_ROWS: number;
|
|
15
|
+
MAX_DISTINCT_VALUES: number;
|
|
16
|
+
VALID_VALUE_RATIO_LIMIT: number;
|
|
17
|
+
PIE_RATIO_LIMIT: number;
|
|
18
|
+
PIE_COUNT_LIMIT: number;
|
|
19
|
+
};
|
|
20
|
+
export interface ChartXFieldDefinition {
|
|
21
|
+
field: string;
|
|
22
|
+
title?: string;
|
|
23
|
+
transformFunction: ChartXTransformFunction;
|
|
24
|
+
sortOrder?: 'natural' | 'ascKeys' | 'descKeys' | 'ascValues' | 'descValues';
|
|
25
|
+
windowAlign?: 'start' | 'end';
|
|
26
|
+
windowSize?: number;
|
|
27
|
+
parentAggregateLimit?: number;
|
|
28
|
+
}
|
|
29
|
+
export interface ChartYFieldDefinition {
|
|
30
|
+
field: string;
|
|
31
|
+
title?: string;
|
|
32
|
+
aggregateFunction: ChartYAggregateFunction;
|
|
33
|
+
}
|
|
34
|
+
export interface ChartDefinition {
|
|
35
|
+
chartType: ChartTypeEnum;
|
|
36
|
+
title?: string;
|
|
37
|
+
pieRatioLimit?: number;
|
|
38
|
+
pieCountLimit?: number;
|
|
39
|
+
xdef: ChartXFieldDefinition;
|
|
40
|
+
ydefs: ChartYFieldDefinition[];
|
|
41
|
+
useDataLabels?: boolean;
|
|
42
|
+
dataLabelFormatter?: ChartDataLabelFormatter;
|
|
43
|
+
}
|
|
44
|
+
export interface ChartDateParsed {
|
|
45
|
+
year: number;
|
|
46
|
+
month?: number;
|
|
47
|
+
day?: number;
|
|
48
|
+
hour?: number;
|
|
49
|
+
minute?: number;
|
|
50
|
+
second?: number;
|
|
51
|
+
fraction?: string;
|
|
52
|
+
}
|
|
53
|
+
export interface ChartAvailableColumn {
|
|
54
|
+
field: string;
|
|
55
|
+
}
|
|
56
|
+
export interface ProcessedChart {
|
|
57
|
+
minX?: string;
|
|
58
|
+
maxX?: string;
|
|
59
|
+
rowsAdded: number;
|
|
60
|
+
buckets: {
|
|
61
|
+
[key: string]: any;
|
|
62
|
+
};
|
|
63
|
+
bucketKeysOrdered: string[];
|
|
64
|
+
bucketKeyDateParsed: {
|
|
65
|
+
[key: string]: ChartDateParsed;
|
|
66
|
+
};
|
|
67
|
+
isGivenDefinition: boolean;
|
|
68
|
+
invalidXRows: number;
|
|
69
|
+
invalidYRows: {
|
|
70
|
+
[key: string]: number;
|
|
71
|
+
};
|
|
72
|
+
validYRows: {
|
|
73
|
+
[key: string]: number;
|
|
74
|
+
};
|
|
75
|
+
topDistinctValues: {
|
|
76
|
+
[key: string]: Set<any>;
|
|
77
|
+
};
|
|
78
|
+
availableColumns: ChartAvailableColumn[];
|
|
79
|
+
definition: ChartDefinition;
|
|
80
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ChartLimits = exports.ChartConstDefaults = void 0;
|
|
4
|
+
exports.ChartConstDefaults = {
|
|
5
|
+
sortOrder: ' asc',
|
|
6
|
+
windowAlign: 'end',
|
|
7
|
+
windowSize: 100,
|
|
8
|
+
parentAggregateLimit: 200,
|
|
9
|
+
};
|
|
10
|
+
exports.ChartLimits = {
|
|
11
|
+
AUTODETECT_CHART_LIMIT: 10,
|
|
12
|
+
AUTODETECT_MEASURES_LIMIT: 10,
|
|
13
|
+
APPLY_LIMIT_AFTER_ROWS: 100,
|
|
14
|
+
MAX_DISTINCT_VALUES: 10,
|
|
15
|
+
VALID_VALUE_RATIO_LIMIT: 0.5,
|
|
16
|
+
PIE_RATIO_LIMIT: 0.05,
|
|
17
|
+
PIE_COUNT_LIMIT: 10, // limit for number of pie chart slices, if the number of slices is above this, it will be grouped into "Other"
|
|
18
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { ChartAvailableColumn, ChartDateParsed, ChartDefinition, ProcessedChart } from './chartDefinitions';
|
|
2
|
+
export declare class ChartProcessor {
|
|
3
|
+
givenDefinitions: ChartDefinition[];
|
|
4
|
+
chartsProcessing: ProcessedChart[];
|
|
5
|
+
charts: ProcessedChart[];
|
|
6
|
+
availableColumnsDict: {
|
|
7
|
+
[field: string]: ChartAvailableColumn;
|
|
8
|
+
};
|
|
9
|
+
availableColumns: ChartAvailableColumn[];
|
|
10
|
+
autoDetectCharts: boolean;
|
|
11
|
+
rowsAdded: number;
|
|
12
|
+
constructor(givenDefinitions?: ChartDefinition[]);
|
|
13
|
+
addRow(row: any): void;
|
|
14
|
+
applyLimitsOnCharts(): void;
|
|
15
|
+
addRows(...rows: any[]): void;
|
|
16
|
+
finalize(): void;
|
|
17
|
+
groupPieOtherBuckets(chart: ProcessedChart): void;
|
|
18
|
+
applyRawData(chart: ProcessedChart, row: any, dateParsed: ChartDateParsed, numericColumns: {
|
|
19
|
+
[key: string]: number;
|
|
20
|
+
}, stringColumns: {
|
|
21
|
+
[key: string]: string;
|
|
22
|
+
}): void;
|
|
23
|
+
}
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.ChartProcessor = void 0;
|
|
7
|
+
const chartDefinitions_1 = require("./chartDefinitions");
|
|
8
|
+
const sortBy_1 = __importDefault(require("lodash/sortBy"));
|
|
9
|
+
const sum_1 = __importDefault(require("lodash/sum"));
|
|
10
|
+
const chartTools_1 = require("./chartTools");
|
|
11
|
+
const chartScoring_1 = require("./chartScoring");
|
|
12
|
+
class ChartProcessor {
|
|
13
|
+
constructor(givenDefinitions = []) {
|
|
14
|
+
this.givenDefinitions = givenDefinitions;
|
|
15
|
+
this.chartsProcessing = [];
|
|
16
|
+
this.charts = [];
|
|
17
|
+
this.availableColumnsDict = {};
|
|
18
|
+
this.availableColumns = [];
|
|
19
|
+
this.autoDetectCharts = false;
|
|
20
|
+
this.rowsAdded = 0;
|
|
21
|
+
for (const definition of givenDefinitions) {
|
|
22
|
+
this.chartsProcessing.push({
|
|
23
|
+
definition,
|
|
24
|
+
rowsAdded: 0,
|
|
25
|
+
bucketKeysOrdered: [],
|
|
26
|
+
buckets: {},
|
|
27
|
+
bucketKeyDateParsed: {},
|
|
28
|
+
isGivenDefinition: true,
|
|
29
|
+
invalidXRows: 0,
|
|
30
|
+
invalidYRows: {},
|
|
31
|
+
availableColumns: [],
|
|
32
|
+
validYRows: {},
|
|
33
|
+
topDistinctValues: {},
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
this.autoDetectCharts = this.givenDefinitions.length == 0;
|
|
37
|
+
}
|
|
38
|
+
// findOrCreateChart(definition: ChartDefinition, isGivenDefinition: boolean): ProcessedChart {
|
|
39
|
+
// const signatureItems = [
|
|
40
|
+
// definition.chartType,
|
|
41
|
+
// definition.xdef.field,
|
|
42
|
+
// definition.xdef.transformFunction,
|
|
43
|
+
// definition.ydefs.map(y => y.field).join(','),
|
|
44
|
+
// ];
|
|
45
|
+
// const signature = signatureItems.join('::');
|
|
46
|
+
// if (this.chartsBySignature[signature]) {
|
|
47
|
+
// return this.chartsBySignature[signature];
|
|
48
|
+
// }
|
|
49
|
+
// const chart: ProcessedChart = {
|
|
50
|
+
// definition,
|
|
51
|
+
// rowsAdded: 0,
|
|
52
|
+
// bucketKeysOrdered: [],
|
|
53
|
+
// buckets: {},
|
|
54
|
+
// bucketKeyDateParsed: {},
|
|
55
|
+
// isGivenDefinition,
|
|
56
|
+
// };
|
|
57
|
+
// this.chartsBySignature[signature] = chart;
|
|
58
|
+
// return chart;
|
|
59
|
+
// }
|
|
60
|
+
addRow(row) {
|
|
61
|
+
const dateColumns = {};
|
|
62
|
+
const numericColumns = {};
|
|
63
|
+
const numericColumnsForAutodetect = {};
|
|
64
|
+
const stringColumns = {};
|
|
65
|
+
for (const [key, value] of Object.entries(row)) {
|
|
66
|
+
const number = typeof value == 'string' ? Number(value) : typeof value == 'number' ? value : NaN;
|
|
67
|
+
this.availableColumnsDict[key] = {
|
|
68
|
+
field: key,
|
|
69
|
+
};
|
|
70
|
+
const keyLower = key.toLowerCase();
|
|
71
|
+
const keyIsId = keyLower.endsWith('_id') || keyLower == 'id' || key.endsWith('Id');
|
|
72
|
+
const parsedDate = (0, chartTools_1.tryParseChartDate)(value);
|
|
73
|
+
if (parsedDate) {
|
|
74
|
+
dateColumns[key] = parsedDate;
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
if (!isNaN(number) && isFinite(number)) {
|
|
78
|
+
numericColumns[key] = number;
|
|
79
|
+
if (!keyIsId) {
|
|
80
|
+
numericColumnsForAutodetect[key] = number; // for auto-detecting charts
|
|
81
|
+
}
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
if (typeof value === 'string' && isNaN(number) && value.length < 100) {
|
|
85
|
+
stringColumns[key] = value;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
// const sortedNumericColumnns = Object.keys(numericColumns).sort();
|
|
89
|
+
if (this.autoDetectCharts) {
|
|
90
|
+
// create charts from data, if there are no given definitions
|
|
91
|
+
for (const datecol in dateColumns) {
|
|
92
|
+
let usedChart = this.chartsProcessing.find(chart => {
|
|
93
|
+
var _a;
|
|
94
|
+
return !chart.isGivenDefinition &&
|
|
95
|
+
chart.definition.xdef.field === datecol &&
|
|
96
|
+
((_a = chart.definition.xdef.transformFunction) === null || _a === void 0 ? void 0 : _a.startsWith('date:'));
|
|
97
|
+
});
|
|
98
|
+
if (!usedChart &&
|
|
99
|
+
(this.rowsAdded < chartDefinitions_1.ChartLimits.APPLY_LIMIT_AFTER_ROWS ||
|
|
100
|
+
this.chartsProcessing.length < chartDefinitions_1.ChartLimits.AUTODETECT_CHART_LIMIT)) {
|
|
101
|
+
usedChart = {
|
|
102
|
+
definition: {
|
|
103
|
+
chartType: 'line',
|
|
104
|
+
xdef: {
|
|
105
|
+
field: datecol,
|
|
106
|
+
transformFunction: 'date:day',
|
|
107
|
+
},
|
|
108
|
+
ydefs: [],
|
|
109
|
+
},
|
|
110
|
+
rowsAdded: 0,
|
|
111
|
+
bucketKeysOrdered: [],
|
|
112
|
+
buckets: {},
|
|
113
|
+
bucketKeyDateParsed: {},
|
|
114
|
+
isGivenDefinition: false,
|
|
115
|
+
invalidXRows: 0,
|
|
116
|
+
invalidYRows: {},
|
|
117
|
+
availableColumns: [],
|
|
118
|
+
validYRows: {},
|
|
119
|
+
topDistinctValues: {},
|
|
120
|
+
};
|
|
121
|
+
this.chartsProcessing.push(usedChart);
|
|
122
|
+
}
|
|
123
|
+
for (const [key, value] of Object.entries(row)) {
|
|
124
|
+
if (value == null)
|
|
125
|
+
continue;
|
|
126
|
+
if (key == datecol)
|
|
127
|
+
continue; // skip date column itself
|
|
128
|
+
let existingYDef = usedChart.definition.ydefs.find(y => y.field === key);
|
|
129
|
+
if (!existingYDef &&
|
|
130
|
+
(this.rowsAdded < chartDefinitions_1.ChartLimits.APPLY_LIMIT_AFTER_ROWS ||
|
|
131
|
+
usedChart.definition.ydefs.length < chartDefinitions_1.ChartLimits.AUTODETECT_MEASURES_LIMIT)) {
|
|
132
|
+
existingYDef = {
|
|
133
|
+
field: key,
|
|
134
|
+
aggregateFunction: 'sum',
|
|
135
|
+
};
|
|
136
|
+
usedChart.definition.ydefs.push(existingYDef);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
// apply on all charts with this date column
|
|
142
|
+
for (const chart of this.chartsProcessing) {
|
|
143
|
+
this.applyRawData(chart, row, dateColumns[chart.definition.xdef.field], chart.isGivenDefinition ? numericColumns : numericColumnsForAutodetect, stringColumns);
|
|
144
|
+
}
|
|
145
|
+
for (let i = 0; i < this.chartsProcessing.length; i++) {
|
|
146
|
+
this.chartsProcessing[i] = (0, chartTools_1.autoAggregateCompactTimelineChart)(this.chartsProcessing[i]);
|
|
147
|
+
}
|
|
148
|
+
this.rowsAdded += 1;
|
|
149
|
+
if (this.rowsAdded == chartDefinitions_1.ChartLimits.APPLY_LIMIT_AFTER_ROWS) {
|
|
150
|
+
this.applyLimitsOnCharts();
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
applyLimitsOnCharts() {
|
|
154
|
+
const autodetectProcessingCharts = this.chartsProcessing.filter(chart => !chart.isGivenDefinition);
|
|
155
|
+
if (autodetectProcessingCharts.length > chartDefinitions_1.ChartLimits.AUTODETECT_CHART_LIMIT) {
|
|
156
|
+
const newAutodetectProcessingCharts = (0, sortBy_1.default)(this.chartsProcessing.slice(0, chartDefinitions_1.ChartLimits.AUTODETECT_CHART_LIMIT), chart => -(0, chartScoring_1.getChartScore)(chart));
|
|
157
|
+
for (const chart of autodetectProcessingCharts) {
|
|
158
|
+
chart.definition.ydefs = (0, sortBy_1.default)(chart.definition.ydefs, yfield => -(0, chartScoring_1.getChartYFieldScore)(chart, yfield)).slice(0, chartDefinitions_1.ChartLimits.AUTODETECT_MEASURES_LIMIT);
|
|
159
|
+
}
|
|
160
|
+
this.chartsProcessing = [
|
|
161
|
+
...this.chartsProcessing.filter(chart => chart.isGivenDefinition),
|
|
162
|
+
...newAutodetectProcessingCharts,
|
|
163
|
+
];
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
addRows(...rows) {
|
|
167
|
+
for (const row of rows) {
|
|
168
|
+
this.addRow(row);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
finalize() {
|
|
172
|
+
var _a;
|
|
173
|
+
this.applyLimitsOnCharts();
|
|
174
|
+
this.availableColumns = Object.values(this.availableColumnsDict);
|
|
175
|
+
for (const chart of this.chartsProcessing) {
|
|
176
|
+
let addedChart = chart;
|
|
177
|
+
if (chart.rowsAdded == 0) {
|
|
178
|
+
continue; // skip empty charts
|
|
179
|
+
}
|
|
180
|
+
const sortOrder = (_a = chart.definition.xdef.sortOrder) !== null && _a !== void 0 ? _a : 'ascKeys';
|
|
181
|
+
if (sortOrder != 'natural') {
|
|
182
|
+
if (sortOrder == 'ascKeys' || sortOrder == 'descKeys') {
|
|
183
|
+
if (chart.definition.xdef.transformFunction.startsWith('date:')) {
|
|
184
|
+
addedChart = (0, chartTools_1.autoAggregateCompactTimelineChart)(addedChart);
|
|
185
|
+
(0, chartTools_1.fillChartTimelineBuckets)(addedChart);
|
|
186
|
+
}
|
|
187
|
+
addedChart.bucketKeysOrdered = (0, sortBy_1.default)(Object.keys(addedChart.buckets));
|
|
188
|
+
if (sortOrder == 'descKeys') {
|
|
189
|
+
addedChart.bucketKeysOrdered.reverse();
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
if (sortOrder == 'ascValues' || sortOrder == 'descValues') {
|
|
193
|
+
addedChart.bucketKeysOrdered = (0, sortBy_1.default)(Object.keys(addedChart.buckets), key => (0, chartTools_1.computeChartBucketCardinality)(addedChart.buckets[key]));
|
|
194
|
+
if (sortOrder == 'descValues') {
|
|
195
|
+
addedChart.bucketKeysOrdered.reverse();
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
if (!addedChart.isGivenDefinition) {
|
|
200
|
+
addedChart = Object.assign(Object.assign({}, addedChart), { definition: Object.assign(Object.assign({}, addedChart.definition), { ydefs: addedChart.definition.ydefs.filter(y => !addedChart.invalidYRows[y.field] &&
|
|
201
|
+
addedChart.validYRows[y.field] / addedChart.rowsAdded >= chartDefinitions_1.ChartLimits.VALID_VALUE_RATIO_LIMIT) }) });
|
|
202
|
+
}
|
|
203
|
+
if (addedChart) {
|
|
204
|
+
addedChart.availableColumns = this.availableColumns;
|
|
205
|
+
this.charts.push(addedChart);
|
|
206
|
+
}
|
|
207
|
+
this.groupPieOtherBuckets(addedChart);
|
|
208
|
+
}
|
|
209
|
+
this.charts = [
|
|
210
|
+
...this.charts.filter(x => x.isGivenDefinition),
|
|
211
|
+
...(0, sortBy_1.default)(this.charts.filter(x => !x.isGivenDefinition), chart => -(0, chartScoring_1.getChartScore)(chart)),
|
|
212
|
+
];
|
|
213
|
+
}
|
|
214
|
+
groupPieOtherBuckets(chart) {
|
|
215
|
+
var _a, _b, _c;
|
|
216
|
+
if (chart.definition.chartType !== 'pie') {
|
|
217
|
+
return; // only for pie charts
|
|
218
|
+
}
|
|
219
|
+
const ratioLimit = (_a = chart.definition.pieRatioLimit) !== null && _a !== void 0 ? _a : chartDefinitions_1.ChartLimits.PIE_RATIO_LIMIT;
|
|
220
|
+
const countLimit = (_b = chart.definition.pieCountLimit) !== null && _b !== void 0 ? _b : chartDefinitions_1.ChartLimits.PIE_COUNT_LIMIT;
|
|
221
|
+
if (ratioLimit == 0 && countLimit == 0) {
|
|
222
|
+
return; // no grouping if limit is 0
|
|
223
|
+
}
|
|
224
|
+
const otherBucket = {};
|
|
225
|
+
let newBuckets = {};
|
|
226
|
+
const cardSum = (0, sum_1.default)(Object.values(chart.buckets).map(bucket => (0, chartTools_1.computeChartBucketCardinality)(bucket)));
|
|
227
|
+
if (cardSum == 0) {
|
|
228
|
+
return; // no buckets to process
|
|
229
|
+
}
|
|
230
|
+
for (const [bucketKey, bucket] of Object.entries(chart.buckets)) {
|
|
231
|
+
if ((0, chartTools_1.computeChartBucketCardinality)(bucket) / cardSum < ratioLimit) {
|
|
232
|
+
for (const field in bucket) {
|
|
233
|
+
otherBucket[field] = ((_c = otherBucket[field]) !== null && _c !== void 0 ? _c : 0) + bucket[field];
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
237
|
+
newBuckets[bucketKey] = bucket;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
if (Object.keys(newBuckets).length > countLimit) {
|
|
241
|
+
const sortedBucketKeys = (0, sortBy_1.default)(Object.entries(newBuckets), ([, bucket]) => -(0, chartTools_1.computeChartBucketCardinality)(bucket)).map(([key]) => key);
|
|
242
|
+
const newBuckets2 = {};
|
|
243
|
+
sortedBucketKeys.forEach((key, index) => {
|
|
244
|
+
var _a;
|
|
245
|
+
if (index < countLimit) {
|
|
246
|
+
newBuckets2[key] = newBuckets[key];
|
|
247
|
+
}
|
|
248
|
+
else {
|
|
249
|
+
for (const field in newBuckets[key]) {
|
|
250
|
+
otherBucket[field] = ((_a = otherBucket[field]) !== null && _a !== void 0 ? _a : 0) + newBuckets[key][field];
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
newBuckets = newBuckets2;
|
|
255
|
+
}
|
|
256
|
+
if (Object.keys(otherBucket).length > 0) {
|
|
257
|
+
newBuckets['Other'] = otherBucket;
|
|
258
|
+
}
|
|
259
|
+
chart.buckets = newBuckets;
|
|
260
|
+
chart.bucketKeysOrdered = [...chart.bucketKeysOrdered, 'Other'].filter(key => key in newBuckets);
|
|
261
|
+
}
|
|
262
|
+
applyRawData(chart, row, dateParsed, numericColumns, stringColumns) {
|
|
263
|
+
if (chart.definition.xdef == null) {
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
if (row[chart.definition.xdef.field] == null) {
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
if (dateParsed == null && chart.definition.xdef.transformFunction.startsWith('date:')) {
|
|
270
|
+
chart.invalidXRows += 1;
|
|
271
|
+
return; // skip if date is invalid
|
|
272
|
+
}
|
|
273
|
+
const [bucketKey, bucketKeyParsed] = (0, chartTools_1.computeChartBucketKey)(dateParsed, chart, row);
|
|
274
|
+
if (!bucketKey) {
|
|
275
|
+
return; // skip if no bucket key
|
|
276
|
+
}
|
|
277
|
+
if (bucketKeyParsed) {
|
|
278
|
+
chart.bucketKeyDateParsed[bucketKey] = bucketKeyParsed;
|
|
279
|
+
}
|
|
280
|
+
if (chart.minX == null || bucketKey < chart.minX) {
|
|
281
|
+
chart.minX = bucketKey;
|
|
282
|
+
}
|
|
283
|
+
if (chart.maxX == null || bucketKey > chart.maxX) {
|
|
284
|
+
chart.maxX = bucketKey;
|
|
285
|
+
}
|
|
286
|
+
if (!chart.buckets[bucketKey]) {
|
|
287
|
+
chart.buckets[bucketKey] = {};
|
|
288
|
+
if (chart.definition.xdef.sortOrder == 'natural') {
|
|
289
|
+
chart.bucketKeysOrdered.push(bucketKey);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
(0, chartTools_1.aggregateChartNumericValuesFromSource)(chart, bucketKey, numericColumns, row);
|
|
293
|
+
chart.rowsAdded += 1;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
exports.ChartProcessor = ChartProcessor;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getChartYFieldScore = exports.getChartScore = void 0;
|
|
7
|
+
const sortBy_1 = __importDefault(require("lodash/sortBy"));
|
|
8
|
+
const sum_1 = __importDefault(require("lodash/sum"));
|
|
9
|
+
const chartDefinitions_1 = require("./chartDefinitions");
|
|
10
|
+
function getChartScore(chart) {
|
|
11
|
+
let res = 0;
|
|
12
|
+
res += chart.rowsAdded * 5;
|
|
13
|
+
const ydefScores = chart.definition.ydefs.map(yField => getChartYFieldScore(chart, yField));
|
|
14
|
+
const sorted = (0, sortBy_1.default)(ydefScores).reverse();
|
|
15
|
+
res += (0, sum_1.default)(sorted.slice(0, chartDefinitions_1.ChartLimits.AUTODETECT_MEASURES_LIMIT));
|
|
16
|
+
return res;
|
|
17
|
+
}
|
|
18
|
+
exports.getChartScore = getChartScore;
|
|
19
|
+
function getChartYFieldScore(chart, yField) {
|
|
20
|
+
var _a, _b, _c;
|
|
21
|
+
let res = 0;
|
|
22
|
+
res += chart.validYRows[yField.field] * 5; // score for valid Y rows
|
|
23
|
+
res += ((_b = (_a = chart.topDistinctValues[yField.field]) === null || _a === void 0 ? void 0 : _a.size) !== null && _b !== void 0 ? _b : 0) * 20; // score for distinct values in Y field
|
|
24
|
+
res += chart.rowsAdded * 2; // base score for rows added
|
|
25
|
+
res -= ((_c = chart.invalidYRows[yField.field]) !== null && _c !== void 0 ? _c : 0) * 50; // penalty for invalid Y rows
|
|
26
|
+
return res;
|
|
27
|
+
}
|
|
28
|
+
exports.getChartYFieldScore = getChartYFieldScore;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { ChartDateParsed, ChartXTransformFunction, ProcessedChart } from './chartDefinitions';
|
|
2
|
+
export declare function getChartDebugPrint(chart: ProcessedChart): string;
|
|
3
|
+
export declare function tryParseChartDate(dateInput: any): ChartDateParsed | null;
|
|
4
|
+
export declare function stringifyChartDate(value: ChartDateParsed, transform: ChartXTransformFunction): string;
|
|
5
|
+
export declare function incrementChartDate(value: ChartDateParsed, transform: ChartXTransformFunction): ChartDateParsed;
|
|
6
|
+
export declare function computeChartBucketKey(dateParsed: ChartDateParsed, chart: ProcessedChart, row: any): [string, ChartDateParsed];
|
|
7
|
+
export declare function computeDateBucketDistance(begin: ChartDateParsed, end: ChartDateParsed, transform: ChartXTransformFunction): number;
|
|
8
|
+
export declare function compareChartDatesParsed(a: ChartDateParsed, b: ChartDateParsed, transform: ChartXTransformFunction): number;
|
|
9
|
+
export declare function autoAggregateCompactTimelineChart(chart: ProcessedChart): ProcessedChart;
|
|
10
|
+
export declare function aggregateChartNumericValuesFromSource(chart: ProcessedChart, bucketKey: string, numericColumns: {
|
|
11
|
+
[key: string]: number;
|
|
12
|
+
}, row: any): void;
|
|
13
|
+
export declare function aggregateChartNumericValuesFromChild(chart: ProcessedChart, bucketKey: string, childBucketValues: {
|
|
14
|
+
[key: string]: any;
|
|
15
|
+
}): void;
|
|
16
|
+
export declare function fillChartTimelineBuckets(chart: ProcessedChart): void;
|
|
17
|
+
export declare function computeChartBucketCardinality(bucket: {
|
|
18
|
+
[key: string]: any;
|
|
19
|
+
}): number;
|