add strict configuration

This commit is contained in:
Marc-Roig 2022-12-12 18:16:37 +01:00
parent 32bb3a0645
commit 2639f8418e
4 changed files with 93 additions and 40 deletions

View File

@ -98,6 +98,30 @@ describe('Given I have some relations in the database', () => {
]);
});
});
describe('When you connect a relation before a non-existing relation in non-strict mode', () => {
test('Then it is placed at the end', () => {
const orderer = relationsOrderer(
[
{ id: 1, order: 1 },
{ id: 2, order: 2 },
{ id: 3, order: 3 },
],
'id',
'order',
false
);
orderer.connect([{ id: 4, position: { before: 5 } }]);
expect(orderer.get()).toMatchObject([
{ id: 1, order: 1 },
{ id: 2, order: 2 },
{ id: 3, order: 3 },
{ id: 4, order: 3.5 },
]);
});
});
});
describe('Given there are no relations in the database', () => {

View File

@ -78,6 +78,9 @@ const toAssocs = (data) => {
}
return {
options: {
strictConnect: data?.options?.strictConnect,
},
connect: toIdArray(data?.connect).map((elm) => ({
id: elm.id,
position: elm.position ? elm.position : { end: true },
@ -876,7 +879,8 @@ const createEntityManager = (db) => {
const orderMap = relationsOrderer(
adjacentRelations,
inverseJoinColumn.name,
joinTable.orderColumnName
joinTable.orderColumnName,
cleanRelationData.options.strictConnect
)
.connect(cleanRelationData.connect)
.getOrderMap();

View File

@ -20,7 +20,7 @@ const { InvalidRelationError } = require('../errors');
* { id: 5, position: { before: 1 } }
*
*/
const sortConnectArray = (connectArr, initialArr = []) => {
const sortConnectArray = (connectArr, initialArr = [], strictSort = true) => {
const sortedConnect = [];
// Boolean to know if we have to recalculate the order of the relations
let needsSorting = false;
@ -69,7 +69,7 @@ const sortConnectArray = (connectArr, initialArr = []) => {
computedIdx[adjacentRelIdx] = true;
computeRelation(adjacentRel);
pushRelation(rel);
} else {
} else if (strictSort) {
// If we reach this point, it means that the adjacent relation is not in the connect array
// and it is not in the database. This should not happen.
throw new InvalidRelationError(
@ -77,6 +77,9 @@ const sortConnectArray = (connectArr, initialArr = []) => {
rel.position
)}. The relation with id ${adjacentRelId} needs to be connected first.`
);
} else {
// We are in non-strict mode so we can push the relation.
pushRelation({ id: rel.id, position: { end: true } });
}
};
@ -114,9 +117,11 @@ const sortConnectArray = (connectArr, initialArr = []) => {
* @param {Array<*>} initArr - array of relations to initialize the class with
* @param {string} idColumn - the column name of the id
* @param {string} orderColumn - the column name of the order
* @param {boolean} strictConnect - if true, will throw an error if a relation is connected adjacent to
* another one that does not exist
* @return {*}
*/
const relationsOrderer = (initArr, idColumn, orderColumn) => {
const relationsOrderer = (initArr, idColumn, orderColumn, strictConnect) => {
const arr = _.castArray(initArr || []).map((r) => ({
init: true,
id: r[idColumn],
@ -170,7 +175,7 @@ const relationsOrderer = (initArr, idColumn, orderColumn) => {
return this;
},
connect(relations) {
const sortedRelations = sortConnectArray(relations, arr);
const sortedRelations = sortConnectArray(relations, arr, strictConnect);
sortedRelations.forEach((relation) => {
this.disconnect(relation);

View File

@ -138,6 +138,7 @@ const createShop = async ({
anyToManyRel = [{ id: id1 }, { id: id2 }, { id: id3 }],
data = {},
populate,
strictConnect = true,
}) => {
return createEntry(
'shops',
@ -146,12 +147,12 @@ const createShop = async ({
products_ow: { connect: anyToOneRel },
products_oo: { connect: anyToOneRel },
products_mo: { connect: anyToOneRel },
products_om: { connect: anyToManyRel },
products_mm: { connect: anyToManyRel },
products_mw: { connect: anyToManyRel },
products_om: { options: { strictConnect }, connect: anyToManyRel },
products_mm: { options: { strictConnect }, connect: anyToManyRel },
products_mw: { options: { strictConnect }, connect: anyToManyRel },
myCompo: {
compo_products_ow: { connect: anyToOneRel },
compo_products_mw: { connect: anyToManyRel },
compo_products_mw: { options: { strictConnect }, connect: anyToManyRel },
},
...data,
},
@ -167,6 +168,7 @@ const updateShop = async (
relAction = 'connect',
data = {},
populate,
strictConnect = true,
}
) => {
return updateEntry(
@ -177,13 +179,13 @@ const updateShop = async (
products_ow: { [relAction]: anyToOneRel },
products_oo: { [relAction]: anyToOneRel },
products_mo: { [relAction]: anyToOneRel },
products_om: { [relAction]: anyToManyRel },
products_mm: { [relAction]: anyToManyRel },
products_mw: { [relAction]: anyToManyRel },
products_om: { options: { strictConnect }, [relAction]: anyToManyRel },
products_mm: { options: { strictConnect }, [relAction]: anyToManyRel },
products_mw: { options: { strictConnect }, [relAction]: anyToManyRel },
myCompo: {
id: shop.attributes?.myCompo?.id,
compo_products_ow: { [relAction]: anyToOneRel },
compo_products_mw: { [relAction]: anyToManyRel },
compo_products_mw: { options: { strictConnect }, [relAction]: anyToManyRel },
},
...data,
},
@ -831,40 +833,58 @@ describe('Relations', () => {
});
expect(updatedShop.data).toMatchObject(expectedShop);
});
});
test('Update relations using the same id multiple times', async () => {
const shop = await createShop({
anyToManyRel: [
{ id: id1, position: { end: true } },
{ id: id2, position: { end: true } },
],
test('Update relations using the same id multiple times', async () => {
const shop = await createShop({
anyToManyRel: [
{ id: id1, position: { end: true } },
{ id: id2, position: { end: true } },
],
});
const updatedShop = await updateShop(shop.data, {
anyToManyRel: [
{ id: id1, position: { end: true } },
{ id: id1, position: { start: true } },
{ id: id1, position: { after: id2 } },
],
});
const expectedShop = shopFactory({
anyToManyRel: [{ id: id2 }, { id: id1 }],
});
expect(updatedShop.data).toMatchObject(expectedShop);
});
const updatedShop = await updateShop(shop.data, {
anyToManyRel: [
{ id: id1, position: { end: true } },
{ id: id1, position: { start: true } },
{ id: id1, position: { after: id2 } },
],
test('Update relations with invalid connect array in strict mode', async () => {
const shop = await createShop({
anyToManyRel: [],
});
// Connect before an id that does not exist.
const updatedShop = await updateShop(shop.data, {
anyToManyRel: [{ id: id1, position: { after: id2 } }],
});
expect(updatedShop.error).toMatchObject({ status: 400, name: 'ValidationError' });
});
const expectedShop = shopFactory({
anyToManyRel: [{ id: id2 }, { id: id1 }],
});
expect(updatedShop.data).toMatchObject(expectedShop);
});
test('Update relations with invalid connect array in non-strict mode', async () => {
const shop = await createShop({
anyToManyRel: [{ id: id1 }],
});
test('Update relations with invalid connect array in strict mode', async () => {
const shop = await createShop({
anyToManyRel: [{ id: id1, position: { end: true } }],
});
// Connect before an id that does not exist.
const updatedShop = await updateShop(shop.data, {
anyToManyRel: [{ id: id2, position: { after: id3 } }],
strictConnect: false,
});
// Connect relation before id2, but id2 is not in the DB or in the connect array
const updatedShop = await updateShop(shop.data, {
anyToManyRel: [{ id: id1, position: { after: id2 } }],
});
const expectedShop = shopFactory({
anyToManyRel: [{ id: id1 }, { id: id2 }],
});
expect(updatedShop.error).toMatchObject({ status: 400, name: 'ValidationError' });
expect(updatedShop.data).toMatchObject(expectedShop);
});
});
});