mirror of
https://github.com/immich-app/immich.git
synced 2025-06-03 05:34:32 -04:00
refactor: view repository (#15496)
This commit is contained in:
parent
5171630b98
commit
ccf6d71c3c
@ -1,8 +0,0 @@
|
|||||||
import { AssetEntity } from 'src/entities/asset.entity';
|
|
||||||
|
|
||||||
export const IViewRepository = 'IViewRepository';
|
|
||||||
|
|
||||||
export interface IViewRepository {
|
|
||||||
getAssetsByOriginalPath(userId: string, partialPath: string): Promise<AssetEntity[]>;
|
|
||||||
getUniqueOriginalPaths(userId: string): Promise<string[]>;
|
|
||||||
}
|
|
@ -31,7 +31,6 @@ import { ITelemetryRepository } from 'src/interfaces/telemetry.interface';
|
|||||||
import { ITrashRepository } from 'src/interfaces/trash.interface';
|
import { ITrashRepository } from 'src/interfaces/trash.interface';
|
||||||
import { IUserRepository } from 'src/interfaces/user.interface';
|
import { IUserRepository } from 'src/interfaces/user.interface';
|
||||||
import { IVersionHistoryRepository } from 'src/interfaces/version-history.interface';
|
import { IVersionHistoryRepository } from 'src/interfaces/version-history.interface';
|
||||||
import { IViewRepository } from 'src/interfaces/view.interface';
|
|
||||||
import { AccessRepository } from 'src/repositories/access.repository';
|
import { AccessRepository } from 'src/repositories/access.repository';
|
||||||
import { ActivityRepository } from 'src/repositories/activity.repository';
|
import { ActivityRepository } from 'src/repositories/activity.repository';
|
||||||
import { AlbumUserRepository } from 'src/repositories/album-user.repository';
|
import { AlbumUserRepository } from 'src/repositories/album-user.repository';
|
||||||
@ -79,6 +78,7 @@ export const repositories = [
|
|||||||
AuditRepository,
|
AuditRepository,
|
||||||
ApiKeyRepository,
|
ApiKeyRepository,
|
||||||
ConfigRepository,
|
ConfigRepository,
|
||||||
|
ViewRepository,
|
||||||
];
|
];
|
||||||
|
|
||||||
export const providers = [
|
export const providers = [
|
||||||
@ -115,5 +115,4 @@ export const providers = [
|
|||||||
{ provide: ITrashRepository, useClass: TrashRepository },
|
{ provide: ITrashRepository, useClass: TrashRepository },
|
||||||
{ provide: IUserRepository, useClass: UserRepository },
|
{ provide: IUserRepository, useClass: UserRepository },
|
||||||
{ provide: IVersionHistoryRepository, useClass: VersionHistoryRepository },
|
{ provide: IVersionHistoryRepository, useClass: VersionHistoryRepository },
|
||||||
{ provide: IViewRepository, useClass: ViewRepository },
|
|
||||||
];
|
];
|
||||||
|
@ -2,15 +2,14 @@ import { Kysely } from 'kysely';
|
|||||||
import { InjectKysely } from 'nestjs-kysely';
|
import { InjectKysely } from 'nestjs-kysely';
|
||||||
import { DB } from 'src/db';
|
import { DB } from 'src/db';
|
||||||
import { DummyValue, GenerateSql } from 'src/decorators';
|
import { DummyValue, GenerateSql } from 'src/decorators';
|
||||||
import { AssetEntity, withExif } from 'src/entities/asset.entity';
|
import { withExif } from 'src/entities/asset.entity';
|
||||||
import { IViewRepository } from 'src/interfaces/view.interface';
|
|
||||||
import { asUuid } from 'src/utils/database';
|
import { asUuid } from 'src/utils/database';
|
||||||
|
|
||||||
export class ViewRepository implements IViewRepository {
|
export class ViewRepository {
|
||||||
constructor(@InjectKysely() private db: Kysely<DB>) {}
|
constructor(@InjectKysely() private db: Kysely<DB>) {}
|
||||||
|
|
||||||
@GenerateSql({ params: [DummyValue.UUID] })
|
@GenerateSql({ params: [DummyValue.UUID] })
|
||||||
async getUniqueOriginalPaths(userId: string): Promise<string[]> {
|
async getUniqueOriginalPaths(userId: string) {
|
||||||
const results = await this.db
|
const results = await this.db
|
||||||
.selectFrom('assets')
|
.selectFrom('assets')
|
||||||
.select((eb) => eb.fn<string>('substring', ['assets.originalPath', eb.val('^(.*/)[^/]*$')]).as('directoryPath'))
|
.select((eb) => eb.fn<string>('substring', ['assets.originalPath', eb.val('^(.*/)[^/]*$')]).as('directoryPath'))
|
||||||
@ -25,7 +24,7 @@ export class ViewRepository implements IViewRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@GenerateSql({ params: [DummyValue.UUID, DummyValue.STRING] })
|
@GenerateSql({ params: [DummyValue.UUID, DummyValue.STRING] })
|
||||||
async getAssetsByOriginalPath(userId: string, partialPath: string): Promise<AssetEntity[]> {
|
async getAssetsByOriginalPath(userId: string, partialPath: string) {
|
||||||
const normalizedPath = partialPath.replaceAll(/^\/|\/$/g, '');
|
const normalizedPath = partialPath.replaceAll(/^\/|\/$/g, '');
|
||||||
|
|
||||||
return this.db
|
return this.db
|
||||||
@ -42,6 +41,6 @@ export class ViewRepository implements IViewRepository {
|
|||||||
(eb) => eb.fn('regexp_replace', ['assets.originalPath', eb.val('.*/(.+)'), eb.val(String.raw`\1`)]),
|
(eb) => eb.fn('regexp_replace', ['assets.originalPath', eb.val('.*/(.+)'), eb.val(String.raw`\1`)]),
|
||||||
'asc',
|
'asc',
|
||||||
)
|
)
|
||||||
.execute() as any as Promise<AssetEntity[]>;
|
.execute();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,12 +39,12 @@ import { ITelemetryRepository } from 'src/interfaces/telemetry.interface';
|
|||||||
import { ITrashRepository } from 'src/interfaces/trash.interface';
|
import { ITrashRepository } from 'src/interfaces/trash.interface';
|
||||||
import { IUserRepository } from 'src/interfaces/user.interface';
|
import { IUserRepository } from 'src/interfaces/user.interface';
|
||||||
import { IVersionHistoryRepository } from 'src/interfaces/version-history.interface';
|
import { IVersionHistoryRepository } from 'src/interfaces/version-history.interface';
|
||||||
import { IViewRepository } from 'src/interfaces/view.interface';
|
|
||||||
import { AccessRepository } from 'src/repositories/access.repository';
|
import { AccessRepository } from 'src/repositories/access.repository';
|
||||||
import { ActivityRepository } from 'src/repositories/activity.repository';
|
import { ActivityRepository } from 'src/repositories/activity.repository';
|
||||||
import { ApiKeyRepository } from 'src/repositories/api-key.repository';
|
import { ApiKeyRepository } from 'src/repositories/api-key.repository';
|
||||||
import { AuditRepository } from 'src/repositories/audit.repository';
|
import { AuditRepository } from 'src/repositories/audit.repository';
|
||||||
import { ConfigRepository } from 'src/repositories/config.repository';
|
import { ConfigRepository } from 'src/repositories/config.repository';
|
||||||
|
import { ViewRepository } from 'src/repositories/view-repository';
|
||||||
import { AccessRequest, checkAccess, requireAccess } from 'src/utils/access';
|
import { AccessRequest, checkAccess, requireAccess } from 'src/utils/access';
|
||||||
import { getConfig, updateConfig } from 'src/utils/config';
|
import { getConfig, updateConfig } from 'src/utils/config';
|
||||||
|
|
||||||
@ -90,7 +90,7 @@ export class BaseService {
|
|||||||
@Inject(ITrashRepository) protected trashRepository: ITrashRepository,
|
@Inject(ITrashRepository) protected trashRepository: ITrashRepository,
|
||||||
@Inject(IUserRepository) protected userRepository: IUserRepository,
|
@Inject(IUserRepository) protected userRepository: IUserRepository,
|
||||||
@Inject(IVersionHistoryRepository) protected versionRepository: IVersionHistoryRepository,
|
@Inject(IVersionHistoryRepository) protected versionRepository: IVersionHistoryRepository,
|
||||||
@Inject(IViewRepository) protected viewRepository: IViewRepository,
|
protected viewRepository: ViewRepository,
|
||||||
) {
|
) {
|
||||||
this.logger.setContext(this.constructor.name);
|
this.logger.setContext(this.constructor.name);
|
||||||
this.storageCore = StorageCore.create(
|
this.storageCore = StorageCore.create(
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { mapAsset } from 'src/dtos/asset-response.dto';
|
import { mapAsset } from 'src/dtos/asset-response.dto';
|
||||||
import { IViewRepository } from 'src/interfaces/view.interface';
|
|
||||||
import { ViewService } from 'src/services/view.service';
|
import { ViewService } from 'src/services/view.service';
|
||||||
|
import { IViewRepository } from 'src/types';
|
||||||
import { assetStub } from 'test/fixtures/asset.stub';
|
import { assetStub } from 'test/fixtures/asset.stub';
|
||||||
import { authStub } from 'test/fixtures/auth.stub';
|
import { authStub } from 'test/fixtures/auth.stub';
|
||||||
import { newTestService } from 'test/utils';
|
import { newTestService } from 'test/utils';
|
||||||
@ -42,7 +42,7 @@ describe(ViewService.name, () => {
|
|||||||
|
|
||||||
const mockAssetReponseDto = mockAssets.map((a) => mapAsset(a, { auth: authStub.admin }));
|
const mockAssetReponseDto = mockAssets.map((a) => mapAsset(a, { auth: authStub.admin }));
|
||||||
|
|
||||||
viewMock.getAssetsByOriginalPath.mockResolvedValue(mockAssets);
|
viewMock.getAssetsByOriginalPath.mockResolvedValue(mockAssets as any);
|
||||||
|
|
||||||
const result = await sut.getAssetsByOriginalPath(authStub.admin, path);
|
const result = await sut.getAssetsByOriginalPath(authStub.admin, path);
|
||||||
expect(result).toEqual(mockAssetReponseDto);
|
expect(result).toEqual(mockAssetReponseDto);
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { AssetResponseDto, mapAsset } from 'src/dtos/asset-response.dto';
|
import { AssetResponseDto, mapAsset } from 'src/dtos/asset-response.dto';
|
||||||
import { AuthDto } from 'src/dtos/auth.dto';
|
import { AuthDto } from 'src/dtos/auth.dto';
|
||||||
|
import { AssetEntity } from 'src/entities/asset.entity';
|
||||||
import { BaseService } from 'src/services/base.service';
|
import { BaseService } from 'src/services/base.service';
|
||||||
|
|
||||||
export class ViewService extends BaseService {
|
export class ViewService extends BaseService {
|
||||||
@ -9,6 +10,6 @@ export class ViewService extends BaseService {
|
|||||||
|
|
||||||
async getAssetsByOriginalPath(auth: AuthDto, path: string): Promise<AssetResponseDto[]> {
|
async getAssetsByOriginalPath(auth: AuthDto, path: string): Promise<AssetResponseDto[]> {
|
||||||
const assets = await this.viewRepository.getAssetsByOriginalPath(auth.user.id, path);
|
const assets = await this.viewRepository.getAssetsByOriginalPath(auth.user.id, path);
|
||||||
return assets.map((asset) => mapAsset(asset, { auth }));
|
return assets.map((asset) => mapAsset(asset as unknown as AssetEntity, { auth }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import { ActivityRepository } from 'src/repositories/activity.repository';
|
|||||||
import { ApiKeyRepository } from 'src/repositories/api-key.repository';
|
import { ApiKeyRepository } from 'src/repositories/api-key.repository';
|
||||||
import { AuditRepository } from 'src/repositories/audit.repository';
|
import { AuditRepository } from 'src/repositories/audit.repository';
|
||||||
import { ConfigRepository } from 'src/repositories/config.repository';
|
import { ConfigRepository } from 'src/repositories/config.repository';
|
||||||
|
import { ViewRepository } from 'src/repositories/view-repository';
|
||||||
|
|
||||||
export type AuthApiKey = {
|
export type AuthApiKey = {
|
||||||
id: string;
|
id: string;
|
||||||
@ -20,6 +21,7 @@ export type IAccessRepository = { [K in keyof AccessRepository]: RepositoryInter
|
|||||||
export type IApiKeyRepository = RepositoryInterface<ApiKeyRepository>;
|
export type IApiKeyRepository = RepositoryInterface<ApiKeyRepository>;
|
||||||
export type IAuditRepository = RepositoryInterface<AuditRepository>;
|
export type IAuditRepository = RepositoryInterface<AuditRepository>;
|
||||||
export type IConfigRepository = RepositoryInterface<ConfigRepository>;
|
export type IConfigRepository = RepositoryInterface<ConfigRepository>;
|
||||||
|
export type IViewRepository = RepositoryInterface<ViewRepository>;
|
||||||
|
|
||||||
export type ActivityItem =
|
export type ActivityItem =
|
||||||
| Awaited<ReturnType<IActivityRepository['create']>>
|
| Awaited<ReturnType<IActivityRepository['create']>>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { IViewRepository } from 'src/interfaces/view.interface';
|
import { IViewRepository } from 'src/types';
|
||||||
import { Mocked, vitest } from 'vitest';
|
import { Mocked, vitest } from 'vitest';
|
||||||
|
|
||||||
export const newViewRepositoryMock = (): Mocked<IViewRepository> => {
|
export const newViewRepositoryMock = (): Mocked<IViewRepository> => {
|
||||||
|
@ -7,8 +7,15 @@ import { AccessRepository } from 'src/repositories/access.repository';
|
|||||||
import { ActivityRepository } from 'src/repositories/activity.repository';
|
import { ActivityRepository } from 'src/repositories/activity.repository';
|
||||||
import { ApiKeyRepository } from 'src/repositories/api-key.repository';
|
import { ApiKeyRepository } from 'src/repositories/api-key.repository';
|
||||||
import { AuditRepository } from 'src/repositories/audit.repository';
|
import { AuditRepository } from 'src/repositories/audit.repository';
|
||||||
|
import { ViewRepository } from 'src/repositories/view-repository';
|
||||||
import { BaseService } from 'src/services/base.service';
|
import { BaseService } from 'src/services/base.service';
|
||||||
import { IAccessRepository, IActivityRepository, IApiKeyRepository, IAuditRepository } from 'src/types';
|
import {
|
||||||
|
IAccessRepository,
|
||||||
|
IActivityRepository,
|
||||||
|
IApiKeyRepository,
|
||||||
|
IAuditRepository,
|
||||||
|
IViewRepository,
|
||||||
|
} from 'src/types';
|
||||||
import { newAccessRepositoryMock } from 'test/repositories/access.repository.mock';
|
import { newAccessRepositoryMock } from 'test/repositories/access.repository.mock';
|
||||||
import { newActivityRepositoryMock } from 'test/repositories/activity.repository.mock';
|
import { newActivityRepositoryMock } from 'test/repositories/activity.repository.mock';
|
||||||
import { newAlbumUserRepositoryMock } from 'test/repositories/album-user.repository.mock';
|
import { newAlbumUserRepositoryMock } from 'test/repositories/album-user.repository.mock';
|
||||||
@ -145,7 +152,7 @@ export const newTestService = <T extends BaseService>(
|
|||||||
trashMock,
|
trashMock,
|
||||||
userMock,
|
userMock,
|
||||||
versionHistoryMock,
|
versionHistoryMock,
|
||||||
viewMock,
|
viewMock as IViewRepository as ViewRepository,
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user