@memberjunction/core 3.4.0 → 4.1.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/dist/generic/InMemoryLocalStorageProvider.d.ts +1 -1
- package/dist/generic/InMemoryLocalStorageProvider.js +2 -6
- package/dist/generic/InMemoryLocalStorageProvider.js.map +1 -1
- package/dist/generic/QueryCache.d.ts +1 -1
- package/dist/generic/QueryCache.js +6 -10
- package/dist/generic/QueryCache.js.map +1 -1
- package/dist/generic/QueryCacheConfig.js +1 -2
- package/dist/generic/RegisterForStartup.d.ts +2 -2
- package/dist/generic/RegisterForStartup.js +7 -12
- package/dist/generic/RegisterForStartup.js.map +1 -1
- package/dist/generic/applicationInfo.d.ts +3 -3
- package/dist/generic/applicationInfo.js +4 -10
- package/dist/generic/applicationInfo.js.map +1 -1
- package/dist/generic/authEvaluator.d.ts +1 -1
- package/dist/generic/authEvaluator.js +4 -8
- package/dist/generic/authEvaluator.js.map +1 -1
- package/dist/generic/authTypes.js +1 -4
- package/dist/generic/authTypes.js.map +1 -1
- package/dist/generic/baseEngine.d.ts +5 -5
- package/dist/generic/baseEngine.js +51 -56
- package/dist/generic/baseEngine.js.map +1 -1
- package/dist/generic/baseEngineRegistry.js +13 -17
- package/dist/generic/baseEngineRegistry.js.map +1 -1
- package/dist/generic/baseEntity.d.ts +171 -5
- package/dist/generic/baseEntity.d.ts.map +1 -1
- package/dist/generic/baseEntity.js +651 -121
- package/dist/generic/baseEntity.js.map +1 -1
- package/dist/generic/baseInfo.js +3 -7
- package/dist/generic/baseInfo.js.map +1 -1
- package/dist/generic/compositeKey.d.ts +2 -2
- package/dist/generic/compositeKey.js +5 -11
- package/dist/generic/compositeKey.js.map +1 -1
- package/dist/generic/databaseProviderBase.d.ts +2 -2
- package/dist/generic/databaseProviderBase.js +2 -6
- package/dist/generic/databaseProviderBase.js.map +1 -1
- package/dist/generic/entityInfo.d.ts +84 -5
- package/dist/generic/entityInfo.d.ts.map +1 -1
- package/dist/generic/entityInfo.js +235 -108
- package/dist/generic/entityInfo.js.map +1 -1
- package/dist/generic/explorerNavigationItem.d.ts +1 -1
- package/dist/generic/explorerNavigationItem.js +2 -6
- package/dist/generic/explorerNavigationItem.js.map +1 -1
- package/dist/generic/graphqlTypeNames.d.ts +1 -1
- package/dist/generic/graphqlTypeNames.js +4 -9
- package/dist/generic/graphqlTypeNames.js.map +1 -1
- package/dist/generic/interfaces.d.ts +104 -14
- package/dist/generic/interfaces.d.ts.map +1 -1
- package/dist/generic/interfaces.js +28 -30
- package/dist/generic/interfaces.js.map +1 -1
- package/dist/generic/libraryInfo.d.ts +1 -1
- package/dist/generic/libraryInfo.js +2 -6
- package/dist/generic/libraryInfo.js.map +1 -1
- package/dist/generic/localCacheManager.d.ts +2 -2
- package/dist/generic/localCacheManager.js +44 -48
- package/dist/generic/localCacheManager.js.map +1 -1
- package/dist/generic/logging.d.ts.map +1 -1
- package/dist/generic/logging.js +54 -67
- package/dist/generic/logging.js.map +1 -1
- package/dist/generic/metadata.d.ts +12 -12
- package/dist/generic/metadata.d.ts.map +1 -1
- package/dist/generic/metadata.js +21 -25
- package/dist/generic/metadata.js.map +1 -1
- package/dist/generic/metadataUtil.d.ts +1 -1
- package/dist/generic/metadataUtil.js +3 -7
- package/dist/generic/metadataUtil.js.map +1 -1
- package/dist/generic/providerBase.d.ts +63 -16
- package/dist/generic/providerBase.d.ts.map +1 -1
- package/dist/generic/providerBase.js +253 -130
- package/dist/generic/providerBase.js.map +1 -1
- package/dist/generic/queryInfo.d.ts +5 -5
- package/dist/generic/queryInfo.js +21 -30
- package/dist/generic/queryInfo.js.map +1 -1
- package/dist/generic/queryInfoInterfaces.js +1 -2
- package/dist/generic/queryInfoInterfaces.js.map +1 -1
- package/dist/generic/querySQLFilters.js +5 -10
- package/dist/generic/querySQLFilters.js.map +1 -1
- package/dist/generic/runQuery.d.ts +2 -2
- package/dist/generic/runQuery.js +5 -9
- package/dist/generic/runQuery.js.map +1 -1
- package/dist/generic/runQuerySQLFilterImplementations.d.ts +1 -1
- package/dist/generic/runQuerySQLFilterImplementations.js +4 -8
- package/dist/generic/runQuerySQLFilterImplementations.js.map +1 -1
- package/dist/generic/runReport.d.ts +2 -2
- package/dist/generic/runReport.js +5 -9
- package/dist/generic/runReport.js.map +1 -1
- package/dist/generic/securityInfo.d.ts +2 -2
- package/dist/generic/securityInfo.js +10 -20
- package/dist/generic/securityInfo.js.map +1 -1
- package/dist/generic/telemetryManager.js +20 -32
- package/dist/generic/telemetryManager.js.map +1 -1
- package/dist/generic/transactionGroup.d.ts +1 -1
- package/dist/generic/transactionGroup.d.ts.map +1 -1
- package/dist/generic/transactionGroup.js +11 -19
- package/dist/generic/transactionGroup.js.map +1 -1
- package/dist/generic/util.js +15 -31
- package/dist/generic/util.js.map +1 -1
- package/dist/index.d.ts +34 -34
- package/dist/index.js +45 -63
- package/dist/index.js.map +1 -1
- package/dist/views/runView.d.ts +3 -3
- package/dist/views/runView.js +6 -11
- package/dist/views/runView.js.map +1 -1
- package/dist/views/viewInfo.d.ts +3 -3
- package/dist/views/viewInfo.js +10 -17
- package/dist/views/viewInfo.js.map +1 -1
- package/package.json +11 -10
- package/readme.md +871 -1271
|
@@ -1,15 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
const util_1 = require("./util");
|
|
7
|
-
const logging_1 = require("./logging");
|
|
8
|
-
const global_1 = require("@memberjunction/global");
|
|
1
|
+
import { BaseInfo } from "./baseInfo.js";
|
|
2
|
+
import { Metadata } from "./metadata.js";
|
|
3
|
+
import { TypeScriptTypeFromSQLType, SQLFullType, SQLMaxLength, FormatValue, CodeNameFromString } from "./util.js";
|
|
4
|
+
import { LogError } from "./logging.js";
|
|
5
|
+
import { WarningManager, SafeJSONParse } from "@memberjunction/global";
|
|
9
6
|
/**
|
|
10
7
|
* The possible status values for a record change
|
|
11
8
|
*/
|
|
12
|
-
|
|
9
|
+
export const RecordChangeStatus = {
|
|
13
10
|
Pending: 'Pending',
|
|
14
11
|
Complete: 'Complete',
|
|
15
12
|
Error: 'Error',
|
|
@@ -17,9 +14,9 @@ exports.RecordChangeStatus = {
|
|
|
17
14
|
/**
|
|
18
15
|
* Record Change object has information on a change to a record in the Record Changes entity
|
|
19
16
|
*/
|
|
20
|
-
class RecordChange extends
|
|
17
|
+
export class RecordChange extends BaseInfo {
|
|
21
18
|
get StatusValue() {
|
|
22
|
-
return
|
|
19
|
+
return RecordChangeStatus[this.Status?.trim()];
|
|
23
20
|
}
|
|
24
21
|
get Changes() {
|
|
25
22
|
return JSON.parse(this.ChangesJSON);
|
|
@@ -40,7 +37,6 @@ class RecordChange extends baseInfo_1.BaseInfo {
|
|
|
40
37
|
this.copyInitData(initData);
|
|
41
38
|
}
|
|
42
39
|
}
|
|
43
|
-
exports.RecordChange = RecordChange;
|
|
44
40
|
/**
|
|
45
41
|
* Information about the Entity Relationship between the Entity and the Related Entity - this class
|
|
46
42
|
* maps to information in the Entity Relationships metadata entity.
|
|
@@ -49,7 +45,7 @@ exports.RecordChange = RecordChange;
|
|
|
49
45
|
* Metadata about relationships between entities including display preferences for the UI.
|
|
50
46
|
* Defines foreign key relationships and how they should be represented in the user interface.
|
|
51
47
|
*/
|
|
52
|
-
class EntityRelationshipInfo extends
|
|
48
|
+
export class EntityRelationshipInfo extends BaseInfo {
|
|
53
49
|
constructor(initData) {
|
|
54
50
|
super();
|
|
55
51
|
this.ID = null;
|
|
@@ -97,54 +93,52 @@ class EntityRelationshipInfo extends baseInfo_1.BaseInfo {
|
|
|
97
93
|
this.copyInitData(initData);
|
|
98
94
|
}
|
|
99
95
|
}
|
|
100
|
-
|
|
101
|
-
exports.EntityPermissionType = {
|
|
96
|
+
export const EntityPermissionType = {
|
|
102
97
|
Read: 'Read',
|
|
103
98
|
Create: 'Create',
|
|
104
99
|
Update: 'Update',
|
|
105
100
|
Delete: 'Delete',
|
|
106
101
|
};
|
|
107
|
-
class EntityUserPermissionInfo {
|
|
102
|
+
export class EntityUserPermissionInfo {
|
|
108
103
|
constructor() {
|
|
109
104
|
this.ID = null;
|
|
110
105
|
}
|
|
111
106
|
}
|
|
112
|
-
exports.EntityUserPermissionInfo = EntityUserPermissionInfo;
|
|
113
107
|
/**
|
|
114
108
|
* Security settings for each entity.
|
|
115
109
|
* Controls which roles can perform create, read, update, and delete operations.
|
|
116
110
|
*/
|
|
117
|
-
class EntityPermissionInfo extends
|
|
111
|
+
export class EntityPermissionInfo extends BaseInfo {
|
|
118
112
|
get CreateRLSFilterObject() {
|
|
119
|
-
return this.RLSFilter(
|
|
113
|
+
return this.RLSFilter(EntityPermissionType.Create);
|
|
120
114
|
}
|
|
121
115
|
get ReadRLSFilterObject() {
|
|
122
|
-
return this.RLSFilter(
|
|
116
|
+
return this.RLSFilter(EntityPermissionType.Read);
|
|
123
117
|
}
|
|
124
118
|
get UpdateRLSFilterObject() {
|
|
125
|
-
return this.RLSFilter(
|
|
119
|
+
return this.RLSFilter(EntityPermissionType.Update);
|
|
126
120
|
}
|
|
127
121
|
get DeleteRLSFilterObject() {
|
|
128
|
-
return this.RLSFilter(
|
|
122
|
+
return this.RLSFilter(EntityPermissionType.Delete);
|
|
129
123
|
}
|
|
130
124
|
RLSFilter(type) {
|
|
131
125
|
let fID = "";
|
|
132
126
|
switch (type) {
|
|
133
|
-
case
|
|
127
|
+
case EntityPermissionType.Read:
|
|
134
128
|
fID = this.ReadRLSFilterID;
|
|
135
129
|
break;
|
|
136
|
-
case
|
|
130
|
+
case EntityPermissionType.Create:
|
|
137
131
|
fID = this.CreateRLSFilterID;
|
|
138
132
|
break;
|
|
139
|
-
case
|
|
133
|
+
case EntityPermissionType.Update:
|
|
140
134
|
fID = this.UpdateRLSFilterID;
|
|
141
135
|
break;
|
|
142
|
-
case
|
|
136
|
+
case EntityPermissionType.Delete:
|
|
143
137
|
fID = this.DeleteRLSFilterID;
|
|
144
138
|
break;
|
|
145
139
|
}
|
|
146
140
|
if (fID && fID.length > 0)
|
|
147
|
-
return
|
|
141
|
+
return Metadata.Provider.RowLevelSecurityFilters.find(f => f.ID === fID);
|
|
148
142
|
}
|
|
149
143
|
constructor(initData) {
|
|
150
144
|
super();
|
|
@@ -172,21 +166,20 @@ class EntityPermissionInfo extends baseInfo_1.BaseInfo {
|
|
|
172
166
|
this.copyInitData(initData);
|
|
173
167
|
}
|
|
174
168
|
}
|
|
175
|
-
|
|
176
|
-
exports.EntityFieldTSType = {
|
|
169
|
+
export const EntityFieldTSType = {
|
|
177
170
|
String: 'string',
|
|
178
171
|
Number: 'number',
|
|
179
172
|
Date: 'Date',
|
|
180
173
|
Boolean: 'boolean',
|
|
181
174
|
};
|
|
182
|
-
|
|
175
|
+
export const EntityFieldGraphQLType = {
|
|
183
176
|
Int: 'Int',
|
|
184
177
|
Float: 'Float',
|
|
185
178
|
String: 'String',
|
|
186
179
|
Boolean: 'Boolean',
|
|
187
180
|
Timestamp: 'Timestamp',
|
|
188
181
|
};
|
|
189
|
-
|
|
182
|
+
export const EntityFieldValueListType = {
|
|
190
183
|
None: 'None',
|
|
191
184
|
List: 'List',
|
|
192
185
|
ListOrUserEntry: 'ListOrUserEntry',
|
|
@@ -195,7 +188,7 @@ exports.EntityFieldValueListType = {
|
|
|
195
188
|
* Defines allowed values for entity fields with value lists.
|
|
196
189
|
* Supports dropdowns, validations, and data integrity constraints.
|
|
197
190
|
*/
|
|
198
|
-
class EntityFieldValueInfo extends
|
|
191
|
+
export class EntityFieldValueInfo extends BaseInfo {
|
|
199
192
|
constructor(initData) {
|
|
200
193
|
super();
|
|
201
194
|
this.ID = null;
|
|
@@ -209,8 +202,7 @@ class EntityFieldValueInfo extends baseInfo_1.BaseInfo {
|
|
|
209
202
|
this.copyInitData(initData);
|
|
210
203
|
}
|
|
211
204
|
}
|
|
212
|
-
|
|
213
|
-
exports.GeneratedFormSectionType = {
|
|
205
|
+
export const GeneratedFormSectionType = {
|
|
214
206
|
Top: 'Top',
|
|
215
207
|
Details: 'Details',
|
|
216
208
|
Category: 'Category',
|
|
@@ -222,7 +214,7 @@ exports.GeneratedFormSectionType = {
|
|
|
222
214
|
* List of all fields within each entity with metadata about each field.
|
|
223
215
|
* Includes data types, relationships, defaults, and UI display preferences.
|
|
224
216
|
*/
|
|
225
|
-
class EntityFieldInfo extends
|
|
217
|
+
export class EntityFieldInfo extends BaseInfo {
|
|
226
218
|
/**
|
|
227
219
|
* JSON configuration for additional fields to join from the related entity.
|
|
228
220
|
* Parsed from the RelatedEntityJoinFields column. Uses lazy initialization and caching
|
|
@@ -242,7 +234,7 @@ class EntityFieldInfo extends baseInfo_1.BaseInfo {
|
|
|
242
234
|
return this._relatedEntityJoinFieldsParsed;
|
|
243
235
|
}
|
|
244
236
|
// Parse and cache the configuration
|
|
245
|
-
const parsed =
|
|
237
|
+
const parsed = SafeJSONParse(this.RelatedEntityJoinFields, false);
|
|
246
238
|
if (parsed === null) {
|
|
247
239
|
// Parsing failed - mark as failed so we don't try again
|
|
248
240
|
this._relatedEntityJoinFieldsFailedParsing = true;
|
|
@@ -260,34 +252,34 @@ class EntityFieldInfo extends baseInfo_1.BaseInfo {
|
|
|
260
252
|
*/
|
|
261
253
|
get ValueListTypeEnum() {
|
|
262
254
|
if (this.ValueListType == null)
|
|
263
|
-
return
|
|
255
|
+
return EntityFieldValueListType.None;
|
|
264
256
|
else {
|
|
265
257
|
// iterate through list of possibilities from enum and compare lcase
|
|
266
|
-
for (let enumMember in
|
|
267
|
-
if (typeof
|
|
258
|
+
for (let enumMember in EntityFieldValueListType) {
|
|
259
|
+
if (typeof EntityFieldValueListType[enumMember] === 'string' &&
|
|
268
260
|
enumMember.toLowerCase().trim() === this.ValueListType.toLowerCase().trim()) {
|
|
269
|
-
return
|
|
261
|
+
return EntityFieldValueListType[enumMember];
|
|
270
262
|
}
|
|
271
263
|
}
|
|
272
264
|
}
|
|
273
265
|
}
|
|
274
266
|
get GeneratedFormSectionType() {
|
|
275
|
-
return
|
|
267
|
+
return GeneratedFormSectionType[this.GeneratedFormSection];
|
|
276
268
|
}
|
|
277
269
|
/**
|
|
278
270
|
* Provides the TypeScript type for a given Entity Field. This is useful to map
|
|
279
271
|
* a wide array of database types to a narrower set of TypeScript types.
|
|
280
272
|
*/
|
|
281
273
|
get TSType() {
|
|
282
|
-
switch (
|
|
274
|
+
switch (TypeScriptTypeFromSQLType(this.Type).toLowerCase()) {
|
|
283
275
|
case "number":
|
|
284
|
-
return
|
|
276
|
+
return EntityFieldTSType.Number;
|
|
285
277
|
case "boolean":
|
|
286
|
-
return
|
|
278
|
+
return EntityFieldTSType.Boolean;
|
|
287
279
|
case "date":
|
|
288
|
-
return
|
|
280
|
+
return EntityFieldTSType.Date;
|
|
289
281
|
default:
|
|
290
|
-
return
|
|
282
|
+
return EntityFieldTSType.String;
|
|
291
283
|
}
|
|
292
284
|
}
|
|
293
285
|
/**
|
|
@@ -332,8 +324,8 @@ class EntityFieldInfo extends baseInfo_1.BaseInfo {
|
|
|
332
324
|
*/
|
|
333
325
|
get NeedsQuotes() {
|
|
334
326
|
switch (this.TSType) {
|
|
335
|
-
case
|
|
336
|
-
case
|
|
327
|
+
case EntityFieldTSType.Number:
|
|
328
|
+
case EntityFieldTSType.Boolean:
|
|
337
329
|
return false;
|
|
338
330
|
default:
|
|
339
331
|
return true;
|
|
@@ -341,12 +333,12 @@ class EntityFieldInfo extends baseInfo_1.BaseInfo {
|
|
|
341
333
|
}
|
|
342
334
|
get CodeName() {
|
|
343
335
|
if (this._codeName === null) {
|
|
344
|
-
this._codeName =
|
|
336
|
+
this._codeName = CodeNameFromString(this.Name);
|
|
345
337
|
}
|
|
346
338
|
return this._codeName;
|
|
347
339
|
}
|
|
348
340
|
get GraphQLType() {
|
|
349
|
-
switch (
|
|
341
|
+
switch (TypeScriptTypeFromSQLType(this.Type).toLowerCase()) {
|
|
350
342
|
case "number":
|
|
351
343
|
// either an int or float if not an int
|
|
352
344
|
switch (this.Type.toLowerCase().trim()) {
|
|
@@ -354,30 +346,34 @@ class EntityFieldInfo extends baseInfo_1.BaseInfo {
|
|
|
354
346
|
case "smallint":
|
|
355
347
|
case "tinyint":
|
|
356
348
|
case "bigint":
|
|
357
|
-
return
|
|
349
|
+
return EntityFieldGraphQLType.Int;
|
|
358
350
|
default:
|
|
359
|
-
return
|
|
351
|
+
return EntityFieldGraphQLType.Float;
|
|
360
352
|
}
|
|
361
353
|
case "boolean":
|
|
362
|
-
return
|
|
354
|
+
return EntityFieldGraphQLType.Boolean;
|
|
363
355
|
case "date":
|
|
364
|
-
return
|
|
356
|
+
return EntityFieldGraphQLType.Timestamp;
|
|
365
357
|
default:
|
|
366
|
-
return
|
|
358
|
+
return EntityFieldGraphQLType.String;
|
|
367
359
|
}
|
|
368
360
|
}
|
|
369
361
|
/**
|
|
370
362
|
* Returns a string with the full SQL data type that combines, as appropriate, Type, Length, Precision and Scale where these attributes are relevant to the Type
|
|
371
363
|
*/
|
|
372
364
|
get SQLFullType() {
|
|
373
|
-
return
|
|
365
|
+
return SQLFullType(this.Type, this.Length, this.Precision, this.Scale);
|
|
374
366
|
}
|
|
375
367
|
get MaxLength() {
|
|
376
|
-
return
|
|
368
|
+
return SQLMaxLength(this.Type, this.Length);
|
|
377
369
|
}
|
|
378
370
|
get ReadOnly() {
|
|
379
|
-
|
|
380
|
-
|
|
371
|
+
// Note: IsVirtual is intentionally NOT checked here. For IS-A (table-per-type) inheritance,
|
|
372
|
+
// parent entity fields on child entities are marked IsVirtual=1 (they don't exist in the
|
|
373
|
+
// child's base table) but ARE editable via the parent save chain. The AllowUpdateAPI flag
|
|
374
|
+
// already correctly distinguishes editable IS-A parent fields (AllowUpdateAPI=1) from
|
|
375
|
+
// truly read-only virtual fields like joined display names (AllowUpdateAPI=0).
|
|
376
|
+
return !this.AllowUpdateAPI ||
|
|
381
377
|
this.IsPrimaryKey ||
|
|
382
378
|
this.IsSpecialDateField;
|
|
383
379
|
}
|
|
@@ -451,7 +447,7 @@ class EntityFieldInfo extends baseInfo_1.BaseInfo {
|
|
|
451
447
|
* @returns either the original string value or a formatted version. If the format cannot be applied an an exception occurs it is captured and the error is put to the log, and the original value is returned
|
|
452
448
|
*/
|
|
453
449
|
FormatValue(value, decimals = 2, currency = 'USD', maxLength = 0, trailingChars = "...") {
|
|
454
|
-
return
|
|
450
|
+
return FormatValue(this.Type, value, decimals, currency, maxLength, trailingChars);
|
|
455
451
|
}
|
|
456
452
|
constructor(initData = null) {
|
|
457
453
|
super();
|
|
@@ -752,15 +748,26 @@ class EntityFieldInfo extends baseInfo_1.BaseInfo {
|
|
|
752
748
|
}
|
|
753
749
|
if (entityField.Status?.trim().toLowerCase() === 'deprecated') {
|
|
754
750
|
// Record deprecation warning - will be batched and displayed after debounce period
|
|
755
|
-
|
|
751
|
+
WarningManager.Instance.RecordFieldDeprecationWarning(entityField.Entity, entityField.Name, callerName);
|
|
756
752
|
}
|
|
757
753
|
else if (entityField.Status?.trim().toLowerCase() === 'disabled') {
|
|
758
754
|
// console.error and throw the exception
|
|
759
755
|
const exceptionString = `${callerName}: Entity Field ${entityField.Entity}.${entityField.Name} is disabled and cannot be used.`;
|
|
760
|
-
|
|
756
|
+
LogError(exceptionString);
|
|
761
757
|
throw new Error(exceptionString);
|
|
762
758
|
}
|
|
763
759
|
}
|
|
760
|
+
/**
|
|
761
|
+
* Readonly array of SQL Server date/time functions that return the current date/time
|
|
762
|
+
*/
|
|
763
|
+
static { this.SQL_CURRENT_DATE_FUNCTIONS = [
|
|
764
|
+
'getdate()',
|
|
765
|
+
'getutcdate()',
|
|
766
|
+
'sysdatetimeoffset()',
|
|
767
|
+
'current_timestamp',
|
|
768
|
+
'sysdatetime()',
|
|
769
|
+
'sysutcdatetime()'
|
|
770
|
+
]; }
|
|
764
771
|
/**
|
|
765
772
|
* Checks if a default value is a SQL Server function that returns the current date/time
|
|
766
773
|
* @param defaultValue - The default value to check
|
|
@@ -777,18 +784,6 @@ class EntityFieldInfo extends baseInfo_1.BaseInfo {
|
|
|
777
784
|
return EntityFieldInfo.SQL_CURRENT_DATE_FUNCTIONS.some(func => normalizedValue.includes(func));
|
|
778
785
|
}
|
|
779
786
|
}
|
|
780
|
-
exports.EntityFieldInfo = EntityFieldInfo;
|
|
781
|
-
/**
|
|
782
|
-
* Readonly array of SQL Server date/time functions that return the current date/time
|
|
783
|
-
*/
|
|
784
|
-
EntityFieldInfo.SQL_CURRENT_DATE_FUNCTIONS = [
|
|
785
|
-
'getdate()',
|
|
786
|
-
'getutcdate()',
|
|
787
|
-
'sysdatetimeoffset()',
|
|
788
|
-
'current_timestamp',
|
|
789
|
-
'sysdatetime()',
|
|
790
|
-
'sysutcdatetime()'
|
|
791
|
-
];
|
|
792
787
|
/**
|
|
793
788
|
* Entity Document Type Info object has information about the document types that exist across all entities. When Entity Documents are created they are associated with a document type.
|
|
794
789
|
*/
|
|
@@ -796,7 +791,7 @@ EntityFieldInfo.SQL_CURRENT_DATE_FUNCTIONS = [
|
|
|
796
791
|
* Defines types of documents that can be generated from entity data.
|
|
797
792
|
* Supports various output formats for entity records.
|
|
798
793
|
*/
|
|
799
|
-
class EntityDocumentTypeInfo extends
|
|
794
|
+
export class EntityDocumentTypeInfo extends BaseInfo {
|
|
800
795
|
constructor(initData = null) {
|
|
801
796
|
super();
|
|
802
797
|
this.ID = null;
|
|
@@ -807,7 +802,6 @@ class EntityDocumentTypeInfo extends baseInfo_1.BaseInfo {
|
|
|
807
802
|
this.copyInitData(initData);
|
|
808
803
|
}
|
|
809
804
|
}
|
|
810
|
-
exports.EntityDocumentTypeInfo = EntityDocumentTypeInfo;
|
|
811
805
|
/**
|
|
812
806
|
* Settings allow you to store key/value pairs of information that can be used to configure the behavior of the entity.
|
|
813
807
|
*/
|
|
@@ -815,7 +809,7 @@ exports.EntityDocumentTypeInfo = EntityDocumentTypeInfo;
|
|
|
815
809
|
* Stores entity-specific configuration settings.
|
|
816
810
|
* Allows customization of how entities function within the system.
|
|
817
811
|
*/
|
|
818
|
-
class EntitySettingInfo extends
|
|
812
|
+
export class EntitySettingInfo extends BaseInfo {
|
|
819
813
|
constructor(initData = null) {
|
|
820
814
|
super();
|
|
821
815
|
this.ID = null;
|
|
@@ -828,12 +822,11 @@ class EntitySettingInfo extends baseInfo_1.BaseInfo {
|
|
|
828
822
|
this.copyInitData(initData);
|
|
829
823
|
}
|
|
830
824
|
}
|
|
831
|
-
exports.EntitySettingInfo = EntitySettingInfo;
|
|
832
825
|
/**
|
|
833
826
|
* Catalog of all entities across all schemas.
|
|
834
827
|
* Contains comprehensive metadata about each entity including its database mappings, security settings, and UI preferences.
|
|
835
828
|
*/
|
|
836
|
-
class EntityInfo extends
|
|
829
|
+
export class EntityInfo extends BaseInfo {
|
|
837
830
|
/**
|
|
838
831
|
* Returns the primary key field for the entity. For entities with a composite primary key, use the PrimaryKeys property which returns all.
|
|
839
832
|
* In the case of a composite primary key, the PrimaryKey property will return the first field in the sequence of the primary key fields.
|
|
@@ -897,6 +890,17 @@ class EntityInfo extends baseInfo_1.BaseInfo {
|
|
|
897
890
|
get Settings() {
|
|
898
891
|
return this._Settings;
|
|
899
892
|
}
|
|
893
|
+
/**
|
|
894
|
+
* Gets the parsed FieldCategoryInfo map for this entity, keyed by category name.
|
|
895
|
+
* Auto-populated from the 'FieldCategoryInfo' EntitySetting (with legacy 'FieldCategoryIcons' fallback)
|
|
896
|
+
* during EntityInfo construction. Returns null if no category info is configured.
|
|
897
|
+
*/
|
|
898
|
+
get FieldCategories() {
|
|
899
|
+
return this._FieldCategories;
|
|
900
|
+
}
|
|
901
|
+
static { this.__createdAtFieldName = '__mj_CreatedAt'; }
|
|
902
|
+
static { this.__updatedAtFieldName = '__mj_UpdatedAt'; }
|
|
903
|
+
static { this.__deletedAtFieldName = '__mj_DeletedAt'; }
|
|
900
904
|
/**
|
|
901
905
|
* Returns the name of the special reserved field that is used to store the CreatedAt timestamp across all of MJ. This is only used when an entity has TrackRecordChanges turned on
|
|
902
906
|
*/
|
|
@@ -928,12 +932,12 @@ class EntityInfo extends baseInfo_1.BaseInfo {
|
|
|
928
932
|
}
|
|
929
933
|
if (entity.Status?.trim().toLowerCase() === 'deprecated') {
|
|
930
934
|
// Record deprecation warning - will be batched and displayed after debounce period
|
|
931
|
-
|
|
935
|
+
WarningManager.Instance.RecordEntityDeprecationWarning(entity.Name, callerName);
|
|
932
936
|
}
|
|
933
937
|
else if (entity.Status?.trim().toLowerCase() === 'disabled') {
|
|
934
938
|
// console.error and throw the exception
|
|
935
939
|
const exceptionString = `${callerName}: Entity ${entity.Name} is disabled and cannot be used.`;
|
|
936
|
-
|
|
940
|
+
LogError(exceptionString);
|
|
937
941
|
throw new Error(exceptionString);
|
|
938
942
|
}
|
|
939
943
|
}
|
|
@@ -960,6 +964,104 @@ class EntityInfo extends baseInfo_1.BaseInfo {
|
|
|
960
964
|
else
|
|
961
965
|
return f;
|
|
962
966
|
}
|
|
967
|
+
/**************************************************************************
|
|
968
|
+
* IS-A Type Relationship Computed Properties
|
|
969
|
+
*
|
|
970
|
+
* These properties support the IS-A (parent/child type) inheritance model
|
|
971
|
+
* where child entities share their parent's primary key and inherit all
|
|
972
|
+
* parent fields. Example: Meeting IS-A Product, Webinar IS-A Meeting.
|
|
973
|
+
**************************************************************************/
|
|
974
|
+
/**
|
|
975
|
+
* Returns the parent EntityInfo for IS-A type inheritance, or null if this entity
|
|
976
|
+
* has no parent type. Uses the existing ParentID column on the Entity table.
|
|
977
|
+
* Example: For "Meetings" entity with ParentID pointing to "Products", returns the Products EntityInfo.
|
|
978
|
+
*/
|
|
979
|
+
get ParentEntityInfo() {
|
|
980
|
+
if (!this.ParentID)
|
|
981
|
+
return null;
|
|
982
|
+
return Metadata.Provider?.Entities?.find(e => e.ID === this.ParentID) ?? null;
|
|
983
|
+
}
|
|
984
|
+
/**
|
|
985
|
+
* Returns all child entities that have their ParentID set to this entity's ID.
|
|
986
|
+
* These represent IS-A type specializations of this entity.
|
|
987
|
+
* Example: For "Products" entity, might return [Meetings, Publications].
|
|
988
|
+
*/
|
|
989
|
+
get ChildEntities() {
|
|
990
|
+
return Metadata.Provider?.Entities?.filter(e => e.ParentID === this.ID) ?? [];
|
|
991
|
+
}
|
|
992
|
+
/**
|
|
993
|
+
* Walks the IS-A chain upward from this entity to the root, returning all parent entities.
|
|
994
|
+
* Does NOT include this entity itself.
|
|
995
|
+
* Example: For Webinars (IS-A Meetings IS-A Products), returns [Meetings, Products].
|
|
996
|
+
* Results are cached after first computation for performance.
|
|
997
|
+
*/
|
|
998
|
+
get ParentChain() {
|
|
999
|
+
if (this._parentChainCache !== null)
|
|
1000
|
+
return this._parentChainCache;
|
|
1001
|
+
const chain = [];
|
|
1002
|
+
let current = this.ParentEntityInfo;
|
|
1003
|
+
const visited = new Set(); // circular reference protection
|
|
1004
|
+
while (current) {
|
|
1005
|
+
if (visited.has(current.ID))
|
|
1006
|
+
break; // prevent infinite loop
|
|
1007
|
+
visited.add(current.ID);
|
|
1008
|
+
chain.push(current);
|
|
1009
|
+
current = current.ParentEntityInfo;
|
|
1010
|
+
}
|
|
1011
|
+
this._parentChainCache = chain;
|
|
1012
|
+
return chain;
|
|
1013
|
+
}
|
|
1014
|
+
/**
|
|
1015
|
+
* Returns true if this entity is a child type in an IS-A relationship (has a parent entity).
|
|
1016
|
+
*/
|
|
1017
|
+
get IsChildType() {
|
|
1018
|
+
return this.ParentID != null;
|
|
1019
|
+
}
|
|
1020
|
+
/**
|
|
1021
|
+
* Returns true if this entity is a parent type in an IS-A relationship (has child entities).
|
|
1022
|
+
*/
|
|
1023
|
+
get IsParentType() {
|
|
1024
|
+
return this.ChildEntities.length > 0;
|
|
1025
|
+
}
|
|
1026
|
+
/**
|
|
1027
|
+
* Returns all fields from all parent entities in the IS-A chain, excluding primary keys,
|
|
1028
|
+
* virtual fields, and timestamp fields (__mj_ prefixed). These represent the inherited
|
|
1029
|
+
* fields that should be available on child entities.
|
|
1030
|
+
*/
|
|
1031
|
+
get AllParentFields() {
|
|
1032
|
+
const fields = [];
|
|
1033
|
+
for (const parent of this.ParentChain) {
|
|
1034
|
+
fields.push(...parent.Fields.filter(f => !f.IsPrimaryKey && !f.Name.startsWith('__mj_') && !f.IsVirtual));
|
|
1035
|
+
}
|
|
1036
|
+
return fields;
|
|
1037
|
+
}
|
|
1038
|
+
/**
|
|
1039
|
+
* Returns a cached Set of field names that belong to parent entities in the IS-A chain,
|
|
1040
|
+
* including the shared primary key(s). Used for efficient field routing in
|
|
1041
|
+
* BaseEntity.Set/Get/SetMany/Hydrate operations.
|
|
1042
|
+
* The Set enables O(1) lookup to determine if a field should be routed to the parent entity.
|
|
1043
|
+
*
|
|
1044
|
+
* Note: AllParentFields excludes PKs (they aren't "inherited data" fields), but the
|
|
1045
|
+
* routing set must include them so that SetMany and Hydrate can forward the shared
|
|
1046
|
+
* IS-A primary key to parent entities.
|
|
1047
|
+
*/
|
|
1048
|
+
get ParentEntityFieldNames() {
|
|
1049
|
+
if (this._parentEntityFieldNamesCache !== null)
|
|
1050
|
+
return this._parentEntityFieldNamesCache;
|
|
1051
|
+
const names = this.AllParentFields.map(f => f.Name);
|
|
1052
|
+
// Add shared PK names from the immediate parent — these are excluded from
|
|
1053
|
+
// AllParentFields but must be routed so parent entities receive their identity.
|
|
1054
|
+
const parentEntity = this.ParentEntityInfo;
|
|
1055
|
+
if (parentEntity) {
|
|
1056
|
+
for (const pk of parentEntity.PrimaryKeys) {
|
|
1057
|
+
if (!names.includes(pk.Name)) {
|
|
1058
|
+
names.push(pk.Name);
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
this._parentEntityFieldNamesCache = new Set(names);
|
|
1063
|
+
return this._parentEntityFieldNamesCache;
|
|
1064
|
+
}
|
|
963
1065
|
/**
|
|
964
1066
|
* Returns the Permissions for this entity for a given user, based on the roles the user is part of
|
|
965
1067
|
* @param user
|
|
@@ -1008,19 +1110,19 @@ class EntityInfo extends baseInfo_1.BaseInfo {
|
|
|
1008
1110
|
const roleMatch = user.UserRoles?.find((r) => r.RoleID === ep.RoleID);
|
|
1009
1111
|
if (roleMatch) { // user has this role
|
|
1010
1112
|
switch (type) {
|
|
1011
|
-
case
|
|
1113
|
+
case EntityPermissionType.Create:
|
|
1012
1114
|
if (!ep.CreateRLSFilterID)
|
|
1013
1115
|
return true;
|
|
1014
1116
|
break;
|
|
1015
|
-
case
|
|
1117
|
+
case EntityPermissionType.Read:
|
|
1016
1118
|
if (!ep.ReadRLSFilterID)
|
|
1017
1119
|
return true;
|
|
1018
1120
|
break;
|
|
1019
|
-
case
|
|
1121
|
+
case EntityPermissionType.Update:
|
|
1020
1122
|
if (!ep.UpdateRLSFilterID)
|
|
1021
1123
|
return true;
|
|
1022
1124
|
break;
|
|
1023
|
-
case
|
|
1125
|
+
case EntityPermissionType.Delete:
|
|
1024
1126
|
if (!ep.DeleteRLSFilterID)
|
|
1025
1127
|
return true;
|
|
1026
1128
|
break;
|
|
@@ -1043,19 +1145,19 @@ class EntityInfo extends baseInfo_1.BaseInfo {
|
|
|
1043
1145
|
if (roleMatch) { // user has this role
|
|
1044
1146
|
let matchObject = null;
|
|
1045
1147
|
switch (type) {
|
|
1046
|
-
case
|
|
1148
|
+
case EntityPermissionType.Create:
|
|
1047
1149
|
if (ep.CreateRLSFilterID)
|
|
1048
1150
|
matchObject = ep.CreateRLSFilterObject;
|
|
1049
1151
|
break;
|
|
1050
|
-
case
|
|
1152
|
+
case EntityPermissionType.Read:
|
|
1051
1153
|
if (ep.ReadRLSFilterID)
|
|
1052
1154
|
matchObject = ep.ReadRLSFilterObject;
|
|
1053
1155
|
break;
|
|
1054
|
-
case
|
|
1156
|
+
case EntityPermissionType.Update:
|
|
1055
1157
|
if (ep.UpdateRLSFilterID)
|
|
1056
1158
|
matchObject = ep.UpdateRLSFilterObject;
|
|
1057
1159
|
break;
|
|
1058
|
-
case
|
|
1160
|
+
case EntityPermissionType.Delete:
|
|
1059
1161
|
if (ep.DeleteRLSFilterID)
|
|
1060
1162
|
matchObject = ep.DeleteRLSFilterObject;
|
|
1061
1163
|
break;
|
|
@@ -1436,11 +1538,16 @@ class EntityInfo extends baseInfo_1.BaseInfo {
|
|
|
1436
1538
|
this.ParentEntity = null;
|
|
1437
1539
|
this.ParentBaseTable = null;
|
|
1438
1540
|
this.ParentBaseView = null;
|
|
1541
|
+
this._FieldCategories = null;
|
|
1439
1542
|
this._hasIdField = false;
|
|
1440
1543
|
this._virtualCount = 0;
|
|
1441
1544
|
this._manyToManyCount = 0;
|
|
1442
1545
|
this._oneToManyCount = 0;
|
|
1443
1546
|
this._floatCount = 0;
|
|
1547
|
+
// Cache for ParentChain to avoid repeated walks
|
|
1548
|
+
this._parentChainCache = null;
|
|
1549
|
+
// Cache for ParentEntityFieldNames
|
|
1550
|
+
this._parentEntityFieldNamesCache = null;
|
|
1444
1551
|
if (initData) {
|
|
1445
1552
|
this.copyInitData(initData);
|
|
1446
1553
|
// do some special handling to create class instances instead of just data objects
|
|
@@ -1466,6 +1573,8 @@ class EntityInfo extends baseInfo_1.BaseInfo {
|
|
|
1466
1573
|
if (es) {
|
|
1467
1574
|
es.map((s) => this._Settings.push(new EntitySettingInfo(s)));
|
|
1468
1575
|
}
|
|
1576
|
+
// auto-populate FieldCategories from the FieldCategoryInfo setting
|
|
1577
|
+
this._FieldCategories = this.parseFieldCategoriesFromSettings();
|
|
1469
1578
|
// copy the Related Entities
|
|
1470
1579
|
this._RelatedEntities = [];
|
|
1471
1580
|
const er = initData.EntityRelationships || initData._RelatedEntities;
|
|
@@ -1525,47 +1634,65 @@ class EntityInfo extends baseInfo_1.BaseInfo {
|
|
|
1525
1634
|
this._oneToManyCount = oneToManyCount;
|
|
1526
1635
|
}
|
|
1527
1636
|
catch (e) {
|
|
1528
|
-
|
|
1637
|
+
LogError(e);
|
|
1638
|
+
}
|
|
1639
|
+
}
|
|
1640
|
+
/**
|
|
1641
|
+
* Parses FieldCategoryInfo from EntitySettings, with legacy FieldCategoryIcons fallback.
|
|
1642
|
+
* Called once during construction so the result is cached on _FieldCategories.
|
|
1643
|
+
*/
|
|
1644
|
+
parseFieldCategoriesFromSettings() {
|
|
1645
|
+
if (!this._Settings || this._Settings.length === 0) {
|
|
1646
|
+
return null;
|
|
1647
|
+
}
|
|
1648
|
+
// Try new format first
|
|
1649
|
+
const infoSetting = this._Settings.find(s => s.Name === 'FieldCategoryInfo');
|
|
1650
|
+
if (infoSetting?.Value) {
|
|
1651
|
+
const parsed = SafeJSONParse(infoSetting.Value, false);
|
|
1652
|
+
if (parsed) {
|
|
1653
|
+
return parsed;
|
|
1654
|
+
}
|
|
1655
|
+
}
|
|
1656
|
+
// Fallback to legacy FieldCategoryIcons format (icon-only map)
|
|
1657
|
+
const iconSetting = this._Settings.find(s => s.Name === 'FieldCategoryIcons');
|
|
1658
|
+
if (iconSetting?.Value) {
|
|
1659
|
+
const icons = SafeJSONParse(iconSetting.Value, false);
|
|
1660
|
+
if (icons) {
|
|
1661
|
+
const result = {};
|
|
1662
|
+
for (const [category, icon] of Object.entries(icons)) {
|
|
1663
|
+
result[category] = { icon, description: '' };
|
|
1664
|
+
}
|
|
1665
|
+
return result;
|
|
1666
|
+
}
|
|
1529
1667
|
}
|
|
1668
|
+
return null;
|
|
1530
1669
|
}
|
|
1531
1670
|
}
|
|
1532
|
-
exports.EntityInfo = EntityInfo;
|
|
1533
|
-
EntityInfo.__createdAtFieldName = '__mj_CreatedAt';
|
|
1534
|
-
EntityInfo.__updatedAtFieldName = '__mj_UpdatedAt';
|
|
1535
|
-
EntityInfo.__deletedAtFieldName = '__mj_DeletedAt';
|
|
1536
1671
|
// Re-export validation types from @memberjunction/global for backward compatibility
|
|
1537
|
-
|
|
1538
|
-
Object.defineProperty(exports, "ValidationErrorType", { enumerable: true, get: function () { return global_2.ValidationErrorType; } });
|
|
1539
|
-
Object.defineProperty(exports, "ValidationErrorInfo", { enumerable: true, get: function () { return global_2.ValidationErrorInfo; } });
|
|
1540
|
-
Object.defineProperty(exports, "ValidationResult", { enumerable: true, get: function () { return global_2.ValidationResult; } });
|
|
1672
|
+
export { ValidationErrorType, ValidationErrorInfo, ValidationResult } from '@memberjunction/global';
|
|
1541
1673
|
/**
|
|
1542
1674
|
* Information about the link between two entities
|
|
1543
1675
|
*/
|
|
1544
|
-
class EntityDependency {
|
|
1676
|
+
export class EntityDependency {
|
|
1545
1677
|
}
|
|
1546
|
-
exports.EntityDependency = EntityDependency;
|
|
1547
1678
|
/**
|
|
1548
1679
|
* Information about the link between two records
|
|
1549
1680
|
*/
|
|
1550
|
-
class RecordDependency {
|
|
1681
|
+
export class RecordDependency {
|
|
1551
1682
|
}
|
|
1552
|
-
exports.RecordDependency = RecordDependency;
|
|
1553
1683
|
/**
|
|
1554
1684
|
* Information about a merge request including the entity, the surviving record and the records to merge into the surviving record. Additionally, there is an optional field map that can be used to override field values in the surviving record to values specified.
|
|
1555
1685
|
*/
|
|
1556
|
-
class RecordMergeRequest {
|
|
1686
|
+
export class RecordMergeRequest {
|
|
1557
1687
|
}
|
|
1558
|
-
exports.RecordMergeRequest = RecordMergeRequest;
|
|
1559
1688
|
/**
|
|
1560
1689
|
* The result of a merge request for a single record
|
|
1561
1690
|
*/
|
|
1562
|
-
class RecordMergeDetailResult {
|
|
1691
|
+
export class RecordMergeDetailResult {
|
|
1563
1692
|
}
|
|
1564
|
-
exports.RecordMergeDetailResult = RecordMergeDetailResult;
|
|
1565
1693
|
/**
|
|
1566
1694
|
* The result of a merge request
|
|
1567
1695
|
*/
|
|
1568
|
-
class RecordMergeResult {
|
|
1696
|
+
export class RecordMergeResult {
|
|
1569
1697
|
}
|
|
1570
|
-
exports.RecordMergeResult = RecordMergeResult;
|
|
1571
1698
|
//# sourceMappingURL=entityInfo.js.map
|