sedentary 0.0.22 → 0.0.25

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.
@@ -1,6 +1,6 @@
1
- export declare type Natural = Date | Record<string, unknown> | boolean | number | string;
1
+ export declare type Natural = Date | Record<string, unknown> | boolean | number | string | null;
2
2
  export declare class EntryBase {
3
- constructor(from?: Partial<EntryBase> | "load");
3
+ constructor(from?: Partial<EntryBase>);
4
4
  construct(): void;
5
5
  postLoad(): void;
6
6
  postSave(): void;
@@ -31,7 +31,7 @@ export declare class Type<N extends Natural, E> {
31
31
  }
32
32
  export interface Attribute<N extends Natural, E> extends Type<N, E> {
33
33
  attributeName: string;
34
- defaultValue?: unknown;
34
+ defaultValue?: Natural;
35
35
  fieldName: string;
36
36
  modelName: string;
37
37
  notNull: boolean;
@@ -57,7 +57,11 @@ interface ITable {
57
57
  autoIncrement: boolean;
58
58
  constraints: Constraint[];
59
59
  indexes: Index[];
60
- parent: any;
60
+ model: {
61
+ load: (where: any, order?: string[], tx?: Transaction) => Promise<EntryBase[]>;
62
+ };
63
+ parent?: Attribute<Natural, unknown>;
64
+ pk: Attribute<Natural, unknown>;
61
65
  sync: boolean;
62
66
  tableName: string;
63
67
  }
@@ -67,7 +71,7 @@ export declare class Table extends Table_base {
67
71
  oid?: number;
68
72
  findField(name: string): Attribute<Natural, unknown>;
69
73
  }
70
- export declare abstract class DB {
74
+ export declare abstract class DB<T extends Transaction> {
71
75
  tables: Table[];
72
76
  protected log: (message: string) => void;
73
77
  protected sync: boolean;
@@ -78,6 +82,10 @@ export declare abstract class DB {
78
82
  protected indexesEq(a: Index, b: Index): boolean;
79
83
  syncDataBase(): Promise<void>;
80
84
  protected syncLog(message: string): void;
85
+ abstract begin(): Promise<T>;
86
+ abstract escape(value: Natural): string;
87
+ abstract load(tableName: string, attributes: Record<string, string>, pk: Attribute<Natural, unknown>, model: new () => EntryBase, table: Table): (where: string, order?: string[], tx?: Transaction) => Promise<EntryBase[]>;
88
+ abstract save(tableName: string, attributes: Record<string, string>, pk: Attribute<Natural, unknown>): (this: EntryBase & Record<string, Natural>) => Promise<boolean>;
81
89
  abstract dropConstraints(table: Table): Promise<number[]>;
82
90
  abstract dropFields(table: Table): Promise<void>;
83
91
  abstract dropIndexes(table: Table, constraintIndexes: number[]): Promise<void>;
@@ -87,4 +95,11 @@ export declare abstract class DB {
87
95
  abstract syncSequence(table: Table): Promise<void>;
88
96
  abstract syncTable(table: Table): Promise<void>;
89
97
  }
98
+ export declare class Transaction {
99
+ private entries;
100
+ addEntry(entry: EntryBase): void;
101
+ clean(): void;
102
+ commit(): Promise<void>;
103
+ rollback(): Promise<void>;
104
+ }
90
105
  export {};
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DB = exports.Table = exports.Attribute = exports.Type = exports.EntryBase = void 0;
3
+ exports.Transaction = exports.DB = exports.Table = exports.Attribute = exports.Type = exports.EntryBase = void 0;
4
4
  class EntryBase {
5
5
  constructor(from) {
6
6
  if (from === "load")
@@ -85,3 +85,24 @@ class DB {
85
85
  }
86
86
  }
87
87
  exports.DB = DB;
88
+ class Transaction {
89
+ constructor() {
90
+ this.entries = [];
91
+ }
92
+ addEntry(entry) {
93
+ this.entries.push(entry);
94
+ }
95
+ clean() {
96
+ const { entries } = this;
97
+ for (const entry of entries)
98
+ delete entry.tx;
99
+ this.entries = [];
100
+ }
101
+ async commit() {
102
+ this.clean();
103
+ }
104
+ async rollback() {
105
+ this.clean();
106
+ }
107
+ }
108
+ exports.Transaction = Transaction;
package/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { Attribute, DB, EntryBase, ForeignKeyOptions, Natural, Type } from "./lib/db";
2
- export { EntryBase, ForeignKeyActions, ForeignKeyOptions, Natural, Type } from "./lib/db";
1
+ import { Attribute, DB, EntryBase, ForeignKeyOptions, Natural, Transaction, Type } from "./db";
2
+ export { EntryBase, ForeignKeyActions, ForeignKeyOptions, Natural, Transaction, Type } from "./db";
3
3
  export declare type TypeDefinition<N extends Natural, E> = (() => Type<N, E>) | Type<N, E>;
4
4
  export interface AttributeOptions<N extends Natural, E> {
5
5
  defaultValue?: N;
@@ -16,7 +16,7 @@ declare type ForeignKeysAttributes<T, k> = T extends AttributeDefinition<Natural
16
16
  declare type ForeignKeys<A extends AttributesDefinition> = {
17
17
  [a in keyof A]?: ForeignKeysAttributes<A[a], a>;
18
18
  }[keyof A];
19
- declare type Native__<T> = T extends Type<infer N, unknown> ? N : never;
19
+ declare type Native__<T> = T extends Type<infer N, unknown> ? N | null : never;
20
20
  declare type Native_<T> = T extends () => Type<infer N, infer E> ? Native__<Type<N, E>> : Native__<T>;
21
21
  declare type Native<T> = T extends AttributeOptions<infer N, infer E> ? Native__<Type<N, E>> : Native_<T>;
22
22
  export declare type IndexAttributes = string[] | string;
@@ -36,14 +36,15 @@ interface BaseModelOptions {
36
36
  }
37
37
  export interface ModelOptions extends BaseModelOptions {
38
38
  int8id?: boolean;
39
- parent?: Type<Natural, EntryBase>;
39
+ parent?: Attribute<Natural, EntryBase>;
40
40
  primaryKey?: string;
41
41
  }
42
- declare type ConditionAttribute<N extends Natural> = N | [">" | "<" | ">=" | "<=" | "<>", N] | ["LIKE", string] | ["IN", ...N[]];
42
+ declare type ConditionAttribute<N extends Natural> = N | ["=" | ">" | "<" | ">=" | "<=" | "<>", N] | ["IN", N[]] | ["IS NULL"] | ["LIKE", string] | ["NOT"];
43
43
  declare type ConditionBase<A extends AttributesDefinition> = string | {
44
44
  [a in keyof A]?: ConditionAttribute<Native<A[a]>>;
45
45
  };
46
46
  declare type Condition<A extends AttributesDefinition> = ConditionBase<A> | ["NOT", Condition<A>] | ["AND", ...Condition<A>[]] | ["OR", ...Condition<A>[]];
47
+ declare type Order<A extends AttributesDefinition> = (keyof A | `-${string & keyof A}`)[];
47
48
  declare type UnionToIntersection<U> = (U extends unknown ? (k: U) => void : never) extends (k: infer I) => void ? I : never;
48
49
  declare type IsUnion<T> = [T] extends [UnionToIntersection<T>] ? false : true;
49
50
  declare type BaseKeyType<B extends boolean> = IsUnion<B> extends true ? number : B extends true ? string : number;
@@ -61,16 +62,19 @@ declare type ModelAttributesIf<A extends AttributesDefinition, T> = keyof A exte
61
62
  declare type ModelAttributes<A extends AttributesDefinition, B extends boolean, K extends string, P extends ModelStd> = K extends keyof A ? A : ModelAttributesIf<A, P extends new () => EntryBase ? P["attributes"] : {
62
63
  id: Type<BaseKeyType<B>, unknown>;
63
64
  }>;
64
- declare type ModelBase<N extends Natural, A extends AttributesDefinition, EA extends Record<string, Natural | undefined>, EM extends EntryBase, E extends EntryBase> = (new (from?: EA) => E) & Attribute<N, E> & {
65
+ interface ModelLoad<A extends AttributesDefinition, E extends EntryBase> {
65
66
  attributes: A;
67
+ load(where: Condition<A>, order?: Order<A>, tx?: Transaction): Promise<E[]>;
68
+ load(where: Condition<A>, tx: Transaction): Promise<E[]>;
69
+ }
70
+ declare type ModelBase<N extends Natural, A extends AttributesDefinition, EA extends Record<string, Natural | undefined>, EM extends EntryBase, E extends EntryBase> = (new (from?: EA) => E) & Attribute<N, E> & {
66
71
  foreignKeys: Record<string, boolean>;
67
72
  methods: EM;
68
73
  parent?: ModelStd;
69
74
  tableName: string;
70
- load: (where?: Condition<A>) => Promise<E[]>;
71
75
  } & {
72
76
  [a in keyof A]: Attribute<Native<A[a]>, E>;
73
- };
77
+ } & ModelLoad<A, E>;
74
78
  declare type Model<N extends Natural, A extends AttributesDefinition, EM extends EntryBase> = ModelBase<N, A, EntryBaseAttributes<A>, EM, EntryBaseAttributes<A> & EM>;
75
79
  declare type ModelStd = Attribute<Natural, EntryBase> & {
76
80
  attributes: AttributesDefinition;
@@ -79,28 +83,40 @@ declare type ModelStd = Attribute<Natural, EntryBase> & {
79
83
  parent?: ModelStd;
80
84
  };
81
85
  export declare type Entry<M> = M extends new () => infer E ? E : never;
82
- export declare type Where<M> = M extends {
83
- load: (where: infer T) => void;
86
+ export declare type OrderBy<M> = M extends {
87
+ load(where: unknown, order?: infer T, tx?: Transaction): void;
88
+ load(where: unknown, tx?: Transaction): void;
84
89
  } ? Exclude<T, undefined> : never;
90
+ export declare type Where<M> = M extends {
91
+ load(where: infer T, order?: unknown, tx?: Transaction): void;
92
+ load(where: unknown, tx?: Transaction): void;
93
+ } ? T : never;
85
94
  export interface SedentaryOptions {
95
+ autoSync?: boolean;
86
96
  log?: ((message: string) => void) | null;
87
- serverless?: boolean;
88
97
  sync?: boolean;
89
98
  }
90
- export declare class Sedentary {
91
- protected db: DB;
99
+ export declare class Sedentary<D extends DB<T>, T extends Transaction> {
100
+ protected autoSync: boolean;
101
+ protected db: D;
102
+ protected doSync: boolean;
92
103
  protected log: (...data: unknown[]) => void;
93
- protected sync: boolean;
94
104
  private models;
95
- constructor(filename: string, options?: SedentaryOptions);
105
+ constructor(options?: SedentaryOptions);
96
106
  DATETIME(): Type<Date, unknown>;
97
107
  FKEY<N extends Natural, E extends EntryBase>(attribute: Attribute<N, E>, options?: ForeignKeyOptions): Type<N, E>;
98
108
  INT(size?: number): Type<number, unknown>;
99
109
  INT8(): Type<string, unknown>;
100
110
  VARCHAR(size?: number): Type<string, unknown>;
101
- checkSize(size: number, message: string): number;
102
- connect(): Promise<void>;
111
+ private checkDB;
112
+ private checkOrderBy;
113
+ private checkSize;
114
+ private createWhere;
115
+ connect(sync?: boolean): Promise<void>;
116
+ sync(): Promise<void>;
103
117
  end(): Promise<void>;
118
+ begin(): Promise<T>;
119
+ escape(value: Natural): string;
104
120
  model<A extends AttributesDefinition, B extends boolean, K extends string, P extends ModelStd, EM extends EntryMethods<A, P>>(modelName: string, attributes: A, options?: BaseModelOptions & {
105
121
  int8id?: B;
106
122
  parent?: P;
@@ -112,4 +128,3 @@ export declare class Sedentary {
112
128
  primaryKey?: K | keyof A;
113
129
  }, methods: M & Record<keyof M, (this: EA & EM & M, ...args: any[]) => void>): Model<K extends keyof A ? Native<A[K]> : KeyType<B, P>, ModelAttributes<A, B, K, P>, EM & M>;
114
130
  }
115
- export declare const Package: typeof Sedentary;
package/index.js CHANGED
@@ -1,38 +1,40 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Package = exports.Sedentary = exports.Type = exports.EntryBase = void 0;
4
- const db_1 = require("./lib/db");
5
- const minidb_1 = require("./lib/minidb");
6
- var db_2 = require("./lib/db");
3
+ exports.Sedentary = exports.Type = exports.Transaction = exports.EntryBase = void 0;
4
+ const db_1 = require("./db");
5
+ var db_2 = require("./db");
7
6
  Object.defineProperty(exports, "EntryBase", { enumerable: true, get: function () { return db_2.EntryBase; } });
7
+ Object.defineProperty(exports, "Transaction", { enumerable: true, get: function () { return db_2.Transaction; } });
8
8
  Object.defineProperty(exports, "Type", { enumerable: true, get: function () { return db_2.Type; } });
9
+ const operators = ["=", ">", "<", ">=", "<=", "<>", "IN", "IS NULL", "LIKE", "NOT"];
9
10
  const allowedOption = ["indexes", "int8id", "parent", "primaryKey", "sync", "tableName"];
10
11
  const reservedNames = [
11
- ...["attributeName", "attributes", "base", "class", "construct", "constructor", "defaultValue", "entry", "fieldName", "foreignKeys", "load"],
12
- ...["methods", "name", "postLoad", "postSave", "preLoad", "preSave", "primaryKey", "prototype", "save", "size", "tableName", "type"]
12
+ ...["attr2field", "attributeName", "attributes", "base", "class", "construct", "constructor", "defaultValue", "entry", "fieldName", "foreignKeys", "load"],
13
+ ...["loaded", "methods", "name", "postLoad", "postSave", "preLoad", "preSave", "primaryKey", "prototype", "save", "size", "tableName", "tx", "type"]
13
14
  ];
14
15
  class Sedentary {
15
- constructor(filename, options) {
16
- this.sync = true;
16
+ constructor(options) {
17
+ this.doSync = true;
17
18
  this.models = {};
18
- if (typeof filename !== "string")
19
- throw new Error("new Sedentary: 'filename' argument: Wrong type, expected 'string'");
20
19
  if (!options)
21
20
  options = {};
22
21
  if (!(options instanceof Object))
23
22
  throw new Error("new Sedentary: 'options' argument: Wrong type, expected 'Object'");
24
23
  for (const k in options)
25
- if (!["log", "sync"].includes(k))
24
+ if (!["autoSync", "log", "sync"].includes(k))
26
25
  throw new Error(`new Sedentary: 'options' argument: Unknown '${k}' option`);
27
- const { log, sync } = Object.assign({ sync: true }, options);
26
+ const { autoSync, log, sync } = Object.assign({ autoSync: true, sync: true }, options);
27
+ if (typeof autoSync !== "boolean")
28
+ throw new Error("new Sedentary: 'autoSync' option: Wrong type, expected 'boolean'");
28
29
  if (log !== null && log !== undefined && !(log instanceof Function))
29
30
  throw new Error("new Sedentary: 'log' option: Wrong type, expected 'null' or 'Function'");
30
31
  if (typeof sync !== "boolean")
31
32
  throw new Error("new Sedentary: 'sync' option: Wrong type, expected 'boolean'");
33
+ this.autoSync = autoSync;
34
+ this.db = null;
32
35
  // eslint-disable-next-line no-console
33
36
  this.log = log ? log : log === null ? () => { } : console.log;
34
- this.db = new minidb_1.MiniDB(filename, this.log);
35
- this.sync = sync;
37
+ this.doSync = sync;
36
38
  }
37
39
  DATETIME() {
38
40
  return new db_1.Type({ base: Date, type: "DATETIME" });
@@ -56,6 +58,28 @@ class Sedentary {
56
58
  size = size ? this.checkSize(size, message) : undefined;
57
59
  return new db_1.Type({ base: String, size, type: "VARCHAR" });
58
60
  }
61
+ checkDB() {
62
+ if (!this.db)
63
+ throw new Error("Package sedentary can't be used directly. Please check: https://www.npmjs.com/package/sedentary#disclaimer");
64
+ }
65
+ checkOrderBy(order, attributes, modelName) {
66
+ if (!order)
67
+ return true;
68
+ if (!(order instanceof Array))
69
+ return false;
70
+ const provided = {};
71
+ for (const attribute of order) {
72
+ if (typeof attribute !== "string")
73
+ return false;
74
+ const attributeName = attribute.startsWith("-") ? attribute.substring(1) : attribute;
75
+ if (!(attributeName in attributes))
76
+ throw new Error(`${modelName}.load: 'order' argument: '${attributeName}' is not an attribute name`);
77
+ if (provided[attributeName])
78
+ throw new Error(`${modelName}.load: 'order' argument: Reused '${attributeName}' attribute`);
79
+ provided[attributeName] = true;
80
+ }
81
+ return true;
82
+ }
59
83
  checkSize(size, message) {
60
84
  const str = size.toString();
61
85
  const parsed = parseInt(str, 10);
@@ -63,26 +87,109 @@ class Sedentary {
63
87
  throw new Error(message);
64
88
  return parsed;
65
89
  }
66
- async connect() {
90
+ createWhere(modelName, attributes, where) {
91
+ if (typeof where === "string")
92
+ return [where, true, true];
93
+ if (typeof where !== "object")
94
+ throw new Error(`${modelName}.load: 'where' argument: Wrong type, expected 'Array', 'Object' or 'string'`);
95
+ if (!where)
96
+ return ["", false, false];
97
+ if (where instanceof Array) {
98
+ const length = where.length;
99
+ if (!length)
100
+ throw new Error(`${modelName}.load: 'where' argument: Empty Array`);
101
+ if (!["AND", "NOT", "OR"].includes(where[0]))
102
+ throw new Error(`${modelName}.load: 'where' argument: Wrong logical operator, expected 'AND', 'OR' or 'NOT'`);
103
+ if (length === 1)
104
+ return ["", false, false];
105
+ if (where[0] === "NOT") {
106
+ if (length > 2)
107
+ throw new Error(`${modelName}.load: 'where' argument: 'NOT' operator is unary`);
108
+ const [res] = this.createWhere(modelName, attributes, where[1]);
109
+ return [res === "" ? "" : `NOT (${res})`, false, false];
110
+ }
111
+ const conditions = where
112
+ .filter((_, i) => i)
113
+ .map(_ => this.createWhere(modelName, attributes, _))
114
+ .filter(([_]) => _);
115
+ if (conditions.length === 1)
116
+ return conditions[0];
117
+ const isOr = where[0] === "OR";
118
+ return [isOr ? conditions.map(([_, , a]) => (a ? `(${_})` : _)).join(" OR ") : conditions.map(([_, o]) => (o ? `(${_})` : _)).join(" AND "), isOr, false];
119
+ }
120
+ const conditions = [];
121
+ for (const key in where) {
122
+ const field = attributes[key];
123
+ if (!field)
124
+ throw new Error(`${modelName}.load: 'where' argument: Unknown '${key}' attribute`);
125
+ const value = where[key];
126
+ if (value instanceof Array) {
127
+ const operator = value[0];
128
+ const length = value.length;
129
+ if (!length)
130
+ throw new Error(`${modelName}.load: 'where' argument: Missing arithmetic operator, expected one of: ${operators.map(_ => `'${_}'`).join(", ")}`);
131
+ if (!operators.includes(operator))
132
+ throw new Error(`${modelName}.load: 'where' argument: Wrong arithmetic operator, expected one of: ${operators.map(_ => `'${_}'`).join(", ")}`);
133
+ if (operator === "IS NULL") {
134
+ if (length !== 1)
135
+ throw new Error(`${modelName}.load: 'where' argument: 'IS NULL' operator is unary`);
136
+ conditions.push(`${field} IS NULL`);
137
+ }
138
+ else if (operator === "NOT") {
139
+ if (length !== 1)
140
+ throw new Error(`${modelName}.load: 'where' argument: 'NOT' operator is unary`);
141
+ conditions.push(`NOT ${field}`);
142
+ }
143
+ else {
144
+ if (length !== 2)
145
+ throw new Error(`${modelName}.load: 'where' argument: '${operator}' operator is binary`);
146
+ if (operator === "IN") {
147
+ if (!(value[1] instanceof Array))
148
+ throw new Error(`${modelName}.load: 'where' argument: 'IN' right operand: Wrong type, expected Array`);
149
+ conditions.push(`${field} IN (${value[1].map(_ => this.escape(_)).join(", ")})`);
150
+ }
151
+ else
152
+ conditions.push(`${field} ${operator} ${this.escape(value[1])}`);
153
+ }
154
+ }
155
+ else
156
+ conditions.push(`${field} = ${this.escape(value)}`);
157
+ }
158
+ return [conditions.length ? conditions.join(" AND ") : "", false, false];
159
+ }
160
+ async connect(sync) {
67
161
  try {
162
+ this.checkDB();
68
163
  this.log("Connecting...");
69
164
  await this.db.connect();
70
- this.log("Connected, syncing...");
71
- await this.db.syncDataBase();
72
- this.log("Synced");
165
+ this.log("Connected");
166
+ if (this.autoSync || sync)
167
+ await this.sync();
73
168
  }
74
169
  catch (e) {
75
170
  this.log("Connecting: " + (e instanceof Error ? e.message : JSON.stringify(e)));
76
171
  throw e;
77
172
  }
78
173
  }
174
+ async sync() {
175
+ this.log("Syncing...");
176
+ await this.db.syncDataBase();
177
+ this.log("Synced");
178
+ }
79
179
  async end() {
80
180
  this.log("Closing connection...");
81
181
  await this.db.end();
82
182
  this.log("Connection closed");
83
183
  }
184
+ async begin() {
185
+ return this.db.begin();
186
+ }
187
+ escape(value) {
188
+ return this.db.escape(value);
189
+ }
84
190
  /* eslint-enable @typescript-eslint/no-explicit-any */
85
191
  model(modelName, attributes, options, methods) {
192
+ this.checkDB();
86
193
  if (typeof modelName !== "string")
87
194
  throw new Error("Sedentary.model: 'name' argument: Wrong type, expected 'string'");
88
195
  if (this.models[modelName])
@@ -105,13 +212,14 @@ class Sedentary {
105
212
  if (options.parent && options.primaryKey)
106
213
  throw new Error(`Sedentary.model: '${modelName}' model: 'parent' and 'primaryKey' options conflict each other`);
107
214
  let autoIncrement = true;
108
- const { indexes, int8id, parent, primaryKey, sync, tableName } = Object.assign({ sync: this.sync, tableName: modelName }, options);
215
+ const { indexes, int8id, parent, primaryKey, sync, tableName } = Object.assign({ sync: this.doSync, tableName: modelName }, options);
109
216
  let aarray = int8id
110
217
  ? [new db_1.Attribute(Object.assign(Object.assign({}, this.INT8()), { attributeName: "id", fieldName: "id", modelName, notNull: true, tableName, unique: true }))]
111
218
  : [new db_1.Attribute(Object.assign(Object.assign({}, this.INT(4)), { attributeName: "id", fieldName: "id", modelName, notNull: true, tableName, unique: true }))];
112
219
  let constraints = [{ attribute: aarray[0], constraintName: `${tableName}_id_unique`, type: "u" }];
113
220
  const iarray = [];
114
- const pk = aarray[0];
221
+ let pk = aarray[0];
222
+ let attr2field = { id: "id" };
115
223
  if (!methods)
116
224
  methods = {};
117
225
  if (!(methods instanceof Object))
@@ -124,6 +232,8 @@ class Sedentary {
124
232
  if (primaryKey && !Object.keys(attributes).includes(primaryKey))
125
233
  throw new Error(`Sedentary.model: '${modelName}' model: 'primaryKey' option: Attribute '${primaryKey}' does not exists`);
126
234
  if (parent || primaryKey) {
235
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
236
+ attr2field = parent ? Object.assign({}, parent.attr2field) : {};
127
237
  autoIncrement = false;
128
238
  aarray = [];
129
239
  constraints = [];
@@ -200,7 +310,10 @@ class Sedentary {
200
310
  if (defaultValue)
201
311
  notNull = true;
202
312
  const attribute = new db_1.Attribute({ attributeName, base, defaultValue, fieldName, foreignKey, modelName, notNull, size, tableName, type, unique });
313
+ if (primaryKey === attributeName)
314
+ pk = attribute;
203
315
  aarray.push(attribute);
316
+ attr2field[attributeName] = fieldName;
204
317
  if (foreignKey)
205
318
  constraints.push({ attribute, constraintName: `fkey_${fieldName}_${foreignKey.tableName}_${foreignKey.fieldName}`, type: "f" });
206
319
  if (unique)
@@ -258,7 +371,6 @@ class Sedentary {
258
371
  iarray.push({ fields: attributes, indexName, type, unique });
259
372
  }
260
373
  }
261
- this.db.tables.push(new db_1.Table({ autoIncrement, constraints, attributes: aarray, indexes: iarray, parent, sync, tableName }));
262
374
  this.models[modelName] = true;
263
375
  const foreignKeys = aarray
264
376
  .filter(_ => _.foreignKey)
@@ -299,29 +411,43 @@ class Sedentary {
299
411
  for (const foreignKey in parent.foreignKeys)
300
412
  if (foreignKey + "Load" === method)
301
413
  throw new Error(`Sedentary.model: '${modelName}' model: '${method}' method: conflicts with an inferred methods of '${parent.modelName}' model`);
302
- if (method in parent.methods)
303
- throw new Error(`Sedentary.model: '${modelName}' model: '${method}' method: conflicts with a method of '${parent.modelName}' model`);
304
414
  }
305
415
  checkParent(parent.parent);
306
416
  };
307
417
  checkParent(parent);
308
418
  const ret = class extends (parent || db_1.EntryBase) {
309
419
  };
310
- const load = (boh) => new Promise((resolve, reject) => setTimeout(() => {
311
- if (boh)
312
- return resolve([new ret()]);
313
- reject(new Error("boh"));
314
- }, 10));
420
+ const table = new db_1.Table({ autoIncrement, constraints, attributes: aarray, indexes: iarray, model: ret, parent, pk, sync, tableName });
421
+ this.db.tables.push(table);
422
+ const load_ = this.db.load(tableName, attr2field, pk, ret, table);
423
+ const load = async (where, order, tx) => {
424
+ if (order instanceof db_1.Transaction) {
425
+ tx = order;
426
+ order = undefined;
427
+ }
428
+ if (!this.checkOrderBy(order, attr2field, modelName))
429
+ throw new Error(`${modelName}.load: 'order' argument: Wrong type, expected 'string[]'`);
430
+ const [str] = this.createWhere(modelName, attr2field, where);
431
+ const ret = await load_(str, order, tx);
432
+ return ret;
433
+ };
315
434
  Object.defineProperty(load, "name", { value: modelName + ".load" });
316
435
  Object.defineProperty(ret, "name", { value: modelName });
317
436
  Object.defineProperty(ret, "load", { value: load });
437
+ Object.defineProperty(ret, "attr2field", { value: attr2field });
318
438
  Object.defineProperty(ret, "attributes", { value: attributes });
319
439
  Object.defineProperty(ret, "foreignKeys", { value: foreignKeys });
320
440
  Object.defineProperty(ret, "methods", { value: methods });
321
441
  Object.assign(ret.prototype, methods);
322
- ret.prototype.save = function () {
323
- return Promise.resolve(false);
442
+ const save = this.db.save(tableName, attr2field, pk);
443
+ ret.prototype.save = async function () {
444
+ this.preSave();
445
+ const ret = await save.call(this);
446
+ if (ret)
447
+ this.postSave();
448
+ return ret;
324
449
  };
450
+ Object.defineProperty(ret.prototype.save, "name", { value: modelName + ".save" });
325
451
  for (const attribute of aarray)
326
452
  Object.defineProperty(ret, attribute.attributeName, { value: attribute });
327
453
  for (const key of ["attributeName", "base", "fieldName", "modelName", "size", "tableName", "type", "unique"])
@@ -330,4 +456,3 @@ class Sedentary {
330
456
  }
331
457
  }
332
458
  exports.Sedentary = Sedentary;
333
- exports.Package = Sedentary;
package/package.json CHANGED
@@ -8,18 +8,18 @@
8
8
  "dependencies": {},
9
9
  "description": "The ORM which never needs to migrate",
10
10
  "devDependencies": {
11
- "@types/mocha": "9.0.0",
12
- "@types/node": "17.0.5",
11
+ "@types/mocha": "9.1.0",
12
+ "@types/node": "17.0.19",
13
13
  "@types/yamljs": "0.2.31",
14
- "@typescript-eslint/eslint-plugin": "5.8.1",
15
- "@typescript-eslint/parser": "5.8.1",
16
- "eslint": "8.5.0",
17
- "mocha": "9.1.3",
14
+ "@typescript-eslint/eslint-plugin": "5.12.1",
15
+ "@typescript-eslint/parser": "5.12.1",
16
+ "eslint": "8.9.0",
17
+ "mocha": "9.2.1",
18
18
  "nyc": "15.1.0",
19
19
  "prettier": "2.5.1",
20
- "ts-node": "10.4.0",
21
- "tsd": "0.19.0",
22
- "typescript": "4.5.4",
20
+ "ts-node": "10.5.0",
21
+ "tsd": "0.19.1",
22
+ "typescript": "4.5.5",
23
23
  "yamljs": "0.3.0"
24
24
  },
25
25
  "engines": {
@@ -78,5 +78,5 @@
78
78
  }
79
79
  },
80
80
  "types": "index.d.ts",
81
- "version": "0.0.22"
81
+ "version": "0.0.25"
82
82
  }
package/lib/minidb.d.ts DELETED
@@ -1,17 +0,0 @@
1
- import { DB, Table } from "./db";
2
- export declare class MiniDB extends DB {
3
- private body;
4
- private file;
5
- constructor(filename: string, log: (message: string) => void);
6
- connect(): Promise<void>;
7
- dropConstraints(table: Table): Promise<number[]>;
8
- dropFields(table: Table): Promise<void>;
9
- dropIndexes(table: Table, constraintIndexes: number[]): Promise<void>;
10
- end(): Promise<void>;
11
- save(): Promise<void>;
12
- syncConstraints(table: Table): Promise<void>;
13
- syncIndexes(table: Table): Promise<void>;
14
- syncFields(table: Table): Promise<void>;
15
- syncSequence(table: Table): Promise<void>;
16
- syncTable(table: Table): Promise<void>;
17
- }
package/lib/minidb.js DELETED
@@ -1,191 +0,0 @@
1
- "use strict";
2
- /* eslint-disable @typescript-eslint/no-explicit-any */
3
- Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.MiniDB = void 0;
5
- const db_1 = require("./db");
6
- const fs_1 = require("fs");
7
- const { readFile, writeFile } = fs_1.promises;
8
- class MiniDB extends db_1.DB {
9
- constructor(filename, log) {
10
- super(log);
11
- this.file = filename;
12
- }
13
- async connect() {
14
- this.body = { next: {}, tables: {} };
15
- try {
16
- this.body = JSON.parse((await readFile(this.file)).toString());
17
- }
18
- catch (e) {
19
- const err = e;
20
- if (err.code !== "ENOENT")
21
- throw e;
22
- }
23
- }
24
- async dropConstraints(table) {
25
- const { constraints } = this.body.tables[table.tableName] || { constraints: { f: {}, u: {} } };
26
- for (const constraint of Object.keys(constraints.f).sort()) {
27
- const arr = table.constraints.filter(({ constraintName, type }) => constraintName === constraint && type === "f");
28
- const dbOptions = arr.length ? arr[0].attribute.foreignKey.options : { onDelete: "delete", onUpdate: "delete" };
29
- const inOptions = constraints.f[constraint].options;
30
- if (dbOptions.onDelete !== inOptions.onDelete || dbOptions.onUpdate !== inOptions.onUpdate) {
31
- this.syncLog(`'${table.tableName}': Removing foreign key: '${constraint}'`);
32
- if (this.sync)
33
- delete constraints.f[constraint];
34
- }
35
- }
36
- for (const constraint of Object.keys(constraints.u).sort()) {
37
- if (!table.constraints.filter(({ constraintName, type }) => constraintName === constraint && type === "u").length) {
38
- this.syncLog(`'${table.tableName}': Removing unique constraint from field: '${constraints.u[constraint].on}'`);
39
- if (this.sync)
40
- delete constraints.u[constraint];
41
- }
42
- }
43
- await this.save();
44
- return [];
45
- }
46
- async dropFields(table) {
47
- const { fields } = this.body.tables[table.tableName] || { fields: {} };
48
- for (const attribute of Object.keys(fields).sort()) {
49
- if (!table.findField(attribute)) {
50
- this.syncLog(`'${table.tableName}': Removing field: '${attribute}'`);
51
- if (this.sync)
52
- delete fields[attribute];
53
- }
54
- }
55
- await this.save();
56
- }
57
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
58
- async dropIndexes(table, constraintIndexes) {
59
- const { indexes } = this.body.tables[table.tableName] || { indexes: {} };
60
- for (const name of Object.keys(indexes).sort()) {
61
- const index = table.indexes.filter(_ => _.indexName === name);
62
- if (index.length === 0 || !this.indexesEq(indexes[name], index[0])) {
63
- this.syncLog(`'${table.tableName}': Removing index: '${name}'`);
64
- if (this.sync)
65
- delete indexes[name];
66
- }
67
- }
68
- await this.save();
69
- }
70
- async end() { }
71
- async save() {
72
- await writeFile(this.file, JSON.stringify(this.body));
73
- }
74
- async syncConstraints(table) {
75
- const { constraints } = this.body.tables[table.tableName] || { constraints: { f: {}, u: {} } };
76
- for (const constraint of table.constraints) {
77
- const { attribute, constraintName, type } = constraint;
78
- if (!constraints[type][constraintName]) {
79
- if (type === "f") {
80
- const { fieldName, options, tableName } = attribute.foreignKey;
81
- const onDelete = options.onDelete !== "no action" ? ` on delete ${options.onDelete}` : "";
82
- const onUpdate = options.onUpdate !== "no action" ? ` on update ${options.onUpdate}` : "";
83
- this.syncLog(`'${table.tableName}': Adding foreign key '${constraint.constraintName}' on field: '${attribute.fieldName}' references '${tableName}(${fieldName})'${onDelete}${onUpdate}`);
84
- if (this.sync)
85
- constraints[type][constraintName] = { on: attribute.fieldName, options, fieldName, tableName };
86
- }
87
- else {
88
- this.syncLog(`'${table.tableName}': Adding unique constraint on field: '${attribute.fieldName}'`);
89
- if (this.sync)
90
- constraints[type][constraintName] = { on: attribute.fieldName };
91
- }
92
- }
93
- }
94
- await this.save();
95
- }
96
- async syncIndexes(table) {
97
- const { indexes } = this.body.tables[table.tableName] || { indexes: {} };
98
- for (const index of table.indexes) {
99
- const { indexName } = index;
100
- if (!(indexName in indexes)) {
101
- this.syncLog(`'${table.tableName}': Adding index: '${indexName}' on (${index.fields.map(_ => `'${_}'`).join(", ")}) type '${index.type}'${index.unique ? " unique" : ""}`);
102
- if (this.sync)
103
- indexes[indexName] = index;
104
- }
105
- }
106
- await this.save();
107
- }
108
- async syncFields(table) {
109
- for (const attribute of table.attributes) {
110
- const { fields } = this.body.tables[table.tableName] || { fields: {} };
111
- const { defaultValue, fieldName, notNull, size, type } = attribute;
112
- let field = fields[fieldName];
113
- if (!field) {
114
- this.syncLog(`'${table.tableName}': Adding field: '${fieldName}' '${type}' '${size || ""}'`);
115
- if (this.sync)
116
- field = fields[fieldName] = { size, type };
117
- else
118
- field = {};
119
- }
120
- if (field.size !== size || field.type !== type) {
121
- this.syncLog(`'${table.tableName}': Changing field type: '${fieldName}' '${type}' '${size || ""}'`);
122
- if (this.sync)
123
- field = fields[fieldName] = Object.assign(Object.assign({}, field), { size, type });
124
- }
125
- if (field.default) {
126
- if (!defaultValue) {
127
- this.syncLog(`'${table.tableName}': Dropping default value for field: '${fieldName}'`);
128
- if (this.sync)
129
- delete field.default;
130
- }
131
- else if (field.default !== defaultValue) {
132
- this.syncLog(`'${table.tableName}': Changing default value to '${defaultValue}' for field: '${fieldName}'`);
133
- if (this.sync)
134
- field.default = defaultValue;
135
- }
136
- }
137
- else if (defaultValue) {
138
- this.syncLog(`'${table.tableName}': Setting default value '${defaultValue instanceof Date ? defaultValue.toISOString() : defaultValue}' for field: '${fieldName}'`);
139
- if (this.sync)
140
- field.default = defaultValue;
141
- }
142
- if (field.notNull) {
143
- if (!notNull) {
144
- this.syncLog(`'${table.tableName}': Dropping not null for field: '${fieldName}'`);
145
- if (this.sync)
146
- delete field.notNull;
147
- }
148
- }
149
- else if (notNull) {
150
- this.syncLog(`'${table.tableName}': Setting not null for field: '${fieldName}'`);
151
- if (this.sync)
152
- field.notNull = true;
153
- }
154
- }
155
- await this.save();
156
- }
157
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
158
- async syncSequence(table) { }
159
- async syncTable(table) {
160
- if (this.body.tables[table.tableName]) {
161
- (() => {
162
- if (table.parent) {
163
- if (this.body.tables[table.tableName].parent === table.parent.tableName)
164
- return;
165
- }
166
- else if (!this.body.tables[table.tableName].parent)
167
- return;
168
- this.syncLog(`Removing table: '${table.tableName}'`);
169
- if (this.sync)
170
- delete this.body.tables[table.tableName];
171
- })();
172
- }
173
- if (!this.body.tables[table.tableName]) {
174
- this.syncLog(`Adding table: '${table.tableName}'`);
175
- if (this.sync)
176
- this.body.tables[table.tableName] = { constraints: { f: {}, u: {} }, fields: {}, indexes: {} };
177
- if (table.parent) {
178
- this.syncLog(`Setting parent: '${table.parent.tableName}' - to table: '${table.tableName}'`);
179
- if (this.sync)
180
- this.body.tables[table.tableName].parent = table.parent.tableName;
181
- }
182
- if (table.autoIncrement && !this.body.next[table.tableName]) {
183
- this.syncLog(`Setting auto increment: '${table.tableName}'`);
184
- if (this.sync)
185
- this.body.next[table.tableName] = 1;
186
- }
187
- }
188
- await this.save();
189
- }
190
- }
191
- exports.MiniDB = MiniDB;
@@ -1,2 +0,0 @@
1
- export declare class Transaction {
2
- }
@@ -1,6 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Transaction = void 0;
4
- class Transaction {
5
- }
6
- exports.Transaction = Transaction;