mirror of
				https://github.com/immich-app/immich.git
				synced 2025-11-04 03:27:09 -05:00 
			
		
		
		
	refactor: database types (#19624)
This commit is contained in:
		
							parent
							
								
									09cbc5d3f4
								
							
						
					
					
						commit
						e60bc3c304
					
				@ -29,7 +29,6 @@
 | 
			
		||||
    "migrations:run": "node ./dist/bin/migrations.js run",
 | 
			
		||||
    "schema:drop": "node ./dist/bin/migrations.js query 'DROP schema public cascade; CREATE schema public;'",
 | 
			
		||||
    "schema:reset": "npm run schema:drop && npm run migrations:run",
 | 
			
		||||
    "kysely:codegen": "npx kysely-codegen --include-pattern=\"(public|vectors).*\" --dialect postgres --url postgres://postgres:postgres@localhost/immich --log-level debug --out-file=./src/db.d.ts",
 | 
			
		||||
    "sync:open-api": "node ./dist/bin/sync-open-api.js",
 | 
			
		||||
    "sync:sql": "node ./dist/bin/sync-sql.js",
 | 
			
		||||
    "email:dev": "email dev -p 3050 --dir src/emails",
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,4 @@
 | 
			
		||||
import { Selectable } from 'kysely';
 | 
			
		||||
import { Albums, Exif as DatabaseExif } from 'src/db';
 | 
			
		||||
import { MapAsset } from 'src/dtos/asset-response.dto';
 | 
			
		||||
import {
 | 
			
		||||
  AlbumUserRole,
 | 
			
		||||
@ -13,6 +12,8 @@ import {
 | 
			
		||||
  UserAvatarColor,
 | 
			
		||||
  UserStatus,
 | 
			
		||||
} from 'src/enum';
 | 
			
		||||
import { AlbumTable } from 'src/schema/tables/album.table';
 | 
			
		||||
import { ExifTable } from 'src/schema/tables/exif.table';
 | 
			
		||||
import { UserMetadataItem } from 'src/types';
 | 
			
		||||
 | 
			
		||||
export type AuthUser = {
 | 
			
		||||
@ -193,7 +194,7 @@ export type SharedLink = {
 | 
			
		||||
  userId: string;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export type Album = Selectable<Albums> & {
 | 
			
		||||
export type Album = Selectable<AlbumTable> & {
 | 
			
		||||
  owner: User;
 | 
			
		||||
  assets: MapAsset[];
 | 
			
		||||
};
 | 
			
		||||
@ -239,7 +240,7 @@ export type Session = {
 | 
			
		||||
  pinExpiresAt: Date | null;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export type Exif = Omit<Selectable<DatabaseExif>, 'updatedAt' | 'updateId'>;
 | 
			
		||||
export type Exif = Omit<Selectable<ExifTable>, 'updatedAt' | 'updateId'>;
 | 
			
		||||
 | 
			
		||||
export type Person = {
 | 
			
		||||
  createdAt: Date;
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										540
									
								
								server/src/db.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										540
									
								
								server/src/db.d.ts
									
									
									
									
										vendored
									
									
								
							@ -1,540 +0,0 @@
 | 
			
		||||
/**
 | 
			
		||||
 * This file was generated by kysely-codegen.
 | 
			
		||||
 * Please do not edit it manually.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
import type { ColumnType } from 'kysely';
 | 
			
		||||
import {
 | 
			
		||||
  AlbumUserRole,
 | 
			
		||||
  AssetFileType,
 | 
			
		||||
  AssetOrder,
 | 
			
		||||
  AssetStatus,
 | 
			
		||||
  AssetType,
 | 
			
		||||
  AssetVisibility,
 | 
			
		||||
  MemoryType,
 | 
			
		||||
  NotificationLevel,
 | 
			
		||||
  NotificationType,
 | 
			
		||||
  Permission,
 | 
			
		||||
  SharedLinkType,
 | 
			
		||||
  SourceType,
 | 
			
		||||
  SyncEntityType,
 | 
			
		||||
} from 'src/enum';
 | 
			
		||||
import { MemoryAssetAuditTable } from 'src/schema/tables/memory-asset-audit.table';
 | 
			
		||||
import { MemoryAssetTable } from 'src/schema/tables/memory-asset.table';
 | 
			
		||||
import { MemoryAuditTable } from 'src/schema/tables/memory-audit.table';
 | 
			
		||||
import { UserTable } from 'src/schema/tables/user.table';
 | 
			
		||||
import { UserMetadataItem } from 'src/types';
 | 
			
		||||
 | 
			
		||||
export type ArrayType<T> = ArrayTypeImpl<T> extends (infer U)[] ? U[] : ArrayTypeImpl<T>;
 | 
			
		||||
 | 
			
		||||
export type ArrayTypeImpl<T> = T extends ColumnType<infer S, infer I, infer U> ? ColumnType<S[], I[], U[]> : T[];
 | 
			
		||||
 | 
			
		||||
export type Generated<T> =
 | 
			
		||||
  T extends ColumnType<infer S, infer I, infer U> ? ColumnType<S, I | undefined, U> : ColumnType<T, T | undefined, T>;
 | 
			
		||||
 | 
			
		||||
export type Int8 = ColumnType<number>;
 | 
			
		||||
 | 
			
		||||
export type Json = JsonValue;
 | 
			
		||||
 | 
			
		||||
export type JsonArray = JsonValue[];
 | 
			
		||||
 | 
			
		||||
export type JsonObject = {
 | 
			
		||||
  [x: string]: JsonValue | undefined;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export type JsonPrimitive = boolean | number | string | null;
 | 
			
		||||
 | 
			
		||||
export type JsonValue = JsonArray | JsonObject | JsonPrimitive;
 | 
			
		||||
 | 
			
		||||
export type Timestamp = ColumnType<Date, Date | string, Date | string>;
 | 
			
		||||
 | 
			
		||||
export interface Activity {
 | 
			
		||||
  albumId: string;
 | 
			
		||||
  assetId: string | null;
 | 
			
		||||
  comment: string | null;
 | 
			
		||||
  createdAt: Generated<Timestamp>;
 | 
			
		||||
  id: Generated<string>;
 | 
			
		||||
  isLiked: Generated<boolean>;
 | 
			
		||||
  updatedAt: Generated<Timestamp>;
 | 
			
		||||
  updateId: Generated<string>;
 | 
			
		||||
  userId: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface Albums {
 | 
			
		||||
  albumName: Generated<string>;
 | 
			
		||||
  /**
 | 
			
		||||
   * Asset ID to be used as thumbnail
 | 
			
		||||
   */
 | 
			
		||||
  albumThumbnailAssetId: string | null;
 | 
			
		||||
  createdAt: Generated<Timestamp>;
 | 
			
		||||
  deletedAt: Timestamp | null;
 | 
			
		||||
  description: Generated<string>;
 | 
			
		||||
  id: Generated<string>;
 | 
			
		||||
  isActivityEnabled: Generated<boolean>;
 | 
			
		||||
  order: Generated<AssetOrder>;
 | 
			
		||||
  ownerId: string;
 | 
			
		||||
  updatedAt: Generated<Timestamp>;
 | 
			
		||||
  updateId: Generated<string>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface AlbumsAudit {
 | 
			
		||||
  deletedAt: Generated<Timestamp>;
 | 
			
		||||
  id: Generated<string>;
 | 
			
		||||
  albumId: string;
 | 
			
		||||
  userId: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface AlbumUsersAudit {
 | 
			
		||||
  deletedAt: Generated<Timestamp>;
 | 
			
		||||
  id: Generated<string>;
 | 
			
		||||
  albumId: string;
 | 
			
		||||
  userId: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface AlbumsAssetsAssets {
 | 
			
		||||
  albumsId: string;
 | 
			
		||||
  assetsId: string;
 | 
			
		||||
  createdAt: Generated<Timestamp>;
 | 
			
		||||
  updatedAt: Generated<Timestamp>;
 | 
			
		||||
  updateId: Generated<string>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface AlbumAssetsAudit {
 | 
			
		||||
  deletedAt: Generated<Timestamp>;
 | 
			
		||||
  id: Generated<string>;
 | 
			
		||||
  albumId: string;
 | 
			
		||||
  assetId: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface AlbumsSharedUsersUsers {
 | 
			
		||||
  albumsId: string;
 | 
			
		||||
  role: Generated<AlbumUserRole>;
 | 
			
		||||
  usersId: string;
 | 
			
		||||
  createId: Generated<string>;
 | 
			
		||||
  createdAt: Generated<Timestamp>;
 | 
			
		||||
  updateId: Generated<string>;
 | 
			
		||||
  updatedAt: Generated<Timestamp>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface ApiKeys {
 | 
			
		||||
  createdAt: Generated<Timestamp>;
 | 
			
		||||
  id: Generated<string>;
 | 
			
		||||
  key: string;
 | 
			
		||||
  name: string;
 | 
			
		||||
  permissions: Permission[];
 | 
			
		||||
  updatedAt: Generated<Timestamp>;
 | 
			
		||||
  updateId: Generated<string>;
 | 
			
		||||
  userId: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface AssetFaces {
 | 
			
		||||
  assetId: string;
 | 
			
		||||
  boundingBoxX1: Generated<number>;
 | 
			
		||||
  boundingBoxX2: Generated<number>;
 | 
			
		||||
  boundingBoxY1: Generated<number>;
 | 
			
		||||
  boundingBoxY2: Generated<number>;
 | 
			
		||||
  deletedAt: Timestamp | null;
 | 
			
		||||
  id: Generated<string>;
 | 
			
		||||
  imageHeight: Generated<number>;
 | 
			
		||||
  imageWidth: Generated<number>;
 | 
			
		||||
  personId: string | null;
 | 
			
		||||
  sourceType: Generated<SourceType>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface AssetFiles {
 | 
			
		||||
  assetId: string;
 | 
			
		||||
  createdAt: Generated<Timestamp>;
 | 
			
		||||
  id: Generated<string>;
 | 
			
		||||
  path: string;
 | 
			
		||||
  type: AssetFileType;
 | 
			
		||||
  updatedAt: Generated<Timestamp>;
 | 
			
		||||
  updateId: Generated<string>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface AssetJobStatus {
 | 
			
		||||
  assetId: string;
 | 
			
		||||
  duplicatesDetectedAt: Timestamp | null;
 | 
			
		||||
  facesRecognizedAt: Timestamp | null;
 | 
			
		||||
  metadataExtractedAt: Timestamp | null;
 | 
			
		||||
  previewAt: Timestamp | null;
 | 
			
		||||
  thumbnailAt: Timestamp | null;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface AssetsAudit {
 | 
			
		||||
  deletedAt: Generated<Timestamp>;
 | 
			
		||||
  id: Generated<string>;
 | 
			
		||||
  assetId: string;
 | 
			
		||||
  ownerId: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface Assets {
 | 
			
		||||
  checksum: Buffer;
 | 
			
		||||
  createdAt: Generated<Timestamp>;
 | 
			
		||||
  deletedAt: Timestamp | null;
 | 
			
		||||
  deviceAssetId: string;
 | 
			
		||||
  deviceId: string;
 | 
			
		||||
  duplicateId: string | null;
 | 
			
		||||
  duration: string | null;
 | 
			
		||||
  encodedVideoPath: Generated<string | null>;
 | 
			
		||||
  fileCreatedAt: Timestamp;
 | 
			
		||||
  fileModifiedAt: Timestamp;
 | 
			
		||||
  id: Generated<string>;
 | 
			
		||||
  isExternal: Generated<boolean>;
 | 
			
		||||
  isFavorite: Generated<boolean>;
 | 
			
		||||
  isOffline: Generated<boolean>;
 | 
			
		||||
  visibility: Generated<AssetVisibility>;
 | 
			
		||||
  libraryId: string | null;
 | 
			
		||||
  livePhotoVideoId: string | null;
 | 
			
		||||
  localDateTime: Timestamp;
 | 
			
		||||
  originalFileName: string;
 | 
			
		||||
  originalPath: string;
 | 
			
		||||
  ownerId: string;
 | 
			
		||||
  sidecarPath: string | null;
 | 
			
		||||
  stackId: string | null;
 | 
			
		||||
  status: Generated<AssetStatus>;
 | 
			
		||||
  thumbhash: Buffer | null;
 | 
			
		||||
  type: AssetType;
 | 
			
		||||
  updatedAt: Generated<Timestamp>;
 | 
			
		||||
  updateId: Generated<string>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface AssetStack {
 | 
			
		||||
  id: Generated<string>;
 | 
			
		||||
  ownerId: string;
 | 
			
		||||
  primaryAssetId: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface Audit {
 | 
			
		||||
  action: string;
 | 
			
		||||
  createdAt: Generated<Timestamp>;
 | 
			
		||||
  entityId: string;
 | 
			
		||||
  entityType: string;
 | 
			
		||||
  id: Generated<number>;
 | 
			
		||||
  ownerId: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface Exif {
 | 
			
		||||
  assetId: string;
 | 
			
		||||
  updateId: Generated<string>;
 | 
			
		||||
  updatedAt: Generated<Timestamp>;
 | 
			
		||||
  autoStackId: string | null;
 | 
			
		||||
  bitsPerSample: number | null;
 | 
			
		||||
  city: string | null;
 | 
			
		||||
  colorspace: string | null;
 | 
			
		||||
  country: string | null;
 | 
			
		||||
  dateTimeOriginal: Timestamp | null;
 | 
			
		||||
  description: Generated<string>;
 | 
			
		||||
  exifImageHeight: number | null;
 | 
			
		||||
  exifImageWidth: number | null;
 | 
			
		||||
  exposureTime: string | null;
 | 
			
		||||
  fileSizeInByte: Int8 | null;
 | 
			
		||||
  fNumber: number | null;
 | 
			
		||||
  focalLength: number | null;
 | 
			
		||||
  fps: number | null;
 | 
			
		||||
  iso: number | null;
 | 
			
		||||
  latitude: number | null;
 | 
			
		||||
  lensModel: string | null;
 | 
			
		||||
  livePhotoCID: string | null;
 | 
			
		||||
  longitude: number | null;
 | 
			
		||||
  make: string | null;
 | 
			
		||||
  model: string | null;
 | 
			
		||||
  modifyDate: Timestamp | null;
 | 
			
		||||
  orientation: string | null;
 | 
			
		||||
  profileDescription: string | null;
 | 
			
		||||
  projectionType: string | null;
 | 
			
		||||
  rating: number | null;
 | 
			
		||||
  state: string | null;
 | 
			
		||||
  timeZone: string | null;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface FaceSearch {
 | 
			
		||||
  embedding: string;
 | 
			
		||||
  faceId: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface GeodataPlaces {
 | 
			
		||||
  admin1Code: string | null;
 | 
			
		||||
  admin1Name: string | null;
 | 
			
		||||
  admin2Code: string | null;
 | 
			
		||||
  admin2Name: string | null;
 | 
			
		||||
  alternateNames: string | null;
 | 
			
		||||
  countryCode: string;
 | 
			
		||||
  id: number;
 | 
			
		||||
  latitude: number;
 | 
			
		||||
  longitude: number;
 | 
			
		||||
  modificationDate: Timestamp;
 | 
			
		||||
  name: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface Libraries {
 | 
			
		||||
  createdAt: Generated<Timestamp>;
 | 
			
		||||
  deletedAt: Timestamp | null;
 | 
			
		||||
  exclusionPatterns: string[];
 | 
			
		||||
  id: Generated<string>;
 | 
			
		||||
  importPaths: string[];
 | 
			
		||||
  name: string;
 | 
			
		||||
  ownerId: string;
 | 
			
		||||
  refreshedAt: Timestamp | null;
 | 
			
		||||
  updatedAt: Generated<Timestamp>;
 | 
			
		||||
  updateId: Generated<string>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface Memories {
 | 
			
		||||
  createdAt: Generated<Timestamp>;
 | 
			
		||||
  data: object;
 | 
			
		||||
  deletedAt: Timestamp | null;
 | 
			
		||||
  hideAt: Timestamp | null;
 | 
			
		||||
  id: Generated<string>;
 | 
			
		||||
  isSaved: Generated<boolean>;
 | 
			
		||||
  memoryAt: Timestamp;
 | 
			
		||||
  ownerId: string;
 | 
			
		||||
  seenAt: Timestamp | null;
 | 
			
		||||
  showAt: Timestamp | null;
 | 
			
		||||
  type: MemoryType;
 | 
			
		||||
  updatedAt: Generated<Timestamp>;
 | 
			
		||||
  updateId: Generated<string>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface Notifications {
 | 
			
		||||
  id: Generated<string>;
 | 
			
		||||
  createdAt: Generated<Timestamp>;
 | 
			
		||||
  updatedAt: Generated<Timestamp>;
 | 
			
		||||
  deletedAt: Timestamp | null;
 | 
			
		||||
  updateId: Generated<string>;
 | 
			
		||||
  userId: string;
 | 
			
		||||
  level: Generated<NotificationLevel>;
 | 
			
		||||
  type: NotificationType;
 | 
			
		||||
  title: string;
 | 
			
		||||
  description: string | null;
 | 
			
		||||
  data: any | null;
 | 
			
		||||
  readAt: Timestamp | null;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface Migrations {
 | 
			
		||||
  id: Generated<number>;
 | 
			
		||||
  name: string;
 | 
			
		||||
  timestamp: Int8;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface MoveHistory {
 | 
			
		||||
  entityId: string;
 | 
			
		||||
  id: Generated<string>;
 | 
			
		||||
  newPath: string;
 | 
			
		||||
  oldPath: string;
 | 
			
		||||
  pathType: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface NaturalearthCountries {
 | 
			
		||||
  admin: string;
 | 
			
		||||
  admin_a3: string;
 | 
			
		||||
  coordinates: string;
 | 
			
		||||
  id: Generated<number>;
 | 
			
		||||
  type: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface PartnersAudit {
 | 
			
		||||
  deletedAt: Generated<Timestamp>;
 | 
			
		||||
  id: Generated<string>;
 | 
			
		||||
  sharedById: string;
 | 
			
		||||
  sharedWithId: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface Partners {
 | 
			
		||||
  createdAt: Generated<Timestamp>;
 | 
			
		||||
  createId: Generated<string>;
 | 
			
		||||
  inTimeline: Generated<boolean>;
 | 
			
		||||
  sharedById: string;
 | 
			
		||||
  sharedWithId: string;
 | 
			
		||||
  updatedAt: Generated<Timestamp>;
 | 
			
		||||
  updateId: Generated<string>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface Person {
 | 
			
		||||
  birthDate: Timestamp | null;
 | 
			
		||||
  color: string | null;
 | 
			
		||||
  createdAt: Generated<Timestamp>;
 | 
			
		||||
  faceAssetId: string | null;
 | 
			
		||||
  id: Generated<string>;
 | 
			
		||||
  isFavorite: Generated<boolean>;
 | 
			
		||||
  isHidden: Generated<boolean>;
 | 
			
		||||
  name: Generated<string>;
 | 
			
		||||
  ownerId: string;
 | 
			
		||||
  thumbnailPath: Generated<string>;
 | 
			
		||||
  updatedAt: Generated<Timestamp>;
 | 
			
		||||
  updateId: Generated<string>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface Sessions {
 | 
			
		||||
  createdAt: Generated<Timestamp>;
 | 
			
		||||
  deviceOS: Generated<string>;
 | 
			
		||||
  deviceType: Generated<string>;
 | 
			
		||||
  id: Generated<string>;
 | 
			
		||||
  parentId: string | null;
 | 
			
		||||
  expiresAt: Date | null;
 | 
			
		||||
  token: string;
 | 
			
		||||
  updatedAt: Generated<Timestamp>;
 | 
			
		||||
  updateId: Generated<string>;
 | 
			
		||||
  userId: string;
 | 
			
		||||
  pinExpiresAt: Timestamp | null;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface SessionSyncCheckpoints {
 | 
			
		||||
  ack: string;
 | 
			
		||||
  createdAt: Generated<Timestamp>;
 | 
			
		||||
  sessionId: string;
 | 
			
		||||
  type: SyncEntityType;
 | 
			
		||||
  updatedAt: Generated<Timestamp>;
 | 
			
		||||
  updateId: Generated<string>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface SharedLinkAsset {
 | 
			
		||||
  assetsId: string;
 | 
			
		||||
  sharedLinksId: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface SharedLinks {
 | 
			
		||||
  albumId: string | null;
 | 
			
		||||
  allowDownload: Generated<boolean>;
 | 
			
		||||
  allowUpload: Generated<boolean>;
 | 
			
		||||
  createdAt: Generated<Timestamp>;
 | 
			
		||||
  description: string | null;
 | 
			
		||||
  expiresAt: Timestamp | null;
 | 
			
		||||
  id: Generated<string>;
 | 
			
		||||
  key: Buffer;
 | 
			
		||||
  password: string | null;
 | 
			
		||||
  showExif: Generated<boolean>;
 | 
			
		||||
  type: SharedLinkType;
 | 
			
		||||
  userId: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface SmartSearch {
 | 
			
		||||
  assetId: string;
 | 
			
		||||
  embedding: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface SocketIoAttachments {
 | 
			
		||||
  created_at: Generated<Timestamp | null>;
 | 
			
		||||
  id: Generated<Int8>;
 | 
			
		||||
  payload: Buffer | null;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface SystemConfig {
 | 
			
		||||
  key: string;
 | 
			
		||||
  value: string | null;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface SystemMetadata {
 | 
			
		||||
  key: string;
 | 
			
		||||
  value: Json;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface TagAsset {
 | 
			
		||||
  assetsId: string;
 | 
			
		||||
  tagsId: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface Tags {
 | 
			
		||||
  color: string | null;
 | 
			
		||||
  createdAt: Generated<Timestamp>;
 | 
			
		||||
  id: Generated<string>;
 | 
			
		||||
  parentId: string | null;
 | 
			
		||||
  updatedAt: Generated<Timestamp>;
 | 
			
		||||
  updateId: Generated<string>;
 | 
			
		||||
  userId: string;
 | 
			
		||||
  value: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface TagsClosure {
 | 
			
		||||
  id_ancestor: string;
 | 
			
		||||
  id_descendant: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface TypeormMetadata {
 | 
			
		||||
  database: string | null;
 | 
			
		||||
  name: string | null;
 | 
			
		||||
  schema: string | null;
 | 
			
		||||
  table: string | null;
 | 
			
		||||
  type: string;
 | 
			
		||||
  value: string | null;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface UserMetadata extends UserMetadataItem {
 | 
			
		||||
  userId: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface UsersAudit {
 | 
			
		||||
  id: Generated<string>;
 | 
			
		||||
  userId: string;
 | 
			
		||||
  deletedAt: Generated<Timestamp>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface VectorsPgVectorIndexStat {
 | 
			
		||||
  idx_growing: ArrayType<Int8> | null;
 | 
			
		||||
  idx_indexing: boolean | null;
 | 
			
		||||
  idx_options: string | null;
 | 
			
		||||
  idx_sealed: ArrayType<Int8> | null;
 | 
			
		||||
  idx_size: Int8 | null;
 | 
			
		||||
  idx_status: string | null;
 | 
			
		||||
  idx_tuples: Int8 | null;
 | 
			
		||||
  idx_write: Int8 | null;
 | 
			
		||||
  indexname: string | null;
 | 
			
		||||
  indexrelid: number | null;
 | 
			
		||||
  tablename: string | null;
 | 
			
		||||
  tablerelid: number | null;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface VersionHistory {
 | 
			
		||||
  createdAt: Generated<Timestamp>;
 | 
			
		||||
  id: Generated<string>;
 | 
			
		||||
  version: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface DB {
 | 
			
		||||
  activity: Activity;
 | 
			
		||||
  albums: Albums;
 | 
			
		||||
  albums_audit: AlbumsAudit;
 | 
			
		||||
  albums_assets_assets: AlbumsAssetsAssets;
 | 
			
		||||
  album_assets_audit: AlbumAssetsAudit;
 | 
			
		||||
  albums_shared_users_users: AlbumsSharedUsersUsers;
 | 
			
		||||
  album_users_audit: AlbumUsersAudit;
 | 
			
		||||
  api_keys: ApiKeys;
 | 
			
		||||
  asset_faces: AssetFaces;
 | 
			
		||||
  asset_files: AssetFiles;
 | 
			
		||||
  asset_job_status: AssetJobStatus;
 | 
			
		||||
  asset_stack: AssetStack;
 | 
			
		||||
  assets: Assets;
 | 
			
		||||
  assets_audit: AssetsAudit;
 | 
			
		||||
  audit: Audit;
 | 
			
		||||
  exif: Exif;
 | 
			
		||||
  face_search: FaceSearch;
 | 
			
		||||
  geodata_places: GeodataPlaces;
 | 
			
		||||
  libraries: Libraries;
 | 
			
		||||
  memories: Memories;
 | 
			
		||||
  memories_audit: MemoryAuditTable;
 | 
			
		||||
  memories_assets_assets: MemoryAssetTable;
 | 
			
		||||
  memory_assets_audit: MemoryAssetAuditTable;
 | 
			
		||||
  migrations: Migrations;
 | 
			
		||||
  notifications: Notifications;
 | 
			
		||||
  move_history: MoveHistory;
 | 
			
		||||
  naturalearth_countries: NaturalearthCountries;
 | 
			
		||||
  partners_audit: PartnersAudit;
 | 
			
		||||
  partners: Partners;
 | 
			
		||||
  person: Person;
 | 
			
		||||
  sessions: Sessions;
 | 
			
		||||
  session_sync_checkpoints: SessionSyncCheckpoints;
 | 
			
		||||
  shared_link__asset: SharedLinkAsset;
 | 
			
		||||
  shared_links: SharedLinks;
 | 
			
		||||
  smart_search: SmartSearch;
 | 
			
		||||
  socket_io_attachments: SocketIoAttachments;
 | 
			
		||||
  system_config: SystemConfig;
 | 
			
		||||
  system_metadata: SystemMetadata;
 | 
			
		||||
  tag_asset: TagAsset;
 | 
			
		||||
  tags: Tags;
 | 
			
		||||
  tags_closure: TagsClosure;
 | 
			
		||||
  typeorm_metadata: TypeormMetadata;
 | 
			
		||||
  user_metadata: UserMetadata;
 | 
			
		||||
  users: UserTable;
 | 
			
		||||
  users_audit: UsersAudit;
 | 
			
		||||
  'vectors.pg_vector_index_stat': VectorsPgVectorIndexStat;
 | 
			
		||||
  version_history: VersionHistory;
 | 
			
		||||
}
 | 
			
		||||
@ -4,10 +4,10 @@ import { IsArray, IsInt, IsNotEmpty, IsNumber, IsString, Max, Min, ValidateNeste
 | 
			
		||||
import { Selectable } from 'kysely';
 | 
			
		||||
import { DateTime } from 'luxon';
 | 
			
		||||
import { AssetFace, Person } from 'src/database';
 | 
			
		||||
import { AssetFaces } from 'src/db';
 | 
			
		||||
import { PropertyLifecycle } from 'src/decorators';
 | 
			
		||||
import { AuthDto } from 'src/dtos/auth.dto';
 | 
			
		||||
import { SourceType } from 'src/enum';
 | 
			
		||||
import { AssetFaceTable } from 'src/schema/tables/asset-face.table';
 | 
			
		||||
import { asDateString } from 'src/utils/date';
 | 
			
		||||
import {
 | 
			
		||||
  IsDateStringFormat,
 | 
			
		||||
@ -232,7 +232,7 @@ export function mapPerson(person: Person): PersonResponseDto {
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function mapFacesWithoutPerson(face: Selectable<AssetFaces>): AssetFaceWithoutPersonResponseDto {
 | 
			
		||||
export function mapFacesWithoutPerson(face: Selectable<AssetFaceTable>): AssetFaceWithoutPersonResponseDto {
 | 
			
		||||
  return {
 | 
			
		||||
    id: face.id,
 | 
			
		||||
    imageHeight: face.imageHeight,
 | 
			
		||||
 | 
			
		||||
@ -1,9 +1,9 @@
 | 
			
		||||
import { Injectable } from '@nestjs/common';
 | 
			
		||||
import { Kysely, sql } from 'kysely';
 | 
			
		||||
import { InjectKysely } from 'nestjs-kysely';
 | 
			
		||||
import { DB } from 'src/db';
 | 
			
		||||
import { ChunkedSet, DummyValue, GenerateSql } from 'src/decorators';
 | 
			
		||||
import { AlbumUserRole, AssetVisibility } from 'src/enum';
 | 
			
		||||
import { DB } from 'src/schema';
 | 
			
		||||
import { asUuid } from 'src/utils/database';
 | 
			
		||||
 | 
			
		||||
class ActivityAccess {
 | 
			
		||||
 | 
			
		||||
@ -3,9 +3,10 @@ import { Insertable, Kysely, NotNull, sql } from 'kysely';
 | 
			
		||||
import { jsonObjectFrom } from 'kysely/helpers/postgres';
 | 
			
		||||
import { InjectKysely } from 'nestjs-kysely';
 | 
			
		||||
import { columns } from 'src/database';
 | 
			
		||||
import { Activity, DB } from 'src/db';
 | 
			
		||||
import { DummyValue, GenerateSql } from 'src/decorators';
 | 
			
		||||
import { AssetVisibility } from 'src/enum';
 | 
			
		||||
import { DB } from 'src/schema';
 | 
			
		||||
import { ActivityTable } from 'src/schema/tables/activity.table';
 | 
			
		||||
import { asUuid } from 'src/utils/database';
 | 
			
		||||
 | 
			
		||||
export interface ActivitySearch {
 | 
			
		||||
@ -48,7 +49,7 @@ export class ActivityRepository {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @GenerateSql({ params: [{ albumId: DummyValue.UUID, userId: DummyValue.UUID }] })
 | 
			
		||||
  async create(activity: Insertable<Activity>) {
 | 
			
		||||
  async create(activity: Insertable<ActivityTable>) {
 | 
			
		||||
    return this.db
 | 
			
		||||
      .insertInto('activity')
 | 
			
		||||
      .values(activity)
 | 
			
		||||
 | 
			
		||||
@ -1,9 +1,10 @@
 | 
			
		||||
import { Injectable } from '@nestjs/common';
 | 
			
		||||
import { Insertable, Kysely, Updateable } from 'kysely';
 | 
			
		||||
import { InjectKysely } from 'nestjs-kysely';
 | 
			
		||||
import { AlbumsSharedUsersUsers, DB } from 'src/db';
 | 
			
		||||
import { DummyValue, GenerateSql } from 'src/decorators';
 | 
			
		||||
import { AlbumUserRole } from 'src/enum';
 | 
			
		||||
import { DB } from 'src/schema';
 | 
			
		||||
import { AlbumUserTable } from 'src/schema/tables/album-user.table';
 | 
			
		||||
 | 
			
		||||
export type AlbumPermissionId = {
 | 
			
		||||
  albumsId: string;
 | 
			
		||||
@ -15,7 +16,7 @@ export class AlbumUserRepository {
 | 
			
		||||
  constructor(@InjectKysely() private db: Kysely<DB>) {}
 | 
			
		||||
 | 
			
		||||
  @GenerateSql({ params: [{ usersId: DummyValue.UUID, albumsId: DummyValue.UUID }] })
 | 
			
		||||
  create(albumUser: Insertable<AlbumsSharedUsersUsers>) {
 | 
			
		||||
  create(albumUser: Insertable<AlbumUserTable>) {
 | 
			
		||||
    return this.db
 | 
			
		||||
      .insertInto('albums_shared_users_users')
 | 
			
		||||
      .values(albumUser)
 | 
			
		||||
@ -24,7 +25,7 @@ export class AlbumUserRepository {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @GenerateSql({ params: [{ usersId: DummyValue.UUID, albumsId: DummyValue.UUID }, { role: AlbumUserRole.VIEWER }] })
 | 
			
		||||
  update({ usersId, albumsId }: AlbumPermissionId, dto: Updateable<AlbumsSharedUsersUsers>) {
 | 
			
		||||
  update({ usersId, albumsId }: AlbumPermissionId, dto: Updateable<AlbumUserTable>) {
 | 
			
		||||
    return this.db
 | 
			
		||||
      .updateTable('albums_shared_users_users')
 | 
			
		||||
      .set(dto)
 | 
			
		||||
 | 
			
		||||
@ -3,9 +3,10 @@ import { ExpressionBuilder, Insertable, Kysely, NotNull, sql, Updateable } from
 | 
			
		||||
import { jsonArrayFrom, jsonObjectFrom } from 'kysely/helpers/postgres';
 | 
			
		||||
import { InjectKysely } from 'nestjs-kysely';
 | 
			
		||||
import { columns, Exif } from 'src/database';
 | 
			
		||||
import { Albums, DB } from 'src/db';
 | 
			
		||||
import { Chunked, ChunkedArray, ChunkedSet, DummyValue, GenerateSql } from 'src/decorators';
 | 
			
		||||
import { AlbumUserCreateDto } from 'src/dtos/album.dto';
 | 
			
		||||
import { DB } from 'src/schema';
 | 
			
		||||
import { AlbumTable } from 'src/schema/tables/album.table';
 | 
			
		||||
import { withDefaultVisibility } from 'src/utils/database';
 | 
			
		||||
 | 
			
		||||
export interface AlbumAssetCount {
 | 
			
		||||
@ -269,7 +270,7 @@ export class AlbumRepository {
 | 
			
		||||
    await this.addAssets(this.db, albumId, assetIds);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  create(album: Insertable<Albums>, assetIds: string[], albumUsers: AlbumUserCreateDto[]) {
 | 
			
		||||
  create(album: Insertable<AlbumTable>, assetIds: string[], albumUsers: AlbumUserCreateDto[]) {
 | 
			
		||||
    return this.db.transaction().execute(async (tx) => {
 | 
			
		||||
      const newAlbum = await tx.insertInto('albums').values(album).returning('albums.id').executeTakeFirst();
 | 
			
		||||
 | 
			
		||||
@ -302,7 +303,7 @@ export class AlbumRepository {
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  update(id: string, album: Updateable<Albums>) {
 | 
			
		||||
  update(id: string, album: Updateable<AlbumTable>) {
 | 
			
		||||
    return this.db
 | 
			
		||||
      .updateTable('albums')
 | 
			
		||||
      .set(album)
 | 
			
		||||
 | 
			
		||||
@ -3,19 +3,20 @@ import { Insertable, Kysely, Updateable } from 'kysely';
 | 
			
		||||
import { jsonObjectFrom } from 'kysely/helpers/postgres';
 | 
			
		||||
import { InjectKysely } from 'nestjs-kysely';
 | 
			
		||||
import { columns } from 'src/database';
 | 
			
		||||
import { ApiKeys, DB } from 'src/db';
 | 
			
		||||
import { DummyValue, GenerateSql } from 'src/decorators';
 | 
			
		||||
import { DB } from 'src/schema';
 | 
			
		||||
import { ApiKeyTable } from 'src/schema/tables/api-key.table';
 | 
			
		||||
import { asUuid } from 'src/utils/database';
 | 
			
		||||
 | 
			
		||||
@Injectable()
 | 
			
		||||
export class ApiKeyRepository {
 | 
			
		||||
  constructor(@InjectKysely() private db: Kysely<DB>) {}
 | 
			
		||||
 | 
			
		||||
  create(dto: Insertable<ApiKeys>) {
 | 
			
		||||
  create(dto: Insertable<ApiKeyTable>) {
 | 
			
		||||
    return this.db.insertInto('api_keys').values(dto).returning(columns.apiKey).executeTakeFirstOrThrow();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async update(userId: string, id: string, dto: Updateable<ApiKeys>) {
 | 
			
		||||
  async update(userId: string, id: string, dto: Updateable<ApiKeyTable>) {
 | 
			
		||||
    return this.db
 | 
			
		||||
      .updateTable('api_keys')
 | 
			
		||||
      .set(dto)
 | 
			
		||||
 | 
			
		||||
@ -3,9 +3,9 @@ import { Kysely } from 'kysely';
 | 
			
		||||
import { jsonArrayFrom } from 'kysely/helpers/postgres';
 | 
			
		||||
import { InjectKysely } from 'nestjs-kysely';
 | 
			
		||||
import { Asset, columns } from 'src/database';
 | 
			
		||||
import { DB } from 'src/db';
 | 
			
		||||
import { DummyValue, GenerateSql } from 'src/decorators';
 | 
			
		||||
import { AssetFileType, AssetType, AssetVisibility } from 'src/enum';
 | 
			
		||||
import { DB } from 'src/schema';
 | 
			
		||||
import { StorageAsset } from 'src/types';
 | 
			
		||||
import {
 | 
			
		||||
  anyUuid,
 | 
			
		||||
 | 
			
		||||
@ -3,9 +3,13 @@ import { Insertable, Kysely, NotNull, Selectable, UpdateResult, Updateable, sql
 | 
			
		||||
import { isEmpty, isUndefined, omitBy } from 'lodash';
 | 
			
		||||
import { InjectKysely } from 'nestjs-kysely';
 | 
			
		||||
import { Stack } from 'src/database';
 | 
			
		||||
import { AssetFiles, AssetJobStatus, Assets, DB, Exif } from 'src/db';
 | 
			
		||||
import { Chunked, ChunkedArray, DummyValue, GenerateSql } from 'src/decorators';
 | 
			
		||||
import { AssetFileType, AssetOrder, AssetStatus, AssetType, AssetVisibility } from 'src/enum';
 | 
			
		||||
import { DB } from 'src/schema';
 | 
			
		||||
import { AssetFileTable } from 'src/schema/tables/asset-files.table';
 | 
			
		||||
import { AssetJobStatusTable } from 'src/schema/tables/asset-job-status.table';
 | 
			
		||||
import { AssetTable } from 'src/schema/tables/asset.table';
 | 
			
		||||
import { ExifTable } from 'src/schema/tables/exif.table';
 | 
			
		||||
import {
 | 
			
		||||
  anyUuid,
 | 
			
		||||
  asUuid,
 | 
			
		||||
@ -110,7 +114,7 @@ interface GetByIdsRelations {
 | 
			
		||||
export class AssetRepository {
 | 
			
		||||
  constructor(@InjectKysely() private db: Kysely<DB>) {}
 | 
			
		||||
 | 
			
		||||
  async upsertExif(exif: Insertable<Exif>): Promise<void> {
 | 
			
		||||
  async upsertExif(exif: Insertable<ExifTable>): Promise<void> {
 | 
			
		||||
    const value = { ...exif, assetId: asUuid(exif.assetId) };
 | 
			
		||||
    await this.db
 | 
			
		||||
      .insertInto('exif')
 | 
			
		||||
@ -157,7 +161,7 @@ export class AssetRepository {
 | 
			
		||||
 | 
			
		||||
  @GenerateSql({ params: [[DummyValue.UUID], { model: DummyValue.STRING }] })
 | 
			
		||||
  @Chunked()
 | 
			
		||||
  async updateAllExif(ids: string[], options: Updateable<Exif>): Promise<void> {
 | 
			
		||||
  async updateAllExif(ids: string[], options: Updateable<ExifTable>): Promise<void> {
 | 
			
		||||
    if (ids.length === 0) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
@ -165,7 +169,7 @@ export class AssetRepository {
 | 
			
		||||
    await this.db.updateTable('exif').set(options).where('assetId', 'in', ids).execute();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async upsertJobStatus(...jobStatus: Insertable<AssetJobStatus>[]): Promise<void> {
 | 
			
		||||
  async upsertJobStatus(...jobStatus: Insertable<AssetJobStatusTable>[]): Promise<void> {
 | 
			
		||||
    if (jobStatus.length === 0) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
@ -191,11 +195,11 @@ export class AssetRepository {
 | 
			
		||||
      .execute();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  create(asset: Insertable<Assets>) {
 | 
			
		||||
  create(asset: Insertable<AssetTable>) {
 | 
			
		||||
    return this.db.insertInto('assets').values(asset).returningAll().executeTakeFirstOrThrow();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  createAll(assets: Insertable<Assets>[]) {
 | 
			
		||||
  createAll(assets: Insertable<AssetTable>[]) {
 | 
			
		||||
    return this.db.insertInto('assets').values(assets).returningAll().execute();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -375,18 +379,18 @@ export class AssetRepository {
 | 
			
		||||
 | 
			
		||||
  @GenerateSql({ params: [[DummyValue.UUID], { deviceId: DummyValue.STRING }] })
 | 
			
		||||
  @Chunked()
 | 
			
		||||
  async updateAll(ids: string[], options: Updateable<Assets>): Promise<void> {
 | 
			
		||||
  async updateAll(ids: string[], options: Updateable<AssetTable>): Promise<void> {
 | 
			
		||||
    if (ids.length === 0) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    await this.db.updateTable('assets').set(options).where('id', '=', anyUuid(ids)).execute();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async updateByLibraryId(libraryId: string, options: Updateable<Assets>): Promise<void> {
 | 
			
		||||
  async updateByLibraryId(libraryId: string, options: Updateable<AssetTable>): Promise<void> {
 | 
			
		||||
    await this.db.updateTable('assets').set(options).where('libraryId', '=', asUuid(libraryId)).execute();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async update(asset: Updateable<Assets> & { id: string }) {
 | 
			
		||||
  async update(asset: Updateable<AssetTable> & { id: string }) {
 | 
			
		||||
    const value = omitBy(asset, isUndefined);
 | 
			
		||||
    delete value.id;
 | 
			
		||||
    if (!isEmpty(value)) {
 | 
			
		||||
@ -742,7 +746,7 @@ export class AssetRepository {
 | 
			
		||||
      .execute();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async upsertFile(file: Pick<Insertable<AssetFiles>, 'assetId' | 'path' | 'type'>): Promise<void> {
 | 
			
		||||
  async upsertFile(file: Pick<Insertable<AssetFileTable>, 'assetId' | 'path' | 'type'>): Promise<void> {
 | 
			
		||||
    const value = { ...file, assetId: asUuid(file.assetId) };
 | 
			
		||||
    await this.db
 | 
			
		||||
      .insertInto('asset_files')
 | 
			
		||||
@ -755,7 +759,7 @@ export class AssetRepository {
 | 
			
		||||
      .execute();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async upsertFiles(files: Pick<Insertable<AssetFiles>, 'assetId' | 'path' | 'type'>[]): Promise<void> {
 | 
			
		||||
  async upsertFiles(files: Pick<Insertable<AssetFileTable>, 'assetId' | 'path' | 'type'>[]): Promise<void> {
 | 
			
		||||
    if (files.length === 0) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
@ -772,7 +776,7 @@ export class AssetRepository {
 | 
			
		||||
      .execute();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async deleteFiles(files: Pick<Selectable<AssetFiles>, 'id'>[]): Promise<void> {
 | 
			
		||||
  async deleteFiles(files: Pick<Selectable<AssetFileTable>, 'id'>[]): Promise<void> {
 | 
			
		||||
    if (files.length === 0) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -1,9 +1,9 @@
 | 
			
		||||
import { Injectable } from '@nestjs/common';
 | 
			
		||||
import { Kysely } from 'kysely';
 | 
			
		||||
import { InjectKysely } from 'nestjs-kysely';
 | 
			
		||||
import { DB } from 'src/db';
 | 
			
		||||
import { DummyValue, GenerateSql } from 'src/decorators';
 | 
			
		||||
import { DatabaseAction, EntityType } from 'src/enum';
 | 
			
		||||
import { DB } from 'src/schema';
 | 
			
		||||
 | 
			
		||||
export interface AuditSearch {
 | 
			
		||||
  action?: DatabaseAction;
 | 
			
		||||
 | 
			
		||||
@ -15,11 +15,11 @@ import {
 | 
			
		||||
  VECTORCHORD_VERSION_RANGE,
 | 
			
		||||
  VECTORS_VERSION_RANGE,
 | 
			
		||||
} from 'src/constants';
 | 
			
		||||
import { DB } from 'src/db';
 | 
			
		||||
import { GenerateSql } from 'src/decorators';
 | 
			
		||||
import { DatabaseExtension, DatabaseLock, VectorIndex } from 'src/enum';
 | 
			
		||||
import { ConfigRepository } from 'src/repositories/config.repository';
 | 
			
		||||
import { LoggingRepository } from 'src/repositories/logging.repository';
 | 
			
		||||
import { DB } from 'src/schema';
 | 
			
		||||
import { ExtensionVersion, VectorExtension, VectorUpdateResult } from 'src/types';
 | 
			
		||||
import { vectorIndexQuery } from 'src/utils/database';
 | 
			
		||||
import { isValidInteger } from 'src/validation';
 | 
			
		||||
 | 
			
		||||
@ -1,8 +1,8 @@
 | 
			
		||||
import { Injectable } from '@nestjs/common';
 | 
			
		||||
import { Kysely } from 'kysely';
 | 
			
		||||
import { InjectKysely } from 'nestjs-kysely';
 | 
			
		||||
import { DB } from 'src/db';
 | 
			
		||||
import { AssetVisibility } from 'src/enum';
 | 
			
		||||
import { DB } from 'src/schema';
 | 
			
		||||
import { anyUuid } from 'src/utils/database';
 | 
			
		||||
 | 
			
		||||
const builder = (db: Kysely<DB>) =>
 | 
			
		||||
 | 
			
		||||
@ -1,11 +1,11 @@
 | 
			
		||||
import { Injectable } from '@nestjs/common';
 | 
			
		||||
import { Kysely, NotNull, sql } from 'kysely';
 | 
			
		||||
import { InjectKysely } from 'nestjs-kysely';
 | 
			
		||||
import { DB } from 'src/db';
 | 
			
		||||
import { Chunked, DummyValue, GenerateSql } from 'src/decorators';
 | 
			
		||||
import { MapAsset } from 'src/dtos/asset-response.dto';
 | 
			
		||||
import { AssetType, VectorIndex } from 'src/enum';
 | 
			
		||||
import { probes } from 'src/repositories/database.repository';
 | 
			
		||||
import { DB } from 'src/schema';
 | 
			
		||||
import { anyUuid, asUuid, withDefaultVisibility } from 'src/utils/database';
 | 
			
		||||
 | 
			
		||||
interface DuplicateSearch {
 | 
			
		||||
 | 
			
		||||
@ -1,10 +1,11 @@
 | 
			
		||||
import { Injectable } from '@nestjs/common';
 | 
			
		||||
import { Insertable, Kysely, sql, Updateable } from 'kysely';
 | 
			
		||||
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 { AssetType, AssetVisibility } from 'src/enum';
 | 
			
		||||
import { DB } from 'src/schema';
 | 
			
		||||
import { LibraryTable } from 'src/schema/tables/library.table';
 | 
			
		||||
 | 
			
		||||
export enum AssetSyncResult {
 | 
			
		||||
  DO_NOTHING,
 | 
			
		||||
@ -47,7 +48,7 @@ export class LibraryRepository {
 | 
			
		||||
      .execute();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  create(library: Insertable<Libraries>) {
 | 
			
		||||
  create(library: Insertable<LibraryTable>) {
 | 
			
		||||
    return this.db.insertInto('libraries').values(library).returningAll().executeTakeFirstOrThrow();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -59,7 +60,7 @@ export class LibraryRepository {
 | 
			
		||||
    await this.db.updateTable('libraries').set({ deletedAt: new Date() }).where('libraries.id', '=', id).execute();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  update(id: string, library: Updateable<Libraries>) {
 | 
			
		||||
  update(id: string, library: Updateable<LibraryTable>) {
 | 
			
		||||
    return this.db
 | 
			
		||||
      .updateTable('libraries')
 | 
			
		||||
      .set(library)
 | 
			
		||||
 | 
			
		||||
@ -6,12 +6,14 @@ import { createReadStream, existsSync } from 'node:fs';
 | 
			
		||||
import { readFile } from 'node:fs/promises';
 | 
			
		||||
import readLine from 'node:readline';
 | 
			
		||||
import { citiesFile } from 'src/constants';
 | 
			
		||||
import { DB, GeodataPlaces, NaturalearthCountries } from 'src/db';
 | 
			
		||||
import { DummyValue, GenerateSql } from 'src/decorators';
 | 
			
		||||
import { AssetVisibility, SystemMetadataKey } from 'src/enum';
 | 
			
		||||
import { ConfigRepository } from 'src/repositories/config.repository';
 | 
			
		||||
import { LoggingRepository } from 'src/repositories/logging.repository';
 | 
			
		||||
import { SystemMetadataRepository } from 'src/repositories/system-metadata.repository';
 | 
			
		||||
import { DB } from 'src/schema';
 | 
			
		||||
import { GeodataPlacesTable } from 'src/schema/tables/geodata-places.table';
 | 
			
		||||
import { NaturalEarthCountriesTable } from 'src/schema/tables/natural-earth-countries.table';
 | 
			
		||||
 | 
			
		||||
export interface MapMarkerSearchOptions {
 | 
			
		||||
  isArchived?: boolean;
 | 
			
		||||
@ -38,8 +40,8 @@ export interface MapMarker extends ReverseGeocodeResult {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface MapDB extends DB {
 | 
			
		||||
  geodata_places_tmp: GeodataPlaces;
 | 
			
		||||
  naturalearth_countries_tmp: NaturalearthCountries;
 | 
			
		||||
  geodata_places_tmp: GeodataPlacesTable;
 | 
			
		||||
  naturalearth_countries_tmp: NaturalEarthCountriesTable;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Injectable()
 | 
			
		||||
@ -193,11 +195,11 @@ export class MapRepository {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const entities: Insertable<NaturalearthCountries>[] = [];
 | 
			
		||||
    const entities: Insertable<NaturalEarthCountriesTable>[] = [];
 | 
			
		||||
    for (const feature of geoJSONData.features) {
 | 
			
		||||
      for (const entry of feature.geometry.coordinates) {
 | 
			
		||||
        const coordinates: number[][][] = feature.geometry.type === 'MultiPolygon' ? entry[0] : entry;
 | 
			
		||||
        const featureRecord: Insertable<NaturalearthCountries> = {
 | 
			
		||||
        const featureRecord: Insertable<NaturalEarthCountriesTable> = {
 | 
			
		||||
          admin: feature.properties.ADMIN,
 | 
			
		||||
          admin_a3: feature.properties.ADM0_A3,
 | 
			
		||||
          type: feature.properties.TYPE,
 | 
			
		||||
 | 
			
		||||
@ -3,10 +3,11 @@ import { Insertable, Kysely, sql, Updateable } from 'kysely';
 | 
			
		||||
import { jsonArrayFrom } from 'kysely/helpers/postgres';
 | 
			
		||||
import { DateTime } from 'luxon';
 | 
			
		||||
import { InjectKysely } from 'nestjs-kysely';
 | 
			
		||||
import { DB, Memories } from 'src/db';
 | 
			
		||||
import { Chunked, ChunkedSet, DummyValue, GenerateSql } from 'src/decorators';
 | 
			
		||||
import { MemorySearchDto } from 'src/dtos/memory.dto';
 | 
			
		||||
import { AssetVisibility } from 'src/enum';
 | 
			
		||||
import { DB } from 'src/schema';
 | 
			
		||||
import { MemoryTable } from 'src/schema/tables/memory.table';
 | 
			
		||||
import { IBulkAsset } from 'src/types';
 | 
			
		||||
 | 
			
		||||
@Injectable()
 | 
			
		||||
@ -80,7 +81,7 @@ export class MemoryRepository implements IBulkAsset {
 | 
			
		||||
    return this.getByIdBuilder(id).executeTakeFirst();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async create(memory: Insertable<Memories>, assetIds: Set<string>) {
 | 
			
		||||
  async create(memory: Insertable<MemoryTable>, assetIds: Set<string>) {
 | 
			
		||||
    const id = await this.db.transaction().execute(async (tx) => {
 | 
			
		||||
      const { id } = await tx.insertInto('memories').values(memory).returning('id').executeTakeFirstOrThrow();
 | 
			
		||||
 | 
			
		||||
@ -96,7 +97,7 @@ export class MemoryRepository implements IBulkAsset {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @GenerateSql({ params: [DummyValue.UUID, { ownerId: DummyValue.UUID, isSaved: true }] })
 | 
			
		||||
  async update(id: string, memory: Updateable<Memories>) {
 | 
			
		||||
  async update(id: string, memory: Updateable<MemoryTable>) {
 | 
			
		||||
    await this.db.updateTable('memories').set(memory).where('id', '=', id).execute();
 | 
			
		||||
    return this.getByIdBuilder(id).executeTakeFirstOrThrow();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -1,15 +1,16 @@
 | 
			
		||||
import { Injectable } from '@nestjs/common';
 | 
			
		||||
import { Insertable, Kysely, sql, Updateable } from 'kysely';
 | 
			
		||||
import { InjectKysely } from 'nestjs-kysely';
 | 
			
		||||
import { DB, MoveHistory } from 'src/db';
 | 
			
		||||
import { DummyValue, GenerateSql } from 'src/decorators';
 | 
			
		||||
import { AssetPathType, PathType } from 'src/enum';
 | 
			
		||||
import { DB } from 'src/schema';
 | 
			
		||||
import { MoveTable } from 'src/schema/tables/move.table';
 | 
			
		||||
 | 
			
		||||
@Injectable()
 | 
			
		||||
export class MoveRepository {
 | 
			
		||||
  constructor(@InjectKysely() private db: Kysely<DB>) {}
 | 
			
		||||
 | 
			
		||||
  create(entity: Insertable<MoveHistory>) {
 | 
			
		||||
  create(entity: Insertable<MoveTable>) {
 | 
			
		||||
    return this.db.insertInto('move_history').values(entity).returningAll().executeTakeFirstOrThrow();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -23,7 +24,7 @@ export class MoveRepository {
 | 
			
		||||
      .executeTakeFirst();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  update(id: string, entity: Updateable<MoveHistory>) {
 | 
			
		||||
  update(id: string, entity: Updateable<MoveTable>) {
 | 
			
		||||
    return this.db
 | 
			
		||||
      .updateTable('move_history')
 | 
			
		||||
      .set(entity)
 | 
			
		||||
 | 
			
		||||
@ -2,9 +2,10 @@ import { Insertable, Kysely, Updateable } from 'kysely';
 | 
			
		||||
import { DateTime } from 'luxon';
 | 
			
		||||
import { InjectKysely } from 'nestjs-kysely';
 | 
			
		||||
import { columns } from 'src/database';
 | 
			
		||||
import { DB, Notifications } from 'src/db';
 | 
			
		||||
import { DummyValue, GenerateSql } from 'src/decorators';
 | 
			
		||||
import { NotificationSearchDto } from 'src/dtos/notification.dto';
 | 
			
		||||
import { DB } from 'src/schema';
 | 
			
		||||
import { NotificationTable } from 'src/schema/tables/notification.table';
 | 
			
		||||
 | 
			
		||||
export class NotificationRepository {
 | 
			
		||||
  constructor(@InjectKysely() private db: Kysely<DB>) {}
 | 
			
		||||
@ -53,7 +54,7 @@ export class NotificationRepository {
 | 
			
		||||
      .execute();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  create(notification: Insertable<Notifications>) {
 | 
			
		||||
  create(notification: Insertable<NotificationTable>) {
 | 
			
		||||
    return this.db
 | 
			
		||||
      .insertInto('notifications')
 | 
			
		||||
      .values(notification)
 | 
			
		||||
@ -70,7 +71,7 @@ export class NotificationRepository {
 | 
			
		||||
      .executeTakeFirst();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  update(id: string, notification: Updateable<Notifications>) {
 | 
			
		||||
  update(id: string, notification: Updateable<NotificationTable>) {
 | 
			
		||||
    return this.db
 | 
			
		||||
      .updateTable('notifications')
 | 
			
		||||
      .set(notification)
 | 
			
		||||
@ -80,7 +81,7 @@ export class NotificationRepository {
 | 
			
		||||
      .executeTakeFirstOrThrow();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async updateAll(ids: string[], notification: Updateable<Notifications>) {
 | 
			
		||||
  async updateAll(ids: string[], notification: Updateable<NotificationTable>) {
 | 
			
		||||
    await this.db.updateTable('notifications').set(notification).where('id', 'in', ids).execute();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -3,8 +3,9 @@ import { ExpressionBuilder, Insertable, Kysely, NotNull, Updateable } from 'kyse
 | 
			
		||||
import { jsonObjectFrom } from 'kysely/helpers/postgres';
 | 
			
		||||
import { InjectKysely } from 'nestjs-kysely';
 | 
			
		||||
import { columns } from 'src/database';
 | 
			
		||||
import { DB, Partners } from 'src/db';
 | 
			
		||||
import { DummyValue, GenerateSql } from 'src/decorators';
 | 
			
		||||
import { DB } from 'src/schema';
 | 
			
		||||
import { PartnerTable } from 'src/schema/tables/partner.table';
 | 
			
		||||
 | 
			
		||||
export interface PartnerIds {
 | 
			
		||||
  sharedById: string;
 | 
			
		||||
@ -47,7 +48,7 @@ export class PartnerRepository {
 | 
			
		||||
      .executeTakeFirst();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  create(values: Insertable<Partners>) {
 | 
			
		||||
  create(values: Insertable<PartnerTable>) {
 | 
			
		||||
    return this.db
 | 
			
		||||
      .insertInto('partners')
 | 
			
		||||
      .values(values)
 | 
			
		||||
@ -59,7 +60,7 @@ export class PartnerRepository {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @GenerateSql({ params: [{ sharedWithId: DummyValue.UUID, sharedById: DummyValue.UUID }, { inTimeline: true }] })
 | 
			
		||||
  update({ sharedWithId, sharedById }: PartnerIds, values: Updateable<Partners>) {
 | 
			
		||||
  update({ sharedWithId, sharedById }: PartnerIds, values: Updateable<PartnerTable>) {
 | 
			
		||||
    return this.db
 | 
			
		||||
      .updateTable('partners')
 | 
			
		||||
      .set(values)
 | 
			
		||||
 | 
			
		||||
@ -2,9 +2,12 @@ import { Injectable } from '@nestjs/common';
 | 
			
		||||
import { ExpressionBuilder, Insertable, Kysely, Selectable, sql, Updateable } from 'kysely';
 | 
			
		||||
import { jsonObjectFrom } from 'kysely/helpers/postgres';
 | 
			
		||||
import { InjectKysely } from 'nestjs-kysely';
 | 
			
		||||
import { AssetFaces, DB, FaceSearch, Person } from 'src/db';
 | 
			
		||||
import { Chunked, ChunkedArray, DummyValue, GenerateSql } from 'src/decorators';
 | 
			
		||||
import { AssetFileType, AssetVisibility, SourceType } from 'src/enum';
 | 
			
		||||
import { DB } from 'src/schema';
 | 
			
		||||
import { AssetFaceTable } from 'src/schema/tables/asset-face.table';
 | 
			
		||||
import { FaceSearchTable } from 'src/schema/tables/face-search.table';
 | 
			
		||||
import { PersonTable } from 'src/schema/tables/person.table';
 | 
			
		||||
import { removeUndefinedKeys } from 'src/utils/database';
 | 
			
		||||
import { paginationHelper, PaginationOptions } from 'src/utils/pagination';
 | 
			
		||||
 | 
			
		||||
@ -57,7 +60,7 @@ export interface GetAllFacesOptions {
 | 
			
		||||
 | 
			
		||||
export type UnassignFacesOptions = DeleteFacesOptions;
 | 
			
		||||
 | 
			
		||||
export type SelectFaceOptions = (keyof Selectable<AssetFaces>)[];
 | 
			
		||||
export type SelectFaceOptions = (keyof Selectable<AssetFaceTable>)[];
 | 
			
		||||
 | 
			
		||||
const withPerson = (eb: ExpressionBuilder<DB, 'asset_faces'>) => {
 | 
			
		||||
  return jsonObjectFrom(
 | 
			
		||||
@ -378,11 +381,11 @@ export class PersonRepository {
 | 
			
		||||
      .executeTakeFirstOrThrow();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  create(person: Insertable<Person>) {
 | 
			
		||||
  create(person: Insertable<PersonTable>) {
 | 
			
		||||
    return this.db.insertInto('person').values(person).returningAll().executeTakeFirstOrThrow();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async createAll(people: Insertable<Person>[]): Promise<string[]> {
 | 
			
		||||
  async createAll(people: Insertable<PersonTable>[]): Promise<string[]> {
 | 
			
		||||
    if (people.length === 0) {
 | 
			
		||||
      return [];
 | 
			
		||||
    }
 | 
			
		||||
@ -393,9 +396,9 @@ export class PersonRepository {
 | 
			
		||||
 | 
			
		||||
  @GenerateSql({ params: [[], [], [{ faceId: DummyValue.UUID, embedding: DummyValue.VECTOR }]] })
 | 
			
		||||
  async refreshFaces(
 | 
			
		||||
    facesToAdd: (Insertable<AssetFaces> & { assetId: string })[],
 | 
			
		||||
    facesToAdd: (Insertable<AssetFaceTable> & { assetId: string })[],
 | 
			
		||||
    faceIdsToRemove: string[],
 | 
			
		||||
    embeddingsToAdd?: Insertable<FaceSearch>[],
 | 
			
		||||
    embeddingsToAdd?: Insertable<FaceSearchTable>[],
 | 
			
		||||
  ): Promise<void> {
 | 
			
		||||
    let query = this.db;
 | 
			
		||||
    if (facesToAdd.length > 0) {
 | 
			
		||||
@ -415,7 +418,7 @@ export class PersonRepository {
 | 
			
		||||
    await query.selectFrom(sql`(select 1)`.as('dummy')).execute();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async update(person: Updateable<Person> & { id: string }) {
 | 
			
		||||
  async update(person: Updateable<PersonTable> & { id: string }) {
 | 
			
		||||
    return this.db
 | 
			
		||||
      .updateTable('person')
 | 
			
		||||
      .set(person)
 | 
			
		||||
@ -424,7 +427,7 @@ export class PersonRepository {
 | 
			
		||||
      .executeTakeFirstOrThrow();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async updateAll(people: Insertable<Person>[]): Promise<void> {
 | 
			
		||||
  async updateAll(people: Insertable<PersonTable>[]): Promise<void> {
 | 
			
		||||
    if (people.length === 0) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
@ -496,7 +499,7 @@ export class PersonRepository {
 | 
			
		||||
    return result?.latestDate;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async createAssetFace(face: Insertable<AssetFaces>): Promise<void> {
 | 
			
		||||
  async createAssetFace(face: Insertable<AssetFaceTable>): Promise<void> {
 | 
			
		||||
    await this.db.insertInto('asset_faces').values(face).execute();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -2,11 +2,12 @@ import { Injectable } from '@nestjs/common';
 | 
			
		||||
import { Kysely, OrderByDirection, Selectable, sql } from 'kysely';
 | 
			
		||||
import { InjectKysely } from 'nestjs-kysely';
 | 
			
		||||
import { randomUUID } from 'node:crypto';
 | 
			
		||||
import { DB, Exif } from 'src/db';
 | 
			
		||||
import { DummyValue, GenerateSql } from 'src/decorators';
 | 
			
		||||
import { MapAsset } from 'src/dtos/asset-response.dto';
 | 
			
		||||
import { AssetStatus, AssetType, AssetVisibility, VectorIndex } from 'src/enum';
 | 
			
		||||
import { probes } from 'src/repositories/database.repository';
 | 
			
		||||
import { DB } from 'src/schema';
 | 
			
		||||
import { ExifTable } from 'src/schema/tables/exif.table';
 | 
			
		||||
import { anyUuid, searchAssetBuilder } from 'src/utils/database';
 | 
			
		||||
import { paginationHelper } from 'src/utils/pagination';
 | 
			
		||||
import { isValidInteger } from 'src/validation';
 | 
			
		||||
@ -385,7 +386,7 @@ export class SearchRepository {
 | 
			
		||||
      .select((eb) =>
 | 
			
		||||
        eb
 | 
			
		||||
          .fn('to_jsonb', [eb.table('exif')])
 | 
			
		||||
          .$castTo<Selectable<Exif>>()
 | 
			
		||||
          .$castTo<Selectable<ExifTable>>()
 | 
			
		||||
          .as('exifInfo'),
 | 
			
		||||
      )
 | 
			
		||||
      .orderBy('exif.city')
 | 
			
		||||
 | 
			
		||||
@ -4,8 +4,9 @@ import { jsonObjectFrom } from 'kysely/helpers/postgres';
 | 
			
		||||
import { DateTime } from 'luxon';
 | 
			
		||||
import { InjectKysely } from 'nestjs-kysely';
 | 
			
		||||
import { columns } from 'src/database';
 | 
			
		||||
import { DB, Sessions } from 'src/db';
 | 
			
		||||
import { DummyValue, GenerateSql } from 'src/decorators';
 | 
			
		||||
import { DB } from 'src/schema';
 | 
			
		||||
import { SessionTable } from 'src/schema/tables/session.table';
 | 
			
		||||
import { asUuid } from 'src/utils/database';
 | 
			
		||||
 | 
			
		||||
export type SessionSearchOptions = { updatedBefore: Date };
 | 
			
		||||
@ -72,11 +73,11 @@ export class SessionRepository {
 | 
			
		||||
      .execute();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  create(dto: Insertable<Sessions>) {
 | 
			
		||||
  create(dto: Insertable<SessionTable>) {
 | 
			
		||||
    return this.db.insertInto('sessions').values(dto).returningAll().executeTakeFirstOrThrow();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  update(id: string, dto: Updateable<Sessions>) {
 | 
			
		||||
  update(id: string, dto: Updateable<SessionTable>) {
 | 
			
		||||
    return this.db
 | 
			
		||||
      .updateTable('sessions')
 | 
			
		||||
      .set(dto)
 | 
			
		||||
 | 
			
		||||
@ -4,10 +4,11 @@ import { jsonObjectFrom } from 'kysely/helpers/postgres';
 | 
			
		||||
import _ from 'lodash';
 | 
			
		||||
import { InjectKysely } from 'nestjs-kysely';
 | 
			
		||||
import { Album, columns } from 'src/database';
 | 
			
		||||
import { DB, SharedLinks } from 'src/db';
 | 
			
		||||
import { DummyValue, GenerateSql } from 'src/decorators';
 | 
			
		||||
import { MapAsset } from 'src/dtos/asset-response.dto';
 | 
			
		||||
import { SharedLinkType } from 'src/enum';
 | 
			
		||||
import { DB } from 'src/schema';
 | 
			
		||||
import { SharedLinkTable } from 'src/schema/tables/shared-link.table';
 | 
			
		||||
 | 
			
		||||
export type SharedLinkSearchOptions = {
 | 
			
		||||
  userId: string;
 | 
			
		||||
@ -183,7 +184,7 @@ export class SharedLinkRepository {
 | 
			
		||||
      .executeTakeFirst();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async create(entity: Insertable<SharedLinks> & { assetIds?: string[] }) {
 | 
			
		||||
  async create(entity: Insertable<SharedLinkTable> & { assetIds?: string[] }) {
 | 
			
		||||
    const { id } = await this.db
 | 
			
		||||
      .insertInto('shared_links')
 | 
			
		||||
      .values(_.omit(entity, 'assetIds'))
 | 
			
		||||
@ -200,7 +201,7 @@ export class SharedLinkRepository {
 | 
			
		||||
    return this.getSharedLinks(id);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async update(entity: Updateable<SharedLinks> & { id: string; assetIds?: string[] }) {
 | 
			
		||||
  async update(entity: Updateable<SharedLinkTable> & { id: string; assetIds?: string[] }) {
 | 
			
		||||
    const { id } = await this.db
 | 
			
		||||
      .updateTable('shared_links')
 | 
			
		||||
      .set(_.omit(entity, 'assets', 'album', 'assetIds'))
 | 
			
		||||
 | 
			
		||||
@ -3,8 +3,9 @@ import { ExpressionBuilder, Kysely, Updateable } from 'kysely';
 | 
			
		||||
import { jsonArrayFrom } from 'kysely/helpers/postgres';
 | 
			
		||||
import { InjectKysely } from 'nestjs-kysely';
 | 
			
		||||
import { columns } from 'src/database';
 | 
			
		||||
import { AssetStack, DB } from 'src/db';
 | 
			
		||||
import { DummyValue, GenerateSql } from 'src/decorators';
 | 
			
		||||
import { DB } from 'src/schema';
 | 
			
		||||
import { StackTable } from 'src/schema/tables/stack.table';
 | 
			
		||||
import { asUuid, withDefaultVisibility } from 'src/utils/database';
 | 
			
		||||
 | 
			
		||||
export interface StackSearch {
 | 
			
		||||
@ -130,7 +131,7 @@ export class StackRepository {
 | 
			
		||||
    await this.db.deleteFrom('asset_stack').where('id', 'in', ids).execute();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  update(id: string, entity: Updateable<AssetStack>) {
 | 
			
		||||
  update(id: string, entity: Updateable<StackTable>) {
 | 
			
		||||
    return this.db
 | 
			
		||||
      .updateTable('asset_stack')
 | 
			
		||||
      .set(entity)
 | 
			
		||||
 | 
			
		||||
@ -1,9 +1,10 @@
 | 
			
		||||
import { Injectable } from '@nestjs/common';
 | 
			
		||||
import { Insertable, Kysely } from 'kysely';
 | 
			
		||||
import { InjectKysely } from 'nestjs-kysely';
 | 
			
		||||
import { DB, SessionSyncCheckpoints } from 'src/db';
 | 
			
		||||
import { DummyValue, GenerateSql } from 'src/decorators';
 | 
			
		||||
import { SyncEntityType } from 'src/enum';
 | 
			
		||||
import { DB } from 'src/schema';
 | 
			
		||||
import { SessionSyncCheckpointTable } from 'src/schema/tables/sync-checkpoint.table';
 | 
			
		||||
 | 
			
		||||
@Injectable()
 | 
			
		||||
export class SyncCheckpointRepository {
 | 
			
		||||
@ -18,7 +19,7 @@ export class SyncCheckpointRepository {
 | 
			
		||||
      .execute();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  upsertAll(items: Insertable<SessionSyncCheckpoints>[]) {
 | 
			
		||||
  upsertAll(items: Insertable<SessionSyncCheckpointTable>[]) {
 | 
			
		||||
    return this.db
 | 
			
		||||
      .insertInto('session_sync_checkpoints')
 | 
			
		||||
      .values(items)
 | 
			
		||||
 | 
			
		||||
@ -2,8 +2,8 @@ import { Injectable } from '@nestjs/common';
 | 
			
		||||
import { Kysely, SelectQueryBuilder, sql } from 'kysely';
 | 
			
		||||
import { InjectKysely } from 'nestjs-kysely';
 | 
			
		||||
import { columns } from 'src/database';
 | 
			
		||||
import { DB } from 'src/db';
 | 
			
		||||
import { DummyValue, GenerateSql } from 'src/decorators';
 | 
			
		||||
import { DB } from 'src/schema';
 | 
			
		||||
import { SyncAck } from 'src/types';
 | 
			
		||||
 | 
			
		||||
type AuditTables =
 | 
			
		||||
 | 
			
		||||
@ -2,11 +2,12 @@ import { Injectable } from '@nestjs/common';
 | 
			
		||||
import { Insertable, Kysely } from 'kysely';
 | 
			
		||||
import { InjectKysely } from 'nestjs-kysely';
 | 
			
		||||
import { readFile } from 'node:fs/promises';
 | 
			
		||||
import { DB, SystemMetadata as DbSystemMetadata } from 'src/db';
 | 
			
		||||
import { GenerateSql } from 'src/decorators';
 | 
			
		||||
import { DB } from 'src/schema';
 | 
			
		||||
import { SystemMetadataTable } from 'src/schema/tables/system-metadata.table';
 | 
			
		||||
import { SystemMetadata } from 'src/types';
 | 
			
		||||
 | 
			
		||||
type Upsert = Insertable<DbSystemMetadata>;
 | 
			
		||||
type Upsert = Insertable<SystemMetadataTable>;
 | 
			
		||||
 | 
			
		||||
@Injectable()
 | 
			
		||||
export class SystemMetadataRepository {
 | 
			
		||||
 | 
			
		||||
@ -2,9 +2,11 @@ import { Injectable } from '@nestjs/common';
 | 
			
		||||
import { Insertable, Kysely, sql, Updateable } from 'kysely';
 | 
			
		||||
import { InjectKysely } from 'nestjs-kysely';
 | 
			
		||||
import { columns } from 'src/database';
 | 
			
		||||
import { DB, TagAsset, Tags } from 'src/db';
 | 
			
		||||
import { Chunked, ChunkedSet, DummyValue, GenerateSql } from 'src/decorators';
 | 
			
		||||
import { LoggingRepository } from 'src/repositories/logging.repository';
 | 
			
		||||
import { DB } from 'src/schema';
 | 
			
		||||
import { TagAssetTable } from 'src/schema/tables/tag-asset.table';
 | 
			
		||||
import { TagTable } from 'src/schema/tables/tag.table';
 | 
			
		||||
 | 
			
		||||
@Injectable()
 | 
			
		||||
export class TagRepository {
 | 
			
		||||
@ -72,12 +74,12 @@ export class TagRepository {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @GenerateSql({ params: [{ userId: DummyValue.UUID, color: DummyValue.STRING, value: DummyValue.STRING }] })
 | 
			
		||||
  create(tag: Insertable<Tags>) {
 | 
			
		||||
  create(tag: Insertable<TagTable>) {
 | 
			
		||||
    return this.db.insertInto('tags').values(tag).returningAll().executeTakeFirstOrThrow();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @GenerateSql({ params: [DummyValue.UUID, { color: DummyValue.STRING }] })
 | 
			
		||||
  update(id: string, dto: Updateable<Tags>) {
 | 
			
		||||
  update(id: string, dto: Updateable<TagTable>) {
 | 
			
		||||
    return this.db.updateTable('tags').set(dto).where('id', '=', id).returningAll().executeTakeFirstOrThrow();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -128,7 +130,7 @@ export class TagRepository {
 | 
			
		||||
 | 
			
		||||
  @GenerateSql({ params: [[{ assetId: DummyValue.UUID, tagsIds: [DummyValue.UUID] }]] })
 | 
			
		||||
  @Chunked()
 | 
			
		||||
  upsertAssetIds(items: Insertable<TagAsset>[]) {
 | 
			
		||||
  upsertAssetIds(items: Insertable<TagAssetTable>[]) {
 | 
			
		||||
    if (items.length === 0) {
 | 
			
		||||
      return Promise.resolve([]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -1,8 +1,8 @@
 | 
			
		||||
import { Kysely } from 'kysely';
 | 
			
		||||
import { InjectKysely } from 'nestjs-kysely';
 | 
			
		||||
import { DB } from 'src/db';
 | 
			
		||||
import { DummyValue, GenerateSql } from 'src/decorators';
 | 
			
		||||
import { AssetStatus } from 'src/enum';
 | 
			
		||||
import { DB } from 'src/schema';
 | 
			
		||||
 | 
			
		||||
export class TrashRepository {
 | 
			
		||||
  constructor(@InjectKysely() private db: Kysely<DB>) {}
 | 
			
		||||
 | 
			
		||||
@ -4,14 +4,15 @@ import { jsonArrayFrom } from 'kysely/helpers/postgres';
 | 
			
		||||
import { DateTime } from 'luxon';
 | 
			
		||||
import { InjectKysely } from 'nestjs-kysely';
 | 
			
		||||
import { columns } from 'src/database';
 | 
			
		||||
import { DB, UserMetadata as DbUserMetadata } from 'src/db';
 | 
			
		||||
import { DummyValue, GenerateSql } from 'src/decorators';
 | 
			
		||||
import { AssetType, AssetVisibility, UserStatus } from 'src/enum';
 | 
			
		||||
import { DB } from 'src/schema';
 | 
			
		||||
import { UserMetadataTable } from 'src/schema/tables/user-metadata.table';
 | 
			
		||||
import { UserTable } from 'src/schema/tables/user.table';
 | 
			
		||||
import { UserMetadata, UserMetadataItem } from 'src/types';
 | 
			
		||||
import { asUuid } from 'src/utils/database';
 | 
			
		||||
 | 
			
		||||
type Upsert = Insertable<DbUserMetadata>;
 | 
			
		||||
type Upsert = Insertable<UserMetadataTable>;
 | 
			
		||||
 | 
			
		||||
export interface UserListFilter {
 | 
			
		||||
  id?: string;
 | 
			
		||||
 | 
			
		||||
@ -1,8 +1,9 @@
 | 
			
		||||
import { Injectable } from '@nestjs/common';
 | 
			
		||||
import { Insertable, Kysely } from 'kysely';
 | 
			
		||||
import { InjectKysely } from 'nestjs-kysely';
 | 
			
		||||
import { DB, VersionHistory } from 'src/db';
 | 
			
		||||
import { GenerateSql } from 'src/decorators';
 | 
			
		||||
import { DB } from 'src/schema';
 | 
			
		||||
import { VersionHistoryTable } from 'src/schema/tables/version-history.table';
 | 
			
		||||
 | 
			
		||||
@Injectable()
 | 
			
		||||
export class VersionHistoryRepository {
 | 
			
		||||
@ -18,7 +19,7 @@ export class VersionHistoryRepository {
 | 
			
		||||
    return this.db.selectFrom('version_history').selectAll().orderBy('createdAt', 'desc').executeTakeFirst();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  create(version: Insertable<VersionHistory>) {
 | 
			
		||||
  create(version: Insertable<VersionHistoryTable>) {
 | 
			
		||||
    return this.db.insertInto('version_history').values(version).returningAll().executeTakeFirstOrThrow();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,8 +1,8 @@
 | 
			
		||||
import { Kysely } from 'kysely';
 | 
			
		||||
import { InjectKysely } from 'nestjs-kysely';
 | 
			
		||||
import { DB } from 'src/db';
 | 
			
		||||
import { DummyValue, GenerateSql } from 'src/decorators';
 | 
			
		||||
import { AssetVisibility } from 'src/enum';
 | 
			
		||||
import { DB } from 'src/schema';
 | 
			
		||||
import { asUuid, withExif } from 'src/utils/database';
 | 
			
		||||
 | 
			
		||||
export class ViewRepository {
 | 
			
		||||
 | 
			
		||||
@ -21,7 +21,7 @@ import { AlbumAuditTable } from 'src/schema/tables/album-audit.table';
 | 
			
		||||
import { AlbumUserAuditTable } from 'src/schema/tables/album-user-audit.table';
 | 
			
		||||
import { AlbumUserTable } from 'src/schema/tables/album-user.table';
 | 
			
		||||
import { AlbumTable } from 'src/schema/tables/album.table';
 | 
			
		||||
import { APIKeyTable } from 'src/schema/tables/api-key.table';
 | 
			
		||||
import { ApiKeyTable } from 'src/schema/tables/api-key.table';
 | 
			
		||||
import { AssetAuditTable } from 'src/schema/tables/asset-audit.table';
 | 
			
		||||
import { AssetFaceTable } from 'src/schema/tables/asset-face.table';
 | 
			
		||||
import { AssetFileTable } from 'src/schema/tables/asset-files.table';
 | 
			
		||||
@ -51,11 +51,12 @@ import { SessionSyncCheckpointTable } from 'src/schema/tables/sync-checkpoint.ta
 | 
			
		||||
import { SystemMetadataTable } from 'src/schema/tables/system-metadata.table';
 | 
			
		||||
import { TagAssetTable } from 'src/schema/tables/tag-asset.table';
 | 
			
		||||
import { TagClosureTable } from 'src/schema/tables/tag-closure.table';
 | 
			
		||||
import { TagTable } from 'src/schema/tables/tag.table';
 | 
			
		||||
import { UserAuditTable } from 'src/schema/tables/user-audit.table';
 | 
			
		||||
import { UserMetadataTable } from 'src/schema/tables/user-metadata.table';
 | 
			
		||||
import { UserTable } from 'src/schema/tables/user.table';
 | 
			
		||||
import { VersionHistoryTable } from 'src/schema/tables/version-history.table';
 | 
			
		||||
import { Database, Extensions } from 'src/sql-tools';
 | 
			
		||||
import { Database, Extensions, Generated, Int8 } from 'src/sql-tools';
 | 
			
		||||
 | 
			
		||||
@Extensions(['uuid-ossp', 'unaccent', 'cube', 'earthdistance', 'pg_trgm', 'plpgsql'])
 | 
			
		||||
@Database({ name: 'immich' })
 | 
			
		||||
@ -68,7 +69,7 @@ export class ImmichDatabase {
 | 
			
		||||
    AlbumUserAuditTable,
 | 
			
		||||
    AlbumUserTable,
 | 
			
		||||
    AlbumTable,
 | 
			
		||||
    APIKeyTable,
 | 
			
		||||
    ApiKeyTable,
 | 
			
		||||
    AssetAuditTable,
 | 
			
		||||
    AssetFaceTable,
 | 
			
		||||
    AssetJobStatusTable,
 | 
			
		||||
@ -96,6 +97,7 @@ export class ImmichDatabase {
 | 
			
		||||
    StackTable,
 | 
			
		||||
    SessionSyncCheckpointTable,
 | 
			
		||||
    SystemMetadataTable,
 | 
			
		||||
    TagTable,
 | 
			
		||||
    TagAssetTable,
 | 
			
		||||
    TagClosureTable,
 | 
			
		||||
    UserAuditTable,
 | 
			
		||||
@ -122,3 +124,55 @@ export class ImmichDatabase {
 | 
			
		||||
 | 
			
		||||
  enum = [assets_status_enum, asset_face_source_type, asset_visibility_enum];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface Migrations {
 | 
			
		||||
  id: Generated<number>;
 | 
			
		||||
  name: string;
 | 
			
		||||
  timestamp: Int8;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface DB {
 | 
			
		||||
  activity: ActivityTable;
 | 
			
		||||
  albums: AlbumTable;
 | 
			
		||||
  albums_audit: AlbumAuditTable;
 | 
			
		||||
  albums_assets_assets: AlbumAssetTable;
 | 
			
		||||
  album_assets_audit: AlbumAssetAuditTable;
 | 
			
		||||
  albums_shared_users_users: AlbumUserTable;
 | 
			
		||||
  album_users_audit: AlbumUserAuditTable;
 | 
			
		||||
  api_keys: ApiKeyTable;
 | 
			
		||||
  asset_faces: AssetFaceTable;
 | 
			
		||||
  asset_files: AssetFileTable;
 | 
			
		||||
  asset_job_status: AssetJobStatusTable;
 | 
			
		||||
  asset_stack: StackTable;
 | 
			
		||||
  assets: AssetTable;
 | 
			
		||||
  assets_audit: AssetAuditTable;
 | 
			
		||||
  audit: AuditTable;
 | 
			
		||||
  exif: ExifTable;
 | 
			
		||||
  face_search: FaceSearchTable;
 | 
			
		||||
  geodata_places: GeodataPlacesTable;
 | 
			
		||||
  libraries: LibraryTable;
 | 
			
		||||
  memories: MemoryTable;
 | 
			
		||||
  memories_audit: MemoryAuditTable;
 | 
			
		||||
  memories_assets_assets: MemoryAssetTable;
 | 
			
		||||
  memory_assets_audit: MemoryAssetAuditTable;
 | 
			
		||||
  migrations: Migrations;
 | 
			
		||||
  notifications: NotificationTable;
 | 
			
		||||
  move_history: MoveTable;
 | 
			
		||||
  naturalearth_countries: NaturalEarthCountriesTable;
 | 
			
		||||
  partners_audit: PartnerAuditTable;
 | 
			
		||||
  partners: PartnerTable;
 | 
			
		||||
  person: PersonTable;
 | 
			
		||||
  sessions: SessionTable;
 | 
			
		||||
  session_sync_checkpoints: SessionSyncCheckpointTable;
 | 
			
		||||
  shared_link__asset: SharedLinkAssetTable;
 | 
			
		||||
  shared_links: SharedLinkTable;
 | 
			
		||||
  smart_search: SmartSearchTable;
 | 
			
		||||
  system_metadata: SystemMetadataTable;
 | 
			
		||||
  tag_asset: TagAssetTable;
 | 
			
		||||
  tags: TagTable;
 | 
			
		||||
  tags_closure: TagClosureTable;
 | 
			
		||||
  user_metadata: UserMetadataTable;
 | 
			
		||||
  users: UserTable;
 | 
			
		||||
  users_audit: UserAuditTable;
 | 
			
		||||
  version_history: VersionHistoryTable;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -7,9 +7,11 @@ import {
 | 
			
		||||
  Column,
 | 
			
		||||
  CreateDateColumn,
 | 
			
		||||
  ForeignKeyColumn,
 | 
			
		||||
  Generated,
 | 
			
		||||
  Index,
 | 
			
		||||
  PrimaryGeneratedColumn,
 | 
			
		||||
  Table,
 | 
			
		||||
  Timestamp,
 | 
			
		||||
  UpdateDateColumn,
 | 
			
		||||
} from 'src/sql-tools';
 | 
			
		||||
 | 
			
		||||
@ -27,13 +29,13 @@ import {
 | 
			
		||||
})
 | 
			
		||||
export class ActivityTable {
 | 
			
		||||
  @PrimaryGeneratedColumn()
 | 
			
		||||
  id!: string;
 | 
			
		||||
  id!: Generated<string>;
 | 
			
		||||
 | 
			
		||||
  @CreateDateColumn()
 | 
			
		||||
  createdAt!: Date;
 | 
			
		||||
  createdAt!: Generated<Timestamp>;
 | 
			
		||||
 | 
			
		||||
  @UpdateDateColumn()
 | 
			
		||||
  updatedAt!: Date;
 | 
			
		||||
  updatedAt!: Generated<Timestamp>;
 | 
			
		||||
 | 
			
		||||
  @ForeignKeyColumn(() => AlbumTable, { onDelete: 'CASCADE', onUpdate: 'CASCADE' })
 | 
			
		||||
  albumId!: string;
 | 
			
		||||
@ -48,8 +50,8 @@ export class ActivityTable {
 | 
			
		||||
  comment!: string | null;
 | 
			
		||||
 | 
			
		||||
  @Column({ type: 'boolean', default: false })
 | 
			
		||||
  isLiked!: boolean;
 | 
			
		||||
  isLiked!: Generated<boolean>;
 | 
			
		||||
 | 
			
		||||
  @UpdateIdColumn({ indexName: 'IDX_activity_update_id' })
 | 
			
		||||
  updateId!: string;
 | 
			
		||||
  updateId!: Generated<string>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,11 +1,11 @@
 | 
			
		||||
import { PrimaryGeneratedUuidV7Column } from 'src/decorators';
 | 
			
		||||
import { AlbumTable } from 'src/schema/tables/album.table';
 | 
			
		||||
import { Column, CreateDateColumn, ForeignKeyColumn, Table } from 'src/sql-tools';
 | 
			
		||||
import { Column, CreateDateColumn, ForeignKeyColumn, Generated, Table, Timestamp } from 'src/sql-tools';
 | 
			
		||||
 | 
			
		||||
@Table('album_assets_audit')
 | 
			
		||||
export class AlbumAssetAuditTable {
 | 
			
		||||
  @PrimaryGeneratedUuidV7Column()
 | 
			
		||||
  id!: string;
 | 
			
		||||
  id!: Generated<string>;
 | 
			
		||||
 | 
			
		||||
  @ForeignKeyColumn(() => AlbumTable, {
 | 
			
		||||
    type: 'uuid',
 | 
			
		||||
@ -19,5 +19,5 @@ export class AlbumAssetAuditTable {
 | 
			
		||||
  assetId!: string;
 | 
			
		||||
 | 
			
		||||
  @CreateDateColumn({ default: () => 'clock_timestamp()', indexName: 'IDX_album_assets_audit_deleted_at' })
 | 
			
		||||
  deletedAt!: Date;
 | 
			
		||||
  deletedAt!: Generated<Timestamp>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -2,7 +2,15 @@ import { UpdatedAtTrigger, UpdateIdColumn } from 'src/decorators';
 | 
			
		||||
import { album_assets_delete_audit } from 'src/schema/functions';
 | 
			
		||||
import { AlbumTable } from 'src/schema/tables/album.table';
 | 
			
		||||
import { AssetTable } from 'src/schema/tables/asset.table';
 | 
			
		||||
import { AfterDeleteTrigger, CreateDateColumn, ForeignKeyColumn, Table, UpdateDateColumn } from 'src/sql-tools';
 | 
			
		||||
import {
 | 
			
		||||
  AfterDeleteTrigger,
 | 
			
		||||
  CreateDateColumn,
 | 
			
		||||
  ForeignKeyColumn,
 | 
			
		||||
  Generated,
 | 
			
		||||
  Table,
 | 
			
		||||
  Timestamp,
 | 
			
		||||
  UpdateDateColumn,
 | 
			
		||||
} from 'src/sql-tools';
 | 
			
		||||
 | 
			
		||||
@Table({ name: 'albums_assets_assets', primaryConstraintName: 'PK_c67bc36fa845fb7b18e0e398180' })
 | 
			
		||||
@UpdatedAtTrigger('album_assets_updated_at')
 | 
			
		||||
@ -21,11 +29,11 @@ export class AlbumAssetTable {
 | 
			
		||||
  assetsId!: string;
 | 
			
		||||
 | 
			
		||||
  @CreateDateColumn()
 | 
			
		||||
  createdAt!: Date;
 | 
			
		||||
  createdAt!: Generated<Timestamp>;
 | 
			
		||||
 | 
			
		||||
  @UpdateDateColumn()
 | 
			
		||||
  updatedAt!: Date;
 | 
			
		||||
  updatedAt!: Generated<Timestamp>;
 | 
			
		||||
 | 
			
		||||
  @UpdateIdColumn({ indexName: 'IDX_album_assets_update_id' })
 | 
			
		||||
  updateId!: string;
 | 
			
		||||
  updateId!: Generated<string>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,10 +1,10 @@
 | 
			
		||||
import { PrimaryGeneratedUuidV7Column } from 'src/decorators';
 | 
			
		||||
import { Column, CreateDateColumn, Table } from 'src/sql-tools';
 | 
			
		||||
import { Column, CreateDateColumn, Generated, Table, Timestamp } from 'src/sql-tools';
 | 
			
		||||
 | 
			
		||||
@Table('albums_audit')
 | 
			
		||||
export class AlbumAuditTable {
 | 
			
		||||
  @PrimaryGeneratedUuidV7Column()
 | 
			
		||||
  id!: string;
 | 
			
		||||
  id!: Generated<string>;
 | 
			
		||||
 | 
			
		||||
  @Column({ type: 'uuid', indexName: 'IDX_albums_audit_album_id' })
 | 
			
		||||
  albumId!: string;
 | 
			
		||||
@ -13,5 +13,5 @@ export class AlbumAuditTable {
 | 
			
		||||
  userId!: string;
 | 
			
		||||
 | 
			
		||||
  @CreateDateColumn({ default: () => 'clock_timestamp()', indexName: 'IDX_albums_audit_deleted_at' })
 | 
			
		||||
  deletedAt!: Date;
 | 
			
		||||
  deletedAt!: Generated<Timestamp>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,10 +1,10 @@
 | 
			
		||||
import { PrimaryGeneratedUuidV7Column } from 'src/decorators';
 | 
			
		||||
import { Column, CreateDateColumn, Table } from 'src/sql-tools';
 | 
			
		||||
import { Column, CreateDateColumn, Generated, Table, Timestamp } from 'src/sql-tools';
 | 
			
		||||
 | 
			
		||||
@Table('album_users_audit')
 | 
			
		||||
export class AlbumUserAuditTable {
 | 
			
		||||
  @PrimaryGeneratedUuidV7Column()
 | 
			
		||||
  id!: string;
 | 
			
		||||
  id!: Generated<string>;
 | 
			
		||||
 | 
			
		||||
  @Column({ type: 'uuid', indexName: 'IDX_album_users_audit_album_id' })
 | 
			
		||||
  albumId!: string;
 | 
			
		||||
@ -13,5 +13,5 @@ export class AlbumUserAuditTable {
 | 
			
		||||
  userId!: string;
 | 
			
		||||
 | 
			
		||||
  @CreateDateColumn({ default: () => 'clock_timestamp()', indexName: 'IDX_album_users_audit_deleted_at' })
 | 
			
		||||
  deletedAt!: Date;
 | 
			
		||||
  deletedAt!: Generated<Timestamp>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -9,8 +9,10 @@ import {
 | 
			
		||||
  Column,
 | 
			
		||||
  CreateDateColumn,
 | 
			
		||||
  ForeignKeyColumn,
 | 
			
		||||
  Generated,
 | 
			
		||||
  Index,
 | 
			
		||||
  Table,
 | 
			
		||||
  Timestamp,
 | 
			
		||||
  UpdateDateColumn,
 | 
			
		||||
} from 'src/sql-tools';
 | 
			
		||||
 | 
			
		||||
@ -50,17 +52,17 @@ export class AlbumUserTable {
 | 
			
		||||
  usersId!: string;
 | 
			
		||||
 | 
			
		||||
  @Column({ type: 'character varying', default: AlbumUserRole.EDITOR })
 | 
			
		||||
  role!: AlbumUserRole;
 | 
			
		||||
  role!: Generated<AlbumUserRole>;
 | 
			
		||||
 | 
			
		||||
  @CreateIdColumn({ indexName: 'IDX_album_users_create_id' })
 | 
			
		||||
  createId?: string;
 | 
			
		||||
  createId!: Generated<string>;
 | 
			
		||||
 | 
			
		||||
  @CreateDateColumn()
 | 
			
		||||
  createdAt!: Date;
 | 
			
		||||
  createdAt!: Generated<Timestamp>;
 | 
			
		||||
 | 
			
		||||
  @UpdateIdColumn({ indexName: 'IDX_album_users_update_id' })
 | 
			
		||||
  updateId?: string;
 | 
			
		||||
  updateId!: Generated<string>;
 | 
			
		||||
 | 
			
		||||
  @UpdateDateColumn()
 | 
			
		||||
  updatedAt!: Date;
 | 
			
		||||
  updatedAt!: Generated<Timestamp>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -9,8 +9,10 @@ import {
 | 
			
		||||
  CreateDateColumn,
 | 
			
		||||
  DeleteDateColumn,
 | 
			
		||||
  ForeignKeyColumn,
 | 
			
		||||
  Generated,
 | 
			
		||||
  PrimaryGeneratedColumn,
 | 
			
		||||
  Table,
 | 
			
		||||
  Timestamp,
 | 
			
		||||
  UpdateDateColumn,
 | 
			
		||||
} from 'src/sql-tools';
 | 
			
		||||
 | 
			
		||||
@ -25,16 +27,16 @@ import {
 | 
			
		||||
})
 | 
			
		||||
export class AlbumTable {
 | 
			
		||||
  @PrimaryGeneratedColumn()
 | 
			
		||||
  id!: string;
 | 
			
		||||
  id!: Generated<string>;
 | 
			
		||||
 | 
			
		||||
  @ForeignKeyColumn(() => UserTable, { onDelete: 'CASCADE', onUpdate: 'CASCADE', nullable: false })
 | 
			
		||||
  ownerId!: string;
 | 
			
		||||
 | 
			
		||||
  @Column({ default: 'Untitled Album' })
 | 
			
		||||
  albumName!: string;
 | 
			
		||||
  albumName!: Generated<string>;
 | 
			
		||||
 | 
			
		||||
  @CreateDateColumn()
 | 
			
		||||
  createdAt!: Date;
 | 
			
		||||
  createdAt!: Generated<Timestamp>;
 | 
			
		||||
 | 
			
		||||
  @ForeignKeyColumn(() => AssetTable, {
 | 
			
		||||
    nullable: true,
 | 
			
		||||
@ -42,23 +44,23 @@ export class AlbumTable {
 | 
			
		||||
    onUpdate: 'CASCADE',
 | 
			
		||||
    comment: 'Asset ID to be used as thumbnail',
 | 
			
		||||
  })
 | 
			
		||||
  albumThumbnailAssetId!: string;
 | 
			
		||||
  albumThumbnailAssetId!: string | null;
 | 
			
		||||
 | 
			
		||||
  @UpdateDateColumn()
 | 
			
		||||
  updatedAt!: Date;
 | 
			
		||||
  updatedAt!: Generated<Timestamp>;
 | 
			
		||||
 | 
			
		||||
  @Column({ type: 'text', default: '' })
 | 
			
		||||
  description!: string;
 | 
			
		||||
  description!: Generated<string>;
 | 
			
		||||
 | 
			
		||||
  @DeleteDateColumn()
 | 
			
		||||
  deletedAt!: Date | null;
 | 
			
		||||
  deletedAt!: Timestamp | null;
 | 
			
		||||
 | 
			
		||||
  @Column({ type: 'boolean', default: true })
 | 
			
		||||
  isActivityEnabled!: boolean;
 | 
			
		||||
  isActivityEnabled!: Generated<boolean>;
 | 
			
		||||
 | 
			
		||||
  @Column({ default: AssetOrder.DESC })
 | 
			
		||||
  order!: AssetOrder;
 | 
			
		||||
  order!: Generated<AssetOrder>;
 | 
			
		||||
 | 
			
		||||
  @UpdateIdColumn({ indexName: 'IDX_albums_update_id' })
 | 
			
		||||
  updateId?: string;
 | 
			
		||||
  updateId!: Generated<string>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -5,14 +5,19 @@ import {
 | 
			
		||||
  Column,
 | 
			
		||||
  CreateDateColumn,
 | 
			
		||||
  ForeignKeyColumn,
 | 
			
		||||
  Generated,
 | 
			
		||||
  PrimaryGeneratedColumn,
 | 
			
		||||
  Table,
 | 
			
		||||
  Timestamp,
 | 
			
		||||
  UpdateDateColumn,
 | 
			
		||||
} from 'src/sql-tools';
 | 
			
		||||
 | 
			
		||||
@Table('api_keys')
 | 
			
		||||
@UpdatedAtTrigger('api_keys_updated_at')
 | 
			
		||||
export class APIKeyTable {
 | 
			
		||||
export class ApiKeyTable {
 | 
			
		||||
  @PrimaryGeneratedColumn()
 | 
			
		||||
  id!: Generated<string>;
 | 
			
		||||
 | 
			
		||||
  @Column()
 | 
			
		||||
  name!: string;
 | 
			
		||||
 | 
			
		||||
@ -23,17 +28,14 @@ export class APIKeyTable {
 | 
			
		||||
  userId!: string;
 | 
			
		||||
 | 
			
		||||
  @CreateDateColumn()
 | 
			
		||||
  createdAt!: Date;
 | 
			
		||||
  createdAt!: Generated<Timestamp>;
 | 
			
		||||
 | 
			
		||||
  @UpdateDateColumn()
 | 
			
		||||
  updatedAt!: Date;
 | 
			
		||||
 | 
			
		||||
  @PrimaryGeneratedColumn()
 | 
			
		||||
  id!: string;
 | 
			
		||||
  updatedAt!: Generated<Timestamp>;
 | 
			
		||||
 | 
			
		||||
  @Column({ array: true, type: 'character varying' })
 | 
			
		||||
  permissions!: Permission[];
 | 
			
		||||
 | 
			
		||||
  @UpdateIdColumn({ indexName: 'IDX_api_keys_update_id' })
 | 
			
		||||
  updateId?: string;
 | 
			
		||||
  updateId!: Generated<string>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,10 +1,10 @@
 | 
			
		||||
import { PrimaryGeneratedUuidV7Column } from 'src/decorators';
 | 
			
		||||
import { Column, CreateDateColumn, Table } from 'src/sql-tools';
 | 
			
		||||
import { Column, CreateDateColumn, Generated, Table, Timestamp } from 'src/sql-tools';
 | 
			
		||||
 | 
			
		||||
@Table('assets_audit')
 | 
			
		||||
export class AssetAuditTable {
 | 
			
		||||
  @PrimaryGeneratedUuidV7Column()
 | 
			
		||||
  id!: string;
 | 
			
		||||
  id!: Generated<string>;
 | 
			
		||||
 | 
			
		||||
  @Column({ type: 'uuid', indexName: 'IDX_assets_audit_asset_id' })
 | 
			
		||||
  assetId!: string;
 | 
			
		||||
@ -13,5 +13,5 @@ export class AssetAuditTable {
 | 
			
		||||
  ownerId!: string;
 | 
			
		||||
 | 
			
		||||
  @CreateDateColumn({ default: () => 'clock_timestamp()', indexName: 'IDX_assets_audit_deleted_at' })
 | 
			
		||||
  deletedAt!: Date;
 | 
			
		||||
  deletedAt!: Generated<Timestamp>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -2,12 +2,24 @@ import { SourceType } from 'src/enum';
 | 
			
		||||
import { asset_face_source_type } from 'src/schema/enums';
 | 
			
		||||
import { AssetTable } from 'src/schema/tables/asset.table';
 | 
			
		||||
import { PersonTable } from 'src/schema/tables/person.table';
 | 
			
		||||
import { Column, DeleteDateColumn, ForeignKeyColumn, Index, PrimaryGeneratedColumn, Table } from 'src/sql-tools';
 | 
			
		||||
import {
 | 
			
		||||
  Column,
 | 
			
		||||
  DeleteDateColumn,
 | 
			
		||||
  ForeignKeyColumn,
 | 
			
		||||
  Generated,
 | 
			
		||||
  Index,
 | 
			
		||||
  PrimaryGeneratedColumn,
 | 
			
		||||
  Table,
 | 
			
		||||
  Timestamp,
 | 
			
		||||
} from 'src/sql-tools';
 | 
			
		||||
 | 
			
		||||
@Table({ name: 'asset_faces' })
 | 
			
		||||
@Index({ name: 'IDX_asset_faces_assetId_personId', columns: ['assetId', 'personId'] })
 | 
			
		||||
@Index({ columns: ['personId', 'assetId'] })
 | 
			
		||||
export class AssetFaceTable {
 | 
			
		||||
  @PrimaryGeneratedColumn()
 | 
			
		||||
  id!: Generated<string>;
 | 
			
		||||
 | 
			
		||||
  @ForeignKeyColumn(() => AssetTable, {
 | 
			
		||||
    onDelete: 'CASCADE',
 | 
			
		||||
    onUpdate: 'CASCADE',
 | 
			
		||||
@ -26,29 +38,26 @@ export class AssetFaceTable {
 | 
			
		||||
  personId!: string | null;
 | 
			
		||||
 | 
			
		||||
  @Column({ default: 0, type: 'integer' })
 | 
			
		||||
  imageWidth!: number;
 | 
			
		||||
  imageWidth!: Generated<number>;
 | 
			
		||||
 | 
			
		||||
  @Column({ default: 0, type: 'integer' })
 | 
			
		||||
  imageHeight!: number;
 | 
			
		||||
  imageHeight!: Generated<number>;
 | 
			
		||||
 | 
			
		||||
  @Column({ default: 0, type: 'integer' })
 | 
			
		||||
  boundingBoxX1!: number;
 | 
			
		||||
  boundingBoxX1!: Generated<number>;
 | 
			
		||||
 | 
			
		||||
  @Column({ default: 0, type: 'integer' })
 | 
			
		||||
  boundingBoxY1!: number;
 | 
			
		||||
  boundingBoxY1!: Generated<number>;
 | 
			
		||||
 | 
			
		||||
  @Column({ default: 0, type: 'integer' })
 | 
			
		||||
  boundingBoxX2!: number;
 | 
			
		||||
  boundingBoxX2!: Generated<number>;
 | 
			
		||||
 | 
			
		||||
  @Column({ default: 0, type: 'integer' })
 | 
			
		||||
  boundingBoxY2!: number;
 | 
			
		||||
 | 
			
		||||
  @PrimaryGeneratedColumn()
 | 
			
		||||
  id!: string;
 | 
			
		||||
  boundingBoxY2!: Generated<number>;
 | 
			
		||||
 | 
			
		||||
  @Column({ default: SourceType.MACHINE_LEARNING, enum: asset_face_source_type })
 | 
			
		||||
  sourceType!: SourceType;
 | 
			
		||||
  sourceType!: Generated<SourceType>;
 | 
			
		||||
 | 
			
		||||
  @DeleteDateColumn()
 | 
			
		||||
  deletedAt!: Date | null;
 | 
			
		||||
  deletedAt!: Timestamp | null;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -5,8 +5,10 @@ import {
 | 
			
		||||
  Column,
 | 
			
		||||
  CreateDateColumn,
 | 
			
		||||
  ForeignKeyColumn,
 | 
			
		||||
  Generated,
 | 
			
		||||
  PrimaryGeneratedColumn,
 | 
			
		||||
  Table,
 | 
			
		||||
  Timestamp,
 | 
			
		||||
  Unique,
 | 
			
		||||
  UpdateDateColumn,
 | 
			
		||||
} from 'src/sql-tools';
 | 
			
		||||
@ -16,20 +18,20 @@ import {
 | 
			
		||||
@UpdatedAtTrigger('asset_files_updated_at')
 | 
			
		||||
export class AssetFileTable {
 | 
			
		||||
  @PrimaryGeneratedColumn()
 | 
			
		||||
  id!: string;
 | 
			
		||||
  id!: Generated<string>;
 | 
			
		||||
 | 
			
		||||
  @ForeignKeyColumn(() => AssetTable, {
 | 
			
		||||
    onDelete: 'CASCADE',
 | 
			
		||||
    onUpdate: 'CASCADE',
 | 
			
		||||
    indexName: 'IDX_asset_files_assetId',
 | 
			
		||||
  })
 | 
			
		||||
  assetId?: string;
 | 
			
		||||
  assetId!: string;
 | 
			
		||||
 | 
			
		||||
  @CreateDateColumn()
 | 
			
		||||
  createdAt!: Date;
 | 
			
		||||
  createdAt!: Generated<Timestamp>;
 | 
			
		||||
 | 
			
		||||
  @UpdateDateColumn()
 | 
			
		||||
  updatedAt!: Date;
 | 
			
		||||
  updatedAt!: Generated<Timestamp>;
 | 
			
		||||
 | 
			
		||||
  @Column()
 | 
			
		||||
  type!: AssetFileType;
 | 
			
		||||
@ -38,5 +40,5 @@ export class AssetFileTable {
 | 
			
		||||
  path!: string;
 | 
			
		||||
 | 
			
		||||
  @UpdateIdColumn({ indexName: 'IDX_asset_files_update_id' })
 | 
			
		||||
  updateId?: string;
 | 
			
		||||
  updateId!: Generated<string>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
import { AssetTable } from 'src/schema/tables/asset.table';
 | 
			
		||||
import { Column, ForeignKeyColumn, Table } from 'src/sql-tools';
 | 
			
		||||
import { Column, ForeignKeyColumn, Table, Timestamp } from 'src/sql-tools';
 | 
			
		||||
 | 
			
		||||
@Table('asset_job_status')
 | 
			
		||||
export class AssetJobStatusTable {
 | 
			
		||||
@ -7,17 +7,17 @@ export class AssetJobStatusTable {
 | 
			
		||||
  assetId!: string;
 | 
			
		||||
 | 
			
		||||
  @Column({ type: 'timestamp with time zone', nullable: true })
 | 
			
		||||
  facesRecognizedAt!: Date | null;
 | 
			
		||||
  facesRecognizedAt!: Timestamp | null;
 | 
			
		||||
 | 
			
		||||
  @Column({ type: 'timestamp with time zone', nullable: true })
 | 
			
		||||
  metadataExtractedAt!: Date | null;
 | 
			
		||||
  metadataExtractedAt!: Timestamp | null;
 | 
			
		||||
 | 
			
		||||
  @Column({ type: 'timestamp with time zone', nullable: true })
 | 
			
		||||
  duplicatesDetectedAt!: Date | null;
 | 
			
		||||
  duplicatesDetectedAt!: Timestamp | null;
 | 
			
		||||
 | 
			
		||||
  @Column({ type: 'timestamp with time zone', nullable: true })
 | 
			
		||||
  previewAt!: Date | null;
 | 
			
		||||
  previewAt!: Timestamp | null;
 | 
			
		||||
 | 
			
		||||
  @Column({ type: 'timestamp with time zone', nullable: true })
 | 
			
		||||
  thumbnailAt!: Date | null;
 | 
			
		||||
  thumbnailAt!: Timestamp | null;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -11,9 +11,11 @@ import {
 | 
			
		||||
  CreateDateColumn,
 | 
			
		||||
  DeleteDateColumn,
 | 
			
		||||
  ForeignKeyColumn,
 | 
			
		||||
  Generated,
 | 
			
		||||
  Index,
 | 
			
		||||
  PrimaryGeneratedColumn,
 | 
			
		||||
  Table,
 | 
			
		||||
  Timestamp,
 | 
			
		||||
  UpdateDateColumn,
 | 
			
		||||
} from 'src/sql-tools';
 | 
			
		||||
import { ASSET_CHECKSUM_CONSTRAINT } from 'src/utils/database';
 | 
			
		||||
@ -60,7 +62,7 @@ import { ASSET_CHECKSUM_CONSTRAINT } from 'src/utils/database';
 | 
			
		||||
// For all assets, each originalpath must be unique per user and library
 | 
			
		||||
export class AssetTable {
 | 
			
		||||
  @PrimaryGeneratedColumn()
 | 
			
		||||
  id!: string;
 | 
			
		||||
  id!: Generated<string>;
 | 
			
		||||
 | 
			
		||||
  @Column()
 | 
			
		||||
  deviceAssetId!: string;
 | 
			
		||||
@ -78,13 +80,13 @@ export class AssetTable {
 | 
			
		||||
  originalPath!: string;
 | 
			
		||||
 | 
			
		||||
  @Column({ type: 'timestamp with time zone', indexName: 'idx_asset_file_created_at' })
 | 
			
		||||
  fileCreatedAt!: Date;
 | 
			
		||||
  fileCreatedAt!: Timestamp;
 | 
			
		||||
 | 
			
		||||
  @Column({ type: 'timestamp with time zone' })
 | 
			
		||||
  fileModifiedAt!: Date;
 | 
			
		||||
  fileModifiedAt!: Timestamp;
 | 
			
		||||
 | 
			
		||||
  @Column({ type: 'boolean', default: false })
 | 
			
		||||
  isFavorite!: boolean;
 | 
			
		||||
  isFavorite!: Generated<boolean>;
 | 
			
		||||
 | 
			
		||||
  @Column({ type: 'character varying', nullable: true })
 | 
			
		||||
  duration!: string | null;
 | 
			
		||||
@ -99,10 +101,10 @@ export class AssetTable {
 | 
			
		||||
  livePhotoVideoId!: string | null;
 | 
			
		||||
 | 
			
		||||
  @UpdateDateColumn()
 | 
			
		||||
  updatedAt!: Date;
 | 
			
		||||
  updatedAt!: Generated<Timestamp>;
 | 
			
		||||
 | 
			
		||||
  @CreateDateColumn()
 | 
			
		||||
  createdAt!: Date;
 | 
			
		||||
  createdAt!: Generated<Timestamp>;
 | 
			
		||||
 | 
			
		||||
  @Column({ index: true })
 | 
			
		||||
  originalFileName!: string;
 | 
			
		||||
@ -114,32 +116,32 @@ export class AssetTable {
 | 
			
		||||
  thumbhash!: Buffer | null;
 | 
			
		||||
 | 
			
		||||
  @Column({ type: 'boolean', default: false })
 | 
			
		||||
  isOffline!: boolean;
 | 
			
		||||
  isOffline!: Generated<boolean>;
 | 
			
		||||
 | 
			
		||||
  @ForeignKeyColumn(() => LibraryTable, { onDelete: 'CASCADE', onUpdate: 'CASCADE', nullable: true })
 | 
			
		||||
  libraryId?: string | null;
 | 
			
		||||
  libraryId!: string | null;
 | 
			
		||||
 | 
			
		||||
  @Column({ type: 'boolean', default: false })
 | 
			
		||||
  isExternal!: boolean;
 | 
			
		||||
  isExternal!: Generated<boolean>;
 | 
			
		||||
 | 
			
		||||
  @DeleteDateColumn()
 | 
			
		||||
  deletedAt!: Date | null;
 | 
			
		||||
  deletedAt!: Timestamp | null;
 | 
			
		||||
 | 
			
		||||
  @Column({ type: 'timestamp with time zone' })
 | 
			
		||||
  localDateTime!: Date;
 | 
			
		||||
  localDateTime!: Timestamp;
 | 
			
		||||
 | 
			
		||||
  @ForeignKeyColumn(() => StackTable, { nullable: true, onDelete: 'SET NULL', onUpdate: 'CASCADE' })
 | 
			
		||||
  stackId?: string | null;
 | 
			
		||||
  stackId!: string | null;
 | 
			
		||||
 | 
			
		||||
  @Column({ type: 'uuid', nullable: true, indexName: 'IDX_assets_duplicateId' })
 | 
			
		||||
  duplicateId!: string | null;
 | 
			
		||||
 | 
			
		||||
  @Column({ enum: assets_status_enum, default: AssetStatus.ACTIVE })
 | 
			
		||||
  status!: AssetStatus;
 | 
			
		||||
  status!: Generated<AssetStatus>;
 | 
			
		||||
 | 
			
		||||
  @UpdateIdColumn({ indexName: 'IDX_assets_update_id' })
 | 
			
		||||
  updateId?: string;
 | 
			
		||||
  updateId!: Generated<string>;
 | 
			
		||||
 | 
			
		||||
  @Column({ enum: asset_visibility_enum, default: AssetVisibility.TIMELINE })
 | 
			
		||||
  visibility!: AssetVisibility;
 | 
			
		||||
  visibility!: Generated<AssetVisibility>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,11 +1,11 @@
 | 
			
		||||
import { DatabaseAction, EntityType } from 'src/enum';
 | 
			
		||||
import { Column, CreateDateColumn, Index, PrimaryColumn, Table } from 'src/sql-tools';
 | 
			
		||||
import { Column, CreateDateColumn, Generated, Index, PrimaryColumn, Table, Timestamp } from 'src/sql-tools';
 | 
			
		||||
 | 
			
		||||
@Table('audit')
 | 
			
		||||
@Index({ name: 'IDX_ownerId_createdAt', columns: ['ownerId', 'createdAt'] })
 | 
			
		||||
export class AuditTable {
 | 
			
		||||
  @PrimaryColumn({ type: 'serial', synchronize: false })
 | 
			
		||||
  id!: number;
 | 
			
		||||
  id!: Generated<number>;
 | 
			
		||||
 | 
			
		||||
  @Column()
 | 
			
		||||
  entityType!: EntityType;
 | 
			
		||||
@ -20,5 +20,5 @@ export class AuditTable {
 | 
			
		||||
  ownerId!: string;
 | 
			
		||||
 | 
			
		||||
  @CreateDateColumn()
 | 
			
		||||
  createdAt!: Date;
 | 
			
		||||
  createdAt!: Generated<Timestamp>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
import { UpdatedAtTrigger, UpdateIdColumn } from 'src/decorators';
 | 
			
		||||
import { AssetTable } from 'src/schema/tables/asset.table';
 | 
			
		||||
import { Column, ForeignKeyColumn, Table, UpdateDateColumn } from 'src/sql-tools';
 | 
			
		||||
import { Column, ForeignKeyColumn, Generated, Int8, Table, Timestamp, UpdateDateColumn } from 'src/sql-tools';
 | 
			
		||||
 | 
			
		||||
@Table('exif')
 | 
			
		||||
@UpdatedAtTrigger('asset_exif_updated_at')
 | 
			
		||||
@ -21,16 +21,16 @@ export class ExifTable {
 | 
			
		||||
  exifImageHeight!: number | null;
 | 
			
		||||
 | 
			
		||||
  @Column({ type: 'bigint', nullable: true })
 | 
			
		||||
  fileSizeInByte!: number | null;
 | 
			
		||||
  fileSizeInByte!: Int8 | null;
 | 
			
		||||
 | 
			
		||||
  @Column({ type: 'character varying', nullable: true })
 | 
			
		||||
  orientation!: string | null;
 | 
			
		||||
 | 
			
		||||
  @Column({ type: 'timestamp with time zone', nullable: true })
 | 
			
		||||
  dateTimeOriginal!: Date | null;
 | 
			
		||||
  dateTimeOriginal!: Timestamp | null;
 | 
			
		||||
 | 
			
		||||
  @Column({ type: 'timestamp with time zone', nullable: true })
 | 
			
		||||
  modifyDate!: Date | null;
 | 
			
		||||
  modifyDate!: Timestamp | null;
 | 
			
		||||
 | 
			
		||||
  @Column({ type: 'character varying', nullable: true })
 | 
			
		||||
  lensModel!: string | null;
 | 
			
		||||
@ -60,10 +60,10 @@ export class ExifTable {
 | 
			
		||||
  country!: string | null;
 | 
			
		||||
 | 
			
		||||
  @Column({ type: 'text', default: '' })
 | 
			
		||||
  description!: string; // or caption
 | 
			
		||||
  description!: Generated<string>; // or caption
 | 
			
		||||
 | 
			
		||||
  @Column({ type: 'double precision', nullable: true })
 | 
			
		||||
  fps?: number | null;
 | 
			
		||||
  fps!: number | null;
 | 
			
		||||
 | 
			
		||||
  @Column({ type: 'character varying', nullable: true })
 | 
			
		||||
  exposureTime!: string | null;
 | 
			
		||||
@ -93,8 +93,8 @@ export class ExifTable {
 | 
			
		||||
  rating!: number | null;
 | 
			
		||||
 | 
			
		||||
  @UpdateDateColumn({ default: () => 'clock_timestamp()' })
 | 
			
		||||
  updatedAt?: Date;
 | 
			
		||||
  updatedAt!: Generated<Date>;
 | 
			
		||||
 | 
			
		||||
  @UpdateIdColumn({ indexName: 'IDX_asset_exif_update_id' })
 | 
			
		||||
  updateId?: string;
 | 
			
		||||
  updateId!: Generated<string>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
import { Column, Index, PrimaryColumn, Table } from 'src/sql-tools';
 | 
			
		||||
import { Column, Index, PrimaryColumn, Table, Timestamp } from 'src/sql-tools';
 | 
			
		||||
 | 
			
		||||
@Table({ name: 'geodata_places', synchronize: false })
 | 
			
		||||
@Index({
 | 
			
		||||
@ -47,20 +47,20 @@ export class GeodataPlacesTable {
 | 
			
		||||
  countryCode!: string;
 | 
			
		||||
 | 
			
		||||
  @Column({ type: 'character varying', length: 20, nullable: true })
 | 
			
		||||
  admin1Code!: string;
 | 
			
		||||
  admin1Code!: string | null;
 | 
			
		||||
 | 
			
		||||
  @Column({ type: 'character varying', length: 80, nullable: true })
 | 
			
		||||
  admin2Code!: string;
 | 
			
		||||
  admin2Code!: string | null;
 | 
			
		||||
 | 
			
		||||
  @Column({ type: 'date' })
 | 
			
		||||
  modificationDate!: Date;
 | 
			
		||||
  modificationDate!: Timestamp;
 | 
			
		||||
 | 
			
		||||
  @Column({ type: 'character varying', nullable: true })
 | 
			
		||||
  admin1Name!: string;
 | 
			
		||||
  admin1Name!: string | null;
 | 
			
		||||
 | 
			
		||||
  @Column({ type: 'character varying', nullable: true })
 | 
			
		||||
  admin2Name!: string;
 | 
			
		||||
  admin2Name!: string | null;
 | 
			
		||||
 | 
			
		||||
  @Column({ type: 'character varying', nullable: true })
 | 
			
		||||
  alternateNames!: string;
 | 
			
		||||
  alternateNames!: string | null;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -5,8 +5,10 @@ import {
 | 
			
		||||
  CreateDateColumn,
 | 
			
		||||
  DeleteDateColumn,
 | 
			
		||||
  ForeignKeyColumn,
 | 
			
		||||
  Generated,
 | 
			
		||||
  PrimaryGeneratedColumn,
 | 
			
		||||
  Table,
 | 
			
		||||
  Timestamp,
 | 
			
		||||
  UpdateDateColumn,
 | 
			
		||||
} from 'src/sql-tools';
 | 
			
		||||
 | 
			
		||||
@ -14,7 +16,7 @@ import {
 | 
			
		||||
@UpdatedAtTrigger('libraries_updated_at')
 | 
			
		||||
export class LibraryTable {
 | 
			
		||||
  @PrimaryGeneratedColumn()
 | 
			
		||||
  id!: string;
 | 
			
		||||
  id!: Generated<string>;
 | 
			
		||||
 | 
			
		||||
  @Column()
 | 
			
		||||
  name!: string;
 | 
			
		||||
@ -29,17 +31,17 @@ export class LibraryTable {
 | 
			
		||||
  exclusionPatterns!: string[];
 | 
			
		||||
 | 
			
		||||
  @CreateDateColumn()
 | 
			
		||||
  createdAt!: Date;
 | 
			
		||||
  createdAt!: Generated<Timestamp>;
 | 
			
		||||
 | 
			
		||||
  @UpdateDateColumn()
 | 
			
		||||
  updatedAt!: Date;
 | 
			
		||||
  updatedAt!: Generated<Date>;
 | 
			
		||||
 | 
			
		||||
  @DeleteDateColumn()
 | 
			
		||||
  deletedAt?: Date;
 | 
			
		||||
  deletedAt!: Timestamp | null;
 | 
			
		||||
 | 
			
		||||
  @Column({ type: 'timestamp with time zone', nullable: true })
 | 
			
		||||
  refreshedAt!: Date | null;
 | 
			
		||||
  refreshedAt!: Timestamp | null;
 | 
			
		||||
 | 
			
		||||
  @UpdateIdColumn({ indexName: 'IDX_libraries_update_id' })
 | 
			
		||||
  updateId?: string;
 | 
			
		||||
  updateId!: Generated<string>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,13 +1,16 @@
 | 
			
		||||
import { ColumnType } from 'kysely';
 | 
			
		||||
import { UpdatedAtTrigger, UpdateIdColumn } from 'src/decorators';
 | 
			
		||||
import { memory_assets_delete_audit } from 'src/schema/functions';
 | 
			
		||||
import { AssetTable } from 'src/schema/tables/asset.table';
 | 
			
		||||
import { MemoryTable } from 'src/schema/tables/memory.table';
 | 
			
		||||
import { AfterDeleteTrigger, CreateDateColumn, ForeignKeyColumn, Table, UpdateDateColumn } from 'src/sql-tools';
 | 
			
		||||
 | 
			
		||||
type Timestamp = ColumnType<Date, Date | string, Date | string>;
 | 
			
		||||
type Generated<T> =
 | 
			
		||||
  T extends ColumnType<infer S, infer I, infer U> ? ColumnType<S, I | undefined, U> : ColumnType<T, T | undefined, T>;
 | 
			
		||||
import {
 | 
			
		||||
  AfterDeleteTrigger,
 | 
			
		||||
  CreateDateColumn,
 | 
			
		||||
  ForeignKeyColumn,
 | 
			
		||||
  Generated,
 | 
			
		||||
  Table,
 | 
			
		||||
  Timestamp,
 | 
			
		||||
  UpdateDateColumn,
 | 
			
		||||
} from 'src/sql-tools';
 | 
			
		||||
 | 
			
		||||
@Table('memories_assets_assets')
 | 
			
		||||
@UpdatedAtTrigger('memory_assets_updated_at')
 | 
			
		||||
 | 
			
		||||
@ -1,10 +1,5 @@
 | 
			
		||||
import { ColumnType } from 'kysely';
 | 
			
		||||
import { PrimaryGeneratedUuidV7Column } from 'src/decorators';
 | 
			
		||||
import { Column, CreateDateColumn, Table } from 'src/sql-tools';
 | 
			
		||||
 | 
			
		||||
type Timestamp = ColumnType<Date, Date | string, Date | string>;
 | 
			
		||||
type Generated<T> =
 | 
			
		||||
  T extends ColumnType<infer S, infer I, infer U> ? ColumnType<S, I | undefined, U> : ColumnType<T, T | undefined, T>;
 | 
			
		||||
import { Column, CreateDateColumn, Generated, Table, Timestamp } from 'src/sql-tools';
 | 
			
		||||
 | 
			
		||||
@Table('memories_audit')
 | 
			
		||||
export class MemoryAuditTable {
 | 
			
		||||
@ -18,5 +13,5 @@ export class MemoryAuditTable {
 | 
			
		||||
  userId!: string;
 | 
			
		||||
 | 
			
		||||
  @CreateDateColumn({ default: () => 'clock_timestamp()', indexName: 'IDX_memories_audit_deleted_at' })
 | 
			
		||||
  deletedAt!: Timestamp;
 | 
			
		||||
  deletedAt!: Generated<Timestamp>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -8,8 +8,10 @@ import {
 | 
			
		||||
  CreateDateColumn,
 | 
			
		||||
  DeleteDateColumn,
 | 
			
		||||
  ForeignKeyColumn,
 | 
			
		||||
  Generated,
 | 
			
		||||
  PrimaryGeneratedColumn,
 | 
			
		||||
  Table,
 | 
			
		||||
  Timestamp,
 | 
			
		||||
  UpdateDateColumn,
 | 
			
		||||
} from 'src/sql-tools';
 | 
			
		||||
 | 
			
		||||
@ -24,16 +26,16 @@ import {
 | 
			
		||||
})
 | 
			
		||||
export class MemoryTable {
 | 
			
		||||
  @PrimaryGeneratedColumn()
 | 
			
		||||
  id!: string;
 | 
			
		||||
  id!: Generated<string>;
 | 
			
		||||
 | 
			
		||||
  @CreateDateColumn()
 | 
			
		||||
  createdAt!: Date;
 | 
			
		||||
  createdAt!: Generated<Timestamp>;
 | 
			
		||||
 | 
			
		||||
  @UpdateDateColumn()
 | 
			
		||||
  updatedAt!: Date;
 | 
			
		||||
  updatedAt!: Generated<Timestamp>;
 | 
			
		||||
 | 
			
		||||
  @DeleteDateColumn()
 | 
			
		||||
  deletedAt?: Date;
 | 
			
		||||
  deletedAt!: Timestamp | null;
 | 
			
		||||
 | 
			
		||||
  @ForeignKeyColumn(() => UserTable, { onDelete: 'CASCADE', onUpdate: 'CASCADE', nullable: false })
 | 
			
		||||
  ownerId!: string;
 | 
			
		||||
@ -46,22 +48,22 @@ export class MemoryTable {
 | 
			
		||||
 | 
			
		||||
  /** unless set to true, will be automatically deleted in the future */
 | 
			
		||||
  @Column({ type: 'boolean', default: false })
 | 
			
		||||
  isSaved!: boolean;
 | 
			
		||||
  isSaved!: Generated<boolean>;
 | 
			
		||||
 | 
			
		||||
  /** memories are sorted in ascending order by this value */
 | 
			
		||||
  @Column({ type: 'timestamp with time zone' })
 | 
			
		||||
  memoryAt!: Date;
 | 
			
		||||
  memoryAt!: Timestamp;
 | 
			
		||||
 | 
			
		||||
  /** when the user last viewed the memory */
 | 
			
		||||
  @Column({ type: 'timestamp with time zone', nullable: true })
 | 
			
		||||
  seenAt?: Date;
 | 
			
		||||
  seenAt!: Timestamp | null;
 | 
			
		||||
 | 
			
		||||
  @Column({ type: 'timestamp with time zone', nullable: true })
 | 
			
		||||
  showAt?: Date;
 | 
			
		||||
  showAt!: Timestamp | null;
 | 
			
		||||
 | 
			
		||||
  @Column({ type: 'timestamp with time zone', nullable: true })
 | 
			
		||||
  hideAt?: Date;
 | 
			
		||||
  hideAt!: Timestamp | null;
 | 
			
		||||
 | 
			
		||||
  @UpdateIdColumn({ indexName: 'IDX_memories_update_id' })
 | 
			
		||||
  updateId?: string;
 | 
			
		||||
  updateId!: Generated<string>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
import { PathType } from 'src/enum';
 | 
			
		||||
import { Column, PrimaryGeneratedColumn, Table, Unique } from 'src/sql-tools';
 | 
			
		||||
import { Column, Generated, PrimaryGeneratedColumn, Table, Unique } from 'src/sql-tools';
 | 
			
		||||
 | 
			
		||||
@Table('move_history')
 | 
			
		||||
// path lock (per entity)
 | 
			
		||||
@ -8,7 +8,7 @@ import { Column, PrimaryGeneratedColumn, Table, Unique } from 'src/sql-tools';
 | 
			
		||||
@Unique({ name: 'UQ_newPath', columns: ['newPath'] })
 | 
			
		||||
export class MoveTable {
 | 
			
		||||
  @PrimaryGeneratedColumn()
 | 
			
		||||
  id!: string;
 | 
			
		||||
  id!: Generated<string>;
 | 
			
		||||
 | 
			
		||||
  @Column({ type: 'uuid' })
 | 
			
		||||
  entityId!: string;
 | 
			
		||||
 | 
			
		||||
@ -1,9 +1,9 @@
 | 
			
		||||
import { Column, PrimaryGeneratedColumn, Table } from 'src/sql-tools';
 | 
			
		||||
import { Column, Generated, PrimaryGeneratedColumn, Table } from 'src/sql-tools';
 | 
			
		||||
 | 
			
		||||
@Table({ name: 'naturalearth_countries', primaryConstraintName: 'naturalearth_countries_pkey' })
 | 
			
		||||
export class NaturalEarthCountriesTable {
 | 
			
		||||
  @PrimaryGeneratedColumn({ strategy: 'identity' })
 | 
			
		||||
  id!: number;
 | 
			
		||||
  id!: Generated<number>;
 | 
			
		||||
 | 
			
		||||
  @Column({ type: 'character varying', length: 50 })
 | 
			
		||||
  admin!: string;
 | 
			
		||||
 | 
			
		||||
@ -6,8 +6,10 @@ import {
 | 
			
		||||
  CreateDateColumn,
 | 
			
		||||
  DeleteDateColumn,
 | 
			
		||||
  ForeignKeyColumn,
 | 
			
		||||
  Generated,
 | 
			
		||||
  PrimaryGeneratedColumn,
 | 
			
		||||
  Table,
 | 
			
		||||
  Timestamp,
 | 
			
		||||
  UpdateDateColumn,
 | 
			
		||||
} from 'src/sql-tools';
 | 
			
		||||
 | 
			
		||||
@ -15,28 +17,28 @@ import {
 | 
			
		||||
@UpdatedAtTrigger('notifications_updated_at')
 | 
			
		||||
export class NotificationTable {
 | 
			
		||||
  @PrimaryGeneratedColumn()
 | 
			
		||||
  id!: string;
 | 
			
		||||
  id!: Generated<string>;
 | 
			
		||||
 | 
			
		||||
  @CreateDateColumn()
 | 
			
		||||
  createdAt!: Date;
 | 
			
		||||
  createdAt!: Generated<Timestamp>;
 | 
			
		||||
 | 
			
		||||
  @UpdateDateColumn()
 | 
			
		||||
  updatedAt!: Date;
 | 
			
		||||
  updatedAt!: Generated<Timestamp>;
 | 
			
		||||
 | 
			
		||||
  @DeleteDateColumn()
 | 
			
		||||
  deletedAt?: Date;
 | 
			
		||||
  deletedAt!: Timestamp | null;
 | 
			
		||||
 | 
			
		||||
  @UpdateIdColumn({ indexName: 'IDX_notifications_update_id' })
 | 
			
		||||
  updateId?: string;
 | 
			
		||||
  updateId!: Generated<string>;
 | 
			
		||||
 | 
			
		||||
  @ForeignKeyColumn(() => UserTable, { onDelete: 'CASCADE', onUpdate: 'CASCADE', nullable: true })
 | 
			
		||||
  userId!: string;
 | 
			
		||||
 | 
			
		||||
  @Column({ default: NotificationLevel.Info })
 | 
			
		||||
  level!: NotificationLevel;
 | 
			
		||||
  level!: Generated<NotificationLevel>;
 | 
			
		||||
 | 
			
		||||
  @Column({ default: NotificationLevel.Info })
 | 
			
		||||
  type!: NotificationType;
 | 
			
		||||
  type!: Generated<NotificationType>;
 | 
			
		||||
 | 
			
		||||
  @Column({ type: 'jsonb', nullable: true })
 | 
			
		||||
  data!: any | null;
 | 
			
		||||
@ -45,8 +47,8 @@ export class NotificationTable {
 | 
			
		||||
  title!: string;
 | 
			
		||||
 | 
			
		||||
  @Column({ type: 'text', nullable: true })
 | 
			
		||||
  description!: string;
 | 
			
		||||
  description!: string | null;
 | 
			
		||||
 | 
			
		||||
  @Column({ type: 'timestamp with time zone', nullable: true })
 | 
			
		||||
  readAt?: Date | null;
 | 
			
		||||
  readAt!: Timestamp | null;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,10 +1,10 @@
 | 
			
		||||
import { PrimaryGeneratedUuidV7Column } from 'src/decorators';
 | 
			
		||||
import { Column, CreateDateColumn, Table } from 'src/sql-tools';
 | 
			
		||||
import { Column, CreateDateColumn, Generated, Table, Timestamp } from 'src/sql-tools';
 | 
			
		||||
 | 
			
		||||
@Table('partners_audit')
 | 
			
		||||
export class PartnerAuditTable {
 | 
			
		||||
  @PrimaryGeneratedUuidV7Column()
 | 
			
		||||
  id!: string;
 | 
			
		||||
  id!: Generated<string>;
 | 
			
		||||
 | 
			
		||||
  @Column({ type: 'uuid', indexName: 'IDX_partners_audit_shared_by_id' })
 | 
			
		||||
  sharedById!: string;
 | 
			
		||||
@ -13,5 +13,5 @@ export class PartnerAuditTable {
 | 
			
		||||
  sharedWithId!: string;
 | 
			
		||||
 | 
			
		||||
  @CreateDateColumn({ default: () => 'clock_timestamp()', indexName: 'IDX_partners_audit_deleted_at' })
 | 
			
		||||
  deletedAt!: Date;
 | 
			
		||||
  deletedAt!: Generated<Timestamp>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,16 @@
 | 
			
		||||
import { CreateIdColumn, UpdatedAtTrigger, UpdateIdColumn } from 'src/decorators';
 | 
			
		||||
import { partners_delete_audit } from 'src/schema/functions';
 | 
			
		||||
import { UserTable } from 'src/schema/tables/user.table';
 | 
			
		||||
import { AfterDeleteTrigger, Column, CreateDateColumn, ForeignKeyColumn, Table, UpdateDateColumn } from 'src/sql-tools';
 | 
			
		||||
import {
 | 
			
		||||
  AfterDeleteTrigger,
 | 
			
		||||
  Column,
 | 
			
		||||
  CreateDateColumn,
 | 
			
		||||
  ForeignKeyColumn,
 | 
			
		||||
  Generated,
 | 
			
		||||
  Table,
 | 
			
		||||
  Timestamp,
 | 
			
		||||
  UpdateDateColumn,
 | 
			
		||||
} from 'src/sql-tools';
 | 
			
		||||
 | 
			
		||||
@Table('partners')
 | 
			
		||||
@UpdatedAtTrigger('partners_updated_at')
 | 
			
		||||
@ -25,17 +34,17 @@ export class PartnerTable {
 | 
			
		||||
  sharedWithId!: string;
 | 
			
		||||
 | 
			
		||||
  @CreateDateColumn()
 | 
			
		||||
  createdAt!: Date;
 | 
			
		||||
  createdAt!: Generated<Timestamp>;
 | 
			
		||||
 | 
			
		||||
  @CreateIdColumn({ indexName: 'IDX_partners_create_id' })
 | 
			
		||||
  createId!: string;
 | 
			
		||||
  createId!: Generated<string>;
 | 
			
		||||
 | 
			
		||||
  @UpdateDateColumn()
 | 
			
		||||
  updatedAt!: Date;
 | 
			
		||||
  updatedAt!: Generated<Timestamp>;
 | 
			
		||||
 | 
			
		||||
  @Column({ type: 'boolean', default: false })
 | 
			
		||||
  inTimeline!: boolean;
 | 
			
		||||
  inTimeline!: Generated<boolean>;
 | 
			
		||||
 | 
			
		||||
  @UpdateIdColumn({ indexName: 'IDX_partners_update_id' })
 | 
			
		||||
  updateId!: string;
 | 
			
		||||
  updateId!: Generated<string>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -6,8 +6,10 @@ import {
 | 
			
		||||
  Column,
 | 
			
		||||
  CreateDateColumn,
 | 
			
		||||
  ForeignKeyColumn,
 | 
			
		||||
  Generated,
 | 
			
		||||
  PrimaryGeneratedColumn,
 | 
			
		||||
  Table,
 | 
			
		||||
  Timestamp,
 | 
			
		||||
  UpdateDateColumn,
 | 
			
		||||
} from 'src/sql-tools';
 | 
			
		||||
 | 
			
		||||
@ -16,38 +18,38 @@ import {
 | 
			
		||||
@Check({ name: 'CHK_b0f82b0ed662bfc24fbb58bb45', expression: `"birthDate" <= CURRENT_DATE` })
 | 
			
		||||
export class PersonTable {
 | 
			
		||||
  @PrimaryGeneratedColumn('uuid')
 | 
			
		||||
  id!: string;
 | 
			
		||||
  id!: Generated<string>;
 | 
			
		||||
 | 
			
		||||
  @CreateDateColumn()
 | 
			
		||||
  createdAt!: Date;
 | 
			
		||||
  createdAt!: Generated<Timestamp>;
 | 
			
		||||
 | 
			
		||||
  @UpdateDateColumn()
 | 
			
		||||
  updatedAt!: Date;
 | 
			
		||||
  updatedAt!: Generated<Timestamp>;
 | 
			
		||||
 | 
			
		||||
  @ForeignKeyColumn(() => UserTable, { onDelete: 'CASCADE', onUpdate: 'CASCADE', nullable: false })
 | 
			
		||||
  ownerId!: string;
 | 
			
		||||
 | 
			
		||||
  @Column({ default: '' })
 | 
			
		||||
  name!: string;
 | 
			
		||||
  name!: Generated<string>;
 | 
			
		||||
 | 
			
		||||
  @Column({ default: '' })
 | 
			
		||||
  thumbnailPath!: string;
 | 
			
		||||
  thumbnailPath!: Generated<string>;
 | 
			
		||||
 | 
			
		||||
  @Column({ type: 'boolean', default: false })
 | 
			
		||||
  isHidden!: boolean;
 | 
			
		||||
  isHidden!: Generated<boolean>;
 | 
			
		||||
 | 
			
		||||
  @Column({ type: 'date', nullable: true })
 | 
			
		||||
  birthDate!: Date | string | null;
 | 
			
		||||
  birthDate!: Timestamp | null;
 | 
			
		||||
 | 
			
		||||
  @ForeignKeyColumn(() => AssetFaceTable, { onDelete: 'SET NULL', nullable: true })
 | 
			
		||||
  faceAssetId!: string | null;
 | 
			
		||||
 | 
			
		||||
  @Column({ type: 'boolean', default: false })
 | 
			
		||||
  isFavorite!: boolean;
 | 
			
		||||
  isFavorite!: Generated<boolean>;
 | 
			
		||||
 | 
			
		||||
  @Column({ type: 'character varying', nullable: true, default: null })
 | 
			
		||||
  color?: string | null;
 | 
			
		||||
  color!: string | null;
 | 
			
		||||
 | 
			
		||||
  @UpdateIdColumn({ indexName: 'IDX_person_update_id' })
 | 
			
		||||
  updateId!: string;
 | 
			
		||||
  updateId!: Generated<string>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -4,8 +4,10 @@ import {
 | 
			
		||||
  Column,
 | 
			
		||||
  CreateDateColumn,
 | 
			
		||||
  ForeignKeyColumn,
 | 
			
		||||
  Generated,
 | 
			
		||||
  PrimaryGeneratedColumn,
 | 
			
		||||
  Table,
 | 
			
		||||
  Timestamp,
 | 
			
		||||
  UpdateDateColumn,
 | 
			
		||||
} from 'src/sql-tools';
 | 
			
		||||
 | 
			
		||||
@ -13,20 +15,20 @@ import {
 | 
			
		||||
@UpdatedAtTrigger('sessions_updated_at')
 | 
			
		||||
export class SessionTable {
 | 
			
		||||
  @PrimaryGeneratedColumn()
 | 
			
		||||
  id!: string;
 | 
			
		||||
  id!: Generated<string>;
 | 
			
		||||
 | 
			
		||||
  // TODO convert to byte[]
 | 
			
		||||
  @Column()
 | 
			
		||||
  token!: string;
 | 
			
		||||
 | 
			
		||||
  @CreateDateColumn()
 | 
			
		||||
  createdAt!: Date;
 | 
			
		||||
  createdAt!: Generated<Timestamp>;
 | 
			
		||||
 | 
			
		||||
  @UpdateDateColumn()
 | 
			
		||||
  updatedAt!: Date;
 | 
			
		||||
  updatedAt!: Generated<Timestamp>;
 | 
			
		||||
 | 
			
		||||
  @Column({ type: 'timestamp with time zone', nullable: true })
 | 
			
		||||
  expiresAt!: Date | null;
 | 
			
		||||
  expiresAt!: Timestamp | null;
 | 
			
		||||
 | 
			
		||||
  @ForeignKeyColumn(() => UserTable, { onUpdate: 'CASCADE', onDelete: 'CASCADE' })
 | 
			
		||||
  userId!: string;
 | 
			
		||||
@ -35,14 +37,14 @@ export class SessionTable {
 | 
			
		||||
  parentId!: string | null;
 | 
			
		||||
 | 
			
		||||
  @Column({ default: '' })
 | 
			
		||||
  deviceType!: string;
 | 
			
		||||
  deviceType!: Generated<string>;
 | 
			
		||||
 | 
			
		||||
  @Column({ default: '' })
 | 
			
		||||
  deviceOS!: string;
 | 
			
		||||
  deviceOS!: Generated<string>;
 | 
			
		||||
 | 
			
		||||
  @UpdateIdColumn({ indexName: 'IDX_sessions_update_id' })
 | 
			
		||||
  updateId!: string;
 | 
			
		||||
  updateId!: Generated<string>;
 | 
			
		||||
 | 
			
		||||
  @Column({ type: 'timestamp with time zone', nullable: true })
 | 
			
		||||
  pinExpiresAt!: Date | null;
 | 
			
		||||
  pinExpiresAt!: Timestamp | null;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,13 +1,22 @@
 | 
			
		||||
import { SharedLinkType } from 'src/enum';
 | 
			
		||||
import { AlbumTable } from 'src/schema/tables/album.table';
 | 
			
		||||
import { UserTable } from 'src/schema/tables/user.table';
 | 
			
		||||
import { Column, CreateDateColumn, ForeignKeyColumn, PrimaryGeneratedColumn, Table, Unique } from 'src/sql-tools';
 | 
			
		||||
import {
 | 
			
		||||
  Column,
 | 
			
		||||
  CreateDateColumn,
 | 
			
		||||
  ForeignKeyColumn,
 | 
			
		||||
  Generated,
 | 
			
		||||
  PrimaryGeneratedColumn,
 | 
			
		||||
  Table,
 | 
			
		||||
  Timestamp,
 | 
			
		||||
  Unique,
 | 
			
		||||
} from 'src/sql-tools';
 | 
			
		||||
 | 
			
		||||
@Table('shared_links')
 | 
			
		||||
@Unique({ name: 'UQ_sharedlink_key', columns: ['key'] })
 | 
			
		||||
export class SharedLinkTable {
 | 
			
		||||
  @PrimaryGeneratedColumn()
 | 
			
		||||
  id!: string;
 | 
			
		||||
  id!: Generated<string>;
 | 
			
		||||
 | 
			
		||||
  @Column({ type: 'character varying', nullable: true })
 | 
			
		||||
  description!: string | null;
 | 
			
		||||
@ -22,10 +31,10 @@ export class SharedLinkTable {
 | 
			
		||||
  type!: SharedLinkType;
 | 
			
		||||
 | 
			
		||||
  @CreateDateColumn()
 | 
			
		||||
  createdAt!: Date;
 | 
			
		||||
  createdAt!: Generated<Timestamp>;
 | 
			
		||||
 | 
			
		||||
  @Column({ type: 'timestamp with time zone', nullable: true })
 | 
			
		||||
  expiresAt!: Date | null;
 | 
			
		||||
  expiresAt!: Timestamp | null;
 | 
			
		||||
 | 
			
		||||
  @Column({ type: 'boolean', default: false })
 | 
			
		||||
  allowUpload!: boolean;
 | 
			
		||||
@ -36,13 +45,13 @@ export class SharedLinkTable {
 | 
			
		||||
    onUpdate: 'CASCADE',
 | 
			
		||||
    indexName: 'IDX_sharedlink_albumId',
 | 
			
		||||
  })
 | 
			
		||||
  albumId!: string;
 | 
			
		||||
  albumId!: string | null;
 | 
			
		||||
 | 
			
		||||
  @Column({ type: 'boolean', default: true })
 | 
			
		||||
  allowDownload!: boolean;
 | 
			
		||||
  allowDownload!: Generated<boolean>;
 | 
			
		||||
 | 
			
		||||
  @Column({ type: 'boolean', default: true })
 | 
			
		||||
  showExif!: boolean;
 | 
			
		||||
  showExif!: Generated<boolean>;
 | 
			
		||||
 | 
			
		||||
  @Column({ type: 'character varying', nullable: true })
 | 
			
		||||
  password!: string | null;
 | 
			
		||||
 | 
			
		||||
@ -1,11 +1,11 @@
 | 
			
		||||
import { AssetTable } from 'src/schema/tables/asset.table';
 | 
			
		||||
import { UserTable } from 'src/schema/tables/user.table';
 | 
			
		||||
import { ForeignKeyColumn, PrimaryGeneratedColumn, Table } from 'src/sql-tools';
 | 
			
		||||
import { ForeignKeyColumn, Generated, PrimaryGeneratedColumn, Table } from 'src/sql-tools';
 | 
			
		||||
 | 
			
		||||
@Table('asset_stack')
 | 
			
		||||
export class StackTable {
 | 
			
		||||
  @PrimaryGeneratedColumn()
 | 
			
		||||
  id!: string;
 | 
			
		||||
  id!: Generated<string>;
 | 
			
		||||
 | 
			
		||||
  //TODO: Add constraint to ensure primary asset exists in the assets array
 | 
			
		||||
  @ForeignKeyColumn(() => AssetTable, { nullable: false, unique: true })
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,16 @@
 | 
			
		||||
import { UpdatedAtTrigger, UpdateIdColumn } from 'src/decorators';
 | 
			
		||||
import { SyncEntityType } from 'src/enum';
 | 
			
		||||
import { SessionTable } from 'src/schema/tables/session.table';
 | 
			
		||||
import { Column, CreateDateColumn, ForeignKeyColumn, PrimaryColumn, Table, UpdateDateColumn } from 'src/sql-tools';
 | 
			
		||||
import {
 | 
			
		||||
  Column,
 | 
			
		||||
  CreateDateColumn,
 | 
			
		||||
  ForeignKeyColumn,
 | 
			
		||||
  Generated,
 | 
			
		||||
  PrimaryColumn,
 | 
			
		||||
  Table,
 | 
			
		||||
  Timestamp,
 | 
			
		||||
  UpdateDateColumn,
 | 
			
		||||
} from 'src/sql-tools';
 | 
			
		||||
 | 
			
		||||
@Table('session_sync_checkpoints')
 | 
			
		||||
@UpdatedAtTrigger('session_sync_checkpoints_updated_at')
 | 
			
		||||
@ -13,14 +22,14 @@ export class SessionSyncCheckpointTable {
 | 
			
		||||
  type!: SyncEntityType;
 | 
			
		||||
 | 
			
		||||
  @CreateDateColumn()
 | 
			
		||||
  createdAt!: Date;
 | 
			
		||||
  createdAt!: Generated<Timestamp>;
 | 
			
		||||
 | 
			
		||||
  @UpdateDateColumn()
 | 
			
		||||
  updatedAt!: Date;
 | 
			
		||||
  updatedAt!: Generated<Timestamp>;
 | 
			
		||||
 | 
			
		||||
  @Column()
 | 
			
		||||
  ack!: string;
 | 
			
		||||
 | 
			
		||||
  @UpdateIdColumn({ indexName: 'IDX_session_sync_checkpoints_update_id' })
 | 
			
		||||
  updateId!: string;
 | 
			
		||||
  updateId!: Generated<string>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -4,8 +4,10 @@ import {
 | 
			
		||||
  Column,
 | 
			
		||||
  CreateDateColumn,
 | 
			
		||||
  ForeignKeyColumn,
 | 
			
		||||
  Generated,
 | 
			
		||||
  PrimaryGeneratedColumn,
 | 
			
		||||
  Table,
 | 
			
		||||
  Timestamp,
 | 
			
		||||
  Unique,
 | 
			
		||||
  UpdateDateColumn,
 | 
			
		||||
} from 'src/sql-tools';
 | 
			
		||||
@ -15,7 +17,7 @@ import {
 | 
			
		||||
@Unique({ columns: ['userId', 'value'] })
 | 
			
		||||
export class TagTable {
 | 
			
		||||
  @PrimaryGeneratedColumn()
 | 
			
		||||
  id!: string;
 | 
			
		||||
  id!: Generated<string>;
 | 
			
		||||
 | 
			
		||||
  @ForeignKeyColumn(() => UserTable, {
 | 
			
		||||
    onUpdate: 'CASCADE',
 | 
			
		||||
@ -29,17 +31,17 @@ export class TagTable {
 | 
			
		||||
  value!: string;
 | 
			
		||||
 | 
			
		||||
  @CreateDateColumn()
 | 
			
		||||
  createdAt!: Date;
 | 
			
		||||
  createdAt!: Generated<Timestamp>;
 | 
			
		||||
 | 
			
		||||
  @UpdateDateColumn()
 | 
			
		||||
  updatedAt!: Date;
 | 
			
		||||
  updatedAt!: Generated<Timestamp>;
 | 
			
		||||
 | 
			
		||||
  @Column({ type: 'character varying', nullable: true, default: null })
 | 
			
		||||
  color!: string | null;
 | 
			
		||||
 | 
			
		||||
  @ForeignKeyColumn(() => TagTable, { nullable: true, onDelete: 'CASCADE' })
 | 
			
		||||
  parentId?: string;
 | 
			
		||||
  parentId!: string | null;
 | 
			
		||||
 | 
			
		||||
  @UpdateIdColumn({ indexName: 'IDX_tags_update_id' })
 | 
			
		||||
  updateId!: string;
 | 
			
		||||
  updateId!: Generated<string>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,14 +1,14 @@
 | 
			
		||||
import { PrimaryGeneratedUuidV7Column } from 'src/decorators';
 | 
			
		||||
import { Column, CreateDateColumn, Table } from 'src/sql-tools';
 | 
			
		||||
import { Column, CreateDateColumn, Generated, Table, Timestamp } from 'src/sql-tools';
 | 
			
		||||
 | 
			
		||||
@Table('users_audit')
 | 
			
		||||
export class UserAuditTable {
 | 
			
		||||
  @PrimaryGeneratedUuidV7Column()
 | 
			
		||||
  id!: Generated<string>;
 | 
			
		||||
 | 
			
		||||
  @Column({ type: 'uuid' })
 | 
			
		||||
  userId!: string;
 | 
			
		||||
 | 
			
		||||
  @CreateDateColumn({ default: () => 'clock_timestamp()', indexName: 'IDX_users_audit_deleted_at' })
 | 
			
		||||
  deletedAt!: Date;
 | 
			
		||||
 | 
			
		||||
  @PrimaryGeneratedUuidV7Column()
 | 
			
		||||
  id!: string;
 | 
			
		||||
  deletedAt!: Generated<Timestamp>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -7,16 +7,14 @@ import {
 | 
			
		||||
  Column,
 | 
			
		||||
  CreateDateColumn,
 | 
			
		||||
  DeleteDateColumn,
 | 
			
		||||
  Generated,
 | 
			
		||||
  Index,
 | 
			
		||||
  PrimaryGeneratedColumn,
 | 
			
		||||
  Table,
 | 
			
		||||
  Timestamp,
 | 
			
		||||
  UpdateDateColumn,
 | 
			
		||||
} from 'src/sql-tools';
 | 
			
		||||
 | 
			
		||||
type Timestamp = ColumnType<Date, Date | string, Date | string>;
 | 
			
		||||
type Generated<T> =
 | 
			
		||||
  T extends ColumnType<infer S, infer I, infer U> ? ColumnType<S, I | undefined, U> : ColumnType<T, T | undefined, T>;
 | 
			
		||||
 | 
			
		||||
@Table('users')
 | 
			
		||||
@UpdatedAtTrigger('users_updated_at')
 | 
			
		||||
@AfterDeleteTrigger({
 | 
			
		||||
 | 
			
		||||
@ -1,12 +1,12 @@
 | 
			
		||||
import { Column, CreateDateColumn, PrimaryGeneratedColumn, Table } from 'src/sql-tools';
 | 
			
		||||
import { Column, CreateDateColumn, Generated, PrimaryGeneratedColumn, Table, Timestamp } from 'src/sql-tools';
 | 
			
		||||
 | 
			
		||||
@Table('version_history')
 | 
			
		||||
export class VersionHistoryTable {
 | 
			
		||||
  @PrimaryGeneratedColumn()
 | 
			
		||||
  id!: string;
 | 
			
		||||
  id!: Generated<string>;
 | 
			
		||||
 | 
			
		||||
  @CreateDateColumn()
 | 
			
		||||
  createdAt!: Date;
 | 
			
		||||
  createdAt!: Generated<Timestamp>;
 | 
			
		||||
 | 
			
		||||
  @Column()
 | 
			
		||||
  version!: string;
 | 
			
		||||
 | 
			
		||||
@ -6,7 +6,6 @@ import path, { basename, isAbsolute, parse } from 'node:path';
 | 
			
		||||
import picomatch from 'picomatch';
 | 
			
		||||
import { JOBS_LIBRARY_PAGINATION_SIZE } from 'src/constants';
 | 
			
		||||
import { StorageCore } from 'src/cores/storage.core';
 | 
			
		||||
import { Assets } from 'src/db';
 | 
			
		||||
import { OnEvent, OnJob } from 'src/decorators';
 | 
			
		||||
import {
 | 
			
		||||
  CreateLibraryDto,
 | 
			
		||||
@ -21,6 +20,7 @@ import {
 | 
			
		||||
import { AssetStatus, AssetType, DatabaseLock, ImmichWorker, JobName, JobStatus, QueueName } from 'src/enum';
 | 
			
		||||
import { ArgOf } from 'src/repositories/event.repository';
 | 
			
		||||
import { AssetSyncResult } from 'src/repositories/library.repository';
 | 
			
		||||
import { AssetTable } from 'src/schema/tables/asset.table';
 | 
			
		||||
import { BaseService } from 'src/services/base.service';
 | 
			
		||||
import { JobOf } from 'src/types';
 | 
			
		||||
import { mimeTypes } from 'src/utils/mime-types';
 | 
			
		||||
@ -237,7 +237,7 @@ export class LibraryService extends BaseService {
 | 
			
		||||
      return JobStatus.FAILED;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const assetImports: Insertable<Assets>[] = [];
 | 
			
		||||
    const assetImports: Insertable<AssetTable>[] = [];
 | 
			
		||||
    await Promise.all(
 | 
			
		||||
      job.paths.map((path) =>
 | 
			
		||||
        this.processEntity(path, library.ownerId, job.libraryId)
 | 
			
		||||
 | 
			
		||||
@ -9,7 +9,6 @@ import path from 'node:path';
 | 
			
		||||
import { JOBS_ASSET_PAGINATION_SIZE } from 'src/constants';
 | 
			
		||||
import { StorageCore } from 'src/cores/storage.core';
 | 
			
		||||
import { Asset, AssetFace } from 'src/database';
 | 
			
		||||
import { AssetFaces, Exif, Person } from 'src/db';
 | 
			
		||||
import { OnEvent, OnJob } from 'src/decorators';
 | 
			
		||||
import {
 | 
			
		||||
  AssetType,
 | 
			
		||||
@ -25,6 +24,9 @@ import {
 | 
			
		||||
import { ArgOf } from 'src/repositories/event.repository';
 | 
			
		||||
import { ReverseGeocodeResult } from 'src/repositories/map.repository';
 | 
			
		||||
import { ImmichTags } from 'src/repositories/metadata.repository';
 | 
			
		||||
import { AssetFaceTable } from 'src/schema/tables/asset-face.table';
 | 
			
		||||
import { ExifTable } from 'src/schema/tables/exif.table';
 | 
			
		||||
import { PersonTable } from 'src/schema/tables/person.table';
 | 
			
		||||
import { BaseService } from 'src/services/base.service';
 | 
			
		||||
import { JobItem, JobOf } from 'src/types';
 | 
			
		||||
import { isFaceImportEnabled } from 'src/utils/misc';
 | 
			
		||||
@ -162,7 +164,7 @@ export class MetadataService extends BaseService {
 | 
			
		||||
 | 
			
		||||
  private async linkLivePhotos(
 | 
			
		||||
    asset: { id: string; type: AssetType; ownerId: string; libraryId: string | null },
 | 
			
		||||
    exifInfo: Insertable<Exif>,
 | 
			
		||||
    exifInfo: Insertable<ExifTable>,
 | 
			
		||||
  ): Promise<void> {
 | 
			
		||||
    if (!exifInfo.livePhotoCID) {
 | 
			
		||||
      return;
 | 
			
		||||
@ -240,7 +242,7 @@ export class MetadataService extends BaseService {
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const exifData: Insertable<Exif> = {
 | 
			
		||||
    const exifData: Insertable<ExifTable> = {
 | 
			
		||||
      assetId: asset.id,
 | 
			
		||||
 | 
			
		||||
      // dates
 | 
			
		||||
@ -710,10 +712,10 @@ export class MetadataService extends BaseService {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const facesToAdd: (Insertable<AssetFaces> & { assetId: string })[] = [];
 | 
			
		||||
    const facesToAdd: (Insertable<AssetFaceTable> & { assetId: string })[] = [];
 | 
			
		||||
    const existingNames = await this.personRepository.getDistinctNames(asset.ownerId, { withHidden: true });
 | 
			
		||||
    const existingNameMap = new Map(existingNames.map(({ id, name }) => [name.toLowerCase(), id]));
 | 
			
		||||
    const missing: (Insertable<Person> & { ownerId: string })[] = [];
 | 
			
		||||
    const missing: (Insertable<PersonTable> & { ownerId: string })[] = [];
 | 
			
		||||
    const missingWithFaceAsset: { id: string; ownerId: string; faceAssetId: string }[] = [];
 | 
			
		||||
 | 
			
		||||
    const adjustedRegionInfo = this.orientRegionInfo(tags.RegionInfo, tags.Orientation);
 | 
			
		||||
 | 
			
		||||
@ -2,7 +2,6 @@ import { BadRequestException, Injectable, NotFoundException } from '@nestjs/comm
 | 
			
		||||
import { Insertable, Updateable } from 'kysely';
 | 
			
		||||
import { JOBS_ASSET_PAGINATION_SIZE } from 'src/constants';
 | 
			
		||||
import { Person } from 'src/database';
 | 
			
		||||
import { AssetFaces, FaceSearch } from 'src/db';
 | 
			
		||||
import { Chunked, OnJob } from 'src/decorators';
 | 
			
		||||
import { BulkIdErrorReason, BulkIdResponseDto, BulkIdsDto } from 'src/dtos/asset-ids.response.dto';
 | 
			
		||||
import { AuthDto } from 'src/dtos/auth.dto';
 | 
			
		||||
@ -37,6 +36,8 @@ import {
 | 
			
		||||
} from 'src/enum';
 | 
			
		||||
import { BoundingBox } from 'src/repositories/machine-learning.repository';
 | 
			
		||||
import { UpdateFacesData } from 'src/repositories/person.repository';
 | 
			
		||||
import { AssetFaceTable } from 'src/schema/tables/asset-face.table';
 | 
			
		||||
import { FaceSearchTable } from 'src/schema/tables/face-search.table';
 | 
			
		||||
import { BaseService } from 'src/services/base.service';
 | 
			
		||||
import { JobItem, JobOf } from 'src/types';
 | 
			
		||||
import { ImmichFileResponse } from 'src/utils/file';
 | 
			
		||||
@ -317,8 +318,8 @@ export class PersonService extends BaseService {
 | 
			
		||||
    );
 | 
			
		||||
    this.logger.debug(`${faces.length} faces detected in ${previewFile.path}`);
 | 
			
		||||
 | 
			
		||||
    const facesToAdd: (Insertable<AssetFaces> & { id: string })[] = [];
 | 
			
		||||
    const embeddings: FaceSearch[] = [];
 | 
			
		||||
    const facesToAdd: (Insertable<AssetFaceTable> & { id: string })[] = [];
 | 
			
		||||
    const embeddings: FaceSearchTable[] = [];
 | 
			
		||||
    const mlFaceIds = new Set<string>();
 | 
			
		||||
 | 
			
		||||
    for (const face of asset.faces) {
 | 
			
		||||
 | 
			
		||||
@ -3,7 +3,6 @@ import { Insertable } from 'kysely';
 | 
			
		||||
import { DateTime } from 'luxon';
 | 
			
		||||
import { Writable } from 'node:stream';
 | 
			
		||||
import { AUDIT_LOG_MAX_DURATION } from 'src/constants';
 | 
			
		||||
import { SessionSyncCheckpoints } from 'src/db';
 | 
			
		||||
import { AssetResponseDto, mapAsset } from 'src/dtos/asset-response.dto';
 | 
			
		||||
import { AuthDto } from 'src/dtos/auth.dto';
 | 
			
		||||
import {
 | 
			
		||||
@ -17,6 +16,7 @@ import {
 | 
			
		||||
  SyncStreamDto,
 | 
			
		||||
} from 'src/dtos/sync.dto';
 | 
			
		||||
import { AssetVisibility, DatabaseAction, EntityType, Permission, SyncEntityType, SyncRequestType } from 'src/enum';
 | 
			
		||||
import { SessionSyncCheckpointTable } from 'src/schema/tables/sync-checkpoint.table';
 | 
			
		||||
import { BaseService } from 'src/services/base.service';
 | 
			
		||||
import { SyncAck } from 'src/types';
 | 
			
		||||
import { getMyPartnerIds } from 'src/utils/asset.util';
 | 
			
		||||
@ -90,7 +90,7 @@ export class SyncService extends BaseService {
 | 
			
		||||
      return throwSessionRequired();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const checkpoints: Record<string, Insertable<SessionSyncCheckpoints>> = {};
 | 
			
		||||
    const checkpoints: Record<string, Insertable<SessionSyncCheckpointTable>> = {};
 | 
			
		||||
    for (const ack of dto.acks) {
 | 
			
		||||
      const { type } = fromAck(ack);
 | 
			
		||||
      // TODO proper ack validation via class validator
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,5 @@
 | 
			
		||||
import { BadRequestException, Injectable } from '@nestjs/common';
 | 
			
		||||
import { Insertable } from 'kysely';
 | 
			
		||||
import { TagAsset } from 'src/db';
 | 
			
		||||
import { OnJob } from 'src/decorators';
 | 
			
		||||
import { BulkIdResponseDto, BulkIdsDto } from 'src/dtos/asset-ids.response.dto';
 | 
			
		||||
import { AuthDto } from 'src/dtos/auth.dto';
 | 
			
		||||
@ -14,6 +13,7 @@ import {
 | 
			
		||||
  mapTag,
 | 
			
		||||
} from 'src/dtos/tag.dto';
 | 
			
		||||
import { JobName, JobStatus, Permission, QueueName } from 'src/enum';
 | 
			
		||||
import { TagAssetTable } from 'src/schema/tables/tag-asset.table';
 | 
			
		||||
import { BaseService } from 'src/services/base.service';
 | 
			
		||||
import { addAssets, removeAssets } from 'src/utils/asset.util';
 | 
			
		||||
import { upsertTags } from 'src/utils/tag';
 | 
			
		||||
@ -81,7 +81,7 @@ export class TagService extends BaseService {
 | 
			
		||||
      this.checkAccess({ auth, permission: Permission.ASSET_UPDATE, ids: dto.assetIds }),
 | 
			
		||||
    ]);
 | 
			
		||||
 | 
			
		||||
    const items: Insertable<TagAsset>[] = [];
 | 
			
		||||
    const items: Insertable<TagAssetTable>[] = [];
 | 
			
		||||
    for (const tagsId of tagIds) {
 | 
			
		||||
      for (const assetsId of assetIds) {
 | 
			
		||||
        items.push({ tagsId, assetsId });
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
import { Kysely } from 'kysely';
 | 
			
		||||
import { Kysely, ColumnType as KyselyColumnType } from 'kysely';
 | 
			
		||||
 | 
			
		||||
export type PostgresDB = {
 | 
			
		||||
  pg_am: {
 | 
			
		||||
@ -476,3 +476,10 @@ export enum Reason {
 | 
			
		||||
  MissingInSource = 'missing in source',
 | 
			
		||||
  MissingInTarget = 'missing in target',
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export type Timestamp = KyselyColumnType<Date, Date | string, Date | string>;
 | 
			
		||||
export type Generated<T> =
 | 
			
		||||
  T extends KyselyColumnType<infer S, infer I, infer U>
 | 
			
		||||
    ? KyselyColumnType<S, I | undefined, U>
 | 
			
		||||
    : KyselyColumnType<T, T | undefined, T>;
 | 
			
		||||
export type Int8 = KyselyColumnType<number>;
 | 
			
		||||
 | 
			
		||||
@ -16,9 +16,9 @@ import { jsonArrayFrom, jsonObjectFrom } from 'kysely/helpers/postgres';
 | 
			
		||||
import { parse } from 'pg-connection-string';
 | 
			
		||||
import postgres, { Notice } from 'postgres';
 | 
			
		||||
import { columns, Exif, Person } from 'src/database';
 | 
			
		||||
import { DB } from 'src/db';
 | 
			
		||||
import { AssetFileType, AssetVisibility, DatabaseExtension, DatabaseSslMode } from 'src/enum';
 | 
			
		||||
import { AssetSearchBuilderOptions } from 'src/repositories/search.repository';
 | 
			
		||||
import { DB } from 'src/schema';
 | 
			
		||||
import { DatabaseConnectionParams, VectorExtension } from 'src/types';
 | 
			
		||||
 | 
			
		||||
type Ssl = 'require' | 'allow' | 'prefer' | 'verify-full' | boolean | object;
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										1
									
								
								server/test/fixtures/asset.stub.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								server/test/fixtures/asset.stub.ts
									
									
									
									
										vendored
									
									
								
							@ -35,6 +35,7 @@ export const stackStub = (stackId: string, assets: (MapAsset & { exifInfo: Exif
 | 
			
		||||
    primaryAssetId: assets[0].id,
 | 
			
		||||
    createdAt: new Date('2023-02-23T05:06:29.716Z'),
 | 
			
		||||
    updatedAt: new Date('2023-02-23T05:06:29.716Z'),
 | 
			
		||||
    updateId: 'uuid-v7',
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -4,7 +4,6 @@ import { DateTime } from 'luxon';
 | 
			
		||||
import { createHash, randomBytes } from 'node:crypto';
 | 
			
		||||
import { Writable } from 'node:stream';
 | 
			
		||||
import { AssetFace } from 'src/database';
 | 
			
		||||
import { Albums, AssetJobStatus, Assets, DB, Exif, FaceSearch, Memories, Person, Sessions } from 'src/db';
 | 
			
		||||
import { AuthDto, LoginResponseDto } from 'src/dtos/auth.dto';
 | 
			
		||||
import { AlbumUserRole, AssetType, AssetVisibility, MemoryType, SourceType, SyncRequestType } from 'src/enum';
 | 
			
		||||
import { AccessRepository } from 'src/repositories/access.repository';
 | 
			
		||||
@ -32,6 +31,15 @@ import { SyncRepository } from 'src/repositories/sync.repository';
 | 
			
		||||
import { SystemMetadataRepository } from 'src/repositories/system-metadata.repository';
 | 
			
		||||
import { UserRepository } from 'src/repositories/user.repository';
 | 
			
		||||
import { VersionHistoryRepository } from 'src/repositories/version-history.repository';
 | 
			
		||||
import { DB } from 'src/schema';
 | 
			
		||||
import { AlbumTable } from 'src/schema/tables/album.table';
 | 
			
		||||
import { AssetJobStatusTable } from 'src/schema/tables/asset-job-status.table';
 | 
			
		||||
import { AssetTable } from 'src/schema/tables/asset.table';
 | 
			
		||||
import { ExifTable } from 'src/schema/tables/exif.table';
 | 
			
		||||
import { FaceSearchTable } from 'src/schema/tables/face-search.table';
 | 
			
		||||
import { MemoryTable } from 'src/schema/tables/memory.table';
 | 
			
		||||
import { PersonTable } from 'src/schema/tables/person.table';
 | 
			
		||||
import { SessionTable } from 'src/schema/tables/session.table';
 | 
			
		||||
import { UserTable } from 'src/schema/tables/user.table';
 | 
			
		||||
import { BASE_SERVICE_DEPENDENCIES, BaseService } from 'src/services/base.service';
 | 
			
		||||
import { SyncService } from 'src/services/sync.service';
 | 
			
		||||
@ -125,13 +133,13 @@ export class MediumTestContext<S extends BaseService = BaseService> {
 | 
			
		||||
    return { partner, result };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async newAsset(dto: Partial<Insertable<Assets>> = {}) {
 | 
			
		||||
  async newAsset(dto: Partial<Insertable<AssetTable>> = {}) {
 | 
			
		||||
    const asset = mediumFactory.assetInsert(dto);
 | 
			
		||||
    const result = await this.get(AssetRepository).create(asset);
 | 
			
		||||
    return { asset, result };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async newMemory(dto: Partial<Insertable<Memories>> = {}) {
 | 
			
		||||
  async newMemory(dto: Partial<Insertable<MemoryTable>> = {}) {
 | 
			
		||||
    const memory = mediumFactory.memoryInsert(dto);
 | 
			
		||||
    const result = await this.get(MemoryRepository).create(memory, new Set<string>());
 | 
			
		||||
    return { memory, result };
 | 
			
		||||
@ -142,12 +150,12 @@ export class MediumTestContext<S extends BaseService = BaseService> {
 | 
			
		||||
    return { memoryAsset: dto, result };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async newExif(dto: Insertable<Exif>) {
 | 
			
		||||
  async newExif(dto: Insertable<ExifTable>) {
 | 
			
		||||
    const result = await this.get(AssetRepository).upsertExif(dto);
 | 
			
		||||
    return { result };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async newAlbum(dto: Insertable<Albums>) {
 | 
			
		||||
  async newAlbum(dto: Insertable<AlbumTable>) {
 | 
			
		||||
    const album = mediumFactory.albumInsert(dto);
 | 
			
		||||
    const result = await this.get(AlbumRepository).create(album, [], []);
 | 
			
		||||
    return { album, result };
 | 
			
		||||
@ -164,19 +172,19 @@ export class MediumTestContext<S extends BaseService = BaseService> {
 | 
			
		||||
    return { albumUser: { albumId, userId, role }, result };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async newJobStatus(dto: Partial<Insertable<AssetJobStatus>> & { assetId: string }) {
 | 
			
		||||
  async newJobStatus(dto: Partial<Insertable<AssetJobStatusTable>> & { assetId: string }) {
 | 
			
		||||
    const jobStatus = mediumFactory.assetJobStatusInsert({ assetId: dto.assetId });
 | 
			
		||||
    const result = await this.get(AssetRepository).upsertJobStatus(jobStatus);
 | 
			
		||||
    return { jobStatus, result };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async newPerson(dto: Partial<Insertable<Person>> & { ownerId: string }) {
 | 
			
		||||
  async newPerson(dto: Partial<Insertable<PersonTable>> & { ownerId: string }) {
 | 
			
		||||
    const person = mediumFactory.personInsert(dto);
 | 
			
		||||
    const result = await this.get(PersonRepository).create(person);
 | 
			
		||||
    return { person, result };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async newSession(dto: Partial<Insertable<Sessions>> & { userId: string }) {
 | 
			
		||||
  async newSession(dto: Partial<Insertable<SessionTable>> & { userId: string }) {
 | 
			
		||||
    const session = mediumFactory.sessionInsert(dto);
 | 
			
		||||
    const result = await this.get(SessionRepository).create(session);
 | 
			
		||||
    return { session, result };
 | 
			
		||||
@ -338,10 +346,10 @@ const newMockRepository = <T>(key: ClassConstructor<T>) => {
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const assetInsert = (asset: Partial<Insertable<Assets>> = {}) => {
 | 
			
		||||
const assetInsert = (asset: Partial<Insertable<AssetTable>> = {}) => {
 | 
			
		||||
  const id = asset.id || newUuid();
 | 
			
		||||
  const now = newDate();
 | 
			
		||||
  const defaults: Insertable<Assets> = {
 | 
			
		||||
  const defaults: Insertable<AssetTable> = {
 | 
			
		||||
    deviceAssetId: '',
 | 
			
		||||
    deviceId: '',
 | 
			
		||||
    originalFileName: '',
 | 
			
		||||
@ -363,9 +371,9 @@ const assetInsert = (asset: Partial<Insertable<Assets>> = {}) => {
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const albumInsert = (album: Partial<Insertable<Albums>> & { ownerId: string }) => {
 | 
			
		||||
const albumInsert = (album: Partial<Insertable<AlbumTable>> & { ownerId: string }) => {
 | 
			
		||||
  const id = album.id || newUuid();
 | 
			
		||||
  const defaults: Omit<Insertable<Albums>, 'ownerId'> = {
 | 
			
		||||
  const defaults: Omit<Insertable<AlbumTable>, 'ownerId'> = {
 | 
			
		||||
    albumName: 'Album',
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
@ -376,7 +384,7 @@ const albumInsert = (album: Partial<Insertable<Albums>> & { ownerId: string }) =
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const faceInsert = (face: Partial<Insertable<FaceSearch>> & { faceId: string }) => {
 | 
			
		||||
const faceInsert = (face: Partial<Insertable<FaceSearchTable>> & { faceId: string }) => {
 | 
			
		||||
  const defaults = {
 | 
			
		||||
    faceId: face.faceId,
 | 
			
		||||
    embedding: face.embedding || newEmbedding(),
 | 
			
		||||
@ -409,10 +417,10 @@ const assetFaceInsert = (assetFace: Partial<AssetFace> & { assetId: string }) =>
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const assetJobStatusInsert = (
 | 
			
		||||
  job: Partial<Insertable<AssetJobStatus>> & { assetId: string },
 | 
			
		||||
): Insertable<AssetJobStatus> => {
 | 
			
		||||
  job: Partial<Insertable<AssetJobStatusTable>> & { assetId: string },
 | 
			
		||||
): Insertable<AssetJobStatusTable> => {
 | 
			
		||||
  const date = DateTime.now().minus({ days: 15 }).toISO();
 | 
			
		||||
  const defaults: Omit<Insertable<AssetJobStatus>, 'assetId'> = {
 | 
			
		||||
  const defaults: Omit<Insertable<AssetJobStatusTable>, 'assetId'> = {
 | 
			
		||||
    duplicatesDetectedAt: date,
 | 
			
		||||
    facesRecognizedAt: date,
 | 
			
		||||
    metadataExtractedAt: date,
 | 
			
		||||
@ -426,7 +434,7 @@ const assetJobStatusInsert = (
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const personInsert = (person: Partial<Insertable<Person>> & { ownerId: string }) => {
 | 
			
		||||
const personInsert = (person: Partial<Insertable<PersonTable>> & { ownerId: string }) => {
 | 
			
		||||
  const defaults = {
 | 
			
		||||
    birthDate: person.birthDate || null,
 | 
			
		||||
    color: person.color || null,
 | 
			
		||||
@ -449,8 +457,12 @@ const personInsert = (person: Partial<Insertable<Person>> & { ownerId: string })
 | 
			
		||||
 | 
			
		||||
const sha256 = (value: string) => createHash('sha256').update(value).digest('base64');
 | 
			
		||||
 | 
			
		||||
const sessionInsert = ({ id = newUuid(), userId, ...session }: Partial<Insertable<Sessions>> & { userId: string }) => {
 | 
			
		||||
  const defaults: Insertable<Sessions> = {
 | 
			
		||||
const sessionInsert = ({
 | 
			
		||||
  id = newUuid(),
 | 
			
		||||
  userId,
 | 
			
		||||
  ...session
 | 
			
		||||
}: Partial<Insertable<SessionTable>> & { userId: string }) => {
 | 
			
		||||
  const defaults: Insertable<SessionTable> = {
 | 
			
		||||
    id,
 | 
			
		||||
    userId,
 | 
			
		||||
    token: sha256(id),
 | 
			
		||||
@ -478,11 +490,11 @@ const userInsert = (user: Partial<Insertable<UserTable>> = {}) => {
 | 
			
		||||
  return { ...defaults, ...user, id };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const memoryInsert = (memory: Partial<Insertable<Memories>> = {}) => {
 | 
			
		||||
const memoryInsert = (memory: Partial<Insertable<MemoryTable>> = {}) => {
 | 
			
		||||
  const id = memory.id || newUuid();
 | 
			
		||||
  const date = newDate();
 | 
			
		||||
 | 
			
		||||
  const defaults: Insertable<Memories> = {
 | 
			
		||||
  const defaults: Insertable<MemoryTable> = {
 | 
			
		||||
    id,
 | 
			
		||||
    createdAt: date,
 | 
			
		||||
    updatedAt: date,
 | 
			
		||||
 | 
			
		||||
@ -1,8 +1,8 @@
 | 
			
		||||
import { Kysely } from 'kysely';
 | 
			
		||||
import { DB } from 'src/db';
 | 
			
		||||
import { ConfigRepository } from 'src/repositories/config.repository';
 | 
			
		||||
import { DatabaseRepository } from 'src/repositories/database.repository';
 | 
			
		||||
import { LoggingRepository } from 'src/repositories/logging.repository';
 | 
			
		||||
import { DB } from 'src/schema';
 | 
			
		||||
import { getKyselyConfig } from 'src/utils/database';
 | 
			
		||||
import { GenericContainer, Wait } from 'testcontainers';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
import { Kysely } from 'kysely';
 | 
			
		||||
import { DB } from 'src/db';
 | 
			
		||||
import { AssetRepository } from 'src/repositories/asset.repository';
 | 
			
		||||
import { LoggingRepository } from 'src/repositories/logging.repository';
 | 
			
		||||
import { DB } from 'src/schema';
 | 
			
		||||
import { AssetService } from 'src/services/asset.service';
 | 
			
		||||
import { newMediumService } from 'test/medium.factory';
 | 
			
		||||
import { factory } from 'test/small.factory';
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,6 @@
 | 
			
		||||
import { BadRequestException } from '@nestjs/common';
 | 
			
		||||
import { hash } from 'bcrypt';
 | 
			
		||||
import { Kysely } from 'kysely';
 | 
			
		||||
import { DB } from 'src/db';
 | 
			
		||||
import { AuthType } from 'src/enum';
 | 
			
		||||
import { AccessRepository } from 'src/repositories/access.repository';
 | 
			
		||||
import { ConfigRepository } from 'src/repositories/config.repository';
 | 
			
		||||
@ -13,6 +12,7 @@ import { SessionRepository } from 'src/repositories/session.repository';
 | 
			
		||||
import { StorageRepository } from 'src/repositories/storage.repository';
 | 
			
		||||
import { SystemMetadataRepository } from 'src/repositories/system-metadata.repository';
 | 
			
		||||
import { UserRepository } from 'src/repositories/user.repository';
 | 
			
		||||
import { DB } from 'src/schema';
 | 
			
		||||
import { AuthService } from 'src/services/auth.service';
 | 
			
		||||
import { mediumFactory, newMediumService } from 'test/medium.factory';
 | 
			
		||||
import { factory } from 'test/small.factory';
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,5 @@
 | 
			
		||||
import { Kysely } from 'kysely';
 | 
			
		||||
import { DateTime } from 'luxon';
 | 
			
		||||
import { DB } from 'src/db';
 | 
			
		||||
import { AssetFileType, MemoryType } from 'src/enum';
 | 
			
		||||
import { AccessRepository } from 'src/repositories/access.repository';
 | 
			
		||||
import { AssetRepository } from 'src/repositories/asset.repository';
 | 
			
		||||
@ -10,6 +9,7 @@ import { MemoryRepository } from 'src/repositories/memory.repository';
 | 
			
		||||
import { PartnerRepository } from 'src/repositories/partner.repository';
 | 
			
		||||
import { SystemMetadataRepository } from 'src/repositories/system-metadata.repository';
 | 
			
		||||
import { UserRepository } from 'src/repositories/user.repository';
 | 
			
		||||
import { DB } from 'src/schema';
 | 
			
		||||
import { MemoryService } from 'src/services/memory.service';
 | 
			
		||||
import { newMediumService } from 'test/medium.factory';
 | 
			
		||||
import { factory } from 'test/small.factory';
 | 
			
		||||
 | 
			
		||||
@ -1,10 +1,10 @@
 | 
			
		||||
import { Kysely } from 'kysely';
 | 
			
		||||
import { DB } from 'src/db';
 | 
			
		||||
import { AccessRepository } from 'src/repositories/access.repository';
 | 
			
		||||
import { DatabaseRepository } from 'src/repositories/database.repository';
 | 
			
		||||
import { LoggingRepository } from 'src/repositories/logging.repository';
 | 
			
		||||
import { PersonRepository } from 'src/repositories/person.repository';
 | 
			
		||||
import { StorageRepository } from 'src/repositories/storage.repository';
 | 
			
		||||
import { DB } from 'src/schema';
 | 
			
		||||
import { PersonService } from 'src/services/person.service';
 | 
			
		||||
import { newMediumService } from 'test/medium.factory';
 | 
			
		||||
import { factory } from 'test/small.factory';
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,5 @@
 | 
			
		||||
import { Kysely } from 'kysely';
 | 
			
		||||
import { DateTime } from 'luxon';
 | 
			
		||||
import { DB } from 'src/db';
 | 
			
		||||
import { ImmichEnvironment, JobName, JobStatus } from 'src/enum';
 | 
			
		||||
import { ConfigRepository } from 'src/repositories/config.repository';
 | 
			
		||||
import { CryptoRepository } from 'src/repositories/crypto.repository';
 | 
			
		||||
@ -8,6 +7,7 @@ import { JobRepository } from 'src/repositories/job.repository';
 | 
			
		||||
import { LoggingRepository } from 'src/repositories/logging.repository';
 | 
			
		||||
import { SystemMetadataRepository } from 'src/repositories/system-metadata.repository';
 | 
			
		||||
import { UserRepository } from 'src/repositories/user.repository';
 | 
			
		||||
import { DB } from 'src/schema';
 | 
			
		||||
import { UserService } from 'src/services/user.service';
 | 
			
		||||
import { mediumFactory, newMediumService } from 'test/medium.factory';
 | 
			
		||||
import { factory } from 'test/small.factory';
 | 
			
		||||
 | 
			
		||||
@ -1,11 +1,11 @@
 | 
			
		||||
import { Kysely } from 'kysely';
 | 
			
		||||
import { serverVersion } from 'src/constants';
 | 
			
		||||
import { DB } from 'src/db';
 | 
			
		||||
import { JobName } from 'src/enum';
 | 
			
		||||
import { DatabaseRepository } from 'src/repositories/database.repository';
 | 
			
		||||
import { JobRepository } from 'src/repositories/job.repository';
 | 
			
		||||
import { LoggingRepository } from 'src/repositories/logging.repository';
 | 
			
		||||
import { VersionHistoryRepository } from 'src/repositories/version-history.repository';
 | 
			
		||||
import { DB } from 'src/schema';
 | 
			
		||||
import { VersionService } from 'src/services/version.service';
 | 
			
		||||
import { newMediumService } from 'test/medium.factory';
 | 
			
		||||
import { getKyselyDB } from 'test/utils';
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
import { Kysely } from 'kysely';
 | 
			
		||||
import { DB } from 'src/db';
 | 
			
		||||
import { AlbumUserRole, SyncEntityType, SyncRequestType } from 'src/enum';
 | 
			
		||||
import { DB } from 'src/schema';
 | 
			
		||||
import { SyncTestContext } from 'test/medium.factory';
 | 
			
		||||
import { factory } from 'test/small.factory';
 | 
			
		||||
import { getKyselyDB, wait } from 'test/utils';
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
import { Kysely } from 'kysely';
 | 
			
		||||
import { DB } from 'src/db';
 | 
			
		||||
import { AlbumUserRole, SyncEntityType, SyncRequestType } from 'src/enum';
 | 
			
		||||
import { DB } from 'src/schema';
 | 
			
		||||
import { SyncTestContext } from 'test/medium.factory';
 | 
			
		||||
import { factory } from 'test/small.factory';
 | 
			
		||||
import { getKyselyDB, wait } from 'test/utils';
 | 
			
		||||
 | 
			
		||||
@ -1,8 +1,8 @@
 | 
			
		||||
import { Kysely } from 'kysely';
 | 
			
		||||
import { DB } from 'src/db';
 | 
			
		||||
import { AlbumUserRole, SyncEntityType, SyncRequestType } from 'src/enum';
 | 
			
		||||
import { AlbumRepository } from 'src/repositories/album.repository';
 | 
			
		||||
import { AssetRepository } from 'src/repositories/asset.repository';
 | 
			
		||||
import { DB } from 'src/schema';
 | 
			
		||||
import { SyncTestContext } from 'test/medium.factory';
 | 
			
		||||
import { getKyselyDB, wait } from 'test/utils';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
import { Kysely } from 'kysely';
 | 
			
		||||
import { DB } from 'src/db';
 | 
			
		||||
import { AlbumUserRole, SyncEntityType, SyncRequestType } from 'src/enum';
 | 
			
		||||
import { AlbumUserRepository } from 'src/repositories/album-user.repository';
 | 
			
		||||
import { DB } from 'src/schema';
 | 
			
		||||
import { SyncTestContext } from 'test/medium.factory';
 | 
			
		||||
import { getKyselyDB, wait } from 'test/utils';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,8 +1,8 @@
 | 
			
		||||
import { Kysely } from 'kysely';
 | 
			
		||||
import { DB } from 'src/db';
 | 
			
		||||
import { AlbumUserRole, SyncEntityType, SyncRequestType } from 'src/enum';
 | 
			
		||||
import { AlbumUserRepository } from 'src/repositories/album-user.repository';
 | 
			
		||||
import { AlbumRepository } from 'src/repositories/album.repository';
 | 
			
		||||
import { DB } from 'src/schema';
 | 
			
		||||
import { SyncTestContext } from 'test/medium.factory';
 | 
			
		||||
import { getKyselyDB } from 'test/utils';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
import { Kysely } from 'kysely';
 | 
			
		||||
import { DB } from 'src/db';
 | 
			
		||||
import { SyncEntityType, SyncRequestType } from 'src/enum';
 | 
			
		||||
import { DB } from 'src/schema';
 | 
			
		||||
import { SyncTestContext } from 'test/medium.factory';
 | 
			
		||||
import { factory } from 'test/small.factory';
 | 
			
		||||
import { getKyselyDB } from 'test/utils';
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
import { Kysely } from 'kysely';
 | 
			
		||||
import { DB } from 'src/db';
 | 
			
		||||
import { SyncEntityType, SyncRequestType } from 'src/enum';
 | 
			
		||||
import { AssetRepository } from 'src/repositories/asset.repository';
 | 
			
		||||
import { DB } from 'src/schema';
 | 
			
		||||
import { SyncTestContext } from 'test/medium.factory';
 | 
			
		||||
import { factory } from 'test/small.factory';
 | 
			
		||||
import { getKyselyDB } from 'test/utils';
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
import { Kysely } from 'kysely';
 | 
			
		||||
import { DB } from 'src/db';
 | 
			
		||||
import { SyncEntityType, SyncRequestType } from 'src/enum';
 | 
			
		||||
import { MemoryRepository } from 'src/repositories/memory.repository';
 | 
			
		||||
import { DB } from 'src/schema';
 | 
			
		||||
import { SyncTestContext } from 'test/medium.factory';
 | 
			
		||||
import { getKyselyDB } from 'test/utils';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
import { Kysely } from 'kysely';
 | 
			
		||||
import { DB } from 'src/db';
 | 
			
		||||
import { SyncEntityType, SyncRequestType } from 'src/enum';
 | 
			
		||||
import { MemoryRepository } from 'src/repositories/memory.repository';
 | 
			
		||||
import { DB } from 'src/schema';
 | 
			
		||||
import { SyncTestContext } from 'test/medium.factory';
 | 
			
		||||
import { getKyselyDB } from 'test/utils';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
import { Kysely } from 'kysely';
 | 
			
		||||
import { DB } from 'src/db';
 | 
			
		||||
import { SyncEntityType, SyncRequestType } from 'src/enum';
 | 
			
		||||
import { DB } from 'src/schema';
 | 
			
		||||
import { SyncTestContext } from 'test/medium.factory';
 | 
			
		||||
import { factory } from 'test/small.factory';
 | 
			
		||||
import { getKyselyDB, wait } from 'test/utils';
 | 
			
		||||
 | 
			
		||||
@ -1,9 +1,9 @@
 | 
			
		||||
import { Kysely } from 'kysely';
 | 
			
		||||
import { DB } from 'src/db';
 | 
			
		||||
import { SyncEntityType, SyncRequestType } from 'src/enum';
 | 
			
		||||
import { AssetRepository } from 'src/repositories/asset.repository';
 | 
			
		||||
import { PartnerRepository } from 'src/repositories/partner.repository';
 | 
			
		||||
import { UserRepository } from 'src/repositories/user.repository';
 | 
			
		||||
import { DB } from 'src/schema';
 | 
			
		||||
import { SyncTestContext } from 'test/medium.factory';
 | 
			
		||||
import { factory } from 'test/small.factory';
 | 
			
		||||
import { getKyselyDB, wait } from 'test/utils';
 | 
			
		||||
 | 
			
		||||
@ -1,8 +1,8 @@
 | 
			
		||||
import { Kysely } from 'kysely';
 | 
			
		||||
import { DB } from 'src/db';
 | 
			
		||||
import { SyncEntityType, SyncRequestType } from 'src/enum';
 | 
			
		||||
import { PartnerRepository } from 'src/repositories/partner.repository';
 | 
			
		||||
import { UserRepository } from 'src/repositories/user.repository';
 | 
			
		||||
import { DB } from 'src/schema';
 | 
			
		||||
import { SyncTestContext } from 'test/medium.factory';
 | 
			
		||||
import { getKyselyDB } from 'test/utils';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
import { Kysely } from 'kysely';
 | 
			
		||||
import { DB } from 'src/db';
 | 
			
		||||
import { SyncEntityType, SyncRequestType } from 'src/enum';
 | 
			
		||||
import { UserRepository } from 'src/repositories/user.repository';
 | 
			
		||||
import { DB } from 'src/schema';
 | 
			
		||||
import { SyncTestContext } from 'test/medium.factory';
 | 
			
		||||
import { getKyselyDB } from 'test/utils';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -7,7 +7,6 @@ import { ChildProcessWithoutNullStreams } from 'node:child_process';
 | 
			
		||||
import { Writable } from 'node:stream';
 | 
			
		||||
import { PNG } from 'pngjs';
 | 
			
		||||
import postgres from 'postgres';
 | 
			
		||||
import { DB } from 'src/db';
 | 
			
		||||
import { AssetUploadInterceptor } from 'src/middleware/asset-upload.interceptor';
 | 
			
		||||
import { AuthGuard } from 'src/middleware/auth.guard';
 | 
			
		||||
import { FileUploadInterceptor } from 'src/middleware/file-upload.interceptor';
 | 
			
		||||
@ -56,6 +55,7 @@ import { TrashRepository } from 'src/repositories/trash.repository';
 | 
			
		||||
import { UserRepository } from 'src/repositories/user.repository';
 | 
			
		||||
import { VersionHistoryRepository } from 'src/repositories/version-history.repository';
 | 
			
		||||
import { ViewRepository } from 'src/repositories/view-repository';
 | 
			
		||||
import { DB } from 'src/schema';
 | 
			
		||||
import { AuthService } from 'src/services/auth.service';
 | 
			
		||||
import { BaseService } from 'src/services/base.service';
 | 
			
		||||
import { RepositoryInterface } from 'src/types';
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user