@saltcorn/postgres 1.1.4-alpha.0 → 1.1.4-alpha.2

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.
Files changed (2) hide show
  1. package/package.json +2 -2
  2. package/postgres.js +67 -35
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@saltcorn/postgres",
3
- "version": "1.1.4-alpha.0",
3
+ "version": "1.1.4-alpha.2",
4
4
  "description": "Postgres structures for Saltcorn, open-source no-code platform",
5
5
  "homepage": "https://saltcorn.com",
6
6
  "scripts": {
@@ -12,7 +12,7 @@
12
12
  "license": "MIT",
13
13
  "main": "index.js",
14
14
  "dependencies": {
15
- "@saltcorn/db-common": "1.1.4-alpha.0",
15
+ "@saltcorn/db-common": "1.1.4-alpha.2",
16
16
  "pg": "^8.13.1",
17
17
  "pg-copy-streams": "^6.0.6",
18
18
  "replacestream": "4.0.3"
package/postgres.js CHANGED
@@ -17,9 +17,9 @@ const {
17
17
  } = require("@saltcorn/db-common/internal");
18
18
 
19
19
  let getTenantSchema;
20
+ let getRequestContext;
20
21
  let getConnectObject = null;
21
22
  let pool = null;
22
- let client = null;
23
23
 
24
24
  let log_sql_enabled = false;
25
25
 
@@ -74,20 +74,20 @@ const changeConnection = async (connObj = Object.create(null)) => {
74
74
  };
75
75
 
76
76
  const begin = async () => {
77
- client = await getClient();
78
- await client.query("BEGIN");
77
+ //client = await getClient();
78
+ await query("BEGIN");
79
79
  };
80
80
 
81
81
  const commit = async () => {
82
- await client.query("COMMIT");
83
- client.release(true);
84
- client = null;
82
+ await query("COMMIT");
85
83
  };
86
84
 
87
85
  const rollback = async () => {
88
- await client.query("ROLLBACK");
89
- client.release(true);
90
- client = null;
86
+ await query("ROLLBACK");
87
+ };
88
+
89
+ const getMyClient = (selopts) => {
90
+ return selopts?.client || getRequestContext()?.client || pool;
91
91
  };
92
92
 
93
93
  /**
@@ -108,7 +108,7 @@ const select = async (tbl, whereObj, selectopts = Object.create(null)) => {
108
108
  false
109
109
  )}`;
110
110
  sql_log(sql, values);
111
- const tq = await (client || selectopts.client || pool).query(sql, values);
111
+ const tq = await getMyClient(selectopts).query(sql, values);
112
112
 
113
113
  return tq.rows;
114
114
  };
@@ -127,7 +127,7 @@ const drop_reset_schema = async (schema) => {
127
127
  COMMENT ON SCHEMA "${schema}" IS 'standard public schema';`;
128
128
  sql_log(sql);
129
129
 
130
- await pool.query(sql);
130
+ await getMyClient().query(sql);
131
131
  };
132
132
 
133
133
  /**
@@ -152,7 +152,7 @@ const count = async (tbl, whereObj) => {
152
152
  FROM pg_catalog.pg_class c
153
153
  WHERE c.oid = '"${getTenantSchema()}"."${sqlsanitize(tbl)}"'::regclass`;
154
154
  sql_log(sql);
155
- const tq = await (client || pool).query(sql, []);
155
+ const tq = await getMyClient().query(sql, []);
156
156
  const n = +tq.rows[0].int8;
157
157
  if (n && n > 10000) return n;
158
158
  } catch {
@@ -164,7 +164,7 @@ WHERE c.oid = '"${getTenantSchema()}"."${sqlsanitize(tbl)}"'::regclass`;
164
164
  tbl
165
165
  )}" ${where}`;
166
166
  sql_log(sql, values);
167
- const tq = await (client || pool).query(sql, values);
167
+ const tq = await getMyClient().query(sql, values);
168
168
 
169
169
  return parseInt(tq.rows[0].count);
170
170
  };
@@ -177,7 +177,7 @@ WHERE c.oid = '"${getTenantSchema()}"."${sqlsanitize(tbl)}"'::regclass`;
177
177
  const getVersion = async (short) => {
178
178
  const sql = `SELECT version();`;
179
179
  sql_log(sql);
180
- const tq = await pool.query(sql);
180
+ const tq = await getMyClient().query(sql);
181
181
  const v = tq.rows[0].version;
182
182
  if (short) {
183
183
  const ws = v.split(" ");
@@ -200,7 +200,7 @@ const deleteWhere = async (tbl, whereObj, opts = Object.create(null)) => {
200
200
  )}" ${where}`;
201
201
  sql_log(sql, values);
202
202
 
203
- const tq = await (client || opts.client || pool).query(sql, values);
203
+ const tq = await getMyClient(opts).query(sql, values);
204
204
 
205
205
  return tq.rows;
206
206
  };
@@ -209,7 +209,7 @@ const truncate = async (tbl) => {
209
209
  const sql = `truncate "${getTenantSchema()}"."${sqlsanitize(tbl)}"`;
210
210
  sql_log(sql, []);
211
211
 
212
- const tq = await (client || pool).query(sql, []);
212
+ const tq = await getMyClient().query(sql, []);
213
213
 
214
214
  return tq.rows;
215
215
  };
@@ -252,7 +252,7 @@ const insert = async (tbl, obj, opts = Object.create(null)) => {
252
252
  tbl
253
253
  )}" DEFAULT VALUES returning ${opts.noid ? "*" : ppPK(opts.pk_name)}`;
254
254
  sql_log(sql, valList);
255
- const { rows } = await (client || opts.client || pool).query(sql, valList);
255
+ const { rows } = await getMyClient(opts).query(sql, valList);
256
256
  if (opts.noid) return;
257
257
  else if (conflict && rows.length === 0) return;
258
258
  else return rows[0][opts.pk_name || "id"];
@@ -280,7 +280,7 @@ const update = async (tbl, obj, id, opts = Object.create(null)) => {
280
280
  tbl
281
281
  )}" set ${assigns} where ${ppPK(opts.pk_name)}=$${kvs.length + 1}`;
282
282
  sql_log(q, valList);
283
- await (client || opts.client || pool).query(q, valList);
283
+ await getMyClient(opts).query(q, valList);
284
284
  };
285
285
 
286
286
  /**
@@ -304,7 +304,7 @@ const updateWhere = async (tbl, obj, whereObj, opts = Object.create(null)) => {
304
304
  tbl
305
305
  )}" set ${assigns} ${where}`;
306
306
  sql_log(q, valList);
307
- await (client || opts.client || pool).query(q, valList);
307
+ await getMyClient().query(q, valList);
308
308
  };
309
309
 
310
310
  /**
@@ -356,7 +356,7 @@ const reset_sequence = async (tblname, pkname = "id") => {
356
356
  )}"', '${pkname}'), coalesce(max("${pkname}"),0) + 1, false) FROM "${getTenantSchema()}"."${sqlsanitize(
357
357
  tblname
358
358
  )}";`;
359
- await (client || pool).query(sql);
359
+ await getMyClient().query(sql);
360
360
  };
361
361
 
362
362
  /**
@@ -375,7 +375,7 @@ const add_unique_constraint = async (table_name, field_names) => {
375
375
  .map((f) => `"${sqlsanitize(f)}"`)
376
376
  .join(",")});`;
377
377
  sql_log(sql);
378
- await pool.query(sql);
378
+ await getMyClient().query(sql);
379
379
  };
380
380
 
381
381
  /**
@@ -392,7 +392,7 @@ const drop_unique_constraint = async (table_name, field_names) => {
392
392
  .map((f) => sqlsanitize(f))
393
393
  .join("_")}_unique";`;
394
394
  sql_log(sql);
395
- await pool.query(sql);
395
+ await getMyClient().query(sql);
396
396
  };
397
397
 
398
398
  /**
@@ -409,7 +409,7 @@ const add_index = async (table_name, field_name) => {
409
409
  table_name
410
410
  )}" ("${sqlsanitize(field_name)}");`;
411
411
  sql_log(sql);
412
- await pool.query(sql);
412
+ await getMyClient().query(sql);
413
413
  };
414
414
 
415
415
  /**
@@ -428,7 +428,7 @@ const add_fts_index = async (table_name, field_expression, language) => {
428
428
  language || "english"
429
429
  }', ${field_expression}));`;
430
430
  sql_log(sql);
431
- await pool.query(sql);
431
+ await getMyClient().query(sql);
432
432
  };
433
433
  const drop_fts_index = async (table_name) => {
434
434
  // TBD check that there are no problems with lenght of constraint name
@@ -436,7 +436,7 @@ const drop_fts_index = async (table_name) => {
436
436
  table_name
437
437
  )}_fts_index";`;
438
438
  sql_log(sql);
439
- await pool.query(sql);
439
+ await getMyClient().query(sql);
440
440
  };
441
441
 
442
442
  /**
@@ -451,7 +451,7 @@ const drop_index = async (table_name, field_name) => {
451
451
  table_name
452
452
  )}_${sqlsanitize(field_name)}_index";`;
453
453
  sql_log(sql);
454
- await pool.query(sql);
454
+ await getMyClient().query(sql);
455
455
  };
456
456
 
457
457
  /**
@@ -477,7 +477,7 @@ const copyToJson = async (fileStream, tableName, client) => {
477
477
  const sql = `COPY (SELECT (row_to_json("${sqlsanitize(tableName)}".*) || ',')
478
478
  FROM "${getTenantSchema()}"."${sqlsanitize(tableName)}") TO STDOUT`;
479
479
  sql_log(sql);
480
- const stream = (client || pool).query(copyStreams.to(sql));
480
+ const stream = (client || getMyClient()).query(copyStreams.to(sql));
481
481
 
482
482
  return await pipeline(stream, replace("\\\\", "\\"), fileStream);
483
483
  };
@@ -489,7 +489,7 @@ const slugify = (s) =>
489
489
  .replace(/[^\w-]/g, "");
490
490
 
491
491
  const time = async () => {
492
- const result = await (client || pool).query("select now()");
492
+ const result = await getMyClient().query("select now()");
493
493
  const row = result.rows[0];
494
494
  return new Date(row.now);
495
495
  };
@@ -499,7 +499,7 @@ const time = async () => {
499
499
  * @returns
500
500
  */
501
501
  const listTables = async () => {
502
- const tq = await pool.query(
502
+ const tq = await getMyClient().query(
503
503
  `SELECT table_name FROM information_schema.tables WHERE table_schema = '${getTenantSchema()}'`
504
504
  );
505
505
  return tq.rows.map((row) => {
@@ -512,7 +512,7 @@ const listTables = async () => {
512
512
  * @returns
513
513
  */
514
514
  const listUserDefinedTables = async () => {
515
- const tq = await pool.query(
515
+ const tq = await getMyClient().query(
516
516
  `SELECT table_name FROM information_schema.tables WHERE table_schema = '${getTenantSchema()}' AND table_name NOT LIKE '_sc_%'`
517
517
  );
518
518
  return tq.rows.map((row) => {
@@ -525,7 +525,7 @@ const listUserDefinedTables = async () => {
525
525
  * @returns
526
526
  */
527
527
  const listScTables = async () => {
528
- const tq = await pool.query(
528
+ const tq = await getMyClient().query(
529
529
  `SELECT table_name FROM information_schema.tables WHERE table_schema = '${getTenantSchema()}' AND table_name LIKE '_sc_%'`
530
530
  );
531
531
  return tq.rows.map((row) => {
@@ -533,6 +533,37 @@ const listScTables = async () => {
533
533
  });
534
534
  };
535
535
 
536
+ /* rules of using this:
537
+
538
+ - no try catch inside unless you rethrow: wouldnt roll back
539
+ - no res.json, res.redirect etc inside (client is released on res finish event)
540
+ - no state.refresh_*() inside: other works wouldnt see updates as they are in transactioon
541
+ - you can use state.refresh_*(true) for update on own worker only
542
+
543
+ */
544
+ const withTransaction = async (f, onError) => {
545
+ await query("BEGIN;");
546
+ let aborted = false;
547
+ const rollback = async () => {
548
+ aborted = true;
549
+ await query("ROLLBACK;");
550
+ };
551
+ try {
552
+ const result = await f(rollback);
553
+ if (!aborted) await query("COMMIT;");
554
+ return result;
555
+ } catch (error) {
556
+ if (!aborted) await query("ROLLBACK;");
557
+ if (onError) return onError(error);
558
+ else throw error;
559
+ }
560
+ };
561
+
562
+ const query = (text, params) => {
563
+ sql_log(text, params);
564
+ return getMyClient().query(text, params);
565
+ };
566
+
536
567
  const postgresExports = {
537
568
  pool,
538
569
  /**
@@ -540,10 +571,7 @@ const postgresExports = {
540
571
  * @param {object} params
541
572
  * @returns {object}
542
573
  */
543
- query: (text, params) => {
544
- sql_log(text, params);
545
- return (client || pool).query(text, params);
546
- },
574
+ query,
547
575
  begin,
548
576
  commit,
549
577
  rollback,
@@ -579,6 +607,7 @@ const postgresExports = {
579
607
  listScTables,
580
608
  listUserDefinedTables,
581
609
  truncate,
610
+ withTransaction,
582
611
  };
583
612
 
584
613
  module.exports = (getConnectObjectPara) => {
@@ -590,6 +619,9 @@ module.exports = (getConnectObjectPara) => {
590
619
  getTenantSchema = require("@saltcorn/db-common/tenants")(
591
620
  connectObj
592
621
  ).getTenantSchema;
622
+ getRequestContext = require("@saltcorn/db-common/tenants")(
623
+ connectObj
624
+ ).getRequestContext;
593
625
  postgresExports.pool = pool;
594
626
  } else {
595
627
  throw new Error("Unable to retrieve a database connection object.");