sedentary 0.0.12 → 0.0.16
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/README.md +3 -0
- package/index.d.ts +78 -40
- package/index.js +134 -110
- package/lib/db.d.ts +38 -47
- package/lib/db.js +21 -31
- package/lib/log.d.ts +4 -0
- package/lib/log.js +20 -0
- package/lib/log.ts +22 -0
- package/lib/minidb.d.ts +2 -2
- package/lib/minidb.js +51 -34
- package/package.json +10 -7
- package/requirements.txt +2 -0
- package/tmp.js +0 -123
package/README.md
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
[![Stars][stars-badge]][github-url]
|
|
10
10
|
|
|
11
11
|
[![Types][types-badge]][npm-url]
|
|
12
|
+
[![Documentation][doc-badge]][doc-url]
|
|
12
13
|
[![Dependents][deps-badge]][npm-url]
|
|
13
14
|
[![Donate][donate-badge]][donate-url]
|
|
14
15
|
|
|
@@ -16,6 +17,8 @@
|
|
|
16
17
|
[code-url]: https://codeclimate.com/github/iccicci/sedentary
|
|
17
18
|
[cover-badge]: https://codeclimate.com/github/iccicci/sedentary/badges/coverage.svg
|
|
18
19
|
[deps-badge]: https://badgen.net/npm/dependents/sedentary?icon=npm&cache=300
|
|
20
|
+
[doc-badge]: https://readthedocs.org/projects/sedentary/badge/?version=latest
|
|
21
|
+
[doc-url]: https://sedentary.readthedocs.io/
|
|
19
22
|
[donate-badge]: https://badgen.net/badge/donate/bitcoin?icon=bitcoin&cache=300
|
|
20
23
|
[donate-url]: https://blockchain.info/address/1Md9WFAHrXTb3yPBwQWmUfv2RmzrtbHioB
|
|
21
24
|
[github-url]: https://github.com/iccicci/sedentary
|
package/index.d.ts
CHANGED
|
@@ -1,79 +1,117 @@
|
|
|
1
|
-
import { DB,
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { DB, Entry, Meta, Natural, Type } from "./lib/db";
|
|
2
|
+
export { Entry, Natural, Type } from "./lib/db";
|
|
3
|
+
export declare type TypeDefinition<N extends Natural, E> = (() => Type<N, E>) | Type<N, E>;
|
|
4
|
+
export interface AttributeOptions<N extends Natural, E> {
|
|
4
5
|
defaultValue?: N;
|
|
5
6
|
fieldName?: string;
|
|
6
7
|
notNull?: boolean;
|
|
7
|
-
type: TypeDefinition<N,
|
|
8
|
+
type: TypeDefinition<N, E>;
|
|
8
9
|
unique?: boolean;
|
|
9
10
|
}
|
|
10
|
-
declare type
|
|
11
|
-
declare type
|
|
12
|
-
[key: string]:
|
|
11
|
+
export declare type AttributeDefinition<N extends Natural, E> = TypeDefinition<N, E> | AttributeOptions<N, E>;
|
|
12
|
+
export declare type AttributesDefinition = {
|
|
13
|
+
[key: string]: AttributeDefinition<Natural, unknown>;
|
|
13
14
|
};
|
|
14
|
-
declare type
|
|
15
|
-
declare type
|
|
16
|
-
|
|
17
|
-
[f in keyof F]?: ForeignKeyFileds<F[f], f>;
|
|
15
|
+
declare type KeysAttributes<T, k> = T extends AttributeDefinition<Natural, infer E> ? (E extends Entry ? k : never) : never;
|
|
16
|
+
declare type Keys<F extends AttributesDefinition> = {
|
|
17
|
+
[f in keyof F]?: KeysAttributes<F[f], f>;
|
|
18
18
|
}[keyof F];
|
|
19
19
|
declare type Methods<T> = {
|
|
20
20
|
[key: string]: (this: T) => unknown;
|
|
21
21
|
};
|
|
22
22
|
declare type Native__<T> = T extends Type<infer N, unknown> ? N : never;
|
|
23
|
-
declare type Native_<T> = T extends () => Type<infer N, infer
|
|
24
|
-
declare type Native<T> = T extends
|
|
25
|
-
declare type Parent<T> = T extends Meta<
|
|
26
|
-
declare type
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
23
|
+
declare type Native_<T> = T extends () => Type<infer N, infer E> ? Native__<Type<N, E>> : Native__<T>;
|
|
24
|
+
declare type Native<T> = T extends AttributeOptions<infer N, infer E> ? Native__<Type<N, E>> : Native_<T>;
|
|
25
|
+
declare type Parent<T> = T extends Meta<Natural, infer E> ? E : never;
|
|
26
|
+
export declare type IndexAttributes = string[] | string;
|
|
27
|
+
export interface IndexOptions {
|
|
28
|
+
attributes: IndexAttributes;
|
|
29
|
+
type?: "btree" | "hash";
|
|
30
|
+
unique?: boolean;
|
|
31
|
+
}
|
|
32
|
+
export declare type IndexDefinition = IndexAttributes | IndexOptions;
|
|
33
|
+
export declare type IndexesDefinition = {
|
|
34
|
+
[key: string]: IndexDefinition;
|
|
35
|
+
};
|
|
36
|
+
declare type BaseModelOptions<T> = {
|
|
37
|
+
indexes?: IndexesDefinition;
|
|
30
38
|
init?: (this: T) => void;
|
|
31
|
-
methods?: M;
|
|
32
39
|
sync?: boolean;
|
|
33
40
|
tableName?: string;
|
|
34
41
|
};
|
|
35
|
-
declare type
|
|
36
|
-
|
|
42
|
+
export declare type ModelOptions<K extends string, M extends Methods<T>, P extends Meta<Natural, Entry>, T extends Entry> = BaseModelOptions<T> & {
|
|
43
|
+
int8id?: boolean;
|
|
44
|
+
methods?: M;
|
|
45
|
+
parent?: P;
|
|
46
|
+
primaryKey?: K;
|
|
47
|
+
};
|
|
48
|
+
declare type ForeignKey<T> = T extends AttributeDefinition<Natural, infer E> ? () => Promise<E> : never;
|
|
49
|
+
declare type ModelWithMetods<A extends AttributesDefinition, M> = {
|
|
50
|
+
[a in keyof A]?: Native<A[a]>;
|
|
37
51
|
} & {
|
|
38
|
-
[
|
|
52
|
+
[a in Keys<A> & string as `${a}Load`]?: ForeignKey<A[a]>;
|
|
39
53
|
} & M;
|
|
40
|
-
declare type
|
|
41
|
-
[
|
|
54
|
+
declare type Model<A extends AttributesDefinition> = {
|
|
55
|
+
[a in keyof A]?: Native<A[a]>;
|
|
56
|
+
} & {
|
|
57
|
+
[a in Keys<A> & string as `${a}Load`]?: ForeignKey<A[a]>;
|
|
58
|
+
};
|
|
59
|
+
declare type Ancestor<A, N extends Natural, T extends Entry> = (new () => T) & {
|
|
60
|
+
[a in keyof A]?: Meta<Native<A[a]>, T>;
|
|
42
61
|
} & {
|
|
43
62
|
load: (boh: boolean) => Promise<T[]>;
|
|
44
63
|
} & Meta<N, T>;
|
|
45
|
-
export interface
|
|
46
|
-
log?: (message: string) => void;
|
|
64
|
+
export interface SedentaryOptions {
|
|
65
|
+
log?: ((message: string) => void) | null;
|
|
66
|
+
serverless?: boolean;
|
|
47
67
|
sync?: boolean;
|
|
48
68
|
}
|
|
49
69
|
export declare class Sedentary {
|
|
50
70
|
protected db: DB;
|
|
51
|
-
protected log: (
|
|
52
|
-
|
|
71
|
+
protected log: (...data: unknown[]) => void;
|
|
72
|
+
protected sync: boolean;
|
|
53
73
|
private models;
|
|
54
|
-
constructor(filename: string, options?:
|
|
74
|
+
constructor(filename: string, options?: SedentaryOptions);
|
|
55
75
|
DATETIME(): Type<Date, unknown>;
|
|
56
|
-
FKEY<N extends
|
|
76
|
+
FKEY<N extends Natural, E extends Entry>(attribute: Type<N, E>): Type<N, E>;
|
|
57
77
|
INT(size?: number): Type<number, unknown>;
|
|
58
78
|
INT8(): Type<string, unknown>;
|
|
59
79
|
VARCHAR(size?: number): Type<string, unknown>;
|
|
60
80
|
connect(): Promise<void>;
|
|
61
81
|
end(): Promise<void>;
|
|
62
|
-
model<
|
|
82
|
+
model<A extends AttributesDefinition, M extends Methods<T>, T extends Entry & {
|
|
83
|
+
id?: string;
|
|
84
|
+
} & ModelWithMetods<A, M>>(name: string, attributes: A, options?: BaseModelOptions<T> & {
|
|
85
|
+
int8id: true;
|
|
86
|
+
methods: M;
|
|
87
|
+
}): Ancestor<A, string, T>;
|
|
88
|
+
model<A extends AttributesDefinition, K extends keyof A, M extends Methods<T>, N extends K extends keyof A ? Native<A[K]> : never, T extends Entry & ModelWithMetods<A, M>>(name: string, attributes: A, options?: BaseModelOptions<T> & {
|
|
89
|
+
methods: M;
|
|
90
|
+
primaryKey: K;
|
|
91
|
+
}): Ancestor<A, N, T>;
|
|
92
|
+
model<A extends AttributesDefinition, M extends Methods<T>, P extends Meta<Natural, Entry>, N extends P extends Meta<infer N, Entry> ? N : never, T extends Parent<P> & ModelWithMetods<A, M>>(name: string, attributes: A, options?: BaseModelOptions<T> & {
|
|
93
|
+
methods: M;
|
|
94
|
+
parent: P;
|
|
95
|
+
}): Ancestor<A, N, T>;
|
|
96
|
+
model<A extends AttributesDefinition, M extends Methods<T>, T extends Entry & {
|
|
97
|
+
id?: number;
|
|
98
|
+
} & ModelWithMetods<A, M>>(name: string, attributes: A, options?: BaseModelOptions<T> & {
|
|
99
|
+
methods: M;
|
|
100
|
+
}): Ancestor<A, number, T>;
|
|
101
|
+
model<A extends AttributesDefinition, T extends Entry & {
|
|
63
102
|
id?: string;
|
|
64
|
-
} & Model<
|
|
103
|
+
} & Model<A>>(name: string, attributes: A, options?: BaseModelOptions<T> & {
|
|
65
104
|
int8id: true;
|
|
66
|
-
}): Ancestor<
|
|
67
|
-
model<
|
|
105
|
+
}): Ancestor<A, string, T>;
|
|
106
|
+
model<A extends AttributesDefinition, K extends keyof A, N extends K extends keyof A ? Native<A[K]> : never, T extends Entry & Model<A>>(name: string, attributes: A, options?: BaseModelOptions<T> & {
|
|
68
107
|
primaryKey: K;
|
|
69
|
-
}): Ancestor<
|
|
70
|
-
model<
|
|
108
|
+
}): Ancestor<A, N, T>;
|
|
109
|
+
model<A extends AttributesDefinition, P extends Meta<Natural, Entry>, N extends P extends Meta<infer N, Entry> ? N : never, T extends Parent<P> & Model<A>>(name: string, attributes: A, options?: BaseModelOptions<T> & {
|
|
71
110
|
parent: P;
|
|
72
|
-
}): Ancestor<
|
|
73
|
-
model<
|
|
111
|
+
}): Ancestor<A, N, T>;
|
|
112
|
+
model<A extends AttributesDefinition, T extends Entry & {
|
|
74
113
|
id?: number;
|
|
75
|
-
} & Model<
|
|
114
|
+
} & Model<A>>(name: string, attributes: A, options?: BaseModelOptions<T>): Ancestor<A, number, T>;
|
|
76
115
|
checkSize(size: number, message: string): number;
|
|
77
116
|
}
|
|
78
117
|
export declare const Package: typeof Sedentary;
|
|
79
|
-
export {};
|
package/index.js
CHANGED
|
@@ -1,33 +1,45 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Package = exports.Sedentary = void 0;
|
|
3
|
+
exports.Package = exports.Sedentary = exports.Type = exports.Entry = void 0;
|
|
4
4
|
const db_1 = require("./lib/db");
|
|
5
|
+
const log_1 = require("./lib/log");
|
|
5
6
|
const minidb_1 = require("./lib/minidb");
|
|
7
|
+
var db_2 = require("./lib/db");
|
|
8
|
+
Object.defineProperty(exports, "Entry", { enumerable: true, get: function () { return db_2.Entry; } });
|
|
9
|
+
Object.defineProperty(exports, "Type", { enumerable: true, get: function () { return db_2.Type; } });
|
|
6
10
|
const allowedOption = ["indexes", "init", "int8id", "methods", "parent", "primaryKey", "sync", "tableName", "type"];
|
|
11
|
+
const reservedNames = [
|
|
12
|
+
...["attributeName", "base", "class", "constructor", "defaultValue", "entry", "fieldName", "init", "isModel"],
|
|
13
|
+
...["load", "meta", "methods", "name", "primaryKey", "prototype", "save", "size", "tableName", "type"]
|
|
14
|
+
];
|
|
7
15
|
class Sedentary {
|
|
8
16
|
constructor(filename, options) {
|
|
9
17
|
this.sync = true;
|
|
10
18
|
this.models = {};
|
|
11
19
|
if (typeof filename !== "string")
|
|
12
|
-
throw new Error("Sedentary
|
|
20
|
+
throw new Error("new Sedentary: 'filename' argument: Wrong type, expected 'string'");
|
|
13
21
|
if (!options)
|
|
14
22
|
options = {};
|
|
15
23
|
if (!(options instanceof Object))
|
|
16
|
-
throw new Error("Sedentary
|
|
17
|
-
for (const k in options)
|
|
18
|
-
if (["log", "sync"].
|
|
19
|
-
throw new Error(`Sedentary
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
+
throw new Error("new Sedentary: 'options' argument: Wrong type, expected 'Object'");
|
|
25
|
+
for (const k in options)
|
|
26
|
+
if (!["log", "sync"].includes(k))
|
|
27
|
+
throw new Error(`new Sedentary: 'options' argument: Unknown '${k}' option`);
|
|
28
|
+
const { log, sync } = Object.assign({ sync: true }, options);
|
|
29
|
+
if (log !== null && log !== undefined && !(log instanceof Function))
|
|
30
|
+
throw new Error("new Sedentary: 'log' option: Wrong type, expected 'null' or 'Function'");
|
|
31
|
+
if (typeof sync !== "boolean")
|
|
32
|
+
throw new Error("new Sedentary: 'sync' option: Wrong type, expected 'boolean'");
|
|
33
|
+
this.log = (0, log_1.createLogger)(log);
|
|
24
34
|
this.db = new minidb_1.MiniDB(filename, this.log);
|
|
35
|
+
this.sync = sync;
|
|
25
36
|
}
|
|
26
37
|
DATETIME() {
|
|
27
38
|
return new db_1.Type({ base: Date, type: "DATETIME" });
|
|
28
39
|
}
|
|
29
|
-
FKEY(
|
|
30
|
-
|
|
40
|
+
FKEY(attribute) {
|
|
41
|
+
const { attributeName, base, fieldName, size, tableName, type } = attribute;
|
|
42
|
+
return new db_1.Type({ base, foreignKey: { attributeName, fieldName, tableName }, size, type });
|
|
31
43
|
}
|
|
32
44
|
INT(size) {
|
|
33
45
|
const message = "Sedentary.INT: 'size' argument: Wrong value, expected 2 or 4";
|
|
@@ -49,11 +61,11 @@ class Sedentary {
|
|
|
49
61
|
this.log("Connecting...");
|
|
50
62
|
await this.db.connect();
|
|
51
63
|
this.log("Connected, syncing...");
|
|
52
|
-
await this.db.
|
|
64
|
+
await this.db.syncDataBase();
|
|
53
65
|
this.log("Synced");
|
|
54
66
|
}
|
|
55
67
|
catch (e) {
|
|
56
|
-
this.log("Connecting:
|
|
68
|
+
this.log("Connecting:", e.message);
|
|
57
69
|
throw e;
|
|
58
70
|
}
|
|
59
71
|
}
|
|
@@ -62,21 +74,21 @@ class Sedentary {
|
|
|
62
74
|
await this.db.end();
|
|
63
75
|
this.log("Connection closed");
|
|
64
76
|
}
|
|
65
|
-
model(name,
|
|
77
|
+
model(name, attributes, options) {
|
|
66
78
|
if (typeof name !== "string")
|
|
67
79
|
throw new Error("Sedentary.model: 'name' argument: Wrong type, expected 'string'");
|
|
68
80
|
if (this.models[name])
|
|
69
81
|
throw new Error(`Sedentary.model: '${name}' model: Model already defined`);
|
|
70
|
-
if (!
|
|
71
|
-
|
|
72
|
-
if (!(
|
|
73
|
-
throw new Error(`Sedentary.model: '${name}' model: '
|
|
82
|
+
if (!attributes)
|
|
83
|
+
attributes = {};
|
|
84
|
+
if (!(attributes instanceof Object))
|
|
85
|
+
throw new Error(`Sedentary.model: '${name}' model: 'attributes' argument: Wrong type, expected 'Object'`);
|
|
74
86
|
if (!options)
|
|
75
87
|
options = {};
|
|
76
88
|
if (!(options instanceof Object))
|
|
77
89
|
throw new Error(`Sedentary.model: '${name}' model: 'options' argument: Wrong type, expected 'Object'`);
|
|
78
90
|
for (const k in options)
|
|
79
|
-
if (allowedOption.
|
|
91
|
+
if (!allowedOption.includes(k))
|
|
80
92
|
throw new Error(`Sedentary.model: '${name}' model: 'options' argument: Unknown '${k}' option`);
|
|
81
93
|
if (options.int8id && options.parent)
|
|
82
94
|
throw new Error(`Sedentary.model: '${name}' model: 'int8id' and 'parent' options conflict each other`);
|
|
@@ -84,14 +96,15 @@ class Sedentary {
|
|
|
84
96
|
throw new Error(`Sedentary.model: '${name}' model: 'int8id' and 'primaryKey' options conflict each other`);
|
|
85
97
|
if (options.parent && options.primaryKey)
|
|
86
98
|
throw new Error(`Sedentary.model: '${name}' model: 'parent' and 'primaryKey' options conflict each other`);
|
|
87
|
-
|
|
88
|
-
const { indexes, int8id, parent, primaryKey, sync, tableName } = Object.assign({ sync: this.sync, tableName: name
|
|
99
|
+
let autoIncrement = true;
|
|
100
|
+
const { indexes, int8id, parent, primaryKey, sync, tableName } = Object.assign({ sync: this.sync, tableName: name }, options);
|
|
89
101
|
let { methods } = options;
|
|
102
|
+
let aarray = int8id
|
|
103
|
+
? [new db_1.Attribute(Object.assign(Object.assign({}, this.INT8()), { attributeName: "id", fieldName: "id", notNull: true, tableName, unique: true }))]
|
|
104
|
+
: [new db_1.Attribute(Object.assign(Object.assign({}, this.INT(4)), { attributeName: "id", fieldName: "id", notNull: true, tableName, unique: true }))];
|
|
105
|
+
let constraints = [{ attribute: aarray[0], constraintName: `${tableName}_id_unique`, type: "u" }];
|
|
90
106
|
const iarray = [];
|
|
91
|
-
const
|
|
92
|
-
let farray = int8id
|
|
93
|
-
? [new db_1.Field({ fieldName: "id", notNull: true, size: 8, type: "INT8", unique: true })]
|
|
94
|
-
: [new db_1.Field({ fieldName: "id", notNull: true, size: 4, type: "INT", unique: true })];
|
|
107
|
+
const pk = aarray[0];
|
|
95
108
|
if (methods && !(methods instanceof Object))
|
|
96
109
|
throw new Error(`Sedentary.model: '${name}' model: 'methods' option: Wrong type, expected 'Object'`);
|
|
97
110
|
if (parent) {
|
|
@@ -106,119 +119,127 @@ class Sedentary {
|
|
|
106
119
|
}
|
|
107
120
|
if (primaryKey && typeof primaryKey !== "string")
|
|
108
121
|
throw new Error(`Sedentary.model: '${name}' model: 'primaryKey' option: Wrong type, expected 'string'`);
|
|
109
|
-
if (primaryKey && Object.keys(
|
|
110
|
-
throw new Error(`Sedentary.model: '${name}' model: 'primaryKey' option:
|
|
111
|
-
if (parent || primaryKey)
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
122
|
+
if (primaryKey && !Object.keys(attributes).includes(primaryKey))
|
|
123
|
+
throw new Error(`Sedentary.model: '${name}' model: 'primaryKey' option: Attribute '${primaryKey}' does not exists`);
|
|
124
|
+
if (parent || primaryKey) {
|
|
125
|
+
autoIncrement = false;
|
|
126
|
+
aarray = [];
|
|
127
|
+
constraints = [];
|
|
128
|
+
}
|
|
129
|
+
for (const attributeName in attributes) {
|
|
130
|
+
if (reservedNames.includes(attributeName))
|
|
131
|
+
throw new Error(`Sedentary.model: '${name}' model: '${attributeName}' attribute: Reserved name`);
|
|
132
|
+
const call = (defaultValue, fieldName, notNull, unique, func, message1, message2) => {
|
|
133
|
+
if (func === this.FKEY)
|
|
134
|
+
throw new Error(`${message1} 'this.FKEY' can't be used directly`);
|
|
135
|
+
if (func !== this.DATETIME && func !== this.INT && func !== this.INT8 && func !== this.VARCHAR)
|
|
136
|
+
throw new Error(`${message1} ${message2}`);
|
|
137
|
+
return new db_1.Attribute(Object.assign({ attributeName, defaultValue, fieldName, notNull, tableName, unique }, func()));
|
|
138
|
+
};
|
|
139
|
+
const attributeDefinition = attributes[attributeName];
|
|
140
|
+
let { base, defaultValue, fieldName, foreignKey, notNull, size, type, unique } = (() => {
|
|
121
141
|
const ret = (() => {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
};
|
|
129
|
-
|
|
130
|
-
return new db_1.Field(Object.assign({ fieldName: fname }, Object.assign({ notNull: false }, field)));
|
|
131
|
-
if (field instanceof Function)
|
|
132
|
-
return call(undefined, fname, false, false, field, `Sedentary.model: '${name}' model: '${fname}' field: Wrong type, expected 'Field'`);
|
|
133
|
-
if (!(field instanceof Object))
|
|
134
|
-
throw new Error(`Sedentary.model: '${name}' model: '${fname}' field: Wrong field type, expected 'Field'`);
|
|
135
|
-
({ defaultValue, fieldName, notNull, unique, type } = Object.assign({ notNull: false }, field));
|
|
136
|
-
if (!fieldName)
|
|
137
|
-
fieldName = fname;
|
|
142
|
+
if (attributeDefinition instanceof db_1.Type)
|
|
143
|
+
return new db_1.Attribute(Object.assign({ attributeName, fieldName: attributeName, notNull: false, tableName }, attributeDefinition));
|
|
144
|
+
if (attributeDefinition instanceof Function)
|
|
145
|
+
return call(undefined, attributeName, false, false, attributeDefinition, `Sedentary.model: '${name}' model: '${attributeName}' attribute:`, "Wrong type, expected 'Attribute'");
|
|
146
|
+
if (!(attributeDefinition instanceof Object))
|
|
147
|
+
throw new Error(`Sedentary.model: '${name}' model: '${attributeName}' attribute: Wrong attribute type, expected 'Attribute'`);
|
|
148
|
+
const attributeDefaults = Object.assign({ defaultValue: undefined, fieldName: attributeName, notNull: false, unique: false }, attributeDefinition);
|
|
149
|
+
const { defaultValue, fieldName, notNull, unique, type } = attributeDefaults;
|
|
138
150
|
if (defaultValue === null)
|
|
139
|
-
throw new Error(`Sedentary.model: '${name}' model: '${
|
|
151
|
+
throw new Error(`Sedentary.model: '${name}' model: '${attributeName}' attribute: 'defaultValue' option: Does 'null' default value really makes sense?`);
|
|
140
152
|
if (typeof fieldName !== "string")
|
|
141
|
-
throw new Error(`Sedentary.model: '${name}' model: '${
|
|
142
|
-
if (
|
|
143
|
-
throw new Error(`Sedentary.model: '${name}' model: '${
|
|
153
|
+
throw new Error(`Sedentary.model: '${name}' model: '${attributeName}' attribute: 'fieldName' option: Wrong type, expected 'string'`);
|
|
154
|
+
if (typeof notNull !== "boolean")
|
|
155
|
+
throw new Error(`Sedentary.model: '${name}' model: '${attributeName}' attribute: 'notNull' option: Wrong type, expected 'boolean'`);
|
|
156
|
+
if (typeof unique !== "boolean")
|
|
157
|
+
throw new Error(`Sedentary.model: '${name}' model: '${attributeName}' attribute: 'unique' option: Wrong type, expected 'boolean'`);
|
|
158
|
+
if (type === undefined)
|
|
159
|
+
throw new Error(`Sedentary.model: '${name}' model: '${attributeName}' attribute: Missing 'type' option`);
|
|
144
160
|
if (type instanceof db_1.Type)
|
|
145
|
-
return new db_1.
|
|
161
|
+
return new db_1.Attribute(Object.assign({ attributeName, defaultValue, fieldName, notNull, tableName, unique }, type));
|
|
146
162
|
if (type instanceof Function)
|
|
147
|
-
return call(defaultValue, fieldName, notNull, unique, type, `Sedentary.model: '${name}' model: '${
|
|
148
|
-
throw new Error(`Sedentary.model: '${name}' model: '${
|
|
163
|
+
return call(defaultValue, fieldName, notNull, unique, type, `Sedentary.model: '${name}' model: '${attributeName}' attribute: 'type' option:`, "Wrong type, expected 'Type'");
|
|
164
|
+
throw new Error(`Sedentary.model: '${name}' model: '${attributeName}' attribute: 'type' option: Wrong type, expected 'Type'`);
|
|
149
165
|
})();
|
|
150
166
|
const { base, defaultValue } = ret;
|
|
151
167
|
if (defaultValue !== undefined) {
|
|
168
|
+
if (base === Date && !(defaultValue instanceof Date))
|
|
169
|
+
throw new Error(`Sedentary.model: '${name}' model: '${attributeName}' attribute: 'defaultValue' option: Wrong type, expected 'Date'`);
|
|
152
170
|
if (base === Number && typeof defaultValue !== "number")
|
|
153
|
-
throw new Error(`Sedentary.model: '${name}' model: '${
|
|
171
|
+
throw new Error(`Sedentary.model: '${name}' model: '${attributeName}' attribute: 'defaultValue' option: Wrong type, expected 'number'`);
|
|
154
172
|
if (base === String && typeof defaultValue !== "string")
|
|
155
|
-
throw new Error(`Sedentary.model: '${name}' model: '${
|
|
173
|
+
throw new Error(`Sedentary.model: '${name}' model: '${attributeName}' attribute: 'defaultValue' option: Wrong type, expected 'string'`);
|
|
156
174
|
}
|
|
157
175
|
return ret;
|
|
158
176
|
})();
|
|
159
|
-
if (primaryKey ===
|
|
177
|
+
if (primaryKey === attributeName) {
|
|
160
178
|
notNull = true;
|
|
161
179
|
unique = true;
|
|
162
180
|
}
|
|
163
181
|
if (defaultValue)
|
|
164
182
|
notNull = true;
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
183
|
+
const attribute = new db_1.Attribute({ attributeName, base, defaultValue, fieldName, foreignKey, notNull, size, tableName, type, unique });
|
|
184
|
+
aarray.push(attribute);
|
|
185
|
+
if (foreignKey)
|
|
186
|
+
constraints.push({ attribute, constraintName: `fkey_${fieldName}_${foreignKey.tableName}_${foreignKey.fieldName}`, type: "f" });
|
|
187
|
+
if (unique)
|
|
188
|
+
constraints.push({ attribute, constraintName: `${tableName}_${fieldName}_unique`, type: "u" });
|
|
168
189
|
}
|
|
169
190
|
if (indexes) {
|
|
170
|
-
const flds =
|
|
191
|
+
const flds = attributes;
|
|
171
192
|
if (!(indexes instanceof Object))
|
|
172
193
|
throw new Error(`Sedentary.model: '${name}' model: 'indexes' option: Wrong type, expected 'Object'`);
|
|
173
|
-
for (const
|
|
174
|
-
if (
|
|
175
|
-
throw new Error(`Sedentary.model: '${name}' model: '${
|
|
176
|
-
const idx = indexes[
|
|
177
|
-
const
|
|
178
|
-
if (typeof
|
|
179
|
-
throw new Error(`Sedentary.model: '${name}' model: '${
|
|
180
|
-
if (!(
|
|
181
|
-
throw new Error(`Sedentary.model: '${name}' model: '${
|
|
194
|
+
for (const indexName in indexes) {
|
|
195
|
+
if (aarray.filter(({ fieldName, unique }) => unique && `${tableName}_${fieldName}_unique` === indexName).length !== 0)
|
|
196
|
+
throw new Error(`Sedentary.model: '${name}' model: '${indexName}' index: index name already inferred by the unique constraint on an attribute`);
|
|
197
|
+
const idx = indexes[indexName];
|
|
198
|
+
const checkAttribute = (attribute, l) => {
|
|
199
|
+
if (typeof attribute !== "string")
|
|
200
|
+
throw new Error(`Sedentary.model: '${name}' model: '${indexName}' index: #${l + 1} attribute: Wrong type, expected 'string'`);
|
|
201
|
+
if (!(attribute in flds))
|
|
202
|
+
throw new Error(`Sedentary.model: '${name}' model: '${indexName}' index: #${l + 1} attribute: Unknown attribute '${attribute}'`);
|
|
182
203
|
};
|
|
183
|
-
let
|
|
204
|
+
let attributes;
|
|
184
205
|
let type = "btree";
|
|
185
206
|
let unique = false;
|
|
186
207
|
if (idx instanceof Array) {
|
|
187
|
-
idx.forEach(
|
|
188
|
-
|
|
208
|
+
idx.forEach(checkAttribute);
|
|
209
|
+
attributes = idx;
|
|
189
210
|
}
|
|
190
211
|
else if (typeof idx === "string") {
|
|
191
|
-
|
|
192
|
-
|
|
212
|
+
checkAttribute(idx, 0);
|
|
213
|
+
attributes = [idx];
|
|
193
214
|
}
|
|
194
215
|
else if (idx instanceof Object) {
|
|
195
216
|
for (const k in idx)
|
|
196
|
-
if (["
|
|
197
|
-
throw new Error(`Sedentary.model: '${name}' model: '${
|
|
198
|
-
({
|
|
199
|
-
if (!
|
|
200
|
-
throw new Error(`Sedentary.model: '${name}' model: '${
|
|
201
|
-
if (
|
|
202
|
-
|
|
203
|
-
else if (typeof
|
|
204
|
-
|
|
205
|
-
|
|
217
|
+
if (!["attributes", "type", "unique"].includes(k))
|
|
218
|
+
throw new Error(`Sedentary.model: '${name}' model: '${indexName}' index: Unknown index option '${k}'`);
|
|
219
|
+
({ attributes, type, unique } = Object.assign({ type: "btree", unique: false }, idx));
|
|
220
|
+
if (!attributes)
|
|
221
|
+
throw new Error(`Sedentary.model: '${name}' model: '${indexName}' index: Missing 'attributes' option`);
|
|
222
|
+
if (attributes instanceof Array)
|
|
223
|
+
attributes.forEach(checkAttribute);
|
|
224
|
+
else if (typeof attributes === "string") {
|
|
225
|
+
checkAttribute(attributes, 0);
|
|
226
|
+
attributes = [attributes];
|
|
206
227
|
}
|
|
207
228
|
else
|
|
208
|
-
throw new Error(`Sedentary.model: '${name}' model: '${
|
|
229
|
+
throw new Error(`Sedentary.model: '${name}' model: '${indexName}' index: 'attributes' option: Wrong type, expected 'FieldNames'`);
|
|
209
230
|
if (typeof type !== "string")
|
|
210
|
-
throw new Error(`Sedentary.model: '${name}' model: '${
|
|
211
|
-
if (["btree", "hash"].
|
|
212
|
-
throw new Error(`Sedentary.model: '${name}' model: '${
|
|
231
|
+
throw new Error(`Sedentary.model: '${name}' model: '${indexName}' index: 'type' option: Wrong type, expected 'string'`);
|
|
232
|
+
if (!["btree", "hash"].includes(type))
|
|
233
|
+
throw new Error(`Sedentary.model: '${name}' model: '${indexName}' index: 'type' option: Wrong value, expected 'btree' or 'hash'`);
|
|
213
234
|
if (typeof unique !== "boolean")
|
|
214
|
-
throw new Error(`Sedentary.model: '${name}' model: '${
|
|
235
|
+
throw new Error(`Sedentary.model: '${name}' model: '${indexName}' index: 'unique' option: Wrong type, expected 'boolean'`);
|
|
215
236
|
}
|
|
216
237
|
else
|
|
217
|
-
throw new Error(`Sedentary.model: '${name}' model: '${
|
|
218
|
-
iarray.push({ fields
|
|
238
|
+
throw new Error(`Sedentary.model: '${name}' model: '${indexName}' index: Wrong type, expected 'Object'`);
|
|
239
|
+
iarray.push({ fields: attributes, indexName, type, unique });
|
|
219
240
|
}
|
|
220
241
|
}
|
|
221
|
-
this.db.
|
|
242
|
+
this.db.tables.push(new db_1.Table({ autoIncrement, constraints, attributes: aarray, indexes: iarray, parent, sync, tableName }));
|
|
222
243
|
this.models[name] = true;
|
|
223
244
|
const init = parent
|
|
224
245
|
? options.init
|
|
@@ -229,7 +250,7 @@ class Sedentary {
|
|
|
229
250
|
: parent.init
|
|
230
251
|
: options.init;
|
|
231
252
|
const flds = {};
|
|
232
|
-
for (const key in
|
|
253
|
+
for (const key in attributes)
|
|
233
254
|
flds[key] = null;
|
|
234
255
|
class Class {
|
|
235
256
|
constructor() {
|
|
@@ -249,15 +270,19 @@ class Sedentary {
|
|
|
249
270
|
return resolve([new Class()]);
|
|
250
271
|
reject(new Error("boh"));
|
|
251
272
|
}, 10));
|
|
252
|
-
Object.defineProperty(load, "name", { value: name + "
|
|
253
|
-
const meta = { tableName, primaryKey, init, methods };
|
|
254
|
-
Object.defineProperty(Class, "
|
|
273
|
+
Object.defineProperty(load, "name", { value: name + ".load" });
|
|
274
|
+
const meta = { base: Number, type: "meta", tableName, primaryKey, init, methods };
|
|
275
|
+
Object.defineProperty(Class, "isModel", { value: () => true });
|
|
255
276
|
Object.defineProperty(Class, "load", { value: load });
|
|
256
277
|
Object.defineProperty(Class, "meta", { value: new db_1.Meta(meta) });
|
|
278
|
+
Object.defineProperty(Class, "name", { value: name });
|
|
257
279
|
Object.defineProperty(Class.prototype.save, "name", { value: name + ".save" });
|
|
258
280
|
Object.assign(Class, new db_1.Meta(meta));
|
|
259
|
-
Object.assign(Class, Object.assign(Object.assign({}, fields), { isModel: () => true }));
|
|
260
281
|
Object.assign(Class.prototype, methods);
|
|
282
|
+
for (const attribute of aarray)
|
|
283
|
+
Object.defineProperty(Class, attribute.attributeName, { value: attribute });
|
|
284
|
+
for (const key of ["attributeName", "base", "fieldName", "size", "type", "unique"])
|
|
285
|
+
Object.defineProperty(Class, key, { value: pk[key] });
|
|
261
286
|
return Class;
|
|
262
287
|
}
|
|
263
288
|
checkSize(size, message) {
|
|
@@ -271,12 +296,11 @@ class Sedentary {
|
|
|
271
296
|
exports.Sedentary = Sedentary;
|
|
272
297
|
exports.Package = Sedentary;
|
|
273
298
|
const db = new Sedentary("gino");
|
|
274
|
-
const Users = db.model("User", { foo: db.INT(), bar: db.VARCHAR() }, {});
|
|
275
|
-
|
|
299
|
+
const Users = db.model("User", { foo: db.INT(), bar: { type: db.VARCHAR(), unique: true } }, {});
|
|
300
|
+
class Item extends db.model("Item", {
|
|
276
301
|
num: db.FKEY(Users),
|
|
277
302
|
str: db.VARCHAR()
|
|
278
|
-
}
|
|
279
|
-
class Item extends db.model("Item", fields, {
|
|
303
|
+
}, {
|
|
280
304
|
init: function () {
|
|
281
305
|
this.num = 0;
|
|
282
306
|
this.str = "0";
|
|
@@ -309,7 +333,7 @@ class Next extends db.model("Next", { a: db.INT, b: db.INT }, {
|
|
|
309
333
|
primaryKey: "a"
|
|
310
334
|
}) {
|
|
311
335
|
}
|
|
312
|
-
class Current extends db.model("Current", { b: db.FKEY(Next) }, {
|
|
336
|
+
class Current extends db.model("Current", { b: { type: db.FKEY(Next), unique: true } }, {
|
|
313
337
|
init: function () {
|
|
314
338
|
this.b = 24;
|
|
315
339
|
}
|
package/lib/db.d.ts
CHANGED
|
@@ -1,89 +1,80 @@
|
|
|
1
|
-
export declare
|
|
1
|
+
export declare type Natural = Date | Record<string, unknown> | boolean | number | string;
|
|
2
|
+
export declare class Entry {
|
|
2
3
|
init(): void;
|
|
3
4
|
save(): Promise<boolean>;
|
|
4
5
|
}
|
|
5
|
-
export declare class Type<N extends
|
|
6
|
+
export declare class Type<N extends Natural, E> {
|
|
6
7
|
base: unknown;
|
|
8
|
+
entry?: E;
|
|
7
9
|
native?: N;
|
|
8
|
-
record?: R;
|
|
9
10
|
size?: number;
|
|
10
11
|
type: string;
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
methods: {
|
|
16
|
-
[key: string]: () => unknown;
|
|
12
|
+
foreignKey?: {
|
|
13
|
+
attributeName: string;
|
|
14
|
+
fieldName: string;
|
|
15
|
+
tableName: string;
|
|
17
16
|
};
|
|
18
|
-
|
|
19
|
-
tableName: string;
|
|
17
|
+
constructor(from: Type<N, E>);
|
|
20
18
|
}
|
|
21
|
-
export declare class Meta<N extends
|
|
19
|
+
export declare class Meta<N extends Natural, E> extends Type<N, E> {
|
|
22
20
|
init: () => void;
|
|
21
|
+
isModel?: () => boolean;
|
|
23
22
|
methods: {
|
|
24
23
|
[key: string]: () => unknown;
|
|
25
24
|
};
|
|
26
25
|
primaryKey: string;
|
|
27
26
|
tableName: string;
|
|
28
|
-
constructor(
|
|
29
|
-
isModel(): boolean;
|
|
27
|
+
constructor(from: Meta<N, E>);
|
|
30
28
|
}
|
|
31
|
-
export declare class
|
|
29
|
+
export declare class Attribute<N extends Natural, E> extends Type<N, E> {
|
|
30
|
+
attributeName: string;
|
|
32
31
|
defaultValue?: unknown;
|
|
33
|
-
fieldName
|
|
34
|
-
notNull
|
|
32
|
+
fieldName: string;
|
|
33
|
+
notNull: boolean;
|
|
34
|
+
tableName: string;
|
|
35
35
|
unique?: boolean;
|
|
36
|
-
constructor(from:
|
|
36
|
+
constructor(from: Attribute<N, E>);
|
|
37
37
|
}
|
|
38
38
|
export interface Constraint {
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
attribute: Attribute<Natural, unknown>;
|
|
40
|
+
constraintName: string;
|
|
41
41
|
type: "f" | "u";
|
|
42
42
|
}
|
|
43
|
-
export
|
|
44
|
-
export interface IndexDef {
|
|
43
|
+
export interface Index {
|
|
45
44
|
fields: string[];
|
|
46
|
-
|
|
45
|
+
indexName: string;
|
|
47
46
|
type: "btree" | "hash";
|
|
48
47
|
unique: boolean;
|
|
49
48
|
}
|
|
50
|
-
interface IndexOptions {
|
|
51
|
-
fields: IndexFields;
|
|
52
|
-
type?: "btree" | "hash";
|
|
53
|
-
unique?: boolean;
|
|
54
|
-
}
|
|
55
|
-
export declare type Index = IndexFields | IndexOptions;
|
|
56
49
|
interface ITable {
|
|
50
|
+
attributes: Attribute<Natural, unknown>[];
|
|
51
|
+
autoIncrement: boolean;
|
|
57
52
|
constraints: Constraint[];
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
oid?: number;
|
|
61
|
-
parent: Meta<unknown, Record>;
|
|
62
|
-
primaryKey: string;
|
|
53
|
+
indexes: Index[];
|
|
54
|
+
parent: Meta<Natural, unknown>;
|
|
63
55
|
sync: boolean;
|
|
64
56
|
tableName: string;
|
|
65
57
|
}
|
|
66
58
|
declare const Table_base: new (defaults?: ITable) => ITable;
|
|
67
59
|
export declare class Table extends Table_base {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
60
|
+
autoIncrementOwn?: boolean;
|
|
61
|
+
oid?: number;
|
|
62
|
+
findField(name: string): Attribute<Natural, unknown>;
|
|
71
63
|
}
|
|
72
64
|
export declare abstract class DB {
|
|
73
|
-
tables:
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
tablesArr: Table[];
|
|
77
|
-
protected log: (message: string) => void;
|
|
65
|
+
tables: Table[];
|
|
66
|
+
protected log: (...data: unknown[]) => void;
|
|
67
|
+
protected sync: boolean;
|
|
78
68
|
abstract connect(): Promise<void>;
|
|
79
69
|
abstract end(): Promise<void>;
|
|
80
70
|
constructor(log: (message: string) => void);
|
|
81
|
-
|
|
82
|
-
protected indexesEq(a:
|
|
83
|
-
|
|
84
|
-
|
|
71
|
+
findTable(name: string): Table;
|
|
72
|
+
protected indexesEq(a: Index, b: Index): boolean;
|
|
73
|
+
syncDataBase(): Promise<void>;
|
|
74
|
+
protected syncLog(...data: unknown[]): void;
|
|
75
|
+
abstract dropConstraints(table: Table): Promise<number[]>;
|
|
85
76
|
abstract dropFields(table: Table): Promise<void>;
|
|
86
|
-
abstract dropIndexes(table: Table): Promise<void>;
|
|
77
|
+
abstract dropIndexes(table: Table, constraintIndexes: number[]): Promise<void>;
|
|
87
78
|
abstract syncConstraints(table: Table): Promise<void>;
|
|
88
79
|
abstract syncFields(table: Table): Promise<void>;
|
|
89
80
|
abstract syncIndexes(table: Table): Promise<void>;
|
package/lib/db.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.DB = exports.Table = exports.
|
|
4
|
-
class
|
|
3
|
+
exports.DB = exports.Table = exports.Attribute = exports.Meta = exports.Type = exports.Entry = void 0;
|
|
4
|
+
class Entry {
|
|
5
5
|
init() { }
|
|
6
6
|
async save() {
|
|
7
7
|
return false;
|
|
8
8
|
}
|
|
9
9
|
}
|
|
10
|
-
exports.
|
|
10
|
+
exports.Entry = Entry;
|
|
11
11
|
class Type {
|
|
12
12
|
constructor(from) {
|
|
13
13
|
Object.assign(this, from);
|
|
@@ -15,21 +15,17 @@ class Type {
|
|
|
15
15
|
}
|
|
16
16
|
exports.Type = Type;
|
|
17
17
|
class Meta extends Type {
|
|
18
|
-
constructor(
|
|
19
|
-
super(
|
|
20
|
-
Object.assign(this, options);
|
|
21
|
-
}
|
|
22
|
-
isModel() {
|
|
23
|
-
return true;
|
|
18
|
+
constructor(from) {
|
|
19
|
+
super(from);
|
|
24
20
|
}
|
|
25
21
|
}
|
|
26
22
|
exports.Meta = Meta;
|
|
27
|
-
class
|
|
23
|
+
class Attribute extends Type {
|
|
28
24
|
constructor(from) {
|
|
29
25
|
super(from);
|
|
30
26
|
}
|
|
31
27
|
}
|
|
32
|
-
exports.
|
|
28
|
+
exports.Attribute = Attribute;
|
|
33
29
|
function autoImplement() {
|
|
34
30
|
return class {
|
|
35
31
|
constructor(defaults) {
|
|
@@ -38,28 +34,18 @@ function autoImplement() {
|
|
|
38
34
|
};
|
|
39
35
|
}
|
|
40
36
|
class Table extends autoImplement() {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
if (!this.primaryKey) {
|
|
44
|
-
if (this.parent)
|
|
45
|
-
this.primaryKey = this.parent.primaryKey;
|
|
46
|
-
else {
|
|
47
|
-
this.primaryKey = "id";
|
|
48
|
-
this.autoIncrement = true;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
37
|
+
findField(name) {
|
|
38
|
+
return this.attributes.filter(_ => _.fieldName === name)[0];
|
|
51
39
|
}
|
|
52
40
|
}
|
|
53
41
|
exports.Table = Table;
|
|
54
42
|
class DB {
|
|
55
43
|
constructor(log) {
|
|
56
|
-
this.tables =
|
|
57
|
-
this.tablesArr = [];
|
|
44
|
+
this.tables = [];
|
|
58
45
|
this.log = log;
|
|
59
46
|
}
|
|
60
|
-
|
|
61
|
-
this.tables
|
|
62
|
-
this.tablesArr.push(table);
|
|
47
|
+
findTable(name) {
|
|
48
|
+
return this.tables.filter(_ => _.tableName === name)[0];
|
|
63
49
|
}
|
|
64
50
|
indexesEq(a, b) {
|
|
65
51
|
if (a.fields.length !== b.fields.length)
|
|
@@ -73,12 +59,12 @@ class DB {
|
|
|
73
59
|
return false;
|
|
74
60
|
return true;
|
|
75
61
|
}
|
|
76
|
-
async
|
|
77
|
-
for (const
|
|
78
|
-
|
|
62
|
+
async syncDataBase() {
|
|
63
|
+
for (const table of this.tables) {
|
|
64
|
+
this.sync = table.sync;
|
|
79
65
|
await this.syncTable(table);
|
|
80
|
-
await this.dropConstraints(table);
|
|
81
|
-
await this.dropIndexes(table);
|
|
66
|
+
const indexes = await this.dropConstraints(table);
|
|
67
|
+
await this.dropIndexes(table, indexes);
|
|
82
68
|
await this.dropFields(table);
|
|
83
69
|
await this.syncFields(table);
|
|
84
70
|
await this.syncSequence(table);
|
|
@@ -86,5 +72,9 @@ class DB {
|
|
|
86
72
|
await this.syncIndexes(table);
|
|
87
73
|
}
|
|
88
74
|
}
|
|
75
|
+
syncLog(...data) {
|
|
76
|
+
const args = this.sync ? data : ["NOT SYNCING:", ...data];
|
|
77
|
+
this.log(...args);
|
|
78
|
+
}
|
|
89
79
|
}
|
|
90
80
|
exports.DB = DB;
|
package/lib/log.d.ts
ADDED
package/lib/log.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createLogger = void 0;
|
|
4
|
+
const console_1 = require("console");
|
|
5
|
+
const stream_1 = require("stream");
|
|
6
|
+
class Logger extends stream_1.Writable {
|
|
7
|
+
constructor(log) {
|
|
8
|
+
super();
|
|
9
|
+
this.log = log;
|
|
10
|
+
}
|
|
11
|
+
_write(chunk, encoding, callback) {
|
|
12
|
+
this.log(chunk.toString());
|
|
13
|
+
callback();
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function createLogger(log) {
|
|
17
|
+
// eslint-disable-next-line no-console
|
|
18
|
+
return log ? new console_1.Console(new Logger(log)).log : log === null ? () => { } : console.log;
|
|
19
|
+
}
|
|
20
|
+
exports.createLogger = createLogger;
|
package/lib/log.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Console } from "console";
|
|
2
|
+
import { Writable } from "stream";
|
|
3
|
+
|
|
4
|
+
class Logger extends Writable {
|
|
5
|
+
private log: (message: string) => void;
|
|
6
|
+
|
|
7
|
+
constructor(log: (message: string) => void) {
|
|
8
|
+
super();
|
|
9
|
+
|
|
10
|
+
this.log = log;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
_write(chunk: Buffer, encoding: string, callback: () => void) {
|
|
14
|
+
this.log(chunk.toString());
|
|
15
|
+
callback();
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function createLogger(log: ((message: string) => void) | null | undefined) {
|
|
20
|
+
// eslint-disable-next-line no-console
|
|
21
|
+
return log ? new Console(new Logger(log)).log : log === null ? () => {} : console.log;
|
|
22
|
+
}
|
package/lib/minidb.d.ts
CHANGED
|
@@ -4,9 +4,9 @@ export declare class MiniDB extends DB {
|
|
|
4
4
|
private file;
|
|
5
5
|
constructor(filename: string, log: (message: string) => void);
|
|
6
6
|
connect(): Promise<void>;
|
|
7
|
-
dropConstraints(table: Table): Promise<
|
|
7
|
+
dropConstraints(table: Table): Promise<number[]>;
|
|
8
8
|
dropFields(table: Table): Promise<void>;
|
|
9
|
-
dropIndexes(table: Table): Promise<void>;
|
|
9
|
+
dropIndexes(table: Table, constraintIndexes: number[]): Promise<void>;
|
|
10
10
|
end(): Promise<void>;
|
|
11
11
|
save(): Promise<void>;
|
|
12
12
|
syncConstraints(table: Table): Promise<void>;
|
package/lib/minidb.js
CHANGED
|
@@ -22,28 +22,36 @@ class MiniDB extends db_1.DB {
|
|
|
22
22
|
}
|
|
23
23
|
async dropConstraints(table) {
|
|
24
24
|
const { constraints } = this.body.tables[table.tableName];
|
|
25
|
-
for (const constraint
|
|
26
|
-
if (!table.constraints.filter(({
|
|
27
|
-
this.log(`'${table.tableName}': Removing
|
|
25
|
+
for (const constraint of Object.keys(constraints.f).sort()) {
|
|
26
|
+
if (!table.constraints.filter(({ constraintName, type }) => constraintName === constraint && type === "f").length) {
|
|
27
|
+
this.log(`'${table.tableName}': Removing foreign key: '${constraint}'`);
|
|
28
|
+
delete constraints.f[constraint];
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
for (const constraint of Object.keys(constraints.u).sort()) {
|
|
32
|
+
if (!table.constraints.filter(({ constraintName, type }) => constraintName === constraint && type === "u").length) {
|
|
33
|
+
this.log(`'${table.tableName}': Removing unique constraint from field: '${constraints.u[constraint].fieldName}'`);
|
|
28
34
|
delete constraints.u[constraint];
|
|
29
35
|
}
|
|
30
36
|
}
|
|
31
37
|
await this.save();
|
|
38
|
+
return [];
|
|
32
39
|
}
|
|
33
40
|
async dropFields(table) {
|
|
34
41
|
const { fields } = this.body.tables[table.tableName];
|
|
35
|
-
for (const
|
|
36
|
-
if (table.
|
|
37
|
-
this.log(`'${table.tableName}': Removing field: '${
|
|
38
|
-
delete fields[
|
|
42
|
+
for (const attribute in fields) {
|
|
43
|
+
if (!table.findField(attribute)) {
|
|
44
|
+
this.log(`'${table.tableName}': Removing field: '${attribute}'`);
|
|
45
|
+
delete fields[attribute];
|
|
39
46
|
}
|
|
40
47
|
}
|
|
41
48
|
await this.save();
|
|
42
49
|
}
|
|
43
|
-
|
|
50
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
51
|
+
async dropIndexes(table, constraintIndexes) {
|
|
44
52
|
const { indexes } = this.body.tables[table.tableName];
|
|
45
53
|
for (const name in indexes) {
|
|
46
|
-
const index = table.indexes.filter(_ => _.
|
|
54
|
+
const index = table.indexes.filter(_ => _.indexName === name);
|
|
47
55
|
if (index.length === 0 || !this.indexesEq(indexes[name], index[0])) {
|
|
48
56
|
this.log(`'${table.tableName}': Removing index: '${name}'`);
|
|
49
57
|
delete indexes[name];
|
|
@@ -57,11 +65,20 @@ class MiniDB extends db_1.DB {
|
|
|
57
65
|
}
|
|
58
66
|
async syncConstraints(table) {
|
|
59
67
|
const { constraints } = this.body.tables[table.tableName];
|
|
60
|
-
for (const
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
68
|
+
for (const constraint of table.constraints) {
|
|
69
|
+
const { constraintName, type } = constraint;
|
|
70
|
+
const { fieldName, foreignKey } = constraint.attribute;
|
|
71
|
+
if (!constraints[type][constraintName]) {
|
|
72
|
+
switch (type) {
|
|
73
|
+
case "f":
|
|
74
|
+
this.log(`'${table.tableName}': Adding foreign key '${constraint.constraintName}' on field: '${fieldName}' references '${foreignKey.tableName}(${foreignKey.fieldName})'`);
|
|
75
|
+
constraints[type][constraintName] = { fieldName, toField: foreignKey.fieldName, toTable: foreignKey.tableName };
|
|
76
|
+
break;
|
|
77
|
+
case "u":
|
|
78
|
+
this.log(`'${table.tableName}': Adding unique constraint on field: '${fieldName}'`);
|
|
79
|
+
constraints[type][constraintName] = { fieldName };
|
|
80
|
+
break;
|
|
81
|
+
}
|
|
65
82
|
}
|
|
66
83
|
}
|
|
67
84
|
await this.save();
|
|
@@ -69,50 +86,50 @@ class MiniDB extends db_1.DB {
|
|
|
69
86
|
async syncIndexes(table) {
|
|
70
87
|
const { indexes } = this.body.tables[table.tableName];
|
|
71
88
|
for (const index of table.indexes) {
|
|
72
|
-
const {
|
|
73
|
-
if (!(
|
|
74
|
-
this.log(`'${table.tableName}': Adding index: '${
|
|
75
|
-
indexes[
|
|
89
|
+
const { indexName } = index;
|
|
90
|
+
if (!(indexName in indexes)) {
|
|
91
|
+
this.log(`'${table.tableName}': Adding index: '${indexName}' on (${index.fields.map(_ => `'${_}'`).join(", ")}) type '${index.type}'${index.unique ? " unique" : ""}`);
|
|
92
|
+
indexes[indexName] = index;
|
|
76
93
|
}
|
|
77
94
|
}
|
|
78
95
|
await this.save();
|
|
79
96
|
}
|
|
80
97
|
async syncFields(table) {
|
|
81
|
-
for (const
|
|
98
|
+
for (const attribute of table.attributes) {
|
|
82
99
|
const { fields } = this.body.tables[table.tableName];
|
|
83
|
-
const { defaultValue, fieldName, notNull, size, type } =
|
|
84
|
-
let
|
|
85
|
-
if (!
|
|
100
|
+
const { defaultValue, fieldName, notNull, size, type } = attribute;
|
|
101
|
+
let field = fields[fieldName];
|
|
102
|
+
if (!field) {
|
|
86
103
|
this.log(`'${table.tableName}': Adding field: '${fieldName}' '${type}' '${size || ""}'`);
|
|
87
|
-
|
|
104
|
+
field = fields[fieldName] = { size, type };
|
|
88
105
|
}
|
|
89
|
-
if (
|
|
106
|
+
if (field.size !== size || field.type !== type) {
|
|
90
107
|
this.log(`'${table.tableName}': Changing field type: '${fieldName}' '${type}' '${size || ""}'`);
|
|
91
|
-
|
|
108
|
+
field = fields[fieldName] = Object.assign(Object.assign({}, field), { size, type });
|
|
92
109
|
}
|
|
93
|
-
if (
|
|
110
|
+
if (field.default) {
|
|
94
111
|
if (!defaultValue) {
|
|
95
112
|
this.log(`'${table.tableName}': Dropping default value for field: '${fieldName}'`);
|
|
96
|
-
delete
|
|
113
|
+
delete field.default;
|
|
97
114
|
}
|
|
98
|
-
else if (
|
|
115
|
+
else if (field.default !== defaultValue) {
|
|
99
116
|
this.log(`'${table.tableName}': Changing default value to '${defaultValue}' for field: '${fieldName}'`);
|
|
100
|
-
|
|
117
|
+
field.default = defaultValue;
|
|
101
118
|
}
|
|
102
119
|
}
|
|
103
120
|
else if (defaultValue) {
|
|
104
|
-
this.log(`'${table.tableName}': Setting default value '${defaultValue}' for field: '${fieldName}'`);
|
|
105
|
-
|
|
121
|
+
this.log(`'${table.tableName}': Setting default value '${defaultValue instanceof Date ? defaultValue.toISOString() : defaultValue}' for field: '${fieldName}'`);
|
|
122
|
+
field.default = defaultValue;
|
|
106
123
|
}
|
|
107
|
-
if (
|
|
124
|
+
if (field.notNull) {
|
|
108
125
|
if (!notNull) {
|
|
109
126
|
this.log(`'${table.tableName}': Dropping not null for field: '${fieldName}'`);
|
|
110
|
-
delete
|
|
127
|
+
delete field.notNull;
|
|
111
128
|
}
|
|
112
129
|
}
|
|
113
130
|
else if (notNull) {
|
|
114
131
|
this.log(`'${table.tableName}': Setting not null for field: '${fieldName}'`);
|
|
115
|
-
|
|
132
|
+
field.notNull = true;
|
|
116
133
|
}
|
|
117
134
|
}
|
|
118
135
|
await this.save();
|
package/package.json
CHANGED
|
@@ -5,21 +5,24 @@
|
|
|
5
5
|
"description": "The ORM which never needs to migrate",
|
|
6
6
|
"devDependencies": {
|
|
7
7
|
"@types/mocha": "9.0.0",
|
|
8
|
-
"@types/node": "16.11.
|
|
8
|
+
"@types/node": "16.11.10",
|
|
9
9
|
"@types/yamljs": "0.2.31",
|
|
10
|
-
"@typescript-eslint/eslint-plugin": "5.
|
|
11
|
-
"@typescript-eslint/parser": "5.
|
|
12
|
-
"eslint": "8.
|
|
10
|
+
"@typescript-eslint/eslint-plugin": "5.4.0",
|
|
11
|
+
"@typescript-eslint/parser": "5.4.0",
|
|
12
|
+
"eslint": "8.3.0",
|
|
13
13
|
"mocha": "9.1.3",
|
|
14
14
|
"nyc": "15.1.0",
|
|
15
|
-
"prettier": "2.
|
|
15
|
+
"prettier": "2.5.0",
|
|
16
16
|
"ts-node": "10.4.0",
|
|
17
|
-
"typescript": "4.
|
|
17
|
+
"typescript": "4.5.2",
|
|
18
18
|
"yamljs": "0.3.0"
|
|
19
19
|
},
|
|
20
20
|
"engines": {
|
|
21
21
|
"node": ">=12.0"
|
|
22
22
|
},
|
|
23
|
+
"funding": {
|
|
24
|
+
"url": "https://blockchain.info/address/1Md9WFAHrXTb3yPBwQWmUfv2RmzrtbHioB"
|
|
25
|
+
},
|
|
23
26
|
"homepage": "https://github.com/iccicci/sedentary#readme",
|
|
24
27
|
"keywords": [
|
|
25
28
|
"DB",
|
|
@@ -53,5 +56,5 @@
|
|
|
53
56
|
"version": "node -r ts-node/register utils.ts version"
|
|
54
57
|
},
|
|
55
58
|
"types": "index.d.ts",
|
|
56
|
-
"version": "0.0.
|
|
59
|
+
"version": "0.0.16"
|
|
57
60
|
}
|
package/requirements.txt
ADDED
package/tmp.js
DELETED
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
/* eslint-disable no-console */
|
|
2
|
-
|
|
3
|
-
// The account we use to store followings
|
|
4
|
-
const followingsUID = 3186068;
|
|
5
|
-
// Gather the loggedUID from window.localStorage
|
|
6
|
-
const { loggedUID } = window.localStorage;
|
|
7
|
-
// Gather the CSRF-Token from the cookies
|
|
8
|
-
const csrf = document.cookie.split("; ").reduce((ret, _) => (_.startsWith("session_key=") ? _.substr(12) : ret), null);
|
|
9
|
-
|
|
10
|
-
// APIs could have errors, let's do some retries
|
|
11
|
-
async function myFetch(url, options, attempt = 0) {
|
|
12
|
-
try {
|
|
13
|
-
const res = await fetch("https://booyah.live/api/v3/" + url, options);
|
|
14
|
-
const ret = await res.json();
|
|
15
|
-
|
|
16
|
-
return ret;
|
|
17
|
-
} catch(e) {
|
|
18
|
-
// After too many consecutive errors, let's abort: we need to retry later
|
|
19
|
-
if(attempt === 3) throw e;
|
|
20
|
-
|
|
21
|
-
return myFetch(url, option, attempt + 1);
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function expire(uid, add = true) {
|
|
26
|
-
const { followingsExpire } = window.localStorage;
|
|
27
|
-
let expires = {};
|
|
28
|
-
|
|
29
|
-
try {
|
|
30
|
-
// Get and parse followingsExpire from localStorage
|
|
31
|
-
expires = JSON.parse(followingsExpire);
|
|
32
|
-
} catch(e) {
|
|
33
|
-
// In case of error (ex. new browsers) simply init to empty
|
|
34
|
-
window.localStorage.followingsExpire = "{}";
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
if(! uid) return expires;
|
|
38
|
-
|
|
39
|
-
// Set expire after 1 day
|
|
40
|
-
if(add) expires[uid] = new Date().getTime() + 3600 * 24 * 1000;
|
|
41
|
-
else delete expires[uid];
|
|
42
|
-
|
|
43
|
-
window.localStorage.followingsExpire = JSON.stringify(expires);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
async function clean() {
|
|
47
|
-
try {
|
|
48
|
-
const expires = expire();
|
|
49
|
-
const now = new Date().getTime();
|
|
50
|
-
|
|
51
|
-
for(const uid in expires) {
|
|
52
|
-
if(expires[uid] < now) {
|
|
53
|
-
await followUser(parseInt(uid), false);
|
|
54
|
-
expire(uid, false);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
} catch(e) {}
|
|
58
|
-
|
|
59
|
-
// Repeat clean in an hour
|
|
60
|
-
window.setTimeout(clean, 3600 * 1000);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
async function fetchFollow(uid, type = "followers", from = 0) {
|
|
64
|
-
const { cursor, follower_list, following_list } = await myFetch(`users/${uid}/${type}?cursor=${from}&count=50`);
|
|
65
|
-
const got = (type === "followers" ? follower_list : following_list).map(_ => _.uid);
|
|
66
|
-
const others = cursor ? await fetchFollow(uid, type, cursor) : [];
|
|
67
|
-
|
|
68
|
-
return [...got, ...others];
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
async function followUser(uid, follow = true) {
|
|
72
|
-
console.log(`${follow ? "F" : "Unf"}ollowing ${uid}...`);
|
|
73
|
-
return myFetch(`users/${loggedUID}/followings`, {
|
|
74
|
-
method: follow ? "POST" : "DELETE",
|
|
75
|
-
headers: { "X-CSRF-Token": csrf },
|
|
76
|
-
body: JSON.stringify({ followee_uid: uid, source: 43 })
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
async function doAll() {
|
|
81
|
-
if(! loggedUID) throw new Error("Can't get 'loggedUID' from localStorage: try to login again");
|
|
82
|
-
if(! csrf) throw new Error("Can't get session token from cookies: try to login again");
|
|
83
|
-
|
|
84
|
-
console.log("Fetching current followings...");
|
|
85
|
-
const currentFollowings = await fetchFollow(loggedUID, "followings");
|
|
86
|
-
|
|
87
|
-
console.log("Fetching permanent followings...");
|
|
88
|
-
const permanentFollowings = await fetchFollow(followingsUID, "followings");
|
|
89
|
-
|
|
90
|
-
console.log("Syncing permanent followings...");
|
|
91
|
-
for(const uid of permanentFollowings) {
|
|
92
|
-
expire(uid, false);
|
|
93
|
-
|
|
94
|
-
if(currentFollowings.indexOf(uid) === -1) {
|
|
95
|
-
await followUser(uid);
|
|
96
|
-
currentFollowings.push(uid);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
// Sync followingsExpire in localStorage
|
|
101
|
-
for(const uid of currentFollowings) if(permanentFollowings.indexOf(uid) === -1) expire(uid);
|
|
102
|
-
// Call first clean task in 5 minutes
|
|
103
|
-
window.setTimeout(clean, 300 * 1000);
|
|
104
|
-
|
|
105
|
-
// Gather uid from window.location
|
|
106
|
-
const match = /\/studio\/(\d+)/.exec(window.location.pathname);
|
|
107
|
-
|
|
108
|
-
if(match) {
|
|
109
|
-
console.log("Fetching this user followers...");
|
|
110
|
-
const followings = await fetchFollow(parseInt(match[1]));
|
|
111
|
-
|
|
112
|
-
for(const uid of followings) {
|
|
113
|
-
if(currentFollowings.indexOf(uid) === -1) {
|
|
114
|
-
await followUser(uid);
|
|
115
|
-
expire(uid);
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
return "Done";
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
await doAll();
|