@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 +120 -5
- package/diffview.js +1 -1
- package/index.js +3 -3
- package/package.json +1 -1
- package/table-provider.js +32 -4
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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
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 {
|
|
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
|
-
{
|
|
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
|
};
|