Merge pull request #15302 from backstage/freben/catalog-order
Implement server side ordering in the entities endpoint
This commit is contained in:
@@ -161,6 +161,17 @@ export type EntityFilterQuery =
|
||||
| Record<string, string | symbol | (string | symbol)[]>[]
|
||||
| Record<string, string | symbol | (string | symbol)[]>;
|
||||
|
||||
// @public
|
||||
export type EntityOrderQuery =
|
||||
| {
|
||||
field: string;
|
||||
order: 'asc' | 'desc';
|
||||
}
|
||||
| Array<{
|
||||
field: string;
|
||||
order: 'asc' | 'desc';
|
||||
}>;
|
||||
|
||||
// @public
|
||||
export interface GetEntitiesByRefsRequest {
|
||||
entityRefs: string[];
|
||||
@@ -179,6 +190,7 @@ export interface GetEntitiesRequest {
|
||||
filter?: EntityFilterQuery;
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
order?: EntityOrderQuery;
|
||||
}
|
||||
|
||||
// @public
|
||||
|
||||
@@ -193,6 +193,31 @@ describe('CatalogClient', () => {
|
||||
|
||||
expect(response.items).toEqual([]);
|
||||
});
|
||||
|
||||
it('handles ordering properly', async () => {
|
||||
expect.assertions(2);
|
||||
|
||||
server.use(
|
||||
rest.get(`${mockBaseUrl}/entities`, (req, res, ctx) => {
|
||||
expect(req.url.search).toBe(
|
||||
'?order=asc:kind&order=desc:metadata.name',
|
||||
);
|
||||
return res(ctx.json([]));
|
||||
}),
|
||||
);
|
||||
|
||||
const response = await client.getEntities(
|
||||
{
|
||||
order: [
|
||||
{ field: 'kind', order: 'asc' },
|
||||
{ field: 'metadata.name', order: 'desc' },
|
||||
],
|
||||
},
|
||||
{ token },
|
||||
);
|
||||
|
||||
expect(response.items).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getEntitiesByRefs', () => {
|
||||
|
||||
@@ -99,7 +99,14 @@ export class CatalogClient implements CatalogApi {
|
||||
request?: GetEntitiesRequest,
|
||||
options?: CatalogRequestOptions,
|
||||
): Promise<GetEntitiesResponse> {
|
||||
const { filter = [], fields = [], offset, limit, after } = request ?? {};
|
||||
const {
|
||||
filter = [],
|
||||
fields = [],
|
||||
order,
|
||||
offset,
|
||||
limit,
|
||||
after,
|
||||
} = request ?? {};
|
||||
const params: string[] = [];
|
||||
|
||||
// filter param can occur multiple times, for example
|
||||
@@ -129,6 +136,18 @@ export class CatalogClient implements CatalogApi {
|
||||
params.push(`fields=${fields.map(encodeURIComponent).join(',')}`);
|
||||
}
|
||||
|
||||
if (order) {
|
||||
for (const directive of [order].flat()) {
|
||||
if (directive) {
|
||||
params.push(
|
||||
`order=${encodeURIComponent(directive.order)}:${encodeURIComponent(
|
||||
directive.field,
|
||||
)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (offset !== undefined) {
|
||||
params.push(`offset=${offset}`);
|
||||
}
|
||||
|
||||
@@ -98,6 +98,48 @@ export type EntityFilterQuery =
|
||||
*/
|
||||
export type EntityFieldsQuery = string[];
|
||||
|
||||
/**
|
||||
* Dot-separated field based ordering directives, controlling the sort order of
|
||||
* the output entities.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* Each field is a dot-separated path into an entity's keys. The order is either
|
||||
* ascending (`asc`, lexicographical order) or descending (`desc`, reverse
|
||||
* lexicographical order). The ordering is case insensitive.
|
||||
*
|
||||
* If more than one order directive is given, later directives have lower
|
||||
* precedence (they are applied only when directives of higher precedence have
|
||||
* equal values).
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```
|
||||
* [
|
||||
* { field: 'kind', order: 'asc' },
|
||||
* { field: 'metadata.name', order: 'desc' },
|
||||
* ]
|
||||
* ```
|
||||
*
|
||||
* This will order the output first by kind ascending, and then within each kind
|
||||
* (if there's more than one of a given kind) by their name descending.
|
||||
*
|
||||
* When given a field that does NOT exist on all entities in the result set,
|
||||
* those entities that do not have the field will always be sorted last in that
|
||||
* particular order step, no matter what the desired order was.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type EntityOrderQuery =
|
||||
| {
|
||||
field: string;
|
||||
order: 'asc' | 'desc';
|
||||
}
|
||||
| Array<{
|
||||
field: string;
|
||||
order: 'asc' | 'desc';
|
||||
}>;
|
||||
|
||||
/**
|
||||
* The request type for {@link CatalogClient.getEntities}.
|
||||
*
|
||||
@@ -113,6 +155,10 @@ export interface GetEntitiesRequest {
|
||||
* declarations.
|
||||
*/
|
||||
fields?: EntityFieldsQuery;
|
||||
/**
|
||||
*If given, order the result set by those directives.
|
||||
*/
|
||||
order?: EntityOrderQuery;
|
||||
/**
|
||||
* If given, skips over the first N items in the result set.
|
||||
*/
|
||||
|
||||
@@ -22,6 +22,7 @@ export type {
|
||||
CatalogRequestOptions,
|
||||
EntityFieldsQuery,
|
||||
EntityFilterQuery,
|
||||
EntityOrderQuery,
|
||||
GetEntitiesByRefsRequest,
|
||||
GetEntitiesByRefsResponse,
|
||||
GetEntitiesRequest,
|
||||
|
||||
Reference in New Issue
Block a user