Skip to content

Commit

Permalink
LF-3994, 3984 - add migration to fix naming, and error handling
Browse files Browse the repository at this point in the history
  • Loading branch information
Duncan-Brain committed Feb 2, 2024
1 parent 99be8cf commit a98eccd
Show file tree
Hide file tree
Showing 6 changed files with 138 additions and 32 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
*/

export const up = async function (knex) {
await knex.schema.alterTable('animal_batch_sex_detail', (t) => {
t.renameColumn('batch_id', 'animal_batch_id');
});

await knex('permissions')
.where({ permission_id: 159 })
.update({ name: 'add:animal_batches', description: 'add animal_batches' });
Expand All @@ -29,6 +33,10 @@ export const up = async function (knex) {
};

export const down = async function (knex) {
await knex.schema.alterTable('animal_batch_sex_detail', (t) => {
t.renameColumn('animal_batch_id', 'batch_id');
});

await knex('permissions')
.where({ permission_id: 159 })
.update({ name: 'add:animal_batch', description: 'add animal_batch' });
Expand Down
2 changes: 1 addition & 1 deletion packages/api/src/models/animalBatchModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ class AnimalBatchModel extends baseModel {
modelClass: AnimalBatchSexDetailModel,
join: {
from: 'animal_batch.id',
to: 'animal_batch_sex_detail.batch_id',
to: 'animal_batch_sex_detail.animal_batch_id',
},
},
};
Expand Down
4 changes: 2 additions & 2 deletions packages/api/src/models/animalBatchSexDetailModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ class AnimalBatchSexDetailModel extends baseModel {
static get jsonSchema() {
return {
type: 'object',
required: ['batch_id', 'count', 'sex_id'],
required: ['animal_batch_id', 'count', 'sex_id'],
properties: {
batch_id: { type: 'integer' },
animal_batch_id: { type: 'integer' },
count: { type: 'integer' },
id: { type: 'integer' },
sex_id: { type: 'integer' },
Expand Down
148 changes: 123 additions & 25 deletions packages/api/src/util/errorCodes.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,12 @@
* GNU General Public License for more details, see <https://www.gnu.org/licenses/>.
*/

// See https://github.com/Vincit/objection.js/issues/2023#issuecomment-806059039
import objection from 'objection';

/**
* Handles objection.js errors and sends appropriate responses based on the error type.
* Augmented from: https://vincit.github.io/objection.js/recipes/error-handling.html#examples
*
* @param {Error} err - The objection.js error object.
* @param {import('express').Response} res - The Express response object.
Expand All @@ -25,34 +29,128 @@
* try {
* // Some objection.js operation that may throw an error
* } catch (error) {
* await handleObjectionError(error, res, trx);
* await handleObjectionError(error, res);
* }
*/

export async function handleObjectionError(err, res, trx) {
switch (err.name) {
case 'ValidationError': {
await trx.rollback();
const errorString = Object.keys(err.data).reduce((acc, cv, ci) => {
const comma = Object.keys(err.data).length - 1 == ci ? '' : ', ';
return acc.concat(`${cv} ${err.data[cv][0].message}${comma}`);
}, '');
return res.status(err.statusCode).send(`Validation error: ${errorString}`);
}
case 'CheckViolationError': {
await trx.rollback();
return res.status(400).send(`Constraint check error: ${err.constraint}`);
}
case 'ForeignKeyViolationError': {
await trx.rollback();
return res.status(400).send(`Foreign key violation: ${err.nativeError.detail}`);
}
default: {
console.error(err);
await trx.rollback();
return res.status(500).json({
err,
});
if (err instanceof objection.ValidationError) {
switch (err.type) {
case 'ModelValidation':
await trx.rollback();
res.status(400).send({
message: err.message,
type: err.type,
data: err.data,
});
break;
case 'RelationExpression':
await trx.rollback();
res.status(400).send({
message: err.message,
type: 'RelationExpression',
data: {},
});
break;
case 'UnallowedRelation':
await trx.rollback();
res.status(400).send({
message: err.message,
type: err.type,
data: {},
});
break;
case 'InvalidGraph':
await trx.rollback();
res.status(400).send({
message: err.message,
type: err.type,
data: {},
});
break;
default:
await trx.rollback();
res.status(400).send({
message: err.message,
type: 'UnknownValidationError',
data: {},
});
break;
}
} else if (err instanceof objection.NotFoundError) {
await trx.rollback();
res.status(404).send({
message: err.message,
type: 'NotFound',
data: {},
});
} else if (err instanceof objection.UniqueViolationError) {
await trx.rollback();
res.status(409).send({
message: err.message,
type: 'UniqueViolation',
data: {
columns: err.columns,
table: err.table,
constraint: err.constraint,
},
});
} else if (err instanceof objection.NotNullViolationError) {
await trx.rollback();
res.status(400).send({
message: err.message,
type: 'NotNullViolation',
data: {
column: err.column,
table: err.table,
},
});
} else if (err instanceof objection.ForeignKeyViolationError) {
await trx.rollback();
res.status(409).send({
message: err.message,
type: 'ForeignKeyViolation',
data: {
table: err.table,
constraint: err.constraint,
},
});
} else if (err instanceof objection.CheckViolationError) {
await trx.rollback();
res.status(400).send({
message: err.message,
type: 'CheckViolation',
data: {
table: err.table,
constraint: err.constraint,
},
});
} else if (err instanceof objection.ConstraintViolationError) {
await trx.rollback();
res.status(400).send({
message: err.message,
type: 'ConstraintViolation',
data: {},
});
} else if (err instanceof objection.DataError) {
await trx.rollback();
res.status(400).send({
message: err.message,
type: 'InvalidData',
data: {},
});
} else if (err instanceof objection.DBError) {
await trx.rollback();
res.status(500).send({
message: err.message,
type: 'UnknownDatabaseError',
data: {},
});
} else {
await trx.rollback();
res.status(500).send({
message: err.message,
type: 'UnknownError',
data: {},
});
}
}
2 changes: 1 addition & 1 deletion packages/api/tests/animal_batch.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ describe('Animal Batch Tests', () => {
}

async function makeAnimalBatch(mainFarm, properties) {
const [animalBatch] = await mocks.animalBatchFactory({
const [animalBatch] = await mocks.animal_batchFactory({
promisedFarm: [mainFarm],
properties,
});
Expand Down
6 changes: 3 additions & 3 deletions packages/api/tests/mock.factories.js
Original file line number Diff line number Diff line change
Expand Up @@ -2261,7 +2261,7 @@ function fakeAnimalBatch(defaultData = {}) {
};
}

async function animalBatchFactory(
async function animal_batchFactory(
{
promisedFarm = farmFactory(),
promisedDefaultAnimalType = default_animal_typeFactory(),
Expand Down Expand Up @@ -2295,7 +2295,7 @@ async function animalBatchFactory(
let details = [];
for (const sexDetail of animal_batch_sex_detail) {
const detail = await trx
.insert({ ...sexDetail, batch_id: batch[0].id })
.insert({ ...sexDetail, animal_batch_id: batch[0].id })
.into('animal_batch_sex_detail')
.returning('*');
details.push(detail[0]);
Expand Down Expand Up @@ -2466,7 +2466,7 @@ export default {
fakeAnimal,
fakeAnimalBatch,
animalFactory,
animalBatchFactory,
animal_batchFactory,
animal_identifier_colorFactory,
animal_identifier_placementFactory,
animal_sexFactory,
Expand Down

0 comments on commit a98eccd

Please sign in to comment.