mirror of
https://github.com/immich-app/immich.git
synced 2025-01-28 00:59:18 -05:00
refactor: migrate library repository to kysely (#15271)
This commit is contained in:
parent
81568dbda3
commit
a2207f2eef
5 changed files with 225 additions and 205 deletions
|
@ -1,3 +1,5 @@
|
|||
import { Insertable, Updateable } from 'kysely';
|
||||
import { Libraries } from 'src/db';
|
||||
import { LibraryStatsResponseDto } from 'src/dtos/library.dto';
|
||||
import { LibraryEntity } from 'src/entities/library.entity';
|
||||
|
||||
|
@ -6,10 +8,10 @@ export const ILibraryRepository = 'ILibraryRepository';
|
|||
export interface ILibraryRepository {
|
||||
getAll(withDeleted?: boolean): Promise<LibraryEntity[]>;
|
||||
getAllDeleted(): Promise<LibraryEntity[]>;
|
||||
get(id: string, withDeleted?: boolean): Promise<LibraryEntity | null>;
|
||||
create(library: Partial<LibraryEntity>): Promise<LibraryEntity>;
|
||||
get(id: string, withDeleted?: boolean): Promise<LibraryEntity | undefined>;
|
||||
create(library: Insertable<Libraries>): Promise<LibraryEntity>;
|
||||
delete(id: string): Promise<void>;
|
||||
softDelete(id: string): Promise<void>;
|
||||
update(library: Partial<LibraryEntity>): Promise<LibraryEntity>;
|
||||
update(id: string, library: Updateable<Libraries>): Promise<LibraryEntity>;
|
||||
getStatistics(id: string): Promise<LibraryStatsResponseDto | undefined>;
|
||||
}
|
||||
|
|
|
@ -1,150 +1,137 @@
|
|||
-- NOTE: This file is auto generated by ./sql-generator
|
||||
|
||||
-- LibraryRepository.get
|
||||
SELECT DISTINCT
|
||||
"distinctAlias"."LibraryEntity_id" AS "ids_LibraryEntity_id"
|
||||
FROM
|
||||
select
|
||||
"libraries".*,
|
||||
(
|
||||
SELECT
|
||||
"LibraryEntity"."id" AS "LibraryEntity_id",
|
||||
"LibraryEntity"."name" AS "LibraryEntity_name",
|
||||
"LibraryEntity"."ownerId" AS "LibraryEntity_ownerId",
|
||||
"LibraryEntity"."importPaths" AS "LibraryEntity_importPaths",
|
||||
"LibraryEntity"."exclusionPatterns" AS "LibraryEntity_exclusionPatterns",
|
||||
"LibraryEntity"."createdAt" AS "LibraryEntity_createdAt",
|
||||
"LibraryEntity"."updatedAt" AS "LibraryEntity_updatedAt",
|
||||
"LibraryEntity"."deletedAt" AS "LibraryEntity_deletedAt",
|
||||
"LibraryEntity"."refreshedAt" AS "LibraryEntity_refreshedAt",
|
||||
"LibraryEntity__LibraryEntity_owner"."id" AS "LibraryEntity__LibraryEntity_owner_id",
|
||||
"LibraryEntity__LibraryEntity_owner"."name" AS "LibraryEntity__LibraryEntity_owner_name",
|
||||
"LibraryEntity__LibraryEntity_owner"."isAdmin" AS "LibraryEntity__LibraryEntity_owner_isAdmin",
|
||||
"LibraryEntity__LibraryEntity_owner"."email" AS "LibraryEntity__LibraryEntity_owner_email",
|
||||
"LibraryEntity__LibraryEntity_owner"."storageLabel" AS "LibraryEntity__LibraryEntity_owner_storageLabel",
|
||||
"LibraryEntity__LibraryEntity_owner"."oauthId" AS "LibraryEntity__LibraryEntity_owner_oauthId",
|
||||
"LibraryEntity__LibraryEntity_owner"."profileImagePath" AS "LibraryEntity__LibraryEntity_owner_profileImagePath",
|
||||
"LibraryEntity__LibraryEntity_owner"."shouldChangePassword" AS "LibraryEntity__LibraryEntity_owner_shouldChangePassword",
|
||||
"LibraryEntity__LibraryEntity_owner"."createdAt" AS "LibraryEntity__LibraryEntity_owner_createdAt",
|
||||
"LibraryEntity__LibraryEntity_owner"."deletedAt" AS "LibraryEntity__LibraryEntity_owner_deletedAt",
|
||||
"LibraryEntity__LibraryEntity_owner"."status" AS "LibraryEntity__LibraryEntity_owner_status",
|
||||
"LibraryEntity__LibraryEntity_owner"."updatedAt" AS "LibraryEntity__LibraryEntity_owner_updatedAt",
|
||||
"LibraryEntity__LibraryEntity_owner"."quotaSizeInBytes" AS "LibraryEntity__LibraryEntity_owner_quotaSizeInBytes",
|
||||
"LibraryEntity__LibraryEntity_owner"."quotaUsageInBytes" AS "LibraryEntity__LibraryEntity_owner_quotaUsageInBytes",
|
||||
"LibraryEntity__LibraryEntity_owner"."profileChangedAt" AS "LibraryEntity__LibraryEntity_owner_profileChangedAt"
|
||||
FROM
|
||||
"libraries" "LibraryEntity"
|
||||
LEFT JOIN "users" "LibraryEntity__LibraryEntity_owner" ON "LibraryEntity__LibraryEntity_owner"."id" = "LibraryEntity"."ownerId"
|
||||
AND (
|
||||
"LibraryEntity__LibraryEntity_owner"."deletedAt" IS NULL
|
||||
)
|
||||
WHERE
|
||||
((("LibraryEntity"."id" = $1)))
|
||||
AND ("LibraryEntity"."deletedAt" IS NULL)
|
||||
) "distinctAlias"
|
||||
ORDER BY
|
||||
"LibraryEntity_id" ASC
|
||||
LIMIT
|
||||
1
|
||||
select
|
||||
to_json(obj)
|
||||
from
|
||||
(
|
||||
select
|
||||
"users"."id",
|
||||
"users"."email",
|
||||
"users"."createdAt",
|
||||
"users"."profileImagePath",
|
||||
"users"."isAdmin",
|
||||
"users"."shouldChangePassword",
|
||||
"users"."deletedAt",
|
||||
"users"."oauthId",
|
||||
"users"."updatedAt",
|
||||
"users"."storageLabel",
|
||||
"users"."name",
|
||||
"users"."quotaSizeInBytes",
|
||||
"users"."quotaUsageInBytes",
|
||||
"users"."status",
|
||||
"users"."profileChangedAt"
|
||||
from
|
||||
"users"
|
||||
where
|
||||
"users"."id" = "libraries"."ownerId"
|
||||
) as obj
|
||||
) as "owner"
|
||||
from
|
||||
"libraries"
|
||||
where
|
||||
"libraries"."id" = $1
|
||||
and "libraries"."deletedAt" is null
|
||||
|
||||
-- LibraryRepository.getAll
|
||||
SELECT
|
||||
"LibraryEntity"."id" AS "LibraryEntity_id",
|
||||
"LibraryEntity"."name" AS "LibraryEntity_name",
|
||||
"LibraryEntity"."ownerId" AS "LibraryEntity_ownerId",
|
||||
"LibraryEntity"."importPaths" AS "LibraryEntity_importPaths",
|
||||
"LibraryEntity"."exclusionPatterns" AS "LibraryEntity_exclusionPatterns",
|
||||
"LibraryEntity"."createdAt" AS "LibraryEntity_createdAt",
|
||||
"LibraryEntity"."updatedAt" AS "LibraryEntity_updatedAt",
|
||||
"LibraryEntity"."deletedAt" AS "LibraryEntity_deletedAt",
|
||||
"LibraryEntity"."refreshedAt" AS "LibraryEntity_refreshedAt",
|
||||
"LibraryEntity__LibraryEntity_owner"."id" AS "LibraryEntity__LibraryEntity_owner_id",
|
||||
"LibraryEntity__LibraryEntity_owner"."name" AS "LibraryEntity__LibraryEntity_owner_name",
|
||||
"LibraryEntity__LibraryEntity_owner"."isAdmin" AS "LibraryEntity__LibraryEntity_owner_isAdmin",
|
||||
"LibraryEntity__LibraryEntity_owner"."email" AS "LibraryEntity__LibraryEntity_owner_email",
|
||||
"LibraryEntity__LibraryEntity_owner"."storageLabel" AS "LibraryEntity__LibraryEntity_owner_storageLabel",
|
||||
"LibraryEntity__LibraryEntity_owner"."oauthId" AS "LibraryEntity__LibraryEntity_owner_oauthId",
|
||||
"LibraryEntity__LibraryEntity_owner"."profileImagePath" AS "LibraryEntity__LibraryEntity_owner_profileImagePath",
|
||||
"LibraryEntity__LibraryEntity_owner"."shouldChangePassword" AS "LibraryEntity__LibraryEntity_owner_shouldChangePassword",
|
||||
"LibraryEntity__LibraryEntity_owner"."createdAt" AS "LibraryEntity__LibraryEntity_owner_createdAt",
|
||||
"LibraryEntity__LibraryEntity_owner"."deletedAt" AS "LibraryEntity__LibraryEntity_owner_deletedAt",
|
||||
"LibraryEntity__LibraryEntity_owner"."status" AS "LibraryEntity__LibraryEntity_owner_status",
|
||||
"LibraryEntity__LibraryEntity_owner"."updatedAt" AS "LibraryEntity__LibraryEntity_owner_updatedAt",
|
||||
"LibraryEntity__LibraryEntity_owner"."quotaSizeInBytes" AS "LibraryEntity__LibraryEntity_owner_quotaSizeInBytes",
|
||||
"LibraryEntity__LibraryEntity_owner"."quotaUsageInBytes" AS "LibraryEntity__LibraryEntity_owner_quotaUsageInBytes",
|
||||
"LibraryEntity__LibraryEntity_owner"."profileChangedAt" AS "LibraryEntity__LibraryEntity_owner_profileChangedAt"
|
||||
FROM
|
||||
"libraries" "LibraryEntity"
|
||||
LEFT JOIN "users" "LibraryEntity__LibraryEntity_owner" ON "LibraryEntity__LibraryEntity_owner"."id" = "LibraryEntity"."ownerId"
|
||||
AND (
|
||||
"LibraryEntity__LibraryEntity_owner"."deletedAt" IS NULL
|
||||
)
|
||||
WHERE
|
||||
"LibraryEntity"."deletedAt" IS NULL
|
||||
ORDER BY
|
||||
"LibraryEntity"."createdAt" ASC
|
||||
select
|
||||
"libraries".*,
|
||||
(
|
||||
select
|
||||
to_json(obj)
|
||||
from
|
||||
(
|
||||
select
|
||||
"users"."id",
|
||||
"users"."email",
|
||||
"users"."createdAt",
|
||||
"users"."profileImagePath",
|
||||
"users"."isAdmin",
|
||||
"users"."shouldChangePassword",
|
||||
"users"."deletedAt",
|
||||
"users"."oauthId",
|
||||
"users"."updatedAt",
|
||||
"users"."storageLabel",
|
||||
"users"."name",
|
||||
"users"."quotaSizeInBytes",
|
||||
"users"."quotaUsageInBytes",
|
||||
"users"."status",
|
||||
"users"."profileChangedAt"
|
||||
from
|
||||
"users"
|
||||
where
|
||||
"users"."id" = "libraries"."ownerId"
|
||||
) as obj
|
||||
) as "owner"
|
||||
from
|
||||
"libraries"
|
||||
where
|
||||
"libraries"."deletedAt" is null
|
||||
order by
|
||||
"createdAt" asc
|
||||
|
||||
-- LibraryRepository.getAllDeleted
|
||||
SELECT
|
||||
"LibraryEntity"."id" AS "LibraryEntity_id",
|
||||
"LibraryEntity"."name" AS "LibraryEntity_name",
|
||||
"LibraryEntity"."ownerId" AS "LibraryEntity_ownerId",
|
||||
"LibraryEntity"."importPaths" AS "LibraryEntity_importPaths",
|
||||
"LibraryEntity"."exclusionPatterns" AS "LibraryEntity_exclusionPatterns",
|
||||
"LibraryEntity"."createdAt" AS "LibraryEntity_createdAt",
|
||||
"LibraryEntity"."updatedAt" AS "LibraryEntity_updatedAt",
|
||||
"LibraryEntity"."deletedAt" AS "LibraryEntity_deletedAt",
|
||||
"LibraryEntity"."refreshedAt" AS "LibraryEntity_refreshedAt",
|
||||
"LibraryEntity__LibraryEntity_owner"."id" AS "LibraryEntity__LibraryEntity_owner_id",
|
||||
"LibraryEntity__LibraryEntity_owner"."name" AS "LibraryEntity__LibraryEntity_owner_name",
|
||||
"LibraryEntity__LibraryEntity_owner"."isAdmin" AS "LibraryEntity__LibraryEntity_owner_isAdmin",
|
||||
"LibraryEntity__LibraryEntity_owner"."email" AS "LibraryEntity__LibraryEntity_owner_email",
|
||||
"LibraryEntity__LibraryEntity_owner"."storageLabel" AS "LibraryEntity__LibraryEntity_owner_storageLabel",
|
||||
"LibraryEntity__LibraryEntity_owner"."oauthId" AS "LibraryEntity__LibraryEntity_owner_oauthId",
|
||||
"LibraryEntity__LibraryEntity_owner"."profileImagePath" AS "LibraryEntity__LibraryEntity_owner_profileImagePath",
|
||||
"LibraryEntity__LibraryEntity_owner"."shouldChangePassword" AS "LibraryEntity__LibraryEntity_owner_shouldChangePassword",
|
||||
"LibraryEntity__LibraryEntity_owner"."createdAt" AS "LibraryEntity__LibraryEntity_owner_createdAt",
|
||||
"LibraryEntity__LibraryEntity_owner"."deletedAt" AS "LibraryEntity__LibraryEntity_owner_deletedAt",
|
||||
"LibraryEntity__LibraryEntity_owner"."status" AS "LibraryEntity__LibraryEntity_owner_status",
|
||||
"LibraryEntity__LibraryEntity_owner"."updatedAt" AS "LibraryEntity__LibraryEntity_owner_updatedAt",
|
||||
"LibraryEntity__LibraryEntity_owner"."quotaSizeInBytes" AS "LibraryEntity__LibraryEntity_owner_quotaSizeInBytes",
|
||||
"LibraryEntity__LibraryEntity_owner"."quotaUsageInBytes" AS "LibraryEntity__LibraryEntity_owner_quotaUsageInBytes",
|
||||
"LibraryEntity__LibraryEntity_owner"."profileChangedAt" AS "LibraryEntity__LibraryEntity_owner_profileChangedAt"
|
||||
FROM
|
||||
"libraries" "LibraryEntity"
|
||||
LEFT JOIN "users" "LibraryEntity__LibraryEntity_owner" ON "LibraryEntity__LibraryEntity_owner"."id" = "LibraryEntity"."ownerId"
|
||||
WHERE
|
||||
((NOT ("LibraryEntity"."deletedAt" IS NULL)))
|
||||
ORDER BY
|
||||
"LibraryEntity"."createdAt" ASC
|
||||
select
|
||||
"libraries".*,
|
||||
(
|
||||
select
|
||||
to_json(obj)
|
||||
from
|
||||
(
|
||||
select
|
||||
"users"."id",
|
||||
"users"."email",
|
||||
"users"."createdAt",
|
||||
"users"."profileImagePath",
|
||||
"users"."isAdmin",
|
||||
"users"."shouldChangePassword",
|
||||
"users"."deletedAt",
|
||||
"users"."oauthId",
|
||||
"users"."updatedAt",
|
||||
"users"."storageLabel",
|
||||
"users"."name",
|
||||
"users"."quotaSizeInBytes",
|
||||
"users"."quotaUsageInBytes",
|
||||
"users"."status",
|
||||
"users"."profileChangedAt"
|
||||
from
|
||||
"users"
|
||||
where
|
||||
"users"."id" = "libraries"."ownerId"
|
||||
) as obj
|
||||
) as "owner"
|
||||
from
|
||||
"libraries"
|
||||
where
|
||||
"libraries"."deletedAt" is not null
|
||||
order by
|
||||
"createdAt" asc
|
||||
|
||||
-- LibraryRepository.getStatistics
|
||||
SELECT
|
||||
"libraries"."id" AS "libraries_id",
|
||||
"libraries"."name" AS "libraries_name",
|
||||
"libraries"."ownerId" AS "libraries_ownerId",
|
||||
"libraries"."importPaths" AS "libraries_importPaths",
|
||||
"libraries"."exclusionPatterns" AS "libraries_exclusionPatterns",
|
||||
"libraries"."createdAt" AS "libraries_createdAt",
|
||||
"libraries"."updatedAt" AS "libraries_updatedAt",
|
||||
"libraries"."deletedAt" AS "libraries_deletedAt",
|
||||
"libraries"."refreshedAt" AS "libraries_refreshedAt",
|
||||
COUNT("assets"."id") FILTER (
|
||||
WHERE
|
||||
"assets"."type" = 'IMAGE'
|
||||
AND "assets"."isVisible"
|
||||
) AS "photos",
|
||||
COUNT("assets"."id") FILTER (
|
||||
WHERE
|
||||
"assets"."type" = 'VIDEO'
|
||||
AND "assets"."isVisible"
|
||||
) AS "videos",
|
||||
COALESCE(SUM("exif"."fileSizeInByte"), 0) AS "usage"
|
||||
FROM
|
||||
"libraries" "libraries"
|
||||
LEFT JOIN "assets" "assets" ON "assets"."libraryId" = "libraries"."id"
|
||||
AND ("assets"."deletedAt" IS NULL)
|
||||
LEFT JOIN "exif" "exif" ON "exif"."assetId" = "assets"."id"
|
||||
WHERE
|
||||
("libraries"."id" = $1)
|
||||
AND ("libraries"."deletedAt" IS NULL)
|
||||
GROUP BY
|
||||
select
|
||||
count("assets"."id") filter (
|
||||
where
|
||||
(
|
||||
"assets"."type" = $1
|
||||
and "assets"."isVisible" = $2
|
||||
)
|
||||
) as "photos",
|
||||
count(*) filter (
|
||||
where
|
||||
(
|
||||
"assets"."type" = $3
|
||||
and "assets"."isVisible" = $4
|
||||
)
|
||||
) as "videos",
|
||||
coalesce(sum("exif"."fileSizeInByte"), $5) as "usage"
|
||||
from
|
||||
"libraries"
|
||||
inner join "assets" on "assets"."libraryId" = "libraries"."id"
|
||||
inner join "exif" on "exif"."assetId" = "assets"."id"
|
||||
where
|
||||
"libraries"."id" = $6
|
||||
group by
|
||||
"libraries"."id"
|
||||
|
|
|
@ -1,84 +1,122 @@
|
|||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { ExpressionBuilder, Insertable, Kysely, Updateable } from 'kysely';
|
||||
import { jsonObjectFrom } from 'kysely/helpers/postgres';
|
||||
import { InjectKysely } from 'nestjs-kysely';
|
||||
import { DB, Libraries } from 'src/db';
|
||||
import { DummyValue, GenerateSql } from 'src/decorators';
|
||||
import { LibraryStatsResponseDto } from 'src/dtos/library.dto';
|
||||
import { LibraryEntity } from 'src/entities/library.entity';
|
||||
import { AssetType } from 'src/enum';
|
||||
import { ILibraryRepository } from 'src/interfaces/library.interface';
|
||||
import { IsNull, Not } from 'typeorm';
|
||||
import { Repository } from 'typeorm/repository/Repository.js';
|
||||
|
||||
const userColumns = [
|
||||
'users.id',
|
||||
'users.email',
|
||||
'users.createdAt',
|
||||
'users.profileImagePath',
|
||||
'users.isAdmin',
|
||||
'users.shouldChangePassword',
|
||||
'users.deletedAt',
|
||||
'users.oauthId',
|
||||
'users.updatedAt',
|
||||
'users.storageLabel',
|
||||
'users.name',
|
||||
'users.quotaSizeInBytes',
|
||||
'users.quotaUsageInBytes',
|
||||
'users.status',
|
||||
'users.profileChangedAt',
|
||||
] as const;
|
||||
|
||||
const withOwner = (eb: ExpressionBuilder<DB, 'libraries'>) => {
|
||||
return jsonObjectFrom(eb.selectFrom('users').whereRef('users.id', '=', 'libraries.ownerId').select(userColumns)).as(
|
||||
'owner',
|
||||
);
|
||||
};
|
||||
|
||||
@Injectable()
|
||||
export class LibraryRepository implements ILibraryRepository {
|
||||
constructor(@InjectRepository(LibraryEntity) private repository: Repository<LibraryEntity>) {}
|
||||
constructor(@InjectKysely() private db: Kysely<DB>) {}
|
||||
|
||||
@GenerateSql({ params: [DummyValue.UUID] })
|
||||
get(id: string, withDeleted = false): Promise<LibraryEntity | null> {
|
||||
return this.repository.findOneOrFail({
|
||||
where: {
|
||||
id,
|
||||
},
|
||||
relations: { owner: true },
|
||||
withDeleted,
|
||||
});
|
||||
get(id: string, withDeleted = false): Promise<LibraryEntity | undefined> {
|
||||
return this.db
|
||||
.selectFrom('libraries')
|
||||
.selectAll('libraries')
|
||||
.select(withOwner)
|
||||
.where('libraries.id', '=', id)
|
||||
.$if(!withDeleted, (qb) => qb.where('libraries.deletedAt', 'is', null))
|
||||
.executeTakeFirst() as Promise<LibraryEntity | undefined>;
|
||||
}
|
||||
|
||||
@GenerateSql({ params: [] })
|
||||
getAll(withDeleted = false): Promise<LibraryEntity[]> {
|
||||
return this.repository.find({
|
||||
relations: {
|
||||
owner: true,
|
||||
},
|
||||
order: {
|
||||
createdAt: 'ASC',
|
||||
},
|
||||
withDeleted,
|
||||
});
|
||||
return this.db
|
||||
.selectFrom('libraries')
|
||||
.selectAll('libraries')
|
||||
.select(withOwner)
|
||||
.orderBy('createdAt', 'asc')
|
||||
.$if(!withDeleted, (qb) => qb.where('libraries.deletedAt', 'is', null))
|
||||
.execute() as unknown as Promise<LibraryEntity[]>;
|
||||
}
|
||||
|
||||
@GenerateSql()
|
||||
getAllDeleted(): Promise<LibraryEntity[]> {
|
||||
return this.repository.find({
|
||||
where: {
|
||||
deletedAt: Not(IsNull()),
|
||||
},
|
||||
relations: {
|
||||
owner: true,
|
||||
},
|
||||
order: {
|
||||
createdAt: 'ASC',
|
||||
},
|
||||
withDeleted: true,
|
||||
});
|
||||
return this.db
|
||||
.selectFrom('libraries')
|
||||
.selectAll('libraries')
|
||||
.select(withOwner)
|
||||
.where('libraries.deletedAt', 'is not', null)
|
||||
.orderBy('createdAt', 'asc')
|
||||
.execute() as unknown as Promise<LibraryEntity[]>;
|
||||
}
|
||||
|
||||
create(library: Omit<LibraryEntity, 'id' | 'createdAt' | 'updatedAt' | 'ownerId'>): Promise<LibraryEntity> {
|
||||
return this.repository.save(library);
|
||||
create(library: Insertable<Libraries>): Promise<LibraryEntity> {
|
||||
return this.db
|
||||
.insertInto('libraries')
|
||||
.values(library)
|
||||
.returningAll()
|
||||
.executeTakeFirstOrThrow() as Promise<LibraryEntity>;
|
||||
}
|
||||
|
||||
async delete(id: string): Promise<void> {
|
||||
await this.repository.delete({ id });
|
||||
await this.db.deleteFrom('libraries').where('libraries.id', '=', id).execute();
|
||||
}
|
||||
|
||||
async softDelete(id: string): Promise<void> {
|
||||
await this.repository.softDelete({ id });
|
||||
await this.db.updateTable('libraries').set({ deletedAt: new Date() }).where('libraries.id', '=', id).execute();
|
||||
}
|
||||
|
||||
async update(library: Partial<LibraryEntity>): Promise<LibraryEntity> {
|
||||
return this.save(library);
|
||||
update(id: string, library: Updateable<Libraries>): Promise<LibraryEntity> {
|
||||
return this.db
|
||||
.updateTable('libraries')
|
||||
.set(library)
|
||||
.where('libraries.id', '=', id)
|
||||
.returningAll()
|
||||
.executeTakeFirstOrThrow() as Promise<LibraryEntity>;
|
||||
}
|
||||
|
||||
@GenerateSql({ params: [DummyValue.UUID] })
|
||||
async getStatistics(id: string): Promise<LibraryStatsResponseDto | undefined> {
|
||||
const stats = await this.repository
|
||||
.createQueryBuilder('libraries')
|
||||
.addSelect(`COUNT(assets.id) FILTER (WHERE assets.type = 'IMAGE' AND assets.isVisible)`, 'photos')
|
||||
.addSelect(`COUNT(assets.id) FILTER (WHERE assets.type = 'VIDEO' AND assets.isVisible)`, 'videos')
|
||||
.addSelect('COALESCE(SUM(exif.fileSizeInByte), 0)', 'usage')
|
||||
.leftJoin('libraries.assets', 'assets')
|
||||
.leftJoin('assets.exifInfo', 'exif')
|
||||
const stats = await this.db
|
||||
.selectFrom('libraries')
|
||||
.innerJoin('assets', 'assets.libraryId', 'libraries.id')
|
||||
.innerJoin('exif', 'exif.assetId', 'assets.id')
|
||||
.select((eb) =>
|
||||
eb.fn
|
||||
.count('assets.id')
|
||||
.filterWhere((eb) => eb.and([eb('assets.type', '=', AssetType.IMAGE), eb('assets.isVisible', '=', true)]))
|
||||
.as('photos'),
|
||||
)
|
||||
.select((eb) =>
|
||||
eb.fn
|
||||
.countAll()
|
||||
.filterWhere((eb) => eb.and([eb('assets.type', '=', AssetType.VIDEO), eb('assets.isVisible', '=', true)]))
|
||||
.as('videos'),
|
||||
)
|
||||
.select((eb) => eb.fn.coalesce((eb) => eb.fn.sum('exif.fileSizeInByte'), eb.val(0)).as('usage'))
|
||||
.groupBy('libraries.id')
|
||||
.where('libraries.id = :id', { id })
|
||||
.getRawOne();
|
||||
.where('libraries.id', '=', id)
|
||||
.executeTakeFirst();
|
||||
|
||||
if (!stats) {
|
||||
return;
|
||||
|
@ -91,9 +129,4 @@ export class LibraryRepository implements ILibraryRepository {
|
|||
total: Number(stats.photos) + Number(stats.videos),
|
||||
};
|
||||
}
|
||||
|
||||
private async save(library: Partial<LibraryEntity>) {
|
||||
const { id } = await this.repository.save(library);
|
||||
return this.repository.findOneByOrFail({ id });
|
||||
}
|
||||
}
|
||||
|
|
|
@ -87,7 +87,7 @@ describe(LibraryService.name, () => {
|
|||
Promise.resolve(
|
||||
[libraryStub.externalLibraryWithImportPaths1, libraryStub.externalLibraryWithImportPaths2].find(
|
||||
(library) => library.id === id,
|
||||
) || null,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
|
@ -190,8 +190,6 @@ describe(LibraryService.name, () => {
|
|||
});
|
||||
|
||||
it("should fail when library can't be found", async () => {
|
||||
libraryMock.get.mockResolvedValue(null);
|
||||
|
||||
await expect(sut.handleQueueSyncFiles({ id: libraryStub.externalLibrary1.id })).resolves.toBe(JobStatus.SKIPPED);
|
||||
});
|
||||
|
||||
|
@ -242,8 +240,6 @@ describe(LibraryService.name, () => {
|
|||
});
|
||||
|
||||
it("should fail when library can't be found", async () => {
|
||||
libraryMock.get.mockResolvedValue(null);
|
||||
|
||||
await expect(sut.handleQueueSyncAssets({ id: libraryStub.externalLibrary1.id })).resolves.toBe(JobStatus.SKIPPED);
|
||||
});
|
||||
});
|
||||
|
@ -630,7 +626,6 @@ describe(LibraryService.name, () => {
|
|||
});
|
||||
|
||||
it('should throw an error when a library is not found', async () => {
|
||||
libraryMock.get.mockResolvedValue(null);
|
||||
await expect(sut.get(libraryStub.externalLibrary1.id)).rejects.toBeInstanceOf(BadRequestException);
|
||||
expect(libraryMock.get).toHaveBeenCalledWith(libraryStub.externalLibrary1.id);
|
||||
});
|
||||
|
@ -825,7 +820,10 @@ describe(LibraryService.name, () => {
|
|||
await expect(sut.update('library-id', { importPaths: [`${cwd}/foo/bar`] })).resolves.toEqual(
|
||||
mapLibrary(libraryStub.externalLibrary1),
|
||||
);
|
||||
expect(libraryMock.update).toHaveBeenCalledWith(expect.objectContaining({ id: 'library-id' }));
|
||||
expect(libraryMock.update).toHaveBeenCalledWith(
|
||||
'library-id',
|
||||
expect.objectContaining({ importPaths: [`${cwd}/foo/bar`] }),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -1015,7 +1013,7 @@ describe(LibraryService.name, () => {
|
|||
Promise.resolve(
|
||||
[libraryStub.externalLibraryWithImportPaths1, libraryStub.externalLibraryWithImportPaths2].find(
|
||||
(library) => library.id === id,
|
||||
) || null,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
|
|
|
@ -311,7 +311,7 @@ export class LibraryService extends BaseService {
|
|||
}
|
||||
}
|
||||
|
||||
const library = await this.libraryRepository.update({ id, ...dto });
|
||||
const library = await this.libraryRepository.update(id, dto);
|
||||
return mapLibrary(library);
|
||||
}
|
||||
|
||||
|
@ -571,7 +571,7 @@ export class LibraryService extends BaseService {
|
|||
this.logger.debug(`No non-excluded assets found in any import path for library ${library.id}`);
|
||||
}
|
||||
|
||||
await this.libraryRepository.update({ id: job.id, refreshedAt: new Date() });
|
||||
await this.libraryRepository.update(job.id, { refreshedAt: new Date() });
|
||||
|
||||
return JobStatus.SUCCESS;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue