1
0
mirror of https://github.com/immich-app/immich.git synced 2024-12-27 10:58:13 +02:00

fix(server): search suggestions include partner assets (#12269)

search suggestions now include partner assets

Co-authored-by: Alex <alex.tran1502@gmail.com>
This commit is contained in:
Lukas 2024-09-05 10:12:46 -04:00 committed by GitHub
parent 259bc8a6b0
commit 27e283e724
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 26 additions and 25 deletions

View File

@ -53,9 +53,9 @@ export interface IMetadataRepository {
readTags(path: string): Promise<ImmichTags | null>;
writeTags(path: string, tags: Partial<Tags>): Promise<void>;
extractBinaryTag(tagName: string, path: string): Promise<Buffer>;
getCountries(userId: string): Promise<Array<string | null>>;
getStates(userId: string, country?: string): Promise<Array<string | null>>;
getCities(userId: string, country?: string, state?: string): Promise<Array<string | null>>;
getCameraMakes(userId: string, model?: string): Promise<Array<string | null>>;
getCameraModels(userId: string, make?: string): Promise<Array<string | null>>;
getCountries(userIds: string[]): Promise<Array<string | null>>;
getStates(userIds: string[], country?: string): Promise<Array<string | null>>;
getCities(userIds: string[], country?: string, state?: string): Promise<Array<string | null>>;
getCameraMakes(userIds: string[], model?: string): Promise<Array<string | null>>;
getCameraModels(userIds: string[], make?: string): Promise<Array<string | null>>;
}

View File

@ -56,11 +56,11 @@ export class MetadataRepository implements IMetadataRepository {
}
@GenerateSql({ params: [DummyValue.UUID] })
async getCountries(userId: string): Promise<string[]> {
async getCountries(userIds: string[]): Promise<string[]> {
const results = await this.exifRepository
.createQueryBuilder('exif')
.leftJoin('exif.asset', 'asset')
.where('asset.ownerId = :userId', { userId })
.where('asset.ownerId IN (:...userIds )', { userIds })
.select('exif.country', 'country')
.distinctOn(['exif.country'])
.getRawMany<{ country: string }>();
@ -69,11 +69,11 @@ export class MetadataRepository implements IMetadataRepository {
}
@GenerateSql({ params: [DummyValue.UUID, DummyValue.STRING] })
async getStates(userId: string, country: string | undefined): Promise<string[]> {
async getStates(userIds: string[], country: string | undefined): Promise<string[]> {
const query = this.exifRepository
.createQueryBuilder('exif')
.leftJoin('exif.asset', 'asset')
.where('asset.ownerId = :userId', { userId })
.where('asset.ownerId IN (:...userIds )', { userIds })
.select('exif.state', 'state')
.distinctOn(['exif.state']);
@ -87,11 +87,11 @@ export class MetadataRepository implements IMetadataRepository {
}
@GenerateSql({ params: [DummyValue.UUID, DummyValue.STRING, DummyValue.STRING] })
async getCities(userId: string, country: string | undefined, state: string | undefined): Promise<string[]> {
async getCities(userIds: string[], country: string | undefined, state: string | undefined): Promise<string[]> {
const query = this.exifRepository
.createQueryBuilder('exif')
.leftJoin('exif.asset', 'asset')
.where('asset.ownerId = :userId', { userId })
.where('asset.ownerId IN (:...userIds )', { userIds })
.select('exif.city', 'city')
.distinctOn(['exif.city']);
@ -109,11 +109,11 @@ export class MetadataRepository implements IMetadataRepository {
}
@GenerateSql({ params: [DummyValue.UUID, DummyValue.STRING] })
async getCameraMakes(userId: string, model: string | undefined): Promise<string[]> {
async getCameraMakes(userIds: string[], model: string | undefined): Promise<string[]> {
const query = this.exifRepository
.createQueryBuilder('exif')
.leftJoin('exif.asset', 'asset')
.where('asset.ownerId = :userId', { userId })
.where('asset.ownerId IN (:...userIds )', { userIds })
.select('exif.make', 'make')
.distinctOn(['exif.make']);
@ -126,11 +126,11 @@ export class MetadataRepository implements IMetadataRepository {
}
@GenerateSql({ params: [DummyValue.UUID, DummyValue.STRING] })
async getCameraModels(userId: string, make: string | undefined): Promise<string[]> {
async getCameraModels(userIds: string[], make: string | undefined): Promise<string[]> {
const query = this.exifRepository
.createQueryBuilder('exif')
.leftJoin('exif.asset', 'asset')
.where('asset.ownerId = :userId', { userId })
.where('asset.ownerId IN (:...userIds )', { userIds })
.select('exif.model', 'model')
.distinctOn(['exif.model']);

View File

@ -103,7 +103,7 @@ describe(SearchService.name, () => {
await expect(
sut.getSearchSuggestions(authStub.user1, { includeNull: true, type: SearchSuggestionType.COUNTRY }),
).resolves.toEqual(['USA', null]);
expect(metadataMock.getCountries).toHaveBeenCalledWith(authStub.user1.user.id);
expect(metadataMock.getCountries).toHaveBeenCalledWith([authStub.user1.user.id]);
});
it('should return search suggestions (without null)', async () => {
@ -111,7 +111,7 @@ describe(SearchService.name, () => {
await expect(
sut.getSearchSuggestions(authStub.user1, { includeNull: false, type: SearchSuggestionType.COUNTRY }),
).resolves.toEqual(['USA']);
expect(metadataMock.getCountries).toHaveBeenCalledWith(authStub.user1.user.id);
expect(metadataMock.getCountries).toHaveBeenCalledWith([authStub.user1.user.id]);
});
});
});

View File

@ -121,26 +121,27 @@ export class SearchService {
}
async getSearchSuggestions(auth: AuthDto, dto: SearchSuggestionRequestDto) {
const results = await this.getSuggestions(auth.user.id, dto);
const userIds = await this.getUserIdsToSearch(auth);
const results = await this.getSuggestions(userIds, dto);
return results.filter((result) => (dto.includeNull ? true : result !== null));
}
private getSuggestions(userId: string, dto: SearchSuggestionRequestDto) {
private getSuggestions(userIds: string[], dto: SearchSuggestionRequestDto) {
switch (dto.type) {
case SearchSuggestionType.COUNTRY: {
return this.metadataRepository.getCountries(userId);
return this.metadataRepository.getCountries(userIds);
}
case SearchSuggestionType.STATE: {
return this.metadataRepository.getStates(userId, dto.country);
return this.metadataRepository.getStates(userIds, dto.country);
}
case SearchSuggestionType.CITY: {
return this.metadataRepository.getCities(userId, dto.country, dto.state);
return this.metadataRepository.getCities(userIds, dto.country, dto.state);
}
case SearchSuggestionType.CAMERA_MAKE: {
return this.metadataRepository.getCameraMakes(userId, dto.model);
return this.metadataRepository.getCameraMakes(userIds, dto.model);
}
case SearchSuggestionType.CAMERA_MODEL: {
return this.metadataRepository.getCameraModels(userId, dto.make);
return this.metadataRepository.getCameraModels(userIds, dto.make);
}
default: {
return [];

View File

@ -5,7 +5,7 @@ export const newPartnerRepositoryMock = (): Mocked<IPartnerRepository> => {
return {
create: vitest.fn(),
remove: vitest.fn(),
getAll: vitest.fn(),
getAll: vitest.fn().mockResolvedValue([]),
get: vitest.fn(),
update: vitest.fn(),
};