@strapi/database 4.2.0-beta.2 → 4.2.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.
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { createLifecyclesProvider } = require('../lifecycles');
|
|
4
|
+
|
|
5
|
+
describe('LifecycleProvider', () => {
|
|
6
|
+
describe('run', () => {
|
|
7
|
+
/** @type {import("../lifecycles").LifecycleProvider} */
|
|
8
|
+
let provider;
|
|
9
|
+
let dbMetadataGetStub = jest.fn(uid => ({ uid, name: 'TestModel' }));
|
|
10
|
+
|
|
11
|
+
beforeEach(() => {
|
|
12
|
+
const db = {
|
|
13
|
+
metadata: {
|
|
14
|
+
get: dbMetadataGetStub,
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
provider = createLifecyclesProvider(db);
|
|
18
|
+
provider.clear();
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('store state', async () => {
|
|
22
|
+
const expectedState = new Date().toISOString();
|
|
23
|
+
|
|
24
|
+
const subscriber = {
|
|
25
|
+
async beforeEvent(event) {
|
|
26
|
+
event.state = expectedState;
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
provider.subscribe(subscriber);
|
|
30
|
+
|
|
31
|
+
const stateBefore = await provider.run('beforeEvent', 'test-model', { id: 'instance-id' });
|
|
32
|
+
|
|
33
|
+
expect(stateBefore.get(subscriber)).toEqual(expectedState);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('use shared state', async () => {
|
|
37
|
+
const expectedState = { value: new Date().toISOString() };
|
|
38
|
+
let receivedState;
|
|
39
|
+
|
|
40
|
+
provider.subscribe({
|
|
41
|
+
async beforeEvent(event) {
|
|
42
|
+
event.state.value = expectedState.value;
|
|
43
|
+
},
|
|
44
|
+
async afterEvent(event) {
|
|
45
|
+
receivedState = event.state;
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
const stateBefore = await provider.run('beforeEvent', 'test-model', { id: 'instance-id' });
|
|
50
|
+
await provider.run('afterEvent', 'test-model', { id: 'instance-id' }, stateBefore);
|
|
51
|
+
|
|
52
|
+
expect(receivedState).toEqual(expectedState);
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
});
|
package/lib/entity-manager.js
CHANGED
|
@@ -113,33 +113,33 @@ const createEntityManager = db => {
|
|
|
113
113
|
|
|
114
114
|
return {
|
|
115
115
|
async findOne(uid, params) {
|
|
116
|
-
await db.lifecycles.run('beforeFindOne', uid, { params });
|
|
116
|
+
const states = await db.lifecycles.run('beforeFindOne', uid, { params });
|
|
117
117
|
|
|
118
118
|
const result = await this.createQueryBuilder(uid)
|
|
119
119
|
.init(params)
|
|
120
120
|
.first()
|
|
121
121
|
.execute();
|
|
122
122
|
|
|
123
|
-
await db.lifecycles.run('afterFindOne', uid, { params, result });
|
|
123
|
+
await db.lifecycles.run('afterFindOne', uid, { params, result }, states);
|
|
124
124
|
|
|
125
125
|
return result;
|
|
126
126
|
},
|
|
127
127
|
|
|
128
128
|
// should we name it findOne because people are used to it ?
|
|
129
129
|
async findMany(uid, params) {
|
|
130
|
-
await db.lifecycles.run('beforeFindMany', uid, { params });
|
|
130
|
+
const states = await db.lifecycles.run('beforeFindMany', uid, { params });
|
|
131
131
|
|
|
132
132
|
const result = await this.createQueryBuilder(uid)
|
|
133
133
|
.init(params)
|
|
134
134
|
.execute();
|
|
135
135
|
|
|
136
|
-
await db.lifecycles.run('afterFindMany', uid, { params, result });
|
|
136
|
+
await db.lifecycles.run('afterFindMany', uid, { params, result }, states);
|
|
137
137
|
|
|
138
138
|
return result;
|
|
139
139
|
},
|
|
140
140
|
|
|
141
|
-
async count(uid, params
|
|
142
|
-
await db.lifecycles.run('beforeCount', uid, { params });
|
|
141
|
+
async count(uid, params) {
|
|
142
|
+
const states = await db.lifecycles.run('beforeCount', uid, { params });
|
|
143
143
|
|
|
144
144
|
const res = await this.createQueryBuilder(uid)
|
|
145
145
|
.init(_.pick(['_q', 'where', 'filters'], params))
|
|
@@ -149,13 +149,13 @@ const createEntityManager = db => {
|
|
|
149
149
|
|
|
150
150
|
const result = Number(res.count);
|
|
151
151
|
|
|
152
|
-
await db.lifecycles.run('afterCount', uid, { params, result });
|
|
152
|
+
await db.lifecycles.run('afterCount', uid, { params, result }, states);
|
|
153
153
|
|
|
154
154
|
return result;
|
|
155
155
|
},
|
|
156
156
|
|
|
157
157
|
async create(uid, params = {}) {
|
|
158
|
-
await db.lifecycles.run('beforeCreate', uid, { params });
|
|
158
|
+
const states = await db.lifecycles.run('beforeCreate', uid, { params });
|
|
159
159
|
|
|
160
160
|
const metadata = db.metadata.get(uid);
|
|
161
161
|
const { data } = params;
|
|
@@ -182,14 +182,14 @@ const createEntityManager = db => {
|
|
|
182
182
|
populate: params.populate,
|
|
183
183
|
});
|
|
184
184
|
|
|
185
|
-
await db.lifecycles.run('afterCreate', uid, { params, result });
|
|
185
|
+
await db.lifecycles.run('afterCreate', uid, { params, result }, states);
|
|
186
186
|
|
|
187
187
|
return result;
|
|
188
188
|
},
|
|
189
189
|
|
|
190
190
|
// TODO: where do we handle relation processing for many queries ?
|
|
191
191
|
async createMany(uid, params = {}) {
|
|
192
|
-
await db.lifecycles.run('beforeCreateMany', uid, { params });
|
|
192
|
+
const states = await db.lifecycles.run('beforeCreateMany', uid, { params });
|
|
193
193
|
|
|
194
194
|
const metadata = db.metadata.get(uid);
|
|
195
195
|
const { data } = params;
|
|
@@ -210,13 +210,13 @@ const createEntityManager = db => {
|
|
|
210
210
|
|
|
211
211
|
const result = { count: data.length };
|
|
212
212
|
|
|
213
|
-
await db.lifecycles.run('afterCreateMany', uid, { params, result });
|
|
213
|
+
await db.lifecycles.run('afterCreateMany', uid, { params, result }, states);
|
|
214
214
|
|
|
215
215
|
return result;
|
|
216
216
|
},
|
|
217
217
|
|
|
218
218
|
async update(uid, params = {}) {
|
|
219
|
-
await db.lifecycles.run('beforeUpdate', uid, { params });
|
|
219
|
+
const states = await db.lifecycles.run('beforeUpdate', uid, { params });
|
|
220
220
|
|
|
221
221
|
const metadata = db.metadata.get(uid);
|
|
222
222
|
const { where, data } = params;
|
|
@@ -259,14 +259,14 @@ const createEntityManager = db => {
|
|
|
259
259
|
populate: params.populate,
|
|
260
260
|
});
|
|
261
261
|
|
|
262
|
-
await db.lifecycles.run('afterUpdate', uid, { params, result });
|
|
262
|
+
await db.lifecycles.run('afterUpdate', uid, { params, result }, states);
|
|
263
263
|
|
|
264
264
|
return result;
|
|
265
265
|
},
|
|
266
266
|
|
|
267
267
|
// TODO: where do we handle relation processing for many queries ?
|
|
268
268
|
async updateMany(uid, params = {}) {
|
|
269
|
-
await db.lifecycles.run('beforeUpdateMany', uid, { params });
|
|
269
|
+
const states = await db.lifecycles.run('beforeUpdateMany', uid, { params });
|
|
270
270
|
|
|
271
271
|
const metadata = db.metadata.get(uid);
|
|
272
272
|
const { where, data } = params;
|
|
@@ -284,13 +284,13 @@ const createEntityManager = db => {
|
|
|
284
284
|
|
|
285
285
|
const result = { count: updatedRows };
|
|
286
286
|
|
|
287
|
-
await db.lifecycles.run('afterUpdateMany', uid, { params, result });
|
|
287
|
+
await db.lifecycles.run('afterUpdateMany', uid, { params, result }, states);
|
|
288
288
|
|
|
289
289
|
return result;
|
|
290
290
|
},
|
|
291
291
|
|
|
292
292
|
async delete(uid, params = {}) {
|
|
293
|
-
await db.lifecycles.run('beforeDelete', uid, { params });
|
|
293
|
+
const states = await db.lifecycles.run('beforeDelete', uid, { params });
|
|
294
294
|
|
|
295
295
|
const { where, select, populate } = params;
|
|
296
296
|
|
|
@@ -318,14 +318,14 @@ const createEntityManager = db => {
|
|
|
318
318
|
|
|
319
319
|
await this.deleteRelations(uid, id);
|
|
320
320
|
|
|
321
|
-
await db.lifecycles.run('afterDelete', uid, { params, result: entity });
|
|
321
|
+
await db.lifecycles.run('afterDelete', uid, { params, result: entity }, states);
|
|
322
322
|
|
|
323
323
|
return entity;
|
|
324
324
|
},
|
|
325
325
|
|
|
326
326
|
// TODO: where do we handle relation processing for many queries ?
|
|
327
327
|
async deleteMany(uid, params = {}) {
|
|
328
|
-
await db.lifecycles.run('beforeDeleteMany', uid, { params });
|
|
328
|
+
const states = await db.lifecycles.run('beforeDeleteMany', uid, { params });
|
|
329
329
|
|
|
330
330
|
const { where } = params;
|
|
331
331
|
|
|
@@ -336,7 +336,7 @@ const createEntityManager = db => {
|
|
|
336
336
|
|
|
337
337
|
const result = { count: deletedRows };
|
|
338
338
|
|
|
339
|
-
await db.lifecycles.run('
|
|
339
|
+
await db.lifecycles.run('afterDeleteMany', uid, { params, result }, states);
|
|
340
340
|
|
|
341
341
|
return result;
|
|
342
342
|
},
|
|
@@ -43,7 +43,8 @@ export interface Event {
|
|
|
43
43
|
export interface LifecycleProvider {
|
|
44
44
|
subscribe(subscriber: Subscriber): () => void;
|
|
45
45
|
clear(): void;
|
|
46
|
-
run(action: Action, uid: string, properties: any): Promise<
|
|
46
|
+
run(action: Action, uid: string, properties: any): Promise<Map<any, any>>;
|
|
47
|
+
run(action: Action, uid: string, properties: any, states: Map<any, any>): Promise<Map<any, any>>;
|
|
47
48
|
createEvent(action: Action, uid: string, properties: any): Event;
|
|
48
49
|
}
|
|
49
50
|
|
package/lib/lifecycles/index.js
CHANGED
|
@@ -30,21 +30,39 @@ const createLifecyclesProvider = db => {
|
|
|
30
30
|
subscribers = [];
|
|
31
31
|
},
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
/**
|
|
34
|
+
* @param {string} action
|
|
35
|
+
* @param {string} uid
|
|
36
|
+
* @param {{ params?: any, result?: any }} properties
|
|
37
|
+
* @param {Map<any, any>} state
|
|
38
|
+
*/
|
|
39
|
+
createEvent(action, uid, properties, state) {
|
|
34
40
|
const model = db.metadata.get(uid);
|
|
35
41
|
|
|
36
42
|
return {
|
|
37
43
|
action,
|
|
38
44
|
model,
|
|
45
|
+
state,
|
|
39
46
|
...properties,
|
|
40
47
|
};
|
|
41
48
|
},
|
|
42
49
|
|
|
43
|
-
|
|
44
|
-
|
|
50
|
+
/**
|
|
51
|
+
* @param {string} action
|
|
52
|
+
* @param {string} uid
|
|
53
|
+
* @param {{ params?: any, result?: any }} properties
|
|
54
|
+
* @param {Map<any, any>} states
|
|
55
|
+
*/
|
|
56
|
+
async run(action, uid, properties, states = new Map()) {
|
|
57
|
+
for (let i = 0; i < subscribers.length; i++) {
|
|
58
|
+
const subscriber = subscribers[i];
|
|
45
59
|
if (typeof subscriber === 'function') {
|
|
46
|
-
const
|
|
60
|
+
const state = states.get(subscriber) || {};
|
|
61
|
+
const event = this.createEvent(action, uid, properties, state);
|
|
47
62
|
await subscriber(event);
|
|
63
|
+
if (event.state) {
|
|
64
|
+
states.set(subscriber, event.state || state);
|
|
65
|
+
}
|
|
48
66
|
continue;
|
|
49
67
|
}
|
|
50
68
|
|
|
@@ -52,11 +70,17 @@ const createLifecyclesProvider = db => {
|
|
|
52
70
|
const hasModel = !subscriber.models || subscriber.models.includes(uid);
|
|
53
71
|
|
|
54
72
|
if (hasAction && hasModel) {
|
|
55
|
-
const
|
|
73
|
+
const state = states.get(subscriber) || {};
|
|
74
|
+
const event = this.createEvent(action, uid, properties, state);
|
|
56
75
|
|
|
57
76
|
await subscriber[action](event);
|
|
77
|
+
if (event.state) {
|
|
78
|
+
states.set(subscriber, event.state);
|
|
79
|
+
}
|
|
58
80
|
}
|
|
59
81
|
}
|
|
82
|
+
|
|
83
|
+
return states;
|
|
60
84
|
},
|
|
61
85
|
};
|
|
62
86
|
};
|
package/lib/migrations/index.js
CHANGED
|
@@ -2,42 +2,48 @@
|
|
|
2
2
|
|
|
3
3
|
const path = require('path');
|
|
4
4
|
const fse = require('fs-extra');
|
|
5
|
-
const Umzug = require('umzug');
|
|
5
|
+
const { Umzug } = require('umzug');
|
|
6
6
|
|
|
7
7
|
const createStorage = require('./storage');
|
|
8
8
|
|
|
9
|
+
const wrapTransaction = db => fn => () =>
|
|
10
|
+
db.getConnection().transaction(trx => Promise.resolve(fn(trx)));
|
|
11
|
+
|
|
9
12
|
// TODO: check multiple commands in one sql statement
|
|
10
|
-
const migrationResolver = path => {
|
|
13
|
+
const migrationResolver = ({ name, path, context }) => {
|
|
14
|
+
const { db } = context;
|
|
15
|
+
|
|
11
16
|
// if sql file run with knex raw
|
|
12
17
|
if (path.match(/\.sql$/)) {
|
|
13
18
|
const sql = fse.readFileSync(path, 'utf8');
|
|
14
19
|
|
|
15
20
|
return {
|
|
16
|
-
|
|
21
|
+
name,
|
|
22
|
+
up: wrapTransaction(db)(knex => knex.raw(sql)),
|
|
17
23
|
down() {},
|
|
18
24
|
};
|
|
19
25
|
}
|
|
20
26
|
|
|
21
27
|
// NOTE: we can add some ts register if we want to handle ts migration files at some point
|
|
22
|
-
|
|
28
|
+
const migration = require(path);
|
|
29
|
+
return {
|
|
30
|
+
name,
|
|
31
|
+
up: wrapTransaction(db)(migration.up),
|
|
32
|
+
down: wrapTransaction(db)(migration.down),
|
|
33
|
+
};
|
|
23
34
|
};
|
|
24
35
|
|
|
25
36
|
const createUmzugProvider = db => {
|
|
26
|
-
const migrationDir = path.join(strapi.dirs.
|
|
37
|
+
const migrationDir = path.join(strapi.dirs.root, 'database/migrations');
|
|
27
38
|
|
|
28
39
|
fse.ensureDirSync(migrationDir);
|
|
29
40
|
|
|
30
|
-
const wrapFn = fn => db => db.getConnection().transaction(trx => Promise.resolve(fn(trx)));
|
|
31
|
-
const storage = createStorage({ db, tableName: 'strapi_migrations' });
|
|
32
|
-
|
|
33
41
|
return new Umzug({
|
|
34
|
-
storage,
|
|
42
|
+
storage: createStorage({ db, tableName: 'strapi_migrations' }),
|
|
43
|
+
context: { db },
|
|
35
44
|
migrations: {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
params: [db],
|
|
39
|
-
wrap: wrapFn,
|
|
40
|
-
customResolver: migrationResolver,
|
|
45
|
+
glob: ['*.{js,sql}', { cwd: migrationDir }],
|
|
46
|
+
resolve: migrationResolver,
|
|
41
47
|
},
|
|
42
48
|
});
|
|
43
49
|
};
|
|
@@ -14,21 +14,21 @@ const createStorage = (opts = {}) => {
|
|
|
14
14
|
};
|
|
15
15
|
|
|
16
16
|
return {
|
|
17
|
-
async logMigration(
|
|
17
|
+
async logMigration({ name }) {
|
|
18
18
|
await db
|
|
19
19
|
.getConnection()
|
|
20
20
|
.insert({
|
|
21
|
-
name
|
|
21
|
+
name,
|
|
22
22
|
time: new Date(),
|
|
23
23
|
})
|
|
24
24
|
.into(tableName);
|
|
25
25
|
},
|
|
26
26
|
|
|
27
|
-
async unlogMigration(
|
|
27
|
+
async unlogMigration({ name }) {
|
|
28
28
|
await db
|
|
29
29
|
.getConnection(tableName)
|
|
30
30
|
.del()
|
|
31
|
-
.where({ name
|
|
31
|
+
.where({ name });
|
|
32
32
|
},
|
|
33
33
|
|
|
34
34
|
async executed() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@strapi/database",
|
|
3
|
-
"version": "4.2.0
|
|
3
|
+
"version": "4.2.0",
|
|
4
4
|
"description": "Strapi's database layer",
|
|
5
5
|
"homepage": "https://strapi.io",
|
|
6
6
|
"bugs": {
|
|
@@ -36,11 +36,11 @@
|
|
|
36
36
|
"fs-extra": "10.0.0",
|
|
37
37
|
"knex": "1.0.4",
|
|
38
38
|
"lodash": "4.17.21",
|
|
39
|
-
"umzug": "
|
|
39
|
+
"umzug": "3.1.1"
|
|
40
40
|
},
|
|
41
41
|
"engines": {
|
|
42
|
-
"node": ">=
|
|
42
|
+
"node": ">=14.19.1 <=16.x.x",
|
|
43
43
|
"npm": ">=6.0.0"
|
|
44
44
|
},
|
|
45
|
-
"gitHead": "
|
|
45
|
+
"gitHead": "12c8ee3b2d95fe417de4d939db0311a0513bd8da"
|
|
46
46
|
}
|