1
0
Fork 0
mirror of https://github.com/immich-app/immich.git synced 2025-01-24 04:32:45 +01:00

use min year for memory time series, sql generation fixes

This commit is contained in:
mertalev 2024-12-19 20:00:42 -05:00
parent 38a82d39d3
commit 4731f271e2
No known key found for this signature in database
GPG key ID: 3A2B5BFC678DBC80
10 changed files with 177 additions and 132 deletions

View file

@ -450,19 +450,6 @@ WHERE
ORDER BY
"AlbumEntity"."createdAt" DESC
-- AlbumRepository.removeAsset
DELETE FROM "albums_assets_assets"
WHERE
"albums_assets_assets"."assetsId" = $1
-- AlbumRepository.removeAssetIds
DELETE FROM "albums_assets_assets"
WHERE
(
"albumsId" = $1
AND "assetsId" IN ($2)
)
-- AlbumRepository.getAssetIds
SELECT
"albums_assets"."assetsId" AS "assetId"
@ -471,52 +458,3 @@ FROM
WHERE
"albums_assets"."albumsId" = $1
AND "albums_assets"."assetsId" IN ($2)
-- AlbumRepository.addAssetIds
INSERT INTO
"albums_assets_assets" ("albumsId", "assetsId")
VALUES
($1, $2)
-- AlbumRepository.updateThumbnails
UPDATE "albums"
SET
"albumThumbnailAssetId" = (
SELECT
"album_assets"."assetsId"
FROM
"albums_assets_assets" "album_assets"
INNER JOIN "assets" "assets" ON "album_assets"."assetsId" = "assets"."id"
AND "assets"."deletedAt" IS NULL
WHERE
"album_assets"."albumsId" = "albums"."id"
ORDER BY
"assets"."fileCreatedAt" DESC
LIMIT
1
),
"updatedAt" = CURRENT_TIMESTAMP
WHERE
"albums"."albumThumbnailAssetId" IS NULL
AND EXISTS (
SELECT
1
FROM
"albums_assets_assets" "album_assets"
INNER JOIN "assets" "assets" ON "album_assets"."assetsId" = "assets"."id"
AND "assets"."deletedAt" IS NULL
WHERE
"album_assets"."albumsId" = "albums"."id"
)
OR "albums"."albumThumbnailAssetId" IS NOT NULL
AND NOT EXISTS (
SELECT
1
FROM
"albums_assets_assets" "album_assets"
INNER JOIN "assets" "assets" ON "album_assets"."assetsId" = "assets"."id"
AND "assets"."deletedAt" IS NULL
WHERE
"album_assets"."albumsId" = "albums"."id"
AND "albums"."albumThumbnailAssetId" = "album_assets"."assetsId"
)

View file

