sedentary 0.0.54 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/es/db.js CHANGED
@@ -26,19 +26,22 @@ export class EntryBase {
26
26
  preLoad() { }
27
27
  preRemove() { }
28
28
  preSave() { }
29
- async remove() {
30
- return false;
29
+ remove() {
30
+ return Promise.resolve(false);
31
31
  }
32
- async save() {
33
- return false;
32
+ save() {
33
+ return Promise.resolve(false);
34
34
  }
35
35
  }
36
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging
36
37
  export class Type {
37
38
  constructor(from) {
38
39
  Object.assign(this, from);
39
40
  }
40
41
  }
42
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging
41
43
  export class Attribute extends Type {
44
+ // eslint-disable-next-line @typescript-eslint/no-useless-constructor
42
45
  constructor(from) {
43
46
  super(from);
44
47
  }
@@ -54,10 +57,10 @@ export class Table extends autoImplement() {
54
57
  autoIncrementOwn;
55
58
  oid;
56
59
  findAttribute(name) {
57
- return this.attributes.filter(_ => _.attributeName === name)[0];
60
+ return this.attributes.find(_ => _.attributeName === name);
58
61
  }
59
62
  findField(name) {
60
- return this.attributes.filter(_ => _.fieldName === name)[0];
63
+ return this.attributes.find(_ => _.fieldName === name);
61
64
  }
62
65
  }
63
66
  export class DB {
@@ -68,12 +71,12 @@ export class DB {
68
71
  this.log = log;
69
72
  }
70
73
  findTable(name) {
71
- return this.tables.filter(_ => _.tableName === name)[0];
74
+ return this.tables.find(_ => _.tableName === name);
72
75
  }
73
76
  indexesEq(a, b) {
74
77
  if (a.fields.length !== b.fields.length)
75
78
  return false;
76
- for (const i in a.fields)
79
+ for (let i = 0; i < a.fields.length; ++i)
77
80
  if (a.fields[i] !== b.fields[i])
78
81
  return false;
79
82
  if (a.type !== b.type)
@@ -96,7 +99,7 @@ export class DB {
96
99
  }
97
100
  }
98
101
  syncLog(message) {
99
- this.log(this.sync ? message : "NOT SYNCING: " + message);
102
+ this.log(this.sync ? message : `NOT SYNCING: ${message}`);
100
103
  }
101
104
  }
102
105
  export class Transaction {
@@ -117,12 +120,13 @@ export class Transaction {
117
120
  }
118
121
  this.entries = [];
119
122
  }
120
- async commit() {
123
+ commit() {
121
124
  const { entries } = this;
122
125
  for (const entry of entries)
123
126
  if (entry[actions])
124
127
  entry.postCommit(entry[actions]);
125
128
  this.clean();
129
+ return Promise.resolve();
126
130
  }
127
131
  preCommit() {
128
132
  const { entries } = this;
@@ -130,8 +134,9 @@ export class Transaction {
130
134
  if (entry[actions])
131
135
  entry.preCommit(entry[actions]);
132
136
  }
133
- async rollback() {
137
+ rollback() {
134
138
  this.clean();
139
+ return Promise.resolve();
135
140
  }
136
141
  }
137
142
  const sortedEntries = (obj) => Object.entries(obj).sort((entryA, entryB) => (entryA[0] > entryB[0] ? -1 : 1));
package/dist/es/index.js CHANGED
@@ -5,9 +5,53 @@ const methods = Symbol("methods");
5
5
  const operators = ["=", ">", "<", ">=", "<=", "<>", "IN", "IS NULL", "LIKE", "NOT"];
6
6
  const allowedOption = ["indexes", "int8id", "parent", "primaryKey", "sync", "tableName"];
7
7
  const reservedNames = [
8
- ...["attr2field", "attributeName", "cancel", "class", "construct", "constructor", "defaultValue", "fieldName", "foreignKeys", "load", "name"],
9
- ...["postCommit", "postLoad", "postRemove", "postSave", "preCommit", "preLoad", "preRemove", "preSave", "primaryKey", "prototype", "save", "tableName", "type"]
8
+ "attr2field",
9
+ "attributeName",
10
+ "cancel",
11
+ "class",
12
+ "construct",
13
+ "constructor",
14
+ "defaultValue",
15
+ "fieldName",
16
+ "foreignKeys",
17
+ "load",
18
+ "modelName",
19
+ "name",
20
+ "postCommit",
21
+ "postLoad",
22
+ "postRemove",
23
+ "postSave",
24
+ "preCommit",
25
+ "preLoad",
26
+ "preRemove",
27
+ "preSave",
28
+ "primaryKey",
29
+ "prototype",
30
+ "remove",
31
+ "save",
32
+ "tableName",
33
+ "type",
34
+ "unique"
10
35
  ];
36
+ /** Model and attribute names: ASCII letters, digits, underscore; cannot start with digit. */
37
+ const reModelAttributeName = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
38
+ /** tableName and fieldName: ASCII lowercase letters, digits, underscore; cannot start with digit. */
39
+ const reSqlName = /^[a-z_][a-z0-9_]*$/;
40
+ /**
41
+ * Converts a JavaScript name to the default SQL name (snake_case).
42
+ * Uppercase letters become lowercase preceded by underscore, except the first character
43
+ * which is only lowercased without underscore.
44
+ */
45
+ export function toSqlName(name) {
46
+ if (typeof name !== "string" || name.length === 0)
47
+ throw new Error("toSqlName: 'name' must be a non-empty string");
48
+ let result = name[0].toLowerCase();
49
+ for (let i = 1; i < name.length; i++) {
50
+ const c = name[i];
51
+ result += c >= "A" && c <= "Z" ? `_${c.toLowerCase()}` : c;
52
+ }
53
+ return result;
54
+ }
11
55
  export class Sedentary {
12
56
  autoSync;
13
57
  db;
@@ -35,46 +79,56 @@ export class Sedentary {
35
79
  this.log = log ? log : log === null ? () => { } : console.log;
36
80
  this.doSync = sync;
37
81
  }
38
- Boolean() {
39
- return new Type({ [base]: Boolean, type: "BOOLEAN" });
82
+ Boolean(options) {
83
+ return new Type({ ...options, [base]: Boolean, type: "BOOLEAN" });
40
84
  }
41
- DateTime() {
42
- return new Type({ [base]: Date, type: "DATETIME" });
85
+ DateTime(options) {
86
+ return new Type({ ...options, [base]: Date, type: "DATETIME" });
43
87
  }
44
88
  FKey(attribute, options) {
45
- const { attributeName, fieldName, tableName, type, [base]: _base, [size]: _size } = attribute;
89
+ const { attributeName, fieldName, modelName, tableName, type, unique, [base]: _base, [size]: _size } = attribute;
90
+ if (!unique)
91
+ throw new Error(`Sedentary.FKey: '${modelName}' model: '${attributeName}' attribute: is not unique: can't be used as FKey target`);
46
92
  return new Type({ [base]: _base, foreignKey: { attributeName, fieldName, options, tableName }, [size]: _size, type });
47
93
  }
48
- Float(_size) {
49
- const message = "Sedentary.Float: 'size' argument: Wrong value, expected 4 or 8";
50
- _size = _size ? this.checkSize(_size, message) : 8;
51
- if (_size !== 4 && _size !== 8)
52
- throw new Error(message);
53
- return new Type({ [base]: Number, [size]: _size, type: "FLOAT" });
94
+ Float(options) {
95
+ const sizeFloat = "Sedentary.Float: 'size' argument: Wrong value, expected 4 or 8";
96
+ let storageSize;
97
+ let rest;
98
+ [storageSize, rest] = this.checkSize(sizeFloat, options);
99
+ if (storageSize === undefined)
100
+ storageSize = 8;
101
+ if (storageSize !== 4 && storageSize !== 8)
102
+ throw new Error(sizeFloat);
103
+ return new Type({ ...rest, [base]: Number, [size]: storageSize, type: "FLOAT" });
54
104
  }
55
- Int(_size) {
56
- const message = "Sedentary.Int: 'size' argument: Wrong value, expected 2 or 4";
57
- _size = _size ? this.checkSize(_size, message) : 4;
58
- if (_size !== 2 && _size !== 4)
59
- throw new Error(message);
60
- return new Type({ [base]: Number, [size]: _size, type: "INT" });
105
+ Int(options) {
106
+ const sizeInt = "Sedentary.Int: 'size' argument: Wrong value, expected 2 or 4";
107
+ let storageSize;
108
+ let rest;
109
+ [storageSize, rest] = this.checkSize(sizeInt, options);
110
+ if (storageSize === undefined)
111
+ storageSize = 4;
112
+ if (storageSize !== 2 && storageSize !== 4)
113
+ throw new Error(sizeInt);
114
+ return new Type({ ...rest, [base]: Number, [size]: storageSize, type: "INT" });
61
115
  }
62
- Int8() {
63
- return new Type({ [base]: BigInt, [size]: 8, type: "INT8" });
116
+ Int8(options) {
117
+ return new Type({ ...options, [base]: BigInt, [size]: 8, type: "INT8" });
64
118
  }
65
- JSON() {
66
- return new Type({ [base]: Object, type: "JSON" });
119
+ JSON(options) {
120
+ return new Type({ ...options, [base]: Object, type: "JSON" });
67
121
  }
68
- Number() {
69
- return new Type({ [base]: Number, type: "NUMBER" });
122
+ Number(options) {
123
+ return new Type({ ...options, [base]: Number, type: "NUMBER" });
70
124
  }
71
- None() {
72
- return new Type({ [base]: undefined, type: "NONE" });
125
+ None(options) {
126
+ return new Type({ ...options, [base]: undefined, type: "NONE" });
73
127
  }
74
- VarChar(_size) {
128
+ VarChar(options) {
75
129
  const message = "Sedentary.VarChar: 'size' argument: Wrong value, expected positive integer";
76
- _size = _size ? this.checkSize(_size, message) : undefined;
77
- return new Type({ [base]: String, [size]: _size, type: "VARCHAR" });
130
+ const [maxSize, rest] = this.checkSize(message, options);
131
+ return new Type({ ...rest, [base]: String, [size]: maxSize, type: "VARCHAR" });
78
132
  }
79
133
  checkDB() {
80
134
  if (!this.db)
@@ -103,12 +157,19 @@ export class Sedentary {
103
157
  }
104
158
  return true;
105
159
  }
106
- checkSize(size, message) {
107
- const str = size.toString();
108
- const parsed = parseInt(str, 10);
109
- if (str !== parsed.toString())
160
+ checkSize(message, options) {
161
+ if (!options)
162
+ return [undefined, {}];
163
+ const { size, ...rest } = options;
164
+ if (size === undefined)
165
+ return [undefined, rest];
166
+ if (typeof size !== "number")
110
167
  throw new Error(message);
111
- return parsed;
168
+ if (size !== parseInt(size.toString(), 10))
169
+ throw new Error(message);
170
+ if (size <= 0)
171
+ throw new Error(message);
172
+ return [size, rest];
112
173
  }
113
174
  createWhere(modelName, attributes, where) {
114
175
  if (typeof where === "string")
@@ -189,9 +250,9 @@ export class Sedentary {
189
250
  if (this.autoSync || sync)
190
251
  await this.sync();
191
252
  }
192
- catch (e) {
193
- this.log("Connecting: " + (e instanceof Error ? e.message : JSON.stringify(e)));
194
- throw e;
253
+ catch (error) {
254
+ this.log(`Connecting: ${error instanceof Error ? error.message : JSON.stringify(error)}`);
255
+ throw error;
195
256
  }
196
257
  }
197
258
  async sync() {
@@ -215,6 +276,8 @@ export class Sedentary {
215
276
  this.checkDB();
216
277
  if (typeof modelName !== "string")
217
278
  throw new Error("Sedentary.model: 'name' argument: Wrong type, expected 'string'");
279
+ if (!reModelAttributeName.test(modelName))
280
+ throw new Error(`Sedentary.model: '${modelName}' model: Invalid model name, expected ASCII letters, digits or underscore, cannot start with digit`);
218
281
  if (this.models[modelName])
219
282
  throw new Error(`Sedentary.model: '${modelName}' model: Model already defined`);
220
283
  if (!_attributes)
@@ -235,10 +298,12 @@ export class Sedentary {
235
298
  if (options.parent && options.primaryKey)
236
299
  throw new Error(`Sedentary.model: '${modelName}' model: 'parent' and 'primaryKey' options conflict each other`);
237
300
  let autoIncrement = true;
238
- const { indexes, int8id, parent, primaryKey, sync, tableName } = { sync: this.doSync, tableName: modelName, ...options };
301
+ const { indexes, int8id, parent, primaryKey, sync, tableName } = { sync: this.doSync, tableName: toSqlName(modelName), ...options };
302
+ if (!reSqlName.test(tableName))
303
+ throw new Error(`Sedentary.model: '${modelName}' model: Invalid tableName '${tableName}', expected lowercase ASCII letters, digits or underscore, cannot start with digit`);
239
304
  let aArray = int8id
240
- ? [new Attribute({ ...this.Int8(), attributeName: "id", fieldName: "id", modelName, notNull: true, tableName, unique: true })]
241
- : [new Attribute({ ...this.Int(4), attributeName: "id", fieldName: "id", modelName, notNull: true, tableName, unique: true })];
305
+ ? [new Attribute({ ...this.Int8(), attributeName: "id", fieldName: toSqlName("id"), modelName, notNull: true, tableName, unique: true })]
306
+ : [new Attribute({ ...this.Int({ size: 4 }), attributeName: "id", fieldName: toSqlName("id"), modelName, notNull: true, tableName, unique: true })];
242
307
  let constraints = [{ attribute: aArray[0], constraintName: `${tableName}_id_unique`, type: "u" }];
243
308
  const iArray = [];
244
309
  let pk = aArray[0];
@@ -262,51 +327,37 @@ export class Sedentary {
262
327
  constraints = [];
263
328
  }
264
329
  for (const attributeName of Object.keys(_attributes).sort()) {
330
+ if (!reModelAttributeName.test(attributeName))
331
+ throw new Error(`Sedentary.model: '${modelName}' model: '${attributeName}' attribute: Invalid attribute name, expected ASCII letters, digits or underscore, cannot start with digit`);
265
332
  if (reservedNames.includes(attributeName))
266
333
  throw new Error(`Sedentary.model: '${modelName}' model: '${attributeName}' attribute: Reserved name`);
267
- const call = (defaultValue, fieldName, notNull, unique, func, message1, message2) => {
268
- if (func === this.FKey)
269
- throw new Error(`${message1} 'this.FKey' can't be used directly`);
270
- if (![this.Boolean, this.DateTime, this.Float, this.Int, this.JSON, this.Int8, this.None, this.Number, this.VarChar].includes(func))
271
- throw new Error(`${message1} ${message2}`);
272
- return new Attribute({ attributeName, defaultValue, fieldName, modelName, notNull, tableName, unique, ...func() });
273
- };
274
334
  const attributeDefinition = _attributes[attributeName];
275
335
  let { [base]: _base, defaultValue, fieldName, foreignKey, notNull, [size]: _size, type, unique } = (() => {
276
- const ret = (() => {
277
- if (attributeDefinition instanceof Type)
278
- return new Attribute({ attributeName, fieldName: attributeName, modelName, notNull: false, tableName, ...attributeDefinition });
279
- if (attributeDefinition instanceof Function)
280
- return call(undefined, attributeName, false, false, attributeDefinition, `Sedentary.model: '${modelName}' model: '${attributeName}' attribute:`, "Wrong type, expected 'Attribute'");
281
- if (!(attributeDefinition instanceof Object))
282
- throw new Error(`Sedentary.model: '${modelName}' model: '${attributeName}' attribute: Wrong attribute type, expected 'Attribute'`);
283
- const attributeDefaults = { defaultValue: undefined, fieldName: attributeName, notNull: false, unique: false, ...attributeDefinition };
284
- const { defaultValue, fieldName, notNull, unique, type } = attributeDefaults;
285
- if (defaultValue === null)
286
- throw new Error(`Sedentary.model: '${modelName}' model: '${attributeName}' attribute: 'defaultValue' option: Does 'null' default value really makes sense?`);
287
- if (typeof fieldName !== "string")
288
- throw new Error(`Sedentary.model: '${modelName}' model: '${attributeName}' attribute: 'fieldName' option: Wrong type, expected 'string'`);
289
- if (typeof notNull !== "boolean")
290
- throw new Error(`Sedentary.model: '${modelName}' model: '${attributeName}' attribute: 'notNull' option: Wrong type, expected 'boolean'`);
291
- if (typeof unique !== "boolean")
292
- throw new Error(`Sedentary.model: '${modelName}' model: '${attributeName}' attribute: 'unique' option: Wrong type, expected 'boolean'`);
293
- if (type === undefined)
294
- throw new Error(`Sedentary.model: '${modelName}' model: '${attributeName}' attribute: Missing 'type' option`);
295
- if (type instanceof Type)
296
- return new Attribute({ attributeName, defaultValue, fieldName, modelName, notNull, tableName, unique, ...type });
297
- if (type instanceof Function)
298
- return call(defaultValue, fieldName, notNull, unique, type, `Sedentary.model: '${modelName}' model: '${attributeName}' attribute: 'type' option:`, "Wrong type, expected 'Type'");
299
- throw new Error(`Sedentary.model: '${modelName}' model: '${attributeName}' attribute: 'type' option: Wrong type, expected 'Type'`);
300
- })();
301
- const { [base]: _base, defaultValue } = ret;
302
- if (defaultValue !== undefined) {
303
- if (_base === BigInt && typeof defaultValue !== "bigint")
336
+ if (!(attributeDefinition instanceof Type))
337
+ throw new Error(`Sedentary.model: '${modelName}' model: '${attributeName}' attribute: '${attributeName}': Wrong type, expected 'Type'`);
338
+ const ret = new Attribute({ attributeName, fieldName: toSqlName(attributeName), modelName, notNull: false, tableName, unique: false, ...attributeDefinition });
339
+ const { defaultValue, fieldName, notNull, unique } = ret;
340
+ if (defaultValue === null)
341
+ throw new Error(`Sedentary.model: '${modelName}' model: '${attributeName}' attribute: 'defaultValue' option: Does 'null' default value really make sense?`);
342
+ if (typeof fieldName !== "string")
343
+ throw new Error(`Sedentary.model: '${modelName}' model: '${attributeName}' attribute: 'fieldName' option: Wrong type, expected 'string'`);
344
+ if (!reSqlName.test(fieldName)) {
345
+ throw new Error(`Sedentary.model: '${modelName}' model: '${attributeName}' attribute: Invalid fieldName '${fieldName}', ` +
346
+ "expected lowercase ASCII letters, digits or underscore, cannot start with digit");
347
+ }
348
+ if (typeof notNull !== "boolean")
349
+ throw new Error(`Sedentary.model: '${modelName}' model: '${attributeName}' attribute: 'notNull' option: Wrong type, expected 'boolean'`);
350
+ if (typeof unique !== "boolean")
351
+ throw new Error(`Sedentary.model: '${modelName}' model: '${attributeName}' attribute: 'unique' option: Wrong type, expected 'boolean'`);
352
+ const { [base]: _base, defaultValue: _defaultValue } = ret;
353
+ if (_defaultValue !== undefined) {
354
+ if (_base === BigInt && typeof _defaultValue !== "bigint")
304
355
  throw new Error(`Sedentary.model: '${modelName}' model: '${attributeName}' attribute: 'defaultValue' option: Wrong type, expected 'BigInt'`);
305
- if (_base === Date && !(defaultValue instanceof Date))
356
+ if (_base === Date && !(_defaultValue instanceof Date))
306
357
  throw new Error(`Sedentary.model: '${modelName}' model: '${attributeName}' attribute: 'defaultValue' option: Wrong type, expected 'Date'`);
307
- if (_base === Number && typeof defaultValue !== "number")
358
+ if (_base === Number && typeof _defaultValue !== "number")
308
359
  throw new Error(`Sedentary.model: '${modelName}' model: '${attributeName}' attribute: 'defaultValue' option: Wrong type, expected 'number'`);
309
- if (_base === String && typeof defaultValue !== "string")
360
+ if (_base === String && typeof _defaultValue !== "string")
310
361
  throw new Error(`Sedentary.model: '${modelName}' model: '${attributeName}' attribute: 'defaultValue' option: Wrong type, expected 'string'`);
311
362
  }
312
363
  return ret;
@@ -405,9 +456,9 @@ export class Sedentary {
405
456
  return ret;
406
457
  }, {});
407
458
  for (const foreignKey in foreignKeys) {
408
- if (foreignKey + "Load" in _attributes)
459
+ if (`${foreignKey}Load` in _attributes)
409
460
  throw new Error(`Sedentary.model: '${modelName}' model: '${foreignKey}' attribute: '${foreignKey}Load' inferred methods conflicts with an attribute`);
410
- if (foreignKey + "Load" in _methods)
461
+ if (`${foreignKey}Load` in _methods)
411
462
  throw new Error(`Sedentary.model: '${modelName}' model: '${foreignKey}' attribute: '${foreignKey}Load' inferred methods conflicts with a method`);
412
463
  }
413
464
  for (const method in _methods)
@@ -422,20 +473,20 @@ export class Sedentary {
422
473
  if (attribute in parent[methods])
423
474
  throw new Error(`Sedentary.model: '${modelName}' model: '${attribute}' attribute: conflicts with a method of '${parent.modelName}' model`);
424
475
  for (const foreignKey in parent.foreignKeys)
425
- if (attribute === foreignKey + "Load")
476
+ if (attribute === `${foreignKey}Load`)
426
477
  throw new Error(`Sedentary.model: '${modelName}' model: '${attribute}' attribute: conflicts with an inferred methods of '${parent.modelName}' model`);
427
478
  }
428
479
  for (const foreignKey in foreignKeys) {
429
- if (foreignKey + "Load" in parent[attributes])
480
+ if (`${foreignKey}Load` in parent[attributes])
430
481
  throw new Error(`Sedentary.model: '${modelName}' model: '${foreignKey}' attribute: '${foreignKey}Load' inferred methods conflicts with an attribute of '${parent.modelName}' model`);
431
- if (foreignKey + "Load" in parent[methods])
482
+ if (`${foreignKey}Load` in parent[methods])
432
483
  throw new Error(`Sedentary.model: '${modelName}' model: '${foreignKey}' attribute: '${foreignKey}Load' inferred methods conflicts with a method of '${parent.modelName}' model`);
433
484
  }
434
485
  for (const method in _methods) {
435
486
  if (method in parent[attributes])
436
487
  throw new Error(`Sedentary.model: '${modelName}' model: '${method}' method: conflicts with an attribute of '${parent.modelName}' model`);
437
488
  for (const foreignKey in parent.foreignKeys)
438
- if (foreignKey + "Load" === method)
489
+ if (`${foreignKey}Load` === method)
439
490
  throw new Error(`Sedentary.model: '${modelName}' model: '${method}' method: conflicts with an inferred methods of '${parent.modelName}' model`);
440
491
  }
441
492
  checkParent(parent.parent);
@@ -452,7 +503,7 @@ export class Sedentary {
452
503
  this.db.tables.push(table);
453
504
  const cancel_ = this.db.cancel(tableName);
454
505
  const cancel = (where, tx) => cancel_(this.createWhere(modelName, attr2field, where)[0], tx);
455
- Object.defineProperty(cancel, "name", { value: modelName + ".cancel" });
506
+ Object.defineProperty(cancel, "name", { value: `${modelName}.cancel` });
456
507
  const load_ = this.db.load(tableName, attr2field, pk, ret, table);
457
508
  const load = (where, ...args) => {
458
509
  let order = undefined;
@@ -489,7 +540,7 @@ export class Sedentary {
489
540
  throw new Error(`${modelName}.load: 'tx' argument: Wrong type, expected 'Transaction'`);
490
541
  return load_(this.createWhere(modelName, attr2field, where)[0], order, limit, tx, lock);
491
542
  };
492
- Object.defineProperty(load, "name", { value: modelName + ".load" });
543
+ Object.defineProperty(load, "name", { value: `${modelName}.load` });
493
544
  Object.defineProperty(ret, "cancel", { value: cancel });
494
545
  Object.defineProperty(ret, "name", { value: modelName });
495
546
  Object.defineProperty(ret, "load", { value: load });
@@ -514,7 +565,7 @@ export class Sedentary {
514
565
  ensureActions(this).push({ action: "remove", records });
515
566
  return records;
516
567
  };
517
- Object.defineProperty(ret.prototype.remove, "name", { value: modelName + ".remove" });
568
+ Object.defineProperty(ret.prototype.remove, "name", { value: `${modelName}.remove` });
518
569
  const save = this.db.save(tableName, attr2field, pk);
519
570
  ret.prototype.save = async function () {
520
571
  this.preSave();
@@ -524,7 +575,7 @@ export class Sedentary {
524
575
  ensureActions(this).push({ action: "save", records });
525
576
  return records;
526
577
  };
527
- Object.defineProperty(ret.prototype.save, "name", { value: modelName + ".save" });
578
+ Object.defineProperty(ret.prototype.save, "name", { value: `${modelName}.save` });
528
579
  for (const attribute of aArray)
529
580
  Object.defineProperty(ret, attribute.attributeName, { value: attribute });
530
581
  for (const key of ["attributeName", base, "fieldName", "modelName", size, "tableName", "type", "unique"])
@@ -3,33 +3,37 @@ export declare const base: unique symbol;
3
3
  export declare const loaded: unique symbol;
4
4
  export declare const size: unique symbol;
5
5
  export declare const transaction: unique symbol;
6
- export interface Action {
7
- action: "remove" | "save";
6
+ export type TxAction = {
7
+ action: "remove";
8
+ records: number;
9
+ } | {
10
+ action: "save";
8
11
  records: number | false;
9
- }
12
+ };
10
13
  export declare class EntryBase {
11
14
  constructor(from?: Partial<EntryBase>);
12
15
  construct(): void;
13
- postCommit(actions: Action[]): void;
16
+ postCommit(actions: TxAction[]): void;
14
17
  postLoad(): void;
15
18
  postRemove(deletedRecords: number): void;
16
19
  postSave(savedRecords: number | false): void;
17
- preCommit(actions: Action[]): void;
20
+ preCommit(actions: TxAction[]): void;
18
21
  preLoad(): void;
19
22
  preRemove(): void;
20
23
  preSave(): void;
21
24
  remove(): Promise<boolean>;
22
- save(): Promise<boolean>;
25
+ save(): Promise<number | false>;
23
26
  }
24
27
  export type ForeignKeyActions = "cascade" | "no action" | "restrict" | "set default" | "set null";
25
28
  export interface ForeignKeyOptions {
26
29
  onDelete?: ForeignKeyActions;
27
30
  onUpdate?: ForeignKeyActions;
28
31
  }
29
- export interface Type<T, E> {
32
+ export interface Type<T, N extends boolean, E> {
30
33
  [base]: unknown;
31
34
  entry?: E;
32
35
  native?: T;
36
+ notNull?: N;
33
37
  [size]?: number;
34
38
  type: string;
35
39
  foreignKey?: {
@@ -39,23 +43,23 @@ export interface Type<T, E> {
39
43
  tableName: string;
40
44
  };
41
45
  }
42
- export declare class Type<T, E> {
43
- constructor(from: Type<T, E>);
46
+ export declare class Type<T, N extends boolean, E> {
47
+ constructor(from: Type<T, N, E>);
44
48
  }
45
- export interface Attribute<T, E> extends Type<T, E> {
49
+ export interface Attribute<T, N extends boolean, E> extends Type<T, N, E> {
46
50
  attributeName: string;
47
51
  defaultValue?: unknown;
48
52
  fieldName: string;
49
53
  modelName: string;
50
- notNull: boolean;
54
+ notNull: N;
51
55
  tableName: string;
52
56
  unique?: boolean;
53
57
  }
54
- export declare class Attribute<T, E> extends Type<T, E> {
55
- constructor(from: Attribute<T, E>);
58
+ export declare class Attribute<T, N extends boolean, E> extends Type<T, N, E> {
59
+ constructor(from: Attribute<T, N, E>);
56
60
  }
57
61
  export interface Constraint {
58
- attribute: Attribute<unknown, unknown>;
62
+ attribute: Attribute<unknown, boolean, unknown>;
59
63
  constraintName: string;
60
64
  type: "f" | "u";
61
65
  }
@@ -66,15 +70,15 @@ export interface Index {
66
70
  unique: boolean;
67
71
  }
68
72
  interface ITable {
69
- attributes: Attribute<unknown, unknown>[];
73
+ attributes: Attribute<unknown, boolean, unknown>[];
70
74
  autoIncrement: boolean;
71
75
  constraints: Constraint[];
72
76
  indexes: Index[];
73
77
  model: {
74
- load: (where: any, order?: string[], tx?: Transaction) => Promise<EntryBase[]>;
78
+ load: (where: any, order?: any, tx?: Transaction) => Promise<EntryBase[]>;
75
79
  };
76
- parent?: Attribute<unknown, unknown>;
77
- pk: Attribute<unknown, unknown>;
80
+ parent?: Attribute<unknown, boolean, unknown>;
81
+ pk: Attribute<unknown, boolean, unknown>;
78
82
  sync: boolean;
79
83
  tableName: string;
80
84
  }
@@ -82,8 +86,8 @@ declare const Table_base: new (defaults?: ITable | undefined) => ITable;
82
86
  export declare class Table extends Table_base {
83
87
  autoIncrementOwn?: boolean;
84
88
  oid?: number;
85
- findAttribute(name: string): Attribute<unknown, unknown>;
86
- findField(name: string): Attribute<unknown, unknown>;
89
+ findAttribute(name: string): Attribute<unknown, boolean, unknown>;
90
+ findField(name: string): Attribute<unknown, boolean, unknown>;
87
91
  }
88
92
  export declare abstract class DB<T extends Transaction> {
89
93
  tables: Table[];
@@ -99,9 +103,9 @@ export declare abstract class DB<T extends Transaction> {
99
103
  abstract begin(): Promise<T>;
100
104
  abstract cancel(tableName: string): (where: string, tx?: Transaction) => Promise<number>;
101
105
  abstract escape(value: unknown): string;
102
- abstract load(tableName: string, attributes: Record<string, string>, pk: Attribute<unknown, unknown>, model: new () => EntryBase, table: Table): (where: string, order?: string | string[], limit?: number, tx?: Transaction, lock?: boolean) => Promise<EntryBase[]>;
103
- abstract remove(tableName: string, pk: Attribute<unknown, unknown>): (this: EntryBase & Record<string, unknown>) => Promise<number>;
104
- abstract save(tableName: string, attr2field: Record<string, string>, pk: Attribute<unknown, unknown>): (this: EntryBase & Record<string, unknown>) => Promise<number | false>;
106
+ abstract load(tableName: string, attributes: Record<string, string>, pk: Attribute<unknown, boolean, unknown>, model: new () => EntryBase, table: Table): (where: string, order?: string | string[], limit?: number, tx?: Transaction, lock?: boolean) => Promise<EntryBase[]>;
107
+ abstract remove(tableName: string, pk: Attribute<unknown, boolean, unknown>): (this: EntryBase & Record<string, unknown>) => Promise<number>;
108
+ abstract save(tableName: string, attr2field: Record<string, string>, pk: Attribute<unknown, boolean, unknown>): (this: EntryBase & Record<string, unknown>) => Promise<number | false>;
105
109
  abstract dropConstraints(table: Table): Promise<number[]>;
106
110
  abstract dropFields(table: Table): Promise<void>;
107
111
  abstract dropIndexes(table: Table, constraintIndexes: number[]): Promise<void>;