@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
Section titled “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.
graph TD
A["CodeGen"] -->|generates| B["entity_subclasses.ts"]
B --> C["Entity Class A<br/>@RegisterClass"]
B --> D["Entity Class B<br/>@RegisterClass"]
B --> E["Entity Class N<br/>@RegisterClass"]
F["Metadata.GetEntityObject()"] -->|class factory| C
F -->|class factory| D
F -->|class factory| E
C --> G["Zod Schema<br/>(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
Section titled “Installation”This package is a private package used internally within MemberJunction applications:
# Within the MemberJunction monorepo workspacenpm installNote: This package is marked as private ("private": true) in package.json and is not published to npm.
Dependencies
Section titled “Dependencies”@memberjunction/core(v2.43.0): Core MemberJunction functionality including BaseEntity@memberjunction/global(v2.43.0): Global utilities and constantszod(v3.23.8): Schema validation library
Package Structure
Section titled “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.mdImportant: MemberJunction Entity Creation Pattern
Section titled “Important: MemberJunction Entity Creation Pattern”Never directly instantiate entity classes. Always use the Metadata system to ensure proper class registration:
import { Metadata } from '@memberjunction/core';
// ❌ Wrong - bypasses MJ class systemconst entity = new UserEntity();
// ✅ Correct - uses MJ metadata systemconst md = new Metadata();const entity = await md.GetEntityObject<UserEntity>('Users');Loading Generated Entities for ESBuild
Section titled “Loading Generated Entities for ESBuild”To ensure generated entities are included in ESBuild builds (avoiding tree-shaking issues):
import { LoadGeneratedEntities } from 'mj_generatedentities';
// Call this function early in your application initializationLoadGeneratedEntities();Working with Entity Classes
Section titled “Working with Entity Classes”import { Metadata, RunView } from '@memberjunction/core';
// Load a single entity by IDasync function getUserById(userId: string): Promise<UserEntity | null> { const md = new Metadata(); const user = await md.GetEntityObject<UserEntity>('Users');
if (await user.Load(userId)) { return user; } return null;}
// Load multiple entities with RunViewasync function getActiveUsers(): Promise<UserEntity[]> { const rv = new RunView(); const result = await rv.RunView<UserEntity>({ EntityName: 'Users', ExtraFilter: `IsActive = 1`, OrderBy: 'CreatedAt DESC', ResultType: 'entity_object' // Returns entity objects, not raw data });
return result.Results;}
// Update an entityasync function updateUser(userId: string, updates: Partial<UserEntity>): Promise<boolean> { const md = new Metadata(); const user = await md.GetEntityObject<UserEntity>('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
Section titled “Entity Relationships”import { Metadata, RunView } from '@memberjunction/core';
async function getUserWithRoles(userId: string) { const md = new Metadata(); const user = await md.GetEntityObject<UserEntity>('Users');
if (await user.Load(userId)) { // Load related entities using RunView const rv = new RunView(); const rolesResult = await rv.RunView<RoleEntity>({ EntityName: 'User Roles', ExtraFilter: `UserID = '${userId}'`, ResultType: 'entity_object' });
return { user, roles: rolesResult.Results }; }
return null;}Extending Generated Entities
Section titled “Extending Generated Entities”You can extend the generated entities with custom business logic. Use the @RegisterClass decorator to ensure proper registration:
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<string> { return `${this.FirstName} ${this.LastName}`; }
// Add custom validation override async Validate(): Promise<ValidationResult> { 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
Section titled “Important Notes on Extending Entities”- Always use
@RegisterClassdecorator to register your subclass with MemberJunction - When overriding property getters/setters, you MUST override both getter and setter
- Call super methods when overriding to maintain base functionality
- Version parameter in
@RegisterClassallows for entity versioning
Zod Schema Validation
Section titled “Zod Schema Validation”Generated entities use Zod for schema validation:
import { z } from 'zod';
// Each generated entity includes a Zod schemaconst 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 entitiesasync function createUserFromData(userData: unknown) { const result = userSchema.safeParse(userData);
if (result.success) { const md = new Metadata(); const user = await md.GetEntityObject<UserEntity>('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
Section titled “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
Section titled “Build Scripts”# Build the packagenpm run build
# Development mode with auto-reloadnpm run start
# Run tests (not implemented yet)npm testCode Generation
Section titled “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:
- Ensure your database schema is up to date
- Run the MemberJunction code generation tool from the appropriate package
- The generated files will be automatically updated
Development Notes
Section titled “Development Notes”- The package includes TypeScript declaration files (
*.d.ts) in the dist folder - Source maps are generated for debugging
- The
loadModuleexport 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
Section titled “License”ISC