feat(server): sort assets randomly from the API 'api/search/metadata' endpoint by including 'order': 'rand' in the API call. (#12741)

feat(server): search metadata random sort order

Co-authored-by: Jason Rasmussen <jason@rasm.me>
This commit is contained in:
jschwalbe
2024-09-23 12:09:26 -04:00
committed by GitHub
parent a7719a94fc
commit 9f8a7e0bea
15 changed files with 967 additions and 11 deletions

View File

@@ -1,5 +1,6 @@
import { Body, Controller, Delete, Get, HttpCode, HttpStatus, Param, Post, Put, Query } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { EndpointLifecycle } from 'src/decorators';
import { AssetResponseDto, MemoryLaneResponseDto } from 'src/dtos/asset-response.dto';
import {
AssetBulkDeleteDto,
@@ -31,6 +32,7 @@ export class AssetController {
@Get('random')
@Authenticated()
@EndpointLifecycle({ deprecatedAt: 'v1.116.0' })
getRandom(@Auth() auth: AuthDto, @Query() dto: RandomAssetsDto): Promise<AssetResponseDto[]> {
return this.service.getRandom(auth, dto.count ?? 1);
}

View File

@@ -6,6 +6,7 @@ import { PersonResponseDto } from 'src/dtos/person.dto';
import {
MetadataSearchDto,
PlacesResponseDto,
RandomSearchDto,
SearchExploreResponseDto,
SearchPeopleDto,
SearchPlacesDto,
@@ -28,6 +29,13 @@ export class SearchController {
return this.service.searchMetadata(auth, dto);
}
@Post('random')
@HttpCode(HttpStatus.OK)
@Authenticated()
searchRandom(@Auth() auth: AuthDto, @Body() dto: RandomSearchDto): Promise<SearchResponseDto> {
return this.service.searchRandom(auth, dto);
}
@Post('smart')
@HttpCode(HttpStatus.OK)
@Authenticated()

View File

@@ -119,7 +119,15 @@ class BaseSearchDto {
personIds?: string[];
}
export class MetadataSearchDto extends BaseSearchDto {
export class RandomSearchDto extends BaseSearchDto {
@ValidateBoolean({ optional: true })
withStacked?: boolean;
@ValidateBoolean({ optional: true })
withPeople?: boolean;
}
export class MetadataSearchDto extends RandomSearchDto {
@ValidateUUID({ optional: true })
id?: string;
@@ -133,12 +141,6 @@ export class MetadataSearchDto extends BaseSearchDto {
@Optional()
checksum?: string;
@ValidateBoolean({ optional: true })
withStacked?: boolean;
@ValidateBoolean({ optional: true })
withPeople?: boolean;
@IsString()
@IsNotEmpty()
@Optional()

View File

@@ -116,6 +116,7 @@ export interface SearchPeopleOptions {
export interface SearchOrderOptions {
orderDirection?: 'ASC' | 'DESC';
random?: boolean;
}
export interface SearchPaginationOptions {

View File

@@ -73,8 +73,13 @@ export class SearchRepository implements ISearchRepository {
async searchMetadata(pagination: SearchPaginationOptions, options: AssetSearchOptions): Paginated<AssetEntity> {
let builder = this.assetRepository.createQueryBuilder('asset');
builder = searchAssetBuilder(builder, options);
builder.orderBy('asset.fileCreatedAt', options.orderDirection ?? 'DESC');
if (options.random) {
// TODO replace with complicated SQL magic after kysely migration
builder.addSelect('RANDOM() as r').orderBy('r');
}
return paginatedBuilder<AssetEntity>(builder, {
mode: PaginationMode.SKIP_TAKE,
skip: (pagination.page - 1) * pagination.size,

View File

@@ -6,6 +6,7 @@ import { PersonResponseDto } from 'src/dtos/person.dto';
import {
MetadataSearchDto,
PlacesResponseDto,
RandomSearchDto,
SearchPeopleDto,
SearchPlacesDto,
SearchResponseDto,
@@ -93,6 +94,22 @@ export class SearchService {
return this.mapResponse(items, hasNextPage ? (page + 1).toString() : null, { auth });
}
async searchRandom(auth: AuthDto, dto: RandomSearchDto): Promise<SearchResponseDto> {
const userIds = await this.getUserIdsToSearch(auth);
const page = dto.page ?? 1;
const size = dto.size || 250;
const { hasNextPage, items } = await this.searchRepository.searchMetadata(
{ page, size },
{
...dto,
userIds,
random: true,
},
);
return this.mapResponse(items, hasNextPage ? (page + 1).toString() : null, { auth });
}
async searchSmart(auth: AuthDto, dto: SmartSearchDto): Promise<SearchResponseDto> {
const { machineLearning } = await this.configCore.getConfig({ withCache: false });
if (!isSmartSearchEnabled(machineLearning)) {