@mj-biz-apps/common-entities 5.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +289 -0
- package/dist/demo/demoContactEntitySubclass.d.ts +11 -0
- package/dist/demo/demoContactEntitySubclass.d.ts.map +1 -0
- package/dist/demo/demoContactEntitySubclass.js +35 -0
- package/dist/demo/demoContactEntitySubclass.js.map +1 -0
- package/dist/generated/entity_subclasses.d.ts +1965 -0
- package/dist/generated/entity_subclasses.d.ts.map +1 -0
- package/dist/generated/entity_subclasses.js +2834 -0
- package/dist/generated/entity_subclasses.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/package.json +34 -0
package/README.md
ADDED
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
# MemberJunction Generated Entities
|
|
2
|
+
|
|
3
|
+
This package contains automatically generated TypeScript entity classes that provide strongly-typed representations of database tables in the MemberJunction ecosystem.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
`mj_generatedentities` 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.
|
|
8
|
+
|
|
9
|
+
Key features:
|
|
10
|
+
- **Type-safe data access**: All entity properties are strongly typed to match database columns
|
|
11
|
+
- **Generated code**: Automatically maintained by MemberJunction to stay in sync with database schema
|
|
12
|
+
- **Schema validation**: Uses Zod for runtime validation of entity data
|
|
13
|
+
- **Extensible**: Base classes for extending with custom business logic
|
|
14
|
+
- **MemberJunction integration**: Works seamlessly with MemberJunction's data context and API
|
|
15
|
+
- **Webpack tree-shaking support**: Includes `LoadGeneratedEntities()` function to ensure proper bundling
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
This package is a private package used internally within MemberJunction applications:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
# Within the MemberJunction monorepo workspace
|
|
23
|
+
npm install
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Note: This package is marked as private (`"private": true`) in package.json and is not published to npm.
|
|
27
|
+
|
|
28
|
+
## Dependencies
|
|
29
|
+
|
|
30
|
+
- `@memberjunction/core` (v2.43.0): Core MemberJunction functionality including BaseEntity
|
|
31
|
+
- `@memberjunction/global` (v2.43.0): Global utilities and constants
|
|
32
|
+
- `zod` (v3.23.8): Schema validation library
|
|
33
|
+
|
|
34
|
+
## Package Structure
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
mj_generatedentities/
|
|
38
|
+
├── src/
|
|
39
|
+
│ ├── index.ts # Main export file
|
|
40
|
+
│ ├── generated/
|
|
41
|
+
│ │ └── entity_subclasses.ts # Auto-generated entity classes
|
|
42
|
+
│ └── demo/
|
|
43
|
+
│ └── demoContactEntitySubclass.ts # Example of extending entities
|
|
44
|
+
├── dist/ # Compiled JavaScript output
|
|
45
|
+
├── package.json
|
|
46
|
+
├── tsconfig.json
|
|
47
|
+
└── README.md
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Usage
|
|
51
|
+
|
|
52
|
+
### Important: MemberJunction Entity Creation Pattern
|
|
53
|
+
|
|
54
|
+
**Never directly instantiate entity classes**. Always use the Metadata system to ensure proper class registration:
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
import { Metadata } from '@memberjunction/core';
|
|
58
|
+
|
|
59
|
+
// ❌ Wrong - bypasses MJ class system
|
|
60
|
+
const entity = new UserEntity();
|
|
61
|
+
|
|
62
|
+
// ✅ Correct - uses MJ metadata system
|
|
63
|
+
const md = new Metadata();
|
|
64
|
+
const entity = await md.GetEntityObject<UserEntity>('Users');
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Loading Generated Entities for Webpack
|
|
68
|
+
|
|
69
|
+
To ensure generated entities are included in webpack builds (avoiding tree-shaking issues):
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
import { LoadGeneratedEntities } from 'mj_generatedentities';
|
|
73
|
+
|
|
74
|
+
// Call this function early in your application initialization
|
|
75
|
+
LoadGeneratedEntities();
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Working with Entity Classes
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
import { Metadata, RunView } from '@memberjunction/core';
|
|
82
|
+
|
|
83
|
+
// Load a single entity by ID
|
|
84
|
+
async function getUserById(userId: string): Promise<UserEntity | null> {
|
|
85
|
+
const md = new Metadata();
|
|
86
|
+
const user = await md.GetEntityObject<UserEntity>('Users');
|
|
87
|
+
|
|
88
|
+
if (await user.Load(userId)) {
|
|
89
|
+
return user;
|
|
90
|
+
}
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Load multiple entities with RunView
|
|
95
|
+
async function getActiveUsers(): Promise<UserEntity[]> {
|
|
96
|
+
const rv = new RunView();
|
|
97
|
+
const result = await rv.RunView<UserEntity>({
|
|
98
|
+
EntityName: 'Users',
|
|
99
|
+
ExtraFilter: `IsActive = 1`,
|
|
100
|
+
OrderBy: 'CreatedAt DESC',
|
|
101
|
+
ResultType: 'entity_object' // Returns entity objects, not raw data
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
return result.Results;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Update an entity
|
|
108
|
+
async function updateUser(userId: string, updates: Partial<UserEntity>): Promise<boolean> {
|
|
109
|
+
const md = new Metadata();
|
|
110
|
+
const user = await md.GetEntityObject<UserEntity>('Users');
|
|
111
|
+
|
|
112
|
+
if (await user.Load(userId)) {
|
|
113
|
+
// Apply updates
|
|
114
|
+
Object.assign(user, updates);
|
|
115
|
+
|
|
116
|
+
// Save changes
|
|
117
|
+
const result = await user.Save();
|
|
118
|
+
return result.Success;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Entity Relationships
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
import { Metadata, RunView } from '@memberjunction/core';
|
|
129
|
+
|
|
130
|
+
async function getUserWithRoles(userId: string) {
|
|
131
|
+
const md = new Metadata();
|
|
132
|
+
const user = await md.GetEntityObject<UserEntity>('Users');
|
|
133
|
+
|
|
134
|
+
if (await user.Load(userId)) {
|
|
135
|
+
// Load related entities using RunView
|
|
136
|
+
const rv = new RunView();
|
|
137
|
+
const rolesResult = await rv.RunView<RoleEntity>({
|
|
138
|
+
EntityName: 'User Roles',
|
|
139
|
+
ExtraFilter: `UserID = '${userId}'`,
|
|
140
|
+
ResultType: 'entity_object'
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
return {
|
|
144
|
+
user,
|
|
145
|
+
roles: rolesResult.Results
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### Extending Generated Entities
|
|
154
|
+
|
|
155
|
+
You can extend the generated entities with custom business logic. Use the `@RegisterClass` decorator to ensure proper registration:
|
|
156
|
+
|
|
157
|
+
```typescript
|
|
158
|
+
import { RegisterClass } from '@memberjunction/global';
|
|
159
|
+
import { BaseEntity } from '@memberjunction/core';
|
|
160
|
+
|
|
161
|
+
// Example from demo/demoContactEntitySubclass.ts
|
|
162
|
+
@RegisterClass(BaseEntity, 'Contacts', 1)
|
|
163
|
+
export class ContactEntity extends ContactBaseEntity {
|
|
164
|
+
// Override property getters/setters (must override both)
|
|
165
|
+
get FirstName(): string {
|
|
166
|
+
console.log("Getting FirstName from subclass");
|
|
167
|
+
return super.FirstName;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
set FirstName(value: string) {
|
|
171
|
+
super.FirstName = value;
|
|
172
|
+
console.log("Setting FirstName from subclass");
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Add custom methods
|
|
176
|
+
async getFullName(): Promise<string> {
|
|
177
|
+
return `${this.FirstName} ${this.LastName}`;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Add custom validation
|
|
181
|
+
override async Validate(): Promise<ValidationResult> {
|
|
182
|
+
const result = await super.Validate();
|
|
183
|
+
|
|
184
|
+
if (this.Email && !this.Email.includes('@')) {
|
|
185
|
+
result.Success = false;
|
|
186
|
+
result.Errors.push({
|
|
187
|
+
Source: 'Email',
|
|
188
|
+
Message: 'Email must contain @ symbol',
|
|
189
|
+
Type: ValidationErrorType.Failure
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return result;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### Important Notes on Extending Entities
|
|
199
|
+
|
|
200
|
+
1. **Always use `@RegisterClass` decorator** to register your subclass with MemberJunction
|
|
201
|
+
2. **When overriding property getters/setters**, you MUST override both getter and setter
|
|
202
|
+
3. **Call super methods** when overriding to maintain base functionality
|
|
203
|
+
4. **Version parameter** in `@RegisterClass` allows for entity versioning
|
|
204
|
+
|
|
205
|
+
### Zod Schema Validation
|
|
206
|
+
|
|
207
|
+
Generated entities use Zod for schema validation:
|
|
208
|
+
|
|
209
|
+
```typescript
|
|
210
|
+
import { z } from 'zod';
|
|
211
|
+
|
|
212
|
+
// Each generated entity includes a Zod schema
|
|
213
|
+
const userSchema = z.object({
|
|
214
|
+
ID: z.string(),
|
|
215
|
+
FirstName: z.string(),
|
|
216
|
+
LastName: z.string(),
|
|
217
|
+
Email: z.string().email(),
|
|
218
|
+
IsActive: z.boolean(),
|
|
219
|
+
CreatedAt: z.date(),
|
|
220
|
+
UpdatedAt: z.date()
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
// Validate data before creating entities
|
|
224
|
+
async function createUserFromData(userData: unknown) {
|
|
225
|
+
const result = userSchema.safeParse(userData);
|
|
226
|
+
|
|
227
|
+
if (result.success) {
|
|
228
|
+
const md = new Metadata();
|
|
229
|
+
const user = await md.GetEntityObject<UserEntity>('Users');
|
|
230
|
+
await user.LoadFromData(result.data);
|
|
231
|
+
|
|
232
|
+
const saveResult = await user.Save();
|
|
233
|
+
return saveResult.Success;
|
|
234
|
+
} else {
|
|
235
|
+
console.error('Validation errors:', result.error.format());
|
|
236
|
+
return false;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
## Entity Base Class Methods
|
|
242
|
+
|
|
243
|
+
All generated entities inherit from `BaseEntity` and provide these key methods:
|
|
244
|
+
|
|
245
|
+
| Method | Description |
|
|
246
|
+
|--------|-------------|
|
|
247
|
+
| `Load(id: CompositeKey)` | Loads an entity by its primary key |
|
|
248
|
+
| `LoadFromData(data: any)` | Populates entity from a data object |
|
|
249
|
+
| `Save(options?: EntitySaveOptions)` | Saves changes to the database |
|
|
250
|
+
| `Delete()` | Deletes the entity from the database |
|
|
251
|
+
| `Validate()` | Validates the entity, returns ValidationResult |
|
|
252
|
+
| `GetFieldValue(fieldName: string)` | Gets the value of a specific field |
|
|
253
|
+
| `SetFieldValue(fieldName: string, value: any)` | Sets the value of a specific field |
|
|
254
|
+
| `TransactionMode` | Property to control transaction behavior |
|
|
255
|
+
|
|
256
|
+
## Build Scripts
|
|
257
|
+
|
|
258
|
+
```bash
|
|
259
|
+
# Build the package
|
|
260
|
+
npm run build
|
|
261
|
+
|
|
262
|
+
# Development mode with auto-reload
|
|
263
|
+
npm run start
|
|
264
|
+
|
|
265
|
+
# Run tests (not implemented yet)
|
|
266
|
+
npm test
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
## Code Generation
|
|
270
|
+
|
|
271
|
+
This package is automatically maintained by MemberJunction's code generation system. The `entity_subclasses.ts` file is generated based on your database schema.
|
|
272
|
+
|
|
273
|
+
**Important**: Do not manually edit files in the `generated/` directory as they will be overwritten during the next code generation cycle.
|
|
274
|
+
|
|
275
|
+
To regenerate entities:
|
|
276
|
+
1. Ensure your database schema is up to date
|
|
277
|
+
2. Run the MemberJunction code generation tool from the appropriate package
|
|
278
|
+
3. The generated files will be automatically updated
|
|
279
|
+
|
|
280
|
+
## Development Notes
|
|
281
|
+
|
|
282
|
+
- The package includes TypeScript declaration files (`*.d.ts`) in the dist folder
|
|
283
|
+
- Source maps are generated for debugging
|
|
284
|
+
- The `loadModule` export in entity_subclasses.ts ensures the module is valid even when empty
|
|
285
|
+
- Use the demo file as a reference for creating custom entity subclasses
|
|
286
|
+
|
|
287
|
+
## License
|
|
288
|
+
|
|
289
|
+
ISC
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { BaseEntity } from "@memberjunction/core";
|
|
2
|
+
declare class ContactBaseEntityStub extends BaseEntity {
|
|
3
|
+
get FirstName(): string;
|
|
4
|
+
set FirstName(value: string);
|
|
5
|
+
}
|
|
6
|
+
export declare class ContactDemoEntity extends ContactBaseEntityStub {
|
|
7
|
+
get FirstName(): string;
|
|
8
|
+
set FirstName(value: string);
|
|
9
|
+
}
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=demoContactEntitySubclass.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"demoContactEntitySubclass.d.ts","sourceRoot":"","sources":["../../src/demo/demoContactEntitySubclass.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAKlD,cAAM,qBAAsB,SAAQ,UAAU;IAC1C,IAAI,SAAS,IAAI,MAAM,CAEtB;IACD,IAAI,SAAS,CAAC,KAAK,EAAE,MAAM,EAC1B;CACJ;AAKD,qBACa,iBAAkB,SAAQ,qBAAqB;IACxD,IAAI,SAAS,IAAI,MAAM,CAGtB;IACD,IAAI,SAAS,CAAC,KAAK,EAAE,MAAM,EAG1B;CACJ"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
//import { ContactBaseEntity } from "../generated/entity_subclasses.js";
|
|
8
|
+
import { BaseEntity } from "@memberjunction/core";
|
|
9
|
+
import { RegisterClass } from "@memberjunction/global";
|
|
10
|
+
// STUB base class- you would DELETE this and use a real base class from ../generated/entity_subclasses instead
|
|
11
|
+
class ContactBaseEntityStub extends BaseEntity {
|
|
12
|
+
get FirstName() {
|
|
13
|
+
return "";
|
|
14
|
+
}
|
|
15
|
+
set FirstName(value) {
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
// Super simple example of a sub-class for an example Contacts entity doesn't do anything but you can see here you can do stuff with sub-class overrides
|
|
19
|
+
// Also, important, if you're going to override the getter/setter for a property, you MUST call super.propertyName in the getter/setter AND you must also
|
|
20
|
+
// override BOTH the getter and setter, otherwise you'll get a runtime error! This is because the getter/setter is actually a single property on the object
|
|
21
|
+
let ContactDemoEntity = class ContactDemoEntity extends ContactBaseEntityStub /*here you would change this to sub-class the real base class from ../generated/entity_subclasses */ {
|
|
22
|
+
get FirstName() {
|
|
23
|
+
console.log("I'm getting the FirstName property from the sub-class!");
|
|
24
|
+
return super.FirstName;
|
|
25
|
+
}
|
|
26
|
+
set FirstName(value) {
|
|
27
|
+
super.FirstName = value;
|
|
28
|
+
console.log("I'm setting the FirstName property from the sub-class!");
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
ContactDemoEntity = __decorate([
|
|
32
|
+
RegisterClass(BaseEntity, 'Contacts', 1)
|
|
33
|
+
], ContactDemoEntity);
|
|
34
|
+
export { ContactDemoEntity };
|
|
35
|
+
//# sourceMappingURL=demoContactEntitySubclass.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"demoContactEntitySubclass.js","sourceRoot":"","sources":["../../src/demo/demoContactEntitySubclass.ts"],"names":[],"mappings":";;;;;;AAAA,qEAAqE;AACrE,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAGvD,gHAAgH;AAChH,MAAM,qBAAsB,SAAQ,UAAU;IAC1C,IAAI,SAAS;QACT,OAAO,EAAE,CAAC;IACd,CAAC;IACD,IAAI,SAAS,CAAC,KAAa;IAC3B,CAAC;CACJ;AAED,yJAAyJ;AACzJ,yJAAyJ;AACzJ,2JAA2J;AAEpJ,IAAM,iBAAiB,GAAvB,MAAM,iBAAkB,SAAQ,qBAAqB,CAAC,oGAAoG;IAC7J,IAAI,SAAS;QACT,OAAO,CAAC,GAAG,CAAC,wDAAwD,CAAC,CAAA;QACrE,OAAO,KAAK,CAAC,SAAS,CAAC;IAC3B,CAAC;IACD,IAAI,SAAS,CAAC,KAAa;QACvB,KAAK,CAAC,SAAS,GAAG,KAAK,CAAC;QACxB,OAAO,CAAC,GAAG,CAAC,wDAAwD,CAAC,CAAA;IACzE,CAAC;CACJ,CAAA;AATY,iBAAiB;IAD7B,aAAa,CAAC,UAAU,EAAE,UAAU,EAAE,CAAC,CAAC;GAC5B,iBAAiB,CAS7B"}
|