mirror of
https://github.com/immich-app/immich.git
synced 2026-03-04 09:57:33 +03:00
refactor: repositories (#15561)
* refactor: version history repository * refactor: oauth repository * refactor: trash repository * refactor: telemetry repository * refactor: metadata repository * refactor: cron repository * refactor: map repository * refactor: server-info repository * refactor: album user repository * refactor: notification repository
This commit is contained in:
@@ -4,10 +4,14 @@ import { InjectKysely } from 'nestjs-kysely';
|
||||
import { AlbumsSharedUsersUsers, DB } from 'src/db';
|
||||
import { DummyValue, GenerateSql } from 'src/decorators';
|
||||
import { AlbumUserRole } from 'src/enum';
|
||||
import { AlbumPermissionId, IAlbumUserRepository } from 'src/interfaces/album-user.interface';
|
||||
|
||||
export type AlbumPermissionId = {
|
||||
albumsId: string;
|
||||
usersId: string;
|
||||
};
|
||||
|
||||
@Injectable()
|
||||
export class AlbumUserRepository implements IAlbumUserRepository {
|
||||
export class AlbumUserRepository {
|
||||
constructor(@InjectKysely() private db: Kysely<DB>) {}
|
||||
|
||||
@GenerateSql({ params: [{ usersId: DummyValue.UUID, albumsId: DummyValue.UUID }] })
|
||||
@@ -16,10 +20,7 @@ export class AlbumUserRepository implements IAlbumUserRepository {
|
||||
}
|
||||
|
||||
@GenerateSql({ params: [{ usersId: DummyValue.UUID, albumsId: DummyValue.UUID }, { role: AlbumUserRole.VIEWER }] })
|
||||
update(
|
||||
{ usersId, albumsId }: AlbumPermissionId,
|
||||
dto: Updateable<AlbumsSharedUsersUsers>,
|
||||
): Promise<Selectable<AlbumsSharedUsersUsers>> {
|
||||
update({ usersId, albumsId }: AlbumPermissionId, dto: Updateable<AlbumsSharedUsersUsers>) {
|
||||
return this.db
|
||||
.updateTable('albums_shared_users_users')
|
||||
.set(dto)
|
||||
|
||||
@@ -43,8 +43,8 @@ import {
|
||||
WithProperty,
|
||||
WithoutProperty,
|
||||
} from 'src/interfaces/asset.interface';
|
||||
import { MapMarker, MapMarkerSearchOptions } from 'src/interfaces/map.interface';
|
||||
import { AssetSearchOptions, SearchExploreItem, SearchExploreItemSet } from 'src/interfaces/search.interface';
|
||||
import { MapMarker, MapMarkerSearchOptions } from 'src/repositories/map.repository';
|
||||
import { anyUuid, asUuid, mapUpsertColumns } from 'src/utils/database';
|
||||
import { Paginated, PaginationOptions, paginationHelper } from 'src/utils/pagination';
|
||||
|
||||
|
||||
@@ -1,11 +1,24 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { SchedulerRegistry } from '@nestjs/schedule';
|
||||
import { CronJob, CronTime } from 'cron';
|
||||
import { CronCreate, CronUpdate, ICronRepository } from 'src/interfaces/cron.interface';
|
||||
import { LoggingRepository } from 'src/repositories/logging.repository';
|
||||
|
||||
type CronBase = {
|
||||
name: string;
|
||||
start?: boolean;
|
||||
};
|
||||
|
||||
export type CronCreate = CronBase & {
|
||||
expression: string;
|
||||
onTick: () => void;
|
||||
};
|
||||
|
||||
export type CronUpdate = CronBase & {
|
||||
expression?: string;
|
||||
};
|
||||
|
||||
@Injectable()
|
||||
export class CronRepository implements ICronRepository {
|
||||
export class CronRepository {
|
||||
constructor(
|
||||
private schedulerRegistry: SchedulerRegistry,
|
||||
private logger: LoggingRepository,
|
||||
|
||||
@@ -1,33 +1,23 @@
|
||||
import { IAlbumUserRepository } from 'src/interfaces/album-user.interface';
|
||||
import { IAlbumRepository } from 'src/interfaces/album.interface';
|
||||
import { IAssetRepository } from 'src/interfaces/asset.interface';
|
||||
import { ICronRepository } from 'src/interfaces/cron.interface';
|
||||
import { ICryptoRepository } from 'src/interfaces/crypto.interface';
|
||||
import { IDatabaseRepository } from 'src/interfaces/database.interface';
|
||||
import { IEventRepository } from 'src/interfaces/event.interface';
|
||||
import { IJobRepository } from 'src/interfaces/job.interface';
|
||||
import { ILibraryRepository } from 'src/interfaces/library.interface';
|
||||
import { IMachineLearningRepository } from 'src/interfaces/machine-learning.interface';
|
||||
import { IMapRepository } from 'src/interfaces/map.interface';
|
||||
import { IMetadataRepository } from 'src/interfaces/metadata.interface';
|
||||
import { IMoveRepository } from 'src/interfaces/move.interface';
|
||||
import { INotificationRepository } from 'src/interfaces/notification.interface';
|
||||
import { IOAuthRepository } from 'src/interfaces/oauth.interface';
|
||||
import { IPartnerRepository } from 'src/interfaces/partner.interface';
|
||||
import { IPersonRepository } from 'src/interfaces/person.interface';
|
||||
import { IProcessRepository } from 'src/interfaces/process.interface';
|
||||
import { ISearchRepository } from 'src/interfaces/search.interface';
|
||||
import { IServerInfoRepository } from 'src/interfaces/server-info.interface';
|
||||
import { ISessionRepository } from 'src/interfaces/session.interface';
|
||||
import { ISharedLinkRepository } from 'src/interfaces/shared-link.interface';
|
||||
import { IStackRepository } from 'src/interfaces/stack.interface';
|
||||
import { IStorageRepository } from 'src/interfaces/storage.interface';
|
||||
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
|
||||
import { ITagRepository } from 'src/interfaces/tag.interface';
|
||||
import { ITelemetryRepository } from 'src/interfaces/telemetry.interface';
|
||||
import { ITrashRepository } from 'src/interfaces/trash.interface';
|
||||
import { IUserRepository } from 'src/interfaces/user.interface';
|
||||
import { IVersionHistoryRepository } from 'src/interfaces/version-history.interface';
|
||||
import { AccessRepository } from 'src/repositories/access.repository';
|
||||
import { ActivityRepository } from 'src/repositories/activity.repository';
|
||||
import { AlbumUserRepository } from 'src/repositories/album-user.repository';
|
||||
@@ -71,44 +61,44 @@ import { ViewRepository } from 'src/repositories/view-repository';
|
||||
export const repositories = [
|
||||
AccessRepository,
|
||||
ActivityRepository,
|
||||
AlbumUserRepository,
|
||||
AuditRepository,
|
||||
ApiKeyRepository,
|
||||
ConfigRepository,
|
||||
CronRepository,
|
||||
LoggingRepository,
|
||||
MapRepository,
|
||||
MediaRepository,
|
||||
MemoryRepository,
|
||||
MetadataRepository,
|
||||
NotificationRepository,
|
||||
OAuthRepository,
|
||||
ServerInfoRepository,
|
||||
TelemetryRepository,
|
||||
TrashRepository,
|
||||
ViewRepository,
|
||||
VersionHistoryRepository,
|
||||
];
|
||||
|
||||
export const providers = [
|
||||
{ provide: IAlbumRepository, useClass: AlbumRepository },
|
||||
{ provide: IAlbumUserRepository, useClass: AlbumUserRepository },
|
||||
{ provide: IAssetRepository, useClass: AssetRepository },
|
||||
{ provide: ICronRepository, useClass: CronRepository },
|
||||
{ provide: ICryptoRepository, useClass: CryptoRepository },
|
||||
{ provide: IDatabaseRepository, useClass: DatabaseRepository },
|
||||
{ provide: IEventRepository, useClass: EventRepository },
|
||||
{ provide: IJobRepository, useClass: JobRepository },
|
||||
{ provide: ILibraryRepository, useClass: LibraryRepository },
|
||||
{ provide: IMachineLearningRepository, useClass: MachineLearningRepository },
|
||||
{ provide: IMapRepository, useClass: MapRepository },
|
||||
{ provide: IMetadataRepository, useClass: MetadataRepository },
|
||||
{ provide: IMoveRepository, useClass: MoveRepository },
|
||||
{ provide: INotificationRepository, useClass: NotificationRepository },
|
||||
{ provide: IOAuthRepository, useClass: OAuthRepository },
|
||||
{ provide: IPartnerRepository, useClass: PartnerRepository },
|
||||
{ provide: IPersonRepository, useClass: PersonRepository },
|
||||
{ provide: IProcessRepository, useClass: ProcessRepository },
|
||||
{ provide: ISearchRepository, useClass: SearchRepository },
|
||||
{ provide: IServerInfoRepository, useClass: ServerInfoRepository },
|
||||
{ provide: ISessionRepository, useClass: SessionRepository },
|
||||
{ provide: ISharedLinkRepository, useClass: SharedLinkRepository },
|
||||
{ provide: IStackRepository, useClass: StackRepository },
|
||||
{ provide: IStorageRepository, useClass: StorageRepository },
|
||||
{ provide: ISystemMetadataRepository, useClass: SystemMetadataRepository },
|
||||
{ provide: ITagRepository, useClass: TagRepository },
|
||||
{ provide: ITelemetryRepository, useClass: TelemetryRepository },
|
||||
{ provide: ITrashRepository, useClass: TrashRepository },
|
||||
{ provide: IUserRepository, useClass: UserRepository },
|
||||
{ provide: IVersionHistoryRepository, useClass: VersionHistoryRepository },
|
||||
];
|
||||
|
||||
@@ -11,24 +11,41 @@ import { DB, GeodataPlaces, NaturalearthCountries } from 'src/db';
|
||||
import { AssetEntity, withExif } from 'src/entities/asset.entity';
|
||||
import { NaturalEarthCountriesTempEntity } from 'src/entities/natural-earth-countries.entity';
|
||||
import { LogLevel, SystemMetadataKey } from 'src/enum';
|
||||
import {
|
||||
GeoPoint,
|
||||
IMapRepository,
|
||||
MapMarker,
|
||||
MapMarkerSearchOptions,
|
||||
ReverseGeocodeResult,
|
||||
} from 'src/interfaces/map.interface';
|
||||
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
|
||||
import { ConfigRepository } from 'src/repositories/config.repository';
|
||||
import { LoggingRepository } from 'src/repositories/logging.repository';
|
||||
|
||||
export interface MapMarkerSearchOptions {
|
||||
isArchived?: boolean;
|
||||
isFavorite?: boolean;
|
||||
fileCreatedBefore?: Date;
|
||||
fileCreatedAfter?: Date;
|
||||
}
|
||||
|
||||
export interface GeoPoint {
|
||||
latitude: number;
|
||||
longitude: number;
|
||||
}
|
||||
|
||||
export interface ReverseGeocodeResult {
|
||||
country: string | null;
|
||||
state: string | null;
|
||||
city: string | null;
|
||||
}
|
||||
|
||||
export interface MapMarker extends ReverseGeocodeResult {
|
||||
id: string;
|
||||
lat: number;
|
||||
lon: number;
|
||||
}
|
||||
|
||||
interface MapDB extends DB {
|
||||
geodata_places_tmp: GeodataPlaces;
|
||||
naturalearth_countries_tmp: NaturalearthCountries;
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class MapRepository implements IMapRepository {
|
||||
export class MapRepository {
|
||||
constructor(
|
||||
private configRepository: ConfigRepository,
|
||||
@Inject(ISystemMetadataRepository) private metadataRepository: ISystemMetadataRepository,
|
||||
|
||||
@@ -1,11 +1,72 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { DefaultReadTaskOptions, ExifTool, Tags } from 'exiftool-vendored';
|
||||
import { BinaryField, DefaultReadTaskOptions, ExifTool, Tags } from 'exiftool-vendored';
|
||||
import geotz from 'geo-tz';
|
||||
import { IMetadataRepository, ImmichTags } from 'src/interfaces/metadata.interface';
|
||||
import { LoggingRepository } from 'src/repositories/logging.repository';
|
||||
|
||||
interface ExifDuration {
|
||||
Value: number;
|
||||
Scale?: number;
|
||||
}
|
||||
|
||||
type StringOrNumber = string | number;
|
||||
|
||||
type TagsWithWrongTypes =
|
||||
| 'FocalLength'
|
||||
| 'Duration'
|
||||
| 'Description'
|
||||
| 'ImageDescription'
|
||||
| 'RegionInfo'
|
||||
| 'TagsList'
|
||||
| 'Keywords'
|
||||
| 'HierarchicalSubject'
|
||||
| 'ISO';
|
||||
|
||||
export interface ImmichTags extends Omit<Tags, TagsWithWrongTypes> {
|
||||
ContentIdentifier?: string;
|
||||
MotionPhoto?: number;
|
||||
MotionPhotoVersion?: number;
|
||||
MotionPhotoPresentationTimestampUs?: number;
|
||||
MediaGroupUUID?: string;
|
||||
ImagePixelDepth?: string;
|
||||
FocalLength?: number;
|
||||
Duration?: number | string | ExifDuration;
|
||||
EmbeddedVideoType?: string;
|
||||
EmbeddedVideoFile?: BinaryField;
|
||||
MotionPhotoVideo?: BinaryField;
|
||||
TagsList?: StringOrNumber[];
|
||||
HierarchicalSubject?: StringOrNumber[];
|
||||
Keywords?: StringOrNumber | StringOrNumber[];
|
||||
ISO?: number | number[];
|
||||
|
||||
// Type is wrong, can also be number.
|
||||
Description?: StringOrNumber;
|
||||
ImageDescription?: StringOrNumber;
|
||||
|
||||
// Extended properties for image regions, such as faces
|
||||
RegionInfo?: {
|
||||
AppliedToDimensions: {
|
||||
W: number;
|
||||
H: number;
|
||||
Unit: string;
|
||||
};
|
||||
RegionList: {
|
||||
Area: {
|
||||
// (X,Y) // center of the rectangle
|
||||
X: number;
|
||||
Y: number;
|
||||
W: number;
|
||||
H: number;
|
||||
Unit: string;
|
||||
};
|
||||
Rotation?: number;
|
||||
Type?: string;
|
||||
Name?: string;
|
||||
}[];
|
||||
};
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class MetadataRepository implements IMetadataRepository {
|
||||
export class MetadataRepository {
|
||||
private exiftool = new ExifTool({
|
||||
defaultVideosToUTC: true,
|
||||
backfillTimezones: true,
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { EmailRenderRequest, EmailTemplate } from 'src/interfaces/notification.interface';
|
||||
import { LoggingRepository } from 'src/repositories/logging.repository';
|
||||
import { NotificationRepository } from 'src/repositories/notification.repository';
|
||||
import { EmailRenderRequest, EmailTemplate, NotificationRepository } from 'src/repositories/notification.repository';
|
||||
import { ILoggingRepository } from 'src/types';
|
||||
import { newLoggingRepositoryMock } from 'test/repositories/logger.repository.mock';
|
||||
import { Mocked } from 'vitest';
|
||||
|
||||
@@ -6,18 +6,104 @@ import { AlbumInviteEmail } from 'src/emails/album-invite.email';
|
||||
import { AlbumUpdateEmail } from 'src/emails/album-update.email';
|
||||
import { TestEmail } from 'src/emails/test.email';
|
||||
import { WelcomeEmail } from 'src/emails/welcome.email';
|
||||
import {
|
||||
EmailRenderRequest,
|
||||
EmailTemplate,
|
||||
INotificationRepository,
|
||||
SendEmailOptions,
|
||||
SendEmailResponse,
|
||||
SmtpOptions,
|
||||
} from 'src/interfaces/notification.interface';
|
||||
import { LoggingRepository } from 'src/repositories/logging.repository';
|
||||
|
||||
export type EmailImageAttachment = {
|
||||
filename: string;
|
||||
path: string;
|
||||
cid: string;
|
||||
};
|
||||
|
||||
export type SendEmailOptions = {
|
||||
from: string;
|
||||
to: string;
|
||||
replyTo?: string;
|
||||
subject: string;
|
||||
html: string;
|
||||
text: string;
|
||||
imageAttachments?: EmailImageAttachment[];
|
||||
smtp: SmtpOptions;
|
||||
};
|
||||
|
||||
export type SmtpOptions = {
|
||||
host: string;
|
||||
port?: number;
|
||||
username?: string;
|
||||
password?: string;
|
||||
ignoreCert?: boolean;
|
||||
};
|
||||
|
||||
export enum EmailTemplate {
|
||||
TEST_EMAIL = 'test',
|
||||
|
||||
// AUTH
|
||||
WELCOME = 'welcome',
|
||||
RESET_PASSWORD = 'reset-password',
|
||||
|
||||
// ALBUM
|
||||
ALBUM_INVITE = 'album-invite',
|
||||
ALBUM_UPDATE = 'album-update',
|
||||
}
|
||||
|
||||
interface BaseEmailProps {
|
||||
baseUrl: string;
|
||||
customTemplate?: string;
|
||||
}
|
||||
|
||||
export interface TestEmailProps extends BaseEmailProps {
|
||||
displayName: string;
|
||||
}
|
||||
|
||||
export interface WelcomeEmailProps extends BaseEmailProps {
|
||||
displayName: string;
|
||||
username: string;
|
||||
password?: string;
|
||||
}
|
||||
|
||||
export interface AlbumInviteEmailProps extends BaseEmailProps {
|
||||
albumName: string;
|
||||
albumId: string;
|
||||
senderName: string;
|
||||
recipientName: string;
|
||||
cid?: string;
|
||||
}
|
||||
|
||||
export interface AlbumUpdateEmailProps extends BaseEmailProps {
|
||||
albumName: string;
|
||||
albumId: string;
|
||||
recipientName: string;
|
||||
cid?: string;
|
||||
}
|
||||
|
||||
export type EmailRenderRequest =
|
||||
| {
|
||||
template: EmailTemplate.TEST_EMAIL;
|
||||
data: TestEmailProps;
|
||||
customTemplate: string;
|
||||
}
|
||||
| {
|
||||
template: EmailTemplate.WELCOME;
|
||||
data: WelcomeEmailProps;
|
||||
customTemplate: string;
|
||||
}
|
||||
| {
|
||||
template: EmailTemplate.ALBUM_INVITE;
|
||||
data: AlbumInviteEmailProps;
|
||||
customTemplate: string;
|
||||
}
|
||||
| {
|
||||
template: EmailTemplate.ALBUM_UPDATE;
|
||||
data: AlbumUpdateEmailProps;
|
||||
customTemplate: string;
|
||||
};
|
||||
|
||||
export type SendEmailResponse = {
|
||||
messageId: string;
|
||||
response: any;
|
||||
};
|
||||
|
||||
@Injectable()
|
||||
export class NotificationRepository implements INotificationRepository {
|
||||
export class NotificationRepository {
|
||||
constructor(private logger: LoggingRepository) {
|
||||
this.logger.setContext(NotificationRepository.name);
|
||||
}
|
||||
|
||||
@@ -1,10 +1,21 @@
|
||||
import { Injectable, InternalServerErrorException } from '@nestjs/common';
|
||||
import { custom, generators, Issuer } from 'openid-client';
|
||||
import { IOAuthRepository, OAuthConfig, OAuthProfile } from 'src/interfaces/oauth.interface';
|
||||
import { custom, generators, Issuer, UserinfoResponse } from 'openid-client';
|
||||
import { LoggingRepository } from 'src/repositories/logging.repository';
|
||||
|
||||
export type OAuthConfig = {
|
||||
clientId: string;
|
||||
clientSecret: string;
|
||||
issuerUrl: string;
|
||||
mobileOverrideEnabled: boolean;
|
||||
mobileRedirectUri: string;
|
||||
profileSigningAlgorithm: string;
|
||||
scope: string;
|
||||
signingAlgorithm: string;
|
||||
};
|
||||
export type OAuthProfile = UserinfoResponse;
|
||||
|
||||
@Injectable()
|
||||
export class OAuthRepository implements IOAuthRepository {
|
||||
export class OAuthRepository {
|
||||
constructor(private logger: LoggingRepository) {
|
||||
this.logger.setContext(OAuthRepository.name);
|
||||
}
|
||||
|
||||
@@ -4,10 +4,27 @@ import { exec as execCallback } from 'node:child_process';
|
||||
import { readFile } from 'node:fs/promises';
|
||||
import { promisify } from 'node:util';
|
||||
import sharp from 'sharp';
|
||||
import { GitHubRelease, IServerInfoRepository, ServerBuildVersions } from 'src/interfaces/server-info.interface';
|
||||
import { ConfigRepository } from 'src/repositories/config.repository';
|
||||
import { LoggingRepository } from 'src/repositories/logging.repository';
|
||||
|
||||
export interface GitHubRelease {
|
||||
id: number;
|
||||
url: string;
|
||||
tag_name: string;
|
||||
name: string;
|
||||
created_at: string;
|
||||
published_at: string;
|
||||
body: string;
|
||||
}
|
||||
|
||||
export interface ServerBuildVersions {
|
||||
nodejs: string;
|
||||
ffmpeg: string;
|
||||
libvips: string;
|
||||
exiftool: string;
|
||||
imagemagick: string;
|
||||
}
|
||||
|
||||
const exec = promisify(execCallback);
|
||||
const maybeFirstLine = async (command: string): Promise<string> => {
|
||||
try {
|
||||
@@ -34,7 +51,7 @@ const getLockfileVersion = (name: string, lockfile?: BuildLockfile) => {
|
||||
};
|
||||
|
||||
@Injectable()
|
||||
export class ServerInfoRepository implements IServerInfoRepository {
|
||||
export class ServerInfoRepository {
|
||||
constructor(
|
||||
private configRepository: ConfigRepository,
|
||||
private logger: LoggingRepository,
|
||||
|
||||
@@ -15,11 +15,12 @@ import { MetricService } from 'nestjs-otel';
|
||||
import { copyMetadataFromFunctionToFunction } from 'nestjs-otel/lib/opentelemetry.utils';
|
||||
import { serverVersion } from 'src/constants';
|
||||
import { ImmichTelemetry, MetadataKey } from 'src/enum';
|
||||
import { IMetricGroupRepository, ITelemetryRepository, MetricGroupOptions } from 'src/interfaces/telemetry.interface';
|
||||
import { ConfigRepository } from 'src/repositories/config.repository';
|
||||
import { LoggingRepository } from 'src/repositories/logging.repository';
|
||||
|
||||
class MetricGroupRepository implements IMetricGroupRepository {
|
||||
type MetricGroupOptions = { enabled: boolean };
|
||||
|
||||
export class MetricGroupRepository {
|
||||
private enabled = false;
|
||||
|
||||
constructor(private metricService: MetricService) {}
|
||||
@@ -86,7 +87,7 @@ export const teardownTelemetry = async () => {
|
||||
};
|
||||
|
||||
@Injectable()
|
||||
export class TelemetryRepository implements ITelemetryRepository {
|
||||
export class TelemetryRepository {
|
||||
api: MetricGroupRepository;
|
||||
host: MetricGroupRepository;
|
||||
jobs: MetricGroupRepository;
|
||||
|
||||
@@ -3,9 +3,8 @@ import { InjectKysely } from 'nestjs-kysely';
|
||||
import { DB } from 'src/db';
|
||||
import { DummyValue, GenerateSql } from 'src/decorators';
|
||||
import { AssetStatus } from 'src/enum';
|
||||
import { ITrashRepository } from 'src/interfaces/trash.interface';
|
||||
|
||||
export class TrashRepository implements ITrashRepository {
|
||||
export class TrashRepository {
|
||||
constructor(@InjectKysely() private db: Kysely<DB>) {}
|
||||
|
||||
getDeletedIds(): AsyncIterableIterator<{ id: string }> {
|
||||
|
||||
@@ -3,25 +3,23 @@ import { Insertable, Kysely } from 'kysely';
|
||||
import { InjectKysely } from 'nestjs-kysely';
|
||||
import { DB, VersionHistory } from 'src/db';
|
||||
import { GenerateSql } from 'src/decorators';
|
||||
import { VersionHistoryEntity } from 'src/entities/version-history.entity';
|
||||
import { IVersionHistoryRepository } from 'src/interfaces/version-history.interface';
|
||||
|
||||
@Injectable()
|
||||
export class VersionHistoryRepository implements IVersionHistoryRepository {
|
||||
export class VersionHistoryRepository {
|
||||
constructor(@InjectKysely() private db: Kysely<DB>) {}
|
||||
|
||||
@GenerateSql()
|
||||
getAll(): Promise<VersionHistoryEntity[]> {
|
||||
getAll() {
|
||||
return this.db.selectFrom('version_history').selectAll().orderBy('createdAt', 'desc').execute();
|
||||
}
|
||||
|
||||
@GenerateSql()
|
||||
getLatest(): Promise<VersionHistoryEntity | undefined> {
|
||||
getLatest() {
|
||||
return this.db.selectFrom('version_history').selectAll().orderBy('createdAt', 'desc').executeTakeFirst();
|
||||
}
|
||||
|
||||
@GenerateSql({ params: [{ version: 'v1.123.0' }] })
|
||||
create(version: Insertable<VersionHistory>): Promise<VersionHistoryEntity> {
|
||||
create(version: Insertable<VersionHistory>) {
|
||||
return this.db.insertInto('version_history').values(version).returningAll().executeTakeFirstOrThrow();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user