@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opengis/fastify-table",
3
- "version": "1.4.24",
3
+ "version": "1.4.26",
4
4
  "type": "module",
5
5
  "description": "core-plugins",
6
6
  "keywords": [
@@ -1,8 +1,14 @@
1
1
  import routeFilter from '../../../routes/table/controllers/filter.js';
2
2
 
3
- export default async function getFilter({ pg, table, filter, custom, state, search, user }) {
3
+ export default async function getFilter({
4
+ pg, table, filter, custom, state, search, user,
5
+ }, reply) {
4
6
  const params = { table };
5
- const query = { filter, custom, state, search };
6
- const result = await routeFilter({ pg, params, query, user });
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 filterList1 = await Promise.all((filterList || (body?.filter_list || [])
89
- .concat(body?.filterInline || [])
90
- .concat(body?.filterCustom || [])
91
- .concat(body?.filterState || [])
92
- .concat(body?.filterList || [])
93
- .concat(body?.filters || [])
94
- )?.filter(el => el.id || el.name)?.map(async (el) => {
95
- el.name = el.name || el.id;
96
-
97
- if (el.name && extraColumns.find(item => item?.name === el?.name)) {
98
- Object.assign(el, { extra: { table: extraDataTable, input: extraColumns.find(item => item?.name === el?.name)?.type } });
99
- }
100
- if (!el?.data) return el;
101
- // const cls = await getTemplate(['cls', 'select'], el.data); // only git cls
102
- const cls = await getSelect(el.data, pg); // git + db cls
103
-
104
- if (Array.isArray(cls?.arr) && cls.arr.length) {
105
- Object.assign(el, { cls: el.data, options: cls, select: `select code, name from admin.cls where parent='${el.data}'` });
106
- }
107
- else if (typeof (cls?.sql || cls) === 'string') {
108
- Object.assign(el, { select: cls?.sql || cls });
109
- }
110
- return el;
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.pk?.[table]) {
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;
@@ -28,6 +28,10 @@ export default async function postTablpostSettingsTableeProperties({
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 {
32
36
  deleted = [],
33
37
  columns = [],
@@ -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?`, { scheme: propertiesSchema }, getSettingsApp);
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
- export default async function filterAPI(req) {
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 sqlTable = loadTable.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('') || '';
16
- const { fields: columns = [] } = await pg.query(`select * from ${loadTable.table} t ${sqlTable} limit 0`);
17
- const { fields = [] } = await pg.query(`select * from ${loadTable.table} t limit 0`);
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 ${loadTable.table} t ${sqlTable} where ${loadTable.query || '1=1'}`.replace(/{{uid}}/g, user?.uid);
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: loadTable.table, columns: filters.filter((el) => columns?.find?.((item) => item?.name === el.name)) })
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 = loadTable?.form ? await getTemplate('form', loadTable.form) : {};
39
- const extraColumns = loadTemplate?.extra ? Object.keys(loadTemplate?.schema || {}).filter(key => !columns.find(col => col.name === key)) : [];
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 || !loadTable.table) return;
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, loadTable.table]);
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: loadTable.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 = ((loadTable?.filterState || []).concat(loadTable?.filterCustom || [])).filter((el) => el.name && el.sql).map((el) => `select count(*), '${el.name}' as name from (${optimizedSQL})q where ${el.sql}`).join(' union all ');
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
- ((loadTable?.filterState || []).concat(loadTable?.filterCustom || [])).filter((el) => el.name && el.sql).forEach((el) => {
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 ${loadTable.table} ${sqlList && false ? ` t ${sqlList}` : ''} where ${loadTable.query || '1=1'}`,
109
- { table: loadTable.table },
110
- ).then(el => {
111
- if (el.timeout) {
112
- logger.file('timeout/filter', { table: params.table, type: 'Range', filter: el.name });
113
- return el;
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 el.rows?.[0]?.range;
131
+ return res.rows?.[0]?.range;
116
132
  });
117
133
  Object.assign(el, { data });
118
134
  }));
119
135
 
120
- const sqlFilters = (loadTable?.filterCustom || []).filter((el) => el.name && el.sql);
121
- const q1 = sqlFilters.map((el) => `select count(*), '${el.name}' as name from ${loadTable.table} where ${loadTable.query || '1=1'} and ${el.sql}`).join(' union all ');
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: loadTable.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: loadTable?.filterCustom,
151
+ list: filters?.map?.(el => ({ ...el, sql: iscalled ? el.sql : undefined })),
152
+ custom: filterCustom,
137
153
  inline: loadTable?.filterInline,
138
- state: loadTable?.filterState,
154
+ state: filterState,
139
155
  };
140
156
  }
@@ -1,4 +1,6 @@
1
- import { customTokens, userTokens, handlebarsSync, setOpt, getOpt } from "../../../../utils.js";
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;