@saltcorn/data 0.6.2 → 0.6.3-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.
Files changed (173) 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 +72 -67
  5. package/dist/base-plugin/index.d.ts.map +1 -1
  6. package/dist/base-plugin/types.d.ts.map +1 -1
  7. package/dist/base-plugin/types.js +9 -8
  8. package/dist/base-plugin/types.js.map +1 -1
  9. package/dist/base-plugin/viewtemplates/edit.d.ts +1 -1
  10. package/dist/base-plugin/viewtemplates/edit.d.ts.map +1 -1
  11. package/dist/base-plugin/viewtemplates/edit.js +25 -2
  12. package/dist/base-plugin/viewtemplates/edit.js.map +1 -1
  13. package/dist/base-plugin/viewtemplates/feed.d.ts +1 -1
  14. package/dist/base-plugin/viewtemplates/feed.d.ts.map +1 -1
  15. package/dist/base-plugin/viewtemplates/feed.js +11 -1
  16. package/dist/base-plugin/viewtemplates/feed.js.map +1 -1
  17. package/dist/base-plugin/viewtemplates/list.d.ts +1 -1
  18. package/dist/base-plugin/viewtemplates/list.d.ts.map +1 -1
  19. package/dist/base-plugin/viewtemplates/list.js +23 -11
  20. package/dist/base-plugin/viewtemplates/list.js.map +1 -1
  21. package/dist/base-plugin/viewtemplates/show.d.ts +5 -0
  22. package/dist/base-plugin/viewtemplates/show.d.ts.map +1 -1
  23. package/dist/base-plugin/viewtemplates/show.js +43 -7
  24. package/dist/base-plugin/viewtemplates/show.js.map +1 -1
  25. package/dist/base-plugin/viewtemplates/viewable_fields.d.ts +2 -1
  26. package/dist/base-plugin/viewtemplates/viewable_fields.d.ts.map +1 -1
  27. package/dist/base-plugin/viewtemplates/viewable_fields.js +30 -10
  28. package/dist/base-plugin/viewtemplates/viewable_fields.js.map +1 -1
  29. package/dist/contracts.js +1 -1
  30. package/dist/contracts.js.map +1 -1
  31. package/dist/db/connect.d.ts.map +1 -1
  32. package/dist/db/connect.js +9 -2
  33. package/dist/db/connect.js.map +1 -1
  34. package/dist/db/index.d.ts +6 -0
  35. package/dist/db/index.d.ts.map +1 -1
  36. package/dist/db/index.js +6 -0
  37. package/dist/db/index.js.map +1 -1
  38. package/dist/db/state.d.ts +1 -0
  39. package/dist/db/state.d.ts.map +1 -1
  40. package/dist/db/state.js +13 -4
  41. package/dist/db/state.js.map +1 -1
  42. package/dist/migrate.js +1 -1
  43. package/dist/migrate.js.map +1 -1
  44. package/dist/migrations/202112282254.d.ts +3 -0
  45. package/dist/migrations/202112282254.d.ts.map +1 -0
  46. package/dist/migrations/202112282254.js +5 -0
  47. package/dist/migrations/202112282254.js.map +1 -0
  48. package/dist/models/backup.d.ts +8 -21
  49. package/dist/models/backup.d.ts.map +1 -1
  50. package/dist/models/backup.js +107 -103
  51. package/dist/models/backup.js.map +1 -1
  52. package/dist/models/config.d.ts +39 -179
  53. package/dist/models/config.d.ts.map +1 -1
  54. package/dist/models/config.js +77 -50
  55. package/dist/models/config.js.map +1 -1
  56. package/dist/models/crash.d.ts +40 -47
  57. package/dist/models/crash.d.ts.map +1 -1
  58. package/dist/models/crash.js +40 -39
  59. package/dist/models/crash.js.map +1 -1
  60. package/dist/models/email.d.ts +11 -13
  61. package/dist/models/email.d.ts.map +1 -1
  62. package/dist/models/email.js +19 -15
  63. package/dist/models/email.js.map +1 -1
  64. package/dist/models/eventlog.d.ts +39 -38
  65. package/dist/models/eventlog.d.ts.map +1 -1
  66. package/dist/models/eventlog.js +14 -29
  67. package/dist/models/eventlog.js.map +1 -1
  68. package/dist/models/expression.d.ts +37 -31
  69. package/dist/models/expression.d.ts.map +1 -1
  70. package/dist/models/expression.js +47 -23
  71. package/dist/models/expression.js.map +1 -1
  72. package/dist/models/field.d.ts +125 -121
  73. package/dist/models/field.d.ts.map +1 -1
  74. package/dist/models/field.js +125 -147
  75. package/dist/models/field.js.map +1 -1
  76. package/dist/models/fieldrepeat.d.ts +25 -20
  77. package/dist/models/fieldrepeat.d.ts.map +1 -1
  78. package/dist/models/fieldrepeat.js +8 -14
  79. package/dist/models/fieldrepeat.js.map +1 -1
  80. package/dist/models/file.d.ts +56 -58
  81. package/dist/models/file.d.ts.map +1 -1
  82. package/dist/models/file.js +25 -52
  83. package/dist/models/file.js.map +1 -1
  84. package/dist/models/form.d.ts +69 -50
  85. package/dist/models/form.d.ts.map +1 -1
  86. package/dist/models/form.js +49 -49
  87. package/dist/models/form.js.map +1 -1
  88. package/dist/models/index.d.ts +39 -0
  89. package/dist/models/index.d.ts.map +1 -1
  90. package/dist/models/index.js.map +1 -1
  91. package/dist/models/layout.d.ts +16 -31
  92. package/dist/models/layout.d.ts.map +1 -1
  93. package/dist/models/layout.js +2 -4
  94. package/dist/models/layout.js.map +1 -1
  95. package/dist/models/library.d.ts +21 -19
  96. package/dist/models/library.d.ts.map +1 -1
  97. package/dist/models/library.js +10 -8
  98. package/dist/models/library.js.map +1 -1
  99. package/dist/models/pack.d.ts +37 -87
  100. package/dist/models/pack.d.ts.map +1 -1
  101. package/dist/models/pack.js +120 -87
  102. package/dist/models/pack.js.map +1 -1
  103. package/dist/models/page.d.ts +23 -47
  104. package/dist/models/page.d.ts.map +1 -1
  105. package/dist/models/page.js +16 -40
  106. package/dist/models/page.js.map +1 -1
  107. package/dist/models/plugin.d.ts +41 -65
  108. package/dist/models/plugin.d.ts.map +1 -1
  109. package/dist/models/plugin.js +17 -39
  110. package/dist/models/plugin.js.map +1 -1
  111. package/dist/models/role.d.ts +18 -11
  112. package/dist/models/role.d.ts.map +1 -1
  113. package/dist/models/role.js +16 -8
  114. package/dist/models/role.js.map +1 -1
  115. package/dist/models/scheduler.d.ts +8 -8
  116. package/dist/models/scheduler.d.ts.map +1 -1
  117. package/dist/models/scheduler.js +17 -14
  118. package/dist/models/scheduler.js.map +1 -1
  119. package/dist/models/table.d.ts +87 -133
  120. package/dist/models/table.d.ts.map +1 -1
  121. package/dist/models/table.js +237 -182
  122. package/dist/models/table.js.map +1 -1
  123. package/dist/models/table_constraints.d.ts +44 -39
  124. package/dist/models/table_constraints.d.ts.map +1 -1
  125. package/dist/models/table_constraints.js +13 -32
  126. package/dist/models/table_constraints.js.map +1 -1
  127. package/dist/models/tenant.d.ts +6 -0
  128. package/dist/models/tenant.d.ts.map +1 -1
  129. package/dist/models/tenant.js +9 -0
  130. package/dist/models/tenant.js.map +1 -1
  131. package/dist/models/trigger.d.ts +50 -69
  132. package/dist/models/trigger.d.ts.map +1 -1
  133. package/dist/models/trigger.js +8 -34
  134. package/dist/models/trigger.js.map +1 -1
  135. package/dist/models/user.d.ts +108 -142
  136. package/dist/models/user.d.ts.map +1 -1
  137. package/dist/models/user.js +51 -71
  138. package/dist/models/user.js.map +1 -1
  139. package/dist/models/view.d.ts +94 -98
  140. package/dist/models/view.d.ts.map +1 -1
  141. package/dist/models/view.js +103 -80
  142. package/dist/models/view.js.map +1 -1
  143. package/dist/models/workflow.d.ts +23 -21
  144. package/dist/models/workflow.d.ts.map +1 -1
  145. package/dist/models/workflow.js +9 -17
  146. package/dist/models/workflow.js.map +1 -1
  147. package/dist/plugin-helper.d.ts.map +1 -1
  148. package/dist/plugin-helper.js +30 -12
  149. package/dist/plugin-helper.js.map +1 -1
  150. package/dist/tests/calc.test.js +13 -0
  151. package/dist/tests/calc.test.js.map +1 -1
  152. package/dist/tests/exact_views.test.js +214 -0
  153. package/dist/tests/exact_views.test.js.map +1 -1
  154. package/dist/tests/table.test.js +57 -2
  155. package/dist/tests/table.test.js.map +1 -1
  156. package/dist/tsconfig.ref.tsbuildinfo +1 -1
  157. package/dist/utils.d.ts +2 -0
  158. package/dist/utils.d.ts.map +1 -1
  159. package/dist/utils.js +26 -0
  160. package/dist/utils.js.map +1 -1
  161. package/package.json +17 -5
  162. package/dist/coverage/lcov-report/block-navigation.d.ts +0 -2
  163. package/dist/coverage/lcov-report/block-navigation.d.ts.map +0 -1
  164. package/dist/coverage/lcov-report/block-navigation.js +0 -66
  165. package/dist/coverage/lcov-report/block-navigation.js.map +0 -1
  166. package/dist/coverage/lcov-report/prettify.d.ts +0 -1
  167. package/dist/coverage/lcov-report/prettify.d.ts.map +0 -1
  168. package/dist/coverage/lcov-report/prettify.js +0 -478
  169. package/dist/coverage/lcov-report/prettify.js.map +0 -1
  170. package/dist/coverage/lcov-report/sorter.d.ts +0 -2
  171. package/dist/coverage/lcov-report/sorter.d.ts.map +0 -1
  172. package/dist/coverage/lcov-report/sorter.js +0 -141
  173. package/dist/coverage/lcov-report/sorter.js.map +0 -1
