@saltcorn/data 0.6.2-beta.5 → 0.6.3-beta.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 (111) hide show
  1. package/dist/base-plugin/fieldviews.d.ts.map +1 -1
  2. package/dist/base-plugin/fieldviews.js +2 -0
  3. package/dist/base-plugin/fieldviews.js.map +1 -1
  4. package/dist/base-plugin/index.d.ts +16 -11
  5. package/dist/base-plugin/index.d.ts.map +1 -1
  6. package/dist/base-plugin/types.d.ts +8 -8
  7. package/dist/base-plugin/types.d.ts.map +1 -1
  8. package/dist/base-plugin/viewtemplates/edit.d.ts +1 -1
  9. package/dist/base-plugin/viewtemplates/edit.d.ts.map +1 -1
  10. package/dist/base-plugin/viewtemplates/edit.js +25 -2
  11. package/dist/base-plugin/viewtemplates/edit.js.map +1 -1
  12. package/dist/base-plugin/viewtemplates/feed.d.ts +1 -1
  13. package/dist/base-plugin/viewtemplates/feed.d.ts.map +1 -1
  14. package/dist/base-plugin/viewtemplates/feed.js +11 -1
  15. package/dist/base-plugin/viewtemplates/feed.js.map +1 -1
  16. package/dist/base-plugin/viewtemplates/list.d.ts +1 -1
  17. package/dist/base-plugin/viewtemplates/list.d.ts.map +1 -1
  18. package/dist/base-plugin/viewtemplates/list.js +23 -11
  19. package/dist/base-plugin/viewtemplates/list.js.map +1 -1
  20. package/dist/base-plugin/viewtemplates/show.d.ts +5 -0
  21. package/dist/base-plugin/viewtemplates/show.d.ts.map +1 -1
  22. package/dist/base-plugin/viewtemplates/show.js +40 -5
  23. package/dist/base-plugin/viewtemplates/show.js.map +1 -1
  24. package/dist/base-plugin/viewtemplates/viewable_fields.d.ts +2 -1
  25. package/dist/base-plugin/viewtemplates/viewable_fields.d.ts.map +1 -1
  26. package/dist/base-plugin/viewtemplates/viewable_fields.js +29 -9
  27. package/dist/base-plugin/viewtemplates/viewable_fields.js.map +1 -1
  28. package/dist/db/connect.d.ts.map +1 -1
  29. package/dist/db/connect.js +8 -2
  30. package/dist/db/connect.js.map +1 -1
  31. package/dist/db/index.d.ts +6 -0
  32. package/dist/db/index.d.ts.map +1 -1
  33. package/dist/db/index.js +6 -0
  34. package/dist/db/index.js.map +1 -1
  35. package/dist/db/state.js +4 -4
  36. package/dist/db/state.js.map +1 -1
  37. package/dist/migrate.js +1 -1
  38. package/dist/migrate.js.map +1 -1
  39. package/dist/migrations/202112282254.d.ts +3 -0
  40. package/dist/migrations/202112282254.d.ts.map +1 -0
  41. package/dist/migrations/202112282254.js +5 -0
  42. package/dist/migrations/202112282254.js.map +1 -0
  43. package/dist/models/backup.d.ts +8 -21
  44. package/dist/models/backup.d.ts.map +1 -1
  45. package/dist/models/backup.js +105 -103
  46. package/dist/models/backup.js.map +1 -1
  47. package/dist/models/config.d.ts.map +1 -1
  48. package/dist/models/config.js +3 -1
  49. package/dist/models/config.js.map +1 -1
  50. package/dist/models/eventlog.d.ts +39 -38
  51. package/dist/models/eventlog.d.ts.map +1 -1
  52. package/dist/models/eventlog.js +14 -29
  53. package/dist/models/eventlog.js.map +1 -1
  54. package/dist/models/expression.d.ts.map +1 -1
  55. package/dist/models/expression.js +14 -3
  56. package/dist/models/expression.js.map +1 -1
  57. package/dist/models/field.d.ts +125 -121
  58. package/dist/models/field.d.ts.map +1 -1
  59. package/dist/models/field.js +125 -147
  60. package/dist/models/field.js.map +1 -1
  61. package/dist/models/fieldrepeat.d.ts +22 -20
  62. package/dist/models/fieldrepeat.d.ts.map +1 -1
  63. package/dist/models/fieldrepeat.js +6 -14
  64. package/dist/models/fieldrepeat.js.map +1 -1
  65. package/dist/models/form.d.ts +69 -50
  66. package/dist/models/form.d.ts.map +1 -1
  67. package/dist/models/form.js +49 -49
  68. package/dist/models/form.js.map +1 -1
  69. package/dist/models/library.d.ts +29 -19
  70. package/dist/models/library.d.ts.map +1 -1
  71. package/dist/models/library.js +10 -8
  72. package/dist/models/library.js.map +1 -1
  73. package/dist/models/role.d.ts +22 -9
  74. package/dist/models/role.d.ts.map +1 -1
  75. package/dist/models/role.js +16 -8
  76. package/dist/models/role.js.map +1 -1
  77. package/dist/models/table.d.ts +98 -133
  78. package/dist/models/table.d.ts.map +1 -1
  79. package/dist/models/table.js +236 -180
  80. package/dist/models/table.js.map +1 -1
  81. package/dist/models/tenant.d.ts +6 -0
  82. package/dist/models/tenant.d.ts.map +1 -1
  83. package/dist/models/tenant.js +9 -0
  84. package/dist/models/tenant.js.map +1 -1
  85. package/dist/models/trigger.d.ts +62 -66
  86. package/dist/models/trigger.d.ts.map +1 -1
  87. package/dist/models/trigger.js +7 -33
  88. package/dist/models/trigger.js.map +1 -1
  89. package/dist/models/view.d.ts +109 -98
  90. package/dist/models/view.d.ts.map +1 -1
  91. package/dist/models/view.js +103 -80
  92. package/dist/models/view.js.map +1 -1
  93. package/dist/models/workflow.d.ts +23 -21
  94. package/dist/models/workflow.d.ts.map +1 -1
  95. package/dist/models/workflow.js +9 -17
  96. package/dist/models/workflow.js.map +1 -1
  97. package/dist/plugin-helper.d.ts.map +1 -1
  98. package/dist/plugin-helper.js +30 -12
  99. package/dist/plugin-helper.js.map +1 -1
  100. package/dist/tests/calc.test.js +13 -0
  101. package/dist/tests/calc.test.js.map +1 -1
  102. package/dist/tests/exact_views.test.js +214 -0
  103. package/dist/tests/exact_views.test.js.map +1 -1
  104. package/dist/tests/table.test.js +57 -2
  105. package/dist/tests/table.test.js.map +1 -1
  106. package/dist/tsconfig.ref.tsbuildinfo +1 -1
  107. package/dist/utils.d.ts +2 -0
  108. package/dist/utils.d.ts.map +1 -1
  109. package/dist/utils.js +26 -0
  110. package/dist/utils.js.map +1 -1
  111. package/package.json +11 -5
