@isoftdata/utility-dashboard-backend 1.1.0 → 1.2.1
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/README.md +164 -133
- package/index.js +39 -20
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,133 +1,164 @@
|
|
|
1
|
-
# utility-dashboard-backend
|
|
2
|
-
A backend utility for formatting and loading dashboard chart and report data to be usable by the [frontend dashboard component](https://github.com/ISoft-Data-Systems/ractive-component-web-dashboard).
|
|
3
|
-
|
|
4
|
-
## Prerequisites
|
|
5
|
-
|
|
6
|
-
* A MySQL database schema as outlined in [schema.md](schema.md)
|
|
7
|
-
* A backend that can fetches rows from the chart, report, and report chart tables from the database with their primary keys. Any json columns should be parsed as objects.
|
|
8
|
-
* A connection or pool of connections from the `mysql` NPM module for running the charts' queries
|
|
9
|
-
* The [dashboard Ractive component](https://github.com/ISoft-Data-Systems/ractive-component-web-dashboard) on the client
|
|
10
|
-
|
|
11
|
-
## API
|
|
12
|
-
|
|
13
|
-
### formatReportMetadata
|
|
14
|
-
|
|
15
|
-
This function returns data in the format expected for the `loadReportMetadata` function on the dashboard client component.
|
|
16
|
-
|
|
17
|
-
#### Function signature:
|
|
18
|
-
|
|
19
|
-
```js
|
|
20
|
-
async formatReportMetadata(mysqlConnection, { report, chartsInReport })
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
#### Example Usage (From Pro Web `server/chart-loader.js`):
|
|
24
|
-
|
|
25
|
-
```js
|
|
26
|
-
async function loadReportMetadata({ dashboardReportId, chartId }) {
|
|
27
|
-
const report = await db.dashboardReport.loadById({ dashboardReportId }) // gets a report by its id
|
|
28
|
-
const chartsInReport = await db.dashboardChart.loadByReport({ dashboardReportId, chartId }) // gets all charts for a specified report, or if `chartId` is specified, only gets that chart for that report.
|
|
29
|
-
return await formatReportMetadata(db.pool, { report, chartsInReport })
|
|
30
|
-
}
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
#### mysqlConnection
|
|
34
|
-
A connection or pool of connections from the `mysql` npm module.
|
|
35
|
-
|
|
36
|
-
#### report
|
|
37
|
-
|
|
38
|
-
A report `object`, a single row from the `dashboard_report`/`wa_dashboard_report` table/view. The `parameters` Array from the `json` column should also be parsed from JSON and appended to this object.
|
|
39
|
-
|
|
40
|
-
Example:
|
|
41
|
-
|
|
42
|
-
```js
|
|
43
|
-
{
|
|
44
|
-
dashboardReportId: 1,
|
|
45
|
-
reportName: 'report_overview',
|
|
46
|
-
reportTitle: 'Overview',
|
|
47
|
-
shareType: 'everyone',
|
|
48
|
-
shareId: null,
|
|
49
|
-
ownerId: null,
|
|
50
|
-
parameters: [ // parameters deconstructed from `json` column after parsing
|
|
51
|
-
{
|
|
52
|
-
name: 'date_range',
|
|
53
|
-
type: 'dateRange',
|
|
54
|
-
title: 'Date Range',
|
|
55
|
-
default: 'This Year'
|
|
56
|
-
}
|
|
57
|
-
]
|
|
58
|
-
}
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
#### chartsInReport
|
|
62
|
-
|
|
63
|
-
An `Array` of chart `object`s, one for each chart in the report, multiple rows from the `dashboard_chart`/`wa_dashboard_chart` table/view joined with `dashboard_report_chart`/`wa_dashboard_report_chart` to get the chart's rank.
|
|
64
|
-
|
|
65
|
-
Example:
|
|
66
|
-
|
|
67
|
-
```js
|
|
68
|
-
[
|
|
69
|
-
{
|
|
70
|
-
chartId: 10,
|
|
71
|
-
name: 'line_sales_over_time_and_previous_period',
|
|
72
|
-
title: 'Sales over Time',
|
|
73
|
-
supertype: 'google',
|
|
74
|
-
formatting: { Sales: [Object] },
|
|
75
|
-
multiSeries: {
|
|
76
|
-
value: 'Sales',
|
|
77
|
-
series: 'Period',
|
|
78
|
-
tooltip: 'Tooltip',
|
|
79
|
-
groupXAxisBy: 'Date'
|
|
80
|
-
},
|
|
81
|
-
chartWrapper: { options: [Object], chartType: 'LineChart' },
|
|
82
|
-
rank: 1
|
|
83
|
-
},
|
|
84
|
-
{
|
|
85
|
-
chartId: 16,
|
|
86
|
-
name: 'map_sales_by_lat_long',
|
|
87
|
-
title: 'Sales Map',
|
|
88
|
-
supertype: 'google',
|
|
89
|
-
formatting: { Sales: [Object] },
|
|
90
|
-
chartWrapper: { options: [Object], chartType: 'GeoChart' },
|
|
91
|
-
rank: 2
|
|
92
|
-
}
|
|
93
|
-
]
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
### formatChartDataForReport
|
|
97
|
-
|
|
98
|
-
This function returns data in the format expected for the `loadChartDataForReport` function on the dashboard client component, including applying any report-specific chart options overrides and running the chart's query.
|
|
99
|
-
|
|
100
|
-
#### Function signature
|
|
101
|
-
|
|
102
|
-
```js
|
|
103
|
-
async formatChartDataForReport(mysqlConnection, { reportParameters, chart, reportChart, parameterSelectionList })
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
#### Example usage: (from Pro Web `server/chart-loader.js`)
|
|
107
|
-
|
|
108
|
-
```js
|
|
109
|
-
async function loadChartDataForReport ({ dashboardReportId, chartId, parameterSelectionList }) {
|
|
110
|
-
const report = await db.dashboardReport.loadById({ dashboardReportId }) // get the report object
|
|
111
|
-
const chart = await db.dashboardChart.loadById({ chartId }) // get the chart object
|
|
112
|
-
const reportChart = await db.dashboardReportChart.loadByReportAndChartId({ chartId, dashboardReportId }) // get the report chart for the rank/overrides
|
|
113
|
-
try {
|
|
114
|
-
const chartData = await formatChartDataForReport(db.pool, { reportParameters: report.parameters, chart, reportChart, parameterSelectionList })
|
|
115
|
-
return chartData
|
|
116
|
-
} catch (err) {
|
|
117
|
-
console.error(err)
|
|
118
|
-
return { isErrored: true }
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
#### mysqlConnection
|
|
124
|
-
A connection or pool of connections from the `mysql` npm module.
|
|
125
|
-
|
|
126
|
-
#### reportParameters
|
|
127
|
-
The `parameters` array from a report object.
|
|
128
|
-
|
|
129
|
-
#### chartId
|
|
130
|
-
The id of a chart row in `wa_dashboard_chart`.
|
|
131
|
-
|
|
132
|
-
#### parameterSelectionList
|
|
133
|
-
The array of selected parameters sent from the client dashboard.
|
|
1
|
+
# utility-dashboard-backend
|
|
2
|
+
A backend utility for formatting and loading dashboard chart and report data to be usable by the [frontend dashboard component](https://github.com/ISoft-Data-Systems/ractive-component-web-dashboard).
|
|
3
|
+
|
|
4
|
+
## Prerequisites
|
|
5
|
+
|
|
6
|
+
* A MySQL database schema as outlined in [schema.md](schema.md)
|
|
7
|
+
* A backend that can fetches rows from the chart, report, and report chart tables from the database with their primary keys. Any json columns should be parsed as objects.
|
|
8
|
+
* A connection or pool of connections from the `mysql` NPM module for running the charts' queries
|
|
9
|
+
* The [dashboard Ractive component](https://github.com/ISoft-Data-Systems/ractive-component-web-dashboard) on the client
|
|
10
|
+
|
|
11
|
+
## API
|
|
12
|
+
|
|
13
|
+
### formatReportMetadata
|
|
14
|
+
|
|
15
|
+
This function returns data in the format expected for the `loadReportMetadata` function on the dashboard client component.
|
|
16
|
+
|
|
17
|
+
#### Function signature:
|
|
18
|
+
|
|
19
|
+
```js
|
|
20
|
+
async formatReportMetadata(mysqlConnection, { report, chartsInReport })
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
#### Example Usage (From Pro Web `server/chart-loader.js`):
|
|
24
|
+
|
|
25
|
+
```js
|
|
26
|
+
async function loadReportMetadata({ dashboardReportId, chartId }) {
|
|
27
|
+
const report = await db.dashboardReport.loadById({ dashboardReportId }) // gets a report by its id
|
|
28
|
+
const chartsInReport = await db.dashboardChart.loadByReport({ dashboardReportId, chartId }) // gets all charts for a specified report, or if `chartId` is specified, only gets that chart for that report.
|
|
29
|
+
return await formatReportMetadata(db.pool, { report, chartsInReport })
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
#### mysqlConnection
|
|
34
|
+
A connection or pool of connections from the `mysql` npm module.
|
|
35
|
+
|
|
36
|
+
#### report
|
|
37
|
+
|
|
38
|
+
A report `object`, a single row from the `dashboard_report`/`wa_dashboard_report` table/view. The `parameters` Array from the `json` column should also be parsed from JSON and appended to this object.
|
|
39
|
+
|
|
40
|
+
Example:
|
|
41
|
+
|
|
42
|
+
```js
|
|
43
|
+
{
|
|
44
|
+
dashboardReportId: 1,
|
|
45
|
+
reportName: 'report_overview',
|
|
46
|
+
reportTitle: 'Overview',
|
|
47
|
+
shareType: 'everyone',
|
|
48
|
+
shareId: null,
|
|
49
|
+
ownerId: null,
|
|
50
|
+
parameters: [ // parameters deconstructed from `json` column after parsing
|
|
51
|
+
{
|
|
52
|
+
name: 'date_range',
|
|
53
|
+
type: 'dateRange',
|
|
54
|
+
title: 'Date Range',
|
|
55
|
+
default: 'This Year'
|
|
56
|
+
}
|
|
57
|
+
]
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
#### chartsInReport
|
|
62
|
+
|
|
63
|
+
An `Array` of chart `object`s, one for each chart in the report, multiple rows from the `dashboard_chart`/`wa_dashboard_chart` table/view joined with `dashboard_report_chart`/`wa_dashboard_report_chart` to get the chart's rank.
|
|
64
|
+
|
|
65
|
+
Example:
|
|
66
|
+
|
|
67
|
+
```js
|
|
68
|
+
[
|
|
69
|
+
{
|
|
70
|
+
chartId: 10,
|
|
71
|
+
name: 'line_sales_over_time_and_previous_period',
|
|
72
|
+
title: 'Sales over Time',
|
|
73
|
+
supertype: 'google',
|
|
74
|
+
formatting: { Sales: [Object] },
|
|
75
|
+
multiSeries: {
|
|
76
|
+
value: 'Sales',
|
|
77
|
+
series: 'Period',
|
|
78
|
+
tooltip: 'Tooltip',
|
|
79
|
+
groupXAxisBy: 'Date'
|
|
80
|
+
},
|
|
81
|
+
chartWrapper: { options: [Object], chartType: 'LineChart' },
|
|
82
|
+
rank: 1
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
chartId: 16,
|
|
86
|
+
name: 'map_sales_by_lat_long',
|
|
87
|
+
title: 'Sales Map',
|
|
88
|
+
supertype: 'google',
|
|
89
|
+
formatting: { Sales: [Object] },
|
|
90
|
+
chartWrapper: { options: [Object], chartType: 'GeoChart' },
|
|
91
|
+
rank: 2
|
|
92
|
+
}
|
|
93
|
+
]
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### formatChartDataForReport
|
|
97
|
+
|
|
98
|
+
This function returns data in the format expected for the `loadChartDataForReport` function on the dashboard client component, including applying any report-specific chart options overrides and running the chart's query.
|
|
99
|
+
|
|
100
|
+
#### Function signature
|
|
101
|
+
|
|
102
|
+
```js
|
|
103
|
+
async formatChartDataForReport(mysqlConnection, { reportParameters, chart, reportChart, parameterSelectionList })
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
#### Example usage: (from Pro Web `server/chart-loader.js`)
|
|
107
|
+
|
|
108
|
+
```js
|
|
109
|
+
async function loadChartDataForReport ({ dashboardReportId, chartId, parameterSelectionList }) {
|
|
110
|
+
const report = await db.dashboardReport.loadById({ dashboardReportId }) // get the report object
|
|
111
|
+
const chart = await db.dashboardChart.loadById({ chartId }) // get the chart object
|
|
112
|
+
const reportChart = await db.dashboardReportChart.loadByReportAndChartId({ chartId, dashboardReportId }) // get the report chart for the rank/overrides
|
|
113
|
+
try {
|
|
114
|
+
const chartData = await formatChartDataForReport(db.pool, { reportParameters: report.parameters, chart, reportChart, parameterSelectionList })
|
|
115
|
+
return chartData
|
|
116
|
+
} catch (err) {
|
|
117
|
+
console.error(err)
|
|
118
|
+
return { isErrored: true }
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
#### mysqlConnection
|
|
124
|
+
A connection or pool of connections from the `mysql` npm module.
|
|
125
|
+
|
|
126
|
+
#### reportParameters
|
|
127
|
+
The `parameters` array from a report object.
|
|
128
|
+
|
|
129
|
+
#### chartId
|
|
130
|
+
The id of a chart row in `wa_dashboard_chart`.
|
|
131
|
+
|
|
132
|
+
#### parameterSelectionList
|
|
133
|
+
The array of selected parameters sent from the client dashboard.
|
|
134
|
+
|
|
135
|
+
### loadOutputParameterValues
|
|
136
|
+
|
|
137
|
+
This function outputs the report's parameter values in the format expected by the dashboard client and backend. When sending to the client, including `forClient: true` will not include the properties only needed by the backend.
|
|
138
|
+
|
|
139
|
+
### Function signature
|
|
140
|
+
|
|
141
|
+
```js
|
|
142
|
+
async function loadOutputParameterValues(mysqlConnection, { definitionList, selectionList = [], forClient = false })
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
#### Example Usage
|
|
146
|
+
|
|
147
|
+
#### mysqlConnection
|
|
148
|
+
A connection or pool of connections from the `mysql` npm module.
|
|
149
|
+
|
|
150
|
+
#### definitionList
|
|
151
|
+
|
|
152
|
+
The `parameters` property from the `json` column of a row in the `dashboard_report` table.
|
|
153
|
+
|
|
154
|
+
#### selectionList
|
|
155
|
+
|
|
156
|
+
An array of objects representing the selected parameters sent from the client. Only needed when loading the chart data, not when loading the report "metadata". Each parameter object should match the format specified in [schema.md](schema.md).
|
|
157
|
+
|
|
158
|
+
#### forClient
|
|
159
|
+
|
|
160
|
+
If this value is truthy, parameters' `queryValues` properties will be excluded, as the client does not need them.
|
|
161
|
+
|
|
162
|
+
### Returns
|
|
163
|
+
|
|
164
|
+
An array of objects matching the format outlined in [schema.md](schema.md)
|
package/index.js
CHANGED
|
@@ -32,33 +32,15 @@ const handleChartTypeSpecificQuirks = (chartType, resultSet) => {
|
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
const loadChartData = async(mysqlConnection, { name, query: queryObject, formatting, chartWrapper, multiSeries, parameters, table, ...theRest }) => { // needs database connection
|
|
35
|
-
|
|
36
|
-
let data = handleChartTypeSpecificQuirks(chartWrapper.chartType, queryResultSet)
|
|
37
|
-
|
|
38
|
-
if (multiSeries) {
|
|
39
|
-
({ data, formatting, fields } = getMultiSeriesData({
|
|
40
|
-
data,
|
|
41
|
-
seriesOptions: multiSeries,
|
|
42
|
-
formatting,
|
|
43
|
-
fields,
|
|
44
|
-
}))
|
|
45
|
-
}
|
|
35
|
+
const dataTable = await loadDataTable(mysqlConnection, { query: queryObject, multiSeries, formatting, chartType: chartWrapper.chartType })
|
|
46
36
|
|
|
47
37
|
const proccessedFormatting = handleFormattingTemplates(formatting)
|
|
48
38
|
|
|
49
|
-
let dataTable = getDataTableFormat(data, fields, multiSeries) //per the Google Charts docs, the DataTable object literal format is the most performant, so we'll turn it into that format before returning
|
|
50
|
-
|
|
51
|
-
// Stacked area charts will have holes / jagged lines if there are nulls in the middle of a column
|
|
52
|
-
// Presumably we'll also want to be able to have non-cumulative area charts at some point
|
|
53
|
-
if (chartWrapper.chartType == 'AreaChart') {
|
|
54
|
-
dataTable = makeDataCumulative(dataTable)
|
|
55
|
-
}
|
|
56
|
-
|
|
57
39
|
if (chartWrapper.chartType === 'Table') {
|
|
58
40
|
return {
|
|
59
41
|
...theRest,
|
|
60
42
|
chartWrapper,
|
|
61
|
-
table: { ...table, ...
|
|
43
|
+
table: { ...table, ...dataTable },
|
|
62
44
|
formatting: proccessedFormatting,
|
|
63
45
|
}
|
|
64
46
|
}
|
|
@@ -71,6 +53,38 @@ const loadChartData = async(mysqlConnection, { name, query: queryObject, formatt
|
|
|
71
53
|
formatting: proccessedFormatting,
|
|
72
54
|
}
|
|
73
55
|
}
|
|
56
|
+
/*
|
|
57
|
+
* Returns only the data needed to render out the chart. If chartType is 'Table', it will return it in the format consumed by the ractive table component.
|
|
58
|
+
* Otherwise, it will return data in the google chart Datatable object literal format.
|
|
59
|
+
* multiSeries, formatting properties should be deconstructed from the chart object, chartType should be deconstructed from the chart's chartWrapper property
|
|
60
|
+
*/
|
|
61
|
+
const loadDataTable = async(mysqlConnection, { query: queryObject, multiSeries, formatting, chartType }) => {
|
|
62
|
+
let { results: queryResultSet, fields } = (queryObject && queryObject.sql) ? await queryWithFields(mysqlConnection, queryObject) : { fields: [], results: [] }
|
|
63
|
+
let data = handleChartTypeSpecificQuirks(chartType, queryResultSet)
|
|
64
|
+
|
|
65
|
+
if (chartType === 'Table') {
|
|
66
|
+
return getRactiveTableDataFormat(data, fields, formatting)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (multiSeries) {
|
|
70
|
+
({ data, formatting, fields } = getMultiSeriesData({
|
|
71
|
+
data,
|
|
72
|
+
seriesOptions: multiSeries,
|
|
73
|
+
formatting,
|
|
74
|
+
fields,
|
|
75
|
+
}))
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
let dataTable = getDataTableFormat(data, fields, multiSeries) //per the Google Charts docs, the DataTable object literal format is the most performant, so we'll turn it into that format before returning
|
|
79
|
+
|
|
80
|
+
// Stacked area charts will have holes / jagged lines if there are nulls in the middle of a column
|
|
81
|
+
// Presumably we'll also want to be able to have non-cumulative area charts at some point
|
|
82
|
+
if (chartType === 'AreaChart') {
|
|
83
|
+
dataTable = makeDataCumulative(dataTable)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return dataTable
|
|
87
|
+
}
|
|
74
88
|
|
|
75
89
|
const loadOptionList = async(mysqlConnection, optionListQuery, optionList = []) => {
|
|
76
90
|
return [
|
|
@@ -173,6 +187,10 @@ module.exports = {
|
|
|
173
187
|
formatChartDataForReport: async(mysqlConnection, { reportParameters, chart, reportChart, parameterSelectionList }) => {
|
|
174
188
|
try {
|
|
175
189
|
const parameterValues = await loadOutputParameterValues(mysqlConnection, { definitionList: reportParameters, selectionList: parameterSelectionList })
|
|
190
|
+
if (reportChart?.jsonOverride?.chartWrapper?.dataTable) {
|
|
191
|
+
const { dataTable, ...chartWrapper } = reportChart.jsonOverride.chartWrapper
|
|
192
|
+
reportChart.jsonOverride.chartWrapper = chartWrapper
|
|
193
|
+
}
|
|
176
194
|
return await loadChartData(mysqlConnection, {
|
|
177
195
|
...chart,
|
|
178
196
|
reportChartId: reportChart.reportChartId,
|
|
@@ -185,4 +203,5 @@ module.exports = {
|
|
|
185
203
|
}
|
|
186
204
|
},
|
|
187
205
|
loadOutputParameterValues,
|
|
206
|
+
loadDataTable,
|
|
188
207
|
}
|
package/package.json
CHANGED