{"version":3,"file":"bidirectional.mjs","sources":["../../../src/validations/relations/bidirectional.ts"],"sourcesContent":["import { snakeCase } from 'lodash/fp';\nimport type { Database } from '../..';\nimport type { Relation } from '../../types';\nimport { identifiers } from '../../utils/identifiers';\n\ntype Link = {\n relation: Relation.Bidirectional & { inversedBy: string };\n invRelation: Relation.Bidirectional & { inversedBy: string };\n};\n\nconst getLinksWithoutMappedBy = (db: Database): Array => {\n const relationsToUpdate: Record = {};\n\n db.metadata.forEach((modelMetadata) => {\n const attributes = modelMetadata.attributes;\n\n // For each relation attribute, add the joinTable name to tablesToUpdate\n Object.values(attributes).forEach((attribute) => {\n if (attribute.type !== 'relation') {\n return;\n }\n\n if ('inversedBy' in attribute && attribute.inversedBy) {\n const invRelation = db.metadata.get(attribute.target).attributes[attribute.inversedBy];\n\n // Both relations use inversedBy.\n if ('inversedBy' in invRelation && invRelation.inversedBy) {\n relationsToUpdate[attribute.joinTable.name] = {\n relation: attribute as Relation.Bidirectional & { inversedBy: string },\n invRelation: invRelation as Relation.Bidirectional & { inversedBy: string },\n };\n }\n }\n });\n });\n\n return Object.values(relationsToUpdate);\n};\n\nconst isLinkTableEmpty = async (db: Database, linkTableName: string) => {\n // If the table doesn't exist, it's empty\n const exists = await db.getSchemaConnection().hasTable(linkTableName);\n if (!exists) return true;\n\n const result = await db.getConnection().from(linkTableName).count('* as count');\n return Number(result[0].count) === 0;\n};\n\n/**\n * Validates bidirectional relations before starting the server.\n * - If both sides use inversedBy, one of the sides must switch to mappedBy.\n * When this happens, two join tables exist in the database.\n * This makes sure you switch the side which does not delete any data.\n *\n * @param {*} db\n * @return {*}\n */\nexport const validateBidirectionalRelations = async (db: Database) => {\n const invalidLinks = getLinksWithoutMappedBy(db);\n\n for (const { relation, invRelation } of invalidLinks) {\n const modelMetadata = db.metadata.get(invRelation.target);\n const invModelMetadata = db.metadata.get(relation.target);\n\n // Generate the join table name based on the relation target table and attribute name.\n const joinTableName = identifiers.getJoinTableName(\n snakeCase(modelMetadata.tableName),\n snakeCase(invRelation.inversedBy)\n );\n const inverseJoinTableName = identifiers.getJoinTableName(\n snakeCase(invModelMetadata.tableName),\n snakeCase(relation.inversedBy)\n );\n\n const joinTableEmpty = await isLinkTableEmpty(db, joinTableName);\n const inverseJoinTableEmpty = await isLinkTableEmpty(db, inverseJoinTableName);\n\n if (joinTableEmpty) {\n process.emitWarning(\n `Error on attribute \"${invRelation.inversedBy}\" in model \"${modelMetadata.singularName}\" (${modelMetadata.uid}).` +\n ` Please modify your ${modelMetadata.singularName} schema by renaming the key \"inversedBy\" to \"mappedBy\".` +\n ` Ex: { \"inversedBy\": \"${relation.inversedBy}\" } -> { \"mappedBy\": \"${relation.inversedBy}\" }`\n );\n } else if (inverseJoinTableEmpty) {\n // Its safe to delete the inverse join table\n process.emitWarning(\n `Error on attribute \"${relation.inversedBy}\" in model \"${invModelMetadata.singularName}\" (${invModelMetadata.uid}).` +\n ` Please modify your ${invModelMetadata.singularName} schema by renaming the key \"inversedBy\" to \"mappedBy\".` +\n ` Ex: { \"inversedBy\": \"${invRelation.inversedBy}\" } -> { \"mappedBy\": \"${invRelation.inversedBy}\" }`\n );\n } else {\n // Both sides have data in the join table\n }\n }\n};\n"],"names":["getLinksWithoutMappedBy","db","relationsToUpdate","metadata","forEach","modelMetadata","attributes","Object","values","attribute","type","inversedBy","invRelation","get","target","joinTable","name","relation","isLinkTableEmpty","linkTableName","exists","getSchemaConnection","hasTable","result","getConnection","from","count","Number","validateBidirectionalRelations","invalidLinks","invModelMetadata","joinTableName","identifiers","getJoinTableName","snakeCase","tableName","inverseJoinTableName","joinTableEmpty","inverseJoinTableEmpty","process","emitWarning","singularName","uid"],"mappings":"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"}