@simonbackx/simple-database 1.34.0 → 1.35.0
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/cjs/index.d.ts +10 -0
- package/dist/cjs/index.d.ts.map +1 -0
- package/dist/cjs/index.js +13 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/package.json +1 -0
- package/dist/{src → cjs/src}/classes/Column.d.ts +3 -2
- package/dist/cjs/src/classes/Column.d.ts.map +1 -0
- package/dist/{src → cjs/src}/classes/Column.js +21 -8
- package/dist/cjs/src/classes/Column.js.map +1 -0
- package/dist/cjs/src/classes/ColumnType.d.ts +2 -0
- package/dist/cjs/src/classes/ColumnType.d.ts.map +1 -0
- package/dist/cjs/src/classes/ColumnType.js +3 -0
- package/dist/cjs/src/classes/ColumnType.js.map +1 -0
- package/dist/{src → cjs/src}/classes/Database.d.ts +2 -1
- package/dist/cjs/src/classes/Database.d.ts.map +1 -0
- package/dist/{src → cjs/src}/classes/Database.js +19 -20
- package/dist/cjs/src/classes/Database.js.map +1 -0
- package/dist/cjs/src/classes/DatabaseStoredValue.d.ts +2 -0
- package/dist/cjs/src/classes/DatabaseStoredValue.d.ts.map +1 -0
- package/dist/cjs/src/classes/DatabaseStoredValue.js +3 -0
- package/dist/cjs/src/classes/DatabaseStoredValue.js.map +1 -0
- package/dist/{src → cjs/src}/classes/Factory.d.ts +1 -0
- package/dist/cjs/src/classes/Factory.d.ts.map +1 -0
- package/dist/{src → cjs/src}/classes/Factory.js +8 -7
- package/dist/cjs/src/classes/Factory.js.map +1 -0
- package/dist/{src → cjs/src}/classes/ManyToManyRelation.d.ts +4 -3
- package/dist/cjs/src/classes/ManyToManyRelation.d.ts.map +1 -0
- package/dist/{src → cjs/src}/classes/ManyToManyRelation.js +29 -18
- package/dist/cjs/src/classes/ManyToManyRelation.js.map +1 -0
- package/dist/{src → cjs/src}/classes/ManyToOneRelation.d.ts +2 -1
- package/dist/cjs/src/classes/ManyToOneRelation.d.ts.map +1 -0
- package/dist/{src → cjs/src}/classes/ManyToOneRelation.js +11 -2
- package/dist/cjs/src/classes/ManyToOneRelation.js.map +1 -0
- package/dist/{src → cjs/src}/classes/Migration.d.ts +2 -0
- package/dist/cjs/src/classes/Migration.d.ts.map +1 -0
- package/dist/{src → cjs/src}/classes/Migration.js +64 -17
- package/dist/cjs/src/classes/Migration.js.map +1 -0
- package/dist/{src → cjs/src}/classes/Model.d.ts +17 -6
- package/dist/cjs/src/classes/Model.d.ts.map +1 -0
- package/dist/{src → cjs/src}/classes/Model.js +83 -33
- package/dist/cjs/src/classes/Model.js.map +1 -0
- package/dist/{src → cjs/src}/classes/OneToManyRelation.d.ts +2 -1
- package/dist/cjs/src/classes/OneToManyRelation.d.ts.map +1 -0
- package/dist/{src → cjs/src}/classes/OneToManyRelation.js +17 -3
- package/dist/cjs/src/classes/OneToManyRelation.js.map +1 -0
- package/dist/{src → cjs/src}/classes/data/boys.d.ts +1 -0
- package/dist/cjs/src/classes/data/boys.d.ts.map +1 -0
- package/dist/cjs/src/classes/data/boys.js.map +1 -0
- package/dist/cjs/src/classes/data/family-names.d.ts +3 -0
- package/dist/cjs/src/classes/data/family-names.d.ts.map +1 -0
- package/dist/cjs/src/classes/data/family-names.js.map +1 -0
- package/dist/{src → cjs/src}/classes/data/girls.d.ts +1 -0
- package/dist/cjs/src/classes/data/girls.d.ts.map +1 -0
- package/dist/cjs/src/classes/data/girls.js.map +1 -0
- package/dist/cjs/src/classes/data/streets.d.ts +3 -0
- package/dist/cjs/src/classes/data/streets.d.ts.map +1 -0
- package/dist/cjs/src/classes/data/streets.js.map +1 -0
- package/dist/{src → cjs/src}/decorators/Column.d.ts +4 -3
- package/dist/cjs/src/decorators/Column.d.ts.map +1 -0
- package/dist/{src → cjs/src}/decorators/Column.js +3 -4
- package/dist/cjs/src/decorators/Column.js.map +1 -0
- package/dist/{src → cjs/src}/models/Migration.d.ts +2 -1
- package/dist/cjs/src/models/Migration.d.ts.map +1 -0
- package/dist/{src → cjs/src}/models/Migration.js +14 -15
- package/dist/cjs/src/models/Migration.js.map +1 -0
- package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -0
- package/dist/esm/index.d.ts +10 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +10 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/src/classes/Column.d.ts +30 -0
- package/dist/esm/src/classes/Column.d.ts.map +1 -0
- package/dist/esm/src/classes/Column.js +179 -0
- package/dist/esm/src/classes/Column.js.map +1 -0
- package/dist/esm/src/classes/ColumnType.d.ts +2 -0
- package/dist/esm/src/classes/ColumnType.d.ts.map +1 -0
- package/dist/esm/src/classes/ColumnType.js +2 -0
- package/dist/esm/src/classes/ColumnType.js.map +1 -0
- package/dist/esm/src/classes/Database.d.ts +59 -0
- package/dist/esm/src/classes/Database.d.ts.map +1 -0
- package/dist/esm/src/classes/Database.js +171 -0
- package/dist/esm/src/classes/Database.js.map +1 -0
- package/dist/esm/src/classes/DatabaseStoredValue.d.ts +2 -0
- package/dist/esm/src/classes/DatabaseStoredValue.d.ts.map +1 -0
- package/dist/esm/src/classes/DatabaseStoredValue.js +2 -0
- package/dist/esm/src/classes/DatabaseStoredValue.js.map +1 -0
- package/dist/esm/src/classes/Factory.d.ts +14 -0
- package/dist/esm/src/classes/Factory.d.ts.map +1 -0
- package/dist/esm/src/classes/Factory.js +51 -0
- package/dist/esm/src/classes/Factory.js.map +1 -0
- package/dist/esm/src/classes/ManyToManyRelation.d.ts +79 -0
- package/dist/esm/src/classes/ManyToManyRelation.d.ts.map +1 -0
- package/dist/esm/src/classes/ManyToManyRelation.js +254 -0
- package/dist/esm/src/classes/ManyToManyRelation.js.map +1 -0
- package/dist/esm/src/classes/ManyToOneRelation.d.ts +22 -0
- package/dist/esm/src/classes/ManyToOneRelation.d.ts.map +1 -0
- package/dist/esm/src/classes/ManyToOneRelation.js +47 -0
- package/dist/esm/src/classes/ManyToOneRelation.js.map +1 -0
- package/dist/esm/src/classes/Migration.d.ts +14 -0
- package/dist/esm/src/classes/Migration.d.ts.map +1 -0
- package/dist/esm/src/classes/Migration.js +168 -0
- package/dist/esm/src/classes/Migration.js.map +1 -0
- package/dist/esm/src/classes/Model.d.ts +159 -0
- package/dist/esm/src/classes/Model.d.ts.map +1 -0
- package/dist/esm/src/classes/Model.js +635 -0
- package/dist/esm/src/classes/Model.js.map +1 -0
- package/dist/esm/src/classes/OneToManyRelation.d.ts +38 -0
- package/dist/esm/src/classes/OneToManyRelation.d.ts.map +1 -0
- package/dist/esm/src/classes/OneToManyRelation.js +75 -0
- package/dist/esm/src/classes/OneToManyRelation.js.map +1 -0
- package/dist/{src/classes/data/family-names.d.ts → esm/src/classes/data/boys.d.ts} +1 -0
- package/dist/esm/src/classes/data/boys.d.ts.map +1 -0
- package/dist/esm/src/classes/data/boys.js +1003 -0
- package/dist/{src → esm/src}/classes/data/boys.js.map +1 -1
- package/dist/esm/src/classes/data/family-names.d.ts +3 -0
- package/dist/esm/src/classes/data/family-names.d.ts.map +1 -0
- package/dist/esm/src/classes/data/family-names.js +1003 -0
- package/dist/{src → esm/src}/classes/data/family-names.js.map +1 -1
- package/dist/{src/classes/data/streets.d.ts → esm/src/classes/data/girls.d.ts} +1 -0
- package/dist/esm/src/classes/data/girls.d.ts.map +1 -0
- package/dist/esm/src/classes/data/girls.js +1002 -0
- package/dist/{src → esm/src}/classes/data/girls.js.map +1 -1
- package/dist/esm/src/classes/data/streets.d.ts +3 -0
- package/dist/esm/src/classes/data/streets.d.ts.map +1 -0
- package/dist/esm/src/classes/data/streets.js +294 -0
- package/dist/{src → esm/src}/classes/data/streets.js.map +1 -1
- package/dist/esm/src/decorators/Column.d.ts +18 -0
- package/dist/esm/src/decorators/Column.d.ts.map +1 -0
- package/dist/esm/src/decorators/Column.js +36 -0
- package/dist/esm/src/decorators/Column.js.map +1 -0
- package/dist/esm/src/models/Migration.d.ts +11 -0
- package/dist/esm/src/models/Migration.d.ts.map +1 -0
- package/dist/esm/src/models/Migration.js +48 -0
- package/dist/esm/src/models/Migration.js.map +1 -0
- package/dist/esm/tsconfig.esm.tsbuildinfo +1 -0
- package/package.json +52 -36
- package/dist/index.d.ts +0 -9
- package/dist/index.js +0 -13
- package/dist/index.js.map +0 -1
- package/dist/migrations.d.ts +0 -1
- package/dist/migrations.js +0 -18
- package/dist/migrations.js.map +0 -1
- package/dist/src/classes/Column.js.map +0 -1
- package/dist/src/classes/Database.js.map +0 -1
- package/dist/src/classes/Factory.js.map +0 -1
- package/dist/src/classes/ManyToManyRelation.js.map +0 -1
- package/dist/src/classes/ManyToOneRelation.js.map +0 -1
- package/dist/src/classes/Migration.js.map +0 -1
- package/dist/src/classes/Model.js.map +0 -1
- package/dist/src/classes/Model.test.d.ts +0 -1
- package/dist/src/classes/Model.test.js +0 -629
- package/dist/src/classes/Model.test.js.map +0 -1
- package/dist/src/classes/OneToManyRelation.js.map +0 -1
- package/dist/src/decorators/Column.js.map +0 -1
- package/dist/src/models/Migration.js.map +0 -1
- package/dist/tests/jest.global.setup.d.ts +0 -3
- package/dist/tests/jest.global.setup.js +0 -12
- package/dist/tests/jest.global.setup.js.map +0 -1
- package/dist/tests/jest.setup.d.ts +0 -1
- package/dist/tests/jest.setup.js +0 -8
- package/dist/tests/jest.setup.js.map +0 -1
- /package/dist/{src → cjs/src}/classes/data/boys.js +0 -0
- /package/dist/{src → cjs/src}/classes/data/family-names.js +0 -0
- /package/dist/{src → cjs/src}/classes/data/girls.js +0 -0
- /package/dist/{src → cjs/src}/classes/data/streets.js +0 -0
- /package/{dist/src/migrations → migrations}/000000000-setup-migrations.sql +0 -0
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
import { Database } from './Database.js';
|
|
2
|
+
import { Model } from './Model.js';
|
|
3
|
+
export class ManyToManyRelation {
|
|
4
|
+
modelA;
|
|
5
|
+
modelB;
|
|
6
|
+
modelLink;
|
|
7
|
+
/**
|
|
8
|
+
* E.g. parents
|
|
9
|
+
*/
|
|
10
|
+
modelKey;
|
|
11
|
+
/**
|
|
12
|
+
* Sort the loading of this relation
|
|
13
|
+
*/
|
|
14
|
+
sortKey;
|
|
15
|
+
sortOrder = 'ASC';
|
|
16
|
+
/**
|
|
17
|
+
* E.g. _models_parents
|
|
18
|
+
*/
|
|
19
|
+
get linkTable() {
|
|
20
|
+
if (this.modelLink) {
|
|
21
|
+
return this.modelLink.table;
|
|
22
|
+
}
|
|
23
|
+
return '_' + [this.modelA.table, this.modelB.table].sort().join('_');
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* e.g. modelsId
|
|
27
|
+
*/
|
|
28
|
+
get linkKeyA() {
|
|
29
|
+
return (this.modelA.table
|
|
30
|
+
+ this.modelA.primary.name.charAt(0).toUpperCase()
|
|
31
|
+
+ this.modelA.primary.name.substring(1)
|
|
32
|
+
+ (this.modelA === this.modelB ? 'A' : ''));
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* e.g. parentsId
|
|
36
|
+
*/
|
|
37
|
+
get linkKeyB() {
|
|
38
|
+
return (this.modelB.table
|
|
39
|
+
+ this.modelB.primary.name.charAt(0).toUpperCase()
|
|
40
|
+
+ this.modelB.primary.name.substring(1)
|
|
41
|
+
+ (this.modelA === this.modelB ? 'B' : ''));
|
|
42
|
+
}
|
|
43
|
+
constructor(modelA, modelB, modelKey, modelLink) {
|
|
44
|
+
this.modelA = modelA;
|
|
45
|
+
this.modelB = modelB;
|
|
46
|
+
this.modelKey = modelKey;
|
|
47
|
+
this.modelLink = modelLink;
|
|
48
|
+
}
|
|
49
|
+
reverse(modelKey) {
|
|
50
|
+
return new ManyToManyRelation(this.modelB, this.modelA, modelKey, this.modelLink);
|
|
51
|
+
}
|
|
52
|
+
setSort(key, order = 'ASC') {
|
|
53
|
+
this.sortKey = key;
|
|
54
|
+
this.sortOrder = order;
|
|
55
|
+
return this;
|
|
56
|
+
}
|
|
57
|
+
/// Generate a join query
|
|
58
|
+
joinQuery(namespaceA, namespaceB) {
|
|
59
|
+
const linkNamespace = namespaceA + '_' + namespaceB;
|
|
60
|
+
let str = `LEFT JOIN ${this.linkTable} as ${linkNamespace} on ${linkNamespace}.${this.linkKeyA} = ${namespaceA}.${this.modelA.primary.name}\n`;
|
|
61
|
+
str += `LEFT JOIN ${this.modelB.table} as ${namespaceB} on ${linkNamespace}.${this.linkKeyB} = ${namespaceB}.${this.modelB.primary.name}`;
|
|
62
|
+
return str;
|
|
63
|
+
}
|
|
64
|
+
orderByQuery(namespaceA, namespaceB) {
|
|
65
|
+
if (this.sortKey === undefined) {
|
|
66
|
+
return '';
|
|
67
|
+
}
|
|
68
|
+
const linkNamespace = namespaceA + '_' + namespaceB;
|
|
69
|
+
let str = `\nORDER BY ${linkNamespace}.${this.sortKey}`;
|
|
70
|
+
if (this.sortOrder === 'DESC') {
|
|
71
|
+
str += ' DESC';
|
|
72
|
+
}
|
|
73
|
+
return str + '\n';
|
|
74
|
+
}
|
|
75
|
+
/// Load the relation of a model and return the loaded models
|
|
76
|
+
async load(modelA, sorted = true, where, whereLink) {
|
|
77
|
+
const namespaceB = 'B';
|
|
78
|
+
const linkNamespace = 'A_B';
|
|
79
|
+
let select = this.modelB.getDefaultSelect(namespaceB);
|
|
80
|
+
if (this.modelLink) {
|
|
81
|
+
select += ', ' + this.modelLink.getDefaultSelect(linkNamespace);
|
|
82
|
+
}
|
|
83
|
+
let str = `SELECT ${select} FROM ${this.linkTable} as ${linkNamespace}\n`;
|
|
84
|
+
str += `JOIN ${this.modelB.table} as ${namespaceB} on ${linkNamespace}.${this.linkKeyB} = ${namespaceB}.${this.modelB.primary.name}\n`;
|
|
85
|
+
str += `WHERE ${linkNamespace}.${this.linkKeyA} = ?`;
|
|
86
|
+
const params = [modelA.getPrimaryKey()];
|
|
87
|
+
if (where) {
|
|
88
|
+
for (const key in where) {
|
|
89
|
+
if (Object.hasOwnProperty.call(where, key)) {
|
|
90
|
+
str += ` AND ${namespaceB}.\`${key}\` = ?`;
|
|
91
|
+
params.push(where[key]);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (whereLink) {
|
|
96
|
+
for (const key in whereLink) {
|
|
97
|
+
if (Object.hasOwnProperty.call(whereLink, key)) {
|
|
98
|
+
str += ` AND ${linkNamespace}.\`${key}\` = ?`;
|
|
99
|
+
params.push(whereLink[key]);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
if (sorted) {
|
|
104
|
+
str += this.orderByQuery('A', 'B');
|
|
105
|
+
}
|
|
106
|
+
const [rows] = await Database.select(str, params);
|
|
107
|
+
const modelsB = this.modelB.fromRows(rows, namespaceB);
|
|
108
|
+
// Also load link table if possible
|
|
109
|
+
if (this.modelLink) {
|
|
110
|
+
for (const row of rows) {
|
|
111
|
+
const model = this.modelLink.fromRow(row[linkNamespace]);
|
|
112
|
+
// Fin modelB
|
|
113
|
+
const modelB = modelsB.find(m => m.getPrimaryKey() === row[linkNamespace][this.linkKeyB]);
|
|
114
|
+
if (!modelB) {
|
|
115
|
+
throw new Error('Unexpected linking');
|
|
116
|
+
}
|
|
117
|
+
// Save link
|
|
118
|
+
modelB._link = model;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
modelA.setManyRelation(this, modelsB);
|
|
122
|
+
return modelsB;
|
|
123
|
+
}
|
|
124
|
+
/// Whether this relation is loaded
|
|
125
|
+
isLoaded(model) {
|
|
126
|
+
// Also not loaded if null, since it should be an empty array or an array if it is loaded
|
|
127
|
+
return Array.isArray(model[this.modelKey]);
|
|
128
|
+
}
|
|
129
|
+
async setLinkTable(modelA, modelB, linkTableValues) {
|
|
130
|
+
const str = `UPDATE ${this.linkTable} SET ? WHERE ${Database.escapeId(this.linkKeyA)} = ? AND ${Database.escapeId(this.linkKeyB)} = ?`;
|
|
131
|
+
const [result] = await Database.update(str, [linkTableValues, modelA.getPrimaryKey(), modelB.getPrimaryKey()]);
|
|
132
|
+
if (result.changedRows !== 1) {
|
|
133
|
+
// Todo: add option to fail silently
|
|
134
|
+
throw new Error('Failed to update link table. Check if combination exists');
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
async linkIds(modelA, modelsB, linkTableValues) {
|
|
138
|
+
if (modelsB.length === 0) {
|
|
139
|
+
return 0;
|
|
140
|
+
}
|
|
141
|
+
// Nested arrays are turned into grouped lists (for bulk inserts), e.g. [['a', 'b'], ['c', 'd']] turns into ('a', 'b'), ('c', 'd')
|
|
142
|
+
let result;
|
|
143
|
+
if (linkTableValues !== undefined) {
|
|
144
|
+
const linkTableKeys = Object.keys(linkTableValues);
|
|
145
|
+
for (const property in linkTableValues) {
|
|
146
|
+
if (Object.hasOwnProperty.call(linkTableValues, property)) {
|
|
147
|
+
if (linkTableValues[property].length !== modelsB.length) {
|
|
148
|
+
throw new Error('Amount of link table values for key '
|
|
149
|
+
+ property
|
|
150
|
+
+ ' ('
|
|
151
|
+
+ linkTableValues[property].length
|
|
152
|
+
+ ') are not equal to amount of models linked ('
|
|
153
|
+
+ modelsB.length
|
|
154
|
+
+ ')');
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
const query = `INSERT INTO ${Database.escapeId(this.linkTable)} (
|
|
159
|
+
${Database.escapeId(this.linkKeyA)},
|
|
160
|
+
${Database.escapeId(this.linkKeyB)},
|
|
161
|
+
${linkTableKeys.map(k => Database.escapeId(k)).join(', ')}
|
|
162
|
+
) VALUES ?`;
|
|
163
|
+
[result] = await Database.insert(query, [modelsB.map((modelB, i) => [modelA, modelB, ...linkTableKeys.map(k => linkTableValues[k][i])])]);
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
const query = `INSERT INTO ${Database.escapeId(this.linkTable)} (
|
|
167
|
+
${Database.escapeId(this.linkKeyA)},
|
|
168
|
+
${Database.escapeId(this.linkKeyB)}
|
|
169
|
+
) VALUES ?`;
|
|
170
|
+
[result] = await Database.insert(query, [modelsB.map(modelB => [modelA, modelB])]);
|
|
171
|
+
}
|
|
172
|
+
return result.affectedRows;
|
|
173
|
+
}
|
|
174
|
+
async link(modelA, modelsB, linkTableValues) {
|
|
175
|
+
const modelAId = modelA.getPrimaryKey();
|
|
176
|
+
if (!modelAId) {
|
|
177
|
+
throw new Error('Cannot link if model is not saved yet');
|
|
178
|
+
}
|
|
179
|
+
const affectedRows = await this.linkIds(modelAId, modelsB.map((modelB) => {
|
|
180
|
+
const id = modelB.getPrimaryKey();
|
|
181
|
+
if (!id) {
|
|
182
|
+
throw new Error('Cannot link to a model that is not saved yet');
|
|
183
|
+
}
|
|
184
|
+
return id;
|
|
185
|
+
}), linkTableValues);
|
|
186
|
+
// If the relation is loaded, also modify the value of the relation
|
|
187
|
+
if (this.isLoaded(modelA)) {
|
|
188
|
+
if (affectedRows === modelsB.length) {
|
|
189
|
+
const arr = modelA[this.modelKey];
|
|
190
|
+
arr.push(...modelsB);
|
|
191
|
+
}
|
|
192
|
+
else {
|
|
193
|
+
// This could happen in race conditions and simultanious requests
|
|
194
|
+
console.warn('Warning: linking expected to affect ' + modelsB.length + ' rows, but only affected ' + affectedRows + ' rows');
|
|
195
|
+
// TODO: Manually correct by doing a query (safest)
|
|
196
|
+
throw new Error('Fallback behaviour net yet implemented');
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Delete all the links from modelA for this relation
|
|
202
|
+
* @param modelA
|
|
203
|
+
*/
|
|
204
|
+
async clearId(modelA) {
|
|
205
|
+
const query = `DELETE FROM ${this.linkTable} WHERE ${this.linkKeyA} = ?`;
|
|
206
|
+
// Arrays are turned into list, e.g. ['a', 'b'] turns into 'a', 'b'
|
|
207
|
+
const [result] = await Database.delete(query, [modelA]);
|
|
208
|
+
if (result.affectedRows === 0 && Model.debug) {
|
|
209
|
+
console.warn("Cleared many to many relation, but didn't deleted any entries");
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Delete all the links from modelA for this relation
|
|
214
|
+
* @param modelA
|
|
215
|
+
*/
|
|
216
|
+
async clear(modelA) {
|
|
217
|
+
await this.clearId(modelA.getPrimaryKey());
|
|
218
|
+
modelA.setManyRelation(this, []);
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Delete all the links from modelA for this relation
|
|
222
|
+
* @param modelA
|
|
223
|
+
*/
|
|
224
|
+
async syncId(modelA, modelsB, linkTableValues) {
|
|
225
|
+
// todo: add transaction
|
|
226
|
+
await this.clearId(modelA);
|
|
227
|
+
await this.linkIds(modelA, modelsB, linkTableValues);
|
|
228
|
+
}
|
|
229
|
+
async unlinkIds(modelA, ...modelsB) {
|
|
230
|
+
const query = `DELETE FROM ${this.linkTable} WHERE ${this.linkKeyA} = ? AND ${this.linkKeyB} IN (?)`;
|
|
231
|
+
// Arrays are turned into list, e.g. ['a', 'b'] turns into 'a', 'b'
|
|
232
|
+
const [result] = await Database.delete(query, [modelA, modelsB]);
|
|
233
|
+
return result;
|
|
234
|
+
}
|
|
235
|
+
async unlink(modelA, ...modelsB) {
|
|
236
|
+
const result = await this.unlinkIds(modelA.getPrimaryKey(), ...modelsB.map(modelB => modelB.getPrimaryKey()));
|
|
237
|
+
if (this.isLoaded(modelA)) {
|
|
238
|
+
if (result.affectedRows === modelsB.length) {
|
|
239
|
+
const arr = modelA[this.modelKey];
|
|
240
|
+
const idMap = modelsB.map(model => model.getPrimaryKey());
|
|
241
|
+
modelA.setManyRelation(this, arr.filter((model) => {
|
|
242
|
+
return !idMap.includes(model.getPrimaryKey());
|
|
243
|
+
}));
|
|
244
|
+
}
|
|
245
|
+
else {
|
|
246
|
+
// This could happen in race conditions and simultanious requests
|
|
247
|
+
console.warn('Warning: unlinking expected to affect ' + modelsB.length + ' rows, but only affected ' + result.affectedRows + ' rows');
|
|
248
|
+
// TODO: Manually correct by doing a query (safest)
|
|
249
|
+
throw new Error('Fallback behaviour net yet implemented');
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
//# sourceMappingURL=ManyToManyRelation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ManyToManyRelation.js","sourceRoot":"","sources":["../../../../src/classes/ManyToManyRelation.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Model } from './Model.js';
|
|
2
|
+
export declare class ManyToOneRelation<Key extends keyof any, M extends Model> {
|
|
3
|
+
model: {
|
|
4
|
+
new (): M;
|
|
5
|
+
} & typeof Model;
|
|
6
|
+
/**
|
|
7
|
+
* E.g. addressId
|
|
8
|
+
*/
|
|
9
|
+
foreignKey: string;
|
|
10
|
+
/**
|
|
11
|
+
* E.g. address
|
|
12
|
+
*/
|
|
13
|
+
modelKey: Key;
|
|
14
|
+
constructor(model: {
|
|
15
|
+
new (): M;
|
|
16
|
+
} & typeof Model, modelKey: Key);
|
|
17
|
+
isLoaded(model: Model): boolean;
|
|
18
|
+
isSet(model: Model): boolean;
|
|
19
|
+
joinQuery(namespaceA: string, namespaceB: string): string;
|
|
20
|
+
load<A extends Model>(modelsA: A[]): Promise<(A & Record<Key, M>)[]>;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=ManyToOneRelation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ManyToOneRelation.d.ts","sourceRoot":"","sources":["../../../../src/classes/ManyToOneRelation.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEnC,qBAAa,iBAAiB,CAAC,GAAG,SAAS,MAAM,GAAG,EAAE,CAAC,SAAS,KAAK;IACjE,KAAK,EAAE;QAAE,QAAQ,CAAC,CAAA;KAAE,GAAG,OAAO,KAAK,CAAC;IAEpC;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,QAAQ,EAAE,GAAG,CAAC;gBAEF,KAAK,EAAE;QAAE,QAAQ,CAAC,CAAA;KAAE,GAAG,OAAO,KAAK,EAAE,QAAQ,EAAE,GAAG;IAM9D,QAAQ,CAAC,KAAK,EAAE,KAAK;IAKrB,KAAK,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO;IAK5B,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM;IAKnD,IAAI,CAAC,CAAC,SAAS,KAAK,EAAE,OAAO,EAAE,CAAC,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;CAmB7E"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { Database } from './Database.js';
|
|
2
|
+
export class ManyToOneRelation {
|
|
3
|
+
model;
|
|
4
|
+
/**
|
|
5
|
+
* E.g. addressId
|
|
6
|
+
*/
|
|
7
|
+
foreignKey;
|
|
8
|
+
/**
|
|
9
|
+
* E.g. address
|
|
10
|
+
*/
|
|
11
|
+
modelKey;
|
|
12
|
+
constructor(model, modelKey) {
|
|
13
|
+
this.model = model;
|
|
14
|
+
this.modelKey = modelKey;
|
|
15
|
+
}
|
|
16
|
+
/// Whether this relation is loaded
|
|
17
|
+
isLoaded(model) {
|
|
18
|
+
return model[this.modelKey] !== undefined;
|
|
19
|
+
}
|
|
20
|
+
/// Whether this relation is set
|
|
21
|
+
isSet(model) {
|
|
22
|
+
return model[this.modelKey] !== undefined && model[this.modelKey] !== null;
|
|
23
|
+
}
|
|
24
|
+
/// Generate a join query
|
|
25
|
+
joinQuery(namespaceA, namespaceB) {
|
|
26
|
+
return `LEFT JOIN ${this.model.table} as ${namespaceB} on ${namespaceB}.${this.model.primary.name} = ${namespaceA}.${this.foreignKey}\n`;
|
|
27
|
+
}
|
|
28
|
+
/// Load the relation of a list of models
|
|
29
|
+
async load(modelsA) {
|
|
30
|
+
if (modelsA.length === 0) {
|
|
31
|
+
return [];
|
|
32
|
+
}
|
|
33
|
+
let str = `SELECT ${this.model.getDefaultSelect()} FROM ${this.model.table}\n`;
|
|
34
|
+
str += `WHERE ${this.model.primary.name} IN (?)`;
|
|
35
|
+
const [rows] = await Database.select(str, [modelsA.map(m => m[this.foreignKey])]);
|
|
36
|
+
const modelsB = this.model.fromRows(rows, this.model.table);
|
|
37
|
+
for (const model of modelsA) {
|
|
38
|
+
const found = modelsB.find(m => m.getPrimaryKey() === model[this.foreignKey]);
|
|
39
|
+
if (!found) {
|
|
40
|
+
throw new Error('Could not load many to one relation: no match found when loading');
|
|
41
|
+
}
|
|
42
|
+
model.setRelation(this, found);
|
|
43
|
+
}
|
|
44
|
+
return modelsA;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=ManyToOneRelation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ManyToOneRelation.js","sourceRoot":"","sources":["../../../../src/classes/ManyToOneRelation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAGzC,MAAM,OAAO,iBAAiB;IAC1B,KAAK,CAA+B;IAEpC;;OAEG;IACH,UAAU,CAAS;IAEnB;;OAEG;IACH,QAAQ,CAAM;IAEd,YAAY,KAAmC,EAAE,QAAa;QAC1D,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC7B,CAAC;IAED,mCAAmC;IACnC,QAAQ,CAAC,KAAY;QACjB,OAAQ,KAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,SAAS,CAAC;IACvD,CAAC;IAED,gCAAgC;IAChC,KAAK,CAAC,KAAY;QACd,OAAQ,KAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,SAAS,IAAK,KAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC;IACjG,CAAC;IAED,yBAAyB;IACzB,SAAS,CAAC,UAAkB,EAAE,UAAkB;QAC5C,OAAO,aAAa,IAAI,CAAC,KAAK,CAAC,KAAK,OAAO,UAAU,OAAO,UAAU,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,MAAM,UAAU,IAAI,IAAI,CAAC,UAAU,IAAI,CAAC;IAC7I,CAAC;IAED,yCAAyC;IACzC,KAAK,CAAC,IAAI,CAAkB,OAAY;QACpC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvB,OAAO,EAAE,CAAC;QACd,CAAC;QACD,IAAI,GAAG,GAAG,UAAU,IAAI,CAAC,KAAK,CAAC,gBAAgB,EAAE,SAAS,IAAI,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC;QAC/E,GAAG,IAAI,SAAS,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,SAAS,CAAC;QAEjD,MAAM,CAAC,IAAI,CAAC,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;QAClF,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAQ,CAAC;QAEnE,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC1B,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,aAAa,EAAE,KAAK,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;YAC9E,IAAI,CAAC,KAAK,EAAE,CAAC;gBACT,MAAM,IAAI,KAAK,CAAC,kEAAkE,CAAC,CAAC;YACxF,CAAC;YACD,KAAK,CAAC,WAAW,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QACnC,CAAC;QACD,OAAO,OAAiC,CAAC;IAC7C,CAAC;CACJ"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export declare function fileExists(file: string): Promise<boolean>;
|
|
2
|
+
type MigrationFunction = () => Promise<void>;
|
|
3
|
+
export declare class Migration {
|
|
4
|
+
up: MigrationFunction;
|
|
5
|
+
down: MigrationFunction | undefined;
|
|
6
|
+
constructor(up: MigrationFunction, down?: MigrationFunction);
|
|
7
|
+
/***
|
|
8
|
+
* Given a folder, loop all the folders in that folder and run the migrations in the 'migrations' folder
|
|
9
|
+
*/
|
|
10
|
+
static runAll(folder: string): Promise<boolean>;
|
|
11
|
+
static getMigration(file: string): Promise<Migration | undefined>;
|
|
12
|
+
}
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=Migration.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Migration.d.ts","sourceRoot":"","sources":["../../../../src/classes/Migration.ts"],"names":[],"mappings":"AAuBA,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAQ/D;AAaD,KAAK,iBAAiB,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;AAW7C,qBAAa,SAAS;IAClB,EAAE,EAAE,iBAAiB,CAAC;IACtB,IAAI,EAAE,iBAAiB,GAAG,SAAS,CAAC;gBAExB,EAAE,EAAE,iBAAiB,EAAE,IAAI,CAAC,EAAE,iBAAiB;IAK3D;;OAEG;WACU,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;WA8HxC,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;CA6B1E"}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { promises as fs } from 'fs';
|
|
2
|
+
import { Migration as MigrationModel } from '../models/Migration.js';
|
|
3
|
+
import { Database } from './Database.js';
|
|
4
|
+
import { logger, StyledText } from '@simonbackx/simple-logging';
|
|
5
|
+
import { dirname } from 'node:path';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
function getDirname() {
|
|
8
|
+
// CJS environment
|
|
9
|
+
if (typeof __dirname !== 'undefined') {
|
|
10
|
+
return __dirname;
|
|
11
|
+
}
|
|
12
|
+
// ESM environment
|
|
13
|
+
// @ts-ignore
|
|
14
|
+
if (typeof import.meta !== 'undefined' && import.meta.url) {
|
|
15
|
+
// @ts-ignore
|
|
16
|
+
return dirname(fileURLToPath(import.meta.url));
|
|
17
|
+
}
|
|
18
|
+
throw new Error('Cannot determine __dirname');
|
|
19
|
+
}
|
|
20
|
+
export async function fileExists(file) {
|
|
21
|
+
try {
|
|
22
|
+
await fs.access(file);
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
catch (e) {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
async function getProjectRoot() {
|
|
30
|
+
let path = getDirname();
|
|
31
|
+
for (let index = 0; index < 5; index++) {
|
|
32
|
+
if (await fileExists(path + '/migrations')) {
|
|
33
|
+
return path;
|
|
34
|
+
}
|
|
35
|
+
path += '/..';
|
|
36
|
+
}
|
|
37
|
+
throw new Error('Could not find migrations root');
|
|
38
|
+
}
|
|
39
|
+
async function directoryExists(filePath) {
|
|
40
|
+
try {
|
|
41
|
+
return (await fs.stat(filePath)).isDirectory();
|
|
42
|
+
}
|
|
43
|
+
catch (err) {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
export class Migration {
|
|
48
|
+
up;
|
|
49
|
+
down;
|
|
50
|
+
constructor(up, down) {
|
|
51
|
+
this.up = up;
|
|
52
|
+
this.down = down;
|
|
53
|
+
}
|
|
54
|
+
/***
|
|
55
|
+
* Given a folder, loop all the folders in that folder and run the migrations in the 'migrations' folder
|
|
56
|
+
*/
|
|
57
|
+
static async runAll(folder) {
|
|
58
|
+
const dirname = getDirname();
|
|
59
|
+
// Get the current working directory by removing shared part of folder and dirname
|
|
60
|
+
const shared = dirname.split('/').filter((part, index) => part === folder.split('/')[index]).join('/');
|
|
61
|
+
const cwd = folder.replace(shared, '');
|
|
62
|
+
logger.log(new StyledText('[Migration]').addClass('migration', 'prefix').addTag('migration'), ' ', new StyledText('Running all... ').addClass('migration', 'runAll'), new StyledText(cwd).addClass('migration', 'folder').addStyle('dim'));
|
|
63
|
+
process.env.DB_MULTIPLE_STATEMENTS = 'true';
|
|
64
|
+
// First check if we have migrations table
|
|
65
|
+
const projectRoot = await getProjectRoot();
|
|
66
|
+
const setupMigration = await this.getMigration(projectRoot + '/migrations/000000000-setup-migrations.sql');
|
|
67
|
+
if (!setupMigration) {
|
|
68
|
+
throw new Error('Setup migration missing');
|
|
69
|
+
}
|
|
70
|
+
await setupMigration.up();
|
|
71
|
+
await MigrationModel.markAsExecuted('000000000-setup-migrations.sql');
|
|
72
|
+
const parts = folder.split('/');
|
|
73
|
+
const firstPart = parts.shift();
|
|
74
|
+
if (firstPart === undefined) {
|
|
75
|
+
throw new Error('Invalid folder path');
|
|
76
|
+
}
|
|
77
|
+
let folderQueue = [firstPart];
|
|
78
|
+
const migrations = [];
|
|
79
|
+
for (const part of parts) {
|
|
80
|
+
if (part === '*') {
|
|
81
|
+
const newQueue = [];
|
|
82
|
+
for (folder of folderQueue) {
|
|
83
|
+
// Read all directories
|
|
84
|
+
const recursiveFolders = (await fs.readdir(folder, { withFileTypes: true })).filter(dirent => dirent.isDirectory()).map(dirent => folder + '/' + dirent.name);
|
|
85
|
+
newQueue.push(...recursiveFolders);
|
|
86
|
+
}
|
|
87
|
+
folderQueue = newQueue;
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
folderQueue = folderQueue.map(folder => folder + '/' + part);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
for (const p of folderQueue) {
|
|
94
|
+
if (await directoryExists(p)) {
|
|
95
|
+
const folderFiles = await fs.readdir(p);
|
|
96
|
+
for (const file of folderFiles) {
|
|
97
|
+
const full = p + '/' + file;
|
|
98
|
+
const name = file;
|
|
99
|
+
if (!(await MigrationModel.isExecuted(name))) {
|
|
100
|
+
migrations.push([name, full]);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
// Make sure we run the migrations in order
|
|
106
|
+
migrations.sort((a, b) => {
|
|
107
|
+
// It is expected to return a negative value if first argument is less than second argument, zero if they're equal and a positive value otherwise. If omitted, the elements are sorted in ascending, ASCII character order.
|
|
108
|
+
if (a < b)
|
|
109
|
+
return -1;
|
|
110
|
+
if (a > b)
|
|
111
|
+
return 1;
|
|
112
|
+
return 0;
|
|
113
|
+
});
|
|
114
|
+
for (const [name, file] of migrations) {
|
|
115
|
+
// Check if SQL or TypeScript
|
|
116
|
+
const migration = await this.getMigration(file);
|
|
117
|
+
if (!migration) {
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
logger.log(new StyledText('[Migration]').addClass('migration', 'prefix').addTag('migration'), ' ', new StyledText('Running ').addClass('migration', 'start'), new StyledText(name).addClass('migration', 'start', 'name'));
|
|
121
|
+
try {
|
|
122
|
+
await logger.setContext({
|
|
123
|
+
prefixes: [new StyledText('[Migration]').addClass('migration', 'prefix'), ' '],
|
|
124
|
+
tags: ['migration'],
|
|
125
|
+
}, async () => {
|
|
126
|
+
await migration.up();
|
|
127
|
+
await MigrationModel.markAsExecuted(name);
|
|
128
|
+
});
|
|
129
|
+
logger.log(new StyledText('[Migration]').addClass('migration', 'prefix').addTag('migration'), ' ', new StyledText('✓').addClass('migration', 'success', 'tag'), ' ', new StyledText('Migration ' + name + ' ran successfully').addClass('migration', 'success', 'text'));
|
|
130
|
+
}
|
|
131
|
+
catch (e) {
|
|
132
|
+
// Logger.errorWithContext({textColor: ['dim', 'red'], prefix: ' FAILED ', addSpace: true, prefixColor: ['bgRed']}, "Migration " + name + " failed", e)
|
|
133
|
+
logger.error(new StyledText('[Migration]').addClass('migration', 'prefix').addTag('migration'), ' ', new StyledText('✗').addClass('migration', 'failed', 'tag'), ' ', new StyledText('Migration ' + name + ' failed').addClass('migration', 'failed', 'text'), ' ', new StyledText(e).addClass('migration', 'failed', 'error'));
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
logger.log(new StyledText('[Migration]').addClass('migration', 'prefix').addTag('migration'), ' ', new StyledText('✨').addClass('migration', 'success', 'tag', 'all'), ' ', new StyledText('All migrations done').addClass('migration', 'success', 'text', 'all'));
|
|
138
|
+
return true;
|
|
139
|
+
}
|
|
140
|
+
static async getMigration(file) {
|
|
141
|
+
let migration;
|
|
142
|
+
if (file.endsWith('.sql')) {
|
|
143
|
+
if (file.endsWith('.down.sql')) {
|
|
144
|
+
// Ignore. This will contain the downgrade implementation.
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
const sqlStatement = await fs.readFile(file, { encoding: 'utf-8' });
|
|
148
|
+
migration = new Migration(async () => {
|
|
149
|
+
await Database.statement(sqlStatement);
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
if (file.includes('.test.')) {
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
if (file.endsWith('.d.ts')) {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
if (!file.endsWith('.ts') && !file.endsWith('.js')) {
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
const imported = await import(file);
|
|
163
|
+
migration = imported.default;
|
|
164
|
+
}
|
|
165
|
+
return migration;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
//# sourceMappingURL=Migration.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Migration.js","sourceRoot":"","sources":["../../../../src/classes/Migration.ts"],"names":[],"mappings":"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"}
|