mirror of
https://github.com/immich-app/immich
synced 2025-06-08 06:00:59 +00:00
refactor: database types (#17468)
This commit is contained in:
parent
ac65d46ec6
commit
4794eeca88
@ -1,5 +1,6 @@
|
|||||||
import { UserMetadataEntity } from 'src/entities/user-metadata.entity';
|
import { UserMetadataEntity } from 'src/entities/user-metadata.entity';
|
||||||
import { AssetStatus, AssetType, Permission, UserStatus } from 'src/enum';
|
import { AssetStatus, AssetType, MemoryType, Permission, UserStatus } from 'src/enum';
|
||||||
|
import { OnThisDayData } from 'src/types';
|
||||||
|
|
||||||
export type AuthUser = {
|
export type AuthUser = {
|
||||||
id: string;
|
id: string;
|
||||||
@ -38,6 +39,31 @@ export type ApiKey = {
|
|||||||
permissions: Permission[];
|
permissions: Permission[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type Tag = {
|
||||||
|
id: string;
|
||||||
|
value: string;
|
||||||
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
|
color: string | null;
|
||||||
|
parentId: string | null;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Memory = {
|
||||||
|
id: string;
|
||||||
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
|
deletedAt: Date | null;
|
||||||
|
memoryAt: Date;
|
||||||
|
seenAt: Date | null;
|
||||||
|
showAt: Date | null;
|
||||||
|
hideAt: Date | null;
|
||||||
|
type: MemoryType;
|
||||||
|
data: OnThisDayData;
|
||||||
|
ownerId: string;
|
||||||
|
isSaved: boolean;
|
||||||
|
assets: Asset[];
|
||||||
|
};
|
||||||
|
|
||||||
export type User = {
|
export type User = {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import { ApiProperty } from '@nestjs/swagger';
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
import { Type } from 'class-transformer';
|
import { Type } from 'class-transformer';
|
||||||
import { IsEnum, IsInt, IsObject, IsPositive, ValidateNested } from 'class-validator';
|
import { IsEnum, IsInt, IsObject, IsPositive, ValidateNested } from 'class-validator';
|
||||||
|
import { Memory } from 'src/database';
|
||||||
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 { AssetEntity } from 'src/entities/asset.entity';
|
||||||
import { MemoryType } from 'src/enum';
|
import { MemoryType } from 'src/enum';
|
||||||
import { MemoryItem } from 'src/types';
|
|
||||||
import { Optional, ValidateBoolean, ValidateDate, ValidateUUID } from 'src/validation';
|
import { Optional, ValidateBoolean, ValidateDate, ValidateUUID } from 'src/validation';
|
||||||
|
|
||||||
class MemoryBaseDto {
|
class MemoryBaseDto {
|
||||||
@ -89,7 +89,7 @@ export class MemoryResponseDto {
|
|||||||
assets!: AssetResponseDto[];
|
assets!: AssetResponseDto[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export const mapMemory = (entity: MemoryItem, auth: AuthDto): MemoryResponseDto => {
|
export const mapMemory = (entity: Memory, auth: AuthDto): MemoryResponseDto => {
|
||||||
return {
|
return {
|
||||||
id: entity.id,
|
id: entity.id,
|
||||||
createdAt: entity.createdAt,
|
createdAt: entity.createdAt,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { ApiProperty } from '@nestjs/swagger';
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
import { IsHexColor, IsNotEmpty, IsString } from 'class-validator';
|
import { IsHexColor, IsNotEmpty, IsString } from 'class-validator';
|
||||||
import { TagItem } from 'src/types';
|
import { Tag } from 'src/database';
|
||||||
import { Optional, ValidateHexColor, ValidateUUID } from 'src/validation';
|
import { Optional, ValidateHexColor, ValidateUUID } from 'src/validation';
|
||||||
|
|
||||||
export class TagCreateDto {
|
export class TagCreateDto {
|
||||||
@ -51,7 +51,7 @@ export class TagResponseDto {
|
|||||||
color?: string;
|
color?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function mapTag(entity: TagItem): TagResponseDto {
|
export function mapTag(entity: Tag): TagResponseDto {
|
||||||
return {
|
return {
|
||||||
id: entity.id,
|
id: entity.id,
|
||||||
parentId: entity.parentId ?? undefined,
|
parentId: entity.parentId ?? undefined,
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { DeduplicateJoinsPlugin, ExpressionBuilder, Kysely, SelectQueryBuilder, sql } from 'kysely';
|
import { DeduplicateJoinsPlugin, ExpressionBuilder, Kysely, SelectQueryBuilder, sql } from 'kysely';
|
||||||
import { jsonArrayFrom, jsonObjectFrom } from 'kysely/helpers/postgres';
|
import { jsonArrayFrom, jsonObjectFrom } from 'kysely/helpers/postgres';
|
||||||
|
import { Tag } from 'src/database';
|
||||||
import { DB } from 'src/db';
|
import { DB } from 'src/db';
|
||||||
import { AlbumEntity } from 'src/entities/album.entity';
|
import { AlbumEntity } from 'src/entities/album.entity';
|
||||||
import { AssetFaceEntity } from 'src/entities/asset-face.entity';
|
import { AssetFaceEntity } from 'src/entities/asset-face.entity';
|
||||||
@ -12,7 +13,6 @@ import { UserEntity } from 'src/entities/user.entity';
|
|||||||
import { AssetFileType, AssetStatus, AssetType } from 'src/enum';
|
import { AssetFileType, AssetStatus, AssetType } from 'src/enum';
|
||||||
import { TimeBucketSize } from 'src/repositories/asset.repository';
|
import { TimeBucketSize } from 'src/repositories/asset.repository';
|
||||||
import { AssetSearchBuilderOptions } from 'src/repositories/search.repository';
|
import { AssetSearchBuilderOptions } from 'src/repositories/search.repository';
|
||||||
import { TagItem } from 'src/types';
|
|
||||||
import { anyUuid, asUuid } from 'src/utils/database';
|
import { anyUuid, asUuid } from 'src/utils/database';
|
||||||
|
|
||||||
export const ASSET_CHECKSUM_CONSTRAINT = 'UQ_assets_owner_checksum';
|
export const ASSET_CHECKSUM_CONSTRAINT = 'UQ_assets_owner_checksum';
|
||||||
@ -49,7 +49,7 @@ export class AssetEntity {
|
|||||||
originalFileName!: string;
|
originalFileName!: string;
|
||||||
sidecarPath!: string | null;
|
sidecarPath!: string | null;
|
||||||
exifInfo?: ExifEntity;
|
exifInfo?: ExifEntity;
|
||||||
tags?: TagItem[];
|
tags?: Tag[];
|
||||||
sharedLinks!: SharedLinkEntity[];
|
sharedLinks!: SharedLinkEntity[];
|
||||||
albums?: AlbumEntity[];
|
albums?: AlbumEntity[];
|
||||||
faces!: AssetFaceEntity[];
|
faces!: AssetFaceEntity[];
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import { BadRequestException, Injectable } from '@nestjs/common';
|
import { BadRequestException, Injectable } from '@nestjs/common';
|
||||||
|
import { ApiKey } from 'src/database';
|
||||||
import { APIKeyCreateDto, APIKeyCreateResponseDto, APIKeyResponseDto, APIKeyUpdateDto } from 'src/dtos/api-key.dto';
|
import { APIKeyCreateDto, APIKeyCreateResponseDto, APIKeyResponseDto, APIKeyUpdateDto } from 'src/dtos/api-key.dto';
|
||||||
import { AuthDto } from 'src/dtos/auth.dto';
|
import { AuthDto } from 'src/dtos/auth.dto';
|
||||||
import { Permission } from 'src/enum';
|
import { Permission } from 'src/enum';
|
||||||
import { BaseService } from 'src/services/base.service';
|
import { BaseService } from 'src/services/base.service';
|
||||||
import { ApiKeyItem } from 'src/types';
|
|
||||||
import { isGranted } from 'src/utils/access';
|
import { isGranted } from 'src/utils/access';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
@ -58,7 +58,7 @@ export class ApiKeyService extends BaseService {
|
|||||||
return keys.map((key) => this.map(key));
|
return keys.map((key) => this.map(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
private map(entity: ApiKeyItem): APIKeyResponseDto {
|
private map(entity: ApiKey): APIKeyResponseDto {
|
||||||
return {
|
return {
|
||||||
id: entity.id,
|
id: entity.id,
|
||||||
name: entity.name,
|
name: entity.name,
|
||||||
|
@ -14,8 +14,6 @@ import {
|
|||||||
VideoCodec,
|
VideoCodec,
|
||||||
} from 'src/enum';
|
} from 'src/enum';
|
||||||
import { ActivityRepository } from 'src/repositories/activity.repository';
|
import { ActivityRepository } from 'src/repositories/activity.repository';
|
||||||
import { ApiKeyRepository } from 'src/repositories/api-key.repository';
|
|
||||||
import { MemoryRepository } from 'src/repositories/memory.repository';
|
|
||||||
import { SearchRepository } from 'src/repositories/search.repository';
|
import { SearchRepository } from 'src/repositories/search.repository';
|
||||||
import { SessionRepository } from 'src/repositories/session.repository';
|
import { SessionRepository } from 'src/repositories/session.repository';
|
||||||
|
|
||||||
@ -24,8 +22,6 @@ export type DeepPartial<T> = T extends object ? { [K in keyof T]?: DeepPartial<T
|
|||||||
export type RepositoryInterface<T extends object> = Pick<T, keyof T>;
|
export type RepositoryInterface<T extends object> = Pick<T, keyof T>;
|
||||||
|
|
||||||
type IActivityRepository = RepositoryInterface<ActivityRepository>;
|
type IActivityRepository = RepositoryInterface<ActivityRepository>;
|
||||||
type IApiKeyRepository = RepositoryInterface<ApiKeyRepository>;
|
|
||||||
type IMemoryRepository = RepositoryInterface<MemoryRepository>;
|
|
||||||
type ISearchRepository = RepositoryInterface<SearchRepository>;
|
type ISearchRepository = RepositoryInterface<SearchRepository>;
|
||||||
type ISessionRepository = RepositoryInterface<SessionRepository>;
|
type ISessionRepository = RepositoryInterface<SessionRepository>;
|
||||||
|
|
||||||
@ -35,26 +31,8 @@ export type ActivityItem =
|
|||||||
|
|
||||||
export type SearchPlacesItem = Awaited<ReturnType<ISearchRepository['searchPlaces']>>[0];
|
export type SearchPlacesItem = Awaited<ReturnType<ISearchRepository['searchPlaces']>>[0];
|
||||||
|
|
||||||
export type ApiKeyItem =
|
|
||||||
| Awaited<ReturnType<IApiKeyRepository['create']>>
|
|
||||||
| NonNullable<Awaited<ReturnType<IApiKeyRepository['getById']>>>
|
|
||||||
| Awaited<ReturnType<IApiKeyRepository['getByUserId']>>[0];
|
|
||||||
|
|
||||||
export type MemoryItem =
|
|
||||||
| Awaited<ReturnType<IMemoryRepository['create']>>
|
|
||||||
| Awaited<ReturnType<IMemoryRepository['search']>>[0];
|
|
||||||
|
|
||||||
export type SessionItem = Awaited<ReturnType<ISessionRepository['getByUserId']>>[0];
|
export type SessionItem = Awaited<ReturnType<ISessionRepository['getByUserId']>>[0];
|
||||||
|
|
||||||
export type TagItem = {
|
|
||||||
id: string;
|
|
||||||
value: string;
|
|
||||||
createdAt: Date;
|
|
||||||
updatedAt: Date;
|
|
||||||
color: string | null;
|
|
||||||
parentId: string | null;
|
|
||||||
};
|
|
||||||
|
|
||||||
export interface CropOptions {
|
export interface CropOptions {
|
||||||
top: number;
|
top: number;
|
||||||
left: number;
|
left: number;
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
|
import { Tag } from 'src/database';
|
||||||
import { TagRepository } from 'src/repositories/tag.repository';
|
import { TagRepository } from 'src/repositories/tag.repository';
|
||||||
import { TagItem } from 'src/types';
|
|
||||||
|
|
||||||
type UpsertRequest = { userId: string; tags: string[] };
|
type UpsertRequest = { userId: string; tags: string[] };
|
||||||
export const upsertTags = async (repository: TagRepository, { userId, tags }: UpsertRequest) => {
|
export const upsertTags = async (repository: TagRepository, { userId, tags }: UpsertRequest) => {
|
||||||
tags = [...new Set(tags)];
|
tags = [...new Set(tags)];
|
||||||
|
|
||||||
const results: TagItem[] = [];
|
const results: Tag[] = [];
|
||||||
|
|
||||||
for (const tag of tags) {
|
for (const tag of tags) {
|
||||||
const parts = tag.split('/').filter(Boolean);
|
const parts = tag.split('/').filter(Boolean);
|
||||||
let parent: TagItem | undefined;
|
let parent: Tag | undefined;
|
||||||
|
|
||||||
for (const part of parts) {
|
for (const part of parts) {
|
||||||
const value = parent ? `${parent.value}/${part}` : part;
|
const value = parent ? `${parent.value}/${part}` : part;
|
||||||
|
6
server/test/fixtures/tag.stub.ts
vendored
6
server/test/fixtures/tag.stub.ts
vendored
@ -1,7 +1,7 @@
|
|||||||
|
import { Tag } from 'src/database';
|
||||||
import { TagResponseDto } from 'src/dtos/tag.dto';
|
import { TagResponseDto } from 'src/dtos/tag.dto';
|
||||||
import { TagItem } from 'src/types';
|
|
||||||
|
|
||||||
const parent = Object.freeze<TagItem>({
|
const parent = Object.freeze<Tag>({
|
||||||
id: 'tag-parent',
|
id: 'tag-parent',
|
||||||
createdAt: new Date('2021-01-01T00:00:00Z'),
|
createdAt: new Date('2021-01-01T00:00:00Z'),
|
||||||
updatedAt: new Date('2021-01-01T00:00:00Z'),
|
updatedAt: new Date('2021-01-01T00:00:00Z'),
|
||||||
@ -10,7 +10,7 @@ const parent = Object.freeze<TagItem>({
|
|||||||
parentId: null,
|
parentId: null,
|
||||||
});
|
});
|
||||||
|
|
||||||
const child = Object.freeze<TagItem>({
|
const child = Object.freeze<Tag>({
|
||||||
id: 'tag-child',
|
id: 'tag-child',
|
||||||
createdAt: new Date('2021-01-01T00:00:00Z'),
|
createdAt: new Date('2021-01-01T00:00:00Z'),
|
||||||
updatedAt: new Date('2021-01-01T00:00:00Z'),
|
updatedAt: new Date('2021-01-01T00:00:00Z'),
|
||||||
|
@ -5,6 +5,7 @@ import {
|
|||||||
AuthApiKey,
|
AuthApiKey,
|
||||||
AuthUser,
|
AuthUser,
|
||||||
Library,
|
Library,
|
||||||
|
Memory,
|
||||||
Partner,
|
Partner,
|
||||||
SidecarWriteAsset,
|
SidecarWriteAsset,
|
||||||
User,
|
User,
|
||||||
@ -12,7 +13,7 @@ import {
|
|||||||
} from 'src/database';
|
} from 'src/database';
|
||||||
import { AuthDto } from 'src/dtos/auth.dto';
|
import { AuthDto } from 'src/dtos/auth.dto';
|
||||||
import { AssetStatus, AssetType, MemoryType, Permission, UserStatus } from 'src/enum';
|
import { AssetStatus, AssetType, MemoryType, Permission, UserStatus } from 'src/enum';
|
||||||
import { ActivityItem, MemoryItem, OnThisDayData } from 'src/types';
|
import { ActivityItem, OnThisDayData } from 'src/types';
|
||||||
|
|
||||||
export const newUuid = () => randomUUID() as string;
|
export const newUuid = () => randomUUID() as string;
|
||||||
export const newUuids = () =>
|
export const newUuids = () =>
|
||||||
@ -196,7 +197,7 @@ const libraryFactory = (library: Partial<Library> = {}) => ({
|
|||||||
...library,
|
...library,
|
||||||
});
|
});
|
||||||
|
|
||||||
const memoryFactory = (memory: Partial<MemoryItem> = {}) => ({
|
const memoryFactory = (memory: Partial<Memory> = {}) => ({
|
||||||
id: newUuid(),
|
id: newUuid(),
|
||||||
createdAt: newDate(),
|
createdAt: newDate(),
|
||||||
updatedAt: newDate(),
|
updatedAt: newDate(),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user