@saltcorn/history-control 0.3.1 → 0.4.1

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/common.js CHANGED
@@ -2,7 +2,7 @@ const Table = require("@saltcorn/data/models/table");
2
2
  const db = require("@saltcorn/data/db");
3
3
  const { mkWhere } = require("@saltcorn/db-common/internal");
4
4
 
5
- const runQuery = async (table, whereFull) => {
5
+ const get_where_vals = (table_name, whereFull) => {
6
6
  if (whereFull?._fts?.fields) {
7
7
  whereFull._fts.fields = whereFull?._fts?.fields.filter(
8
8
  (f) => f.name !== "_version_id" && f.name !== "_deleted"
@@ -18,22 +18,28 @@ const runQuery = async (table, whereFull) => {
18
18
  where = `${
19
19
  where ? where + " and" : "where"
20
20
  } h._version = (select max(ih._version) from ${schemaPrefix}"${db.sqlsanitize(
21
- table.name
21
+ table_name
22
22
  )}__history" ih where ih.id = h.id)`;
23
23
  }
24
24
  if (_deleted === false || _deleted === "false")
25
25
  where = `${
26
26
  where ? where + " and " : "where"
27
27
  } exists(select id from ${schemaPrefix}"${db.sqlsanitize(
28
- table.name
28
+ table_name
29
29
  )}" t where t.id = h.id)`;
30
30
  else if (_deleted)
31
31
  where = `${
32
32
  where ? where + " and " : "where"
33
33
  } not exists(select id from ${schemaPrefix}"${db.sqlsanitize(
34
- table.name
34
+ table_name
35
35
  )}" t where t.id = h.id)`;
36
36
 
37
+ return { where, values };
38
+ };
39
+
40
+ const runQuery = async (table, whereFull, opts) => {
41
+ const schemaPrefix = db.getTenantSchemaPrefix();
42
+ const { where, values } = get_where_vals(table.name, whereFull);
37
43
  const sql = `select
38
44
  _version || '_'|| id as _version_id,
39
45
  _version = (select max(ih._version) from ${schemaPrefix}"${db.sqlsanitize(
@@ -44,8 +50,117 @@ const runQuery = async (table, whereFull) => {
44
50
  )}" t where t.id = h.id) as _deleted,
45
51
  * from ${schemaPrefix}"${db.sqlsanitize(table.name)}__history" h ${
46
52
  where.length ? ` ${where}` : ""
53
+ }${
54
+ opts.orderBy && opts.orderBy !== "_version_id"
55
+ ? ` order by "${db.sqlsanitize(opts.orderBy)}"${
56
+ opts.orderDesc ? " DESC" : ""
57
+ }`
58
+ : ""
59
+ }${opts.limit ? ` limit ${+opts.limit}` : ""}${
60
+ opts.offset ? ` offset ${+opts.offset}` : ""
47
61
  }`;
48
62
  return await db.query(sql, values);
49
63
  };
50
64
 
51
- module.exports = { runQuery };
65
+ const updateRow = async (table_name, update_in, version_id) => {
66
+ const { _version_id, _is_latest, _deleted, ...update } = update_in;
67
+ const schemaPrefix = db.getTenantSchemaPrefix();
68
+ const sqlParts = [],
69
+ values = [];
70
+ const nkeys = Object.keys(update).length;
71
+ const [version, id] = version_id.split("_");
72
+ Object.entries(update).forEach(([k, v], ix) => {
73
+ sqlParts.push(`"${db.sqlsanitize(k)}"=$${ix + 1}`);
74
+ values.push(v);
75
+ });
76
+ values.push(version);
77
+ values.push(id);
78
+ const sql = `update ${schemaPrefix}"${db.sqlsanitize(
79
+ table_name
80
+ )}__history" SET ${sqlParts.join()} where _version = $${
81
+ nkeys + 1
82
+ } and id = $${nkeys + 2}`;
83
+ await db.query(sql, values);
84
+ return {};
85
+ };
86
+
87
+ const insertRow = async (table, rec_in) => {
88
+ const { _is_latest, _deleted, _version_id, ...rec } = rec_in;
89
+ const kvs = Object.entries(rec);
90
+ const fnameList = kvs.map(([k, v]) => `"${db.sqlsanitize(k)}"`).join();
91
+ var valPosList = [];
92
+ var valList = [];
93
+ const schemaPrefix = db.getTenantSchemaPrefix();
94
+
95
+ kvs.forEach(([k, v]) => {
96
+ valList.push(v);
97
+ valPosList.push(`$${valList.length}`);
98
+ });
99
+ const sql =
100
+ valPosList.length > 0
101
+ ? `insert into ${schemaPrefix}"${db.sqlsanitize(
102
+ table.name
103
+ )}__history"(${fnameList}) values(${valPosList.join()}) returning "${
104
+ table.pk_name || "id"
105
+ }"`
106
+ : `insert into ${schemaPrefix}"${db.sqlsanitize(
107
+ table.name
108
+ )}" DEFAULT VALUES returning "${table.pk_name || "id"}"`;
109
+ const { rows } = await db.query(sql, valList);
110
+ return rows[0][table.pk_name || "id"];
111
+ };
112
+
113
+ const countRows = async (table_name, whereFull) => {
114
+ const schemaPrefix = db.getTenantSchemaPrefix();
115
+ const { where, values } = get_where_vals(table_name, whereFull);
116
+ const sql = `select count(*) from ${schemaPrefix}"${db.sqlsanitize(
117
+ table_name
118
+ )}__history" h ${where.length ? ` ${where}` : ""}`;
119
+ const { rows } = await db.query(sql, values);
120
+ //console.log(rows);
121
+ return +rows?.[0]?.count;
122
+ };
123
+
124
+ const deleteRows = async (table_name, whereFull) => {
125
+ const schemaPrefix = db.getTenantSchemaPrefix();
126
+ const { where, values } = get_where_vals(table_name, whereFull);
127
+ const sql = `delete from ${schemaPrefix}"${db.sqlsanitize(
128
+ table_name
129
+ )}__history" h ${where.length ? ` ${where}` : ""}`;
130
+ await db.query(sql, values);
131
+ };
132
+
133
+ const distinctValues = async (table_name, fieldnm, whereObj) => {
134
+ const schemaPrefix = db.getTenantSchemaPrefix();
135
+
136
+ if (whereObj) {
137
+ const { where, values } = mkWhere(whereObj, db.isSQLite);
138
+ const res = await db.query(
139
+ `select distinct "${db.sqlsanitize(
140
+ fieldnm
141
+ )}" from ${schemaPrefix}"${db.sqlsanitize(
142
+ table_name
143
+ )}__history" ${where} order by "${db.sqlsanitize(fieldnm)}"`,
144
+ values
145
+ );
146
+ return res.rows.map((r) => r[fieldnm]);
147
+ } else {
148
+ const res = await db.query(
149
+ `select distinct "${db.sqlsanitize(
150
+ fieldnm
151
+ )}" from ${schemaPrefix}"${db.sqlsanitize(
152
+ table_name
153
+ )}__history" order by "${db.sqlsanitize(fieldnm)}"`
154
+ );
155
+ return res.rows.map((r) => r[fieldnm]);
156
+ }
157
+ };
158
+
159
+ module.exports = {
160
+ runQuery,
161
+ countRows,
162
+ deleteRows,
163
+ updateRow,
164
+ insertRow,
165
+ distinctValues,
166
+ };
package/diffview.js CHANGED
@@ -125,7 +125,7 @@ const run = async (
125
125
  const oldH = cmpMode === "Latest" ? row[diff_field] : cmpTo[diff_field];
126
126
  const newH = cmpMode === "Latest" ? cmpTo[diff_field] : row[diff_field];
127
127
  diff_html = HtmlDiff.default.execute(oldH, newH);
128
- console.log({ oldH, newH, diff_html });
128
+ //console.log({ oldH, newH, diff_html });
129
129
  }
130
130
  }
131
131
 
package/index.js CHANGED
@@ -9,7 +9,7 @@ const actions = {
9
9
  requireRow: true,
10
10
  run: async ({ table, row, user }) => {
11
11
  if (!table.versioned) return { error: "History not enabled for table" };
12
- await table.undo_row_changes(row.id, user);
12
+ await table.undo_row_changes(row[table.pk_name], user);
13
13
  return { reload_page: true };
14
14
  },
15
15
  },
@@ -17,7 +17,7 @@ const actions = {
17
17
  requireRow: true,
18
18
  run: async ({ table, row, user }) => {
19
19
  if (!table.versioned) return { error: "History not enabled for table" };
20
- await table.redo_row_changes(row.id, user);
20
+ await table.redo_row_changes(row[table.pk_name], user);
21
21
  return { reload_page: true };
22
22
  },
23
23
  },
@@ -79,7 +79,7 @@ const undelete_cascaded = async (table, row) => {
79
79
  )
80
80
  continue;
81
81
 
82
- const crows = await runQuery(ctable, { [field.name]: row.id });
82
+ const crows = await runQuery(ctable, { [field.name]: row[table.pk_name] });
83
83
  for (const crow of crows.rows) {
84
84
  if (crow._deleted && crow._is_latest) {
85
85
  const insRow = {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@saltcorn/history-control",
3
- "version": "0.3.1",
3
+ "version": "0.4.1",
4
4
  "description": "Allow users to interact with row history",
5
5
  "main": "index.js",
6
6
  "dependencies": {
package/table-provider.js CHANGED
@@ -7,7 +7,14 @@ const Table = require("@saltcorn/data/models/table");
7
7
  const { getState } = require("@saltcorn/data/db/state");
8
8
  const { mkTable } = require("@saltcorn/markup");
9
9
  const { pre, code } = require("@saltcorn/markup/tags");
10
- const { runQuery } = require("./common");
10
+ const {
11
+ runQuery,
12
+ countRows,
13
+ deleteRows,
14
+ updateRow,
15
+ insertRow,
16
+ distinctValues,
17
+ } = require("./common");
11
18
  const configuration_workflow = (req) =>
12
19
  new Workflow({
13
20
  steps: [
@@ -42,7 +49,12 @@ module.exports = {
42
49
 
43
50
  const table = Table.findOne({ name: cfg.table });
44
51
  return [
45
- { name: "_version_id", type: "String", primary_key: true },
52
+ {
53
+ name: "_version_id",
54
+ type: "String",
55
+ primary_key: true,
56
+ is_unique: true,
57
+ },
46
58
  ...table.fields.map((f) => {
47
59
  f.primary_key = false;
48
60
  f.validator = undefined;
@@ -64,10 +76,26 @@ module.exports = {
64
76
  },
65
77
  get_table: (cfg) => {
66
78
  return {
79
+ disableFiltering: true,
80
+ deleteRows: async (where, user) => {
81
+ return await deleteRows(cfg.table, where, user);
82
+ },
83
+ updateRow: async (update, version_id, user) => {
84
+ return await updateRow(cfg.table, update, version_id);
85
+ },
86
+ insertRow: async (rec, user) => {
87
+ const table = Table.findOne({ name: cfg.table });
88
+ return await insertRow(table, rec);
89
+ },
90
+ countRows: async (where, opts) => {
91
+ return await countRows(cfg.table, where || {});
92
+ },
93
+ distinctValues: async (fldNm, opts) => {
94
+ return await distinctValues(cfg.table, fldNm, opts);
95
+ },
67
96
  getRows: async (where, opts) => {
68
97
  const table = Table.findOne({ name: cfg.table });
69
-
70
- const qres = await runQuery(table, where);
98
+ const qres = await runQuery(table, where, opts);
71
99
  return qres.rows;
72
100
  },
73
101
  };