@isoftdata/utility-dashboard-backend 2.4.0 → 2.4.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/dist/index.js CHANGED
@@ -1,346 +1,346 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
25
- var __importDefault = (this && this.__importDefault) || function (mod) {
26
- return (mod && mod.__esModule) ? mod : { "default": mod };
27
- };
28
- Object.defineProperty(exports, "__esModule", { value: true });
29
- exports.formatChartDataForReport = exports.formatReportMetadata = exports.parameterizeUrl = exports.parameterizeQuery = exports.parameterRegex = exports.loadOutputParameterValues = exports.loadDataTable = exports.loadDataTableAndProcessedFormatting = exports.handleFormattingTemplates = exports.formatterTemplates = void 0;
30
- const db = require('@isoftdata/utility-db');
31
- const chart_helper_js_1 = require("./chart-helper.js");
32
- const utility_date_time_1 = require("@isoftdata/utility-date-time");
33
- const formatDate = require('date-fns/format');
34
- const camelcase_1 = __importDefault(require("camelcase"));
35
- const mysql = require('mysql');
36
- const deepmerge = require('deepmerge');
37
- exports.formatterTemplates = __importStar(require("./formatting-templates"));
38
- var chart_helper_js_2 = require("./chart-helper.js");
39
- Object.defineProperty(exports, "handleFormattingTemplates", { enumerable: true, get: function () { return chart_helper_js_2.handleFormattingTemplates; } });
40
- const handleChartTypeSpecificQuirks = (chartType, resultSet) => {
41
- if (resultSet.length) {
42
- switch (chartType) {
43
- case 'PieChart':
44
- resultSet = (0, chart_helper_js_1.makeNegativeNumericValuesZero)(resultSet);
45
- break;
46
- case 'TreeMap':
47
- resultSet = (0, chart_helper_js_1.coerceNullColumn)(Object.keys(resultSet[0])[1], resultSet);
48
- if (resultSet.length === 1) {
49
- resultSet[0].id = 'No Data';
50
- }
51
- break;
52
- default:
53
- resultSet = (0, chart_helper_js_1.coerceNullColumn)(Object.keys(resultSet[0])[0], resultSet);
54
- }
55
- }
56
- return resultSet;
57
- };
58
- async function loadChartData(mysqlConnection, chart, queryObject, customDataSource) {
59
- let { formatting, chartWrapper, multiSeries, table, supertype, cumulative, ...theRest } = chart;
60
- if (!chartWrapper) {
61
- chartWrapper = {
62
- chartType: supertype,
63
- options: {
64
- height: 450, width: 800,
65
- },
66
- };
67
- }
68
- cumulative = cumulative || (chartWrapper?.chartType === 'AreaChart' && cumulative !== false);
69
- let dataTable = {}, processedFormatting = {};
70
- try {
71
- const dataTableAndProcessedFormatting = await loadDataTableAndProcessedFormatting(mysqlConnection, { query: queryObject, multiSeries, formatting, chartType: chartWrapper?.chartType, cumulative, table, customDataSource });
72
- dataTable = dataTableAndProcessedFormatting.dataTable;
73
- processedFormatting = dataTableAndProcessedFormatting.processedFormatting;
74
- }
75
- catch (err) {
76
- console.error('Error loading dataTable / processedFormatting');
77
- throw err;
78
- }
79
- if (chartWrapper?.chartType === 'Table') {
80
- return {
81
- ...theRest,
82
- supertype,
83
- chartWrapper,
84
- table: { ...table, ...dataTable },
85
- formatting: processedFormatting,
86
- };
87
- }
88
- return {
89
- ...theRest,
90
- cumulative,
91
- supertype,
92
- chartWrapper: {
93
- ...chartWrapper,
94
- dataTable: dataTable,
95
- },
96
- formatting: processedFormatting,
97
- };
98
- }
99
- async function loadDataTableAndProcessedFormatting(mysqlConnection, { query: queryObject, multiSeries, formatting, chartType, cumulative = false, table = {}, customDataSource }) {
100
- let results = [];
101
- let fields = {};
102
- if (typeof customDataSource === 'function') {
103
- ({ results, fields } = await customDataSource(queryObject.sql, queryObject.values));
104
- }
105
- else if (queryObject?.sql) {
106
- ({ results, fields } = await (0, chart_helper_js_1.queryWithFields)(mysqlConnection, queryObject));
107
- }
108
- let data = handleChartTypeSpecificQuirks(chartType, results);
109
- if (multiSeries) {
110
- ({ data, formatting, fields } = (0, chart_helper_js_1.getMultiSeriesData)({
111
- data,
112
- seriesOptions: multiSeries,
113
- formatting,
114
- fields,
115
- }));
116
- }
117
- const processedFormatting = (0, chart_helper_js_1.handleFormattingTemplates)(formatting);
118
- if (chartType?.toLowerCase() === 'table') {
119
- return { dataTable: (0, chart_helper_js_1.getRactiveTableDataFormat)(data, fields, processedFormatting, table?.style), processedFormatting, fields };
120
- }
121
- let dataTable = (0, chart_helper_js_1.getDataTableFormat)(data, fields, multiSeries);
122
- if (cumulative || chartType === 'AreaChart') {
123
- dataTable = (0, chart_helper_js_1.makeDataCumulative)(dataTable, cumulative);
124
- }
125
- return { dataTable, processedFormatting, fields };
126
- }
127
- exports.loadDataTableAndProcessedFormatting = loadDataTableAndProcessedFormatting;
128
- async function loadDataTable(mysqlConnection, { query: queryObject, multiSeries, formatting, chartType }) {
129
- const { dataTable } = await loadDataTableAndProcessedFormatting(mysqlConnection, { query: queryObject, multiSeries, formatting, chartType });
130
- return dataTable;
131
- }
132
- exports.loadDataTable = loadDataTable;
133
- const loadOptionList = async (mysqlConnection, optionListQuery, optionList = []) => {
134
- const optionsFromQuery = (optionListQuery && await db.query(mysqlConnection, optionListQuery)) || [];
135
- return [
136
- ...optionList,
137
- ...optionsFromQuery.map((option) => ({ ...option, fromQuery: true })),
138
- ];
139
- };
140
- async function loadOutputParameterValues(mysqlConnection, { definitionList = [], selectionList = [], forClient = false, session, site = 'store', siteIdColumn, siteNameColumn }) {
141
- if (!(definitionList instanceof Array) || !definitionList.length) {
142
- return [];
143
- }
144
- const parameterValues = [];
145
- for (const definition of definitionList) {
146
- const matchingParameterSelection = selectionList.find(param => param.name === definition.name);
147
- let typedParameter;
148
- const baseParameter = {
149
- name: definition.name,
150
- title: definition.title || definition.name,
151
- default: definition.default,
152
- value: (matchingParameterSelection?.value) ?? definition.default,
153
- queryValues: {},
154
- };
155
- if (definition.type === 'dateRange') {
156
- baseParameter.value = baseParameter.value || 'Last 30 Days';
157
- typedParameter = {
158
- ...baseParameter,
159
- type: 'dateRange',
160
- dates: matchingParameterSelection?.dates ?? (0, utility_date_time_1.datesFromRange)(baseParameter.value),
161
- };
162
- if (typedParameter.value !== 'Custom') {
163
- typedParameter.dates = (0, utility_date_time_1.datesFromRange)(typedParameter.value);
164
- }
165
- if (!forClient) {
166
- typedParameter.queryValues = {
167
- [`${typedParameter.name}_start_date`]: typedParameter.dates.from,
168
- [`${typedParameter.name}_end_date`]: typedParameter.dates.to,
169
- };
170
- }
171
- }
172
- else if (definition.type === 'selection') {
173
- typedParameter = {
174
- ...baseParameter,
175
- type: 'selection',
176
- optionListQuery: definition?.optionListQuery,
177
- optionList: definition?.optionList,
178
- };
179
- typedParameter.optionList = await loadOptionList(mysqlConnection, typedParameter.optionListQuery, typedParameter.optionList);
180
- if (!typedParameter.optionList.some(option => option.id?.toString() === typedParameter.value?.toString())) {
181
- typedParameter.value = typedParameter.optionList?.[0]?.id?.toString();
182
- }
183
- const option = typedParameter.optionList.find(option => option.id.toString() === typedParameter.value);
184
- if (!forClient) {
185
- typedParameter.queryValues = {
186
- [typedParameter.name]: option?.rawSql ? mysql.raw(typedParameter.value) : typedParameter.value,
187
- };
188
- }
189
- }
190
- else if (definition.type === 'siteSelection') {
191
- typedParameter = {
192
- ...baseParameter,
193
- type: 'siteSelection',
194
- permission: definition?.permission,
195
- optionList: [],
196
- };
197
- typedParameter.value = typedParameter.value ?? (session.siteId ?? session[`${site}Id`]);
198
- siteIdColumn = siteIdColumn ? mysqlConnection.escapeId(siteIdColumn) : mysqlConnection.escapeId(`${site}id`);
199
- siteNameColumn = siteNameColumn ? mysqlConnection.escapeId(siteNameColumn) : 'name';
200
- const siteTableName = mysqlConnection.escapeId(site);
201
- if (typedParameter.permission) {
202
- typedParameter.optionList = await db.query(mysqlConnection, {
203
- sql: `SELECT ${siteIdColumn} AS id, ${siteNameColumn} AS \`name\` FROM ${siteTableName} WHERE f_check_user_permission(?, ?, ${siteIdColumn})`,
204
- values: [session.userAccountId, definition.permission],
205
- });
206
- }
207
- else {
208
- typedParameter.optionList = await db.query(mysqlConnection, {
209
- sql: `SELECT ${siteIdColumn} AS id, ${siteNameColumn} AS \`name\` FROM ${siteTableName} WHERE f_useraccount_has_site_access(?, ${siteIdColumn})`,
210
- values: [session.userAccountId],
211
- });
212
- }
213
- if (typedParameter.optionList.length > 1) {
214
- typedParameter.optionList = typedParameter.optionList.map(option => ({ ...option, fromQuery: true }));
215
- typedParameter.optionList.unshift({ id: 0, name: 'All', fromQuery: true });
216
- }
217
- if (!typedParameter.optionList.some(option => option.id?.toString() === typedParameter.value?.toString())) {
218
- typedParameter.value = typedParameter.optionList?.[0]?.id.toString();
219
- }
220
- if (!forClient && typedParameter.value?.toString() === '0') {
221
- typedParameter.queryValues = {
222
- [typedParameter.name]: typedParameter.optionList
223
- .map(({ id }) => id?.toString())
224
- .filter(id => id !== '0'),
225
- };
226
- }
227
- else if (!forClient) {
228
- typedParameter.queryValues = {
229
- [typedParameter.name]: [typedParameter.value],
230
- };
231
- }
232
- }
233
- else if (definition.type === 'date') {
234
- typedParameter = {
235
- ...baseParameter,
236
- type: 'date',
237
- };
238
- typedParameter.value = typedParameter.value || formatDate(new Date(), 'yyyy-MM-dd');
239
- if (!forClient) {
240
- typedParameter.queryValues = {
241
- [typedParameter.name]: typedParameter.value,
242
- };
243
- }
244
- }
245
- else if (definition.type === 'session') {
246
- typedParameter = {
247
- ...baseParameter,
248
- type: 'session',
249
- };
250
- const parameterName = (0, camelcase_1.default)(definition.name);
251
- typedParameter.value = (session[parameterName] ?? '').toString();
252
- if (!forClient) {
253
- typedParameter.queryValues = {
254
- [typedParameter.name]: typedParameter.value,
255
- };
256
- }
257
- }
258
- else {
259
- throw new Error(`Parameter type mismatch for ${baseParameter.name}`);
260
- }
261
- parameterValues.push(typedParameter);
262
- }
263
- return parameterValues;
264
- }
265
- exports.loadOutputParameterValues = loadOutputParameterValues;
266
- exports.parameterRegex = /\${([^}]+)}/g;
267
- function parameterizeQuery(queryString, parameterValues) {
268
- if (!queryString) {
269
- return {
270
- sql: '',
271
- values: [],
272
- };
273
- }
274
- const queryParameterValues = parameterValues.reduce((acc, val) => {
275
- return val.queryValues ? {
276
- ...acc,
277
- ...val.queryValues,
278
- } : acc;
279
- }, {});
280
- const queryParameterKeys = [...queryString.matchAll(exports.parameterRegex)].map(([, insideToken]) => insideToken.trim());
281
- const queryParameters = queryParameterKeys.map(key => queryParameterValues[key] || null);
282
- return {
283
- sql: queryString.replace(exports.parameterRegex, '?'),
284
- values: queryParameters,
285
- };
286
- }
287
- exports.parameterizeQuery = parameterizeQuery;
288
- function parameterizeUrl(url, parameterValues) {
289
- if (!url) {
290
- return '';
291
- }
292
- const queryParameterValues = parameterValues.reduce((acc, val) => {
293
- return val.queryValues ? {
294
- ...acc,
295
- ...val.queryValues,
296
- } : acc;
297
- }, {});
298
- const queryParameterKeys = [...url.matchAll(exports.parameterRegex)].map(([, insideToken]) => insideToken.trim());
299
- const formattedUrl = queryParameterKeys.reduce((acc, key) => {
300
- return acc.replace(`\${${key}}`, queryParameterValues[key] || '');
301
- }, url);
302
- return formattedUrl;
303
- }
304
- exports.parameterizeUrl = parameterizeUrl;
305
- async function formatReportMetadata(mysqlConnection, { report, chartsInReport, session = {}, site, siteIdColumn, siteNameColumn }) {
306
- try {
307
- const parameterValues = await loadOutputParameterValues(mysqlConnection, { definitionList: report.parameters, forClient: true, session, site, siteIdColumn, siteNameColumn });
308
- return {
309
- dashboardReportId: report.dashboardReportId,
310
- name: report.reportName,
311
- title: report.reportTitle,
312
- charts: chartsInReport,
313
- parameterValues,
314
- ownerId: report.ownerId,
315
- autoRefreshInterval: report.autoRefreshInterval,
316
- description: report.description ?? '',
317
- };
318
- }
319
- catch (err) {
320
- console.error(err);
321
- throw err;
322
- }
323
- }
324
- exports.formatReportMetadata = formatReportMetadata;
325
- async function formatChartDataForReport(mysqlConnection, { reportParameters, chart, reportChart, parameterSelectionList, session = {}, site, siteIdColumn, siteNameColumn, customDataSource }) {
326
- try {
327
- const parameterValues = await loadOutputParameterValues(mysqlConnection, { definitionList: reportParameters, selectionList: parameterSelectionList, session, site, siteIdColumn, siteNameColumn });
328
- if (reportChart?.jsonOverride?.chartWrapper?.dataTable) {
329
- const { dataTable, ...chartWrapper } = reportChart.jsonOverride.chartWrapper;
330
- reportChart.jsonOverride.chartWrapper = chartWrapper;
331
- }
332
- const combinedChart = deepmerge(chart, reportChart.jsonOverride ?? {});
333
- return await loadChartData(mysqlConnection, {
334
- ...combinedChart,
335
- rank: reportChart.rank,
336
- reportChartId: reportChart.reportChartId,
337
- description: combinedChart.description ?? '',
338
- }, parameterizeQuery(chart.query, parameterValues), customDataSource);
339
- }
340
- catch (err) {
341
- console.error(err);
342
- throw err;
343
- }
344
- }
345
- exports.formatChartDataForReport = formatChartDataForReport;
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __importDefault = (this && this.__importDefault) || function (mod) {
26
+ return (mod && mod.__esModule) ? mod : { "default": mod };
27
+ };
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ exports.formatChartDataForReport = exports.formatReportMetadata = exports.parameterizeUrl = exports.parameterizeQuery = exports.parameterRegex = exports.loadOutputParameterValues = exports.loadDataTable = exports.loadDataTableAndProcessedFormatting = exports.handleFormattingTemplates = exports.formatterTemplates = void 0;
30
+ const db = require('@isoftdata/utility-db');
31
+ const chart_helper_js_1 = require("./chart-helper.js");
32
+ const utility_date_time_1 = require("@isoftdata/utility-date-time");
33
+ const formatDate = require('date-fns/format');
34
+ const camelcase_1 = __importDefault(require("camelcase"));
35
+ const mysql = require('mysql');
36
+ const deepmerge = require('deepmerge');
37
+ exports.formatterTemplates = __importStar(require("./formatting-templates"));
38
+ var chart_helper_js_2 = require("./chart-helper.js");
39
+ Object.defineProperty(exports, "handleFormattingTemplates", { enumerable: true, get: function () { return chart_helper_js_2.handleFormattingTemplates; } });
40
+ const handleChartTypeSpecificQuirks = (chartType, resultSet) => {
41
+ if (resultSet.length) {
42
+ switch (chartType) {
43
+ case 'PieChart':
44
+ resultSet = (0, chart_helper_js_1.makeNegativeNumericValuesZero)(resultSet);
45
+ break;
46
+ case 'TreeMap':
47
+ resultSet = (0, chart_helper_js_1.coerceNullColumn)(Object.keys(resultSet[0])[1], resultSet);
48
+ if (resultSet.length === 1) {
49
+ resultSet[0].id = 'No Data';
50
+ }
51
+ break;
52
+ default:
53
+ resultSet = (0, chart_helper_js_1.coerceNullColumn)(Object.keys(resultSet[0])[0], resultSet);
54
+ }
55
+ }
56
+ return resultSet;
57
+ };
58
+ async function loadChartData(mysqlConnection, chart, queryObject, customDataSource) {
59
+ let { formatting, chartWrapper, multiSeries, table, supertype, cumulative, ...theRest } = chart;
60
+ if (!chartWrapper) {
61
+ chartWrapper = {
62
+ chartType: supertype,
63
+ options: {
64
+ height: 450, width: 800,
65
+ },
66
+ };
67
+ }
68
+ cumulative = cumulative || (chartWrapper?.chartType === 'AreaChart' && cumulative !== false);
69
+ let dataTable = {}, processedFormatting = {};
70
+ try {
71
+ const dataTableAndProcessedFormatting = await loadDataTableAndProcessedFormatting(mysqlConnection, { query: queryObject, multiSeries, formatting, chartType: chartWrapper?.chartType, cumulative, table, customDataSource });
72
+ dataTable = dataTableAndProcessedFormatting.dataTable;
73
+ processedFormatting = dataTableAndProcessedFormatting.processedFormatting;
74
+ }
75
+ catch (err) {
76
+ console.error('Error loading dataTable / processedFormatting');
77
+ throw err;
78
+ }
79
+ if (chartWrapper?.chartType === 'Table') {
80
+ return {
81
+ ...theRest,
82
+ supertype,
83
+ chartWrapper,
84
+ table: { ...table, ...dataTable },
85
+ formatting: processedFormatting,
86
+ };
87
+ }
88
+ return {
89
+ ...theRest,
90
+ cumulative,
91
+ supertype,
92
+ chartWrapper: {
93
+ ...chartWrapper,
94
+ dataTable: dataTable,
95
+ },
96
+ formatting: processedFormatting,
97
+ };
98
+ }
99
+ async function loadDataTableAndProcessedFormatting(mysqlConnection, { query: queryObject, multiSeries, formatting, chartType, cumulative = false, table = {}, customDataSource }) {
100
+ let results = [];
101
+ let fields = {};
102
+ if (typeof customDataSource === 'function') {
103
+ ({ results, fields } = await customDataSource(queryObject.sql, queryObject.values));
104
+ }
105
+ else if (queryObject?.sql) {
106
+ ({ results, fields } = await (0, chart_helper_js_1.queryWithFields)(mysqlConnection, queryObject));
107
+ }
108
+ let data = handleChartTypeSpecificQuirks(chartType, results);
109
+ if (multiSeries) {
110
+ ({ data, formatting, fields } = (0, chart_helper_js_1.getMultiSeriesData)({
111
+ data,
112
+ seriesOptions: multiSeries,
113
+ formatting,
114
+ fields,
115
+ }));
116
+ }
117
+ const processedFormatting = (0, chart_helper_js_1.handleFormattingTemplates)(formatting);
118
+ if (chartType?.toLowerCase() === 'table') {
119
+ return { dataTable: (0, chart_helper_js_1.getRactiveTableDataFormat)(data, fields, processedFormatting, table?.style), processedFormatting, fields };
120
+ }
121
+ let dataTable = (0, chart_helper_js_1.getDataTableFormat)(data, fields, multiSeries);
122
+ if (cumulative || chartType === 'AreaChart') {
123
+ dataTable = (0, chart_helper_js_1.makeDataCumulative)(dataTable, cumulative);
124
+ }
125
+ return { dataTable, processedFormatting, fields };
126
+ }
127
+ exports.loadDataTableAndProcessedFormatting = loadDataTableAndProcessedFormatting;
128
+ async function loadDataTable(mysqlConnection, { query: queryObject, multiSeries, formatting, chartType }) {
129
+ const { dataTable } = await loadDataTableAndProcessedFormatting(mysqlConnection, { query: queryObject, multiSeries, formatting, chartType });
130
+ return dataTable;
131
+ }
132
+ exports.loadDataTable = loadDataTable;
133
+ const loadOptionList = async (mysqlConnection, optionListQuery, optionList = []) => {
134
+ const optionsFromQuery = (optionListQuery && await db.query(mysqlConnection, optionListQuery)) || [];
135
+ return [
136
+ ...optionList,
137
+ ...optionsFromQuery.map((option) => ({ ...option, fromQuery: true })),
138
+ ];
139
+ };
140
+ async function loadOutputParameterValues(mysqlConnection, { definitionList = [], selectionList = [], forClient = false, session, site = 'store', siteIdColumn, siteNameColumn }) {
141
+ if (!(definitionList instanceof Array) || !definitionList.length) {
142
+ return [];
143
+ }
144
+ const parameterValues = [];
145
+ for (const definition of definitionList) {
146
+ const matchingParameterSelection = selectionList.find(param => param.name === definition.name);
147
+ let typedParameter;
148
+ const baseParameter = {
149
+ name: definition.name,
150
+ title: definition.title || definition.name,
151
+ default: definition.default,
152
+ value: (matchingParameterSelection?.value) ?? definition.default,
153
+ queryValues: {},
154
+ };
155
+ if (definition.type === 'dateRange') {
156
+ baseParameter.value = baseParameter.value || 'Last 30 Days';
157
+ typedParameter = {
158
+ ...baseParameter,
159
+ type: 'dateRange',
160
+ dates: matchingParameterSelection?.dates ?? (0, utility_date_time_1.datesFromRange)(baseParameter.value),
161
+ };
162
+ if (typedParameter.value !== 'Custom') {
163
+ typedParameter.dates = (0, utility_date_time_1.datesFromRange)(typedParameter.value);
164
+ }
165
+ if (!forClient) {
166
+ typedParameter.queryValues = {
167
+ [`${typedParameter.name}_start_date`]: typedParameter.dates.from,
168
+ [`${typedParameter.name}_end_date`]: typedParameter.dates.to,
169
+ };
170
+ }
171
+ }
172
+ else if (definition.type === 'selection') {
173
+ typedParameter = {
174
+ ...baseParameter,
175
+ type: 'selection',
176
+ optionListQuery: definition?.optionListQuery,
177
+ optionList: definition?.optionList,
178
+ };
179
+ typedParameter.optionList = await loadOptionList(mysqlConnection, typedParameter.optionListQuery, typedParameter.optionList);
180
+ if (!typedParameter.optionList.some(option => option.id?.toString() === typedParameter.value?.toString())) {
181
+ typedParameter.value = typedParameter.optionList?.[0]?.id?.toString();
182
+ }
183
+ const option = typedParameter.optionList.find(option => option.id.toString() === typedParameter.value);
184
+ if (!forClient) {
185
+ typedParameter.queryValues = {
186
+ [typedParameter.name]: option?.rawSql ? mysql.raw(typedParameter.value) : typedParameter.value,
187
+ };
188
+ }
189
+ }
190
+ else if (definition.type === 'siteSelection') {
191
+ typedParameter = {
192
+ ...baseParameter,
193
+ type: 'siteSelection',
194
+ permission: definition?.permission,
195
+ optionList: [],
196
+ };
197
+ typedParameter.value = typedParameter.value ?? (session.siteId ?? session[`${site}Id`]);
198
+ siteIdColumn = siteIdColumn ? mysqlConnection.escapeId(siteIdColumn) : mysqlConnection.escapeId(`${site}id`);
199
+ siteNameColumn = siteNameColumn ? mysqlConnection.escapeId(siteNameColumn) : 'name';
200
+ const siteTableName = mysqlConnection.escapeId(site);
201
+ if (typedParameter.permission) {
202
+ typedParameter.optionList = await db.query(mysqlConnection, {
203
+ sql: `SELECT ${siteIdColumn} AS id, ${siteNameColumn} AS \`name\` FROM ${siteTableName} WHERE f_check_user_permission(?, ?, ${siteIdColumn})`,
204
+ values: [session.userAccountId, definition.permission],
205
+ });
206
+ }
207
+ else {
208
+ typedParameter.optionList = await db.query(mysqlConnection, {
209
+ sql: `SELECT ${siteIdColumn} AS id, ${siteNameColumn} AS \`name\` FROM ${siteTableName} WHERE f_useraccount_has_site_access(?, ${siteIdColumn})`,
210
+ values: [session.userAccountId],
211
+ });
212
+ }
213
+ if (typedParameter.optionList.length > 1) {
214
+ typedParameter.optionList = typedParameter.optionList.map(option => ({ ...option, fromQuery: true }));
215
+ typedParameter.optionList.unshift({ id: 0, name: 'All', fromQuery: true });
216
+ }
217
+ if (!typedParameter.optionList.some(option => option.id?.toString() === typedParameter.value?.toString())) {
218
+ typedParameter.value = typedParameter.optionList?.[0]?.id.toString();
219
+ }
220
+ if (!forClient && typedParameter.value?.toString() === '0') {
221
+ typedParameter.queryValues = {
222
+ [typedParameter.name]: typedParameter.optionList
223
+ .map(({ id }) => id?.toString())
224
+ .filter(id => id !== '0'),
225
+ };
226
+ }
227
+ else if (!forClient) {
228
+ typedParameter.queryValues = {
229
+ [typedParameter.name]: [typedParameter.value],
230
+ };
231
+ }
232
+ }
233
+ else if (definition.type === 'date') {
234
+ typedParameter = {
235
+ ...baseParameter,
236
+ type: 'date',
237
+ };
238
+ typedParameter.value = typedParameter.value || formatDate(new Date(), 'yyyy-MM-dd');
239
+ if (!forClient) {
240
+ typedParameter.queryValues = {
241
+ [typedParameter.name]: typedParameter.value,
242
+ };
243
+ }
244
+ }
245
+ else if (definition.type === 'session') {
246
+ typedParameter = {
247
+ ...baseParameter,
248
+ type: 'session',
249
+ };
250
+ const parameterName = (0, camelcase_1.default)(definition.name);
251
+ typedParameter.value = (session[parameterName] ?? '').toString();
252
+ if (!forClient) {
253
+ typedParameter.queryValues = {
254
+ [typedParameter.name]: typedParameter.value,
255
+ };
256
+ }
257
+ }
258
+ else {
259
+ throw new Error(`Parameter type mismatch for ${baseParameter.name}`);
260
+ }
261
+ parameterValues.push(typedParameter);
262
+ }
263
+ return parameterValues;
264
+ }
265
+ exports.loadOutputParameterValues = loadOutputParameterValues;
266
+ exports.parameterRegex = /\${([^}]+)}/g;
267
+ function parameterizeQuery(queryString, parameterValues) {
268
+ if (!queryString) {
269
+ return {
270
+ sql: '',
271
+ values: [],
272
+ };
273
+ }
274
+ const queryParameterValues = parameterValues.reduce((acc, val) => {
275
+ return val.queryValues ? {
276
+ ...acc,
277
+ ...val.queryValues,
278
+ } : acc;
279
+ }, {});
280
+ const queryParameterKeys = [...queryString.matchAll(exports.parameterRegex)].map(([, insideToken]) => insideToken.trim());
281
+ const queryParameters = queryParameterKeys.map(key => queryParameterValues[key] || null);
282
+ return {
283
+ sql: queryString.replace(exports.parameterRegex, '?'),
284
+ values: queryParameters,
285
+ };
286
+ }
287
+ exports.parameterizeQuery = parameterizeQuery;
288
+ function parameterizeUrl(url, parameterValues) {
289
+ if (!url) {
290
+ return '';
291
+ }
292
+ const queryParameterValues = parameterValues.reduce((acc, val) => {
293
+ return val.queryValues ? {
294
+ ...acc,
295
+ ...val.queryValues,
296
+ } : acc;
297
+ }, {});
298
+ const queryParameterKeys = [...url.matchAll(exports.parameterRegex)].map(([, insideToken]) => insideToken.trim());
299
+ const formattedUrl = queryParameterKeys.reduce((acc, key) => {
300
+ return acc.replace(`\${${key}}`, queryParameterValues[key] || '');
301
+ }, url);
302
+ return formattedUrl;
303
+ }
304
+ exports.parameterizeUrl = parameterizeUrl;
305
+ async function formatReportMetadata(mysqlConnection, { report, chartsInReport, session = {}, site, siteIdColumn, siteNameColumn }) {
306
+ try {
307
+ const parameterValues = await loadOutputParameterValues(mysqlConnection, { definitionList: report.parameters, forClient: true, session, site, siteIdColumn, siteNameColumn });
308
+ return {
309
+ dashboardReportId: report.dashboardReportId,
310
+ name: report.reportName,
311
+ title: report.reportTitle,
312
+ charts: chartsInReport,
313
+ parameterValues,
314
+ ownerId: report.ownerId,
315
+ autoRefreshInterval: report.autoRefreshInterval,
316
+ description: report.description ?? '',
317
+ };
318
+ }
319
+ catch (err) {
320
+ console.error(err);
321
+ throw err;
322
+ }
323
+ }
324
+ exports.formatReportMetadata = formatReportMetadata;
325
+ async function formatChartDataForReport(mysqlConnection, { reportParameters, chart, reportChart, parameterSelectionList, session = {}, site, siteIdColumn, siteNameColumn, customDataSource }) {
326
+ try {
327
+ const parameterValues = await loadOutputParameterValues(mysqlConnection, { definitionList: reportParameters, selectionList: parameterSelectionList, session, site, siteIdColumn, siteNameColumn });
328
+ if (reportChart?.jsonOverride?.chartWrapper?.dataTable) {
329
+ const { dataTable, ...chartWrapper } = reportChart.jsonOverride.chartWrapper;
330
+ reportChart.jsonOverride.chartWrapper = chartWrapper;
331
+ }
332
+ const combinedChart = deepmerge(chart, reportChart.jsonOverride ?? {});
333
+ return await loadChartData(mysqlConnection, {
334
+ ...combinedChart,
335
+ rank: reportChart.rank,
336
+ reportChartId: reportChart.reportChartId,
337
+ description: combinedChart.description ?? '',
338
+ }, parameterizeQuery(chart.query, parameterValues), customDataSource);
339
+ }
340
+ catch (err) {
341
+ console.error(err);
342
+ throw err;
343
+ }
344
+ }
345
+ exports.formatChartDataForReport = formatChartDataForReport;
346
346
  //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSxNQUFNLEVBQUUsR0FBRyxPQUFPLENBQUMsdUJBQXVCLENBQUMsQ0FBQTtBQUMzQyx1REFTNkM7QUFDN0Msb0VBQTZEO0FBQzdELE1BQU0sVUFBVSxHQUFHLE9BQU8sQ0FBQyxpQkFBaUIsQ0FBQyxDQUFBO0FBQzdDLDBEQUFpQztBQUNqQyxNQUFNLEtBQUssR0FBRyxPQUFPLENBQUMsT0FBTyxDQUFDLENBQUE7QUFDOUIsTUFBTSxTQUFTLEdBQUcsT0FBTyxDQUFDLFdBQVcsQ0FBQyxDQUFBO0FBTXRDLDZFQUE0RDtBQUM1RCxxREFBNkQ7QUFBcEQsNEhBQUEseUJBQXlCLE9BQUE7QUFLbEMsTUFBTSw2QkFBNkIsR0FBRyxDQUFDLFNBQWlCLEVBQUUsU0FBMEIsRUFBRSxFQUFFO0lBQ3ZGLElBQUksU0FBUyxDQUFDLE1BQU0sRUFBRTtRQUNyQixRQUFRLFNBQVMsRUFBRTtZQUNsQixLQUFLLFVBQVU7Z0JBRWQsU0FBUyxHQUFHLElBQUEsK0NBQTZCLEVBQUMsU0FBUyxDQUFDLENBQUE7Z0JBQ3BELE1BQUs7WUFDTixLQUFLLFNBQVM7Z0JBRWIsU0FBUyxHQUFHLElBQUEsa0NBQWdCLEVBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxTQUFTLENBQUMsQ0FBQTtnQkFDckUsSUFBSSxTQUFTLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRTtvQkFDM0IsU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsR0FBRyxTQUFTLENBQUE7aUJBQzNCO2dCQUNELE1BQUs7WUFDTjtnQkFFQyxTQUFTLEdBQUcsSUFBQSxrQ0FBZ0IsRUFBQyxNQUFNLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFD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