@contrail/flexplm 1.4.0-alpha.6954f61 → 1.5.0-alpha.0d65410
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/CHANGELOG.md +5 -0
- package/lib/transform/identifier-conversion.js +1 -1
- package/lib/transform/identifier-conversion.spec.js +31 -0
- package/lib/util/config-defaults.d.ts +18 -0
- package/lib/util/config-defaults.js +22 -15
- package/lib/util/config-defaults.spec.js +47 -0
- package/lib/util/data-converter.d.ts +5 -0
- package/lib/util/data-converter.js +68 -33
- package/lib/util/data-converter.spec.js +428 -0
- package/lib/util/type-defaults.d.ts +3 -0
- package/lib/util/type-defaults.js +32 -4
- package/lib/util/type-defaults.spec.js +110 -0
- package/package.json +1 -1
- package/src/transform/identifier-conversion.spec.ts +32 -0
- package/src/transform/identifier-conversion.ts +1 -1
- package/src/util/config-defaults.spec.ts +53 -0
- package/src/util/config-defaults.ts +25 -16
- package/src/util/data-converter.spec.ts +502 -0
- package/src/util/data-converter.ts +90 -37
- package/src/util/type-defaults.spec.ts +128 -0
- package/src/util/type-defaults.ts +45 -6
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,11 @@ Versioning follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [1.5.0] - 2026-05-12
|
|
11
|
+
### Added
|
|
12
|
+
- Added support for Inbound `LCSMaterial` to sync to the entity class `item` with type path `item:material` and `itemNumber` as identifier. This is controlled by an `LCSMaterial.processAsItem` (default `false`) config default.
|
|
13
|
+
- Added optional identity-service lookup in `DataConverter.setObjectReferenceValue` for resolving inbound `object_reference` values. Enabled per referenced entity type via `config.search.<entityType>.useIdentityServiceForInboundData`. When enabled the reference is resolved via the identity service using a uniqueness pool key; otherwise behavior falls through to the existing `getAllObjectReferences` query path.
|
|
14
|
+
|
|
10
15
|
## [1.4.0] - 2026-05-06
|
|
11
16
|
### Added
|
|
12
17
|
- Added `getEntityUsingIdentityService` method to `BaseEntityProcessor` for looking up entities via the identity service using a pool key and property criteria. Returns the resolved entity from the identity's `entityReference`, `undefined` if not found, or throws if multiple matches exist.
|
|
@@ -201,7 +201,7 @@ class IdentifierConversion {
|
|
|
201
201
|
}
|
|
202
202
|
static async getItemCriteriaFromObject(transformMapFile, mapFileUtil, dc, object) {
|
|
203
203
|
const criteria = await IdentifierConversion.getEntityCriteriaFromObject(transformMapFile, mapFileUtil, dc, object);
|
|
204
|
-
const roles = (object.flexPLMObjectClass
|
|
204
|
+
const roles = (['LCSProduct', 'LCSMaterial'].includes(object.flexPLMObjectClass)) ? 'family' : 'color';
|
|
205
205
|
criteria['roles'] = roles;
|
|
206
206
|
return criteria;
|
|
207
207
|
}
|
|
@@ -4,6 +4,7 @@ const transform_data_1 = require("@contrail/transform-data");
|
|
|
4
4
|
const identifier_conversion_1 = require("./identifier-conversion");
|
|
5
5
|
const data_converter_1 = require("../util/data-converter");
|
|
6
6
|
const sdk_1 = require("@contrail/sdk");
|
|
7
|
+
const type_defaults_1 = require("../util/type-defaults");
|
|
7
8
|
const mapFile1Data = require('./identifier-conversion-spec-mockData');
|
|
8
9
|
const mapFile1Mappings = mapFile1Data?.mapping;
|
|
9
10
|
const mapFile2Mappings = mapFile1Data?.mapping2;
|
|
@@ -296,6 +297,36 @@ describe('getItemCriteriaFromObject', () => {
|
|
|
296
297
|
}
|
|
297
298
|
}
|
|
298
299
|
});
|
|
300
|
+
it('should return the item family criteria from the object -LCSMaterial', async () => {
|
|
301
|
+
const object = {
|
|
302
|
+
"flexPLMObjectClass": "LCSMaterial",
|
|
303
|
+
"flexPLMTypePath": "Material\\form",
|
|
304
|
+
"itemNumber": "MAT-100"
|
|
305
|
+
};
|
|
306
|
+
const criteriaObject = {
|
|
307
|
+
flexPLMObjectClass: 'LCSMaterial',
|
|
308
|
+
itemNumber: 'MAT-100',
|
|
309
|
+
flexPLMTypePath: 'Material\\form',
|
|
310
|
+
};
|
|
311
|
+
const resultsObject = {
|
|
312
|
+
roles: 'family',
|
|
313
|
+
itemNumber: 'MAT-100'
|
|
314
|
+
};
|
|
315
|
+
let getEntityValuesSpyOn = undefined;
|
|
316
|
+
type_defaults_1.TypeDefaults.applyConfig({ LCSMaterial: { processAsItem: true } });
|
|
317
|
+
try {
|
|
318
|
+
getEntityValuesSpyOn = jest.spyOn(dc, 'getEntityValues');
|
|
319
|
+
const result = await identifier_conversion_1.IdentifierConversion.getItemCriteriaFromObject(transformMapFile1, mapFileUtil, dc, object);
|
|
320
|
+
expect(getEntityValuesSpyOn).toHaveBeenCalledWith('LCSMaterial', criteriaObject, []);
|
|
321
|
+
expect(result).toEqual(resultsObject);
|
|
322
|
+
}
|
|
323
|
+
finally {
|
|
324
|
+
if (getEntityValuesSpyOn) {
|
|
325
|
+
getEntityValuesSpyOn.mockRestore();
|
|
326
|
+
}
|
|
327
|
+
type_defaults_1.TypeDefaults.applyConfig({});
|
|
328
|
+
}
|
|
329
|
+
});
|
|
299
330
|
it('should return the item option criteria from the object -uniqueIdentifierA, uniqueIdentifierB', async () => {
|
|
300
331
|
const object = {
|
|
301
332
|
"flexBoolean": false,
|
|
@@ -3,6 +3,24 @@ export declare class ConfigDefaults {
|
|
|
3
3
|
static NEED_CONFIG_VALUES: string;
|
|
4
4
|
static STATIC_CONFIG_CACHE: {};
|
|
5
5
|
static setConfigDefaults(config: any): Promise<FCConfig>;
|
|
6
|
+
static getDefaultConfig(): {
|
|
7
|
+
urlContext: string;
|
|
8
|
+
sendMode: {
|
|
9
|
+
ASYNC_PUBLISH_SEASON: string;
|
|
10
|
+
};
|
|
11
|
+
itemPreDevelopmentLifecycleStages: string[];
|
|
12
|
+
identifierAtts: {
|
|
13
|
+
LCSProduct: string[];
|
|
14
|
+
LCSSeason: string[];
|
|
15
|
+
LCSSKU: string[];
|
|
16
|
+
};
|
|
17
|
+
LCSMaterial: {
|
|
18
|
+
processAsItem: boolean;
|
|
19
|
+
};
|
|
20
|
+
csrfEndpoint: string;
|
|
21
|
+
vibeEventEndpoint: string;
|
|
22
|
+
payloadDefaultAsArray: boolean;
|
|
23
|
+
};
|
|
6
24
|
static getConfigFile(fileId: string): Promise<any>;
|
|
7
25
|
static isPropertyTrue(value: any): boolean;
|
|
8
26
|
static clearConfigCache(): void;
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.ConfigDefaults = void 0;
|
|
4
4
|
const sdk_1 = require("@contrail/sdk");
|
|
5
5
|
const util_1 = require("@contrail/util");
|
|
6
|
+
const type_defaults_1 = require("./type-defaults");
|
|
6
7
|
class ConfigDefaults {
|
|
7
8
|
static async setConfigDefaults(config) {
|
|
8
9
|
if (!config.apiHost || !config.userName || !config.password) {
|
|
@@ -14,7 +15,24 @@ class ConfigDefaults {
|
|
|
14
15
|
else if (Object.keys(config).includes('itemPreDevelopmentLifecycleStages')) {
|
|
15
16
|
delete config['itemPreDevelopmentLifecycleStages'];
|
|
16
17
|
}
|
|
17
|
-
const
|
|
18
|
+
const configArr = [ConfigDefaults.getDefaultConfig()];
|
|
19
|
+
if (config.configFile) {
|
|
20
|
+
const fileConfig = await ConfigDefaults.getConfigFile(config.configFile);
|
|
21
|
+
configArr.push(fileConfig);
|
|
22
|
+
}
|
|
23
|
+
configArr.push(config);
|
|
24
|
+
const outputConfig = util_1.ObjectUtil.mergeDeep({}, ...configArr);
|
|
25
|
+
const uName = outputConfig.userName;
|
|
26
|
+
const pass = outputConfig.password;
|
|
27
|
+
outputConfig.userName = () => uName;
|
|
28
|
+
outputConfig.password = () => pass;
|
|
29
|
+
outputConfig['OOBvibeEventEndpoint'] = '/rfa/vibeiq/vibeEvents';
|
|
30
|
+
type_defaults_1.TypeDefaults.applyConfig(outputConfig);
|
|
31
|
+
console.log('outputConfig: ' + JSON.stringify(outputConfig));
|
|
32
|
+
return outputConfig;
|
|
33
|
+
}
|
|
34
|
+
static getDefaultConfig() {
|
|
35
|
+
return {
|
|
18
36
|
urlContext: '/Windchill',
|
|
19
37
|
sendMode: {
|
|
20
38
|
ASYNC_PUBLISH_SEASON: 'vibeiqfile'
|
|
@@ -25,24 +43,13 @@ class ConfigDefaults {
|
|
|
25
43
|
LCSSeason: ['flexPLMSeasonName'],
|
|
26
44
|
LCSSKU: ['itemNumber']
|
|
27
45
|
},
|
|
46
|
+
LCSMaterial: {
|
|
47
|
+
processAsItem: false
|
|
48
|
+
},
|
|
28
49
|
csrfEndpoint: '/servlet/rest/security/csrf',
|
|
29
50
|
vibeEventEndpoint: '/rfa/vibeiq/vibeEvents',
|
|
30
51
|
payloadDefaultAsArray: true
|
|
31
52
|
};
|
|
32
|
-
const configArr = [defaultConfig];
|
|
33
|
-
if (config.configFile) {
|
|
34
|
-
const fileConfig = await ConfigDefaults.getConfigFile(config.configFile);
|
|
35
|
-
configArr.push(fileConfig);
|
|
36
|
-
}
|
|
37
|
-
configArr.push(config);
|
|
38
|
-
const outputConfig = util_1.ObjectUtil.mergeDeep({}, ...configArr);
|
|
39
|
-
const uName = outputConfig.userName;
|
|
40
|
-
const pass = outputConfig.password;
|
|
41
|
-
outputConfig.userName = () => uName;
|
|
42
|
-
outputConfig.password = () => pass;
|
|
43
|
-
outputConfig['OOBvibeEventEndpoint'] = '/rfa/vibeiq/vibeEvents';
|
|
44
|
-
console.log('outputConfig: ' + JSON.stringify(outputConfig));
|
|
45
|
-
return outputConfig;
|
|
46
53
|
}
|
|
47
54
|
static async getConfigFile(fileId) {
|
|
48
55
|
try {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const config_defaults_1 = require("./config-defaults");
|
|
4
|
+
const type_defaults_1 = require("./type-defaults");
|
|
4
5
|
let entityObject = {};
|
|
5
6
|
jest.mock('@contrail/sdk', () => {
|
|
6
7
|
return {
|
|
@@ -296,6 +297,52 @@ describe('all tests', () => {
|
|
|
296
297
|
expect(config_defaults_1.ConfigDefaults.isPropertyTrue(1)).toBe(false);
|
|
297
298
|
});
|
|
298
299
|
});
|
|
300
|
+
describe('getDefaultConfig', () => {
|
|
301
|
+
it('returns LCSMaterial.processAsItem=false by default', () => {
|
|
302
|
+
const dc = config_defaults_1.ConfigDefaults.getDefaultConfig();
|
|
303
|
+
expect(dc.LCSMaterial).toBeDefined();
|
|
304
|
+
expect(dc.LCSMaterial.processAsItem).toBe(false);
|
|
305
|
+
});
|
|
306
|
+
it('returns a fresh object each call (no shared reference)', () => {
|
|
307
|
+
const a = config_defaults_1.ConfigDefaults.getDefaultConfig();
|
|
308
|
+
const b = config_defaults_1.ConfigDefaults.getDefaultConfig();
|
|
309
|
+
expect(a).not.toBe(b);
|
|
310
|
+
expect(a.LCSMaterial).not.toBe(b.LCSMaterial);
|
|
311
|
+
a.LCSMaterial.processAsItem = true;
|
|
312
|
+
expect(b.LCSMaterial.processAsItem).toBe(false);
|
|
313
|
+
});
|
|
314
|
+
});
|
|
315
|
+
describe('setConfigDefaults - LCSMaterial', () => {
|
|
316
|
+
const config = {
|
|
317
|
+
apiHost: 'http://test.com',
|
|
318
|
+
userName: 'vibeiq',
|
|
319
|
+
password: 'vibeiq'
|
|
320
|
+
};
|
|
321
|
+
it('LCSMaterial.processAsItem-get default', async () => {
|
|
322
|
+
const startConfig = Object.assign({}, config);
|
|
323
|
+
const fcConfig = await config_defaults_1.ConfigDefaults.setConfigDefaults(startConfig);
|
|
324
|
+
expect(fcConfig.LCSMaterial.processAsItem).toBe(false);
|
|
325
|
+
});
|
|
326
|
+
it('LCSMaterial.processAsItem-override', async () => {
|
|
327
|
+
const startConfig = Object.assign({}, config);
|
|
328
|
+
startConfig.LCSMaterial = { processAsItem: true };
|
|
329
|
+
const fcConfig = await config_defaults_1.ConfigDefaults.setConfigDefaults(startConfig);
|
|
330
|
+
expect(fcConfig.LCSMaterial.processAsItem).toBe(true);
|
|
331
|
+
});
|
|
332
|
+
it('applies LCSMaterial.processAsItem to TypeDefaults', async () => {
|
|
333
|
+
try {
|
|
334
|
+
const startConfig = Object.assign({}, config, { LCSMaterial: { processAsItem: true } });
|
|
335
|
+
await config_defaults_1.ConfigDefaults.setConfigDefaults(startConfig);
|
|
336
|
+
expect(type_defaults_1.TypeDefaults.processLCSMaterialAsItem).toBe(true);
|
|
337
|
+
const defaultStart = Object.assign({}, config);
|
|
338
|
+
await config_defaults_1.ConfigDefaults.setConfigDefaults(defaultStart);
|
|
339
|
+
expect(type_defaults_1.TypeDefaults.processLCSMaterialAsItem).toBe(false);
|
|
340
|
+
}
|
|
341
|
+
finally {
|
|
342
|
+
type_defaults_1.TypeDefaults.applyConfig({});
|
|
343
|
+
}
|
|
344
|
+
});
|
|
345
|
+
});
|
|
299
346
|
describe('getConfigFile', () => {
|
|
300
347
|
beforeEach(() => {
|
|
301
348
|
config_defaults_1.ConfigDefaults.clearConfigCache();
|
|
@@ -28,6 +28,11 @@ export declare class DataConverter {
|
|
|
28
28
|
setEnumerationKeys(prop: any, nd: any, matchByDisplay: any): any;
|
|
29
29
|
getPersistableChanges(entity: object, changes: object): object;
|
|
30
30
|
setObjectReferenceValue(prop: any, nd: any): Promise<any>;
|
|
31
|
+
private applyInboundTransformMap;
|
|
32
|
+
private buildObjectReferenceContext;
|
|
33
|
+
private lookupObjectReferenceViaIdentityService;
|
|
34
|
+
private lookupObjectReferenceViaQuery;
|
|
35
|
+
private pickSingleResult;
|
|
31
36
|
getAllObjectReferences(entityType: string, rootTypeCriteria: any, postProcessCriteria?: any): Promise<any[]>;
|
|
32
37
|
checkKeysAndValues(criteria: any, arrayOfObjects: any, entityTypePath: any): any[];
|
|
33
38
|
filterOutArchivedAndTrashedEntities(entities: any[]): any[];
|
|
@@ -7,6 +7,7 @@ const app_framework_1 = require("@contrail/app-framework");
|
|
|
7
7
|
const util_1 = require("@contrail/util");
|
|
8
8
|
const type_conversion_utils_1 = require("./type-conversion-utils");
|
|
9
9
|
const map_utils_1 = require("./map-utils");
|
|
10
|
+
const config_defaults_1 = require("./config-defaults");
|
|
10
11
|
class DataConverter {
|
|
11
12
|
static clearStaticUserCache() {
|
|
12
13
|
DataConverter.staticUserCache = {};
|
|
@@ -235,7 +236,7 @@ class DataConverter {
|
|
|
235
236
|
const type = await this.typeUtils.getByRootAndPath(tco);
|
|
236
237
|
const typePath = type['typePath'];
|
|
237
238
|
if (typePath && (typePath.startsWith('item') || typePath.startsWith('project-item'))) {
|
|
238
|
-
if (['LCSProduct', 'LCSProductSeasonLink'].includes(objectClass)) {
|
|
239
|
+
if (['LCSProduct', 'LCSProductSeasonLink', 'LCSMaterial'].includes(objectClass)) {
|
|
239
240
|
entityValues['roles'] = ['family'];
|
|
240
241
|
}
|
|
241
242
|
else {
|
|
@@ -347,30 +348,51 @@ class DataConverter {
|
|
|
347
348
|
return diffValues;
|
|
348
349
|
}
|
|
349
350
|
async setObjectReferenceValue(prop, nd) {
|
|
350
|
-
let objectReferenceId = "";
|
|
351
351
|
if (!nd) {
|
|
352
|
-
return
|
|
352
|
+
return "";
|
|
353
|
+
}
|
|
354
|
+
nd = await this.applyInboundTransformMap(nd);
|
|
355
|
+
const ctx = await this.buildObjectReferenceContext(prop, nd);
|
|
356
|
+
if (!ctx) {
|
|
357
|
+
return "";
|
|
358
|
+
}
|
|
359
|
+
if (this.objRefCache[ctx.cacheKey]) {
|
|
360
|
+
if (app_framework_1.Logger.isDebugOn()) {
|
|
361
|
+
console.debug(`object reference cache hit: ${ctx.cacheKey}`);
|
|
362
|
+
}
|
|
363
|
+
return this.objRefCache[ctx.cacheKey];
|
|
353
364
|
}
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
365
|
+
const objectReferenceId = ctx.useIdentityService
|
|
366
|
+
? await this.lookupObjectReferenceViaIdentityService(ctx, nd)
|
|
367
|
+
: await this.lookupObjectReferenceViaQuery(ctx);
|
|
368
|
+
if (objectReferenceId) {
|
|
369
|
+
this.objRefCache[ctx.cacheKey] = objectReferenceId;
|
|
357
370
|
}
|
|
371
|
+
return objectReferenceId;
|
|
372
|
+
}
|
|
373
|
+
async applyInboundTransformMap(nd) {
|
|
374
|
+
if (!this.transformMapFile) {
|
|
375
|
+
return nd;
|
|
376
|
+
}
|
|
377
|
+
const mapKey = await type_conversion_utils_1.TypeConversionUtils.getMapKeyFromObject(this.transformMapFile, this.mapFileUtil, nd, type_conversion_utils_1.TypeConversionUtils.FLEX2VIBE_DIRECTION);
|
|
378
|
+
return map_utils_1.MapUtil.applyTransformMap(this.transformMapFile, this.mapFileUtil, nd, mapKey, type_conversion_utils_1.TypeConversionUtils.FLEX2VIBE_DIRECTION);
|
|
379
|
+
}
|
|
380
|
+
async buildObjectReferenceContext(prop, nd) {
|
|
358
381
|
const entityType = prop['referencedTypeRootSlug'];
|
|
359
382
|
const entityTypePath = prop['referencedTypePath'];
|
|
360
383
|
const entityKeys = Object.keys(nd);
|
|
361
384
|
const identifierKeys = await type_conversion_utils_1.TypeConversionUtils.getIdentifierPropertiesFromObject(this.transformMapFile, this.mapFileUtil, nd);
|
|
362
385
|
const hasAllIdentifiers = identifierKeys.every(key => entityKeys.includes(key));
|
|
363
|
-
if (identifierKeys.length
|
|
386
|
+
if (identifierKeys.length === 0 || !hasAllIdentifiers) {
|
|
364
387
|
console.warn(`The inbound ${entityType} for prop '${prop['slug']}' doesnt have all "identifier" properties, so there is no processing. Identifier properties: ${identifierKeys}`);
|
|
365
|
-
return
|
|
388
|
+
return null;
|
|
366
389
|
}
|
|
367
390
|
const rootType = await this.typeUtils.getByRootAndPath({ root: entityType });
|
|
368
391
|
const rootTypeProps = this.typeUtils.filterTypeProperties(rootType, nd);
|
|
369
|
-
|
|
370
|
-
|
|
392
|
+
const rootTypeCriteria = {};
|
|
393
|
+
const typeCriteria = {};
|
|
371
394
|
identifierKeys.forEach(keyName => {
|
|
372
|
-
|
|
373
|
-
if (foundInObjects) {
|
|
395
|
+
if (rootTypeProps.some(obj => obj.slug === keyName)) {
|
|
374
396
|
rootTypeCriteria[keyName] = nd[keyName];
|
|
375
397
|
}
|
|
376
398
|
else {
|
|
@@ -379,30 +401,43 @@ class DataConverter {
|
|
|
379
401
|
});
|
|
380
402
|
const combinedCriteria = { ...rootTypeCriteria, ...typeCriteria, typePath: entityTypePath };
|
|
381
403
|
const cacheKey = Object.values(combinedCriteria).join('_');
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
404
|
+
const rolesIsTypeDiscriminator = entityType === 'item' || entityType === 'project-item';
|
|
405
|
+
const identityLookupKeys = rolesIsTypeDiscriminator
|
|
406
|
+
? identifierKeys.filter(key => key !== 'roles')
|
|
407
|
+
: identifierKeys;
|
|
408
|
+
const useIdentityService = config_defaults_1.ConfigDefaults.isPropertyTrue(this.config?.search?.[entityType]?.useIdentityServiceForInboundData)
|
|
409
|
+
&& identityLookupKeys.length === 1;
|
|
410
|
+
return { entityType, entityTypePath, rootTypeCriteria, typeCriteria, combinedCriteria, cacheKey, useIdentityService, identityLookupKeys };
|
|
411
|
+
}
|
|
412
|
+
async lookupObjectReferenceViaIdentityService(ctx, nd) {
|
|
413
|
+
const propertyName = ctx.identityLookupKeys[0];
|
|
414
|
+
const propertyValue = nd[propertyName];
|
|
415
|
+
const poolKey = await type_conversion_utils_1.TypeConversionUtils.getUniquenessPoolKeyFromObject(this.transformMapFile, this.mapFileUtil, nd);
|
|
416
|
+
const identityResults = await new sdk_1.Entities().get({
|
|
417
|
+
entityName: 'identity',
|
|
418
|
+
criteria: { poolKey, propertyName, propertyValue }
|
|
419
|
+
}) ?? [];
|
|
420
|
+
const match = this.pickSingleResult(identityResults, ctx.combinedCriteria);
|
|
421
|
+
return match ? match.entityReference.split(':')[1] : "";
|
|
422
|
+
}
|
|
423
|
+
async lookupObjectReferenceViaQuery(ctx) {
|
|
424
|
+
let arrObjectReferences = await this.getAllObjectReferences(ctx.entityType, ctx.rootTypeCriteria);
|
|
425
|
+
if (ctx.entityType !== ctx.entityTypePath) {
|
|
426
|
+
arrObjectReferences = this.checkKeysAndValues(ctx.typeCriteria, arrObjectReferences, ctx.entityTypePath);
|
|
399
427
|
}
|
|
400
|
-
|
|
428
|
+
const match = this.pickSingleResult(arrObjectReferences, ctx.combinedCriteria);
|
|
429
|
+
return match ? match.id : "";
|
|
430
|
+
}
|
|
431
|
+
pickSingleResult(results, combinedCriteria) {
|
|
432
|
+
if (!results.length) {
|
|
401
433
|
console.warn(`The passed in object reference criteria ${JSON.stringify(combinedCriteria)} didn't match any entities.`);
|
|
402
|
-
return
|
|
434
|
+
return undefined;
|
|
403
435
|
}
|
|
404
|
-
|
|
405
|
-
|
|
436
|
+
if (results.length > 1) {
|
|
437
|
+
console.warn(`The passed in object reference criteria has duplicate records found ${JSON.stringify(combinedCriteria)}.`);
|
|
438
|
+
return undefined;
|
|
439
|
+
}
|
|
440
|
+
return results[0];
|
|
406
441
|
}
|
|
407
442
|
async getAllObjectReferences(entityType, rootTypeCriteria, postProcessCriteria = null) {
|
|
408
443
|
const entities = new sdk_1.Entities();
|