Skip to content

Commit cd69fca

Browse files
committed
add transaction for folder update
1 parent 27bd19b commit cd69fca

File tree

3 files changed

+116
-44
lines changed

3 files changed

+116
-44
lines changed

packages/core/database/lib/index.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,10 @@ class Database {
5858
return schema ? trx.schema.withSchema(schema) : trx.schema;
5959
}
6060

61+
transaction() {
62+
return this.connection.transaction();
63+
}
64+
6165
queryBuilder(uid) {
6266
return this.entityManager.createQueryBuilder(uid);
6367
}

packages/core/database/lib/query/query-builder.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ const createQueryBuilder = (uid, db) => {
1919
populate: null,
2020
limit: null,
2121
offset: null,
22+
transaction: null,
23+
forUpdate: false,
2224
orderBy: [],
2325
groupBy: [],
2426
};
@@ -115,6 +117,16 @@ const createQueryBuilder = (uid, db) => {
115117
return this;
116118
},
117119

120+
transacting(transaction) {
121+
state.transaction = transaction;
122+
return this;
123+
},
124+
125+
forUpdate() {
126+
state.forUpdate = true;
127+
return this;
128+
},
129+
118130
init(params = {}) {
119131
const { _q, filters, where, select, limit, offset, orderBy, groupBy, populate } = params;
120132

@@ -308,6 +320,14 @@ const createQueryBuilder = (uid, db) => {
308320
}
309321
}
310322

323+
if (state.transaction) {
324+
qb.transacting(state.transaction);
325+
}
326+
327+
if (state.forUpdate) {
328+
qb.forUpdate();
329+
}
330+
311331
if (state.limit) {
312332
qb.limit(state.limit);
313333
}

packages/core/upload/server/services/folder.js

Lines changed: 92 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -74,53 +74,101 @@ const deleteByIds = async (ids = []) => {
7474
* @returns {Promise<boolean>}
7575
*/
7676
const update = async (id, { name, parent }, { user }) => {
77-
const existingFolder = await strapi.entityService.findOne(FOLDER_MODEL_UID, id);
78-
79-
if (!existingFolder) {
80-
return undefined;
81-
}
82-
83-
if (!isUndefined(parent)) {
84-
const folderPathColumnName = strapi.db.metadata.get(FILE_MODEL_UID).attributes.folderPath
85-
.columnName;
86-
const pathColumnName = strapi.db.metadata.get(FOLDER_MODEL_UID).attributes.path.columnName;
87-
88-
// Todo wrap into a transaction
89-
const destinationFolder =
90-
parent === null ? '/' : (await strapi.entityService.findOne(FOLDER_MODEL_UID, parent)).path;
91-
92-
const folderTable = strapi.getModel(FOLDER_MODEL_UID).collectionName;
93-
const fileTable = strapi.getModel(FILE_MODEL_UID).collectionName;
94-
95-
await strapi.db
96-
.connection(folderTable)
97-
.where(pathColumnName, 'like', `${existingFolder.path}%`)
98-
.update(
99-
pathColumnName,
100-
strapi.db.connection.raw('REPLACE(??, ?, ?)', [
77+
// only name is updated
78+
if (isUndefined(parent)) {
79+
const existingFolder = await strapi.entityService.findOne(FOLDER_MODEL_UID, id);
80+
81+
if (!existingFolder) {
82+
return undefined;
83+
}
84+
85+
const newFolder = setCreatorFields({ user, isEdition: true })({ name, parent });
86+
87+
if (isUndefined(parent)) {
88+
const folder = await strapi.entityService.update(FOLDER_MODEL_UID, id, { data: newFolder });
89+
return folder;
90+
}
91+
// location is updated => using transaction
92+
} else {
93+
const trx = await strapi.db.transaction();
94+
try {
95+
// fetch existing folder
96+
const existingFolder = await strapi.db
97+
.queryBuilder(FOLDER_MODEL_UID)
98+
.select(['uid', 'path'])
99+
.where({ id })
100+
.transacting(trx)
101+
.forUpdate()
102+
.first()
103+
.execute();
104+
105+
// update parent folder
106+
const joinTable = strapi.db.metadata.get(FOLDER_MODEL_UID).attributes.parent.joinTable;
107+
await strapi.db
108+
.queryBuilder(joinTable.name)
109+
.transacting(trx)
110+
.update({ [joinTable.inverseJoinColumn.name]: parent })
111+
.where({ [joinTable.joinColumn.name]: id })
112+
.execute();
113+
114+
// fetch destinationFolder path
115+
let destinationFolderPath = '/';
116+
if (parent !== null) {
117+
const destinationFolder = await strapi.db
118+
.queryBuilder(FOLDER_MODEL_UID)
119+
.select('path')
120+
.where({ id: parent })
121+
.transacting(trx)
122+
.first()
123+
.execute();
124+
destinationFolderPath = destinationFolder.path;
125+
}
126+
127+
const folderTable = strapi.getModel(FOLDER_MODEL_UID).collectionName;
128+
const fileTable = strapi.getModel(FILE_MODEL_UID).collectionName;
129+
const folderPathColumnName = strapi.db.metadata.get(FILE_MODEL_UID).attributes.folderPath
130+
.columnName;
131+
const pathColumnName = strapi.db.metadata.get(FOLDER_MODEL_UID).attributes.path.columnName;
132+
133+
// update folders below
134+
await strapi.db
135+
.connection(folderTable)
136+
.transacting(trx)
137+
.where(pathColumnName, 'like', `${existingFolder.path}%`)
138+
.update(
101139
pathColumnName,
102-
existingFolder.path,
103-
joinBy('/', destinationFolder, existingFolder.uid),
104-
])
105-
);
106-
107-
await strapi.db
108-
.connection(fileTable)
109-
.where(folderPathColumnName, 'like', `${existingFolder.path}%`)
110-
.update(
111-
folderPathColumnName,
112-
strapi.db.connection.raw('REPLACE(??, ?, ?)', [
140+
strapi.db.connection.raw('REPLACE(??, ?, ?)', [
141+
pathColumnName,
142+
existingFolder.path,
143+
joinBy('/', destinationFolderPath, existingFolder.uid),
144+
])
145+
);
146+
147+
// update files below
148+
await strapi.db
149+
.connection(fileTable)
150+
.transacting(trx)
151+
.where(folderPathColumnName, 'like', `${existingFolder.path}%`)
152+
.update(
113153
folderPathColumnName,
114-
existingFolder.path,
115-
joinBy('/', destinationFolder, existingFolder.uid),
116-
])
117-
);
154+
strapi.db.connection.raw('REPLACE(??, ?, ?)', [
155+
folderPathColumnName,
156+
existingFolder.path,
157+
joinBy('/', destinationFolderPath, existingFolder.uid),
158+
])
159+
);
160+
161+
await trx.commit();
162+
} catch (e) {
163+
await trx.rollback();
164+
throw e;
165+
}
166+
167+
// update less critical information (name + updatedBy)
168+
const newFolder = setCreatorFields({ user, isEdition: true })({ name });
169+
const folder = await strapi.entityService.update(FOLDER_MODEL_UID, id, { data: newFolder });
170+
return folder;
118171
}
119-
120-
const newFolder = setCreatorFields({ user, isEdition: true })({ name, parent });
121-
const folder = await strapi.entityService.update(FOLDER_MODEL_UID, id, { data: newFolder });
122-
123-
return folder;
124172
};
125173

126174
/**

0 commit comments

Comments
 (0)