@opengis/fastify-table 1.4.20 → 1.4.22

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/config.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import dotenv from 'dotenv';
2
+ import path from 'node:path';
2
3
 
3
4
  import { existsSync, readFileSync } from 'node:fs';
4
5
 
@@ -16,19 +17,39 @@ Object.assign(config, {
16
17
  env: process.env?.NODE_ENV || process.argv[2]?.split?.('=')?.pop?.(),
17
18
  });
18
19
 
19
- if (config.env && existsSync(`.env.${config.env}`)) {
20
- const { parsed } = dotenv.config({ path: `.env.${config.env}` });
21
- console.log('start with env:', config.env);
22
-
23
- const obj = unflattenObject(parsed);
24
-
25
- Object.keys(obj)
26
- .filter(key => typeof obj[key] === 'string'
27
- && (obj[key].startsWith('[') || ['true', 'false'].includes(obj[key]))) // json array / boolean
28
- .forEach(key => {
29
- obj[key] = JSON.parse(obj[key]);
30
- });
31
- Object.assign(config, { ...obj });
20
+ function loadEnvConfig() {
21
+ if (config.env && existsSync(`.env.${config.env}`)) {
22
+ const { parsed } = dotenv.config({ path: `.env.${config.env}` });
23
+ if (parsed) {
24
+ console.log('start with env:', config.env);
25
+
26
+ const obj = unflattenObject(parsed);
27
+
28
+ Object.keys(obj || {})
29
+ .filter(key => typeof obj[key] === 'string'
30
+ && (obj[key].startsWith('[') || ['true', 'false'].includes(obj[key]))) // json array / boolean
31
+ .forEach(key => {
32
+ try {
33
+ obj[key] = JSON.parse(obj[key]);
34
+ }
35
+ catch (err) {
36
+ console.warn(`Invalid JSON for key "${key}": ${obj[key]}`);
37
+ }
38
+ });
39
+ if (obj) {
40
+ Object.assign(config, obj);
41
+ console.log('env init success', config.env, config.pg?.database);
42
+ }
43
+ else {
44
+ console.log('env init error', config.env, config.pg?.database);
45
+ }
46
+ }
47
+ else {
48
+ console.error('env init error: malformed file', config.env);
49
+ }
50
+ }
32
51
  }
33
52
 
53
+ loadEnvConfig();
54
+
34
55
  export default config;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opengis/fastify-table",
3
- "version": "1.4.20",
3
+ "version": "1.4.22",
4
4
  "type": "module",
5
5
  "description": "core-plugins",
6
6
  "keywords": [
@@ -11,7 +11,7 @@ import logger from '../../logger/getLogger.js';
11
11
  const rclient = getRedis();
12
12
 
13
13
  export default async function dataDelete({
14
- table, tokenData, referer, id, pg: pg1, uid,
14
+ table: table1, tokenData, referer, id, pg: pg1, uid,
15
15
  }) {
16
16
  const pg = pg1 || getPG({ name: 'client' });
17
17
 
@@ -24,33 +24,67 @@ export default async function dataDelete({
24
24
  pg.pk = pgClients.client?.pk;
25
25
  }
26
26
 
27
- const { pk } = await getMeta({ pg, table })
28
- .catch(err => {
29
- logger.file('crud/delete', {
30
- error: err.toString(), stack: err.stack, table, id, referer, uid,
31
- });
32
- throw new Error(err);
33
- });
34
- const table1 = table.replace(/"/g, '');
27
+ const table = table1.replace(/"/g, '');
28
+
29
+ const { pk } = await getMeta({ pg, table });
30
+
35
31
  if (!pg.tlist?.includes(table1)) return 'table not exist';
32
+
36
33
  const delQuery = `delete from ${table} WHERE ${pk}::text = $1::text returning *`;
37
34
 
38
- const extraRes = await extraData({
39
- table, form: tokenData?.form, id, uid,
40
- }, pg);
35
+ // for transactions
36
+ const isClient = typeof pg.query === 'function' && typeof pg.release === 'function';
37
+ const client = isClient ? pg : await pg.connect();
38
+
39
+ if (!isClient) {
40
+ client.caller = 'dataDelete';
41
+ }
42
+
43
+ if (isClient || !client.pk) {
44
+ client.options = pg.options;
45
+ client.tlist = pg.tlist;
46
+ client.pgType = pg.pgType;
47
+ client.relkinds = pg.relkinds;
48
+ client.pk = pg.pk;
49
+ }
50
+
51
+ try {
52
+ if (client.caller === 'dataDelete') {
53
+ await client.query('begin;');
54
+ }
55
+
56
+ const row = {};
57
+ await extraData({
58
+ table, form: tokenData?.form, id, uid, row,
59
+ }, client);
60
+
61
+ const res = await client.query(delQuery, [id])
62
+ .then(el => (el.rows?.[0] ? { rowCount: 1, ...el.rows[0] } : {}));
63
+
64
+ await logChanges({
65
+ pg: client, table, tokenData, referer, id, uid, type: 'DELETE',
66
+ });
67
+
68
+ if (config.redis) { rclient.incr(`pg:${table}:crud`); }
69
+
70
+ if (client.caller === 'dataDelete') {
71
+ await client.query('commit;');
72
+ }
41
73
 
42
- const res = await pg.query(delQuery, [id])
43
- .catch(err => {
74
+ return { ...res, ...row };
75
+ }
76
+ catch (err) {
44
77
  logger.file('crud/delete', {
45
- error: err.toString(), stack: err.stack, table, id, referer, uid, q: delQuery,
78
+ error: err.toString(), stack: err.stack, table, id, referer, uid, form: tokenData?.form,
46
79
  });
80
+ if (client.caller === 'dataDelete') {
81
+ await client.query('rollback;');
82
+ }
47
83
  throw err;
48
- })
49
- .then(el => (el.rows?.[0] ? { rowCount: 1, ...el.rows[0] } : {}));
50
-
51
- await logChanges({
52
- pg, table, tokenData, referer, id, uid, type: 'DELETE',
53
- });
54
- if (config.redis) { rclient.incr(`pg:${table}:crud`); }
55
- return { ...res, ...extraRes || {} };
84
+ }
85
+ finally {
86
+ if (client.caller === 'dataDelete') {
87
+ await client.query('begin;');
88
+ }
89
+ }
56
90
  }
@@ -15,6 +15,7 @@ export default async function dataInsert({
15
15
  id, table: table1, referer, data, pg: pg1, uid, tokenData = {},
16
16
  }) {
17
17
  const pg = pg1 || getPG({ name: 'client' });
18
+ if (!pg) return null;
18
19
 
19
20
  // pg client single transaction support
20
21
  if (!pg?.pk && config.pg) {
@@ -38,16 +39,24 @@ export default async function dataInsert({
38
39
  if (!insertQuery || !args.length) return null;
39
40
 
40
41
  // for transactions
41
- const client = pg?._connected ? pg : await pg.connect();
42
+ const isClient = typeof pg.query === 'function' && typeof pg.release === 'function';
43
+ const client = isClient ? pg : await pg.connect();
44
+ if (!isClient) {
45
+ client.caller = 'dataInsert';
46
+ }
42
47
 
43
- client.options = pg?.options;
44
- client.tlist = pg?.tlist;
45
- client.pgType = pg?.pgType;
46
- client.relkinds = pg?.relkinds;
47
- client.pk = pg?.pk;
48
+ if (isClient || !client.pk) {
49
+ client.options = pg.options;
50
+ client.tlist = pg.tlist;
51
+ client.pgType = pg.pgType;
52
+ client.relkinds = pg.relkinds;
53
+ client.pk = pg.pk;
54
+ }
48
55
 
49
56
  try {
50
- await client.query('begin;');
57
+ if (client.caller === 'dataInsert') {
58
+ await client.query('begin;');
59
+ }
51
60
  const res = await client.query(insertQuery, args).then(el => el || {});
52
61
 
53
62
  const id1 = res.rows?.[0]?.[pg.pk[table1]];
@@ -98,17 +107,23 @@ export default async function dataInsert({
98
107
  });
99
108
 
100
109
  if (config.redis) { rclient.incr(`pg:${table}:crud`); }
101
- await client.query('commit;');
110
+ if (client.caller === 'dataInsert') {
111
+ await client.query('commit;');
112
+ }
102
113
  return res;
103
114
  }
104
115
  catch (err) {
105
116
  logger.file('crud/insert', {
106
117
  error: err.toString(), stack: err.stack, table, id, referer, uid, form: tokenData?.form,
107
118
  });
108
- await client.query('rollback;');
119
+ if (client.caller === 'dataInsert') {
120
+ await client.query('rollback;');
121
+ }
109
122
  throw err;
110
123
  }
111
124
  finally {
112
- client.release();
125
+ if (client.caller === 'dataInsert') {
126
+ client.release();
127
+ }
113
128
  }
114
129
  }
@@ -29,6 +29,7 @@ export default async function dataUpdate({
29
29
  if (!data || !table || !id) return null;
30
30
 
31
31
  const pg = pg1 || getPG({ name: 'client' });
32
+ if (!pg) return null;
32
33
 
33
34
  // pg client single transaction support
34
35
  if (!pg?.pk && config.pg) {
@@ -75,10 +76,25 @@ export default async function dataUpdate({
75
76
  // console.log(updateQuery, filterValue);
76
77
 
77
78
  // for transactions
78
- const client = pg?._connected ? pg : await pg.connect();
79
+ const isClient = typeof pg.query === 'function' && typeof pg.release === 'function';
80
+ const client = isClient ? pg : await pg.connect();
81
+
82
+ if (!isClient) {
83
+ client.caller = 'dataUpdate';
84
+ }
85
+
86
+ if (isClient || !client.pk) {
87
+ client.options = pg.options;
88
+ client.tlist = pg.tlist;
89
+ client.pgType = pg.pgType;
90
+ client.relkinds = pg.relkinds;
91
+ client.pk = pg.pk;
92
+ }
79
93
 
80
94
  try {
81
- await client.query('begin;');
95
+ if (client.caller === 'dataUpdate') {
96
+ await client.query('begin;');
97
+ }
82
98
  const res = await client.query(updateQuery, [id, ...filterValue])
83
99
  .catch(err => {
84
100
  logger.file('crud/update', {
@@ -145,17 +161,23 @@ export default async function dataUpdate({
145
161
 
146
162
  if (config.redis) { rclient.incr(`pg:${table}:crud`); }
147
163
 
148
- await client.query('commit;');
164
+ if (client.caller === 'dataUpdate') {
165
+ await client.query('commit;');
166
+ }
149
167
  return res || {};
150
168
  }
151
169
  catch (err) {
152
170
  logger.file('crud/update', {
153
171
  error: err.toString(), stack: err.stack, table, id, referer, uid, form: tokenData?.form,
154
172
  });
155
- await client.query('rollback;');
173
+ if (client.caller === 'dataUpdate') {
174
+ await client.query('rollback;');
175
+ }
156
176
  throw err;
157
177
  }
158
178
  finally {
159
- client.release();
179
+ if (client.caller === 'dataUpdate') {
180
+ client.release();
181
+ }
160
182
  }
161
183
  }
@@ -9,7 +9,7 @@ const defaultTable = 'crm.extra_data';
9
9
  function format(key, value, schema) {
10
10
  if (!key || !schema?.[key]) return value;
11
11
  if (schema?.[key]?.type && ['Number', 'Switcher'].includes(schema?.[key]?.type)) {
12
- return JSON.parse(value || null);
12
+ return typeof value === 'string' ? JSON.parse(value) : value;
13
13
  }
14
14
  return value;
15
15
  }
@@ -45,7 +45,9 @@ export default async function extraData({
45
45
  const deleteRes = await pg.query(`delete from ${extraTable} where object_id=$1 and property_key = any($2::text[]) returning *`, [id, Object.keys(loadTemplate?.schema || {})]);
46
46
 
47
47
  if (!data) {
48
- return deleteRes?.rows?.reduce?.((acc, curr) => Object.assign(acc, { [curr.property_key]: format(curr.property_key, curr.value_text, curr.value_array, loadTemplate?.schema) }), {});
48
+ const result = deleteRes?.rows?.reduce?.((acc, curr) => Object.assign(acc, { [curr.property_key]: format(curr.property_key, curr.value_text || curr.value_array, loadTemplate?.schema) }), {}) || {};
49
+ Object.assign(row, result);
50
+ return result;
49
51
  }
50
52
 
51
53
  const rows = Object.keys(data || {})
@@ -70,7 +72,7 @@ export default async function extraData({
70
72
  }));
71
73
 
72
74
  Object.assign(row, {
73
- ...res.reduce((acc, curr) => Object.assign(acc, { [curr.property_key]: format(curr.property_key, curr.value_text, curr.value_array, loadTemplate?.schema) }), {}),
75
+ ...res.reduce((acc, curr) => Object.assign(acc, { [curr.property_key]: format(curr.property_key, curr.value_text || curr.value_array, loadTemplate?.schema) }), {}),
74
76
  id: res?.[0]?.object_id,
75
77
  });
76
78
  return row;
@@ -44,21 +44,9 @@ export default async function extraDataGet({
44
44
  rows.forEach(row => {
45
45
  Object.assign(row, {
46
46
  ...extraRows
47
- .filter(el => el.object_id === row.id)
47
+ .filter(el => el.object_id === row.id && (el.value_text || el.value_array))
48
48
  .reduce((acc, curr) => {
49
- let value = null;
50
-
51
- if (curr.value_text !== null) {
52
- value = curr.value_text;
53
- }
54
- else if (curr.value_array !== null) {
55
- value = curr.value_array;
56
- }
57
-
58
- if (value !== null) {
59
- acc[curr.property_key] = format(curr.property_key, value, loadTemplate?.schema);
60
- }
61
-
49
+ acc[curr.property_key] = format(curr.property_key, curr.value_text || curr.value_array, loadTemplate?.schema);
62
50
  return acc;
63
51
  }, {}),
64
52
  });
@@ -32,7 +32,7 @@ export default async function insert(req, reply) {
32
32
  return reply.status(400).send('invalid token');
33
33
  }
34
34
 
35
- if (!actions.includes('add') && !config.local) {
35
+ if (!actions.includes('add') && !config.local && !tokenData) {
36
36
  return reply.status(403).send('access restricted: actions');
37
37
  }
38
38
 
@@ -36,7 +36,7 @@ export default async function update(req, reply) {
36
36
  return reply.status(400).send('invalid token');
37
37
  }
38
38
 
39
- if (!actions.includes('edit') && !config.local) {
39
+ if (!actions.includes('edit') && !config.local && !tokenData) {
40
40
  return reply.status(403).send('access restricted: actions');
41
41
  }
42
42
 
@@ -13,7 +13,7 @@ export default function checkUserAccess({ user = {}, token }) {
13
13
  return { message: 'access granted', status: 200 };
14
14
  }
15
15
  // console.log(user);
16
- if (user.user_type !== 'admin' && !config?.local && !config.auth?.disable) {
16
+ if (!user.user_type?.includes?.('admin') && !config?.local && !config.auth?.disable) {
17
17
  return { message: 'access restricted', status: 403 };
18
18
  }
19
19