catalog-backend: sortFields to orderFields
Signed-off-by: Vincenzo Scamporlino <vincenzos@spotify.com>
This commit is contained in:
@@ -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,
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user