@opengis/bi 1.2.32 → 1.2.34

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.
Files changed (74) hide show
  1. package/README.md +92 -92
  2. package/dist/bi.js +1 -1
  3. package/dist/bi.umd.cjs +68 -68
  4. package/dist/{import-file-D-ISqB7l.js → import-file-BwxPX622.js} +1132 -1079
  5. package/dist/style.css +1 -1
  6. package/dist/{vs-funnel-bar-aoZzvriV.js → vs-funnel-bar-BV18EA4K.js} +3 -3
  7. package/dist/{vs-list-CBkyJSBj.js → vs-list-WrrWQ5KF.js} +32 -53
  8. package/dist/{vs-map-C3C11qmT.js → vs-map-CYd9vdrd.js} +3 -3
  9. package/dist/{vs-map-cluster-BsPmHIMx.js → vs-map-cluster-5TnGPuBH.js} +3 -3
  10. package/dist/{vs-number-d58ftpH5.js → vs-number-DUeRr7uz.js} +3 -3
  11. package/dist/{vs-table-BHa5Velm.js → vs-table-CZJnXfUv.js} +6 -6
  12. package/dist/{vs-text-Bq87gMTx.js → vs-text-D3nCPkgk.js} +4 -4
  13. package/package.json +77 -77
  14. package/plugin.js +21 -21
  15. package/server/helpers/mdToHTML.js +17 -17
  16. package/server/migrations/bi.dataset.sql +46 -46
  17. package/server/migrations/bi.sql +114 -114
  18. package/server/plugins/docs.js +48 -48
  19. package/server/plugins/hook.js +89 -89
  20. package/server/routes/dashboard/controllers/dashboard.import.js +103 -103
  21. package/server/routes/dashboard/controllers/dashboard.js +158 -158
  22. package/server/routes/dashboard/controllers/dashboard.list.js +60 -60
  23. package/server/routes/dashboard/controllers/utils/yaml.js +11 -11
  24. package/server/routes/dashboard/index.mjs +26 -26
  25. package/server/routes/data/controllers/data.js +230 -230
  26. package/server/routes/data/controllers/util/chartSQL.js +49 -49
  27. package/server/routes/data/controllers/util/normalizeData.js +65 -65
  28. package/server/routes/data/index.mjs +38 -38
  29. package/server/routes/dataset/controllers/bi.dataset.list.js +29 -29
  30. package/server/routes/dataset/controllers/bi.db.list.js +19 -19
  31. package/server/routes/dataset/controllers/comment.js +55 -55
  32. package/server/routes/dataset/controllers/createDatasetPost.js +134 -134
  33. package/server/routes/dataset/controllers/data.js +149 -149
  34. package/server/routes/dataset/controllers/dbTablePreview.js +58 -58
  35. package/server/routes/dataset/controllers/dbTables.js +34 -34
  36. package/server/routes/dataset/controllers/delete.js +40 -40
  37. package/server/routes/dataset/controllers/deleteDataset.js +52 -52
  38. package/server/routes/dataset/controllers/editDataset.js +90 -90
  39. package/server/routes/dataset/controllers/export.js +214 -214
  40. package/server/routes/dataset/controllers/form.js +99 -99
  41. package/server/routes/dataset/controllers/format.js +46 -46
  42. package/server/routes/dataset/controllers/insert.js +47 -47
  43. package/server/routes/dataset/controllers/table.js +68 -68
  44. package/server/routes/dataset/controllers/update.js +43 -43
  45. package/server/routes/dataset/index.mjs +132 -132
  46. package/server/routes/dataset/utils/convertJSONToCSV.js +17 -17
  47. package/server/routes/dataset/utils/convertJSONToXls.js +47 -47
  48. package/server/routes/dataset/utils/createTableQuery.js +59 -59
  49. package/server/routes/dataset/utils/datasetForms.js +1 -1
  50. package/server/routes/dataset/utils/descriptionList.js +45 -45
  51. package/server/routes/dataset/utils/downloadRemoteFile.js +58 -58
  52. package/server/routes/dataset/utils/executeQuery.js +46 -46
  53. package/server/routes/dataset/utils/getLayersData.js +106 -106
  54. package/server/routes/dataset/utils/getTableData.js +46 -46
  55. package/server/routes/dataset/utils/insertDataQuery.js +12 -12
  56. package/server/routes/dataset/utils/metaFormat.js +24 -24
  57. package/server/routes/edit/controllers/dashboard.add.js +36 -36
  58. package/server/routes/edit/controllers/dashboard.delete.js +39 -39
  59. package/server/routes/edit/controllers/dashboard.edit.js +61 -61
  60. package/server/routes/edit/controllers/widget.add.js +78 -78
  61. package/server/routes/edit/controllers/widget.del.js +58 -58
  62. package/server/routes/edit/controllers/widget.edit.js +115 -115
  63. package/server/routes/edit/index.mjs +33 -33
  64. package/server/routes/map/controllers/cluster.js +125 -125
  65. package/server/routes/map/controllers/clusterVtile.js +166 -166
  66. package/server/routes/map/controllers/geojson.js +127 -127
  67. package/server/routes/map/controllers/heatmap.js +118 -118
  68. package/server/routes/map/controllers/map.js +69 -69
  69. package/server/routes/map/controllers/utils/downloadClusterData.js +44 -44
  70. package/server/routes/map/controllers/vtile.js +183 -183
  71. package/server/routes/map/index.mjs +32 -32
  72. package/server/templates/page/login.html +58 -58
  73. package/server/utils/getWidget.js +118 -118
  74. package/utils.js +12 -12
