Skip to content

Commit

Permalink
Don't call onError() with internal exception (#2603)
Browse files Browse the repository at this point in the history
  • Loading branch information
lehni committed Feb 12, 2024
1 parent 78e6d9d commit 1ecdc39
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 24 deletions.
2 changes: 2 additions & 0 deletions lib/queryBuilder/InternalOptions.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ class InternalOptions {
constructor() {
this.skipUndefined = false;
this.keepImplicitJoinProps = false;
this.returnImmediatelyValue = undefined;
this.isInternalQuery = false;
this.debug = false;
this.schema = undefined;
Expand All @@ -14,6 +15,7 @@ class InternalOptions {

copy.skipUndefined = this.skipUndefined;
copy.keepImplicitJoinProps = this.keepImplicitJoinProps;
copy.returnImmediatelyValue = this.returnImmediatelyValue;
copy.isInternalQuery = this.isInternalQuery;
copy.debug = this.debug;
copy.schema = this.schema;
Expand Down
31 changes: 27 additions & 4 deletions lib/queryBuilder/QueryBuilder.js
Original file line number Diff line number Diff line change
Expand Up @@ -1119,7 +1119,24 @@ function afterExecute(builder, result) {
return promise;
}

class ReturnImmediatelyException {
constructor(value) {
this.value = value;
}
}

function handleReturnImmediatelyValue(builder) {
const { returnImmediatelyValue } = builder.internalOptions();
if (returnImmediatelyValue !== undefined) {
throw new ReturnImmediatelyException(returnImmediatelyValue);
}
}

function handleExecuteError(builder, err) {
if (err instanceof ReturnImmediatelyException) {
return Promise.resolve(err.value);
}

let promise = Promise.reject(wrapError(err));

builder.forEachOperation(true, (op) => {
Expand All @@ -1139,9 +1156,11 @@ function chainOperationHooks(promise, builder, hookName) {

builder.forEachOperation(true, (op) => {
if (op.hasHook(hookName)) {
promise = promise.then((result) =>
builder.callAsyncOperationMethod(op, hookName, [builder, result]),
);
promise = promise.then((result) => {
const res = builder.callAsyncOperationMethod(op, hookName, [builder, result]);
handleReturnImmediatelyValue(builder);
return res;
});
}
});

Expand Down Expand Up @@ -1261,7 +1280,11 @@ async function chainHooks(promise, builder, func) {
let promise = Promise.resolve(result);

if (isFunction(func)) {
promise = promise.then((result) => func.call(builder, result, builder));
promise = promise.then((result) => {
const res = func.call(builder, result, builder);
handleReturnImmediatelyValue(builder);
return res;
});
} else if (Array.isArray(func)) {
func.forEach((func) => {
promise = chainHooks(promise, builder, func);
Expand Down
29 changes: 9 additions & 20 deletions lib/queryBuilder/graph/patch/GraphPatchAction.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,24 +82,15 @@ class GraphPatchAction extends GraphAction {
.copyFrom(builder, GraphAction.ReturningAllSelector);

if (hasBeforeUpdate) {
updateBuilder
.context({
runBefore: () => {
// Call handleUpdate in the runBefore hook which runs after the
// $beforeUpdate hook, allowing it to modify the object before the
// updated properties are determined. See issue #2233.
if (hasBeforeUpdate && !handleUpdate()) {
throw new ReturnNullException();
}
},
})
.onError((error) => {
if (error instanceof ReturnNullException) {
return null;
} else {
return Promise.reject(error);
}
});
updateBuilder.internalContext().runBefore.push((result, builder) => {
// Call handleUpdate in the runBefore hook which runs after the
// $beforeUpdate hook, allowing it to modify the object before the
// updated properties are determined. See issue #2233.
if (hasBeforeUpdate && !handleUpdate()) {
builder.internalOptions().returnImmediatelyValue = null;
}
return result;
});
}

if (shouldPatch) {
Expand Down Expand Up @@ -235,8 +226,6 @@ class GraphPatchAction extends GraphAction {
}
}

class ReturnNullException {}

function childQueryOptions() {
return {
fork: true,
Expand Down
28 changes: 28 additions & 0 deletions tests/integration/upsertGraph.js
Original file line number Diff line number Diff line change
Expand Up @@ -4131,6 +4131,34 @@ module.exports = (session) => {
});
});

describe('should not call onError() with internal exception (#2603)', () => {
let query;

before(() => {
query = Model1.query;
});

after(() => {
Model1.query = query;
});

it('should not call onError() with internal exception', async () => {
const upsert = { id: 2 };

let error = null;
Model1.query = function (trx) {
return query.call(this, trx).onError((err) => {
error = err;
});
};

await transaction(session.knex, (trx) =>
Model1.query(trx).upsertGraph(upsert, { fetchStrategy }),
);
expect(error).to.equal(null);
});
});

if (session.isPostgres()) {
describe('returning', () => {
it('should propagate returning(*) to all update an insert operations', () => {
Expand Down

0 comments on commit 1ecdc39

Please sign in to comment.