-
-
Notifications
You must be signed in to change notification settings - Fork 62
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
kanel import name conflict when different schemas contain tables with the same name #589
Comments
Yeah, I expected that I would run into this sooner or later. The quick solution would probably be to support adding schema names as a prefix to model names, but I think few people would like that. The more correct solution would be that it intelligently detects the name clash and does something like import type { ProductId as TermLifeProductId } from '../term_life/Product';
import type { ProductId as IncomeProtectionProductId } from '../income_protection/Product'; This should be possible but it's obviously not completely trivial. I will ponder this :-) |
here's my workaround thanks to the awesome postRenderHook config and gpt const path = require("path")
/**
* Post-render hook to resolve duplicate imports by renaming conflicting identifiers with schema-based aliases.
* @param {string} filePath - The file path.
* @param {string[]} lines - The content lines of the file.
* @param {object} instantiatedConfig - The instantiated configuration object.
* @returns {Promise<string[]>} - The modified lines with resolved naming conflicts.
*/
async function resolveDuplicateImports(filePath, lines, instantiatedConfig) {
// Collect import statements
const imports = [];
const importRegex = /^import type { (\w+) } from ['"](.+)['"];$/;
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
const match = line.match(importRegex);
if (match) {
const [_, importedIdentifier, modulePath] = match;
imports.push({ lineIndex: i, importedIdentifier, modulePath });
}
}
// Build a mapping of imported identifiers to their module paths
const importMap = {};
for (const imp of imports) {
const { importedIdentifier, modulePath } = imp;
if (!importMap[importedIdentifier]) {
importMap[importedIdentifier] = [];
}
importMap[importedIdentifier].push(modulePath);
}
// Identify duplicate imports
const duplicates = {};
for (const importedIdentifier in importMap) {
const modulePaths = importMap[importedIdentifier];
if (modulePaths.length > 1) {
duplicates[importedIdentifier] = modulePaths;
}
}
if (Object.keys(duplicates).length === 0) {
// No duplicates, return lines as is
return lines;
}
// Generate aliases for duplicate imports
const aliases = {}; // key: importedIdentifier + '|' + modulePath, value: alias
const schemaToAlias = {}; // key: importedIdentifier, value: { schemaName: alias }
for (const importedIdentifier in duplicates) {
schemaToAlias[importedIdentifier] = {};
const modulePaths = duplicates[importedIdentifier];
for (const modulePath of modulePaths) {
// Resolve the absolute module path
const absoluteModulePath = path.resolve(path.dirname(filePath), modulePath);
// Extract the schema name
const schemaName = getSchemaNameFromModulePath(absoluteModulePath);
// Generate alias
const alias = importedIdentifier + capitalize(schemaName);
aliases[importedIdentifier + '|' + modulePath] = alias;
schemaToAlias[importedIdentifier][schemaName] = alias;
}
}
// Update import statements to include aliases
for (const imp of imports) {
const { lineIndex, importedIdentifier, modulePath } = imp;
if (duplicates[importedIdentifier]) {
const alias = aliases[importedIdentifier + '|' + modulePath];
lines[lineIndex] = `import type { ${importedIdentifier} as ${alias} } from '${modulePath}';`;
}
}
// Function to capitalize the first letter
function capitalize(str) {
if (!str) return str;
return str.charAt(0).toUpperCase() + str.slice(1);
}
// Function to get schema name from module path
function getSchemaNameFromModulePath(absoluteModulePath) {
const pathSegments = absoluteModulePath.split(path.sep);
const modelsIndex = pathSegments.lastIndexOf('models');
if (modelsIndex >= 0 && modelsIndex + 1 < pathSegments.length) {
const schemaName = pathSegments[modelsIndex + 1];
return schemaName;
}
return null;
}
// Function to get schema name from property name
function getSchemaNameFromPropertyName(propertyName) {
const prefix = propertyName.split('_')[0];
return prefix;
}
// Update the rest of the code to use aliases
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
// Skip import lines
if (line.startsWith('import')) continue;
// Match property definitions
const propertyMatch = line.match(/^\s*(\w+):\s*ColumnType<(.+)>;$/);
if (propertyMatch) {
const propertyName = propertyMatch[1];
const columnTypeContent = propertyMatch[2];
const types = columnTypeContent.split(',').map(t => t.trim());
const updatedTypes = types.map(type => {
if (duplicates[type]) {
// Determine schema name from property name
const schemaName = getSchemaNameFromPropertyName(propertyName);
const alias = schemaToAlias[type][schemaName];
if (alias) {
return alias;
} else {
// Could not find alias for schema, default to original type
return type;
}
} else {
return type;
}
});
// Reconstruct the line
const updatedColumnTypeContent = updatedTypes.join(', ');
lines[i] = ` ${propertyName}: ColumnType<${updatedColumnTypeContent}>;`;
}
}
return lines;
}
module.exports = {
importsExtension: ".js",
postRenderHooks: [resolveDuplicateImports],
}; |
I'm currently using multiple schemas as namespaces.
For example, I have the following database design:
term_life
schema, I have aproduct
table.income_protection
schema, I have aproduct
table as well, but with different columns.public
schema, I have ainsurance_application
table that contains foreign keys referencing both products.term_life_product_id
referencingterm_life.product.id
.income_protection_product_id
referencingincome_protection.prodcut.id
The generated code looked like this:
I made a
preRenderHook
to fix this, but it's a bit hacky:I'm not sure what the best solution entails, but the generated code should not create conflicting imports.
The text was updated successfully, but these errors were encountered: