Hi,
When i use transaction to wrap some queries. The promise is resolve before queries in the transaction are executed. This is the code that make the transaction.
objection.transaction(Model.knex(), trx =>
Model.query(trx)
.upsertGraph(req.body.model, {
relate: true,
unrelate: false
})
.then(model => {
res.status(httpCode.HTTP_CREATED).json(model);
}).catch(err => {
res.statusMessage = "There is an error";
res.status(httpCode.HTTP_UNPROCESSABLE_ENTITY).end();
})
);
Now this code is the unit test that call this endpoint :
chai.request(server)
.post(`${basePath}/models`)
.set("Authorization", `JWT ${tokenAdmin}`)
.set("Content-Type", "application/json")
.send({
model: newModel
})
.then(res => {
Model.query().findOne({name: "modelName"}).then(model => {
console.log(model); // model is undefined
res.should.have.status(httpCode.HTTP_CREATED);
res.body.should.be.a("object");
res.body.should.not.be.empty;
res.body.should.have.property("description", "modelDescription");
Model.query().delete().where("id", model.id).then(() => {
done();
}).catch(err => {
done(err);
});
}).catch(err => {
done(err);
});
}).catch(err => {
done(err);
});
If I pause the test with breakpoints. This test works well. So what's the problem? am I missing something?
thx
You need to return a promise from the transaction callback:
objection.transaction(Model.knex(), trx =>
// HERE: notice the return in the next line.
return Model.query(trx)
.upsertGraph(req.body.model, {
relate: true,
unrelate: false
})
.then(model => {
res.status(httpCode.HTTP_CREATED).json(model);
}).catch(err => {
res.statusMessage = "There is an error";
res.status(httpCode.HTTP_UNPROCESSABLE_ENTITY).end();
})
);
Also you shouldn't respond inside the transaction or you can lose atomicity. This is better:
objection.transaction(Model.knex(), trx =>
// HERE: notice the return in the next line.
return Model.query(trx)
.upsertGraph(req.body.model, {
relate: true,
unrelate: false
});
}).then(model => {
// Here the transaction has been committed.
res.status(httpCode.HTTP_CREATED).json(model);
}).catch(err => {
// Here the transaction has been roleld back.
res.statusMessage = "There is an error";
res.status(httpCode.HTTP_UNPROCESSABLE_ENTITY).end();
});
This is off topic, but it always bugs me when people don't use promises correctly 馃槃 . Your unit test can be written like this using promise chaining:
chai.request(server)
.post(`${basePath}/models`)
.set("Authorization", `JWT ${tokenAdmin}`)
.set("Content-Type", "application/json")
.send({
model: newModel
})
.then(res => {
return Model.query().findOne({name: "modelName"}).then(model => {
console.log(model); // model is undefined
res.should.have.status(httpCode.HTTP_CREATED);
res.body.should.be.a("object");
res.body.should.not.be.empty;
res.body.should.have.property("description", "modelDescription");
return Model.query().delete().where("id", model.id);
});
})
.then(() => {
done();
})
.catch(err => {
done(err);
});
Now there is only one catch block but the result is exactly same.
Nice, this works like a charme. And i will update my test code.
Just for information, write
val => {
return foo();
}
is exactly the same as writing :
val => foo()
馃槅
Yes I know 馃槃 I just copied your style of writing the arrow functions from your example.
Most helpful comment
This is off topic, but it always bugs me when people don't use promises correctly 馃槃 . Your unit test can be written like this using promise chaining:
Now there is only one
catchblock but the result is exactly same.