From 4411b6d5bdd7299d04feafbc35ac6c11929ef657 Mon Sep 17 00:00:00 2001 From: Richard Ward Date: Tue, 30 Dec 2025 22:12:59 +0000 Subject: [PATCH] code: tools,schema,codegen (2 files) --- tools/codegen/schema-cli.ts | 42 ++++++++++++++++++++++++++++++++ tools/codegen/schema-registry.ts | 25 +++++++++---------- 2 files changed, 54 insertions(+), 13 deletions(-) diff --git a/tools/codegen/schema-cli.ts b/tools/codegen/schema-cli.ts index 0128af6ce..7564f98cb 100644 --- a/tools/codegen/schema-cli.ts +++ b/tools/codegen/schema-cli.ts @@ -9,6 +9,7 @@ * reject - Reject a migration * generate - Generate Prisma fragment for approved migrations * status - Show overall migration status + * prefix - 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} Reject a migration ${colors.green}generate${colors.reset} Generate Prisma fragment ${colors.green}preview${colors.reset} Preview Prisma output for package + ${colors.green}prefix${colors.reset} [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 [entity]') + break + } + cmdPrefix(args[1], args[2]) + break default: log.error(`Unknown command: ${command}`) printUsage() diff --git a/tools/codegen/schema-registry.ts b/tools/codegen/schema-registry.ts index 985340e6b..f27f50c26 100644 --- a/tools/codegen/schema-registry.ts +++ b/tools/codegen/schema-registry.ts @@ -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,