@@ -1,20 +1,24 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  /**
3
6
  * Table Database Access Layer
4
7
  * @category saltcorn-data
5
8
  * @module models/table
6
9
  * @subcategory models
7
10
  */
8
- const db = require("../db");
9
- const { sqlsanitize, mkWhere, mkSelectOptions, } = require("@saltcorn/db-common/internal");
10
- const Field = require("./field");
11
- const Trigger = require("./trigger");
11
+ const db_1 = __importDefault(require("../db"));
12
+ const internal_1 = require("@saltcorn/db-common/internal");
13
+ const field_1 = __importDefault(require("./field"));
14
+ const common_types_1 = require("@saltcorn/types/common_types");
15
+ const trigger_1 = __importDefault(require("./trigger"));
12
16
  const { apply_calculated_fields, apply_calculated_fields_stored, recalculate_for_stored, get_expression_function, } = require("./expression");
13
- const { contract, is } = require("contractis");
14
- const { is_table_query } = require("../contracts");
15
- const csvtojson = require("csvtojson");
16
- const moment = require("moment");
17
- const fs = require("fs");
17
+ const csvtojson_1 = __importDefault(require("csvtojson"));
18
+ const moment_1 = __importDefault(require("moment"));
19
+ const fs_1 = require("fs");
20
+ const promises_1 = require("fs/promises");
21
+ const utils_1 = require("../utils");
18
22
  const { InvalidConfiguration, InvalidAdminAction, satisfies, structuredClone, getLines, } = require("../utils");
19
23
  /**
20
24
  * Transponce Objects
@@ -40,7 +44,7 @@ const transposeObjects = (objs) => {
40
44
  return res;
41
45
  };
42
46
  // todo support also other date formats https://momentjs.com/docs/
43
- const dateFormats = [moment.ISO_8601];
47
+ const dateFormats = [moment_1.default.ISO_8601];
44
48
  // todo refactor - move to separated data utils module?
45
49
  /**
46
50
  * Is Valid Date of format moment.ISO_8601,
@@ -50,7 +54,7 @@ const dateFormats = [moment.ISO_8601];
50
54
  * @returns {boolean}
51
55
  */
52
56
  const isDate = function (date) {
53
- return moment(date, dateFormats, true).isValid();
57
+ return (0, moment_1.default)(date, dateFormats, true).isValid();
54
58
  };
55
59
  // todo resolve database specific
56
60
  /**
@@ -59,7 +63,7 @@ const isDate = function (date) {
59
63
  * @returns {string}
60
64
  */
61
65
  // todo refactor
62
- const normalise_error_message = (msg) => db.isSQLite
66
+ const normalise_error_message = (msg) => db_1.default.isSQLite
63
67
  ? msg.replace(/SQLITE_CONSTRAINT: UNIQUE constraint failed: (.*?)\.(.*?)/, "Duplicate value for unique field: $2")
64
68
  : msg.replace(/duplicate key value violates unique constraint "(.*?)_(.*?)_unique"/, "Duplicate value for unique field: $2");
65
69
  /**
@@ -82,8 +86,7 @@ class Table {
82
86
  this.external = false;
83
87
  this.description = o.description;
84
88
  if (o.fields)
85
- this.fields = o.fields.map((f) => new Field(f));
86
- contract.class(this);
89
+ this.fields = o.fields.map((f) => new field_1.default(f));
87
90
  }
88
91
  /**
89
92
  *
@@ -125,7 +128,7 @@ class Table {
125
128
  const { getState } = require("../db/state");
126
129
  return getState().tables.map((t) => new Table(t));
127
130
  }
128
- const tbls = await db.select("_sc_tables", where, selectopts);
131
+ const tbls = await db_1.default.select("_sc_tables", where, selectopts);
129
132
  return tbls.map((t) => new Table(t));
130
133
  }
131
134
  /**
@@ -144,7 +147,7 @@ class Table {
144
147
  }
145
148
  if (external !== true) {
146
149
  //do include db tables
147
- const tbls = await db.select("_sc_tables", where, selectopts);
150
+ const tbls = await db_1.default.select("_sc_tables", where, selectopts);
148
151
  dbs = tbls.map((t) => new Table(t));
149
152
  }
150
153
  return [...dbs, ...externals];
@@ -155,10 +158,10 @@ class Table {
155
158
  * @returns {null|*} null or owner column name
156
159
  */
157
160
  owner_fieldname_from_fields(fields) {
158
- if (!this.ownership_field_id)
161
+ if (!this.ownership_field_id || !fields)
159
162
  return null;
160
163
  const field = fields.find((f) => f.id === this.ownership_field_id);
161
- return field.name;
164
+ return field?.name;
162
165
  }
163
166
  /**
164
167
  * Get owner column name
@@ -185,7 +188,9 @@ class Table {
185
188
  return f(row, user);
186
189
  }
187
190
  const field_name = this.owner_fieldname();
188
- return field_name && row[field_name] === user.id;
191
+ if (!field_name && this.name === "users")
192
+ return user && user.id && row && `${row.id}` === `${user.id}`;
193
+ return typeof field_name === "string" && row[field_name] === user.id;
189
194
  }
190
195
  /**
191
196
  * Create table
@@ -194,9 +199,9 @@ class Table {
194
199
  * @returns {Promise<Table>} table
195
200
  */
