feat: add query predicate support to InMemoryCatalogClient

Adds support for the `query` field in `getEntitiesByRefs` and
`getEntityFacets` on InMemoryCatalogClient, matching the backend
behavior.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Fredrik Adelöw <freben@gmail.com>
This commit is contained in:
Fredrik Adelöw
2026-02-26 21:50:33 +01:00
parent 2ffb23df02
commit ec411a01ae
2 changed files with 54 additions and 2 deletions
@@ -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', () => {
@@ -361,10 +361,15 @@ export class InMemoryCatalogClient implements CatalogApi {
request: GetEntitiesByRefsRequest,
): Promise<GetEntitiesByRefsResponse> {
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<GetEntityFacetsResponse> {
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<string, number>();