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:
@@ -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[]>;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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 };
|
||||
|
||||
Reference in New Issue
Block a user