Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support pagination to getRelations #193

Merged
merged 12 commits into from
Oct 16, 2024
1 change: 1 addition & 0 deletions api/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export {
RETURN_FAVORITES_COLUMNS,
RETURN_NAVIGATION_COLUMNS,
INTER_TENANT_GET_ENTRIES_SCHEMA,
ALLOWED_ENTRIES_SCOPE,
AUTHORIZATION_HEADER,
DL_AUTH_HEADER_KEY,
} from '../src/const';
9 changes: 9 additions & 0 deletions src/const/common.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import {EntryScope} from '../db/models/new/entry/types';
import {Mode} from '../types/models';

export const TRUE_FLAGS = ['1', 'true', true];
Expand Down Expand Up @@ -244,3 +245,11 @@ export const INTER_TENANT_GET_ENTRIES_SCHEMA = {
};

export const ModeValues: Mode[] = ['save', 'publish'];

export const ALLOWED_ENTRIES_SCOPE = [
EntryScope.Dash,
EntryScope.Widget,
EntryScope.Dataset,
EntryScope.Connection,
EntryScope.Report,
] as const;
4 changes: 4 additions & 0 deletions src/controllers/entries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import {
formatGetEntryMetaPrivateResponse,
formatEntryModel,
} from '../services/new/entry/formatters';
import {EntryScope} from '../db/models/new/entry/types';

export default {
getEntry: async (req: Request, res: Response) => {
Expand Down Expand Up @@ -243,6 +244,9 @@ export default {
entryId: params.entryId,
direction: query.direction as Optional<RelationDirection>,
includePermissionsInfo: Utils.isTrueArg(query.includePermissionsInfo),
page: (query.page && Number(query.page)) as number | undefined,
pageSize: (query.pageSize && Number(query.pageSize)) as number | undefined,
scope: query.scope as EntryScope | undefined,
},
);

Expand Down
54 changes: 52 additions & 2 deletions src/services/entry/actions/get-entry-relations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,22 @@ import {Entry, EntryColumn} from '../../../db/models/new/entry';
import {DlsActions} from '../../../types/models';
import {ServiceArgs} from '../../new/types';
import Utils from '../../../utils';
import {US_ERRORS} from '../../../const';
import {ALLOWED_ENTRIES_SCOPE, US_ERRORS} from '../../../const';
import {makeSchemaValidator} from '../../../components/validation-schema-compiler';
import {getWorkbook} from '../../new/workbook/get-workbook';
import {getEntryPermissionsByWorkbook} from '../../new/workbook/utils';
import {getRelatedEntries, RelationDirection} from './get-related-entries';
import {registry} from '../../../registry';
import {getReplica} from '../../new/utils';
import {EntryScope} from '../../../db/models/new/entry/types';

export type GetEntryRelationsArgs = {
entryId: string;
direction?: RelationDirection;
includePermissionsInfo?: boolean;
scope?: EntryScope;
page?: number;
pageSize?: number;
};

const validateArgs = makeSchemaValidator({
Expand All @@ -31,6 +35,19 @@ const validateArgs = makeSchemaValidator({
includePermissionsInfo: {
type: 'boolean',
},
scope: {
type: 'string',
enum: ALLOWED_ENTRIES_SCOPE,
},
page: {
type: 'number',
minimum: 0,
},
pageSize: {
type: 'number',
minimum: 1,
maximum: 200,
},
},
});

Expand All @@ -42,11 +59,21 @@ export async function getEntryRelations(

const {tenantId, isPrivateRoute} = ctx.get('info');

const {entryId, direction = RelationDirection.Parent, includePermissionsInfo = false} = args;
const {
entryId,
scope,
page,
pageSize,
direction = RelationDirection.Parent,
includePermissionsInfo = false,
} = args;

ctx.log('GET_ENTRY_RELATIONS_REQUEST', {
entryId: Utils.encodeId(entryId),
direction,
scope,
page,
pageSize,
includePermissionsInfo,
});

Expand Down Expand Up @@ -74,9 +101,24 @@ export async function getEntryRelations(
{
entryIds: [entryId],
direction,
scope,
page,
pageSize,
},
);

const isPagination = typeof page !== 'undefined' && typeof pageSize !== 'undefined';

let nextPageToken;

if (isPagination) {
nextPageToken = Utils.getOptimisticNextPageToken({
page: page,
pageSize: pageSize,
curPage: relations,
});
}

relations = relations.filter((item) => item.tenantId === entry.tenantId);

if (entry.workbookId) {
Expand Down Expand Up @@ -138,5 +180,13 @@ export async function getEntryRelations(

ctx.log('GET_ENTRY_RELATIONS_SUCCESS', {count: relations.length});

// TODO: leave a response with pagination only, when there will be pagination support everywhere in the frontend
if (isPagination) {
return {
relations,
nextPageToken,
};
}

return relations;
Sergey-weber marked this conversation as resolved.
Show resolved Hide resolved
}
37 changes: 29 additions & 8 deletions src/services/entry/actions/get-related-entries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
} from '../../../const';
import {getReplica} from '../../new/utils';
import {EntryScope} from '../../../db/models/new/entry/types';
import {EntryColumn} from '../../../db/models/new/entry';

export enum RelationDirection {
Parent = 'parent',
Expand All @@ -18,6 +19,9 @@ type GetRelatedEntriesData = {
entryIds: string[];
direction?: RelationDirection;
extendedTimeout?: boolean;
scope?: EntryScope;
page?: number;
pageSize?: number;
};

type GetRelatedEntriesResult = {
Expand All @@ -38,14 +42,17 @@ export async function getRelatedEntries(
{
entryIds,
direction = RelationDirection.Parent,
scope,
page,
pageSize,
extendedTimeout = false,
}: GetRelatedEntriesData,
) {
ctx.log('GET_RELATED_ENTRIES_RUN');
ctx.log('GET_RELATED_ENTRIES_RUN', {scope, page, pageSize});

const endToStart = direction === RelationDirection.Parent;

const relatedEntries = (await Entry.query(getReplica(trx))
const relatedEntries = Entry.query(getReplica(trx))
.withRecursive('relatedEntries', (qb) => {
qb.select(['fromId', 'toId', raw('1 depth')])
.from('links')
Expand Down Expand Up @@ -82,14 +89,28 @@ export async function getRelatedEntries(
.join('revisions', 'entries.savedId', 'revisions.revId')
.as('re');
})
.orderBy('depth')
.timeout(
extendedTimeout ? EXTENDED_QUERY_TIMEOUT : DEFAULT_QUERY_TIMEOUT,
)) as unknown[] as GetRelatedEntriesResult[];
.where((builder) => {
if (scope) {
builder.where({[EntryColumn.Scope]: scope});
}
})
.orderBy('depth');
Sergey-weber marked this conversation as resolved.
Show resolved Hide resolved

if (pageSize) {
relatedEntries.limit(pageSize);

if (page) {
relatedEntries.offset(pageSize * page);
}
}

const result = (await relatedEntries.timeout(
extendedTimeout ? EXTENDED_QUERY_TIMEOUT : DEFAULT_QUERY_TIMEOUT,
)) as unknown[] as GetRelatedEntriesResult[];

ctx.log('GET_RELATED_ENTRIES_DONE', {
amount: relatedEntries && relatedEntries.length,
amount: result && result.length,
Sergey-weber marked this conversation as resolved.
Show resolved Hide resolved
});

return relatedEntries;
return result;
}
12 changes: 0 additions & 12 deletions src/utils/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -441,18 +441,6 @@ export class Utils {
return dsnList;
}

/** @deprecated use getOptimisticNextPageToken */
static getNextPageToken(page: number, pageSize: number, total: number) {
const lastPage = Math.ceil(total / pageSize) - 1;
let nextPageToken;

if (page >= 0 && page < lastPage) {
nextPageToken = String(page + 1);
}

return nextPageToken;
}

static getOptimisticNextPageToken({
page,
pageSize,
Expand Down
Loading