# Entity Metadata System

# Entity Metadata System

<details>
<summary>Relevant source files</summary>

The following files were used as context for generating this wiki page:

- [src/meta/entity-decorators.ts](src/meta/entity-decorators.ts)
- [src/meta/entity-meta.ts](src/meta/entity-meta.ts)
- [src/meta/entity-ts-to-pg.ts](src/meta/entity-ts-to-pg.ts)

</details>



The Entity Metadata System is the foundational layer of the `@primebrick/dal-pg` package. It uses TypeScript decorators and the `reflect-metadata` API to bridge the gap between JavaScript class definitions and PostgreSQL relational structures [src/meta/entity-decorators.ts:1-23]().

The system is designed with a "convention over configuration" philosophy: every own enumerable property of an entity class is implicitly treated as a database column unless explicitly excluded [src/meta/entity-decorators.ts:11-13]().

## Metadata Storage and Retrieval

Metadata is stored using a `WeakMap` where the keys are the class constructors (functions) and the values are `ClassEntityMeta` objects [src/meta/entity-decorators.ts:106-115](). This ensures that metadata does not leak memory and is scoped strictly to the entity classes.

### Core Metadata Functions

| Function | Purpose |
| :--- | :--- |
| `ensureMeta(ctor)` | Retrieves or initializes the `ClassEntityMeta` for a given class [src/meta/entity-decorators.ts:108-115](). |
| `touchColumn(ctor, key)` | Ensures a `ColumnRegistration` exists for a specific property, defaulting the `sqlName` to the property name [src/meta/entity-decorators.ts:117-125](). |
| `syncImplicitEntityColumns(ctor)` | Discovers all instance properties and applies type inference to those not explicitly decorated [src/meta/entity-decorators.ts:134-155](). |
| `getEntityPersistenceMeta(ctor)` | The primary public API to retrieve the complete, resolved metadata for an entity [src/meta/entity-meta.ts:24](). |

### Metadata Data Flow
The following diagram illustrates how a class definition is transformed into a persistence metadata object used by the Repository.

**Entity Metadata Extraction Flow**
```mermaid
graph TD
    classDef["@Entity Class Definition"] --> decorator["Decorators (@Column, @Key, etc.)"]
    decorator --> ensureMeta["ensureMeta(ctor)"]
    ensureMeta --> weakMap["WeakMap Storage"]
    
    subgraph "Inference Pipeline"
        sync["syncImplicitEntityColumns(ctor)"]
        discover["discoverInstancePropertyKeys(ctor)"]
        reflect["Reflect.getMetadata('design:type')"]
        infer["inferPgTypeFromEntityColumn"]
    end
    
    weakMap --> sync
    sync --> discover
    sync --> reflect
    reflect --> infer
    
    infer --> finalMeta["EntityPersistenceMeta"]
    finalMeta --> repo["Repository / Query Builder"]
```
Sources: [src/meta/entity-decorators.ts:106-155](), [src/meta/entity-ts-to-pg.ts:137-143]()

## Decorator API

The DAL provides a rich set of decorators to define table structure and behavior.

### Table and Column Definition
*   `@Entity(tableName?, schema?)`: Maps a class to a table. If `tableName` is omitted, it defaults to the class name [src/meta/entity-decorators.ts:161-168]().
*   `@Column(opts)`: Overrides default naming or type inference. Required only for specifying `pgType`, `length`, `precision`, or `nullable` [src/meta/entity-decorators.ts:188-204]().
*   `@Key(opts?)`: Marks a property as the Primary Key. Supports `identity` (default) or `manual` generation [src/meta/entity-decorators.ts:223-231]().
*   `@Unique()`: Marks a column as having a unique constraint [src/meta/entity-decorators.ts:234-239]().
*   `@IsNotColumn()`: Explicitly excludes a property from persistence [src/meta/entity-decorators.ts:242-247]().

### Specialized Field Decorators
These decorators mark fields for internal DAL subsystems like Audit and Soft-Delete.

*   `@AuditableField(type)`: Links a property to `CREATED_AT`, `CREATED_BY`, `UPDATED_AT`, `UPDATED_BY`, or `VERSION` [src/meta/entity-decorators.ts:250-258]().
*   `@DeletableField(type)`: Links a property to `DELETED_AT` or `DELETED_BY` for soft-delete logic [src/meta/entity-decorators.ts:265-273]().
*   `@SynchronizableField(type)`: Marks fields for sync tracking, e.g., `LAST_SYNCED_AT` [src/meta/entity-decorators.ts:280-288]().
*   `@CloneField()`: Marks a field for tracking the source of a cloned record [src/meta/entity-decorators.ts:295-300]().
*   `@AuditTrail()`: Indicates that the entity has a corresponding audit trail table [src/meta/entity-decorators.ts:303-308]().

Sources: [src/meta/entity-decorators.ts:161-308](), [src/meta/entity-meta.ts:4-17]()

## Type Inference Pipeline

The `entity-ts-to-pg.ts` module handles the mapping from TypeScript types and naming heuristics to PostgreSQL base types. This is critical when `emitDecoratorMetadata` is active or when developers rely on naming conventions.

### Inference Logic
1.  **Explicit Type**: If `@Column({ pgType: '...' })` is used, it always wins [src/meta/entity-ts-to-pg.ts:139]().
2.  **Design Type**: Uses `design:type` metadata (e.g., `Number` → `integer`, `Date` → `timestamptz`) [src/meta/entity-ts-to-pg.ts:92-118]().
3.  **Naming Heuristics**: If types are ambiguous (like `Object` in some transpilation setups), it looks at the property name:
    *   Ends in `_at` or `_on` → `timestamptz` [src/meta/entity-ts-to-pg.ts:76-85]().
    *   Named `uuid` → `uuid` [src/meta/entity-ts-to-pg.ts:64-66]().
    *   Named `id` and is a Key → `bigint` [src/meta/entity-ts-to-pg.ts:67-69]().

### Type Modifiers
The system applies modifiers for length, precision, and scale. For example, `text` with `length: 20` becomes `varchar(20)` [src/meta/entity-ts-to-pg.ts:25-58]().

**TS to PG Type Mapping Matrix**
| TS Property / Type | Heuristic / Meta | PG Type |
| :--- | :--- | :--- |
| `id: number` | `@Key()` | `bigint` |
| `version: number` | Name match | `integer` |
| `createdAt: Date` | Name `*_at` | `timestamptz` |
| `bio: string` | Default | `text` |
| `price: number` | `precision: 10, scale: 2` | `numeric(10,2)` |

Sources: [src/meta/entity-ts-to-pg.ts:60-143]()

## System Interaction Diagram

This diagram shows how the metadata system connects the high-level TypeScript Entity definitions to the low-level PostgreSQL requirements.

**Metadata Pipeline: TS Space to PG Space**
```mermaid
graph LR
    subgraph "TypeScript Space (Natural Language)"
        Class["class UserEntity"]
        Prop["@Column() email: string"]
        PK["@Key() id: number"]
    end

    subgraph "Code Entity Space (Metadata)"
        sync["syncImplicitEntityColumns"]
        infer["inferPgTypeFromEntityColumn"]
        MetaObj["EntityPersistenceMeta"]
    end

    subgraph "PostgreSQL Space"
        Table["TABLE users"]
        Col1["email TEXT NOT NULL"]
        Col2["id BIGINT PRIMARY KEY"]
    end

    Class -- "reflects" --> sync
    Prop -- "extracts" --> MetaObj
    PK -- "extracts" --> MetaObj
    MetaObj -- "informs" --> infer
    infer -- "generates SQL for" --> Table
    MetaObj -- "maps to" --> Col1
    MetaObj -- "maps to" --> Col2
```
Sources: [src/meta/entity-decorators.ts:134-155](), [src/meta/entity-ts-to-pg.ts:137-143](), [src/meta/entity-meta.ts:24-30]()

---
