# @memberjunction/generated-entities CodeGen-produced entity subclasses for MemberJunction. Contains auto-generated TypeScript classes with Zod schemas for every entity in the database, providing strongly-typed getters/setters, validation, and class registration. ## Overview This package contains entity subclasses that are generated and maintained by MemberJunction's code generation system. These entities map directly to database tables and views, providing type-safe access to your data while abstracting away the complexity of data access. ```mermaid graph TD A["CodeGen"] -->|generates| B["entity_subclasses.ts"] B --> C["Entity Class A
@RegisterClass"] B --> D["Entity Class B
@RegisterClass"] B --> E["Entity Class N
@RegisterClass"] F["Metadata.GetEntityObject()"] -->|class factory| C F -->|class factory| D F -->|class factory| E C --> G["Zod Schema
(Validation)"] C --> H["Typed Getters/Setters"] C --> I["Foreign Key Relations"] style A fill:#2d6a9f,stroke:#1a4971,color:#fff style B fill:#7c5295,stroke:#563a6b,color:#fff style C fill:#2d8659,stroke:#1a5c3a,color:#fff style D fill:#2d8659,stroke:#1a5c3a,color:#fff style E fill:#2d8659,stroke:#1a5c3a,color:#fff style F fill:#b8762f,stroke:#8a5722,color:#fff style G fill:#7c5295,stroke:#563a6b,color:#fff ``` Key features: - **Type-safe data access**: All entity properties are strongly typed to match database columns - **Generated code**: Automatically maintained by MemberJunction to stay in sync with database schema - **Schema validation**: Uses Zod for runtime validation of entity data - **Extensible**: Base classes for extending with custom business logic - **MemberJunction integration**: Works seamlessly with MemberJunction's data context and API - **ESBuild tree-shaking support**: Includes `LoadGeneratedEntities()` function to ensure proper bundling ## Installation This package is a private package used internally within MemberJunction applications: ```bash # Within the MemberJunction monorepo workspace npm install ``` Note: This package is marked as private (`"private": true`) in package.json and is not published to npm. ## Dependencies - `@memberjunction/core` (v2.43.0): Core MemberJunction functionality including BaseEntity - `@memberjunction/global` (v2.43.0): Global utilities and constants - `zod` (v3.23.8): Schema validation library ## Package Structure ``` mj_generatedentities/ ├── src/ │ ├── index.ts # Main export file │ ├── generated/ │ │ └── entity_subclasses.ts # Auto-generated entity classes │ └── demo/ │ └── demoContactEntitySubclass.ts # Example of extending entities ├── dist/ # Compiled JavaScript output ├── package.json ├── tsconfig.json └── README.md ``` ## Usage ### Important: MemberJunction Entity Creation Pattern **Never directly instantiate entity classes**. Always use the Metadata system to ensure proper class registration: ```typescript import { Metadata } from '@memberjunction/core'; // ❌ Wrong - bypasses MJ class system const entity = new UserEntity(); // ✅ Correct - uses MJ metadata system const md = new Metadata(); const entity = await md.GetEntityObject('Users'); ``` ### Loading Generated Entities for ESBuild To ensure generated entities are included in ESBuild builds (avoiding tree-shaking issues): ```typescript import { LoadGeneratedEntities } from 'mj_generatedentities'; // Call this function early in your application initialization LoadGeneratedEntities(); ``` ### Working with Entity Classes ```typescript import { Metadata, RunView } from '@memberjunction/core'; // Load a single entity by ID async function getUserById(userId: string): Promise { const md = new Metadata(); const user = await md.GetEntityObject('Users'); if (await user.Load(userId)) { return user; } return null; } // Load multiple entities with RunView async function getActiveUsers(): Promise { const rv = new RunView(); const result = await rv.RunView({ EntityName: 'Users', ExtraFilter: `IsActive = 1`, OrderBy: 'CreatedAt DESC', ResultType: 'entity_object' // Returns entity objects, not raw data }); return result.Results; } // Update an entity async function updateUser(userId: string, updates: Partial): Promise { const md = new Metadata(); const user = await md.GetEntityObject('Users'); if (await user.Load(userId)) { // Apply updates Object.assign(user, updates); // Save changes const result = await user.Save(); return result.Success; } return false; } ``` ### Entity Relationships ```typescript import { Metadata, RunView } from '@memberjunction/core'; async function getUserWithRoles(userId: string) { const md = new Metadata(); const user = await md.GetEntityObject('Users'); if (await user.Load(userId)) { // Load related entities using RunView const rv = new RunView(); const rolesResult = await rv.RunView({ EntityName: 'User Roles', ExtraFilter: `UserID = '${userId}'`, ResultType: 'entity_object' }); return { user, roles: rolesResult.Results }; } return null; } ``` ### Extending Generated Entities You can extend the generated entities with custom business logic. Use the `@RegisterClass` decorator to ensure proper registration: ```typescript import { RegisterClass } from '@memberjunction/global'; import { BaseEntity } from '@memberjunction/core'; // Example from demo/demoContactEntitySubclass.ts @RegisterClass(BaseEntity, 'Contacts', 1) export class ContactEntity extends ContactBaseEntity { // Override property getters/setters (must override both) get FirstName(): string { console.log("Getting FirstName from subclass"); return super.FirstName; } set FirstName(value: string) { super.FirstName = value; console.log("Setting FirstName from subclass"); } // Add custom methods async getFullName(): Promise { return `${this.FirstName} ${this.LastName}`; } // Add custom validation override async Validate(): Promise { const result = await super.Validate(); if (this.Email && !this.Email.includes('@')) { result.Success = false; result.Errors.push({ Source: 'Email', Message: 'Email must contain @ symbol', Type: ValidationErrorType.Failure }); } return result; } } ``` ### Important Notes on Extending Entities 1. **Always use `@RegisterClass` decorator** to register your subclass with MemberJunction 2. **When overriding property getters/setters**, you MUST override both getter and setter 3. **Call super methods** when overriding to maintain base functionality 4. **Version parameter** in `@RegisterClass` allows for entity versioning ### Zod Schema Validation Generated entities use Zod for schema validation: ```typescript import { z } from 'zod'; // Each generated entity includes a Zod schema const userSchema = z.object({ ID: z.string(), FirstName: z.string(), LastName: z.string(), Email: z.string().email(), IsActive: z.boolean(), CreatedAt: z.date(), UpdatedAt: z.date() }); // Validate data before creating entities async function createUserFromData(userData: unknown) { const result = userSchema.safeParse(userData); if (result.success) { const md = new Metadata(); const user = await md.GetEntityObject('Users'); await user.LoadFromData(result.data); const saveResult = await user.Save(); return saveResult.Success; } else { console.error('Validation errors:', result.error.format()); return false; } } ``` ## Entity Base Class Methods All generated entities inherit from `BaseEntity` and provide these key methods: | Method | Description | |--------|-------------| | `Load(id: CompositeKey)` | Loads an entity by its primary key | | `LoadFromData(data: any)` | Populates entity from a data object | | `Save(options?: EntitySaveOptions)` | Saves changes to the database | | `Delete()` | Deletes the entity from the database | | `Validate()` | Validates the entity, returns ValidationResult | | `GetFieldValue(fieldName: string)` | Gets the value of a specific field | | `SetFieldValue(fieldName: string, value: any)` | Sets the value of a specific field | | `TransactionMode` | Property to control transaction behavior | ## Build Scripts ```bash # Build the package npm run build # Development mode with auto-reload npm run start # Run tests (not implemented yet) npm test ``` ## Code Generation This package is automatically maintained by MemberJunction's code generation system. The `entity_subclasses.ts` file is generated based on your database schema. **Important**: Do not manually edit files in the `generated/` directory as they will be overwritten during the next code generation cycle. To regenerate entities: 1. Ensure your database schema is up to date 2. Run the MemberJunction code generation tool from the appropriate package 3. The generated files will be automatically updated ## Development Notes - The package includes TypeScript declaration files (`*.d.ts`) in the dist folder - Source maps are generated for debugging - The `loadModule` export in entity_subclasses.ts ensures the module is valid even when empty - Use the demo file as a reference for creating custom entity subclasses ## License ISC