@contrail/flexplm 1.1.56 → 1.1.58

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.
@@ -0,0 +1,20 @@
1
+ {
2
+ // Use IntelliSense to learn about possible attributes.
3
+ // Hover to view descriptions of existing attributes.
4
+ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5
+ "version": "0.2.0",
6
+ "configurations": [
7
+ {
8
+ "type": "node",
9
+ "request": "launch",
10
+ "name": "Launch Program",
11
+ "skipFiles": [
12
+ "<node_internals>/**"
13
+ ],
14
+ "program": "${workspaceFolder}\\lib\\index.js",
15
+ "outFiles": [
16
+ "${workspaceFolder}/**/*.js"
17
+ ]
18
+ }
19
+ ]
20
+ }
@@ -19,6 +19,8 @@ export declare abstract class BaseEntityProcessor {
19
19
  inbound(event: EntityPayloadType): Promise<any>;
20
20
  handleIncomingUpsert(event: EntityPayloadType): Promise<any>;
21
21
  getInboundStatusMessage(statusObject: any): string;
22
+ queryEntityWithSubTypeCriteria(entityType: string, entityTypePath: string, propertyCriteria: any): Promise<any[]>;
23
+ getRootTypePropertyKeys(rootType: any, propertyCriteria?: any): string[];
22
24
  handleIncomingDelete(event: any): Promise<void>;
23
25
  getTransformedData(event: any): Promise<any>;
24
26
  getUpdatesForEntity(entity: any, inboundData: any): Promise<object>;
@@ -114,6 +114,33 @@ class BaseEntityProcessor {
114
114
  + ', federatedId: ' + statusObject.federatedId
115
115
  + ', orgSlug: ' + this.orgSlug;
116
116
  }
117
+ async queryEntityWithSubTypeCriteria(entityType, entityTypePath, propertyCriteria) {
118
+ if (!entityType || !entityTypePath) {
119
+ throw new Error('type and entityTypePath must be defined');
120
+ }
121
+ if (!propertyCriteria || Object.getOwnPropertyNames(propertyCriteria).length == 0) {
122
+ throw new Error('propertyCriteria must be defined and have at least one property');
123
+ }
124
+ const rootType = await this.typeUtil.getByRootAndPath({ root: entityType });
125
+ const rootTypePropertyKeys = await this.getRootTypePropertyKeys(rootType, propertyCriteria);
126
+ const rootTypeCriteria = { typePath: entityTypePath };
127
+ const subTypeCriteria = {};
128
+ for (const key in propertyCriteria) {
129
+ if (rootTypePropertyKeys.includes(key)) {
130
+ rootTypeCriteria[key] = propertyCriteria[key];
131
+ }
132
+ else {
133
+ subTypeCriteria[key] = propertyCriteria[key];
134
+ }
135
+ }
136
+ const returnedEntities = await this.dc.getAllObjectReferences(entityType, rootTypeCriteria, subTypeCriteria);
137
+ return returnedEntities;
138
+ }
139
+ getRootTypePropertyKeys(rootType, propertyCriteria = null) {
140
+ const props = rootType['typeProperties'];
141
+ const rootTypePropertyKeys = props.map(prop => prop.slug);
142
+ return rootTypePropertyKeys;
143
+ }
117
144
  async handleIncomingDelete(event) {
118
145
  console.warn('delete is not configured', event);
119
146
  }
@@ -4,6 +4,26 @@ const sdk_1 = require("@contrail/sdk");
4
4
  const transform_data_1 = require("@contrail/transform-data");
5
5
  const data_converter_1 = require("../util/data-converter");
6
6
  const base_entity_processor_1 = require("./base-entity-processor");
7
+ const mockRootType = {
8
+ typeProperties: [
9
+ { slug: 'rootText' }
10
+ ]
11
+ };
12
+ const mockTypeUtilGetByRootAndPath = jest.fn((options) => {
13
+ return Promise.resolve(mockRootType);
14
+ });
15
+ jest.mock('@contrail/sdk', () => {
16
+ const origModule = jest.requireActual('@contrail/sdk');
17
+ return {
18
+ __esModule: true,
19
+ ...origModule,
20
+ Types: jest.fn().mockImplementation(() => {
21
+ return {
22
+ getByRootAndPath: mockTypeUtilGetByRootAndPath
23
+ };
24
+ })
25
+ };
26
+ });
7
27
  class TestBaseEntityProcessor extends base_entity_processor_1.BaseEntityProcessor {
8
28
  getIncomingEntity(event, inboundData) {
9
29
  throw new Error("Method not implemented.");
@@ -72,4 +92,78 @@ describe('BaseEntityProcessor', () => {
72
92
  expect(updates).toBeUndefined();
73
93
  });
74
94
  });
95
+ describe('queryEntityWithSubType', () => {
96
+ const config = {};
97
+ const mapFileUtil = new transform_data_1.MapFileUtil(new sdk_1.Entities());
98
+ beforeEach(() => {
99
+ });
100
+ it('entity parameter not set', async () => {
101
+ const btep = new TestBaseEntityProcessor({}, {}, {}, 'test');
102
+ const entity = '';
103
+ const subType = 'test';
104
+ const propertyCriteria = { a: 'val' };
105
+ expect(async () => { await btep.queryEntityWithSubTypeCriteria(entity, subType, propertyCriteria); }).rejects.toThrow();
106
+ });
107
+ it('entityTypePath not set', async () => {
108
+ const btep = new TestBaseEntityProcessor({}, {}, {}, 'test');
109
+ const entity = 'test';
110
+ const subType = '';
111
+ const propertyCriteria = {};
112
+ expect(async () => { await btep.queryEntityWithSubTypeCriteria(entity, subType, propertyCriteria); }).rejects.toThrow();
113
+ });
114
+ it('propertyCriteria not set', async () => {
115
+ const btep = new TestBaseEntityProcessor({}, {}, {}, 'test');
116
+ const entity = 'test';
117
+ const subType = 'test';
118
+ const propertyCriteria = {};
119
+ expect(async () => { await btep.queryEntityWithSubTypeCriteria(entity, subType, propertyCriteria); }).rejects.toThrow();
120
+ });
121
+ it('basic queryEntityWithSubTypeCriteria test', async () => {
122
+ const dc = new data_converter_1.DataConverter(config, mapFileUtil);
123
+ const btep = new TestBaseEntityProcessor(config, dc, mapFileUtil, 'test');
124
+ const entityType = 'custom-entity';
125
+ const entityTypePath = 'custom-entity:sample';
126
+ const rootCriteria = {
127
+ rootText: 'root'
128
+ };
129
+ const subCriteria = {
130
+ sampleText: 'sample'
131
+ };
132
+ const propertyCriteria = Object.assign({}, rootCriteria, subCriteria);
133
+ const rootCriteriaResults = Object.assign({ typePath: entityTypePath }, rootCriteria);
134
+ const mockGetByRootTypeProperties = jest.spyOn(btep, 'getRootTypePropertyKeys').mockReturnValue(['rootText']);
135
+ const mockDCgetAllObjectReferences = jest.spyOn(dc, 'getAllObjectReferences').mockReturnValue(Promise.resolve([]));
136
+ const results = await btep.queryEntityWithSubTypeCriteria(entityType, entityTypePath, propertyCriteria);
137
+ expect(results).toEqual([]);
138
+ expect(mockTypeUtilGetByRootAndPath).toBeCalledTimes(1);
139
+ expect(mockTypeUtilGetByRootAndPath).toBeCalledWith({ root: entityType });
140
+ expect(mockGetByRootTypeProperties).toBeCalledTimes(1);
141
+ expect(mockGetByRootTypeProperties).toBeCalledWith(mockRootType, propertyCriteria);
142
+ expect(mockDCgetAllObjectReferences).toBeCalledTimes(1);
143
+ expect(mockDCgetAllObjectReferences).toBeCalledWith(entityType, rootCriteriaResults, subCriteria);
144
+ });
145
+ });
146
+ describe('getRootTypePropertyKeys', () => {
147
+ it('rootType parameter not set', async () => {
148
+ const btep = new TestBaseEntityProcessor({}, {}, {}, 'test');
149
+ const rootType = '';
150
+ expect(async () => { await btep.getRootTypePropertyKeys(rootType); }).rejects.toThrow();
151
+ });
152
+ it('get keys from rootType.typeProperties', async () => {
153
+ const btep = new TestBaseEntityProcessor({}, {}, {}, 'test');
154
+ const rootType = {
155
+ typeProperties: ['a', 'b']
156
+ };
157
+ const keys = await btep.getRootTypePropertyKeys(rootType);
158
+ expect(keys).not.toEqual(['a', 'b']);
159
+ });
160
+ it('get keys from rootType.typeProperties', async () => {
161
+ const btep = new TestBaseEntityProcessor({}, {}, {}, 'test');
162
+ const rootType = {
163
+ typeProperties: [{ slug: 'a' }, { slug: 'b' }]
164
+ };
165
+ const keys = await btep.getRootTypePropertyKeys(rootType);
166
+ expect(keys).toEqual(['a', 'b']);
167
+ });
168
+ });
75
169
  });
