mirror of
https://github.com/immich-app/immich.git
synced 2024-12-29 07:01:59 +00:00
fix(server): allow library id to be null in metadata search (#10512)
* fix: allow library id to be null in metadata search * chore: open api
This commit is contained in:
parent
0fda67543d
commit
5e9a7b17d9
9 changed files with 22 additions and 8 deletions
|
@ -339,6 +339,13 @@ describe('/search', () => {
|
||||||
should: 'should search by model',
|
should: 'should search by model',
|
||||||
deferred: () => ({ dto: { model: 'Canon EOS 7D' }, assets: [assetDenali] }),
|
deferred: () => ({ dto: { model: 'Canon EOS 7D' }, assets: [assetDenali] }),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
should: 'should allow searching the upload library (libraryId: null)',
|
||||||
|
deferred: () => ({
|
||||||
|
dto: { libraryId: null, size: 1 },
|
||||||
|
assets: [assetLast],
|
||||||
|
}),
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
for (const { should, deferred } of searchTests) {
|
for (const { should, deferred } of searchTests) {
|
||||||
|
|
BIN
mobile/openapi/lib/model/metadata_search_dto.dart
generated
BIN
mobile/openapi/lib/model/metadata_search_dto.dart
generated
Binary file not shown.
BIN
mobile/openapi/lib/model/smart_search_dto.dart
generated
BIN
mobile/openapi/lib/model/smart_search_dto.dart
generated
Binary file not shown.
|
@ -9026,6 +9026,7 @@
|
||||||
},
|
},
|
||||||
"libraryId": {
|
"libraryId": {
|
||||||
"format": "uuid",
|
"format": "uuid",
|
||||||
|
"nullable": true,
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"make": {
|
"make": {
|
||||||
|
@ -10140,6 +10141,7 @@
|
||||||
},
|
},
|
||||||
"libraryId": {
|
"libraryId": {
|
||||||
"format": "uuid",
|
"format": "uuid",
|
||||||
|
"nullable": true,
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"make": {
|
"make": {
|
||||||
|
|
|
@ -697,7 +697,7 @@ export type MetadataSearchDto = {
|
||||||
isOffline?: boolean;
|
isOffline?: boolean;
|
||||||
isVisible?: boolean;
|
isVisible?: boolean;
|
||||||
lensModel?: string;
|
lensModel?: string;
|
||||||
libraryId?: string;
|
libraryId?: string | null;
|
||||||
make?: string;
|
make?: string;
|
||||||
model?: string;
|
model?: string;
|
||||||
order?: AssetOrder;
|
order?: AssetOrder;
|
||||||
|
@ -768,7 +768,7 @@ export type SmartSearchDto = {
|
||||||
isOffline?: boolean;
|
isOffline?: boolean;
|
||||||
isVisible?: boolean;
|
isVisible?: boolean;
|
||||||
lensModel?: string;
|
lensModel?: string;
|
||||||
libraryId?: string;
|
libraryId?: string | null;
|
||||||
make?: string;
|
make?: string;
|
||||||
model?: string;
|
model?: string;
|
||||||
page?: number;
|
page?: number;
|
||||||
|
|
|
@ -9,8 +9,8 @@ import { GeodataPlacesEntity } from 'src/entities/geodata-places.entity';
|
||||||
import { Optional, ValidateBoolean, ValidateDate, ValidateUUID } from 'src/validation';
|
import { Optional, ValidateBoolean, ValidateDate, ValidateUUID } from 'src/validation';
|
||||||
|
|
||||||
class BaseSearchDto {
|
class BaseSearchDto {
|
||||||
@ValidateUUID({ optional: true })
|
@ValidateUUID({ optional: true, nullable: true })
|
||||||
libraryId?: string;
|
libraryId?: string | null;
|
||||||
|
|
||||||
@IsString()
|
@IsString()
|
||||||
@IsNotEmpty()
|
@IsNotEmpty()
|
||||||
|
|
|
@ -45,7 +45,7 @@ export interface SearchAssetIDOptions {
|
||||||
|
|
||||||
export interface SearchUserIdOptions {
|
export interface SearchUserIdOptions {
|
||||||
deviceId?: string;
|
deviceId?: string;
|
||||||
libraryId?: string;
|
libraryId?: string | null;
|
||||||
userIds?: string[];
|
userIds?: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,6 +52,11 @@ export function searchAssetBuilder(
|
||||||
}
|
}
|
||||||
|
|
||||||
const id = _.pick(options, ['checksum', 'deviceAssetId', 'deviceId', 'id', 'libraryId']);
|
const id = _.pick(options, ['checksum', 'deviceAssetId', 'deviceId', 'id', 'libraryId']);
|
||||||
|
|
||||||
|
if (id.libraryId === null) {
|
||||||
|
id.libraryId = IsNull() as unknown as string;
|
||||||
|
}
|
||||||
|
|
||||||
builder.andWhere(_.omitBy(id, _.isUndefined));
|
builder.andWhere(_.omitBy(id, _.isUndefined));
|
||||||
|
|
||||||
if (options.userIds) {
|
if (options.userIds) {
|
||||||
|
|
|
@ -80,13 +80,13 @@ export function Optional({ nullable, ...validationOptions }: OptionalOptions = {
|
||||||
return ValidateIf((object: any, v: any) => v !== undefined, validationOptions);
|
return ValidateIf((object: any, v: any) => v !== undefined, validationOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
type UUIDOptions = { optional?: boolean; each?: boolean };
|
type UUIDOptions = { optional?: boolean; each?: boolean; nullable?: boolean };
|
||||||
export const ValidateUUID = (options?: UUIDOptions) => {
|
export const ValidateUUID = (options?: UUIDOptions) => {
|
||||||
const { optional, each } = { optional: false, each: false, ...options };
|
const { optional, each, nullable } = { optional: false, each: false, nullable: false, ...options };
|
||||||
return applyDecorators(
|
return applyDecorators(
|
||||||
IsUUID('4', { each }),
|
IsUUID('4', { each }),
|
||||||
ApiProperty({ format: 'uuid' }),
|
ApiProperty({ format: 'uuid' }),
|
||||||
optional ? Optional() : IsNotEmpty(),
|
optional ? Optional({ nullable }) : IsNotEmpty(),
|
||||||
each ? IsArray() : IsString(),
|
each ? IsArray() : IsString(),
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue