mirror of
https://github.com/immich-app/immich.git
synced 2026-02-12 03:47:51 +03:00
refactor: use cursors instead of pages
This commit is contained in:
@@ -130,6 +130,14 @@ const create = (path: string, up: string[], down: string[]) => {
|
||||
const compare = async () => {
|
||||
const configRepository = new ConfigRepository();
|
||||
const { database } = configRepository.getEnv();
|
||||
database.config = {
|
||||
connectionType: 'parts',
|
||||
database: 'immich',
|
||||
host: 'database',
|
||||
password: 'postgres',
|
||||
username: 'postgres',
|
||||
port: 5432,
|
||||
};
|
||||
const db = postgres(asPostgresConnectionConfig(database.config));
|
||||
|
||||
const source = schemaFromCode({ overrides: true, namingStrategy: 'default' });
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { Type } from 'class-transformer';
|
||||
import { IsInt, IsOptional, Min } from 'class-validator';
|
||||
import { IsInt, IsOptional, IsUUID, Min } from 'class-validator';
|
||||
import { IntegrityReportType } from 'src/enum';
|
||||
import { ValidateEnum } from 'src/validation';
|
||||
|
||||
@@ -17,17 +17,15 @@ export class IntegrityGetReportDto {
|
||||
@ValidateEnum({ enum: IntegrityReportType, name: 'IntegrityReportType' })
|
||||
type!: IntegrityReportType;
|
||||
|
||||
@IsInt()
|
||||
@Min(1)
|
||||
@IsOptional()
|
||||
@Type(() => Number)
|
||||
page?: number;
|
||||
@IsUUID()
|
||||
cursor?: string;
|
||||
|
||||
@IsInt()
|
||||
@Min(1)
|
||||
@IsOptional()
|
||||
@Type(() => Number)
|
||||
size?: number;
|
||||
limit?: number;
|
||||
}
|
||||
|
||||
export class IntegrityDeleteReportDto {
|
||||
@@ -44,5 +42,5 @@ class IntegrityReportDto {
|
||||
|
||||
export class IntegrityReportResponseDto {
|
||||
items!: IntegrityReportDto[];
|
||||
hasNextPage!: boolean;
|
||||
nextCursor?: string;
|
||||
}
|
||||
|
||||
@@ -31,16 +31,16 @@ select
|
||||
"type",
|
||||
"path",
|
||||
"assetId",
|
||||
"fileAssetId"
|
||||
"fileAssetId",
|
||||
"createdAt"
|
||||
from
|
||||
"integrity_report"
|
||||
where
|
||||
"type" = $1
|
||||
and "createdAt" <= $2
|
||||
order by
|
||||
"createdAt" desc
|
||||
limit
|
||||
$2
|
||||
offset
|
||||
$3
|
||||
|
||||
-- IntegrityRepository.getAssetPathsByPaths
|
||||
|
||||
@@ -5,11 +5,10 @@ import { DummyValue, GenerateSql } from 'src/decorators';
|
||||
import { IntegrityReportType } from 'src/enum';
|
||||
import { DB } from 'src/schema';
|
||||
import { IntegrityReportTable } from 'src/schema/tables/integrity-report.table';
|
||||
import { paginationHelper } from 'src/utils/pagination';
|
||||
|
||||
export interface ReportPaginationOptions {
|
||||
page: number;
|
||||
size: number;
|
||||
cursor?: string;
|
||||
limit: number;
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
@@ -64,18 +63,21 @@ export class IntegrityRepository {
|
||||
.executeTakeFirstOrThrow();
|
||||
}
|
||||
|
||||
@GenerateSql({ params: [{ page: 1, size: 100 }, DummyValue.STRING] })
|
||||
@GenerateSql({ params: [{ cursor: DummyValue.NUMBER, limit: 100 }, DummyValue.STRING] })
|
||||
async getIntegrityReports(pagination: ReportPaginationOptions, type: IntegrityReportType) {
|
||||
const items = await this.db
|
||||
.selectFrom('integrity_report')
|
||||
.select(['id', 'type', 'path', 'assetId', 'fileAssetId'])
|
||||
.select(['id', 'type', 'path', 'assetId', 'fileAssetId', 'createdAt'])
|
||||
.where('type', '=', type)
|
||||
.orderBy('createdAt', 'desc')
|
||||
.limit(pagination.size + 1)
|
||||
.offset((pagination.page - 1) * pagination.size)
|
||||
.$if(pagination.cursor !== undefined, (eb) => eb.where('id', '<=', pagination.cursor!))
|
||||
.orderBy('id', 'desc')
|
||||
.limit(pagination.limit + 1)
|
||||
.execute();
|
||||
|
||||
return paginationHelper(items, pagination.size);
|
||||
return {
|
||||
items: items.slice(0, pagination.limit),
|
||||
nextCursor: items[pagination.limit]?.id,
|
||||
};
|
||||
}
|
||||
|
||||
@GenerateSql({ params: [DummyValue.STRING] })
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Kysely, sql } from 'kysely';
|
||||
|
||||
export async function up(db: Kysely<any>): Promise<void> {
|
||||
await sql`CREATE TABLE "integrity_report" (
|
||||
"id" uuid NOT NULL DEFAULT uuid_generate_v4(),
|
||||
"id" uuid NOT NULL DEFAULT immich_uuid_v7(),
|
||||
"type" character varying NOT NULL,
|
||||
"path" character varying NOT NULL,
|
||||
"createdAt" timestamp with time zone NOT NULL DEFAULT now(),
|
||||
|
||||
@@ -1,21 +1,13 @@
|
||||
import { PrimaryGeneratedUuidV7Column } from 'src/decorators';
|
||||
import { IntegrityReportType } from 'src/enum';
|
||||
import { AssetFileTable } from 'src/schema/tables/asset-file.table';
|
||||
import { AssetTable } from 'src/schema/tables/asset.table';
|
||||
import {
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
ForeignKeyColumn,
|
||||
Generated,
|
||||
PrimaryGeneratedColumn,
|
||||
Table,
|
||||
Timestamp,
|
||||
Unique,
|
||||
} from 'src/sql-tools';
|
||||
import { Column, CreateDateColumn, ForeignKeyColumn, Generated, Table, Timestamp, Unique } from 'src/sql-tools';
|
||||
|
||||
@Table('integrity_report')
|
||||
@Unique({ columns: ['type', 'path'] })
|
||||
export class IntegrityReportTable {
|
||||
@PrimaryGeneratedColumn()
|
||||
@PrimaryGeneratedUuidV7Column()
|
||||
id!: Generated<string>;
|
||||
|
||||
@Column()
|
||||
|
||||
@@ -140,7 +140,7 @@ export class IntegrityService extends BaseService {
|
||||
}
|
||||
|
||||
async getIntegrityReport(dto: IntegrityGetReportDto): Promise<IntegrityReportResponseDto> {
|
||||
return this.integrityRepository.getIntegrityReports({ page: dto.page || 1, size: dto.size || 100 }, dto.type);
|
||||
return this.integrityRepository.getIntegrityReports({ cursor: dto.cursor, limit: dto.limit || 100 }, dto.type);
|
||||
}
|
||||
|
||||
getIntegrityReportCsv(type: IntegrityReportType): Readable {
|
||||
|
||||
Reference in New Issue
Block a user