@saltcorn/data 0.8.8-beta.1 → 0.8.8-beta.3
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/dist/base-plugin/actions.js +2 -2
- package/dist/base-plugin/actions.js.map +1 -1
- package/dist/base-plugin/fieldviews.js +1 -1
- package/dist/base-plugin/fieldviews.js.map +1 -1
- package/dist/base-plugin/index.d.ts +87 -87
- package/dist/base-plugin/types.d.ts.map +1 -1
- package/dist/base-plugin/types.js +1 -0
- package/dist/base-plugin/types.js.map +1 -1
- package/dist/base-plugin/viewtemplates/edit.d.ts.map +1 -1
- package/dist/base-plugin/viewtemplates/edit.js +14 -1
- package/dist/base-plugin/viewtemplates/edit.js.map +1 -1
- package/dist/base-plugin/viewtemplates/filter.js +1 -1
- package/dist/base-plugin/viewtemplates/filter.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/migrations/202308211648.d.ts +2 -0
- package/dist/migrations/202308211648.d.ts.map +1 -0
- package/dist/migrations/202308211648.js +4 -0
- package/dist/migrations/202308211648.js.map +1 -0
- package/dist/models/expression.d.ts +1 -1
- package/dist/models/expression.d.ts.map +1 -1
- package/dist/models/expression.js +17 -3
- package/dist/models/expression.js.map +1 -1
- package/dist/models/index.d.ts +2 -2
- package/dist/models/index.d.ts.map +1 -1
- package/dist/models/page.d.ts.map +1 -1
- package/dist/models/page.js +7 -1
- package/dist/models/page.js.map +1 -1
- package/dist/models/plugin.js +1 -1
- package/dist/models/plugin.js.map +1 -1
- package/dist/models/table.d.ts +85 -6
- package/dist/models/table.d.ts.map +1 -1
- package/dist/models/table.js +216 -24
- package/dist/models/table.js.map +1 -1
- package/dist/models/table_constraints.d.ts.map +1 -1
- package/dist/models/table_constraints.js +19 -4
- package/dist/models/table_constraints.js.map +1 -1
- package/dist/models/view.js +1 -1
- package/dist/models/view.js.map +1 -1
- package/dist/plugin-helper.d.ts.map +1 -1
- package/dist/plugin-helper.js +35 -29
- package/dist/plugin-helper.js.map +1 -1
- package/dist/tests/table.test.js +22 -0
- package/dist/tests/table.test.js.map +1 -1
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +3 -1
- package/dist/utils.js.map +1 -1
- package/package.json +7 -7
package/dist/models/table.js
CHANGED
|
@@ -42,10 +42,10 @@ const csvtojson_1 = __importDefault(require("csvtojson"));
|
|
|
42
42
|
const moment_1 = __importDefault(require("moment"));
|
|
43
43
|
const fs_1 = require("fs");
|
|
44
44
|
const promises_1 = require("fs/promises");
|
|
45
|
-
const utils_1 = __importDefault(require("../utils"));
|
|
46
45
|
//import { num_between } from "@saltcorn/types/generators";
|
|
47
46
|
//import { devNull } from "os";
|
|
48
|
-
const
|
|
47
|
+
const utils_1 = __importDefault(require("../utils"));
|
|
48
|
+
const { prefixFieldsInWhere, InvalidConfiguration, InvalidAdminAction, satisfies, structuredClone, getLines, mergeIntoWhere, stringToJSON, isNode, } = utils_1.default;
|
|
49
49
|
const tags_1 = __importDefault(require("@saltcorn/markup/tags"));
|
|
50
50
|
const { text } = tags_1.default;
|
|
51
51
|
/**
|
|
@@ -111,6 +111,7 @@ class Table {
|
|
|
111
111
|
this.ownership_field_id = o.ownership_field_id;
|
|
112
112
|
this.ownership_formula = o.ownership_formula;
|
|
113
113
|
this.versioned = !!o.versioned;
|
|
114
|
+
this.has_sync_info = !!o.has_sync_info;
|
|
114
115
|
this.is_user_group = !!o.is_user_group;
|
|
115
116
|
this.external = false;
|
|
116
117
|
this.description = o.description;
|
|
@@ -233,6 +234,11 @@ class Table {
|
|
|
233
234
|
}
|
|
234
235
|
return [...dbs, ...externals];
|
|
235
236
|
}
|
|
237
|
+
/**
|
|
238
|
+
* Get Models
|
|
239
|
+
* tbd why this function in this file - needs to models
|
|
240
|
+
* @param opts
|
|
241
|
+
*/
|
|
236
242
|
async get_models(opts) {
|
|
237
243
|
const Model = require("./model");
|
|
238
244
|
if (typeof opts === "string")
|
|
@@ -281,6 +287,10 @@ class Table {
|
|
|
281
287
|
return user && user.id && row && `${row.id}` === `${user.id}`;
|
|
282
288
|
return typeof field_name === "string" && row[field_name] === user.id;
|
|
283
289
|
}
|
|
290
|
+
/**
|
|
291
|
+
* get Ownership options
|
|
292
|
+
* user interface...
|
|
293
|
+
*/
|
|
284
294
|
async ownership_options() {
|
|
285
295
|
const fields = this.fields;
|
|
286
296
|
//start with userfields
|
|
@@ -391,6 +401,9 @@ class Table {
|
|
|
391
401
|
}
|
|
392
402
|
return opts;
|
|
393
403
|
}
|
|
404
|
+
/**
|
|
405
|
+
* get sanitized name of table
|
|
406
|
+
*/
|
|
394
407
|
get santized_name() {
|
|
395
408
|
return (0, internal_1.sqlsanitize)(this.name);
|
|
396
409
|
}
|
|
@@ -461,8 +474,10 @@ class Table {
|
|
|
461
474
|
}
|
|
462
475
|
/**
|
|
463
476
|
* Drop current table
|
|
477
|
+
* @param only_forget boolean - if true that only
|
|
464
478
|
* @returns {Promise<void>}
|
|
465
479
|
*/
|
|
480
|
+
// tbd check all other tables related to table description
|
|
466
481
|
async delete(only_forget = false) {
|
|
467
482
|
const schema = db_1.default.getTenantSchemaPrefix();
|
|
468
483
|
const is_sqlite = db_1.default.isSQLite;
|
|
@@ -470,12 +485,16 @@ class Table {
|
|
|
470
485
|
const client = is_sqlite ? db_1.default : await db_1.default.getClient();
|
|
471
486
|
await client.query(`BEGIN`);
|
|
472
487
|
try {
|
|
488
|
+
// drop table
|
|
473
489
|
if (!only_forget)
|
|
474
490
|
await client.query(`drop table if exists ${schema}"${(0, internal_1.sqlsanitize)(this.name)}"`);
|
|
491
|
+
// delete fields
|
|
475
492
|
await client.query(`delete FROM ${schema}_sc_fields WHERE table_id = $1`, [this.id]);
|
|
493
|
+
// delete table description
|
|
476
494
|
await client.query(`delete FROM ${schema}_sc_tables WHERE id = $1`, [
|
|
477
495
|
this.id,
|
|
478
496
|
]);
|
|
497
|
+
// delete versioned table
|
|
479
498
|
if (this.versioned)
|
|
480
499
|
await client.query(`drop table if exists ${schema}"${(0, internal_1.sqlsanitize)(this.name)}__history"`);
|
|
481
500
|
await client.query(`COMMIT`);
|
|
@@ -491,12 +510,15 @@ class Table {
|
|
|
491
510
|
await require("../db/state").getState().refresh_tables();
|
|
492
511
|
}
|
|
493
512
|
/***
|
|
494
|
-
*
|
|
513
|
+
* Get Table SQL Name
|
|
495
514
|
* @type {string}
|
|
496
515
|
*/
|
|
497
516
|
get sql_name() {
|
|
498
517
|
return `${db_1.default.getTenantSchemaPrefix()}"${(0, internal_1.sqlsanitize)(this.name)}"`;
|
|
499
518
|
}
|
|
519
|
+
/**
|
|
520
|
+
* Reset Sequence
|
|
521
|
+
*/
|
|
500
522
|
async resetSequence() {
|
|
501
523
|
const fields = this.fields;
|
|
502
524
|
const pk = fields.find((f) => f.primary_key);
|
|
@@ -508,6 +530,13 @@ class Table {
|
|
|
508
530
|
pk.type.name === "Integer")
|
|
509
531
|
await db_1.default.reset_sequence(this.name);
|
|
510
532
|
}
|
|
533
|
+
/**
|
|
534
|
+
* update Where with Ownership
|
|
535
|
+
* @param where
|
|
536
|
+
* @param fields
|
|
537
|
+
* @param user
|
|
538
|
+
* @param forRead
|
|
539
|
+
*/
|
|
511
540
|
updateWhereWithOwnership(where, fields, user, forRead) {
|
|
512
541
|
const role = user?.role_id;
|
|
513
542
|
const min_role = forRead ? this.min_role_read : this.min_role_write;
|
|
@@ -524,13 +553,31 @@ class Table {
|
|
|
524
553
|
});
|
|
525
554
|
}
|
|
526
555
|
}
|
|
556
|
+
async addDeleteSyncInfo(ids, timestamp) {
|
|
557
|
+
if (ids.length > 0) {
|
|
558
|
+
const schema = db_1.default.getTenantSchemaPrefix();
|
|
559
|
+
const pkName = this.pk_name;
|
|
560
|
+
if (isNode()) {
|
|
561
|
+
await db_1.default.query(`delete from ${schema}${db_1.default.sqlsanitize(this.name)}_sync_info where ref in (
|
|
562
|
+
${ids.map((row) => row[pkName]).join(",")})`);
|
|
563
|
+
await db_1.default.query(`insert into ${schema}${db_1.default.sqlsanitize(this.name)}_sync_info values ${ids
|
|
564
|
+
.map((row) => `(${row[pkName]}, date_trunc('milliseconds', to_timestamp( ${timestamp.valueOf() / 1000.0} ) ), true)`)
|
|
565
|
+
.join(",")}`);
|
|
566
|
+
}
|
|
567
|
+
else {
|
|
568
|
+
await db_1.default.query(`update ${db_1.default.sqlsanitize(this.name)}_sync_info
|
|
569
|
+
set deleted = true, modified_local = true
|
|
570
|
+
where ref in (${ids.map((row) => row[pkName]).join(",")})`);
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
}
|
|
527
574
|
/**
|
|
528
575
|
* Delete rows from table
|
|
529
576
|
* @param where - condition
|
|
530
577
|
* @param user - optional user, if null then no authorization will be checked
|
|
531
578
|
* @returns
|
|
532
579
|
*/
|
|
533
|
-
async deleteRows(where, user) {
|
|
580
|
+
async deleteRows(where, user, noTrigger) {
|
|
534
581
|
// get triggers on delete
|
|
535
582
|
const triggers = await trigger_1.default.getTableTriggers("Delete", this);
|
|
536
583
|
const fields = this.fields;
|
|
@@ -548,7 +595,7 @@ class Table {
|
|
|
548
595
|
}
|
|
549
596
|
const deleteFileFields = fields.filter((f) => f.type === "File" && f.attributes?.also_delete_file);
|
|
550
597
|
const deleteFiles = [];
|
|
551
|
-
if (triggers.length > 0 || deleteFileFields.length > 0) {
|
|
598
|
+
if ((triggers.length > 0 || deleteFileFields.length > 0) && !noTrigger) {
|
|
552
599
|
const File = require("./file");
|
|
553
600
|
if (!rows)
|
|
554
601
|
rows = await this.getJoinedRows({
|
|
@@ -569,12 +616,28 @@ class Table {
|
|
|
569
616
|
}
|
|
570
617
|
}
|
|
571
618
|
}
|
|
572
|
-
if (rows)
|
|
619
|
+
if (rows) {
|
|
573
620
|
await db_1.default.deleteWhere(this.name, {
|
|
574
621
|
[this.pk_name]: { in: rows.map((r) => r[this.pk_name]) },
|
|
575
622
|
});
|
|
576
|
-
|
|
623
|
+
if (this.has_sync_info) {
|
|
624
|
+
const dbTime = await db_1.default.time();
|
|
625
|
+
const ids = rows.map((r) => r[this.pk_name || "id"]);
|
|
626
|
+
await this.addDeleteSyncInfo(ids, dbTime);
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
else {
|
|
630
|
+
const delIds = this.has_sync_info
|
|
631
|
+
? await db_1.default.select(this.name, where, {
|
|
632
|
+
fields: [this.pk_name],
|
|
633
|
+
})
|
|
634
|
+
: null;
|
|
577
635
|
await db_1.default.deleteWhere(this.name, where);
|
|
636
|
+
if (this.has_sync_info) {
|
|
637
|
+
const dbTime = await db_1.default.time();
|
|
638
|
+
await this.addDeleteSyncInfo(delIds, dbTime);
|
|
639
|
+
}
|
|
640
|
+
}
|
|
578
641
|
if (fields.find((f) => f.primary_key))
|
|
579
642
|
await this.resetSequence();
|
|
580
643
|
for (const file of deleteFiles) {
|
|
@@ -658,7 +721,7 @@ class Table {
|
|
|
658
721
|
else
|
|
659
722
|
return []; //no ownership
|
|
660
723
|
}
|
|
661
|
-
return apply_calculated_fields(rows.map((r) => this.readFromDB(r)), this.fields);
|
|
724
|
+
return apply_calculated_fields(rows.map((r) => this.readFromDB(r)), this.fields, !!selopts.ignore_errors);
|
|
662
725
|
}
|
|
663
726
|
/**
|
|
664
727
|
* Count amount of rows in db table
|
|
@@ -685,6 +748,9 @@ class Table {
|
|
|
685
748
|
return res.rows.map((r) => r[fieldnm]);
|
|
686
749
|
}
|
|
687
750
|
}
|
|
751
|
+
/**
|
|
752
|
+
*
|
|
753
|
+
*/
|
|
688
754
|
storedExpressionJoinFields() {
|
|
689
755
|
let freeVars = new Set([]);
|
|
690
756
|
for (const f of this.fields)
|
|
@@ -697,14 +763,14 @@ class Table {
|
|
|
697
763
|
}
|
|
698
764
|
/**
|
|
699
765
|
* Update row
|
|
700
|
-
* @param v_in -
|
|
766
|
+
* @param v_in - columns with values to update
|
|
701
767
|
* @param id - id value
|
|
702
768
|
* @param _userid - user id
|
|
703
769
|
* @param noTrigger
|
|
704
770
|
* @param resultCollector
|
|
705
771
|
* @returns
|
|
706
772
|
*/
|
|
707
|
-
async updateRow(v_in, id, user, noTrigger, resultCollector, restore_of_version) {
|
|
773
|
+
async updateRow(v_in, id, user, noTrigger, resultCollector, restore_of_version, syncTimestamp) {
|
|
708
774
|
let existing;
|
|
709
775
|
let v = { ...v_in };
|
|
710
776
|
const fields = this.fields;
|
|
@@ -827,6 +893,13 @@ class Table {
|
|
|
827
893
|
});
|
|
828
894
|
}
|
|
829
895
|
await db_1.default.update(this.name, v, id, { pk_name });
|
|
896
|
+
if (this.has_sync_info) {
|
|
897
|
+
const oldInfo = await this.latestSyncInfo(id);
|
|
898
|
+
if (oldInfo && !oldInfo.deleted)
|
|
899
|
+
await this.updateSyncInfo(id, oldInfo.last_modified, syncTimestamp);
|
|
900
|
+
else
|
|
901
|
+
await this.insertSyncInfo(id, syncTimestamp);
|
|
902
|
+
}
|
|
830
903
|
const newRow = { ...existing, ...v, [pk_name]: id };
|
|
831
904
|
if (!noTrigger) {
|
|
832
905
|
const trigPromise = trigger_1.default.runTableTriggers("Update", this, newRow, resultCollector, role === 100 ? undefined : user, { old_row: existing, updated_fields: v_in });
|
|
@@ -834,6 +907,39 @@ class Table {
|
|
|
834
907
|
await trigPromise;
|
|
835
908
|
}
|
|
836
909
|
}
|
|
910
|
+
async latestSyncInfo(id) {
|
|
911
|
+
const rows = await this.latestSyncInfos([id]);
|
|
912
|
+
return rows?.length === 1 ? rows[0] : null;
|
|
913
|
+
}
|
|
914
|
+
async latestSyncInfos(ids) {
|
|
915
|
+
const schema = db_1.default.getTenantSchemaPrefix();
|
|
916
|
+
const dbResult = await db_1.default.query(`select max(last_modified) "last_modified", ref
|
|
917
|
+
from ${schema}"${db_1.default.sqlsanitize(this.name)}_sync_info"
|
|
918
|
+
group by ref having ref in (${ids.join(",")})`);
|
|
919
|
+
return dbResult.rows;
|
|
920
|
+
}
|
|
921
|
+
async insertSyncInfo(id, syncTimestamp) {
|
|
922
|
+
const schema = db_1.default.getTenantSchemaPrefix();
|
|
923
|
+
if (isNode()) {
|
|
924
|
+
await db_1.default.query(`insert into ${schema}"${db_1.default.sqlsanitize(this.name)}_sync_info" values(${id},
|
|
925
|
+
date_trunc('milliseconds', to_timestamp(${(syncTimestamp ? syncTimestamp : await db_1.default.time()).valueOf() / 1000.0})))`);
|
|
926
|
+
}
|
|
927
|
+
else {
|
|
928
|
+
await db_1.default.query(`insert into "${db_1.default.sqlsanitize(this.name)}_sync_info"
|
|
929
|
+
(ref, modified_local, deleted)
|
|
930
|
+
values(${id}, true, false)`);
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
async updateSyncInfo(id, oldLastModified, syncTimestamp) {
|
|
934
|
+
const schema = db_1.default.getTenantSchemaPrefix();
|
|
935
|
+
if (!db_1.default.isSQLite) {
|
|
936
|
+
await db_1.default.query(`update ${schema}"${db_1.default.sqlsanitize(this.name)}_sync_info" set last_modified=date_trunc('milliseconds', to_timestamp(${(syncTimestamp ? syncTimestamp : await db_1.default.time()).valueOf() / 1000.0})) where ref=${id} and last_modified = to_timestamp(${oldLastModified.valueOf() / 1000.0})`);
|
|
937
|
+
}
|
|
938
|
+
else {
|
|
939
|
+
await db_1.default.query(`update "${db_1.default.sqlsanitize(this.name)}_sync_info" set modified_local = true
|
|
940
|
+
where ref = ${id} and last_modified = ${oldLastModified.valueOf()}`);
|
|
941
|
+
}
|
|
942
|
+
}
|
|
837
943
|
/**
|
|
838
944
|
* Try to Update row
|
|
839
945
|
* @param v
|
|
@@ -876,7 +982,16 @@ class Table {
|
|
|
876
982
|
}
|
|
877
983
|
return pkField;
|
|
878
984
|
}
|
|
879
|
-
|
|
985
|
+
/**
|
|
986
|
+
* Check table constraints
|
|
987
|
+
* @param row
|
|
988
|
+
*/
|
|
989
|
+
check_table_constraints(row0) {
|
|
990
|
+
const row = { ...row0 };
|
|
991
|
+
this.fields.forEach((f) => {
|
|
992
|
+
if (typeof row[f.name] === "undefined")
|
|
993
|
+
row[f.name] = null;
|
|
994
|
+
});
|
|
880
995
|
const fmls = this.constraints
|
|
881
996
|
.filter((c) => c.type === "Formula")
|
|
882
997
|
.map((c) => c.configuration);
|
|
@@ -886,6 +1001,11 @@ class Table {
|
|
|
886
1001
|
}
|
|
887
1002
|
return undefined;
|
|
888
1003
|
}
|
|
1004
|
+
/**
|
|
1005
|
+
*
|
|
1006
|
+
* @param row
|
|
1007
|
+
* @param user
|
|
1008
|
+
*/
|
|
889
1009
|
check_field_write_role(row, user) {
|
|
890
1010
|
for (const field of this.fields) {
|
|
891
1011
|
if (typeof row[field.name] !== "undefined" &&
|
|
@@ -902,7 +1022,7 @@ class Table {
|
|
|
902
1022
|
* @param resultCollector
|
|
903
1023
|
* @returns {Promise<*>}
|
|
904
1024
|
*/
|
|
905
|
-
async insertRow(v_in, user, resultCollector) {
|
|
1025
|
+
async insertRow(v_in, user, resultCollector, noTrigger, syncTimestamp) {
|
|
906
1026
|
const fields = this.fields;
|
|
907
1027
|
const pk_name = this.pk_name;
|
|
908
1028
|
const joinFields = this.storedExpressionJoinFields();
|
|
@@ -980,9 +1100,23 @@ class Table {
|
|
|
980
1100
|
_userid: user?.id,
|
|
981
1101
|
_time: new Date(),
|
|
982
1102
|
});
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
1103
|
+
if (this.has_sync_info) {
|
|
1104
|
+
if (isNode()) {
|
|
1105
|
+
const schemaPrefix = db_1.default.getTenantSchemaPrefix();
|
|
1106
|
+
await db_1.default.query(`insert into ${schemaPrefix}${db_1.default.sqlsanitize(this.name)}_sync_info
|
|
1107
|
+
values(${id}, date_trunc('milliseconds', to_timestamp(${(syncTimestamp ? syncTimestamp : await db_1.default.time()).valueOf() / 1000.0})))`);
|
|
1108
|
+
}
|
|
1109
|
+
else {
|
|
1110
|
+
await db_1.default.query(`insert into ${db_1.default.sqlsanitize(this.name)}_sync_info
|
|
1111
|
+
(last_modified, ref, modified_local, deleted)
|
|
1112
|
+
values(NULL, ${id}, true, false)`);
|
|
1113
|
+
}
|
|
1114
|
+
}
|
|
1115
|
+
if (!noTrigger) {
|
|
1116
|
+
const trigPromise = trigger_1.default.runTableTriggers("Insert", this, { [pk_name]: id, ...v }, resultCollector, user);
|
|
1117
|
+
if (resultCollector)
|
|
1118
|
+
await trigPromise;
|
|
1119
|
+
}
|
|
986
1120
|
return id;
|
|
987
1121
|
}
|
|
988
1122
|
/**
|
|
@@ -1005,6 +1139,10 @@ class Table {
|
|
|
1005
1139
|
return { error: this.normalise_error_message(e.message) };
|
|
1006
1140
|
}
|
|
1007
1141
|
}
|
|
1142
|
+
/**
|
|
1143
|
+
*
|
|
1144
|
+
* @param msg
|
|
1145
|
+
*/
|
|
1008
1146
|
normalise_error_message(msg) {
|
|
1009
1147
|
let fieldnm = "";
|
|
1010
1148
|
if (msg.toLowerCase().includes("unique constraint")) {
|
|
@@ -1118,6 +1256,28 @@ class Table {
|
|
|
1118
1256
|
,PRIMARY KEY("${pk}", _version)
|
|
1119
1257
|
);`);
|
|
1120
1258
|
}
|
|
1259
|
+
async create_sync_info_table() {
|
|
1260
|
+
const schemaPrefix = db_1.default.getTenantSchemaPrefix();
|
|
1261
|
+
const fields = this.fields;
|
|
1262
|
+
const pk = fields.find((f) => f.primary_key)?.name;
|
|
1263
|
+
if (!pk) {
|
|
1264
|
+
throw new Error("Unable to find a field with a primary key.");
|
|
1265
|
+
}
|
|
1266
|
+
await db_1.default.query(`create table ${schemaPrefix}${(0, internal_1.sqlsanitize)(this.name)}_sync_info (ref integer, last_modified timestamp, deleted boolean default false)`);
|
|
1267
|
+
await db_1.default.query(`create index ${(0, internal_1.sqlsanitize)(this.name)}_sync_info_ref_index on ${schemaPrefix}${(0, internal_1.sqlsanitize)(this.name)}_sync_info(ref)`);
|
|
1268
|
+
await db_1.default.query(`create index ${(0, internal_1.sqlsanitize)(this.name)}_sync_info_lm_index on ${schemaPrefix}${(0, internal_1.sqlsanitize)(this.name)}_sync_info(last_modified)`);
|
|
1269
|
+
}
|
|
1270
|
+
async drop_sync_table() {
|
|
1271
|
+
const schemaPrefix = db_1.default.getTenantSchemaPrefix();
|
|
1272
|
+
await db_1.default.query(`
|
|
1273
|
+
drop table ${schemaPrefix}"${(0, internal_1.sqlsanitize)(this.name)}_sync_info";`);
|
|
1274
|
+
}
|
|
1275
|
+
/**
|
|
1276
|
+
* Restore Row Version
|
|
1277
|
+
* @param id
|
|
1278
|
+
* @param version
|
|
1279
|
+
* @param user
|
|
1280
|
+
*/
|
|
1121
1281
|
async restore_row_version(id, version, user) {
|
|
1122
1282
|
const row = await db_1.default.selectOne(`${db_1.default.sqlsanitize(this.name)}__history`, {
|
|
1123
1283
|
id,
|
|
@@ -1131,28 +1291,38 @@ class Table {
|
|
|
1131
1291
|
//console.log("restore_row_version", r);
|
|
1132
1292
|
await this.updateRow(r, id, user, false, undefined, version);
|
|
1133
1293
|
}
|
|
1294
|
+
/**
|
|
1295
|
+
* Undo row chnages
|
|
1296
|
+
* @param id
|
|
1297
|
+
* @param user
|
|
1298
|
+
*/
|
|
1134
1299
|
async undo_row_changes(id, user) {
|
|
1135
|
-
const
|
|
1300
|
+
const current_version_row = await db_1.default.selectMaybeOne(`${(0, internal_1.sqlsanitize)(this.name)}__history`, { id }, { orderBy: "_version", orderDesc: true, limit: 1 });
|
|
1136
1301
|
//get max that is not a restore
|
|
1137
1302
|
const last_non_restore = await db_1.default.selectMaybeOne(`${(0, internal_1.sqlsanitize)(this.name)}__history`, {
|
|
1138
1303
|
id,
|
|
1139
1304
|
_version: {
|
|
1140
|
-
lt:
|
|
1141
|
-
?
|
|
1142
|
-
:
|
|
1305
|
+
lt: current_version_row._restore_of_version
|
|
1306
|
+
? current_version_row._restore_of_version
|
|
1307
|
+
: current_version_row._version,
|
|
1143
1308
|
},
|
|
1144
1309
|
}, { orderBy: "_version", orderDesc: true, limit: 1 });
|
|
1145
1310
|
if (last_non_restore) {
|
|
1146
1311
|
await this.restore_row_version(id, last_non_restore._version, user);
|
|
1147
1312
|
}
|
|
1148
1313
|
}
|
|
1314
|
+
/**
|
|
1315
|
+
* Redo row changes
|
|
1316
|
+
* @param id
|
|
1317
|
+
* @param user
|
|
1318
|
+
*/
|
|
1149
1319
|
async redo_row_changes(id, user) {
|
|
1150
|
-
const
|
|
1151
|
-
if (
|
|
1320
|
+
const current_version_row = await db_1.default.selectMaybeOne(`${(0, internal_1.sqlsanitize)(this.name)}__history`, { id }, { orderBy: "_version", orderDesc: true, limit: 1 });
|
|
1321
|
+
if (current_version_row._restore_of_version) {
|
|
1152
1322
|
const next_version = await db_1.default.selectMaybeOne(`${(0, internal_1.sqlsanitize)(this.name)}__history`, {
|
|
1153
1323
|
id,
|
|
1154
1324
|
_version: {
|
|
1155
|
-
gt:
|
|
1325
|
+
gt: current_version_row._restore_of_version,
|
|
1156
1326
|
},
|
|
1157
1327
|
}, { orderBy: "_version", limit: 1 });
|
|
1158
1328
|
if (next_version) {
|
|
@@ -1228,6 +1398,12 @@ class Table {
|
|
|
1228
1398
|
else if (!new_table.versioned && existing.versioned) {
|
|
1229
1399
|
await new_table.drop_history_table();
|
|
1230
1400
|
}
|
|
1401
|
+
if (new_table.has_sync_info && !existing.has_sync_info) {
|
|
1402
|
+
await this.create_sync_info_table();
|
|
1403
|
+
}
|
|
1404
|
+
else if (!new_table.has_sync_info && existing.has_sync_info) {
|
|
1405
|
+
await new_table.drop_sync_table();
|
|
1406
|
+
}
|
|
1231
1407
|
Object.assign(this, new_table_rec);
|
|
1232
1408
|
}
|
|
1233
1409
|
}
|
|
@@ -1334,6 +1510,10 @@ class Table {
|
|
|
1334
1510
|
await require("../db/state").getState().refresh_tables();
|
|
1335
1511
|
return parse_res;
|
|
1336
1512
|
}
|
|
1513
|
+
/**
|
|
1514
|
+
*
|
|
1515
|
+
* @param state
|
|
1516
|
+
*/
|
|
1337
1517
|
read_state_strict(state) {
|
|
1338
1518
|
let errorString = "";
|
|
1339
1519
|
this.fields.forEach((f) => {
|
|
@@ -2057,7 +2237,7 @@ class Table {
|
|
|
2057
2237
|
const res = await db_1.default.query(sql, values);
|
|
2058
2238
|
if (res.length === 0)
|
|
2059
2239
|
return res; // check
|
|
2060
|
-
let calcRow = apply_calculated_fields(res.rows, fields);
|
|
2240
|
+
let calcRow = apply_calculated_fields(res.rows, fields, !!opts?.ignore_errors);
|
|
2061
2241
|
//rename joinfields
|
|
2062
2242
|
if (Object.values(joinFields || {}).some((jf) => jf.rename_object)) {
|
|
2063
2243
|
let f = (x) => x;
|
|
@@ -2127,6 +2307,9 @@ class Table {
|
|
|
2127
2307
|
}
|
|
2128
2308
|
return calcRow;
|
|
2129
2309
|
}
|
|
2310
|
+
/**
|
|
2311
|
+
*
|
|
2312
|
+
*/
|
|
2130
2313
|
async slug_options() {
|
|
2131
2314
|
const fields = this.fields;
|
|
2132
2315
|
const unique_fields = fields.filter((f) => f.is_unique);
|
|
@@ -2151,18 +2334,27 @@ class Table {
|
|
|
2151
2334
|
opts.unshift({ label: "", steps: [] });
|
|
2152
2335
|
return opts;
|
|
2153
2336
|
}
|
|
2337
|
+
/**
|
|
2338
|
+
*
|
|
2339
|
+
*/
|
|
2154
2340
|
static async allSlugOptions() {
|
|
2155
|
-
const tables = await Table.find({});
|
|
2341
|
+
const tables = await Table.find({}, { cached: true });
|
|
2156
2342
|
const options = {};
|
|
2157
2343
|
for (const table of tables) {
|
|
2158
2344
|
options[table.name] = await table.slug_options();
|
|
2159
2345
|
}
|
|
2160
2346
|
return options;
|
|
2161
2347
|
}
|
|
2348
|
+
/**
|
|
2349
|
+
*
|
|
2350
|
+
*/
|
|
2162
2351
|
async getTags() {
|
|
2163
2352
|
const Tag = (await Promise.resolve().then(() => __importStar(require("./tag")))).default;
|
|
2164
2353
|
return await Tag.findWithEntries({ table_id: this.id });
|
|
2165
2354
|
}
|
|
2355
|
+
/**
|
|
2356
|
+
*
|
|
2357
|
+
*/
|
|
2166
2358
|
async getForeignTables() {
|
|
2167
2359
|
const result = new Array();
|
|
2168
2360
|
if (this.fields) {
|