196
201
  static async create(name, options = {}) {
197
- const schema = db.getTenantSchemaPrefix();
202
+ const schema = db_1.default.getTenantSchemaPrefix();
198
203
  // create table in database
199
- await db.query(`create table ${schema}"${sqlsanitize(name)}" (id ${db.isSQLite ? "integer" : "serial"} primary key)`);
204
+ await db_1.default.query(`create table ${schema}"${(0, internal_1.sqlsanitize)(name)}" (id ${db_1.default.isSQLite ? "integer" : "serial"} primary key)`);
200
205
  // populate table definition row
201
206
  const tblrow = {
202
207
  name,
@@ -208,9 +213,9 @@ class Table {
208
213
  description: options.description || "",
209
214
  };
210
215
  // insert table defintion into _sc_tables
211
- const id = await db.insert("_sc_tables", tblrow);
216
+ const id = await db_1.default.insert("_sc_tables", tblrow);
212
217
  // add primary key columnt ID
213
- await db.query(`insert into ${schema}_sc_fields(table_id, name, label, type, attributes, required, is_unique,primary_key)
218
+ await db_1.default.query(`insert into ${schema}_sc_fields(table_id, name, label, type, attributes, required, is_unique,primary_key)
214
219
  values($1,'id','ID','Integer', '{}', true, true, true)`, [id]);
215
220
  // create table
216
221
  const table = new Table({ ...tblrow, id });
@@ -226,20 +231,20 @@ class Table {
226
231
  * @returns {Promise<void>}
227
232
  */
228
233
  async delete(only_forget = false) {
229
- const schema = db.getTenantSchemaPrefix();
230
- const is_sqlite = db.isSQLite;
234
+ const schema = db_1.default.getTenantSchemaPrefix();
235
+ const is_sqlite = db_1.default.isSQLite;
231
236
  await this.update({ ownership_field_id: null });
232
- const client = is_sqlite ? db : await db.getClient();
237
+ const client = is_sqlite ? db_1.default : await db_1.default.getClient();
233
238
  await client.query(`BEGIN`);
234
239
  try {
235
240
  if (!only_forget)
236
- await client.query(`drop table if exists ${schema}"${sqlsanitize(this.name)}"`);
241
+ await client.query(`drop table if exists ${schema}"${(0, internal_1.sqlsanitize)(this.name)}"`);
237
242
  await client.query(`delete FROM ${schema}_sc_fields WHERE table_id = $1`, [this.id]);
238
243
  await client.query(`delete FROM ${schema}_sc_tables WHERE id = $1`, [
239
244
  this.id,
240
245
  ]);
241
246
  if (this.versioned)
242
- await client.query(`drop table if exists ${schema}"${sqlsanitize(this.name)}__history"`);
247
+ await client.query(`drop table if exists ${schema}"${(0, internal_1.sqlsanitize)(this.name)}__history"`);
243
248
  await client.query(`COMMIT`);
244
249
  }
245
250
  catch (e) {
@@ -257,7 +262,7 @@ class Table {
257
262
  * @type {string}
258
263
  */
259
264
  get sql_name() {
260
- return `${db.getTenantSchemaPrefix()}"${sqlsanitize(this.name)}"`;
265
+ return `${db_1.default.getTenantSchemaPrefix()}"${(0, internal_1.sqlsanitize)(this.name)}"`;
261
266
  }
262
267
  /**
263
268
  * Delete rows from table
@@ -266,7 +271,7 @@ class Table {
266
271
  */
267
272
  async deleteRows(where) {
268
273
  // get triggers on delete
269
- const triggers = await Trigger.getTableTriggers("Delete", this);
274
+ const triggers = await trigger_1.default.getTableTriggers("Delete", this);
270
275
  if (triggers.length > 0) {
271
276
  const rows = await this.getRows(where);
272
277
  for (const trigger of triggers) {
@@ -276,7 +281,7 @@ class Table {
276
281
  }
277
282
  }
278
283
  }
279
- await db.deleteWhere(this.name, where);
284
+ await db_1.default.deleteWhere(this.name, where);
280
285
  }
281
286
  /**
282
287
  * Returns row with only fields that can be read from db (readFromDB flag)
@@ -284,9 +289,11 @@ class Table {
284
289
  * @returns {*}
285
290
  */
286
291
  readFromDB(row) {
287
- for (const f of this.fields) {
288
- if (f.type && f.type.readFromDB)
289
- row[f.name] = f.type.readFromDB(row[f.name]);
292
+ if (this.fields) {
293
+ for (const f of this.fields) {
294
+ if (f.type && (0, common_types_1.instanceOfType)(f.type) && f.type.readFromDB)
295
+ row[f.name] = f.type.readFromDB(row[f.name]);
296
+ }
290
297
  }
291
298
  return row;
292
299
  }
@@ -297,7 +304,7 @@ class Table {
297
304
  */
298
305
  async getRow(where = {}) {
299
306
  await this.getFields();
300
- const row = await db.selectMaybeOne(this.name, where);
307
+ const row = await db_1.default.selectMaybeOne(this.name, where);
301
308
  if (!row)
302
309
  return null;
303
310
  return apply_calculated_fields([this.readFromDB(row)], this.fields)[0];
@@ -310,7 +317,7 @@ class Table {
310
317
  */
311
318
  async getRows(where = {}, selopts) {
312
319
  await this.getFields();
313
- const rows = await db.select(this.name, where, selopts);
320
+ const rows = await db_1.default.select(this.name, where, selopts);
314
321
  return apply_calculated_fields(rows.map((r) => this.readFromDB(r)), this.fields);
315
322
  }
316
323
  /**
@@ -319,7 +326,7 @@ class Table {
319
326
  * @returns {Promise<number>}
320
327
  */
321
328
  async countRows(where) {
322
- return await db.count(this.name, where);
329
+ return await db_1.default.count(this.name, where);
323
330
  }
324
331
  /**
325
332
  * Return distinct Values for column in table
@@ -328,7 +335,7 @@ class Table {
328
335
  * @returns {Promise<Object[]>}
329
336
  */
330
337
  async distinctValues(fieldnm) {
331
- const res = await db.query(`select distinct "${db.sqlsanitize(fieldnm)}" from ${this.sql_name}`);
338
+ const res = await db_1.default.query(`select distinct "${db_1.default.sqlsanitize(fieldnm)}" from ${this.sql_name}`);
332
339
  return res.rows.map((r) => r[fieldnm]);
333
340
  }
334
341
  /**
@@ -344,15 +351,15 @@ class Table {
344
351
  const fields = await this.getFields();
345
352
  const pk_name = this.pk_name;
346
353
  if (fields.some((f) => f.calculated && f.stored)) {
347
- existing = await db.selectOne(this.name, { [pk_name]: id });
354
+ existing = await db_1.default.selectOne(this.name, { [pk_name]: id });
348
355
  v = await apply_calculated_fields_stored({ ...existing, ...v_in }, this.fields);
349
356
  }
350
357
  else
351
358
  v = v_in;
352
359
  if (this.versioned) {
353
360
  if (!existing)
354
- existing = await db.selectOne(this.name, { [pk_name]: id });
355
- await db.insert(this.name + "__history", {
361
+ existing = await db_1.default.selectOne(this.name, { [pk_name]: id });
362
+ await db_1.default.insert(this.name + "__history", {
356
363
  ...existing,
357
364
  ...v,
358
365
  [pk_name]: id,
@@ -363,14 +370,14 @@ class Table {
363
370
  _userid,
364
371
  });
365
372
  }
366
- await db.update(this.name, v, id, { pk_name });
373
+ await db_1.default.update(this.name, v, id, { pk_name });
367
374
  if (typeof existing === "undefined") {
368
- const triggers = await Trigger.getTableTriggers("Update", this);
375
+ const triggers = await trigger_1.default.getTableTriggers("Update", this);
369
376
  if (triggers.length > 0)
370
- existing = await db.selectOne(this.name, { [pk_name]: id });
377
+ existing = await db_1.default.selectOne(this.name, { [pk_name]: id });
371
378
  }
372
379
  const newRow = { ...existing, ...v, [pk_name]: id };
373
- await Trigger.runTableTriggers("Update", this, newRow);
380
+ await trigger_1.default.runTableTriggers("Update", this, newRow);
374
381
  }
375
382
  /**
376
383
  * Try to Update row
@@ -395,11 +402,13 @@ class Table {
395
402
  * @returns {Promise<void>}
396
403
  */
397
404
  async toggleBool(id, field_name) {
398
- const schema = db.getTenantSchemaPrefix();
399
- await db.query(`update ${schema}"${sqlsanitize(this.name)}" set "${sqlsanitize(field_name)}"=NOT coalesce("${sqlsanitize(field_name)}", false) where id=$1`, [id]);
400
- const triggers = await Trigger.getTableTriggers("Update", this);
405
+ const schema = db_1.default.getTenantSchemaPrefix();
406
+ await db_1.default.query(`update ${schema}"${(0, internal_1.sqlsanitize)(this.name)}" set "${(0, internal_1.sqlsanitize)(field_name)}"=NOT coalesce("${(0, internal_1.sqlsanitize)(field_name)}", false) where id=$1`, [id]);
407
+ const triggers = await trigger_1.default.getTableTriggers("Update", this);
401
408
  if (triggers.length > 0) {
402
409
  const row = await this.getRow({ id });
410
+ if (!row)
411
+ throw new Error(`Unable to find row with id: ${id}`);
403
412
  for (const trigger of triggers) {
404
413
  await trigger.run(row);
405
414
  }
@@ -410,7 +419,11 @@ class Table {
410
419
  * @type {string}
411
420
  */
412
421
  get pk_name() {
413
- return this.fields.find((f) => f.primary_key).name;
422
+ const pkField = this.fields?.find((f) => f.primary_key)?.name;
423
+ if (!pkField) {
424
+ throw new Error("A primary key field is mandatory");
425
+ }
426
+ return pkField;
414
427
  }
415
428
  /**
416
429
  * Insert row
@@ -422,16 +435,16 @@ class Table {
422
435
  await this.getFields();
423
436
  const v = await apply_calculated_fields_stored(v_in, this.fields);
424
437
  const pk_name = this.pk_name;
425
- const id = await db.insert(this.name, v, { pk_name });
438
+ const id = await db_1.default.insert(this.name, v, { pk_name });
426
439
  if (this.versioned)
427
- await db.insert(this.name + "__history", {
440
+ await db_1.default.insert(this.name + "__history", {
428
441
  ...v,
429
442
  [pk_name]: id,
430
443
  _version: 1,
431
444
  _userid,
432
445
  _time: new Date(),
433
446
  });
434
- Trigger.runTableTriggers("Insert", this, { [pk_name]: id, ...v });
447
+ trigger_1.default.runTableTriggers("Insert", this, { [pk_name]: id, ...v });
435
448
  return id;
436
449
  }
437
450
  /**
@@ -455,7 +468,10 @@ class Table {
455
468
  */
456
469
  async getFields() {
457
470
  if (!this.fields) {
458
- this.fields = await Field.find({ table_id: this.id }, { orderBy: "id" });
471
+ this.fields = await field_1.default.find({ table_id: this.id }, { orderBy: "id" });
472
+ for (let field of this.fields) {
473
+ field.table = this;
474
+ }
459
475
  }
460
476
  return this.fields;
461
477
  }
@@ -465,12 +481,15 @@ class Table {
465
481
  */
466
482
  // todo create function that returns history table name for table
467
483
  async create_history_table() {
468
- const schemaPrefix = db.getTenantSchemaPrefix();
484
+ const schemaPrefix = db_1.default.getTenantSchemaPrefix();
469
485
  const fields = await this.getFields();
470
- const flds = fields.map((f) => `,"${sqlsanitize(f.name)}" ${f.sql_bare_type}`);
471
- const pk = fields.find((f) => f.primary_key).name;
486
+ const flds = fields.map((f) => `,"${(0, internal_1.sqlsanitize)(f.name)}" ${f.sql_bare_type}`);
487
+ const pk = fields.find((f) => f.primary_key)?.name;
488
+ if (!pk) {
489
+ throw new Error("Unable to find a field with a primary key.");
490
+ }
472
491
  // create history table
473
- await db.query(`create table ${schemaPrefix}"${sqlsanitize(this.name)}__history" (
492
+ await db_1.default.query(`create table ${schemaPrefix}"${(0, internal_1.sqlsanitize)(this.name)}__history" (
474
493
  _version integer,
475
494
  _time timestamp,
476
495
  _userid integer
@@ -483,9 +502,9 @@ class Table {
483
502
  * @returns {Promise<void>}
484
503
  */
485
504
  async drop_history_table() {
486
- const schemaPrefix = db.getTenantSchemaPrefix();
487
- await db.query(`
488
- drop table ${schemaPrefix}"${sqlsanitize(this.name)}__history";`);
505
+ const schemaPrefix = db_1.default.getTenantSchemaPrefix();
506
+ await db_1.default.query(`
507
+ drop table ${schemaPrefix}"${(0, internal_1.sqlsanitize)(this.name)}__history";`);
489
508
  }
490
509
  /**
491
510
  * Rename table
@@ -494,19 +513,19 @@ class Table {
494
513
  */
495
514
  async rename(new_name) {
496
515
  //in transaction
497
- if (db.isSQLite)
516
+ if (db_1.default.isSQLite)
498
517
  throw new InvalidAdminAction("Cannot rename table on SQLite");
499
- const schemaPrefix = db.getTenantSchemaPrefix();
500
- const client = await db.getClient();
518
+ const schemaPrefix = db_1.default.getTenantSchemaPrefix();
519
+ const client = await db_1.default.getClient();
501
520
  await client.query(`BEGIN`);
502
521
  try {
503
522
  //rename table
504
- await db.query(`alter table ${schemaPrefix}"${sqlsanitize(this.name)}" rename to "${sqlsanitize(new_name)}";`);
523
+ await db_1.default.query(`alter table ${schemaPrefix}"${(0, internal_1.sqlsanitize)(this.name)}" rename to "${(0, internal_1.sqlsanitize)(new_name)}";`);
505
524
  //change refs
506
- await db.query(`update ${schemaPrefix}_sc_fields set reftable_name=$1 where reftable_name=$2`, [sqlsanitize(new_name), sqlsanitize(this.name)]);
525
+ await db_1.default.query(`update ${schemaPrefix}_sc_fields set reftable_name=$1 where reftable_name=$2`, [(0, internal_1.sqlsanitize)(new_name), (0, internal_1.sqlsanitize)(this.name)]);
507
526
  //rename history
508
527
  if (this.versioned)
509
- await db.query(`alter table ${schemaPrefix}"${sqlsanitize(this.name)}__history" rename to "${sqlsanitize(new_name)}__history";`);
528
+ await db_1.default.query(`alter table ${schemaPrefix}"${(0, internal_1.sqlsanitize)(this.name)}__history" rename to "${(0, internal_1.sqlsanitize)(new_name)}__history";`);
510
529
  //1. change record
511
530
  await this.update({ name: new_name });
512
531
  await client.query(`COMMIT`);
@@ -529,17 +548,25 @@ class Table {
529
548
  if (new_table_rec.ownership_field_id === "")
530
549
  delete new_table_rec.ownership_field_id;
531
550
  const existing = await Table.findOne({ id: this.id });
551
+ if (!existing) {
552
+ throw new Error(`Unable to find table with id: ${this.id}`);
553
+ }
532
554
  const { external, fields, ...upd_rec } = new_table_rec;
533
- await db.update("_sc_tables", upd_rec, this.id);
555
+ await db_1.default.update("_sc_tables", upd_rec, this.id);
534
556
  await require("../db/state").getState().refresh_tables();
535
557
  const new_table = await Table.findOne({ id: this.id });
536
- if (new_table.versioned && !existing.versioned) {
537
- await new_table.create_history_table();
558
+ if (!new_table) {
559
+ throw new Error(`Unable to find table with id: ${this.id}`);
538
560
  }
539
- else if (!new_table.versioned && existing.versioned) {
540
- await new_table.drop_history_table();
561
+ else {
562
+ if (new_table.versioned && !existing.versioned) {
563
+ await new_table.create_history_table();
564
+ }
565
+ else if (!new_table.versioned && existing.versioned) {
566
+ await new_table.drop_history_table();
567
+ }
568
+ Object.assign(this, new_table_rec);
541
569
  }
542
- Object.assign(this, new_table_rec);
543
570
  }
544
571
  /**
545
572
  * Get table history data
@@ -547,7 +574,7 @@ class Table {
547
574
  * @returns {Promise<*>}
548
575
  */
549
576
  async get_history(id) {
550
- return await db.select(`${sqlsanitize(this.name)}__history`, { id }, { orderBy: "_version" });
577
+ return await db_1.default.select(`${(0, internal_1.sqlsanitize)(this.name)}__history`, { id }, { orderBy: "_version" });
551
578
  }
552
579
  /**
553
580
  * Enable constraints
@@ -568,7 +595,7 @@ class Table {
568
595
  let rows;
569
596
  try {
570
597
  const s = await getLines(filePath, 500);
571
- rows = await csvtojson().fromString(s); // todo agrument type unknown
598
+ rows = await (0, csvtojson_1.default)().fromString(s); // todo agrument type unknown
572
599
  }
573
600
  catch (e) {
574
601
  return { error: `Error processing CSV file` };
@@ -595,14 +622,14 @@ class Table {
595
622
  type = "String";
596
623
  const label = (k.charAt(0).toUpperCase() + k.slice(1)).replace(/_/g, " ");
597
624
  //can fail here if: non integer i d, duplicate headers, invalid name
598
- const fld = new Field({
599
- name: Field.labelToName(k),
625
+ const fld = new field_1.default({
626
+ name: field_1.default.labelToName(k),
600
627
  required,
601
628
  type,
602
629
  table,
603
630
  label,
604
631
  });
605
- if (db.sqlsanitize(k.toLowerCase()) === "id") {
632
+ if (db_1.default.sqlsanitize(k.toLowerCase()) === "id") {
606
633
  if (type !== "Integer") {
607
634
  await table.delete();
608
635
  return { error: `Columns named "id" must have only integers` };
@@ -613,14 +640,14 @@ class Table {
613
640
  }
614
641
  continue;
615
642
  }
616
- if (db.sqlsanitize(fld.name) === "") {
643
+ if (db_1.default.sqlsanitize(fld.name) === "") {
617
644
  await table.delete();
618
645
  return {
619
646
  error: `Invalid column name ${k} - Use A-Z, a-z, 0-9, _ only`,
620
647
  };
621
648
  }
622
649
  try {
623
- await Field.create(fld);
650
+ await field_1.default.create(fld);
624
651
  }
625
652
  catch (e) {
626
653
  await table.delete();
@@ -628,7 +655,7 @@ class Table {
628
655
  }
629
656
  }
630
657
  const parse_res = await table.import_csv_file(filePath);
631
- if (parse_res.error) {
658
+ if ((0, common_types_1.instanceOfErrorMsg)(parse_res)) {
632
659
  await table.delete();
633
660
  return { error: parse_res.error };
634
661
  }
@@ -648,7 +675,7 @@ class Table {
648
675
  const { readStateStrict } = require("../plugin-helper");
649
676
  try {
650
677
  const s = await getLines(filePath, 1);
651
- [headers] = await csvtojson({
678
+ [headers] = await (0, csvtojson_1.default)({
652
679
  output: "csv",
653
680
  noheader: true,
654
681
  }).fromString(s); // todo agrument type unknown
@@ -680,15 +707,15 @@ class Table {
680
707
  const colRe = new RegExp(`(${Object.keys(okHeaders).join("|")})`);
681
708
  let i = 1;
682
709
  let rejects = 0;
683
- const client = db.isSQLite ? db : await db.getClient();
684
- const stats = await fs.promises.stat(filePath);
710
+ const client = db_1.default.isSQLite ? db_1.default : await db_1.default.getClient();
711
+ const stats = await (0, promises_1.stat)(filePath);
685
712
  const fileSizeInMegabytes = stats.size / (1024 * 1024);
686
713
  await client.query("BEGIN");
687
- const readStream = fs.createReadStream(filePath);
714
+ const readStream = (0, fs_1.createReadStream)(filePath);
688
715
  try {
689
- if (db.copyFrom && fileSizeInMegabytes > 1) {
716
+ if (db_1.default.copyFrom && fileSizeInMegabytes > 1) {
690
717
  let theError;
691
- const copyres = await db
718
+ const copyres = await db_1.default
692
719
  .copyFrom(readStream, this.name, fieldNames, client)
693
720
  .catch((cate) => {
694
721
  theError = cate;
@@ -704,7 +731,7 @@ class Table {
704
731
  }
705
732
  else {
706
733
  await new Promise((resolve, reject) => {
707
- csvtojson({
734
+ (0, csvtojson_1.default)({
708
735
  includeColumns: colRe,
709
736
  })
710
737
  .fromStream(readStream)
@@ -719,7 +746,7 @@ class Table {
719
746
  });
720
747
  const rowOk = readStateStrict(rec, fields);
721
748
  if (rowOk)
722
- await db.insert(this.name, rec, {
749
+ await db_1.default.insert(this.name, rec, {
723
750
  noid: true,
724
751
  client,
725
752
  pk_name,
@@ -729,7 +756,7 @@ class Table {
729
756
  }
730
757
  catch (e) {
731
758
  await client.query("ROLLBACK");
732
- if (!db.isSQLite)
759
+ if (!db_1.default.isSQLite)
733
760
  await client.release(true);
734
761
  reject({ error: `${e.message} in row ${i}` });
735
762
  }
@@ -748,12 +775,19 @@ class Table {
748
775
  };
749
776
  }
750
777
  await client.query("COMMIT");
751
- if (!db.isSQLite)
778
+ if (!db_1.default.isSQLite)
752
779
  await client.release(true);
753
780
  const pk = fields.find((f) => f.primary_key);
754
- if (db.reset_sequence && pk.type.name === "Integer")
755
- await db.reset_sequence(this.name);
756
- if (recalc_stored && this.fields.some((f) => f.calculated && f.stored)) {
781
+ if (!pk) {
782
+ throw new Error("Unable to find a field with a primary key.");
783
+ }
784
+ if (db_1.default.reset_sequence &&
785
+ (0, common_types_1.instanceOfType)(pk.type) &&
786
+ pk.type.name === "Integer")
787
+ await db_1.default.reset_sequence(this.name);
788
+ if (recalc_stored &&
789
+ this.fields &&
790
+ this.fields.some((f) => f.calculated && f.stored)) {
757
791
  await recalculate_for_stored(this);
758
792
  }
759
793
  return {
@@ -768,12 +802,12 @@ class Table {
768
802
  */
769
803
  async import_json_file(filePath, skip_first_data_row) {
770
804
  // todo argument type buffer is not assignable for type String...
771
- const file_rows = JSON.parse(await fs.promises.readFile(filePath));
805
+ const file_rows = JSON.parse(await (await (0, promises_1.readFile)(filePath)).toString());
772
806
  const fields = await this.getFields();
773
807
  const pk_name = this.pk_name;
774
808
  const { readState } = require("../plugin-helper");
775
809
  let i = 1;
776
- const client = db.isSQLite ? db : await db.getClient();
810
+ const client = db_1.default.isSQLite ? db_1.default : await db_1.default.getClient();
777
811
  await client.query("BEGIN");
778
812
  for (const rec of file_rows) {
779
813
  i += 1;
@@ -788,21 +822,25 @@ class Table {
788
822
  });
789
823
  try {
790
824
  readState(rec, fields);
791
- await db.insert(this.name, rec, { noid: true, client, pk_name });
825
+ await db_1.default.insert(this.name, rec, { noid: true, client, pk_name });
792
826
  }
793
827
  catch (e) {
794
828
  await client.query("ROLLBACK");
795
- if (!db.isSQLite)
829
+ if (!db_1.default.isSQLite)
796
830
  await client.release(true);
797
831
  return { error: `${e.message} in row ${i}` };
798
832
  }
799
833
  }
800
834
  await client.query("COMMIT");
801
- if (!db.isSQLite)
835
+ if (!db_1.default.isSQLite)
802
836
  await client.release(true);
803
837
  const pk = fields.find((f) => f.primary_key);
804
- if (db.reset_sequence && pk.type.name === "Integer")
805
- await db.reset_sequence(this.name);
838
+ if (!pk)
839
+ throw new Error("Unable to find a primary key field.");
840
+ if (db_1.default.reset_sequence &&
841
+ (0, common_types_1.instanceOfType)(pk.type) &&
842
+ pk.type.name === "Integer")
843
+ await db_1.default.reset_sequence(this.name);
806
844
  return {
807
845
  success: `Imported ${file_rows.length} rows into table ${this.name}`,
808
846
  };
@@ -819,21 +857,47 @@ class Table {
819
857
  for (const f of fields) {
820
858
  if (f.is_fkey && f.type !== "File") {
821
859
  const table = await Table.findOne({ name: f.reftable_name });
860
+ if (!table)
861
+ throw new Error(`Unable to find table '${f.reftable_name}`);
822
862
  await table.getFields();
863
+ if (!table.fields)
864
+ throw new Error(`The table '${f.reftable_name} has no fields.`);
823
865
  for (const pf of table.fields.filter((f) => !f.calculated || f.stored)) {
824
866
  parent_field_list.push(`${f.name}.${pf.name}`);
825
867
  if (pf.is_fkey && pf.type !== "File" && allow_double) {
826
868
  const table1 = await Table.findOne({ name: pf.reftable_name });
869
+ if (!table1)
870
+ throw new Error(`Unable to find table '${pf.reftable_name}`);
827
871
  await table1.getFields();
828
- for (const gpf of table1.fields.filter((f) => !f.calculated || f.stored)) {
829
- parent_field_list.push(`${f.name}.${pf.name}.${gpf.name}`);
830
- }
872
+ if (!table1.fields)
873
+ throw new Error(`The table '${pf.reftable_name} has no fields.`);
874
+ if (table1.fields)
875
+ for (const gpf of table1.fields.filter((f) => !f.calculated || f.stored)) {
876
+ parent_field_list.push(`${f.name}.${pf.name}.${gpf.name}`);
877
+ }
831
878
  parent_relations.push({ key_field: pf, through: f, table: table1 });
832
879
  }
833
880
  }
834
881
  parent_relations.push({ key_field: f, table });
835
882
  }
836
883
  }
884
+ const o2o_rels = await field_1.default.find({
885
+ reftable_name: this.name,
886
+ is_unique: true,
887
+ });
888
+ for (const relation of o2o_rels) {
889
+ const related_table = await Table.findOne({ id: relation.table_id });
890
+ if (related_table) {
891
+ const relfields = await related_table.getFields();
892
+ for (const relfield of relfields) {
893
+ parent_field_list.push(`${related_table.name}.${relation.name}->${relfield.name}`);
894
+ parent_relations.push({
895
+ key_field: relation,
896
+ ontable: related_table,
897
+ });
898
+ }
899
+ }
900
+ }
837
901
  return { parent_relations, parent_field_list };
838
902
  }
839
903
  /**
@@ -841,12 +905,15 @@ class Table {
841
905
  * @returns {Promise<{child_relations: object[], child_field_list: object[]}>}
842
906
  */
843
907
  async get_child_relations() {
844
- const cfields = await Field.find({ reftable_name: this.name });
908
+ const cfields = await field_1.default.find({ reftable_name: this.name });
845
909
  let child_relations = [];
846
910
  let child_field_list = [];
847
911
  for (const f of cfields) {
848
912
  if (f.is_fkey) {
849
913
  const table = await Table.findOne({ id: f.table_id });
914
+ if (!table) {
915
+ throw new Error(`Unable to find table with id: ${f.table_id}`);
916
+ }
850
917
  child_field_list.push(`${table.name}.${f.name}`);
851
918
  await table.getFields();
852
919
  child_relations.push({ key_field: f, table });
@@ -865,7 +932,7 @@ class Table {
865
932
  let joinq = "";
866
933
  let joinTables = [];
867
934
  let joinFields = opts.joinFields || [];
868
- const schema = db.getTenantSchemaPrefix();
935
+ const schema = db_1.default.getTenantSchemaPrefix();
869
936
  fields
870
937
  .filter((f) => f.type === "File")
871
938
  .forEach((f) => {
@@ -875,17 +942,29 @@ class Table {
875
942
  target: `filename`,
876
943
  };
877
944
  });
878
- for (const [fldnm, { ref, target, through }] of Object.entries(joinFields)) {
879
- const reffield = fields.find((f) => f.name === ref);
945
+ for (const [fldnm, { ref, target, through, ontable }] of Object.entries(joinFields)) {
946
+ let reffield;
947
+ if (ontable) {
948
+ const ontableTbl = Table.findOne({ name: ontable });
949
+ if (!ontableTbl)
950
+ throw new InvalidConfiguration(`Related table ${ontable} not found in table ${this.name}`);
951
+ reffield = (await ontableTbl.getFields()).find((f) => f.name === ref);
952
+ }
953
+ else {
954
+ reffield = fields.find((f) => f.name === ref);
955
+ }
880
956
  if (!reffield)
881
957
  throw new InvalidConfiguration(`Key field ${ref} not found in table ${this.name}`);
882
- const reftable = reffield.reftable_name;
958
+ const reftable = ontable || reffield.reftable_name;
883
959
  if (!reftable)
884
960
  throw new InvalidConfiguration(`Field ${ref} is not a key field`);
885
- const jtNm = `${sqlsanitize(reftable)}_jt_${sqlsanitize(ref)}`;
961
+ const jtNm = `${(0, internal_1.sqlsanitize)(reftable)}_jt_${(0, internal_1.sqlsanitize)(ref)}`;
886
962
  if (!joinTables.includes(jtNm)) {
887
963
  joinTables.push(jtNm);
888
- joinq += ` left join ${schema}"${sqlsanitize(reftable)}" ${jtNm} on ${jtNm}."${reffield.refname}"=a."${sqlsanitize(ref)}"`;
964
+ if (ontable)
965
+ joinq += ` left join ${schema}"${(0, internal_1.sqlsanitize)(reftable)}" ${jtNm} on ${jtNm}."${(0, internal_1.sqlsanitize)(ref)}"=a."${reffield.refname}"`;
966
+ else
967
+ joinq += ` left join ${schema}"${(0, internal_1.sqlsanitize)(reftable)}" ${jtNm} on ${jtNm}."${reffield.refname}"=a."${(0, internal_1.sqlsanitize)(ref)}"`;
889
968
  }
890
969
  if (through) {
891
970
  const throughTable = await Table.findOne({
@@ -898,48 +977,42 @@ class Table {
898
977
  if (!throughRefField)
899
978
  throw new InvalidConfiguration(`Reference field field ${through} not found in table ${throughTable.name}`);
900
979
  const finalTable = throughRefField.reftable_name;
901
- const jtNm1 = `${sqlsanitize(reftable)}_jt_${sqlsanitize(through)}_jt_${sqlsanitize(ref)}`;
980
+ const jtNm1 = `${(0, internal_1.sqlsanitize)(reftable)}_jt_${(0, internal_1.sqlsanitize)(through)}_jt_${(0, internal_1.sqlsanitize)(ref)}`;
902
981
  if (!joinTables.includes(jtNm1)) {
982
+ if (!finalTable)
983
+ throw new Error("Unable to build a joind without a reftable_name.");
903
984
  joinTables.push(jtNm1);
904
- joinq += ` left join ${schema}"${sqlsanitize(finalTable)}" ${jtNm1} on ${jtNm1}.id=${jtNm}."${sqlsanitize(through)}"`;
985
+ joinq += ` left join ${schema}"${(0, internal_1.sqlsanitize)(finalTable)}" ${jtNm1} on ${jtNm1}.id=${jtNm}."${(0, internal_1.sqlsanitize)(through)}"`;
905
986
  }
906
- fldNms.push(`${jtNm1}.${sqlsanitize(target)} as ${sqlsanitize(fldnm)}`);
987
+ fldNms.push(`${jtNm1}.${(0, internal_1.sqlsanitize)(target)} as ${(0, internal_1.sqlsanitize)(fldnm)}`);
907
988
  }
908
989
  else {
909
- fldNms.push(`${jtNm}.${sqlsanitize(target)} as ${sqlsanitize(fldnm)}`);
990
+ fldNms.push(`${jtNm}.${(0, internal_1.sqlsanitize)(target)} as ${(0, internal_1.sqlsanitize)(fldnm)}`);
910
991
  }
911
992
  }
912
993
  for (const f of fields.filter((f) => !f.calculated || f.stored)) {
913
- fldNms.push(`a."${sqlsanitize(f.name)}"`);
994
+ fldNms.push(`a."${(0, internal_1.sqlsanitize)(f.name)}"`);
914
995
  }
915
996
  Object.entries(opts.aggregations || {}).forEach(([fldnm, { table, ref, field, where, aggregate, subselect }]) => {
916
997
  if (aggregate.startsWith("Latest ")) {
917
998
  const dateField = aggregate.replace("Latest ", "");
918
- fldNms.push(`(select "${sqlsanitize(field)}" from ${schema}"${sqlsanitize(table)}" where ${dateField}=(select max(${dateField}) from ${schema}"${sqlsanitize(table)}" where "${sqlsanitize(ref)}"=a.id${where ? ` and ${where}` : ""}) and "${sqlsanitize(ref)}"=a.id) ${sqlsanitize(fldnm)}`);
999
+ fldNms.push(`(select "${(0, internal_1.sqlsanitize)(field)}" from ${schema}"${(0, internal_1.sqlsanitize)(table)}" where ${dateField}=(select max(${dateField}) from ${schema}"${(0, internal_1.sqlsanitize)(table)}" where "${(0, internal_1.sqlsanitize)(ref)}"=a.id${where ? ` and ${where}` : ""}) and "${(0, internal_1.sqlsanitize)(ref)}"=a.id) ${(0, internal_1.sqlsanitize)(fldnm)}`);
919
1000
  }
920
1001
  else if (subselect)
921
- fldNms.push(`(select ${sqlsanitize(aggregate)}(${field ? `"${sqlsanitize(field)}"` : "*"}) from ${schema}"${sqlsanitize(table)}" where ${sqlsanitize(ref)} in (select "${subselect.field}" from ${schema}"${subselect.table.name}" where "${subselect.whereField}"=a.id)) ${sqlsanitize(fldnm)}`);
1002
+ fldNms.push(`(select ${(0, internal_1.sqlsanitize)(aggregate)}(${field ? `"${(0, internal_1.sqlsanitize)(field)}"` : "*"}) from ${schema}"${(0, internal_1.sqlsanitize)(table)}" where ${(0, internal_1.sqlsanitize)(ref)} in (select "${subselect.field}" from ${schema}"${subselect.table.name}" where "${subselect.whereField}"=a.id)) ${(0, internal_1.sqlsanitize)(fldnm)}`);
922
1003
  else
923
- fldNms.push(`(select ${sqlsanitize(aggregate)}(${field ? `"${sqlsanitize(field)}"` : "*"}) from ${schema}"${sqlsanitize(table)}" where "${sqlsanitize(ref)}"=a.id${where ? ` and ${where}` : ""}) ${sqlsanitize(fldnm)}`);
1004
+ fldNms.push(`(select ${(0, internal_1.sqlsanitize)(aggregate)}(${field ? `"${(0, internal_1.sqlsanitize)(field)}"` : "*"}) from ${schema}"${(0, internal_1.sqlsanitize)(table)}" where "${(0, internal_1.sqlsanitize)(ref)}"=a.id${where ? ` and ${where}` : ""}) ${(0, internal_1.sqlsanitize)(fldnm)}`);
924
1005
  });
925
- let whereObj = {};
926
- if (opts.where) {
927
- Object.keys(opts.where).forEach((k) => {
928
- if (k === "_fts")
929
- whereObj[k] = { table: "a", ...opts.where[k] };
930
- else
931
- whereObj[`a."${k}"`] = opts.where[k];
932
- });
933
- }
934
- const { where, values } = mkWhere(whereObj, db.isSQLite);
1006
+ const whereObj = (0, utils_1.prefixFieldsInWhere)(opts.where, "a");
1007
+ const { where, values } = (0, internal_1.mkWhere)(whereObj, db_1.default.isSQLite);
935
1008
  const selectopts = {
936
1009
  limit: opts.limit,
937
1010
  orderBy: opts.orderBy &&
938
- (opts.orderBy.distance ? opts.orderBy : "a." + opts.orderBy),
1011
+ ((0, internal_1.orderByIsObject)(opts.orderBy) ? opts.orderBy : "a." + opts.orderBy),
939
1012
  orderDesc: opts.orderDesc,
940
1013
  offset: opts.offset,
941
1014
  };
942
- const sql = `SELECT ${fldNms.join()} FROM ${schema}"${sqlsanitize(this.name)}" a ${joinq} ${where} ${mkSelectOptions(selectopts)}`;
1015
+ const sql = `SELECT ${fldNms.join()} FROM ${schema}"${(0, internal_1.sqlsanitize)(this.name)}" a ${joinq} ${where} ${(0, internal_1.mkSelectOptions)(selectopts)}`;
943
1016
  return { sql, values };
944
1017
  }
945
1018
  /**
@@ -949,58 +1022,41 @@ class Table {
949
1022
  async getJoinedRows(opts = {}) {
950
1023
  const fields = await this.getFields();
951
1024
  const { sql, values } = await this.getJoinedQuery(opts);
952
- const res = await db.query(sql, values);
1025
+ const res = await db_1.default.query(sql, values);
953
1026
  return apply_calculated_fields(res.rows, fields);
954
1027
  }
1028
+ async slug_options() {
1029
+ const fields = await this.getFields();
1030
+ const unique_fields = fields.filter((f) => f.is_unique);
1031
+ const opts = [];
1032
+ unique_fields.forEach((f) => {
1033
+ const label = (0, common_types_1.instanceOfType)(f.type) && f.type.name === "String"
1034
+ ? `/slugify-${f.name}`
1035
+ : `/:${f.name}`;
1036
+ opts.push({
1037
+ label,
1038
+ steps: [
1039
+ {
1040
+ field: f.name,
1041
+ unique: true,
1042
+ transform: (0, common_types_1.instanceOfType)(f.type) && f.type.name === "String"
1043
+ ? "slugify"
1044
+ : null,
1045
+ },
1046
+ ],
1047
+ });
1048
+ });
1049
+ opts.unshift({ label: "", steps: [] });
1050
+ return opts;
1051
+ }
1052
+ static async allSlugOptions() {
1053
+ const tables = await Table.find({});
1054
+ const options = {};
1055
+ for (const table of tables) {
1056
+ options[table.name] = await table.slug_options();
1057
+ }
1058
+ return options;
1059
+ }
955
1060
  }
956
- /**
957
- * Table contract
958
- * @type {{variables: {name: ((function(*=): *)|*)}, methods: {updateRow: ((function(*=): *)|*), get_history: ((function(*=): *)|*), tryUpdateRow: ((function(*=): *)|*), deleteRows: ((function(*=): *)|*), update: ((function(*=): *)|*), getRows: ((function(*=): *)|*), getRow: ((function(*=): *)|*), delete: ((function(*=): *)|*), get_parent_relations: ((function(*=): *)|*), get_child_relations: ((function(*=): *)|*), tryInsertRow: ((function(*=): *)|*), getFields: ((function(*=): *)|*), insertRow: ((function(*=): *)|*), toggleBool: ((function(*=): *)|*), getJoinedRows: ((function(*=): *)|*), countRows: ((function(*=): *)|*), distinctValues: ((function(*=): *)|*), sql_name: ((function(*=): *)|*), import_csv_file: ((function(*=): *)|*)}, static_methods: {find: ((function(*=): *)|*), create_from_csv: ((function(*=): *)|*), findOne: ((function(*=): *)|*), find_with_external: ((function(*=): *)|*), create: ((function(*=): *)|*)}, constructs: {name: ((function(*=): *)|*)}}}
959
- */
960
- Table.contract = {
961
- constructs: { name: is.str },
962
- variables: { name: is.str },
963
- methods: {
964
- delete: is.fun([], is.promise(is.eq(undefined))),
965
- update: is.fun(is.obj(), is.promise(is.eq(undefined))),
966
- deleteRows: is.fun(is.obj(), is.promise(is.eq(undefined))),
967
- getRow: is.fun(is.maybe(is.obj()), is.promise(is.maybe(is.obj()))),
968
- getRows: is.fun(is.maybe(is.obj()), is.promise(is.array(is.obj()))),
969
- countRows: is.fun(is.maybe(is.obj()), is.promise(is.posint)),
970
- updateRow: is.fun([is.obj(), is.any], is.promise(is.eq(undefined))),
971
- toggleBool: is.fun([is.any, is.str], is.promise(is.eq(undefined))),
972
- insertRow: is.fun(is.obj(), is.promise(is.any)),
973
- get_history: is.fun(is.posint, is.promise(is.array(is.obj()))),
974
- distinctValues: is.fun(is.str, is.promise(is.array(is.any))),
975
- tryInsertRow: is.fun([is.obj(), is.maybe(is.posint)], is.promise(is.or(is.obj({ error: is.str }), is.obj({ success: is.any })))),
976
- tryUpdateRow: is.fun([is.obj(), is.any, is.maybe(is.posint)], is.promise(is.or(is.obj({ error: is.str }), is.obj({ success: is.eq(true) })))),
977
- sql_name: is.getter(is.str),
978
- getFields: is.fun([], is.promise(is.array(is.class("Field")))),
979
- get_parent_relations: is.fun([], is.promise(is.obj({
980
- parent_relations: is.array(is.obj({
981
- key_field: is.class("Field"),
982
- table: is.class("Table"),
983
- })),
984
- parent_field_list: is.array(is.str),
985
- }))),
986
- get_child_relations: is.fun([], is.promise(is.obj({
987
- child_relations: is.array(is.obj({
988
- key_field: is.class("Field"),
989
- table: is.class("Table"),
990
- })),
991
- child_field_list: is.array(is.str),
992
- }))),
993
- import_csv_file: is.fun(is.str, is.promise(is.or(is.obj({ success: is.str }), is.obj({ error: is.str })))),
994
- getJoinedRows: is.fun(is.maybe(is_table_query), is.promise(is.array(is.obj({})))),
995
- },
996
- static_methods: {
997
- find: is.fun([is.maybe(is.obj()), is.maybe(is.obj())], is.promise(is.array(is.class("Table")))),
998
- find_with_external: is.fun([is.maybe(is.obj()), is.maybe(is.obj())], is.promise(is.array(is.or(is.class("Table"), is.obj({ external: is.eq(true) }))))),
999
- findOne: is.fun(is.or(is.obj(), is.str, is.posint), is.maybe(is.or(is.class("Table"), is.obj({ external: is.eq(true) })))),
1000
- create: is.fun(is.str, is.promise(is.class("Table"))),
1001
- create_from_csv: is.fun([is.str, is.str], is.promise(is.or(is.obj({ success: is.str, table: is.class("Table") }), is.obj({ error: is.str })))),
1002
- //update: is.fun([is.posint, is.obj({})], is.promise(is.eq(undefined)))
1003
- },
1004
- };
1005
1061
  module.exports = Table;
1006
1062
  //# sourceMappingURL=table.js.map