@saltcorn/history-control 0.2.3 → 0.3.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 +51 -0
- package/index.js +35 -0
- package/package.json +1 -1
- package/table-provider.js +4 -49
package/common.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
const Table = require("@saltcorn/data/models/table");
|
|
2
|
+
const db = require("@saltcorn/data/db");
|
|
3
|
+
const { mkWhere } = require("@saltcorn/db-common/internal");
|
|
4
|
+
|
|
5
|
+
const runQuery = async (table, whereFull) => {
|
|
6
|
+
if (whereFull?._fts?.fields) {
|
|
7
|
+
whereFull._fts.fields = whereFull?._fts?.fields.filter(
|
|
8
|
+
(f) => f.name !== "_version_id" && f.name !== "_deleted"
|
|
9
|
+
);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const schemaPrefix = db.getTenantSchemaPrefix();
|
|
13
|
+
const { _is_latest, _deleted, ...whereRest } = whereFull;
|
|
14
|
+
|
|
15
|
+
let { where, values } = mkWhere(whereRest || {});
|
|
16
|
+
where = where.replaceAll('"_version_id"', "(_version || '_' || id)");
|
|
17
|
+
if (_is_latest) {
|
|
18
|
+
where = `${
|
|
19
|
+
where ? where + " and" : "where"
|
|
20
|
+
} h._version = (select max(ih._version) from ${schemaPrefix}"${db.sqlsanitize(
|
|
21
|
+
table.name
|
|
22
|
+
)}__history" ih where ih.id = h.id)`;
|
|
23
|
+
}
|
|
24
|
+
if (_deleted === false || _deleted === "false")
|
|
25
|
+
where = `${
|
|
26
|
+
where ? where + " and " : "where"
|
|
27
|
+
} exists(select id from ${schemaPrefix}"${db.sqlsanitize(
|
|
28
|
+
table.name
|
|
29
|
+
)}" t where t.id = h.id)`;
|
|
30
|
+
else if (_deleted)
|
|
31
|
+
where = `${
|
|
32
|
+
where ? where + " and " : "where"
|
|
33
|
+
} not exists(select id from ${schemaPrefix}"${db.sqlsanitize(
|
|
34
|
+
table.name
|
|
35
|
+
)}" t where t.id = h.id)`;
|
|
36
|
+
|
|
37
|
+
const sql = `select
|
|
38
|
+
_version || '_'|| id as _version_id,
|
|
39
|
+
_version = (select max(ih._version) from ${schemaPrefix}"${db.sqlsanitize(
|
|
40
|
+
table.name
|
|
41
|
+
)}__history" ih where ih.id = h.id) as _is_latest,
|
|
42
|
+
not exists(select id from ${schemaPrefix}"${db.sqlsanitize(
|
|
43
|
+
table.name
|
|
44
|
+
)}" t where t.id = h.id) as _deleted,
|
|
45
|
+
* from ${schemaPrefix}"${db.sqlsanitize(table.name)}__history" h ${
|
|
46
|
+
where.length ? ` ${where}` : ""
|
|
47
|
+
}`;
|
|
48
|
+
return await db.query(sql, values);
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
module.exports = { runQuery };
|
package/index.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
const { features } = require("@saltcorn/data/db/state");
|
|
2
2
|
const Table = require("@saltcorn/data/models/table");
|
|
3
|
+
const Field = require("@saltcorn/data/models/field");
|
|
4
|
+
const { runQuery } = require("./common");
|
|
3
5
|
|
|
4
6
|
// user subscribe action
|
|
5
7
|
const actions = {
|
|
@@ -37,6 +39,7 @@ const actions = {
|
|
|
37
39
|
insRow[field.name] = row[field.name];
|
|
38
40
|
}
|
|
39
41
|
await real_table.insertRow(insRow);
|
|
42
|
+
await undelete_cascaded(real_table, insRow);
|
|
40
43
|
} else {
|
|
41
44
|
const updRow = {};
|
|
42
45
|
for (const field of real_table.fields) {
|
|
@@ -57,6 +60,38 @@ const actions = {
|
|
|
57
60
|
},
|
|
58
61
|
};
|
|
59
62
|
|
|
63
|
+
const undelete_cascaded = async (table, row) => {
|
|
64
|
+
//inbound keys with on cascade delete
|
|
65
|
+
const fields = await Field.find(
|
|
66
|
+
{
|
|
67
|
+
reftable_name: table.name,
|
|
68
|
+
},
|
|
69
|
+
{ cached: true }
|
|
70
|
+
);
|
|
71
|
+
for (const field of fields) {
|
|
72
|
+
const ctable = field.table || Table.findOne({ id: field.table_id });
|
|
73
|
+
if (
|
|
74
|
+
!ctable.versioned ||
|
|
75
|
+
!(
|
|
76
|
+
field.attributes.on_delete_cascade ||
|
|
77
|
+
field.attributes?.on_delete === "Cascade"
|
|
78
|
+
)
|
|
79
|
+
)
|
|
80
|
+
continue;
|
|
81
|
+
|
|
82
|
+
const crows = await runQuery(ctable, { [field.name]: row.id });
|
|
83
|
+
for (const crow of crows.rows) {
|
|
84
|
+
if (crow._deleted && crow._is_latest) {
|
|
85
|
+
const insRow = {};
|
|
86
|
+
for (const cfield of ctable.fields) {
|
|
87
|
+
insRow[cfield.name] = crow[cfield.name];
|
|
88
|
+
}
|
|
89
|
+
await ctable.insertRow(insRow);
|
|
90
|
+
await undelete_cascaded(ctable, insRow);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
};
|
|
60
95
|
module.exports = {
|
|
61
96
|
sc_plugin_api_version: 1,
|
|
62
97
|
actions: features?.table_undo ? actions : undefined,
|
package/package.json
CHANGED
package/table-provider.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
const db = require("@saltcorn/data/db");
|
|
2
1
|
const { eval_expression } = require("@saltcorn/data/models/expression");
|
|
3
2
|
const Workflow = require("@saltcorn/data/models/workflow");
|
|
4
3
|
const Form = require("@saltcorn/data/models/form");
|
|
@@ -8,8 +7,7 @@ const Table = require("@saltcorn/data/models/table");
|
|
|
8
7
|
const { getState } = require("@saltcorn/data/db/state");
|
|
9
8
|
const { mkTable } = require("@saltcorn/markup");
|
|
10
9
|
const { pre, code } = require("@saltcorn/markup/tags");
|
|
11
|
-
const {
|
|
12
|
-
|
|
10
|
+
const { runQuery } = require("./common");
|
|
13
11
|
const configuration_workflow = (req) =>
|
|
14
12
|
new Workflow({
|
|
15
13
|
steps: [
|
|
@@ -35,52 +33,7 @@ const configuration_workflow = (req) =>
|
|
|
35
33
|
},
|
|
36
34
|
],
|
|
37
35
|
});
|
|
38
|
-
const runQuery = async (cfg, whereFull, opts) => {
|
|
39
|
-
if (whereFull?._fts?.fields) {
|
|
40
|
-
whereFull._fts.fields = whereFull?._fts?.fields.filter(
|
|
41
|
-
(f) => f.name !== "_version_id" && f.name !== "_deleted"
|
|
42
|
-
);
|
|
43
|
-
}
|
|
44
|
-
const table = Table.findOne({ name: cfg.table });
|
|
45
|
-
|
|
46
|
-
const schemaPrefix = db.getTenantSchemaPrefix();
|
|
47
|
-
const { _is_latest, _deleted, ...whereRest } = whereFull;
|
|
48
|
-
|
|
49
|
-
let { where, values } = mkWhere(whereRest || {});
|
|
50
36
|
|
|
51
|
-
if (_is_latest) {
|
|
52
|
-
where = `${
|
|
53
|
-
where ? where + " and" : "where"
|
|
54
|
-
} h._version = (select max(ih._version) from ${schemaPrefix}"${db.sqlsanitize(
|
|
55
|
-
table.name
|
|
56
|
-
)}__history" ih where ih.id = h.id)`;
|
|
57
|
-
}
|
|
58
|
-
if (_deleted === false || _deleted === "false")
|
|
59
|
-
where = `${
|
|
60
|
-
where ? where + " and " : "where"
|
|
61
|
-
} exists(select id from ${schemaPrefix}"${db.sqlsanitize(
|
|
62
|
-
table.name
|
|
63
|
-
)}" t where t.id = h.id)`;
|
|
64
|
-
else if (_deleted)
|
|
65
|
-
where = `${
|
|
66
|
-
where ? where + " and " : "where"
|
|
67
|
-
} not exists(select id from ${schemaPrefix}"${db.sqlsanitize(
|
|
68
|
-
table.name
|
|
69
|
-
)}" t where t.id = h.id)`;
|
|
70
|
-
|
|
71
|
-
const sql = `select
|
|
72
|
-
_version || '_'|| id as _version_id,
|
|
73
|
-
_version = (select max(ih._version) from ${schemaPrefix}"${db.sqlsanitize(
|
|
74
|
-
table.name
|
|
75
|
-
)}__history" ih where ih.id = h.id) as _is_latest,
|
|
76
|
-
not exists(select id from ${schemaPrefix}"${db.sqlsanitize(
|
|
77
|
-
table.name
|
|
78
|
-
)}" t where t.id = h.id) as _deleted,
|
|
79
|
-
* from ${schemaPrefix}"${db.sqlsanitize(table.name)}__history" h ${
|
|
80
|
-
where.length ? ` ${where}` : ""
|
|
81
|
-
}`;
|
|
82
|
-
return await db.query(sql, values);
|
|
83
|
-
};
|
|
84
37
|
module.exports = {
|
|
85
38
|
"History for database table": {
|
|
86
39
|
configuration_workflow,
|
|
@@ -112,7 +65,9 @@ module.exports = {
|
|
|
112
65
|
get_table: (cfg) => {
|
|
113
66
|
return {
|
|
114
67
|
getRows: async (where, opts) => {
|
|
115
|
-
const
|
|
68
|
+
const table = Table.findOne({ name: cfg.table });
|
|
69
|
+
|
|
70
|
+
const qres = await runQuery(table, where);
|
|
116
71
|
return qres.rows;
|
|
117
72
|
},
|
|
118
73
|
};
|