@ -9,12 +9,16 @@ with
make_date(year::int, $1::int, $2::int) as "date"
from
generate_series(
$3,
extract(
year
(
select
date_part(
'year',
min((("localDateTime" at time zone 'UTC')::date))
)::int
from
current_date
) - 1
assets
),
date_part('year', current_date)::int - 1
) as "year"
)
select
@ -31,20 +35,20 @@ with
where
"asset_job_status"."previewAt" is not null
and (assets."localDateTime" at time zone 'UTC')::date = today.date
and "assets"."ownerId" = any ($4::uuid [])
and "assets"."isVisible" = $5
and "assets"."isArchived" = $6
and "assets"."ownerId" = any ($3::uuid [])
and "assets"."isVisible" = $4
and "assets"."isArchived" = $5
and exists (
select
from
"asset_files"
where
"assetId" = "assets"."id"
and "asset_files"."type" = $7
and "asset_files"."type" = $6
)
and "assets"."deletedAt" is null
limit
$8
$7
) as "a" on true
inner join "exif" on "a"."id" = "exif"."assetId"
)
@ -60,7 +64,7 @@ group by
order by
("localDateTime" at time zone 'UTC')::date desc
limit
$9
$8
-- AssetRepository.getByIds
select
@ -208,6 +212,17 @@ where
limit
$4
-- AssetRepository.getByChecksums
select
"id",
"checksum",
"deletedAt"
from
"assets"
where
"ownerId" = $1::uuid
and "checksum" in ($2)
-- AssetRepository.getUploadAssetIdByChecksum
select
"id"
@ -274,6 +289,52 @@ where
order by
"assets"."localDateTime" desc
-- AssetRepository.getDuplicates
with
"duplicates" as (
select
"duplicateId",
jsonb_agg("assets") as "assets"
from
"assets"
where
"ownerId" = $1::uuid
and "duplicateId" is not null
and "deletedAt" is null
and "isVisible" = $2
group by
"duplicateId"
),
"unique" as (
select
"duplicateId"
from
"duplicates"
where
jsonb_array_length("assets") = $3
),
"removed_unique" as (
update "assets"
set
"duplicateId" = $4
from
"unique"
where
"assets"."duplicateId" = "unique"."duplicateId"
)
select
*
from
"duplicates"
where
not exists (
select
from
"unique"
where
"unique"."duplicateId" = "duplicates"."duplicateId"
)
-- AssetRepository.getAssetIdByCity
with
"cities" as (
@ -317,3 +378,23 @@ order by
"id" asc
limit
$5
-- AssetRepository.getChangedDeltaSync
select
"assets".*,
(
select
count(*) as "stackedAssetsCount"
from
"asset_stack"
where
"asset_stack"."id" = "assets"."stackId"
) as "stackedAssetsCount"
from
"assets"
where
"ownerId" = any ($1::uuid [])
and "isVisible" = $2
and "updatedAt" > $3
limit
$4

View file

@ -8,17 +8,3 @@ FROM
WHERE
"memories_assets"."memoriesId" = $1
AND "memories_assets"."assetsId" IN ($2)
-- MemoryRepository.addAssetIds
INSERT INTO
"memories_assets_assets" ("memoriesId", "assetsId")
VALUES
($1, $2)
-- MemoryRepository.removeAssetIds
DELETE FROM "memories_assets_assets"
WHERE
(
"memoriesId" = $1
AND "assetsId" IN ($2)
)

View file

@ -20,6 +20,47 @@ limit
offset
$7
-- SearchRepository.searchRandom
(
select
"assets".*
from
"assets"
inner join "exif" on "assets"."id" = "exif"."assetId"
where
"assets"."fileCreatedAt" >= $1
and "exif"."lensModel" = $2
and "assets"."ownerId" = any ($3::uuid [])
and "assets"."isFavorite" = $4
and "assets"."isArchived" = $5
and "assets"."deletedAt" is null
and "assets"."id" < $6
order by
"assets"."id"
limit
$7
)
union all
(
select
"assets".*
from
"assets"
inner join "exif" on "assets"."id" = "exif"."assetId"
where
"assets"."fileCreatedAt" >= $8
and "exif"."lensModel" = $9
and "assets"."ownerId" = any ($10::uuid [])
and "assets"."isFavorite" = $11
and "assets"."isArchived" = $12
and "assets"."deletedAt" is null
and "assets"."id" > $13
order by
"assets"."id"
limit
$14
)
-- SearchRepository.searchSmart
select
"assets".*
@ -41,6 +82,34 @@ limit
offset
$8
-- SearchRepository.searchDuplicates
with
"cte" as (
select
"assets"."id" as "assetId",
"assets"."duplicateId",
smart_search.embedding <= > $1::vector as "distance"
from
"assets"
inner join "smart_search" on "assets"."id" = "smart_search"."assetId"
where
"assets"."ownerId" = any ($2::uuid [])
and "assets"."deletedAt" is null
and "assets"."isVisible" = $3
and "assets"."type" = $4
and "assets"."id" != $5::uuid
order by
smart_search.embedding <= > $6::vector
limit
$7
)
select
*
from
"cte"
where
"cte"."distance" <= $8
-- SearchRepository.searchFaces
with
"cte" as (

View file

@ -8,23 +8,3 @@ FROM
WHERE
"tag_asset"."tagsId" = $1
AND "tag_asset"."assetsId" IN ($2)
-- TagRepository.addAssetIds
INSERT INTO
"tag_asset" ("assetsId", "tagsId")
VALUES
($1, $2)
-- TagRepository.removeAssetIds
DELETE FROM "tag_asset"
WHERE
(
"tagsId" = $1
AND "assetsId" IN ($2)
)
-- TagRepository.upsertAssetIds
INSERT INTO
"tag_asset" ("assetsId", "tagsId")
VALUES
($1, $2)

View file

@ -153,7 +153,6 @@ export class AlbumRepository implements IAlbumRepository {
await this.repository.delete({ ownerId: userId });
}
@GenerateSql({ params: [DummyValue.UUID] })
async removeAsset(assetId: string): Promise<void> {
// Using dataSource, because there is no direct access to albums_assets_assets.
await this.dataSource
@ -164,7 +163,6 @@ export class AlbumRepository implements IAlbumRepository {
.execute();
}
@GenerateSql({ params: [DummyValue.UUID, [DummyValue.UUID]] })
@Chunked({ paramIndex: 1 })
async removeAssetIds(albumId: string, assetIds: string[]): Promise<void> {
if (assetIds.length === 0) {
@ -207,7 +205,6 @@ export class AlbumRepository implements IAlbumRepository {
return new Set(results.map(({ assetId }) => assetId));
}
@GenerateSql({ params: [DummyValue.UUID, [DummyValue.UUID]] })
async addAssetIds(albumId: string, assetIds: string[]): Promise<void> {
await this.addAssets(this.dataSource.manager, albumId, assetIds);
}
@ -272,7 +269,6 @@ export class AlbumRepository implements IAlbumRepository {
*
* @returns Amount of updated album thumbnails or undefined when unknown
*/
@GenerateSql()
async updateThumbnails(): Promise<number | undefined> {
// Subquery for getting a new thumbnail.

View file

@ -92,15 +92,18 @@ export class AssetRepository implements IAssetRepository {
@GenerateSql({ params: [DummyValue.UUID, { day: 1, month: 1 }] })
getByDayOfYear(ownerIds: string[], { day, month }: MonthDay): Promise<DayOfYearAssets[]> {
// TODO: CREATE INDEX idx_local_date_time ON public.assets ((("localDateTime" at time zone 'UTC')::date));
// TODO: drop IDX_day_of_month and IDX_month
return this.db
.with('res', (qb) =>
qb
.with('today', (qb) =>
qb
.selectFrom((eb) =>
eb.fn('generate_series', [eb.val(1970), sql`extract(year from current_date) - 1`]).as('year'),
eb
.fn('generate_series', [
sql`(select date_part('year', min((("localDateTime" at time zone 'UTC')::date)))::int from assets)`,
sql`date_part('year', current_date)::int - 1`,
])
.as('year'),
)
.select((eb) => eb.fn('make_date', [sql`year::int`, sql`${month}::int`, sql`${day}::int`]).as('date')),
)
@ -348,7 +351,7 @@ export class AssetRepository implements IAssetRepository {
.executeTakeFirst() as Promise<AssetEntity | undefined>;
}
@GenerateSql({ params: [DummyValue.UUID, DummyValue.BUFFER] })
@GenerateSql({ params: [DummyValue.UUID, [DummyValue.BUFFER]] })
getByChecksums(userId: string, checksums: Buffer[]): Promise<AssetEntity[]> {
return this.db
.selectFrom('assets')
@ -576,7 +579,6 @@ export class AssetRepository implements IAssetRepository {
@GenerateSql({ params: [DummyValue.TIME_BUCKET, { size: TimeBucketSize.MONTH }] })
async getTimeBucket(timeBucket: string, options: TimeBucketOptions): Promise<AssetEntity[]> {
// TODO: CREATE INDEX idx_local_date_time_month ON public.assets (date_trunc('MONTH', "localDateTime" at time zone 'UTC'));
return hasPeople(this.db, options.personId ? [options.personId] : undefined)
.selectAll('assets')
.$call(withExif)
@ -601,7 +603,7 @@ export class AssetRepository implements IAssetRepository {
.execute() as any as Promise<AssetEntity[]>;
}
@GenerateSql({ params: [{ userIds: [DummyValue.UUID, DummyValue.UUID] }] })
@GenerateSql({ params: [DummyValue.UUID] })
getDuplicates(userId: string): Promise<DuplicateGroup[]> {
return (
this.db
@ -692,7 +694,7 @@ export class AssetRepository implements IAssetRepository {
.execute() as any as Promise<AssetEntity[]>;
}
@GenerateSql({ params: [{ userIds: [DummyValue.UUID], updatedAfter: DummyValue.DATE }] })
@GenerateSql({ params: [{ userIds: [DummyValue.UUID], updatedAfter: DummyValue.DATE, limit: 100 }] })
async getChangedDeltaSync(options: AssetDeltaSyncOptions): Promise<AssetEntity[]> {
return this.db
.selectFrom('assets')
@ -711,7 +713,6 @@ export class AssetRepository implements IAssetRepository {
.execute() as any as Promise<AssetEntity[]>;
}
@GenerateSql({ params: [{ assetId: DummyValue.UUID, type: AssetFileType.PREVIEW, path: '/path/to/file' }] })
async upsertFile(file: Pick<Insertable<AssetFiles>, 'assetId' | 'path' | 'type'>): Promise<void> {
const value = { ...file, assetId: asUuid(file.assetId) };
await this.db
@ -725,7 +726,6 @@ export class AssetRepository implements IAssetRepository {
.execute();
}
@GenerateSql({ params: [{ assetId: DummyValue.UUID, type: AssetFileType.PREVIEW, path: '/path/to/file' }] })
async upsertFiles(files: Pick<Insertable<AssetFiles>, 'assetId' | 'path' | 'type'>[]): Promise<void> {
if (files.length === 0) {
return;

View file

@ -64,7 +64,6 @@ export class MemoryRepository implements IMemoryRepository {
return new Set(results.map(({ assetId }) => assetId));
}
@GenerateSql({ params: [DummyValue.UUID, [DummyValue.UUID]] })
async addAssetIds(id: string, assetIds: string[]): Promise<void> {
await this.dataSource
.createQueryBuilder()
@ -74,7 +73,6 @@ export class MemoryRepository implements IMemoryRepository {
.execute();
}
@GenerateSql({ params: [DummyValue.UUID, [DummyValue.UUID]] })
@Chunked({ paramIndex: 1 })
async removeAssetIds(id: string, assetIds: string[]): Promise<void> {
await this.dataSource

View file

@ -6,6 +6,7 @@ import { DB } from 'src/db';
import { DummyValue, GenerateSql } from 'src/decorators';
import { AssetEntity, searchAssetBuilder } from 'src/entities/asset.entity';
import { GeodataPlacesEntity } from 'src/entities/geodata-places.entity';
import { AssetType } from 'src/enum';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import {
AssetDuplicateSearch,
@ -71,12 +72,9 @@ export class SearchRepository implements ISearchRepository {
searchRandom(size: number, options: AssetSearchOptions): Promise<AssetEntity[]> {
const uuid = randomUUID();
const builder = searchAssetBuilder(this.db, options);
return builder
.where('assets.id', '>', uuid)
.orderBy('assets.id')
.limit(size)
.unionAll(() => builder.where('assets.id', '<', uuid).orderBy('assets.id').limit(size))
.execute() as any as Promise<AssetEntity[]>;
const lessThan = builder.where('assets.id', '<', uuid).orderBy('assets.id').limit(size);
const greaterThan = builder.where('assets.id', '>', uuid).orderBy('assets.id').limit(size);
return sql`${lessThan} union all ${greaterThan}`.execute(this.db) as any as Promise<AssetEntity[]>;
}
@GenerateSql({
@ -112,8 +110,10 @@ export class SearchRepository implements ISearchRepository {
@GenerateSql({
params: [
{
assetId: DummyValue.UUID,
embedding: Array.from({ length: 512 }, Math.random),
maxDistance: 0.6,
type: AssetType.IMAGE,
userIds: [DummyValue.UUID],
},
],
@ -134,7 +134,7 @@ export class SearchRepository implements ISearchRepository {
.where('assets.deletedAt', 'is', null)
.where('assets.isVisible', '=', true)
.where('assets.type', '=', type)
.where('assets.id', '!=', assetId)
.where('assets.id', '!=', asUuid(assetId))
.orderBy(sql`smart_search.embedding <=> ${vector}`)
.limit(64),
)

View file

@ -108,7 +108,6 @@ export class TagRepository implements ITagRepository {
return new Set(results.map(({ assetId }) => assetId));
}
@GenerateSql({ params: [DummyValue.UUID, [DummyValue.UUID]] })
async addAssetIds(tagId: string, assetIds: string[]): Promise<void> {
if (assetIds.length === 0) {
return;
@ -122,7 +121,6 @@ export class TagRepository implements ITagRepository {
.execute();
}
@GenerateSql({ params: [DummyValue.UUID, [DummyValue.UUID]] })
@Chunked({ paramIndex: 1 })
async removeAssetIds(tagId: string, assetIds: string[]): Promise<void> {
if (assetIds.length === 0) {
@ -140,7 +138,6 @@ export class TagRepository implements ITagRepository {
.execute();
}
@GenerateSql({ params: [[{ assetId: DummyValue.UUID, tagId: DummyValue.UUID }]] })
@Chunked()
async upsertAssetIds(items: AssetTagItem[]): Promise<AssetTagItem[]> {
if (items.length === 0) {