feat: rename schema (#19891)

This commit is contained in:
Jason Rasmussen 2025-07-14 10:13:06 -04:00 committed by GitHub
parent 33c29e4305
commit c699df002a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
103 changed files with 4378 additions and 3224 deletions

View File

@ -20,7 +20,7 @@ describe('/api-keys', () => {
}); });
beforeEach(async () => { beforeEach(async () => {
await utils.resetDatabase(['api_keys']); await utils.resetDatabase(['api_key']);
}); });
describe('POST /api-keys', () => { describe('POST /api-keys', () => {

View File

@ -37,7 +37,7 @@ describe('/tags', () => {
beforeEach(async () => { beforeEach(async () => {
// tagging assets eventually triggers metadata extraction which can impact other tests // tagging assets eventually triggers metadata extraction which can impact other tests
await utils.waitForQueueFinish(admin.accessToken, 'metadataExtraction'); await utils.waitForQueueFinish(admin.accessToken, 'metadataExtraction');
await utils.resetDatabase(['tags']); await utils.resetDatabase(['tag']);
}); });
describe('POST /tags', () => { describe('POST /tags', () => {

View File

@ -97,7 +97,7 @@ describe(`immich upload`, () => {
}); });
beforeEach(async () => { beforeEach(async () => {
await utils.resetDatabase(['assets', 'albums']); await utils.resetDatabase(['asset', 'album']);
}); });
describe(`immich upload /path/to/file.jpg`, () => { describe(`immich upload /path/to/file.jpg`, () => {

View File

@ -154,19 +154,19 @@ export const utils = {
tables = tables || [ tables = tables || [
// TODO e2e test for deleting a stack, since it is quite complex // TODO e2e test for deleting a stack, since it is quite complex
'asset_stack', 'stack',
'libraries', 'library',
'shared_links', 'shared_link',
'person', 'person',
'albums', 'album',
'assets', 'asset',
'asset_faces', 'asset_face',
'activity', 'activity',
'api_keys', 'api_key',
'sessions', 'session',
'users', 'user',
'system_metadata', 'system_metadata',
'tags', 'tag',
]; ];
const sql: string[] = []; const sql: string[] = [];
@ -175,7 +175,7 @@ export const utils = {
if (table === 'system_metadata') { if (table === 'system_metadata') {
sql.push(`DELETE FROM "system_metadata" where "key" NOT IN ('reverse-geocoding-state', 'system-flags');`); sql.push(`DELETE FROM "system_metadata" where "key" NOT IN ('reverse-geocoding-state', 'system-flags');`);
} else { } else {
sql.push(`DELETE FROM ${table} CASCADE;`); sql.push(`DELETE FROM "${table}" CASCADE;`);
} }
} }
@ -451,7 +451,7 @@ export const utils = {
return; return;
} }
await client.query('INSERT INTO asset_faces ("assetId", "personId") VALUES ($1, $2)', [assetId, personId]); await client.query('INSERT INTO asset_face ("assetId", "personId") VALUES ($1, $2)', [assetId, personId]);
}, },
setPersonThumbnail: async (personId: string) => { setPersonThumbnail: async (personId: string) => {

View File

@ -9,13 +9,7 @@ import { ConfigRepository } from 'src/repositories/config.repository';
import { DatabaseRepository } from 'src/repositories/database.repository'; import { DatabaseRepository } from 'src/repositories/database.repository';
import { LoggingRepository } from 'src/repositories/logging.repository'; import { LoggingRepository } from 'src/repositories/logging.repository';
import 'src/schema'; import 'src/schema';
import { import { schemaDiff, schemaFromCode, schemaFromDatabase } from 'src/sql-tools';
DefaultNamingStrategy,
HashNamingStrategy,
schemaDiff,
schemaFromCode,
schemaFromDatabase,
} from 'src/sql-tools';
import { asPostgresConnectionConfig, getKyselyConfig } from 'src/utils/database'; import { asPostgresConnectionConfig, getKyselyConfig } from 'src/utils/database';
const main = async () => { const main = async () => {
@ -113,22 +107,7 @@ const compare = async () => {
const { database } = configRepository.getEnv(); const { database } = configRepository.getEnv();
const db = postgres(asPostgresConnectionConfig(database.config)); const db = postgres(asPostgresConnectionConfig(database.config));
const tables = new Set<string>(); const source = schemaFromCode({ overrides: true, namingStrategy: 'default' });
const preferred = new DefaultNamingStrategy();
const fallback = new HashNamingStrategy();
const source = schemaFromCode({
overrides: true,
namingStrategy: {
getName(item) {
if ('tableName' in item && tables.has(item.tableName)) {
return preferred.getName(item);
}
return fallback.getName(item);
},
},
});
const target = await schemaFromDatabase(db, {}); const target = await schemaFromDatabase(db, {});
console.log(source.warnings.join('\n')); console.log(source.warnings.join('\n'));

View File

@ -13,7 +13,7 @@ import {
UserStatus, UserStatus,
} from 'src/enum'; } from 'src/enum';
import { AlbumTable } from 'src/schema/tables/album.table'; import { AlbumTable } from 'src/schema/tables/album.table';
import { ExifTable } from 'src/schema/tables/exif.table'; import { AssetExifTable } from 'src/schema/tables/asset-exif.table';
import { UserMetadataItem } from 'src/types'; import { UserMetadataItem } from 'src/types';
export type AuthUser = { export type AuthUser = {
@ -242,7 +242,7 @@ export type Session = {
isPendingSyncReset: boolean; isPendingSyncReset: boolean;
}; };
export type Exif = Omit<Selectable<ExifTable>, 'updatedAt' | 'updateId'>; export type Exif = Omit<Selectable<AssetExifTable>, 'updatedAt' | 'updateId'>;
export type Person = { export type Person = {
createdAt: Date; createdAt: Date;
@ -276,52 +276,45 @@ export type AssetFace = {
const userColumns = ['id', 'name', 'email', 'avatarColor', 'profileImagePath', 'profileChangedAt'] as const; const userColumns = ['id', 'name', 'email', 'avatarColor', 'profileImagePath', 'profileChangedAt'] as const;
const userWithPrefixColumns = [ const userWithPrefixColumns = [
'users.id', 'user2.id',
'users.name', 'user2.name',
'users.email', 'user2.email',
'users.avatarColor', 'user2.avatarColor',
'users.profileImagePath', 'user2.profileImagePath',
'users.profileChangedAt', 'user2.profileChangedAt',
] as const; ] as const;
export const columns = { export const columns = {
asset: [ asset: [
'assets.id', 'asset.id',
'assets.checksum', 'asset.checksum',
'assets.deviceAssetId', 'asset.deviceAssetId',
'assets.deviceId', 'asset.deviceId',
'assets.fileCreatedAt', 'asset.fileCreatedAt',
'assets.fileModifiedAt', 'asset.fileModifiedAt',
'assets.isExternal', 'asset.isExternal',
'assets.visibility', 'asset.visibility',
'assets.libraryId', 'asset.libraryId',
'assets.livePhotoVideoId', 'asset.livePhotoVideoId',
'assets.localDateTime', 'asset.localDateTime',
'assets.originalFileName', 'asset.originalFileName',
'assets.originalPath', 'asset.originalPath',
'assets.ownerId', 'asset.ownerId',
'assets.sidecarPath', 'asset.sidecarPath',
'assets.type', 'asset.type',
], ],
assetFiles: ['asset_files.id', 'asset_files.path', 'asset_files.type'], assetFiles: ['asset_file.id', 'asset_file.path', 'asset_file.type'],
authUser: [ authUser: ['user.id', 'user.name', 'user.email', 'user.isAdmin', 'user.quotaUsageInBytes', 'user.quotaSizeInBytes'],
'users.id', authApiKey: ['api_key.id', 'api_key.permissions'],
'users.name', authSession: ['session.id', 'session.isPendingSyncReset', 'session.updatedAt', 'session.pinExpiresAt'],
'users.email',
'users.isAdmin',
'users.quotaUsageInBytes',
'users.quotaSizeInBytes',
],
authApiKey: ['api_keys.id', 'api_keys.permissions'],
authSession: ['sessions.id', 'sessions.isPendingSyncReset', 'sessions.updatedAt', 'sessions.pinExpiresAt'],
authSharedLink: [ authSharedLink: [
'shared_links.id', 'shared_link.id',
'shared_links.userId', 'shared_link.userId',
'shared_links.expiresAt', 'shared_link.expiresAt',
'shared_links.showExif', 'shared_link.showExif',
'shared_links.allowUpload', 'shared_link.allowUpload',
'shared_links.allowDownload', 'shared_link.allowDownload',
'shared_links.password', 'shared_link.password',
], ],
user: userColumns, user: userColumns,
userWithPrefix: userWithPrefixColumns, userWithPrefix: userWithPrefixColumns,
@ -339,89 +332,83 @@ export const columns = {
'quotaSizeInBytes', 'quotaSizeInBytes',
'quotaUsageInBytes', 'quotaUsageInBytes',
], ],
tag: ['tags.id', 'tags.value', 'tags.createdAt', 'tags.updatedAt', 'tags.color', 'tags.parentId'], tag: ['tag.id', 'tag.value', 'tag.createdAt', 'tag.updatedAt', 'tag.color', 'tag.parentId'],
apiKey: ['id', 'name', 'userId', 'createdAt', 'updatedAt', 'permissions'], apiKey: ['id', 'name', 'userId', 'createdAt', 'updatedAt', 'permissions'],
notification: ['id', 'createdAt', 'level', 'type', 'title', 'description', 'data', 'readAt'], notification: ['id', 'createdAt', 'level', 'type', 'title', 'description', 'data', 'readAt'],
syncAsset: [ syncAsset: [
'assets.id', 'asset.id',
'assets.ownerId', 'asset.ownerId',
'assets.originalFileName', 'asset.originalFileName',
'assets.thumbhash', 'asset.thumbhash',
'assets.checksum', 'asset.checksum',
'assets.fileCreatedAt', 'asset.fileCreatedAt',
'assets.fileModifiedAt', 'asset.fileModifiedAt',
'assets.localDateTime', 'asset.localDateTime',
'assets.type', 'asset.type',
'assets.deletedAt', 'asset.deletedAt',
'assets.isFavorite', 'asset.isFavorite',
'assets.visibility', 'asset.visibility',
'assets.duration', 'asset.duration',
],
syncAlbumUser: ['album_users.albumsId as albumId', 'album_users.usersId as userId', 'album_users.role'],
syncStack: [
'asset_stack.id',
'asset_stack.createdAt',
'asset_stack.updatedAt',
'asset_stack.primaryAssetId',
'asset_stack.ownerId',
], ],
syncAlbumUser: ['album_user.albumsId as albumId', 'album_user.usersId as userId', 'album_user.role'],
syncStack: ['stack.id', 'stack.createdAt', 'stack.updatedAt', 'stack.primaryAssetId', 'stack.ownerId'],
stack: ['stack.id', 'stack.primaryAssetId', 'ownerId'], stack: ['stack.id', 'stack.primaryAssetId', 'ownerId'],
syncAssetExif: [ syncAssetExif: [
'exif.assetId', 'asset_exif.assetId',
'exif.description', 'asset_exif.description',
'exif.exifImageWidth', 'asset_exif.exifImageWidth',
'exif.exifImageHeight', 'asset_exif.exifImageHeight',
'exif.fileSizeInByte', 'asset_exif.fileSizeInByte',
'exif.orientation', 'asset_exif.orientation',
'exif.dateTimeOriginal', 'asset_exif.dateTimeOriginal',
'exif.modifyDate', 'asset_exif.modifyDate',
'exif.timeZone', 'asset_exif.timeZone',
'exif.latitude', 'asset_exif.latitude',
'exif.longitude', 'asset_exif.longitude',
'exif.projectionType', 'asset_exif.projectionType',
'exif.city', 'asset_exif.city',
'exif.state', 'asset_exif.state',
'exif.country', 'asset_exif.country',
'exif.make', 'asset_exif.make',
'exif.model', 'asset_exif.model',
'exif.lensModel', 'asset_exif.lensModel',
'exif.fNumber', 'asset_exif.fNumber',
'exif.focalLength', 'asset_exif.focalLength',
'exif.iso', 'asset_exif.iso',
'exif.exposureTime', 'asset_exif.exposureTime',
'exif.profileDescription', 'asset_exif.profileDescription',
'exif.rating', 'asset_exif.rating',
'exif.fps', 'asset_exif.fps',
], ],
exif: [ exif: [
'exif.assetId', 'asset_exif.assetId',
'exif.autoStackId', 'asset_exif.autoStackId',
'exif.bitsPerSample', 'asset_exif.bitsPerSample',
'exif.city', 'asset_exif.city',
'exif.colorspace', 'asset_exif.colorspace',
'exif.country', 'asset_exif.country',
'exif.dateTimeOriginal', 'asset_exif.dateTimeOriginal',
'exif.description', 'asset_exif.description',
'exif.exifImageHeight', 'asset_exif.exifImageHeight',
'exif.exifImageWidth', 'asset_exif.exifImageWidth',
'exif.exposureTime', 'asset_exif.exposureTime',
'exif.fileSizeInByte', 'asset_exif.fileSizeInByte',
'exif.fNumber', 'asset_exif.fNumber',
'exif.focalLength', 'asset_exif.focalLength',
'exif.fps', 'asset_exif.fps',
'exif.iso', 'asset_exif.iso',
'exif.latitude', 'asset_exif.latitude',
'exif.lensModel', 'asset_exif.lensModel',
'exif.livePhotoCID', 'asset_exif.livePhotoCID',
'exif.longitude', 'asset_exif.longitude',
'exif.make', 'asset_exif.make',
'exif.model', 'asset_exif.model',
'exif.modifyDate', 'asset_exif.modifyDate',
'exif.orientation', 'asset_exif.orientation',
'exif.profileDescription', 'asset_exif.profileDescription',
'exif.projectionType', 'asset_exif.projectionType',
'exif.rating', 'asset_exif.rating',
'exif.state', 'asset_exif.state',
'exif.timeZone', 'asset_exif.timeZone',
], ],
} as const; } as const;

View File

@ -14,161 +14,161 @@ select
"activity"."id" "activity"."id"
from from
"activity" "activity"
left join "albums" on "activity"."albumId" = "albums"."id" left join "album" on "activity"."albumId" = "album"."id"
and "albums"."deletedAt" is null and "album"."deletedAt" is null
where where
"activity"."id" in ($1) "activity"."id" in ($1)
and "albums"."ownerId" = $2::uuid and "album"."ownerId" = $2::uuid
-- AccessRepository.activity.checkCreateAccess -- AccessRepository.activity.checkCreateAccess
select select
"albums"."id" "album"."id"
from from
"albums" "album"
left join "albums_shared_users_users" as "albumUsers" on "albumUsers"."albumsId" = "albums"."id" left join "album_user" as "albumUsers" on "albumUsers"."albumsId" = "album"."id"
left join "users" on "users"."id" = "albumUsers"."usersId" left join "user" on "user"."id" = "albumUsers"."usersId"
and "users"."deletedAt" is null and "user"."deletedAt" is null
where where
"albums"."id" in ($1) "album"."id" in ($1)
and "albums"."isActivityEnabled" = $2 and "album"."isActivityEnabled" = $2
and ( and (
"albums"."ownerId" = $3 "album"."ownerId" = $3
or "users"."id" = $4 or "user"."id" = $4
) )
and "albums"."deletedAt" is null and "album"."deletedAt" is null
-- AccessRepository.album.checkOwnerAccess -- AccessRepository.album.checkOwnerAccess
select select
"albums"."id" "album"."id"
from from
"albums" "album"
where where
"albums"."id" in ($1) "album"."id" in ($1)
and "albums"."ownerId" = $2 and "album"."ownerId" = $2
and "albums"."deletedAt" is null and "album"."deletedAt" is null
-- AccessRepository.album.checkSharedAlbumAccess -- AccessRepository.album.checkSharedAlbumAccess
select select
"albums"."id" "album"."id"
from from
"albums" "album"
left join "albums_shared_users_users" as "albumUsers" on "albumUsers"."albumsId" = "albums"."id" left join "album_user" on "album_user"."albumsId" = "album"."id"
left join "users" on "users"."id" = "albumUsers"."usersId" left join "user" on "user"."id" = "album_user"."usersId"
and "users"."deletedAt" is null and "user"."deletedAt" is null
where where
"albums"."id" in ($1) "album"."id" in ($1)
and "albums"."deletedAt" is null and "album"."deletedAt" is null
and "users"."id" = $2 and "user"."id" = $2
and "albumUsers"."role" in ($3, $4) and "album_user"."role" in ($3, $4)
-- AccessRepository.album.checkSharedLinkAccess -- AccessRepository.album.checkSharedLinkAccess
select select
"shared_links"."albumId" "shared_link"."albumId"
from from
"shared_links" "shared_link"
where where
"shared_links"."id" = $1 "shared_link"."id" = $1
and "shared_links"."albumId" in ($2) and "shared_link"."albumId" in ($2)
-- AccessRepository.asset.checkAlbumAccess -- AccessRepository.asset.checkAlbumAccess
select select
"assets"."id", "asset"."id",
"assets"."livePhotoVideoId" "asset"."livePhotoVideoId"
from from
"albums" "album"
inner join "albums_assets_assets" as "albumAssets" on "albums"."id" = "albumAssets"."albumsId" inner join "album_asset" as "albumAssets" on "album"."id" = "albumAssets"."albumsId"
inner join "assets" on "assets"."id" = "albumAssets"."assetsId" inner join "asset" on "asset"."id" = "albumAssets"."assetsId"
and "assets"."deletedAt" is null and "asset"."deletedAt" is null
left join "albums_shared_users_users" as "albumUsers" on "albumUsers"."albumsId" = "albums"."id" left join "album_user" as "albumUsers" on "albumUsers"."albumsId" = "album"."id"
left join "users" on "users"."id" = "albumUsers"."usersId" left join "user" on "user"."id" = "albumUsers"."usersId"
and "users"."deletedAt" is null and "user"."deletedAt" is null
where where
array["assets"."id", "assets"."livePhotoVideoId"] && array[$1]::uuid[] array["asset"."id", "asset"."livePhotoVideoId"] && array[$1]::uuid[]
and ( and (
"albums"."ownerId" = $2 "album"."ownerId" = $2
or "users"."id" = $3 or "user"."id" = $3
) )
and "albums"."deletedAt" is null and "album"."deletedAt" is null
-- AccessRepository.asset.checkOwnerAccess -- AccessRepository.asset.checkOwnerAccess
select select
"assets"."id" "asset"."id"
from from
"assets" "asset"
where where
"assets"."id" in ($1) "asset"."id" in ($1)
and "assets"."ownerId" = $2 and "asset"."ownerId" = $2
and "assets"."visibility" != $3 and "asset"."visibility" != $3
-- AccessRepository.asset.checkPartnerAccess -- AccessRepository.asset.checkPartnerAccess
select select
"assets"."id" "asset"."id"
from from
"partners" as "partner" "partner"
inner join "users" as "sharedBy" on "sharedBy"."id" = "partner"."sharedById" inner join "user" as "sharedBy" on "sharedBy"."id" = "partner"."sharedById"
and "sharedBy"."deletedAt" is null and "sharedBy"."deletedAt" is null
inner join "assets" on "assets"."ownerId" = "sharedBy"."id" inner join "asset" on "asset"."ownerId" = "sharedBy"."id"
and "assets"."deletedAt" is null and "asset"."deletedAt" is null
where where
"partner"."sharedWithId" = $1 "partner"."sharedWithId" = $1
and ( and (
"assets"."visibility" = 'timeline' "asset"."visibility" = 'timeline'
or "assets"."visibility" = 'hidden' or "asset"."visibility" = 'hidden'
) )
and "assets"."id" in ($2) and "asset"."id" in ($2)
-- AccessRepository.asset.checkSharedLinkAccess -- AccessRepository.asset.checkSharedLinkAccess
select select
"assets"."id" as "assetId", "asset"."id" as "assetId",
"assets"."livePhotoVideoId" as "assetLivePhotoVideoId", "asset"."livePhotoVideoId" as "assetLivePhotoVideoId",
"albumAssets"."id" as "albumAssetId", "albumAssets"."id" as "albumAssetId",
"albumAssets"."livePhotoVideoId" as "albumAssetLivePhotoVideoId" "albumAssets"."livePhotoVideoId" as "albumAssetLivePhotoVideoId"
from from
"shared_links" "shared_link"
left join "albums" on "albums"."id" = "shared_links"."albumId" left join "album" on "album"."id" = "shared_link"."albumId"
and "albums"."deletedAt" is null and "album"."deletedAt" is null
left join "shared_link__asset" on "shared_link__asset"."sharedLinksId" = "shared_links"."id" left join "shared_link_asset" on "shared_link_asset"."sharedLinksId" = "shared_link"."id"
left join "assets" on "assets"."id" = "shared_link__asset"."assetsId" left join "asset" on "asset"."id" = "shared_link_asset"."assetsId"
and "assets"."deletedAt" is null and "asset"."deletedAt" is null
left join "albums_assets_assets" on "albums_assets_assets"."albumsId" = "albums"."id" left join "album_asset" on "album_asset"."albumsId" = "album"."id"
left join "assets" as "albumAssets" on "albumAssets"."id" = "albums_assets_assets"."assetsId" left join "asset" as "albumAssets" on "albumAssets"."id" = "album_asset"."assetsId"
and "albumAssets"."deletedAt" is null and "albumAssets"."deletedAt" is null
where where
"shared_links"."id" = $1 "shared_link"."id" = $1
and array[ and array[
"assets"."id", "asset"."id",
"assets"."livePhotoVideoId", "asset"."livePhotoVideoId",
"albumAssets"."id", "albumAssets"."id",
"albumAssets"."livePhotoVideoId" "albumAssets"."livePhotoVideoId"
] && array[$2]::uuid[] ] && array[$2]::uuid[]
-- AccessRepository.authDevice.checkOwnerAccess -- AccessRepository.authDevice.checkOwnerAccess
select select
"sessions"."id" "session"."id"
from from
"sessions" "session"
where where
"sessions"."userId" = $1 "session"."userId" = $1
and "sessions"."id" in ($2) and "session"."id" in ($2)
-- AccessRepository.memory.checkOwnerAccess -- AccessRepository.memory.checkOwnerAccess
select select
"memories"."id" "memory"."id"
from from
"memories" "memory"
where where
"memories"."id" in ($1) "memory"."id" in ($1)
and "memories"."ownerId" = $2 and "memory"."ownerId" = $2
and "memories"."deletedAt" is null and "memory"."deletedAt" is null
-- AccessRepository.notification.checkOwnerAccess -- AccessRepository.notification.checkOwnerAccess
select select
"notifications"."id" "notification"."id"
from from
"notifications" "notification"
where where
"notifications"."id" in ($1) "notification"."id" in ($1)
and "notifications"."userId" = $2 and "notification"."userId" = $2
-- AccessRepository.person.checkOwnerAccess -- AccessRepository.person.checkOwnerAccess
select select
@ -181,56 +181,56 @@ where
-- AccessRepository.person.checkFaceOwnerAccess -- AccessRepository.person.checkFaceOwnerAccess
select select
"asset_faces"."id" "asset_face"."id"
from from
"asset_faces" "asset_face"
left join "assets" on "assets"."id" = "asset_faces"."assetId" left join "asset" on "asset"."id" = "asset_face"."assetId"
and "assets"."deletedAt" is null and "asset"."deletedAt" is null
where where
"asset_faces"."id" in ($1) "asset_face"."id" in ($1)
and "assets"."ownerId" = $2 and "asset"."ownerId" = $2
-- AccessRepository.partner.checkUpdateAccess -- AccessRepository.partner.checkUpdateAccess
select select
"partners"."sharedById" "partner"."sharedById"
from from
"partners" "partner"
where where
"partners"."sharedById" in ($1) "partner"."sharedById" in ($1)
and "partners"."sharedWithId" = $2 and "partner"."sharedWithId" = $2
-- AccessRepository.session.checkOwnerAccess -- AccessRepository.session.checkOwnerAccess
select select
"sessions"."id" "session"."id"
from from
"sessions" "session"
where where
"sessions"."id" in ($1) "session"."id" in ($1)
and "sessions"."userId" = $2 and "session"."userId" = $2
-- AccessRepository.stack.checkOwnerAccess -- AccessRepository.stack.checkOwnerAccess
select select
"stacks"."id" "stack"."id"
from from
"asset_stack" as "stacks" "stack"
where where
"stacks"."id" in ($1) "stack"."id" in ($1)
and "stacks"."ownerId" = $2 and "stack"."ownerId" = $2
-- AccessRepository.tag.checkOwnerAccess -- AccessRepository.tag.checkOwnerAccess
select select
"tags"."id" "tag"."id"
from from
"tags" "tag"
where where
"tags"."id" in ($1) "tag"."id" in ($1)
and "tags"."userId" = $2 and "tag"."userId" = $2
-- AccessRepository.timeline.checkPartnerAccess -- AccessRepository.timeline.checkPartnerAccess
select select
"partners"."sharedById" "partner"."sharedById"
from from
"partners" "partner"
where where
"partners"."sharedById" in ($1) "partner"."sharedById" in ($1)
and "partners"."sharedWithId" = $2 and "partner"."sharedWithId" = $2

View File

@ -6,26 +6,26 @@ select
to_json("user") as "user" to_json("user") as "user"
from from
"activity" "activity"
inner join "users" on "users"."id" = "activity"."userId" inner join "user" as "user2" on "user2"."id" = "activity"."userId"
and "users"."deletedAt" is null and "user2"."deletedAt" is null
inner join lateral ( inner join lateral (
select select
"users"."id", "user2"."id",
"users"."name", "user2"."name",
"users"."email", "user2"."email",
"users"."avatarColor", "user2"."avatarColor",
"users"."profileImagePath", "user2"."profileImagePath",
"users"."profileChangedAt" "user2"."profileChangedAt"
from from
( (
select select
1 1
) as "dummy" ) as "dummy"
) as "user" on true ) as "user" on true
left join "assets" on "assets"."id" = "activity"."assetId" left join "asset" on "asset"."id" = "activity"."assetId"
where where
"activity"."albumId" = $1 "activity"."albumId" = $1
and "assets"."deletedAt" is null and "asset"."deletedAt" is null
order by order by
"activity"."createdAt" asc "activity"."createdAt" asc
@ -49,9 +49,9 @@ returning
"profileImagePath", "profileImagePath",
"profileChangedAt" "profileChangedAt"
from from
"users" "user"
where where
"users"."id" = "activity"."userId" "user"."id" = "activity"."userId"
) as obj ) as obj
) as "user" ) as "user"
@ -72,16 +72,16 @@ select
) as "likes" ) as "likes"
from from
"activity" "activity"
inner join "users" on "users"."id" = "activity"."userId" inner join "user" on "user"."id" = "activity"."userId"
and "users"."deletedAt" is null and "user"."deletedAt" is null
left join "assets" on "assets"."id" = "activity"."assetId" left join "asset" on "asset"."id" = "activity"."assetId"
where where
"activity"."assetId" = $3 "activity"."assetId" = $3
and "activity"."albumId" = $4 and "activity"."albumId" = $4
and ( and (
( (
"assets"."deletedAt" is null "asset"."deletedAt" is null
and "assets"."visibility" != 'locked' and "asset"."visibility" != 'locked'
) )
or "assets"."id" is null or "asset"."id" is null
) )

View File

@ -2,7 +2,7 @@
-- AlbumRepository.getById -- AlbumRepository.getById
select select
"albums".*, "album".*,
( (
select select
to_json(obj) to_json(obj)
@ -16,9 +16,9 @@ select
"profileImagePath", "profileImagePath",
"profileChangedAt" "profileChangedAt"
from from
"users" "user"
where where
"users"."id" = "albums"."ownerId" "user"."id" = "album"."ownerId"
) as obj ) as obj
) as "owner", ) as "owner",
( (
@ -27,7 +27,7 @@ select
from from
( (
select select
"album_users"."role", "album_user"."role",
( (
select select
to_json(obj) to_json(obj)
@ -41,15 +41,15 @@ select
"profileImagePath", "profileImagePath",
"profileChangedAt" "profileChangedAt"
from from
"users" "user"
where where
"users"."id" = "album_users"."usersId" "user"."id" = "album_user"."usersId"
) as obj ) as obj
) as "user" ) as "user"
from from
"albums_shared_users_users" as "album_users" "album_user"
where where
"album_users"."albumsId" = "albums"."id" "album_user"."albumsId" = "album"."id"
) as agg ) as agg
) as "albumUsers", ) as "albumUsers",
( (
@ -60,9 +60,9 @@ select
select select
* *
from from
"shared_links" "shared_link"
where where
"shared_links"."albumId" = "albums"."id" "shared_link"."albumId" = "album"."id"
) as agg ) as agg
) as "sharedLinks", ) as "sharedLinks",
( (
@ -71,29 +71,29 @@ select
from from
( (
select select
"assets".*, "asset".*,
"exif" as "exifInfo" "asset_exif" as "exifInfo"
from from
"assets" "asset"
left join "exif" on "assets"."id" = "exif"."assetId" left join "asset_exif" on "asset"."id" = "asset_exif"."assetId"
inner join "albums_assets_assets" on "albums_assets_assets"."assetsId" = "assets"."id" inner join "album_asset" on "album_asset"."assetsId" = "asset"."id"
where where
"albums_assets_assets"."albumsId" = "albums"."id" "album_asset"."albumsId" = "album"."id"
and "assets"."deletedAt" is null and "asset"."deletedAt" is null
and "assets"."visibility" in ('archive', 'timeline') and "asset"."visibility" in ('archive', 'timeline')
order by order by
"assets"."fileCreatedAt" desc "asset"."fileCreatedAt" desc
) as "asset" ) as "asset"
) as "assets" ) as "assets"
from from
"albums" "album"
where where
"albums"."id" = $1 "album"."id" = $1
and "albums"."deletedAt" is null and "album"."deletedAt" is null
-- AlbumRepository.getByAssetId -- AlbumRepository.getByAssetId
select select
"albums".*, "album".*,
( (
select select
to_json(obj) to_json(obj)
@ -107,9 +107,9 @@ select
"profileImagePath", "profileImagePath",
"profileChangedAt" "profileChangedAt"
from from
"users" "user"
where where
"users"."id" = "albums"."ownerId" "user"."id" = "album"."ownerId"
) as obj ) as obj
) as "owner", ) as "owner",
( (
@ -118,7 +118,7 @@ select
from from
( (
select select
"album_users"."role", "album_user"."role",
( (
select select
to_json(obj) to_json(obj)
@ -132,62 +132,62 @@ select
"profileImagePath", "profileImagePath",
"profileChangedAt" "profileChangedAt"
from from
"users" "user"
where where
"users"."id" = "album_users"."usersId" "user"."id" = "album_user"."usersId"
) as obj ) as obj
) as "user" ) as "user"
from from
"albums_shared_users_users" as "album_users" "album_user"
where where
"album_users"."albumsId" = "albums"."id" "album_user"."albumsId" = "album"."id"
) as agg ) as agg
) as "albumUsers" ) as "albumUsers"
from from
"albums" "album"
inner join "albums_assets_assets" as "album_assets" on "album_assets"."albumsId" = "albums"."id" inner join "album_asset" on "album_asset"."albumsId" = "album"."id"
where where
( (
"albums"."ownerId" = $1 "album"."ownerId" = $1
or exists ( or exists (
select select
from from
"albums_shared_users_users" as "album_users" "album_user"
where where
"album_users"."albumsId" = "albums"."id" "album_user"."albumsId" = "album"."id"
and "album_users"."usersId" = $2 and "album_user"."usersId" = $2
) )
) )
and "album_assets"."assetsId" = $3 and "album_asset"."assetsId" = $3
and "albums"."deletedAt" is null and "album"."deletedAt" is null
order by order by
"albums"."createdAt" desc, "album"."createdAt" desc,
"albums"."createdAt" desc "album"."createdAt" desc
-- AlbumRepository.getMetadataForIds -- AlbumRepository.getMetadataForIds
select select
"album_assets"."albumsId" as "albumId", "album_asset"."albumsId" as "albumId",
min( min(
("assets"."localDateTime" AT TIME ZONE 'UTC'::text)::date ("asset"."localDateTime" AT TIME ZONE 'UTC'::text)::date
) as "startDate", ) as "startDate",
max( max(
("assets"."localDateTime" AT TIME ZONE 'UTC'::text)::date ("asset"."localDateTime" AT TIME ZONE 'UTC'::text)::date
) as "endDate", ) as "endDate",
max("assets"."updatedAt") as "lastModifiedAssetTimestamp", max("asset"."updatedAt") as "lastModifiedAssetTimestamp",
count("assets"."id")::int as "assetCount" count("asset"."id")::int as "assetCount"
from from
"assets" "asset"
inner join "albums_assets_assets" as "album_assets" on "album_assets"."assetsId" = "assets"."id" inner join "album_asset" on "album_asset"."assetsId" = "asset"."id"
where where
"assets"."visibility" in ('archive', 'timeline') "asset"."visibility" in ('archive', 'timeline')
and "album_assets"."albumsId" in ($1) and "album_asset"."albumsId" in ($1)
and "assets"."deletedAt" is null and "asset"."deletedAt" is null
group by group by
"album_assets"."albumsId" "album_asset"."albumsId"
-- AlbumRepository.getOwned -- AlbumRepository.getOwned
select select
"albums".*, "album".*,
( (
select select
to_json(obj) to_json(obj)
@ -201,9 +201,9 @@ select
"profileImagePath", "profileImagePath",
"profileChangedAt" "profileChangedAt"
from from
"users" "user"
where where
"users"."id" = "albums"."ownerId" "user"."id" = "album"."ownerId"
) as obj ) as obj
) as "owner", ) as "owner",
( (
@ -212,7 +212,7 @@ select
from from
( (
select select
"album_users"."role", "album_user"."role",
( (
select select
to_json(obj) to_json(obj)
@ -226,15 +226,15 @@ select
"profileImagePath", "profileImagePath",
"profileChangedAt" "profileChangedAt"
from from
"users" "user"
where where
"users"."id" = "album_users"."usersId" "user"."id" = "album_user"."usersId"
) as obj ) as obj
) as "user" ) as "user"
from from
"albums_shared_users_users" as "album_users" "album_user"
where where
"album_users"."albumsId" = "albums"."id" "album_user"."albumsId" = "album"."id"
) as agg ) as agg
) as "albumUsers", ) as "albumUsers",
( (
@ -245,29 +245,29 @@ select
select select
* *
from from
"shared_links" "shared_link"
where where
"shared_links"."albumId" = "albums"."id" "shared_link"."albumId" = "album"."id"
) as agg ) as agg
) as "sharedLinks" ) as "sharedLinks"
from from
"albums" "album"
where where
"albums"."ownerId" = $1 "album"."ownerId" = $1
and "albums"."deletedAt" is null and "album"."deletedAt" is null
order by order by
"albums"."createdAt" desc "album"."createdAt" desc
-- AlbumRepository.getShared -- AlbumRepository.getShared
select select
"albums".*, "album".*,
( (
select select
coalesce(json_agg(agg), '[]') coalesce(json_agg(agg), '[]')
from from
( (
select select
"album_users"."role", "album_user"."role",
( (
select select
to_json(obj) to_json(obj)
@ -281,15 +281,15 @@ select
"profileImagePath", "profileImagePath",
"profileChangedAt" "profileChangedAt"
from from
"users" "user"
where where
"users"."id" = "album_users"."usersId" "user"."id" = "album_user"."usersId"
) as obj ) as obj
) as "user" ) as "user"
from from
"albums_shared_users_users" as "album_users" "album_user"
where where
"album_users"."albumsId" = "albums"."id" "album_user"."albumsId" = "album"."id"
) as agg ) as agg
) as "albumUsers", ) as "albumUsers",
( (
@ -305,9 +305,9 @@ select
"profileImagePath", "profileImagePath",
"profileChangedAt" "profileChangedAt"
from from
"users" "user"
where where
"users"."id" = "albums"."ownerId" "user"."id" = "album"."ownerId"
) as obj ) as obj
) as "owner", ) as "owner",
( (
@ -318,42 +318,42 @@ select
select select
* *
from from
"shared_links" "shared_link"
where where
"shared_links"."albumId" = "albums"."id" "shared_link"."albumId" = "album"."id"
) as agg ) as agg
) as "sharedLinks" ) as "sharedLinks"
from from
"albums" "album"
where where
( (
exists ( exists (
select select
from from
"albums_shared_users_users" as "album_users" "album_user"
where where
"album_users"."albumsId" = "albums"."id" "album_user"."albumsId" = "album"."id"
and ( and (
"albums"."ownerId" = $1 "album"."ownerId" = $1
or "album_users"."usersId" = $2 or "album_user"."usersId" = $2
) )
) )
or exists ( or exists (
select select
from from
"shared_links" "shared_link"
where where
"shared_links"."albumId" = "albums"."id" "shared_link"."albumId" = "album"."id"
and "shared_links"."userId" = $3 and "shared_link"."userId" = $3
) )
) )
and "albums"."deletedAt" is null and "album"."deletedAt" is null
order by order by
"albums"."createdAt" desc "album"."createdAt" desc
-- AlbumRepository.getNotShared -- AlbumRepository.getNotShared
select select
"albums".*, "album".*,
( (
select select
to_json(obj) to_json(obj)
@ -367,43 +367,43 @@ select
"profileImagePath", "profileImagePath",
"profileChangedAt" "profileChangedAt"
from from
"users" "user"
where where
"users"."id" = "albums"."ownerId" "user"."id" = "album"."ownerId"
) as obj ) as obj
) as "owner" ) as "owner"
from from
"albums" "album"
where where
"albums"."ownerId" = $1 "album"."ownerId" = $1
and "albums"."deletedAt" is null and "album"."deletedAt" is null
and not exists ( and not exists (
select select
from from
"albums_shared_users_users" as "album_users" "album_user"
where where
"album_users"."albumsId" = "albums"."id" "album_user"."albumsId" = "album"."id"
) )
and not exists ( and not exists (
select select
from from
"shared_links" "shared_link"
where where
"shared_links"."albumId" = "albums"."id" "shared_link"."albumId" = "album"."id"
) )
order by order by
"albums"."createdAt" desc "album"."createdAt" desc
-- AlbumRepository.removeAssetsFromAll -- AlbumRepository.removeAssetsFromAll
delete from "albums_assets_assets" delete from "album_asset"
where where
"albums_assets_assets"."assetsId" in ($1) "album_asset"."assetsId" in ($1)
-- AlbumRepository.getAssetIds -- AlbumRepository.getAssetIds
select select
* *
from from
"albums_assets_assets" "album_asset"
where where
"albums_assets_assets"."albumsId" = $1 "album_asset"."albumsId" = $1
and "albums_assets_assets"."assetsId" in ($2) and "album_asset"."assetsId" in ($2)

View File

@ -2,7 +2,7 @@
-- AlbumUserRepository.create -- AlbumUserRepository.create
insert into insert into
"albums_shared_users_users" ("usersId", "albumsId") "album_user" ("usersId", "albumsId")
values values
($1, $2) ($1, $2)
returning returning
@ -11,7 +11,7 @@ returning
"role" "role"
-- AlbumUserRepository.update -- AlbumUserRepository.update
update "albums_shared_users_users" update "album_user"
set set
"role" = $1 "role" = $1
where where
@ -21,7 +21,7 @@ returning
* *
-- AlbumUserRepository.delete -- AlbumUserRepository.delete
delete from "albums_shared_users_users" delete from "album_user"
where where
"usersId" = $1 "usersId" = $1
and "albumsId" = $2 and "albumsId" = $2

View File

@ -2,31 +2,31 @@
-- ApiKeyRepository.getKey -- ApiKeyRepository.getKey
select select
"api_keys"."id", "api_key"."id",
"api_keys"."permissions", "api_key"."permissions",
( (
select select
to_json(obj) to_json(obj)
from from
( (
select select
"users"."id", "user"."id",
"users"."name", "user"."name",
"users"."email", "user"."email",
"users"."isAdmin", "user"."isAdmin",
"users"."quotaUsageInBytes", "user"."quotaUsageInBytes",
"users"."quotaSizeInBytes" "user"."quotaSizeInBytes"
from from
"users" "user"
where where
"users"."id" = "api_keys"."userId" "user"."id" = "api_key"."userId"
and "users"."deletedAt" is null and "user"."deletedAt" is null
) as obj ) as obj
) as "user" ) as "user"
from from
"api_keys" "api_key"
where where
"api_keys"."key" = $1 "api_key"."key" = $1
-- ApiKeyRepository.getById -- ApiKeyRepository.getById
select select
@ -37,7 +37,7 @@ select
"updatedAt", "updatedAt",
"permissions" "permissions"
from from
"api_keys" "api_key"
where where
"id" = $1::uuid "id" = $1::uuid
and "userId" = $2 and "userId" = $2
@ -51,7 +51,7 @@ select
"updatedAt", "updatedAt",
"permissions" "permissions"
from from
"api_keys" "api_key"
where where
"userId" = $1 "userId" = $1
order by order by

View File

@ -10,10 +10,10 @@ select
"visibility", "visibility",
"smart_search"."embedding" "smart_search"."embedding"
from from
"assets" "asset"
left join "smart_search" on "assets"."id" = "smart_search"."assetId" left join "smart_search" on "asset"."id" = "smart_search"."assetId"
where where
"assets"."id" = $1::uuid "asset"."id" = $1::uuid
limit limit
$2 $2
@ -28,227 +28,227 @@ select
from from
( (
select select
"tags"."value" "tag"."value"
from from
"tags" "tag"
inner join "tag_asset" on "tags"."id" = "tag_asset"."tagsId" inner join "tag_asset" on "tag"."id" = "tag_asset"."tagsId"
where where
"assets"."id" = "tag_asset"."assetsId" "asset"."id" = "tag_asset"."assetsId"
) as agg ) as agg
) as "tags" ) as "tags"
from from
"assets" "asset"
where where
"assets"."id" = $1::uuid "asset"."id" = $1::uuid
limit limit
$2 $2
-- AssetJobRepository.streamForThumbnailJob -- AssetJobRepository.streamForThumbnailJob
select select
"assets"."id", "asset"."id",
"assets"."thumbhash", "asset"."thumbhash",
( (
select select
coalesce(json_agg(agg), '[]') coalesce(json_agg(agg), '[]')
from from
( (
select select
"asset_files"."id", "asset_file"."id",
"asset_files"."path", "asset_file"."path",
"asset_files"."type" "asset_file"."type"
from from
"asset_files" "asset_file"
where where
"asset_files"."assetId" = "assets"."id" "asset_file"."assetId" = "asset"."id"
) as agg ) as agg
) as "files" ) as "files"
from from
"assets" "asset"
inner join "asset_job_status" on "asset_job_status"."assetId" = "assets"."id" inner join "asset_job_status" on "asset_job_status"."assetId" = "asset"."id"
where where
"assets"."deletedAt" is null "asset"."deletedAt" is null
and "assets"."visibility" != $1 and "asset"."visibility" != $1
and ( and (
"asset_job_status"."previewAt" is null "asset_job_status"."previewAt" is null
or "asset_job_status"."thumbnailAt" is null or "asset_job_status"."thumbnailAt" is null
or "assets"."thumbhash" is null or "asset"."thumbhash" is null
) )
-- AssetJobRepository.getForMigrationJob -- AssetJobRepository.getForMigrationJob
select select
"assets"."id", "asset"."id",
"assets"."ownerId", "asset"."ownerId",
"assets"."encodedVideoPath", "asset"."encodedVideoPath",
( (
select select
coalesce(json_agg(agg), '[]') coalesce(json_agg(agg), '[]')
from from
( (
select select
"asset_files"."id", "asset_file"."id",
"asset_files"."path", "asset_file"."path",
"asset_files"."type" "asset_file"."type"
from from
"asset_files" "asset_file"
where where
"asset_files"."assetId" = "assets"."id" "asset_file"."assetId" = "asset"."id"
) as agg ) as agg
) as "files" ) as "files"
from from
"assets" "asset"
where where
"assets"."id" = $1 "asset"."id" = $1
-- AssetJobRepository.getForGenerateThumbnailJob -- AssetJobRepository.getForGenerateThumbnailJob
select select
"assets"."id", "asset"."id",
"assets"."visibility", "asset"."visibility",
"assets"."originalFileName", "asset"."originalFileName",
"assets"."originalPath", "asset"."originalPath",
"assets"."ownerId", "asset"."ownerId",
"assets"."thumbhash", "asset"."thumbhash",
"assets"."type", "asset"."type",
( (
select select
coalesce(json_agg(agg), '[]') coalesce(json_agg(agg), '[]')
from from
( (
select select
"asset_files"."id", "asset_file"."id",
"asset_files"."path", "asset_file"."path",
"asset_files"."type" "asset_file"."type"
from from
"asset_files" "asset_file"
where where
"asset_files"."assetId" = "assets"."id" "asset_file"."assetId" = "asset"."id"
) as agg ) as agg
) as "files", ) as "files",
to_json("exif") as "exifInfo" to_json("asset_exif") as "exifInfo"
from from
"assets" "asset"
inner join "exif" on "assets"."id" = "exif"."assetId" inner join "asset_exif" on "asset"."id" = "asset_exif"."assetId"
where where
"assets"."id" = $1 "asset"."id" = $1
-- AssetJobRepository.getForMetadataExtraction -- AssetJobRepository.getForMetadataExtraction
select select
"assets"."id", "asset"."id",
"assets"."checksum", "asset"."checksum",
"assets"."deviceAssetId", "asset"."deviceAssetId",
"assets"."deviceId", "asset"."deviceId",
"assets"."fileCreatedAt", "asset"."fileCreatedAt",
"assets"."fileModifiedAt", "asset"."fileModifiedAt",
"assets"."isExternal", "asset"."isExternal",
"assets"."visibility", "asset"."visibility",
"assets"."libraryId", "asset"."libraryId",
"assets"."livePhotoVideoId", "asset"."livePhotoVideoId",
"assets"."localDateTime", "asset"."localDateTime",
"assets"."originalFileName", "asset"."originalFileName",
"assets"."originalPath", "asset"."originalPath",
"assets"."ownerId", "asset"."ownerId",
"assets"."sidecarPath", "asset"."sidecarPath",
"assets"."type", "asset"."type",
( (
select select
coalesce(json_agg(agg), '[]') coalesce(json_agg(agg), '[]')
from from
( (
select select
"asset_faces".* "asset_face".*
from from
"asset_faces" "asset_face"
where where
"asset_faces"."assetId" = "assets"."id" "asset_face"."assetId" = "asset"."id"
and "asset_faces"."deletedAt" is null and "asset_face"."deletedAt" is null
) as agg ) as agg
) as "faces" ) as "faces"
from from
"assets" "asset"
where where
"assets"."id" = $1 "asset"."id" = $1
-- AssetJobRepository.getAlbumThumbnailFiles -- AssetJobRepository.getAlbumThumbnailFiles
select select
"asset_files"."id", "asset_file"."id",
"asset_files"."path", "asset_file"."path",
"asset_files"."type" "asset_file"."type"
from from
"asset_files" "asset_file"
where where
"asset_files"."assetId" = $1 "asset_file"."assetId" = $1
and "asset_files"."type" = $2 and "asset_file"."type" = $2
-- AssetJobRepository.streamForSearchDuplicates -- AssetJobRepository.streamForSearchDuplicates
select select
"assets"."id" "asset"."id"
from from
"assets" "asset"
inner join "smart_search" on "assets"."id" = "smart_search"."assetId" inner join "smart_search" on "asset"."id" = "smart_search"."assetId"
inner join "asset_job_status" as "job_status" on "job_status"."assetId" = "assets"."id" inner join "asset_job_status" as "job_status" on "job_status"."assetId" = "asset"."id"
where where
"assets"."deletedAt" is null "asset"."deletedAt" is null
and "assets"."visibility" in ('archive', 'timeline') and "asset"."visibility" in ('archive', 'timeline')
and "job_status"."duplicatesDetectedAt" is null and "job_status"."duplicatesDetectedAt" is null
-- AssetJobRepository.streamForEncodeClip -- AssetJobRepository.streamForEncodeClip
select select
"assets"."id" "asset"."id"
from from
"assets" "asset"
inner join "asset_job_status" as "job_status" on "assetId" = "assets"."id" inner join "asset_job_status" as "job_status" on "assetId" = "asset"."id"
where where
"assets"."visibility" != $1 "asset"."visibility" != $1
and "assets"."deletedAt" is null and "asset"."deletedAt" is null
and "job_status"."previewAt" is not null and "job_status"."previewAt" is not null
and not exists ( and not exists (
select select
from from
"smart_search" "smart_search"
where where
"assetId" = "assets"."id" "assetId" = "asset"."id"
) )
-- AssetJobRepository.getForClipEncoding -- AssetJobRepository.getForClipEncoding
select select
"assets"."id", "asset"."id",
"assets"."visibility", "asset"."visibility",
( (
select select
coalesce(json_agg(agg), '[]') coalesce(json_agg(agg), '[]')
from from
( (
select select
"asset_files"."id", "asset_file"."id",
"asset_files"."path", "asset_file"."path",
"asset_files"."type" "asset_file"."type"
from from
"asset_files" "asset_file"
where where
"asset_files"."assetId" = "assets"."id" "asset_file"."assetId" = "asset"."id"
and "asset_files"."type" = $1 and "asset_file"."type" = $1
) as agg ) as agg
) as "files" ) as "files"
from from
"assets" "asset"
where where
"assets"."id" = $2 "asset"."id" = $2
-- AssetJobRepository.getForDetectFacesJob -- AssetJobRepository.getForDetectFacesJob
select select
"assets"."id", "asset"."id",
"assets"."visibility", "asset"."visibility",
to_json("exif") as "exifInfo", to_json("asset_exif") as "exifInfo",
( (
select select
coalesce(json_agg(agg), '[]') coalesce(json_agg(agg), '[]')
from from
( (
select select
"asset_faces".* "asset_face".*
from from
"asset_faces" "asset_face"
where where
"asset_faces"."assetId" = "assets"."id" "asset_face"."assetId" = "asset"."id"
) as agg ) as agg
) as "faces", ) as "faces",
( (
@ -257,67 +257,67 @@ select
from from
( (
select select
"asset_files"."id", "asset_file"."id",
"asset_files"."path", "asset_file"."path",
"asset_files"."type" "asset_file"."type"
from from
"asset_files" "asset_file"
where where
"asset_files"."assetId" = "assets"."id" "asset_file"."assetId" = "asset"."id"
and "asset_files"."type" = $1 and "asset_file"."type" = $1
) as agg ) as agg
) as "files" ) as "files"
from from
"assets" "asset"
inner join "exif" on "assets"."id" = "exif"."assetId" inner join "asset_exif" on "asset"."id" = "asset_exif"."assetId"
where where
"assets"."id" = $2 "asset"."id" = $2
-- AssetJobRepository.getForSyncAssets -- AssetJobRepository.getForSyncAssets
select select
"assets"."id", "asset"."id",
"assets"."isOffline", "asset"."isOffline",
"assets"."libraryId", "asset"."libraryId",
"assets"."originalPath", "asset"."originalPath",
"assets"."status", "asset"."status",
"assets"."fileModifiedAt" "asset"."fileModifiedAt"
from from
"assets" "asset"
where where
"assets"."id" = any ($1::uuid[]) "asset"."id" = any ($1::uuid[])
-- AssetJobRepository.getForAssetDeletion -- AssetJobRepository.getForAssetDeletion
select select
"assets"."id", "asset"."id",
"assets"."visibility", "asset"."visibility",
"assets"."libraryId", "asset"."libraryId",
"assets"."ownerId", "asset"."ownerId",
"assets"."livePhotoVideoId", "asset"."livePhotoVideoId",
"assets"."sidecarPath", "asset"."sidecarPath",
"assets"."encodedVideoPath", "asset"."encodedVideoPath",
"assets"."originalPath", "asset"."originalPath",
to_json("exif") as "exifInfo", to_json("asset_exif") as "exifInfo",
( (
select select
coalesce(json_agg(agg), '[]') coalesce(json_agg(agg), '[]')
from from
( (
select select
"asset_faces".*, "asset_face".*,
"person" as "person" "person" as "person"
from from
"asset_faces" "asset_face"
left join lateral ( left join lateral (
select select
"person".* "person".*
from from
"person" "person"
where where
"asset_faces"."personId" = "person"."id" "asset_face"."personId" = "person"."id"
) as "person" on true ) as "person" on true
where where
"asset_faces"."assetId" = "assets"."id" "asset_face"."assetId" = "asset"."id"
and "asset_faces"."deletedAt" is null and "asset_face"."deletedAt" is null
) as agg ) as agg
) as "faces", ) as "faces",
( (
@ -326,156 +326,156 @@ select
from from
( (
select select
"asset_files"."id", "asset_file"."id",
"asset_files"."path", "asset_file"."path",
"asset_files"."type" "asset_file"."type"
from from
"asset_files" "asset_file"
where where
"asset_files"."assetId" = "assets"."id" "asset_file"."assetId" = "asset"."id"
) as agg ) as agg
) as "files", ) as "files",
to_json("stacked_assets") as "stack" to_json("stacked_assets") as "stack"
from from
"assets" "asset"
left join "exif" on "assets"."id" = "exif"."assetId" left join "asset_exif" on "asset"."id" = "asset_exif"."assetId"
left join "asset_stack" on "asset_stack"."id" = "assets"."stackId" left join "stack" on "stack"."id" = "asset"."stackId"
left join lateral ( left join lateral (
select select
"asset_stack"."id", "stack"."id",
"asset_stack"."primaryAssetId", "stack"."primaryAssetId",
array_agg("stacked") as "assets" array_agg("stacked") as "assets"
from from
"assets" as "stacked" "asset" as "stacked"
where where
"stacked"."deletedAt" is not null "stacked"."deletedAt" is not null
and "stacked"."visibility" = $1 and "stacked"."visibility" = $1
and "stacked"."stackId" = "asset_stack"."id" and "stacked"."stackId" = "stack"."id"
group by group by
"asset_stack"."id" "stack"."id"
) as "stacked_assets" on "asset_stack"."id" is not null ) as "stacked_assets" on "stack"."id" is not null
where where
"assets"."id" = $2 "asset"."id" = $2
-- AssetJobRepository.streamForVideoConversion -- AssetJobRepository.streamForVideoConversion
select select
"assets"."id" "asset"."id"
from from
"assets" "asset"
where where
"assets"."type" = $1 "asset"."type" = $1
and ( and (
"assets"."encodedVideoPath" is null "asset"."encodedVideoPath" is null
or "assets"."encodedVideoPath" = $2 or "asset"."encodedVideoPath" = $2
) )
and "assets"."visibility" != $3 and "asset"."visibility" != $3
and "assets"."deletedAt" is null and "asset"."deletedAt" is null
-- AssetJobRepository.getForVideoConversion -- AssetJobRepository.getForVideoConversion
select select
"assets"."id", "asset"."id",
"assets"."ownerId", "asset"."ownerId",
"assets"."originalPath", "asset"."originalPath",
"assets"."encodedVideoPath" "asset"."encodedVideoPath"
from from
"assets" "asset"
where where
"assets"."id" = $1 "asset"."id" = $1
and "assets"."type" = $2 and "asset"."type" = $2
-- AssetJobRepository.streamForMetadataExtraction -- AssetJobRepository.streamForMetadataExtraction
select select
"assets"."id" "asset"."id"
from from
"assets" "asset"
left join "asset_job_status" on "asset_job_status"."assetId" = "assets"."id" left join "asset_job_status" on "asset_job_status"."assetId" = "asset"."id"
where where
( (
"asset_job_status"."metadataExtractedAt" is null "asset_job_status"."metadataExtractedAt" is null
or "asset_job_status"."assetId" is null or "asset_job_status"."assetId" is null
) )
and "assets"."deletedAt" is null and "asset"."deletedAt" is null
-- AssetJobRepository.getForStorageTemplateJob -- AssetJobRepository.getForStorageTemplateJob
select select
"assets"."id", "asset"."id",
"assets"."ownerId", "asset"."ownerId",
"assets"."type", "asset"."type",
"assets"."checksum", "asset"."checksum",
"assets"."originalPath", "asset"."originalPath",
"assets"."isExternal", "asset"."isExternal",
"assets"."sidecarPath", "asset"."sidecarPath",
"assets"."originalFileName", "asset"."originalFileName",
"assets"."livePhotoVideoId", "asset"."livePhotoVideoId",
"assets"."fileCreatedAt", "asset"."fileCreatedAt",
"exif"."timeZone", "asset_exif"."timeZone",
"exif"."fileSizeInByte" "asset_exif"."fileSizeInByte"
from from
"assets" "asset"
inner join "exif" on "assets"."id" = "exif"."assetId" inner join "asset_exif" on "asset"."id" = "asset_exif"."assetId"
where where
"assets"."deletedAt" is null "asset"."deletedAt" is null
and "assets"."id" = $1 and "asset"."id" = $1
-- AssetJobRepository.streamForStorageTemplateJob -- AssetJobRepository.streamForStorageTemplateJob
select select
"assets"."id", "asset"."id",
"assets"."ownerId", "asset"."ownerId",
"assets"."type", "asset"."type",
"assets"."checksum", "asset"."checksum",
"assets"."originalPath", "asset"."originalPath",
"assets"."isExternal", "asset"."isExternal",
"assets"."sidecarPath", "asset"."sidecarPath",
"assets"."originalFileName", "asset"."originalFileName",
"assets"."livePhotoVideoId", "asset"."livePhotoVideoId",
"assets"."fileCreatedAt", "asset"."fileCreatedAt",
"exif"."timeZone", "asset_exif"."timeZone",
"exif"."fileSizeInByte" "asset_exif"."fileSizeInByte"
from from
"assets" "asset"
inner join "exif" on "assets"."id" = "exif"."assetId" inner join "asset_exif" on "asset"."id" = "asset_exif"."assetId"
where where
"assets"."deletedAt" is null "asset"."deletedAt" is null
-- AssetJobRepository.streamForDeletedJob -- AssetJobRepository.streamForDeletedJob
select select
"id", "id",
"isOffline" "isOffline"
from from
"assets" "asset"
where where
"assets"."deletedAt" <= $1 "asset"."deletedAt" <= $1
-- AssetJobRepository.streamForSidecar -- AssetJobRepository.streamForSidecar
select select
"assets"."id" "asset"."id"
from from
"assets" "asset"
where where
( (
"assets"."sidecarPath" = $1 "asset"."sidecarPath" = $1
or "assets"."sidecarPath" is null or "asset"."sidecarPath" is null
) )
and "assets"."visibility" != $2 and "asset"."visibility" != $2
-- AssetJobRepository.streamForDetectFacesJob -- AssetJobRepository.streamForDetectFacesJob
select select
"assets"."id" "asset"."id"
from from
"assets" "asset"
inner join "asset_job_status" as "job_status" on "assetId" = "assets"."id" inner join "asset_job_status" as "job_status" on "assetId" = "asset"."id"
where where
"assets"."visibility" != $1 "asset"."visibility" != $1
and "assets"."deletedAt" is null and "asset"."deletedAt" is null
and "job_status"."previewAt" is not null and "job_status"."previewAt" is not null
and "job_status"."facesRecognizedAt" is null and "job_status"."facesRecognizedAt" is null
order by order by
"assets"."createdAt" desc "asset"."createdAt" desc
-- AssetJobRepository.streamForMigrationJob -- AssetJobRepository.streamForMigrationJob
select select
"id" "id"
from from
"assets" "asset"
where where
"assets"."deletedAt" is null "asset"."deletedAt" is null

View File

@ -1,7 +1,7 @@
-- NOTE: This file is auto generated by ./sql-generator -- NOTE: This file is auto generated by ./sql-generator
-- AssetRepository.updateAllExif -- AssetRepository.updateAllExif
update "exif" update "asset_exif"
set set
"model" = $1 "model" = $1
where where
@ -23,42 +23,42 @@ with
min(("localDateTime" at time zone 'UTC')::date) min(("localDateTime" at time zone 'UTC')::date)
)::int )::int
from from
assets asset
), ),
date_part('year', current_date)::int - 1 date_part('year', current_date)::int - 1
) as "year" ) as "year"
) )
select select
"a".*, "a".*,
to_json("exif") as "exifInfo" to_json("asset_exif") as "exifInfo"
from from
"today" "today"
inner join lateral ( inner join lateral (
select select
"assets".* "asset".*
from from
"assets" "asset"
inner join "asset_job_status" on "assets"."id" = "asset_job_status"."assetId" inner join "asset_job_status" on "asset"."id" = "asset_job_status"."assetId"
where where
"asset_job_status"."previewAt" is not null "asset_job_status"."previewAt" is not null
and (assets."localDateTime" at time zone 'UTC')::date = today.date and (asset."localDateTime" at time zone 'UTC')::date = today.date
and "assets"."ownerId" = any ($3::uuid[]) and "asset"."ownerId" = any ($3::uuid[])
and "assets"."visibility" = $4 and "asset"."visibility" = $4
and exists ( and exists (
select select
from from
"asset_files" "asset_file"
where where
"assetId" = "assets"."id" "assetId" = "asset"."id"
and "asset_files"."type" = $5 and "asset_file"."type" = $5
) )
and "assets"."deletedAt" is null and "asset"."deletedAt" is null
order by order by
(assets."localDateTime" at time zone 'UTC')::date desc (asset."localDateTime" at time zone 'UTC')::date desc
limit limit
$6 $6
) as "a" on true ) as "a" on true
inner join "exif" on "a"."id" = "exif"."assetId" inner join "asset_exif" on "a"."id" = "asset_exif"."assetId"
) )
select select
date_part( date_part(
@ -75,36 +75,36 @@ order by
-- AssetRepository.getByIds -- AssetRepository.getByIds
select select
"assets".* "asset".*
from from
"assets" "asset"
where where
"assets"."id" = any ($1::uuid[]) "asset"."id" = any ($1::uuid[])
-- AssetRepository.getByIdsWithAllRelationsButStacks -- AssetRepository.getByIdsWithAllRelationsButStacks
select select
"assets".*, "asset".*,
( (
select select
coalesce(json_agg(agg), '[]') coalesce(json_agg(agg), '[]')
from from
( (
select select
"asset_faces".*, "asset_face".*,
"person" as "person" "person" as "person"
from from
"asset_faces" "asset_face"
left join lateral ( left join lateral (
select select
"person".* "person".*
from from
"person" "person"
where where
"asset_faces"."personId" = "person"."id" "asset_face"."personId" = "person"."id"
) as "person" on true ) as "person" on true
where where
"asset_faces"."assetId" = "assets"."id" "asset_face"."assetId" = "asset"."id"
and "asset_faces"."deletedAt" is null and "asset_face"."deletedAt" is null
) as agg ) as agg
) as "faces", ) as "faces",
( (
@ -113,36 +113,36 @@ select
from from
( (
select select
"tags"."id", "tag"."id",
"tags"."value", "tag"."value",
"tags"."createdAt", "tag"."createdAt",
"tags"."updatedAt", "tag"."updatedAt",
"tags"."color", "tag"."color",
"tags"."parentId" "tag"."parentId"
from from
"tags" "tag"
inner join "tag_asset" on "tags"."id" = "tag_asset"."tagsId" inner join "tag_asset" on "tag"."id" = "tag_asset"."tagsId"
where where
"assets"."id" = "tag_asset"."assetsId" "asset"."id" = "tag_asset"."assetsId"
) as agg ) as agg
) as "tags", ) as "tags",
to_json("exif") as "exifInfo" to_json("asset_exif") as "exifInfo"
from from
"assets" "asset"
left join "exif" on "assets"."id" = "exif"."assetId" left join "asset_exif" on "asset"."id" = "asset_exif"."assetId"
where where
"assets"."id" = any ($1::uuid[]) "asset"."id" = any ($1::uuid[])
-- AssetRepository.deleteAll -- AssetRepository.deleteAll
delete from "assets" delete from "asset"
where where
"ownerId" = $1 "ownerId" = $1
-- AssetRepository.getByLibraryIdAndOriginalPath -- AssetRepository.getByLibraryIdAndOriginalPath
select select
"assets".* "asset".*
from from
"assets" "asset"
where where
"libraryId" = $1::uuid "libraryId" = $1::uuid
and "originalPath" = $2 and "originalPath" = $2
@ -153,7 +153,7 @@ limit
select select
"deviceAssetId" "deviceAssetId"
from from
"assets" "asset"
where where
"ownerId" = $1::uuid "ownerId" = $1::uuid
and "deviceId" = $2 and "deviceId" = $2
@ -164,22 +164,22 @@ where
select select
count(*) as "count" count(*) as "count"
from from
"assets" "asset"
where where
"livePhotoVideoId" = $1::uuid "livePhotoVideoId" = $1::uuid
-- AssetRepository.getById -- AssetRepository.getById
select select
"assets".* "asset".*
from from
"assets" "asset"
where where
"assets"."id" = $1::uuid "asset"."id" = $1::uuid
limit limit
$2 $2
-- AssetRepository.updateAll -- AssetRepository.updateAll
update "assets" update "asset"
set set
"deviceId" = $1 "deviceId" = $1
where where
@ -187,9 +187,9 @@ where
-- AssetRepository.getByChecksum -- AssetRepository.getByChecksum
select select
"assets".* "asset".*
from from
"assets" "asset"
where where
"ownerId" = $1::uuid "ownerId" = $1::uuid
and "checksum" = $2 and "checksum" = $2
@ -203,7 +203,7 @@ select
"checksum", "checksum",
"deletedAt" "deletedAt"
from from
"assets" "asset"
where where
"ownerId" = $1::uuid "ownerId" = $1::uuid
and "checksum" in ($2) and "checksum" in ($2)
@ -212,7 +212,7 @@ where
select select
"id" "id"
from from
"assets" "asset"
where where
"ownerId" = $1::uuid "ownerId" = $1::uuid
and "checksum" = $2 and "checksum" = $2
@ -222,20 +222,20 @@ limit
-- AssetRepository.getTimeBuckets -- AssetRepository.getTimeBuckets
with with
"assets" as ( "asset" as (
select select
date_trunc('MONTH', "localDateTime" AT TIME ZONE 'UTC') AT TIME ZONE 'UTC' as "timeBucket" date_trunc('MONTH', "localDateTime" AT TIME ZONE 'UTC') AT TIME ZONE 'UTC' as "timeBucket"
from from
"assets" "asset"
where where
"assets"."deletedAt" is null "asset"."deletedAt" is null
and "assets"."visibility" in ('archive', 'timeline') and "asset"."visibility" in ('archive', 'timeline')
) )
select select
("timeBucket" AT TIME ZONE 'UTC')::date::text as "timeBucket", ("timeBucket" AT TIME ZONE 'UTC')::date::text as "timeBucket",
count(*) as "count" count(*) as "count"
from from
"assets" "asset"
group by group by
"timeBucket" "timeBucket"
order by order by
@ -245,37 +245,37 @@ order by
with with
"cte" as ( "cte" as (
select select
"assets"."duration", "asset"."duration",
"assets"."id", "asset"."id",
"assets"."visibility", "asset"."visibility",
"assets"."isFavorite", "asset"."isFavorite",
assets.type = 'IMAGE' as "isImage", asset.type = 'IMAGE' as "isImage",
assets."deletedAt" is not null as "isTrashed", asset."deletedAt" is not null as "isTrashed",
"assets"."livePhotoVideoId", "asset"."livePhotoVideoId",
extract( extract(
epoch epoch
from from
( (
assets."localDateTime" - assets."fileCreatedAt" at time zone 'UTC' asset."localDateTime" - asset."fileCreatedAt" at time zone 'UTC'
) )
)::real / 3600 as "localOffsetHours", )::real / 3600 as "localOffsetHours",
"assets"."ownerId", "asset"."ownerId",
"assets"."status", "asset"."status",
assets."fileCreatedAt" at time zone 'utc' as "fileCreatedAt", asset."fileCreatedAt" at time zone 'utc' as "fileCreatedAt",
encode("assets"."thumbhash", 'base64') as "thumbhash", encode("asset"."thumbhash", 'base64') as "thumbhash",
"exif"."city", "asset_exif"."city",
"exif"."country", "asset_exif"."country",
"exif"."projectionType", "asset_exif"."projectionType",
coalesce( coalesce(
case case
when exif."exifImageHeight" = 0 when asset_exif."exifImageHeight" = 0
or exif."exifImageWidth" = 0 then 1 or asset_exif."exifImageWidth" = 0 then 1
when "exif"."orientation" in ('5', '6', '7', '8', '-90', '90') then round( when "asset_exif"."orientation" in ('5', '6', '7', '8', '-90', '90') then round(
exif."exifImageHeight"::numeric / exif."exifImageWidth"::numeric, asset_exif."exifImageHeight"::numeric / asset_exif."exifImageWidth"::numeric,
3 3
) )
else round( else round(
exif."exifImageWidth"::numeric / exif."exifImageHeight"::numeric, asset_exif."exifImageWidth"::numeric / asset_exif."exifImageHeight"::numeric,
3 3
) )
end, end,
@ -283,34 +283,34 @@ with
) as "ratio", ) as "ratio",
"stack" "stack"
from from
"assets" "asset"
inner join "exif" on "assets"."id" = "exif"."assetId" inner join "asset_exif" on "asset"."id" = "asset_exif"."assetId"
left join lateral ( left join lateral (
select select
array[stacked."stackId"::text, count('stacked')::text] as "stack" array[stacked."stackId"::text, count('stacked')::text] as "stack"
from from
"assets" as "stacked" "asset" as "stacked"
where where
"stacked"."stackId" = "assets"."stackId" "stacked"."stackId" = "asset"."stackId"
and "stacked"."deletedAt" is null and "stacked"."deletedAt" is null
and "stacked"."visibility" = $1 and "stacked"."visibility" = $1
group by group by
"stacked"."stackId" "stacked"."stackId"
) as "stacked_assets" on true ) as "stacked_assets" on true
where where
"assets"."deletedAt" is null "asset"."deletedAt" is null
and "assets"."visibility" in ('archive', 'timeline') and "asset"."visibility" in ('archive', 'timeline')
and date_trunc('MONTH', "localDateTime" AT TIME ZONE 'UTC') AT TIME ZONE 'UTC' = $2 and date_trunc('MONTH', "localDateTime" AT TIME ZONE 'UTC') AT TIME ZONE 'UTC' = $2
and not exists ( and not exists (
select select
from from
"asset_stack" "stack"
where where
"asset_stack"."id" = "assets"."stackId" "stack"."id" = "asset"."stackId"
and "asset_stack"."primaryAssetId" != "assets"."id" and "stack"."primaryAssetId" != "asset"."id"
) )
order by order by
"assets"."fileCreatedAt" desc "asset"."fileCreatedAt" desc
), ),
"agg" as ( "agg" as (
select select
@ -345,7 +345,7 @@ with
select select
"city" "city"
from from
"exif" "asset_exif"
where where
"city" is not null "city" is not null
group by group by
@ -354,12 +354,12 @@ with
count("assetId") >= $1 count("assetId") >= $1
) )
select distinct select distinct
on ("exif"."city") "assetId" as "data", on ("asset_exif"."city") "assetId" as "data",
"exif"."city" as "value" "asset_exif"."city" as "value"
from from
"assets" "asset"
inner join "exif" on "assets"."id" = "exif"."assetId" inner join "asset_exif" on "asset"."id" = "asset_exif"."assetId"
inner join "cities" on "exif"."city" = "cities"."city" inner join "cities" on "asset_exif"."city" = "cities"."city"
where where
"ownerId" = $2::uuid "ownerId" = $2::uuid
and "visibility" = $3 and "visibility" = $3
@ -370,63 +370,63 @@ limit
-- AssetRepository.getAllForUserFullSync -- AssetRepository.getAllForUserFullSync
select select
"assets".*, "asset".*,
to_json("exif") as "exifInfo", to_json("asset_exif") as "exifInfo",
to_json("stacked_assets") as "stack" to_json("stacked_assets") as "stack"
from from
"assets" "asset"
left join "exif" on "assets"."id" = "exif"."assetId" left join "asset_exif" on "asset"."id" = "asset_exif"."assetId"
left join "asset_stack" on "asset_stack"."id" = "assets"."stackId" left join "stack" on "stack"."id" = "asset"."stackId"
left join lateral ( left join lateral (
select select
"asset_stack".*, "stack".*,
count("stacked") as "assetCount" count("stacked") as "assetCount"
from from
"assets" as "stacked" "asset" as "stacked"
where where
"stacked"."stackId" = "asset_stack"."id" "stacked"."stackId" = "stack"."id"
group by group by
"asset_stack"."id" "stack"."id"
) as "stacked_assets" on "asset_stack"."id" is not null ) as "stacked_assets" on "stack"."id" is not null
where where
"assets"."ownerId" = $1::uuid "asset"."ownerId" = $1::uuid
and "assets"."visibility" != $2 and "asset"."visibility" != $2
and "assets"."updatedAt" <= $3 and "asset"."updatedAt" <= $3
and "assets"."id" > $4 and "asset"."id" > $4
order by order by
"assets"."id" "asset"."id"
limit limit
$5 $5
-- AssetRepository.getChangedDeltaSync -- AssetRepository.getChangedDeltaSync
select select
"assets".*, "asset".*,
to_json("exif") as "exifInfo", to_json("asset_exif") as "exifInfo",
to_json("stacked_assets") as "stack" to_json("stacked_assets") as "stack"
from from
"assets" "asset"
left join "exif" on "assets"."id" = "exif"."assetId" left join "asset_exif" on "asset"."id" = "asset_exif"."assetId"
left join "asset_stack" on "asset_stack"."id" = "assets"."stackId" left join "stack" on "stack"."id" = "asset"."stackId"
left join lateral ( left join lateral (
select select
"asset_stack".*, "stack".*,
count("stacked") as "assetCount" count("stacked") as "assetCount"
from from
"assets" as "stacked" "asset" as "stacked"
where where
"stacked"."stackId" = "asset_stack"."id" "stacked"."stackId" = "stack"."id"
group by group by
"asset_stack"."id" "stack"."id"
) as "stacked_assets" on "asset_stack"."id" is not null ) as "stacked_assets" on "stack"."id" is not null
where where
"assets"."ownerId" = any ($1::uuid[]) "asset"."ownerId" = any ($1::uuid[])
and "assets"."visibility" != $2 and "asset"."visibility" != $2
and "assets"."updatedAt" > $3 and "asset"."updatedAt" > $3
limit limit
$4 $4
-- AssetRepository.detectOfflineExternalAssets -- AssetRepository.detectOfflineExternalAssets
update "assets" update "asset"
set set
"isOffline" = $1, "isOffline" = $1,
"deletedAt" = $2 "deletedAt" = $2
@ -449,9 +449,9 @@ where
select select
"originalPath" "originalPath"
from from
"assets" "asset"
where where
"assets"."originalPath" = "path" "asset"."originalPath" = "path"
and "libraryId" = $2::uuid and "libraryId" = $2::uuid
and "isExternal" = $3 and "isExternal" = $3
) )

View File

@ -4,31 +4,31 @@
with with
"duplicates" as ( "duplicates" as (
select select
"assets"."duplicateId", "asset"."duplicateId",
json_agg( json_agg(
"asset" "asset2"
order by order by
"assets"."localDateTime" asc "asset"."localDateTime" asc
) as "assets" ) as "assets"
from from
"assets" "asset"
left join lateral ( left join lateral (
select select
"assets".*, "asset".*,
"exif" as "exifInfo" "asset_exif" as "exifInfo"
from from
"exif" "asset_exif"
where where
"exif"."assetId" = "assets"."id" "asset_exif"."assetId" = "asset"."id"
) as "asset" on true ) as "asset2" on true
where where
"assets"."visibility" in ('archive', 'timeline') "asset"."visibility" in ('archive', 'timeline')
and "assets"."ownerId" = $1::uuid and "asset"."ownerId" = $1::uuid
and "assets"."duplicateId" is not null and "asset"."duplicateId" is not null
and "assets"."deletedAt" is null and "asset"."deletedAt" is null
and "assets"."stackId" is null and "asset"."stackId" is null
group by group by
"assets"."duplicateId" "asset"."duplicateId"
), ),
"unique" as ( "unique" as (
select select
@ -39,13 +39,13 @@ with
json_array_length("assets") = $2 json_array_length("assets") = $2
), ),
"removed_unique" as ( "removed_unique" as (
update "assets" update "asset"
set set
"duplicateId" = $3 "duplicateId" = $3
from from
"unique" "unique"
where where
"assets"."duplicateId" = "unique"."duplicateId" "asset"."duplicateId" = "unique"."duplicateId"
) )
select select
* *
@ -61,7 +61,7 @@ where
) )
-- DuplicateRepository.delete -- DuplicateRepository.delete
update "assets" update "asset"
set set
"duplicateId" = $1 "duplicateId" = $1
where where
@ -69,7 +69,7 @@ where
and "duplicateId" = $3 and "duplicateId" = $3
-- DuplicateRepository.deleteAll -- DuplicateRepository.deleteAll
update "assets" update "asset"
set set
"duplicateId" = $1 "duplicateId" = $1
where where
@ -83,19 +83,19 @@ set
with with
"cte" as ( "cte" as (
select select
"assets"."id" as "assetId", "asset"."id" as "assetId",
"assets"."duplicateId", "asset"."duplicateId",
smart_search.embedding <=> $1 as "distance" smart_search.embedding <=> $1 as "distance"
from from
"assets" "asset"
inner join "smart_search" on "assets"."id" = "smart_search"."assetId" inner join "smart_search" on "asset"."id" = "smart_search"."assetId"
where where
"assets"."visibility" in ('archive', 'timeline') "asset"."visibility" in ('archive', 'timeline')
and "assets"."ownerId" = any ($2::uuid[]) and "asset"."ownerId" = any ($2::uuid[])
and "assets"."deletedAt" is null and "asset"."deletedAt" is null
and "assets"."type" = $3 and "asset"."type" = $3
and "assets"."id" != $4::uuid and "asset"."id" != $4::uuid
and "assets"."stackId" is null and "asset"."stackId" is null
order by order by
"distance" "distance"
limit limit
@ -110,7 +110,7 @@ where
commit commit
-- DuplicateRepository.merge -- DuplicateRepository.merge
update "assets" update "asset"
set set
where where
( (

View File

@ -2,30 +2,30 @@
-- LibraryRepository.get -- LibraryRepository.get
select select
"libraries".* "library".*
from from
"libraries" "library"
where where
"libraries"."id" = $1 "library"."id" = $1
and "libraries"."deletedAt" is null and "library"."deletedAt" is null
-- LibraryRepository.getAll -- LibraryRepository.getAll
select select
"libraries".* "library".*
from from
"libraries" "library"
where where
"libraries"."deletedAt" is null "library"."deletedAt" is null
order by order by
"createdAt" asc "createdAt" asc
-- LibraryRepository.getAllDeleted -- LibraryRepository.getAllDeleted
select select
"libraries".* "library".*
from from
"libraries" "library"
where where
"libraries"."deletedAt" is not null "library"."deletedAt" is not null
order by order by
"createdAt" asc "createdAt" asc
@ -34,32 +34,32 @@ select
count(*) filter ( count(*) filter (
where where
( (
"assets"."type" = $1 "asset"."type" = $1
and "assets"."visibility" != $2 and "asset"."visibility" != $2
) )
) as "photos", ) as "photos",
count(*) filter ( count(*) filter (
where where
( (
"assets"."type" = $3 "asset"."type" = $3
and "assets"."visibility" != $4 and "asset"."visibility" != $4
) )
) as "videos", ) as "videos",
coalesce(sum("exif"."fileSizeInByte"), $5) as "usage" coalesce(sum("asset_exif"."fileSizeInByte"), $5) as "usage"
from from
"libraries" "library"
inner join "assets" on "assets"."libraryId" = "libraries"."id" inner join "asset" on "asset"."libraryId" = "library"."id"
left join "exif" on "exif"."assetId" = "assets"."id" left join "asset_exif" on "asset_exif"."assetId" = "asset"."id"
where where
"libraries"."id" = $6 "library"."id" = $6
group by group by
"libraries"."id" "library"."id"
select select
0::int as "photos", 0::int as "photos",
0::int as "videos", 0::int as "videos",
0::int as "usage", 0::int as "usage",
0::int as "total" 0::int as "total"
from from
"libraries" "library"
where where
"libraries"."id" = $1 "library"."id" = $1

View File

@ -3,28 +3,28 @@
-- MapRepository.getMapMarkers -- MapRepository.getMapMarkers
select select
"id", "id",
"exif"."latitude" as "lat", "asset_exif"."latitude" as "lat",
"exif"."longitude" as "lon", "asset_exif"."longitude" as "lon",
"exif"."city", "asset_exif"."city",
"exif"."state", "asset_exif"."state",
"exif"."country" "asset_exif"."country"
from from
"assets" "asset"
inner join "exif" on "assets"."id" = "exif"."assetId" inner join "asset_exif" on "asset"."id" = "asset_exif"."assetId"
and "exif"."latitude" is not null and "asset_exif"."latitude" is not null
and "exif"."longitude" is not null and "asset_exif"."longitude" is not null
where where
"assets"."visibility" = $1 "asset"."visibility" = $1
and "deletedAt" is null and "deletedAt" is null
and ( and (
"ownerId" in ($2) "ownerId" in ($2)
or exists ( or exists (
select select
from from
"albums_assets_assets" "album_asset"
where where
"assets"."id" = "albums_assets_assets"."assetsId" "asset"."id" = "album_asset"."assetsId"
and "albums_assets_assets"."albumsId" in ($3) and "album_asset"."albumsId" in ($3)
) )
) )
order by order by

View File

@ -4,7 +4,7 @@
select select
count(*) as "total" count(*) as "total"
from from
"memories" "memory"
where where
"deletedAt" is null "deletedAt" is null
and "ownerId" = $1 and "ownerId" = $1
@ -13,7 +13,7 @@ where
select select
count(*) as "total" count(*) as "total"
from from
"memories" "memory"
where where
( (
"showAt" is null "showAt" is null
@ -34,21 +34,21 @@ select
from from
( (
select select
"assets".* "asset".*
from from
"assets" "asset"
inner join "memories_assets_assets" on "assets"."id" = "memories_assets_assets"."assetsId" inner join "memory_asset" on "asset"."id" = "memory_asset"."assetsId"
where where
"memories_assets_assets"."memoriesId" = "memories"."id" "memory_asset"."memoriesId" = "memory"."id"
and "assets"."visibility" = 'timeline' and "asset"."visibility" = 'timeline'
and "assets"."deletedAt" is null and "asset"."deletedAt" is null
order by order by
"assets"."fileCreatedAt" asc "asset"."fileCreatedAt" asc
) as agg ) as agg
) as "assets", ) as "assets",
"memories".* "memory".*
from from
"memories" "memory"
where where
"deletedAt" is null "deletedAt" is null
and "ownerId" = $1 and "ownerId" = $1
@ -63,21 +63,21 @@ select
from from
( (
select select
"assets".* "asset".*
from from
"assets" "asset"
inner join "memories_assets_assets" on "assets"."id" = "memories_assets_assets"."assetsId" inner join "memory_asset" on "asset"."id" = "memory_asset"."assetsId"
where where
"memories_assets_assets"."memoriesId" = "memories"."id" "memory_asset"."memoriesId" = "memory"."id"
and "assets"."visibility" = 'timeline' and "asset"."visibility" = 'timeline'
and "assets"."deletedAt" is null and "asset"."deletedAt" is null
order by order by
"assets"."fileCreatedAt" asc "asset"."fileCreatedAt" asc
) as agg ) as agg
) as "assets", ) as "assets",
"memories".* "memory".*
from from
"memories" "memory"
where where
( (
"showAt" is null "showAt" is null
@ -94,66 +94,66 @@ order by
-- MemoryRepository.get -- MemoryRepository.get
select select
"memories".*, "memory".*,
( (
select select
coalesce(json_agg(agg), '[]') coalesce(json_agg(agg), '[]')
from from
( (
select select
"assets".* "asset".*
from from
"assets" "asset"
inner join "memories_assets_assets" on "assets"."id" = "memories_assets_assets"."assetsId" inner join "memory_asset" on "asset"."id" = "memory_asset"."assetsId"
where where
"memories_assets_assets"."memoriesId" = "memories"."id" "memory_asset"."memoriesId" = "memory"."id"
and "assets"."visibility" = 'timeline' and "asset"."visibility" = 'timeline'
and "assets"."deletedAt" is null and "asset"."deletedAt" is null
order by order by
"assets"."fileCreatedAt" asc "asset"."fileCreatedAt" asc
) as agg ) as agg
) as "assets" ) as "assets"
from from
"memories" "memory"
where where
"id" = $1 "id" = $1
and "deletedAt" is null and "deletedAt" is null
-- MemoryRepository.update -- MemoryRepository.update
update "memories" update "memory"
set set
"ownerId" = $1, "ownerId" = $1,
"isSaved" = $2 "isSaved" = $2
where where
"id" = $3 "id" = $3
select select
"memories".*, "memory".*,
( (
select select
coalesce(json_agg(agg), '[]') coalesce(json_agg(agg), '[]')
from from
( (
select select
"assets".* "asset".*
from from
"assets" "asset"
inner join "memories_assets_assets" on "assets"."id" = "memories_assets_assets"."assetsId" inner join "memory_asset" on "asset"."id" = "memory_asset"."assetsId"
where where
"memories_assets_assets"."memoriesId" = "memories"."id" "memory_asset"."memoriesId" = "memory"."id"
and "assets"."visibility" = 'timeline' and "asset"."visibility" = 'timeline'
and "assets"."deletedAt" is null and "asset"."deletedAt" is null
order by order by
"assets"."fileCreatedAt" asc "asset"."fileCreatedAt" asc
) as agg ) as agg
) as "assets" ) as "assets"
from from
"memories" "memory"
where where
"id" = $1 "id" = $1
and "deletedAt" is null and "deletedAt" is null
-- MemoryRepository.delete -- MemoryRepository.delete
delete from "memories" delete from "memory"
where where
"id" = $1 "id" = $1
@ -161,13 +161,13 @@ where
select select
"assetsId" "assetsId"
from from
"memories_assets_assets" "memory_asset"
where where
"memoriesId" = $1 "memoriesId" = $1
and "assetsId" in ($2) and "assetsId" in ($2)
-- MemoryRepository.addAssetIds -- MemoryRepository.addAssetIds
insert into insert into
"memories_assets_assets" ("memoriesId", "assetsId") "memory_asset" ("memoriesId", "assetsId")
values values
($1, $2) ($1, $2)

View File

@ -11,7 +11,7 @@ select
"data", "data",
"readAt" "readAt"
from from
"notifications" "notification"
where where
"userId" = $1 "userId" = $1
and "deletedAt" is null and "deletedAt" is null
@ -29,7 +29,7 @@ select
"data", "data",
"readAt" "readAt"
from from
"notifications" "notification"
where where
( (
"userId" = $1 "userId" = $1

View File

@ -2,7 +2,7 @@
-- PartnerRepository.getAll -- PartnerRepository.getAll
select select
"partners".*, "partner".*,
( (
select select
to_json(obj) to_json(obj)
@ -16,9 +16,9 @@ select
"profileImagePath", "profileImagePath",
"profileChangedAt" "profileChangedAt"
from from
"users" as "sharedBy" "user" as "sharedBy"
where where
"sharedBy"."id" = "partners"."sharedById" "sharedBy"."id" = "partner"."sharedById"
) as obj ) as obj
) as "sharedBy", ) as "sharedBy",
( (
@ -34,16 +34,16 @@ select
"profileImagePath", "profileImagePath",
"profileChangedAt" "profileChangedAt"
from from
"users" as "sharedWith" "user" as "sharedWith"
where where
"sharedWith"."id" = "partners"."sharedWithId" "sharedWith"."id" = "partner"."sharedWithId"
) as obj ) as obj
) as "sharedWith" ) as "sharedWith"
from from
"partners" "partner"
inner join "users" as "sharedBy" on "partners"."sharedById" = "sharedBy"."id" inner join "user" as "sharedBy" on "partner"."sharedById" = "sharedBy"."id"
and "sharedBy"."deletedAt" is null and "sharedBy"."deletedAt" is null
inner join "users" as "sharedWith" on "partners"."sharedWithId" = "sharedWith"."id" inner join "user" as "sharedWith" on "partner"."sharedWithId" = "sharedWith"."id"
and "sharedWith"."deletedAt" is null and "sharedWith"."deletedAt" is null
where where
( (
@ -53,7 +53,7 @@ where
-- PartnerRepository.get -- PartnerRepository.get
select select
"partners".*, "partner".*,
( (
select select
to_json(obj) to_json(obj)
@ -67,9 +67,9 @@ select
"profileImagePath", "profileImagePath",
"profileChangedAt" "profileChangedAt"
from from
"users" as "sharedBy" "user" as "sharedBy"
where where
"sharedBy"."id" = "partners"."sharedById" "sharedBy"."id" = "partner"."sharedById"
) as obj ) as obj
) as "sharedBy", ) as "sharedBy",
( (
@ -85,23 +85,23 @@ select
"profileImagePath", "profileImagePath",
"profileChangedAt" "profileChangedAt"
from from
"users" as "sharedWith" "user" as "sharedWith"
where where
"sharedWith"."id" = "partners"."sharedWithId" "sharedWith"."id" = "partner"."sharedWithId"
) as obj ) as obj
) as "sharedWith" ) as "sharedWith"
from from
"partners" "partner"
inner join "users" as "sharedBy" on "partners"."sharedById" = "sharedBy"."id" inner join "user" as "sharedBy" on "partner"."sharedById" = "sharedBy"."id"
and "sharedBy"."deletedAt" is null and "sharedBy"."deletedAt" is null
inner join "users" as "sharedWith" on "partners"."sharedWithId" = "sharedWith"."id" inner join "user" as "sharedWith" on "partner"."sharedWithId" = "sharedWith"."id"
and "sharedWith"."deletedAt" is null and "sharedWith"."deletedAt" is null
where where
"sharedWithId" = $1 "sharedWithId" = $1
and "sharedById" = $2 and "sharedById" = $2
-- PartnerRepository.update -- PartnerRepository.update
update "partners" update "partner"
set set
"inTimeline" = $1 "inTimeline" = $1
where where
@ -122,9 +122,9 @@ returning
"profileImagePath", "profileImagePath",
"profileChangedAt" "profileChangedAt"
from from
"users" as "sharedBy" "user" as "sharedBy"
where where
"sharedBy"."id" = "partners"."sharedById" "sharedBy"."id" = "partner"."sharedById"
) as obj ) as obj
) as "sharedBy", ) as "sharedBy",
( (
@ -140,14 +140,14 @@ returning
"profileImagePath", "profileImagePath",
"profileChangedAt" "profileChangedAt"
from from
"users" as "sharedWith" "user" as "sharedWith"
where where
"sharedWith"."id" = "partners"."sharedWithId" "sharedWith"."id" = "partner"."sharedWithId"
) as obj ) as obj
) as "sharedWith" ) as "sharedWith"
-- PartnerRepository.remove -- PartnerRepository.remove
delete from "partners" delete from "partner"
where where
"sharedWithId" = $1 "sharedWithId" = $1
and "sharedById" = $2 and "sharedById" = $2

View File

@ -1,11 +1,11 @@
-- NOTE: This file is auto generated by ./sql-generator -- NOTE: This file is auto generated by ./sql-generator
-- PersonRepository.reassignFaces -- PersonRepository.reassignFaces
update "asset_faces" update "asset_face"
set set
"personId" = $1 "personId" = $1
where where
"asset_faces"."personId" = $2 "asset_face"."personId" = $2
-- PersonRepository.delete -- PersonRepository.delete
delete from "person" delete from "person"
@ -17,26 +17,26 @@ select
"person".* "person".*
from from
"person" "person"
inner join "asset_faces" on "asset_faces"."personId" = "person"."id" inner join "asset_face" on "asset_face"."personId" = "person"."id"
inner join "assets" on "asset_faces"."assetId" = "assets"."id" inner join "asset" on "asset_face"."assetId" = "asset"."id"
and "assets"."visibility" = 'timeline' and "asset"."visibility" = 'timeline'
and "assets"."deletedAt" is null and "asset"."deletedAt" is null
where where
"person"."ownerId" = $1 "person"."ownerId" = $1
and "asset_faces"."deletedAt" is null and "asset_face"."deletedAt" is null
and "person"."isHidden" = $2 and "person"."isHidden" = $2
group by group by
"person"."id" "person"."id"
having having
( (
"person"."name" != $3 "person"."name" != $3
or count("asset_faces"."assetId") >= $4 or count("asset_face"."assetId") >= $4
) )
order by order by
"person"."isHidden" asc, "person"."isHidden" asc,
"person"."isFavorite" desc, "person"."isFavorite" desc,
NULLIF(person.name, '') is null asc, NULLIF(person.name, '') is null asc,
count("asset_faces"."assetId") desc, count("asset_face"."assetId") desc,
NULLIF(person.name, '') asc nulls last, NULLIF(person.name, '') asc nulls last,
"person"."createdAt" "person"."createdAt"
limit limit
@ -49,17 +49,17 @@ select
"person".* "person".*
from from
"person" "person"
left join "asset_faces" on "asset_faces"."personId" = "person"."id" left join "asset_face" on "asset_face"."personId" = "person"."id"
where where
"asset_faces"."deletedAt" is null "asset_face"."deletedAt" is null
group by group by
"person"."id" "person"."id"
having having
count("asset_faces"."assetId") = $1 count("asset_face"."assetId") = $1
-- PersonRepository.getFaces -- PersonRepository.getFaces
select select
"asset_faces".*, "asset_face".*,
( (
select select
to_json(obj) to_json(obj)
@ -70,20 +70,20 @@ select
from from
"person" "person"
where where
"person"."id" = "asset_faces"."personId" "person"."id" = "asset_face"."personId"
) as obj ) as obj
) as "person" ) as "person"
from from
"asset_faces" "asset_face"
where where
"asset_faces"."assetId" = $1 "asset_face"."assetId" = $1
and "asset_faces"."deletedAt" is null and "asset_face"."deletedAt" is null
order by order by
"asset_faces"."boundingBoxX1" asc "asset_face"."boundingBoxX1" asc
-- PersonRepository.getFaceById -- PersonRepository.getFaceById
select select
"asset_faces".*, "asset_face".*,
( (
select select
to_json(obj) to_json(obj)
@ -94,33 +94,33 @@ select
from from
"person" "person"
where where
"person"."id" = "asset_faces"."personId" "person"."id" = "asset_face"."personId"
) as obj ) as obj
) as "person" ) as "person"
from from
"asset_faces" "asset_face"
where where
"asset_faces"."id" = $1 "asset_face"."id" = $1
and "asset_faces"."deletedAt" is null and "asset_face"."deletedAt" is null
-- PersonRepository.getFaceForFacialRecognitionJob -- PersonRepository.getFaceForFacialRecognitionJob
select select
"asset_faces"."id", "asset_face"."id",
"asset_faces"."personId", "asset_face"."personId",
"asset_faces"."sourceType", "asset_face"."sourceType",
( (
select select
to_json(obj) to_json(obj)
from from
( (
select select
"assets"."ownerId", "asset"."ownerId",
"assets"."visibility", "asset"."visibility",
"assets"."fileCreatedAt" "asset"."fileCreatedAt"
from from
"assets" "asset"
where where
"assets"."id" = "asset_faces"."assetId" "asset"."id" = "asset_face"."assetId"
) as obj ) as obj
) as "asset", ) as "asset",
( (
@ -133,51 +133,51 @@ select
from from
"face_search" "face_search"
where where
"face_search"."faceId" = "asset_faces"."id" "face_search"."faceId" = "asset_face"."id"
) as obj ) as obj
) as "faceSearch" ) as "faceSearch"
from from
"asset_faces" "asset_face"
where where
"asset_faces"."id" = $1 "asset_face"."id" = $1
and "asset_faces"."deletedAt" is null and "asset_face"."deletedAt" is null
-- PersonRepository.getDataForThumbnailGenerationJob -- PersonRepository.getDataForThumbnailGenerationJob
select select
"person"."ownerId", "person"."ownerId",
"asset_faces"."boundingBoxX1" as "x1", "asset_face"."boundingBoxX1" as "x1",
"asset_faces"."boundingBoxY1" as "y1", "asset_face"."boundingBoxY1" as "y1",
"asset_faces"."boundingBoxX2" as "x2", "asset_face"."boundingBoxX2" as "x2",
"asset_faces"."boundingBoxY2" as "y2", "asset_face"."boundingBoxY2" as "y2",
"asset_faces"."imageWidth" as "oldWidth", "asset_face"."imageWidth" as "oldWidth",
"asset_faces"."imageHeight" as "oldHeight", "asset_face"."imageHeight" as "oldHeight",
"assets"."type", "asset"."type",
"assets"."originalPath", "asset"."originalPath",
"exif"."orientation" as "exifOrientation", "asset_exif"."orientation" as "exifOrientation",
( (
select select
"asset_files"."path" "asset_file"."path"
from from
"asset_files" "asset_file"
where where
"asset_files"."assetId" = "assets"."id" "asset_file"."assetId" = "asset"."id"
and "asset_files"."type" = 'preview' and "asset_file"."type" = 'preview'
) as "previewPath" ) as "previewPath"
from from
"person" "person"
inner join "asset_faces" on "asset_faces"."id" = "person"."faceAssetId" inner join "asset_face" on "asset_face"."id" = "person"."faceAssetId"
inner join "assets" on "asset_faces"."assetId" = "assets"."id" inner join "asset" on "asset_face"."assetId" = "asset"."id"
left join "exif" on "exif"."assetId" = "assets"."id" left join "asset_exif" on "asset_exif"."assetId" = "asset"."id"
where where
"person"."id" = $1 "person"."id" = $1
and "asset_faces"."deletedAt" is null and "asset_face"."deletedAt" is null
-- PersonRepository.reassignFace -- PersonRepository.reassignFace
update "asset_faces" update "asset_face"
set set
"personId" = $1 "personId" = $1
where where
"asset_faces"."id" = $2 "asset_face"."id" = $2
-- PersonRepository.getByName -- PersonRepository.getByName
select select
@ -209,15 +209,15 @@ where
-- PersonRepository.getStatistics -- PersonRepository.getStatistics
select select
count(distinct ("assets"."id")) as "count" count(distinct ("asset"."id")) as "count"
from from
"asset_faces" "asset_face"
left join "assets" on "assets"."id" = "asset_faces"."assetId" left join "asset" on "asset"."id" = "asset_face"."assetId"
and "asset_faces"."personId" = $1 and "asset_face"."personId" = $1
and "assets"."visibility" = 'timeline' and "asset"."visibility" = 'timeline'
and "assets"."deletedAt" is null and "asset"."deletedAt" is null
where where
"asset_faces"."deletedAt" is null "asset_face"."deletedAt" is null
-- PersonRepository.getNumberOfPeople -- PersonRepository.getNumberOfPeople
select select
@ -235,18 +235,18 @@ where
exists ( exists (
select select
from from
"asset_faces" "asset_face"
where where
"asset_faces"."personId" = "person"."id" "asset_face"."personId" = "person"."id"
and "asset_faces"."deletedAt" is null and "asset_face"."deletedAt" is null
and exists ( and exists (
select select
from from
"assets" "asset"
where where
"assets"."id" = "asset_faces"."assetId" "asset"."id" = "asset_face"."assetId"
and "assets"."visibility" = 'timeline' and "asset"."visibility" = 'timeline'
and "assets"."deletedAt" is null and "asset"."deletedAt" is null
) )
) )
and "person"."ownerId" = $2 and "person"."ownerId" = $2
@ -268,18 +268,18 @@ from
-- PersonRepository.getFacesByIds -- PersonRepository.getFacesByIds
select select
"asset_faces".*, "asset_face".*,
( (
select select
to_json(obj) to_json(obj)
from from
( (
select select
"assets".* "asset".*
from from
"assets" "asset"
where where
"assets"."id" = "asset_faces"."assetId" "asset"."id" = "asset_face"."assetId"
) as obj ) as obj
) as "asset", ) as "asset",
( (
@ -292,24 +292,24 @@ select
from from
"person" "person"
where where
"person"."id" = "asset_faces"."personId" "person"."id" = "asset_face"."personId"
) as obj ) as obj
) as "person" ) as "person"
from from
"asset_faces" "asset_face"
where where
"asset_faces"."assetId" in ($1) "asset_face"."assetId" in ($1)
and "asset_faces"."personId" in ($2) and "asset_face"."personId" in ($2)
and "asset_faces"."deletedAt" is null and "asset_face"."deletedAt" is null
-- PersonRepository.getRandomFace -- PersonRepository.getRandomFace
select select
"asset_faces".* "asset_face".*
from from
"asset_faces" "asset_face"
where where
"asset_faces"."personId" = $1 "asset_face"."personId" = $1
and "asset_faces"."deletedAt" is null and "asset_face"."deletedAt" is null
-- PersonRepository.getLatestFaceDate -- PersonRepository.getLatestFaceDate
select select
@ -318,16 +318,16 @@ from
"asset_job_status" "asset_job_status"
-- PersonRepository.deleteAssetFace -- PersonRepository.deleteAssetFace
delete from "asset_faces" delete from "asset_face"
where where
"asset_faces"."id" = $1 "asset_face"."id" = $1
-- PersonRepository.softDeleteAssetFaces -- PersonRepository.softDeleteAssetFaces
update "asset_faces" update "asset_face"
set set
"deletedAt" = $1 "deletedAt" = $1
where where
"asset_faces"."id" = $2 "asset_face"."id" = $2
-- PersonRepository.getForPeopleDelete -- PersonRepository.getForPeopleDelete
select select

View File

@ -2,19 +2,19 @@
-- SearchRepository.searchMetadata -- SearchRepository.searchMetadata
select select
"assets".* "asset".*
from from
"assets" "asset"
inner join "exif" on "assets"."id" = "exif"."assetId" inner join "asset_exif" on "asset"."id" = "asset_exif"."assetId"
where where
"assets"."visibility" = $1 "asset"."visibility" = $1
and "assets"."fileCreatedAt" >= $2 and "asset"."fileCreatedAt" >= $2
and "exif"."lensModel" = $3 and "asset_exif"."lensModel" = $3
and "assets"."ownerId" = any ($4::uuid[]) and "asset"."ownerId" = any ($4::uuid[])
and "assets"."isFavorite" = $5 and "asset"."isFavorite" = $5
and "assets"."deletedAt" is null and "asset"."deletedAt" is null
order by order by
"assets"."fileCreatedAt" desc "asset"."fileCreatedAt" desc
limit limit
$6 $6
offset offset
@ -24,31 +24,31 @@ offset
select select
count(*) as "total" count(*) as "total"
from from
"assets" "asset"
inner join "exif" on "assets"."id" = "exif"."assetId" inner join "asset_exif" on "asset"."id" = "asset_exif"."assetId"
where where
"assets"."visibility" = $1 "asset"."visibility" = $1
and "assets"."fileCreatedAt" >= $2 and "asset"."fileCreatedAt" >= $2
and "exif"."lensModel" = $3 and "asset_exif"."lensModel" = $3
and "assets"."ownerId" = any ($4::uuid[]) and "asset"."ownerId" = any ($4::uuid[])
and "assets"."isFavorite" = $5 and "asset"."isFavorite" = $5
and "assets"."deletedAt" is null and "asset"."deletedAt" is null
-- SearchRepository.searchRandom -- SearchRepository.searchRandom
( (
select select
"assets".* "asset".*
from from
"assets" "asset"
inner join "exif" on "assets"."id" = "exif"."assetId" inner join "asset_exif" on "asset"."id" = "asset_exif"."assetId"
where where
"assets"."visibility" = $1 "asset"."visibility" = $1
and "assets"."fileCreatedAt" >= $2 and "asset"."fileCreatedAt" >= $2
and "exif"."lensModel" = $3 and "asset_exif"."lensModel" = $3
and "assets"."ownerId" = any ($4::uuid[]) and "asset"."ownerId" = any ($4::uuid[])
and "assets"."isFavorite" = $5 and "asset"."isFavorite" = $5
and "assets"."deletedAt" is null and "asset"."deletedAt" is null
and "assets"."id" < $6 and "asset"."id" < $6
order by order by
random() random()
limit limit
@ -57,18 +57,18 @@ where
union all union all
( (
select select
"assets".* "asset".*
from from
"assets" "asset"
inner join "exif" on "assets"."id" = "exif"."assetId" inner join "asset_exif" on "asset"."id" = "asset_exif"."assetId"
where where
"assets"."visibility" = $8 "asset"."visibility" = $8
and "assets"."fileCreatedAt" >= $9 and "asset"."fileCreatedAt" >= $9
and "exif"."lensModel" = $10 and "asset_exif"."lensModel" = $10
and "assets"."ownerId" = any ($11::uuid[]) and "asset"."ownerId" = any ($11::uuid[])
and "assets"."isFavorite" = $12 and "asset"."isFavorite" = $12
and "assets"."deletedAt" is null and "asset"."deletedAt" is null
and "assets"."id" > $13 and "asset"."id" > $13
order by order by
random() random()
limit limit
@ -82,18 +82,18 @@ begin
set set
local vchordrq.probes = 1 local vchordrq.probes = 1
select select
"assets".* "asset".*
from from
"assets" "asset"
inner join "exif" on "assets"."id" = "exif"."assetId" inner join "asset_exif" on "asset"."id" = "asset_exif"."assetId"
inner join "smart_search" on "assets"."id" = "smart_search"."assetId" inner join "smart_search" on "asset"."id" = "smart_search"."assetId"
where where
"assets"."visibility" = $1 "asset"."visibility" = $1
and "assets"."fileCreatedAt" >= $2 and "asset"."fileCreatedAt" >= $2
and "exif"."lensModel" = $3 and "asset_exif"."lensModel" = $3
and "assets"."ownerId" = any ($4::uuid[]) and "asset"."ownerId" = any ($4::uuid[])
and "assets"."isFavorite" = $5 and "asset"."isFavorite" = $5
and "assets"."deletedAt" is null and "asset"."deletedAt" is null
order by order by
smart_search.embedding <=> $6 smart_search.embedding <=> $6
limit limit
@ -109,17 +109,17 @@ set
with with
"cte" as ( "cte" as (
select select
"asset_faces"."id", "asset_face"."id",
"asset_faces"."personId", "asset_face"."personId",
face_search.embedding <=> $1 as "distance" face_search.embedding <=> $1 as "distance"
from from
"asset_faces" "asset_face"
inner join "assets" on "assets"."id" = "asset_faces"."assetId" inner join "asset" on "asset"."id" = "asset_face"."assetId"
inner join "face_search" on "face_search"."faceId" = "asset_faces"."id" inner join "face_search" on "face_search"."faceId" = "asset_face"."id"
left join "person" on "person"."id" = "asset_faces"."personId" left join "person" on "person"."id" = "asset_face"."personId"
where where
"assets"."ownerId" = any ($2::uuid[]) "asset"."ownerId" = any ($2::uuid[])
and "assets"."deletedAt" is null and "asset"."deletedAt" is null
order by order by
"distance" "distance"
limit limit
@ -165,13 +165,13 @@ with recursive
"city", "city",
"assetId" "assetId"
from from
"exif" "asset_exif"
inner join "assets" on "assets"."id" = "exif"."assetId" inner join "asset" on "asset"."id" = "asset_exif"."assetId"
where where
"assets"."ownerId" = any ($1::uuid[]) "asset"."ownerId" = any ($1::uuid[])
and "assets"."visibility" = $2 and "asset"."visibility" = $2
and "assets"."type" = $3 and "asset"."type" = $3
and "assets"."deletedAt" is null and "asset"."deletedAt" is null
order by order by
"city" "city"
limit limit
@ -189,14 +189,14 @@ with recursive
"city", "city",
"assetId" "assetId"
from from
"exif" "asset_exif"
inner join "assets" on "assets"."id" = "exif"."assetId" inner join "asset" on "asset"."id" = "asset_exif"."assetId"
where where
"assets"."ownerId" = any ($5::uuid[]) "asset"."ownerId" = any ($5::uuid[])
and "assets"."visibility" = $6 and "asset"."visibility" = $6
and "assets"."type" = $7 and "asset"."type" = $7
and "assets"."deletedAt" is null and "asset"."deletedAt" is null
and "exif"."city" > "cte"."city" and "asset_exif"."city" > "cte"."city"
order by order by
"city" "city"
limit limit
@ -205,21 +205,21 @@ with recursive
) )
) )
select select
"assets".*, "asset".*,
to_jsonb("exif") as "exifInfo" to_jsonb("asset_exif") as "exifInfo"
from from
"assets" "asset"
inner join "exif" on "assets"."id" = "exif"."assetId" inner join "asset_exif" on "asset"."id" = "asset_exif"."assetId"
inner join "cte" on "assets"."id" = "cte"."assetId" inner join "cte" on "asset"."id" = "cte"."assetId"
order by order by
"exif"."city" "asset_exif"."city"
-- SearchRepository.getStates -- SearchRepository.getStates
select distinct select distinct
on ("state") "state" on ("state") "state"
from from
"exif" "asset_exif"
inner join "assets" on "assets"."id" = "exif"."assetId" inner join "asset" on "asset"."id" = "asset_exif"."assetId"
where where
"ownerId" = any ($1::uuid[]) "ownerId" = any ($1::uuid[])
and "visibility" = $2 and "visibility" = $2
@ -230,8 +230,8 @@ where
select distinct select distinct
on ("city") "city" on ("city") "city"
from from
"exif" "asset_exif"
inner join "assets" on "assets"."id" = "exif"."assetId" inner join "asset" on "asset"."id" = "asset_exif"."assetId"
where where
"ownerId" = any ($1::uuid[]) "ownerId" = any ($1::uuid[])
and "visibility" = $2 and "visibility" = $2
@ -242,8 +242,8 @@ where
select distinct select distinct
on ("make") "make" on ("make") "make"
from from
"exif" "asset_exif"
inner join "assets" on "assets"."id" = "exif"."assetId" inner join "asset" on "asset"."id" = "asset_exif"."assetId"
where where
"ownerId" = any ($1::uuid[]) "ownerId" = any ($1::uuid[])
and "visibility" = $2 and "visibility" = $2
@ -254,8 +254,8 @@ where
select distinct select distinct
on ("model") "model" on ("model") "model"
from from
"exif" "asset_exif"
inner join "assets" on "assets"."id" = "exif"."assetId" inner join "asset" on "asset"."id" = "asset_exif"."assetId"
where where
"ownerId" = any ($1::uuid[]) "ownerId" = any ($1::uuid[])
and "visibility" = $2 and "visibility" = $2

View File

@ -6,68 +6,68 @@ select
"expiresAt", "expiresAt",
"pinExpiresAt" "pinExpiresAt"
from from
"sessions" "session"
where where
"id" = $1 "id" = $1
-- SessionRepository.getByToken -- SessionRepository.getByToken
select select
"sessions"."id", "session"."id",
"sessions"."isPendingSyncReset", "session"."isPendingSyncReset",
"sessions"."updatedAt", "session"."updatedAt",
"sessions"."pinExpiresAt", "session"."pinExpiresAt",
( (
select select
to_json(obj) to_json(obj)
from from
( (
select select
"users"."id", "user"."id",
"users"."name", "user"."name",
"users"."email", "user"."email",
"users"."isAdmin", "user"."isAdmin",
"users"."quotaUsageInBytes", "user"."quotaUsageInBytes",
"users"."quotaSizeInBytes" "user"."quotaSizeInBytes"
from from
"users" "user"
where where
"users"."id" = "sessions"."userId" "user"."id" = "session"."userId"
and "users"."deletedAt" is null and "user"."deletedAt" is null
) as obj ) as obj
) as "user" ) as "user"
from from
"sessions" "session"
where where
"sessions"."token" = $1 "session"."token" = $1
and ( and (
"sessions"."expiresAt" is null "session"."expiresAt" is null
or "sessions"."expiresAt" > $2 or "session"."expiresAt" > $2
) )
-- SessionRepository.getByUserId -- SessionRepository.getByUserId
select select
"sessions".* "session".*
from from
"sessions" "session"
inner join "users" on "users"."id" = "sessions"."userId" inner join "user" on "user"."id" = "session"."userId"
and "users"."deletedAt" is null and "user"."deletedAt" is null
where where
"sessions"."userId" = $1 "session"."userId" = $1
and ( and (
"sessions"."expiresAt" is null "session"."expiresAt" is null
or "sessions"."expiresAt" > $2 or "session"."expiresAt" > $2
) )
order by order by
"sessions"."updatedAt" desc, "session"."updatedAt" desc,
"sessions"."createdAt" desc "session"."createdAt" desc
-- SessionRepository.delete -- SessionRepository.delete
delete from "sessions" delete from "session"
where where
"id" = $1::uuid "id" = $1::uuid
-- SessionRepository.lockAll -- SessionRepository.lockAll
update "sessions" update "session"
set set
"pinExpiresAt" = $1 "pinExpiresAt" = $1
where where
@ -75,12 +75,12 @@ where
-- SessionRepository.resetSyncProgress -- SessionRepository.resetSyncProgress
begin begin
update "sessions" update "session"
set set
"isPendingSyncReset" = $1 "isPendingSyncReset" = $1
where where
"id" = $2 "id" = $2
delete from "session_sync_checkpoints" delete from "session_sync_checkpoint"
where where
"sessionId" = $1 "sessionId" = $1
commit commit

View File

@ -2,7 +2,7 @@
-- SharedLinkRepository.get -- SharedLinkRepository.get
select select
"shared_links".*, "shared_link".*,
coalesce( coalesce(
json_agg("a") filter ( json_agg("a") filter (
where where
@ -12,31 +12,31 @@ select
) as "assets", ) as "assets",
to_json("album") as "album" to_json("album") as "album"
from from
"shared_links" "shared_link"
left join lateral ( left join lateral (
select select
"assets".*, "asset".*,
to_json("exifInfo") as "exifInfo" to_json("exifInfo") as "exifInfo"
from from
"shared_link__asset" "shared_link_asset"
inner join "assets" on "assets"."id" = "shared_link__asset"."assetsId" inner join "asset" on "asset"."id" = "shared_link_asset"."assetsId"
inner join lateral ( inner join lateral (
select select
"exif".* "asset_exif".*
from from
"exif" "asset_exif"
where where
"exif"."assetId" = "assets"."id" "asset_exif"."assetId" = "asset"."id"
) as "exifInfo" on true ) as "exifInfo" on true
where where
"shared_links"."id" = "shared_link__asset"."sharedLinksId" "shared_link"."id" = "shared_link_asset"."sharedLinksId"
and "assets"."deletedAt" is null and "asset"."deletedAt" is null
order by order by
"assets"."fileCreatedAt" asc "asset"."fileCreatedAt" asc
) as "a" on true ) as "a" on true
left join lateral ( left join lateral (
select select
"albums".*, "album".*,
coalesce( coalesce(
json_agg("assets") filter ( json_agg("assets") filter (
where where
@ -46,151 +46,151 @@ from
) as "assets", ) as "assets",
to_json("owner") as "owner" to_json("owner") as "owner"
from from
"albums" "album"
left join "albums_assets_assets" on "albums_assets_assets"."albumsId" = "albums"."id" left join "album_asset" on "album_asset"."albumsId" = "album"."id"
left join lateral ( left join lateral (
select select
"assets".*, "asset".*,
to_json("assets_exifInfo") as "exifInfo" to_json("exifInfo") as "exifInfo"
from from
"assets" "asset"
inner join lateral ( inner join lateral (
select select
"exif".* "asset_exif".*
from from
"exif" "asset_exif"
where where
"exif"."assetId" = "assets"."id" "asset_exif"."assetId" = "asset"."id"
) as "assets_exifInfo" on true ) as "exifInfo" on true
where where
"albums_assets_assets"."assetsId" = "assets"."id" "album_asset"."assetsId" = "asset"."id"
and "assets"."deletedAt" is null and "asset"."deletedAt" is null
order by order by
"assets"."fileCreatedAt" asc "asset"."fileCreatedAt" asc
) as "assets" on true ) as "assets" on true
inner join lateral ( inner join lateral (
select select
"users".* "user".*
from from
"users" "user"
where where
"users"."id" = "albums"."ownerId" "user"."id" = "album"."ownerId"
and "users"."deletedAt" is null and "user"."deletedAt" is null
) as "owner" on true ) as "owner" on true
where where
"albums"."id" = "shared_links"."albumId" "album"."id" = "shared_link"."albumId"
and "albums"."deletedAt" is null and "album"."deletedAt" is null
group by group by
"albums"."id", "album"."id",
"owner".* "owner".*
) as "album" on true ) as "album" on true
where where
"shared_links"."id" = $1 "shared_link"."id" = $1
and "shared_links"."userId" = $2 and "shared_link"."userId" = $2
and ( and (
"shared_links"."type" = $3 "shared_link"."type" = $3
or "album"."id" is not null or "album"."id" is not null
) )
group by group by
"shared_links"."id", "shared_link"."id",
"album".* "album".*
order by order by
"shared_links"."createdAt" desc "shared_link"."createdAt" desc
-- SharedLinkRepository.getAll -- SharedLinkRepository.getAll
select distinct select distinct
on ("shared_links"."createdAt") "shared_links".*, on ("shared_link"."createdAt") "shared_link".*,
"assets"."assets", "assets"."assets",
to_json("album") as "album" to_json("album") as "album"
from from
"shared_links" "shared_link"
left join "shared_link__asset" on "shared_link__asset"."sharedLinksId" = "shared_links"."id" left join "shared_link_asset" on "shared_link_asset"."sharedLinksId" = "shared_link"."id"
left join lateral ( left join lateral (
select select
json_agg("assets") as "assets" json_agg("asset") as "assets"
from from
"assets" "asset"
where where
"assets"."id" = "shared_link__asset"."assetsId" "asset"."id" = "shared_link_asset"."assetsId"
and "assets"."deletedAt" is null and "asset"."deletedAt" is null
) as "assets" on true ) as "assets" on true
left join lateral ( left join lateral (
select select
"albums".*, "album".*,
to_json("owner") as "owner" to_json("owner") as "owner"
from from
"albums" "album"
inner join lateral ( inner join lateral (
select select
"users"."id", "user"."id",
"users"."email", "user"."email",
"users"."createdAt", "user"."createdAt",
"users"."profileImagePath", "user"."profileImagePath",
"users"."isAdmin", "user"."isAdmin",
"users"."shouldChangePassword", "user"."shouldChangePassword",
"users"."deletedAt", "user"."deletedAt",
"users"."oauthId", "user"."oauthId",
"users"."updatedAt", "user"."updatedAt",
"users"."storageLabel", "user"."storageLabel",
"users"."name", "user"."name",
"users"."quotaSizeInBytes", "user"."quotaSizeInBytes",
"users"."quotaUsageInBytes", "user"."quotaUsageInBytes",
"users"."status", "user"."status",
"users"."profileChangedAt" "user"."profileChangedAt"
from from
"users" "user"
where where
"users"."id" = "albums"."ownerId" "user"."id" = "album"."ownerId"
and "users"."deletedAt" is null and "user"."deletedAt" is null
) as "owner" on true ) as "owner" on true
where where
"albums"."id" = "shared_links"."albumId" "album"."id" = "shared_link"."albumId"
and "albums"."deletedAt" is null and "album"."deletedAt" is null
) as "album" on true ) as "album" on true
where where
"shared_links"."userId" = $1 "shared_link"."userId" = $1
and ( and (
"shared_links"."type" = $2 "shared_link"."type" = $2
or "album"."id" is not null or "album"."id" is not null
) )
and "shared_links"."albumId" = $3 and "shared_link"."albumId" = $3
order by order by
"shared_links"."createdAt" desc "shared_link"."createdAt" desc
-- SharedLinkRepository.getByKey -- SharedLinkRepository.getByKey
select select
"shared_links"."id", "shared_link"."id",
"shared_links"."userId", "shared_link"."userId",
"shared_links"."expiresAt", "shared_link"."expiresAt",
"shared_links"."showExif", "shared_link"."showExif",
"shared_links"."allowUpload", "shared_link"."allowUpload",
"shared_links"."allowDownload", "shared_link"."allowDownload",
"shared_links"."password", "shared_link"."password",
( (
select select
to_json(obj) to_json(obj)
from from
( (
select select
"users"."id", "user"."id",
"users"."name", "user"."name",
"users"."email", "user"."email",
"users"."isAdmin", "user"."isAdmin",
"users"."quotaUsageInBytes", "user"."quotaUsageInBytes",
"users"."quotaSizeInBytes" "user"."quotaSizeInBytes"
from from
"users" "user"
where where
"users"."id" = "shared_links"."userId" "user"."id" = "shared_link"."userId"
) as obj ) as obj
) as "user" ) as "user"
from from
"shared_links" "shared_link"
left join "albums" on "albums"."id" = "shared_links"."albumId" left join "album" on "album"."id" = "shared_link"."albumId"
where where
"shared_links"."key" = $1 "shared_link"."key" = $1
and "albums"."deletedAt" is null and "album"."deletedAt" is null
and ( and (
"shared_links"."type" = $2 "shared_link"."type" = $2
or "albums"."id" is not null or "album"."id" is not null
) )

View File

@ -2,66 +2,66 @@
-- StackRepository.search -- StackRepository.search
select select
"asset_stack".*, "stack".*,
( (
select select
coalesce(json_agg(agg), '[]') coalesce(json_agg(agg), '[]')
from from
( (
select select
"assets".*, "asset".*,
to_json("exifInfo") as "exifInfo" to_json("exifInfo") as "exifInfo"
from from
"assets" "asset"
inner join lateral ( inner join lateral (
select select
"exif"."assetId", "asset_exif"."assetId",
"exif"."autoStackId", "asset_exif"."autoStackId",
"exif"."bitsPerSample", "asset_exif"."bitsPerSample",
"exif"."city", "asset_exif"."city",
"exif"."colorspace", "asset_exif"."colorspace",
"exif"."country", "asset_exif"."country",
"exif"."dateTimeOriginal", "asset_exif"."dateTimeOriginal",
"exif"."description", "asset_exif"."description",
"exif"."exifImageHeight", "asset_exif"."exifImageHeight",
"exif"."exifImageWidth", "asset_exif"."exifImageWidth",
"exif"."exposureTime", "asset_exif"."exposureTime",
"exif"."fileSizeInByte", "asset_exif"."fileSizeInByte",
"exif"."fNumber", "asset_exif"."fNumber",
"exif"."focalLength", "asset_exif"."focalLength",
"exif"."fps", "asset_exif"."fps",
"exif"."iso", "asset_exif"."iso",
"exif"."latitude", "asset_exif"."latitude",
"exif"."lensModel", "asset_exif"."lensModel",
"exif"."livePhotoCID", "asset_exif"."livePhotoCID",
"exif"."longitude", "asset_exif"."longitude",
"exif"."make", "asset_exif"."make",
"exif"."model", "asset_exif"."model",
"exif"."modifyDate", "asset_exif"."modifyDate",
"exif"."orientation", "asset_exif"."orientation",
"exif"."profileDescription", "asset_exif"."profileDescription",
"exif"."projectionType", "asset_exif"."projectionType",
"exif"."rating", "asset_exif"."rating",
"exif"."state", "asset_exif"."state",
"exif"."timeZone" "asset_exif"."timeZone"
from from
"exif" "asset_exif"
where where
"exif"."assetId" = "assets"."id" "asset_exif"."assetId" = "asset"."id"
) as "exifInfo" on true ) as "exifInfo" on true
where where
"assets"."deletedAt" is null "asset"."deletedAt" is null
and "assets"."stackId" = "asset_stack"."id" and "asset"."stackId" = "stack"."id"
and "assets"."visibility" in ('archive', 'timeline') and "asset"."visibility" in ('archive', 'timeline')
) as agg ) as agg
) as "assets" ) as "assets"
from from
"asset_stack" "stack"
where where
"asset_stack"."ownerId" = $1 "stack"."ownerId" = $1
-- StackRepository.delete -- StackRepository.delete
delete from "asset_stack" delete from "stack"
where where
"id" = $1::uuid "id" = $1::uuid
@ -74,72 +74,72 @@ select
from from
( (
select select
"assets".*, "asset".*,
( (
select select
coalesce(json_agg(agg), '[]') coalesce(json_agg(agg), '[]')
from from
( (
select select
"tags"."id", "tag"."id",
"tags"."value", "tag"."value",
"tags"."createdAt", "tag"."createdAt",
"tags"."updatedAt", "tag"."updatedAt",
"tags"."color", "tag"."color",
"tags"."parentId" "tag"."parentId"
from from
"tags" "tag"
inner join "tag_asset" on "tags"."id" = "tag_asset"."tagsId" inner join "tag_asset" on "tag"."id" = "tag_asset"."tagsId"
where where
"tag_asset"."assetsId" = "assets"."id" "tag_asset"."assetsId" = "asset"."id"
) as agg ) as agg
) as "tags", ) as "tags",
to_json("exifInfo") as "exifInfo" to_json("exifInfo") as "exifInfo"
from from
"assets" "asset"
inner join lateral ( inner join lateral (
select select
"exif"."assetId", "asset_exif"."assetId",
"exif"."autoStackId", "asset_exif"."autoStackId",
"exif"."bitsPerSample", "asset_exif"."bitsPerSample",
"exif"."city", "asset_exif"."city",
"exif"."colorspace", "asset_exif"."colorspace",
"exif"."country", "asset_exif"."country",
"exif"."dateTimeOriginal", "asset_exif"."dateTimeOriginal",
"exif"."description", "asset_exif"."description",
"exif"."exifImageHeight", "asset_exif"."exifImageHeight",
"exif"."exifImageWidth", "asset_exif"."exifImageWidth",
"exif"."exposureTime", "asset_exif"."exposureTime",
"exif"."fileSizeInByte", "asset_exif"."fileSizeInByte",
"exif"."fNumber", "asset_exif"."fNumber",
"exif"."focalLength", "asset_exif"."focalLength",
"exif"."fps", "asset_exif"."fps",
"exif"."iso", "asset_exif"."iso",
"exif"."latitude", "asset_exif"."latitude",
"exif"."lensModel", "asset_exif"."lensModel",
"exif"."livePhotoCID", "asset_exif"."livePhotoCID",
"exif"."longitude", "asset_exif"."longitude",
"exif"."make", "asset_exif"."make",
"exif"."model", "asset_exif"."model",
"exif"."modifyDate", "asset_exif"."modifyDate",
"exif"."orientation", "asset_exif"."orientation",
"exif"."profileDescription", "asset_exif"."profileDescription",
"exif"."projectionType", "asset_exif"."projectionType",
"exif"."rating", "asset_exif"."rating",
"exif"."state", "asset_exif"."state",
"exif"."timeZone" "asset_exif"."timeZone"
from from
"exif" "asset_exif"
where where
"exif"."assetId" = "assets"."id" "asset_exif"."assetId" = "asset"."id"
) as "exifInfo" on true ) as "exifInfo" on true
where where
"assets"."deletedAt" is null "asset"."deletedAt" is null
and "assets"."stackId" = "asset_stack"."id" and "asset"."stackId" = "stack"."id"
and "assets"."visibility" in ('archive', 'timeline') and "asset"."visibility" in ('archive', 'timeline')
) as agg ) as agg
) as "assets" ) as "assets"
from from
"asset_stack" "stack"
where where
"id" = $1::uuid "id" = $1::uuid

View File

@ -5,11 +5,11 @@ select
"type", "type",
"ack" "ack"
from from
"session_sync_checkpoints" "session_sync_checkpoint"
where where
"sessionId" = $1 "sessionId" = $1
-- SyncCheckpointRepository.deleteAll -- SyncCheckpointRepository.deleteAll
delete from "session_sync_checkpoints" delete from "session_sync_checkpoint"
where where
"sessionId" = $1 "sessionId" = $1

View File

@ -5,7 +5,7 @@ select
"albumsId" as "id", "albumsId" as "id",
"createId" "createId"
from from
"albums_shared_users_users" "album_user"
where where
"usersId" = $1 "usersId" = $1
and "createId" >= $2 and "createId" >= $2
@ -18,7 +18,7 @@ select
"id", "id",
"albumId" "albumId"
from from
"albums_audit" "album_audit"
where where
"userId" = $1 "userId" = $1
and "deletedAt" < now() - interval '1 millisecond' and "deletedAt" < now() - interval '1 millisecond'
@ -27,165 +27,165 @@ order by
-- SyncRepository.album.getUpserts -- SyncRepository.album.getUpserts
select distinct select distinct
on ("albums"."id", "albums"."updateId") "albums"."id", on ("album"."id", "album"."updateId") "album"."id",
"albums"."ownerId", "album"."ownerId",
"albums"."albumName" as "name", "album"."albumName" as "name",
"albums"."description", "album"."description",
"albums"."createdAt", "album"."createdAt",
"albums"."updatedAt", "album"."updatedAt",
"albums"."albumThumbnailAssetId" as "thumbnailAssetId", "album"."albumThumbnailAssetId" as "thumbnailAssetId",
"albums"."isActivityEnabled", "album"."isActivityEnabled",
"albums"."order", "album"."order",
"albums"."updateId" "album"."updateId"
from from
"albums" "album"
left join "albums_shared_users_users" as "album_users" on "albums"."id" = "album_users"."albumsId" left join "album_user" as "album_users" on "album"."id" = "album_users"."albumsId"
where where
"albums"."updatedAt" < now() - interval '1 millisecond' "album"."updatedAt" < now() - interval '1 millisecond'
and ( and (
"albums"."ownerId" = $1 "album"."ownerId" = $1
or "album_users"."usersId" = $2 or "album_users"."usersId" = $2
) )
order by order by
"albums"."updateId" asc "album"."updateId" asc
-- SyncRepository.albumAsset.getBackfill -- SyncRepository.albumAsset.getBackfill
select select
"assets"."id", "asset"."id",
"assets"."ownerId", "asset"."ownerId",
"assets"."originalFileName", "asset"."originalFileName",
"assets"."thumbhash", "asset"."thumbhash",
"assets"."checksum", "asset"."checksum",
"assets"."fileCreatedAt", "asset"."fileCreatedAt",
"assets"."fileModifiedAt", "asset"."fileModifiedAt",
"assets"."localDateTime", "asset"."localDateTime",
"assets"."type", "asset"."type",
"assets"."deletedAt", "asset"."deletedAt",
"assets"."isFavorite", "asset"."isFavorite",
"assets"."visibility", "asset"."visibility",
"assets"."duration", "asset"."duration",
"assets"."updateId" "asset"."updateId"
from from
"assets" "asset"
inner join "albums_assets_assets" as "album_assets" on "album_assets"."assetsId" = "assets"."id" inner join "album_asset" on "album_asset"."assetsId" = "asset"."id"
where where
"album_assets"."albumsId" = $1 "album_asset"."albumsId" = $1
and "assets"."updatedAt" < now() - interval '1 millisecond' and "asset"."updatedAt" < now() - interval '1 millisecond'
and "assets"."updateId" <= $2 and "asset"."updateId" <= $2
and "assets"."updateId" >= $3 and "asset"."updateId" >= $3
order by order by
"assets"."updateId" asc "asset"."updateId" asc
-- SyncRepository.albumAsset.getUpserts -- SyncRepository.albumAsset.getUpserts
select select
"assets"."id", "asset"."id",
"assets"."ownerId", "asset"."ownerId",
"assets"."originalFileName", "asset"."originalFileName",
"assets"."thumbhash", "asset"."thumbhash",
"assets"."checksum", "asset"."checksum",
"assets"."fileCreatedAt", "asset"."fileCreatedAt",
"assets"."fileModifiedAt", "asset"."fileModifiedAt",
"assets"."localDateTime", "asset"."localDateTime",
"assets"."type", "asset"."type",
"assets"."deletedAt", "asset"."deletedAt",
"assets"."isFavorite", "asset"."isFavorite",
"assets"."visibility", "asset"."visibility",
"assets"."duration", "asset"."duration",
"assets"."updateId" "asset"."updateId"
from from
"assets" "asset"
inner join "albums_assets_assets" as "album_assets" on "album_assets"."assetsId" = "assets"."id" inner join "album_asset" on "album_asset"."assetsId" = "asset"."id"
inner join "albums" on "albums"."id" = "album_assets"."albumsId" inner join "album" on "album"."id" = "album_asset"."albumsId"
left join "albums_shared_users_users" as "album_users" on "album_users"."albumsId" = "album_assets"."albumsId" left join "album_user" on "album_user"."albumsId" = "album_asset"."albumsId"
where where
"assets"."updatedAt" < now() - interval '1 millisecond' "asset"."updatedAt" < now() - interval '1 millisecond'
and ( and (
"albums"."ownerId" = $1 "album"."ownerId" = $1
or "album_users"."usersId" = $2 or "album_user"."usersId" = $2
) )
order by order by
"assets"."updateId" asc "asset"."updateId" asc
-- SyncRepository.albumAssetExif.getBackfill -- SyncRepository.albumAssetExif.getBackfill
select select
"exif"."assetId", "asset_exif"."assetId",
"exif"."description", "asset_exif"."description",
"exif"."exifImageWidth", "asset_exif"."exifImageWidth",
"exif"."exifImageHeight", "asset_exif"."exifImageHeight",
"exif"."fileSizeInByte", "asset_exif"."fileSizeInByte",
"exif"."orientation", "asset_exif"."orientation",
"exif"."dateTimeOriginal", "asset_exif"."dateTimeOriginal",
"exif"."modifyDate", "asset_exif"."modifyDate",
"exif"."timeZone", "asset_exif"."timeZone",
"exif"."latitude", "asset_exif"."latitude",
"exif"."longitude", "asset_exif"."longitude",
"exif"."projectionType", "asset_exif"."projectionType",
"exif"."city", "asset_exif"."city",
"exif"."state", "asset_exif"."state",
"exif"."country", "asset_exif"."country",
"exif"."make", "asset_exif"."make",
"exif"."model", "asset_exif"."model",
"exif"."lensModel", "asset_exif"."lensModel",
"exif"."fNumber", "asset_exif"."fNumber",
"exif"."focalLength", "asset_exif"."focalLength",
"exif"."iso", "asset_exif"."iso",
"exif"."exposureTime", "asset_exif"."exposureTime",
"exif"."profileDescription", "asset_exif"."profileDescription",
"exif"."rating", "asset_exif"."rating",
"exif"."fps", "asset_exif"."fps",
"exif"."updateId" "asset_exif"."updateId"
from from
"exif" "asset_exif"
inner join "albums_assets_assets" as "album_assets" on "album_assets"."assetsId" = "exif"."assetId" inner join "album_asset" on "album_asset"."assetsId" = "asset_exif"."assetId"
where where
"album_assets"."albumsId" = $1 "album_asset"."albumsId" = $1
and "exif"."updatedAt" < now() - interval '1 millisecond' and "asset_exif"."updatedAt" < now() - interval '1 millisecond'
and "exif"."updateId" <= $2 and "asset_exif"."updateId" <= $2
and "exif"."updateId" >= $3 and "asset_exif"."updateId" >= $3
order by order by
"exif"."updateId" asc "asset_exif"."updateId" asc
-- SyncRepository.albumAssetExif.getUpserts -- SyncRepository.albumAssetExif.getUpserts
select select
"exif"."assetId", "asset_exif"."assetId",
"exif"."description", "asset_exif"."description",
"exif"."exifImageWidth", "asset_exif"."exifImageWidth",
"exif"."exifImageHeight", "asset_exif"."exifImageHeight",
"exif"."fileSizeInByte", "asset_exif"."fileSizeInByte",
"exif"."orientation", "asset_exif"."orientation",
"exif"."dateTimeOriginal", "asset_exif"."dateTimeOriginal",
"exif"."modifyDate", "asset_exif"."modifyDate",
"exif"."timeZone", "asset_exif"."timeZone",
"exif"."latitude", "asset_exif"."latitude",
"exif"."longitude", "asset_exif"."longitude",
"exif"."projectionType", "asset_exif"."projectionType",
"exif"."city", "asset_exif"."city",
"exif"."state", "asset_exif"."state",
"exif"."country", "asset_exif"."country",
"exif"."make", "asset_exif"."make",
"exif"."model", "asset_exif"."model",
"exif"."lensModel", "asset_exif"."lensModel",
"exif"."fNumber", "asset_exif"."fNumber",
"exif"."focalLength", "asset_exif"."focalLength",
"exif"."iso", "asset_exif"."iso",
"exif"."exposureTime", "asset_exif"."exposureTime",
"exif"."profileDescription", "asset_exif"."profileDescription",
"exif"."rating", "asset_exif"."rating",
"exif"."fps", "asset_exif"."fps",
"exif"."updateId" "asset_exif"."updateId"
from from
"exif" "asset_exif"
inner join "albums_assets_assets" as "album_assets" on "album_assets"."assetsId" = "exif"."assetId" inner join "album_asset" on "album_asset"."assetsId" = "asset_exif"."assetId"
inner join "albums" on "albums"."id" = "album_assets"."albumsId" inner join "album" on "album"."id" = "album_asset"."albumsId"
left join "albums_shared_users_users" as "album_users" on "album_users"."albumsId" = "album_assets"."albumsId" left join "album_user" on "album_user"."albumsId" = "album_asset"."albumsId"
where where
"exif"."updatedAt" < now() - interval '1 millisecond' "asset_exif"."updatedAt" < now() - interval '1 millisecond'
and ( and (
"albums"."ownerId" = $1 "album"."ownerId" = $1
or "album_users"."usersId" = $2 or "album_user"."usersId" = $2
) )
order by order by
"exif"."updateId" asc "asset_exif"."updateId" asc
-- SyncRepository.albumToAsset.getBackfill -- SyncRepository.albumToAsset.getBackfill
select select
@ -193,7 +193,7 @@ select
"album_assets"."albumsId" as "albumId", "album_assets"."albumsId" as "albumId",
"album_assets"."updateId" "album_assets"."updateId"
from from
"albums_assets_assets" as "album_assets" "album_asset" as "album_assets"
where where
"album_assets"."albumsId" = $1 "album_assets"."albumsId" = $1
and "album_assets"."updatedAt" < now() - interval '1 millisecond' and "album_assets"."updatedAt" < now() - interval '1 millisecond'
@ -208,23 +208,23 @@ select
"assetId", "assetId",
"albumId" "albumId"
from from
"album_assets_audit" "album_asset_audit"
where where
"albumId" in ( "albumId" in (
select select
"id" "id"
from from
"albums" "album"
where where
"ownerId" = $1 "ownerId" = $1
union union
( (
select select
"albumUsers"."albumsId" as "id" "album_user"."albumsId" as "id"
from from
"albums_shared_users_users" as "albumUsers" "album_user"
where where
"albumUsers"."usersId" = $2 "album_user"."usersId" = $2
) )
) )
and "deletedAt" < now() - interval '1 millisecond' and "deletedAt" < now() - interval '1 millisecond'
@ -233,30 +233,30 @@ order by
-- SyncRepository.albumToAsset.getUpserts -- SyncRepository.albumToAsset.getUpserts
select select
"album_assets"."assetsId" as "assetId", "album_asset"."assetsId" as "assetId",
"album_assets"."albumsId" as "albumId", "album_asset"."albumsId" as "albumId",
"album_assets"."updateId" "album_asset"."updateId"
from from
"albums_assets_assets" as "album_assets" "album_asset"
inner join "albums" on "albums"."id" = "album_assets"."albumsId" inner join "album" on "album"."id" = "album_asset"."albumsId"
left join "albums_shared_users_users" as "album_users" on "album_users"."albumsId" = "album_assets"."albumsId" left join "album_user" on "album_user"."albumsId" = "album_asset"."albumsId"
where where
"album_assets"."updatedAt" < now() - interval '1 millisecond' "album_asset"."updatedAt" < now() - interval '1 millisecond'
and ( and (
"albums"."ownerId" = $1 "album"."ownerId" = $1
or "album_users"."usersId" = $2 or "album_user"."usersId" = $2
) )
order by order by
"album_assets"."updateId" asc "album_asset"."updateId" asc
-- SyncRepository.albumUser.getBackfill -- SyncRepository.albumUser.getBackfill
select select
"album_users"."albumsId" as "albumId", "album_user"."albumsId" as "albumId",
"album_users"."usersId" as "userId", "album_user"."usersId" as "userId",
"album_users"."role", "album_user"."role",
"album_users"."updateId" "album_user"."updateId"
from from
"albums_shared_users_users" as "album_users" "album_user"
where where
"albumsId" = $1 "albumsId" = $1
and "updatedAt" < now() - interval '1 millisecond' and "updatedAt" < now() - interval '1 millisecond'
@ -271,23 +271,23 @@ select
"userId", "userId",
"albumId" "albumId"
from from
"album_users_audit" "album_user_audit"
where where
"albumId" in ( "albumId" in (
select select
"id" "id"
from from
"albums" "album"
where where
"ownerId" = $1 "ownerId" = $1
union union
( (
select select
"albumUsers"."albumsId" as "id" "album_user"."albumsId" as "id"
from from
"albums_shared_users_users" as "albumUsers" "album_user"
where where
"albumUsers"."usersId" = $2 "album_user"."usersId" = $2
) )
) )
and "deletedAt" < now() - interval '1 millisecond' and "deletedAt" < now() - interval '1 millisecond'
@ -296,19 +296,19 @@ order by
-- SyncRepository.albumUser.getUpserts -- SyncRepository.albumUser.getUpserts
select select
"album_users"."albumsId" as "albumId", "album_user"."albumsId" as "albumId",
"album_users"."usersId" as "userId", "album_user"."usersId" as "userId",
"album_users"."role", "album_user"."role",
"album_users"."updateId" "album_user"."updateId"
from from
"albums_shared_users_users" as "album_users" "album_user"
where where
"album_users"."updatedAt" < now() - interval '1 millisecond' "album_user"."updatedAt" < now() - interval '1 millisecond'
and "album_users"."albumsId" in ( and "album_user"."albumsId" in (
select select
"id" "id"
from from
"albums" "album"
where where
"ownerId" = $1 "ownerId" = $1
union union
@ -316,20 +316,20 @@ where
select select
"albumUsers"."albumsId" as "id" "albumUsers"."albumsId" as "id"
from from
"albums_shared_users_users" as "albumUsers" "album_user" as "albumUsers"
where where
"albumUsers"."usersId" = $2 "albumUsers"."usersId" = $2
) )
) )
order by order by
"album_users"."updateId" asc "album_user"."updateId" asc
-- SyncRepository.asset.getDeletes -- SyncRepository.asset.getDeletes
select select
"id", "id",
"assetId" "assetId"
from from
"assets_audit" "asset_audit"
where where
"ownerId" = $1 "ownerId" = $1
and "deletedAt" < now() - interval '1 millisecond' and "deletedAt" < now() - interval '1 millisecond'
@ -338,22 +338,22 @@ order by
-- SyncRepository.asset.getUpserts -- SyncRepository.asset.getUpserts
select select
"assets"."id", "asset"."id",
"assets"."ownerId", "asset"."ownerId",
"assets"."originalFileName", "asset"."originalFileName",
"assets"."thumbhash", "asset"."thumbhash",
"assets"."checksum", "asset"."checksum",
"assets"."fileCreatedAt", "asset"."fileCreatedAt",
"assets"."fileModifiedAt", "asset"."fileModifiedAt",
"assets"."localDateTime", "asset"."localDateTime",
"assets"."type", "asset"."type",
"assets"."deletedAt", "asset"."deletedAt",
"assets"."isFavorite", "asset"."isFavorite",
"assets"."visibility", "asset"."visibility",
"assets"."duration", "asset"."duration",
"assets"."updateId" "asset"."updateId"
from from
"assets" "asset"
where where
"ownerId" = $1 "ownerId" = $1
and "updatedAt" < now() - interval '1 millisecond' and "updatedAt" < now() - interval '1 millisecond'
@ -362,40 +362,40 @@ order by
-- SyncRepository.assetExif.getUpserts -- SyncRepository.assetExif.getUpserts
select select
"exif"."assetId", "asset_exif"."assetId",
"exif"."description", "asset_exif"."description",
"exif"."exifImageWidth", "asset_exif"."exifImageWidth",
"exif"."exifImageHeight", "asset_exif"."exifImageHeight",
"exif"."fileSizeInByte", "asset_exif"."fileSizeInByte",
"exif"."orientation", "asset_exif"."orientation",
"exif"."dateTimeOriginal", "asset_exif"."dateTimeOriginal",
"exif"."modifyDate", "asset_exif"."modifyDate",
"exif"."timeZone", "asset_exif"."timeZone",
"exif"."latitude", "asset_exif"."latitude",
"exif"."longitude", "asset_exif"."longitude",
"exif"."projectionType", "asset_exif"."projectionType",
"exif"."city", "asset_exif"."city",
"exif"."state", "asset_exif"."state",
"exif"."country", "asset_exif"."country",
"exif"."make", "asset_exif"."make",
"exif"."model", "asset_exif"."model",
"exif"."lensModel", "asset_exif"."lensModel",
"exif"."fNumber", "asset_exif"."fNumber",
"exif"."focalLength", "asset_exif"."focalLength",
"exif"."iso", "asset_exif"."iso",
"exif"."exposureTime", "asset_exif"."exposureTime",
"exif"."profileDescription", "asset_exif"."profileDescription",
"exif"."rating", "asset_exif"."rating",
"exif"."fps", "asset_exif"."fps",
"exif"."updateId" "asset_exif"."updateId"
from from
"exif" "asset_exif"
where where
"assetId" in ( "assetId" in (
select select
"id" "id"
from from
"assets" "asset"
where where
"ownerId" = $1 "ownerId" = $1
) )
@ -408,7 +408,7 @@ select
"id", "id",
"memoryId" "memoryId"
from from
"memories_audit" "memory_audit"
where where
"userId" = $1 "userId" = $1
and "deletedAt" < now() - interval '1 millisecond' and "deletedAt" < now() - interval '1 millisecond'
@ -431,7 +431,7 @@ select
"hideAt", "hideAt",
"updateId" "updateId"
from from
"memories" "memory"
where where
"ownerId" = $1 "ownerId" = $1
and "updatedAt" < now() - interval '1 millisecond' and "updatedAt" < now() - interval '1 millisecond'
@ -444,13 +444,13 @@ select
"memoryId", "memoryId",
"assetId" "assetId"
from from
"memory_assets_audit" "memory_asset_audit"
where where
"memoryId" in ( "memoryId" in (
select select
"id" "id"
from from
"memories" "memory"
where where
"ownerId" = $1 "ownerId" = $1
) )
@ -464,13 +464,13 @@ select
"assetsId" as "assetId", "assetsId" as "assetId",
"updateId" "updateId"
from from
"memories_assets_assets" "memory_asset"
where where
"memoriesId" in ( "memoriesId" in (
select select
"id" "id"
from from
"memories" "memory"
where where
"ownerId" = $1 "ownerId" = $1
) )
@ -483,13 +483,13 @@ select
"sharedById", "sharedById",
"createId" "createId"
from from
"partners" "partner"
where where
"sharedWithId" = $1 "sharedWithId" = $1
and "createId" >= $2 and "createId" >= $2
and "createdAt" < now() - interval '1 millisecond' and "createdAt" < now() - interval '1 millisecond'
order by order by
"partners"."createId" asc "partner"."createId" asc
-- SyncRepository.partner.getDeletes -- SyncRepository.partner.getDeletes
select select
@ -497,7 +497,7 @@ select
"sharedById", "sharedById",
"sharedWithId" "sharedWithId"
from from
"partners_audit" "partner_audit"
where where
( (
"sharedById" = $1 "sharedById" = $1
@ -514,7 +514,7 @@ select
"inTimeline", "inTimeline",
"updateId" "updateId"
from from
"partners" "partner"
where where
( (
"sharedById" = $1 "sharedById" = $1
@ -526,22 +526,22 @@ order by
-- SyncRepository.partnerAsset.getBackfill -- SyncRepository.partnerAsset.getBackfill
select select
"assets"."id", "asset"."id",
"assets"."ownerId", "asset"."ownerId",
"assets"."originalFileName", "asset"."originalFileName",
"assets"."thumbhash", "asset"."thumbhash",
"assets"."checksum", "asset"."checksum",
"assets"."fileCreatedAt", "asset"."fileCreatedAt",
"assets"."fileModifiedAt", "asset"."fileModifiedAt",
"assets"."localDateTime", "asset"."localDateTime",
"assets"."type", "asset"."type",
"assets"."deletedAt", "asset"."deletedAt",
"assets"."isFavorite", "asset"."isFavorite",
"assets"."visibility", "asset"."visibility",
"assets"."duration", "asset"."duration",
"assets"."updateId" "asset"."updateId"
from from
"assets" "asset"
where where
"ownerId" = $1 "ownerId" = $1
and "updatedAt" < now() - interval '1 millisecond' and "updatedAt" < now() - interval '1 millisecond'
@ -555,13 +555,13 @@ select
"id", "id",
"assetId" "assetId"
from from
"assets_audit" "asset_audit"
where where
"ownerId" in ( "ownerId" in (
select select
"sharedById" "sharedById"
from from
"partners" "partner"
where where
"sharedWithId" = $1 "sharedWithId" = $1
) )
@ -571,28 +571,28 @@ order by
-- SyncRepository.partnerAsset.getUpserts -- SyncRepository.partnerAsset.getUpserts
select select
"assets"."id", "asset"."id",
"assets"."ownerId", "asset"."ownerId",
"assets"."originalFileName", "asset"."originalFileName",
"assets"."thumbhash", "asset"."thumbhash",
"assets"."checksum", "asset"."checksum",
"assets"."fileCreatedAt", "asset"."fileCreatedAt",
"assets"."fileModifiedAt", "asset"."fileModifiedAt",
"assets"."localDateTime", "asset"."localDateTime",
"assets"."type", "asset"."type",
"assets"."deletedAt", "asset"."deletedAt",
"assets"."isFavorite", "asset"."isFavorite",
"assets"."visibility", "asset"."visibility",
"assets"."duration", "asset"."duration",
"assets"."updateId" "asset"."updateId"
from from
"assets" "asset"
where where
"ownerId" in ( "ownerId" in (
select select
"sharedById" "sharedById"
from from
"partners" "partner"
where where
"sharedWithId" = $1 "sharedWithId" = $1
) )
@ -602,85 +602,85 @@ order by
-- SyncRepository.partnerAssetExif.getBackfill -- SyncRepository.partnerAssetExif.getBackfill
select select
"exif"."assetId", "asset_exif"."assetId",
"exif"."description", "asset_exif"."description",
"exif"."exifImageWidth", "asset_exif"."exifImageWidth",
"exif"."exifImageHeight", "asset_exif"."exifImageHeight",
"exif"."fileSizeInByte", "asset_exif"."fileSizeInByte",
"exif"."orientation", "asset_exif"."orientation",
"exif"."dateTimeOriginal", "asset_exif"."dateTimeOriginal",
"exif"."modifyDate", "asset_exif"."modifyDate",
"exif"."timeZone", "asset_exif"."timeZone",
"exif"."latitude", "asset_exif"."latitude",
"exif"."longitude", "asset_exif"."longitude",
"exif"."projectionType", "asset_exif"."projectionType",
"exif"."city", "asset_exif"."city",
"exif"."state", "asset_exif"."state",
"exif"."country", "asset_exif"."country",
"exif"."make", "asset_exif"."make",
"exif"."model", "asset_exif"."model",
"exif"."lensModel", "asset_exif"."lensModel",
"exif"."fNumber", "asset_exif"."fNumber",
"exif"."focalLength", "asset_exif"."focalLength",
"exif"."iso", "asset_exif"."iso",
"exif"."exposureTime", "asset_exif"."exposureTime",
"exif"."profileDescription", "asset_exif"."profileDescription",
"exif"."rating", "asset_exif"."rating",
"exif"."fps", "asset_exif"."fps",
"exif"."updateId" "asset_exif"."updateId"
from from
"exif" "asset_exif"
inner join "assets" on "assets"."id" = "exif"."assetId" inner join "asset" on "asset"."id" = "asset_exif"."assetId"
where where
"assets"."ownerId" = $1 "asset"."ownerId" = $1
and "exif"."updatedAt" < now() - interval '1 millisecond' and "asset_exif"."updatedAt" < now() - interval '1 millisecond'
and "exif"."updateId" <= $2 and "asset_exif"."updateId" <= $2
and "exif"."updateId" >= $3 and "asset_exif"."updateId" >= $3
order by order by
"exif"."updateId" asc "asset_exif"."updateId" asc
-- SyncRepository.partnerAssetExif.getUpserts -- SyncRepository.partnerAssetExif.getUpserts
select select
"exif"."assetId", "asset_exif"."assetId",
"exif"."description", "asset_exif"."description",
"exif"."exifImageWidth", "asset_exif"."exifImageWidth",
"exif"."exifImageHeight", "asset_exif"."exifImageHeight",
"exif"."fileSizeInByte", "asset_exif"."fileSizeInByte",
"exif"."orientation", "asset_exif"."orientation",
"exif"."dateTimeOriginal", "asset_exif"."dateTimeOriginal",
"exif"."modifyDate", "asset_exif"."modifyDate",
"exif"."timeZone", "asset_exif"."timeZone",
"exif"."latitude", "asset_exif"."latitude",
"exif"."longitude", "asset_exif"."longitude",
"exif"."projectionType", "asset_exif"."projectionType",
"exif"."city", "asset_exif"."city",
"exif"."state", "asset_exif"."state",
"exif"."country", "asset_exif"."country",
"exif"."make", "asset_exif"."make",
"exif"."model", "asset_exif"."model",
"exif"."lensModel", "asset_exif"."lensModel",
"exif"."fNumber", "asset_exif"."fNumber",
"exif"."focalLength", "asset_exif"."focalLength",
"exif"."iso", "asset_exif"."iso",
"exif"."exposureTime", "asset_exif"."exposureTime",
"exif"."profileDescription", "asset_exif"."profileDescription",
"exif"."rating", "asset_exif"."rating",
"exif"."fps", "asset_exif"."fps",
"exif"."updateId" "asset_exif"."updateId"
from from
"exif" "asset_exif"
where where
"assetId" in ( "assetId" in (
select select
"id" "id"
from from
"assets" "asset"
where where
"ownerId" in ( "ownerId" in (
select select
"sharedById" "sharedById"
from from
"partners" "partner"
where where
"sharedWithId" = $1 "sharedWithId" = $1
) )
@ -694,13 +694,13 @@ select
"id", "id",
"stackId" "stackId"
from from
"stacks_audit" "stack_audit"
where where
"userId" in ( "userId" in (
select select
"sharedById" "sharedById"
from from
"partners" "partner"
where where
"sharedWithId" = $1 "sharedWithId" = $1
) )
@ -710,14 +710,14 @@ order by
-- SyncRepository.partnerStack.getBackfill -- SyncRepository.partnerStack.getBackfill
select select
"asset_stack"."id", "stack"."id",
"asset_stack"."createdAt", "stack"."createdAt",
"asset_stack"."updatedAt", "stack"."updatedAt",
"asset_stack"."primaryAssetId", "stack"."primaryAssetId",
"asset_stack"."ownerId", "stack"."ownerId",
"updateId" "updateId"
from from
"asset_stack" "stack"
where where
"ownerId" = $1 "ownerId" = $1
and "updatedAt" < now() - interval '1 millisecond' and "updatedAt" < now() - interval '1 millisecond'
@ -728,20 +728,20 @@ order by
-- SyncRepository.partnerStack.getUpserts -- SyncRepository.partnerStack.getUpserts
select select
"asset_stack"."id", "stack"."id",
"asset_stack"."createdAt", "stack"."createdAt",
"asset_stack"."updatedAt", "stack"."updatedAt",
"asset_stack"."primaryAssetId", "stack"."primaryAssetId",
"asset_stack"."ownerId", "stack"."ownerId",
"updateId" "updateId"
from from
"asset_stack" "stack"
where where
"ownerId" in ( "ownerId" in (
select select
"sharedById" "sharedById"
from from
"partners" "partner"
where where
"sharedWithId" = $1 "sharedWithId" = $1
) )
@ -788,7 +788,7 @@ select
"id", "id",
"stackId" "stackId"
from from
"stacks_audit" "stack_audit"
where where
"userId" = $1 "userId" = $1
and "deletedAt" < now() - interval '1 millisecond' and "deletedAt" < now() - interval '1 millisecond'
@ -797,14 +797,14 @@ order by
-- SyncRepository.stack.getUpserts -- SyncRepository.stack.getUpserts
select select
"asset_stack"."id", "stack"."id",
"asset_stack"."createdAt", "stack"."createdAt",
"asset_stack"."updatedAt", "stack"."updatedAt",
"asset_stack"."primaryAssetId", "stack"."primaryAssetId",
"asset_stack"."ownerId", "stack"."ownerId",
"updateId" "updateId"
from from
"asset_stack" "stack"
where where
"ownerId" = $1 "ownerId" = $1
and "updatedAt" < now() - interval '1 millisecond' and "updatedAt" < now() - interval '1 millisecond'
@ -816,7 +816,7 @@ select
"id", "id",
"userId" "userId"
from from
"users_audit" "user_audit"
where where
"deletedAt" < now() - interval '1 millisecond' "deletedAt" < now() - interval '1 millisecond'
order by order by
@ -830,7 +830,7 @@ select
"deletedAt", "deletedAt",
"updateId" "updateId"
from from
"users" "user"
where where
"updatedAt" < now() - interval '1 millisecond' "updatedAt" < now() - interval '1 millisecond'
order by order by

View File

@ -2,27 +2,27 @@
-- TagRepository.get -- TagRepository.get
select select
"tags"."id", "tag"."id",
"tags"."value", "tag"."value",
"tags"."createdAt", "tag"."createdAt",
"tags"."updatedAt", "tag"."updatedAt",
"tags"."color", "tag"."color",
"tags"."parentId" "tag"."parentId"
from from
"tags" "tag"
where where
"id" = $1 "id" = $1
-- TagRepository.getByValue -- TagRepository.getByValue
select select
"tags"."id", "tag"."id",
"tags"."value", "tag"."value",
"tags"."createdAt", "tag"."createdAt",
"tags"."updatedAt", "tag"."updatedAt",
"tags"."color", "tag"."color",
"tags"."parentId" "tag"."parentId"
from from
"tags" "tag"
where where
"userId" = $1 "userId" = $1
and "value" = $2 and "value" = $2
@ -30,31 +30,31 @@ where
-- TagRepository.upsertValue -- TagRepository.upsertValue
begin begin
insert into insert into
"tags" ("userId", "value", "parentId") "tag" ("userId", "value", "parentId")
values values
($1, $2, $3) ($1, $2, $3)
on conflict ("userId", "value") do update on conflict ("userId", "value") do update
set set
"parentId" = $4 "parentId" = $4
returning returning
"tags"."id", "tag"."id",
"tags"."value", "tag"."value",
"tags"."createdAt", "tag"."createdAt",
"tags"."updatedAt", "tag"."updatedAt",
"tags"."color", "tag"."color",
"tags"."parentId" "tag"."parentId"
rollback rollback
-- TagRepository.getAll -- TagRepository.getAll
select select
"tags"."id", "tag"."id",
"tags"."value", "tag"."value",
"tags"."createdAt", "tag"."createdAt",
"tags"."updatedAt", "tag"."updatedAt",
"tags"."color", "tag"."color",
"tags"."parentId" "tag"."parentId"
from from
"tags" "tag"
where where
"userId" = $1 "userId" = $1
order by order by
@ -62,14 +62,14 @@ order by
-- TagRepository.create -- TagRepository.create
insert into insert into
"tags" ("userId", "color", "value") "tag" ("userId", "color", "value")
values values
($1, $2, $3) ($1, $2, $3)
returning returning
* *
-- TagRepository.update -- TagRepository.update
update "tags" update "tag"
set set
"color" = $1 "color" = $1
where where
@ -78,7 +78,7 @@ returning
* *
-- TagRepository.delete -- TagRepository.delete
delete from "tags" delete from "tag"
where where
"id" = $1 "id" = $1

View File

@ -1,7 +1,7 @@
-- NOTE: This file is auto generated by ./sql-generator -- NOTE: This file is auto generated by ./sql-generator
-- TrashRepository.restore -- TrashRepository.restore
update "assets" update "asset"
set set
"status" = $1, "status" = $1,
"deletedAt" = $2 "deletedAt" = $2
@ -10,7 +10,7 @@ where
and "status" = $4 and "status" = $4
-- TrashRepository.empty -- TrashRepository.empty
update "assets" update "asset"
set set
"status" = $1 "status" = $1
where where
@ -18,7 +18,7 @@ where
and "status" = $3 and "status" = $3
-- TrashRepository.restoreAll -- TrashRepository.restoreAll
update "assets" update "asset"
set set
"status" = $1, "status" = $1,
"deletedAt" = $2 "deletedAt" = $2

View File

@ -30,14 +30,14 @@ select
from from
"user_metadata" "user_metadata"
where where
"users"."id" = "user_metadata"."userId" "user"."id" = "user_metadata"."userId"
) as agg ) as agg
) as "metadata" ) as "metadata"
from from
"users" "user"
where where
"users"."id" = $1 "user"."id" = $1
and "users"."deletedAt" is null and "user"."deletedAt" is null
-- UserRepository.getAdmin -- UserRepository.getAdmin
select select
@ -69,43 +69,43 @@ select
from from
"user_metadata" "user_metadata"
where where
"users"."id" = "user_metadata"."userId" "user"."id" = "user_metadata"."userId"
) as agg ) as agg
) as "metadata" ) as "metadata"
from from
"users" "user"
where where
"users"."isAdmin" = $1 "user"."isAdmin" = $1
and "users"."deletedAt" is null and "user"."deletedAt" is null
-- UserRepository.hasAdmin -- UserRepository.hasAdmin
select select
"users"."id" "user"."id"
from from
"users" "user"
where where
"users"."isAdmin" = $1 "user"."isAdmin" = $1
and "users"."deletedAt" is null and "user"."deletedAt" is null
-- UserRepository.getForPinCode -- UserRepository.getForPinCode
select select
"users"."pinCode", "user"."pinCode",
"users"."password" "user"."password"
from from
"users" "user"
where where
"users"."id" = $1 "user"."id" = $1
and "users"."deletedAt" is null and "user"."deletedAt" is null
-- UserRepository.getForChangePassword -- UserRepository.getForChangePassword
select select
"users"."id", "user"."id",
"users"."password" "user"."password"
from from
"users" "user"
where where
"users"."id" = $1 "user"."id" = $1
and "users"."deletedAt" is null and "user"."deletedAt" is null
-- UserRepository.getByEmail -- UserRepository.getByEmail
select select
@ -137,14 +137,14 @@ select
from from
"user_metadata" "user_metadata"
where where
"users"."id" = "user_metadata"."userId" "user"."id" = "user_metadata"."userId"
) as agg ) as agg
) as "metadata" ) as "metadata"
from from
"users" "user"
where where
"email" = $1 "email" = $1
and "users"."deletedAt" is null and "user"."deletedAt" is null
-- UserRepository.getByStorageLabel -- UserRepository.getByStorageLabel
select select
@ -166,10 +166,10 @@ select
"quotaSizeInBytes", "quotaSizeInBytes",
"quotaUsageInBytes" "quotaUsageInBytes"
from from
"users" "user"
where where
"users"."storageLabel" = $1 "user"."storageLabel" = $1
and "users"."deletedAt" is null and "user"."deletedAt" is null
-- UserRepository.getByOAuthId -- UserRepository.getByOAuthId
select select
@ -201,22 +201,22 @@ select
from from
"user_metadata" "user_metadata"
where where
"users"."id" = "user_metadata"."userId" "user"."id" = "user_metadata"."userId"
) as agg ) as agg
) as "metadata" ) as "metadata"
from from
"users" "user"
where where
"users"."oauthId" = $1 "user"."oauthId" = $1
and "users"."deletedAt" is null and "user"."deletedAt" is null
-- UserRepository.getDeletedAfter -- UserRepository.getDeletedAfter
select select
"id" "id"
from from
"users" "user"
where where
"users"."deletedAt" < $1 "user"."deletedAt" < $1
-- UserRepository.getList (with deleted) -- UserRepository.getList (with deleted)
select select
@ -248,11 +248,11 @@ select
from from
"user_metadata" "user_metadata"
where where
"users"."id" = "user_metadata"."userId" "user"."id" = "user_metadata"."userId"
) as agg ) as agg
) as "metadata" ) as "metadata"
from from
"users" "user"
order by order by
"createdAt" desc "createdAt" desc
@ -286,95 +286,95 @@ select
from from
"user_metadata" "user_metadata"
where where
"users"."id" = "user_metadata"."userId" "user"."id" = "user_metadata"."userId"
) as agg ) as agg
) as "metadata" ) as "metadata"
from from
"users" "user"
where where
"users"."deletedAt" is null "user"."deletedAt" is null
order by order by
"createdAt" desc "createdAt" desc
-- UserRepository.getUserStats -- UserRepository.getUserStats
select select
"users"."id" as "userId", "user"."id" as "userId",
"users"."name" as "userName", "user"."name" as "userName",
"users"."quotaSizeInBytes", "user"."quotaSizeInBytes",
count(*) filter ( count(*) filter (
where where
( (
"assets"."type" = 'IMAGE' "asset"."type" = 'IMAGE'
and "assets"."visibility" != 'hidden' and "asset"."visibility" != 'hidden'
) )
) as "photos", ) as "photos",
count(*) filter ( count(*) filter (
where where
( (
"assets"."type" = 'VIDEO' "asset"."type" = 'VIDEO'
and "assets"."visibility" != 'hidden' and "asset"."visibility" != 'hidden'
) )
) as "videos", ) as "videos",
coalesce( coalesce(
sum("exif"."fileSizeInByte") filter ( sum("asset_exif"."fileSizeInByte") filter (
where where
"assets"."libraryId" is null "asset"."libraryId" is null
), ),
0 0
) as "usage", ) as "usage",
coalesce( coalesce(
sum("exif"."fileSizeInByte") filter ( sum("asset_exif"."fileSizeInByte") filter (
where where
( (
"assets"."libraryId" is null "asset"."libraryId" is null
and "assets"."type" = 'IMAGE' and "asset"."type" = 'IMAGE'
) )
), ),
0 0
) as "usagePhotos", ) as "usagePhotos",
coalesce( coalesce(
sum("exif"."fileSizeInByte") filter ( sum("asset_exif"."fileSizeInByte") filter (
where where
( (
"assets"."libraryId" is null "asset"."libraryId" is null
and "assets"."type" = 'VIDEO' and "asset"."type" = 'VIDEO'
) )
), ),
0 0
) as "usageVideos" ) as "usageVideos"
from from
"users" "user"
left join "assets" on "assets"."ownerId" = "users"."id" left join "asset" on "asset"."ownerId" = "user"."id"
and "assets"."deletedAt" is null and "asset"."deletedAt" is null
left join "exif" on "exif"."assetId" = "assets"."id" left join "asset_exif" on "asset_exif"."assetId" = "asset"."id"
group by group by
"users"."id" "user"."id"
order by order by
"users"."createdAt" asc "user"."createdAt" asc
-- UserRepository.updateUsage -- UserRepository.updateUsage
update "users" update "user"
set set
"quotaUsageInBytes" = "quotaUsageInBytes" + $1, "quotaUsageInBytes" = "quotaUsageInBytes" + $1,
"updatedAt" = $2 "updatedAt" = $2
where where
"id" = $3::uuid "id" = $3::uuid
and "users"."deletedAt" is null and "user"."deletedAt" is null
-- UserRepository.syncUsage -- UserRepository.syncUsage
update "users" update "user"
set set
"quotaUsageInBytes" = ( "quotaUsageInBytes" = (
select select
coalesce(sum("exif"."fileSizeInByte"), 0) as "usage" coalesce(sum("asset_exif"."fileSizeInByte"), 0) as "usage"
from from
"assets" "asset"
left join "exif" on "exif"."assetId" = "assets"."id" left join "asset_exif" on "asset_exif"."assetId" = "asset"."id"
where where
"assets"."libraryId" is null "asset"."libraryId" is null
and "assets"."ownerId" = "users"."id" and "asset"."ownerId" = "user"."id"
), ),
"updatedAt" = $1 "updatedAt" = $1
where where
"users"."deletedAt" is null "user"."deletedAt" is null
and "users"."id" = $2::uuid and "user"."id" = $2::uuid

View File

@ -2,9 +2,9 @@
-- ViewRepository.getUniqueOriginalPaths -- ViewRepository.getUniqueOriginalPaths
select distinct select distinct
substring("assets"."originalPath", $1) as "directoryPath" substring("asset"."originalPath", $1) as "directoryPath"
from from
"assets" "asset"
where where
"ownerId" = $2::uuid "ownerId" = $2::uuid
and "visibility" = $3 and "visibility" = $3
@ -15,11 +15,11 @@ where
-- ViewRepository.getAssetsByOriginalPath -- ViewRepository.getAssetsByOriginalPath
select select
"assets".*, "asset".*,
to_json("exif") as "exifInfo" to_json("asset_exif") as "exifInfo"
from from
"assets" "asset"
left join "exif" on "assets"."id" = "exif"."assetId" left join "asset_exif" on "asset"."id" = "asset_exif"."assetId"
where where
"ownerId" = $1::uuid "ownerId" = $1::uuid
and "visibility" = $2 and "visibility" = $2
@ -30,4 +30,4 @@ where
and "originalPath" like $3 and "originalPath" like $3
and "originalPath" not like $4 and "originalPath" not like $4
order by order by
regexp_replace("assets"."originalPath", $5, $6) asc regexp_replace("asset"."originalPath", $5, $6) asc

View File

@ -35,9 +35,9 @@ class ActivityAccess {
return this.db return this.db
.selectFrom('activity') .selectFrom('activity')
.select('activity.id') .select('activity.id')
.leftJoin('albums', (join) => join.onRef('activity.albumId', '=', 'albums.id').on('albums.deletedAt', 'is', null)) .leftJoin('album', (join) => join.onRef('activity.albumId', '=', 'album.id').on('album.deletedAt', 'is', null))
.where('activity.id', 'in', [...activityIds]) .where('activity.id', 'in', [...activityIds])
.whereRef('albums.ownerId', '=', asUuid(userId)) .whereRef('album.ownerId', '=', asUuid(userId))
.execute() .execute()
.then((activities) => new Set(activities.map((activity) => activity.id))); .then((activities) => new Set(activities.map((activity) => activity.id)));
} }
@ -50,14 +50,14 @@ class ActivityAccess {
} }
return this.db return this.db
.selectFrom('albums') .selectFrom('album')
.select('albums.id') .select('album.id')
.leftJoin('albums_shared_users_users as albumUsers', 'albumUsers.albumsId', 'albums.id') .leftJoin('album_user as albumUsers', 'albumUsers.albumsId', 'album.id')
.leftJoin('users', (join) => join.onRef('users.id', '=', 'albumUsers.usersId').on('users.deletedAt', 'is', null)) .leftJoin('user', (join) => join.onRef('user.id', '=', 'albumUsers.usersId').on('user.deletedAt', 'is', null))
.where('albums.id', 'in', [...albumIds]) .where('album.id', 'in', [...albumIds])
.where('albums.isActivityEnabled', '=', true) .where('album.isActivityEnabled', '=', true)
.where((eb) => eb.or([eb('albums.ownerId', '=', userId), eb('users.id', '=', userId)])) .where((eb) => eb.or([eb('album.ownerId', '=', userId), eb('user.id', '=', userId)]))
.where('albums.deletedAt', 'is', null) .where('album.deletedAt', 'is', null)
.execute() .execute()
.then((albums) => new Set(albums.map((album) => album.id))); .then((albums) => new Set(albums.map((album) => album.id)));
} }
@ -74,11 +74,11 @@ class AlbumAccess {
} }
return this.db return this.db
.selectFrom('albums') .selectFrom('album')
.select('albums.id') .select('album.id')
.where('albums.id', 'in', [...albumIds]) .where('album.id', 'in', [...albumIds])
.where('albums.ownerId', '=', userId) .where('album.ownerId', '=', userId)
.where('albums.deletedAt', 'is', null) .where('album.deletedAt', 'is', null)
.execute() .execute()
.then((albums) => new Set(albums.map((album) => album.id))); .then((albums) => new Set(albums.map((album) => album.id)));
} }
@ -94,14 +94,14 @@ class AlbumAccess {
access === AlbumUserRole.EDITOR ? [AlbumUserRole.EDITOR] : [AlbumUserRole.EDITOR, AlbumUserRole.VIEWER]; access === AlbumUserRole.EDITOR ? [AlbumUserRole.EDITOR] : [AlbumUserRole.EDITOR, AlbumUserRole.VIEWER];
return this.db return this.db
.selectFrom('albums') .selectFrom('album')
.select('albums.id') .select('album.id')
.leftJoin('albums_shared_users_users as albumUsers', 'albumUsers.albumsId', 'albums.id') .leftJoin('album_user', 'album_user.albumsId', 'album.id')
.leftJoin('users', (join) => join.onRef('users.id', '=', 'albumUsers.usersId').on('users.deletedAt', 'is', null)) .leftJoin('user', (join) => join.onRef('user.id', '=', 'album_user.usersId').on('user.deletedAt', 'is', null))
.where('albums.id', 'in', [...albumIds]) .where('album.id', 'in', [...albumIds])
.where('albums.deletedAt', 'is', null) .where('album.deletedAt', 'is', null)
.where('users.id', '=', userId) .where('user.id', '=', userId)
.where('albumUsers.role', 'in', [...accessRole]) .where('album_user.role', 'in', [...accessRole])
.execute() .execute()
.then((albums) => new Set(albums.map((album) => album.id))); .then((albums) => new Set(albums.map((album) => album.id)));
} }
@ -114,10 +114,10 @@ class AlbumAccess {
} }
return this.db return this.db
.selectFrom('shared_links') .selectFrom('shared_link')
.select('shared_links.albumId') .select('shared_link.albumId')
.where('shared_links.id', '=', sharedLinkId) .where('shared_link.id', '=', sharedLinkId)
.where('shared_links.albumId', 'in', [...albumIds]) .where('shared_link.albumId', 'in', [...albumIds])
.execute() .execute()
.then( .then(
(sharedLinks) => new Set(sharedLinks.flatMap((sharedLink) => (sharedLink.albumId ? [sharedLink.albumId] : []))), (sharedLinks) => new Set(sharedLinks.flatMap((sharedLink) => (sharedLink.albumId ? [sharedLink.albumId] : []))),
@ -136,21 +136,21 @@ class AssetAccess {
} }
return this.db return this.db
.selectFrom('albums') .selectFrom('album')
.innerJoin('albums_assets_assets as albumAssets', 'albums.id', 'albumAssets.albumsId') .innerJoin('album_asset as albumAssets', 'album.id', 'albumAssets.albumsId')
.innerJoin('assets', (join) => .innerJoin('asset', (join) =>
join.onRef('assets.id', '=', 'albumAssets.assetsId').on('assets.deletedAt', 'is', null), join.onRef('asset.id', '=', 'albumAssets.assetsId').on('asset.deletedAt', 'is', null),
) )
.leftJoin('albums_shared_users_users as albumUsers', 'albumUsers.albumsId', 'albums.id') .leftJoin('album_user as albumUsers', 'albumUsers.albumsId', 'album.id')
.leftJoin('users', (join) => join.onRef('users.id', '=', 'albumUsers.usersId').on('users.deletedAt', 'is', null)) .leftJoin('user', (join) => join.onRef('user.id', '=', 'albumUsers.usersId').on('user.deletedAt', 'is', null))
.select(['assets.id', 'assets.livePhotoVideoId']) .select(['asset.id', 'asset.livePhotoVideoId'])
.where( .where(
sql`array["assets"."id", "assets"."livePhotoVideoId"]`, sql`array["asset"."id", "asset"."livePhotoVideoId"]`,
'&&', '&&',
sql`array[${sql.join([...assetIds])}]::uuid[] `, sql`array[${sql.join([...assetIds])}]::uuid[] `,
) )
.where((eb) => eb.or([eb('albums.ownerId', '=', userId), eb('users.id', '=', userId)])) .where((eb) => eb.or([eb('album.ownerId', '=', userId), eb('user.id', '=', userId)]))
.where('albums.deletedAt', 'is', null) .where('album.deletedAt', 'is', null)
.execute() .execute()
.then((assets) => { .then((assets) => {
const allowedIds = new Set<string>(); const allowedIds = new Set<string>();
@ -174,11 +174,11 @@ class AssetAccess {
} }
return this.db return this.db
.selectFrom('assets') .selectFrom('asset')
.select('assets.id') .select('asset.id')
.where('assets.id', 'in', [...assetIds]) .where('asset.id', 'in', [...assetIds])
.where('assets.ownerId', '=', userId) .where('asset.ownerId', '=', userId)
.$if(!hasElevatedPermission, (eb) => eb.where('assets.visibility', '!=', AssetVisibility.LOCKED)) .$if(!hasElevatedPermission, (eb) => eb.where('asset.visibility', '!=', AssetVisibility.LOCKED))
.execute() .execute()
.then((assets) => new Set(assets.map((asset) => asset.id))); .then((assets) => new Set(assets.map((asset) => asset.id)));
} }
@ -191,23 +191,21 @@ class AssetAccess {
} }
return this.db return this.db
.selectFrom('partners as partner') .selectFrom('partner')
.innerJoin('users as sharedBy', (join) => .innerJoin('user as sharedBy', (join) =>
join.onRef('sharedBy.id', '=', 'partner.sharedById').on('sharedBy.deletedAt', 'is', null), join.onRef('sharedBy.id', '=', 'partner.sharedById').on('sharedBy.deletedAt', 'is', null),
) )
.innerJoin('assets', (join) => .innerJoin('asset', (join) => join.onRef('asset.ownerId', '=', 'sharedBy.id').on('asset.deletedAt', 'is', null))
join.onRef('assets.ownerId', '=', 'sharedBy.id').on('assets.deletedAt', 'is', null), .select('asset.id')
)
.select('assets.id')
.where('partner.sharedWithId', '=', userId) .where('partner.sharedWithId', '=', userId)
.where((eb) => .where((eb) =>
eb.or([ eb.or([
eb('assets.visibility', '=', sql.lit(AssetVisibility.TIMELINE)), eb('asset.visibility', '=', sql.lit(AssetVisibility.TIMELINE)),
eb('assets.visibility', '=', sql.lit(AssetVisibility.HIDDEN)), eb('asset.visibility', '=', sql.lit(AssetVisibility.HIDDEN)),
]), ]),
) )
.where('assets.id', 'in', [...assetIds]) .where('asset.id', 'in', [...assetIds])
.execute() .execute()
.then((assets) => new Set(assets.map((asset) => asset.id))); .then((assets) => new Set(assets.map((asset) => asset.id)));
} }
@ -220,27 +218,25 @@ class AssetAccess {
} }
return this.db return this.db
.selectFrom('shared_links') .selectFrom('shared_link')
.leftJoin('albums', (join) => .leftJoin('album', (join) => join.onRef('album.id', '=', 'shared_link.albumId').on('album.deletedAt', 'is', null))
join.onRef('albums.id', '=', 'shared_links.albumId').on('albums.deletedAt', 'is', null), .leftJoin('shared_link_asset', 'shared_link_asset.sharedLinksId', 'shared_link.id')
.leftJoin('asset', (join) =>
join.onRef('asset.id', '=', 'shared_link_asset.assetsId').on('asset.deletedAt', 'is', null),
) )
.leftJoin('shared_link__asset', 'shared_link__asset.sharedLinksId', 'shared_links.id') .leftJoin('album_asset', 'album_asset.albumsId', 'album.id')
.leftJoin('assets', (join) => .leftJoin('asset as albumAssets', (join) =>
join.onRef('assets.id', '=', 'shared_link__asset.assetsId').on('assets.deletedAt', 'is', null), join.onRef('albumAssets.id', '=', 'album_asset.assetsId').on('albumAssets.deletedAt', 'is', null),
)
.leftJoin('albums_assets_assets', 'albums_assets_assets.albumsId', 'albums.id')
.leftJoin('assets as albumAssets', (join) =>
join.onRef('albumAssets.id', '=', 'albums_assets_assets.assetsId').on('albumAssets.deletedAt', 'is', null),
) )
.select([ .select([
'assets.id as assetId', 'asset.id as assetId',
'assets.livePhotoVideoId as assetLivePhotoVideoId', 'asset.livePhotoVideoId as assetLivePhotoVideoId',
'albumAssets.id as albumAssetId', 'albumAssets.id as albumAssetId',
'albumAssets.livePhotoVideoId as albumAssetLivePhotoVideoId', 'albumAssets.livePhotoVideoId as albumAssetLivePhotoVideoId',
]) ])
.where('shared_links.id', '=', sharedLinkId) .where('shared_link.id', '=', sharedLinkId)
.where( .where(
sql`array["assets"."id", "assets"."livePhotoVideoId", "albumAssets"."id", "albumAssets"."livePhotoVideoId"]`, sql`array["asset"."id", "asset"."livePhotoVideoId", "albumAssets"."id", "albumAssets"."livePhotoVideoId"]`,
'&&', '&&',
sql`array[${sql.join([...assetIds])}]::uuid[] `, sql`array[${sql.join([...assetIds])}]::uuid[] `,
) )
@ -277,10 +273,10 @@ class AuthDeviceAccess {
} }
return this.db return this.db
.selectFrom('sessions') .selectFrom('session')
.select('sessions.id') .select('session.id')
.where('sessions.userId', '=', userId) .where('session.userId', '=', userId)
.where('sessions.id', 'in', [...deviceIds]) .where('session.id', 'in', [...deviceIds])
.execute() .execute()
.then((tokens) => new Set(tokens.map((token) => token.id))); .then((tokens) => new Set(tokens.map((token) => token.id)));
} }
@ -297,10 +293,10 @@ class NotificationAccess {
} }
return this.db return this.db
.selectFrom('notifications') .selectFrom('notification')
.select('notifications.id') .select('notification.id')
.where('notifications.id', 'in', [...notificationIds]) .where('notification.id', 'in', [...notificationIds])
.where('notifications.userId', '=', userId) .where('notification.userId', '=', userId)
.execute() .execute()
.then((stacks) => new Set(stacks.map((stack) => stack.id))); .then((stacks) => new Set(stacks.map((stack) => stack.id)));
} }
@ -317,10 +313,10 @@ class SessionAccess {
} }
return this.db return this.db
.selectFrom('sessions') .selectFrom('session')
.select('sessions.id') .select('session.id')
.where('sessions.id', 'in', [...sessionIds]) .where('session.id', 'in', [...sessionIds])
.where('sessions.userId', '=', userId) .where('session.userId', '=', userId)
.execute() .execute()
.then((sessions) => new Set(sessions.map((session) => session.id))); .then((sessions) => new Set(sessions.map((session) => session.id)));
} }
@ -336,10 +332,10 @@ class StackAccess {
} }
return this.db return this.db
.selectFrom('asset_stack as stacks') .selectFrom('stack')
.select('stacks.id') .select('stack.id')
.where('stacks.id', 'in', [...stackIds]) .where('stack.id', 'in', [...stackIds])
.where('stacks.ownerId', '=', userId) .where('stack.ownerId', '=', userId)
.execute() .execute()
.then((stacks) => new Set(stacks.map((stack) => stack.id))); .then((stacks) => new Set(stacks.map((stack) => stack.id)));
} }
@ -356,10 +352,10 @@ class TimelineAccess {
} }
return this.db return this.db
.selectFrom('partners') .selectFrom('partner')
.select('partners.sharedById') .select('partner.sharedById')
.where('partners.sharedById', 'in', [...partnerIds]) .where('partner.sharedById', 'in', [...partnerIds])
.where('partners.sharedWithId', '=', userId) .where('partner.sharedWithId', '=', userId)
.execute() .execute()
.then((partners) => new Set(partners.map((partner) => partner.sharedById))); .then((partners) => new Set(partners.map((partner) => partner.sharedById)));
} }
@ -376,11 +372,11 @@ class MemoryAccess {
} }
return this.db return this.db
.selectFrom('memories') .selectFrom('memory')
.select('memories.id') .select('memory.id')
.where('memories.id', 'in', [...memoryIds]) .where('memory.id', 'in', [...memoryIds])
.where('memories.ownerId', '=', userId) .where('memory.ownerId', '=', userId)
.where('memories.deletedAt', 'is', null) .where('memory.deletedAt', 'is', null)
.execute() .execute()
.then((memories) => new Set(memories.map((memory) => memory.id))); .then((memories) => new Set(memories.map((memory) => memory.id)));
} }
@ -413,13 +409,11 @@ class PersonAccess {
} }
return this.db return this.db
.selectFrom('asset_faces') .selectFrom('asset_face')
.select('asset_faces.id') .select('asset_face.id')
.leftJoin('assets', (join) => .leftJoin('asset', (join) => join.onRef('asset.id', '=', 'asset_face.assetId').on('asset.deletedAt', 'is', null))
join.onRef('assets.id', '=', 'asset_faces.assetId').on('assets.deletedAt', 'is', null), .where('asset_face.id', 'in', [...assetFaceIds])
) .where('asset.ownerId', '=', userId)
.where('asset_faces.id', 'in', [...assetFaceIds])
.where('assets.ownerId', '=', userId)
.execute() .execute()
.then((faces) => new Set(faces.map((face) => face.id))); .then((faces) => new Set(faces.map((face) => face.id)));
} }
@ -436,10 +430,10 @@ class PartnerAccess {
} }
return this.db return this.db
.selectFrom('partners') .selectFrom('partner')
.select('partners.sharedById') .select('partner.sharedById')
.where('partners.sharedById', 'in', [...partnerIds]) .where('partner.sharedById', 'in', [...partnerIds])
.where('partners.sharedWithId', '=', userId) .where('partner.sharedWithId', '=', userId)
.execute() .execute()
.then((partners) => new Set(partners.map((partner) => partner.sharedById))); .then((partners) => new Set(partners.map((partner) => partner.sharedById)));
} }
@ -456,10 +450,10 @@ class TagAccess {
} }
return this.db return this.db
.selectFrom('tags') .selectFrom('tag')
.select('tags.id') .select('tag.id')
.where('tags.id', 'in', [...tagIds]) .where('tag.id', 'in', [...tagIds])
.where('tags.userId', '=', userId) .where('tag.userId', '=', userId)
.execute() .execute()
.then((tags) => new Set(tags.map((tag) => tag.id))); .then((tags) => new Set(tags.map((tag) => tag.id)));
} }

View File

@ -27,7 +27,9 @@ export class ActivityRepository {
return this.db return this.db
.selectFrom('activity') .selectFrom('activity')
.selectAll('activity') .selectAll('activity')
.innerJoin('users', (join) => join.onRef('users.id', '=', 'activity.userId').on('users.deletedAt', 'is', null)) .innerJoin('user as user2', (join) =>
join.onRef('user2.id', '=', 'activity.userId').on('user2.deletedAt', 'is', null),
)
.innerJoinLateral( .innerJoinLateral(
(eb) => (eb) =>
eb eb
@ -37,13 +39,13 @@ export class ActivityRepository {
(join) => join.onTrue(), (join) => join.onTrue(),
) )
.select((eb) => eb.fn.toJson('user').as('user')) .select((eb) => eb.fn.toJson('user').as('user'))
.leftJoin('assets', 'assets.id', 'activity.assetId') .leftJoin('asset', 'asset.id', 'activity.assetId')
.$if(!!userId, (qb) => qb.where('activity.userId', '=', userId!)) .$if(!!userId, (qb) => qb.where('activity.userId', '=', userId!))
.$if(assetId === null, (qb) => qb.where('assetId', 'is', null)) .$if(assetId === null, (qb) => qb.where('assetId', 'is', null))
.$if(!!assetId, (qb) => qb.where('activity.assetId', '=', assetId!)) .$if(!!assetId, (qb) => qb.where('activity.assetId', '=', assetId!))
.$if(!!albumId, (qb) => qb.where('activity.albumId', '=', albumId!)) .$if(!!albumId, (qb) => qb.where('activity.albumId', '=', albumId!))
.$if(isLiked !== undefined, (qb) => qb.where('activity.isLiked', '=', isLiked!)) .$if(isLiked !== undefined, (qb) => qb.where('activity.isLiked', '=', isLiked!))
.where('assets.deletedAt', 'is', null) .where('asset.deletedAt', 'is', null)
.orderBy('activity.createdAt', 'asc') .orderBy('activity.createdAt', 'asc')
.execute(); .execute();
} }
@ -55,7 +57,7 @@ export class ActivityRepository {
.values(activity) .values(activity)
.returningAll() .returningAll()
.returning((eb) => .returning((eb) =>
jsonObjectFrom(eb.selectFrom('users').whereRef('users.id', '=', 'activity.userId').select(columns.user)).as( jsonObjectFrom(eb.selectFrom('user').whereRef('user.id', '=', 'activity.userId').select(columns.user)).as(
'user', 'user',
), ),
) )
@ -82,14 +84,14 @@ export class ActivityRepository {
eb.fn.countAll<number>().filterWhere('activity.isLiked', '=', false).as('comments'), eb.fn.countAll<number>().filterWhere('activity.isLiked', '=', false).as('comments'),
eb.fn.countAll<number>().filterWhere('activity.isLiked', '=', true).as('likes'), eb.fn.countAll<number>().filterWhere('activity.isLiked', '=', true).as('likes'),
]) ])
.innerJoin('users', (join) => join.onRef('users.id', '=', 'activity.userId').on('users.deletedAt', 'is', null)) .innerJoin('user', (join) => join.onRef('user.id', '=', 'activity.userId').on('user.deletedAt', 'is', null))
.leftJoin('assets', 'assets.id', 'activity.assetId') .leftJoin('asset', 'asset.id', 'activity.assetId')
.$if(!!assetId, (qb) => qb.where('activity.assetId', '=', assetId!)) .$if(!!assetId, (qb) => qb.where('activity.assetId', '=', assetId!))
.where('activity.albumId', '=', albumId) .where('activity.albumId', '=', albumId)
.where(({ or, and, eb }) => .where(({ or, and, eb }) =>
or([ or([
and([eb('assets.deletedAt', 'is', null), eb('assets.visibility', '!=', sql.lit(AssetVisibility.LOCKED))]), and([eb('asset.deletedAt', 'is', null), eb('asset.visibility', '!=', sql.lit(AssetVisibility.LOCKED))]),
eb('assets.id', 'is', null), eb('asset.id', 'is', null),
]), ]),
) )
.executeTakeFirstOrThrow(); .executeTakeFirstOrThrow();

View File

@ -18,7 +18,7 @@ export class AlbumUserRepository {
@GenerateSql({ params: [{ usersId: DummyValue.UUID, albumsId: DummyValue.UUID }] }) @GenerateSql({ params: [{ usersId: DummyValue.UUID, albumsId: DummyValue.UUID }] })
create(albumUser: Insertable<AlbumUserTable>) { create(albumUser: Insertable<AlbumUserTable>) {
return this.db return this.db
.insertInto('albums_shared_users_users') .insertInto('album_user')
.values(albumUser) .values(albumUser)
.returning(['usersId', 'albumsId', 'role']) .returning(['usersId', 'albumsId', 'role'])
.executeTakeFirstOrThrow(); .executeTakeFirstOrThrow();
@ -27,7 +27,7 @@ export class AlbumUserRepository {
@GenerateSql({ params: [{ usersId: DummyValue.UUID, albumsId: DummyValue.UUID }, { role: AlbumUserRole.VIEWER }] }) @GenerateSql({ params: [{ usersId: DummyValue.UUID, albumsId: DummyValue.UUID }, { role: AlbumUserRole.VIEWER }] })
update({ usersId, albumsId }: AlbumPermissionId, dto: Updateable<AlbumUserTable>) { update({ usersId, albumsId }: AlbumPermissionId, dto: Updateable<AlbumUserTable>) {
return this.db return this.db
.updateTable('albums_shared_users_users') .updateTable('album_user')
.set(dto) .set(dto)
.where('usersId', '=', usersId) .where('usersId', '=', usersId)
.where('albumsId', '=', albumsId) .where('albumsId', '=', albumsId)
@ -37,10 +37,6 @@ export class AlbumUserRepository {
@GenerateSql({ params: [{ usersId: DummyValue.UUID, albumsId: DummyValue.UUID }] }) @GenerateSql({ params: [{ usersId: DummyValue.UUID, albumsId: DummyValue.UUID }] })
async delete({ usersId, albumsId }: AlbumPermissionId): Promise<void> { async delete({ usersId, albumsId }: AlbumPermissionId): Promise<void> {
await this.db await this.db.deleteFrom('album_user').where('usersId', '=', usersId).where('albumsId', '=', albumsId).execute();
.deleteFrom('albums_shared_users_users')
.where('usersId', '=', usersId)
.where('albumsId', '=', albumsId)
.execute();
} }
} }

View File

@ -21,47 +21,47 @@ export interface AlbumInfoOptions {
withAssets: boolean; withAssets: boolean;
} }
const withOwner = (eb: ExpressionBuilder<DB, 'albums'>) => { const withOwner = (eb: ExpressionBuilder<DB, 'album'>) => {
return jsonObjectFrom(eb.selectFrom('users').select(columns.user).whereRef('users.id', '=', 'albums.ownerId')) return jsonObjectFrom(eb.selectFrom('user').select(columns.user).whereRef('user.id', '=', 'album.ownerId'))
.$notNull() .$notNull()
.as('owner'); .as('owner');
}; };
const withAlbumUsers = (eb: ExpressionBuilder<DB, 'albums'>) => { const withAlbumUsers = (eb: ExpressionBuilder<DB, 'album'>) => {
return jsonArrayFrom( return jsonArrayFrom(
eb eb
.selectFrom('albums_shared_users_users as album_users') .selectFrom('album_user')
.select('album_users.role') .select('album_user.role')
.select((eb) => .select((eb) =>
jsonObjectFrom(eb.selectFrom('users').select(columns.user).whereRef('users.id', '=', 'album_users.usersId')) jsonObjectFrom(eb.selectFrom('user').select(columns.user).whereRef('user.id', '=', 'album_user.usersId'))
.$notNull() .$notNull()
.as('user'), .as('user'),
) )
.whereRef('album_users.albumsId', '=', 'albums.id'), .whereRef('album_user.albumsId', '=', 'album.id'),
) )
.$notNull() .$notNull()
.as('albumUsers'); .as('albumUsers');
}; };
const withSharedLink = (eb: ExpressionBuilder<DB, 'albums'>) => { const withSharedLink = (eb: ExpressionBuilder<DB, 'album'>) => {
return jsonArrayFrom(eb.selectFrom('shared_links').selectAll().whereRef('shared_links.albumId', '=', 'albums.id')).as( return jsonArrayFrom(eb.selectFrom('shared_link').selectAll().whereRef('shared_link.albumId', '=', 'album.id')).as(
'sharedLinks', 'sharedLinks',
); );
}; };
const withAssets = (eb: ExpressionBuilder<DB, 'albums'>) => { const withAssets = (eb: ExpressionBuilder<DB, 'album'>) => {
return eb return eb
.selectFrom((eb) => .selectFrom((eb) =>
eb eb
.selectFrom('assets') .selectFrom('asset')
.selectAll('assets') .selectAll('asset')
.leftJoin('exif', 'assets.id', 'exif.assetId') .leftJoin('asset_exif', 'asset.id', 'asset_exif.assetId')
.select((eb) => eb.table('exif').$castTo<Exif>().as('exifInfo')) .select((eb) => eb.table('asset_exif').$castTo<Exif>().as('exifInfo'))
.innerJoin('albums_assets_assets', 'albums_assets_assets.assetsId', 'assets.id') .innerJoin('album_asset', 'album_asset.assetsId', 'asset.id')
.whereRef('albums_assets_assets.albumsId', '=', 'albums.id') .whereRef('album_asset.albumsId', '=', 'album.id')
.where('assets.deletedAt', 'is', null) .where('asset.deletedAt', 'is', null)
.$call(withDefaultVisibility) .$call(withDefaultVisibility)
.orderBy('assets.fileCreatedAt', 'desc') .orderBy('asset.fileCreatedAt', 'desc')
.as('asset'), .as('asset'),
) )
.select((eb) => eb.fn.jsonAgg('asset').as('assets')) .select((eb) => eb.fn.jsonAgg('asset').as('assets'))
@ -75,10 +75,10 @@ export class AlbumRepository {
@GenerateSql({ params: [DummyValue.UUID, { withAssets: true }] }) @GenerateSql({ params: [DummyValue.UUID, { withAssets: true }] })
async getById(id: string, options: AlbumInfoOptions) { async getById(id: string, options: AlbumInfoOptions) {
return this.db return this.db
.selectFrom('albums') .selectFrom('album')
.selectAll('albums') .selectAll('album')
.where('albums.id', '=', id) .where('album.id', '=', id)
.where('albums.deletedAt', 'is', null) .where('album.deletedAt', 'is', null)
.select(withOwner) .select(withOwner)
.select(withAlbumUsers) .select(withAlbumUsers)
.select(withSharedLink) .select(withSharedLink)
@ -90,26 +90,26 @@ export class AlbumRepository {
@GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID] }) @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID] })
async getByAssetId(ownerId: string, assetId: string) { async getByAssetId(ownerId: string, assetId: string) {
return this.db return this.db
.selectFrom('albums') .selectFrom('album')
.selectAll('albums') .selectAll('album')
.innerJoin('albums_assets_assets as album_assets', 'album_assets.albumsId', 'albums.id') .innerJoin('album_asset', 'album_asset.albumsId', 'album.id')
.where((eb) => .where((eb) =>
eb.or([ eb.or([
eb('albums.ownerId', '=', ownerId), eb('album.ownerId', '=', ownerId),
eb.exists( eb.exists(
eb eb
.selectFrom('albums_shared_users_users as album_users') .selectFrom('album_user')
.whereRef('album_users.albumsId', '=', 'albums.id') .whereRef('album_user.albumsId', '=', 'album.id')
.where('album_users.usersId', '=', ownerId), .where('album_user.usersId', '=', ownerId),
), ),
]), ]),
) )
.where('album_assets.assetsId', '=', assetId) .where('album_asset.assetsId', '=', assetId)
.where('albums.deletedAt', 'is', null) .where('album.deletedAt', 'is', null)
.orderBy('albums.createdAt', 'desc') .orderBy('album.createdAt', 'desc')
.select(withOwner) .select(withOwner)
.select(withAlbumUsers) .select(withAlbumUsers)
.orderBy('albums.createdAt', 'desc') .orderBy('album.createdAt', 'desc')
.execute(); .execute();
} }
@ -123,18 +123,18 @@ export class AlbumRepository {
return ( return (
this.db this.db
.selectFrom('assets') .selectFrom('asset')
.$call(withDefaultVisibility) .$call(withDefaultVisibility)
.innerJoin('albums_assets_assets as album_assets', 'album_assets.assetsId', 'assets.id') .innerJoin('album_asset', 'album_asset.assetsId', 'asset.id')
.select('album_assets.albumsId as albumId') .select('album_asset.albumsId as albumId')
.select((eb) => eb.fn.min(sql<Date>`("assets"."localDateTime" AT TIME ZONE 'UTC'::text)::date`).as('startDate')) .select((eb) => eb.fn.min(sql<Date>`("asset"."localDateTime" AT TIME ZONE 'UTC'::text)::date`).as('startDate'))
.select((eb) => eb.fn.max(sql<Date>`("assets"."localDateTime" AT TIME ZONE 'UTC'::text)::date`).as('endDate')) .select((eb) => eb.fn.max(sql<Date>`("asset"."localDateTime" AT TIME ZONE 'UTC'::text)::date`).as('endDate'))
// lastModifiedAssetTimestamp is only used in mobile app, please remove if not need // lastModifiedAssetTimestamp is only used in mobile app, please remove if not need
.select((eb) => eb.fn.max('assets.updatedAt').as('lastModifiedAssetTimestamp')) .select((eb) => eb.fn.max('asset.updatedAt').as('lastModifiedAssetTimestamp'))
.select((eb) => sql<number>`${eb.fn.count('assets.id')}::int`.as('assetCount')) .select((eb) => sql<number>`${eb.fn.count('asset.id')}::int`.as('assetCount'))
.where('album_assets.albumsId', 'in', ids) .where('album_asset.albumsId', 'in', ids)
.where('assets.deletedAt', 'is', null) .where('asset.deletedAt', 'is', null)
.groupBy('album_assets.albumsId') .groupBy('album_asset.albumsId')
.execute() .execute()
); );
} }
@ -142,14 +142,14 @@ export class AlbumRepository {
@GenerateSql({ params: [DummyValue.UUID] }) @GenerateSql({ params: [DummyValue.UUID] })
async getOwned(ownerId: string) { async getOwned(ownerId: string) {
return this.db return this.db
.selectFrom('albums') .selectFrom('album')
.selectAll('albums') .selectAll('album')
.select(withOwner) .select(withOwner)
.select(withAlbumUsers) .select(withAlbumUsers)
.select(withSharedLink) .select(withSharedLink)
.where('albums.ownerId', '=', ownerId) .where('album.ownerId', '=', ownerId)
.where('albums.deletedAt', 'is', null) .where('album.deletedAt', 'is', null)
.orderBy('albums.createdAt', 'desc') .orderBy('album.createdAt', 'desc')
.execute(); .execute();
} }
@ -159,29 +159,29 @@ export class AlbumRepository {
@GenerateSql({ params: [DummyValue.UUID] }) @GenerateSql({ params: [DummyValue.UUID] })
async getShared(ownerId: string) { async getShared(ownerId: string) {
return this.db return this.db
.selectFrom('albums') .selectFrom('album')
.selectAll('albums') .selectAll('album')
.where((eb) => .where((eb) =>
eb.or([ eb.or([
eb.exists( eb.exists(
eb eb
.selectFrom('albums_shared_users_users as album_users') .selectFrom('album_user')
.whereRef('album_users.albumsId', '=', 'albums.id') .whereRef('album_user.albumsId', '=', 'album.id')
.where((eb) => eb.or([eb('albums.ownerId', '=', ownerId), eb('album_users.usersId', '=', ownerId)])), .where((eb) => eb.or([eb('album.ownerId', '=', ownerId), eb('album_user.usersId', '=', ownerId)])),
), ),
eb.exists( eb.exists(
eb eb
.selectFrom('shared_links') .selectFrom('shared_link')
.whereRef('shared_links.albumId', '=', 'albums.id') .whereRef('shared_link.albumId', '=', 'album.id')
.where('shared_links.userId', '=', ownerId), .where('shared_link.userId', '=', ownerId),
), ),
]), ]),
) )
.where('albums.deletedAt', 'is', null) .where('album.deletedAt', 'is', null)
.select(withAlbumUsers) .select(withAlbumUsers)
.select(withOwner) .select(withOwner)
.select(withSharedLink) .select(withSharedLink)
.orderBy('albums.createdAt', 'desc') .orderBy('album.createdAt', 'desc')
.execute(); .execute();
} }
@ -191,43 +191,33 @@ export class AlbumRepository {
@GenerateSql({ params: [DummyValue.UUID] }) @GenerateSql({ params: [DummyValue.UUID] })
async getNotShared(ownerId: string) { async getNotShared(ownerId: string) {
return this.db return this.db
.selectFrom('albums') .selectFrom('album')
.selectAll('albums') .selectAll('album')
.where('albums.ownerId', '=', ownerId) .where('album.ownerId', '=', ownerId)
.where('albums.deletedAt', 'is', null) .where('album.deletedAt', 'is', null)
.where((eb) => .where((eb) => eb.not(eb.exists(eb.selectFrom('album_user').whereRef('album_user.albumsId', '=', 'album.id'))))
eb.not( .where((eb) => eb.not(eb.exists(eb.selectFrom('shared_link').whereRef('shared_link.albumId', '=', 'album.id'))))
eb.exists(
eb
.selectFrom('albums_shared_users_users as album_users')
.whereRef('album_users.albumsId', '=', 'albums.id'),
),
),
)
.where((eb) =>
eb.not(eb.exists(eb.selectFrom('shared_links').whereRef('shared_links.albumId', '=', 'albums.id'))),
)
.select(withOwner) .select(withOwner)
.orderBy('albums.createdAt', 'desc') .orderBy('album.createdAt', 'desc')
.execute(); .execute();
} }
async restoreAll(userId: string): Promise<void> { async restoreAll(userId: string): Promise<void> {
await this.db.updateTable('albums').set({ deletedAt: null }).where('ownerId', '=', userId).execute(); await this.db.updateTable('album').set({ deletedAt: null }).where('ownerId', '=', userId).execute();
} }
async softDeleteAll(userId: string): Promise<void> { async softDeleteAll(userId: string): Promise<void> {
await this.db.updateTable('albums').set({ deletedAt: new Date() }).where('ownerId', '=', userId).execute(); await this.db.updateTable('album').set({ deletedAt: new Date() }).where('ownerId', '=', userId).execute();
} }
async deleteAll(userId: string): Promise<void> { async deleteAll(userId: string): Promise<void> {
await this.db.deleteFrom('albums').where('ownerId', '=', userId).execute(); await this.db.deleteFrom('album').where('ownerId', '=', userId).execute();
} }
@GenerateSql({ params: [[DummyValue.UUID]] }) @GenerateSql({ params: [[DummyValue.UUID]] })
@Chunked() @Chunked()
async removeAssetsFromAll(assetIds: string[]): Promise<void> { async removeAssetsFromAll(assetIds: string[]): Promise<void> {
await this.db.deleteFrom('albums_assets_assets').where('albums_assets_assets.assetsId', 'in', assetIds).execute(); await this.db.deleteFrom('album_asset').where('album_asset.assetsId', 'in', assetIds).execute();
} }
@Chunked({ paramIndex: 1 }) @Chunked({ paramIndex: 1 })
@ -237,9 +227,9 @@ export class AlbumRepository {
} }
await this.db await this.db
.deleteFrom('albums_assets_assets') .deleteFrom('album_asset')
.where('albums_assets_assets.albumsId', '=', albumId) .where('album_asset.albumsId', '=', albumId)
.where('albums_assets_assets.assetsId', 'in', assetIds) .where('album_asset.assetsId', 'in', assetIds)
.execute(); .execute();
} }
@ -258,10 +248,10 @@ export class AlbumRepository {
} }
return this.db return this.db
.selectFrom('albums_assets_assets') .selectFrom('album_asset')
.selectAll() .selectAll()
.where('albums_assets_assets.albumsId', '=', albumId) .where('album_asset.albumsId', '=', albumId)
.where('albums_assets_assets.assetsId', 'in', assetIds) .where('album_asset.assetsId', 'in', assetIds)
.execute() .execute()
.then((results) => new Set(results.map(({ assetsId }) => assetsId))); .then((results) => new Set(results.map(({ assetsId }) => assetsId)));
} }
@ -272,7 +262,7 @@ export class AlbumRepository {
create(album: Insertable<AlbumTable>, assetIds: string[], albumUsers: AlbumUserCreateDto[]) { create(album: Insertable<AlbumTable>, assetIds: string[], albumUsers: AlbumUserCreateDto[]) {
return this.db.transaction().execute(async (tx) => { return this.db.transaction().execute(async (tx) => {
const newAlbum = await tx.insertInto('albums').values(album).returning('albums.id').executeTakeFirst(); const newAlbum = await tx.insertInto('album').values(album).returning('album.id').executeTakeFirst();
if (!newAlbum) { if (!newAlbum) {
throw new Error('Failed to create album'); throw new Error('Failed to create album');
@ -284,7 +274,7 @@ export class AlbumRepository {
if (albumUsers.length > 0) { if (albumUsers.length > 0) {
await tx await tx
.insertInto('albums_shared_users_users') .insertInto('album_user')
.values( .values(
albumUsers.map((albumUser) => ({ albumsId: newAlbum.id, usersId: albumUser.userId, role: albumUser.role })), albumUsers.map((albumUser) => ({ albumsId: newAlbum.id, usersId: albumUser.userId, role: albumUser.role })),
) )
@ -292,7 +282,7 @@ export class AlbumRepository {
} }
return tx return tx
.selectFrom('albums') .selectFrom('album')
.selectAll() .selectAll()
.where('id', '=', newAlbum.id) .where('id', '=', newAlbum.id)
.select(withOwner) .select(withOwner)
@ -305,10 +295,10 @@ export class AlbumRepository {
update(id: string, album: Updateable<AlbumTable>) { update(id: string, album: Updateable<AlbumTable>) {
return this.db return this.db
.updateTable('albums') .updateTable('album')
.set(album) .set(album)
.where('id', '=', id) .where('id', '=', id)
.returningAll('albums') .returningAll('album')
.returning(withOwner) .returning(withOwner)
.returning(withSharedLink) .returning(withSharedLink)
.returning(withAlbumUsers) .returning(withAlbumUsers)
@ -316,7 +306,7 @@ export class AlbumRepository {
} }
async delete(id: string): Promise<void> { async delete(id: string): Promise<void> {
await this.db.deleteFrom('albums').where('id', '=', id).execute(); await this.db.deleteFrom('album').where('id', '=', id).execute();
} }
@Chunked({ paramIndex: 2, chunkSize: 30_000 }) @Chunked({ paramIndex: 2, chunkSize: 30_000 })
@ -326,7 +316,7 @@ export class AlbumRepository {
} }
await db await db
.insertInto('albums_assets_assets') .insertInto('album_asset')
.values(assetIds.map((assetId) => ({ albumsId: albumId, assetsId: assetId }))) .values(assetIds.map((assetId) => ({ albumsId: albumId, assetsId: assetId })))
.execute(); .execute();
} }
@ -343,11 +333,11 @@ export class AlbumRepository {
// Subquery for getting a new thumbnail. // Subquery for getting a new thumbnail.
const result = await this.db const result = await this.db
.updateTable('albums') .updateTable('album')
.set((eb) => ({ .set((eb) => ({
albumThumbnailAssetId: this.updateThumbnailBuilder(eb) albumThumbnailAssetId: this.updateThumbnailBuilder(eb)
.select('album_assets.assetsId') .select('album_asset.assetsId')
.orderBy('assets.fileCreatedAt', 'desc') .orderBy('asset.fileCreatedAt', 'desc')
.limit(1), .limit(1),
})) }))
.where((eb) => .where((eb) =>
@ -362,7 +352,7 @@ export class AlbumRepository {
eb.exists( eb.exists(
this.updateThumbnailBuilder(eb) this.updateThumbnailBuilder(eb)
.select(sql`1`.as('1')) .select(sql`1`.as('1'))
.whereRef('albums.albumThumbnailAssetId', '=', 'album_assets.assetsId'), // Has invalid assets .whereRef('album.albumThumbnailAssetId', '=', 'album_asset.assetsId'), // Has invalid assets
), ),
), ),
]), ]),
@ -373,12 +363,12 @@ export class AlbumRepository {
return Number(result[0].numUpdatedRows); return Number(result[0].numUpdatedRows);
} }
private updateThumbnailBuilder(eb: ExpressionBuilder<DB, 'albums'>) { private updateThumbnailBuilder(eb: ExpressionBuilder<DB, 'album'>) {
return eb return eb
.selectFrom('albums_assets_assets as album_assets') .selectFrom('album_asset')
.innerJoin('assets', (join) => .innerJoin('asset', (join) =>
join.onRef('album_assets.assetsId', '=', 'assets.id').on('assets.deletedAt', 'is', null), join.onRef('album_asset.assetsId', '=', 'asset.id').on('asset.deletedAt', 'is', null),
) )
.whereRef('album_assets.albumsId', '=', 'albums.id'); .whereRef('album_asset.albumsId', '=', 'album.id');
} }
} }

View File

@ -13,45 +13,45 @@ export class ApiKeyRepository {
constructor(@InjectKysely() private db: Kysely<DB>) {} constructor(@InjectKysely() private db: Kysely<DB>) {}
create(dto: Insertable<ApiKeyTable>) { create(dto: Insertable<ApiKeyTable>) {
return this.db.insertInto('api_keys').values(dto).returning(columns.apiKey).executeTakeFirstOrThrow(); return this.db.insertInto('api_key').values(dto).returning(columns.apiKey).executeTakeFirstOrThrow();
} }
async update(userId: string, id: string, dto: Updateable<ApiKeyTable>) { async update(userId: string, id: string, dto: Updateable<ApiKeyTable>) {
return this.db return this.db
.updateTable('api_keys') .updateTable('api_key')
.set(dto) .set(dto)
.where('api_keys.userId', '=', userId) .where('api_key.userId', '=', userId)
.where('id', '=', asUuid(id)) .where('id', '=', asUuid(id))
.returning(columns.apiKey) .returning(columns.apiKey)
.executeTakeFirstOrThrow(); .executeTakeFirstOrThrow();
} }
async delete(userId: string, id: string) { async delete(userId: string, id: string) {
await this.db.deleteFrom('api_keys').where('userId', '=', userId).where('id', '=', asUuid(id)).execute(); await this.db.deleteFrom('api_key').where('userId', '=', userId).where('id', '=', asUuid(id)).execute();
} }
@GenerateSql({ params: [DummyValue.STRING] }) @GenerateSql({ params: [DummyValue.STRING] })
getKey(hashedToken: string) { getKey(hashedToken: string) {
return this.db return this.db
.selectFrom('api_keys') .selectFrom('api_key')
.select((eb) => [ .select((eb) => [
...columns.authApiKey, ...columns.authApiKey,
jsonObjectFrom( jsonObjectFrom(
eb eb
.selectFrom('users') .selectFrom('user')
.select(columns.authUser) .select(columns.authUser)
.whereRef('users.id', '=', 'api_keys.userId') .whereRef('user.id', '=', 'api_key.userId')
.where('users.deletedAt', 'is', null), .where('user.deletedAt', 'is', null),
).as('user'), ).as('user'),
]) ])
.where('api_keys.key', '=', hashedToken) .where('api_key.key', '=', hashedToken)
.executeTakeFirst(); .executeTakeFirst();
} }
@GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID] }) @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID] })
getById(userId: string, id: string) { getById(userId: string, id: string) {
return this.db return this.db
.selectFrom('api_keys') .selectFrom('api_key')
.select(columns.apiKey) .select(columns.apiKey)
.where('id', '=', asUuid(id)) .where('id', '=', asUuid(id))
.where('userId', '=', userId) .where('userId', '=', userId)
@ -61,7 +61,7 @@ export class ApiKeyRepository {
@GenerateSql({ params: [DummyValue.UUID] }) @GenerateSql({ params: [DummyValue.UUID] })
getByUserId(userId: string) { getByUserId(userId: string) {
return this.db return this.db
.selectFrom('api_keys') .selectFrom('api_key')
.select(columns.apiKey) .select(columns.apiKey)
.where('userId', '=', userId) .where('userId', '=', userId)
.orderBy('createdAt', 'desc') .orderBy('createdAt', 'desc')

View File

@ -26,9 +26,9 @@ export class AssetJobRepository {
@GenerateSql({ params: [DummyValue.UUID] }) @GenerateSql({ params: [DummyValue.UUID] })
getForSearchDuplicatesJob(id: string) { getForSearchDuplicatesJob(id: string) {
return this.db return this.db
.selectFrom('assets') .selectFrom('asset')
.where('assets.id', '=', asUuid(id)) .where('asset.id', '=', asUuid(id))
.leftJoin('smart_search', 'assets.id', 'smart_search.assetId') .leftJoin('smart_search', 'asset.id', 'smart_search.assetId')
.select(['id', 'type', 'ownerId', 'duplicateId', 'stackId', 'visibility', 'smart_search.embedding']) .select(['id', 'type', 'ownerId', 'duplicateId', 'stackId', 'visibility', 'smart_search.embedding'])
.limit(1) .limit(1)
.executeTakeFirst(); .executeTakeFirst();
@ -37,18 +37,18 @@ export class AssetJobRepository {
@GenerateSql({ params: [DummyValue.UUID] }) @GenerateSql({ params: [DummyValue.UUID] })
getForSidecarWriteJob(id: string) { getForSidecarWriteJob(id: string) {
return this.db return this.db
.selectFrom('assets') .selectFrom('asset')
.where('assets.id', '=', asUuid(id)) .where('asset.id', '=', asUuid(id))
.select((eb) => [ .select((eb) => [
'id', 'id',
'sidecarPath', 'sidecarPath',
'originalPath', 'originalPath',
jsonArrayFrom( jsonArrayFrom(
eb eb
.selectFrom('tags') .selectFrom('tag')
.select(['tags.value']) .select(['tag.value'])
.innerJoin('tag_asset', 'tags.id', 'tag_asset.tagsId') .innerJoin('tag_asset', 'tag.id', 'tag_asset.tagsId')
.whereRef('assets.id', '=', 'tag_asset.assetsId'), .whereRef('asset.id', '=', 'tag_asset.assetsId'),
).as('tags'), ).as('tags'),
]) ])
.limit(1) .limit(1)
@ -58,20 +58,20 @@ export class AssetJobRepository {
@GenerateSql({ params: [false], stream: true }) @GenerateSql({ params: [false], stream: true })
streamForThumbnailJob(force: boolean) { streamForThumbnailJob(force: boolean) {
return this.db return this.db
.selectFrom('assets') .selectFrom('asset')
.select(['assets.id', 'assets.thumbhash']) .select(['asset.id', 'asset.thumbhash'])
.select(withFiles) .select(withFiles)
.where('assets.deletedAt', 'is', null) .where('asset.deletedAt', 'is', null)
.where('assets.visibility', '!=', AssetVisibility.HIDDEN) .where('asset.visibility', '!=', AssetVisibility.HIDDEN)
.$if(!force, (qb) => .$if(!force, (qb) =>
qb qb
// If there aren't any entries, metadata extraction hasn't run yet which is required for thumbnails // If there aren't any entries, metadata extraction hasn't run yet which is required for thumbnails
.innerJoin('asset_job_status', 'asset_job_status.assetId', 'assets.id') .innerJoin('asset_job_status', 'asset_job_status.assetId', 'asset.id')
.where((eb) => .where((eb) =>
eb.or([ eb.or([
eb('asset_job_status.previewAt', 'is', null), eb('asset_job_status.previewAt', 'is', null),
eb('asset_job_status.thumbnailAt', 'is', null), eb('asset_job_status.thumbnailAt', 'is', null),
eb('assets.thumbhash', 'is', null), eb('asset.thumbhash', 'is', null),
]), ]),
), ),
) )
@ -81,72 +81,72 @@ export class AssetJobRepository {
@GenerateSql({ params: [DummyValue.UUID] }) @GenerateSql({ params: [DummyValue.UUID] })
getForMigrationJob(id: string) { getForMigrationJob(id: string) {
return this.db return this.db
.selectFrom('assets') .selectFrom('asset')
.select(['assets.id', 'assets.ownerId', 'assets.encodedVideoPath']) .select(['asset.id', 'asset.ownerId', 'asset.encodedVideoPath'])
.select(withFiles) .select(withFiles)
.where('assets.id', '=', id) .where('asset.id', '=', id)
.executeTakeFirst(); .executeTakeFirst();
} }
@GenerateSql({ params: [DummyValue.UUID] }) @GenerateSql({ params: [DummyValue.UUID] })
getForGenerateThumbnailJob(id: string) { getForGenerateThumbnailJob(id: string) {
return this.db return this.db
.selectFrom('assets') .selectFrom('asset')
.select([ .select([
'assets.id', 'asset.id',
'assets.visibility', 'asset.visibility',
'assets.originalFileName', 'asset.originalFileName',
'assets.originalPath', 'asset.originalPath',
'assets.ownerId', 'asset.ownerId',
'assets.thumbhash', 'asset.thumbhash',
'assets.type', 'asset.type',
]) ])
.select(withFiles) .select(withFiles)
.$call(withExifInner) .$call(withExifInner)
.where('assets.id', '=', id) .where('asset.id', '=', id)
.executeTakeFirst(); .executeTakeFirst();
} }
@GenerateSql({ params: [DummyValue.UUID] }) @GenerateSql({ params: [DummyValue.UUID] })
getForMetadataExtraction(id: string) { getForMetadataExtraction(id: string) {
return this.db return this.db
.selectFrom('assets') .selectFrom('asset')
.select(columns.asset) .select(columns.asset)
.select(withFaces) .select(withFaces)
.where('assets.id', '=', id) .where('asset.id', '=', id)
.executeTakeFirst(); .executeTakeFirst();
} }
@GenerateSql({ params: [DummyValue.UUID, AssetFileType.THUMBNAIL] }) @GenerateSql({ params: [DummyValue.UUID, AssetFileType.THUMBNAIL] })
getAlbumThumbnailFiles(id: string, fileType?: AssetFileType) { getAlbumThumbnailFiles(id: string, fileType?: AssetFileType) {
return this.db return this.db
.selectFrom('asset_files') .selectFrom('asset_file')
.select(columns.assetFiles) .select(columns.assetFiles)
.where('asset_files.assetId', '=', id) .where('asset_file.assetId', '=', id)
.$if(!!fileType, (qb) => qb.where('asset_files.type', '=', fileType!)) .$if(!!fileType, (qb) => qb.where('asset_file.type', '=', fileType!))
.execute(); .execute();
} }
private assetsWithPreviews() { private assetsWithPreviews() {
return this.db return this.db
.selectFrom('assets') .selectFrom('asset')
.where('assets.visibility', '!=', AssetVisibility.HIDDEN) .where('asset.visibility', '!=', AssetVisibility.HIDDEN)
.where('assets.deletedAt', 'is', null) .where('asset.deletedAt', 'is', null)
.innerJoin('asset_job_status as job_status', 'assetId', 'assets.id') .innerJoin('asset_job_status as job_status', 'assetId', 'asset.id')
.where('job_status.previewAt', 'is not', null); .where('job_status.previewAt', 'is not', null);
} }
@GenerateSql({ params: [], stream: true }) @GenerateSql({ params: [], stream: true })
streamForSearchDuplicates(force?: boolean) { streamForSearchDuplicates(force?: boolean) {
return this.db return this.db
.selectFrom('assets') .selectFrom('asset')
.select(['assets.id']) .select(['asset.id'])
.where('assets.deletedAt', 'is', null) .where('asset.deletedAt', 'is', null)
.innerJoin('smart_search', 'assets.id', 'smart_search.assetId') .innerJoin('smart_search', 'asset.id', 'smart_search.assetId')
.$call(withDefaultVisibility) .$call(withDefaultVisibility)
.$if(!force, (qb) => .$if(!force, (qb) =>
qb qb
.innerJoin('asset_job_status as job_status', 'job_status.assetId', 'assets.id') .innerJoin('asset_job_status as job_status', 'job_status.assetId', 'asset.id')
.where('job_status.duplicatesDetectedAt', 'is', null), .where('job_status.duplicatesDetectedAt', 'is', null),
) )
.stream(); .stream();
@ -155,11 +155,9 @@ export class AssetJobRepository {
@GenerateSql({ params: [], stream: true }) @GenerateSql({ params: [], stream: true })
streamForEncodeClip(force?: boolean) { streamForEncodeClip(force?: boolean) {
return this.assetsWithPreviews() return this.assetsWithPreviews()
.select(['assets.id']) .select(['asset.id'])
.$if(!force, (qb) => .$if(!force, (qb) =>
qb.where((eb) => qb.where((eb) => eb.not((eb) => eb.exists(eb.selectFrom('smart_search').whereRef('assetId', '=', 'asset.id')))),
eb.not((eb) => eb.exists(eb.selectFrom('smart_search').whereRef('assetId', '=', 'assets.id'))),
),
) )
.stream(); .stream();
} }
@ -167,142 +165,142 @@ export class AssetJobRepository {
@GenerateSql({ params: [DummyValue.UUID] }) @GenerateSql({ params: [DummyValue.UUID] })
getForClipEncoding(id: string) { getForClipEncoding(id: string) {
return this.db return this.db
.selectFrom('assets') .selectFrom('asset')
.select(['assets.id', 'assets.visibility']) .select(['asset.id', 'asset.visibility'])
.select((eb) => withFiles(eb, AssetFileType.PREVIEW)) .select((eb) => withFiles(eb, AssetFileType.PREVIEW))
.where('assets.id', '=', id) .where('asset.id', '=', id)
.executeTakeFirst(); .executeTakeFirst();
} }
@GenerateSql({ params: [DummyValue.UUID] }) @GenerateSql({ params: [DummyValue.UUID] })
getForDetectFacesJob(id: string) { getForDetectFacesJob(id: string) {
return this.db return this.db
.selectFrom('assets') .selectFrom('asset')
.select(['assets.id', 'assets.visibility']) .select(['asset.id', 'asset.visibility'])
.$call(withExifInner) .$call(withExifInner)
.select((eb) => withFaces(eb, true)) .select((eb) => withFaces(eb, true))
.select((eb) => withFiles(eb, AssetFileType.PREVIEW)) .select((eb) => withFiles(eb, AssetFileType.PREVIEW))
.where('assets.id', '=', id) .where('asset.id', '=', id)
.executeTakeFirst(); .executeTakeFirst();
} }
@GenerateSql({ params: [[DummyValue.UUID]] }) @GenerateSql({ params: [[DummyValue.UUID]] })
getForSyncAssets(ids: string[]) { getForSyncAssets(ids: string[]) {
return this.db return this.db
.selectFrom('assets') .selectFrom('asset')
.select([ .select([
'assets.id', 'asset.id',
'assets.isOffline', 'asset.isOffline',
'assets.libraryId', 'asset.libraryId',
'assets.originalPath', 'asset.originalPath',
'assets.status', 'asset.status',
'assets.fileModifiedAt', 'asset.fileModifiedAt',
]) ])
.where('assets.id', '=', anyUuid(ids)) .where('asset.id', '=', anyUuid(ids))
.execute(); .execute();
} }
@GenerateSql({ params: [DummyValue.UUID] }) @GenerateSql({ params: [DummyValue.UUID] })
getForAssetDeletion(id: string) { getForAssetDeletion(id: string) {
return this.db return this.db
.selectFrom('assets') .selectFrom('asset')
.select([ .select([
'assets.id', 'asset.id',
'assets.visibility', 'asset.visibility',
'assets.libraryId', 'asset.libraryId',
'assets.ownerId', 'asset.ownerId',
'assets.livePhotoVideoId', 'asset.livePhotoVideoId',
'assets.sidecarPath', 'asset.sidecarPath',
'assets.encodedVideoPath', 'asset.encodedVideoPath',
'assets.originalPath', 'asset.originalPath',
]) ])
.$call(withExif) .$call(withExif)
.select(withFacesAndPeople) .select(withFacesAndPeople)
.select(withFiles) .select(withFiles)
.leftJoin('asset_stack', 'asset_stack.id', 'assets.stackId') .leftJoin('stack', 'stack.id', 'asset.stackId')
.leftJoinLateral( .leftJoinLateral(
(eb) => (eb) =>
eb eb
.selectFrom('assets as stacked') .selectFrom('asset as stacked')
.select(['asset_stack.id', 'asset_stack.primaryAssetId']) .select(['stack.id', 'stack.primaryAssetId'])
.select((eb) => eb.fn<Asset[]>('array_agg', [eb.table('stacked')]).as('assets')) .select((eb) => eb.fn<Asset[]>('array_agg', [eb.table('stacked')]).as('assets'))
.where('stacked.deletedAt', 'is not', null) .where('stacked.deletedAt', 'is not', null)
.where('stacked.visibility', '=', AssetVisibility.TIMELINE) .where('stacked.visibility', '=', AssetVisibility.TIMELINE)
.whereRef('stacked.stackId', '=', 'asset_stack.id') .whereRef('stacked.stackId', '=', 'stack.id')
.groupBy('asset_stack.id') .groupBy('stack.id')
.as('stacked_assets'), .as('stacked_assets'),
(join) => join.on('asset_stack.id', 'is not', null), (join) => join.on('stack.id', 'is not', null),
) )
.select((eb) => toJson(eb, 'stacked_assets').as('stack')) .select((eb) => toJson(eb, 'stacked_assets').as('stack'))
.where('assets.id', '=', id) .where('asset.id', '=', id)
.executeTakeFirst(); .executeTakeFirst();
} }
@GenerateSql({ params: [], stream: true }) @GenerateSql({ params: [], stream: true })
streamForVideoConversion(force?: boolean) { streamForVideoConversion(force?: boolean) {
return this.db return this.db
.selectFrom('assets') .selectFrom('asset')
.select(['assets.id']) .select(['asset.id'])
.where('assets.type', '=', AssetType.VIDEO) .where('asset.type', '=', AssetType.VIDEO)
.$if(!force, (qb) => .$if(!force, (qb) =>
qb qb
.where((eb) => eb.or([eb('assets.encodedVideoPath', 'is', null), eb('assets.encodedVideoPath', '=', '')])) .where((eb) => eb.or([eb('asset.encodedVideoPath', 'is', null), eb('asset.encodedVideoPath', '=', '')]))
.where('assets.visibility', '!=', AssetVisibility.HIDDEN), .where('asset.visibility', '!=', AssetVisibility.HIDDEN),
) )
.where('assets.deletedAt', 'is', null) .where('asset.deletedAt', 'is', null)
.stream(); .stream();
} }
@GenerateSql({ params: [DummyValue.UUID] }) @GenerateSql({ params: [DummyValue.UUID] })
getForVideoConversion(id: string) { getForVideoConversion(id: string) {
return this.db return this.db
.selectFrom('assets') .selectFrom('asset')
.select(['assets.id', 'assets.ownerId', 'assets.originalPath', 'assets.encodedVideoPath']) .select(['asset.id', 'asset.ownerId', 'asset.originalPath', 'asset.encodedVideoPath'])
.where('assets.id', '=', id) .where('asset.id', '=', id)
.where('assets.type', '=', AssetType.VIDEO) .where('asset.type', '=', AssetType.VIDEO)
.executeTakeFirst(); .executeTakeFirst();
} }
@GenerateSql({ params: [], stream: true }) @GenerateSql({ params: [], stream: true })
streamForMetadataExtraction(force?: boolean) { streamForMetadataExtraction(force?: boolean) {
return this.db return this.db
.selectFrom('assets') .selectFrom('asset')
.select(['assets.id']) .select(['asset.id'])
.$if(!force, (qb) => .$if(!force, (qb) =>
qb qb
.leftJoin('asset_job_status', 'asset_job_status.assetId', 'assets.id') .leftJoin('asset_job_status', 'asset_job_status.assetId', 'asset.id')
.where((eb) => .where((eb) =>
eb.or([eb('asset_job_status.metadataExtractedAt', 'is', null), eb('asset_job_status.assetId', 'is', null)]), eb.or([eb('asset_job_status.metadataExtractedAt', 'is', null), eb('asset_job_status.assetId', 'is', null)]),
), ),
) )
.where('assets.deletedAt', 'is', null) .where('asset.deletedAt', 'is', null)
.stream(); .stream();
} }
private storageTemplateAssetQuery() { private storageTemplateAssetQuery() {
return this.db return this.db
.selectFrom('assets') .selectFrom('asset')
.innerJoin('exif', 'assets.id', 'exif.assetId') .innerJoin('asset_exif', 'asset.id', 'asset_exif.assetId')
.select([ .select([
'assets.id', 'asset.id',
'assets.ownerId', 'asset.ownerId',
'assets.type', 'asset.type',
'assets.checksum', 'asset.checksum',
'assets.originalPath', 'asset.originalPath',
'assets.isExternal', 'asset.isExternal',
'assets.sidecarPath', 'asset.sidecarPath',
'assets.originalFileName', 'asset.originalFileName',
'assets.livePhotoVideoId', 'asset.livePhotoVideoId',
'assets.fileCreatedAt', 'asset.fileCreatedAt',
'exif.timeZone', 'asset_exif.timeZone',
'exif.fileSizeInByte', 'asset_exif.fileSizeInByte',
]) ])
.where('assets.deletedAt', 'is', null); .where('asset.deletedAt', 'is', null);
} }
@GenerateSql({ params: [DummyValue.UUID] }) @GenerateSql({ params: [DummyValue.UUID] })
getForStorageTemplateJob(id: string): Promise<StorageAsset | undefined> { getForStorageTemplateJob(id: string): Promise<StorageAsset | undefined> {
return this.storageTemplateAssetQuery().where('assets.id', '=', id).executeTakeFirst() as Promise< return this.storageTemplateAssetQuery().where('asset.id', '=', id).executeTakeFirst() as Promise<
StorageAsset | undefined StorageAsset | undefined
>; >;
} }
@ -315,21 +313,21 @@ export class AssetJobRepository {
@GenerateSql({ params: [DummyValue.DATE], stream: true }) @GenerateSql({ params: [DummyValue.DATE], stream: true })
streamForDeletedJob(trashedBefore: Date) { streamForDeletedJob(trashedBefore: Date) {
return this.db return this.db
.selectFrom('assets') .selectFrom('asset')
.select(['id', 'isOffline']) .select(['id', 'isOffline'])
.where('assets.deletedAt', '<=', trashedBefore) .where('asset.deletedAt', '<=', trashedBefore)
.stream(); .stream();
} }
@GenerateSql({ params: [], stream: true }) @GenerateSql({ params: [], stream: true })
streamForSidecar(force?: boolean) { streamForSidecar(force?: boolean) {
return this.db return this.db
.selectFrom('assets') .selectFrom('asset')
.select(['assets.id']) .select(['asset.id'])
.$if(!force, (qb) => .$if(!force, (qb) =>
qb.where((eb) => eb.or([eb('assets.sidecarPath', '=', ''), eb('assets.sidecarPath', 'is', null)])), qb.where((eb) => eb.or([eb('asset.sidecarPath', '=', ''), eb('asset.sidecarPath', 'is', null)])),
) )
.where('assets.visibility', '!=', AssetVisibility.HIDDEN) .where('asset.visibility', '!=', AssetVisibility.HIDDEN)
.stream(); .stream();
} }
@ -337,13 +335,13 @@ export class AssetJobRepository {
streamForDetectFacesJob(force?: boolean) { streamForDetectFacesJob(force?: boolean) {
return this.assetsWithPreviews() return this.assetsWithPreviews()
.$if(!force, (qb) => qb.where('job_status.facesRecognizedAt', 'is', null)) .$if(!force, (qb) => qb.where('job_status.facesRecognizedAt', 'is', null))
.select(['assets.id']) .select(['asset.id'])
.orderBy('assets.createdAt', 'desc') .orderBy('asset.createdAt', 'desc')
.stream(); .stream();
} }
@GenerateSql({ params: [DummyValue.DATE], stream: true }) @GenerateSql({ params: [DummyValue.DATE], stream: true })
streamForMigrationJob() { streamForMigrationJob() {
return this.db.selectFrom('assets').select(['id']).where('assets.deletedAt', 'is', null).stream(); return this.db.selectFrom('asset').select(['id']).where('asset.deletedAt', 'is', null).stream();
} }
} }

View File

@ -6,10 +6,10 @@ import { Stack } from 'src/database';
import { Chunked, ChunkedArray, DummyValue, GenerateSql } from 'src/decorators'; import { Chunked, ChunkedArray, DummyValue, GenerateSql } from 'src/decorators';
import { AssetFileType, AssetOrder, AssetStatus, AssetType, AssetVisibility } from 'src/enum'; import { AssetFileType, AssetOrder, AssetStatus, AssetType, AssetVisibility } from 'src/enum';
import { DB } from 'src/schema'; import { DB } from 'src/schema';
import { AssetFileTable } from 'src/schema/tables/asset-files.table'; import { AssetExifTable } from 'src/schema/tables/asset-exif.table';
import { AssetFileTable } from 'src/schema/tables/asset-file.table';
import { AssetJobStatusTable } from 'src/schema/tables/asset-job-status.table'; import { AssetJobStatusTable } from 'src/schema/tables/asset-job-status.table';
import { AssetTable } from 'src/schema/tables/asset.table'; import { AssetTable } from 'src/schema/tables/asset.table';
import { ExifTable } from 'src/schema/tables/exif.table';
import { import {
anyUuid, anyUuid,
asUuid, asUuid,
@ -114,10 +114,10 @@ interface GetByIdsRelations {
export class AssetRepository { export class AssetRepository {
constructor(@InjectKysely() private db: Kysely<DB>) {} constructor(@InjectKysely() private db: Kysely<DB>) {}
async upsertExif(exif: Insertable<ExifTable>): Promise<void> { async upsertExif(exif: Insertable<AssetExifTable>): Promise<void> {
const value = { ...exif, assetId: asUuid(exif.assetId) }; const value = { ...exif, assetId: asUuid(exif.assetId) };
await this.db await this.db
.insertInto('exif') .insertInto('asset_exif')
.values(value) .values(value)
.onConflict((oc) => .onConflict((oc) =>
oc.column('assetId').doUpdateSet((eb) => oc.column('assetId').doUpdateSet((eb) =>
@ -161,12 +161,12 @@ export class AssetRepository {
@GenerateSql({ params: [[DummyValue.UUID], { model: DummyValue.STRING }] }) @GenerateSql({ params: [[DummyValue.UUID], { model: DummyValue.STRING }] })
@Chunked() @Chunked()
async updateAllExif(ids: string[], options: Updateable<ExifTable>): Promise<void> { async updateAllExif(ids: string[], options: Updateable<AssetExifTable>): Promise<void> {
if (ids.length === 0) { if (ids.length === 0) {
return; return;
} }
await this.db.updateTable('exif').set(options).where('assetId', 'in', ids).execute(); await this.db.updateTable('asset_exif').set(options).where('assetId', 'in', ids).execute();
} }
async upsertJobStatus(...jobStatus: Insertable<AssetJobStatusTable>[]): Promise<void> { async upsertJobStatus(...jobStatus: Insertable<AssetJobStatusTable>[]): Promise<void> {
@ -196,11 +196,11 @@ export class AssetRepository {
} }
create(asset: Insertable<AssetTable>) { create(asset: Insertable<AssetTable>) {
return this.db.insertInto('assets').values(asset).returningAll().executeTakeFirstOrThrow(); return this.db.insertInto('asset').values(asset).returningAll().executeTakeFirstOrThrow();
} }
createAll(assets: Insertable<AssetTable>[]) { createAll(assets: Insertable<AssetTable>[]) {
return this.db.insertInto('assets').values(assets).returningAll().execute(); return this.db.insertInto('asset').values(assets).returningAll().execute();
} }
@GenerateSql({ params: [DummyValue.UUID, { day: 1, month: 1 }] }) @GenerateSql({ params: [DummyValue.UUID, { day: 1, month: 1 }] })
@ -213,7 +213,7 @@ export class AssetRepository {
.selectFrom((eb) => .selectFrom((eb) =>
eb eb
.fn('generate_series', [ .fn('generate_series', [
sql`(select date_part('year', min(("localDateTime" at time zone 'UTC')::date))::int from assets)`, sql`(select date_part('year', min(("localDateTime" at time zone 'UTC')::date))::int from asset)`,
sql`date_part('year', current_date)::int - 1`, sql`date_part('year', current_date)::int - 1`,
]) ])
.as('year'), .as('year'),
@ -224,30 +224,30 @@ export class AssetRepository {
.innerJoinLateral( .innerJoinLateral(
(qb) => (qb) =>
qb qb
.selectFrom('assets') .selectFrom('asset')
.selectAll('assets') .selectAll('asset')
.innerJoin('asset_job_status', 'assets.id', 'asset_job_status.assetId') .innerJoin('asset_job_status', 'asset.id', 'asset_job_status.assetId')
.where('asset_job_status.previewAt', 'is not', null) .where('asset_job_status.previewAt', 'is not', null)
.where(sql`(assets."localDateTime" at time zone 'UTC')::date`, '=', sql`today.date`) .where(sql`(asset."localDateTime" at time zone 'UTC')::date`, '=', sql`today.date`)
.where('assets.ownerId', '=', anyUuid(ownerIds)) .where('asset.ownerId', '=', anyUuid(ownerIds))
.where('assets.visibility', '=', AssetVisibility.TIMELINE) .where('asset.visibility', '=', AssetVisibility.TIMELINE)
.where((eb) => .where((eb) =>
eb.exists((qb) => eb.exists((qb) =>
qb qb
.selectFrom('asset_files') .selectFrom('asset_file')
.whereRef('assetId', '=', 'assets.id') .whereRef('assetId', '=', 'asset.id')
.where('asset_files.type', '=', AssetFileType.PREVIEW), .where('asset_file.type', '=', AssetFileType.PREVIEW),
), ),
) )
.where('assets.deletedAt', 'is', null) .where('asset.deletedAt', 'is', null)
.orderBy(sql`(assets."localDateTime" at time zone 'UTC')::date`, 'desc') .orderBy(sql`(asset."localDateTime" at time zone 'UTC')::date`, 'desc')
.limit(20) .limit(20)
.as('a'), .as('a'),
(join) => join.onTrue(), (join) => join.onTrue(),
) )
.innerJoin('exif', 'a.id', 'exif.assetId') .innerJoin('asset_exif', 'a.id', 'asset_exif.assetId')
.selectAll('a') .selectAll('a')
.select((eb) => eb.fn.toJson(eb.table('exif')).as('exifInfo')), .select((eb) => eb.fn.toJson(eb.table('asset_exif')).as('exifInfo')),
) )
.selectFrom('res') .selectFrom('res')
.select(sql<number>`date_part('year', ("localDateTime" at time zone 'UTC')::date)::int`.as('year')) .select(sql<number>`date_part('year', ("localDateTime" at time zone 'UTC')::date)::int`.as('year'))
@ -260,30 +260,30 @@ export class AssetRepository {
@GenerateSql({ params: [[DummyValue.UUID]] }) @GenerateSql({ params: [[DummyValue.UUID]] })
@ChunkedArray() @ChunkedArray()
getByIds(ids: string[]) { getByIds(ids: string[]) {
return this.db.selectFrom('assets').selectAll('assets').where('assets.id', '=', anyUuid(ids)).execute(); return this.db.selectFrom('asset').selectAll('asset').where('asset.id', '=', anyUuid(ids)).execute();
} }
@GenerateSql({ params: [[DummyValue.UUID]] }) @GenerateSql({ params: [[DummyValue.UUID]] })
@ChunkedArray() @ChunkedArray()
getByIdsWithAllRelationsButStacks(ids: string[]) { getByIdsWithAllRelationsButStacks(ids: string[]) {
return this.db return this.db
.selectFrom('assets') .selectFrom('asset')
.selectAll('assets') .selectAll('asset')
.select(withFacesAndPeople) .select(withFacesAndPeople)
.select(withTags) .select(withTags)
.$call(withExif) .$call(withExif)
.where('assets.id', '=', anyUuid(ids)) .where('asset.id', '=', anyUuid(ids))
.execute(); .execute();
} }
@GenerateSql({ params: [DummyValue.UUID] }) @GenerateSql({ params: [DummyValue.UUID] })
async deleteAll(ownerId: string): Promise<void> { async deleteAll(ownerId: string): Promise<void> {
await this.db.deleteFrom('assets').where('ownerId', '=', ownerId).execute(); await this.db.deleteFrom('asset').where('ownerId', '=', ownerId).execute();
} }
async getByDeviceIds(ownerId: string, deviceId: string, deviceAssetIds: string[]): Promise<string[]> { async getByDeviceIds(ownerId: string, deviceId: string, deviceAssetIds: string[]): Promise<string[]> {
const assets = await this.db const assets = await this.db
.selectFrom('assets') .selectFrom('asset')
.select(['deviceAssetId']) .select(['deviceAssetId'])
.where('deviceAssetId', 'in', deviceAssetIds) .where('deviceAssetId', 'in', deviceAssetIds)
.where('deviceId', '=', deviceId) .where('deviceId', '=', deviceId)
@ -296,8 +296,8 @@ export class AssetRepository {
@GenerateSql({ params: [DummyValue.UUID, DummyValue.STRING] }) @GenerateSql({ params: [DummyValue.UUID, DummyValue.STRING] })
getByLibraryIdAndOriginalPath(libraryId: string, originalPath: string) { getByLibraryIdAndOriginalPath(libraryId: string, originalPath: string) {
return this.db return this.db
.selectFrom('assets') .selectFrom('asset')
.selectAll('assets') .selectAll('asset')
.where('libraryId', '=', asUuid(libraryId)) .where('libraryId', '=', asUuid(libraryId))
.where('originalPath', '=', originalPath) .where('originalPath', '=', originalPath)
.limit(1) .limit(1)
@ -314,7 +314,7 @@ export class AssetRepository {
@GenerateSql({ params: [DummyValue.UUID, DummyValue.STRING] }) @GenerateSql({ params: [DummyValue.UUID, DummyValue.STRING] })
async getAllByDeviceId(ownerId: string, deviceId: string): Promise<string[]> { async getAllByDeviceId(ownerId: string, deviceId: string): Promise<string[]> {
const items = await this.db const items = await this.db
.selectFrom('assets') .selectFrom('asset')
.select(['deviceAssetId']) .select(['deviceAssetId'])
.where('ownerId', '=', asUuid(ownerId)) .where('ownerId', '=', asUuid(ownerId))
.where('deviceId', '=', deviceId) .where('deviceId', '=', deviceId)
@ -328,7 +328,7 @@ export class AssetRepository {
@GenerateSql({ params: [DummyValue.UUID] }) @GenerateSql({ params: [DummyValue.UUID] })
async getLivePhotoCount(motionId: string): Promise<number> { async getLivePhotoCount(motionId: string): Promise<number> {
const [{ count }] = await this.db const [{ count }] = await this.db
.selectFrom('assets') .selectFrom('asset')
.select((eb) => eb.fn.countAll<number>().as('count')) .select((eb) => eb.fn.countAll<number>().as('count'))
.where('livePhotoVideoId', '=', asUuid(motionId)) .where('livePhotoVideoId', '=', asUuid(motionId))
.execute(); .execute();
@ -338,9 +338,9 @@ export class AssetRepository {
@GenerateSql({ params: [DummyValue.UUID] }) @GenerateSql({ params: [DummyValue.UUID] })
getById(id: string, { exifInfo, faces, files, library, owner, smartSearch, stack, tags }: GetByIdsRelations = {}) { getById(id: string, { exifInfo, faces, files, library, owner, smartSearch, stack, tags }: GetByIdsRelations = {}) {
return this.db return this.db
.selectFrom('assets') .selectFrom('asset')
.selectAll('assets') .selectAll('asset')
.where('assets.id', '=', asUuid(id)) .where('asset.id', '=', asUuid(id))
.$if(!!exifInfo, withExif) .$if(!!exifInfo, withExif)
.$if(!!faces, (qb) => qb.select(faces?.person ? withFacesAndPeople : withFaces).$narrowType<{ faces: NotNull }>()) .$if(!!faces, (qb) => qb.select(faces?.person ? withFacesAndPeople : withFaces).$narrowType<{ faces: NotNull }>())
.$if(!!library, (qb) => qb.select(withLibrary)) .$if(!!library, (qb) => qb.select(withLibrary))
@ -348,25 +348,25 @@ export class AssetRepository {
.$if(!!smartSearch, withSmartSearch) .$if(!!smartSearch, withSmartSearch)
.$if(!!stack, (qb) => .$if(!!stack, (qb) =>
qb qb
.leftJoin('asset_stack', 'asset_stack.id', 'assets.stackId') .leftJoin('stack', 'stack.id', 'asset.stackId')
.$if(!stack!.assets, (qb) => .$if(!stack!.assets, (qb) =>
qb.select((eb) => eb.fn.toJson(eb.table('asset_stack')).$castTo<Stack | null>().as('stack')), qb.select((eb) => eb.fn.toJson(eb.table('stack')).$castTo<Stack | null>().as('stack')),
) )
.$if(!!stack!.assets, (qb) => .$if(!!stack!.assets, (qb) =>
qb qb
.leftJoinLateral( .leftJoinLateral(
(eb) => (eb) =>
eb eb
.selectFrom('assets as stacked') .selectFrom('asset as stacked')
.selectAll('asset_stack') .selectAll('stack')
.select((eb) => eb.fn('array_agg', [eb.table('stacked')]).as('assets')) .select((eb) => eb.fn('array_agg', [eb.table('stacked')]).as('assets'))
.whereRef('stacked.stackId', '=', 'asset_stack.id') .whereRef('stacked.stackId', '=', 'stack.id')
.whereRef('stacked.id', '!=', 'asset_stack.primaryAssetId') .whereRef('stacked.id', '!=', 'stack.primaryAssetId')
.where('stacked.deletedAt', 'is', null) .where('stacked.deletedAt', 'is', null)
.where('stacked.visibility', '=', AssetVisibility.TIMELINE) .where('stacked.visibility', '=', AssetVisibility.TIMELINE)
.groupBy('asset_stack.id') .groupBy('stack.id')
.as('stacked_assets'), .as('stacked_assets'),
(join) => join.on('asset_stack.id', 'is not', null), (join) => join.on('stack.id', 'is not', null),
) )
.select((eb) => eb.fn.toJson(eb.table('stacked_assets')).$castTo<Stack | null>().as('stack')), .select((eb) => eb.fn.toJson(eb.table('stacked_assets')).$castTo<Stack | null>().as('stack')),
), ),
@ -383,11 +383,11 @@ export class AssetRepository {
if (ids.length === 0) { if (ids.length === 0) {
return; return;
} }
await this.db.updateTable('assets').set(options).where('id', '=', anyUuid(ids)).execute(); await this.db.updateTable('asset').set(options).where('id', '=', anyUuid(ids)).execute();
} }
async updateByLibraryId(libraryId: string, options: Updateable<AssetTable>): Promise<void> { async updateByLibraryId(libraryId: string, options: Updateable<AssetTable>): Promise<void> {
await this.db.updateTable('assets').set(options).where('libraryId', '=', asUuid(libraryId)).execute(); await this.db.updateTable('asset').set(options).where('libraryId', '=', asUuid(libraryId)).execute();
} }
async update(asset: Updateable<AssetTable> & { id: string }) { async update(asset: Updateable<AssetTable> & { id: string }) {
@ -395,9 +395,9 @@ export class AssetRepository {
delete value.id; delete value.id;
if (!isEmpty(value)) { if (!isEmpty(value)) {
return this.db return this.db
.with('assets', (qb) => qb.updateTable('assets').set(asset).where('id', '=', asUuid(asset.id)).returningAll()) .with('asset', (qb) => qb.updateTable('asset').set(asset).where('id', '=', asUuid(asset.id)).returningAll())
.selectFrom('assets') .selectFrom('asset')
.selectAll('assets') .selectAll('asset')
.$call(withExif) .$call(withExif)
.$call((qb) => qb.select(withFacesAndPeople)) .$call((qb) => qb.select(withFacesAndPeople))
.executeTakeFirst(); .executeTakeFirst();
@ -407,14 +407,14 @@ export class AssetRepository {
} }
async remove(asset: { id: string }): Promise<void> { async remove(asset: { id: string }): Promise<void> {
await this.db.deleteFrom('assets').where('id', '=', asUuid(asset.id)).execute(); await this.db.deleteFrom('asset').where('id', '=', asUuid(asset.id)).execute();
} }
@GenerateSql({ params: [{ ownerId: DummyValue.UUID, libraryId: DummyValue.UUID, checksum: DummyValue.BUFFER }] }) @GenerateSql({ params: [{ ownerId: DummyValue.UUID, libraryId: DummyValue.UUID, checksum: DummyValue.BUFFER }] })
getByChecksum({ ownerId, libraryId, checksum }: AssetGetByChecksumOptions) { getByChecksum({ ownerId, libraryId, checksum }: AssetGetByChecksumOptions) {
return this.db return this.db
.selectFrom('assets') .selectFrom('asset')
.selectAll('assets') .selectAll('asset')
.where('ownerId', '=', asUuid(ownerId)) .where('ownerId', '=', asUuid(ownerId))
.where('checksum', '=', checksum) .where('checksum', '=', checksum)
.$call((qb) => (libraryId ? qb.where('libraryId', '=', asUuid(libraryId)) : qb.where('libraryId', 'is', null))) .$call((qb) => (libraryId ? qb.where('libraryId', '=', asUuid(libraryId)) : qb.where('libraryId', 'is', null)))
@ -425,7 +425,7 @@ export class AssetRepository {
@GenerateSql({ params: [DummyValue.UUID, [DummyValue.BUFFER]] }) @GenerateSql({ params: [DummyValue.UUID, [DummyValue.BUFFER]] })
getByChecksums(userId: string, checksums: Buffer[]) { getByChecksums(userId: string, checksums: Buffer[]) {
return this.db return this.db
.selectFrom('assets') .selectFrom('asset')
.select(['id', 'checksum', 'deletedAt']) .select(['id', 'checksum', 'deletedAt'])
.where('ownerId', '=', asUuid(userId)) .where('ownerId', '=', asUuid(userId))
.where('checksum', 'in', checksums) .where('checksum', 'in', checksums)
@ -435,7 +435,7 @@ export class AssetRepository {
@GenerateSql({ params: [DummyValue.UUID, DummyValue.BUFFER] }) @GenerateSql({ params: [DummyValue.UUID, DummyValue.BUFFER] })
async getUploadAssetIdByChecksum(ownerId: string, checksum: Buffer): Promise<string | undefined> { async getUploadAssetIdByChecksum(ownerId: string, checksum: Buffer): Promise<string | undefined> {
const asset = await this.db const asset = await this.db
.selectFrom('assets') .selectFrom('asset')
.select('id') .select('id')
.where('ownerId', '=', asUuid(ownerId)) .where('ownerId', '=', asUuid(ownerId))
.where('checksum', '=', checksum) .where('checksum', '=', checksum)
@ -449,37 +449,37 @@ export class AssetRepository {
findLivePhotoMatch(options: LivePhotoSearchOptions) { findLivePhotoMatch(options: LivePhotoSearchOptions) {
const { ownerId, otherAssetId, livePhotoCID, type } = options; const { ownerId, otherAssetId, livePhotoCID, type } = options;
return this.db return this.db
.selectFrom('assets') .selectFrom('asset')
.select(['assets.id', 'assets.ownerId']) .select(['asset.id', 'asset.ownerId'])
.innerJoin('exif', 'assets.id', 'exif.assetId') .innerJoin('asset_exif', 'asset.id', 'asset_exif.assetId')
.where('id', '!=', asUuid(otherAssetId)) .where('id', '!=', asUuid(otherAssetId))
.where('ownerId', '=', asUuid(ownerId)) .where('ownerId', '=', asUuid(ownerId))
.where('type', '=', type) .where('type', '=', type)
.where('exif.livePhotoCID', '=', livePhotoCID) .where('asset_exif.livePhotoCID', '=', livePhotoCID)
.limit(1) .limit(1)
.executeTakeFirst(); .executeTakeFirst();
} }
getStatistics(ownerId: string, { visibility, isFavorite, isTrashed }: AssetStatsOptions): Promise<AssetStats> { getStatistics(ownerId: string, { visibility, isFavorite, isTrashed }: AssetStatsOptions): Promise<AssetStats> {
return this.db return this.db
.selectFrom('assets') .selectFrom('asset')
.select((eb) => eb.fn.countAll<number>().filterWhere('type', '=', AssetType.AUDIO).as(AssetType.AUDIO)) .select((eb) => eb.fn.countAll<number>().filterWhere('type', '=', AssetType.AUDIO).as(AssetType.AUDIO))
.select((eb) => eb.fn.countAll<number>().filterWhere('type', '=', AssetType.IMAGE).as(AssetType.IMAGE)) .select((eb) => eb.fn.countAll<number>().filterWhere('type', '=', AssetType.IMAGE).as(AssetType.IMAGE))
.select((eb) => eb.fn.countAll<number>().filterWhere('type', '=', AssetType.VIDEO).as(AssetType.VIDEO)) .select((eb) => eb.fn.countAll<number>().filterWhere('type', '=', AssetType.VIDEO).as(AssetType.VIDEO))
.select((eb) => eb.fn.countAll<number>().filterWhere('type', '=', AssetType.OTHER).as(AssetType.OTHER)) .select((eb) => eb.fn.countAll<number>().filterWhere('type', '=', AssetType.OTHER).as(AssetType.OTHER))
.where('ownerId', '=', asUuid(ownerId)) .where('ownerId', '=', asUuid(ownerId))
.$if(visibility === undefined, withDefaultVisibility) .$if(visibility === undefined, withDefaultVisibility)
.$if(!!visibility, (qb) => qb.where('assets.visibility', '=', visibility!)) .$if(!!visibility, (qb) => qb.where('asset.visibility', '=', visibility!))
.$if(isFavorite !== undefined, (qb) => qb.where('isFavorite', '=', isFavorite!)) .$if(isFavorite !== undefined, (qb) => qb.where('isFavorite', '=', isFavorite!))
.$if(!!isTrashed, (qb) => qb.where('assets.status', '!=', AssetStatus.DELETED)) .$if(!!isTrashed, (qb) => qb.where('asset.status', '!=', AssetStatus.DELETED))
.where('deletedAt', isTrashed ? 'is not' : 'is', null) .where('deletedAt', isTrashed ? 'is not' : 'is', null)
.executeTakeFirstOrThrow(); .executeTakeFirstOrThrow();
} }
getRandom(userIds: string[], take: number) { getRandom(userIds: string[], take: number) {
return this.db return this.db
.selectFrom('assets') .selectFrom('asset')
.selectAll('assets') .selectAll('asset')
.$call(withExif) .$call(withExif)
.$call(withDefaultVisibility) .$call(withDefaultVisibility)
.where('ownerId', '=', anyUuid(userIds)) .where('ownerId', '=', anyUuid(userIds))
@ -492,38 +492,36 @@ export class AssetRepository {
@GenerateSql({ params: [{}] }) @GenerateSql({ params: [{}] })
async getTimeBuckets(options: TimeBucketOptions): Promise<TimeBucketItem[]> { async getTimeBuckets(options: TimeBucketOptions): Promise<TimeBucketItem[]> {
return this.db return this.db
.with('assets', (qb) => .with('asset', (qb) =>
qb qb
.selectFrom('assets') .selectFrom('asset')
.select(truncatedDate<Date>().as('timeBucket')) .select(truncatedDate<Date>().as('timeBucket'))
.$if(!!options.isTrashed, (qb) => qb.where('assets.status', '!=', AssetStatus.DELETED)) .$if(!!options.isTrashed, (qb) => qb.where('asset.status', '!=', AssetStatus.DELETED))
.where('assets.deletedAt', options.isTrashed ? 'is not' : 'is', null) .where('asset.deletedAt', options.isTrashed ? 'is not' : 'is', null)
.$if(options.visibility === undefined, withDefaultVisibility) .$if(options.visibility === undefined, withDefaultVisibility)
.$if(!!options.visibility, (qb) => qb.where('assets.visibility', '=', options.visibility!)) .$if(!!options.visibility, (qb) => qb.where('asset.visibility', '=', options.visibility!))
.$if(!!options.albumId, (qb) => .$if(!!options.albumId, (qb) =>
qb qb
.innerJoin('albums_assets_assets', 'assets.id', 'albums_assets_assets.assetsId') .innerJoin('album_asset', 'asset.id', 'album_asset.assetsId')
.where('albums_assets_assets.albumsId', '=', asUuid(options.albumId!)), .where('album_asset.albumsId', '=', asUuid(options.albumId!)),
) )
.$if(!!options.personId, (qb) => hasPeople(qb, [options.personId!])) .$if(!!options.personId, (qb) => hasPeople(qb, [options.personId!]))
.$if(!!options.withStacked, (qb) => .$if(!!options.withStacked, (qb) =>
qb qb
.leftJoin('asset_stack', (join) => .leftJoin('stack', (join) =>
join join.onRef('stack.id', '=', 'asset.stackId').onRef('stack.primaryAssetId', '=', 'asset.id'),
.onRef('asset_stack.id', '=', 'assets.stackId')
.onRef('asset_stack.primaryAssetId', '=', 'assets.id'),
) )
.where((eb) => eb.or([eb('assets.stackId', 'is', null), eb(eb.table('asset_stack'), 'is not', null)])), .where((eb) => eb.or([eb('asset.stackId', 'is', null), eb(eb.table('stack'), 'is not', null)])),
) )
.$if(!!options.userIds, (qb) => qb.where('assets.ownerId', '=', anyUuid(options.userIds!))) .$if(!!options.userIds, (qb) => qb.where('asset.ownerId', '=', anyUuid(options.userIds!)))
.$if(options.isFavorite !== undefined, (qb) => qb.where('assets.isFavorite', '=', options.isFavorite!)) .$if(options.isFavorite !== undefined, (qb) => qb.where('asset.isFavorite', '=', options.isFavorite!))
.$if(!!options.assetType, (qb) => qb.where('assets.type', '=', options.assetType!)) .$if(!!options.assetType, (qb) => qb.where('asset.type', '=', options.assetType!))
.$if(options.isDuplicate !== undefined, (qb) => .$if(options.isDuplicate !== undefined, (qb) =>
qb.where('assets.duplicateId', options.isDuplicate ? 'is not' : 'is', null), qb.where('asset.duplicateId', options.isDuplicate ? 'is not' : 'is', null),
) )
.$if(!!options.tagId, (qb) => withTagId(qb, options.tagId!)), .$if(!!options.tagId, (qb) => withTagId(qb, options.tagId!)),
) )
.selectFrom('assets') .selectFrom('asset')
.select(sql<string>`("timeBucket" AT TIME ZONE 'UTC')::date::text`.as('timeBucket')) .select(sql<string>`("timeBucket" AT TIME ZONE 'UTC')::date::text`.as('timeBucket'))
.select((eb) => eb.fn.countAll<number>().as('count')) .select((eb) => eb.fn.countAll<number>().as('count'))
.groupBy('timeBucket') .groupBy('timeBucket')
@ -538,75 +536,75 @@ export class AssetRepository {
const query = this.db const query = this.db
.with('cte', (qb) => .with('cte', (qb) =>
qb qb
.selectFrom('assets') .selectFrom('asset')
.innerJoin('exif', 'assets.id', 'exif.assetId') .innerJoin('asset_exif', 'asset.id', 'asset_exif.assetId')
.select((eb) => [ .select((eb) => [
'assets.duration', 'asset.duration',
'assets.id', 'asset.id',
'assets.visibility', 'asset.visibility',
'assets.isFavorite', 'asset.isFavorite',
sql`assets.type = 'IMAGE'`.as('isImage'), sql`asset.type = 'IMAGE'`.as('isImage'),
sql`assets."deletedAt" is not null`.as('isTrashed'), sql`asset."deletedAt" is not null`.as('isTrashed'),
'assets.livePhotoVideoId', 'asset.livePhotoVideoId',
sql`extract(epoch from (assets."localDateTime" - assets."fileCreatedAt" at time zone 'UTC'))::real / 3600`.as( sql`extract(epoch from (asset."localDateTime" - asset."fileCreatedAt" at time zone 'UTC'))::real / 3600`.as(
'localOffsetHours', 'localOffsetHours',
), ),
'assets.ownerId', 'asset.ownerId',
'assets.status', 'asset.status',
sql`assets."fileCreatedAt" at time zone 'utc'`.as('fileCreatedAt'), sql`asset."fileCreatedAt" at time zone 'utc'`.as('fileCreatedAt'),
eb.fn('encode', ['assets.thumbhash', sql.lit('base64')]).as('thumbhash'), eb.fn('encode', ['asset.thumbhash', sql.lit('base64')]).as('thumbhash'),
'exif.city', 'asset_exif.city',
'exif.country', 'asset_exif.country',
'exif.projectionType', 'asset_exif.projectionType',
eb.fn eb.fn
.coalesce( .coalesce(
eb eb
.case() .case()
.when(sql`exif."exifImageHeight" = 0 or exif."exifImageWidth" = 0`) .when(sql`asset_exif."exifImageHeight" = 0 or asset_exif."exifImageWidth" = 0`)
.then(eb.lit(1)) .then(eb.lit(1))
.when('exif.orientation', 'in', sql<string>`('5', '6', '7', '8', '-90', '90')`) .when('asset_exif.orientation', 'in', sql<string>`('5', '6', '7', '8', '-90', '90')`)
.then(sql`round(exif."exifImageHeight"::numeric / exif."exifImageWidth"::numeric, 3)`) .then(sql`round(asset_exif."exifImageHeight"::numeric / asset_exif."exifImageWidth"::numeric, 3)`)
.else(sql`round(exif."exifImageWidth"::numeric / exif."exifImageHeight"::numeric, 3)`) .else(sql`round(asset_exif."exifImageWidth"::numeric / asset_exif."exifImageHeight"::numeric, 3)`)
.end(), .end(),
eb.lit(1), eb.lit(1),
) )
.as('ratio'), .as('ratio'),
]) ])
.where('assets.deletedAt', options.isTrashed ? 'is not' : 'is', null) .where('asset.deletedAt', options.isTrashed ? 'is not' : 'is', null)
.$if(options.visibility == undefined, withDefaultVisibility) .$if(options.visibility == undefined, withDefaultVisibility)
.$if(!!options.visibility, (qb) => qb.where('assets.visibility', '=', options.visibility!)) .$if(!!options.visibility, (qb) => qb.where('asset.visibility', '=', options.visibility!))
.where(truncatedDate(), '=', timeBucket.replace(/^[+-]/, '')) .where(truncatedDate(), '=', timeBucket.replace(/^[+-]/, ''))
.$if(!!options.albumId, (qb) => .$if(!!options.albumId, (qb) =>
qb.where((eb) => qb.where((eb) =>
eb.exists( eb.exists(
eb eb
.selectFrom('albums_assets_assets') .selectFrom('album_asset')
.whereRef('albums_assets_assets.assetsId', '=', 'assets.id') .whereRef('album_asset.assetsId', '=', 'asset.id')
.where('albums_assets_assets.albumsId', '=', asUuid(options.albumId!)), .where('album_asset.albumsId', '=', asUuid(options.albumId!)),
), ),
), ),
) )
.$if(!!options.personId, (qb) => hasPeople(qb, [options.personId!])) .$if(!!options.personId, (qb) => hasPeople(qb, [options.personId!]))
.$if(!!options.userIds, (qb) => qb.where('assets.ownerId', '=', anyUuid(options.userIds!))) .$if(!!options.userIds, (qb) => qb.where('asset.ownerId', '=', anyUuid(options.userIds!)))
.$if(options.isFavorite !== undefined, (qb) => qb.where('assets.isFavorite', '=', options.isFavorite!)) .$if(options.isFavorite !== undefined, (qb) => qb.where('asset.isFavorite', '=', options.isFavorite!))
.$if(!!options.withStacked, (qb) => .$if(!!options.withStacked, (qb) =>
qb qb
.where((eb) => .where((eb) =>
eb.not( eb.not(
eb.exists( eb.exists(
eb eb
.selectFrom('asset_stack') .selectFrom('stack')
.whereRef('asset_stack.id', '=', 'assets.stackId') .whereRef('stack.id', '=', 'asset.stackId')
.whereRef('asset_stack.primaryAssetId', '!=', 'assets.id'), .whereRef('stack.primaryAssetId', '!=', 'asset.id'),
), ),
), ),
) )
.leftJoinLateral( .leftJoinLateral(
(eb) => (eb) =>
eb eb
.selectFrom('assets as stacked') .selectFrom('asset as stacked')
.select(sql`array[stacked."stackId"::text, count('stacked')::text]`.as('stack')) .select(sql`array[stacked."stackId"::text, count('stacked')::text]`.as('stack'))
.whereRef('stacked.stackId', '=', 'assets.stackId') .whereRef('stacked.stackId', '=', 'asset.stackId')
.where('stacked.deletedAt', 'is', null) .where('stacked.deletedAt', 'is', null)
.where('stacked.visibility', '=', AssetVisibility.TIMELINE) .where('stacked.visibility', '=', AssetVisibility.TIMELINE)
.groupBy('stacked.stackId') .groupBy('stacked.stackId')
@ -615,13 +613,13 @@ export class AssetRepository {
) )
.select('stack'), .select('stack'),
) )
.$if(!!options.assetType, (qb) => qb.where('assets.type', '=', options.assetType!)) .$if(!!options.assetType, (qb) => qb.where('asset.type', '=', options.assetType!))
.$if(options.isDuplicate !== undefined, (qb) => .$if(options.isDuplicate !== undefined, (qb) =>
qb.where('assets.duplicateId', options.isDuplicate ? 'is not' : 'is', null), qb.where('asset.duplicateId', options.isDuplicate ? 'is not' : 'is', null),
) )
.$if(!!options.isTrashed, (qb) => qb.where('assets.status', '!=', AssetStatus.DELETED)) .$if(!!options.isTrashed, (qb) => qb.where('asset.status', '!=', AssetStatus.DELETED))
.$if(!!options.tagId, (qb) => withTagId(qb, options.tagId!)) .$if(!!options.tagId, (qb) => withTagId(qb, options.tagId!))
.orderBy('assets.fileCreatedAt', options.order ?? 'desc'), .orderBy('asset.fileCreatedAt', options.order ?? 'desc'),
) )
.with('agg', (qb) => .with('agg', (qb) =>
qb qb
@ -660,17 +658,17 @@ export class AssetRepository {
const items = await this.db const items = await this.db
.with('cities', (qb) => .with('cities', (qb) =>
qb qb
.selectFrom('exif') .selectFrom('asset_exif')
.select('city') .select('city')
.where('city', 'is not', null) .where('city', 'is not', null)
.groupBy('city') .groupBy('city')
.having((eb) => eb.fn('count', [eb.ref('assetId')]), '>=', minAssetsPerField), .having((eb) => eb.fn('count', [eb.ref('assetId')]), '>=', minAssetsPerField),
) )
.selectFrom('assets') .selectFrom('asset')
.innerJoin('exif', 'assets.id', 'exif.assetId') .innerJoin('asset_exif', 'asset.id', 'asset_exif.assetId')
.innerJoin('cities', 'exif.city', 'cities.city') .innerJoin('cities', 'asset_exif.city', 'cities.city')
.distinctOn('exif.city') .distinctOn('asset_exif.city')
.select(['assetId as data', 'exif.city as value']) .select(['assetId as data', 'asset_exif.city as value'])
.$narrowType<{ value: NotNull }>() .$narrowType<{ value: NotNull }>()
.where('ownerId', '=', asUuid(ownerId)) .where('ownerId', '=', asUuid(ownerId))
.where('visibility', '=', AssetVisibility.TIMELINE) .where('visibility', '=', AssetVisibility.TIMELINE)
@ -695,27 +693,27 @@ export class AssetRepository {
getAllForUserFullSync(options: AssetFullSyncOptions) { getAllForUserFullSync(options: AssetFullSyncOptions) {
const { ownerId, lastId, updatedUntil, limit } = options; const { ownerId, lastId, updatedUntil, limit } = options;
return this.db return this.db
.selectFrom('assets') .selectFrom('asset')
.selectAll('assets') .selectAll('asset')
.$call(withExif) .$call(withExif)
.leftJoin('asset_stack', 'asset_stack.id', 'assets.stackId') .leftJoin('stack', 'stack.id', 'asset.stackId')
.leftJoinLateral( .leftJoinLateral(
(eb) => (eb) =>
eb eb
.selectFrom('assets as stacked') .selectFrom('asset as stacked')
.selectAll('asset_stack') .selectAll('stack')
.select((eb) => eb.fn.count(eb.table('stacked')).as('assetCount')) .select((eb) => eb.fn.count(eb.table('stacked')).as('assetCount'))
.whereRef('stacked.stackId', '=', 'asset_stack.id') .whereRef('stacked.stackId', '=', 'stack.id')
.groupBy('asset_stack.id') .groupBy('stack.id')
.as('stacked_assets'), .as('stacked_assets'),
(join) => join.on('asset_stack.id', 'is not', null), (join) => join.on('stack.id', 'is not', null),
) )
.select((eb) => eb.fn.toJson(eb.table('stacked_assets')).$castTo<Stack | null>().as('stack')) .select((eb) => eb.fn.toJson(eb.table('stacked_assets')).$castTo<Stack | null>().as('stack'))
.where('assets.ownerId', '=', asUuid(ownerId)) .where('asset.ownerId', '=', asUuid(ownerId))
.where('assets.visibility', '!=', AssetVisibility.HIDDEN) .where('asset.visibility', '!=', AssetVisibility.HIDDEN)
.where('assets.updatedAt', '<=', updatedUntil) .where('asset.updatedAt', '<=', updatedUntil)
.$if(!!lastId, (qb) => qb.where('assets.id', '>', lastId!)) .$if(!!lastId, (qb) => qb.where('asset.id', '>', lastId!))
.orderBy('assets.id') .orderBy('asset.id')
.limit(limit) .limit(limit)
.execute(); .execute();
} }
@ -723,25 +721,25 @@ export class AssetRepository {
@GenerateSql({ params: [{ userIds: [DummyValue.UUID], updatedAfter: DummyValue.DATE, limit: 100 }] }) @GenerateSql({ params: [{ userIds: [DummyValue.UUID], updatedAfter: DummyValue.DATE, limit: 100 }] })
async getChangedDeltaSync(options: AssetDeltaSyncOptions) { async getChangedDeltaSync(options: AssetDeltaSyncOptions) {
return this.db return this.db
.selectFrom('assets') .selectFrom('asset')
.selectAll('assets') .selectAll('asset')
.$call(withExif) .$call(withExif)
.leftJoin('asset_stack', 'asset_stack.id', 'assets.stackId') .leftJoin('stack', 'stack.id', 'asset.stackId')
.leftJoinLateral( .leftJoinLateral(
(eb) => (eb) =>
eb eb
.selectFrom('assets as stacked') .selectFrom('asset as stacked')
.selectAll('asset_stack') .selectAll('stack')
.select((eb) => eb.fn.count(eb.table('stacked')).as('assetCount')) .select((eb) => eb.fn.count(eb.table('stacked')).as('assetCount'))
.whereRef('stacked.stackId', '=', 'asset_stack.id') .whereRef('stacked.stackId', '=', 'stack.id')
.groupBy('asset_stack.id') .groupBy('stack.id')
.as('stacked_assets'), .as('stacked_assets'),
(join) => join.on('asset_stack.id', 'is not', null), (join) => join.on('stack.id', 'is not', null),
) )
.select((eb) => eb.fn.toJson(eb.table('stacked_assets').$castTo<Stack | null>()).as('stack')) .select((eb) => eb.fn.toJson(eb.table('stacked_assets').$castTo<Stack | null>()).as('stack'))
.where('assets.ownerId', '=', anyUuid(options.userIds)) .where('asset.ownerId', '=', anyUuid(options.userIds))
.where('assets.visibility', '!=', AssetVisibility.HIDDEN) .where('asset.visibility', '!=', AssetVisibility.HIDDEN)
.where('assets.updatedAt', '>', options.updatedAfter) .where('asset.updatedAt', '>', options.updatedAfter)
.limit(options.limit) .limit(options.limit)
.execute(); .execute();
} }
@ -749,7 +747,7 @@ export class AssetRepository {
async upsertFile(file: Pick<Insertable<AssetFileTable>, 'assetId' | 'path' | 'type'>): Promise<void> { async upsertFile(file: Pick<Insertable<AssetFileTable>, 'assetId' | 'path' | 'type'>): Promise<void> {
const value = { ...file, assetId: asUuid(file.assetId) }; const value = { ...file, assetId: asUuid(file.assetId) };
await this.db await this.db
.insertInto('asset_files') .insertInto('asset_file')
.values(value) .values(value)
.onConflict((oc) => .onConflict((oc) =>
oc.columns(['assetId', 'type']).doUpdateSet((eb) => ({ oc.columns(['assetId', 'type']).doUpdateSet((eb) => ({
@ -766,7 +764,7 @@ export class AssetRepository {
const values = files.map((row) => ({ ...row, assetId: asUuid(row.assetId) })); const values = files.map((row) => ({ ...row, assetId: asUuid(row.assetId) }));
await this.db await this.db
.insertInto('asset_files') .insertInto('asset_file')
.values(values) .values(values)
.onConflict((oc) => .onConflict((oc) =>
oc.columns(['assetId', 'type']).doUpdateSet((eb) => ({ oc.columns(['assetId', 'type']).doUpdateSet((eb) => ({
@ -782,7 +780,7 @@ export class AssetRepository {
} }
await this.db await this.db
.deleteFrom('asset_files') .deleteFrom('asset_file')
.where('id', '=', anyUuid(files.map((file) => file.id))) .where('id', '=', anyUuid(files.map((file) => file.id)))
.execute(); .execute();
} }
@ -797,7 +795,7 @@ export class AssetRepository {
const exclusions = exclusionPatterns.map((pattern) => globToSqlPattern(pattern)); const exclusions = exclusionPatterns.map((pattern) => globToSqlPattern(pattern));
return this.db return this.db
.updateTable('assets') .updateTable('asset')
.set({ .set({
isOffline: true, isOffline: true,
deletedAt: new Date(), deletedAt: new Date(),
@ -823,9 +821,9 @@ export class AssetRepository {
eb.not( eb.not(
eb.exists( eb.exists(
this.db this.db
.selectFrom('assets') .selectFrom('asset')
.select('originalPath') .select('originalPath')
.whereRef('assets.originalPath', '=', eb.ref('path')) .whereRef('asset.originalPath', '=', eb.ref('path'))
.where('libraryId', '=', asUuid(libraryId)) .where('libraryId', '=', asUuid(libraryId))
.where('isExternal', '=', true), .where('isExternal', '=', true),
), ),
@ -838,7 +836,7 @@ export class AssetRepository {
async getLibraryAssetCount(libraryId: string): Promise<number> { async getLibraryAssetCount(libraryId: string): Promise<number> {
const { count } = await this.db const { count } = await this.db
.selectFrom('assets') .selectFrom('asset')
.select((eb) => eb.fn.countAll<number>().as('count')) .select((eb) => eb.fn.countAll<number>().as('count'))
.where('libraryId', '=', asUuid(libraryId)) .where('libraryId', '=', asUuid(libraryId))
.executeTakeFirstOrThrow(); .executeTakeFirstOrThrow();

View File

@ -7,34 +7,34 @@ import { anyUuid } from 'src/utils/database';
const builder = (db: Kysely<DB>) => const builder = (db: Kysely<DB>) =>
db db
.selectFrom('assets') .selectFrom('asset')
.innerJoin('exif', 'assetId', 'id') .innerJoin('asset_exif', 'assetId', 'id')
.select(['assets.id', 'assets.livePhotoVideoId', 'exif.fileSizeInByte as size']) .select(['asset.id', 'asset.livePhotoVideoId', 'asset_exif.fileSizeInByte as size'])
.where('assets.deletedAt', 'is', null); .where('asset.deletedAt', 'is', null);
@Injectable() @Injectable()
export class DownloadRepository { export class DownloadRepository {
constructor(@InjectKysely() private db: Kysely<DB>) {} constructor(@InjectKysely() private db: Kysely<DB>) {}
downloadAssetIds(ids: string[]) { downloadAssetIds(ids: string[]) {
return builder(this.db).where('assets.id', '=', anyUuid(ids)).stream(); return builder(this.db).where('asset.id', '=', anyUuid(ids)).stream();
} }
downloadMotionAssetIds(ids: string[]) { downloadMotionAssetIds(ids: string[]) {
return builder(this.db).select(['assets.originalPath']).where('assets.id', '=', anyUuid(ids)).stream(); return builder(this.db).select(['asset.originalPath']).where('asset.id', '=', anyUuid(ids)).stream();
} }
downloadAlbumId(albumId: string) { downloadAlbumId(albumId: string) {
return builder(this.db) return builder(this.db)
.innerJoin('albums_assets_assets', 'assets.id', 'albums_assets_assets.assetsId') .innerJoin('album_asset', 'asset.id', 'album_asset.assetsId')
.where('albums_assets_assets.albumsId', '=', albumId) .where('album_asset.albumsId', '=', albumId)
.stream(); .stream();
} }
downloadUserId(userId: string) { downloadUserId(userId: string) {
return builder(this.db) return builder(this.db)
.where('assets.ownerId', '=', userId) .where('asset.ownerId', '=', userId)
.where('assets.visibility', '!=', AssetVisibility.HIDDEN) .where('asset.visibility', '!=', AssetVisibility.HIDDEN)
.stream(); .stream();
} }
} }

View File

@ -32,28 +32,28 @@ export class DuplicateRepository {
this.db this.db
.with('duplicates', (qb) => .with('duplicates', (qb) =>
qb qb
.selectFrom('assets') .selectFrom('asset')
.$call(withDefaultVisibility) .$call(withDefaultVisibility)
.leftJoinLateral( .leftJoinLateral(
(qb) => (qb) =>
qb qb
.selectFrom('exif') .selectFrom('asset_exif')
.selectAll('assets') .selectAll('asset')
.select((eb) => eb.table('exif').as('exifInfo')) .select((eb) => eb.table('asset_exif').as('exifInfo'))
.whereRef('exif.assetId', '=', 'assets.id') .whereRef('asset_exif.assetId', '=', 'asset.id')
.as('asset'), .as('asset2'),
(join) => join.onTrue(), (join) => join.onTrue(),
) )
.select('assets.duplicateId') .select('asset.duplicateId')
.select((eb) => .select((eb) =>
eb.fn.jsonAgg('asset').orderBy('assets.localDateTime', 'asc').$castTo<MapAsset[]>().as('assets'), eb.fn.jsonAgg('asset2').orderBy('asset.localDateTime', 'asc').$castTo<MapAsset[]>().as('assets'),
) )
.where('assets.ownerId', '=', asUuid(userId)) .where('asset.ownerId', '=', asUuid(userId))
.where('assets.duplicateId', 'is not', null) .where('asset.duplicateId', 'is not', null)
.$narrowType<{ duplicateId: NotNull }>() .$narrowType<{ duplicateId: NotNull }>()
.where('assets.deletedAt', 'is', null) .where('asset.deletedAt', 'is', null)
.where('assets.stackId', 'is', null) .where('asset.stackId', 'is', null)
.groupBy('assets.duplicateId'), .groupBy('asset.duplicateId'),
) )
.with('unique', (qb) => .with('unique', (qb) =>
qb qb
@ -63,10 +63,10 @@ export class DuplicateRepository {
) )
.with('removed_unique', (qb) => .with('removed_unique', (qb) =>
qb qb
.updateTable('assets') .updateTable('asset')
.set({ duplicateId: null }) .set({ duplicateId: null })
.from('unique') .from('unique')
.whereRef('assets.duplicateId', '=', 'unique.duplicateId'), .whereRef('asset.duplicateId', '=', 'unique.duplicateId'),
) )
.selectFrom('duplicates') .selectFrom('duplicates')
.selectAll() .selectAll()
@ -81,7 +81,7 @@ export class DuplicateRepository {
@GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID] }) @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID] })
async delete(userId: string, id: string): Promise<void> { async delete(userId: string, id: string): Promise<void> {
await this.db await this.db
.updateTable('assets') .updateTable('asset')
.set({ duplicateId: null }) .set({ duplicateId: null })
.where('ownerId', '=', userId) .where('ownerId', '=', userId)
.where('duplicateId', '=', id) .where('duplicateId', '=', id)
@ -96,7 +96,7 @@ export class DuplicateRepository {
} }
await this.db await this.db
.updateTable('assets') .updateTable('asset')
.set({ duplicateId: null }) .set({ duplicateId: null })
.where('ownerId', '=', userId) .where('ownerId', '=', userId)
.where('duplicateId', 'in', ids) .where('duplicateId', 'in', ids)
@ -120,19 +120,19 @@ export class DuplicateRepository {
return await trx return await trx
.with('cte', (qb) => .with('cte', (qb) =>
qb qb
.selectFrom('assets') .selectFrom('asset')
.$call(withDefaultVisibility) .$call(withDefaultVisibility)
.select([ .select([
'assets.id as assetId', 'asset.id as assetId',
'assets.duplicateId', 'asset.duplicateId',
sql<number>`smart_search.embedding <=> ${embedding}`.as('distance'), sql<number>`smart_search.embedding <=> ${embedding}`.as('distance'),
]) ])
.innerJoin('smart_search', 'assets.id', 'smart_search.assetId') .innerJoin('smart_search', 'asset.id', 'smart_search.assetId')
.where('assets.ownerId', '=', anyUuid(userIds)) .where('asset.ownerId', '=', anyUuid(userIds))
.where('assets.deletedAt', 'is', null) .where('asset.deletedAt', 'is', null)
.where('assets.type', '=', type) .where('asset.type', '=', type)
.where('assets.id', '!=', asUuid(assetId)) .where('asset.id', '!=', asUuid(assetId))
.where('assets.stackId', 'is', null) .where('asset.stackId', 'is', null)
.orderBy('distance') .orderBy('distance')
.limit(64), .limit(64),
) )
@ -148,7 +148,7 @@ export class DuplicateRepository {
}) })
async merge(options: DuplicateMergeOptions): Promise<void> { async merge(options: DuplicateMergeOptions): Promise<void> {
await this.db await this.db
.updateTable('assets') .updateTable('asset')
.set({ duplicateId: options.targetId }) .set({ duplicateId: options.targetId })
.where((eb) => .where((eb) =>
eb.or([eb('duplicateId', '=', anyUuid(options.sourceIds)), eb('id', '=', anyUuid(options.assetIds))]), eb.or([eb('duplicateId', '=', anyUuid(options.sourceIds)), eb('id', '=', anyUuid(options.assetIds))]),

View File

@ -21,50 +21,50 @@ export class LibraryRepository {
@GenerateSql({ params: [DummyValue.UUID] }) @GenerateSql({ params: [DummyValue.UUID] })
get(id: string, withDeleted = false) { get(id: string, withDeleted = false) {
return this.db return this.db
.selectFrom('libraries') .selectFrom('library')
.selectAll('libraries') .selectAll('library')
.where('libraries.id', '=', id) .where('library.id', '=', id)
.$if(!withDeleted, (qb) => qb.where('libraries.deletedAt', 'is', null)) .$if(!withDeleted, (qb) => qb.where('library.deletedAt', 'is', null))
.executeTakeFirst(); .executeTakeFirst();
} }
@GenerateSql({ params: [] }) @GenerateSql({ params: [] })
getAll(withDeleted = false) { getAll(withDeleted = false) {
return this.db return this.db
.selectFrom('libraries') .selectFrom('library')
.selectAll('libraries') .selectAll('library')
.orderBy('createdAt', 'asc') .orderBy('createdAt', 'asc')
.$if(!withDeleted, (qb) => qb.where('libraries.deletedAt', 'is', null)) .$if(!withDeleted, (qb) => qb.where('library.deletedAt', 'is', null))
.execute(); .execute();
} }
@GenerateSql() @GenerateSql()
getAllDeleted() { getAllDeleted() {
return this.db return this.db
.selectFrom('libraries') .selectFrom('library')
.selectAll('libraries') .selectAll('library')
.where('libraries.deletedAt', 'is not', null) .where('library.deletedAt', 'is not', null)
.orderBy('createdAt', 'asc') .orderBy('createdAt', 'asc')
.execute(); .execute();
} }
create(library: Insertable<LibraryTable>) { create(library: Insertable<LibraryTable>) {
return this.db.insertInto('libraries').values(library).returningAll().executeTakeFirstOrThrow(); return this.db.insertInto('library').values(library).returningAll().executeTakeFirstOrThrow();
} }
async delete(id: string) { async delete(id: string) {
await this.db.deleteFrom('libraries').where('libraries.id', '=', id).execute(); await this.db.deleteFrom('library').where('library.id', '=', id).execute();
} }
async softDelete(id: string) { async softDelete(id: string) {
await this.db.updateTable('libraries').set({ deletedAt: new Date() }).where('libraries.id', '=', id).execute(); await this.db.updateTable('library').set({ deletedAt: new Date() }).where('library.id', '=', id).execute();
} }
update(id: string, library: Updateable<LibraryTable>) { update(id: string, library: Updateable<LibraryTable>) {
return this.db return this.db
.updateTable('libraries') .updateTable('library')
.set(library) .set(library)
.where('libraries.id', '=', id) .where('library.id', '=', id)
.returningAll() .returningAll()
.executeTakeFirstOrThrow(); .executeTakeFirstOrThrow();
} }
@ -72,14 +72,14 @@ export class LibraryRepository {
@GenerateSql({ params: [DummyValue.UUID] }) @GenerateSql({ params: [DummyValue.UUID] })
async getStatistics(id: string): Promise<LibraryStatsResponseDto | undefined> { async getStatistics(id: string): Promise<LibraryStatsResponseDto | undefined> {
const stats = await this.db const stats = await this.db
.selectFrom('libraries') .selectFrom('library')
.innerJoin('assets', 'assets.libraryId', 'libraries.id') .innerJoin('asset', 'asset.libraryId', 'library.id')
.leftJoin('exif', 'exif.assetId', 'assets.id') .leftJoin('asset_exif', 'asset_exif.assetId', 'asset.id')
.select((eb) => .select((eb) =>
eb.fn eb.fn
.countAll<number>() .countAll<number>()
.filterWhere((eb) => .filterWhere((eb) =>
eb.and([eb('assets.type', '=', AssetType.IMAGE), eb('assets.visibility', '!=', AssetVisibility.HIDDEN)]), eb.and([eb('asset.type', '=', AssetType.IMAGE), eb('asset.visibility', '!=', AssetVisibility.HIDDEN)]),
) )
.as('photos'), .as('photos'),
) )
@ -87,25 +87,25 @@ export class LibraryRepository {
eb.fn eb.fn
.countAll<number>() .countAll<number>()
.filterWhere((eb) => .filterWhere((eb) =>
eb.and([eb('assets.type', '=', AssetType.VIDEO), eb('assets.visibility', '!=', AssetVisibility.HIDDEN)]), eb.and([eb('asset.type', '=', AssetType.VIDEO), eb('asset.visibility', '!=', AssetVisibility.HIDDEN)]),
) )
.as('videos'), .as('videos'),
) )
.select((eb) => eb.fn.coalesce((eb) => eb.fn.sum('exif.fileSizeInByte'), eb.val(0)).as('usage')) .select((eb) => eb.fn.coalesce((eb) => eb.fn.sum('asset_exif.fileSizeInByte'), eb.val(0)).as('usage'))
.groupBy('libraries.id') .groupBy('library.id')
.where('libraries.id', '=', id) .where('library.id', '=', id)
.executeTakeFirst(); .executeTakeFirst();
// possibly a new library with 0 assets // possibly a new library with 0 assets
if (!stats) { if (!stats) {
const zero = sql<number>`0::int`; const zero = sql<number>`0::int`;
return this.db return this.db
.selectFrom('libraries') .selectFrom('library')
.select(zero.as('photos')) .select(zero.as('photos'))
.select(zero.as('videos')) .select(zero.as('videos'))
.select(zero.as('usage')) .select(zero.as('usage'))
.select(zero.as('total')) .select(zero.as('total'))
.where('libraries.id', '=', id) .where('library.id', '=', id)
.executeTakeFirst(); .executeTakeFirst();
} }
@ -118,6 +118,6 @@ export class LibraryRepository {
} }
streamAssetIds(libraryId: string) { streamAssetIds(libraryId: string) {
return this.db.selectFrom('assets').select(['id']).where('libraryId', '=', libraryId).stream(); return this.db.selectFrom('asset').select(['id']).where('libraryId', '=', libraryId).stream();
} }
} }

View File

@ -83,25 +83,32 @@ export class MapRepository {
{ isArchived, isFavorite, fileCreatedAfter, fileCreatedBefore }: MapMarkerSearchOptions = {}, { isArchived, isFavorite, fileCreatedAfter, fileCreatedBefore }: MapMarkerSearchOptions = {},
) { ) {
return this.db return this.db
.selectFrom('assets') .selectFrom('asset')
.innerJoin('exif', (builder) => .innerJoin('asset_exif', (builder) =>
builder builder
.onRef('assets.id', '=', 'exif.assetId') .onRef('asset.id', '=', 'asset_exif.assetId')
.on('exif.latitude', 'is not', null) .on('asset_exif.latitude', 'is not', null)
.on('exif.longitude', 'is not', null), .on('asset_exif.longitude', 'is not', null),
) )
.select(['id', 'exif.latitude as lat', 'exif.longitude as lon', 'exif.city', 'exif.state', 'exif.country']) .select([
'id',
'asset_exif.latitude as lat',
'asset_exif.longitude as lon',
'asset_exif.city',
'asset_exif.state',
'asset_exif.country',
])
.$narrowType<{ lat: NotNull; lon: NotNull }>() .$narrowType<{ lat: NotNull; lon: NotNull }>()
.$if(isArchived === true, (qb) => .$if(isArchived === true, (qb) =>
qb.where((eb) => qb.where((eb) =>
eb.or([ eb.or([
eb('assets.visibility', '=', AssetVisibility.TIMELINE), eb('asset.visibility', '=', AssetVisibility.TIMELINE),
eb('assets.visibility', '=', AssetVisibility.ARCHIVE), eb('asset.visibility', '=', AssetVisibility.ARCHIVE),
]), ]),
), ),
) )
.$if(isArchived === false || isArchived === undefined, (qb) => .$if(isArchived === false || isArchived === undefined, (qb) =>
qb.where('assets.visibility', '=', AssetVisibility.TIMELINE), qb.where('asset.visibility', '=', AssetVisibility.TIMELINE),
) )
.$if(isFavorite !== undefined, (q) => q.where('isFavorite', '=', isFavorite!)) .$if(isFavorite !== undefined, (q) => q.where('isFavorite', '=', isFavorite!))
.$if(fileCreatedAfter !== undefined, (q) => q.where('fileCreatedAt', '>=', fileCreatedAfter!)) .$if(fileCreatedAfter !== undefined, (q) => q.where('fileCreatedAt', '>=', fileCreatedAfter!))
@ -118,9 +125,9 @@ export class MapRepository {
expression.push( expression.push(
eb.exists((eb) => eb.exists((eb) =>
eb eb
.selectFrom('albums_assets_assets') .selectFrom('album_asset')
.whereRef('assets.id', '=', 'albums_assets_assets.assetsId') .whereRef('asset.id', '=', 'album_asset.assetsId')
.where('albums_assets_assets.albumsId', 'in', albumIds), .where('album_asset.albumsId', 'in', albumIds),
), ),
); );
} }

View File

@ -16,14 +16,14 @@ export class MemoryRepository implements IBulkAsset {
async cleanup() { async cleanup() {
await this.db await this.db
.deleteFrom('memories_assets_assets') .deleteFrom('memory_asset')
.using('assets') .using('asset')
.whereRef('memories_assets_assets.assetsId', '=', 'assets.id') .whereRef('memory_asset.assetsId', '=', 'asset.id')
.where('assets.visibility', '!=', AssetVisibility.TIMELINE) .where('asset.visibility', '!=', AssetVisibility.TIMELINE)
.execute(); .execute();
return this.db return this.db
.deleteFrom('memories') .deleteFrom('memory')
.where('createdAt', '<', DateTime.now().minus({ days: 30 }).toJSDate()) .where('createdAt', '<', DateTime.now().minus({ days: 30 }).toJSDate())
.where('isSaved', '=', false) .where('isSaved', '=', false)
.execute(); .execute();
@ -31,7 +31,7 @@ export class MemoryRepository implements IBulkAsset {
searchBuilder(ownerId: string, dto: MemorySearchDto) { searchBuilder(ownerId: string, dto: MemorySearchDto) {
return this.db return this.db
.selectFrom('memories') .selectFrom('memory')
.$if(dto.isSaved !== undefined, (qb) => qb.where('isSaved', '=', dto.isSaved!)) .$if(dto.isSaved !== undefined, (qb) => qb.where('isSaved', '=', dto.isSaved!))
.$if(dto.type !== undefined, (qb) => qb.where('type', '=', dto.type!)) .$if(dto.type !== undefined, (qb) => qb.where('type', '=', dto.type!))
.$if(dto.for !== undefined, (qb) => .$if(dto.for !== undefined, (qb) =>
@ -62,16 +62,16 @@ export class MemoryRepository implements IBulkAsset {
.select((eb) => .select((eb) =>
jsonArrayFrom( jsonArrayFrom(
eb eb
.selectFrom('assets') .selectFrom('asset')
.selectAll('assets') .selectAll('asset')
.innerJoin('memories_assets_assets', 'assets.id', 'memories_assets_assets.assetsId') .innerJoin('memory_asset', 'asset.id', 'memory_asset.assetsId')
.whereRef('memories_assets_assets.memoriesId', '=', 'memories.id') .whereRef('memory_asset.memoriesId', '=', 'memory.id')
.orderBy('assets.fileCreatedAt', 'asc') .orderBy('asset.fileCreatedAt', 'asc')
.where('assets.visibility', '=', sql.lit(AssetVisibility.TIMELINE)) .where('asset.visibility', '=', sql.lit(AssetVisibility.TIMELINE))
.where('assets.deletedAt', 'is', null), .where('asset.deletedAt', 'is', null),
).as('assets'), ).as('assets'),
) )
.selectAll('memories') .selectAll('memory')
.orderBy('memoryAt', 'desc') .orderBy('memoryAt', 'desc')
.execute(); .execute();
} }
@ -83,11 +83,11 @@ export class MemoryRepository implements IBulkAsset {
async create(memory: Insertable<MemoryTable>, assetIds: Set<string>) { async create(memory: Insertable<MemoryTable>, assetIds: Set<string>) {
const id = await this.db.transaction().execute(async (tx) => { const id = await this.db.transaction().execute(async (tx) => {
const { id } = await tx.insertInto('memories').values(memory).returning('id').executeTakeFirstOrThrow(); const { id } = await tx.insertInto('memory').values(memory).returning('id').executeTakeFirstOrThrow();
if (assetIds.size > 0) { if (assetIds.size > 0) {
const values = [...assetIds].map((assetId) => ({ memoriesId: id, assetsId: assetId })); const values = [...assetIds].map((assetId) => ({ memoriesId: id, assetsId: assetId }));
await tx.insertInto('memories_assets_assets').values(values).execute(); await tx.insertInto('memory_asset').values(values).execute();
} }
return id; return id;
@ -98,13 +98,13 @@ export class MemoryRepository implements IBulkAsset {
@GenerateSql({ params: [DummyValue.UUID, { ownerId: DummyValue.UUID, isSaved: true }] }) @GenerateSql({ params: [DummyValue.UUID, { ownerId: DummyValue.UUID, isSaved: true }] })
async update(id: string, memory: Updateable<MemoryTable>) { async update(id: string, memory: Updateable<MemoryTable>) {
await this.db.updateTable('memories').set(memory).where('id', '=', id).execute(); await this.db.updateTable('memory').set(memory).where('id', '=', id).execute();
return this.getByIdBuilder(id).executeTakeFirstOrThrow(); return this.getByIdBuilder(id).executeTakeFirstOrThrow();
} }
@GenerateSql({ params: [DummyValue.UUID] }) @GenerateSql({ params: [DummyValue.UUID] })
async delete(id: string) { async delete(id: string) {
await this.db.deleteFrom('memories').where('id', '=', id).execute(); await this.db.deleteFrom('memory').where('id', '=', id).execute();
} }
@GenerateSql({ params: [DummyValue.UUID, [DummyValue.UUID]] }) @GenerateSql({ params: [DummyValue.UUID, [DummyValue.UUID]] })
@ -115,7 +115,7 @@ export class MemoryRepository implements IBulkAsset {
} }
const results = await this.db const results = await this.db
.selectFrom('memories_assets_assets') .selectFrom('memory_asset')
.select(['assetsId']) .select(['assetsId'])
.where('memoriesId', '=', id) .where('memoriesId', '=', id)
.where('assetsId', 'in', assetIds) .where('assetsId', 'in', assetIds)
@ -131,7 +131,7 @@ export class MemoryRepository implements IBulkAsset {
} }
await this.db await this.db
.insertInto('memories_assets_assets') .insertInto('memory_asset')
.values(assetIds.map((assetId) => ({ memoriesId: id, assetsId: assetId }))) .values(assetIds.map((assetId) => ({ memoriesId: id, assetsId: assetId })))
.execute(); .execute();
} }
@ -143,27 +143,23 @@ export class MemoryRepository implements IBulkAsset {
return; return;
} }
await this.db await this.db.deleteFrom('memory_asset').where('memoriesId', '=', id).where('assetsId', 'in', assetIds).execute();
.deleteFrom('memories_assets_assets')
.where('memoriesId', '=', id)
.where('assetsId', 'in', assetIds)
.execute();
} }
private getByIdBuilder(id: string) { private getByIdBuilder(id: string) {
return this.db return this.db
.selectFrom('memories') .selectFrom('memory')
.selectAll('memories') .selectAll('memory')
.select((eb) => .select((eb) =>
jsonArrayFrom( jsonArrayFrom(
eb eb
.selectFrom('assets') .selectFrom('asset')
.selectAll('assets') .selectAll('asset')
.innerJoin('memories_assets_assets', 'assets.id', 'memories_assets_assets.assetsId') .innerJoin('memory_asset', 'asset.id', 'memory_asset.assetsId')
.whereRef('memories_assets_assets.memoriesId', '=', 'memories.id') .whereRef('memory_asset.memoriesId', '=', 'memory.id')
.orderBy('assets.fileCreatedAt', 'asc') .orderBy('asset.fileCreatedAt', 'asc')
.where('assets.visibility', '=', sql.lit(AssetVisibility.TIMELINE)) .where('asset.visibility', '=', sql.lit(AssetVisibility.TIMELINE))
.where('assets.deletedAt', 'is', null), .where('asset.deletedAt', 'is', null),
).as('assets'), ).as('assets'),
) )
.where('id', '=', id) .where('id', '=', id)

View File

@ -45,7 +45,7 @@ export class MoveRepository {
eb( eb(
'move_history.entityId', 'move_history.entityId',
'not in', 'not in',
eb.selectFrom('assets').select('id').whereRef('assets.id', '=', 'move_history.entityId'), eb.selectFrom('asset').select('id').whereRef('asset.id', '=', 'move_history.entityId'),
), ),
) )
.where('move_history.pathType', '=', sql.lit(AssetPathType.ORIGINAL)) .where('move_history.pathType', '=', sql.lit(AssetPathType.ORIGINAL))

View File

@ -12,7 +12,7 @@ export class NotificationRepository {
cleanup() { cleanup() {
return this.db return this.db
.deleteFrom('notifications') .deleteFrom('notification')
.where((eb) => .where((eb) =>
eb.or([ eb.or([
// remove soft-deleted notifications // remove soft-deleted notifications
@ -38,7 +38,7 @@ export class NotificationRepository {
@GenerateSql({ params: [DummyValue.UUID, {}] }, { name: 'unread', params: [DummyValue.UUID, { unread: true }] }) @GenerateSql({ params: [DummyValue.UUID, {}] }, { name: 'unread', params: [DummyValue.UUID, { unread: true }] })
search(userId: string, dto: NotificationSearchDto) { search(userId: string, dto: NotificationSearchDto) {
return this.db return this.db
.selectFrom('notifications') .selectFrom('notification')
.select(columns.notification) .select(columns.notification)
.where((qb) => .where((qb) =>
qb.and({ qb.and({
@ -56,7 +56,7 @@ export class NotificationRepository {
create(notification: Insertable<NotificationTable>) { create(notification: Insertable<NotificationTable>) {
return this.db return this.db
.insertInto('notifications') .insertInto('notification')
.values(notification) .values(notification)
.returning(columns.notification) .returning(columns.notification)
.executeTakeFirstOrThrow(); .executeTakeFirstOrThrow();
@ -64,7 +64,7 @@ export class NotificationRepository {
get(id: string) { get(id: string) {
return this.db return this.db
.selectFrom('notifications') .selectFrom('notification')
.select(columns.notification) .select(columns.notification)
.where('id', '=', id) .where('id', '=', id)
.where('deletedAt', 'is not', null) .where('deletedAt', 'is not', null)
@ -73,7 +73,7 @@ export class NotificationRepository {
update(id: string, notification: Updateable<NotificationTable>) { update(id: string, notification: Updateable<NotificationTable>) {
return this.db return this.db
.updateTable('notifications') .updateTable('notification')
.set(notification) .set(notification)
.where('deletedAt', 'is', null) .where('deletedAt', 'is', null)
.where('id', '=', id) .where('id', '=', id)
@ -82,12 +82,12 @@ export class NotificationRepository {
} }
async updateAll(ids: string[], notification: Updateable<NotificationTable>) { async updateAll(ids: string[], notification: Updateable<NotificationTable>) {
await this.db.updateTable('notifications').set(notification).where('id', 'in', ids).execute(); await this.db.updateTable('notification').set(notification).where('id', 'in', ids).execute();
} }
async delete(id: string) { async delete(id: string) {
await this.db await this.db
.updateTable('notifications') .updateTable('notification')
.set({ deletedAt: DateTime.now().toJSDate() }) .set({ deletedAt: DateTime.now().toJSDate() })
.where('id', '=', id) .where('id', '=', id)
.execute(); .execute();
@ -95,7 +95,7 @@ export class NotificationRepository {
async deleteAll(ids: string[]) { async deleteAll(ids: string[]) {
await this.db await this.db
.updateTable('notifications') .updateTable('notification')
.set({ deletedAt: DateTime.now().toJSDate() }) .set({ deletedAt: DateTime.now().toJSDate() })
.where('id', 'in', ids) .where('id', 'in', ids)
.execute(); .execute();

View File

@ -17,15 +17,15 @@ export enum PartnerDirection {
SharedWith = 'shared-with', SharedWith = 'shared-with',
} }
const withSharedBy = (eb: ExpressionBuilder<DB, 'partners'>) => { const withSharedBy = (eb: ExpressionBuilder<DB, 'partner'>) => {
return jsonObjectFrom( return jsonObjectFrom(
eb.selectFrom('users as sharedBy').select(columns.user).whereRef('sharedBy.id', '=', 'partners.sharedById'), eb.selectFrom('user as sharedBy').select(columns.user).whereRef('sharedBy.id', '=', 'partner.sharedById'),
).as('sharedBy'); ).as('sharedBy');
}; };
const withSharedWith = (eb: ExpressionBuilder<DB, 'partners'>) => { const withSharedWith = (eb: ExpressionBuilder<DB, 'partner'>) => {
return jsonObjectFrom( return jsonObjectFrom(
eb.selectFrom('users as sharedWith').select(columns.user).whereRef('sharedWith.id', '=', 'partners.sharedWithId'), eb.selectFrom('user as sharedWith').select(columns.user).whereRef('sharedWith.id', '=', 'partner.sharedWithId'),
).as('sharedWith'); ).as('sharedWith');
}; };
@ -50,7 +50,7 @@ export class PartnerRepository {
create(values: Insertable<PartnerTable>) { create(values: Insertable<PartnerTable>) {
return this.db return this.db
.insertInto('partners') .insertInto('partner')
.values(values) .values(values)
.returningAll() .returningAll()
.returning(withSharedBy) .returning(withSharedBy)
@ -62,7 +62,7 @@ export class PartnerRepository {
@GenerateSql({ params: [{ sharedWithId: DummyValue.UUID, sharedById: DummyValue.UUID }, { inTimeline: true }] }) @GenerateSql({ params: [{ sharedWithId: DummyValue.UUID, sharedById: DummyValue.UUID }, { inTimeline: true }] })
update({ sharedWithId, sharedById }: PartnerIds, values: Updateable<PartnerTable>) { update({ sharedWithId, sharedById }: PartnerIds, values: Updateable<PartnerTable>) {
return this.db return this.db
.updateTable('partners') .updateTable('partner')
.set(values) .set(values)
.where('sharedWithId', '=', sharedWithId) .where('sharedWithId', '=', sharedWithId)
.where('sharedById', '=', sharedById) .where('sharedById', '=', sharedById)
@ -76,7 +76,7 @@ export class PartnerRepository {
@GenerateSql({ params: [{ sharedWithId: DummyValue.UUID, sharedById: DummyValue.UUID }] }) @GenerateSql({ params: [{ sharedWithId: DummyValue.UUID, sharedById: DummyValue.UUID }] })
async remove({ sharedWithId, sharedById }: PartnerIds) { async remove({ sharedWithId, sharedById }: PartnerIds) {
await this.db await this.db
.deleteFrom('partners') .deleteFrom('partner')
.where('sharedWithId', '=', sharedWithId) .where('sharedWithId', '=', sharedWithId)
.where('sharedById', '=', sharedById) .where('sharedById', '=', sharedById)
.execute(); .execute();
@ -84,14 +84,14 @@ export class PartnerRepository {
private builder() { private builder() {
return this.db return this.db
.selectFrom('partners') .selectFrom('partner')
.innerJoin('users as sharedBy', (join) => .innerJoin('user as sharedBy', (join) =>
join.onRef('partners.sharedById', '=', 'sharedBy.id').on('sharedBy.deletedAt', 'is', null), join.onRef('partner.sharedById', '=', 'sharedBy.id').on('sharedBy.deletedAt', 'is', null),
) )
.innerJoin('users as sharedWith', (join) => .innerJoin('user as sharedWith', (join) =>
join.onRef('partners.sharedWithId', '=', 'sharedWith.id').on('sharedWith.deletedAt', 'is', null), join.onRef('partner.sharedWithId', '=', 'sharedWith.id').on('sharedWith.deletedAt', 'is', null),
) )
.selectAll('partners') .selectAll('partner')
.select(withSharedBy) .select(withSharedBy)
.select(withSharedWith); .select(withSharedWith);
} }

View File

@ -62,21 +62,21 @@ export type UnassignFacesOptions = DeleteFacesOptions;
export type SelectFaceOptions = (keyof Selectable<AssetFaceTable>)[]; export type SelectFaceOptions = (keyof Selectable<AssetFaceTable>)[];
const withPerson = (eb: ExpressionBuilder<DB, 'asset_faces'>) => { const withPerson = (eb: ExpressionBuilder<DB, 'asset_face'>) => {
return jsonObjectFrom( return jsonObjectFrom(
eb.selectFrom('person').selectAll('person').whereRef('person.id', '=', 'asset_faces.personId'), eb.selectFrom('person').selectAll('person').whereRef('person.id', '=', 'asset_face.personId'),
).as('person'); ).as('person');
}; };
const withAsset = (eb: ExpressionBuilder<DB, 'asset_faces'>) => { const withAsset = (eb: ExpressionBuilder<DB, 'asset_face'>) => {
return jsonObjectFrom( return jsonObjectFrom(eb.selectFrom('asset').selectAll('asset').whereRef('asset.id', '=', 'asset_face.assetId')).as(
eb.selectFrom('assets').selectAll('assets').whereRef('assets.id', '=', 'asset_faces.assetId'), 'asset',
).as('asset'); );
}; };
const withFaceSearch = (eb: ExpressionBuilder<DB, 'asset_faces'>) => { const withFaceSearch = (eb: ExpressionBuilder<DB, 'asset_face'>) => {
return jsonObjectFrom( return jsonObjectFrom(
eb.selectFrom('face_search').selectAll('face_search').whereRef('face_search.faceId', '=', 'asset_faces.id'), eb.selectFrom('face_search').selectAll('face_search').whereRef('face_search.faceId', '=', 'asset_face.id'),
).as('faceSearch'); ).as('faceSearch');
}; };
@ -87,10 +87,10 @@ export class PersonRepository {
@GenerateSql({ params: [{ oldPersonId: DummyValue.UUID, newPersonId: DummyValue.UUID }] }) @GenerateSql({ params: [{ oldPersonId: DummyValue.UUID, newPersonId: DummyValue.UUID }] })
async reassignFaces({ oldPersonId, faceIds, newPersonId }: UpdateFacesData): Promise<number> { async reassignFaces({ oldPersonId, faceIds, newPersonId }: UpdateFacesData): Promise<number> {
const result = await this.db const result = await this.db
.updateTable('asset_faces') .updateTable('asset_face')
.set({ personId: newPersonId }) .set({ personId: newPersonId })
.$if(!!oldPersonId, (qb) => qb.where('asset_faces.personId', '=', oldPersonId!)) .$if(!!oldPersonId, (qb) => qb.where('asset_face.personId', '=', oldPersonId!))
.$if(!!faceIds, (qb) => qb.where('asset_faces.id', 'in', faceIds!)) .$if(!!faceIds, (qb) => qb.where('asset_face.id', 'in', faceIds!))
.executeTakeFirst(); .executeTakeFirst();
return Number(result.numChangedRows ?? 0); return Number(result.numChangedRows ?? 0);
@ -98,9 +98,9 @@ export class PersonRepository {
async unassignFaces({ sourceType }: UnassignFacesOptions): Promise<void> { async unassignFaces({ sourceType }: UnassignFacesOptions): Promise<void> {
await this.db await this.db
.updateTable('asset_faces') .updateTable('asset_face')
.set({ personId: null }) .set({ personId: null })
.where('asset_faces.sourceType', '=', sourceType) .where('asset_face.sourceType', '=', sourceType)
.execute(); .execute();
} }
@ -115,18 +115,18 @@ export class PersonRepository {
} }
async deleteFaces({ sourceType }: DeleteFacesOptions): Promise<void> { async deleteFaces({ sourceType }: DeleteFacesOptions): Promise<void> {
await this.db.deleteFrom('asset_faces').where('asset_faces.sourceType', '=', sourceType).execute(); await this.db.deleteFrom('asset_face').where('asset_face.sourceType', '=', sourceType).execute();
} }
getAllFaces(options: GetAllFacesOptions = {}) { getAllFaces(options: GetAllFacesOptions = {}) {
return this.db return this.db
.selectFrom('asset_faces') .selectFrom('asset_face')
.selectAll('asset_faces') .selectAll('asset_face')
.$if(options.personId === null, (qb) => qb.where('asset_faces.personId', 'is', null)) .$if(options.personId === null, (qb) => qb.where('asset_face.personId', 'is', null))
.$if(!!options.personId, (qb) => qb.where('asset_faces.personId', '=', options.personId!)) .$if(!!options.personId, (qb) => qb.where('asset_face.personId', '=', options.personId!))
.$if(!!options.sourceType, (qb) => qb.where('asset_faces.sourceType', '=', options.sourceType!)) .$if(!!options.sourceType, (qb) => qb.where('asset_face.sourceType', '=', options.sourceType!))
.$if(!!options.assetId, (qb) => qb.where('asset_faces.assetId', '=', options.assetId!)) .$if(!!options.assetId, (qb) => qb.where('asset_face.assetId', '=', options.assetId!))
.where('asset_faces.deletedAt', 'is', null) .where('asset_face.deletedAt', 'is', null)
.stream(); .stream();
} }
@ -147,21 +147,21 @@ export class PersonRepository {
const items = await this.db const items = await this.db
.selectFrom('person') .selectFrom('person')
.selectAll('person') .selectAll('person')
.innerJoin('asset_faces', 'asset_faces.personId', 'person.id') .innerJoin('asset_face', 'asset_face.personId', 'person.id')
.innerJoin('assets', (join) => .innerJoin('asset', (join) =>
join join
.onRef('asset_faces.assetId', '=', 'assets.id') .onRef('asset_face.assetId', '=', 'asset.id')
.on('assets.visibility', '=', sql.lit(AssetVisibility.TIMELINE)) .on('asset.visibility', '=', sql.lit(AssetVisibility.TIMELINE))
.on('assets.deletedAt', 'is', null), .on('asset.deletedAt', 'is', null),
) )
.where('person.ownerId', '=', userId) .where('person.ownerId', '=', userId)
.where('asset_faces.deletedAt', 'is', null) .where('asset_face.deletedAt', 'is', null)
.orderBy('person.isHidden', 'asc') .orderBy('person.isHidden', 'asc')
.orderBy('person.isFavorite', 'desc') .orderBy('person.isFavorite', 'desc')
.having((eb) => .having((eb) =>
eb.or([ eb.or([
eb('person.name', '!=', ''), eb('person.name', '!=', ''),
eb((innerEb) => innerEb.fn.count('asset_faces.assetId'), '>=', options?.minimumFaceCount || 1), eb((innerEb) => innerEb.fn.count('asset_face.assetId'), '>=', options?.minimumFaceCount || 1),
]), ]),
) )
.groupBy('person.id') .groupBy('person.id')
@ -185,7 +185,7 @@ export class PersonRepository {
.$if(!options?.closestFaceAssetId, (qb) => .$if(!options?.closestFaceAssetId, (qb) =>
qb qb
.orderBy(sql`NULLIF(person.name, '') is null`, 'asc') .orderBy(sql`NULLIF(person.name, '') is null`, 'asc')
.orderBy((eb) => eb.fn.count('asset_faces.assetId'), 'desc') .orderBy((eb) => eb.fn.count('asset_face.assetId'), 'desc')
.orderBy(sql`NULLIF(person.name, '')`, (om) => om.asc().nullsLast()) .orderBy(sql`NULLIF(person.name, '')`, (om) => om.asc().nullsLast())
.orderBy('person.createdAt'), .orderBy('person.createdAt'),
) )
@ -202,9 +202,9 @@ export class PersonRepository {
return this.db return this.db
.selectFrom('person') .selectFrom('person')
.selectAll('person') .selectAll('person')
.leftJoin('asset_faces', 'asset_faces.personId', 'person.id') .leftJoin('asset_face', 'asset_face.personId', 'person.id')
.where('asset_faces.deletedAt', 'is', null) .where('asset_face.deletedAt', 'is', null)
.having((eb) => eb.fn.count('asset_faces.assetId'), '=', 0) .having((eb) => eb.fn.count('asset_face.assetId'), '=', 0)
.groupBy('person.id') .groupBy('person.id')
.execute(); .execute();
} }
@ -212,12 +212,12 @@ export class PersonRepository {
@GenerateSql({ params: [DummyValue.UUID] }) @GenerateSql({ params: [DummyValue.UUID] })
getFaces(assetId: string) { getFaces(assetId: string) {
return this.db return this.db
.selectFrom('asset_faces') .selectFrom('asset_face')
.selectAll('asset_faces') .selectAll('asset_face')
.select(withPerson) .select(withPerson)
.where('asset_faces.assetId', '=', assetId) .where('asset_face.assetId', '=', assetId)
.where('asset_faces.deletedAt', 'is', null) .where('asset_face.deletedAt', 'is', null)
.orderBy('asset_faces.boundingBoxX1', 'asc') .orderBy('asset_face.boundingBoxX1', 'asc')
.execute(); .execute();
} }
@ -225,30 +225,30 @@ export class PersonRepository {
getFaceById(id: string) { getFaceById(id: string) {
// TODO return null instead of find or fail // TODO return null instead of find or fail
return this.db return this.db
.selectFrom('asset_faces') .selectFrom('asset_face')
.selectAll('asset_faces') .selectAll('asset_face')
.select(withPerson) .select(withPerson)
.where('asset_faces.id', '=', id) .where('asset_face.id', '=', id)
.where('asset_faces.deletedAt', 'is', null) .where('asset_face.deletedAt', 'is', null)
.executeTakeFirstOrThrow(); .executeTakeFirstOrThrow();
} }
@GenerateSql({ params: [DummyValue.UUID] }) @GenerateSql({ params: [DummyValue.UUID] })
getFaceForFacialRecognitionJob(id: string) { getFaceForFacialRecognitionJob(id: string) {
return this.db return this.db
.selectFrom('asset_faces') .selectFrom('asset_face')
.select(['asset_faces.id', 'asset_faces.personId', 'asset_faces.sourceType']) .select(['asset_face.id', 'asset_face.personId', 'asset_face.sourceType'])
.select((eb) => .select((eb) =>
jsonObjectFrom( jsonObjectFrom(
eb eb
.selectFrom('assets') .selectFrom('asset')
.select(['assets.ownerId', 'assets.visibility', 'assets.fileCreatedAt']) .select(['asset.ownerId', 'asset.visibility', 'asset.fileCreatedAt'])
.whereRef('assets.id', '=', 'asset_faces.assetId'), .whereRef('asset.id', '=', 'asset_face.assetId'),
).as('asset'), ).as('asset'),
) )
.select(withFaceSearch) .select(withFaceSearch)
.where('asset_faces.id', '=', id) .where('asset_face.id', '=', id)
.where('asset_faces.deletedAt', 'is', null) .where('asset_face.deletedAt', 'is', null)
.executeTakeFirst(); .executeTakeFirst();
} }
@ -256,40 +256,40 @@ export class PersonRepository {
getDataForThumbnailGenerationJob(id: string) { getDataForThumbnailGenerationJob(id: string) {
return this.db return this.db
.selectFrom('person') .selectFrom('person')
.innerJoin('asset_faces', 'asset_faces.id', 'person.faceAssetId') .innerJoin('asset_face', 'asset_face.id', 'person.faceAssetId')
.innerJoin('assets', 'asset_faces.assetId', 'assets.id') .innerJoin('asset', 'asset_face.assetId', 'asset.id')
.leftJoin('exif', 'exif.assetId', 'assets.id') .leftJoin('asset_exif', 'asset_exif.assetId', 'asset.id')
.select([ .select([
'person.ownerId', 'person.ownerId',
'asset_faces.boundingBoxX1 as x1', 'asset_face.boundingBoxX1 as x1',
'asset_faces.boundingBoxY1 as y1', 'asset_face.boundingBoxY1 as y1',
'asset_faces.boundingBoxX2 as x2', 'asset_face.boundingBoxX2 as x2',
'asset_faces.boundingBoxY2 as y2', 'asset_face.boundingBoxY2 as y2',
'asset_faces.imageWidth as oldWidth', 'asset_face.imageWidth as oldWidth',
'asset_faces.imageHeight as oldHeight', 'asset_face.imageHeight as oldHeight',
'assets.type', 'asset.type',
'assets.originalPath', 'asset.originalPath',
'exif.orientation as exifOrientation', 'asset_exif.orientation as exifOrientation',
]) ])
.select((eb) => .select((eb) =>
eb eb
.selectFrom('asset_files') .selectFrom('asset_file')
.select('asset_files.path') .select('asset_file.path')
.whereRef('asset_files.assetId', '=', 'assets.id') .whereRef('asset_file.assetId', '=', 'asset.id')
.where('asset_files.type', '=', sql.lit(AssetFileType.PREVIEW)) .where('asset_file.type', '=', sql.lit(AssetFileType.PREVIEW))
.as('previewPath'), .as('previewPath'),
) )
.where('person.id', '=', id) .where('person.id', '=', id)
.where('asset_faces.deletedAt', 'is', null) .where('asset_face.deletedAt', 'is', null)
.executeTakeFirst(); .executeTakeFirst();
} }
@GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID] }) @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID] })
async reassignFace(assetFaceId: string, newPersonId: string): Promise<number> { async reassignFace(assetFaceId: string, newPersonId: string): Promise<number> {
const result = await this.db const result = await this.db
.updateTable('asset_faces') .updateTable('asset_face')
.set({ personId: newPersonId }) .set({ personId: newPersonId })
.where('asset_faces.id', '=', assetFaceId) .where('asset_face.id', '=', assetFaceId)
.executeTakeFirst(); .executeTakeFirst();
return Number(result.numChangedRows ?? 0); return Number(result.numChangedRows ?? 0);
@ -336,16 +336,16 @@ export class PersonRepository {
@GenerateSql({ params: [DummyValue.UUID] }) @GenerateSql({ params: [DummyValue.UUID] })
async getStatistics(personId: string): Promise<PersonStatistics> { async getStatistics(personId: string): Promise<PersonStatistics> {
const result = await this.db const result = await this.db
.selectFrom('asset_faces') .selectFrom('asset_face')
.leftJoin('assets', (join) => .leftJoin('asset', (join) =>
join join
.onRef('assets.id', '=', 'asset_faces.assetId') .onRef('asset.id', '=', 'asset_face.assetId')
.on('asset_faces.personId', '=', personId) .on('asset_face.personId', '=', personId)
.on('assets.visibility', '=', sql.lit(AssetVisibility.TIMELINE)) .on('asset.visibility', '=', sql.lit(AssetVisibility.TIMELINE))
.on('assets.deletedAt', 'is', null), .on('asset.deletedAt', 'is', null),
) )
.select((eb) => eb.fn.count(eb.fn('distinct', ['assets.id'])).as('count')) .select((eb) => eb.fn.count(eb.fn('distinct', ['asset.id'])).as('count'))
.where('asset_faces.deletedAt', 'is', null) .where('asset_face.deletedAt', 'is', null)
.executeTakeFirst(); .executeTakeFirst();
return { return {
@ -361,16 +361,16 @@ export class PersonRepository {
.where((eb) => .where((eb) =>
eb.exists((eb) => eb.exists((eb) =>
eb eb
.selectFrom('asset_faces') .selectFrom('asset_face')
.whereRef('asset_faces.personId', '=', 'person.id') .whereRef('asset_face.personId', '=', 'person.id')
.where('asset_faces.deletedAt', 'is', null) .where('asset_face.deletedAt', 'is', null)
.where((eb) => .where((eb) =>
eb.exists((eb) => eb.exists((eb) =>
eb eb
.selectFrom('assets') .selectFrom('asset')
.whereRef('assets.id', '=', 'asset_faces.assetId') .whereRef('asset.id', '=', 'asset_face.assetId')
.where('assets.visibility', '=', sql.lit(AssetVisibility.TIMELINE)) .where('asset.visibility', '=', sql.lit(AssetVisibility.TIMELINE))
.where('assets.deletedAt', 'is', null), .where('asset.deletedAt', 'is', null),
), ),
), ),
), ),
@ -402,12 +402,12 @@ export class PersonRepository {
): Promise<void> { ): Promise<void> {
let query = this.db; let query = this.db;
if (facesToAdd.length > 0) { if (facesToAdd.length > 0) {
(query as any) = query.with('added', (db) => db.insertInto('asset_faces').values(facesToAdd)); (query as any) = query.with('added', (db) => db.insertInto('asset_face').values(facesToAdd));
} }
if (faceIdsToRemove.length > 0) { if (faceIdsToRemove.length > 0) {
(query as any) = query.with('removed', (db) => (query as any) = query.with('removed', (db) =>
db.deleteFrom('asset_faces').where('asset_faces.id', '=', (eb) => eb.fn.any(eb.val(faceIdsToRemove))), db.deleteFrom('asset_face').where('asset_face.id', '=', (eb) => eb.fn.any(eb.val(faceIdsToRemove))),
); );
} }
@ -469,23 +469,23 @@ export class PersonRepository {
} }
return this.db return this.db
.selectFrom('asset_faces') .selectFrom('asset_face')
.selectAll('asset_faces') .selectAll('asset_face')
.select(withAsset) .select(withAsset)
.select(withPerson) .select(withPerson)
.where('asset_faces.assetId', 'in', assetIds) .where('asset_face.assetId', 'in', assetIds)
.where('asset_faces.personId', 'in', personIds) .where('asset_face.personId', 'in', personIds)
.where('asset_faces.deletedAt', 'is', null) .where('asset_face.deletedAt', 'is', null)
.execute(); .execute();
} }
@GenerateSql({ params: [DummyValue.UUID] }) @GenerateSql({ params: [DummyValue.UUID] })
getRandomFace(personId: string) { getRandomFace(personId: string) {
return this.db return this.db
.selectFrom('asset_faces') .selectFrom('asset_face')
.selectAll('asset_faces') .selectAll('asset_face')
.where('asset_faces.personId', '=', personId) .where('asset_face.personId', '=', personId)
.where('asset_faces.deletedAt', 'is', null) .where('asset_face.deletedAt', 'is', null)
.executeTakeFirst(); .executeTakeFirst();
} }
@ -500,22 +500,22 @@ export class PersonRepository {
} }
async createAssetFace(face: Insertable<AssetFaceTable>): Promise<void> { async createAssetFace(face: Insertable<AssetFaceTable>): Promise<void> {
await this.db.insertInto('asset_faces').values(face).execute(); await this.db.insertInto('asset_face').values(face).execute();
} }
@GenerateSql({ params: [DummyValue.UUID] }) @GenerateSql({ params: [DummyValue.UUID] })
async deleteAssetFace(id: string): Promise<void> { async deleteAssetFace(id: string): Promise<void> {
await this.db.deleteFrom('asset_faces').where('asset_faces.id', '=', id).execute(); await this.db.deleteFrom('asset_face').where('asset_face.id', '=', id).execute();
} }
@GenerateSql({ params: [DummyValue.UUID] }) @GenerateSql({ params: [DummyValue.UUID] })
async softDeleteAssetFaces(id: string): Promise<void> { async softDeleteAssetFaces(id: string): Promise<void> {
await this.db.updateTable('asset_faces').set({ deletedAt: new Date() }).where('asset_faces.id', '=', id).execute(); await this.db.updateTable('asset_face').set({ deletedAt: new Date() }).where('asset_face.id', '=', id).execute();
} }
async vacuum({ reindexVectors }: { reindexVectors: boolean }): Promise<void> { async vacuum({ reindexVectors }: { reindexVectors: boolean }): Promise<void> {
await sql`VACUUM ANALYZE asset_faces, face_search, person`.execute(this.db); await sql`VACUUM ANALYZE asset_face, face_search, person`.execute(this.db);
await sql`REINDEX TABLE asset_faces`.execute(this.db); await sql`REINDEX TABLE asset_face`.execute(this.db);
await sql`REINDEX TABLE person`.execute(this.db); await sql`REINDEX TABLE person`.execute(this.db);
if (reindexVectors) { if (reindexVectors) {
await sql`REINDEX TABLE face_search`.execute(this.db); await sql`REINDEX TABLE face_search`.execute(this.db);

View File

@ -7,7 +7,7 @@ import { MapAsset } from 'src/dtos/asset-response.dto';
import { AssetStatus, AssetType, AssetVisibility, VectorIndex } from 'src/enum'; import { AssetStatus, AssetType, AssetVisibility, VectorIndex } from 'src/enum';
import { probes } from 'src/repositories/database.repository'; import { probes } from 'src/repositories/database.repository';
import { DB } from 'src/schema'; import { DB } from 'src/schema';
import { ExifTable } from 'src/schema/tables/exif.table'; import { AssetExifTable } from 'src/schema/tables/asset-exif.table';
import { anyUuid, searchAssetBuilder } from 'src/utils/database'; import { anyUuid, searchAssetBuilder } from 'src/utils/database';
import { paginationHelper } from 'src/utils/pagination'; import { paginationHelper } from 'src/utils/pagination';
import { isValidInteger } from 'src/validation'; import { isValidInteger } from 'src/validation';
@ -183,8 +183,8 @@ export class SearchRepository {
async searchMetadata(pagination: SearchPaginationOptions, options: AssetSearchOptions) { async searchMetadata(pagination: SearchPaginationOptions, options: AssetSearchOptions) {
const orderDirection = (options.orderDirection?.toLowerCase() || 'desc') as OrderByDirection; const orderDirection = (options.orderDirection?.toLowerCase() || 'desc') as OrderByDirection;
const items = await searchAssetBuilder(this.db, options) const items = await searchAssetBuilder(this.db, options)
.selectAll('assets') .selectAll('asset')
.orderBy('assets.fileCreatedAt', orderDirection) .orderBy('asset.fileCreatedAt', orderDirection)
.limit(pagination.size + 1) .limit(pagination.size + 1)
.offset((pagination.page - 1) * pagination.size) .offset((pagination.page - 1) * pagination.size)
.execute(); .execute();
@ -224,13 +224,13 @@ export class SearchRepository {
const uuid = randomUUID(); const uuid = randomUUID();
const builder = searchAssetBuilder(this.db, options); const builder = searchAssetBuilder(this.db, options);
const lessThan = builder const lessThan = builder
.selectAll('assets') .selectAll('asset')
.where('assets.id', '<', uuid) .where('asset.id', '<', uuid)
.orderBy(sql`random()`) .orderBy(sql`random()`)
.limit(size); .limit(size);
const greaterThan = builder const greaterThan = builder
.selectAll('assets') .selectAll('asset')
.where('assets.id', '>', uuid) .where('asset.id', '>', uuid)
.orderBy(sql`random()`) .orderBy(sql`random()`)
.limit(size); .limit(size);
const { rows } = await sql<MapAsset>`${lessThan} union all ${greaterThan} limit ${size}`.execute(this.db); const { rows } = await sql<MapAsset>`${lessThan} union all ${greaterThan} limit ${size}`.execute(this.db);
@ -258,8 +258,8 @@ export class SearchRepository {
return this.db.transaction().execute(async (trx) => { return this.db.transaction().execute(async (trx) => {
await sql`set local vchordrq.probes = ${sql.lit(probes[VectorIndex.CLIP])}`.execute(trx); await sql`set local vchordrq.probes = ${sql.lit(probes[VectorIndex.CLIP])}`.execute(trx);
const items = await searchAssetBuilder(trx, options) const items = await searchAssetBuilder(trx, options)
.selectAll('assets') .selectAll('asset')
.innerJoin('smart_search', 'assets.id', 'smart_search.assetId') .innerJoin('smart_search', 'asset.id', 'smart_search.assetId')
.orderBy(sql`smart_search.embedding <=> ${options.embedding}`) .orderBy(sql`smart_search.embedding <=> ${options.embedding}`)
.limit(pagination.size + 1) .limit(pagination.size + 1)
.offset((pagination.page - 1) * pagination.size) .offset((pagination.page - 1) * pagination.size)
@ -288,18 +288,18 @@ export class SearchRepository {
return await trx return await trx
.with('cte', (qb) => .with('cte', (qb) =>
qb qb
.selectFrom('asset_faces') .selectFrom('asset_face')
.select([ .select([
'asset_faces.id', 'asset_face.id',
'asset_faces.personId', 'asset_face.personId',
sql<number>`face_search.embedding <=> ${embedding}`.as('distance'), sql<number>`face_search.embedding <=> ${embedding}`.as('distance'),
]) ])
.innerJoin('assets', 'assets.id', 'asset_faces.assetId') .innerJoin('asset', 'asset.id', 'asset_face.assetId')
.innerJoin('face_search', 'face_search.faceId', 'asset_faces.id') .innerJoin('face_search', 'face_search.faceId', 'asset_face.id')
.leftJoin('person', 'person.id', 'asset_faces.personId') .leftJoin('person', 'person.id', 'asset_face.personId')
.where('assets.ownerId', '=', anyUuid(userIds)) .where('asset.ownerId', '=', anyUuid(userIds))
.where('assets.deletedAt', 'is', null) .where('asset.deletedAt', 'is', null)
.$if(!!hasPerson, (qb) => qb.where('asset_faces.personId', 'is not', null)) .$if(!!hasPerson, (qb) => qb.where('asset_face.personId', 'is not', null))
.$if(!!minBirthDate, (qb) => .$if(!!minBirthDate, (qb) =>
qb.where((eb) => qb.where((eb) =>
eb.or([eb('person.birthDate', 'is', null), eb('person.birthDate', '<=', minBirthDate!)]), eb.or([eb('person.birthDate', 'is', null), eb('person.birthDate', '<=', minBirthDate!)]),
@ -347,13 +347,13 @@ export class SearchRepository {
return this.db return this.db
.withRecursive('cte', (qb) => { .withRecursive('cte', (qb) => {
const base = qb const base = qb
.selectFrom('exif') .selectFrom('asset_exif')
.select(['city', 'assetId']) .select(['city', 'assetId'])
.innerJoin('assets', 'assets.id', 'exif.assetId') .innerJoin('asset', 'asset.id', 'asset_exif.assetId')
.where('assets.ownerId', '=', anyUuid(userIds)) .where('asset.ownerId', '=', anyUuid(userIds))
.where('assets.visibility', '=', AssetVisibility.TIMELINE) .where('asset.visibility', '=', AssetVisibility.TIMELINE)
.where('assets.type', '=', AssetType.IMAGE) .where('asset.type', '=', AssetType.IMAGE)
.where('assets.deletedAt', 'is', null) .where('asset.deletedAt', 'is', null)
.orderBy('city') .orderBy('city')
.limit(1); .limit(1);
@ -363,14 +363,14 @@ export class SearchRepository {
.innerJoinLateral( .innerJoinLateral(
(qb) => (qb) =>
qb qb
.selectFrom('exif') .selectFrom('asset_exif')
.select(['city', 'assetId']) .select(['city', 'assetId'])
.innerJoin('assets', 'assets.id', 'exif.assetId') .innerJoin('asset', 'asset.id', 'asset_exif.assetId')
.where('assets.ownerId', '=', anyUuid(userIds)) .where('asset.ownerId', '=', anyUuid(userIds))
.where('assets.visibility', '=', AssetVisibility.TIMELINE) .where('asset.visibility', '=', AssetVisibility.TIMELINE)
.where('assets.type', '=', AssetType.IMAGE) .where('asset.type', '=', AssetType.IMAGE)
.where('assets.deletedAt', 'is', null) .where('asset.deletedAt', 'is', null)
.whereRef('exif.city', '>', 'cte.city') .whereRef('asset_exif.city', '>', 'cte.city')
.orderBy('city') .orderBy('city')
.limit(1) .limit(1)
.as('l'), .as('l'),
@ -379,17 +379,17 @@ export class SearchRepository {
return sql<{ city: string; assetId: string }>`(${base} union all ${recursive})`; return sql<{ city: string; assetId: string }>`(${base} union all ${recursive})`;
}) })
.selectFrom('assets') .selectFrom('asset')
.innerJoin('exif', 'assets.id', 'exif.assetId') .innerJoin('asset_exif', 'asset.id', 'asset_exif.assetId')
.innerJoin('cte', 'assets.id', 'cte.assetId') .innerJoin('cte', 'asset.id', 'cte.assetId')
.selectAll('assets') .selectAll('asset')
.select((eb) => .select((eb) =>
eb eb
.fn('to_jsonb', [eb.table('exif')]) .fn('to_jsonb', [eb.table('asset_exif')])
.$castTo<Selectable<ExifTable>>() .$castTo<Selectable<AssetExifTable>>()
.as('exifInfo'), .as('exifInfo'),
) )
.orderBy('exif.city') .orderBy('asset_exif.city')
.execute(); .execute();
} }
@ -445,10 +445,10 @@ export class SearchRepository {
private getExifField<K extends 'city' | 'state' | 'country' | 'make' | 'model'>(field: K, userIds: string[]) { private getExifField<K extends 'city' | 'state' | 'country' | 'make' | 'model'>(field: K, userIds: string[]) {
return this.db return this.db
.selectFrom('exif') .selectFrom('asset_exif')
.select(field) .select(field)
.distinctOn(field) .distinctOn(field)
.innerJoin('assets', 'assets.id', 'exif.assetId') .innerJoin('asset', 'asset.id', 'asset_exif.assetId')
.where('ownerId', '=', anyUuid(userIds)) .where('ownerId', '=', anyUuid(userIds))
.where('visibility', '=', AssetVisibility.TIMELINE) .where('visibility', '=', AssetVisibility.TIMELINE)
.where('deletedAt', 'is', null) .where('deletedAt', 'is', null)

View File

@ -17,7 +17,7 @@ export class SessionRepository {
cleanup() { cleanup() {
return this.db return this.db
.deleteFrom('sessions') .deleteFrom('session')
.where((eb) => .where((eb) =>
eb.or([ eb.or([
eb('updatedAt', '<=', DateTime.now().minus({ days: 90 }).toJSDate()), eb('updatedAt', '<=', DateTime.now().minus({ days: 90 }).toJSDate()),
@ -31,7 +31,7 @@ export class SessionRepository {
@GenerateSql({ params: [DummyValue.UUID] }) @GenerateSql({ params: [DummyValue.UUID] })
get(id: string) { get(id: string) {
return this.db return this.db
.selectFrom('sessions') .selectFrom('session')
.select(['id', 'expiresAt', 'pinExpiresAt']) .select(['id', 'expiresAt', 'pinExpiresAt'])
.where('id', '=', id) .where('id', '=', id)
.executeTakeFirst(); .executeTakeFirst();
@ -40,20 +40,20 @@ export class SessionRepository {
@GenerateSql({ params: [DummyValue.STRING] }) @GenerateSql({ params: [DummyValue.STRING] })
getByToken(token: string) { getByToken(token: string) {
return this.db return this.db
.selectFrom('sessions') .selectFrom('session')
.select((eb) => [ .select((eb) => [
...columns.authSession, ...columns.authSession,
jsonObjectFrom( jsonObjectFrom(
eb eb
.selectFrom('users') .selectFrom('user')
.select(columns.authUser) .select(columns.authUser)
.whereRef('users.id', '=', 'sessions.userId') .whereRef('user.id', '=', 'session.userId')
.where('users.deletedAt', 'is', null), .where('user.deletedAt', 'is', null),
).as('user'), ).as('user'),
]) ])
.where('sessions.token', '=', token) .where('session.token', '=', token)
.where((eb) => .where((eb) =>
eb.or([eb('sessions.expiresAt', 'is', null), eb('sessions.expiresAt', '>', DateTime.now().toJSDate())]), eb.or([eb('session.expiresAt', 'is', null), eb('session.expiresAt', '>', DateTime.now().toJSDate())]),
) )
.executeTakeFirst(); .executeTakeFirst();
} }
@ -61,47 +61,47 @@ export class SessionRepository {
@GenerateSql({ params: [DummyValue.UUID] }) @GenerateSql({ params: [DummyValue.UUID] })
getByUserId(userId: string) { getByUserId(userId: string) {
return this.db return this.db
.selectFrom('sessions') .selectFrom('session')
.innerJoin('users', (join) => join.onRef('users.id', '=', 'sessions.userId').on('users.deletedAt', 'is', null)) .innerJoin('user', (join) => join.onRef('user.id', '=', 'session.userId').on('user.deletedAt', 'is', null))
.selectAll('sessions') .selectAll('session')
.where('sessions.userId', '=', userId) .where('session.userId', '=', userId)
.where((eb) => .where((eb) =>
eb.or([eb('sessions.expiresAt', 'is', null), eb('sessions.expiresAt', '>', DateTime.now().toJSDate())]), eb.or([eb('session.expiresAt', 'is', null), eb('session.expiresAt', '>', DateTime.now().toJSDate())]),
) )
.orderBy('sessions.updatedAt', 'desc') .orderBy('session.updatedAt', 'desc')
.orderBy('sessions.createdAt', 'desc') .orderBy('session.createdAt', 'desc')
.execute(); .execute();
} }
create(dto: Insertable<SessionTable>) { create(dto: Insertable<SessionTable>) {
return this.db.insertInto('sessions').values(dto).returningAll().executeTakeFirstOrThrow(); return this.db.insertInto('session').values(dto).returningAll().executeTakeFirstOrThrow();
} }
update(id: string, dto: Updateable<SessionTable>) { update(id: string, dto: Updateable<SessionTable>) {
return this.db return this.db
.updateTable('sessions') .updateTable('session')
.set(dto) .set(dto)
.where('sessions.id', '=', asUuid(id)) .where('session.id', '=', asUuid(id))
.returningAll() .returningAll()
.executeTakeFirstOrThrow(); .executeTakeFirstOrThrow();
} }
@GenerateSql({ params: [DummyValue.UUID] }) @GenerateSql({ params: [DummyValue.UUID] })
async delete(id: string) { async delete(id: string) {
await this.db.deleteFrom('sessions').where('id', '=', asUuid(id)).execute(); await this.db.deleteFrom('session').where('id', '=', asUuid(id)).execute();
} }
@GenerateSql({ params: [DummyValue.UUID] }) @GenerateSql({ params: [DummyValue.UUID] })
async lockAll(userId: string) { async lockAll(userId: string) {
await this.db.updateTable('sessions').set({ pinExpiresAt: null }).where('userId', '=', userId).execute(); await this.db.updateTable('session').set({ pinExpiresAt: null }).where('userId', '=', userId).execute();
} }
@GenerateSql({ params: [DummyValue.UUID] }) @GenerateSql({ params: [DummyValue.UUID] })
async resetSyncProgress(sessionId: string) { async resetSyncProgress(sessionId: string) {
await this.db.transaction().execute((tx) => { await this.db.transaction().execute((tx) => {
return Promise.all([ return Promise.all([
tx.updateTable('sessions').set({ isPendingSyncReset: false }).where('id', '=', sessionId).execute(), tx.updateTable('session').set({ isPendingSyncReset: false }).where('id', '=', sessionId).execute(),
tx.deleteFrom('session_sync_checkpoints').where('sessionId', '=', sessionId).execute(), tx.deleteFrom('session_sync_checkpoint').where('sessionId', '=', sessionId).execute(),
]); ]);
}); });
} }

View File

@ -22,61 +22,66 @@ export class SharedLinkRepository {
@GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID] }) @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID] })
get(userId: string, id: string) { get(userId: string, id: string) {
return this.db return this.db
.selectFrom('shared_links') .selectFrom('shared_link')
.selectAll('shared_links') .selectAll('shared_link')
.leftJoinLateral( .leftJoinLateral(
(eb) => (eb) =>
eb eb
.selectFrom('shared_link__asset') .selectFrom('shared_link_asset')
.whereRef('shared_links.id', '=', 'shared_link__asset.sharedLinksId') .whereRef('shared_link.id', '=', 'shared_link_asset.sharedLinksId')
.innerJoin('assets', 'assets.id', 'shared_link__asset.assetsId') .innerJoin('asset', 'asset.id', 'shared_link_asset.assetsId')
.where('assets.deletedAt', 'is', null) .where('asset.deletedAt', 'is', null)
.selectAll('assets') .selectAll('asset')
.innerJoinLateral( .innerJoinLateral(
(eb) => eb.selectFrom('exif').selectAll('exif').whereRef('exif.assetId', '=', 'assets.id').as('exifInfo'), (eb) =>
eb
.selectFrom('asset_exif')
.selectAll('asset_exif')
.whereRef('asset_exif.assetId', '=', 'asset.id')
.as('exifInfo'),
(join) => join.onTrue(), (join) => join.onTrue(),
) )
.select((eb) => eb.fn.toJson('exifInfo').as('exifInfo')) .select((eb) => eb.fn.toJson('exifInfo').as('exifInfo'))
.orderBy('assets.fileCreatedAt', 'asc') .orderBy('asset.fileCreatedAt', 'asc')
.as('a'), .as('a'),
(join) => join.onTrue(), (join) => join.onTrue(),
) )
.leftJoinLateral( .leftJoinLateral(
(eb) => (eb) =>
eb eb
.selectFrom('albums') .selectFrom('album')
.selectAll('albums') .selectAll('album')
.whereRef('albums.id', '=', 'shared_links.albumId') .whereRef('album.id', '=', 'shared_link.albumId')
.where('albums.deletedAt', 'is', null) .where('album.deletedAt', 'is', null)
.leftJoin('albums_assets_assets', 'albums_assets_assets.albumsId', 'albums.id') .leftJoin('album_asset', 'album_asset.albumsId', 'album.id')
.leftJoinLateral( .leftJoinLateral(
(eb) => (eb) =>
eb eb
.selectFrom('assets') .selectFrom('asset')
.selectAll('assets') .selectAll('asset')
.whereRef('albums_assets_assets.assetsId', '=', 'assets.id') .whereRef('album_asset.assetsId', '=', 'asset.id')
.where('assets.deletedAt', 'is', null) .where('asset.deletedAt', 'is', null)
.innerJoinLateral( .innerJoinLateral(
(eb) => (eb) =>
eb eb
.selectFrom('exif') .selectFrom('asset_exif')
.selectAll('exif') .selectAll('asset_exif')
.whereRef('exif.assetId', '=', 'assets.id') .whereRef('asset_exif.assetId', '=', 'asset.id')
.as('assets_exifInfo'), .as('exifInfo'),
(join) => join.onTrue(), (join) => join.onTrue(),
) )
.select((eb) => eb.fn.toJson(eb.table('assets_exifInfo')).as('exifInfo')) .select((eb) => eb.fn.toJson(eb.table('exifInfo')).as('exifInfo'))
.orderBy('assets.fileCreatedAt', 'asc') .orderBy('asset.fileCreatedAt', 'asc')
.as('assets'), .as('assets'),
(join) => join.onTrue(), (join) => join.onTrue(),
) )
.innerJoinLateral( .innerJoinLateral(
(eb) => (eb) =>
eb eb
.selectFrom('users') .selectFrom('user')
.selectAll('users') .selectAll('user')
.whereRef('users.id', '=', 'albums.ownerId') .whereRef('user.id', '=', 'album.ownerId')
.where('users.deletedAt', 'is', null) .where('user.deletedAt', 'is', null)
.as('owner'), .as('owner'),
(join) => join.onTrue(), (join) => join.onTrue(),
) )
@ -84,7 +89,7 @@ export class SharedLinkRepository {
eb.fn.coalesce(eb.fn.jsonAgg('assets').filterWhere('assets.id', 'is not', null), sql`'[]'`).as('assets'), eb.fn.coalesce(eb.fn.jsonAgg('assets').filterWhere('assets.id', 'is not', null), sql`'[]'`).as('assets'),
) )
.select((eb) => eb.fn.toJson('owner').as('owner')) .select((eb) => eb.fn.toJson('owner').as('owner'))
.groupBy(['albums.id', sql`"owner".*`]) .groupBy(['album.id', sql`"owner".*`])
.as('album'), .as('album'),
(join) => join.onTrue(), (join) => join.onTrue(),
) )
@ -94,29 +99,29 @@ export class SharedLinkRepository {
.$castTo<MapAsset[]>() .$castTo<MapAsset[]>()
.as('assets'), .as('assets'),
) )
.groupBy(['shared_links.id', sql`"album".*`]) .groupBy(['shared_link.id', sql`"album".*`])
.select((eb) => eb.fn.toJson('album').$castTo<Album | null>().as('album')) .select((eb) => eb.fn.toJson('album').$castTo<Album | null>().as('album'))
.where('shared_links.id', '=', id) .where('shared_link.id', '=', id)
.where('shared_links.userId', '=', userId) .where('shared_link.userId', '=', userId)
.where((eb) => eb.or([eb('shared_links.type', '=', SharedLinkType.INDIVIDUAL), eb('album.id', 'is not', null)])) .where((eb) => eb.or([eb('shared_link.type', '=', SharedLinkType.INDIVIDUAL), eb('album.id', 'is not', null)]))
.orderBy('shared_links.createdAt', 'desc') .orderBy('shared_link.createdAt', 'desc')
.executeTakeFirst(); .executeTakeFirst();
} }
@GenerateSql({ params: [{ userId: DummyValue.UUID, albumId: DummyValue.UUID }] }) @GenerateSql({ params: [{ userId: DummyValue.UUID, albumId: DummyValue.UUID }] })
getAll({ userId, albumId }: SharedLinkSearchOptions) { getAll({ userId, albumId }: SharedLinkSearchOptions) {
return this.db return this.db
.selectFrom('shared_links') .selectFrom('shared_link')
.selectAll('shared_links') .selectAll('shared_link')
.where('shared_links.userId', '=', userId) .where('shared_link.userId', '=', userId)
.leftJoin('shared_link__asset', 'shared_link__asset.sharedLinksId', 'shared_links.id') .leftJoin('shared_link_asset', 'shared_link_asset.sharedLinksId', 'shared_link.id')
.leftJoinLateral( .leftJoinLateral(
(eb) => (eb) =>
eb eb
.selectFrom('assets') .selectFrom('asset')
.select((eb) => eb.fn.jsonAgg('assets').as('assets')) .select((eb) => eb.fn.jsonAgg('asset').as('assets'))
.whereRef('assets.id', '=', 'shared_link__asset.assetsId') .whereRef('asset.id', '=', 'shared_link_asset.assetsId')
.where('assets.deletedAt', 'is', null) .where('asset.deletedAt', 'is', null)
.as('assets'), .as('assets'),
(join) => join.onTrue(), (join) => join.onTrue(),
) )
@ -125,75 +130,75 @@ export class SharedLinkRepository {
.leftJoinLateral( .leftJoinLateral(
(eb) => (eb) =>
eb eb
.selectFrom('albums') .selectFrom('album')
.selectAll('albums') .selectAll('album')
.whereRef('albums.id', '=', 'shared_links.albumId') .whereRef('album.id', '=', 'shared_link.albumId')
.innerJoinLateral( .innerJoinLateral(
(eb) => (eb) =>
eb eb
.selectFrom('users') .selectFrom('user')
.select([ .select([
'users.id', 'user.id',
'users.email', 'user.email',
'users.createdAt', 'user.createdAt',
'users.profileImagePath', 'user.profileImagePath',
'users.isAdmin', 'user.isAdmin',
'users.shouldChangePassword', 'user.shouldChangePassword',
'users.deletedAt', 'user.deletedAt',
'users.oauthId', 'user.oauthId',
'users.updatedAt', 'user.updatedAt',
'users.storageLabel', 'user.storageLabel',
'users.name', 'user.name',
'users.quotaSizeInBytes', 'user.quotaSizeInBytes',
'users.quotaUsageInBytes', 'user.quotaUsageInBytes',
'users.status', 'user.status',
'users.profileChangedAt', 'user.profileChangedAt',
]) ])
.whereRef('users.id', '=', 'albums.ownerId') .whereRef('user.id', '=', 'album.ownerId')
.where('users.deletedAt', 'is', null) .where('user.deletedAt', 'is', null)
.as('owner'), .as('owner'),
(join) => join.onTrue(), (join) => join.onTrue(),
) )
.select((eb) => eb.fn.toJson('owner').as('owner')) .select((eb) => eb.fn.toJson('owner').as('owner'))
.where('albums.deletedAt', 'is', null) .where('album.deletedAt', 'is', null)
.as('album'), .as('album'),
(join) => join.onTrue(), (join) => join.onTrue(),
) )
.select((eb) => eb.fn.toJson('album').$castTo<Album | null>().as('album')) .select((eb) => eb.fn.toJson('album').$castTo<Album | null>().as('album'))
.where((eb) => eb.or([eb('shared_links.type', '=', SharedLinkType.INDIVIDUAL), eb('album.id', 'is not', null)])) .where((eb) => eb.or([eb('shared_link.type', '=', SharedLinkType.INDIVIDUAL), eb('album.id', 'is not', null)]))
.$if(!!albumId, (eb) => eb.where('shared_links.albumId', '=', albumId!)) .$if(!!albumId, (eb) => eb.where('shared_link.albumId', '=', albumId!))
.orderBy('shared_links.createdAt', 'desc') .orderBy('shared_link.createdAt', 'desc')
.distinctOn(['shared_links.createdAt']) .distinctOn(['shared_link.createdAt'])
.execute(); .execute();
} }
@GenerateSql({ params: [DummyValue.BUFFER] }) @GenerateSql({ params: [DummyValue.BUFFER] })
async getByKey(key: Buffer) { async getByKey(key: Buffer) {
return this.db return this.db
.selectFrom('shared_links') .selectFrom('shared_link')
.where('shared_links.key', '=', key) .where('shared_link.key', '=', key)
.leftJoin('albums', 'albums.id', 'shared_links.albumId') .leftJoin('album', 'album.id', 'shared_link.albumId')
.where('albums.deletedAt', 'is', null) .where('album.deletedAt', 'is', null)
.select((eb) => [ .select((eb) => [
...columns.authSharedLink, ...columns.authSharedLink,
jsonObjectFrom( jsonObjectFrom(
eb.selectFrom('users').select(columns.authUser).whereRef('users.id', '=', 'shared_links.userId'), eb.selectFrom('user').select(columns.authUser).whereRef('user.id', '=', 'shared_link.userId'),
).as('user'), ).as('user'),
]) ])
.where((eb) => eb.or([eb('shared_links.type', '=', SharedLinkType.INDIVIDUAL), eb('albums.id', 'is not', null)])) .where((eb) => eb.or([eb('shared_link.type', '=', SharedLinkType.INDIVIDUAL), eb('album.id', 'is not', null)]))
.executeTakeFirst(); .executeTakeFirst();
} }
async create(entity: Insertable<SharedLinkTable> & { assetIds?: string[] }) { async create(entity: Insertable<SharedLinkTable> & { assetIds?: string[] }) {
const { id } = await this.db const { id } = await this.db
.insertInto('shared_links') .insertInto('shared_link')
.values(_.omit(entity, 'assetIds')) .values(_.omit(entity, 'assetIds'))
.returningAll() .returningAll()
.executeTakeFirstOrThrow(); .executeTakeFirstOrThrow();
if (entity.assetIds && entity.assetIds.length > 0) { if (entity.assetIds && entity.assetIds.length > 0) {
await this.db await this.db
.insertInto('shared_link__asset') .insertInto('shared_link_asset')
.values(entity.assetIds!.map((assetsId) => ({ assetsId, sharedLinksId: id }))) .values(entity.assetIds!.map((assetsId) => ({ assetsId, sharedLinksId: id })))
.execute(); .execute();
} }
@ -203,15 +208,15 @@ export class SharedLinkRepository {
async update(entity: Updateable<SharedLinkTable> & { id: string; assetIds?: string[] }) { async update(entity: Updateable<SharedLinkTable> & { id: string; assetIds?: string[] }) {
const { id } = await this.db const { id } = await this.db
.updateTable('shared_links') .updateTable('shared_link')
.set(_.omit(entity, 'assets', 'album', 'assetIds')) .set(_.omit(entity, 'assets', 'album', 'assetIds'))
.where('shared_links.id', '=', entity.id) .where('shared_link.id', '=', entity.id)
.returningAll() .returningAll()
.executeTakeFirstOrThrow(); .executeTakeFirstOrThrow();
if (entity.assetIds && entity.assetIds.length > 0) { if (entity.assetIds && entity.assetIds.length > 0) {
await this.db await this.db
.insertInto('shared_link__asset') .insertInto('shared_link_asset')
.values(entity.assetIds!.map((assetsId) => ({ assetsId, sharedLinksId: id }))) .values(entity.assetIds!.map((assetsId) => ({ assetsId, sharedLinksId: id })))
.execute(); .execute();
} }
@ -220,23 +225,24 @@ export class SharedLinkRepository {
} }
async remove(id: string): Promise<void> { async remove(id: string): Promise<void> {
await this.db.deleteFrom('shared_links').where('shared_links.id', '=', id).execute(); await this.db.deleteFrom('shared_link').where('shared_link.id', '=', id).execute();
} }
private getSharedLinks(id: string) { private getSharedLinks(id: string) {
return this.db return this.db
.selectFrom('shared_links') .selectFrom('shared_link')
.selectAll('shared_links') .selectAll('shared_link')
.where('shared_links.id', '=', id) .where('shared_link.id', '=', id)
.leftJoin('shared_link__asset', 'shared_link__asset.sharedLinksId', 'shared_links.id') .leftJoin('shared_link_asset', 'shared_link_asset.sharedLinksId', 'shared_link.id')
.leftJoinLateral( .leftJoinLateral(
(eb) => (eb) =>
eb eb
.selectFrom('assets') .selectFrom('asset')
.whereRef('assets.id', '=', 'shared_link__asset.assetsId') .whereRef('asset.id', '=', 'shared_link_asset.assetsId')
.selectAll('assets') .selectAll('asset')
.innerJoinLateral( .innerJoinLateral(
(eb) => eb.selectFrom('exif').whereRef('exif.assetId', '=', 'assets.id').selectAll().as('exif'), (eb) =>
eb.selectFrom('asset_exif').whereRef('asset_exif.assetId', '=', 'asset.id').selectAll().as('exif'),
(join) => join.onTrue(), (join) => join.onTrue(),
) )
.as('assets'), .as('assets'),
@ -248,7 +254,7 @@ export class SharedLinkRepository {
.$castTo<MapAsset[]>() .$castTo<MapAsset[]>()
.as('assets'), .as('assets'),
) )
.groupBy('shared_links.id') .groupBy('shared_link.id')
.executeTakeFirstOrThrow(); .executeTakeFirstOrThrow();
} }
} }

View File

@ -13,29 +13,34 @@ export interface StackSearch {
primaryAssetId?: string; primaryAssetId?: string;
} }
const withAssets = (eb: ExpressionBuilder<DB, 'asset_stack'>, withTags = false) => { const withAssets = (eb: ExpressionBuilder<DB, 'stack'>, withTags = false) => {
return jsonArrayFrom( return jsonArrayFrom(
eb eb
.selectFrom('assets') .selectFrom('asset')
.selectAll('assets') .selectAll('asset')
.innerJoinLateral( .innerJoinLateral(
(eb) => eb.selectFrom('exif').select(columns.exif).whereRef('exif.assetId', '=', 'assets.id').as('exifInfo'), (eb) =>
eb
.selectFrom('asset_exif')
.select(columns.exif)
.whereRef('asset_exif.assetId', '=', 'asset.id')
.as('exifInfo'),
(join) => join.onTrue(), (join) => join.onTrue(),
) )
.$if(withTags, (eb) => .$if(withTags, (eb) =>
eb.select((eb) => eb.select((eb) =>
jsonArrayFrom( jsonArrayFrom(
eb eb
.selectFrom('tags') .selectFrom('tag')
.select(columns.tag) .select(columns.tag)
.innerJoin('tag_asset', 'tags.id', 'tag_asset.tagsId') .innerJoin('tag_asset', 'tag.id', 'tag_asset.tagsId')
.whereRef('tag_asset.assetsId', '=', 'assets.id'), .whereRef('tag_asset.assetsId', '=', 'asset.id'),
).as('tags'), ).as('tags'),
), ),
) )
.select((eb) => eb.fn.toJson('exifInfo').as('exifInfo')) .select((eb) => eb.fn.toJson('exifInfo').as('exifInfo'))
.where('assets.deletedAt', 'is', null) .where('asset.deletedAt', 'is', null)
.whereRef('assets.stackId', '=', 'asset_stack.id') .whereRef('asset.stackId', '=', 'stack.id')
.$call(withDefaultVisibility), .$call(withDefaultVisibility),
).as('assets'); ).as('assets');
}; };
@ -47,28 +52,28 @@ export class StackRepository {
@GenerateSql({ params: [{ ownerId: DummyValue.UUID }] }) @GenerateSql({ params: [{ ownerId: DummyValue.UUID }] })
search(query: StackSearch) { search(query: StackSearch) {
return this.db return this.db
.selectFrom('asset_stack') .selectFrom('stack')
.selectAll('asset_stack') .selectAll('stack')
.select(withAssets) .select(withAssets)
.where('asset_stack.ownerId', '=', query.ownerId) .where('stack.ownerId', '=', query.ownerId)
.$if(!!query.primaryAssetId, (eb) => eb.where('asset_stack.primaryAssetId', '=', query.primaryAssetId!)) .$if(!!query.primaryAssetId, (eb) => eb.where('stack.primaryAssetId', '=', query.primaryAssetId!))
.execute(); .execute();
} }
async create(entity: Omit<Insertable<StackTable>, 'primaryAssetId'>, assetIds: string[]) { async create(entity: Omit<Insertable<StackTable>, 'primaryAssetId'>, assetIds: string[]) {
return this.db.transaction().execute(async (tx) => { return this.db.transaction().execute(async (tx) => {
const stacks = await tx const stacks = await tx
.selectFrom('asset_stack') .selectFrom('stack')
.where('asset_stack.ownerId', '=', entity.ownerId) .where('stack.ownerId', '=', entity.ownerId)
.where('asset_stack.primaryAssetId', 'in', assetIds) .where('stack.primaryAssetId', 'in', assetIds)
.select('asset_stack.id') .select('stack.id')
.select((eb) => .select((eb) =>
jsonArrayFrom( jsonArrayFrom(
eb eb
.selectFrom('assets') .selectFrom('asset')
.select('assets.id') .select('asset.id')
.whereRef('assets.stackId', '=', 'asset_stack.id') .whereRef('asset.stackId', '=', 'stack.id')
.where('assets.deletedAt', 'is', null), .where('asset.deletedAt', 'is', null),
).as('assets'), ).as('assets'),
) )
.execute(); .execute();
@ -86,7 +91,7 @@ export class StackRepository {
if (stacks.length > 0) { if (stacks.length > 0) {
await tx await tx
.deleteFrom('asset_stack') .deleteFrom('stack')
.where( .where(
'id', 'id',
'in', 'in',
@ -96,13 +101,13 @@ export class StackRepository {
} }
const newRecord = await tx const newRecord = await tx
.insertInto('asset_stack') .insertInto('stack')
.values({ ...entity, primaryAssetId: assetIds[0] }) .values({ ...entity, primaryAssetId: assetIds[0] })
.returning('id') .returning('id')
.executeTakeFirstOrThrow(); .executeTakeFirstOrThrow();
await tx await tx
.updateTable('assets') .updateTable('asset')
.set({ .set({
stackId: newRecord.id, stackId: newRecord.id,
updatedAt: new Date(), updatedAt: new Date(),
@ -111,8 +116,8 @@ export class StackRepository {
.execute(); .execute();
return tx return tx
.selectFrom('asset_stack') .selectFrom('stack')
.selectAll('asset_stack') .selectAll('stack')
.select(withAssets) .select(withAssets)
.where('id', '=', newRecord.id) .where('id', '=', newRecord.id)
.executeTakeFirstOrThrow(); .executeTakeFirstOrThrow();
@ -121,19 +126,19 @@ export class StackRepository {
@GenerateSql({ params: [DummyValue.UUID] }) @GenerateSql({ params: [DummyValue.UUID] })
async delete(id: string): Promise<void> { async delete(id: string): Promise<void> {
await this.db.deleteFrom('asset_stack').where('id', '=', asUuid(id)).execute(); await this.db.deleteFrom('stack').where('id', '=', asUuid(id)).execute();
} }
async deleteAll(ids: string[]): Promise<void> { async deleteAll(ids: string[]): Promise<void> {
await this.db.deleteFrom('asset_stack').where('id', 'in', ids).execute(); await this.db.deleteFrom('stack').where('id', 'in', ids).execute();
} }
update(id: string, entity: Updateable<StackTable>) { update(id: string, entity: Updateable<StackTable>) {
return this.db return this.db
.updateTable('asset_stack') .updateTable('stack')
.set(entity) .set(entity)
.where('id', '=', asUuid(id)) .where('id', '=', asUuid(id))
.returningAll('asset_stack') .returningAll('stack')
.returning((eb) => withAssets(eb, true)) .returning((eb) => withAssets(eb, true))
.executeTakeFirstOrThrow(); .executeTakeFirstOrThrow();
} }
@ -141,7 +146,7 @@ export class StackRepository {
@GenerateSql({ params: [DummyValue.UUID] }) @GenerateSql({ params: [DummyValue.UUID] })
getById(id: string) { getById(id: string) {
return this.db return this.db
.selectFrom('asset_stack') .selectFrom('stack')
.selectAll() .selectAll()
.select((eb) => withAssets(eb, true)) .select((eb) => withAssets(eb, true))
.where('id', '=', asUuid(id)) .where('id', '=', asUuid(id))

View File

@ -13,7 +13,7 @@ export class SyncCheckpointRepository {
@GenerateSql({ params: [DummyValue.UUID] }) @GenerateSql({ params: [DummyValue.UUID] })
getAll(sessionId: string) { getAll(sessionId: string) {
return this.db return this.db
.selectFrom('session_sync_checkpoints') .selectFrom('session_sync_checkpoint')
.select(['type', 'ack']) .select(['type', 'ack'])
.where('sessionId', '=', sessionId) .where('sessionId', '=', sessionId)
.execute(); .execute();
@ -21,7 +21,7 @@ export class SyncCheckpointRepository {
upsertAll(items: Insertable<SessionSyncCheckpointTable>[]) { upsertAll(items: Insertable<SessionSyncCheckpointTable>[]) {
return this.db return this.db
.insertInto('session_sync_checkpoints') .insertInto('session_sync_checkpoint')
.values(items) .values(items)
.onConflict((oc) => .onConflict((oc) =>
oc.columns(['sessionId', 'type']).doUpdateSet((eb) => ({ oc.columns(['sessionId', 'type']).doUpdateSet((eb) => ({
@ -34,7 +34,7 @@ export class SyncCheckpointRepository {
@GenerateSql({ params: [DummyValue.UUID] }) @GenerateSql({ params: [DummyValue.UUID] })
deleteAll(sessionId: string, types?: SyncEntityType[]) { deleteAll(sessionId: string, types?: SyncEntityType[]) {
return this.db return this.db
.deleteFrom('session_sync_checkpoints') .deleteFrom('session_sync_checkpoint')
.where('sessionId', '=', sessionId) .where('sessionId', '=', sessionId)
.$if(!!types, (qb) => qb.where('type', 'in', types!)) .$if(!!types, (qb) => qb.where('type', 'in', types!))
.execute(); .execute();

View File

@ -7,27 +7,27 @@ import { DB } from 'src/schema';
import { SyncAck } from 'src/types'; import { SyncAck } from 'src/types';
type AuditTables = type AuditTables =
| 'users_audit' | 'user_audit'
| 'partners_audit' | 'partner_audit'
| 'assets_audit' | 'asset_audit'
| 'albums_audit' | 'album_audit'
| 'album_users_audit' | 'album_user_audit'
| 'album_assets_audit' | 'album_asset_audit'
| 'memories_audit' | 'memory_audit'
| 'memory_assets_audit' | 'memory_asset_audit'
| 'stacks_audit' | 'stack_audit'
| 'person_audit' | 'person_audit'
| 'user_metadata_audit'; | 'user_metadata_audit';
type UpsertTables = type UpsertTables =
| 'users' | 'user'
| 'partners' | 'partner'
| 'assets' | 'asset'
| 'exif' | 'asset_exif'
| 'albums' | 'album'
| 'albums_shared_users_users' | 'album_user'
| 'memories' | 'memory'
| 'memories_assets_assets' | 'memory_asset'
| 'asset_stack' | 'stack'
| 'person' | 'person'
| 'user_metadata'; | 'user_metadata';
@ -100,7 +100,7 @@ class AlbumSync extends BaseSync {
@GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID] }) @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID] })
getCreatedAfter(userId: string, afterCreateId?: string) { getCreatedAfter(userId: string, afterCreateId?: string) {
return this.db return this.db
.selectFrom('albums_shared_users_users') .selectFrom('album_user')
.select(['albumsId as id', 'createId']) .select(['albumsId as id', 'createId'])
.where('usersId', '=', userId) .where('usersId', '=', userId)
.$if(!!afterCreateId, (qb) => qb.where('createId', '>=', afterCreateId!)) .$if(!!afterCreateId, (qb) => qb.where('createId', '>=', afterCreateId!))
@ -112,7 +112,7 @@ class AlbumSync extends BaseSync {
@GenerateSql({ params: [DummyValue.UUID], stream: true }) @GenerateSql({ params: [DummyValue.UUID], stream: true })
getDeletes(userId: string, ack?: SyncAck) { getDeletes(userId: string, ack?: SyncAck) {
return this.db return this.db
.selectFrom('albums_audit') .selectFrom('album_audit')
.select(['id', 'albumId']) .select(['id', 'albumId'])
.where('userId', '=', userId) .where('userId', '=', userId)
.$call(this.auditTableFilters(ack)) .$call(this.auditTableFilters(ack))
@ -122,24 +122,24 @@ class AlbumSync extends BaseSync {
@GenerateSql({ params: [DummyValue.UUID], stream: true }) @GenerateSql({ params: [DummyValue.UUID], stream: true })
getUpserts(userId: string, ack?: SyncAck) { getUpserts(userId: string, ack?: SyncAck) {
return this.db return this.db
.selectFrom('albums') .selectFrom('album')
.distinctOn(['albums.id', 'albums.updateId']) .distinctOn(['album.id', 'album.updateId'])
.where('albums.updatedAt', '<', sql.raw<Date>("now() - interval '1 millisecond'")) .where('album.updatedAt', '<', sql.raw<Date>("now() - interval '1 millisecond'"))
.$if(!!ack, (qb) => qb.where('albums.updateId', '>', ack!.updateId)) .$if(!!ack, (qb) => qb.where('album.updateId', '>', ack!.updateId))
.orderBy('albums.updateId', 'asc') .orderBy('album.updateId', 'asc')
.leftJoin('albums_shared_users_users as album_users', 'albums.id', 'album_users.albumsId') .leftJoin('album_user as album_users', 'album.id', 'album_users.albumsId')
.where((eb) => eb.or([eb('albums.ownerId', '=', userId), eb('album_users.usersId', '=', userId)])) .where((eb) => eb.or([eb('album.ownerId', '=', userId), eb('album_users.usersId', '=', userId)]))
.select([ .select([
'albums.id', 'album.id',
'albums.ownerId', 'album.ownerId',
'albums.albumName as name', 'album.albumName as name',
'albums.description', 'album.description',
'albums.createdAt', 'album.createdAt',
'albums.updatedAt', 'album.updatedAt',
'albums.albumThumbnailAssetId as thumbnailAssetId', 'album.albumThumbnailAssetId as thumbnailAssetId',
'albums.isActivityEnabled', 'album.isActivityEnabled',
'albums.order', 'album.order',
'albums.updateId', 'album.updateId',
]) ])
.stream(); .stream();
} }
@ -149,31 +149,31 @@ class AlbumAssetSync extends BaseSync {
@GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID, DummyValue.UUID], stream: true }) @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID, DummyValue.UUID], stream: true })
getBackfill(albumId: string, afterUpdateId: string | undefined, beforeUpdateId: string) { getBackfill(albumId: string, afterUpdateId: string | undefined, beforeUpdateId: string) {
return this.db return this.db
.selectFrom('assets') .selectFrom('asset')
.innerJoin('albums_assets_assets as album_assets', 'album_assets.assetsId', 'assets.id') .innerJoin('album_asset', 'album_asset.assetsId', 'asset.id')
.select(columns.syncAsset) .select(columns.syncAsset)
.select('assets.updateId') .select('asset.updateId')
.where('album_assets.albumsId', '=', albumId) .where('album_asset.albumsId', '=', albumId)
.where('assets.updatedAt', '<', sql.raw<Date>("now() - interval '1 millisecond'")) .where('asset.updatedAt', '<', sql.raw<Date>("now() - interval '1 millisecond'"))
.where('assets.updateId', '<=', beforeUpdateId) .where('asset.updateId', '<=', beforeUpdateId)
.$if(!!afterUpdateId, (eb) => eb.where('assets.updateId', '>=', afterUpdateId!)) .$if(!!afterUpdateId, (eb) => eb.where('asset.updateId', '>=', afterUpdateId!))
.orderBy('assets.updateId', 'asc') .orderBy('asset.updateId', 'asc')
.stream(); .stream();
} }
@GenerateSql({ params: [DummyValue.UUID], stream: true }) @GenerateSql({ params: [DummyValue.UUID], stream: true })
getUpserts(userId: string, ack?: SyncAck) { getUpserts(userId: string, ack?: SyncAck) {
return this.db return this.db
.selectFrom('assets') .selectFrom('asset')
.innerJoin('albums_assets_assets as album_assets', 'album_assets.assetsId', 'assets.id') .innerJoin('album_asset', 'album_asset.assetsId', 'asset.id')
.select(columns.syncAsset) .select(columns.syncAsset)
.select('assets.updateId') .select('asset.updateId')
.where('assets.updatedAt', '<', sql.raw<Date>("now() - interval '1 millisecond'")) .where('asset.updatedAt', '<', sql.raw<Date>("now() - interval '1 millisecond'"))
.$if(!!ack, (qb) => qb.where('assets.updateId', '>', ack!.updateId)) .$if(!!ack, (qb) => qb.where('asset.updateId', '>', ack!.updateId))
.orderBy('assets.updateId', 'asc') .orderBy('asset.updateId', 'asc')
.innerJoin('albums', 'albums.id', 'album_assets.albumsId') .innerJoin('album', 'album.id', 'album_asset.albumsId')
.leftJoin('albums_shared_users_users as album_users', 'album_users.albumsId', 'album_assets.albumsId') .leftJoin('album_user', 'album_user.albumsId', 'album_asset.albumsId')
.where((eb) => eb.or([eb('albums.ownerId', '=', userId), eb('album_users.usersId', '=', userId)])) .where((eb) => eb.or([eb('album.ownerId', '=', userId), eb('album_user.usersId', '=', userId)]))
.stream(); .stream();
} }
} }
@ -182,31 +182,31 @@ class AlbumAssetExifSync extends BaseSync {
@GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID, DummyValue.UUID], stream: true }) @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID, DummyValue.UUID], stream: true })
getBackfill(albumId: string, afterUpdateId: string | undefined, beforeUpdateId: string) { getBackfill(albumId: string, afterUpdateId: string | undefined, beforeUpdateId: string) {
return this.db return this.db
.selectFrom('exif') .selectFrom('asset_exif')
.innerJoin('albums_assets_assets as album_assets', 'album_assets.assetsId', 'exif.assetId') .innerJoin('album_asset', 'album_asset.assetsId', 'asset_exif.assetId')
.select(columns.syncAssetExif) .select(columns.syncAssetExif)
.select('exif.updateId') .select('asset_exif.updateId')
.where('album_assets.albumsId', '=', albumId) .where('album_asset.albumsId', '=', albumId)
.where('exif.updatedAt', '<', sql.raw<Date>("now() - interval '1 millisecond'")) .where('asset_exif.updatedAt', '<', sql.raw<Date>("now() - interval '1 millisecond'"))
.where('exif.updateId', '<=', beforeUpdateId) .where('asset_exif.updateId', '<=', beforeUpdateId)
.$if(!!afterUpdateId, (eb) => eb.where('exif.updateId', '>=', afterUpdateId!)) .$if(!!afterUpdateId, (eb) => eb.where('asset_exif.updateId', '>=', afterUpdateId!))
.orderBy('exif.updateId', 'asc') .orderBy('asset_exif.updateId', 'asc')
.stream(); .stream();
} }
@GenerateSql({ params: [DummyValue.UUID], stream: true }) @GenerateSql({ params: [DummyValue.UUID], stream: true })
getUpserts(userId: string, ack?: SyncAck) { getUpserts(userId: string, ack?: SyncAck) {
return this.db return this.db
.selectFrom('exif') .selectFrom('asset_exif')
.innerJoin('albums_assets_assets as album_assets', 'album_assets.assetsId', 'exif.assetId') .innerJoin('album_asset', 'album_asset.assetsId', 'asset_exif.assetId')
.select(columns.syncAssetExif) .select(columns.syncAssetExif)
.select('exif.updateId') .select('asset_exif.updateId')
.where('exif.updatedAt', '<', sql.raw<Date>("now() - interval '1 millisecond'")) .where('asset_exif.updatedAt', '<', sql.raw<Date>("now() - interval '1 millisecond'"))
.$if(!!ack, (qb) => qb.where('exif.updateId', '>', ack!.updateId)) .$if(!!ack, (qb) => qb.where('asset_exif.updateId', '>', ack!.updateId))
.orderBy('exif.updateId', 'asc') .orderBy('asset_exif.updateId', 'asc')
.innerJoin('albums', 'albums.id', 'album_assets.albumsId') .innerJoin('album', 'album.id', 'album_asset.albumsId')
.leftJoin('albums_shared_users_users as album_users', 'album_users.albumsId', 'album_assets.albumsId') .leftJoin('album_user', 'album_user.albumsId', 'album_asset.albumsId')
.where((eb) => eb.or([eb('albums.ownerId', '=', userId), eb('album_users.usersId', '=', userId)])) .where((eb) => eb.or([eb('album.ownerId', '=', userId), eb('album_user.usersId', '=', userId)]))
.stream(); .stream();
} }
} }
@ -215,7 +215,7 @@ class AlbumToAssetSync extends BaseSync {
@GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID, DummyValue.UUID], stream: true }) @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID, DummyValue.UUID], stream: true })
getBackfill(albumId: string, afterUpdateId: string | undefined, beforeUpdateId: string) { getBackfill(albumId: string, afterUpdateId: string | undefined, beforeUpdateId: string) {
return this.db return this.db
.selectFrom('albums_assets_assets as album_assets') .selectFrom('album_asset as album_assets')
.select(['album_assets.assetsId as assetId', 'album_assets.albumsId as albumId', 'album_assets.updateId']) .select(['album_assets.assetsId as assetId', 'album_assets.albumsId as albumId', 'album_assets.updateId'])
.where('album_assets.albumsId', '=', albumId) .where('album_assets.albumsId', '=', albumId)
.where('album_assets.updatedAt', '<', sql.raw<Date>("now() - interval '1 millisecond'")) .where('album_assets.updatedAt', '<', sql.raw<Date>("now() - interval '1 millisecond'"))
@ -228,22 +228,22 @@ class AlbumToAssetSync extends BaseSync {
@GenerateSql({ params: [DummyValue.UUID], stream: true }) @GenerateSql({ params: [DummyValue.UUID], stream: true })
getDeletes(userId: string, ack?: SyncAck) { getDeletes(userId: string, ack?: SyncAck) {
return this.db return this.db
.selectFrom('album_assets_audit') .selectFrom('album_asset_audit')
.select(['id', 'assetId', 'albumId']) .select(['id', 'assetId', 'albumId'])
.where((eb) => .where((eb) =>
eb( eb(
'albumId', 'albumId',
'in', 'in',
eb eb
.selectFrom('albums') .selectFrom('album')
.select(['id']) .select(['id'])
.where('ownerId', '=', userId) .where('ownerId', '=', userId)
.union((eb) => .union((eb) =>
eb.parens( eb.parens(
eb eb
.selectFrom('albums_shared_users_users as albumUsers') .selectFrom('album_user')
.select(['albumUsers.albumsId as id']) .select(['album_user.albumsId as id'])
.where('albumUsers.usersId', '=', userId), .where('album_user.usersId', '=', userId),
), ),
), ),
), ),
@ -255,14 +255,14 @@ class AlbumToAssetSync extends BaseSync {
@GenerateSql({ params: [DummyValue.UUID], stream: true }) @GenerateSql({ params: [DummyValue.UUID], stream: true })
getUpserts(userId: string, ack?: SyncAck) { getUpserts(userId: string, ack?: SyncAck) {
return this.db return this.db
.selectFrom('albums_assets_assets as album_assets') .selectFrom('album_asset')
.select(['album_assets.assetsId as assetId', 'album_assets.albumsId as albumId', 'album_assets.updateId']) .select(['album_asset.assetsId as assetId', 'album_asset.albumsId as albumId', 'album_asset.updateId'])
.where('album_assets.updatedAt', '<', sql.raw<Date>("now() - interval '1 millisecond'")) .where('album_asset.updatedAt', '<', sql.raw<Date>("now() - interval '1 millisecond'"))
.$if(!!ack, (qb) => qb.where('album_assets.updateId', '>', ack!.updateId)) .$if(!!ack, (qb) => qb.where('album_asset.updateId', '>', ack!.updateId))
.orderBy('album_assets.updateId', 'asc') .orderBy('album_asset.updateId', 'asc')
.innerJoin('albums', 'albums.id', 'album_assets.albumsId') .innerJoin('album', 'album.id', 'album_asset.albumsId')
.leftJoin('albums_shared_users_users as album_users', 'album_users.albumsId', 'album_assets.albumsId') .leftJoin('album_user', 'album_user.albumsId', 'album_asset.albumsId')
.where((eb) => eb.or([eb('albums.ownerId', '=', userId), eb('album_users.usersId', '=', userId)])) .where((eb) => eb.or([eb('album.ownerId', '=', userId), eb('album_user.usersId', '=', userId)]))
.stream(); .stream();
} }
} }
@ -271,9 +271,9 @@ class AlbumUserSync extends BaseSync {
@GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID, DummyValue.UUID, DummyValue.UUID], stream: true }) @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID, DummyValue.UUID, DummyValue.UUID], stream: true })
getBackfill(albumId: string, afterUpdateId: string | undefined, beforeUpdateId: string) { getBackfill(albumId: string, afterUpdateId: string | undefined, beforeUpdateId: string) {
return this.db return this.db
.selectFrom('albums_shared_users_users as album_users') .selectFrom('album_user')
.select(columns.syncAlbumUser) .select(columns.syncAlbumUser)
.select('album_users.updateId') .select('album_user.updateId')
.where('albumsId', '=', albumId) .where('albumsId', '=', albumId)
.where('updatedAt', '<', sql.raw<Date>("now() - interval '1 millisecond'")) .where('updatedAt', '<', sql.raw<Date>("now() - interval '1 millisecond'"))
.where('updateId', '<=', beforeUpdateId) .where('updateId', '<=', beforeUpdateId)
@ -285,22 +285,22 @@ class AlbumUserSync extends BaseSync {
@GenerateSql({ params: [DummyValue.UUID], stream: true }) @GenerateSql({ params: [DummyValue.UUID], stream: true })
getDeletes(userId: string, ack?: SyncAck) { getDeletes(userId: string, ack?: SyncAck) {
return this.db return this.db
.selectFrom('album_users_audit') .selectFrom('album_user_audit')
.select(['id', 'userId', 'albumId']) .select(['id', 'userId', 'albumId'])
.where((eb) => .where((eb) =>
eb( eb(
'albumId', 'albumId',
'in', 'in',
eb eb
.selectFrom('albums') .selectFrom('album')
.select(['id']) .select(['id'])
.where('ownerId', '=', userId) .where('ownerId', '=', userId)
.union((eb) => .union((eb) =>
eb.parens( eb.parens(
eb eb
.selectFrom('albums_shared_users_users as albumUsers') .selectFrom('album_user')
.select(['albumUsers.albumsId as id']) .select(['album_user.albumsId as id'])
.where('albumUsers.usersId', '=', userId), .where('album_user.usersId', '=', userId),
), ),
), ),
), ),
@ -312,24 +312,24 @@ class AlbumUserSync extends BaseSync {
@GenerateSql({ params: [DummyValue.UUID], stream: true }) @GenerateSql({ params: [DummyValue.UUID], stream: true })
getUpserts(userId: string, ack?: SyncAck) { getUpserts(userId: string, ack?: SyncAck) {
return this.db return this.db
.selectFrom('albums_shared_users_users as album_users') .selectFrom('album_user')
.select(columns.syncAlbumUser) .select(columns.syncAlbumUser)
.select('album_users.updateId') .select('album_user.updateId')
.where('album_users.updatedAt', '<', sql.raw<Date>("now() - interval '1 millisecond'")) .where('album_user.updatedAt', '<', sql.raw<Date>("now() - interval '1 millisecond'"))
.$if(!!ack, (qb) => qb.where('album_users.updateId', '>', ack!.updateId)) .$if(!!ack, (qb) => qb.where('album_user.updateId', '>', ack!.updateId))
.orderBy('album_users.updateId', 'asc') .orderBy('album_user.updateId', 'asc')
.where((eb) => .where((eb) =>
eb( eb(
'album_users.albumsId', 'album_user.albumsId',
'in', 'in',
eb eb
.selectFrom('albums') .selectFrom('album')
.select(['id']) .select(['id'])
.where('ownerId', '=', userId) .where('ownerId', '=', userId)
.union((eb) => .union((eb) =>
eb.parens( eb.parens(
eb eb
.selectFrom('albums_shared_users_users as albumUsers') .selectFrom('album_user as albumUsers')
.select(['albumUsers.albumsId as id']) .select(['albumUsers.albumsId as id'])
.where('albumUsers.usersId', '=', userId), .where('albumUsers.usersId', '=', userId),
), ),
@ -344,7 +344,7 @@ class AssetSync extends BaseSync {
@GenerateSql({ params: [DummyValue.UUID], stream: true }) @GenerateSql({ params: [DummyValue.UUID], stream: true })
getDeletes(userId: string, ack?: SyncAck) { getDeletes(userId: string, ack?: SyncAck) {
return this.db return this.db
.selectFrom('assets_audit') .selectFrom('asset_audit')
.select(['id', 'assetId']) .select(['id', 'assetId'])
.where('ownerId', '=', userId) .where('ownerId', '=', userId)
.$call(this.auditTableFilters(ack)) .$call(this.auditTableFilters(ack))
@ -354,9 +354,9 @@ class AssetSync extends BaseSync {
@GenerateSql({ params: [DummyValue.UUID], stream: true }) @GenerateSql({ params: [DummyValue.UUID], stream: true })
getUpserts(userId: string, ack?: SyncAck) { getUpserts(userId: string, ack?: SyncAck) {
return this.db return this.db
.selectFrom('assets') .selectFrom('asset')
.select(columns.syncAsset) .select(columns.syncAsset)
.select('assets.updateId') .select('asset.updateId')
.where('ownerId', '=', userId) .where('ownerId', '=', userId)
.$call(this.upsertTableFilters(ack)) .$call(this.upsertTableFilters(ack))
.stream(); .stream();
@ -402,10 +402,10 @@ class AssetExifSync extends BaseSync {
@GenerateSql({ params: [DummyValue.UUID], stream: true }) @GenerateSql({ params: [DummyValue.UUID], stream: true })
getUpserts(userId: string, ack?: SyncAck) { getUpserts(userId: string, ack?: SyncAck) {
return this.db return this.db
.selectFrom('exif') .selectFrom('asset_exif')
.select(columns.syncAssetExif) .select(columns.syncAssetExif)
.select('exif.updateId') .select('asset_exif.updateId')
.where('assetId', 'in', (eb) => eb.selectFrom('assets').select('id').where('ownerId', '=', userId)) .where('assetId', 'in', (eb) => eb.selectFrom('asset').select('id').where('ownerId', '=', userId))
.$call(this.upsertTableFilters(ack)) .$call(this.upsertTableFilters(ack))
.stream(); .stream();
} }
@ -415,7 +415,7 @@ class MemorySync extends BaseSync {
@GenerateSql({ params: [DummyValue.UUID], stream: true }) @GenerateSql({ params: [DummyValue.UUID], stream: true })
getDeletes(userId: string, ack?: SyncAck) { getDeletes(userId: string, ack?: SyncAck) {
return this.db return this.db
.selectFrom('memories_audit') .selectFrom('memory_audit')
.select(['id', 'memoryId']) .select(['id', 'memoryId'])
.where('userId', '=', userId) .where('userId', '=', userId)
.$call(this.auditTableFilters(ack)) .$call(this.auditTableFilters(ack))
@ -425,7 +425,7 @@ class MemorySync extends BaseSync {
@GenerateSql({ params: [DummyValue.UUID], stream: true }) @GenerateSql({ params: [DummyValue.UUID], stream: true })
getUpserts(userId: string, ack?: SyncAck) { getUpserts(userId: string, ack?: SyncAck) {
return this.db return this.db
.selectFrom('memories') .selectFrom('memory')
.select([ .select([
'id', 'id',
'createdAt', 'createdAt',
@ -451,9 +451,9 @@ class MemoryToAssetSync extends BaseSync {
@GenerateSql({ params: [DummyValue.UUID], stream: true }) @GenerateSql({ params: [DummyValue.UUID], stream: true })
getDeletes(userId: string, ack?: SyncAck) { getDeletes(userId: string, ack?: SyncAck) {
return this.db return this.db
.selectFrom('memory_assets_audit') .selectFrom('memory_asset_audit')
.select(['id', 'memoryId', 'assetId']) .select(['id', 'memoryId', 'assetId'])
.where('memoryId', 'in', (eb) => eb.selectFrom('memories').select('id').where('ownerId', '=', userId)) .where('memoryId', 'in', (eb) => eb.selectFrom('memory').select('id').where('ownerId', '=', userId))
.$call(this.auditTableFilters(ack)) .$call(this.auditTableFilters(ack))
.stream(); .stream();
} }
@ -461,10 +461,10 @@ class MemoryToAssetSync extends BaseSync {
@GenerateSql({ params: [DummyValue.UUID], stream: true }) @GenerateSql({ params: [DummyValue.UUID], stream: true })
getUpserts(userId: string, ack?: SyncAck) { getUpserts(userId: string, ack?: SyncAck) {
return this.db return this.db
.selectFrom('memories_assets_assets') .selectFrom('memory_asset')
.select(['memoriesId as memoryId', 'assetsId as assetId']) .select(['memoriesId as memoryId', 'assetsId as assetId'])
.select('updateId') .select('updateId')
.where('memoriesId', 'in', (eb) => eb.selectFrom('memories').select('id').where('ownerId', '=', userId)) .where('memoriesId', 'in', (eb) => eb.selectFrom('memory').select('id').where('ownerId', '=', userId))
.$call(this.upsertTableFilters(ack)) .$call(this.upsertTableFilters(ack))
.stream(); .stream();
} }
@ -474,19 +474,19 @@ class PartnerSync extends BaseSync {
@GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID] }) @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID] })
getCreatedAfter(userId: string, afterCreateId?: string) { getCreatedAfter(userId: string, afterCreateId?: string) {
return this.db return this.db
.selectFrom('partners') .selectFrom('partner')
.select(['sharedById', 'createId']) .select(['sharedById', 'createId'])
.where('sharedWithId', '=', userId) .where('sharedWithId', '=', userId)
.$if(!!afterCreateId, (qb) => qb.where('createId', '>=', afterCreateId!)) .$if(!!afterCreateId, (qb) => qb.where('createId', '>=', afterCreateId!))
.where('createdAt', '<', sql.raw<Date>("now() - interval '1 millisecond'")) .where('createdAt', '<', sql.raw<Date>("now() - interval '1 millisecond'"))
.orderBy('partners.createId', 'asc') .orderBy('partner.createId', 'asc')
.execute(); .execute();
} }
@GenerateSql({ params: [DummyValue.UUID], stream: true }) @GenerateSql({ params: [DummyValue.UUID], stream: true })
getDeletes(userId: string, ack?: SyncAck) { getDeletes(userId: string, ack?: SyncAck) {
return this.db return this.db
.selectFrom('partners_audit') .selectFrom('partner_audit')
.select(['id', 'sharedById', 'sharedWithId']) .select(['id', 'sharedById', 'sharedWithId'])
.where((eb) => eb.or([eb('sharedById', '=', userId), eb('sharedWithId', '=', userId)])) .where((eb) => eb.or([eb('sharedById', '=', userId), eb('sharedWithId', '=', userId)]))
.$call(this.auditTableFilters(ack)) .$call(this.auditTableFilters(ack))
@ -496,7 +496,7 @@ class PartnerSync extends BaseSync {
@GenerateSql({ params: [DummyValue.UUID], stream: true }) @GenerateSql({ params: [DummyValue.UUID], stream: true })
getUpserts(userId: string, ack?: SyncAck) { getUpserts(userId: string, ack?: SyncAck) {
return this.db return this.db
.selectFrom('partners') .selectFrom('partner')
.select(['sharedById', 'sharedWithId', 'inTimeline', 'updateId']) .select(['sharedById', 'sharedWithId', 'inTimeline', 'updateId'])
.where((eb) => eb.or([eb('sharedById', '=', userId), eb('sharedWithId', '=', userId)])) .where((eb) => eb.or([eb('sharedById', '=', userId), eb('sharedWithId', '=', userId)]))
.$call(this.upsertTableFilters(ack)) .$call(this.upsertTableFilters(ack))
@ -508,9 +508,9 @@ class PartnerAssetsSync extends BaseSync {
@GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID, DummyValue.UUID], stream: true }) @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID, DummyValue.UUID], stream: true })
getBackfill(partnerId: string, afterUpdateId: string | undefined, beforeUpdateId: string) { getBackfill(partnerId: string, afterUpdateId: string | undefined, beforeUpdateId: string) {
return this.db return this.db
.selectFrom('assets') .selectFrom('asset')
.select(columns.syncAsset) .select(columns.syncAsset)
.select('assets.updateId') .select('asset.updateId')
.where('ownerId', '=', partnerId) .where('ownerId', '=', partnerId)
.where('updatedAt', '<', sql.raw<Date>("now() - interval '1 millisecond'")) .where('updatedAt', '<', sql.raw<Date>("now() - interval '1 millisecond'"))
.where('updateId', '<=', beforeUpdateId) .where('updateId', '<=', beforeUpdateId)
@ -522,10 +522,10 @@ class PartnerAssetsSync extends BaseSync {
@GenerateSql({ params: [DummyValue.UUID], stream: true }) @GenerateSql({ params: [DummyValue.UUID], stream: true })
getDeletes(userId: string, ack?: SyncAck) { getDeletes(userId: string, ack?: SyncAck) {
return this.db return this.db
.selectFrom('assets_audit') .selectFrom('asset_audit')
.select(['id', 'assetId']) .select(['id', 'assetId'])
.where('ownerId', 'in', (eb) => .where('ownerId', 'in', (eb) =>
eb.selectFrom('partners').select(['sharedById']).where('sharedWithId', '=', userId), eb.selectFrom('partner').select(['sharedById']).where('sharedWithId', '=', userId),
) )
.$call(this.auditTableFilters(ack)) .$call(this.auditTableFilters(ack))
.stream(); .stream();
@ -534,11 +534,11 @@ class PartnerAssetsSync extends BaseSync {
@GenerateSql({ params: [DummyValue.UUID], stream: true }) @GenerateSql({ params: [DummyValue.UUID], stream: true })
getUpserts(userId: string, ack?: SyncAck) { getUpserts(userId: string, ack?: SyncAck) {
return this.db return this.db
.selectFrom('assets') .selectFrom('asset')
.select(columns.syncAsset) .select(columns.syncAsset)
.select('assets.updateId') .select('asset.updateId')
.where('ownerId', 'in', (eb) => .where('ownerId', 'in', (eb) =>
eb.selectFrom('partners').select(['sharedById']).where('sharedWithId', '=', userId), eb.selectFrom('partner').select(['sharedById']).where('sharedWithId', '=', userId),
) )
.$call(this.upsertTableFilters(ack)) .$call(this.upsertTableFilters(ack))
.stream(); .stream();
@ -549,30 +549,30 @@ class PartnerAssetExifsSync extends BaseSync {
@GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID, DummyValue.UUID], stream: true }) @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID, DummyValue.UUID], stream: true })
getBackfill(partnerId: string, afterUpdateId: string | undefined, beforeUpdateId: string) { getBackfill(partnerId: string, afterUpdateId: string | undefined, beforeUpdateId: string) {
return this.db return this.db
.selectFrom('exif') .selectFrom('asset_exif')
.select(columns.syncAssetExif) .select(columns.syncAssetExif)
.select('exif.updateId') .select('asset_exif.updateId')
.innerJoin('assets', 'assets.id', 'exif.assetId') .innerJoin('asset', 'asset.id', 'asset_exif.assetId')
.where('assets.ownerId', '=', partnerId) .where('asset.ownerId', '=', partnerId)
.where('exif.updatedAt', '<', sql.raw<Date>("now() - interval '1 millisecond'")) .where('asset_exif.updatedAt', '<', sql.raw<Date>("now() - interval '1 millisecond'"))
.where('exif.updateId', '<=', beforeUpdateId) .where('asset_exif.updateId', '<=', beforeUpdateId)
.$if(!!afterUpdateId, (eb) => eb.where('exif.updateId', '>=', afterUpdateId!)) .$if(!!afterUpdateId, (eb) => eb.where('asset_exif.updateId', '>=', afterUpdateId!))
.orderBy('exif.updateId', 'asc') .orderBy('asset_exif.updateId', 'asc')
.stream(); .stream();
} }
@GenerateSql({ params: [DummyValue.UUID], stream: true }) @GenerateSql({ params: [DummyValue.UUID], stream: true })
getUpserts(userId: string, ack?: SyncAck) { getUpserts(userId: string, ack?: SyncAck) {
return this.db return this.db
.selectFrom('exif') .selectFrom('asset_exif')
.select(columns.syncAssetExif) .select(columns.syncAssetExif)
.select('exif.updateId') .select('asset_exif.updateId')
.where('assetId', 'in', (eb) => .where('assetId', 'in', (eb) =>
eb eb
.selectFrom('assets') .selectFrom('asset')
.select('id') .select('id')
.where('ownerId', 'in', (eb) => .where('ownerId', 'in', (eb) =>
eb.selectFrom('partners').select(['sharedById']).where('sharedWithId', '=', userId), eb.selectFrom('partner').select(['sharedById']).where('sharedWithId', '=', userId),
), ),
) )
.$call(this.upsertTableFilters(ack)) .$call(this.upsertTableFilters(ack))
@ -584,7 +584,7 @@ class StackSync extends BaseSync {
@GenerateSql({ params: [DummyValue.UUID], stream: true }) @GenerateSql({ params: [DummyValue.UUID], stream: true })
getDeletes(userId: string, ack?: SyncAck) { getDeletes(userId: string, ack?: SyncAck) {
return this.db return this.db
.selectFrom('stacks_audit') .selectFrom('stack_audit')
.select(['id', 'stackId']) .select(['id', 'stackId'])
.where('userId', '=', userId) .where('userId', '=', userId)
.$call(this.auditTableFilters(ack)) .$call(this.auditTableFilters(ack))
@ -594,7 +594,7 @@ class StackSync extends BaseSync {
@GenerateSql({ params: [DummyValue.UUID], stream: true }) @GenerateSql({ params: [DummyValue.UUID], stream: true })
getUpserts(userId: string, ack?: SyncAck) { getUpserts(userId: string, ack?: SyncAck) {
return this.db return this.db
.selectFrom('asset_stack') .selectFrom('stack')
.select(columns.syncStack) .select(columns.syncStack)
.select('updateId') .select('updateId')
.where('ownerId', '=', userId) .where('ownerId', '=', userId)
@ -607,11 +607,9 @@ class PartnerStackSync extends BaseSync {
@GenerateSql({ params: [DummyValue.UUID], stream: true }) @GenerateSql({ params: [DummyValue.UUID], stream: true })
getDeletes(userId: string, ack?: SyncAck) { getDeletes(userId: string, ack?: SyncAck) {
return this.db return this.db
.selectFrom('stacks_audit') .selectFrom('stack_audit')
.select(['id', 'stackId']) .select(['id', 'stackId'])
.where('userId', 'in', (eb) => .where('userId', 'in', (eb) => eb.selectFrom('partner').select(['sharedById']).where('sharedWithId', '=', userId))
eb.selectFrom('partners').select(['sharedById']).where('sharedWithId', '=', userId),
)
.$call(this.auditTableFilters(ack)) .$call(this.auditTableFilters(ack))
.stream(); .stream();
} }
@ -619,7 +617,7 @@ class PartnerStackSync extends BaseSync {
@GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID, DummyValue.UUID], stream: true }) @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID, DummyValue.UUID], stream: true })
getBackfill(partnerId: string, afterUpdateId: string | undefined, beforeUpdateId: string) { getBackfill(partnerId: string, afterUpdateId: string | undefined, beforeUpdateId: string) {
return this.db return this.db
.selectFrom('asset_stack') .selectFrom('stack')
.select(columns.syncStack) .select(columns.syncStack)
.select('updateId') .select('updateId')
.where('ownerId', '=', partnerId) .where('ownerId', '=', partnerId)
@ -633,11 +631,11 @@ class PartnerStackSync extends BaseSync {
@GenerateSql({ params: [DummyValue.UUID], stream: true }) @GenerateSql({ params: [DummyValue.UUID], stream: true })
getUpserts(userId: string, ack?: SyncAck) { getUpserts(userId: string, ack?: SyncAck) {
return this.db return this.db
.selectFrom('asset_stack') .selectFrom('stack')
.select(columns.syncStack) .select(columns.syncStack)
.select('updateId') .select('updateId')
.where('ownerId', 'in', (eb) => .where('ownerId', 'in', (eb) =>
eb.selectFrom('partners').select(['sharedById']).where('sharedWithId', '=', userId), eb.selectFrom('partner').select(['sharedById']).where('sharedWithId', '=', userId),
) )
.$call(this.upsertTableFilters(ack)) .$call(this.upsertTableFilters(ack))
.stream(); .stream();
@ -647,13 +645,13 @@ class PartnerStackSync extends BaseSync {
class UserSync extends BaseSync { class UserSync extends BaseSync {
@GenerateSql({ params: [], stream: true }) @GenerateSql({ params: [], stream: true })
getDeletes(ack?: SyncAck) { getDeletes(ack?: SyncAck) {
return this.db.selectFrom('users_audit').select(['id', 'userId']).$call(this.auditTableFilters(ack)).stream(); return this.db.selectFrom('user_audit').select(['id', 'userId']).$call(this.auditTableFilters(ack)).stream();
} }
@GenerateSql({ params: [], stream: true }) @GenerateSql({ params: [], stream: true })
getUpserts(ack?: SyncAck) { getUpserts(ack?: SyncAck) {
return this.db return this.db
.selectFrom('users') .selectFrom('user')
.select(['id', 'name', 'email', 'deletedAt', 'updateId']) .select(['id', 'name', 'email', 'deletedAt', 'updateId'])
.$call(this.upsertTableFilters(ack)) .$call(this.upsertTableFilters(ack))
.stream(); .stream();

View File

@ -19,13 +19,13 @@ export class TagRepository {
@GenerateSql({ params: [DummyValue.UUID] }) @GenerateSql({ params: [DummyValue.UUID] })
get(id: string) { get(id: string) {
return this.db.selectFrom('tags').select(columns.tag).where('id', '=', id).executeTakeFirst(); return this.db.selectFrom('tag').select(columns.tag).where('id', '=', id).executeTakeFirst();
} }
@GenerateSql({ params: [DummyValue.UUID, DummyValue.STRING] }) @GenerateSql({ params: [DummyValue.UUID, DummyValue.STRING] })
getByValue(userId: string, value: string) { getByValue(userId: string, value: string) {
return this.db return this.db
.selectFrom('tags') .selectFrom('tag')
.select(columns.tag) .select(columns.tag)
.where('userId', '=', userId) .where('userId', '=', userId)
.where('value', '=', value) .where('value', '=', value)
@ -37,7 +37,7 @@ export class TagRepository {
const parentId = _parentId ?? null; const parentId = _parentId ?? null;
return this.db.transaction().execute(async (tx) => { return this.db.transaction().execute(async (tx) => {
const tag = await this.db const tag = await this.db
.insertInto('tags') .insertInto('tag')
.values({ userId, value, parentId }) .values({ userId, value, parentId })
.onConflict((oc) => oc.columns(['userId', 'value']).doUpdateSet({ parentId })) .onConflict((oc) => oc.columns(['userId', 'value']).doUpdateSet({ parentId }))
.returning(columns.tag) .returning(columns.tag)
@ -45,18 +45,18 @@ export class TagRepository {
// update closure table // update closure table
await tx await tx
.insertInto('tags_closure') .insertInto('tag_closure')
.values({ id_ancestor: tag.id, id_descendant: tag.id }) .values({ id_ancestor: tag.id, id_descendant: tag.id })
.onConflict((oc) => oc.doNothing()) .onConflict((oc) => oc.doNothing())
.execute(); .execute();
if (parentId) { if (parentId) {
await tx await tx
.insertInto('tags_closure') .insertInto('tag_closure')
.columns(['id_ancestor', 'id_descendant']) .columns(['id_ancestor', 'id_descendant'])
.expression( .expression(
this.db this.db
.selectFrom('tags_closure') .selectFrom('tag_closure')
.select(['id_ancestor', sql.raw<string>(`'${tag.id}'`).as('id_descendant')]) .select(['id_ancestor', sql.raw<string>(`'${tag.id}'`).as('id_descendant')])
.where('id_descendant', '=', parentId), .where('id_descendant', '=', parentId),
) )
@ -70,22 +70,22 @@ export class TagRepository {
@GenerateSql({ params: [DummyValue.UUID] }) @GenerateSql({ params: [DummyValue.UUID] })
getAll(userId: string) { getAll(userId: string) {
return this.db.selectFrom('tags').select(columns.tag).where('userId', '=', userId).orderBy('value').execute(); return this.db.selectFrom('tag').select(columns.tag).where('userId', '=', userId).orderBy('value').execute();
} }
@GenerateSql({ params: [{ userId: DummyValue.UUID, color: DummyValue.STRING, value: DummyValue.STRING }] }) @GenerateSql({ params: [{ userId: DummyValue.UUID, color: DummyValue.STRING, value: DummyValue.STRING }] })
create(tag: Insertable<TagTable>) { create(tag: Insertable<TagTable>) {
return this.db.insertInto('tags').values(tag).returningAll().executeTakeFirstOrThrow(); return this.db.insertInto('tag').values(tag).returningAll().executeTakeFirstOrThrow();
} }
@GenerateSql({ params: [DummyValue.UUID, { color: DummyValue.STRING }] }) @GenerateSql({ params: [DummyValue.UUID, { color: DummyValue.STRING }] })
update(id: string, dto: Updateable<TagTable>) { update(id: string, dto: Updateable<TagTable>) {
return this.db.updateTable('tags').set(dto).where('id', '=', id).returningAll().executeTakeFirstOrThrow(); return this.db.updateTable('tag').set(dto).where('id', '=', id).returningAll().executeTakeFirstOrThrow();
} }
@GenerateSql({ params: [DummyValue.UUID] }) @GenerateSql({ params: [DummyValue.UUID] })
async delete(id: string) { async delete(id: string) {
await this.db.deleteFrom('tags').where('id', '=', id).execute(); await this.db.deleteFrom('tag').where('id', '=', id).execute();
} }
@ChunkedSet({ paramIndex: 1 }) @ChunkedSet({ paramIndex: 1 })
@ -166,17 +166,17 @@ export class TagRepository {
// TODO rewrite as a single statement // TODO rewrite as a single statement
await this.db.transaction().execute(async (tx) => { await this.db.transaction().execute(async (tx) => {
const result = await tx const result = await tx
.selectFrom('assets') .selectFrom('asset')
.innerJoin('tag_asset', 'tag_asset.assetsId', 'assets.id') .innerJoin('tag_asset', 'tag_asset.assetsId', 'asset.id')
.innerJoin('tags_closure', 'tags_closure.id_descendant', 'tag_asset.tagsId') .innerJoin('tag_closure', 'tag_closure.id_descendant', 'tag_asset.tagsId')
.innerJoin('tags', 'tags.id', 'tags_closure.id_descendant') .innerJoin('tag', 'tag.id', 'tag_closure.id_descendant')
.select((eb) => ['tags.id', eb.fn.count<number>('assets.id').as('count')]) .select((eb) => ['tag.id', eb.fn.count<number>('asset.id').as('count')])
.groupBy('tags.id') .groupBy('tag.id')
.execute(); .execute();
const ids = result.filter(({ count }) => count === 0).map(({ id }) => id); const ids = result.filter(({ count }) => count === 0).map(({ id }) => id);
if (ids.length > 0) { if (ids.length > 0) {
await this.db.deleteFrom('tags').where('id', 'in', ids).execute(); await this.db.deleteFrom('tag').where('id', 'in', ids).execute();
this.logger.log(`Deleted ${ids.length} empty tags`); this.logger.log(`Deleted ${ids.length} empty tags`);
} }
}); });

View File

@ -8,13 +8,13 @@ export class TrashRepository {
constructor(@InjectKysely() private db: Kysely<DB>) {} constructor(@InjectKysely() private db: Kysely<DB>) {}
getDeletedIds(): AsyncIterableIterator<{ id: string }> { getDeletedIds(): AsyncIterableIterator<{ id: string }> {
return this.db.selectFrom('assets').select(['id']).where('status', '=', AssetStatus.DELETED).stream(); return this.db.selectFrom('asset').select(['id']).where('status', '=', AssetStatus.DELETED).stream();
} }
@GenerateSql({ params: [DummyValue.UUID] }) @GenerateSql({ params: [DummyValue.UUID] })
async restore(userId: string): Promise<number> { async restore(userId: string): Promise<number> {
const { numUpdatedRows } = await this.db const { numUpdatedRows } = await this.db
.updateTable('assets') .updateTable('asset')
.where('ownerId', '=', userId) .where('ownerId', '=', userId)
.where('status', '=', AssetStatus.TRASHED) .where('status', '=', AssetStatus.TRASHED)
.set({ status: AssetStatus.ACTIVE, deletedAt: null }) .set({ status: AssetStatus.ACTIVE, deletedAt: null })
@ -26,7 +26,7 @@ export class TrashRepository {
@GenerateSql({ params: [DummyValue.UUID] }) @GenerateSql({ params: [DummyValue.UUID] })
async empty(userId: string): Promise<number> { async empty(userId: string): Promise<number> {
const { numUpdatedRows } = await this.db const { numUpdatedRows } = await this.db
.updateTable('assets') .updateTable('asset')
.where('ownerId', '=', userId) .where('ownerId', '=', userId)
.where('status', '=', AssetStatus.TRASHED) .where('status', '=', AssetStatus.TRASHED)
.set({ status: AssetStatus.DELETED }) .set({ status: AssetStatus.DELETED })
@ -42,7 +42,7 @@ export class TrashRepository {
} }
const { numUpdatedRows } = await this.db const { numUpdatedRows } = await this.db
.updateTable('assets') .updateTable('asset')
.where('status', '=', AssetStatus.TRASHED) .where('status', '=', AssetStatus.TRASHED)
.where('id', 'in', ids) .where('id', 'in', ids)
.set({ status: AssetStatus.ACTIVE, deletedAt: null }) .set({ status: AssetStatus.ACTIVE, deletedAt: null })

View File

@ -34,12 +34,12 @@ export interface UserFindOptions {
withDeleted?: boolean; withDeleted?: boolean;
} }
const withMetadata = (eb: ExpressionBuilder<DB, 'users'>) => { const withMetadata = (eb: ExpressionBuilder<DB, 'user'>) => {
return jsonArrayFrom( return jsonArrayFrom(
eb eb
.selectFrom('user_metadata') .selectFrom('user_metadata')
.select(['user_metadata.key', 'user_metadata.value']) .select(['user_metadata.key', 'user_metadata.value'])
.whereRef('users.id', '=', 'user_metadata.userId'), .whereRef('user.id', '=', 'user_metadata.userId'),
).as('metadata'); ).as('metadata');
}; };
@ -52,11 +52,11 @@ export class UserRepository {
options = options || {}; options = options || {};
return this.db return this.db
.selectFrom('users') .selectFrom('user')
.select(columns.userAdmin) .select(columns.userAdmin)
.select(withMetadata) .select(withMetadata)
.where('users.id', '=', userId) .where('user.id', '=', userId)
.$if(!options.withDeleted, (eb) => eb.where('users.deletedAt', 'is', null)) .$if(!options.withDeleted, (eb) => eb.where('user.deletedAt', 'is', null))
.executeTakeFirst(); .executeTakeFirst();
} }
@ -71,21 +71,21 @@ export class UserRepository {
@GenerateSql() @GenerateSql()
getAdmin() { getAdmin() {
return this.db return this.db
.selectFrom('users') .selectFrom('user')
.select(columns.userAdmin) .select(columns.userAdmin)
.select(withMetadata) .select(withMetadata)
.where('users.isAdmin', '=', true) .where('user.isAdmin', '=', true)
.where('users.deletedAt', 'is', null) .where('user.deletedAt', 'is', null)
.executeTakeFirst(); .executeTakeFirst();
} }
@GenerateSql() @GenerateSql()
async hasAdmin(): Promise<boolean> { async hasAdmin(): Promise<boolean> {
const admin = await this.db const admin = await this.db
.selectFrom('users') .selectFrom('user')
.select('users.id') .select('user.id')
.where('users.isAdmin', '=', true) .where('user.isAdmin', '=', true)
.where('users.deletedAt', 'is', null) .where('user.deletedAt', 'is', null)
.executeTakeFirst(); .executeTakeFirst();
return !!admin; return !!admin;
@ -94,59 +94,59 @@ export class UserRepository {
@GenerateSql({ params: [DummyValue.UUID] }) @GenerateSql({ params: [DummyValue.UUID] })
getForPinCode(id: string) { getForPinCode(id: string) {
return this.db return this.db
.selectFrom('users') .selectFrom('user')
.select(['users.pinCode', 'users.password']) .select(['user.pinCode', 'user.password'])
.where('users.id', '=', id) .where('user.id', '=', id)
.where('users.deletedAt', 'is', null) .where('user.deletedAt', 'is', null)
.executeTakeFirstOrThrow(); .executeTakeFirstOrThrow();
} }
@GenerateSql({ params: [DummyValue.UUID] }) @GenerateSql({ params: [DummyValue.UUID] })
getForChangePassword(id: string) { getForChangePassword(id: string) {
return this.db return this.db
.selectFrom('users') .selectFrom('user')
.select(['users.id', 'users.password']) .select(['user.id', 'user.password'])
.where('users.id', '=', id) .where('user.id', '=', id)
.where('users.deletedAt', 'is', null) .where('user.deletedAt', 'is', null)
.executeTakeFirstOrThrow(); .executeTakeFirstOrThrow();
} }
@GenerateSql({ params: [DummyValue.EMAIL] }) @GenerateSql({ params: [DummyValue.EMAIL] })
getByEmail(email: string, options?: { withPassword?: boolean }) { getByEmail(email: string, options?: { withPassword?: boolean }) {
return this.db return this.db
.selectFrom('users') .selectFrom('user')
.select(columns.userAdmin) .select(columns.userAdmin)
.select(withMetadata) .select(withMetadata)
.$if(!!options?.withPassword, (eb) => eb.select('password')) .$if(!!options?.withPassword, (eb) => eb.select('password'))
.where('email', '=', email) .where('email', '=', email)
.where('users.deletedAt', 'is', null) .where('user.deletedAt', 'is', null)
.executeTakeFirst(); .executeTakeFirst();
} }
@GenerateSql({ params: [DummyValue.STRING] }) @GenerateSql({ params: [DummyValue.STRING] })
getByStorageLabel(storageLabel: string) { getByStorageLabel(storageLabel: string) {
return this.db return this.db
.selectFrom('users') .selectFrom('user')
.select(columns.userAdmin) .select(columns.userAdmin)
.where('users.storageLabel', '=', storageLabel) .where('user.storageLabel', '=', storageLabel)
.where('users.deletedAt', 'is', null) .where('user.deletedAt', 'is', null)
.executeTakeFirst(); .executeTakeFirst();
} }
@GenerateSql({ params: [DummyValue.STRING] }) @GenerateSql({ params: [DummyValue.STRING] })
getByOAuthId(oauthId: string) { getByOAuthId(oauthId: string) {
return this.db return this.db
.selectFrom('users') .selectFrom('user')
.select(columns.userAdmin) .select(columns.userAdmin)
.select(withMetadata) .select(withMetadata)
.where('users.oauthId', '=', oauthId) .where('user.oauthId', '=', oauthId)
.where('users.deletedAt', 'is', null) .where('user.deletedAt', 'is', null)
.executeTakeFirst(); .executeTakeFirst();
} }
@GenerateSql({ params: [DateTime.now().minus({ years: 1 })] }) @GenerateSql({ params: [DateTime.now().minus({ years: 1 })] })
getDeletedAfter(target: DateTime) { getDeletedAfter(target: DateTime) {
return this.db.selectFrom('users').select(['id']).where('users.deletedAt', '<', target.toJSDate()).execute(); return this.db.selectFrom('user').select(['id']).where('user.deletedAt', '<', target.toJSDate()).execute();
} }
@GenerateSql( @GenerateSql(
@ -155,18 +155,18 @@ export class UserRepository {
) )
getList({ id, withDeleted }: UserListFilter = {}) { getList({ id, withDeleted }: UserListFilter = {}) {
return this.db return this.db
.selectFrom('users') .selectFrom('user')
.select(columns.userAdmin) .select(columns.userAdmin)
.select(withMetadata) .select(withMetadata)
.$if(!withDeleted, (eb) => eb.where('users.deletedAt', 'is', null)) .$if(!withDeleted, (eb) => eb.where('user.deletedAt', 'is', null))
.$if(!!id, (eb) => eb.where('users.id', '=', id!)) .$if(!!id, (eb) => eb.where('user.id', '=', id!))
.orderBy('createdAt', 'desc') .orderBy('createdAt', 'desc')
.execute(); .execute();
} }
async create(dto: Insertable<UserTable>) { async create(dto: Insertable<UserTable>) {
return this.db return this.db
.insertInto('users') .insertInto('user')
.values(dto) .values(dto)
.returning(columns.userAdmin) .returning(columns.userAdmin)
.returning(withMetadata) .returning(withMetadata)
@ -175,10 +175,10 @@ export class UserRepository {
update(id: string, dto: Updateable<UserTable>) { update(id: string, dto: Updateable<UserTable>) {
return this.db return this.db
.updateTable('users') .updateTable('user')
.set(dto) .set(dto)
.where('users.id', '=', asUuid(id)) .where('user.id', '=', asUuid(id))
.where('users.deletedAt', 'is', null) .where('user.deletedAt', 'is', null)
.returning(columns.userAdmin) .returning(columns.userAdmin)
.returning(withMetadata) .returning(withMetadata)
.executeTakeFirstOrThrow(); .executeTakeFirstOrThrow();
@ -186,9 +186,9 @@ export class UserRepository {
restore(id: string) { restore(id: string) {
return this.db return this.db
.updateTable('users') .updateTable('user')
.set({ status: UserStatus.ACTIVE, deletedAt: null }) .set({ status: UserStatus.ACTIVE, deletedAt: null })
.where('users.id', '=', asUuid(id)) .where('user.id', '=', asUuid(id))
.returning(columns.userAdmin) .returning(columns.userAdmin)
.returning(withMetadata) .returning(withMetadata)
.executeTakeFirstOrThrow(); .executeTakeFirstOrThrow();
@ -213,24 +213,24 @@ export class UserRepository {
delete(user: { id: string }, hard?: boolean) { delete(user: { id: string }, hard?: boolean) {
return hard return hard
? this.db.deleteFrom('users').where('id', '=', user.id).execute() ? this.db.deleteFrom('user').where('id', '=', user.id).execute()
: this.db.updateTable('users').set({ deletedAt: new Date() }).where('id', '=', user.id).execute(); : this.db.updateTable('user').set({ deletedAt: new Date() }).where('id', '=', user.id).execute();
} }
@GenerateSql() @GenerateSql()
getUserStats() { getUserStats() {
return this.db return this.db
.selectFrom('users') .selectFrom('user')
.leftJoin('assets', (join) => join.onRef('assets.ownerId', '=', 'users.id').on('assets.deletedAt', 'is', null)) .leftJoin('asset', (join) => join.onRef('asset.ownerId', '=', 'user.id').on('asset.deletedAt', 'is', null))
.leftJoin('exif', 'exif.assetId', 'assets.id') .leftJoin('asset_exif', 'asset_exif.assetId', 'asset.id')
.select(['users.id as userId', 'users.name as userName', 'users.quotaSizeInBytes']) .select(['user.id as userId', 'user.name as userName', 'user.quotaSizeInBytes'])
.select((eb) => [ .select((eb) => [
eb.fn eb.fn
.countAll<number>() .countAll<number>()
.filterWhere((eb) => .filterWhere((eb) =>
eb.and([ eb.and([
eb('assets.type', '=', sql.lit(AssetType.IMAGE)), eb('asset.type', '=', sql.lit(AssetType.IMAGE)),
eb('assets.visibility', '!=', sql.lit(AssetVisibility.HIDDEN)), eb('asset.visibility', '!=', sql.lit(AssetVisibility.HIDDEN)),
]), ]),
) )
.as('photos'), .as('photos'),
@ -238,20 +238,23 @@ export class UserRepository {
.countAll<number>() .countAll<number>()
.filterWhere((eb) => .filterWhere((eb) =>
eb.and([ eb.and([
eb('assets.type', '=', sql.lit(AssetType.VIDEO)), eb('asset.type', '=', sql.lit(AssetType.VIDEO)),
eb('assets.visibility', '!=', sql.lit(AssetVisibility.HIDDEN)), eb('asset.visibility', '!=', sql.lit(AssetVisibility.HIDDEN)),
]), ]),
) )
.as('videos'), .as('videos'),
eb.fn eb.fn
.coalesce(eb.fn.sum<number>('exif.fileSizeInByte').filterWhere('assets.libraryId', 'is', null), eb.lit(0)) .coalesce(
eb.fn.sum<number>('asset_exif.fileSizeInByte').filterWhere('asset.libraryId', 'is', null),
eb.lit(0),
)
.as('usage'), .as('usage'),
eb.fn eb.fn
.coalesce( .coalesce(
eb.fn eb.fn
.sum<number>('exif.fileSizeInByte') .sum<number>('asset_exif.fileSizeInByte')
.filterWhere((eb) => .filterWhere((eb) =>
eb.and([eb('assets.libraryId', 'is', null), eb('assets.type', '=', sql.lit(AssetType.IMAGE))]), eb.and([eb('asset.libraryId', 'is', null), eb('asset.type', '=', sql.lit(AssetType.IMAGE))]),
), ),
eb.lit(0), eb.lit(0),
) )
@ -259,45 +262,45 @@ export class UserRepository {
eb.fn eb.fn
.coalesce( .coalesce(
eb.fn eb.fn
.sum<number>('exif.fileSizeInByte') .sum<number>('asset_exif.fileSizeInByte')
.filterWhere((eb) => .filterWhere((eb) =>
eb.and([eb('assets.libraryId', 'is', null), eb('assets.type', '=', sql.lit(AssetType.VIDEO))]), eb.and([eb('asset.libraryId', 'is', null), eb('asset.type', '=', sql.lit(AssetType.VIDEO))]),
), ),
eb.lit(0), eb.lit(0),
) )
.as('usageVideos'), .as('usageVideos'),
]) ])
.groupBy('users.id') .groupBy('user.id')
.orderBy('users.createdAt', 'asc') .orderBy('user.createdAt', 'asc')
.execute(); .execute();
} }
@GenerateSql({ params: [DummyValue.UUID, DummyValue.NUMBER] }) @GenerateSql({ params: [DummyValue.UUID, DummyValue.NUMBER] })
async updateUsage(id: string, delta: number): Promise<void> { async updateUsage(id: string, delta: number): Promise<void> {
await this.db await this.db
.updateTable('users') .updateTable('user')
.set({ quotaUsageInBytes: sql`"quotaUsageInBytes" + ${delta}`, updatedAt: new Date() }) .set({ quotaUsageInBytes: sql`"quotaUsageInBytes" + ${delta}`, updatedAt: new Date() })
.where('id', '=', asUuid(id)) .where('id', '=', asUuid(id))
.where('users.deletedAt', 'is', null) .where('user.deletedAt', 'is', null)
.execute(); .execute();
} }
@GenerateSql({ params: [DummyValue.UUID] }) @GenerateSql({ params: [DummyValue.UUID] })
async syncUsage(id?: string) { async syncUsage(id?: string) {
const query = this.db const query = this.db
.updateTable('users') .updateTable('user')
.set({ .set({
quotaUsageInBytes: (eb) => quotaUsageInBytes: (eb) =>
eb eb
.selectFrom('assets') .selectFrom('asset')
.leftJoin('exif', 'exif.assetId', 'assets.id') .leftJoin('asset_exif', 'asset_exif.assetId', 'asset.id')
.select((eb) => eb.fn.coalesce(eb.fn.sum<number>('exif.fileSizeInByte'), eb.lit(0)).as('usage')) .select((eb) => eb.fn.coalesce(eb.fn.sum<number>('asset_exif.fileSizeInByte'), eb.lit(0)).as('usage'))
.where('assets.libraryId', 'is', null) .where('asset.libraryId', 'is', null)
.where('assets.ownerId', '=', eb.ref('users.id')), .where('asset.ownerId', '=', eb.ref('user.id')),
updatedAt: new Date(), updatedAt: new Date(),
}) })
.where('users.deletedAt', 'is', null) .where('user.deletedAt', 'is', null)
.$if(id != undefined, (eb) => eb.where('users.id', '=', asUuid(id!))); .$if(id != undefined, (eb) => eb.where('user.id', '=', asUuid(id!)));
await query.execute(); await query.execute();
} }

View File

@ -11,8 +11,8 @@ export class ViewRepository {
@GenerateSql({ params: [DummyValue.UUID] }) @GenerateSql({ params: [DummyValue.UUID] })
async getUniqueOriginalPaths(userId: string) { async getUniqueOriginalPaths(userId: string) {
const results = await this.db const results = await this.db
.selectFrom('assets') .selectFrom('asset')
.select((eb) => eb.fn<string>('substring', ['assets.originalPath', eb.val('^(.*/)[^/]*$')]).as('directoryPath')) .select((eb) => eb.fn<string>('substring', ['asset.originalPath', eb.val('^(.*/)[^/]*$')]).as('directoryPath'))
.distinct() .distinct()
.where('ownerId', '=', asUuid(userId)) .where('ownerId', '=', asUuid(userId))
.where('visibility', '=', AssetVisibility.TIMELINE) .where('visibility', '=', AssetVisibility.TIMELINE)
@ -30,8 +30,8 @@ export class ViewRepository {
const normalizedPath = partialPath.replaceAll(/\/$/g, ''); const normalizedPath = partialPath.replaceAll(/\/$/g, '');
return this.db return this.db
.selectFrom('assets') .selectFrom('asset')
.selectAll('assets') .selectAll('asset')
.$call(withExif) .$call(withExif)
.where('ownerId', '=', asUuid(userId)) .where('ownerId', '=', asUuid(userId))
.where('visibility', '=', AssetVisibility.TIMELINE) .where('visibility', '=', AssetVisibility.TIMELINE)
@ -42,7 +42,7 @@ export class ViewRepository {
.where('originalPath', 'like', `%${normalizedPath}/%`) .where('originalPath', 'like', `%${normalizedPath}/%`)
.where('originalPath', 'not like', `%${normalizedPath}/%/%`) .where('originalPath', 'not like', `%${normalizedPath}/%/%`)
.orderBy( .orderBy(
(eb) => eb.fn('regexp_replace', ['assets.originalPath', eb.val('.*/(.+)'), eb.val(String.raw`\1`)]), (eb) => eb.fn('regexp_replace', ['asset.originalPath', eb.val('.*/(.+)'), eb.val(String.raw`\1`)]),
'asc', 'asc',
) )
.execute(); .execute();

View File

@ -28,7 +28,7 @@ export const album_user_after_insert = registerFunction({
language: 'PLPGSQL', language: 'PLPGSQL',
body: ` body: `
BEGIN BEGIN
UPDATE albums SET "updatedAt" = clock_timestamp(), "updateId" = immich_uuid_v7(clock_timestamp()) UPDATE album SET "updatedAt" = clock_timestamp(), "updateId" = immich_uuid_v7(clock_timestamp())
WHERE "id" IN (SELECT DISTINCT "albumsId" FROM inserted_rows); WHERE "id" IN (SELECT DISTINCT "albumsId" FROM inserted_rows);
RETURN NULL; RETURN NULL;
END`, END`,
@ -80,83 +80,83 @@ export const ll_to_earth_public = registerFunction({
body: `SELECT public.cube(public.cube(public.cube(public.earth()*cos(radians(latitude))*cos(radians(longitude))),public.earth()*cos(radians(latitude))*sin(radians(longitude))),public.earth()*sin(radians(latitude)))::public.earth`, body: `SELECT public.cube(public.cube(public.cube(public.earth()*cos(radians(latitude))*cos(radians(longitude))),public.earth()*cos(radians(latitude))*sin(radians(longitude))),public.earth()*sin(radians(latitude)))::public.earth`,
}); });
export const users_delete_audit = registerFunction({ export const user_delete_audit = registerFunction({
name: 'users_delete_audit', name: 'user_delete_audit',
returnType: 'TRIGGER', returnType: 'TRIGGER',
language: 'PLPGSQL', language: 'PLPGSQL',
body: ` body: `
BEGIN BEGIN
INSERT INTO users_audit ("userId") INSERT INTO user_audit ("userId")
SELECT "id" SELECT "id"
FROM OLD; FROM OLD;
RETURN NULL; RETURN NULL;
END`, END`,
}); });
export const partners_delete_audit = registerFunction({ export const partner_delete_audit = registerFunction({
name: 'partners_delete_audit', name: 'partner_delete_audit',
returnType: 'TRIGGER', returnType: 'TRIGGER',
language: 'PLPGSQL', language: 'PLPGSQL',
body: ` body: `
BEGIN BEGIN
INSERT INTO partners_audit ("sharedById", "sharedWithId") INSERT INTO partner_audit ("sharedById", "sharedWithId")
SELECT "sharedById", "sharedWithId" SELECT "sharedById", "sharedWithId"
FROM OLD; FROM OLD;
RETURN NULL; RETURN NULL;
END`, END`,
}); });
export const assets_delete_audit = registerFunction({ export const asset_delete_audit = registerFunction({
name: 'assets_delete_audit', name: 'asset_delete_audit',
returnType: 'TRIGGER', returnType: 'TRIGGER',
language: 'PLPGSQL', language: 'PLPGSQL',
body: ` body: `
BEGIN BEGIN
INSERT INTO assets_audit ("assetId", "ownerId") INSERT INTO asset_audit ("assetId", "ownerId")
SELECT "id", "ownerId" SELECT "id", "ownerId"
FROM OLD; FROM OLD;
RETURN NULL; RETURN NULL;
END`, END`,
}); });
export const albums_delete_audit = registerFunction({ export const album_delete_audit = registerFunction({
name: 'albums_delete_audit', name: 'album_delete_audit',
returnType: 'TRIGGER', returnType: 'TRIGGER',
language: 'PLPGSQL', language: 'PLPGSQL',
body: ` body: `
BEGIN BEGIN
INSERT INTO albums_audit ("albumId", "userId") INSERT INTO album_audit ("albumId", "userId")
SELECT "id", "ownerId" SELECT "id", "ownerId"
FROM OLD; FROM OLD;
RETURN NULL; RETURN NULL;
END`, END`,
}); });
export const album_assets_delete_audit = registerFunction({ export const album_asset_delete_audit = registerFunction({
name: 'album_assets_delete_audit', name: 'album_asset_delete_audit',
returnType: 'TRIGGER', returnType: 'TRIGGER',
language: 'PLPGSQL', language: 'PLPGSQL',
body: ` body: `
BEGIN BEGIN
INSERT INTO album_assets_audit ("albumId", "assetId") INSERT INTO album_asset_audit ("albumId", "assetId")
SELECT "albumsId", "assetsId" FROM OLD SELECT "albumsId", "assetsId" FROM OLD
WHERE "albumsId" IN (SELECT "id" FROM albums WHERE "id" IN (SELECT "albumsId" FROM OLD)); WHERE "albumsId" IN (SELECT "id" FROM album WHERE "id" IN (SELECT "albumsId" FROM OLD));
RETURN NULL; RETURN NULL;
END`, END`,
}); });
export const album_users_delete_audit = registerFunction({ export const album_user_delete_audit = registerFunction({
name: 'album_users_delete_audit', name: 'album_user_delete_audit',
returnType: 'TRIGGER', returnType: 'TRIGGER',
language: 'PLPGSQL', language: 'PLPGSQL',
body: ` body: `
BEGIN BEGIN
INSERT INTO albums_audit ("albumId", "userId") INSERT INTO album_audit ("albumId", "userId")
SELECT "albumsId", "usersId" SELECT "albumsId", "usersId"
FROM OLD; FROM OLD;
IF pg_trigger_depth() = 1 THEN IF pg_trigger_depth() = 1 THEN
INSERT INTO album_users_audit ("albumId", "userId") INSERT INTO album_user_audit ("albumId", "userId")
SELECT "albumsId", "usersId" SELECT "albumsId", "usersId"
FROM OLD; FROM OLD;
END IF; END IF;
@ -165,39 +165,39 @@ export const album_users_delete_audit = registerFunction({
END`, END`,
}); });
export const memories_delete_audit = registerFunction({ export const memory_delete_audit = registerFunction({
name: 'memories_delete_audit', name: 'memory_delete_audit',
returnType: 'TRIGGER', returnType: 'TRIGGER',
language: 'PLPGSQL', language: 'PLPGSQL',
body: ` body: `
BEGIN BEGIN
INSERT INTO memories_audit ("memoryId", "userId") INSERT INTO memory_audit ("memoryId", "userId")
SELECT "id", "ownerId" SELECT "id", "ownerId"
FROM OLD; FROM OLD;
RETURN NULL; RETURN NULL;
END`, END`,
}); });
export const memory_assets_delete_audit = registerFunction({ export const memory_asset_delete_audit = registerFunction({
name: 'memory_assets_delete_audit', name: 'memory_asset_delete_audit',
returnType: 'TRIGGER', returnType: 'TRIGGER',
language: 'PLPGSQL', language: 'PLPGSQL',
body: ` body: `
BEGIN BEGIN
INSERT INTO memory_assets_audit ("memoryId", "assetId") INSERT INTO memory_asset_audit ("memoryId", "assetId")
SELECT "memoriesId", "assetsId" FROM OLD SELECT "memoriesId", "assetsId" FROM OLD
WHERE "memoriesId" IN (SELECT "id" FROM memories WHERE "id" IN (SELECT "memoriesId" FROM OLD)); WHERE "memoriesId" IN (SELECT "id" FROM memory WHERE "id" IN (SELECT "memoriesId" FROM OLD));
RETURN NULL; RETURN NULL;
END`, END`,
}); });
export const stacks_delete_audit = registerFunction({ export const stack_delete_audit = registerFunction({
name: 'stacks_delete_audit', name: 'stack_delete_audit',
returnType: 'TRIGGER', returnType: 'TRIGGER',
language: 'PLPGSQL', language: 'PLPGSQL',
body: ` body: `
BEGIN BEGIN
INSERT INTO stacks_audit ("stackId", "userId") INSERT INTO stack_audit ("stackId", "userId")
SELECT "id", "ownerId" SELECT "id", "ownerId"
FROM OLD; FROM OLD;
RETURN NULL; RETURN NULL;

View File

@ -1,20 +1,21 @@
import { asset_face_source_type, asset_visibility_enum, assets_status_enum } from 'src/schema/enums'; import { asset_face_source_type, asset_visibility_enum, assets_status_enum } from 'src/schema/enums';
import { import {
album_delete_audit,
album_user_after_insert, album_user_after_insert,
album_users_delete_audit, album_user_delete_audit,
albums_delete_audit, asset_delete_audit,
assets_delete_audit,
f_concat_ws, f_concat_ws,
f_unaccent, f_unaccent,
immich_uuid_v7, immich_uuid_v7,
ll_to_earth_public, ll_to_earth_public,
memories_delete_audit, memory_asset_delete_audit,
memory_assets_delete_audit, memory_delete_audit,
partners_delete_audit, partner_delete_audit,
person_delete_audit, person_delete_audit,
stacks_delete_audit, stack_delete_audit,
updated_at, updated_at,
users_delete_audit, user_delete_audit,
user_metadata_audit,
} from 'src/schema/functions'; } from 'src/schema/functions';
import { ActivityTable } from 'src/schema/tables/activity.table'; import { ActivityTable } from 'src/schema/tables/activity.table';
import { AlbumAssetAuditTable } from 'src/schema/tables/album-asset-audit.table'; import { AlbumAssetAuditTable } from 'src/schema/tables/album-asset-audit.table';
@ -25,12 +26,12 @@ import { AlbumUserTable } from 'src/schema/tables/album-user.table';
import { AlbumTable } from 'src/schema/tables/album.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 { AssetAuditTable } from 'src/schema/tables/asset-audit.table';
import { AssetExifTable } from 'src/schema/tables/asset-exif.table';
import { AssetFaceTable } from 'src/schema/tables/asset-face.table'; import { AssetFaceTable } from 'src/schema/tables/asset-face.table';
import { AssetFileTable } from 'src/schema/tables/asset-files.table'; import { AssetFileTable } from 'src/schema/tables/asset-file.table';
import { AssetJobStatusTable } from 'src/schema/tables/asset-job-status.table'; import { AssetJobStatusTable } from 'src/schema/tables/asset-job-status.table';
import { AssetTable } from 'src/schema/tables/asset.table'; import { AssetTable } from 'src/schema/tables/asset.table';
import { AuditTable } from 'src/schema/tables/audit.table'; import { AuditTable } from 'src/schema/tables/audit.table';
import { ExifTable } from 'src/schema/tables/exif.table';
import { FaceSearchTable } from 'src/schema/tables/face-search.table'; import { FaceSearchTable } from 'src/schema/tables/face-search.table';
import { GeodataPlacesTable } from 'src/schema/tables/geodata-places.table'; import { GeodataPlacesTable } from 'src/schema/tables/geodata-places.table';
import { LibraryTable } from 'src/schema/tables/library.table'; import { LibraryTable } from 'src/schema/tables/library.table';
@ -81,7 +82,7 @@ export class ImmichDatabase {
AssetTable, AssetTable,
AssetFileTable, AssetFileTable,
AuditTable, AuditTable,
ExifTable, AssetExifTable,
FaceSearchTable, FaceSearchTable,
GeodataPlacesTable, GeodataPlacesTable,
LibraryTable, LibraryTable,
@ -120,17 +121,17 @@ export class ImmichDatabase {
f_concat_ws, f_concat_ws,
f_unaccent, f_unaccent,
ll_to_earth_public, ll_to_earth_public,
users_delete_audit, user_delete_audit,
partners_delete_audit, partner_delete_audit,
assets_delete_audit, asset_delete_audit,
albums_delete_audit, album_delete_audit,
album_user_after_insert, album_user_after_insert,
album_users_delete_audit, album_user_delete_audit,
memories_delete_audit, memory_delete_audit,
memory_assets_delete_audit, memory_asset_delete_audit,
stacks_delete_audit, stack_delete_audit,
person_delete_audit, person_delete_audit,
users_delete_audit, user_metadata_audit,
]; ];
enum = [assets_status_enum, asset_face_source_type, asset_visibility_enum]; enum = [assets_status_enum, asset_face_source_type, asset_visibility_enum];
@ -144,49 +145,71 @@ export interface Migrations {
export interface DB { export interface DB {
activity: ActivityTable; activity: ActivityTable;
albums: AlbumTable;
albums_audit: AlbumAuditTable; album: AlbumTable;
albums_assets_assets: AlbumAssetTable; album_audit: AlbumAuditTable;
album_assets_audit: AlbumAssetAuditTable; album_asset: AlbumAssetTable;
albums_shared_users_users: AlbumUserTable; album_asset_audit: AlbumAssetAuditTable;
album_users_audit: AlbumUserAuditTable; album_user: AlbumUserTable;
api_keys: ApiKeyTable; album_user_audit: AlbumUserAuditTable;
asset_faces: AssetFaceTable;
asset_files: AssetFileTable; api_key: ApiKeyTable;
asset: AssetTable;
asset_exif: AssetExifTable;
asset_face: AssetFaceTable;
asset_file: AssetFileTable;
asset_job_status: AssetJobStatusTable; asset_job_status: AssetJobStatusTable;
asset_stack: StackTable; asset_audit: AssetAuditTable;
assets: AssetTable;
assets_audit: AssetAuditTable;
audit: AuditTable; audit: AuditTable;
exif: ExifTable;
face_search: FaceSearchTable; face_search: FaceSearchTable;
geodata_places: GeodataPlacesTable; geodata_places: GeodataPlacesTable;
libraries: LibraryTable;
memories: MemoryTable; library: LibraryTable;
memories_audit: MemoryAuditTable;
memories_assets_assets: MemoryAssetTable; memory: MemoryTable;
memory_assets_audit: MemoryAssetAuditTable; memory_audit: MemoryAuditTable;
memory_asset: MemoryAssetTable;
memory_asset_audit: MemoryAssetAuditTable;
migrations: Migrations; migrations: Migrations;
notifications: NotificationTable;
notification: NotificationTable;
move_history: MoveTable; move_history: MoveTable;
naturalearth_countries: NaturalEarthCountriesTable; naturalearth_countries: NaturalEarthCountriesTable;
partners_audit: PartnerAuditTable;
partners: PartnerTable; partner: PartnerTable;
partner_audit: PartnerAuditTable;
person: PersonTable; person: PersonTable;
person_audit: PersonAuditTable; person_audit: PersonAuditTable;
sessions: SessionTable;
session_sync_checkpoints: SessionSyncCheckpointTable; session: SessionTable;
shared_link__asset: SharedLinkAssetTable; session_sync_checkpoint: SessionSyncCheckpointTable;
shared_links: SharedLinkTable;
shared_link: SharedLinkTable;
shared_link_asset: SharedLinkAssetTable;
smart_search: SmartSearchTable; smart_search: SmartSearchTable;
stacks_audit: StackAuditTable;
stack: StackTable;
stack_audit: StackAuditTable;
system_metadata: SystemMetadataTable; system_metadata: SystemMetadataTable;
tag: TagTable;
tag_asset: TagAssetTable; tag_asset: TagAssetTable;
tags: TagTable; tag_closure: TagClosureTable;
tags_closure: TagClosureTable;
user: UserTable;
user_audit: UserAuditTable;
user_metadata: UserMetadataTable; user_metadata: UserMetadataTable;
user_metadata_audit: UserMetadataAuditTable; user_metadata_audit: UserMetadataAuditTable;
users: UserTable;
users_audit: UserAuditTable;
version_history: VersionHistoryTable; version_history: VersionHistoryTable;
} }

File diff suppressed because it is too large Load Diff

View File

@ -18,19 +18,18 @@ import {
} from 'src/sql-tools'; } from 'src/sql-tools';
@Table('activity') @Table('activity')
@UpdatedAtTrigger('activity_updated_at') @UpdatedAtTrigger('activity_updatedAt')
@Index({ @Index({
name: 'IDX_activity_like', name: 'activity_like_idx',
columns: ['assetId', 'userId', 'albumId'], columns: ['assetId', 'userId', 'albumId'],
unique: true, unique: true,
where: '("isLiked" = true)', where: '("isLiked" = true)',
}) })
@Check({ @Check({
name: 'CHK_2ab1e70f113f450eb40c1e3ec8', name: 'activity_like_check',
expression: `("comment" IS NULL AND "isLiked" = true) OR ("comment" IS NOT NULL AND "isLiked" = false)`, expression: `(comment IS NULL AND "isLiked" = true) OR (comment IS NOT NULL AND "isLiked" = false)`,
}) })
@ForeignKeyConstraint({ @ForeignKeyConstraint({
name: 'fk_activity_album_asset_composite',
columns: ['albumId', 'assetId'], columns: ['albumId', 'assetId'],
referenceTable: () => AlbumAssetTable, referenceTable: () => AlbumAssetTable,
referenceColumns: ['albumsId', 'assetsId'], referenceColumns: ['albumsId', 'assetsId'],
@ -62,6 +61,6 @@ export class ActivityTable {
@Column({ type: 'boolean', default: false }) @Column({ type: 'boolean', default: false })
isLiked!: Generated<boolean>; isLiked!: Generated<boolean>;
@UpdateIdColumn({ indexName: 'IDX_activity_update_id' }) @UpdateIdColumn({ index: true })
updateId!: Generated<string>; updateId!: Generated<string>;
} }

View File

@ -2,22 +2,20 @@ import { PrimaryGeneratedUuidV7Column } from 'src/decorators';
import { AlbumTable } from 'src/schema/tables/album.table'; import { AlbumTable } from 'src/schema/tables/album.table';
import { Column, CreateDateColumn, ForeignKeyColumn, Generated, Table, Timestamp } from 'src/sql-tools'; import { Column, CreateDateColumn, ForeignKeyColumn, Generated, Table, Timestamp } from 'src/sql-tools';
@Table('album_assets_audit') @Table('album_asset_audit')
export class AlbumAssetAuditTable { export class AlbumAssetAuditTable {
@PrimaryGeneratedUuidV7Column() @PrimaryGeneratedUuidV7Column()
id!: Generated<string>; id!: Generated<string>;
@ForeignKeyColumn(() => AlbumTable, { @ForeignKeyColumn(() => AlbumTable, {
type: 'uuid',
indexName: 'IDX_album_assets_audit_album_id',
onDelete: 'CASCADE', onDelete: 'CASCADE',
onUpdate: 'CASCADE', onUpdate: 'CASCADE',
}) })
albumId!: string; albumId!: string;
@Column({ type: 'uuid', indexName: 'IDX_album_assets_audit_asset_id' }) @Column({ type: 'uuid', index: true })
assetId!: string; assetId!: string;
@CreateDateColumn({ default: () => 'clock_timestamp()', indexName: 'IDX_album_assets_audit_deleted_at' }) @CreateDateColumn({ default: () => 'clock_timestamp()', index: true })
deletedAt!: Generated<Timestamp>; deletedAt!: Generated<Timestamp>;
} }

View File

@ -1,5 +1,5 @@
import { UpdatedAtTrigger, UpdateIdColumn } from 'src/decorators'; import { UpdatedAtTrigger, UpdateIdColumn } from 'src/decorators';
import { album_assets_delete_audit } from 'src/schema/functions'; import { album_asset_delete_audit } from 'src/schema/functions';
import { AlbumTable } from 'src/schema/tables/album.table'; import { AlbumTable } from 'src/schema/tables/album.table';
import { AssetTable } from 'src/schema/tables/asset.table'; import { AssetTable } from 'src/schema/tables/asset.table';
import { import {
@ -12,11 +12,11 @@ import {
UpdateDateColumn, UpdateDateColumn,
} from 'src/sql-tools'; } from 'src/sql-tools';
@Table({ name: 'albums_assets_assets', primaryConstraintName: 'PK_c67bc36fa845fb7b18e0e398180' }) @Table({ name: 'album_asset' })
@UpdatedAtTrigger('album_assets_updated_at') @UpdatedAtTrigger('album_asset_updatedAt')
@AfterDeleteTrigger({ @AfterDeleteTrigger({
scope: 'statement', scope: 'statement',
function: album_assets_delete_audit, function: album_asset_delete_audit,
referencingOldTableAs: 'old', referencingOldTableAs: 'old',
when: 'pg_trigger_depth() <= 1', when: 'pg_trigger_depth() <= 1',
}) })
@ -33,6 +33,6 @@ export class AlbumAssetTable {
@UpdateDateColumn() @UpdateDateColumn()
updatedAt!: Generated<Timestamp>; updatedAt!: Generated<Timestamp>;
@UpdateIdColumn({ indexName: 'IDX_album_assets_update_id' }) @UpdateIdColumn({ index: true })
updateId!: Generated<string>; updateId!: Generated<string>;
} }

View File

@ -1,17 +1,17 @@
import { PrimaryGeneratedUuidV7Column } from 'src/decorators'; import { PrimaryGeneratedUuidV7Column } from 'src/decorators';
import { Column, CreateDateColumn, Generated, Table, Timestamp } from 'src/sql-tools'; import { Column, CreateDateColumn, Generated, Table, Timestamp } from 'src/sql-tools';
@Table('albums_audit') @Table('album_audit')
export class AlbumAuditTable { export class AlbumAuditTable {
@PrimaryGeneratedUuidV7Column() @PrimaryGeneratedUuidV7Column()
id!: Generated<string>; id!: Generated<string>;
@Column({ type: 'uuid', indexName: 'IDX_albums_audit_album_id' }) @Column({ type: 'uuid', index: true })
albumId!: string; albumId!: string;
@Column({ type: 'uuid', indexName: 'IDX_albums_audit_user_id' }) @Column({ type: 'uuid', index: true })
userId!: string; userId!: string;
@CreateDateColumn({ default: () => 'clock_timestamp()', indexName: 'IDX_albums_audit_deleted_at' }) @CreateDateColumn({ default: () => 'clock_timestamp()', index: true })
deletedAt!: Generated<Timestamp>; deletedAt!: Generated<Timestamp>;
} }

View File

@ -1,17 +1,17 @@
import { PrimaryGeneratedUuidV7Column } from 'src/decorators'; import { PrimaryGeneratedUuidV7Column } from 'src/decorators';
import { Column, CreateDateColumn, Generated, Table, Timestamp } from 'src/sql-tools'; import { Column, CreateDateColumn, Generated, Table, Timestamp } from 'src/sql-tools';
@Table('album_users_audit') @Table('album_user_audit')
export class AlbumUserAuditTable { export class AlbumUserAuditTable {
@PrimaryGeneratedUuidV7Column() @PrimaryGeneratedUuidV7Column()
id!: Generated<string>; id!: Generated<string>;
@Column({ type: 'uuid', indexName: 'IDX_album_users_audit_album_id' }) @Column({ type: 'uuid', index: true })
albumId!: string; albumId!: string;
@Column({ type: 'uuid', indexName: 'IDX_album_users_audit_user_id' }) @Column({ type: 'uuid', index: true })
userId!: string; userId!: string;
@CreateDateColumn({ default: () => 'clock_timestamp()', indexName: 'IDX_album_users_audit_deleted_at' }) @CreateDateColumn({ default: () => 'clock_timestamp()', index: true })
deletedAt!: Generated<Timestamp>; deletedAt!: Generated<Timestamp>;
} }

View File

@ -1,6 +1,6 @@
import { CreateIdColumn, UpdatedAtTrigger, UpdateIdColumn } from 'src/decorators'; import { CreateIdColumn, UpdatedAtTrigger, UpdateIdColumn } from 'src/decorators';
import { AlbumUserRole } from 'src/enum'; import { AlbumUserRole } from 'src/enum';
import { album_user_after_insert, album_users_delete_audit } from 'src/schema/functions'; import { album_user_after_insert, album_user_delete_audit } from 'src/schema/functions';
import { AlbumTable } from 'src/schema/tables/album.table'; import { AlbumTable } from 'src/schema/tables/album.table';
import { UserTable } from 'src/schema/tables/user.table'; import { UserTable } from 'src/schema/tables/user.table';
import { import {
@ -10,17 +10,14 @@ import {
CreateDateColumn, CreateDateColumn,
ForeignKeyColumn, ForeignKeyColumn,
Generated, Generated,
Index,
Table, Table,
Timestamp, Timestamp,
UpdateDateColumn, UpdateDateColumn,
} from 'src/sql-tools'; } from 'src/sql-tools';
@Table({ name: 'albums_shared_users_users', primaryConstraintName: 'PK_7df55657e0b2e8b626330a0ebc8' }) @Table({ name: 'album_user' })
// Pre-existing indices from original album <--> user ManyToMany mapping // Pre-existing indices from original album <--> user ManyToMany mapping
@Index({ name: 'IDX_427c350ad49bd3935a50baab73', columns: ['albumsId'] }) @UpdatedAtTrigger('album_user_updatedAt')
@Index({ name: 'IDX_f48513bf9bccefd6ff3ad30bd0', columns: ['usersId'] })
@UpdatedAtTrigger('album_users_updated_at')
@AfterInsertTrigger({ @AfterInsertTrigger({
name: 'album_user_after_insert', name: 'album_user_after_insert',
scope: 'statement', scope: 'statement',
@ -29,7 +26,7 @@ import {
}) })
@AfterDeleteTrigger({ @AfterDeleteTrigger({
scope: 'statement', scope: 'statement',
function: album_users_delete_audit, function: album_user_delete_audit,
referencingOldTableAs: 'old', referencingOldTableAs: 'old',
when: 'pg_trigger_depth() <= 1', when: 'pg_trigger_depth() <= 1',
}) })
@ -53,13 +50,13 @@ export class AlbumUserTable {
@Column({ type: 'character varying', default: AlbumUserRole.EDITOR }) @Column({ type: 'character varying', default: AlbumUserRole.EDITOR })
role!: Generated<AlbumUserRole>; role!: Generated<AlbumUserRole>;
@CreateIdColumn({ indexName: 'IDX_album_users_create_id' }) @CreateIdColumn({ index: true })
createId!: Generated<string>; createId!: Generated<string>;
@CreateDateColumn() @CreateDateColumn()
createdAt!: Generated<Timestamp>; createdAt!: Generated<Timestamp>;
@UpdateIdColumn({ indexName: 'IDX_album_users_update_id' }) @UpdateIdColumn({ index: true })
updateId!: Generated<string>; updateId!: Generated<string>;
@UpdateDateColumn() @UpdateDateColumn()

View File

@ -1,6 +1,6 @@
import { UpdatedAtTrigger, UpdateIdColumn } from 'src/decorators'; import { UpdatedAtTrigger, UpdateIdColumn } from 'src/decorators';
import { AssetOrder } from 'src/enum'; import { AssetOrder } from 'src/enum';
import { albums_delete_audit } from 'src/schema/functions'; import { album_delete_audit } from 'src/schema/functions';
import { AssetTable } from 'src/schema/tables/asset.table'; import { AssetTable } from 'src/schema/tables/asset.table';
import { UserTable } from 'src/schema/tables/user.table'; import { UserTable } from 'src/schema/tables/user.table';
import { import {
@ -16,11 +16,11 @@ import {
UpdateDateColumn, UpdateDateColumn,
} from 'src/sql-tools'; } from 'src/sql-tools';
@Table({ name: 'albums', primaryConstraintName: 'PK_7f71c7b5bc7c87b8f94c9a93a00' }) @Table({ name: 'album' })
@UpdatedAtTrigger('albums_updated_at') @UpdatedAtTrigger('album_updatedAt')
@AfterDeleteTrigger({ @AfterDeleteTrigger({
scope: 'statement', scope: 'statement',
function: albums_delete_audit, function: album_delete_audit,
referencingOldTableAs: 'old', referencingOldTableAs: 'old',
when: 'pg_trigger_depth() = 0', when: 'pg_trigger_depth() = 0',
}) })
@ -60,6 +60,6 @@ export class AlbumTable {
@Column({ default: AssetOrder.DESC }) @Column({ default: AssetOrder.DESC })
order!: Generated<AssetOrder>; order!: Generated<AssetOrder>;
@UpdateIdColumn({ indexName: 'IDX_albums_update_id' }) @UpdateIdColumn({ index: true })
updateId!: Generated<string>; updateId!: Generated<string>;
} }

View File

@ -12,8 +12,8 @@ import {
UpdateDateColumn, UpdateDateColumn,
} from 'src/sql-tools'; } from 'src/sql-tools';
@Table('api_keys') @Table('api_key')
@UpdatedAtTrigger('api_keys_updated_at') @UpdatedAtTrigger('api_key_updatedAt')
export class ApiKeyTable { export class ApiKeyTable {
@PrimaryGeneratedColumn() @PrimaryGeneratedColumn()
id!: Generated<string>; id!: Generated<string>;
@ -36,6 +36,6 @@ export class ApiKeyTable {
@Column({ array: true, type: 'character varying' }) @Column({ array: true, type: 'character varying' })
permissions!: Permission[]; permissions!: Permission[];
@UpdateIdColumn({ indexName: 'IDX_api_keys_update_id' }) @UpdateIdColumn({ index: true })
updateId!: Generated<string>; updateId!: Generated<string>;
} }

View File

@ -1,17 +1,17 @@
import { PrimaryGeneratedUuidV7Column } from 'src/decorators'; import { PrimaryGeneratedUuidV7Column } from 'src/decorators';
import { Column, CreateDateColumn, Generated, Table, Timestamp } from 'src/sql-tools'; import { Column, CreateDateColumn, Generated, Table, Timestamp } from 'src/sql-tools';
@Table('assets_audit') @Table('asset_audit')
export class AssetAuditTable { export class AssetAuditTable {
@PrimaryGeneratedUuidV7Column() @PrimaryGeneratedUuidV7Column()
id!: Generated<string>; id!: Generated<string>;
@Column({ type: 'uuid', indexName: 'IDX_assets_audit_asset_id' }) @Column({ type: 'uuid', index: true })
assetId!: string; assetId!: string;
@Column({ type: 'uuid', indexName: 'IDX_assets_audit_owner_id' }) @Column({ type: 'uuid', index: true })
ownerId!: string; ownerId!: string;
@CreateDateColumn({ default: () => 'clock_timestamp()', indexName: 'IDX_assets_audit_deleted_at' }) @CreateDateColumn({ default: () => 'clock_timestamp()', index: true })
deletedAt!: Generated<Timestamp>; deletedAt!: Generated<Timestamp>;
} }

View File

@ -2,9 +2,9 @@ import { UpdatedAtTrigger, UpdateIdColumn } from 'src/decorators';
import { AssetTable } from 'src/schema/tables/asset.table'; import { AssetTable } from 'src/schema/tables/asset.table';
import { Column, ForeignKeyColumn, Generated, Int8, Table, Timestamp, UpdateDateColumn } from 'src/sql-tools'; import { Column, ForeignKeyColumn, Generated, Int8, Table, Timestamp, UpdateDateColumn } from 'src/sql-tools';
@Table('exif') @Table('asset_exif')
@UpdatedAtTrigger('asset_exif_updated_at') @UpdatedAtTrigger('asset_exif_updatedAt')
export class ExifTable { export class AssetExifTable {
@ForeignKeyColumn(() => AssetTable, { onDelete: 'CASCADE', primary: true }) @ForeignKeyColumn(() => AssetTable, { onDelete: 'CASCADE', primary: true })
assetId!: string; assetId!: string;
@ -50,7 +50,7 @@ export class ExifTable {
@Column({ type: 'double precision', nullable: true }) @Column({ type: 'double precision', nullable: true })
longitude!: number | null; longitude!: number | null;
@Column({ type: 'character varying', nullable: true, indexName: 'exif_city' }) @Column({ type: 'character varying', nullable: true, index: true })
city!: string | null; city!: string | null;
@Column({ type: 'character varying', nullable: true }) @Column({ type: 'character varying', nullable: true })
@ -68,7 +68,7 @@ export class ExifTable {
@Column({ type: 'character varying', nullable: true }) @Column({ type: 'character varying', nullable: true })
exposureTime!: string | null; exposureTime!: string | null;
@Column({ type: 'character varying', nullable: true, indexName: 'IDX_live_photo_cid' }) @Column({ type: 'character varying', nullable: true, index: true })
livePhotoCID!: string | null; livePhotoCID!: string | null;
@Column({ type: 'character varying', nullable: true }) @Column({ type: 'character varying', nullable: true })
@ -86,7 +86,7 @@ export class ExifTable {
@Column({ type: 'integer', nullable: true }) @Column({ type: 'integer', nullable: true })
bitsPerSample!: number | null; bitsPerSample!: number | null;
@Column({ type: 'character varying', nullable: true, indexName: 'IDX_auto_stack_id' }) @Column({ type: 'character varying', nullable: true, index: true })
autoStackId!: string | null; autoStackId!: string | null;
@Column({ type: 'integer', nullable: true }) @Column({ type: 'integer', nullable: true })
@ -95,6 +95,6 @@ export class ExifTable {
@UpdateDateColumn({ default: () => 'clock_timestamp()' }) @UpdateDateColumn({ default: () => 'clock_timestamp()' })
updatedAt!: Generated<Date>; updatedAt!: Generated<Date>;
@UpdateIdColumn({ indexName: 'IDX_asset_exif_update_id' }) @UpdateIdColumn({ index: true })
updateId!: Generated<string>; updateId!: Generated<string>;
} }

View File

@ -13,8 +13,9 @@ import {
Timestamp, Timestamp,
} from 'src/sql-tools'; } from 'src/sql-tools';
@Table({ name: 'asset_faces' }) @Table({ name: 'asset_face' })
@Index({ name: 'IDX_asset_faces_assetId_personId', columns: ['assetId', 'personId'] }) // schemaFromDatabase does not preserve column order
@Index({ name: 'asset_face_assetId_personId_idx', columns: ['assetId', 'personId'] })
@Index({ columns: ['personId', 'assetId'] }) @Index({ columns: ['personId', 'assetId'] })
export class AssetFaceTable { export class AssetFaceTable {
@PrimaryGeneratedColumn() @PrimaryGeneratedColumn()

View File

@ -13,18 +13,14 @@ import {
UpdateDateColumn, UpdateDateColumn,
} from 'src/sql-tools'; } from 'src/sql-tools';
@Table('asset_files') @Table('asset_file')
@Unique({ name: 'UQ_assetId_type', columns: ['assetId', 'type'] }) @Unique({ columns: ['assetId', 'type'] })
@UpdatedAtTrigger('asset_files_updated_at') @UpdatedAtTrigger('asset_file_updatedAt')
export class AssetFileTable { export class AssetFileTable {
@PrimaryGeneratedColumn() @PrimaryGeneratedColumn()
id!: Generated<string>; id!: Generated<string>;
@ForeignKeyColumn(() => AssetTable, { @ForeignKeyColumn(() => AssetTable, { onDelete: 'CASCADE', onUpdate: 'CASCADE' })
onDelete: 'CASCADE',
onUpdate: 'CASCADE',
indexName: 'IDX_asset_files_assetId',
})
assetId!: string; assetId!: string;
@CreateDateColumn() @CreateDateColumn()
@ -39,6 +35,6 @@ export class AssetFileTable {
@Column() @Column()
path!: string; path!: string;
@UpdateIdColumn({ indexName: 'IDX_asset_files_update_id' }) @UpdateIdColumn({ index: true })
updateId!: Generated<string>; updateId!: Generated<string>;
} }

View File

@ -1,7 +1,7 @@
import { UpdatedAtTrigger, UpdateIdColumn } from 'src/decorators'; import { UpdatedAtTrigger, UpdateIdColumn } from 'src/decorators';
import { AssetStatus, AssetType, AssetVisibility } from 'src/enum'; import { AssetStatus, AssetType, AssetVisibility } from 'src/enum';
import { asset_visibility_enum, assets_status_enum } from 'src/schema/enums'; import { asset_visibility_enum, assets_status_enum } from 'src/schema/enums';
import { assets_delete_audit } from 'src/schema/functions'; import { asset_delete_audit } from 'src/schema/functions';
import { LibraryTable } from 'src/schema/tables/library.table'; import { LibraryTable } from 'src/schema/tables/library.table';
import { StackTable } from 'src/schema/tables/stack.table'; import { StackTable } from 'src/schema/tables/stack.table';
import { UserTable } from 'src/schema/tables/user.table'; import { UserTable } from 'src/schema/tables/user.table';
@ -20,11 +20,11 @@ import {
} from 'src/sql-tools'; } from 'src/sql-tools';
import { ASSET_CHECKSUM_CONSTRAINT } from 'src/utils/database'; import { ASSET_CHECKSUM_CONSTRAINT } from 'src/utils/database';
@Table('assets') @Table('asset')
@UpdatedAtTrigger('assets_updated_at') @UpdatedAtTrigger('asset_updatedAt')
@AfterDeleteTrigger({ @AfterDeleteTrigger({
scope: 'statement', scope: 'statement',
function: assets_delete_audit, function: asset_delete_audit,
referencingOldTableAs: 'old', referencingOldTableAs: 'old',
when: 'pg_trigger_depth() = 0', when: 'pg_trigger_depth() = 0',
}) })
@ -36,23 +36,22 @@ import { ASSET_CHECKSUM_CONSTRAINT } from 'src/utils/database';
where: '("libraryId" IS NULL)', where: '("libraryId" IS NULL)',
}) })
@Index({ @Index({
name: 'UQ_assets_owner_library_checksum' + '',
columns: ['ownerId', 'libraryId', 'checksum'], columns: ['ownerId', 'libraryId', 'checksum'],
unique: true, unique: true,
where: '("libraryId" IS NOT NULL)', where: '("libraryId" IS NOT NULL)',
}) })
@Index({ @Index({
name: 'idx_local_date_time', name: 'asset_localDateTime_idx',
expression: `(("localDateTime" at time zone 'UTC')::date)`, expression: `(("localDateTime" at time zone 'UTC')::date)`,
}) })
@Index({ @Index({
name: 'idx_local_date_time_month', name: 'asset_localDateTime_month_idx',
expression: `(date_trunc('MONTH'::text, ("localDateTime" AT TIME ZONE 'UTC'::text)) AT TIME ZONE 'UTC'::text)`, expression: `(date_trunc('MONTH'::text, ("localDateTime" AT TIME ZONE 'UTC'::text)) AT TIME ZONE 'UTC'::text)`,
}) })
@Index({ name: 'IDX_originalPath_libraryId', columns: ['originalPath', 'libraryId'] }) @Index({ columns: ['originalPath', 'libraryId'] })
@Index({ name: 'IDX_asset_id_stackId', columns: ['id', 'stackId'] }) @Index({ columns: ['id', 'stackId'] })
@Index({ @Index({
name: 'idx_originalfilename_trigram', name: 'asset_originalFilename_trigram_idx',
using: 'gin', using: 'gin',
expression: 'f_unaccent("originalFileName") gin_trgm_ops', expression: 'f_unaccent("originalFileName") gin_trgm_ops',
}) })
@ -76,7 +75,7 @@ export class AssetTable {
@Column() @Column()
originalPath!: string; originalPath!: string;
@Column({ type: 'timestamp with time zone', indexName: 'idx_asset_file_created_at' }) @Column({ type: 'timestamp with time zone', index: true })
fileCreatedAt!: Timestamp; fileCreatedAt!: Timestamp;
@Column({ type: 'timestamp with time zone' }) @Column({ type: 'timestamp with time zone' })
@ -130,13 +129,13 @@ export class AssetTable {
@ForeignKeyColumn(() => StackTable, { nullable: true, onDelete: 'SET NULL', onUpdate: 'CASCADE' }) @ForeignKeyColumn(() => StackTable, { nullable: true, onDelete: 'SET NULL', onUpdate: 'CASCADE' })
stackId!: string | null; stackId!: string | null;
@Column({ type: 'uuid', nullable: true, indexName: 'IDX_assets_duplicateId' }) @Column({ type: 'uuid', nullable: true, index: true })
duplicateId!: string | null; duplicateId!: string | null;
@Column({ enum: assets_status_enum, default: AssetStatus.ACTIVE }) @Column({ enum: assets_status_enum, default: AssetStatus.ACTIVE })
status!: Generated<AssetStatus>; status!: Generated<AssetStatus>;
@UpdateIdColumn({ indexName: 'IDX_assets_update_id' }) @UpdateIdColumn({ index: true })
updateId!: Generated<string>; updateId!: Generated<string>;
@Column({ enum: asset_visibility_enum, default: AssetVisibility.TIMELINE }) @Column({ enum: asset_visibility_enum, default: AssetVisibility.TIMELINE })

View File

@ -2,7 +2,7 @@ import { DatabaseAction, EntityType } from 'src/enum';
import { Column, CreateDateColumn, Generated, Index, PrimaryColumn, Table, Timestamp } from 'src/sql-tools'; import { Column, CreateDateColumn, Generated, Index, PrimaryColumn, Table, Timestamp } from 'src/sql-tools';
@Table('audit') @Table('audit')
@Index({ name: 'IDX_ownerId_createdAt', columns: ['ownerId', 'createdAt'] }) @Index({ columns: ['ownerId', 'createdAt'] })
export class AuditTable { export class AuditTable {
@PrimaryColumn({ type: 'serial', synchronize: false }) @PrimaryColumn({ type: 'serial', synchronize: false })
id!: Generated<number>; id!: Generated<number>;

View File

@ -1,7 +1,7 @@
import { AssetFaceTable } from 'src/schema/tables/asset-face.table'; import { AssetFaceTable } from 'src/schema/tables/asset-face.table';
import { Column, ForeignKeyColumn, Index, Table } from 'src/sql-tools'; import { Column, ForeignKeyColumn, Index, Table } from 'src/sql-tools';
@Table({ name: 'face_search', primaryConstraintName: 'face_search_pkey' }) @Table({ name: 'face_search' })
@Index({ @Index({
name: 'face_index', name: 'face_index',
using: 'hnsw', using: 'hnsw',
@ -9,11 +9,7 @@ import { Column, ForeignKeyColumn, Index, Table } from 'src/sql-tools';
with: 'ef_construction = 300, m = 16', with: 'ef_construction = 300, m = 16',
}) })
export class FaceSearchTable { export class FaceSearchTable {
@ForeignKeyColumn(() => AssetFaceTable, { @ForeignKeyColumn(() => AssetFaceTable, { onDelete: 'CASCADE', primary: true })
onDelete: 'CASCADE',
primary: true,
constraintName: 'face_search_faceId_fkey',
})
faceId!: string; faceId!: string;
@Column({ type: 'vector', length: 512, synchronize: false }) @Column({ type: 'vector', length: 512, synchronize: false })

View File

@ -12,8 +12,8 @@ import {
UpdateDateColumn, UpdateDateColumn,
} from 'src/sql-tools'; } from 'src/sql-tools';
@Table('libraries') @Table('library')
@UpdatedAtTrigger('libraries_updated_at') @UpdatedAtTrigger('library_updatedAt')
export class LibraryTable { export class LibraryTable {
@PrimaryGeneratedColumn() @PrimaryGeneratedColumn()
id!: Generated<string>; id!: Generated<string>;
@ -42,6 +42,6 @@ export class LibraryTable {
@Column({ type: 'timestamp with time zone', nullable: true }) @Column({ type: 'timestamp with time zone', nullable: true })
refreshedAt!: Timestamp | null; refreshedAt!: Timestamp | null;
@UpdateIdColumn({ indexName: 'IDX_libraries_update_id' }) @UpdateIdColumn({ index: true })
updateId!: Generated<string>; updateId!: Generated<string>;
} }

View File

@ -2,22 +2,17 @@ import { PrimaryGeneratedUuidV7Column } from 'src/decorators';
import { MemoryTable } from 'src/schema/tables/memory.table'; import { MemoryTable } from 'src/schema/tables/memory.table';
import { Column, CreateDateColumn, ForeignKeyColumn, Table } from 'src/sql-tools'; import { Column, CreateDateColumn, ForeignKeyColumn, Table } from 'src/sql-tools';
@Table('memory_assets_audit') @Table('memory_asset_audit')
export class MemoryAssetAuditTable { export class MemoryAssetAuditTable {
@PrimaryGeneratedUuidV7Column() @PrimaryGeneratedUuidV7Column()
id!: string; id!: string;
@ForeignKeyColumn(() => MemoryTable, { @ForeignKeyColumn(() => MemoryTable, { type: 'uuid', onDelete: 'CASCADE', onUpdate: 'CASCADE' })
type: 'uuid',
indexName: 'IDX_memory_assets_audit_memory_id',
onDelete: 'CASCADE',
onUpdate: 'CASCADE',
})
memoryId!: string; memoryId!: string;
@Column({ type: 'uuid', indexName: 'IDX_memory_assets_audit_asset_id' }) @Column({ type: 'uuid', index: true })
assetId!: string; assetId!: string;
@CreateDateColumn({ default: () => 'clock_timestamp()', indexName: 'IDX_memory_assets_audit_deleted_at' }) @CreateDateColumn({ default: () => 'clock_timestamp()', index: true })
deletedAt!: Date; deletedAt!: Date;
} }

View File

@ -1,5 +1,5 @@
import { UpdatedAtTrigger, UpdateIdColumn } from 'src/decorators'; import { UpdatedAtTrigger, UpdateIdColumn } from 'src/decorators';
import { memory_assets_delete_audit } from 'src/schema/functions'; import { memory_asset_delete_audit } from 'src/schema/functions';
import { AssetTable } from 'src/schema/tables/asset.table'; import { AssetTable } from 'src/schema/tables/asset.table';
import { MemoryTable } from 'src/schema/tables/memory.table'; import { MemoryTable } from 'src/schema/tables/memory.table';
import { import {
@ -12,11 +12,11 @@ import {
UpdateDateColumn, UpdateDateColumn,
} from 'src/sql-tools'; } from 'src/sql-tools';
@Table('memories_assets_assets') @Table('memory_asset')
@UpdatedAtTrigger('memory_assets_updated_at') @UpdatedAtTrigger('memory_asset_updatedAt')
@AfterDeleteTrigger({ @AfterDeleteTrigger({
scope: 'statement', scope: 'statement',
function: memory_assets_delete_audit, function: memory_asset_delete_audit,
referencingOldTableAs: 'old', referencingOldTableAs: 'old',
when: 'pg_trigger_depth() <= 1', when: 'pg_trigger_depth() <= 1',
}) })
@ -33,6 +33,6 @@ export class MemoryAssetTable {
@UpdateDateColumn() @UpdateDateColumn()
updatedAt!: Generated<Timestamp>; updatedAt!: Generated<Timestamp>;
@UpdateIdColumn({ indexName: 'IDX_memory_assets_update_id' }) @UpdateIdColumn({ index: true })
updateId!: Generated<string>; updateId!: Generated<string>;
} }

View File

@ -1,17 +1,17 @@
import { PrimaryGeneratedUuidV7Column } from 'src/decorators'; import { PrimaryGeneratedUuidV7Column } from 'src/decorators';
import { Column, CreateDateColumn, Generated, Table, Timestamp } from 'src/sql-tools'; import { Column, CreateDateColumn, Generated, Table, Timestamp } from 'src/sql-tools';
@Table('memories_audit') @Table('memory_audit')
export class MemoryAuditTable { export class MemoryAuditTable {
@PrimaryGeneratedUuidV7Column() @PrimaryGeneratedUuidV7Column()
id!: Generated<string>; id!: Generated<string>;
@Column({ type: 'uuid', indexName: 'IDX_memories_audit_memory_id' }) @Column({ type: 'uuid', index: true })
memoryId!: string; memoryId!: string;
@Column({ type: 'uuid', indexName: 'IDX_memories_audit_user_id' }) @Column({ type: 'uuid', index: true })
userId!: string; userId!: string;
@CreateDateColumn({ default: () => 'clock_timestamp()', indexName: 'IDX_memories_audit_deleted_at' }) @CreateDateColumn({ default: () => 'clock_timestamp()', index: true })
deletedAt!: Generated<Timestamp>; deletedAt!: Generated<Timestamp>;
} }

View File

@ -1,6 +1,6 @@
import { UpdatedAtTrigger, UpdateIdColumn } from 'src/decorators'; import { UpdatedAtTrigger, UpdateIdColumn } from 'src/decorators';
import { MemoryType } from 'src/enum'; import { MemoryType } from 'src/enum';
import { memories_delete_audit } from 'src/schema/functions'; import { memory_delete_audit } from 'src/schema/functions';
import { UserTable } from 'src/schema/tables/user.table'; import { UserTable } from 'src/schema/tables/user.table';
import { import {
AfterDeleteTrigger, AfterDeleteTrigger,
@ -15,11 +15,11 @@ import {
UpdateDateColumn, UpdateDateColumn,
} from 'src/sql-tools'; } from 'src/sql-tools';
@Table('memories') @Table('memory')
@UpdatedAtTrigger('memories_updated_at') @UpdatedAtTrigger('memory_updatedAt')
@AfterDeleteTrigger({ @AfterDeleteTrigger({
scope: 'statement', scope: 'statement',
function: memories_delete_audit, function: memory_delete_audit,
referencingOldTableAs: 'old', referencingOldTableAs: 'old',
when: 'pg_trigger_depth() = 0', when: 'pg_trigger_depth() = 0',
}) })
@ -63,6 +63,6 @@ export class MemoryTable {
@Column({ type: 'timestamp with time zone', nullable: true }) @Column({ type: 'timestamp with time zone', nullable: true })
hideAt!: Timestamp | null; hideAt!: Timestamp | null;
@UpdateIdColumn({ indexName: 'IDX_memories_update_id' }) @UpdateIdColumn({ index: true })
updateId!: Generated<string>; updateId!: Generated<string>;
} }

View File

@ -13,8 +13,8 @@ import {
UpdateDateColumn, UpdateDateColumn,
} from 'src/sql-tools'; } from 'src/sql-tools';
@Table('notifications') @Table('notification')
@UpdatedAtTrigger('notifications_updated_at') @UpdatedAtTrigger('notification_updatedAt')
export class NotificationTable { export class NotificationTable {
@PrimaryGeneratedColumn() @PrimaryGeneratedColumn()
id!: Generated<string>; id!: Generated<string>;
@ -28,7 +28,7 @@ export class NotificationTable {
@DeleteDateColumn() @DeleteDateColumn()
deletedAt!: Timestamp | null; deletedAt!: Timestamp | null;
@UpdateIdColumn({ indexName: 'IDX_notifications_update_id' }) @UpdateIdColumn({ index: true })
updateId!: Generated<string>; updateId!: Generated<string>;
@ForeignKeyColumn(() => UserTable, { onDelete: 'CASCADE', onUpdate: 'CASCADE', nullable: true }) @ForeignKeyColumn(() => UserTable, { onDelete: 'CASCADE', onUpdate: 'CASCADE', nullable: true })

View File

@ -1,17 +1,17 @@
import { PrimaryGeneratedUuidV7Column } from 'src/decorators'; import { PrimaryGeneratedUuidV7Column } from 'src/decorators';
import { Column, CreateDateColumn, Generated, Table, Timestamp } from 'src/sql-tools'; import { Column, CreateDateColumn, Generated, Table, Timestamp } from 'src/sql-tools';
@Table('partners_audit') @Table('partner_audit')
export class PartnerAuditTable { export class PartnerAuditTable {
@PrimaryGeneratedUuidV7Column() @PrimaryGeneratedUuidV7Column()
id!: Generated<string>; id!: Generated<string>;
@Column({ type: 'uuid', indexName: 'IDX_partners_audit_shared_by_id' }) @Column({ type: 'uuid', index: true })
sharedById!: string; sharedById!: string;
@Column({ type: 'uuid', indexName: 'IDX_partners_audit_shared_with_id' }) @Column({ type: 'uuid', index: true })
sharedWithId!: string; sharedWithId!: string;
@CreateDateColumn({ default: () => 'clock_timestamp()', indexName: 'IDX_partners_audit_deleted_at' }) @CreateDateColumn({ default: () => 'clock_timestamp()', index: true })
deletedAt!: Generated<Timestamp>; deletedAt!: Generated<Timestamp>;
} }

View File

@ -1,5 +1,5 @@
import { CreateIdColumn, UpdatedAtTrigger, UpdateIdColumn } from 'src/decorators'; import { CreateIdColumn, UpdatedAtTrigger, UpdateIdColumn } from 'src/decorators';
import { partners_delete_audit } from 'src/schema/functions'; import { partner_delete_audit } from 'src/schema/functions';
import { UserTable } from 'src/schema/tables/user.table'; import { UserTable } from 'src/schema/tables/user.table';
import { import {
AfterDeleteTrigger, AfterDeleteTrigger,
@ -12,11 +12,11 @@ import {
UpdateDateColumn, UpdateDateColumn,
} from 'src/sql-tools'; } from 'src/sql-tools';
@Table('partners') @Table('partner')
@UpdatedAtTrigger('partners_updated_at') @UpdatedAtTrigger('partner_updatedAt')
@AfterDeleteTrigger({ @AfterDeleteTrigger({
scope: 'statement', scope: 'statement',
function: partners_delete_audit, function: partner_delete_audit,
referencingOldTableAs: 'old', referencingOldTableAs: 'old',
when: 'pg_trigger_depth() = 0', when: 'pg_trigger_depth() = 0',
}) })
@ -35,7 +35,7 @@ export class PartnerTable {
@CreateDateColumn() @CreateDateColumn()
createdAt!: Generated<Timestamp>; createdAt!: Generated<Timestamp>;
@CreateIdColumn({ indexName: 'IDX_partners_create_id' }) @CreateIdColumn({ index: true })
createId!: Generated<string>; createId!: Generated<string>;
@UpdateDateColumn() @UpdateDateColumn()
@ -44,6 +44,6 @@ export class PartnerTable {
@Column({ type: 'boolean', default: false }) @Column({ type: 'boolean', default: false })
inTimeline!: Generated<boolean>; inTimeline!: Generated<boolean>;
@UpdateIdColumn({ indexName: 'IDX_partners_update_id' }) @UpdateIdColumn({ index: true })
updateId!: Generated<string>; updateId!: Generated<string>;
} }

View File

@ -6,12 +6,12 @@ export class PersonAuditTable {
@PrimaryGeneratedUuidV7Column() @PrimaryGeneratedUuidV7Column()
id!: Generated<string>; id!: Generated<string>;
@Column({ type: 'uuid', indexName: 'IDX_person_audit_person_id' }) @Column({ type: 'uuid', index: true })
personId!: string; personId!: string;
@Column({ type: 'uuid', indexName: 'IDX_person_audit_owner_id' }) @Column({ type: 'uuid', index: true })
ownerId!: string; ownerId!: string;
@CreateDateColumn({ default: () => 'clock_timestamp()', indexName: 'IDX_person_audit_deleted_at' }) @CreateDateColumn({ default: () => 'clock_timestamp()', index: true })
deletedAt!: Generated<Timestamp>; deletedAt!: Generated<Timestamp>;
} }

View File

@ -16,14 +16,14 @@ import {
} from 'src/sql-tools'; } from 'src/sql-tools';
@Table('person') @Table('person')
@UpdatedAtTrigger('person_updated_at') @UpdatedAtTrigger('person_updatedAt')
@AfterDeleteTrigger({ @AfterDeleteTrigger({
scope: 'statement', scope: 'statement',
function: person_delete_audit, function: person_delete_audit,
referencingOldTableAs: 'old', referencingOldTableAs: 'old',
when: 'pg_trigger_depth() = 0', when: 'pg_trigger_depth() = 0',
}) })
@Check({ name: 'CHK_b0f82b0ed662bfc24fbb58bb45', expression: `"birthDate" <= CURRENT_DATE` }) @Check({ name: 'person_birthDate_chk', expression: `"birthDate" <= CURRENT_DATE` })
export class PersonTable { export class PersonTable {
@PrimaryGeneratedColumn('uuid') @PrimaryGeneratedColumn('uuid')
id!: Generated<string>; id!: Generated<string>;
@ -58,6 +58,6 @@ export class PersonTable {
@Column({ type: 'character varying', nullable: true, default: null }) @Column({ type: 'character varying', nullable: true, default: null })
color!: string | null; color!: string | null;
@UpdateIdColumn({ indexName: 'IDX_person_update_id' }) @UpdateIdColumn({ index: true })
updateId!: Generated<string>; updateId!: Generated<string>;
} }

View File

@ -11,8 +11,8 @@ import {
UpdateDateColumn, UpdateDateColumn,
} from 'src/sql-tools'; } from 'src/sql-tools';
@Table({ name: 'sessions', primaryConstraintName: 'PK_48cb6b5c20faa63157b3c1baf7f' }) @Table({ name: 'session' })
@UpdatedAtTrigger('sessions_updated_at') @UpdatedAtTrigger('session_updatedAt')
export class SessionTable { export class SessionTable {
@PrimaryGeneratedColumn() @PrimaryGeneratedColumn()
id!: Generated<string>; id!: Generated<string>;
@ -42,7 +42,7 @@ export class SessionTable {
@Column({ default: '' }) @Column({ default: '' })
deviceOS!: Generated<string>; deviceOS!: Generated<string>;
@UpdateIdColumn({ indexName: 'IDX_sessions_update_id' }) @UpdateIdColumn({ index: true })
updateId!: Generated<string>; updateId!: Generated<string>;
@Column({ type: 'boolean', default: false }) @Column({ type: 'boolean', default: false })

View File

@ -2,7 +2,7 @@ import { AssetTable } from 'src/schema/tables/asset.table';
import { SharedLinkTable } from 'src/schema/tables/shared-link.table'; import { SharedLinkTable } from 'src/schema/tables/shared-link.table';
import { ForeignKeyColumn, Table } from 'src/sql-tools'; import { ForeignKeyColumn, Table } from 'src/sql-tools';
@Table('shared_link__asset') @Table('shared_link_asset')
export class SharedLinkAssetTable { export class SharedLinkAssetTable {
@ForeignKeyColumn(() => AssetTable, { onUpdate: 'CASCADE', onDelete: 'CASCADE', primary: true }) @ForeignKeyColumn(() => AssetTable, { onUpdate: 'CASCADE', onDelete: 'CASCADE', primary: true })
assetsId!: string; assetsId!: string;

View File

@ -9,11 +9,9 @@ import {
PrimaryGeneratedColumn, PrimaryGeneratedColumn,
Table, Table,
Timestamp, Timestamp,
Unique,
} from 'src/sql-tools'; } from 'src/sql-tools';
@Table('shared_links') @Table('shared_link')
@Unique({ name: 'UQ_sharedlink_key', columns: ['key'] })
export class SharedLinkTable { export class SharedLinkTable {
@PrimaryGeneratedColumn() @PrimaryGeneratedColumn()
id!: Generated<string>; id!: Generated<string>;
@ -24,7 +22,7 @@ export class SharedLinkTable {
@ForeignKeyColumn(() => UserTable, { onDelete: 'CASCADE', onUpdate: 'CASCADE' }) @ForeignKeyColumn(() => UserTable, { onDelete: 'CASCADE', onUpdate: 'CASCADE' })
userId!: string; userId!: string;
@Column({ type: 'bytea', indexName: 'IDX_sharedlink_key' }) @Column({ type: 'bytea', index: true, unique: true })
key!: Buffer; // use to access the individual asset key!: Buffer; // use to access the individual asset
@Column() @Column()
@ -39,12 +37,7 @@ export class SharedLinkTable {
@Column({ type: 'boolean', default: false }) @Column({ type: 'boolean', default: false })
allowUpload!: boolean; allowUpload!: boolean;
@ForeignKeyColumn(() => AlbumTable, { @ForeignKeyColumn(() => AlbumTable, { nullable: true, onDelete: 'CASCADE', onUpdate: 'CASCADE' })
nullable: true,
onDelete: 'CASCADE',
onUpdate: 'CASCADE',
indexName: 'IDX_sharedlink_albumId',
})
albumId!: string | null; albumId!: string | null;
@Column({ type: 'boolean', default: true }) @Column({ type: 'boolean', default: true })

View File

@ -1,7 +1,7 @@
import { AssetTable } from 'src/schema/tables/asset.table'; import { AssetTable } from 'src/schema/tables/asset.table';
import { Column, ForeignKeyColumn, Index, Table } from 'src/sql-tools'; import { Column, ForeignKeyColumn, Index, Table } from 'src/sql-tools';
@Table({ name: 'smart_search', primaryConstraintName: 'smart_search_pkey' }) @Table({ name: 'smart_search' })
@Index({ @Index({
name: 'clip_index', name: 'clip_index',
using: 'hnsw', using: 'hnsw',
@ -10,11 +10,7 @@ import { Column, ForeignKeyColumn, Index, Table } from 'src/sql-tools';
synchronize: false, synchronize: false,
}) })
export class SmartSearchTable { export class SmartSearchTable {
@ForeignKeyColumn(() => AssetTable, { @ForeignKeyColumn(() => AssetTable, { onDelete: 'CASCADE', primary: true })
onDelete: 'CASCADE',
primary: true,
constraintName: 'smart_search_assetId_fkey',
})
assetId!: string; assetId!: string;
@Column({ type: 'vector', length: 512, storage: 'external', synchronize: false }) @Column({ type: 'vector', length: 512, storage: 'external', synchronize: false })

View File

@ -1,7 +1,7 @@
import { PrimaryGeneratedUuidV7Column } from 'src/decorators'; import { PrimaryGeneratedUuidV7Column } from 'src/decorators';
import { Column, CreateDateColumn, Generated, Table, Timestamp } from 'src/sql-tools'; import { Column, CreateDateColumn, Generated, Table, Timestamp } from 'src/sql-tools';
@Table('stacks_audit') @Table('stack_audit')
export class StackAuditTable { export class StackAuditTable {
@PrimaryGeneratedUuidV7Column() @PrimaryGeneratedUuidV7Column()
id!: Generated<string>; id!: Generated<string>;
@ -12,6 +12,6 @@ export class StackAuditTable {
@Column({ type: 'uuid' }) @Column({ type: 'uuid' })
userId!: string; userId!: string;
@CreateDateColumn({ default: () => 'clock_timestamp()', indexName: 'IDX_stacks_audit_deleted_at' }) @CreateDateColumn({ default: () => 'clock_timestamp()', index: true })
deletedAt!: Generated<Timestamp>; deletedAt!: Generated<Timestamp>;
} }

View File

@ -1,5 +1,5 @@
import { UpdatedAtTrigger, UpdateIdColumn } from 'src/decorators'; import { UpdatedAtTrigger, UpdateIdColumn } from 'src/decorators';
import { stacks_delete_audit } from 'src/schema/functions'; import { stack_delete_audit } from 'src/schema/functions';
import { AssetTable } from 'src/schema/tables/asset.table'; import { AssetTable } from 'src/schema/tables/asset.table';
import { UserTable } from 'src/schema/tables/user.table'; import { UserTable } from 'src/schema/tables/user.table';
import { import {
@ -13,11 +13,11 @@ import {
UpdateDateColumn, UpdateDateColumn,
} from 'src/sql-tools'; } from 'src/sql-tools';
@Table('asset_stack') @Table('stack')
@UpdatedAtTrigger('stacks_updated_at') @UpdatedAtTrigger('stack_updatedAt')
@AfterDeleteTrigger({ @AfterDeleteTrigger({
scope: 'statement', scope: 'statement',
function: stacks_delete_audit, function: stack_delete_audit,
referencingOldTableAs: 'old', referencingOldTableAs: 'old',
when: 'pg_trigger_depth() = 0', when: 'pg_trigger_depth() = 0',
}) })
@ -35,11 +35,7 @@ export class StackTable {
updateId!: Generated<string>; updateId!: Generated<string>;
//TODO: Add constraint to ensure primary asset exists in the assets array //TODO: Add constraint to ensure primary asset exists in the assets array
@ForeignKeyColumn(() => AssetTable, { @ForeignKeyColumn(() => AssetTable, { nullable: false, unique: true })
nullable: false,
unique: true,
uniqueConstraintName: 'REL_91704e101438fd0653f582426d',
})
primaryAssetId!: string; primaryAssetId!: string;
@ForeignKeyColumn(() => UserTable, { onDelete: 'CASCADE', onUpdate: 'CASCADE' }) @ForeignKeyColumn(() => UserTable, { onDelete: 'CASCADE', onUpdate: 'CASCADE' })

View File

@ -12,8 +12,8 @@ import {
UpdateDateColumn, UpdateDateColumn,
} from 'src/sql-tools'; } from 'src/sql-tools';
@Table('session_sync_checkpoints') @Table('session_sync_checkpoint')
@UpdatedAtTrigger('session_sync_checkpoints_updated_at') @UpdatedAtTrigger('session_sync_checkpoint_updatedAt')
export class SessionSyncCheckpointTable { export class SessionSyncCheckpointTable {
@ForeignKeyColumn(() => SessionTable, { onDelete: 'CASCADE', onUpdate: 'CASCADE', primary: true }) @ForeignKeyColumn(() => SessionTable, { onDelete: 'CASCADE', onUpdate: 'CASCADE', primary: true })
sessionId!: string; sessionId!: string;
@ -30,6 +30,6 @@ export class SessionSyncCheckpointTable {
@Column() @Column()
ack!: string; ack!: string;
@UpdateIdColumn({ indexName: 'IDX_session_sync_checkpoints_update_id' }) @UpdateIdColumn({ index: true })
updateId!: Generated<string>; updateId!: Generated<string>;
} }

View File

@ -2,7 +2,7 @@ import { AssetTable } from 'src/schema/tables/asset.table';
import { TagTable } from 'src/schema/tables/tag.table'; import { TagTable } from 'src/schema/tables/tag.table';
import { ForeignKeyColumn, Index, Table } from 'src/sql-tools'; import { ForeignKeyColumn, Index, Table } from 'src/sql-tools';
@Index({ name: 'IDX_tag_asset_assetsId_tagsId', columns: ['assetsId', 'tagsId'] }) @Index({ columns: ['assetsId', 'tagsId'] })
@Table('tag_asset') @Table('tag_asset')
export class TagAssetTable { export class TagAssetTable {
@ForeignKeyColumn(() => AssetTable, { onUpdate: 'CASCADE', onDelete: 'CASCADE', primary: true, index: true }) @ForeignKeyColumn(() => AssetTable, { onUpdate: 'CASCADE', onDelete: 'CASCADE', primary: true, index: true })

View File

@ -1,7 +1,7 @@
import { TagTable } from 'src/schema/tables/tag.table'; import { TagTable } from 'src/schema/tables/tag.table';
import { ForeignKeyColumn, Table } from 'src/sql-tools'; import { ForeignKeyColumn, Table } from 'src/sql-tools';
@Table('tags_closure') @Table('tag_closure')
export class TagClosureTable { export class TagClosureTable {
@ForeignKeyColumn(() => TagTable, { primary: true, onDelete: 'CASCADE', onUpdate: 'NO ACTION', index: true }) @ForeignKeyColumn(() => TagTable, { primary: true, onDelete: 'CASCADE', onUpdate: 'NO ACTION', index: true })
id_ancestor!: string; id_ancestor!: string;

View File

@ -12,8 +12,8 @@ import {
UpdateDateColumn, UpdateDateColumn,
} from 'src/sql-tools'; } from 'src/sql-tools';
@Table('tags') @Table('tag')
@UpdatedAtTrigger('tags_updated_at') @UpdatedAtTrigger('tag_updatedAt')
@Unique({ columns: ['userId', 'value'] }) @Unique({ columns: ['userId', 'value'] })
export class TagTable { export class TagTable {
@PrimaryGeneratedColumn() @PrimaryGeneratedColumn()
@ -42,6 +42,6 @@ export class TagTable {
@ForeignKeyColumn(() => TagTable, { nullable: true, onDelete: 'CASCADE' }) @ForeignKeyColumn(() => TagTable, { nullable: true, onDelete: 'CASCADE' })
parentId!: string | null; parentId!: string | null;
@UpdateIdColumn({ indexName: 'IDX_tags_update_id' }) @UpdateIdColumn({ index: true })
updateId!: Generated<string>; updateId!: Generated<string>;
} }

View File

@ -1,7 +1,7 @@
import { PrimaryGeneratedUuidV7Column } from 'src/decorators'; import { PrimaryGeneratedUuidV7Column } from 'src/decorators';
import { Column, CreateDateColumn, Generated, Table, Timestamp } from 'src/sql-tools'; import { Column, CreateDateColumn, Generated, Table, Timestamp } from 'src/sql-tools';
@Table('users_audit') @Table('user_audit')
export class UserAuditTable { export class UserAuditTable {
@PrimaryGeneratedUuidV7Column() @PrimaryGeneratedUuidV7Column()
id!: Generated<string>; id!: Generated<string>;
@ -9,6 +9,6 @@ export class UserAuditTable {
@Column({ type: 'uuid' }) @Column({ type: 'uuid' })
userId!: string; userId!: string;
@CreateDateColumn({ default: () => 'clock_timestamp()', indexName: 'IDX_users_audit_deleted_at' }) @CreateDateColumn({ default: () => 'clock_timestamp()', index: true })
deletedAt!: Generated<Timestamp>; deletedAt!: Generated<Timestamp>;
} }

View File

@ -1,7 +1,7 @@
import { ColumnType } from 'kysely'; import { ColumnType } from 'kysely';
import { UpdatedAtTrigger, UpdateIdColumn } from 'src/decorators'; import { UpdatedAtTrigger, UpdateIdColumn } from 'src/decorators';
import { UserAvatarColor, UserStatus } from 'src/enum'; import { UserAvatarColor, UserStatus } from 'src/enum';
import { users_delete_audit } from 'src/schema/functions'; import { user_delete_audit } from 'src/schema/functions';
import { import {
AfterDeleteTrigger, AfterDeleteTrigger,
Column, Column,
@ -15,15 +15,15 @@ import {
UpdateDateColumn, UpdateDateColumn,
} from 'src/sql-tools'; } from 'src/sql-tools';
@Table('users') @Table('user')
@UpdatedAtTrigger('users_updated_at') @UpdatedAtTrigger('user_updatedAt')
@AfterDeleteTrigger({ @AfterDeleteTrigger({
scope: 'statement', scope: 'statement',
function: users_delete_audit, function: user_delete_audit,
referencingOldTableAs: 'old', referencingOldTableAs: 'old',
when: 'pg_trigger_depth() = 0', when: 'pg_trigger_depth() = 0',
}) })
@Index({ name: 'IDX_users_updated_at_asc_id_asc', columns: ['updatedAt', 'id'] }) @Index({ columns: ['updatedAt', 'id'] })
export class UserTable { export class UserTable {
@PrimaryGeneratedColumn() @PrimaryGeneratedColumn()
id!: Generated<string>; id!: Generated<string>;
@ -79,6 +79,6 @@ export class UserTable {
@Column({ type: 'timestamp with time zone', default: () => 'now()' }) @Column({ type: 'timestamp with time zone', default: () => 'now()' })
profileChangedAt!: Generated<Timestamp>; profileChangedAt!: Generated<Timestamp>;
@UpdateIdColumn({ indexName: 'IDX_users_update_id' }) @UpdateIdColumn({ index: true })
updateId!: Generated<string>; updateId!: Generated<string>;
} }

View File

@ -24,8 +24,8 @@ import {
import { ArgOf } from 'src/repositories/event.repository'; import { ArgOf } from 'src/repositories/event.repository';
import { ReverseGeocodeResult } from 'src/repositories/map.repository'; import { ReverseGeocodeResult } from 'src/repositories/map.repository';
import { ImmichTags } from 'src/repositories/metadata.repository'; import { ImmichTags } from 'src/repositories/metadata.repository';
import { AssetExifTable } from 'src/schema/tables/asset-exif.table';
import { AssetFaceTable } from 'src/schema/tables/asset-face.table'; 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 { PersonTable } from 'src/schema/tables/person.table';
import { BaseService } from 'src/services/base.service'; import { BaseService } from 'src/services/base.service';
import { JobItem, JobOf } from 'src/types'; import { JobItem, JobOf } from 'src/types';
@ -164,7 +164,7 @@ export class MetadataService extends BaseService {
private async linkLivePhotos( private async linkLivePhotos(
asset: { id: string; type: AssetType; ownerId: string; libraryId: string | null }, asset: { id: string; type: AssetType; ownerId: string; libraryId: string | null },
exifInfo: Insertable<ExifTable>, exifInfo: Insertable<AssetExifTable>,
): Promise<void> { ): Promise<void> {
if (!exifInfo.livePhotoCID) { if (!exifInfo.livePhotoCID) {
return; return;
@ -242,7 +242,7 @@ export class MetadataService extends BaseService {
} }
} }
const exifData: Insertable<ExifTable> = { const exifData: Insertable<AssetExifTable> = {
assetId: asset.id, assetId: asset.id,
// dates // dates

View File

@ -31,7 +31,8 @@ export const compareConstraints: Comparer<DatabaseConstraint> = {
} }
case ConstraintType.CHECK: { case ConstraintType.CHECK: {
return asRenameKey([constraint.type, constraint.tableName, constraint.expression]); const expression = constraint.expression.replaceAll('(', '').replaceAll(')', '');
return asRenameKey([constraint.type, constraint.tableName, expression]);
} }
} }
}, },

View File

@ -7,7 +7,7 @@ export const compareIndexes: Comparer<DatabaseIndex> = {
return index.override.value.sql.replace(index.name, 'INDEX_NAME'); return index.override.value.sql.replace(index.name, 'INDEX_NAME');
} }
return asRenameKey([index.tableName, ...(index.columnNames || []).toSorted(), index.unique]); return asRenameKey([index.tableName, ...(index.columnNames || []), index.unique]);
}, },
onRename: (source, target) => [ onRename: (source, target) => [
{ {

View File

@ -30,28 +30,35 @@ export const schemaDiff = (source: DatabaseSchema, target: DatabaseSchema, optio
type SchemaName = SchemaDiff['type']; type SchemaName = SchemaDiff['type'];
const itemMap: Record<SchemaName, SchemaDiff[]> = { const itemMap: Record<SchemaName, SchemaDiff[]> = {
EnumCreate: [],
EnumDrop: [],
ExtensionCreate: [],
ExtensionDrop: [],
FunctionCreate: [],
FunctionDrop: [],
TableCreate: [],
TableDrop: [],
ColumnAdd: [],
ColumnAlter: [],
ColumnRename: [], ColumnRename: [],
ColumnDrop: [],
ConstraintAdd: [],
ConstraintDrop: [],
ConstraintRename: [], ConstraintRename: [],
IndexCreate: [],
IndexRename: [], IndexRename: [],
IndexDrop: [],
TriggerCreate: [], ExtensionDrop: [],
TriggerDrop: [], ExtensionCreate: [],
ParameterSet: [], ParameterSet: [],
ParameterReset: [], ParameterReset: [],
FunctionDrop: [],
FunctionCreate: [],
EnumDrop: [],
EnumCreate: [],
TriggerDrop: [],
ConstraintDrop: [],
TableDrop: [],
ColumnDrop: [],
ColumnAdd: [],
ColumnAlter: [],
TableCreate: [],
ConstraintAdd: [],
TriggerCreate: [],
IndexCreate: [],
IndexDrop: [],
OverrideCreate: [], OverrideCreate: [],
OverrideUpdate: [], OverrideUpdate: [],
OverrideDrop: [], OverrideDrop: [],

Some files were not shown because too many files have changed in this diff Show More