feat: random memories sort order (#20025)

This commit is contained in:
Jonathan Gilbert 2025-11-11 01:38:50 +11:00 committed by GitHub
parent 6c6b00067b
commit d92df63f84
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 85 additions and 6 deletions

BIN
mobile/openapi/README.md generated

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -4268,6 +4268,24 @@
"type": "boolean" "type": "boolean"
} }
}, },
{
"name": "order",
"required": false,
"in": "query",
"schema": {
"$ref": "#/components/schemas/MemorySearchOrder"
}
},
{
"name": "size",
"required": false,
"in": "query",
"description": "Number of memories to return",
"schema": {
"minimum": 1,
"type": "integer"
}
},
{ {
"name": "type", "name": "type",
"required": false, "required": false,
@ -4381,6 +4399,24 @@
"type": "boolean" "type": "boolean"
} }
}, },
{
"name": "order",
"required": false,
"in": "query",
"schema": {
"$ref": "#/components/schemas/MemorySearchOrder"
}
},
{
"name": "size",
"required": false,
"in": "query",
"description": "Number of memories to return",
"schema": {
"minimum": 1,
"type": "integer"
}
},
{ {
"name": "type", "name": "type",
"required": false, "required": false,
@ -12780,6 +12816,14 @@
], ],
"type": "object" "type": "object"
}, },
"MemorySearchOrder": {
"enum": [
"asc",
"desc",
"random"
],
"type": "string"
},
"MemoryStatisticsResponseDto": { "MemoryStatisticsResponseDto": {
"properties": { "properties": {
"total": { "total": {

View file

@ -2956,10 +2956,12 @@ export function reverseGeocode({ lat, lon }: {
/** /**
* This endpoint requires the `memory.read` permission. * This endpoint requires the `memory.read` permission.
*/ */
export function searchMemories({ $for, isSaved, isTrashed, $type }: { export function searchMemories({ $for, isSaved, isTrashed, order, size, $type }: {
$for?: string; $for?: string;
isSaved?: boolean; isSaved?: boolean;
isTrashed?: boolean; isTrashed?: boolean;
order?: MemorySearchOrder;
size?: number;
$type?: MemoryType; $type?: MemoryType;
}, opts?: Oazapfts.RequestOpts) { }, opts?: Oazapfts.RequestOpts) {
return oazapfts.ok(oazapfts.fetchJson<{ return oazapfts.ok(oazapfts.fetchJson<{
@ -2969,6 +2971,8 @@ export function searchMemories({ $for, isSaved, isTrashed, $type }: {
"for": $for, "for": $for,
isSaved, isSaved,
isTrashed, isTrashed,
order,
size,
"type": $type "type": $type
}))}`, { }))}`, {
...opts ...opts
@ -2992,10 +2996,12 @@ export function createMemory({ memoryCreateDto }: {
/** /**
* This endpoint requires the `memory.statistics` permission. * This endpoint requires the `memory.statistics` permission.
*/ */
export function memoriesStatistics({ $for, isSaved, isTrashed, $type }: { export function memoriesStatistics({ $for, isSaved, isTrashed, order, size, $type }: {
$for?: string; $for?: string;
isSaved?: boolean; isSaved?: boolean;
isTrashed?: boolean; isTrashed?: boolean;
order?: MemorySearchOrder;
size?: number;
$type?: MemoryType; $type?: MemoryType;
}, opts?: Oazapfts.RequestOpts) { }, opts?: Oazapfts.RequestOpts) {
return oazapfts.ok(oazapfts.fetchJson<{ return oazapfts.ok(oazapfts.fetchJson<{
@ -3005,6 +3011,8 @@ export function memoriesStatistics({ $for, isSaved, isTrashed, $type }: {
"for": $for, "for": $for,
isSaved, isSaved,
isTrashed, isTrashed,
order,
size,
"type": $type "type": $type
}))}`, { }))}`, {
...opts ...opts
@ -4991,6 +4999,11 @@ export enum JobCommand {
Empty = "empty", Empty = "empty",
ClearFailed = "clear-failed" ClearFailed = "clear-failed"
} }
export enum MemorySearchOrder {
Asc = "asc",
Desc = "desc",
Random = "random"
}
export enum MemoryType { export enum MemoryType {
OnThisDay = "on_this_day" OnThisDay = "on_this_day"
} }

View file

@ -4,7 +4,7 @@ import { IsInt, IsObject, IsPositive, ValidateNested } from 'class-validator';
import { Memory } from 'src/database'; import { Memory } from 'src/database';
import { AssetResponseDto, mapAsset } from 'src/dtos/asset-response.dto'; import { AssetResponseDto, mapAsset } from 'src/dtos/asset-response.dto';
import { AuthDto } from 'src/dtos/auth.dto'; import { AuthDto } from 'src/dtos/auth.dto';
import { MemoryType } from 'src/enum'; import { AssetOrderWithRandom, MemoryType } from 'src/enum';
import { ValidateBoolean, ValidateDate, ValidateEnum, ValidateUUID } from 'src/validation'; import { ValidateBoolean, ValidateDate, ValidateEnum, ValidateUUID } from 'src/validation';
class MemoryBaseDto { class MemoryBaseDto {
@ -27,6 +27,15 @@ export class MemorySearchDto {
@ValidateBoolean({ optional: true }) @ValidateBoolean({ optional: true })
isSaved?: boolean; isSaved?: boolean;
@IsInt()
@IsPositive()
@Type(() => Number)
@ApiProperty({ type: 'integer', description: 'Number of memories to return' })
size?: number;
@ValidateEnum({ enum: AssetOrderWithRandom, name: 'MemorySearchOrder', optional: true })
order?: AssetOrderWithRandom;
} }
class OnThisDayDto { class OnThisDayDto {

View file

@ -71,6 +71,14 @@ export enum MemoryType {
OnThisDay = 'on_this_day', OnThisDay = 'on_this_day',
} }
export enum AssetOrderWithRandom {
// Include existing values
Asc = AssetOrder.Asc,
Desc = AssetOrder.Desc,
/** Randomly Ordered */
Random = 'random',
}
export enum Permission { export enum Permission {
All = 'all', All = 'all',

View file

@ -1,11 +1,11 @@
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import { Insertable, Kysely, sql, Updateable } from 'kysely'; import { Insertable, Kysely, OrderByDirection, sql, Updateable } from 'kysely';
import { jsonArrayFrom } from 'kysely/helpers/postgres'; import { jsonArrayFrom } from 'kysely/helpers/postgres';
import { DateTime } from 'luxon'; import { DateTime } from 'luxon';
import { InjectKysely } from 'nestjs-kysely'; import { InjectKysely } from 'nestjs-kysely';
import { Chunked, ChunkedSet, DummyValue, GenerateSql } from 'src/decorators'; import { Chunked, ChunkedSet, DummyValue, GenerateSql } from 'src/decorators';
import { MemorySearchDto } from 'src/dtos/memory.dto'; import { MemorySearchDto } from 'src/dtos/memory.dto';
import { AssetVisibility } from 'src/enum'; import { AssetOrderWithRandom, AssetVisibility } from 'src/enum';
import { DB } from 'src/schema'; import { DB } from 'src/schema';
import { MemoryTable } from 'src/schema/tables/memory.table'; import { MemoryTable } from 'src/schema/tables/memory.table';
import { IBulkAsset } from 'src/types'; import { IBulkAsset } from 'src/types';
@ -72,7 +72,12 @@ export class MemoryRepository implements IBulkAsset {
).as('assets'), ).as('assets'),
) )
.selectAll('memory') .selectAll('memory')
.orderBy('memoryAt', 'desc') .$call((qb) =>
dto.order === AssetOrderWithRandom.Random
? qb.orderBy(sql`RANDOM()`)
: qb.orderBy('memoryAt', (dto.order?.toLowerCase() || 'desc') as OrderByDirection),
)
.$if(dto.size !== undefined, (qb) => qb.limit(dto.size!))
.execute(); .execute();
} }