@@ -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,18 @@ 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)}"`;
266
+ }
267
+ async resetSequence() {
268
+ const fields = await this.getFields();
269
+ const pk = fields.find((f) => f.primary_key);
270
+ if (!pk) {
271
+ throw new Error("Unable to find a field with a primary key.");
272
+ }
273
+ if (db_1.default.reset_sequence &&
274
+ (0, common_types_1.instanceOfType)(pk.type) &&
275
+ pk.type.name === "Integer")
276
+ await db_1.default.reset_sequence(this.name);
261
277
  }
262
278
  /**
263
279
  * Delete rows from table
@@ -266,7 +282,7 @@ class Table {
266
282
  */
267
283
  async deleteRows(where) {
268
284
  // get triggers on delete
269
- const triggers = await Trigger.getTableTriggers("Delete", this);
285
+ const triggers = await trigger_1.default.getTableTriggers("Delete", this);
270
286
  if (triggers.length > 0) {
271
287
  const rows = await this.getRows(where);
272
288
  for (const trigger of triggers) {
@@ -276,7 +292,8 @@ class Table {
276
292
  }
277
293
  }
278
294
  }
279
- await db.deleteWhere(this.name, where);
295
+ await db_1.default.deleteWhere(this.name, where);
296
+ await this.resetSequence();
280
297
  }
