Sort files chronologically + infinite scroll (#535)

This commit is contained in:
Montassar Ghanmy
2024-07-15 22:56:34 +01:00
committed by GitHub
parent 585da88b0d
commit e76da87916
25 changed files with 719 additions and 153 deletions
@@ -264,12 +264,22 @@ export class MongoConnector extends AbstractConnector<MongoConnectionOptions> {
options,
);
const sort: any = {};
let sort: any = {};
for (const key of entityDefinition.options.primaryKey.slice(1)) {
const defaultOrder =
(columnsDefinition[key as string].options.order || "ASC") === "ASC" ? 1 : -1;
sort[key as string] = (options?.pagination?.reversed ? -1 : 1) * defaultOrder;
}
if (options?.sort) {
sort = options.sort
? Object.fromEntries(
Object.entries(options.sort).map(([field, direction]) => [
field,
direction === "asc" ? 1 : -1,
]),
)
: {};
}
logger.debug(`services.database.orm.mongodb.find - Query: ${JSON.stringify(query)}`);
@@ -277,7 +287,11 @@ export class MongoConnector extends AbstractConnector<MongoConnectionOptions> {
.find(query)
.sort(sort)
.skip(Math.max(0, parseInt(options.pagination.page_token || "0")))
.limit(Math.max(0, parseInt(options.pagination.limitStr || "100")));
.limit(Math.max(0, parseInt(options.pagination.limitStr || "100")))
.collation({
locale: "en_US",
numericOrdering: true,
});
const entities: Table[] = [];
while (await cursor.hasNext()) {
@@ -88,13 +88,20 @@ export class PostgresQueryBuilder {
if (whereClause && whereClause.endsWith("AND ")) whereClause = whereClause.slice(0, -4);
// ==== ORDER BY =====
const orderByClause = `${entityDefinition.options.primaryKey
let orderByClause = `${entityDefinition.options.primaryKey
.slice(1)
.map(
(key: string) =>
`${key} ${(columnsDefinition[key].options.order || "ASC") === "ASC" ? "DESC" : "ASC"}`,
)}`;
// ==== ORDER BY CUSTOM COLUMN =====
if (options?.sort) {
orderByClause = Object.keys(options.sort)
.map(key => `${key} ${options.sort[key].toUpperCase()}`)
.join(", ");
}
// ==== PAGING =====
let limit = 100;
let offset = 0;
@@ -22,6 +22,12 @@ export type inType = [string, Array<any>];
// eslint-disable-next-line @typescript-eslint/no-explicit-any
type likeType = [string, any];
type SortDirection = "asc" | "desc";
type SortOption = {
[field: string]: SortDirection;
};
export type FindOptions = {
pagination?: Pagination;
$lt?: comparisonType[];
@@ -34,6 +40,7 @@ export type FindOptions = {
$in?: inType[];
$nin?: inType[];
$like?: likeType[];
sort?: SortOption;
};
/**
@@ -35,14 +35,14 @@ export class ConsoleServiceImpl implements TdriveServiceProvider {
this.consoleOptions = {
type: type,
authority: s.authority,
client_id: s.client_id,
client_secret: s.client_secret,
audience: s.audience,
issuer: s.issuer,
jwks_uri: s.jwks_uri,
redirect_uris: s.redirect_uris,
disable_account_creation: s.disable_account_creation,
authority: s?.authority,
client_id: s?.client_id,
client_secret: s?.client_secret,
audience: s?.audience,
issuer: s?.issuer,
jwks_uri: s?.jwks_uri,
redirect_uris: s?.redirect_uris,
disable_account_creation: s?.disable_account_creation,
};
this.consoleOptions.type = type;
@@ -29,8 +29,10 @@ import {
DriveFileAccessLevel,
DriveItemDetails,
DriveTdriveTab,
PaginateDocumentBody,
RootType,
SearchDocumentsOptions,
SortDocumentsBody,
TrashType,
} from "../types";
import {
@@ -105,6 +107,8 @@ export class DocumentsService {
browse = async (
id: string,
options: SearchDocumentsOptions,
sort: SortDocumentsBody,
paginate: PaginateDocumentBody,
context: DriveExecutionContext & { public_token?: string },
): Promise<BrowseDetails> => {
if (isSharedWithMeFolder(id)) {
@@ -112,7 +116,7 @@ export class DocumentsService {
} else {
return {
nextPage: null,
...(await this.get(id, context)),
...(await this.get(id, context, false, sort, paginate)),
};
}
};
@@ -154,6 +158,9 @@ export class DocumentsService {
get = async (
id: string,
context: DriveExecutionContext & { public_token?: string },
all?: boolean,
sort?: SortDocumentsBody,
paginate?: PaginateDocumentBody,
): Promise<DriveItemDetails> => {
if (!context) {
this.logger.error("invalid context");
@@ -206,7 +213,26 @@ export class DocumentsService {
)
).getEntities();
//Get children if it is a directory
const sortFieldMapping = {
name: "name",
date: "last_modified",
size: "size",
};
let sortField = {};
sortField[sortFieldMapping[sort?.by] || "last_modified"] = sort?.order || "desc";
const dbType = await globalResolver.database.getConnector().getType();
// Initialize pagination
let pagination;
if (paginate) {
const { page, limit } = paginate;
const pageNumber = dbType === "mongodb" ? page : page / limit + 1;
pagination = new Pagination(`${pageNumber}`, `${limit}`, false);
}
let children = isDirectory
? (
await this.repository.find(
@@ -229,7 +255,15 @@ export class DocumentsService {
is_in_trash: false,
}),
},
{},
all
? {}
: {
sort: {
is_directory: "desc",
...sortField,
},
pagination,
},
context,
)
).getEntities()
@@ -59,6 +59,12 @@ export type SearchDocumentsOptions = {
pagination?: Paginable;
};
export type BrowseDocumentsOptions = {
filter?: SearchDocumentsBody;
sort?: SortDocumentsBody;
paginate?: PaginateDocumentBody;
};
export type SearchDocumentsBody = {
search?: string;
company_id?: string;
@@ -73,6 +79,16 @@ export type SearchDocumentsBody = {
fields?: string[];
};
export type SortDocumentsBody = {
by: string;
order: string;
};
export type PaginateDocumentBody = {
page: number;
limit: number;
};
export type DocumentsMessageQueueRequest = {
item: DriveFile;
version: FileVersion;
@@ -9,16 +9,19 @@ import { CompanyUserRole, PaginationQueryParameters } from "../../../../utils/ty
import { DriveFile } from "../../entities/drive-file";
import { FileVersion } from "../../entities/file-version";
import {
BrowseDocumentsOptions,
CompanyExecutionContext,
DriveExecutionContext,
DriveFileAccessLevel,
DriveItemDetails,
DriveTdriveTab,
ItemRequestParams,
PaginateDocumentBody,
ItemRequestByEditingSessionKeyParams,
RequestParams,
SearchDocumentsBody,
SearchDocumentsOptions,
SortDocumentsBody,
} from "../../types";
import { DriveFileDTO } from "../dto/drive-file-dto";
import { DriveFileDTOBuilder } from "../../services/drive-file-dto-builder";
@@ -196,7 +199,7 @@ export class DocumentsController {
browse = async (
request: FastifyRequest<{
Params: ItemRequestParams;
Body: SearchDocumentsBody;
Body: BrowseDocumentsOptions;
Querystring: PaginationQueryParameters & { public_token?: string };
}>,
): Promise<DriveItemDetails> => {
@@ -204,15 +207,24 @@ export class DocumentsController {
const { id } = request.params;
const options: SearchDocumentsOptions = {
...request.body,
company_id: request.body.company_id || context.company.id,
...request.body.filter,
company_id: request.body.filter?.company_id || context.company.id,
view: DriveFileDTOBuilder.VIEW_SHARED_WITH_ME,
onlyDirectlyShared: true,
onlyUploadedNotByMe: true,
};
const sortOptions: SortDocumentsBody = request.body.sort;
const paginateOptions: PaginateDocumentBody = request.body.paginate;
return {
...(await globalResolver.services.documents.documents.browse(id, options, context)),
...(await globalResolver.services.documents.documents.browse(
id,
options,
sortOptions,
paginateOptions,
context,
)),
};
};
@@ -446,11 +458,12 @@ export class DocumentsController {
downloadZip = async (
request: FastifyRequest<{
Params: RequestParams;
Querystring: { token?: string; items: string; public_token?: string };
Querystring: { token?: string; items: string; public_token?: string; is_directory?: boolean };
}>,
reply: FastifyReply,
): Promise<void> => {
const context = getDriveExecutionContext(request);
const isDirectory = request.query.is_directory || false;
let ids = (request.query.items || "").split(",");
const token = request.query.token;
@@ -466,6 +479,11 @@ export class DocumentsController {
ids = items.children.map(item => item.id);
}
if (isDirectory) {
const items = await globalResolver.services.documents.documents.get(ids[0], context, true);
ids = items.children.map(item => item.id);
}
try {
const archive = await globalResolver.services.documents.documents.createZip(ids, context);