From ec411a01ae8933d96f48f4ab957b2410fcbfd915 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Thu, 26 Feb 2026 21:50:33 +0100 Subject: [PATCH] feat: add query predicate support to InMemoryCatalogClient MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds support for the `query` field in `getEntitiesByRefs` and `getEntityFacets` on InMemoryCatalogClient, matching the backend behavior. Co-Authored-By: Claude Opus 4.6 Signed-off-by: Fredrik Adelöw --- .../testUtils/InMemoryCatalogClient.test.ts | 42 +++++++++++++++++++ .../src/testUtils/InMemoryCatalogClient.ts | 14 ++++++- 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/packages/catalog-client/src/testUtils/InMemoryCatalogClient.test.ts b/packages/catalog-client/src/testUtils/InMemoryCatalogClient.test.ts index aa3b624050..98b5d5c034 100644 --- a/packages/catalog-client/src/testUtils/InMemoryCatalogClient.test.ts +++ b/packages/catalog-client/src/testUtils/InMemoryCatalogClient.test.ts @@ -370,6 +370,25 @@ describe('InMemoryCatalogClient', () => { { kind: 'CustomKind', metadata: { name: 'e1' } }, ]); }); + + it('supports query predicate filter', async () => { + const client = new InMemoryCatalogClient({ entities }); + const result = await client.getEntitiesByRefs({ + entityRefs: ['secondcustomkind:default/e2', 'customkind:default/e1'], + query: { kind: 'CustomKind' }, + }); + expect(result.items).toEqual([undefined, entity1]); + }); + + it('supports both filter and query predicate together', async () => { + const client = new InMemoryCatalogClient({ entities }); + const result = await client.getEntitiesByRefs({ + entityRefs: ['customkind:default/e1', 'customkind:other/e3'], + filter: { kind: 'CustomKind' }, + query: { 'metadata.namespace': 'other' }, + }); + expect(result.items).toEqual([undefined, entity3]); + }); }); describe('queryEntities', () => { @@ -975,6 +994,29 @@ describe('InMemoryCatalogClient', () => { }); expect(result.facets['spec.nonexistent']).toEqual([]); }); + + it('supports query predicate filter', async () => { + const client = new InMemoryCatalogClient({ entities }); + const result = await client.getEntityFacets({ + facets: ['spec.type'], + query: { kind: 'CustomKind' }, + }); + expect(result.facets['spec.type']).toEqual([ + { value: 'service', count: 2 }, + ]); + }); + + it('supports both filter and query predicate together', async () => { + const client = new InMemoryCatalogClient({ entities }); + const result = await client.getEntityFacets({ + facets: ['spec.type'], + filter: { kind: 'CustomKind' }, + query: { 'metadata.namespace': 'default' }, + }); + expect(result.facets['spec.type']).toEqual([ + { value: 'service', count: 1 }, + ]); + }); }); describe('not implemented methods', () => { diff --git a/packages/catalog-client/src/testUtils/InMemoryCatalogClient.ts b/packages/catalog-client/src/testUtils/InMemoryCatalogClient.ts index 0a4dc57386..dd7f269188 100644 --- a/packages/catalog-client/src/testUtils/InMemoryCatalogClient.ts +++ b/packages/catalog-client/src/testUtils/InMemoryCatalogClient.ts @@ -361,10 +361,15 @@ export class InMemoryCatalogClient implements CatalogApi { request: GetEntitiesByRefsRequest, ): Promise { const filter = createFilter(request.filter); + const queryFilter = request.query + ? filterPredicateToFilterFunction(request.query) + : undefined; const refMap = this.#createEntityRefMap(); const items = request.entityRefs .map(ref => refMap.get(ref)) - .map(e => (e && filter(e) ? e : undefined)); + .map(e => + e && filter(e) && (!queryFilter || queryFilter(e)) ? e : undefined, + ); return { items: request.fields ? items.map(e => (e ? applyFieldsFilter(e, request.fields) : undefined)) @@ -506,7 +511,12 @@ export class InMemoryCatalogClient implements CatalogApi { request: GetEntityFacetsRequest, ): Promise { const filter = createFilter(request.filter); - const filteredEntities = this.#entities.filter(filter); + let filteredEntities = this.#entities.filter(filter); + if (request.query) { + filteredEntities = filteredEntities.filter( + filterPredicateToFilterFunction(request.query), + ); + } const facets = Object.fromEntries( request.facets.map(facet => { const facetValues = new Map();