Files
metabuilder/docs/packages/entity-prefixing.md
2025-12-30 22:21:40 +00:00

4.7 KiB

Entity Prefixing for Package Database Operations

Overview

To prevent entity name collisions between packages in the generated Prisma schema, MetaBuilder uses a standardized entity prefixing system. When schemas are generated from package YAML definitions, entity names are automatically prefixed.

Prefix Format

Component Format Example
Entity Name Pkg_{PascalPackage}_{EntityName} Pkg_ForumForge_ForumPost
Table Name {package_id}_{lowercaseentity} forum_forge_forumpost

Examples

Package Entity Prefixed Entity Table Mapping
forum_forge ForumCategory Pkg_ForumForge_ForumCategory forum_forge_forumcategory
forum_forge ForumThread Pkg_ForumForge_ForumThread forum_forge_forumthread
social_hub SocialProfile Pkg_SocialHub_SocialProfile social_hub_socialprofile
github_tools GitHubRepository Pkg_GithubTools_GitHubRepository github_tools_githubrepository

TypeScript (Schema Generation)

The prefixing is handled automatically during schema generation by tools/codegen/schema-registry.ts:

import { getPrefixedEntityName, entityToPrisma } from './schema-registry'

// Get prefixed name
const prefixed = getPrefixedEntityName('forum_forge', 'ForumPost')
// => 'Pkg_ForumForge_ForumPost'

// Generate Prisma model with prefix
const prismaModel = entityToPrisma(schemaEntity, 'forum_forge')

CLI Commands

# Show prefixed entity names for a package
npx tsx tools/codegen/schema-cli.ts prefix forum_forge

# Preview generated Prisma models with prefixes
npx tsx tools/codegen/schema-cli.ts preview forum_forge

Lua (Runtime Operations)

For Lua DB operations, use the shared prefix module:

Simple Usage

local prefix = require('shared.db.prefix')

-- Package ID for entity prefixing
local PACKAGE_ID = 'forum_forge'

-- Helper function
local function entity(name)
  return prefix.getPrefixedName(PACKAGE_ID, name)
end

-- Use in DBAL calls
function M.createPost(dbal, params)
  return dbal:create(entity('ForumPost'), {
    tenantId = params.tenantId,
    content = params.content,
    -- ...
  })
end

function M.listPosts(dbal, threadId)
  return dbal:list(entity('ForumPost'), {
    where = { threadId = threadId },
  })
end

Wrapper-Based Usage

For simpler code, use the wrapper that auto-prefixes all entity names:

local prefix = require('shared.db.prefix')

-- Create a wrapped DBAL instance
local db = prefix.createPackageDb(dbal, 'forum_forge')

-- All calls automatically prefix entity names
function M.createPost(params)
  return db:create('ForumPost', {  -- Automatically becomes 'Pkg_ForumForge_ForumPost'
    tenantId = params.tenantId,
    content = params.content,
  })
end

Schema YAML Files

Schema YAML files in packages/{name}/seed/schema/*.yaml use unprefixed entity names. The prefixing is applied during generation:

# packages/forum_forge/seed/schema/forum.yaml
entities:
  ForumPost:        # Unprefixed in YAML
    fields:
      id:
        type: String
        primaryKey: true
      content:
        type: String
      threadId:
        type: String
    relations:
      thread:
        kind: belongsTo
        target: ForumThread  # Also unprefixed - same-package targets auto-resolve
        foreignKey: threadId

When generated:

  • Entity becomes Pkg_ForumForge_ForumPost
  • Relation target becomes Pkg_ForumForge_ForumThread
  • Table mapping is @@map("forum_forge_forumpost")

Cross-Package Relations

For relations to entities in other packages, use the full prefixed name:

# packages/social_hub/seed/schema/social.yaml
entities:
  SocialProfile:
    relations:
      user:
        kind: belongsTo
        target: User        # Core entity (no prefix)
        foreignKey: userId

Implementation Files

File Purpose
tools/codegen/schema-registry.ts TypeScript prefix functions
tools/codegen/schema-cli.ts CLI commands including prefix
packages/shared/seed/scripts/db/prefix.lua Lua prefix helper module

Benefits

  1. No Collisions: Two packages can have entities named Config without conflict
  2. Clear Ownership: Prefixed names immediately show which package owns an entity
  3. Database Isolation: Table names are namespaced by package
  4. Simple Code: Lua helper means package code uses simple names internally