feat: Search filtering logic (#6968)
* commit * controller/service/repository logic * use enum * openapi * suggest people * suggest place/camera * cursor hover * refactor * Add try catch * Remove get people with name service * Remove deadcode * people selection * People placement * sort people * Update server/src/domain/repositories/metadata.repository.ts Co-authored-by: Jason Rasmussen <jrasm91@gmail.com> * pr feedback * styling * done * open api * fix test * use string type * remmove bad merge * use correct type * fix test * fix lint * remove unused code * remove unused code * pr feedback * pr feedback --------- Co-authored-by: Jason Rasmussen <jrasm91@gmail.com>
This commit is contained in:
@@ -39,4 +39,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<string[]>;
|
||||
getStates(userId: string, country?: string): Promise<string[]>;
|
||||
getCities(userId: string, country?: string, state?: string): Promise<string[]>;
|
||||
getCameraMakes(userId: string, model?: string): Promise<string[]>;
|
||||
getCameraModels(userId: string, make?: string): Promise<string[]>;
|
||||
}
|
||||
|
||||
33
server/src/domain/search/dto/search-suggestion.dto.ts
Normal file
33
server/src/domain/search/dto/search-suggestion.dto.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsEnum, IsNotEmpty, IsOptional, IsString } from 'class-validator';
|
||||
|
||||
export enum SearchSuggestionType {
|
||||
COUNTRY = 'country',
|
||||
STATE = 'state',
|
||||
CITY = 'city',
|
||||
CAMERA_MAKE = 'camera-make',
|
||||
CAMERA_MODEL = 'camera-model',
|
||||
}
|
||||
|
||||
export class SearchSuggestionRequestDto {
|
||||
@IsEnum(SearchSuggestionType)
|
||||
@IsNotEmpty()
|
||||
@ApiProperty({ enumName: 'SearchSuggestionType', enum: SearchSuggestionType })
|
||||
type!: SearchSuggestionType;
|
||||
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
country?: string;
|
||||
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
state?: string;
|
||||
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
make?: string;
|
||||
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
model?: string;
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
authStub,
|
||||
newAssetRepositoryMock,
|
||||
newMachineLearningRepositoryMock,
|
||||
newMetadataRepositoryMock,
|
||||
newPartnerRepositoryMock,
|
||||
newPersonRepositoryMock,
|
||||
newSearchRepositoryMock,
|
||||
@@ -14,6 +15,7 @@ import { mapAsset } from '../asset';
|
||||
import {
|
||||
IAssetRepository,
|
||||
IMachineLearningRepository,
|
||||
IMetadataRepository,
|
||||
IPartnerRepository,
|
||||
IPersonRepository,
|
||||
ISearchRepository,
|
||||
@@ -32,6 +34,7 @@ describe(SearchService.name, () => {
|
||||
let personMock: jest.Mocked<IPersonRepository>;
|
||||
let searchMock: jest.Mocked<ISearchRepository>;
|
||||
let partnerMock: jest.Mocked<IPartnerRepository>;
|
||||
let metadataMock: jest.Mocked<IMetadataRepository>;
|
||||
|
||||
beforeEach(() => {
|
||||
assetMock = newAssetRepositoryMock();
|
||||
@@ -40,7 +43,9 @@ describe(SearchService.name, () => {
|
||||
personMock = newPersonRepositoryMock();
|
||||
searchMock = newSearchRepositoryMock();
|
||||
partnerMock = newPartnerRepositoryMock();
|
||||
sut = new SearchService(configMock, machineMock, personMock, searchMock, assetMock, partnerMock);
|
||||
metadataMock = newMetadataRepositoryMock();
|
||||
|
||||
sut = new SearchService(configMock, machineMock, personMock, searchMock, assetMock, partnerMock, metadataMock);
|
||||
});
|
||||
|
||||
it('should work', () => {
|
||||
|
||||
@@ -7,6 +7,7 @@ import { PersonResponseDto } from '../person';
|
||||
import {
|
||||
IAssetRepository,
|
||||
IMachineLearningRepository,
|
||||
IMetadataRepository,
|
||||
IPartnerRepository,
|
||||
IPersonRepository,
|
||||
ISearchRepository,
|
||||
@@ -16,6 +17,7 @@ import {
|
||||
} from '../repositories';
|
||||
import { FeatureFlag, SystemConfigCore } from '../system-config';
|
||||
import { MetadataSearchDto, SearchDto, SearchPeopleDto, SmartSearchDto } from './dto';
|
||||
import { SearchSuggestionRequestDto, SearchSuggestionType } from './dto/search-suggestion.dto';
|
||||
import { SearchResponseDto } from './response-dto';
|
||||
|
||||
@Injectable()
|
||||
@@ -30,6 +32,7 @@ export class SearchService {
|
||||
@Inject(ISearchRepository) private searchRepository: ISearchRepository,
|
||||
@Inject(IAssetRepository) private assetRepository: IAssetRepository,
|
||||
@Inject(IPartnerRepository) private partnerRepository: IPartnerRepository,
|
||||
@Inject(IMetadataRepository) private metadataRepository: IMetadataRepository,
|
||||
) {
|
||||
this.configCore = SystemConfigCore.create(configRepository);
|
||||
}
|
||||
@@ -176,4 +179,28 @@ export class SearchService {
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
async getSearchSuggestions(auth: AuthDto, dto: SearchSuggestionRequestDto): Promise<string[]> {
|
||||
if (dto.type === SearchSuggestionType.COUNTRY) {
|
||||
return this.metadataRepository.getCountries(auth.user.id);
|
||||
}
|
||||
|
||||
if (dto.type === SearchSuggestionType.STATE) {
|
||||
return this.metadataRepository.getStates(auth.user.id, dto.country);
|
||||
}
|
||||
|
||||
if (dto.type === SearchSuggestionType.CITY) {
|
||||
return this.metadataRepository.getCities(auth.user.id, dto.country, dto.state);
|
||||
}
|
||||
|
||||
if (dto.type === SearchSuggestionType.CAMERA_MAKE) {
|
||||
return this.metadataRepository.getCameraMakes(auth.user.id, dto.model);
|
||||
}
|
||||
|
||||
if (dto.type === SearchSuggestionType.CAMERA_MODEL) {
|
||||
return this.metadataRepository.getCameraModels(auth.user.id, dto.make);
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user