feat(server, web): search location (#7139)

* feat: search location

* fix: tests

* feat: outclick

* location search index

* update query

* fixed query

* updated sql

* update query

* Update search.dto.ts

Co-authored-by: Daniel Dietzler <36593685+danieldietzler@users.noreply.github.com>

* coalesce

* fix: tests

* feat: add alternate names

* fix: generate sql files

* single table, add alternate names to query, cleanup

* merge main

* update sql

* pr feedback

* pr feedback

* chore: fix merge

---------

Co-authored-by: mertalev <101130780+mertalev@users.noreply.github.com>
Co-authored-by: Daniel Dietzler <36593685+danieldietzler@users.noreply.github.com>
This commit is contained in:
martin
2024-02-24 01:42:37 +01:00
committed by GitHub
parent 719dbcc4d0
commit a2934b8830
31 changed files with 1040 additions and 117 deletions
+1 -1
View File
@@ -91,7 +91,7 @@ export const citiesFile = 'cities500.txt';
export const geodataDatePath = join(GEODATA_ROOT_PATH, 'geodata-date.txt');
export const geodataAdmin1Path = join(GEODATA_ROOT_PATH, 'admin1CodesASCII.txt');
export const geodataAdmin2Path = join(GEODATA_ROOT_PATH, 'admin2Codes.txt');
export const geodataCitites500Path = join(GEODATA_ROOT_PATH, citiesFile);
export const geodataCities500Path = join(GEODATA_ROOT_PATH, citiesFile);
const image: Record<string, string[]> = {
'.3fr': ['image/3fr', 'image/x-hasselblad-3fr'],
@@ -1,4 +1,4 @@
import { AssetEntity, AssetFaceEntity, AssetType, SmartInfoEntity } from '@app/infra/entities';
import { AssetEntity, AssetFaceEntity, AssetType, GeodataPlacesEntity, SmartInfoEntity } from '@app/infra/entities';
import { Paginated } from '../domain.util';
export const ISearchRepository = 'ISearchRepository';
@@ -186,4 +186,5 @@ export interface ISearchRepository {
searchSmart(pagination: SearchPaginationOptions, options: SmartSearchOptions): Paginated<AssetEntity>;
searchFaces(search: FaceEmbeddingSearch): Promise<FaceSearchResult[]>;
upsert(smartInfo: Partial<SmartInfoEntity>, embedding?: Embedding): Promise<void>;
searchPlaces(placeName: string): Promise<GeodataPlacesEntity[]>;
}
+25 -1
View File
@@ -1,5 +1,5 @@
import { AssetOrder } from '@app/domain/asset/dto/asset.dto';
import { AssetType } from '@app/infra/entities';
import { AssetType, GeodataPlacesEntity } from '@app/infra/entities';
import { ApiProperty } from '@nestjs/swagger';
import { Transform, Type } from 'class-transformer';
import { IsBoolean, IsEnum, IsInt, IsNotEmpty, IsString, Max, Min } from 'class-validator';
@@ -241,6 +241,12 @@ export class SearchDto {
size?: number;
}
export class SearchPlacesDto {
@IsString()
@IsNotEmpty()
name!: string;
}
export class SearchPeopleDto {
@IsString()
@IsNotEmpty()
@@ -251,3 +257,21 @@ export class SearchPeopleDto {
@Optional()
withHidden?: boolean;
}
export class PlacesResponseDto {
name!: string;
latitude!: number;
longitude!: number;
admin1name?: string;
admin2name?: string;
}
export function mapPlaces(place: GeodataPlacesEntity): PlacesResponseDto {
return {
name: place.name,
latitude: place.latitude,
longitude: place.longitude,
admin1name: place.admin1Name,
admin2name: place.admin2Name,
};
}
+14 -1
View File
@@ -16,7 +16,15 @@ import {
SearchStrategy,
} from '../repositories';
import { FeatureFlag, SystemConfigCore } from '../system-config';
import { MetadataSearchDto, SearchDto, SearchPeopleDto, SmartSearchDto } from './dto';
import {
MetadataSearchDto,
PlacesResponseDto,
SearchDto,
SearchPeopleDto,
SearchPlacesDto,
SmartSearchDto,
mapPlaces,
} from './dto';
import { SearchSuggestionRequestDto, SearchSuggestionType } from './dto/search-suggestion.dto';
import { SearchResponseDto } from './response-dto';
@@ -41,6 +49,11 @@ export class SearchService {
return this.personRepository.getByName(auth.user.id, dto.name, { withHidden: dto.withHidden });
}
async searchPlaces(dto: SearchPlacesDto): Promise<PlacesResponseDto[]> {
const places = await this.searchRepository.searchPlaces(dto.name);
return places.map((place) => mapPlaces(place));
}
async getExploreData(auth: AuthDto): Promise<SearchExploreItem<AssetResponseDto>[]> {
await this.configCore.requireFeature(FeatureFlag.SEARCH);
const options = { maxFields: 12, minAssetsPerField: 5 };