@contrail/flexplm 1.7.8-alpha.69dcae1 → 1.7.8-alpha.6f9b7d7
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.
|
@@ -348,6 +348,9 @@ class BaseProcessPublishAssortment {
|
|
|
348
348
|
const apcDeletes = await this.downloadDeleteChanges(assortmentPublishChange);
|
|
349
349
|
let previousApcDate = Date.parse(apcCreatedOn);
|
|
350
350
|
const sinceDateMilliseconds = sinceDate.getTime();
|
|
351
|
+
// sinceDate matches a publish timestamp when it is the default (previous publish) or 'numberOfPublishes:N'.
|
|
352
|
+
// A date-only sinceDate (e.g. 2026-10-08) matches none, so the walk below must stop on the date instead.
|
|
353
|
+
const hasPublishAtSinceDate = apcHistory.some(apc => Date.parse(apc?.createdOn) === sinceDateMilliseconds);
|
|
351
354
|
console.info('getDeleteChanges(): apc: ' + assortmentPublishChange?.id
|
|
352
355
|
+ ', index: ' + currentAPCIndex + ', previousApcCreatedOn: ' + apcCreatedOn);
|
|
353
356
|
//if only 1 apc, no processing needed
|
|
@@ -361,7 +364,11 @@ class BaseProcessPublishAssortment {
|
|
|
361
364
|
for (let i = currentAPCIndex - 1; i > 0; i--) {
|
|
362
365
|
const workingAPC = apcHistory[i];
|
|
363
366
|
previousApcDate = Date.parse(workingAPC?.createdOn);
|
|
364
|
-
|
|
367
|
+
const reachedSinceDate = hasPublishAtSinceDate
|
|
368
|
+
? previousApcDate === sinceDateMilliseconds
|
|
369
|
+
: previousApcDate < sinceDateMilliseconds;
|
|
370
|
+
if (reachedSinceDate) {
|
|
371
|
+
console.info('getDeleteChanges(): reached sinceDate at apc: ' + workingAPC?.id);
|
|
365
372
|
break;
|
|
366
373
|
}
|
|
367
374
|
if (workingAPC?.deletes > 0) {
|
|
@@ -922,6 +922,60 @@ describe('getDeleteChanges', () => {
|
|
|
922
922
|
spy.mockRestore();
|
|
923
923
|
});
|
|
924
924
|
});
|
|
925
|
+
describe('getDeleteChanges - how far back the history walk goes', () => {
|
|
926
|
+
const config = {};
|
|
927
|
+
const mapFileUtil = new transform_data_1.MapFileUtil(new sdk_1.Entities());
|
|
928
|
+
const dc = new data_converter_1.DataConverter(config, mapFileUtil);
|
|
929
|
+
// Oldest -> newest. 'current' is the publish being processed.
|
|
930
|
+
const history = [
|
|
931
|
+
{ id: 'apc0', createdOn: '2025-09-30T00:00:00.000Z', deletes: 5 },
|
|
932
|
+
{ id: 'apc1', createdOn: '2026-09-28T05:48:26.357Z', deletes: 1 },
|
|
933
|
+
{ id: 'apc2', createdOn: '2026-10-08T07:16:43.363Z', deletes: 2 },
|
|
934
|
+
{ id: 'apc3', createdOn: '2026-10-09T02:37:30.292Z', deletes: 3 },
|
|
935
|
+
{ id: 'apc4', createdOn: '2026-10-14T04:23:10.416Z', deletes: 0 },
|
|
936
|
+
{ id: 'current', createdOn: '2026-10-16T15:25:51.965Z', deletes: 0 }
|
|
937
|
+
];
|
|
938
|
+
const current = history[history.length - 1];
|
|
939
|
+
const baseline = { assortmentItems: [{ itemId: 'stillInPlan' }] };
|
|
940
|
+
let ppa;
|
|
941
|
+
let buildSpy;
|
|
942
|
+
beforeEach(() => {
|
|
943
|
+
ppa = new base_process_publish_assortment_1.BaseProcessPublishAssortment(config, dc, mapFileUtil);
|
|
944
|
+
jest.spyOn(ppa, 'downloadDeleteChanges').mockResolvedValue([]);
|
|
945
|
+
buildSpy = jest.spyOn(ppa, 'buildDeleteChanges')
|
|
946
|
+
.mockImplementation(async (apc) => [{ itemId: 'deleted-in-' + apc['id'] }]);
|
|
947
|
+
});
|
|
948
|
+
afterEach(() => {
|
|
949
|
+
jest.restoreAllMocks();
|
|
950
|
+
});
|
|
951
|
+
const walkedApcIds = () => buildSpy.mock.calls.map(call => call[0]['id']);
|
|
952
|
+
it('does not walk older publishes when sinceDate is the previous publish date (default)', async () => {
|
|
953
|
+
const result = await ppa.getDeleteChanges(current, history, baseline, new Date(history[4].createdOn));
|
|
954
|
+
expect(walkedApcIds()).toEqual([]);
|
|
955
|
+
expect(result).toEqual([]);
|
|
956
|
+
});
|
|
957
|
+
it('stops at the first publish before a date-only sinceDate that matches no publish timestamp', async () => {
|
|
958
|
+
const result = await ppa.getDeleteChanges(current, history, baseline, new Date('2026-10-08T00:00:00.000Z'));
|
|
959
|
+
// apc3 and apc2 are after the cutoff; apc1 (Sep 28) is before it, so the walk ends there and apc0 is never read.
|
|
960
|
+
expect(walkedApcIds()).toEqual(['apc3', 'apc2']);
|
|
961
|
+
expect(result.map(item => item['itemId'])).toEqual(['deleted-in-apc3', 'deleted-in-apc2']);
|
|
962
|
+
});
|
|
963
|
+
it('stops at a publish whose timestamp equals sinceDate without reading it (numberOfPublishes)', async () => {
|
|
964
|
+
await ppa.getDeleteChanges(current, history, baseline, new Date(history[1].createdOn));
|
|
965
|
+
expect(walkedApcIds()).toEqual(['apc3', 'apc2']);
|
|
966
|
+
});
|
|
967
|
+
it('does not walk any publish when a date-only sinceDate is later than the previous publish', async () => {
|
|
968
|
+
await ppa.getDeleteChanges(current, history, baseline, new Date('2026-10-15T00:00:00.000Z'));
|
|
969
|
+
expect(walkedApcIds()).toEqual([]);
|
|
970
|
+
});
|
|
971
|
+
it('skips deleted items still in the plan and de-duplicates across publishes', async () => {
|
|
972
|
+
buildSpy.mockImplementation(async (apc) => apc['id'] === 'apc3'
|
|
973
|
+
? [{ itemId: 'stillInPlan' }, { itemId: 'sameItem' }]
|
|
974
|
+
: [{ itemId: 'sameItem' }, { itemId: 'deleted-in-' + apc['id'] }]);
|
|
975
|
+
const result = await ppa.getDeleteChanges(current, history, baseline, new Date('2026-10-08T00:00:00.000Z'));
|
|
976
|
+
expect(result.map(item => item['itemId'])).toEqual(['sameItem', 'deleted-in-apc2']);
|
|
977
|
+
});
|
|
978
|
+
});
|
|
925
979
|
describe('buildDeleteChanges', () => {
|
|
926
980
|
const config = {};
|
|
927
981
|
const mapFileUtil = new transform_data_1.MapFileUtil(new sdk_1.Entities());
|
|
@@ -191,15 +191,15 @@ describe('filterProperties-color', () => {
|
|
|
191
191
|
});
|
|
192
192
|
});
|
|
193
193
|
describe('TypeUtils.getTypeById() tests', () => {
|
|
194
|
-
it('
|
|
195
|
-
const
|
|
196
|
-
|
|
197
|
-
await expect(
|
|
194
|
+
it('should throw an error containing the missing type id when the type does not exist', async () => {
|
|
195
|
+
const typeUtils = new type_utils_1.TypeUtils();
|
|
196
|
+
typeUtils['typesObj'] = { getType: jest.fn().mockResolvedValue(null) };
|
|
197
|
+
await expect(typeUtils.getTypeById('missingTypeId')).rejects.toThrow('type not found for typeId: missingTypeId');
|
|
198
198
|
});
|
|
199
|
-
it('
|
|
200
|
-
const
|
|
199
|
+
it('should return the same type object when the type exists', async () => {
|
|
200
|
+
const typeUtils = new type_utils_1.TypeUtils();
|
|
201
201
|
const type = { id: 'typeId', typeProperties: [] };
|
|
202
|
-
|
|
203
|
-
expect(await
|
|
202
|
+
typeUtils['typesObj'] = { getType: jest.fn().mockResolvedValue(type) };
|
|
203
|
+
expect(await typeUtils.getTypeById('typeId')).toBe(type);
|
|
204
204
|
});
|
|
205
205
|
});
|