Files
twenty/server/src/utils/pagination/paginated.ts
Jérémy M b1171e22a3 feat: add findAll and findUnique resolver for universal objects (#1576)
* wip: refacto and start creating custom resolver

* feat: findMany & findUnique of a custom entity

* feat: wip pagination

* feat: initial metadata migration

* feat: universal findAll with pagination

* fix: clean small stuff in pagination

* fix: test

* fix: miss file

* feat: rename custom into universal

* feat: create metadata schema in default database

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2023-09-20 17:24:13 -07:00

81 lines
2.3 KiB
TypeScript

import { Type } from '@nestjs/common';
import { ArgsType, Directive, Field, ObjectType } from '@nestjs/graphql';
import { IsNumber, IsOptional, IsString } from 'class-validator';
import { PageInfo } from './page-info';
import { IConnectionArguments } from './interfaces/connection-arguments.interface';
import { IConnection } from './interfaces/connection.interface';
import { IEdge } from './interfaces/edge.interface';
import { IPageInfo } from './interfaces/page-info.interface';
export type ConnectionCursor = string;
/**
* ConnectionArguments
*/
@ArgsType()
export class ConnectionArgs implements IConnectionArguments {
@Field({ nullable: true, description: 'Paginate before opaque cursor' })
@IsString()
@IsOptional()
public before?: ConnectionCursor;
@Field({ nullable: true, description: 'Paginate after opaque cursor' })
@IsString()
@IsOptional()
public after?: ConnectionCursor;
@Field({ nullable: true, description: 'Paginate first' })
@IsNumber()
@IsOptional()
public first?: number;
@Field({ nullable: true, description: 'Paginate last' })
@IsNumber()
@IsOptional()
public last?: number;
}
/**
* Paginated graphQL class inheritance
*/
export function Paginated<T>(classRef: Type<T>): Type<IConnection<T>> {
@ObjectType(`${classRef.name}Edge`, { isAbstract: true })
class Edge implements IEdge<T> {
public name = `${classRef.name}Edge`;
@Field({ nullable: true })
public cursor!: ConnectionCursor;
@Field(() => classRef, { nullable: true })
@Directive(`@cacheControl(inheritMaxAge: true)`)
public node!: T;
}
@ObjectType(`${classRef.name}Connection`, { isAbstract: true })
class Connection implements IConnection<T> {
public name = `${classRef.name}Connection`;
@Field(() => [Edge], { nullable: true })
@Directive(`@cacheControl(inheritMaxAge: true)`)
public edges!: IEdge<T>[];
@Field(() => PageInfo, { nullable: true })
@Directive(`@cacheControl(inheritMaxAge: true)`)
public pageInfo!: IPageInfo;
@Field()
totalCount: number;
}
return Connection as Type<IConnection<T>>;
}
// export const encodeCursor = <Cursor>(cursor: Cursor) =>
// Buffer.from(JSON.stringify(cursor)).toString('base64');
// export const decodeCursor = <Cursor>(cursor: string) =>
// JSON.parse(Buffer.from(cursor, 'base64').toString('ascii')) as Cursor;