@opengis/fastify-table 1.1.116 → 1.1.118

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/README.md CHANGED
@@ -1,26 +1,87 @@
1
- # fastify-table
2
-
3
- [![NPM version](https://img.shields.io/npm/v/@opengis/fastify-table)](https://www.npmjs.com/package/@opengis/fastify-table)
4
- [![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat)](http://standardjs.com/)
5
-
6
- It standardizes the entire form building process, while taking care of everything from rendering to validation and processing:
7
-
8
- - pg
9
- - redis
10
- - crud
11
-
12
- ## Install
13
-
14
- ```bash
15
- npm i @opengis/fastify-table
16
- ```
17
-
18
- ## Usage
19
-
20
- ```js
21
- fastify.register(import('@opengis/fastify-table'), config);
22
- ```
23
-
24
- ## Documenation
25
-
26
- For a detailed understanding fastify-table, its features, and how to use them, refer to our [Documentation](https://apidocs.softpro.ua/gis.storage/).
1
+ # fastify-table
2
+
3
+ <!-- ![alt text](https://cdn.softpro.ua/data/npm/admin/opengis-admin.png) -->
4
+
5
+ [![NPM version](https://img.shields.io/npm/v/@opengis/fastify-table?style=plain)](https://www.npmjs.com/package/@opengis/fastify-table)
6
+ [![NPM last update](https://img.shields.io/npm/last-update/@opengis/fastify-table?style=plain)]()
7
+ [![NPM downloads](https://img.shields.io/npm/dw/@opengis/fastify-table?style=plain)]()
8
+ [![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=plain)](http://standardjs.com/)
9
+
10
+ This is a backend toolkit for database management and more.
11
+
12
+ ### Why fastify-table?
13
+
14
+ - **Logger** - Monitoring user activity and system status.
15
+ - **Redis cache** - Optimizes web page rendering for lightning-fast performance.
16
+ - **Secure** - Ensures protection against XSS attacks in queries.
17
+ - **SQL Migration** - Automatically adds all necessary tables to your project's database.
18
+
19
+
20
+ ### Features
21
+
22
+ - CRUD
23
+ - cron
24
+ - Logger
25
+ - Redis
26
+ - pg
27
+
28
+ ---
29
+
30
+ ### Install
31
+
32
+ ```bash
33
+ npm i @opengis/fastify-table
34
+ ```
35
+
36
+ ### Usage
37
+
38
+ ```js
39
+ fastify.register(import('@opengis/fastify-table'), config);
40
+ ```
41
+
42
+ ---
43
+
44
+ ### Documenation
45
+
46
+ For a detailed understanding `fastify-table`, its features, and how to use them, refer to our [Documentation](https://apidocs.softpro.ua/fastify-table/).
47
+
48
+ ---
49
+
50
+ ### Technology stack
51
+
52
+ <a href="https://fastify.dev/" target="_blank">
53
+ <img src="https://img.shields.io/badge/Fastify-323330?style=for-the-badge&logo=fastify" /></a>
54
+
55
+ <a href="https://www.postgresql.org/" target="_blank">
56
+ <img src="https://img.shields.io/badge/PostgreSQL-323330?style=for-the-badge&logo=postgresql&logoColor=white" /></a>
57
+
58
+ <a href="https://redis.io/" target="_blank">
59
+ <img src="https://img.shields.io/badge/redis-323330.svg?&style=for-the-badge&logo=redis&logoColor=" /></a>
60
+
61
+ <a href="https://www.npmjs.com/package/pino" target="_blank">
62
+ <img src="https://img.shields.io/badge/pino-323330.svg?&style=for-the-badge&logo=pino&logoColor=" /></a>
63
+
64
+ ---
65
+
66
+ ### Contribute
67
+
68
+ Feel free to contact us through our website [SOFTPRO.UA](https://softpro.ua) or email <info@softpro.ua>
69
+
70
+ - Report bugs
71
+ - Share your ideas
72
+ - Ask questions
73
+
74
+ ### Follow Us
75
+
76
+ [Official site](https://softpro.ua)
77
+
78
+ <p>
79
+ <a href="https://www.instagram.com/gissoftpro/" target="_blank"><img src="https://cdn.softpro.ua/data/npm/instagram.png" alt="Softpro Instagram" title="oftpro Instagram"></a>&nbsp;&nbsp;
80
+ <a href="https://www.facebook.com/gissoftpro" target="_blank"><img src="https://cdn.softpro.ua/data/npm/facebook.png" alt="Softpro Facebook" title="Softpro Facebook"></a>&nbsp;&nbsp;
81
+ <a href="https://t.me/softprogis" target="_blank"><img src="https://cdn.softpro.ua/data/npm/telegram.png" alt="Softpro Telegram" title="Softpro Telegram"></a>&nbsp;&nbsp;
82
+ <a href="https://www.linkedin.com/in/softpro-ukraine-a8876b282/recent-activity/all/" target="_blank"><img src="https://cdn.softpro.ua/data/npm/social/linkedin.png" alt="Softpro Linkedin" title="Softpro LinkedIn"></a>&nbsp;&nbsp;
83
+ </p>
84
+
85
+ ### License
86
+
87
+ Copyright © SOFTPRO. All rights reserved.
package/package.json CHANGED
@@ -1,8 +1,9 @@
1
1
  {
2
2
  "name": "@opengis/fastify-table",
3
- "version": "1.1.116",
3
+ "version": "1.1.118",
4
4
  "type": "module",
5
5
  "description": "core-plugins",
6
+ "keywords": ["fastify", "table", "crud", "pg", "backend" ],
6
7
  "main": "index.js",
7
8
  "files": [
8
9
  "server/*",
@@ -14,10 +14,11 @@ export default async function getMeta(opt) {
14
14
  }
15
15
 
16
16
  const { fields } = await pg.query(`select * from ${table} where $1=$1 limit 0`, [1]);
17
- const { pks1 } = await pg.query(`SELECT json_object_agg(c.conrelid::regclass, a.attname) as pks1 FROM pg_constraint c
18
- left join pg_attribute a on c.conrelid=a.attrelid and a.attnum = c.conkey[1] WHERE c.contype='p'::"char" and c.conrelid::regclass = $1::regclass`, [table]).then(el => el.rows[0]) || {};
17
+ const pks1 = await pg.query(`SELECT json_object_agg(c.conrelid::regclass, a.attname) as pks1 FROM pg_constraint c
18
+ left join pg_attribute a on c.conrelid=a.attrelid and a.attnum = c.conkey[1] WHERE c.contype='p'::"char" and c.conrelid::regclass = $1::regclass`, [table])
19
+ .then(el => el.rows[0]?.pks1 || {});
19
20
 
20
- const pk = table.startsWith('public.') ? pks1?.[table.replace('public.', '')] : pks1?.[table];
21
+ const pk = table.startsWith('public.') ? pks1[table.replace('public.', '')] : pks1[table];
21
22
 
22
23
  const geomAttr = fields.find((el) => pg.pgType[el.dataTypeID] === 'geometry')?.name; // change geometry text to geometry code
23
24
 
@@ -1,3 +1,4 @@
1
+ import config from '../../../../config.js';
1
2
  import xssInjection from '../xssInjection.js';
2
3
 
3
4
  // RTE - rich text editor
@@ -11,9 +12,10 @@ function checkXSS({ body, schema = {} }) {
11
12
  if (stopSpecialSymbols?.length) stopSpecialSymbols?.forEach((el) => stopWords.push(el));
12
13
 
13
14
  // escape arrows on non-RTE
15
+ const skipScreening = config.skipScreening || ['Summernote', 'Tiny', 'Ace', 'Texteditor'];
14
16
  Object.keys(body)
15
17
  .filter((key) => ['<', '>'].find((el) => body[key]?.includes?.(el))
16
- && !['Summernote', 'Tiny', 'Ace', 'Texteditor'].includes(schema?.[key]?.type))
18
+ && !skipScreening.includes(schema?.[key]?.type))
17
19
  ?.forEach((key) => {
18
20
  Object.assign(body, { [key]: body[key].replace(/</g, '&lt;').replace(/>/g, '&gt;') });
19
21
  });
@@ -25,7 +27,7 @@ function checkXSS({ body, schema = {} }) {
25
27
  const disabledCheckFields = Object.keys(schema || {})?.filter((el) => schema?.[el]?.xssCheck === false); // exclude specific columns
26
28
 
27
29
  // check RTE
28
- /* const richTextFields = Object.keys(schema).filter((el) => ['Summernote', 'Tiny', 'Ace'].includes(schema[el]?.type));
30
+ /* const richTextFields = Object.keys(schema).filter((el) => skipScreening.includes(schema[el]?.type));
29
31
  richTextFields.filter((key) => !checkList.find((el) => body[key].includes(el)))?.forEach((key) => {
30
32
  disabledCheckFields.push(key);
31
33
  }); */
@@ -1,5 +1,5 @@
1
1
  import {
2
- config, getPG, getTemplate, getSelectMeta,
2
+ config, getPG, getTemplate, getSelectMeta, getMeta,
3
3
  } from '../../../../utils.js';
4
4
 
5
5
  const limit = 50;
@@ -20,13 +20,16 @@ export default async function suggest(req) {
20
20
 
21
21
  const [table, column] = params.data?.includes(':') ? params.data.split(':') : [];
22
22
  const selectName = query.sel || query.name || params.data;
23
+
23
24
  if (!selectName) return { headers, status: 400, message: 'name is required' };
24
25
 
25
26
  const body = await getTemplate('table', table);
27
+
26
28
  if (table && !pg1.pk[body?.table || table]) {
27
29
  return { headers, status: 400, message: 'param name is invalid: 1' };
28
30
  }
29
31
  const columnExists = body?.columns?.find((col) => col?.name === column);
32
+
30
33
  if (table && (!column || !columnExists)) {
31
34
  return { headers, status: 400, message: 'param name is invalid: 2' };
32
35
  }
@@ -37,12 +40,20 @@ export default async function suggest(req) {
37
40
  searchQuery: '(lower("text") ~ $1 )',
38
41
  }
39
42
  : await getSelectMeta({ name: selectName, nocache: query?.nocache });
43
+
40
44
  if (meta?.minLength && query.key && query.key.length < meta?.minLength) {
41
45
  return { message: `min length: ${meta.minLength}` };
42
46
  }
47
+
43
48
  const pg = meta?.db ? getPG(meta.db) : pg1;
44
- if (!meta) return { headers, status: 404, message: 'Not found query select ' };
45
- if (query.meta) return meta;
49
+
50
+ if (!meta) {
51
+ return { headers, status: 404, message: 'Not found query select ' };
52
+ }
53
+
54
+ if (query.meta) {
55
+ return meta;
56
+ }
46
57
 
47
58
  const { arr, searchQuery } = meta;
48
59
 
@@ -65,8 +76,20 @@ export default async function suggest(req) {
65
76
 
66
77
  const val = query.val ? ` ${meta.pk}=any('{${query.val.replace(/'/g, "''")}}')` : '';
67
78
  const where = [search, val, `${meta.pk} is not null`].filter((el) => el).join(' and ') || 'true';
68
- const sqlSuggest = `with c(id,text) as ( ${meta.original.replace(/{{parent}}/gi, parent)} where ${where} order by 2) select * from c limit ${meta.limit || limit}`.replace(/{{uid}}/g, user?.uid || '0');
69
- if (query.sql && config.local) return sqlSuggest;
79
+
80
+ const loadTable = await getTemplate('table', query.token);
81
+ const { columns = [] } = await getMeta({ table: loadTable?.table || query.token });
82
+
83
+ const filterColumn = query.column ? columns.find(el => el.name === query.column)?.name : null;
84
+ const filter = query.token && pg.pk?.[loadTable?.table || query.token] && filterColumn
85
+ ? `id in (select ${filterColumn} from ${(loadTable?.table || query.token).replace(/'/g, "''")})`
86
+ : 'true';
87
+
88
+ const sqlSuggest = `with c(id,text) as ( ${meta.original.replace(/{{parent}}/gi, parent)} where ${where} order by 2) select * from c where ${filter} limit ${meta.limit || limit}`.replace(/{{uid}}/g, user?.uid || '0');
89
+
90
+ if (query.sql && config.local) {
91
+ return sqlSuggest;
92
+ }
70
93
 
71
94
  // query
72
95
  const { rows: dataNew } = await pg.query(sqlSuggest, query.key ? [`${query.key.toLowerCase()}`] : []);