diff --git a/src/dashboard/dashboard-manager.test.ts b/src/dashboard/dashboard-manager.test.ts index eaa2869a..89f72129 100644 --- a/src/dashboard/dashboard-manager.test.ts +++ b/src/dashboard/dashboard-manager.test.ts @@ -175,4 +175,19 @@ describe('Dashboard manager', () => { expect(mockModelManager.destroy).toHaveBeenCalledWith(mockOriginalDataSource); expect(mockDataSourceManager.setRootDataSource).toHaveBeenCalledWith(mockNewDataSource, dashboard.root); }); + + test('can retrieve model instances', () => { + const dashboard = dashboardManager.create({ + type: 'serialized-model' + }); + + const mockDataSource = class MockDataSource { + public readonly value: number = Math.random(); + }; + + mockModelManager.getModelInstances = jest.fn().mockReturnValue([new mockDataSource()]); + + expect(dashboard.getModelInstances(mockDataSource).length).toBe(1); + expect(mockModelManager.getModelInstances).toHaveBeenCalledWith(mockDataSource, {}); + }); }); diff --git a/src/dashboard/dashboard.ts b/src/dashboard/dashboard.ts index 534fcf00..22b8934c 100644 --- a/src/dashboard/dashboard.ts +++ b/src/dashboard/dashboard.ts @@ -23,7 +23,7 @@ export interface Dashboard { setTimeRange(timeRange: TimeRange): this; /** - * Returns a serialized from of this dashboard. Note this does not + * Returns a serialized form of this dashboard. Note this does not * affect the dashboard in any way, it must be explicitly destroyed * if it is no longer in use. */ @@ -56,4 +56,10 @@ export interface Dashboard { */ // tslint:disable-next-line: no-any getRootDataSource>(): T | undefined; + + /** + * Returns a shallow copy array of model instances within a dashboard that match the + * argument model class + */ + getModelInstances(modelClass: Constructable): object[]; } diff --git a/src/dashboard/default-dashboard.ts b/src/dashboard/default-dashboard.ts index 6aed41b7..e763a9f6 100644 --- a/src/dashboard/default-dashboard.ts +++ b/src/dashboard/default-dashboard.ts @@ -86,4 +86,11 @@ export class DefaultDashboard implements Dashboard public getRootDataSource>(): T | undefined { return this.dataSourceManager.getRootDataSource(this.root) as T | undefined; } + + /** + * @inheritdoc + */ + public getModelInstances(modelClass: Constructable): object[] { + return this.modelManager.getModelInstances(modelClass, this.root); + } } diff --git a/src/model/manager/model-manager.test.ts b/src/model/manager/model-manager.test.ts index 9d6c848f..8dedc160 100644 --- a/src/model/manager/model-manager.test.ts +++ b/src/model/manager/model-manager.test.ts @@ -14,6 +14,14 @@ describe('Model manager', () => { // Value used to disambiguate equality between instances public readonly value: number = Math.random(); }; + const testClass1 = class TestClass1 { + // Value used to disambiguate equality between instances + public readonly value: number = Math.random(); + }; + const testClass2 = class TestClass2 { + // Value used to disambiguate equality between instances + public readonly value: number = Math.random(); + }; let manager: ModelManager; let mockLogger: PartialObjectMock; let mockApiBuilder: PartialObjectMock>; @@ -59,6 +67,18 @@ describe('Model manager', () => { manager.registerModelApiBuilder(mockApiBuilder as ModelApiBuilder); }); + test('returns array of instances matching arg', () => { + expect(manager.getModelInstances(testClass, {})).toStrictEqual([]); + + const instance = manager.construct(testClass); + const instance1 = manager.construct(testClass1, instance); + const instance2 = manager.construct(testClass2, instance1); + expect(manager.getModelInstances(testClass, instance)).toStrictEqual([instance]); + expect(manager.getModelInstances(testClass1, instance)).toStrictEqual([instance1]); + expect(manager.getModelInstances(testClass2, instance)).toStrictEqual([instance2]); + expect(manager.getModelInstances(testClass2, instance1)).toStrictEqual([instance2]); + }); + test('allows constructing new models', () => { const instance = manager.construct(testClass); expect(instance.constructor).toBe(testClass); diff --git a/src/model/manager/model-manager.ts b/src/model/manager/model-manager.ts index 0004bcfd..9fc04e93 100644 --- a/src/model/manager/model-manager.ts +++ b/src/model/manager/model-manager.ts @@ -24,6 +24,23 @@ export class ModelManager { private readonly beforeModelDestroyedEvent: BeforeModelDestroyedEvent ) {} + /** + * Returns a shallow copy array of model instances that match the argument model class + */ + public getModelInstances(modelClass: Constructable, root: object): object[] { + let found: object[] = []; + + if (root instanceof modelClass) { + found = [...found, root]; + } + + this.modelInstanceMap + .get(root) + ?.children.forEach(child => (found = [...found, ...this.getModelInstances(modelClass, child)])); + + return found; + } + /** * Constructs (@see `ModelManager.construct`) then initializes (@see `ModelManager.initialize`) it *