@opengis/bi 1.2.5 → 1.2.7
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/bi.js +1 -1
- package/dist/bi.umd.cjs +58 -33
- package/dist/{import-file-iZU4En2W.js → import-file-DnbEvuUN.js} +1281 -1109
- package/dist/{vs-funnel-bar-CyPcyYTP.js → vs-funnel-bar-BzIfzGso.js} +1 -1
- package/dist/{vs-list-BoMIMCT2.js → vs-list-_I6Z56hC.js} +9 -9
- package/dist/{vs-map-DesSaN8x.js → vs-map-BsmBbjRv.js} +2 -2
- package/dist/{vs-map-cluster-Br3XHcWM.js → vs-map-cluster-DT3jfiks.js} +8 -8
- package/dist/{vs-number-sHlpEuZn.js → vs-number-D28OvROP.js} +1 -1
- package/dist/{vs-table-C8ibl5_z.js → vs-table-YpK1qNz6.js} +1 -1
- package/dist/{vs-text-CK4PX9CJ.js → vs-text-BU0n2bXl.js} +1 -1
- package/package.json +4 -2
- package/server/plugins/vite.js +69 -69
- package/server/routes/dashboard/controllers/utils/yaml.js +11 -11
- package/server/routes/map/controllers/cluster.js +125 -125
- package/server/routes/map/controllers/clusterVtile.js +166 -166
- package/server/routes/map/controllers/geojson.js +127 -127
- package/server/routes/map/controllers/map.js +69 -69
- package/server/routes/map/controllers/utils/downloadClusterData.js +44 -44
- package/server/routes/map/controllers/vtile.js +183 -183
- package/utils.js +12 -12
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createElementBlock as l, openBlock as h, createStaticVNode as V, createElementVNode as a, withDirectives as B, toDisplayString as L, vShow as P, Fragment as z, renderList as S, normalizeClass as G, resolveComponent as j, createVNode as D } from "vue";
|
|
2
|
-
import { _ as p } from "./import-file-
|
|
2
|
+
import { _ as p } from "./import-file-DnbEvuUN.js";
|
|
3
3
|
function N(t) {
|
|
4
4
|
return [
|
|
5
5
|
{
|
|
@@ -180,9 +180,9 @@ const O = {
|
|
|
180
180
|
class: "icon icon-tabler icons-tabler-outline icon-tabler-list-details"
|
|
181
181
|
};
|
|
182
182
|
function J(t, e) {
|
|
183
|
-
return h(), l("svg", W,
|
|
183
|
+
return h(), l("svg", W, e[0] || (e[0] = [
|
|
184
184
|
V('<path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M13 5h8"></path><path d="M13 9h5"></path><path d="M13 15h8"></path><path d="M13 19h5"></path><path d="M3 4m0 1a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v4a1 1 0 0 1 -1 1h-4a1 1 0 0 1 -1 -1z"></path><path d="M3 14m0 1a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v4a1 1 0 0 1 -1 1h-4a1 1 0 0 1 -1 -1z"></path>', 7)
|
|
185
|
-
])
|
|
185
|
+
]));
|
|
186
186
|
}
|
|
187
187
|
const U = /* @__PURE__ */ p(R, [["render", J]]), Z = {}, q = {
|
|
188
188
|
class: "shrink-0 size-3",
|
|
@@ -197,10 +197,10 @@ const U = /* @__PURE__ */ p(R, [["render", J]]), Z = {}, q = {
|
|
|
197
197
|
"stroke-linejoin": "round"
|
|
198
198
|
};
|
|
199
199
|
function A(t, e) {
|
|
200
|
-
return h(), l("svg", q,
|
|
200
|
+
return h(), l("svg", q, e[0] || (e[0] = [
|
|
201
201
|
a("path", { d: "M18 6 6 18" }, null, -1),
|
|
202
202
|
a("path", { d: "m6 6 12 12" }, null, -1)
|
|
203
|
-
])
|
|
203
|
+
]));
|
|
204
204
|
}
|
|
205
205
|
const K = /* @__PURE__ */ p(Z, [["render", A]]), zt = {
|
|
206
206
|
pink: ["#fde7e2", "#feafbe", "#fd58a4", "#d7038e", "#86007b"],
|
|
@@ -407,7 +407,7 @@ const ot = {}, nt = {
|
|
|
407
407
|
class: "icon icon-tabler icons-tabler-outline icon-tabler-home"
|
|
408
408
|
};
|
|
409
409
|
function at(t, e) {
|
|
410
|
-
return h(), l("svg", nt,
|
|
410
|
+
return h(), l("svg", nt, e[0] || (e[0] = [
|
|
411
411
|
a("path", {
|
|
412
412
|
stroke: "none",
|
|
413
413
|
d: "M0 0h24v24H0z",
|
|
@@ -416,7 +416,7 @@ function at(t, e) {
|
|
|
416
416
|
a("path", { d: "M5 12l-2 0l9 -9l9 9l-2 0" }, null, -1),
|
|
417
417
|
a("path", { d: "M5 12v7a2 2 0 0 0 2 2h10a2 2 0 0 0 2 -2v-7" }, null, -1),
|
|
418
418
|
a("path", { d: "M9 21v-6a2 2 0 0 1 2 -2h2a2 2 0 0 1 2 2v6" }, null, -1)
|
|
419
|
-
])
|
|
419
|
+
]));
|
|
420
420
|
}
|
|
421
421
|
const ct = /* @__PURE__ */ p(ot, [["render", at]]), lt = {
|
|
422
422
|
props: ["bbox", "map"],
|
|
@@ -450,7 +450,7 @@ const Mt = /* @__PURE__ */ p(lt, [["render", dt]]), ut = {}, pt = {
|
|
|
450
450
|
"stroke-linejoin": "#9E9E9E"
|
|
451
451
|
};
|
|
452
452
|
function ft(t, e) {
|
|
453
|
-
return h(), l("svg", pt,
|
|
453
|
+
return h(), l("svg", pt, e[0] || (e[0] = [
|
|
454
454
|
a("circle", {
|
|
455
455
|
cx: "12",
|
|
456
456
|
cy: "12",
|
|
@@ -466,7 +466,7 @@ function ft(t, e) {
|
|
|
466
466
|
cy: "19",
|
|
467
467
|
r: "1"
|
|
468
468
|
}, null, -1)
|
|
469
|
-
])
|
|
469
|
+
]));
|
|
470
470
|
}
|
|
471
471
|
const mt = /* @__PURE__ */ p(ut, [["render", ft]]), yt = {
|
|
472
472
|
components: { legendIcon: U, menuIcon: mt, closeIcon: K },
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { c as E, l as L, p as $, V as T, a as B, b as H, d as O, e as F } from "./vs-list-
|
|
2
|
-
import { _ as V, c as N } from "./import-file-
|
|
1
|
+
import { c as E, l as L, p as $, V as T, a as B, b as H, d as O, e as F } from "./vs-list-_I6Z56hC.js";
|
|
2
|
+
import { _ as V, c as N } from "./import-file-DnbEvuUN.js";
|
|
3
3
|
import { resolveComponent as u, createElementBlock as p, openBlock as i, Fragment as w, createElementVNode as l, createBlock as C, createCommentVNode as m, createVNode as x, Teleport as P, toDisplayString as f, renderList as S, normalizeStyle as k, normalizeClass as I } from "vue";
|
|
4
4
|
const R = {
|
|
5
5
|
components: { legendIcon: L, closeIcon: E },
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { c as F, l as G, p as T, b as A, V as P, a as Z, d as q, e as D } from "./vs-list-
|
|
2
|
-
import { _ as x, V as K, c as W, e as j } from "./import-file-
|
|
1
|
+
import { c as F, l as G, p as T, b as A, V as P, a as Z, d as q, e as D } from "./vs-list-_I6Z56hC.js";
|
|
2
|
+
import { _ as x, V as K, c as W, e as j } from "./import-file-DnbEvuUN.js";
|
|
3
3
|
import { createElementBlock as p, createCommentVNode as S, openBlock as c, createElementVNode as r, normalizeClass as I, Fragment as N, renderList as R, toDisplayString as O, normalizeStyle as J, createStaticVNode as Q, resolveComponent as g, withDirectives as M, createBlock as k, resolveDynamicComponent as U, createVNode as z, vShow as C } from "vue";
|
|
4
4
|
const X = {
|
|
5
5
|
components: { legendIcon: G, closeIcon: F },
|
|
@@ -88,7 +88,7 @@ const ot = /* @__PURE__ */ x(X, [["render", st]]), rt = {}, nt = {
|
|
|
88
88
|
class: "icon icon-tabler icons-tabler-outline icon-tabler-map"
|
|
89
89
|
};
|
|
90
90
|
function at(e, s) {
|
|
91
|
-
return c(), p("svg", nt,
|
|
91
|
+
return c(), p("svg", nt, s[0] || (s[0] = [
|
|
92
92
|
r("path", {
|
|
93
93
|
stroke: "none",
|
|
94
94
|
d: "M0 0h24v24H0z",
|
|
@@ -97,7 +97,7 @@ function at(e, s) {
|
|
|
97
97
|
r("path", { d: "M3 7l6 -3l6 3l6 -3v13l-6 3l-6 -3l-6 3v-13" }, null, -1),
|
|
98
98
|
r("path", { d: "M9 4v13" }, null, -1),
|
|
99
99
|
r("path", { d: "M15 7v13" }, null, -1)
|
|
100
|
-
])
|
|
100
|
+
]));
|
|
101
101
|
}
|
|
102
102
|
const lt = /* @__PURE__ */ x(rt, [["render", at]]), it = {}, ct = {
|
|
103
103
|
xmlns: "http://www.w3.org/2000/svg",
|
|
@@ -112,7 +112,7 @@ const lt = /* @__PURE__ */ x(rt, [["render", at]]), it = {}, ct = {
|
|
|
112
112
|
class: "icon icon-tabler icons-tabler-outline icon-tabler-table"
|
|
113
113
|
};
|
|
114
114
|
function pt(e, s) {
|
|
115
|
-
return c(), p("svg", ct,
|
|
115
|
+
return c(), p("svg", ct, s[0] || (s[0] = [
|
|
116
116
|
r("path", {
|
|
117
117
|
stroke: "none",
|
|
118
118
|
d: "M0 0h24v24H0z",
|
|
@@ -121,7 +121,7 @@ function pt(e, s) {
|
|
|
121
121
|
r("path", { d: "M3 5a2 2 0 0 1 2 -2h14a2 2 0 0 1 2 2v14a2 2 0 0 1 -2 2h-14a2 2 0 0 1 -2 -2v-14z" }, null, -1),
|
|
122
122
|
r("path", { d: "M3 10h18" }, null, -1),
|
|
123
123
|
r("path", { d: "M10 3v18" }, null, -1)
|
|
124
|
-
])
|
|
124
|
+
]));
|
|
125
125
|
}
|
|
126
126
|
const dt = /* @__PURE__ */ x(it, [["render", pt]]), ht = {}, ut = {
|
|
127
127
|
xmlns: "http://www.w3.org/2000/svg",
|
|
@@ -136,9 +136,9 @@ const dt = /* @__PURE__ */ x(it, [["render", pt]]), ht = {}, ut = {
|
|
|
136
136
|
class: "icon icon-tabler icons-tabler-outline icon-tabler-align-box-left-stretch"
|
|
137
137
|
};
|
|
138
138
|
function mt(e, s) {
|
|
139
|
-
return c(), p("svg", ut,
|
|
139
|
+
return c(), p("svg", ut, s[0] || (s[0] = [
|
|
140
140
|
Q('<path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M3 5a2 2 0 0 1 2 -2h14a2 2 0 0 1 2 2v14a2 2 0 0 1 -2 2h-14a2 2 0 0 1 -2 -2v-14z"></path><path d="M9 17h-2"></path><path d="M13 12h-6"></path><path d="M11 7h-4"></path>', 5)
|
|
141
|
-
])
|
|
141
|
+
]));
|
|
142
142
|
}
|
|
143
143
|
const gt = /* @__PURE__ */ x(ht, [["render", mt]]), ft = {
|
|
144
144
|
mixins: [W, D],
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { _ as m, c as f, b as _, d as b } from "./import-file-
|
|
1
|
+
import { _ as m, c as f, b as _, d as b } from "./import-file-DnbEvuUN.js";
|
|
2
2
|
import { createElementBlock as a, openBlock as r, createElementVNode as s, Fragment as n, renderList as c, toDisplayString as d } from "vue";
|
|
3
3
|
const x = {
|
|
4
4
|
name: "VsTable",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
var ge = Object.defineProperty;
|
|
2
2
|
var ke = (c, e, t) => e in c ? ge(c, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : c[e] = t;
|
|
3
3
|
var k = (c, e, t) => ke(c, typeof e != "symbol" ? e + "" : e, t);
|
|
4
|
-
import { _ as de, c as xe } from "./import-file-
|
|
4
|
+
import { _ as de, c as xe } from "./import-file-DnbEvuUN.js";
|
|
5
5
|
import { createElementBlock as V, openBlock as J, createCommentVNode as be } from "vue";
|
|
6
6
|
function Q() {
|
|
7
7
|
return {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opengis/bi",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.7",
|
|
4
4
|
"description": "BI data visualization module",
|
|
5
5
|
"main": "dist/bi.js",
|
|
6
6
|
"browser": "dist/bi.umd.cjs",
|
|
@@ -42,7 +42,9 @@
|
|
|
42
42
|
"author": "Softpro",
|
|
43
43
|
"license": "ISC",
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@mapbox/sphericalmercator": "^1.2.0"
|
|
45
|
+
"@mapbox/sphericalmercator": "^1.2.0",
|
|
46
|
+
"@opengis/table": "^0.0.30",
|
|
47
|
+
"lucide-vue-next": "^0.546.0"
|
|
46
48
|
},
|
|
47
49
|
"devDependencies": {
|
|
48
50
|
"@highlightjs/vue-plugin": "github:highlightjs/vue-plugin",
|
package/server/plugins/vite.js
CHANGED
|
@@ -1,69 +1,69 @@
|
|
|
1
|
-
import fs from 'fs';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
import config from '../../config.js';
|
|
4
|
-
|
|
5
|
-
const { disableAuth } = config;
|
|
6
|
-
const isProduction = process.env.NODE_ENV === 'production';
|
|
7
|
-
|
|
8
|
-
async function plugin(fastify) {
|
|
9
|
-
// vite server
|
|
10
|
-
if (!isProduction) {
|
|
11
|
-
const vite = await import('vite');
|
|
12
|
-
|
|
13
|
-
const viteServer = await vite.createServer({
|
|
14
|
-
server: {
|
|
15
|
-
middlewareMode: true,
|
|
16
|
-
},
|
|
17
|
-
});
|
|
18
|
-
// hot reload
|
|
19
|
-
viteServer.watcher.on('all', (d, t) => {
|
|
20
|
-
if (!t.includes('module') && !t.includes('templates')) return;
|
|
21
|
-
// console.log(d, t);
|
|
22
|
-
viteServer.ws.send({ type: 'full-reload' });
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
// this is middleware for vite's dev servert
|
|
26
|
-
fastify.addHook('onRequest', async (req, reply) => {
|
|
27
|
-
// const { user } = req.session?.passport || {};
|
|
28
|
-
const next = () => new Promise((resolve) => {
|
|
29
|
-
viteServer.middlewares(req.raw, reply.raw, () => resolve());
|
|
30
|
-
});
|
|
31
|
-
await next();
|
|
32
|
-
});
|
|
33
|
-
fastify.get('*', async () => {});
|
|
34
|
-
return;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// From Build
|
|
38
|
-
fastify.get('*', async (req, reply) => {
|
|
39
|
-
// console.log(disableAuth)
|
|
40
|
-
if (!req.user && !disableAuth) return reply.redirect('/login');
|
|
41
|
-
const stream = fs.createReadStream('dist/index.html');
|
|
42
|
-
return reply
|
|
43
|
-
.headers({ 'Cache-Control': 'public, no-cache' })
|
|
44
|
-
.type('text/html')
|
|
45
|
-
.send(stream);
|
|
46
|
-
});
|
|
47
|
-
fastify.get('/assets/:file', async (req, reply) => {
|
|
48
|
-
const stream = fs.createReadStream(`dist/assets/${req.params.file}`);
|
|
49
|
-
const ext = path.extname(req.params.file);
|
|
50
|
-
const mime = {
|
|
51
|
-
'.js': 'text/javascript',
|
|
52
|
-
'.css': 'text/css',
|
|
53
|
-
'.woff2': 'application/font-woff',
|
|
54
|
-
'.png': 'image/png',
|
|
55
|
-
}[ext];
|
|
56
|
-
// reply.cacheControl('max-age', '1d');
|
|
57
|
-
return mime
|
|
58
|
-
? reply
|
|
59
|
-
.headers({
|
|
60
|
-
'Cache-Control': 'public, max-age=3600',
|
|
61
|
-
'Content-Encoding': 'identity',
|
|
62
|
-
})
|
|
63
|
-
.type(mime)
|
|
64
|
-
.send(stream)
|
|
65
|
-
: stream;
|
|
66
|
-
});
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
export default plugin;
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import config from '../../config.js';
|
|
4
|
+
|
|
5
|
+
const { disableAuth } = config;
|
|
6
|
+
const isProduction = process.env.NODE_ENV === 'production';
|
|
7
|
+
|
|
8
|
+
async function plugin(fastify) {
|
|
9
|
+
// vite server
|
|
10
|
+
if (!isProduction) {
|
|
11
|
+
const vite = await import('vite');
|
|
12
|
+
|
|
13
|
+
const viteServer = await vite.createServer({
|
|
14
|
+
server: {
|
|
15
|
+
middlewareMode: true,
|
|
16
|
+
},
|
|
17
|
+
});
|
|
18
|
+
// hot reload
|
|
19
|
+
viteServer.watcher.on('all', (d, t) => {
|
|
20
|
+
if (!t.includes('module') && !t.includes('templates')) return;
|
|
21
|
+
// console.log(d, t);
|
|
22
|
+
viteServer.ws.send({ type: 'full-reload' });
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
// this is middleware for vite's dev servert
|
|
26
|
+
fastify.addHook('onRequest', async (req, reply) => {
|
|
27
|
+
// const { user } = req.session?.passport || {};
|
|
28
|
+
const next = () => new Promise((resolve) => {
|
|
29
|
+
viteServer.middlewares(req.raw, reply.raw, () => resolve());
|
|
30
|
+
});
|
|
31
|
+
await next();
|
|
32
|
+
});
|
|
33
|
+
fastify.get('*', async () => {});
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// From Build
|
|
38
|
+
fastify.get('*', async (req, reply) => {
|
|
39
|
+
// console.log(disableAuth)
|
|
40
|
+
if (!req.user && !disableAuth) return reply.redirect('/login');
|
|
41
|
+
const stream = fs.createReadStream('dist/index.html');
|
|
42
|
+
return reply
|
|
43
|
+
.headers({ 'Cache-Control': 'public, no-cache' })
|
|
44
|
+
.type('text/html')
|
|
45
|
+
.send(stream);
|
|
46
|
+
});
|
|
47
|
+
fastify.get('/assets/:file', async (req, reply) => {
|
|
48
|
+
const stream = fs.createReadStream(`dist/assets/${req.params.file}`);
|
|
49
|
+
const ext = path.extname(req.params.file);
|
|
50
|
+
const mime = {
|
|
51
|
+
'.js': 'text/javascript',
|
|
52
|
+
'.css': 'text/css',
|
|
53
|
+
'.woff2': 'application/font-woff',
|
|
54
|
+
'.png': 'image/png',
|
|
55
|
+
}[ext];
|
|
56
|
+
// reply.cacheControl('max-age', '1d');
|
|
57
|
+
return mime
|
|
58
|
+
? reply
|
|
59
|
+
.headers({
|
|
60
|
+
'Cache-Control': 'public, max-age=3600',
|
|
61
|
+
'Content-Encoding': 'identity',
|
|
62
|
+
})
|
|
63
|
+
.type(mime)
|
|
64
|
+
.send(stream)
|
|
65
|
+
: stream;
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export default plugin;
|
|
@@ -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,125 +1,125 @@
|
|
|
1
|
-
import { getFilterSQL, logger, pgClients, getMeta } from '@opengis/fastify-table/utils.js';
|
|
2
|
-
|
|
3
|
-
import { getWidget } from '../../../../utils.js';
|
|
4
|
-
|
|
5
|
-
import downloadClusterData from './utils/downloadClusterData.js';
|
|
6
|
-
|
|
7
|
-
const clusterExists = {};
|
|
8
|
-
|
|
9
|
-
export default async function cluster(req, reply) {
|
|
10
|
-
const { query = {} } = req;
|
|
11
|
-
const { widget, filter, dashboard, search } = query;
|
|
12
|
-
|
|
13
|
-
if (!widget) {
|
|
14
|
-
return { message: 'not enough params: widget', status: 400 };
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
const { pg = req.pg || pgClients.client, data, style, controls } = await getWidget({ pg: req.pg, dashboard, widget });
|
|
18
|
-
|
|
19
|
-
const pkey = pg.pk?.[data?.table];
|
|
20
|
-
|
|
21
|
-
if (!pkey) {
|
|
22
|
-
return {
|
|
23
|
-
message: `invalid ${widget ? 'widget' : 'dashboard'}: table pk not found (${data?.table})`,
|
|
24
|
-
status: 400,
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
// data param
|
|
29
|
-
const {
|
|
30
|
-
table,
|
|
31
|
-
query: where = '1=1',
|
|
32
|
-
metrics = [],
|
|
33
|
-
cluster,
|
|
34
|
-
clusterTable = {},
|
|
35
|
-
} = data;
|
|
36
|
-
|
|
37
|
-
if (!cluster) {
|
|
38
|
-
return {
|
|
39
|
-
message: `invalid ${widget ? 'widget' : 'dashboard'}: cluster column not specified`,
|
|
40
|
-
status: 400,
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
if (!metrics.length) {
|
|
45
|
-
return {
|
|
46
|
-
message: `invalid ${widget ? 'widget' : 'dashboard'}: metric columns not found`,
|
|
47
|
-
status: 400,
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
if (!clusterTable?.name) {
|
|
52
|
-
Object.assign(clusterTable, {
|
|
53
|
-
name: 'bi.cluster',
|
|
54
|
-
title: 'title',
|
|
55
|
-
query: `type='${cluster}'`,
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
try {
|
|
60
|
-
if (cluster && !clusterExists[cluster]) {
|
|
61
|
-
const res = await downloadClusterData({ pg, cluster });
|
|
62
|
-
if (res) return res;
|
|
63
|
-
clusterExists[cluster] = 1;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
if (clusterTable?.name && !pg.pk?.[clusterTable?.name]) {
|
|
67
|
-
return {
|
|
68
|
-
message: 'invalid widget params: clusterTable pkey not found',
|
|
69
|
-
status: 404,
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const { bounds, extentStr } = await pg.query(`select count(*),
|
|
74
|
-
st_asgeojson(st_extent(geom))::json as bounds,
|
|
75
|
-
replace(regexp_replace(st_extent(geom)::box2d::text,'BOX\\(|\\)','','g'),' ',',') as "extentStr"
|
|
76
|
-
from ${table} where ${where || '1=1'}`).then((res) => res.rows?.[0] || {});
|
|
77
|
-
const extent = extentStr ? extentStr.split(',') : undefined;
|
|
78
|
-
|
|
79
|
-
// get sql
|
|
80
|
-
const { optimizedSQL } =
|
|
81
|
-
filter || search
|
|
82
|
-
? await getFilterSQL({ pg, table, filter, search })
|
|
83
|
-
: {};
|
|
84
|
-
|
|
85
|
-
const { columns = [] } = await getMeta({ pg, table });
|
|
86
|
-
const columnList = columns.map(el => el.name);
|
|
87
|
-
|
|
88
|
-
if (query.metric && typeof query.metric === 'string') {
|
|
89
|
-
const checkInvalid = query.metric.split(',').find(el => !columnList.includes(el) && el !== 'count');
|
|
90
|
-
if (checkInvalid) {
|
|
91
|
-
return reply.status(404).send(`invalid query metric value: ${checkInvalid}`);
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
const multipleMetrics = query.metric ? query.metric.split(',').map(el => el === 'count' ? 'count(*)' : `sum(${el.replace(/'/g, "''")})::float as ${el}`).join(',') : null;
|
|
96
|
-
const multipleMetricsOrder = query.metric ? query.metric.split(',').map(el => el === 'count' ? 'count(*)' : `sum(${el.replace(/'/g, "''")})::float`).join(',') : null;
|
|
97
|
-
const metricFunc = multipleMetrics
|
|
98
|
-
|| `${clusterTable?.operator || 'sum'}("${metrics[0]}")::float`;
|
|
99
|
-
|
|
100
|
-
const q = `select b.*, ${metricFunc} ${multipleMetrics ? '' : 'as metric'}
|
|
101
|
-
from ${optimizedSQL ? `(${optimizedSQL})` : table} q
|
|
102
|
-
left join lateral (select "${pg.pk?.[clusterTable?.name]}" as id, ${clusterTable?.column || cluster} as name, ${clusterTable?.title} as title from ${clusterTable?.name} where ${clusterTable?.codifierColumn || 'codifier'}=q."${clusterTable?.column || cluster}" limit 1)b on 1=1
|
|
103
|
-
where ${where} group by b.id, b.name, b.title order by ${multipleMetricsOrder || metricFunc} desc`;
|
|
104
|
-
|
|
105
|
-
if (query.sql === '1') return q;
|
|
106
|
-
|
|
107
|
-
// auto Index
|
|
108
|
-
// autoIndex({ table, columns: (metrics || []).concat([cluster]) });
|
|
109
|
-
|
|
110
|
-
const { rows = [] } = await pg.query(q);
|
|
111
|
-
const vals = rows.map((el) => el.metric - 0).sort((a, b) => a - b);
|
|
112
|
-
const len = vals.length;
|
|
113
|
-
const sizes = [
|
|
114
|
-
vals[0],
|
|
115
|
-
vals[Math.floor(len / 4)],
|
|
116
|
-
vals[Math.floor(len / 2)],
|
|
117
|
-
vals[Math.floor(len * 0.75)],
|
|
118
|
-
vals[len - 1],
|
|
119
|
-
];
|
|
120
|
-
return { sizes, style, controls, metrics, rows, columns: columns.map(({ name, title, dataTypeID }) => ({ name, title, type: pg.pgType[dataTypeID] })), bounds, extent, count: rows.length, total: rows?.reduce((acc, curr) => (curr.metric || 0) + acc, 0) };
|
|
121
|
-
} catch (err) {
|
|
122
|
-
logger.file('bi/cluster/error', { error: err.toString(), query });
|
|
123
|
-
return { error: err.toString(), status: 500 };
|
|
124
|
-
}
|
|
125
|
-
}
|
|
1
|
+
import { getFilterSQL, logger, pgClients, getMeta } from '@opengis/fastify-table/utils.js';
|
|
2
|
+
|
|
3
|
+
import { getWidget } from '../../../../utils.js';
|
|
4
|
+
|
|
5
|
+
import downloadClusterData from './utils/downloadClusterData.js';
|
|
6
|
+
|
|
7
|
+
const clusterExists = {};
|
|
8
|
+
|
|
9
|
+
export default async function cluster(req, reply) {
|
|
10
|
+
const { query = {} } = req;
|
|
11
|
+
const { widget, filter, dashboard, search } = query;
|
|
12
|
+
|
|
13
|
+
if (!widget) {
|
|
14
|
+
return { message: 'not enough params: widget', status: 400 };
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const { pg = req.pg || pgClients.client, data, style, controls } = await getWidget({ pg: req.pg, dashboard, widget });
|
|
18
|
+
|
|
19
|
+
const pkey = pg.pk?.[data?.table];
|
|
20
|
+
|
|
21
|
+
if (!pkey) {
|
|
22
|
+
return {
|
|
23
|
+
message: `invalid ${widget ? 'widget' : 'dashboard'}: table pk not found (${data?.table})`,
|
|
24
|
+
status: 400,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// data param
|
|
29
|
+
const {
|
|
30
|
+
table,
|
|
31
|
+
query: where = '1=1',
|
|
32
|
+
metrics = [],
|
|
33
|
+
cluster,
|
|
34
|
+
clusterTable = {},
|
|
35
|
+
} = data;
|
|
36
|
+
|
|
37
|
+
if (!cluster) {
|
|
38
|
+
return {
|
|
39
|
+
message: `invalid ${widget ? 'widget' : 'dashboard'}: cluster column not specified`,
|
|
40
|
+
status: 400,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (!metrics.length) {
|
|
45
|
+
return {
|
|
46
|
+
message: `invalid ${widget ? 'widget' : 'dashboard'}: metric columns not found`,
|
|
47
|
+
status: 400,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (!clusterTable?.name) {
|
|
52
|
+
Object.assign(clusterTable, {
|
|
53
|
+
name: 'bi.cluster',
|
|
54
|
+
title: 'title',
|
|
55
|
+
query: `type='${cluster}'`,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
try {
|
|
60
|
+
if (cluster && !clusterExists[cluster]) {
|
|
61
|
+
const res = await downloadClusterData({ pg, cluster });
|
|
62
|
+
if (res) return res;
|
|
63
|
+
clusterExists[cluster] = 1;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (clusterTable?.name && !pg.pk?.[clusterTable?.name]) {
|
|
67
|
+
return {
|
|
68
|
+
message: 'invalid widget params: clusterTable pkey not found',
|
|
69
|
+
status: 404,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const { bounds, extentStr } = await pg.query(`select count(*),
|
|
74
|
+
st_asgeojson(st_extent(geom))::json as bounds,
|
|
75
|
+
replace(regexp_replace(st_extent(geom)::box2d::text,'BOX\\(|\\)','','g'),' ',',') as "extentStr"
|
|
76
|
+
from ${table} where ${where || '1=1'}`).then((res) => res.rows?.[0] || {});
|
|
77
|
+
const extent = extentStr ? extentStr.split(',') : undefined;
|
|
78
|
+
|
|
79
|
+
// get sql
|
|
80
|
+
const { optimizedSQL } =
|
|
81
|
+
filter || search
|
|
82
|
+
? await getFilterSQL({ pg, table, filter, search })
|
|
83
|
+
: {};
|
|
84
|
+
|
|
85
|
+
const { columns = [] } = await getMeta({ pg, table });
|
|
86
|
+
const columnList = columns.map(el => el.name);
|
|
87
|
+
|
|
88
|
+
if (query.metric && typeof query.metric === 'string') {
|
|
89
|
+
const checkInvalid = query.metric.split(',').find(el => !columnList.includes(el) && el !== 'count');
|
|
90
|
+
if (checkInvalid) {
|
|
91
|
+
return reply.status(404).send(`invalid query metric value: ${checkInvalid}`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const multipleMetrics = query.metric ? query.metric.split(',').map(el => el === 'count' ? 'count(*)' : `sum(${el.replace(/'/g, "''")})::float as ${el}`).join(',') : null;
|
|
96
|
+
const multipleMetricsOrder = query.metric ? query.metric.split(',').map(el => el === 'count' ? 'count(*)' : `sum(${el.replace(/'/g, "''")})::float`).join(',') : null;
|
|
97
|
+
const metricFunc = multipleMetrics
|
|
98
|
+
|| `${clusterTable?.operator || 'sum'}("${metrics[0]}")::float`;
|
|
99
|
+
|
|
100
|
+
const q = `select b.*, ${metricFunc} ${multipleMetrics ? '' : 'as metric'}
|
|
101
|
+
from ${optimizedSQL ? `(${optimizedSQL})` : table} q
|
|
102
|
+
left join lateral (select "${pg.pk?.[clusterTable?.name]}" as id, ${clusterTable?.column || cluster} as name, ${clusterTable?.title} as title from ${clusterTable?.name} where ${clusterTable?.codifierColumn || 'codifier'}=q."${clusterTable?.column || cluster}" limit 1)b on 1=1
|
|
103
|
+
where ${where} group by b.id, b.name, b.title order by ${multipleMetricsOrder || metricFunc} desc`;
|
|
104
|
+
|
|
105
|
+
if (query.sql === '1') return q;
|
|
106
|
+
|
|
107
|
+
// auto Index
|
|
108
|
+
// autoIndex({ table, columns: (metrics || []).concat([cluster]) });
|
|
109
|
+
|
|
110
|
+
const { rows = [] } = await pg.query(q);
|
|
111
|
+
const vals = rows.map((el) => el.metric - 0).sort((a, b) => a - b);
|
|
112
|
+
const len = vals.length;
|
|
113
|
+
const sizes = [
|
|
114
|
+
vals[0],
|
|
115
|
+
vals[Math.floor(len / 4)],
|
|
116
|
+
vals[Math.floor(len / 2)],
|
|
117
|
+
vals[Math.floor(len * 0.75)],
|
|
118
|
+
vals[len - 1],
|
|
119
|
+
];
|
|
120
|
+
return { sizes, style, controls, metrics, rows, columns: columns.map(({ name, title, dataTypeID }) => ({ name, title, type: pg.pgType[dataTypeID] })), bounds, extent, count: rows.length, total: rows?.reduce((acc, curr) => (curr.metric || 0) + acc, 0) };
|
|
121
|
+
} catch (err) {
|
|
122
|
+
logger.file('bi/cluster/error', { error: err.toString(), query });
|
|
123
|
+
return { error: err.toString(), status: 500 };
|
|
124
|
+
}
|
|
125
|
+
}
|