@@ -12,6 +12,7 @@ export declare class BaseProcessPublishAssortment {
12
12
  private config;
13
13
  private mapFileUtil;
14
14
  private transformMapFile;
15
+ protected orgSlug: string;
15
16
  private cache;
16
17
  private assortment;
17
18
  constructor(_config: FCConfig, _dc: DataConverter, _mapFileUtil: MapFileUtil);
@@ -21,6 +21,7 @@ class BaseProcessPublishAssortment {
21
21
  this.dc = _dc;
22
22
  this.mapFileUtil = _mapFileUtil;
23
23
  this.transformMapFile = this.config?.transformMapFile;
24
+ this.orgSlug = this.config?.orgSlug || 'unset-orgSlug';
24
25
  }
25
26
  async process(event) {
26
27
  const assortmentPublishChangeId = event.assortmentPublishChangeId;
@@ -39,7 +40,8 @@ class BaseProcessPublishAssortment {
39
40
  (message.startsWith(BaseProcessPublishAssortment.ASSORTMENT_NO_FED_INFO)) ? event_short_message_status_1.EventShortMessageStatus.NO_FEDERATION_INFO :
40
41
  event_short_message_status_1.EventShortMessageStatus.FAILURE;
41
42
  const processStatus = 'BaseProcessPublishAssortment: ' + eventStatus
42
- + ': assortmentId: ' + event.assortmentId + ': assortmentPublishChangeId: ' + event.assortmentPublishChangeId;
43
+ + ': assortmentId: ' + event.assortmentId + ': assortmentPublishChangeId: ' + event.assortmentPublishChangeId
44
+ + ', orgSlug: ' + this.orgSlug;
43
45
  console.log(JSON.stringify(processStatus));
44
46
  console.log(message);
45
47
  const output = {
@@ -519,7 +521,8 @@ class BaseProcessPublishAssortment {
519
521
  const events = await this.getEventsForPublishChangeData(pcd);
520
522
  if (events.length === 0) {
521
523
  const processStatus = 'BaseProcessPublishAssortment: ' + event_short_message_status_1.EventShortMessageStatus.NO_EVENTS_TO_SEND
522
- + ': assortmentId: ' + pcd.assortmentId + ': assortmentPublishChangeId: ' + pcd.assortmentPublishChangeId;
524
+ + ': assortmentId: ' + pcd.assortmentId + ': assortmentPublishChangeId: ' + pcd.assortmentPublishChangeId
525
+ + ', orgSlug: ' + this.orgSlug;
523
526
  console.log(processStatus);
524
527
  const message = 'No Events to Send; returning';
525
528
  console.log(message);
@@ -532,7 +535,8 @@ class BaseProcessPublishAssortment {
532
535
  const resultsCount = this.getResultsCount(events);
533
536
  const processStatus = 'BaseProcessPublishAssortment: ' + event_short_message_status_1.EventShortMessageStatus.SENDING_EVENTS
534
537
  + ': assortmentId: ' + pcd.assortmentId + ': assortmentPublishChangeId: ' + pcd.assortmentPublishChangeId
535
- + ': resultsCount: ' + JSON.stringify(resultsCount);
538
+ + ': resultsCount: ' + JSON.stringify(resultsCount)
539
+ + ', orgSlug: ' + this.orgSlug;
536
540
  console.log(processStatus);
537
541
  return { results, event, resultsCount };
538
542
  }
@@ -28,7 +28,7 @@ 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
- getAllObjectReferences(entityType: any, rootTypeCriteria: any): Promise<any[]>;
31
+ getAllObjectReferences(entityType: string, rootTypeCriteria: any, postProcessCriteria?: any): Promise<any[]>;
32
32
  checkKeysAndValues(criteria: any, arrayOfObjects: any, entityTypePath: any): any[];
33
33
  setUserListValue(prop: any, nd: any): Promise<any>;
34
34
  getUserByEmail(nd: any): Promise<any>;
@@ -398,22 +398,29 @@ class DataConverter {
398
398
  this.objRefCache[cacheKey] = objectReferenceId;
399
399
  return objectReferenceId;
400
400
  }
401
- async getAllObjectReferences(entityType, rootTypeCriteria) {
401
+ async getAllObjectReferences(entityType, rootTypeCriteria, postProcessCriteria = null) {
402
402
  const entities = new sdk_1.Entities();
403
403
  let loads = [];
404
404
  let nextPageKey;
405
405
  let usedV2 = false;
406
406
  do {
407
+ const take = 1000;
407
408
  const loadPage = await entities.get({
408
409
  entityName: entityType,
409
410
  criteria: rootTypeCriteria,
410
411
  apiVersion: sdk_1.API_VERSION.V2,
412
+ take,
411
413
  nextPageKey,
412
414
  });
413
415
  nextPageKey = loadPage?.nextPageKey;
414
416
  if (Object.keys(loadPage).includes('results')) {
415
417
  usedV2 = true;
416
- loads.push(...loadPage.results);
418
+ let postProcessedResults = loadPage.results;
419
+ if (postProcessCriteria && Object.keys(postProcessCriteria).length !== 0) {
420
+ const subEntityTypePath = rootTypeCriteria.typePath || entityType;
421
+ postProcessedResults = this.checkKeysAndValues(postProcessCriteria, postProcessedResults, subEntityTypePath);
422
+ }
423
+ loads.push(...postProcessedResults);
417
424
  }
418
425
  else {
419
426
  nextPageKey = null;
@@ -430,7 +437,12 @@ class DataConverter {
430
437
  take,
431
438
  skip,
432
439
  });
433
- loads.push(...loadPage);
440
+ let postProcessedResults = loadPage;
441
+ if (postProcessCriteria && Object.keys(postProcessCriteria).length !== 0) {
442
+ const subEntityTypePath = rootTypeCriteria.typePath || entityType;
443
+ postProcessedResults = this.checkKeysAndValues(postProcessCriteria, postProcessedResults, subEntityTypePath);
444
+ }
445
+ loads.push(...postProcessedResults);
434
446
  if (loadPage.length !== take) {
435
447
  done = true;
436
448
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contrail/flexplm",
3
- "version": "1.1.56",
3
+ "version": "1.1.58",
4
4
  "description": "Library used for integration with flexplm.",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -10,7 +10,8 @@
10
10
  "lint": "tslint -p tsconfig.json",
11
11
  "test": "jest",
12
12
  "test-watch": "jest --watch",
13
- "test-debug": "jest --runInBand"
13
+ "test-debug": "jest --runInBand",
14
+ "test-coverage": "jest --coverage"
14
15
  },
15
16
  "keywords": [],
16
17
  "author": "",
@@ -1,9 +1,31 @@
1
- import { Entities } from "@contrail/sdk";
1
+ import { Entities, TypeClientOptions } from "@contrail/sdk";
2
2
  import { MapFileUtil } from "@contrail/transform-data";
3
3
  import { EntityPayloadType, FCConfig } from "../interfaces/interfaces";
4
4
  import { DataConverter } from "../util/data-converter";
5
5
  import { BaseEntityProcessor, IncomingEntityResponse } from "./base-entity-processor";
6
6
 
7
+ const mockRootType = {
8
+ typeProperties: [
9
+ { slug: 'rootText' }
10
+ ]
11
+ };
12
+ const mockTypeUtilGetByRootAndPath = jest.fn((options: TypeClientOptions) => {
13
+ return Promise.resolve(mockRootType);
14
+ });
15
+
16
+ jest.mock('@contrail/sdk', () => {
17
+ const origModule = jest.requireActual('@contrail/sdk');
18
+ return {
19
+ __esModule: true,
20
+ ...origModule,
21
+ Types: jest.fn().mockImplementation(() => {
22
+ return {
23
+ getByRootAndPath: mockTypeUtilGetByRootAndPath
24
+ };
25
+ })
26
+ };
27
+ });
28
+
7
29
  class TestBaseEntityProcessor extends BaseEntityProcessor {
8
30
  protected getIncomingEntity(event: any, inboundData: any): Promise<IncomingEntityResponse> {
9
31
  throw new Error("Method not implemented.");
@@ -77,4 +99,91 @@ describe('BaseEntityProcessor', () =>{
77
99
  expect(updates).toBeUndefined();
78
100
  });
79
101
  });
80
- });
102
+
103
+ describe('queryEntityWithSubType', () =>{
104
+ const config = {} as FCConfig;
105
+ const mapFileUtil = new MapFileUtil(new Entities());
106
+ beforeEach(() =>{
107
+ // jest.clearAllMocks();
108
+ });
109
+ it('entity parameter not set', async () =>{
110
+ const btep = new TestBaseEntityProcessor({} as FCConfig, {} as DataConverter, {} as MapFileUtil, 'test');
111
+ const entity = '';
112
+ const subType = 'test';
113
+ const propertyCriteria = {a:'val'};
114
+ expect(async () => {await btep.queryEntityWithSubTypeCriteria(entity, subType, propertyCriteria)}).rejects.toThrow();
115
+ });
116
+ it('entityTypePath not set', async () =>{
117
+ const btep = new TestBaseEntityProcessor({} as FCConfig, {} as DataConverter, {} as MapFileUtil, 'test');
118
+ const entity = 'test';
119
+ const subType = '';
120
+ const propertyCriteria = {};
121
+ expect(async () => {await btep.queryEntityWithSubTypeCriteria(entity, subType, propertyCriteria)}).rejects.toThrow();
122
+
123
+ });
124
+ it('propertyCriteria not set', async () =>{
125
+ const btep = new TestBaseEntityProcessor({} as FCConfig, {} as DataConverter, {} as MapFileUtil, 'test');
126
+ const entity = 'test';
127
+ const subType = 'test';
128
+ const propertyCriteria = {};
129
+ expect(async () => {await btep.queryEntityWithSubTypeCriteria(entity, subType, propertyCriteria)}).rejects.toThrow();
130
+ });
131
+
132
+ it('basic queryEntityWithSubTypeCriteria test', async () =>{
133
+ const dc = new DataConverter(config, mapFileUtil);
134
+ const btep = new TestBaseEntityProcessor(config, dc, mapFileUtil, 'test');
135
+ const entityType = 'custom-entity';
136
+ const entityTypePath = 'custom-entity:sample';
137
+ const rootCriteria = {
138
+ rootText: 'root'
139
+ };
140
+ const subCriteria = {
141
+ sampleText: 'sample'
142
+ };
143
+ const propertyCriteria = Object.assign({}, rootCriteria, subCriteria);
144
+ const rootCriteriaResults = Object.assign({typePath: entityTypePath}, rootCriteria);
145
+
146
+ const mockGetByRootTypeProperties = jest.spyOn(btep, 'getRootTypePropertyKeys').mockReturnValue(['rootText']);
147
+ const mockDCgetAllObjectReferences = jest.spyOn(dc, 'getAllObjectReferences').mockReturnValue(Promise.resolve([]));
148
+
149
+ const results = await btep.queryEntityWithSubTypeCriteria(entityType, entityTypePath, propertyCriteria);
150
+ expect(results).toEqual([]);
151
+ expect(mockTypeUtilGetByRootAndPath).toBeCalledTimes(1);
152
+ expect(mockTypeUtilGetByRootAndPath).toBeCalledWith({ root: entityType});
153
+ expect(mockGetByRootTypeProperties).toBeCalledTimes(1);
154
+ expect(mockGetByRootTypeProperties).toBeCalledWith(mockRootType, propertyCriteria);
155
+
156
+ expect(mockDCgetAllObjectReferences).toBeCalledTimes(1);
157
+ expect(mockDCgetAllObjectReferences).toBeCalledWith(entityType, rootCriteriaResults, subCriteria);
158
+ });
159
+
160
+ });
161
+
162
+ describe('getRootTypePropertyKeys', () =>{
163
+ it('rootType parameter not set', async () =>{
164
+ const btep = new TestBaseEntityProcessor({} as FCConfig, {} as DataConverter, {} as MapFileUtil, 'test');
165
+ const rootType = '';
166
+ expect(async () => {await btep.getRootTypePropertyKeys(rootType)}).rejects.toThrow();
167
+ });
168
+
169
+ it('get keys from rootType.typeProperties', async () =>{
170
+ const btep = new TestBaseEntityProcessor({} as FCConfig, {} as DataConverter, {} as MapFileUtil, 'test');
171
+ const rootType = {
172
+ typeProperties: ['a', 'b']
173
+ };
174
+ const keys = await btep.getRootTypePropertyKeys(rootType);
175
+ expect(keys).not.toEqual(['a', 'b']);
176
+ });
177
+
178
+ it('get keys from rootType.typeProperties', async () =>{
179
+ const btep = new TestBaseEntityProcessor({} as FCConfig, {} as DataConverter, {} as MapFileUtil, 'test');
180
+ const rootType = {
181
+ typeProperties: [{ slug: 'a'},{slug: 'b'}]
182
+ };
183
+ const keys = await btep.getRootTypePropertyKeys(rootType);
184
+ expect(keys).toEqual(['a', 'b']);
185
+ });
186
+
187
+ });
188
+
189
+ });
@@ -5,6 +5,7 @@ import { FlexPLMConnect,} from '../util/flexplm-connect';
5
5
  import { MapUtil } from '../util/map-utils';
6
6
  import { MapFileUtil } from '@contrail/transform-data';
7
7
  import { Entities } from '@contrail/sdk';
8
+ import { TypeProperty } from '@contrail/types';
8
9
  import { TypeConversionUtils } from '../util/type-conversion-utils';
9
10
  import { EventShortMessageStatus } from '../util/event-short-message-status';
10
11
 
@@ -133,6 +134,60 @@ export abstract class BaseEntityProcessor {
133
134
  + ', orgSlug: ' + this.orgSlug;
134
135
  }
135
136
 
137
+ /**This will query for the entity, and handle post-processing
138
+ * of any critieria that is defined at the sub-type level.
139
+ * Because sub-type criteria can't be used in the search done
140
+ * on the server. This is expected to be called by getIncomingEntity().
141
+ *
142
+ * @param entityType: the root type of the entity
143
+ * @param entityTypePath: the full type path of the entity. Ex: custom-entity:sample
144
+ * @param propertyCriteria: all the criteria to search for the entity
145
+ * @returns the entities that match the criteria
146
+ */
147
+ async queryEntityWithSubTypeCriteria(entityType: string, entityTypePath: string, propertyCriteria: any): Promise<any[]>{
148
+ //allCriteria; identifierKeys; entityType; entityTypePath
149
+ if(!entityType || !entityTypePath){
150
+ throw new Error('type and entityTypePath must be defined');
151
+ }
152
+ if(!propertyCriteria || Object.getOwnPropertyNames(propertyCriteria).length == 0){
153
+ throw new Error('propertyCriteria must be defined and have at least one property');
154
+ }
155
+
156
+ const rootType = await this.typeUtil.getByRootAndPath({root: entityType});
157
+ const rootTypePropertyKeys = await this.getRootTypePropertyKeys(rootType, propertyCriteria);
158
+
159
+ const rootTypeCriteria = {typePath:entityTypePath};
160
+ const subTypeCriteria = {};
161
+ for(const key in propertyCriteria){
162
+ if(rootTypePropertyKeys.includes(key)){
163
+ rootTypeCriteria[key] = propertyCriteria[key];
164
+ }else{
165
+ subTypeCriteria[key] = propertyCriteria[key];
166
+ }
167
+ }
168
+
169
+ const returnedEntities = await this.dc.getAllObjectReferences(entityType, rootTypeCriteria, subTypeCriteria);
170
+
171
+ return returnedEntities;
172
+ }
173
+
174
+ /** This is to get the properties that are owned by the root type
175
+ * This needs to be overridded for multi-level types, such as item
176
+ * and project-item. And for those types, the propertyCriteria
177
+ * will be needed to determine the correct level.
178
+ *
179
+ * @param rootType: the full root type entity for the processed entity
180
+ * @param propertyCriteria: the criteria to determine the correct level (unused for single level types)
181
+ * @returns: string[] of the property keys
182
+ */
183
+ getRootTypePropertyKeys(rootType, propertyCriteria = null): string[] {
184
+ const props: TypeProperty[] = rootType['typeProperties'];
185
+ const rootTypePropertyKeys = props.map(prop => prop.slug);
186
+
187
+ return rootTypePropertyKeys;
188
+ }
189
+
190
+
136
191
  async handleIncomingDelete(event) {
137
192
  console.warn('delete is not configured', event);
138
193
  }
@@ -23,6 +23,7 @@ export class BaseProcessPublishAssortment {
23
23
  private config: FCConfig;
24
24
  private mapFileUtil: MapFileUtil;
25
25
  private transformMapFile: string;
26
+ protected orgSlug: string;
26
27
  private cache = {
27
28
  carriedFromSeason: {}
28
29
  };
@@ -33,6 +34,7 @@ export class BaseProcessPublishAssortment {
33
34
  this.dc = _dc;
34
35
  this.mapFileUtil = _mapFileUtil;
35
36
  this.transformMapFile = this.config?.transformMapFile;
37
+ this.orgSlug = this.config?.orgSlug || 'unset-orgSlug';
36
38
  }
37
39
 
38
40
  public async process(event) {
@@ -53,7 +55,8 @@ export class BaseProcessPublishAssortment {
53
55
  (message.startsWith(BaseProcessPublishAssortment.ASSORTMENT_NO_FED_INFO)) ? EventShortMessageStatus.NO_FEDERATION_INFO :
54
56
  EventShortMessageStatus.FAILURE;
55
57
  const processStatus = 'BaseProcessPublishAssortment: ' + eventStatus
56
- + ': assortmentId: ' + event.assortmentId + ': assortmentPublishChangeId: ' + event.assortmentPublishChangeId;
58
+ + ': assortmentId: ' + event.assortmentId + ': assortmentPublishChangeId: ' + event.assortmentPublishChangeId
59
+ + ', orgSlug: ' + this.orgSlug;
57
60
  console.log(JSON.stringify(processStatus));
58
61
  console.log(message);
59
62
  const output = {
@@ -627,7 +630,8 @@ export class BaseProcessPublishAssortment {
627
630
  const events = await this.getEventsForPublishChangeData(pcd);
628
631
  if (events.length === 0) {
629
632
  const processStatus = 'BaseProcessPublishAssortment: ' + EventShortMessageStatus.NO_EVENTS_TO_SEND
630
- + ': assortmentId: ' + pcd.assortmentId + ': assortmentPublishChangeId: ' + pcd.assortmentPublishChangeId;
633
+ + ': assortmentId: ' + pcd.assortmentId + ': assortmentPublishChangeId: ' + pcd.assortmentPublishChangeId
634
+ + ', orgSlug: ' + this.orgSlug;
631
635
  console.log(processStatus);
632
636
  const message = 'No Events to Send; returning';
633
637
  console.log(message);
@@ -641,9 +645,10 @@ export class BaseProcessPublishAssortment {
641
645
  const results = await this.sendEvents(events);
642
646
  const resultsCount = this.getResultsCount(events);
643
647
  const processStatus = 'BaseProcessPublishAssortment: ' + EventShortMessageStatus.SENDING_EVENTS
644
- + ': assortmentId: ' + pcd.assortmentId + ': assortmentPublishChangeId: ' + pcd.assortmentPublishChangeId
645
- + ': resultsCount: ' + JSON.stringify(resultsCount);
646
- console.log(processStatus);
648
+ + ': assortmentId: ' + pcd.assortmentId + ': assortmentPublishChangeId: ' + pcd.assortmentPublishChangeId
649
+ + ': resultsCount: ' + JSON.stringify(resultsCount)
650
+ + ', orgSlug: ' + this.orgSlug;
651
+ console.log(processStatus);
647
652
  return { results, event, resultsCount };
648
653
 
649
654
  }
@@ -29,205 +29,6 @@ import { FCConfig } from '../interfaces/interfaces';
29
29
  import { TypeConversionUtils } from './type-conversion-utils';
30
30
  import { MapUtil } from './map-utils';
31
31
 
32
- // describe('transformEntity', () =>{
33
- // const config: FCConfig = {
34
- // apiHost: 'host',
35
- // userName: () => 'user',
36
- // password: () => 'pass',
37
- // urlContext: 'xxx',
38
- // vibeEventEndpoint: '/rfa/vibeiq/vibeEvents',
39
- // itemPreDevelopmentLifecycleStages: ['concept'],
40
- // propertyMapping: {
41
- // LCSSeason :{
42
- // flexPLMSeasonName: 'seasonName'
43
- // },
44
- // LCSProduct: {
45
- // name: 'productName'
46
- // },
47
- // LCSSKU: {
48
- // optionName: 'skuName'
49
- // }
50
- // }
51
- // };
52
-
53
- // it('LCSSeason-flexPLMSeasonName', () =>{
54
- // const dc = new DataConverter(new Logger(config), config);
55
- // const flexPLMSeasonName = 'Season Name';
56
- // const stringAtt = 'some value';
57
- // const numberAtt = 44;
58
- // const name = 'productName';
59
- // const seasonEntity = {
60
- // objectClass: 'LCSSeason',
61
- // flexPLMSeasonName,
62
- // stringAtt,
63
- // numberAtt,
64
- // name
65
- // };
66
-
67
- // const seasonObj = dc.transformEntity(seasonEntity);
68
-
69
- // const objectKeys = Object.keys(seasonObj);
70
- // expect(objectKeys.length).toEqual(5);
71
- // expect(seasonObj['seasonName']).toEqual(flexPLMSeasonName);
72
- // expect(seasonObj['numberAtt']).toEqual(numberAtt);
73
- // expect(seasonObj['stringAtt']).toEqual(stringAtt);
74
- // expect(seasonObj['name']).toEqual(name);
75
-
76
- // });
77
-
78
- // it('LCSProduct-name', () =>{
79
- // const dc = new DataConverter(new Logger(config), config);
80
- // const flexPLMSeasonName = 'Season Name';
81
- // const stringAtt = 'some value';
82
- // const numberAtt = 44;
83
- // const name = 'productName';
84
- // const productEntity = {
85
- // objectClass: 'LCSProduct',
86
- // flexPLMSeasonName,
87
- // stringAtt,
88
- // numberAtt,
89
- // name
90
- // };
91
-
92
- // const productObj = dc.transformEntity(productEntity);
93
-
94
- // const objectKeys = Object.keys(productObj);
95
- // expect(objectKeys.length).toEqual(5);
96
- // expect(productObj['flexPLMSeasonName']).toEqual(flexPLMSeasonName);
97
- // expect(productObj['numberAtt']).toEqual(numberAtt);
98
- // expect(productObj['stringAtt']).toEqual(stringAtt);
99
- // expect(productObj['productName']).toEqual(name);
100
-
101
- // });
102
-
103
- // it('LCSSKU-name', () =>{
104
- // const dc = new DataConverter(new Logger(config), config);
105
- // const flexPLMSeasonName = 'Season Name';
106
- // const stringAtt = 'some value';
107
- // const numberAtt = 44;
108
- // const name = 'productName';
109
- // const optionName = 'sku name';
110
- // const skuEntity = {
111
- // objectClass: 'LCSSKU',
112
- // flexPLMSeasonName,
113
- // stringAtt,
114
- // numberAtt,
115
- // name,
116
- // optionName
117
- // };
118
-
119
- // const skuObj = dc.transformEntity(skuEntity);
120
-
121
- // const objectKeys = Object.keys(skuObj);
122
- // expect(objectKeys.length).toEqual(6);
123
- // expect(skuObj['flexPLMSeasonName']).toEqual(flexPLMSeasonName);
124
- // expect(skuObj['numberAtt']).toEqual(numberAtt);
125
- // expect(skuObj['stringAtt']).toEqual(stringAtt);
126
- // expect(skuObj['name']).toEqual(name);
127
- // expect(skuObj['skuName']).toEqual(optionName);
128
-
129
- // });
130
- // });
131
-
132
- // describe('transformObject', () =>{
133
- // const config: FCConfig = {
134
- // apiHost: 'host',
135
- // userName: () => 'user',
136
- // password: () => 'pass',
137
- // urlContext: 'xxx',
138
- // vibeEventEndpoint: '/rfa/vibeiq/vibeEvents',
139
- // itemPreDevelopmentLifecycleStages: ['concept'],
140
- // propertyMapping: {
141
- // LCSSeason :{
142
- // flexPLMSeasonName: 'seasonName'
143
- // },
144
- // LCSProduct: {
145
- // name: 'productName'
146
- // },
147
- // LCSSKU: {
148
- // optionName: 'skuName'
149
- // }
150
- // }
151
- // };
152
-
153
- // it('LCSSeason-flexPLMSeasonName', () =>{
154
- // const dc = new DataConverter(new Logger(config), config);
155
- // const flexPLMSeasonName = 'Season Name';
156
- // const stringAtt = 'some value';
157
- // const numberAtt = 44;
158
- // const name = 'productName';
159
- // const seasonObj = {
160
- // objectClass: 'LCSSeason',
161
- // seasonName: flexPLMSeasonName,
162
- // stringAtt,
163
- // numberAtt,
164
- // name
165
- // };
166
-
167
- // const seasonEntity = dc.transformObject(seasonObj);
168
- // const objectKeys = Object.keys(seasonEntity);
169
- // expect(objectKeys.length).toEqual(5);
170
- // expect(seasonEntity['flexPLMSeasonName']).toEqual(flexPLMSeasonName);
171
- // expect(seasonEntity['numberAtt']).toEqual(numberAtt);
172
- // expect(seasonEntity['stringAtt']).toEqual(stringAtt);
173
- // expect(seasonEntity['name']).toEqual(name);
174
-
175
- // });
176
-
177
- // it('LCSProduct-name', () =>{
178
- // const dc = new DataConverter(new Logger(config), config);
179
- // const flexPLMSeasonName = 'Season Name';
180
- // const stringAtt = 'some value';
181
- // const numberAtt = 44;
182
- // const name = 'productName';
183
- // const productObj = {
184
- // objectClass: 'LCSProduct',
185
- // flexPLMSeasonName,
186
- // stringAtt,
187
- // numberAtt,
188
- // productName: name
189
- // };
190
-
191
- // const productEntity = dc.transformObject(productObj);
192
-
193
- // const objectKeys = Object.keys(productEntity);
194
- // expect(objectKeys.length).toEqual(5);
195
- // expect(productEntity['flexPLMSeasonName']).toEqual(flexPLMSeasonName);
196
- // expect(productEntity['numberAtt']).toEqual(numberAtt);
197
- // expect(productEntity['stringAtt']).toEqual(stringAtt);
198
- // expect(productEntity['name']).toEqual(name);
199
-
200
- // });
201
-
202
- // it('LCSSKU-name', () =>{
203
- // const dc = new DataConverter(new Logger(config), config);
204
- // const flexPLMSeasonName = 'Season Name';
205
- // const stringAtt = 'some value';
206
- // const numberAtt = 44;
207
- // const name = 'productName';
208
- // const optionName = 'sku name';
209
- // const skuObj = {
210
- // objectClass: 'LCSSKU',
211
- // flexPLMSeasonName,
212
- // stringAtt,
213
- // numberAtt,
214
- // name,
215
- // skuName: optionName
216
- // };
217
-
218
- // const skuEntity = dc.transformObject(skuObj);
219
-
220
- // const objectKeys = Object.keys(skuEntity);
221
- // expect(objectKeys.length).toEqual(6);
222
- // expect(skuEntity['flexPLMSeasonName']).toEqual(flexPLMSeasonName);
223
- // expect(skuEntity['numberAtt']).toEqual(numberAtt);
224
- // expect(skuEntity['stringAtt']).toEqual(stringAtt);
225
- // expect(skuEntity['name']).toEqual(name);
226
- // expect(skuEntity['optionName']).toEqual(optionName);
227
-
228
- // });
229
- // });
230
-
231
32
  describe('getFlexPLMValue multi_select', () => {
232
33
  const config: FCConfig = {
233
34
  apiHost: 'host',
@@ -590,7 +391,7 @@ describe('getObjectReferenceValue cache', () =>{
590
391
  }
591
392
  });
592
393
  });
593
- describe('getObjectReferenceValue bad value', () =>{
394
+ describe('getObjectReferenceValue bad value', () =>{
594
395
  const config: FCConfig = {
595
396
  apiHost: 'host',
596
397
  userName: () => 'user',
@@ -495,22 +495,29 @@ export class DataConverter {
495
495
  * @param {object} rootTypeCriteria - The criteria used to filter object references.
496
496
  * @returns {Promise<Array>} A Promise that resolves to an array containing all object references.
497
497
  */
498
- async getAllObjectReferences(entityType, rootTypeCriteria) {
498
+ async getAllObjectReferences(entityType: string, rootTypeCriteria, postProcessCriteria = null) {
499
499
  const entities = new Entities();
500
500
  let loads = [];
501
501
  let nextPageKey;
502
502
  let usedV2 = false;
503
503
  do {
504
+ const take = 1000;
504
505
  const loadPage = await entities.get({
505
506
  entityName: entityType,
506
507
  criteria: rootTypeCriteria,
507
508
  apiVersion: API_VERSION.V2,
509
+ take,
508
510
  nextPageKey,
509
511
  });
510
512
  nextPageKey = loadPage?.nextPageKey;
511
513
  if (Object.keys(loadPage).includes('results')) {
512
514
  usedV2 = true;
513
- loads.push(...loadPage.results);
515
+ let postProcessedResults = loadPage.results;
516
+ if(postProcessCriteria && Object.keys(postProcessCriteria).length !== 0) {
517
+ const subEntityTypePath = rootTypeCriteria.typePath || entityType;
518
+ postProcessedResults = this.checkKeysAndValues(postProcessCriteria, postProcessedResults, subEntityTypePath);
519
+ }
520
+ loads.push(...postProcessedResults);
514
521
  } else {
515
522
  nextPageKey = null;
516
523
  }
@@ -527,7 +534,12 @@ export class DataConverter {
527
534
  take,
528
535
  skip,
529
536
  });
530
- loads.push(...loadPage);
537
+ let postProcessedResults = loadPage;
538
+ if(postProcessCriteria && Object.keys(postProcessCriteria).length !== 0) {
539
+ const subEntityTypePath = rootTypeCriteria.typePath || entityType;
540
+ postProcessedResults = this.checkKeysAndValues(postProcessCriteria, postProcessedResults, subEntityTypePath);
541
+ }
542
+ loads.push(...postProcessedResults);
531
543
 
532
544
  if (loadPage.length !== take) {
533
545
  done = true;