Merge c38eebb53e into f0b069adb9
commit
1d1682f883
|
|
@ -66,9 +66,10 @@ export class MemoryRepository implements IBulkAsset {
|
|||
.selectAll('asset')
|
||||
.innerJoin('memory_asset', 'asset.id', 'memory_asset.assetId')
|
||||
.whereRef('memory_asset.memoriesId', '=', 'memory.id')
|
||||
.orderBy('asset.fileCreatedAt', 'asc')
|
||||
.where('asset.visibility', '=', sql.lit(AssetVisibility.Timeline))
|
||||
.where('asset.deletedAt', 'is', null),
|
||||
.where('asset.deletedAt', 'is', null)
|
||||
.where(sql<boolean>`NOT asset_linked_to_hidden_person("asset"."id")`)
|
||||
.orderBy('asset.fileCreatedAt', 'asc'),
|
||||
).as('assets'),
|
||||
)
|
||||
.selectAll('memory')
|
||||
|
|
|
|||
|
|
@ -255,3 +255,21 @@ export const asset_face_audit = registerFunction({
|
|||
RETURN NULL;
|
||||
END`,
|
||||
});
|
||||
|
||||
export const asset_linked_to_hidden_person = registerFunction({
|
||||
name: 'asset_linked_to_hidden_person',
|
||||
arguments: ['asset_id uuid'],
|
||||
returnType: 'boolean',
|
||||
language: 'PLPGSQL',
|
||||
behavior: 'stable',
|
||||
body: `
|
||||
BEGIN
|
||||
RETURN EXISTS (
|
||||
SELECT 1
|
||||
FROM asset_face
|
||||
INNER JOIN person ON person.id = asset_face."personId"
|
||||
WHERE asset_face."assetId" = asset_id
|
||||
AND person."isHidden" = TRUE
|
||||
);
|
||||
END`,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import {
|
|||
album_user_delete_audit,
|
||||
asset_delete_audit,
|
||||
asset_face_audit,
|
||||
asset_linked_to_hidden_person,
|
||||
asset_metadata_audit,
|
||||
f_concat_ws,
|
||||
f_unaccent,
|
||||
|
|
@ -154,6 +155,7 @@ export class ImmichDatabase {
|
|||
user_metadata_audit,
|
||||
asset_metadata_audit,
|
||||
asset_face_audit,
|
||||
asset_linked_to_hidden_person,
|
||||
];
|
||||
|
||||
enum = [assets_status_enum, asset_face_source_type, asset_visibility_enum];
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
import { Kysely, sql } from 'kysely';
|
||||
|
||||
export async function up(db: Kysely<any>): Promise<void> {
|
||||
await sql`CREATE OR REPLACE FUNCTION asset_linked_to_hidden_person(asset_id uuid)
|
||||
RETURNS boolean
|
||||
STABLE LANGUAGE PLPGSQL
|
||||
AS $$
|
||||
BEGIN
|
||||
RETURN EXISTS (
|
||||
SELECT 1
|
||||
FROM asset_face
|
||||
INNER JOIN person ON person.id = asset_face."personId"
|
||||
WHERE asset_face."assetId" = asset_id
|
||||
AND person."isHidden" = TRUE
|
||||
);
|
||||
END
|
||||
$$;`.execute(db);
|
||||
await sql`INSERT INTO "migration_overrides" ("name", "value") VALUES ('function_asset_linked_to_hidden_person', '{"type":"function","name":"asset_linked_to_hidden_person","sql":"CREATE OR REPLACE FUNCTION asset_linked_to_hidden_person(asset_id uuid)\\n RETURNS boolean\\n STABLE LANGUAGE PLPGSQL\\n AS $$\\n BEGIN\\n RETURN EXISTS (\\n SELECT 1\\n FROM asset_face\\n INNER JOIN person ON person.id = asset_face.\\"personId\\"\\n WHERE asset_face.\\"assetId\\" = asset_id\\n AND person.\\"isHidden\\" = TRUE\\n );\\n END\\n $$;"}'::jsonb);`.execute(db);
|
||||
}
|
||||
|
||||
export async function down(db: Kysely<any>): Promise<void> {
|
||||
await sql`DROP FUNCTION asset_linked_to_hidden_person;`.execute(db);
|
||||
await sql`DELETE FROM "migration_overrides" WHERE "name" = 'function_asset_linked_to_hidden_person';`.execute(db);
|
||||
}
|
||||
|
|
@ -25,25 +25,26 @@ describe(MemoryService.name, () => {
|
|||
});
|
||||
|
||||
describe('search', () => {
|
||||
it('should search memories', async () => {
|
||||
it('should search memories with assets', async () => {
|
||||
const [userId] = newUuids();
|
||||
const asset = factory.asset();
|
||||
const memory1 = factory.memory({ ownerId: userId, assets: [asset] });
|
||||
const memory2 = factory.memory({ ownerId: userId });
|
||||
const memoryWithAsset = factory.memory({ ownerId: userId, assets: [asset] });
|
||||
const memoryWithoutAsset = factory.memory({ ownerId: userId, assets: [] });
|
||||
|
||||
mocks.memory.search.mockResolvedValue([memory1, memory2]);
|
||||
mocks.memory.search.mockResolvedValue([memoryWithAsset, memoryWithoutAsset]);
|
||||
|
||||
await expect(sut.search(factory.auth({ user: { id: userId } }), {})).resolves.toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({ id: memory1.id, assets: [expect.objectContaining({ id: asset.id })] }),
|
||||
expect.objectContaining({ id: memory2.id, assets: [] }),
|
||||
expect.objectContaining({
|
||||
id: memoryWithAsset.id,
|
||||
assets: expect.arrayContaining([expect.objectContaining({ id: asset.id })]),
|
||||
}),
|
||||
]),
|
||||
);
|
||||
});
|
||||
|
||||
it('should map ', async () => {
|
||||
it('should map empty result', async () => {
|
||||
mocks.memory.search.mockResolvedValue([]);
|
||||
|
||||
await expect(sut.search(factory.auth(), {})).resolves.toEqual([]);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { BadRequestException, Injectable } from '@nestjs/common';
|
||||
import { DateTime } from 'luxon';
|
||||
import { Memory } from 'src/database';
|
||||
import { OnJob } from 'src/decorators';
|
||||
import { BulkIdResponseDto, BulkIdsDto } from 'src/dtos/asset-ids.response.dto';
|
||||
import { AuthDto } from 'src/dtos/auth.dto';
|
||||
|
|
@ -70,7 +71,9 @@ export class MemoryService extends BaseService {
|
|||
|
||||
async search(auth: AuthDto, dto: MemorySearchDto) {
|
||||
const memories = await this.memoryRepository.search(auth.user.id, dto);
|
||||
return memories.map((memory) => mapMemory(memory, auth));
|
||||
return memories
|
||||
.filter((memory: Memory) => memory.assets && memory.assets.length > 0)
|
||||
.map((memory: Memory) => mapMemory(memory, auth));
|
||||
}
|
||||
|
||||
statistics(auth: AuthDto, dto: MemorySearchDto) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue