Improve transaction API:

- make it possible to have nested transactions
- wrap the knex transaction api and apply changes everywhere it was used
This commit is contained in:
Bassel 2023-01-13 12:23:30 +02:00
parent e90885ab91
commit 12dd68f4a7
5 changed files with 54 additions and 28 deletions

View File

@ -218,7 +218,7 @@ const createEntityManager = (db) => {
const trx = await strapi.db.transaction();
try {
await this.attachRelations(uid, id, data, { transaction: trx });
await this.attachRelations(uid, id, data, { transaction: trx.get() });
await trx.commit();
} catch (e) {
@ -302,7 +302,7 @@ const createEntityManager = (db) => {
const trx = await strapi.db.transaction();
try {
await this.updateRelations(uid, id, data, { transaction: trx });
await this.updateRelations(uid, id, data, { transaction: trx.get() });
await trx.commit();
} catch (e) {
await trx.rollback();
@ -373,7 +373,7 @@ const createEntityManager = (db) => {
const trx = await strapi.db.transaction();
try {
await this.deleteRelations(uid, id, { transaction: trx });
await this.deleteRelations(uid, id, { transaction: trx.get() });
await trx.commit();
} catch (e) {

View File

@ -1,3 +1,4 @@
import { Knex } from 'knex';
import { LifecycleProvider } from './lifecycles';
import { MigrationProvider } from './migrations';
import { SchemaProvider } from './schema';
@ -31,8 +32,7 @@ type AttributeOperators<T, K extends keyof T> = {
export type WhereParams<T> = {
[K in keyof T]?: T[K] | T[K][] | AttributeOperators<T, K>;
} &
LogicalOperators<T>;
} & LogicalOperators<T>;
type Sortables<T> = {
// check sortable
@ -160,7 +160,12 @@ export interface Database {
entityManager: EntityManager;
query<T extends keyof AllTypes>(uid: T): QueryFromContentType<T>;
transaction(cb: (em: EntityManager) => Promise<any>): Promise<void>;
transaction(
cb?: (trx: Knex.Transaction) => Promise<any>,
options?: any
):
| Promise<void>
| { get: () => Knex.Transaction; rollback: () => Promise<void>; commit: () => Promise<void> };
}
export class Database implements Database {
static transformContentTypes(contentTypes: any[]): ModelConfig[];

View File

@ -48,19 +48,40 @@ class Database {
return this.entityManager.getRepository(uid);
}
async transaction(cb) {
async transaction(cb, { onError, onSuccess } = {}) {
const notNestedTransaction = !transactionCtx.get();
const trx = notNestedTransaction ? await this.connection.transaction() : transactionCtx.get();
if (!cb) {
return this.connection.transaction();
return {
async commit() {
if (notNestedTransaction) {
await trx.commit();
}
},
async rollback() {
if (notNestedTransaction) {
await trx.rollback();
}
},
get() {
return trx;
},
};
}
const trx = await this.connection.transaction();
return transactionCtx.run(trx, async () => {
try {
const res = await cb();
await trx.commit();
const res = await cb(trx);
if (notNestedTransaction) {
await trx.commit();
}
await onSuccess?.();
return res;
} catch (error) {
await trx.rollback();
if (notNestedTransaction) {
await trx.rollback();
}
await onError?.();
throw error;
}
});

View File

@ -84,7 +84,7 @@ module.exports = {
.queryBuilder(FOLDER_MODEL_UID)
.select(['id', 'pathId', 'path'])
.where({ id: { $in: folderIds } })
.transacting(trx)
.transacting(trx.get())
.forUpdate()
.execute();
@ -93,7 +93,7 @@ module.exports = {
.queryBuilder(FILE_MODEL_UID)
.select(['id'])
.where({ id: { $in: fileIds } })
.transacting(trx)
.transacting(trx.get())
.forUpdate()
.execute();
@ -104,7 +104,7 @@ module.exports = {
.queryBuilder(FOLDER_MODEL_UID)
.select('path')
.where({ id: destinationFolderId })
.transacting(trx)
.transacting(trx.get())
.first()
.execute();
destinationFolderPath = destinationFolder.path;
@ -121,7 +121,7 @@ module.exports = {
const { joinTable } = strapi.db.metadata.get(FOLDER_MODEL_UID).attributes.parent;
await strapi.db
.queryBuilder(joinTable.name)
.transacting(trx)
.transacting(trx.get())
.delete()
.where({ [joinTable.joinColumn.name]: { $in: folderIds } })
.execute();
@ -129,7 +129,7 @@ module.exports = {
if (destinationFolderId !== null) {
await strapi.db
.queryBuilder(joinTable.name)
.transacting(trx)
.transacting(trx.get())
.insert(
existingFolders.map((folder) => ({
[joinTable.inverseJoinColumn.name]: destinationFolderId,
@ -155,7 +155,7 @@ module.exports = {
// update path for folders themselves & folders below
totalFolderNumber = await strapi.db
.getConnection(folderTable)
.transacting(trx)
.transacting(trx.get())
.where(pathColName, existingFolder.path)
.orWhere(pathColName, 'like', `${existingFolder.path}/%`)
.update(
@ -170,7 +170,7 @@ module.exports = {
// update path of files below
totalFileNumber = await strapi.db
.getConnection(fileTable)
.transacting(trx)
.transacting(trx.get())
.where(folderPathColName, existingFolder.path)
.orWhere(folderPathColName, 'like', `${existingFolder.path}/%`)
.update(
@ -189,7 +189,7 @@ module.exports = {
const fileJoinTable = strapi.db.metadata.get(FILE_MODEL_UID).attributes.folder.joinTable;
await strapi.db
.queryBuilder(fileJoinTable.name)
.transacting(trx)
.transacting(trx.get())
.delete()
.where({ [fileJoinTable.joinColumn.name]: { $in: fileIds } })
.execute();
@ -197,7 +197,7 @@ module.exports = {
if (destinationFolderId !== null) {
await strapi.db
.queryBuilder(fileJoinTable.name)
.transacting(trx)
.transacting(trx.get())
.insert(
existingFiles.map((file) => ({
[fileJoinTable.inverseJoinColumn.name]: destinationFolderId,
@ -210,7 +210,7 @@ module.exports = {
// update files main fields (path + updatedBy)
await strapi.db
.getConnection(fileTable)
.transacting(trx)
.transacting(trx.get())
.whereIn('id', fileIds)
.update(folderPathColName, destinationFolderPath);
}

View File

@ -103,7 +103,7 @@ const update = async (id, { name, parent }, { user }) => {
.queryBuilder(FOLDER_MODEL_UID)
.select(['pathId', 'path'])
.where({ id })
.transacting(trx)
.transacting(trx.get())
.forUpdate()
.first()
.execute();
@ -112,7 +112,7 @@ const update = async (id, { name, parent }, { user }) => {
const { joinTable } = strapi.db.metadata.get(FOLDER_MODEL_UID).attributes.parent;
await strapi.db
.queryBuilder(joinTable.name)
.transacting(trx)
.transacting(trx.get())
.delete()
.where({ [joinTable.joinColumn.name]: id })
.execute();
@ -120,7 +120,7 @@ const update = async (id, { name, parent }, { user }) => {
if (parent !== null) {
await strapi.db
.queryBuilder(joinTable.name)
.transacting(trx)
.transacting(trx.get())
.insert({ [joinTable.inverseJoinColumn.name]: parent, [joinTable.joinColumn.name]: id })
.where({ [joinTable.joinColumn.name]: id })
.execute();
@ -133,7 +133,7 @@ const update = async (id, { name, parent }, { user }) => {
.queryBuilder(FOLDER_MODEL_UID)
.select('path')
.where({ id: parent })
.transacting(trx)
.transacting(trx.get())
.first()
.execute();
destinationFolderPath = destinationFolder.path;
@ -148,7 +148,7 @@ const update = async (id, { name, parent }, { user }) => {
// update folders below
await strapi.db
.getConnection(folderTable)
.transacting(trx)
.transacting(trx.get())
.where(pathColumnName, existingFolder.path)
.orWhere(pathColumnName, 'like', `${existingFolder.path}/%`)
.update(
@ -163,7 +163,7 @@ const update = async (id, { name, parent }, { user }) => {
// update files below
await strapi.db
.getConnection(fileTable)
.transacting(trx)
.transacting(trx.get())
.where(folderPathColumnName, existingFolder.path)
.orWhere(folderPathColumnName, 'like', `${existingFolder.path}/%`)
.update(