kanel import name conflict when different schemas contain tables with the same name
aq1018 opened this issue · 1 comments
aq1018 commented
I'm currently using multiple schemas as namespaces.
For example, I have the following database design:
- In
term_life
schema, I have aproduct
table. - In
income_protection
schema, I have aproduct
table as well, but with different columns. - In
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
- Only one of them can be populated.
The generated code looked like this:
import type { ProductId } from '../term_life/Product';
import type { ProductId } from '../income_protection/Product';
export default interface InsuranceApplicationTable {
// ... other columns
termLifeProductId: ColumnType<ProductId | null, ProductId | null, ProductId | null>;
incomeProtectionProductId: ColumnType<ProductId | null, ProductId | null, ProductId | null>;
}
I made a preRenderHook
to fix this, but it's a bit hacky:
function uniqueIdentifierImport(output) {
for (const path in output) {
const { declarations } = output[path]
declarations.forEach((declaration) => {
const { declarationType, properties } = declaration
if (declarationType !== 'interface') return
const importMap = {}
// build import map with import name as the key,
// and an array of (property idex, typeImport index) tuples as the value
properties.forEach((property, propertyIndex) => {
if (!property.typeImports) return
property.typeImports.forEach((typeImport, typeImportIndex) => {
importMap[typeImport.name] ??= []
importMap[typeImport.name].push([propertyIndex, typeImportIndex])
})
})
Object.values(importMap).forEach((locations) => {
// skip if no duplicates
if (locations.length < 2) return
locations.forEach(([propertyIndex, typeImportIndex]) => {
const property = properties[propertyIndex]
const typeImport = property.typeImports[typeImportIndex]
const pathSegments = typeImport.path.split('/')
// extract schema name based on import path info
// this is hacky, but I don't have a better way...
const schema = pascalCase(pathSegments[pathSegments.length - 2])
// update import name
const oldImportName = typeImport.name
const newImportName = `${schema}${oldImportName}`
typeImport.name = `${oldImportName} as ${newImportName}`
// update property type name
property.typeName = property.typeName.replaceAll(
oldImportName,
newImportName,
)
})
})
})
}
return output
}
I'm not sure what the best solution entails, but the generated code should not create conflicting imports.
kristiandupont commented
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 :-)