@@ -1,11 +1,11 @@
1
- import yaml from 'js-yaml';
2
-
3
- yaml.loadSafe = (yml) => {
4
- try {
5
- return yaml.load(yml);
6
- } catch (err) {
7
- return { error: err.toString() };
8
- }
9
- };
10
-
11
- export default yaml;
1
+ import yaml from 'js-yaml';
2
+
3
+ yaml.loadSafe = (yml) => {
4
+ try {
5
+ return yaml.load(yml);
6
+ } catch (err) {
7
+ return { error: err.toString() };
8
+ }
9
+ };
10
+
11
+ export default yaml;
@@ -1,26 +1,26 @@
1
- import dashboard from './controllers/dashboard.js';
2
- import dashboardList from './controllers/dashboard.list.js';
3
- import dashboardImport from './controllers/dashboard.import.js';
4
-
5
- const biSchema = {
6
- type: 'object',
7
- properties: {
8
- querystring: {
9
- widget: { type: 'string', pattern: '^([\\d\\w]+)$' },
10
- dashboard: { type: 'string', pattern: '^([\\d\\w]+)$' },
11
- list: { type: 'string', pattern: '^([\\d])$' },
12
- sql: { type: 'string', pattern: '^([\\d])$' },
13
- },
14
- params: {
15
- id: { type: 'string', pattern: '^([\\d\\w]+)$' },
16
- },
17
- },
18
- };
19
-
20
- const policy = ['public'];
21
-
22
- export default async function route(fastify) {
23
- fastify.get(`/bi-dashboard/:id`, { config: { policy }, schema: biSchema }, dashboard);
24
- fastify.get(`/bi-dashboard`, { config: { policy } }, dashboardList);
25
- fastify.get(`/bi-dashboard-import`, { config: { policy } }, dashboardImport);
26
- }
1
+ import dashboard from './controllers/dashboard.js';
2
+ import dashboardList from './controllers/dashboard.list.js';
3
+ import dashboardImport from './controllers/dashboard.import.js';
4
+
5
+ const biSchema = {
6
+ type: 'object',
7
+ properties: {
8
+ querystring: {
9
+ widget: { type: 'string', pattern: '^([\\d\\w]+)$' },
10
+ dashboard: { type: 'string', pattern: '^([\\d\\w]+)$' },
11
+ list: { type: 'string', pattern: '^([\\d])$' },
12
+ sql: { type: 'string', pattern: '^([\\d])$' },
13
+ },
14
+ params: {
15
+ id: { type: 'string', pattern: '^([\\d\\w]+)$' },
16
+ },
17
+ },
18
+ };
19
+
20
+ const policy = ['public'];
21
+
22
+ export default async function route(fastify) {
23
+ fastify.get(`/bi-dashboard/:id`, { config: { policy }, schema: biSchema }, dashboard);
24
+ fastify.get(`/bi-dashboard`, { config: { policy } }, dashboardList);
25
+ fastify.get(`/bi-dashboard-import`, { config: { policy } }, dashboardImport);
26
+ }
@@ -1,231 +1,231 @@
1
- import yaml from 'js-yaml';
2
-
3
- import {
4
- config,
5
- autoIndex,
6
- pgClients,
7
- getSelect,
8
- getSelectVal,
9
- getFilterSQL,
10
- getMeta,
11
- logger,
12
- } from '@opengis/fastify-table/utils.js';
13
-
14
- import chartSQL from './util/chartSQL.js';
15
- import normalizeData from './util/normalizeData.js';
16
-
17
- import { getWidget } from '../../../../utils.js';
18
-
19
- const maxLimit = 100;
20
-
21
- export default async function dataAPI(req, reply) {
22
- const time = Date.now();
23
-
24
- const { query = {}, user = {}, unittest } = req;
25
-
26
- const { dashboard, widget, filter, search, samples } = query;
27
-
28
- const widgetData = await getWidget({ pg: req.pg, dashboard, widget });
29
-
30
- query.metric = Array.isArray(query.metric) ? query.metric.pop() : query.metric || widgetData?.metric || widgetData?.data?.metrics?.[0]?.fx;
31
-
32
- if (widgetData.status) return widgetData;
33
-
34
- const { type, text, data = {}, controls, style, options } = widgetData;
35
-
36
- const pg = widgetData.pg || req.pg || pgClients.client;
37
-
38
- const error1 = {};
39
- const { fields: cols = [] } = await pg.query(
40
- `select * from ${data.table} t ${widgetData.tableSQL || data.tableSQL || ''} limit 0`
41
- ).catch(err => Object.assign(error1, { error: err.toString() })) || {};
42
- const columnTypes = cols?.map?.((el) => ({
43
- name: el.name,
44
- type: pg.pgType?.[el.dataTypeID],
45
- }));
46
-
47
- // data param
48
- const { x, cls, groupbyCls, metric, table, where, tableSQL, groupby, xName, yName, xType, yType, error = error1 } =
49
- normalizeData(widgetData, query, columnTypes);
50
-
51
- const limit = Math.min(query.limit || widgetData.limit || maxLimit, maxLimit);
52
- // if (error) { return reply.status(400).send(error); }
53
-
54
- // auto Index
55
- if (pg.pk?.[data.table]) {
56
- autoIndex({
57
- table: data.table,
58
- pg,
59
- columns: [data?.time]
60
- .concat([xName])
61
- .concat([groupby])
62
- .filter((el) => el),
63
- }).catch((err) => console.log(err));
64
- }
65
-
66
- const { pk, columns = [], view } = await getMeta({ pg, table: data.table });
67
-
68
- if (!view && !pk) {
69
- return { message: `table not found: ${data.table} (${pg.options?.database})`, status: 404 };
70
- }
71
-
72
- // const columnList = columns.map(col => col.name);
73
- const groupbyColumnNotExists = groupby?.split?.(',')?.filter?.(el => !columnTypes.map(el => el.name).includes(el.trim()));
74
-
75
- if (groupby && groupbyColumnNotExists?.length) {
76
- return { message: `groupby column not found: ${groupbyColumnNotExists} (${data.table}/${pg.options?.database})`, status: 404 };
77
- }
78
-
79
- // get group
80
- const groupData = groupby
81
- ? await pg
82
- .query(
83
- `select ${groupby} as name ,count(*) from ${tableSQL || table} group by ${groupby} order by count(*) desc limit ${limit}`
84
- )
85
- .then((el) => el.rows)
86
- : null;
87
-
88
- if (query.sql === '2') return { x, metric, table, tableSQL, data, groupData };
89
-
90
- const order = data.order || (type === 'listbar' && cols.find(el => el.name === 'metric') ? 'metric desc' : null);
91
-
92
- const fData =
93
- filter || search
94
- ? await getFilterSQL({
95
- pg,
96
- table,
97
- filter,
98
- search,
99
- filterList: widgetData.filters,
100
- })
101
- : {};
102
-
103
- const optimizedSQL = widgetData?.sql
104
- ? `${widgetData.sql} ${fData?.q && false ? fData?.q : ''} limit ${limit}`
105
- : (fData?.optimizedSQL || `select * from ${tableSQL || table}`);
106
-
107
- if (type?.includes('bar') && !metric?.length) {
108
- return { message: 'empty widget params: metrics', status: 400 };
109
- }
110
-
111
- const sql = widgetData.sql ? optimizedSQL : (chartSQL[type] || chartSQL.chart)({
112
- where: config.local && user?.user_type === 'superadmin' ? 'true' : where, // test
113
- metric,
114
- yType, // metric type
115
- columns: widgetData.columns,
116
- table: `(${optimizedSQL})q`,
117
- x,
118
- groupData,
119
- groupby,
120
- order,
121
- samples,
122
- limit,
123
- xType,
124
- fx: widgetData.fx,
125
- });
126
-
127
- if (query.sql) return sql;
128
-
129
- if (!sql || sql?.includes('undefined')) {
130
- return {
131
- message: {
132
- error: 'invalid sql',
133
- type,
134
- sql,
135
- where,
136
- metric,
137
- table: `(${optimizedSQL})q`,
138
- x,
139
- groupData,
140
- groupby,
141
- },
142
- status: 500,
143
- };
144
- }
145
-
146
- if (config.trace) console.log(sql, user?.uid);
147
-
148
- const { rows = [], fields = [], errorSql } = await pg.query(sql.replace('{{uid}}', user?.uid)).catch(err => {
149
- logger.file('bi/data', { error: err.toString(), sql });
150
- return { errorSql: err.toString() };
151
- }); // test with limit
152
-
153
- if (groupbyCls) {
154
- const { arr = [] } = await getSelect(groupbyCls, pg) || {};
155
- if (arr.length) {
156
- const ids = arr.map(el => el.id);
157
- const text = arr.reduce((acc, curr) => ({ ...acc, [curr.id]: curr.text }), {});
158
- rows.forEach(row => {
159
- ids.reduce((acc, curr) => {
160
- Object.assign(row, { [text[curr]]: row[curr] });
161
- delete row[curr];
162
- return acc;
163
- }, {});
164
- });
165
- }
166
- }
167
-
168
- if (cls) {
169
- const values = rows
170
- .map((row) => row[x])
171
- ?.filter((el, idx, arr) => el && arr.indexOf(el) === idx);
172
- const vals = await getSelectVal({ pg, name: cls, values });
173
- rows
174
- .filter((row) => row[x])
175
- .forEach((row) => {
176
- Object.assign(row, { [x]: vals?.[row[x]]?.text || vals?.[row[x]] || row[x] });
177
- });
178
- }
179
-
180
- const metaTitles = columns.reduce((acc, curr) => Object.assign(acc, { [curr.name]: curr.title || curr.ua }), {});
181
- const titles = Array.isArray(widgetData?.columns)
182
- ? widgetData.columns.reduce((acc, curr) => Object.assign(acc, { [curr.name]: curr.title || curr.ua }), {})
183
- : Object.keys(widgetData?.columns || {}).reduce((acc, curr) => Object.assign(acc, { [curr]: widgetData?.columns?.[curr] }), {});
184
-
185
- const rows1 = type === 'table' ? rows.map(row => Object.keys(row || {}).reduce((acc, curr) => Object.assign(acc, { [titles?.[curr] || metaTitles?.[curr] || curr]: row?.[curr] }), {})) : rows;
186
-
187
- const yml = widgetData.yml || yaml.dump(extractYml(widgetData));
188
- const dimensions = fields.map((el) => el.name);
189
-
190
- const res = {
191
- time: Date.now() - time,
192
- last_update: widgetData?.last_update,
193
- error: error || errorSql || (!widgetData.sql ? widgetData.error : undefined),
194
- dimensions,
195
- filter: xName,
196
- dimensionsType: [xType, yType].filter((el) => el)?.length
197
- ? [xType, yType].filter((el) => el)
198
- : fields.map((el) => pg.pgType?.[el.dataTypeID]),
199
- type,
200
-
201
- text: text || widgetData?.title || data.text,
202
- // data: query.format === 'data' ? dimensions.map(el => rows.map(r => r[el])) : undefined,
203
- source:
204
- query.format === 'array'
205
- ? dimensions.map((el) => rows1.map((r) => r[el]))
206
- : rows1,
207
- style,
208
- options,
209
- controls,
210
- yml,
211
- data: widgetData.data,
212
- id: query.widget,
213
- columns: columnTypes.map(el => Object.assign(el, { title: titles[el.name] || metaTitles?.[el.name] || el.name })),
214
- params: config?.local || unittest ? {
215
- x,
216
- cls,
217
- metric,
218
- table,
219
- tableSQL,
220
- where,
221
- groupby,
222
- sql,
223
- } : undefined,
224
- };
225
- return res;
226
- }
227
-
228
- function extractYml(sourceData) {
229
- const { title, description, type, data, style, controls } = sourceData;
230
- return { title, description, type, data, style, controls };
1
+ import yaml from 'js-yaml';
2
+
3
+ import {
4
+ config,
5
+ autoIndex,
6
+ pgClients,
7
+ getSelect,
8
+ getSelectVal,
9
+ getFilterSQL,
10
+ getMeta,
11
+ logger,
12
+ } from '@opengis/fastify-table/utils.js';
13
+
14
+ import chartSQL from './util/chartSQL.js';
15
+ import normalizeData from './util/normalizeData.js';
16
+
17
+ import { getWidget } from '../../../../utils.js';
18
+
19
+ const maxLimit = 100;
20
+
21
+ export default async function dataAPI(req, reply) {
22
+ const time = Date.now();
23
+
24
+ const { query = {}, user = {}, unittest } = req;
25
+
26
+ const { dashboard, widget, filter, search, samples } = query;
27
+
28
+ const widgetData = await getWidget({ pg: req.pg, dashboard, widget });
29
+
30
+ query.metric = Array.isArray(query.metric) ? query.metric.pop() : query.metric || widgetData?.metric || widgetData?.data?.metrics?.[0]?.fx;
31
+
32
+ if (widgetData.status) return widgetData;
33
+
34
+ const { type, text, data = {}, controls, style, options } = widgetData;
35
+
36
+ const pg = widgetData.pg || req.pg || pgClients.client;
37
+
38
+ const error1 = {};
39
+ const { fields: cols = [] } = await pg.query(
40
+ `select * from ${data.table} t ${widgetData.tableSQL || data.tableSQL || ''} limit 0`
41
+ ).catch(err => Object.assign(error1, { error: err.toString() })) || {};
42
+ const columnTypes = cols?.map?.((el) => ({
43
+ name: el.name,
44
+ type: pg.pgType?.[el.dataTypeID],
45
+ }));
46
+
47
+ // data param
48
+ const { x, cls, groupbyCls, metric, table, where, tableSQL, groupby, xName, yName, xType, yType, error = error1 } =
49
+ normalizeData(widgetData, query, columnTypes);
50
+
51
+ const limit = Math.min(query.limit || widgetData.limit || maxLimit, maxLimit);
52
+ // if (error) { return reply.status(400).send(error); }
53
+
54
+ // auto Index
55
+ if (pg.pk?.[data.table]) {
56
+ autoIndex({
57
+ table: data.table,
58
+ pg,
59
+ columns: [data?.time]
60
+ .concat([xName])
61
+ .concat([groupby])
62
+ .filter((el) => el),
63
+ }).catch((err) => console.log(err));
64
+ }
65
+
66
+ const { pk, columns = [], view } = await getMeta({ pg, table: data.table });
67
+
68
+ if (!view && !pk) {
69
+ return { message: `table not found: ${data.table} (${pg.options?.database})`, status: 404 };
70
+ }
71
+
72
+ // const columnList = columns.map(col => col.name);
73
+ const groupbyColumnNotExists = groupby?.split?.(',')?.filter?.(el => !columnTypes.map(el => el.name).includes(el.trim()));
74
+
75
+ if (groupby && groupbyColumnNotExists?.length) {
76
+ return { message: `groupby column not found: ${groupbyColumnNotExists} (${data.table}/${pg.options?.database})`, status: 404 };
77
+ }
78
+
79
+ // get group
80
+ const groupData = groupby
81
+ ? await pg
82
+ .query(
83
+ `select ${groupby} as name ,count(*) from ${tableSQL || table} group by ${groupby} order by count(*) desc limit ${limit}`
84
+ )
85
+ .then((el) => el.rows)
86
+ : null;
87
+
88
+ if (query.sql === '2') return { x, metric, table, tableSQL, data, groupData };
89
+
90
+ const order = data.order || (type === 'listbar' && cols.find(el => el.name === 'metric') ? 'metric desc' : null);
91
+
92
+ const fData =
93
+ filter || search
94
+ ? await getFilterSQL({
95
+ pg,
96
+ table,
97
+ filter,
98
+ search,
99
+ filterList: widgetData.filters,
100
+ })
101
+ : {};
102
+
103
+ const optimizedSQL = widgetData?.sql
104
+ ? `${widgetData.sql} ${fData?.q && false ? fData?.q : ''} limit ${limit}`
105
+ : (fData?.optimizedSQL || `select * from ${tableSQL || table}`);
106
+
107
+ if (type?.includes('bar') && !metric?.length) {
108
+ return { message: 'empty widget params: metrics', status: 400 };
109
+ }
110
+
111
+ const sql = widgetData.sql ? optimizedSQL : (chartSQL[type] || chartSQL.chart)({
112
+ where: config.local && user?.user_type === 'superadmin' ? 'true' : where, // test
113
+ metric,
114
+ yType, // metric type
115
+ columns: widgetData.columns,
116
+ table: `(${optimizedSQL})q`,
117
+ x,
118
+ groupData,
119
+ groupby,
120
+ order,
121
+ samples,
122
+ limit,
123
+ xType,
124
+ fx: widgetData.fx,
125
+ });
126
+
127
+ if (query.sql) return sql;
128
+
129
+ if (!sql || sql?.includes('undefined')) {
130
+ return {
131
+ message: {
132
+ error: 'invalid sql',
133
+ type,
134
+ sql,
135
+ where,
136
+ metric,
137
+ table: `(${optimizedSQL})q`,
138
+ x,
139
+ groupData,
140
+ groupby,
141
+ },
142
+ status: 500,
143
+ };
144
+ }
145
+
146
+ if (config.trace) console.log(sql, user?.uid);
147
+
148
+ const { rows = [], fields = [], errorSql } = await pg.query(sql.replace('{{uid}}', user?.uid)).catch(err => {
149
+ logger.file('bi/data', { error: err.toString(), sql });
150
+ return { errorSql: err.toString() };
151
+ }); // test with limit
152
+
153
+ if (groupbyCls) {
154
+ const { arr = [] } = await getSelect(groupbyCls, pg) || {};
155
+ if (arr.length) {
156
+ const ids = arr.map(el => el.id);
157
+ const text = arr.reduce((acc, curr) => ({ ...acc, [curr.id]: curr.text }), {});
158
+ rows.forEach(row => {
159
+ ids.reduce((acc, curr) => {
160
+ Object.assign(row, { [text[curr]]: row[curr] });
161
+ delete row[curr];
162
+ return acc;
163
+ }, {});
164
+ });
165
+ }
166
+ }
167
+
168
+ if (cls) {
169
+ const values = rows
170
+ .map((row) => row[x])
171
+ ?.filter((el, idx, arr) => el && arr.indexOf(el) === idx);
172
+ const vals = await getSelectVal({ pg, name: cls, values });
173
+ rows
174
+ .filter((row) => row[x])
175
+ .forEach((row) => {
176
+ Object.assign(row, { [x]: vals?.[row[x]]?.text || vals?.[row[x]] || row[x] });
177
+ });
178
+ }
179
+
180
+ const metaTitles = columns.reduce((acc, curr) => Object.assign(acc, { [curr.name]: curr.title || curr.ua }), {});
181
+ const titles = Array.isArray(widgetData?.columns)
182
+ ? widgetData.columns.reduce((acc, curr) => Object.assign(acc, { [curr.name]: curr.title || curr.ua }), {})
183
+ : Object.keys(widgetData?.columns || {}).reduce((acc, curr) => Object.assign(acc, { [curr]: widgetData?.columns?.[curr] }), {});
184
+
185
+ const rows1 = type === 'table' ? rows.map(row => Object.keys(row || {}).reduce((acc, curr) => Object.assign(acc, { [titles?.[curr] || metaTitles?.[curr] || curr]: row?.[curr] }), {})) : rows;
186
+
187
+ const yml = widgetData.yml || yaml.dump(extractYml(widgetData));
188
+ const dimensions = fields.map((el) => el.name);
189
+
190
+ const res = {
191
+ time: Date.now() - time,
192
+ last_update: widgetData?.last_update,
193
+ error: error || errorSql || (!widgetData.sql ? widgetData.error : undefined),
194
+ dimensions,
195
+ filter: xName,
196
+ dimensionsType: [xType, yType].filter((el) => el)?.length
197
+ ? [xType, yType].filter((el) => el)
198
+ : fields.map((el) => pg.pgType?.[el.dataTypeID]),
199
+ type,
200
+
201
+ text: text || widgetData?.title || data.text,
202
+ // data: query.format === 'data' ? dimensions.map(el => rows.map(r => r[el])) : undefined,
203
+ source:
204
+ query.format === 'array'
205
+ ? dimensions.map((el) => rows1.map((r) => r[el]))
206
+ : rows1,
207
+ style,
208
+ options,
209
+ controls,
210
+ yml,
211
+ data: widgetData.data,
212
+ id: query.widget,
213
+ columns: columnTypes.map(el => Object.assign(el, { title: titles[el.name] || metaTitles?.[el.name] || el.name })),
214
+ params: config?.local || unittest ? {
215
+ x,
216
+ cls,
217
+ metric,
218
+ table,
219
+ tableSQL,
220
+ where,
221
+ groupby,
222
+ sql,
223
+ } : undefined,
224
+ };
225
+ return res;
226
+ }
227
+
228
+ function extractYml(sourceData) {
229
+ const { title, description, type, data, style, controls } = sourceData;
230
+ return { title, description, type, data, style, controls };
231
231
  }
@@ -1,49 +1,49 @@
1
- function number({ metric, where, table, samples, fx }) {
2
- const sql = `select ${fx || metric} from ${table} where ${where} ${samples ? 'limit 10' : ''}`;
3
- return sql;
4
- }
5
- function table({ columns = [], table, where, samples }) {
6
- const cols = Array.isArray(columns)
7
- ? columns.map((el) => `"${(el.name || el).replace(/'/g, "''")}"`).join(',')
8
- : Object.keys(columns).map(key => `"${key.replace(/'/g, "''")}"`).join(',');
9
- return `select ${cols || '*'} from ${table} where ${where} ${samples ? 'limit 10' : 'limit 20'} `;
10
- }
11
-
12
- function chart({
13
- metric,
14
- yType, // metric type
15
- where,
16
- table,
17
- x,
18
- groupby,
19
- groupData,
20
- order,
21
- samples,
22
- limit = 100,
23
- xType,
24
- fx, // agg function
25
- }) {
26
- const xCol = x && xType?.includes('[]') ? `unnest(${x})` : x;
27
-
28
- const metricData =
29
- groupData
30
- ?.filter(el => el.name)
31
- ?.map(
32
- (el) =>
33
- `${metric} filter (where '${el.name.toString().replace(/'/g, "''")}'=${yType?.includes('[]') ? `any(${groupby.replace(/'/g, "''")}::text[])` : groupby.replace(/'/g, "''")}) as "${el.name.toString().replace(/'/g, "''")}"`
34
- )
35
- .join(',') || `${fx || metric} as metric`;
36
- const sql = `select ${xCol} ${x && xType?.includes('[]') ? `as ${x}` : ''}, ${metricData}
37
- from ${table}
38
- where ${where}
39
- ${xCol ? `group by ${xCol}` : ''}
40
- ${order || xCol ? `order by ${order || xCol}` : ''}
41
- ${samples ? 'limit 10' : `limit ${limit}`}`;
42
- return sql;
43
- }
44
-
45
- function text() {
46
- return undefined;
47
- }
48
-
49
- export default { number, chart, table };
1
+ function number({ metric, where, table, samples, fx }) {
2
+ const sql = `select ${fx || metric} from ${table} where ${where} ${samples ? 'limit 10' : ''}`;
3
+ return sql;
4
+ }
5
+ function table({ columns = [], table, where, samples }) {
6
+ const cols = Array.isArray(columns)
7
+ ? columns.map((el) => `"${(el.name || el).replace(/'/g, "''")}"`).join(',')
8
+ : Object.keys(columns).map(key => `"${key.replace(/'/g, "''")}"`).join(',');
9
+ return `select ${cols || '*'} from ${table} where ${where} ${samples ? 'limit 10' : 'limit 20'} `;
10
+ }
11
+
12
+ function chart({
13
+ metric,
14
+ yType, // metric type
15
+ where,
16
+ table,
17
+ x,
18
+ groupby,
19
+ groupData,
20
+ order,
21
+ samples,
22
+ limit = 100,
23
+ xType,
24
+ fx, // agg function
25
+ }) {
26
+ const xCol = x && xType?.includes('[]') ? `unnest(${x})` : x;
27
+
28
+ const metricData =
29
+ groupData
30
+ ?.filter(el => el.name)
31
+ ?.map(
32
+ (el) =>
33
+ `${metric} filter (where '${el.name.toString().replace(/'/g, "''")}'=${yType?.includes('[]') ? `any(${groupby.replace(/'/g, "''")}::text[])` : groupby.replace(/'/g, "''")}) as "${el.name.toString().replace(/'/g, "''")}"`
34
+ )
35
+ .join(',') || `${fx || metric} as metric`;
36
+ const sql = `select ${xCol} ${x && xType?.includes('[]') ? `as ${x}` : ''}, ${metricData}
37
+ from ${table}
38
+ where ${where}
39
+ ${xCol ? `group by ${xCol}` : ''}
40
+ ${order || xCol ? `order by ${order || xCol}` : ''}
41
+ ${samples ? 'limit 10' : `limit ${limit}`}`;
42
+ return sql;
43
+ }
44
+
45
+ function text() {
46
+ return undefined;
47
+ }
48
+
49
+ export default { number, chart, table };