catalog-backend: sortFields to orderFields

Signed-off-by: Vincenzo Scamporlino <vincenzos@spotify.com>
This commit is contained in:
Vincenzo Scamporlino
2023-02-03 13:19:53 +01:00
parent 7b370a5dad
commit cf166f4030
6 changed files with 44 additions and 30 deletions
+3 -3
View File
@@ -227,7 +227,7 @@ export interface QueryEntitiesInitialRequest {
fields?: (entity: Entity) => Entity;
limit?: number;
filter?: EntityFilter;
sortFields?: EntityOrder[];
orderFields?: EntityOrder[];
query?: string;
}
@@ -275,11 +275,11 @@ export type Cursor = {
* An array of fields used for sorting the data.
* For example, [ { field: 'metadata.name', order: 'asc' } ]
*/
sortFields: EntityOrder[];
orderFields: EntityOrder[];
/**
* The values of the fields of a specific item used for paginating the data.
*/
sortFieldValues: Array<string | null>;
orderFieldValues: Array<string | null>;
/**
* A filter to be applied to the full list of entities.
*/
@@ -767,7 +767,7 @@ describe('DefaultEntitiesCatalog', () => {
const request1: QueryEntitiesInitialRequest = {
filter,
limit,
sortFields: [{ field: 'metadata.name', order: 'asc' }],
orderFields: [{ field: 'metadata.name', order: 'asc' }],
};
const response1 = await catalog.queryEntities(request1);
expect(response1.items).toEqual([entityFrom('A'), entityFrom('B')]);
@@ -912,7 +912,7 @@ describe('DefaultEntitiesCatalog', () => {
const request1: QueryEntitiesInitialRequest = {
filter,
limit,
sortFields: [{ field: 'metadata.name', order: 'desc' }],
orderFields: [{ field: 'metadata.name', order: 'desc' }],
};
const response1 = await catalog.queryEntities(request1);
expect(response1.items).toEqual([entityFrom('G'), entityFrom('F')]);
@@ -1056,7 +1056,7 @@ describe('DefaultEntitiesCatalog', () => {
filter,
limit: 100,
sortFields: [{ field: 'metadata.name', order: 'asc' }],
orderFields: [{ field: 'metadata.name', order: 'asc' }],
query: 'cAt ',
};
const response = await catalog.queryEntities(request);
@@ -1098,7 +1098,7 @@ describe('DefaultEntitiesCatalog', () => {
limit: 0,
};
const response = await catalog.queryEntities(request);
expect(response).toEqual({ totalItems: 20, entities: [] });
expect(response).toEqual({ totalItems: 20, items: [], pageInfo: {} });
},
);
@@ -1127,7 +1127,7 @@ describe('DefaultEntitiesCatalog', () => {
// initial request
const request1: QueryEntitiesInitialRequest = {
limit,
sortFields: [{ field: 'metadata.name', order: 'asc' }],
orderFields: [{ field: 'metadata.name', order: 'asc' }],
};
const response1 = await catalog.queryEntities(request1);
expect(response1.items).toMatchObject([
@@ -338,26 +338,27 @@ export class DefaultEntitiesCatalog implements EntitiesCatalog {
const db = this.database;
const limit = request?.limit ?? 20;
const cursor: Omit<Cursor, 'sortFieldValues'> & {
sortFieldValues?: (string | null)[];
const cursor: Omit<Cursor, 'orderFieldValues'> & {
orderFieldValues?: (string | null)[];
} = {
sortFields: [defaultSortField],
orderFields: [defaultSortField],
isPrevious: false,
...parseCursorFromRequest(request),
};
const isFetchingBackwards = cursor.isPrevious;
if (cursor.sortFields.length > 1) {
if (cursor.orderFields.length > 1) {
this.logger.warn(`Only one sort field is supported, ignoring the rest`);
}
const sortField: EntityOrder = {
...defaultSortField,
...cursor.sortFields[0],
...cursor.orderFields[0],
};
const [prevItemSortFieldValue, prevItemUid] = cursor.sortFieldValues || [];
const [prevItemOrderFieldValue, prevItemUid] =
cursor.orderFieldValues || [];
const dbQuery = db('search')
.join('final_entities', 'search.entity_id', 'final_entities.entity_id')
@@ -379,14 +380,14 @@ export class DefaultEntitiesCatalog implements EntitiesCatalog {
const isOrderingDescending = sortField.order === 'desc';
if (prevItemSortFieldValue) {
if (prevItemOrderFieldValue) {
dbQuery.andWhere(
'value',
isFetchingBackwards !== isOrderingDescending ? '<' : '>',
prevItemSortFieldValue,
prevItemOrderFieldValue,
);
dbQuery.orWhere(function nested() {
this.where('value', '=', prevItemSortFieldValue).andWhere(
this.where('value', '=', prevItemOrderFieldValue).andWhere(
'search.entity_id',
isFetchingBackwards !== isOrderingDescending ? '<' : '>',
prevItemUid,
@@ -451,7 +452,7 @@ export class DefaultEntitiesCatalog implements EntitiesCatalog {
const nextCursor = hasMoreResults
? encodeCursor({
...cursor,
sortFieldValues: sortFieldsFromRow(lastRow),
orderFieldValues: sortFieldsFromRow(lastRow),
firstSortFieldValues,
isPrevious: false,
totalItems,
@@ -464,7 +465,7 @@ export class DefaultEntitiesCatalog implements EntitiesCatalog {
!isEqual(sortFieldsFromRow(firstRow), cursor.firstSortFieldValues)
? encodeCursor({
...cursor,
sortFieldValues: sortFieldsFromRow(firstRow),
orderFieldValues: sortFieldsFromRow(firstRow),
firstSortFieldValues: cursor.firstSortFieldValues,
isPrevious: true,
totalItems,
@@ -475,7 +476,14 @@ export class DefaultEntitiesCatalog implements EntitiesCatalog {
.map(e => JSON.parse(e.final_entity!))
.map(e => (request?.fields ? request.fields(e) : e));
return { items, pageInfo: { prevCursor, nextCursor }, totalItems };
return {
items,
pageInfo: {
...(!!prevCursor && { prevCursor }),
...(!!nextCursor && { nextCursor }),
},
totalItems,
};
}
async removeEntityByUid(uid: string): Promise<void> {
@@ -671,10 +679,10 @@ const entityFilterParser: z.ZodSchema<EntityFilter> = z.lazy(() =>
);
export const cursorParser: z.ZodSchema<Cursor> = z.object({
sortFields: z.array(
orderFields: z.array(
z.object({ field: z.string(), order: z.enum(['asc', 'desc']) }),
),
sortFieldValues: z.array(z.string().or(z.null())),
orderFieldValues: z.array(z.string().or(z.null())),
filter: entityFilterParser.optional(),
isPrevious: z.boolean(),
query: z.string().optional(),
@@ -696,8 +704,12 @@ function parseCursorFromRequest(
request?: QueryEntitiesRequest,
): Partial<Cursor> {
if (isQueryEntitiesInitialRequest(request)) {
const { filter, sortFields = [defaultSortField], query } = request;
return { filter, sortFields, query };
const {
filter,
orderFields: sortFields = [defaultSortField],
query,
} = request;
return { filter, orderFields: sortFields, query };
}
if (isQueryEntitiesCursorRequest(request)) {
try {
@@ -153,7 +153,9 @@ describe('createRouter readonly disabled', () => {
expect(response.body).toEqual({
items,
totalItems: 100,
nextCursor: 'something',
pageInfo: {
nextCursor: 'something',
},
});
});
@@ -181,7 +183,7 @@ describe('createRouter readonly disabled', () => {
{ allOf: [{ key: 'c', values: ['4'] }] },
],
},
sortFields: [
orderFields: [
{ field: 'metadata.name', order: 'asc' },
{ field: 'metadata.uid', order: 'desc' },
],
@@ -210,7 +212,7 @@ describe('createRouter readonly disabled', () => {
expect(response.body).toEqual({
items,
totalItems: 100,
nextCursor: 'next',
pageInfo: { nextCursor: 'next' },
});
});
});
@@ -36,7 +36,7 @@ describe('parseQueryEntitiesParams', () => {
) as QueryEntitiesInitialRequest;
expect(parsedObj.limit).toBe(3);
expect(parsedObj.fields).toBeDefined();
expect(parsedObj.sortFields).toEqual([
expect(parsedObj.orderFields).toEqual([
{ field: 'metadata.name', order: 'desc' },
]);
expect(parsedObj.filter).toBeDefined();
@@ -50,7 +50,7 @@ describe('parseQueryEntitiesParams', () => {
) as QueryEntitiesInitialRequest;
expect(parsedObj.limit).toBeUndefined();
expect(parsedObj.fields).toBeUndefined();
expect(parsedObj.sortFields).toBeUndefined();
expect(parsedObj.orderFields).toBeUndefined();
expect(parsedObj.filter).toBeUndefined();
expect(parsedObj.query).toBeUndefined();
expect(parsedObj).not.toHaveProperty('authorizationToken');
@@ -47,7 +47,7 @@ export function parseQueryEntitiesParams(
fields,
filter,
limit,
sortFields,
orderFields: sortFields,
query,
};