281
298
  /**
282
299
  * Returns row with only fields that can be read from db (readFromDB flag)
@@ -284,9 +301,11 @@ class Table {
284
301
  * @returns {*}
285
302
  */
286
303
  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]);
304
+ if (this.fields) {
305
+ for (const f of this.fields) {
306
+ if (f.type && (0, common_types_1.instanceOfType)(f.type) && f.type.readFromDB)
307
+ row[f.name] = f.type.readFromDB(row[f.name]);
308
+ }
290
309
  }
291
310
  return row;
292
311
  }
@@ -297,7 +316,7 @@ class Table {
297
316
  */
298
317
  async getRow(where = {}) {
299
318
  await this.getFields();
300
- const row = await db.selectMaybeOne(this.name, where);
319
+ const row = await db_1.default.selectMaybeOne(this.name, where);
301
320
  if (!row)
302
321
  return null;
303
322
  return apply_calculated_fields([this.readFromDB(row)], this.fields)[0];
@@ -310,7 +329,7 @@ class Table {
310
329
  */
311
330
  async getRows(where = {}, selopts) {
312
331
  await this.getFields();
313
- const rows = await db.select(this.name, where, selopts);
332
+ const rows = await db_1.default.select(this.name, where, selopts);
314
333
  return apply_calculated_fields(rows.map((r) => this.readFromDB(r)), this.fields);
315
334
  }
316
335
  /**
@@ -319,7 +338,7 @@ class Table {
319
338
  * @returns {Promise<number>}
320
339
  */
321
340
  async countRows(where) {
322
- return await db.count(this.name, where);
341
+ return await db_1.default.count(this.name, where);
323
342
  }
324
343
  /**
325
344
  * Return distinct Values for column in table
@@ -328,7 +347,7 @@ class Table {
328
347
  * @returns {Promise<Object[]>}
329
348
  */
330
349
  async distinctValues(fieldnm) {
331
- const res = await db.query(`select distinct "${db.sqlsanitize(fieldnm)}" from ${this.sql_name}`);
350
+ const res = await db_1.default.query(`select distinct "${db_1.default.sqlsanitize(fieldnm)}" from ${this.sql_name}`);
332
351
  return res.rows.map((r) => r[fieldnm]);
333
352
  }
334
353
  /**
@@ -344,15 +363,15 @@ class Table {
344
363
  const fields = await this.getFields();
345
364
  const pk_name = this.pk_name;
346
365
  if (fields.some((f) => f.calculated && f.stored)) {
347
- existing = await db.selectOne(this.name, { [pk_name]: id });
366
+ existing = await db_1.default.selectOne(this.name, { [pk_name]: id });
348
367
  v = await apply_calculated_fields_stored({ ...existing, ...v_in }, this.fields);
349
368
  }
350
369
  else
351
370
  v = v_in;
352
371
  if (this.versioned) {
353
372
  if (!existing)
354
- existing = await db.selectOne(this.name, { [pk_name]: id });
355
- await db.insert(this.name + "__history", {
373
+ existing = await db_1.default.selectOne(this.name, { [pk_name]: id });
374
+ await db_1.default.insert(this.name + "__history", {
356
375
  ...existing,
357
376
  ...v,
358
377
  [pk_name]: id,
@@ -363,14 +382,14 @@ class Table {
363
382
  _userid,
364
383
  });
365
384
  }
366
- await db.update(this.name, v, id, { pk_name });
385
+ await db_1.default.update(this.name, v, id, { pk_name });
367
386
  if (typeof existing === "undefined") {
368
- const triggers = await Trigger.getTableTriggers("Update", this);
387
+ const triggers = await trigger_1.default.getTableTriggers("Update", this);
369
388
  if (triggers.length > 0)
370
- existing = await db.selectOne(this.name, { [pk_name]: id });
389
+ existing = await db_1.default.selectOne(this.name, { [pk_name]: id });
371
390
  }
372
391
  const newRow = { ...existing, ...v, [pk_name]: id };
373
- await Trigger.runTableTriggers("Update", this, newRow);
392
+ await trigger_1.default.runTableTriggers("Update", this, newRow);
374
393
  }
375
394
  /**
376
395
  * Try to Update row
@@ -395,11 +414,13 @@ class Table {
395
414
  * @returns {Promise<void>}
396
415
  */
397
416
  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);
417
+ const schema = db_1.default.getTenantSchemaPrefix();
418
+ 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]);
419
+ const triggers = await trigger_1.default.getTableTriggers("Update", this);
401
420
  if (triggers.length > 0) {
402
421
  const row = await this.getRow({ id });
422
+ if (!row)
423
+ throw new Error(`Unable to find row with id: ${id}`);
403
424
  for (const trigger of triggers) {
404
425
  await trigger.run(row);
405
426
  }
@@ -410,7 +431,11 @@ class Table {
410
431
  * @type {string}
411
432
  */
412
433
  get pk_name() {
413
- return this.fields.find((f) => f.primary_key).name;
434
+ const pkField = this.fields?.find((f) => f.primary_key)?.name;
435
+ if (!pkField) {
436
+ throw new Error("A primary key field is mandatory");
437
+ }
438
+ return pkField;
414
439
  }
415
440
  /**
416
441
  * Insert row
@@ -422,16 +447,16 @@ class Table {
422
447
  await this.getFields();
423
448
  const v = await apply_calculated_fields_stored(v_in, this.fields);
424
449
  const pk_name = this.pk_name;
425
- const id = await db.insert(this.name, v, { pk_name });
450
+ const id = await db_1.default.insert(this.name, v, { pk_name });
426
451
  if (this.versioned)
427
- await db.insert(this.name + "__history", {
452
+ await db_1.default.insert(this.name + "__history", {
428
453
  ...v,
429
454
  [pk_name]: id,
430
455
  _version: 1,
431
456
  _userid,
432
457
  _time: new Date(),
433
458
  });
434
- Trigger.runTableTriggers("Insert", this, { [pk_name]: id, ...v });
459
+ trigger_1.default.runTableTriggers("Insert", this, { [pk_name]: id, ...v });
435
460
  return id;
436
461
  }
437
462
  /**
@@ -455,7 +480,10 @@ class Table {
455
480
  */
456
481
  async getFields() {
457
482
  if (!this.fields) {
458
- this.fields = await Field.find({ table_id: this.id }, { orderBy: "id" });
483
+ this.fields = await field_1.default.find({ table_id: this.id }, { orderBy: "id" });
484
+ for (let field of this.fields) {
485
+ field.table = this;
486
+ }
459
487
  }
460
488
  return this.fields;
461
489
  }
@@ -465,12 +493,15 @@ class Table {
465
493
  */
466
494
  // todo create function that returns history table name for table
467
495
  async create_history_table() {
468
- const schemaPrefix = db.getTenantSchemaPrefix();
496
+ const schemaPrefix = db_1.default.getTenantSchemaPrefix();
469
497
  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;
498
+ const flds = fields.map((f) => `,"${(0, internal_1.sqlsanitize)(f.name)}" ${f.sql_bare_type}`);
499
+ const pk = fields.find((f) => f.primary_key)?.name;
500
+ if (!pk) {
501
+ throw new Error("Unable to find a field with a primary key.");
502
+ }
472
503
  // create history table
473
- await db.query(`create table ${schemaPrefix}"${sqlsanitize(this.name)}__history" (
504
+ await db_1.default.query(`create table ${schemaPrefix}"${(0, internal_1.sqlsanitize)(this.name)}__history" (
474
505
  _version integer,
475
506
  _time timestamp,
476
507
  _userid integer
@@ -483,9 +514,9 @@ class Table {
483
514
  * @returns {Promise<void>}
484
515
  */
485
516
  async drop_history_table() {
486
- const schemaPrefix = db.getTenantSchemaPrefix();
487
- await db.query(`
488
- drop table ${schemaPrefix}"${sqlsanitize(this.name)}__history";`);
517
+ const schemaPrefix = db_1.default.getTenantSchemaPrefix();
518
+ await db_1.default.query(`
519
+ drop table ${schemaPrefix}"${(0, internal_1.sqlsanitize)(this.name)}__history";`);
489
520
  }
490
521
  /**
491
522
  * Rename table
@@ -494,19 +525,19 @@ class Table {
494
525
  */
495
526
  async rename(new_name) {
496
527
  //in transaction
497
- if (db.isSQLite)
528
+ if (db_1.default.isSQLite)
498
529
  throw new InvalidAdminAction("Cannot rename table on SQLite");
499
- const schemaPrefix = db.getTenantSchemaPrefix();
500
- const client = await db.getClient();
530
+ const schemaPrefix = db_1.default.getTenantSchemaPrefix();
531
+ const client = await db_1.default.getClient();
501
532
  await client.query(`BEGIN`);
502
533
  try {
503
534
  //rename table
504
- await db.query(`alter table ${schemaPrefix}"${sqlsanitize(this.name)}" rename to "${sqlsanitize(new_name)}";`);
535
+ await db_1.default.query(`alter table ${schemaPrefix}"${(0, internal_1.sqlsanitize)(this.name)}" rename to "${(0, internal_1.sqlsanitize)(new_name)}";`);
505
536
  //change refs
506
- await db.query(`update ${schemaPrefix}_sc_fields set reftable_name=$1 where reftable_name=$2`, [sqlsanitize(new_name), sqlsanitize(this.name)]);
537
+ 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
538
  //rename history
508
539
  if (this.versioned)
509
- await db.query(`alter table ${schemaPrefix}"${sqlsanitize(this.name)}__history" rename to "${sqlsanitize(new_name)}__history";`);
540
+ 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
541
  //1. change record
511
542
  await this.update({ name: new_name });
512
543
  await client.query(`COMMIT`);
@@ -529,17 +560,25 @@ class Table {
529
560
  if (new_table_rec.ownership_field_id === "")
530
561
  delete new_table_rec.ownership_field_id;
531
562
  const existing = await Table.findOne({ id: this.id });
563
+ if (!existing) {
564
+ throw new Error(`Unable to find table with id: ${this.id}`);
565
+ }
532
566
  const { external, fields, ...upd_rec } = new_table_rec;
533
- await db.update("_sc_tables", upd_rec, this.id);
567
+ await db_1.default.update("_sc_tables", upd_rec, this.id);
534
568
  await require("../db/state").getState().refresh_tables();
535
569
  const new_table = await Table.findOne({ id: this.id });
536
- if (new_table.versioned && !existing.versioned) {
537
- await new_table.create_history_table();
570
+ if (!new_table) {
571
+ throw new Error(`Unable to find table with id: ${this.id}`);
538
572
  }
539
- else if (!new_table.versioned && existing.versioned) {
540
- await new_table.drop_history_table();
573
+ else {
574
+ if (new_table.versioned && !existing.versioned) {
575
+ await new_table.create_history_table();
576
+ }
577
+ else if (!new_table.versioned && existing.versioned) {
578
+ await new_table.drop_history_table();
579
+ }
580
+ Object.assign(this, new_table_rec);
541
581
  }
542
- Object.assign(this, new_table_rec);
543
582
  }
544
583
  /**
545
584
  * Get table history data
@@ -547,7 +586,7 @@ class Table {
547
586
  * @returns {Promise<*>}
548
587
  */
549
588
  async get_history(id) {
550
- return await db.select(`${sqlsanitize(this.name)}__history`, { id }, { orderBy: "_version" });
589
+ return await db_1.default.select(`${(0, internal_1.sqlsanitize)(this.name)}__history`, { id }, { orderBy: "_version" });
551
590
  }
552
591
  /**
553
592
  * Enable constraints
@@ -568,7 +607,7 @@ class Table {
568
607
  let rows;
569
608
  try {
570
609
  const s = await getLines(filePath, 500);
571
- rows = await csvtojson().fromString(s); // todo agrument type unknown
610
+ rows = await (0, csvtojson_1.default)().fromString(s); // todo agrument type unknown
572
611
  }
573
612
  catch (e) {
574
613
  return { error: `Error processing CSV file` };
@@ -595,14 +634,14 @@ class Table {
595
634
  type = "String";
596
635
  const label = (k.charAt(0).toUpperCase() + k.slice(1)).replace(/_/g, " ");
597
636
  //can fail here if: non integer i d, duplicate headers, invalid name
598
- const fld = new Field({
599
- name: Field.labelToName(k),
637
+ const fld = new field_1.default({
638
+ name: field_1.default.labelToName(k),
600
639
  required,
601
640
  type,
602
641
  table,
603
642
  label,
604
643
  });
605
- if (db.sqlsanitize(k.toLowerCase()) === "id") {
644
+ if (db_1.default.sqlsanitize(k.toLowerCase()) === "id") {
606
645
  if (type !== "Integer") {
607
646
  await table.delete();
608
647
  return { error: `Columns named "id" must have only integers` };
@@ -613,14 +652,14 @@ class Table {
613
652
  }
614
653
  continue;
615
654
  }
616
- if (db.sqlsanitize(fld.name) === "") {
655
+ if (db_1.default.sqlsanitize(fld.name) === "") {
617
656
  await table.delete();
618
657
  return {
619
658
  error: `Invalid column name ${k} - Use A-Z, a-z, 0-9, _ only`,
620
659
  };
621
660
  }
622
661
  try {
623
- await Field.create(fld);
662
+ await field_1.default.create(fld);
624
663
  }
625
664
  catch (e) {
626
665
  await table.delete();
@@ -628,7 +667,7 @@ class Table {
628
667
  }
629
668
  }
630
669
  const parse_res = await table.import_csv_file(filePath);
631
- if (parse_res.error) {
670
+ if ((0, common_types_1.instanceOfErrorMsg)(parse_res)) {
632
671
  await table.delete();
633
672
  return { error: parse_res.error };
634
673
  }
@@ -648,7 +687,7 @@ class Table {
648
687
  const { readStateStrict } = require("../plugin-helper");
649
688
  try {
650
689
  const s = await getLines(filePath, 1);
651
- [headers] = await csvtojson({
690
+ [headers] = await (0, csvtojson_1.default)({
652
691
  output: "csv",
653
692
  noheader: true,
654
693
  }).fromString(s); // todo agrument type unknown
@@ -680,15 +719,15 @@ class Table {
680
719
  const colRe = new RegExp(`(${Object.keys(okHeaders).join("|")})`);
681
720
  let i = 1;
682
721
  let rejects = 0;
683
- const client = db.isSQLite ? db : await db.getClient();
684
- const stats = await fs.promises.stat(filePath);
722
+ const client = db_1.default.isSQLite ? db_1.default : await db_1.default.getClient();
723
+ const stats = await (0, promises_1.stat)(filePath);
685
724
  const fileSizeInMegabytes = stats.size / (1024 * 1024);
686
725
  await client.query("BEGIN");
687
- const readStream = fs.createReadStream(filePath);
726
+ const readStream = (0, fs_1.createReadStream)(filePath);
688
727
  try {
689
- if (db.copyFrom && fileSizeInMegabytes > 1) {
728
+ if (db_1.default.copyFrom && fileSizeInMegabytes > 1) {
690
729
  let theError;
691
- const copyres = await db
730
+ const copyres = await db_1.default
692
731
  .copyFrom(readStream, this.name, fieldNames, client)
693
732
  .catch((cate) => {
694
733
  theError = cate;
@@ -704,7 +743,7 @@ class Table {
704
743
  }
705
744
  else {
706
745
  await new Promise((resolve, reject) => {
707
- csvtojson({
746
+ (0, csvtojson_1.default)({
708
747
  includeColumns: colRe,
709
748
  })
710
749
  .fromStream(readStream)
@@ -719,7 +758,7 @@ class Table {
719
758
  });
720
759
  const rowOk = readStateStrict(rec, fields);
721
760
  if (rowOk)
722
- await db.insert(this.name, rec, {
761
+ await db_1.default.insert(this.name, rec, {
723
762
  noid: true,
724
763
  client,
725
764
  pk_name,
@@ -729,7 +768,7 @@ class Table {
729
768
  }
730
769
  catch (e) {
731
770
  await client.query("ROLLBACK");
732
- if (!db.isSQLite)
771
+ if (!db_1.default.isSQLite)
733
772
  await client.release(true);
734
773
  reject({ error: `${e.message} in row ${i}` });
735
774
  }
@@ -748,12 +787,12 @@ class Table {
748
787
  };
749
788
  }
750
789
  await client.query("COMMIT");
751
- if (!db.isSQLite)
790
+ if (!db_1.default.isSQLite)
752
791
  await client.release(true);
753
- 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)) {
792
+ await this.resetSequence();
793
+ if (recalc_stored &&
794
+ this.fields &&
795
+ this.fields.some((f) => f.calculated && f.stored)) {
757
796
  await recalculate_for_stored(this);
758
797
  }
759
798
  return {
@@ -768,12 +807,12 @@ class Table {
768
807
  */
769
808
  async import_json_file(filePath, skip_first_data_row) {
770
809
  // todo argument type buffer is not assignable for type String...
771
- const file_rows = JSON.parse(await fs.promises.readFile(filePath));
810
+ const file_rows = JSON.parse(await (await (0, promises_1.readFile)(filePath)).toString());
772
811
  const fields = await this.getFields();
773
812
  const pk_name = this.pk_name;
774
813
  const { readState } = require("../plugin-helper");
775
814
  let i = 1;
776
- const client = db.isSQLite ? db : await db.getClient();
815
+ const client = db_1.default.isSQLite ? db_1.default : await db_1.default.getClient();
777
816
  await client.query("BEGIN");
778
817
  for (const rec of file_rows) {
779
818
  i += 1;
@@ -788,21 +827,19 @@ class Table {
788
827
  });
789
828
  try {
790
829
  readState(rec, fields);
791
- await db.insert(this.name, rec, { noid: true, client, pk_name });
830
+ await db_1.default.insert(this.name, rec, { noid: true, client, pk_name });
792
831
  }
793
832
  catch (e) {
794
833
  await client.query("ROLLBACK");
795
- if (!db.isSQLite)
834
+ if (!db_1.default.isSQLite)
796
835
  await client.release(true);
797
836
  return { error: `${e.message} in row ${i}` };
798
837
  }
799
838
  }
800
839
  await client.query("COMMIT");
801
- if (!db.isSQLite)
840
+ if (!db_1.default.isSQLite)
802
841
  await client.release(true);
803
- const pk = fields.find((f) => f.primary_key);
804
- if (db.reset_sequence && pk.type.name === "Integer")
805
- await db.reset_sequence(this.name);
842
+ await this.resetSequence();
806
843
  return {
807
844
  success: `Imported ${file_rows.length} rows into table ${this.name}`,
808
845
  };
@@ -819,21 +856,47 @@ class Table {
819
856
  for (const f of fields) {
820
857
  if (f.is_fkey && f.type !== "File") {
821
858
  const table = await Table.findOne({ name: f.reftable_name });
859
+ if (!table)
860
+ throw new Error(`Unable to find table '${f.reftable_name}`);
822
861
  await table.getFields();
862
+ if (!table.fields)
863
+ throw new Error(`The table '${f.reftable_name} has no fields.`);
823
864
  for (const pf of table.fields.filter((f) => !f.calculated || f.stored)) {
824
865
  parent_field_list.push(`${f.name}.${pf.name}`);
825
866
  if (pf.is_fkey && pf.type !== "File" && allow_double) {
826
867
  const table1 = await Table.findOne({ name: pf.reftable_name });
868
+ if (!table1)
869
+ throw new Error(`Unable to find table '${pf.reftable_name}`);
827
870
  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
- }
871
+ if (!table1.fields)
872
+ throw new Error(`The table '${pf.reftable_name} has no fields.`);
873
+ if (table1.fields)
874
+ for (const gpf of table1.fields.filter((f) => !f.calculated || f.stored)) {
875
+ parent_field_list.push(`${f.name}.${pf.name}.${gpf.name}`);
876
+ }
831
877
  parent_relations.push({ key_field: pf, through: f, table: table1 });
832
878
  }
833
879
  }
834
880
  parent_relations.push({ key_field: f, table });
835
881
  }
836
882
  }
883
+ const o2o_rels = await field_1.default.find({
884
+ reftable_name: this.name,
885
+ is_unique: true,
886
+ });
887
+ for (const relation of o2o_rels) {
888
+ const related_table = await Table.findOne({ id: relation.table_id });
889
+ if (related_table) {
890
+ const relfields = await related_table.getFields();
891
+ for (const relfield of relfields) {
892
+ parent_field_list.push(`${related_table.name}.${relation.name}->${relfield.name}`);
893
+ parent_relations.push({
894
+ key_field: relation,
895
+ ontable: related_table,
896
+ });
897
+ }
898
+ }
899
+ }
837
900
  return { parent_relations, parent_field_list };
838
901
  }
839
902
  /**
@@ -841,12 +904,15 @@ class Table {
841
904
  * @returns {Promise<{child_relations: object[], child_field_list: object[]}>}
842
905
  */
843
906
  async get_child_relations() {
844
- const cfields = await Field.find({ reftable_name: this.name });
907
+ const cfields = await field_1.default.find({ reftable_name: this.name });
845
908
  let child_relations = [];
846
909
  let child_field_list = [];
847
910
  for (const f of cfields) {
848
911
  if (f.is_fkey) {
849
912
  const table = await Table.findOne({ id: f.table_id });
913
+ if (!table) {
914
+ throw new Error(`Unable to find table with id: ${f.table_id}`);
915
+ }
850
916
  child_field_list.push(`${table.name}.${f.name}`);
851
917
  await table.getFields();
852
918
  child_relations.push({ key_field: f, table });
@@ -865,7 +931,7 @@ class Table {
865
931
  let joinq = "";
866
932
  let joinTables = [];
867
933
  let joinFields = opts.joinFields || [];
868
- const schema = db.getTenantSchemaPrefix();
934
+ const schema = db_1.default.getTenantSchemaPrefix();
869
935
  fields
870
936
  .filter((f) => f.type === "File")
871
937
  .forEach((f) => {
@@ -875,17 +941,29 @@ class Table {
875
941
  target: `filename`,
876
942
  };
877
943
  });
878
- for (const [fldnm, { ref, target, through }] of Object.entries(joinFields)) {
879
- const reffield = fields.find((f) => f.name === ref);
944
+ for (const [fldnm, { ref, target, through, ontable }] of Object.entries(joinFields)) {
945
+ let reffield;
946
+ if (ontable) {
947
+ const ontableTbl = Table.findOne({ name: ontable });
948
+ if (!ontableTbl)
949
+ throw new InvalidConfiguration(`Related table ${ontable} not found in table ${this.name}`);
950
+ reffield = (await ontableTbl.getFields()).find((f) => f.name === ref);
951
+ }
952
+ else {
953
+ reffield = fields.find((f) => f.name === ref);
954
+ }
880
955
  if (!reffield)
881
956
  throw new InvalidConfiguration(`Key field ${ref} not found in table ${this.name}`);
882
- const reftable = reffield.reftable_name;
957
+ const reftable = ontable || reffield.reftable_name;
883
958
  if (!reftable)
884
959
  throw new InvalidConfiguration(`Field ${ref} is not a key field`);
885
- const jtNm = `${sqlsanitize(reftable)}_jt_${sqlsanitize(ref)}`;
960
+ const jtNm = `${(0, internal_1.sqlsanitize)(reftable)}_jt_${(0, internal_1.sqlsanitize)(ref)}`;
886
961
  if (!joinTables.includes(jtNm)) {
887
962
  joinTables.push(jtNm);
888
- joinq += ` left join ${schema}"${sqlsanitize(reftable)}" ${jtNm} on ${jtNm}."${reffield.refname}"=a."${sqlsanitize(ref)}"`;
963
+ if (ontable)
964
+ joinq += ` left join ${schema}"${(0, internal_1.sqlsanitize)(reftable)}" ${jtNm} on ${jtNm}."${(0, internal_1.sqlsanitize)(ref)}"=a."${reffield.refname}"`;
965
+ else
966
+ joinq += ` left join ${schema}"${(0, internal_1.sqlsanitize)(reftable)}" ${jtNm} on ${jtNm}."${reffield.refname}"=a."${(0, internal_1.sqlsanitize)(ref)}"`;
889
967
  }
890
968
  if (through) {
891
969
  const throughTable = await Table.findOne({
@@ -898,48 +976,42 @@ class Table {
898
976
  if (!throughRefField)
899
977
  throw new InvalidConfiguration(`Reference field field ${through} not found in table ${throughTable.name}`);
900
978
  const finalTable = throughRefField.reftable_name;
901
- const jtNm1 = `${sqlsanitize(reftable)}_jt_${sqlsanitize(through)}_jt_${sqlsanitize(ref)}`;
979
+ const jtNm1 = `${(0, internal_1.sqlsanitize)(reftable)}_jt_${(0, internal_1.sqlsanitize)(through)}_jt_${(0, internal_1.sqlsanitize)(ref)}`;
902
980
  if (!joinTables.includes(jtNm1)) {
981
+ if (!finalTable)
982
+ throw new Error("Unable to build a joind without a reftable_name.");
903
983
  joinTables.push(jtNm1);
904
- joinq += ` left join ${schema}"${sqlsanitize(finalTable)}" ${jtNm1} on ${jtNm1}.id=${jtNm}."${sqlsanitize(through)}"`;
984
+ joinq += ` left join ${schema}"${(0, internal_1.sqlsanitize)(finalTable)}" ${jtNm1} on ${jtNm1}.id=${jtNm}."${(0, internal_1.sqlsanitize)(through)}"`;
905
985
  }
906
- fldNms.push(`${jtNm1}.${sqlsanitize(target)} as ${sqlsanitize(fldnm)}`);
986
+ fldNms.push(`${jtNm1}.${(0, internal_1.sqlsanitize)(target)} as ${(0, internal_1.sqlsanitize)(fldnm)}`);
907
987
  }
908
988
  else {
909
- fldNms.push(`${jtNm}.${sqlsanitize(target)} as ${sqlsanitize(fldnm)}`);
989
+ fldNms.push(`${jtNm}.${(0, internal_1.sqlsanitize)(target)} as ${(0, internal_1.sqlsanitize)(fldnm)}`);
910
990
  }
911
991
  }
912
992
  for (const f of fields.filter((f) => !f.calculated || f.stored)) {
913
- fldNms.push(`a."${sqlsanitize(f.name)}"`);
993
+ fldNms.push(`a."${(0, internal_1.sqlsanitize)(f.name)}"`);
914
994
  }
915
995
  Object.entries(opts.aggregations || {}).forEach(([fldnm, { table, ref, field, where, aggregate, subselect }]) => {
916
996
  if (aggregate.startsWith("Latest ")) {
917
997
  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)}`);
998
+ 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
999
  }
920
1000
  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)}`);
1001
+ 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
1002
  else
923
- fldNms.push(`(select ${sqlsanitize(aggregate)}(${field ? `"${sqlsanitize(field)}"` : "*"}) from ${schema}"${sqlsanitize(table)}" where "${sqlsanitize(ref)}"=a.id${where ? ` and ${where}` : ""}) ${sqlsanitize(fldnm)}`);
1003
+ 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
1004
  });
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);
1005
+ const whereObj = (0, utils_1.prefixFieldsInWhere)(opts.where, "a");
1006
+ const { where, values } = (0, internal_1.mkWhere)(whereObj, db_1.default.isSQLite);
935
1007
  const selectopts = {
936
1008
  limit: opts.limit,
937
1009
  orderBy: opts.orderBy &&
938
- (opts.orderBy.distance ? opts.orderBy : "a." + opts.orderBy),
1010
+ ((0, internal_1.orderByIsObject)(opts.orderBy) ? opts.orderBy : "a." + opts.orderBy),
939
1011
  orderDesc: opts.orderDesc,
940
1012
  offset: opts.offset,
941
1013
  };
942
- const sql = `SELECT ${fldNms.join()} FROM ${schema}"${sqlsanitize(this.name)}" a ${joinq} ${where} ${mkSelectOptions(selectopts)}`;
1014
+ const sql = `SELECT ${fldNms.join()} FROM ${schema}"${(0, internal_1.sqlsanitize)(this.name)}" a ${joinq} ${where} ${(0, internal_1.mkSelectOptions)(selectopts)}`;
943
1015
  return { sql, values };
944
1016
  }
945
1017
  /**
@@ -949,58 +1021,41 @@ class Table {
949
1021
  async getJoinedRows(opts = {}) {
950
1022
  const fields = await this.getFields();
951
1023
  const { sql, values } = await this.getJoinedQuery(opts);
952
- const res = await db.query(sql, values);
1024
+ const res = await db_1.default.query(sql, values);
953
1025
  return apply_calculated_fields(res.rows, fields);
954
1026
  }
1027
+ async slug_options() {
1028
+ const fields = await this.getFields();
1029
+ const unique_fields = fields.filter((f) => f.is_unique);
1030
+ const opts = [];
1031
+ unique_fields.forEach((f) => {
1032
+ const label = (0, common_types_1.instanceOfType)(f.type) && f.type.name === "String"
1033
+ ? `/slugify-${f.name}`
1034
+ : `/:${f.name}`;
1035
+ opts.push({
1036
+ label,
1037
+ steps: [
1038
+ {
1039
+ field: f.name,
1040
+ unique: true,
1041
+ transform: (0, common_types_1.instanceOfType)(f.type) && f.type.name === "String"
1042
+ ? "slugify"
1043
+ : null,
1044
+ },
1045
+ ],
1046
+ });
1047
+ });
1048
+ opts.unshift({ label: "", steps: [] });
1049
+ return opts;
1050
+ }
1051
+ static async allSlugOptions() {
1052
+ const tables = await Table.find({});
1053
+ const options = {};
1054
+ for (const table of tables) {
1055
+ options[table.name] = await table.slug_options();
1056
+ }
1057
+ return options;
1058
+ }
955
1059
  }
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
1060
  module.exports = Table;
1006
1061
  //# sourceMappingURL=table.js.map