diff --git a/src/__tests__/frameworkContract.test.ts b/src/__tests__/frameworkContract.test.ts index 53d1c37a..60e31c42 100644 --- a/src/__tests__/frameworkContract.test.ts +++ b/src/__tests__/frameworkContract.test.ts @@ -168,6 +168,38 @@ describe('Template method pattern', () => { expect(liveData.length).toBe(1); }); + test('getLiveData threads its scope argument through to buildLiveData', async () => { + let received: ReadonlySet | undefined | 'unset' = 'unset'; + + @destinationController({ category: 'Test' }) + class TestScopedPark extends Destination { + constructor(options?: DestinationConstructor) { + super(options); + } + + protected async buildEntityList(): Promise { return []; } + + protected async buildLiveData(scope?: ReadonlySet): Promise { + received = scope; + return []; + } + + protected async buildSchedules(): Promise { return []; } + async getDestinations(): Promise { return []; } + } + + const park = new TestScopedPark(); + + // Scoped call (streaming push) — buildLiveData must receive the same set. + const scope = new Set(['ride1', 'ride2']); + await park.getLiveData(scope); + expect(received).toBe(scope); + + // No-arg call (poll/REST) — buildLiveData receives undefined (full snapshot). + await park.getLiveData(); + expect(received).toBeUndefined(); + }); + test('framework strips undefined values from live data, entities, and schedules', async () => { // Guards against the collector's hashObject() which rejects undefined. // Parks sometimes produce undefined via patterns like diff --git a/src/destination.ts b/src/destination.ts index f16dc9a1..e63b0c70 100644 --- a/src/destination.ts +++ b/src/destination.ts @@ -953,12 +953,17 @@ export abstract class Destination { * **To provide live data, implement buildLiveData() instead.** * * @final This method is final and should not be overridden. + * @param scope Optional set of published entity ids to limit the build to. + * Streaming (push) destinations pass the ids whose source docs changed this + * fire so the build is emit-per-changed-entity rather than a full snapshot. + * Undefined (the default, and all poll/REST destinations) builds everything. + * Passed through to buildLiveData(); subclasses that ignore it stay full-snapshot. * @returns {LiveData[]} List of live data for entities */ @trace() - async getLiveData(): Promise { + async getLiveData(scope?: ReadonlySet): Promise { await this.init(); - const data = await this.buildLiveData(); + const data = await this.buildLiveData(scope); // Sanitise waitTime values — must be a finite number or null/undefined. // Catches bugs like waitTime:"" which crash downstream integer columns. for (const entry of data) { @@ -1005,9 +1010,13 @@ export abstract class Destination { * Subclasses should override this method to return live data (wait times, * operating status, showtimes, etc.) for their entities. * + * @param scope Optional set of published entity ids to limit the build to + * (see getLiveData). Streaming destinations may honour it to build only the + * changed entities; an override that ignores it returns the full snapshot. * @returns {LiveData[]} List of live data for entities */ - protected async buildLiveData(): Promise { + protected async buildLiveData(scope?: ReadonlySet): Promise { + void scope; throw new Error("buildLiveData not implemented."); }