look for duplicated inverseBy relationships

This commit is contained in:
Marc-Roig 2022-12-20 10:17:38 +01:00
parent 3e01e639d3
commit e273f7f76d
2 changed files with 87 additions and 2 deletions

View File

@ -11,6 +11,8 @@ const errors = require('./errors');
// TODO: move back into strapi
const { transformContentTypes } = require('./utils/content-types');
const { getJoinTableName } = require('./metadata/relations');
const types = require('./types');
class Database {
constructor(config) {
@ -72,9 +74,89 @@ class Database {
}
}
// TODO: Do the same for repeated mappedBy relations
const getLinks = ({ db }) => {
const relationsToUpdate = {};
db.metadata.forEach((contentType) => {
const attributes = contentType.attributes;
// For each relation type, add the joinTable name to tablesToUpdate
Object.values(attributes).forEach((attribute) => {
if (!types.isRelation(attribute.type)) return;
if (attribute.inversedBy) {
const invRelation = db.metadata.get(attribute.target).attributes[attribute.inversedBy];
// Both relations use inversedBy
if (invRelation?.inversedBy) {
relationsToUpdate[attribute.joinTable.name] = {
relation: attribute,
invRelation,
};
}
}
});
});
return Object.values(relationsToUpdate);
};
// const isLinkTableEmpty = async (db, linkTableName) => {
// const result = await db.getConnection().count('* as count').from(linkTableName);
// return result.count === 0;
// };
// TODO: move into strapi
Database.transformContentTypes = transformContentTypes;
Database.init = async (config) => new Database(config);
Database.init = async (config) => {
const db = new Database(config);
// TODO: Create validations folder for this.
const links = getLinks({ db });
const errorList = [];
for (const { relation, invRelation } of links) {
// Generate the join table name based on the relation target
// table and attribute name.
const joinTableName = getJoinTableName(
db.metadata.get(relation.target).tableName,
relation.inversedBy
);
const contentType = db.metadata.get(invRelation.target);
const invContentType = db.metadata.get(relation.target);
// If both sides use inversedBy
// TODO: Same for mappedBy
if (relation.inversedBy && invRelation.inversedBy) {
// If the generated join table name is the same as the one assigned in relation.joinTable,
// relation is on the inversed side of the bidirectional relation.
// and the other is on the owner side.
if (joinTableName === relation.joinTable.name) {
errorList.push(
`Error on attribute "${invRelation.inversedBy}" in model "${invContentType.tableName}"(${invContentType.uid}):` +
` One of the sides of the relationship must be the owning side. You should use mappedBy` +
` instead of inversedBy in the relation "${invRelation.inversedBy}".`
);
} else {
errorList.push(
`Error on attribute "${relation.inversedBy}" in model "${contentType.tableName}"(${contentType.uid}):` +
` One of the sides of the relationship must be the owning side. You should use mappedBy` +
` instead of inversedBy in the relation "${relation.inversedBy}".`
);
}
}
}
if (errorList.length > 0) {
errorList.forEach((error) => strapi.log.error(error));
throw new Error('There are errors in some of your models. Please check the logs above.');
}
return db;
};
module.exports = {
Database,

View File

@ -16,6 +16,8 @@ const isAnyToMany = (attribute) => ['oneToMany', 'manyToMany'].includes(attribut
const isBidirectional = (attribute) => hasInversedBy(attribute) || hasMappedBy(attribute);
const isOwner = (attribute) => !isBidirectional(attribute) || hasInversedBy(attribute);
const shouldUseJoinTable = (attribute) => attribute.useJoinTable !== false;
const getJoinTableName = (tableName, attributeName) =>
_.snakeCase(`${tableName}_${attributeName}_links`);
/**
* Creates a oneToOne relation metadata
@ -397,7 +399,7 @@ const createJoinTable = (metadata, { attributeName, attribute, meta }) => {
throw new Error(`Unknown target ${attribute.target}`);
}
const joinTableName = _.snakeCase(`${meta.tableName}_${attributeName}_links`);
const joinTableName = getJoinTableName(meta.tableName, attributeName);
const joinColumnName = _.snakeCase(`${meta.singularName}_id`);
let inverseJoinColumnName = _.snakeCase(`${targetMeta.singularName}_id`);
@ -560,4 +562,5 @@ module.exports = {
isAnyToMany,
hasOrderColumn,
hasInverseOrderColumn,
getJoinTableName,
};