change to asc and desc prefixes
Signed-off-by: Fredrik Adelöw <freben@gmail.com>
This commit is contained in:
@@ -154,6 +154,29 @@ Some more real world usable examples:
|
||||
|
||||
`/entities?fields=kind,metadata.namespace,metadata.name`
|
||||
|
||||
### Ordering
|
||||
|
||||
By default the entities are returned in an undefined, but stable, order. You can
|
||||
pass in one or more `order` query parameters to affect that ordering.
|
||||
|
||||
Each parameter starts either with `asc:` for ascending lexicographical order or
|
||||
`desc:` for descending (reverse) lexicographical order, followed by a
|
||||
dot-separated path into an entity's keys. 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:
|
||||
|
||||
```text
|
||||
/entities?order=asc:kind&order=desc:metadata.name
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
#### Pagination
|
||||
|
||||
You may pass the `offset` and `limit` query parameters to do classical
|
||||
|
||||
@@ -199,7 +199,9 @@ describe('CatalogClient', () => {
|
||||
|
||||
server.use(
|
||||
rest.get(`${mockBaseUrl}/entities`, (req, res, ctx) => {
|
||||
expect(req.url.search).toBe('?order=kind&order=-metadata.name');
|
||||
expect(req.url.search).toBe(
|
||||
'?order=asc:kind&order=desc:metadata.name',
|
||||
);
|
||||
return res(ctx.json([]));
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -139,13 +139,11 @@ export class CatalogClient implements CatalogApi {
|
||||
if (order) {
|
||||
for (const directive of [order].flat()) {
|
||||
if (directive) {
|
||||
// We could choose to always put in the + prefix, but it's not
|
||||
// required (ascending sort is the default) and it always gets URL
|
||||
// encoded to %2B which looks a bit less pretty - so we don't
|
||||
const str = `${directive.order === 'desc' ? '-' : ''}${
|
||||
directive.field
|
||||
}`;
|
||||
params.push(`order=${encodeURIComponent(str)}`);
|
||||
params.push(
|
||||
`order=${encodeURIComponent(directive.order)}:${encodeURIComponent(
|
||||
directive.field,
|
||||
)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,22 +22,21 @@ describe('parseEntityOrderParams', () => {
|
||||
});
|
||||
|
||||
it('handles parameters with various orders', () => {
|
||||
expect(parseEntityOrderParams({ order: ['a', '+b', '-c'] })).toEqual([
|
||||
expect(
|
||||
parseEntityOrderParams({ order: ['asc:a', 'desc:b', 'asc:c:d'] }),
|
||||
).toEqual([
|
||||
{ field: 'a', order: 'asc' },
|
||||
{ field: 'b', order: 'asc' },
|
||||
{ field: 'c', order: 'desc' },
|
||||
{ field: 'b', order: 'desc' },
|
||||
{ field: 'c:d', order: 'asc' },
|
||||
]);
|
||||
});
|
||||
|
||||
it('rejects missing order or key', () => {
|
||||
expect(() => parseEntityOrderParams({ order: [''] })).toThrow(
|
||||
'Invalid order parameter "", no field given',
|
||||
);
|
||||
expect(() => parseEntityOrderParams({ order: ['+'] })).toThrow(
|
||||
'Invalid order parameter "+", no field given',
|
||||
);
|
||||
expect(() => parseEntityOrderParams({ order: ['-'] })).toThrow(
|
||||
'Invalid order parameter "-", no field given',
|
||||
);
|
||||
});
|
||||
it.each(['', ':', 'ascii:', 'ascii:ebcdic', ':colon'])(
|
||||
'rejects missing/bad order or key, %p',
|
||||
order => {
|
||||
expect(() => parseEntityOrderParams({ order: [order] })).toThrow(
|
||||
`Invalid order parameter "${order}", expected "<asc or desc>:<field name>"`,
|
||||
);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -22,27 +22,16 @@ export function parseEntityOrderParams(
|
||||
params: Record<string, unknown>,
|
||||
): EntityOrder[] | undefined {
|
||||
return parseStringsParam(params.order, 'order')?.map(item => {
|
||||
let order: 'asc' | 'desc';
|
||||
let field: string;
|
||||
switch (item[0]) {
|
||||
case '+':
|
||||
order = 'asc';
|
||||
field = item.slice(1).trim();
|
||||
break;
|
||||
case '-':
|
||||
order = 'desc';
|
||||
field = item.slice(1).trim();
|
||||
break;
|
||||
default:
|
||||
order = 'asc';
|
||||
field = item.trim();
|
||||
break;
|
||||
const match = item.match(/^(asc|desc):(.+)$/);
|
||||
if (!match) {
|
||||
throw new InputError(
|
||||
`Invalid order parameter "${item}", expected "<asc or desc>:<field name>"`,
|
||||
);
|
||||
}
|
||||
|
||||
if (!field) {
|
||||
throw new InputError(`Invalid order parameter "${item}", no field given`);
|
||||
}
|
||||
|
||||
return { field, order };
|
||||
return {
|
||||
order: match[1] as 'asc' | 'desc',
|
||||
field: match[2],
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user