code: tools,schema,codegen (2 files)

This commit is contained in:
Richard Ward
2025-12-30 22:12:59 +00:00
parent 9e8736cc88
commit 4411b6d5bd
2 changed files with 54 additions and 13 deletions

View File

@@ -9,6 +9,7 @@
* reject <id> - Reject a migration
* generate - Generate Prisma fragment for approved migrations
* status - Show overall migration status
* prefix <pkg> <entity> - Show prefixed entity name
*/
import * as path from 'path'
@@ -25,6 +26,10 @@ import {
loadPackageSchema,
computeSchemaChecksum,
entityToPrisma,
getPrefixedEntityName,
packageToPascalCase,
extractPackageFromPrefix,
extractEntityFromPrefix,
type SchemaRegistry,
} from './schema-registry'
@@ -63,12 +68,14 @@ Commands:
${colors.green}reject${colors.reset} <id> Reject a migration
${colors.green}generate${colors.reset} Generate Prisma fragment
${colors.green}preview${colors.reset} <pkg> Preview Prisma output for package
${colors.green}prefix${colors.reset} <pkg> [entity] Show prefixed entity name
${colors.green}status${colors.reset} Show migration status
Examples:
npx ts-node tools/codegen/schema-cli.ts scan
npx ts-node tools/codegen/schema-cli.ts approve all
npx ts-node tools/codegen/schema-cli.ts preview audit_log
npx ts-node tools/codegen/schema-cli.ts prefix forum_forge Post
`)
}
@@ -258,6 +265,33 @@ const cmdStatus = (registry: SchemaRegistry): void => {
}
}
const cmdPrefix = (packageId: string, entityName?: string): void => {
console.log(`\n${colors.cyan}Entity Prefix Info${colors.reset}\n`)
console.log(`Package: ${packageId}`)
console.log(`Pascal Case: ${packageToPascalCase(packageId)}`)
console.log(`Prefix: Pkg_${packageToPascalCase(packageId)}_`)
if (entityName) {
const prefixed = getPrefixedEntityName(packageId, entityName)
console.log(`\n${colors.green}Entity:${colors.reset} ${entityName}`)
console.log(`${colors.green}Prefixed:${colors.reset} ${prefixed}`)
console.log(`${colors.green}Table:${colors.reset} ${packageId}_${entityName.toLowerCase()}`)
} else {
// Show all entities from package schema
const pkgPath = path.join(PACKAGES_PATH, packageId)
const schema = loadPackageSchema(pkgPath)
if (schema && schema.entities) {
console.log(`\n${colors.yellow}Entities in package:${colors.reset}`)
for (const entity of schema.entities) {
const prefixed = getPrefixedEntityName(packageId, entity.name)
console.log(` ${entity.name}${prefixed}`)
console.log(` ${colors.dim}Table: ${packageId}_${entity.name.toLowerCase()}${colors.reset}`)
}
}
}
console.log('')
}
// Main
const main = (): void => {
const args = process.argv.slice(2)
@@ -321,6 +355,14 @@ const main = (): void => {
case 'status':
cmdStatus(registry)
break
case 'prefix':
if (!args[1]) {
log.error('Package name required')
log.info('Usage: prefix <package> [entity]')
break
}
cmdPrefix(args[1], args[2])
break
default:
log.error(`Unknown command: ${command}`)
printUsage()

View File

@@ -362,6 +362,7 @@ export const loadPackageSchema = (packagePath: string): PackageSchema | null =>
/**
* Validate and queue schema changes for a package
* Uses prefixed entity names to prevent cross-package collisions
*/
export const validateAndQueueSchema = (
packageId: string,
@@ -377,30 +378,28 @@ export const validateAndQueueSchema = (
}
for (const entity of schema.entities) {
// Use prefixed entity name to avoid collisions
const prefixedName = getPrefixedEntityName(packageId, entity.name)
const newChecksum = computeSchemaChecksum(entity)
const existing = registry.entities[entity.name]
const existing = registry.entities[prefixedName]
// Check for conflicts with other packages
// Check for conflicts - with prefixes, only same package can conflict
if (existing && existing.ownerPackage !== packageId) {
if (existing.checksum !== newChecksum) {
errors.push(
`Entity "${entity.name}" owned by "${existing.ownerPackage}" has different schema. ` +
`Current: ${existing.checksum}, Proposed: ${newChecksum}. ` +
`Packages must use identical schema or coordinate versions.`
)
continue
}
// Same checksum = compatible, skip
// This should be rare with prefixes, but check anyway
errors.push(
`Entity "${prefixedName}" owned by "${existing.ownerPackage}" conflicts. ` +
`This is unexpected with prefixes - please report this bug.`
)
continue
}
// New entity or updated schema
if (!existing || existing.checksum !== newChecksum) {
const prismaPreview = entityToPrisma(entity)
const prismaPreview = entityToPrisma(entity, packageId)
const item: MigrationQueueItem = {
id: crypto.randomUUID(),
packageId,
entityName: entity.name,
entityName: prefixedName, // Store prefixed name
action: existing ? 'alter' : 'create',
currentChecksum: existing?.checksum || null,
newChecksum,