@opengis/fastify-table 1.4.24 → 1.4.26
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/package.json +1 -1
- package/server/plugins/table/funcs/getFilter.js +9 -3
- package/server/plugins/table/funcs/getFilterSQL/index.js +29 -24
- package/server/routes/properties/controllers/admin.properties.get.js +5 -1
- package/server/routes/properties/controllers/admin.properties.post.js +4 -0
- package/server/routes/properties/controllers/table.properties.get.js +4 -0
- package/server/routes/properties/controllers/table.properties.post.js +4 -0
- package/server/routes/properties/index.js +7 -5
- package/server/routes/table/controllers/filter.js +48 -32
- package/server/routes/util/controllers/user.tokens.js +9 -3
- package/server/routes/util/index.js +1 -1
package/package.json
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
import routeFilter from '../../../routes/table/controllers/filter.js';
|
|
2
2
|
|
|
3
|
-
export default async function getFilter({
|
|
3
|
+
export default async function getFilter({
|
|
4
|
+
pg, table, filter, custom, state, search, user,
|
|
5
|
+
}, reply) {
|
|
4
6
|
const params = { table };
|
|
5
|
-
const query = {
|
|
6
|
-
|
|
7
|
+
const query = {
|
|
8
|
+
filter, custom, state, search,
|
|
9
|
+
};
|
|
10
|
+
const result = await routeFilter({
|
|
11
|
+
pg, params, query, user,
|
|
12
|
+
}, reply, 1);
|
|
7
13
|
return result;
|
|
8
14
|
}
|
|
@@ -7,6 +7,7 @@ import config from '../../../../../config.js';
|
|
|
7
7
|
import getTableSql from './util/getTableSql.js';
|
|
8
8
|
import getFilterQuery from './util/getFilterQuery.js';
|
|
9
9
|
import getOptimizedQuery from './util/getOptimizedQuery.js';
|
|
10
|
+
import getFilter from '../getFilter.js';
|
|
10
11
|
|
|
11
12
|
const checkInline = {};
|
|
12
13
|
const defaultTable = 'crm.extra_data';
|
|
@@ -85,30 +86,34 @@ export default async function getFilterSQL({
|
|
|
85
86
|
return pk && !fieldsList.includes(name) ? `${pk} in (select ${pk} from (${fieldQuery.replace(/limit 0/g, '')} where ${name} ${sval} )q where 1=1)` : `${name} ${sval}`;
|
|
86
87
|
}).join(' or ')} )` : '';
|
|
87
88
|
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
.concat(
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
89
|
+
const filterResponse = await getFilter({
|
|
90
|
+
pg, table, user: { uid },
|
|
91
|
+
}, null, 1);
|
|
92
|
+
|
|
93
|
+
const filterList1 = await Promise.all((filterList || [])
|
|
94
|
+
.concat(filterResponse?.inline || [])
|
|
95
|
+
.concat(filterResponse?.custom || [])
|
|
96
|
+
.concat(filterResponse?.state || [])
|
|
97
|
+
.concat(filterResponse?.list || [])
|
|
98
|
+
?.filter(el => el.id || el.name)
|
|
99
|
+
?.map(async (el) => {
|
|
100
|
+
el.name = el.name || el.id;
|
|
101
|
+
|
|
102
|
+
if (el.name && extraColumns.find(item => item?.name === el?.name)) {
|
|
103
|
+
Object.assign(el, { extra: { table: extraDataTable, input: extraColumns.find(item => item?.name === el?.name)?.type } });
|
|
104
|
+
}
|
|
105
|
+
if (!el?.data) return el;
|
|
106
|
+
// const cls = await getTemplate(['cls', 'select'], el.data); // only git cls
|
|
107
|
+
const cls = await getSelect(el.data, pg); // git + db cls
|
|
108
|
+
|
|
109
|
+
if (Array.isArray(cls?.arr) && cls.arr.length) {
|
|
110
|
+
Object.assign(el, { cls: el.data, options: cls, select: `select code, name from admin.cls where parent='${el.data}'` });
|
|
111
|
+
}
|
|
112
|
+
else if (typeof (cls?.sql || cls) === 'string') {
|
|
113
|
+
Object.assign(el, { select: cls?.sql || cls });
|
|
114
|
+
}
|
|
115
|
+
return el;
|
|
116
|
+
}));
|
|
112
117
|
|
|
113
118
|
const modelQuery = body?.model || body?.table || table;
|
|
114
119
|
|
|
@@ -8,7 +8,11 @@ export default async function getSettingsApp({
|
|
|
8
8
|
}, reply) {
|
|
9
9
|
const time = Date.now();
|
|
10
10
|
|
|
11
|
-
if (!pg
|
|
11
|
+
if (!pg) {
|
|
12
|
+
return reply.status(500).send('empty pg');
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
if (!pg?.pk?.[table]) {
|
|
12
16
|
return reply.status(404).send('table not found');
|
|
13
17
|
}
|
|
14
18
|
|
|
@@ -26,6 +26,10 @@ export default async function postSettingsApp({
|
|
|
26
26
|
return reply.status(400).send('not enough body params');
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
if (!pg) {
|
|
30
|
+
return reply.status(500).send('empty pg');
|
|
31
|
+
}
|
|
32
|
+
|
|
29
33
|
if (!pg?.pk?.[table]) {
|
|
30
34
|
return reply.status(404).send('table not found');
|
|
31
35
|
}
|
|
@@ -28,6 +28,10 @@ export default async function getSettingsTable({
|
|
|
28
28
|
return reply.status(400).send('not enough params: table');
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
if (!pg) {
|
|
32
|
+
return reply.status(500).send('empty pg');
|
|
33
|
+
}
|
|
34
|
+
|
|
31
35
|
const loadTable = await getTemplate('table', table);
|
|
32
36
|
|
|
33
37
|
const tableName = loadTable?.table || table;
|
|
@@ -20,16 +20,18 @@ const propertiesSchema = {
|
|
|
20
20
|
},
|
|
21
21
|
};
|
|
22
22
|
|
|
23
|
+
const policy = ['site']; // cms etc.
|
|
24
|
+
|
|
23
25
|
async function plugin(app, config = {}) {
|
|
24
26
|
const { prefix = '/api' } = config;
|
|
25
|
-
app.get(`${prefix}/properties/:id`, { schema: propertiesSchema }, getExtraProperties);
|
|
26
|
-
app.post(`${prefix}/properties/:id`, { schema: propertiesSchema }, addExtraProperties);
|
|
27
|
+
app.get(`${prefix}/properties/:id`, { config: { policy }, schema: propertiesSchema }, getExtraProperties);
|
|
28
|
+
app.post(`${prefix}/properties/:id`, { config: { policy }, schema: propertiesSchema }, addExtraProperties);
|
|
27
29
|
|
|
28
|
-
app.get(`${prefix}/settings-app/:key?`, {
|
|
30
|
+
app.get(`${prefix}/settings-app/:key?`, { config: { policy }, schema: propertiesSchema }, getSettingsApp);
|
|
29
31
|
app.post(`${prefix}/settings-app`, { config: { policy: ['admin'] } }, postSettingsApp);
|
|
30
32
|
|
|
31
|
-
app.get(`${prefix}/settings-table/:table/:entity?`, {}, getSettingsTable);
|
|
32
|
-
app.post(`${prefix}/settings-table/:table`, {}, postSettingsTable);
|
|
33
|
+
app.get(`${prefix}/settings-table/:table/:entity?`, { config: { policy } }, getSettingsTable);
|
|
34
|
+
app.post(`${prefix}/settings-table/:table`, { config: { policy } }, postSettingsTable);
|
|
33
35
|
}
|
|
34
36
|
|
|
35
37
|
export default plugin;
|
|
@@ -1,26 +1,42 @@
|
|
|
1
|
-
import {
|
|
2
|
-
logger, autoIndex, getSelect, getTemplate, getSelectVal, pgClients,
|
|
3
|
-
} from '../../../../utils.js';
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
/* import {
|
|
2
|
+
logger, autoIndex, getSelect, getTemplate, getSelectVal, pgClients, applyHook,
|
|
3
|
+
} from '../../../../utils.js'; */
|
|
4
|
+
|
|
5
|
+
import logger from '../../../plugins/logger/getLogger.js';
|
|
6
|
+
import autoIndex from '../../../plugins/pg/funcs/autoIndex.js';
|
|
7
|
+
import getSelect from '../../../plugins/table/funcs/getSelect.js';
|
|
8
|
+
import getSelectVal from '../../../plugins/table/funcs/metaFormat/getSelectVal.js';
|
|
9
|
+
import pgClients from '../../../plugins/pg/pgClients.js';
|
|
10
|
+
import applyHook from '../../../plugins/hook/funcs/applyHook.js';
|
|
11
|
+
import getTemplate from '../../../plugins/table/funcs/getTemplate.js';
|
|
12
|
+
|
|
13
|
+
export default async function filterAPI(req, reply, iscalled) {
|
|
6
14
|
const time = Date.now();
|
|
7
15
|
|
|
8
16
|
const {
|
|
9
17
|
params, pg = pgClients.client, user = {}, query = {},
|
|
10
18
|
} = req;
|
|
11
19
|
|
|
20
|
+
const hookData = await applyHook('preFilter', { pg, table: params.table });
|
|
12
21
|
const loadTable = await getTemplate('table', params.table);
|
|
13
|
-
if (!loadTable) { return { status: 404, message: 'not found' }; }
|
|
14
22
|
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
23
|
+
const {
|
|
24
|
+
table, sql, query: tableQuery, form, extra, filterState, filterCustom,
|
|
25
|
+
} = hookData || loadTable || {};
|
|
26
|
+
|
|
27
|
+
if (!table) {
|
|
28
|
+
return { status: 404, message: 'not found' };
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const sqlTable = sql?.filter?.((el) => !el?.disabled && el?.sql?.replace)?.map?.((el, i) => ` left join lateral (${el.sql.replace('{{uid}}', user?.uid)}) ${el.name || `t${i}`} on 1=1 `)?.join?.('') || '';
|
|
32
|
+
const { fields: columns = [] } = await pg.query(`select * from ${table} t ${sqlTable} limit 0`);
|
|
33
|
+
const { fields = [] } = await pg.query(`select * from ${table} t limit 0`);
|
|
18
34
|
|
|
19
|
-
const optimizedSQL = `select * from ${
|
|
35
|
+
const optimizedSQL = `select * from ${table} t ${sqlTable} where ${tableQuery || '1=1'}`.replace(/{{uid}}/g, user?.uid);
|
|
20
36
|
|
|
21
37
|
if (query?.sql && user?.user_type === 'admin') return optimizedSQL;
|
|
22
38
|
|
|
23
|
-
const filters = (loadTable?.filter_list || loadTable?.filters || loadTable?.filterList || []).concat(loadTable?.filterSql || []);
|
|
39
|
+
const filters = (hookData?.filters || loadTable?.filter_list || loadTable?.filters || loadTable?.filterList || []).concat(loadTable?.filterSql || []);
|
|
24
40
|
|
|
25
41
|
// admin.custom_column - user filter NA-165
|
|
26
42
|
const { rows: properties = [] } = await pg.query('select column_id, name, title, format, data from admin.custom_column where entity=$1 and uid=$2 and filter', [params.table, user?.uid]);
|
|
@@ -29,25 +45,25 @@ export default async function filterAPI(req) {
|
|
|
29
45
|
}));
|
|
30
46
|
|
|
31
47
|
// KRYVYIRIH-231
|
|
32
|
-
autoIndex({ table
|
|
48
|
+
autoIndex({ table, columns: filters.filter((el) => columns?.find?.((item) => item?.name === el.name)) })
|
|
33
49
|
.catch(err => {
|
|
34
50
|
console.error(err.toString());
|
|
35
51
|
logger.file('autoindex/error', { name: params?.table, error: err.toString(), stack: err.stack });
|
|
36
52
|
});
|
|
37
53
|
|
|
38
|
-
const loadTemplate =
|
|
39
|
-
const extraColumns =
|
|
54
|
+
const loadTemplate = form ? await getTemplate('form', form) : {};
|
|
55
|
+
const extraColumns = extra ? Object.keys(loadTemplate?.schema || {}).filter(key => !columns.find(col => col.name === key)) : [];
|
|
40
56
|
|
|
41
57
|
filters?.forEach?.(el => Object.assign(el, { id: el.id || el.name, title: el.title || el.ua, extra: extraColumns.includes(el.id || el.name) }));
|
|
42
58
|
|
|
43
59
|
await Promise.all(filters.filter((el) => el.data && el.id && el.type !== 'Autocomplete' && !el.sql).map(async (el) => {
|
|
44
60
|
const cls = await getSelect(el.data, pg);
|
|
45
61
|
|
|
46
|
-
if (!cls
|
|
62
|
+
if (!cls) return;
|
|
47
63
|
const { dataTypeID } = columns.find((item) => item.name === el.id) || {};
|
|
48
64
|
|
|
49
65
|
if (el.extra && Array.isArray(cls?.arr || cls)) {
|
|
50
|
-
const countArr = await pg.query('select value_text as id, count(*) from crm.extra_data where property_key=$1 and property_entity=$2 group by value_text', [el.id,
|
|
66
|
+
const countArr = await pg.query('select value_text as id, count(*) from crm.extra_data where property_key=$1 and property_entity=$2 group by value_text', [el.id, table]);
|
|
51
67
|
const options = countArr.rows.map(cel => {
|
|
52
68
|
const data = (cls?.arr || cls).find(c => c.id === cel.id);
|
|
53
69
|
return { ...cel, ...data };
|
|
@@ -60,7 +76,7 @@ export default async function filterAPI(req) {
|
|
|
60
76
|
? `select unnest(${el.id})::text as id,count(*) from (${optimizedSQL})q group by unnest(${el.id}) limit 100`
|
|
61
77
|
: `select ${el.id}::text as id,count(*) from (${optimizedSQL})q group by ${el.id} limit 100`;
|
|
62
78
|
|
|
63
|
-
const countArr = await pg.queryCache(q, { table
|
|
79
|
+
const countArr = await pg.queryCache(q, { table });
|
|
64
80
|
|
|
65
81
|
if (countArr.timeout) {
|
|
66
82
|
Object.assign(el, { timeout: countArr.timeout });
|
|
@@ -79,13 +95,13 @@ export default async function filterAPI(req) {
|
|
|
79
95
|
Object.assign(el, { options });
|
|
80
96
|
}));
|
|
81
97
|
|
|
82
|
-
const q = ((
|
|
98
|
+
const q = ((filterState || []).concat(filterCustom || [])).filter((el) => el.name && el.sql).map((el) => `select count(*), '${el.name}' as name from (${optimizedSQL})q where ${el.sql}`).join(' union all ');
|
|
83
99
|
|
|
84
100
|
const { rows = [], timeout: timeout1 } = q ? await pg.queryCache(q) : {};
|
|
85
101
|
if (timeout1) logger.file('timeout/filter', { table: params.table, type: 'state/custom' });
|
|
86
102
|
|
|
87
103
|
if (rows?.length) {
|
|
88
|
-
((
|
|
104
|
+
((filterState || []).concat(filterCustom || [])).filter((el) => el.name && el.sql).forEach((el) => {
|
|
89
105
|
const { count } = rows.find((row) => row.name === el.name) || {};
|
|
90
106
|
Object.assign(el, { count, sql: undefined });
|
|
91
107
|
});
|
|
@@ -105,22 +121,22 @@ export default async function filterAPI(req) {
|
|
|
105
121
|
percentile_disc(0.5) within group (order by ${el.name}),
|
|
106
122
|
percentile_disc(0.75) within group (order by ${el.name}),
|
|
107
123
|
max(${el.name})
|
|
108
|
-
] as range from ${
|
|
109
|
-
{ table
|
|
110
|
-
).then(
|
|
111
|
-
if (
|
|
112
|
-
logger.file('timeout/filter', { table: params.table, type: 'Range', filter:
|
|
113
|
-
return
|
|
124
|
+
] as range from ${table} ${sqlList && false ? ` t ${sqlList}` : ''} where ${tableQuery || '1=1'}`,
|
|
125
|
+
{ table },
|
|
126
|
+
).then(res => {
|
|
127
|
+
if (res.timeout) {
|
|
128
|
+
logger.file('timeout/filter', { table: params.table, type: 'Range', filter: res.name });
|
|
129
|
+
return res;
|
|
114
130
|
}
|
|
115
|
-
return
|
|
131
|
+
return res.rows?.[0]?.range;
|
|
116
132
|
});
|
|
117
133
|
Object.assign(el, { data });
|
|
118
134
|
}));
|
|
119
135
|
|
|
120
|
-
const sqlFilters = (
|
|
121
|
-
const q1 = sqlFilters.map((el) => `select count(*), '${el.name}' as name from ${
|
|
136
|
+
const sqlFilters = (filterCustom || []).filter((el) => el.name && el.sql);
|
|
137
|
+
const q1 = sqlFilters.map((el) => `select count(*), '${el.name}' as name from ${table} where ${tableQuery || '1=1'} and ${el.sql}`).join(' union all ');
|
|
122
138
|
|
|
123
|
-
const { rows: sqlRows = [], timeout } = q1 ? await pg.queryCache(q1, { table
|
|
139
|
+
const { rows: sqlRows = [], timeout } = q1 ? await pg.queryCache(q1, { table }) : {};
|
|
124
140
|
if (timeout) logger.file('timeout/filter', { table: params.table, type: 'sqlFilters' });
|
|
125
141
|
|
|
126
142
|
if (sqlRows?.length) {
|
|
@@ -132,9 +148,9 @@ export default async function filterAPI(req) {
|
|
|
132
148
|
|
|
133
149
|
return {
|
|
134
150
|
time: Date.now() - time,
|
|
135
|
-
list: filters?.map?.(el => ({ ...el, sql: undefined })),
|
|
136
|
-
custom:
|
|
151
|
+
list: filters?.map?.(el => ({ ...el, sql: iscalled ? el.sql : undefined })),
|
|
152
|
+
custom: filterCustom,
|
|
137
153
|
inline: loadTable?.filterInline,
|
|
138
|
-
state:
|
|
154
|
+
state: filterState,
|
|
139
155
|
};
|
|
140
156
|
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
customTokens, userTokens, handlebarsSync, setOpt, getOpt, config,
|
|
3
|
+
} from '../../../../utils.js';
|
|
2
4
|
|
|
3
5
|
export default async function userTokensAPI({ params = {}, user = {} }, reply) {
|
|
4
6
|
if (!user?.uid) {
|
|
@@ -9,6 +11,10 @@ export default async function userTokensAPI({ params = {}, user = {} }, reply) {
|
|
|
9
11
|
return reply.status(400).send('not enough params: token');
|
|
10
12
|
}
|
|
11
13
|
|
|
14
|
+
if (!config.redis) {
|
|
15
|
+
return reply.status(500).send('empty redis');
|
|
16
|
+
}
|
|
17
|
+
|
|
12
18
|
if (!customTokens[params.token]) {
|
|
13
19
|
return reply.status(404).send('token not found');
|
|
14
20
|
}
|
|
@@ -22,7 +28,7 @@ export default async function userTokensAPI({ params = {}, user = {} }, reply) {
|
|
|
22
28
|
const token = setOpt(
|
|
23
29
|
{
|
|
24
30
|
...customTokens[params.token],
|
|
25
|
-
query: handlebarsSync.compile(customTokens[params.token]?.query || 'true')({ user, uid: user.uid })
|
|
31
|
+
query: handlebarsSync.compile(customTokens[params.token]?.query || 'true')({ user, uid: user.uid }),
|
|
26
32
|
},
|
|
27
33
|
user.uid,
|
|
28
34
|
);
|
|
@@ -36,4 +42,4 @@ export default async function userTokensAPI({ params = {}, user = {} }, reply) {
|
|
|
36
42
|
userTokens[user.uid][params.token] = token;
|
|
37
43
|
|
|
38
44
|
return token;
|
|
39
|
-
}
|
|
45
|
+
}
|
|
@@ -6,7 +6,7 @@ async function plugin(app, config = {}) {
|
|
|
6
6
|
const { prefix = '/api' } = config;
|
|
7
7
|
app.get(`${prefix}/next-id`, { config: { policy: ['public'] } }, nextId);
|
|
8
8
|
app.get(`${prefix}/status-monitor`, {}, statusMonitor);
|
|
9
|
-
app.get(`${prefix}/user-tokens/:token`, { config: { policy: ['user'] } }, userTokens);
|
|
9
|
+
app.get(`${prefix}/user-tokens/:token`, { config: { policy: ['user', 'site'] } }, userTokens);
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
export default plugin;
|