From 83ab9f7b9c8707a23ac680701033dadb9e52c723 Mon Sep 17 00:00:00 2001 From: yumcoder Date: Tue, 10 Jun 2025 20:48:58 +0000 Subject: [PATCH 1/2] feat: enable cross-trigger transactions via shared context --- .gitpod.yml | 11 +++++++++++ src/Controllers/DatabaseController.js | 5 +++++ src/RestWrite.js | 4 ++++ src/triggers.js | 6 +++++- 4 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 .gitpod.yml diff --git a/.gitpod.yml b/.gitpod.yml new file mode 100644 index 0000000000..e43643f73a --- /dev/null +++ b/.gitpod.yml @@ -0,0 +1,11 @@ +# This configuration file was automatically generated by Gitpod. +# Please adjust to your needs (see https://www.gitpod.io/docs/introduction/learn-gitpod/gitpod-yaml) +# and commit this file to your remote git repository to share the goodness with others. + +# Learn more from ready-to-use templates: https://www.gitpod.io/docs/introduction/getting-started/quickstart + +tasks: + - init: npm install && npm run build + command: npm run start + + diff --git a/src/Controllers/DatabaseController.js b/src/Controllers/DatabaseController.js index 0050216e2c..dce0602042 100644 --- a/src/Controllers/DatabaseController.js +++ b/src/Controllers/DatabaseController.js @@ -1686,9 +1686,14 @@ class DatabaseController { return protectedKeys; } + setTransactionalSession(transactionalSession) { + this._transactionalSession = transactionalSession; + } + createTransactionalSession() { return this.adapter.createTransactionalSession().then(transactionalSession => { this._transactionalSession = transactionalSession; + return this._transactionalSession; }); } diff --git a/src/RestWrite.js b/src/RestWrite.js index 78dd8c8878..dacf3daba1 100644 --- a/src/RestWrite.js +++ b/src/RestWrite.js @@ -95,6 +95,10 @@ function RestWrite(config, auth, className, query, data, originalData, clientSDK // Returns a promise for a {response, status, location} object. // status and location are optional. RestWrite.prototype.execute = function () { + if (this.context.transaction) { + this.config.database.setTransactionalSession(this.context.transaction) + } + return Promise.resolve() .then(() => { return this.getUserAndRoleACL(); diff --git a/src/triggers.js b/src/triggers.js index 2dfbeff7ac..1505d065fc 100644 --- a/src/triggers.js +++ b/src/triggers.js @@ -281,7 +281,11 @@ export function getRequestObject( triggerType === Types.afterFind ) { // Set a copy of the context on the request object. - request.context = Object.assign({}, context); + request.context = Object.assign({ + createTransactionalSession: config.database.createTransactionalSession.bind(config.database), + commitTransactionalSession: config.database.commitTransactionalSession.bind(config.database), + abortTransactionalSession: config.database.abortTransactionalSession.bind(config.database), + }, context); } if (!auth) { From c23c3648d159bc6f714b42114e94e6065dea896d Mon Sep 17 00:00:00 2001 From: yumcoder Date: Wed, 11 Jun 2025 20:54:35 +0000 Subject: [PATCH 2/2] apply review changes for feat: cross-trigger transaction context --- src/RestWrite.js | 7 ++++++- src/triggers.js | 14 +++++++++----- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/RestWrite.js b/src/RestWrite.js index dacf3daba1..f7cd6da343 100644 --- a/src/RestWrite.js +++ b/src/RestWrite.js @@ -169,7 +169,12 @@ RestWrite.prototype.execute = function () { throw new Parse.Error(Parse.Error.EMAIL_NOT_FOUND, 'User email is not verified.'); } return this.response; - }); + }).finally(() => { + if (this.context.transaction) { + // Ensure isolation even on uncaught errors + this.config.database.setTransactionalSession(null); + } + });; }; // Uses the Auth object to get the list of roles, adds the user id diff --git a/src/triggers.js b/src/triggers.js index 1505d065fc..c868677b9b 100644 --- a/src/triggers.js +++ b/src/triggers.js @@ -281,11 +281,15 @@ export function getRequestObject( triggerType === Types.afterFind ) { // Set a copy of the context on the request object. - request.context = Object.assign({ - createTransactionalSession: config.database.createTransactionalSession.bind(config.database), - commitTransactionalSession: config.database.commitTransactionalSession.bind(config.database), - abortTransactionalSession: config.database.abortTransactionalSession.bind(config.database), - }, context); + request.context = Object.assign( + {}, + context, + { + createTransactionalSession: config.database.createTransactionalSession.bind(config.database), + commitTransactionalSession: config.database.commitTransactionalSession.bind(config.database), + abortTransactionalSession: config.database.abortTransactionalSession.bind(config.database), + } + ); } if (!auth) {