mirror of
https://github.com/xuthus83/pigallery2.git
synced 2025-01-14 14:43:17 +08:00
Add person count search and sorting support.
Note it will trigger a DB drop as the scheme changed. #683
This commit is contained in:
parent
1974323b61
commit
0e460d07af
@ -367,6 +367,7 @@ export class IndexingManager {
|
||||
),
|
||||
];
|
||||
}
|
||||
(media[i].metadata as PhotoMetadataEntity).personsLength = (media[i].metadata as PhotoMetadataEntity)?.persons?.length || 0;
|
||||
|
||||
|
||||
if (mediaItem == null) {
|
||||
|
@ -13,9 +13,9 @@ import {
|
||||
DatePatternFrequency,
|
||||
DatePatternSearch,
|
||||
DistanceSearch,
|
||||
FromDateSearch,
|
||||
FromDateSearch, MaxPersonCountSearch,
|
||||
MaxRatingSearch,
|
||||
MaxResolutionSearch,
|
||||
MaxResolutionSearch, MinPersonCountSearch,
|
||||
MinRatingSearch,
|
||||
MinResolutionSearch,
|
||||
OrientationSearch,
|
||||
@ -379,6 +379,12 @@ export class SearchManager {
|
||||
case SortingMethods.ascName:
|
||||
query.addOrderBy('media.name', 'ASC');
|
||||
break;
|
||||
case SortingMethods.descPersonCount:
|
||||
query.addOrderBy('media.metadata.personsLength', 'DESC');
|
||||
break;
|
||||
case SortingMethods.ascPersonCount:
|
||||
query.addOrderBy('media.metadata.personsLength', 'ASC');
|
||||
break;
|
||||
case SortingMethods.random:
|
||||
if (Config.Database.type === DatabaseType.mysql) {
|
||||
query.groupBy('RAND(), media.id');
|
||||
@ -639,6 +645,52 @@ export class SearchManager {
|
||||
return q;
|
||||
});
|
||||
|
||||
case SearchQueryTypes.min_person_count:
|
||||
if (directoryOnly) {
|
||||
throw new Error('not supported in directoryOnly mode');
|
||||
}
|
||||
return new Brackets((q): unknown => {
|
||||
if (typeof (query as MinPersonCountSearch).value === 'undefined') {
|
||||
throw new Error(
|
||||
'Invalid search query: Person count Query should contain minvalue'
|
||||
);
|
||||
}
|
||||
|
||||
const relation = (query as TextSearch).negate ? '<' : '>=';
|
||||
|
||||
const textParam: { [key: string]: unknown } = {};
|
||||
textParam['min' + queryId] = (query as MinPersonCountSearch).value;
|
||||
q.where(
|
||||
`media.metadata.personsLength ${relation} :min${queryId}`,
|
||||
textParam
|
||||
);
|
||||
|
||||
return q;
|
||||
});
|
||||
case SearchQueryTypes.max_person_count:
|
||||
if (directoryOnly) {
|
||||
throw new Error('not supported in directoryOnly mode');
|
||||
}
|
||||
return new Brackets((q): unknown => {
|
||||
if (typeof (query as MaxPersonCountSearch).value === 'undefined') {
|
||||
throw new Error(
|
||||
'Invalid search query: Person count Query should contain max value'
|
||||
);
|
||||
}
|
||||
|
||||
const relation = (query as TextSearch).negate ? '>' : '<=';
|
||||
|
||||
if (typeof (query as MaxRatingSearch).value !== 'undefined') {
|
||||
const textParam: { [key: string]: unknown } = {};
|
||||
textParam['max' + queryId] = (query as MaxPersonCountSearch).value;
|
||||
q.where(
|
||||
`media.metadata.personsLength ${relation} :max${queryId}`,
|
||||
textParam
|
||||
);
|
||||
}
|
||||
return q;
|
||||
});
|
||||
|
||||
case SearchQueryTypes.min_resolution:
|
||||
if (directoryOnly) {
|
||||
throw new Error('not supported in directoryOnly mode');
|
||||
|
@ -1,26 +1,9 @@
|
||||
import {
|
||||
Column,
|
||||
Entity,
|
||||
Index,
|
||||
ManyToOne,
|
||||
OneToMany,
|
||||
PrimaryGeneratedColumn,
|
||||
TableInheritance,
|
||||
Unique,
|
||||
} from 'typeorm';
|
||||
import {Column, Entity, Index, ManyToOne, OneToMany, PrimaryGeneratedColumn, TableInheritance, Unique,} from 'typeorm';
|
||||
import {DirectoryEntity} from './DirectoryEntity';
|
||||
import {
|
||||
MediaDimension,
|
||||
MediaDTO,
|
||||
MediaMetadata,
|
||||
} from '../../../../common/entities/MediaDTO';
|
||||
import {MediaDimension, MediaDTO, MediaMetadata,} from '../../../../common/entities/MediaDTO';
|
||||
import {PersonJunctionTable} from './PersonJunctionTable';
|
||||
import {columnCharsetCS} from './EntityUtils';
|
||||
import {
|
||||
CameraMetadata, FaceRegion,
|
||||
GPSMetadata,
|
||||
PositionMetaData,
|
||||
} from '../../../../common/entities/PhotoDTO';
|
||||
import {CameraMetadata, FaceRegion, GPSMetadata, PositionMetaData,} from '../../../../common/entities/PhotoDTO';
|
||||
|
||||
export class MediaDimensionEntity implements MediaDimension {
|
||||
@Column('int')
|
||||
@ -147,7 +130,8 @@ export class MediaMetadataEntity implements MediaMetadata {
|
||||
type: 'simple-json',
|
||||
nullable: true,
|
||||
charset: columnCharsetCS.charset,
|
||||
collation: columnCharsetCS.collation})
|
||||
collation: columnCharsetCS.collation
|
||||
})
|
||||
faces: FaceRegion[];
|
||||
|
||||
/**
|
||||
@ -162,6 +146,18 @@ export class MediaMetadataEntity implements MediaMetadata {
|
||||
})
|
||||
persons: string[];
|
||||
|
||||
/**
|
||||
* Caches the list of persons' length. Only used for searching
|
||||
*/
|
||||
@Column({
|
||||
type: 'tinyint',
|
||||
select: false,
|
||||
nullable: false,
|
||||
default: 0
|
||||
})
|
||||
personsLength: number;
|
||||
|
||||
|
||||
@Column('int', {unsigned: true})
|
||||
bitRate: number;
|
||||
|
||||
|
@ -35,7 +35,7 @@ export class TopPickSendJob extends Job<{
|
||||
type: 'sort-array',
|
||||
name: backendTexts.sortBy.name,
|
||||
description: backendTexts.sortBy.description,
|
||||
defaultValue: [SortingMethods.descRating],
|
||||
defaultValue: [SortingMethods.descRating, SortingMethods.descPersonCount],
|
||||
}, {
|
||||
id: 'pickAmount',
|
||||
type: 'number',
|
||||
|
@ -1,4 +1,4 @@
|
||||
/**
|
||||
* This version indicates that the sql/entities/*Entity.ts files got changed and the db needs to be recreated
|
||||
*/
|
||||
export const DataStructureVersion = 30;
|
||||
export const DataStructureVersion = 31;
|
||||
|
@ -13,6 +13,8 @@ export const PG2ConfMap = {
|
||||
'.order_descending_rating.pg2conf': SortingMethods.descRating,
|
||||
'.order_ascending_rating.pg2conf': SortingMethods.ascRating,
|
||||
'.order_random.pg2conf': SortingMethods.random,
|
||||
'.order_descending_person_count.pg2conf': SortingMethods.descPersonCount,
|
||||
'.order_ascending_person_count.pg2conf': SortingMethods.descPersonCount,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -4,10 +4,6 @@ import {
|
||||
DatePatternSearch,
|
||||
DistanceSearch,
|
||||
FromDateSearch,
|
||||
MaxRatingSearch,
|
||||
MaxResolutionSearch,
|
||||
MinRatingSearch,
|
||||
MinResolutionSearch,
|
||||
NegatableSearchQuery,
|
||||
OrientationSearch,
|
||||
ORSearchQuery,
|
||||
@ -41,6 +37,8 @@ export interface QueryKeywords {
|
||||
minResolution: string;
|
||||
maxRating: string;
|
||||
minRating: string;
|
||||
maxPersonCount: string;
|
||||
minPersonCount: string;
|
||||
NSomeOf: string;
|
||||
someOf: string;
|
||||
or: string;
|
||||
@ -65,8 +63,10 @@ export const defaultQueryKeywords: QueryKeywords = {
|
||||
to: 'before',
|
||||
|
||||
maxRating: 'max-rating',
|
||||
maxResolution: 'max-resolution',
|
||||
minRating: 'min-rating',
|
||||
maxPersonCount: 'max-persons',
|
||||
minPersonCount: 'min-persons',
|
||||
maxResolution: 'max-resolution',
|
||||
minResolution: 'min-resolution',
|
||||
|
||||
kmFrom: 'km-from',
|
||||
@ -303,38 +303,28 @@ export class SearchQueryParser {
|
||||
} as ToDateSearch;
|
||||
}
|
||||
|
||||
if (kwStartsWith(str, this.keywords.minRating)) {
|
||||
const addValueRangeParser = (matcher: string, type: SearchQueryTypes): RangeSearch | undefined => {
|
||||
if (kwStartsWith(str, matcher)) {
|
||||
return {
|
||||
type: SearchQueryTypes.min_rating,
|
||||
type: type,
|
||||
value: parseInt(str.substring(str.indexOf(':') + 1), 10),
|
||||
...(str.startsWith(this.keywords.minRating + '!:') && {negate: true}), // only add if the value is true
|
||||
} as MinRatingSearch;
|
||||
...(str.startsWith(matcher + '!:') && {negate: true}), // only add if the value is true
|
||||
} as RangeSearch;
|
||||
}
|
||||
if (kwStartsWith(str, this.keywords.maxRating)) {
|
||||
return {
|
||||
type: SearchQueryTypes.max_rating,
|
||||
value: parseInt(str.substring(str.indexOf(':') + 1), 10),
|
||||
...(str.startsWith(this.keywords.maxRating + '!:') && {negate: true}), // only add if the value is true
|
||||
} as MaxRatingSearch;
|
||||
}
|
||||
if (kwStartsWith(str, this.keywords.minResolution)) {
|
||||
return {
|
||||
type: SearchQueryTypes.min_resolution,
|
||||
value: parseInt(str.substring(str.indexOf(':') + 1), 10),
|
||||
...(str.startsWith(this.keywords.minResolution + '!:') && {
|
||||
negate: true,
|
||||
}), // only add if the value is true
|
||||
} as MinResolutionSearch;
|
||||
}
|
||||
if (kwStartsWith(str, this.keywords.maxResolution)) {
|
||||
return {
|
||||
type: SearchQueryTypes.max_resolution,
|
||||
value: parseInt(str.substring(str.indexOf(':') + 1), 10),
|
||||
...(str.startsWith(this.keywords.maxResolution + '!:') && {
|
||||
negate: true,
|
||||
}), // only add if the value is true
|
||||
} as MaxResolutionSearch;
|
||||
};
|
||||
|
||||
const range = addValueRangeParser(this.keywords.minRating, SearchQueryTypes.min_rating) ||
|
||||
addValueRangeParser(this.keywords.maxRating, SearchQueryTypes.max_rating) ||
|
||||
addValueRangeParser(this.keywords.minResolution, SearchQueryTypes.min_resolution) ||
|
||||
addValueRangeParser(this.keywords.maxResolution, SearchQueryTypes.max_resolution) ||
|
||||
addValueRangeParser(this.keywords.minPersonCount, SearchQueryTypes.min_person_count) ||
|
||||
addValueRangeParser(this.keywords.maxPersonCount, SearchQueryTypes.max_person_count);
|
||||
|
||||
if (range) {
|
||||
return range;
|
||||
}
|
||||
|
||||
|
||||
if (new RegExp('^\\d*-' + this.keywords.kmFrom + '!?:').test(str)) {
|
||||
let from = str.slice(
|
||||
new RegExp('^\\d*-' + this.keywords.kmFrom + '!?:').exec(str)[0].length
|
||||
@ -528,6 +518,22 @@ export class SearchQueryParser {
|
||||
? ''
|
||||
: (query as RangeSearch).value)
|
||||
);
|
||||
case SearchQueryTypes.min_person_count:
|
||||
return (
|
||||
this.keywords.minPersonCount +
|
||||
colon +
|
||||
(isNaN((query as RangeSearch).value)
|
||||
? ''
|
||||
: (query as RangeSearch).value)
|
||||
);
|
||||
case SearchQueryTypes.max_person_count:
|
||||
return (
|
||||
this.keywords.maxPersonCount +
|
||||
colon +
|
||||
(isNaN((query as RangeSearch).value)
|
||||
? ''
|
||||
: (query as RangeSearch).value)
|
||||
);
|
||||
case SearchQueryTypes.min_resolution:
|
||||
return (
|
||||
this.keywords.minResolution +
|
||||
|
@ -898,6 +898,7 @@ export class ServerPreviewConfig {
|
||||
Sorting: SortingMethods[] = [
|
||||
SortingMethods.descRating,
|
||||
SortingMethods.descDate,
|
||||
SortingMethods.descPersonCount,
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -14,10 +14,14 @@ export enum SearchQueryTypes {
|
||||
max_rating,
|
||||
min_resolution,
|
||||
max_resolution,
|
||||
min_person_count,
|
||||
max_person_count,
|
||||
|
||||
distance,
|
||||
distance = 50,
|
||||
orientation,
|
||||
date_pattern,
|
||||
|
||||
|
||||
date_pattern = 60,
|
||||
|
||||
// TEXT search types
|
||||
any_text = 100,
|
||||
@ -211,6 +215,17 @@ export interface MaxRatingSearch extends RangeSearch {
|
||||
value: number;
|
||||
}
|
||||
|
||||
|
||||
export interface MinPersonCountSearch extends RangeSearch {
|
||||
type: SearchQueryTypes.min_person_count;
|
||||
value: number;
|
||||
}
|
||||
|
||||
export interface MaxPersonCountSearch extends RangeSearch {
|
||||
type: SearchQueryTypes.max_person_count;
|
||||
value: number;
|
||||
}
|
||||
|
||||
export interface MinResolutionSearch extends RangeSearch {
|
||||
type: SearchQueryTypes.min_resolution;
|
||||
value: number; // in megapixels
|
||||
|
@ -1,9 +1,15 @@
|
||||
/**
|
||||
* Order of these enums determines the order in the UI.
|
||||
* Keep spaces between the values, so new value can be added in between without changing the existing ones
|
||||
*/
|
||||
export enum SortingMethods {
|
||||
ascName = 1,
|
||||
descName,
|
||||
ascDate,
|
||||
descDate,
|
||||
ascRating,
|
||||
descRating,
|
||||
random,
|
||||
ascName = 10,
|
||||
descName = 11,
|
||||
ascDate = 20,
|
||||
descDate = 21,
|
||||
ascRating = 30,
|
||||
descRating = 31,
|
||||
ascPersonCount = 40,
|
||||
descPersonCount = 41,
|
||||
random = 100 // let's keep random as the last in the UI
|
||||
}
|
||||
|
@ -9,6 +9,10 @@ export class IconizeSortingMethod implements PipeTransform {
|
||||
return '<span class="oi oi-sort-ascending"></span><span class="oi oi-star text-bold"></span>';
|
||||
case SortingMethods.descRating:
|
||||
return '<span class="oi oi-sort-descending"></span><span class="oi oi-star text-bold"></span>';
|
||||
case SortingMethods.ascPersonCount:
|
||||
return '<span class="oi oi-sort-ascending"></span><span class="oi oi-person text-bold"></span>';
|
||||
case SortingMethods.descPersonCount:
|
||||
return '<span class="oi oi-sort-descending"></span><span class="oi oi-person text-bold"></span>';
|
||||
case SortingMethods.ascName:
|
||||
return '<span class="oi oi-sort-ascending"></span><strong>A</strong>';
|
||||
case SortingMethods.descName:
|
||||
|
@ -43,6 +43,8 @@ EnumTranslations[SortingMethods[SortingMethods.ascName]] = $localize`ascending n
|
||||
EnumTranslations[SortingMethods[SortingMethods.descRating]] = $localize`descending rating`;
|
||||
EnumTranslations[SortingMethods[SortingMethods.ascRating]] = $localize`ascending rating`;
|
||||
EnumTranslations[SortingMethods[SortingMethods.random]] = $localize`random`;
|
||||
EnumTranslations[SortingMethods[SortingMethods.ascPersonCount]] = $localize`ascending persons`;
|
||||
EnumTranslations[SortingMethods[SortingMethods.descPersonCount]] = $localize`descending persons`;
|
||||
|
||||
|
||||
EnumTranslations[NavigationLinkTypes[NavigationLinkTypes.url]] = $localize`Url`;
|
||||
|
@ -179,6 +179,18 @@ export class GallerySortingService {
|
||||
(b.metadata.rating || 0) - (a.metadata.rating || 0)
|
||||
);
|
||||
break;
|
||||
case SortingMethods.ascPersonCount:
|
||||
c.media.sort(
|
||||
(a: PhotoDTO, b: PhotoDTO) =>
|
||||
(a.metadata?.faces?.length || 0) - (b.metadata?.faces?.length || 0)
|
||||
);
|
||||
break;
|
||||
case SortingMethods.descPersonCount:
|
||||
c.media.sort(
|
||||
(a: PhotoDTO, b: PhotoDTO) =>
|
||||
(b.metadata?.faces?.length || 0) - (a.metadata?.faces?.length || 0)
|
||||
);
|
||||
break;
|
||||
case SortingMethods.random:
|
||||
this.rndService.setSeed(c.media.length);
|
||||
c.media
|
||||
|
@ -29,6 +29,8 @@ export class AutoCompleteService {
|
||||
k !== this.searchQueryParserService.keywords.NSomeOf &&
|
||||
k !== this.searchQueryParserService.keywords.minRating &&
|
||||
k !== this.searchQueryParserService.keywords.maxRating &&
|
||||
k !== this.searchQueryParserService.keywords.minPersonCount &&
|
||||
k !== this.searchQueryParserService.keywords.maxPersonCount &&
|
||||
k !== this.searchQueryParserService.keywords.every_week &&
|
||||
k !== this.searchQueryParserService.keywords.every_month &&
|
||||
k !== this.searchQueryParserService.keywords.every_year &&
|
||||
@ -91,6 +93,11 @@ export class AutoCompleteService {
|
||||
this.noACKeywordsMap[this.searchQueryParserService.keywords.maxRating]
|
||||
= SearchQueryTypes.max_rating;
|
||||
|
||||
this.noACKeywordsMap[this.searchQueryParserService.keywords.minPersonCount]
|
||||
= SearchQueryTypes.min_person_count;
|
||||
this.noACKeywordsMap[this.searchQueryParserService.keywords.maxPersonCount]
|
||||
= SearchQueryTypes.max_person_count;
|
||||
|
||||
this.noACKeywordsMap[this.searchQueryParserService.keywords.minResolution]
|
||||
= SearchQueryTypes.min_resolution;
|
||||
this.noACKeywordsMap[this.searchQueryParserService.keywords.maxResolution]
|
||||
@ -321,11 +328,13 @@ export class AutoCompleteService {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const addRangeAutoComp = (minStr: string, maxStr: string, minRange: number, maxRange: number) => {
|
||||
// only showing rating recommendations of the full query is typed
|
||||
const mrKey = this.searchQueryParserService.keywords.minRating + ':';
|
||||
const mxrKey = this.searchQueryParserService.keywords.maxRating + ':';
|
||||
const mrKey = minStr + ':';
|
||||
const mxrKey = maxStr + ':';
|
||||
if (text.current.toLowerCase().startsWith(mrKey)) {
|
||||
for (let i = 1; i <= 5; ++i) {
|
||||
for (let i = minRange; i <= maxRange; ++i) {
|
||||
ret.push(generateMatch(mrKey + i));
|
||||
}
|
||||
} else if (mrKey.startsWith(text.current.toLowerCase())) {
|
||||
@ -334,12 +343,18 @@ export class AutoCompleteService {
|
||||
|
||||
|
||||
if (text.current.toLowerCase().startsWith(mxrKey)) {
|
||||
for (let i = 1; i <= 5; ++i) {
|
||||
for (let i = minRange; i <= maxRange; ++i) {
|
||||
ret.push(generateMatch(mxrKey + i));
|
||||
}
|
||||
} else if (mxrKey.startsWith(text.current.toLowerCase())) {
|
||||
ret.push(generateMatch(mxrKey));
|
||||
}
|
||||
};
|
||||
addRangeAutoComp(this.searchQueryParserService.keywords.minRating,
|
||||
this.searchQueryParserService.keywords.maxRating, 1, 5);
|
||||
addRangeAutoComp(this.searchQueryParserService.keywords.minPersonCount,
|
||||
this.searchQueryParserService.keywords.maxPersonCount, 0, 9);
|
||||
|
||||
|
||||
// Date patterns
|
||||
if (new RegExp('^' +
|
||||
|
@ -16,8 +16,10 @@ export class SearchQueryParserService {
|
||||
to: 'before',
|
||||
landscape: 'landscape',
|
||||
maxRating: 'max-rating',
|
||||
maxResolution: 'max-resolution',
|
||||
minRating: 'min-rating',
|
||||
minPersonCount: 'min-persons',
|
||||
maxPersonCount: 'max-persons',
|
||||
maxResolution: 'max-resolution',
|
||||
minResolution: 'min-resolution',
|
||||
orientation: 'orientation',
|
||||
|
||||
|
@ -9,8 +9,10 @@ import {
|
||||
DatePatternSearch,
|
||||
DistanceSearch,
|
||||
FromDateSearch,
|
||||
MaxPersonCountSearch,
|
||||
MaxRatingSearch,
|
||||
MaxResolutionSearch,
|
||||
MinPersonCountSearch,
|
||||
MinRatingSearch,
|
||||
MinResolutionSearch,
|
||||
OrientationSearch,
|
||||
@ -1094,6 +1096,83 @@ describe('SearchManager', (sqlHelper: DBTestHelper) => {
|
||||
});
|
||||
|
||||
|
||||
it('should search person count', async () => {
|
||||
const sm = new SearchManager();
|
||||
|
||||
let query: MinPersonCountSearch | MaxPersonCountSearch = {value: 0, type: SearchQueryTypes.max_person_count} as MaxPersonCountSearch;
|
||||
|
||||
|
||||
expect(Utils.clone(await sm.search(query)))
|
||||
.to.deep.equalInAnyOrder(removeDir({
|
||||
searchQuery: query,
|
||||
directories: [],
|
||||
media: [pFaceLess, v],
|
||||
metaFile: [],
|
||||
resultOverflow: false
|
||||
} as SearchResultDTO));
|
||||
|
||||
query = ({value: 20, type: SearchQueryTypes.max_person_count} as MaxPersonCountSearch);
|
||||
expect(Utils.clone(await sm.search(query)))
|
||||
.to.deep.equalInAnyOrder(removeDir({
|
||||
searchQuery: query,
|
||||
directories: [],
|
||||
media: [p, p2, pFaceLess, p4, v],
|
||||
metaFile: [],
|
||||
resultOverflow: false
|
||||
} as SearchResultDTO));
|
||||
|
||||
query = ({value: 20, negate: true, type: SearchQueryTypes.max_person_count} as MaxPersonCountSearch);
|
||||
expect(Utils.clone(await sm.search(query)))
|
||||
.to.deep.equalInAnyOrder(removeDir({
|
||||
searchQuery: query,
|
||||
directories: [],
|
||||
media: [],
|
||||
metaFile: [],
|
||||
resultOverflow: false
|
||||
} as SearchResultDTO));
|
||||
|
||||
|
||||
query = ({value: 4, type: SearchQueryTypes.max_person_count} as MaxPersonCountSearch);
|
||||
expect(Utils.clone(await sm.search(query)))
|
||||
.to.deep.equalInAnyOrder(removeDir({
|
||||
searchQuery: query,
|
||||
directories: [],
|
||||
media: [p2, p4, pFaceLess, v],
|
||||
metaFile: [],
|
||||
resultOverflow: false
|
||||
} as SearchResultDTO));
|
||||
|
||||
query = ({value: 2, type: SearchQueryTypes.min_person_count} as MinPersonCountSearch);
|
||||
expect(Utils.clone(await sm.search(query)))
|
||||
.to.deep.equalInAnyOrder(removeDir({
|
||||
searchQuery: query,
|
||||
directories: [],
|
||||
media: [p, p2, p4],
|
||||
metaFile: [],
|
||||
resultOverflow: false
|
||||
} as SearchResultDTO));
|
||||
|
||||
query = ({value: 6, type: SearchQueryTypes.min_person_count} as MinPersonCountSearch);
|
||||
expect(Utils.clone(await sm.search(query)))
|
||||
.to.deep.equalInAnyOrder(removeDir({
|
||||
searchQuery: query,
|
||||
directories: [],
|
||||
media: [p],
|
||||
metaFile: [],
|
||||
resultOverflow: false
|
||||
} as SearchResultDTO));
|
||||
|
||||
query = ({value: 2, negate: true, type: SearchQueryTypes.min_person_count} as MinPersonCountSearch);
|
||||
expect(Utils.clone(await sm.search(query)))
|
||||
.to.deep.equalInAnyOrder(removeDir({
|
||||
searchQuery: query,
|
||||
directories: [],
|
||||
media: [v, pFaceLess],
|
||||
metaFile: [],
|
||||
resultOverflow: false
|
||||
} as SearchResultDTO));
|
||||
});
|
||||
|
||||
it('should search resolution', async () => {
|
||||
const sm = new SearchManager();
|
||||
|
||||
|
@ -5,8 +5,9 @@ import {
|
||||
DatePatternSearch,
|
||||
DistanceSearch,
|
||||
FromDateSearch,
|
||||
MaxPersonCountSearch,
|
||||
MaxRatingSearch,
|
||||
MaxResolutionSearch,
|
||||
MaxResolutionSearch, MinPersonCountSearch,
|
||||
MinRatingSearch,
|
||||
MinResolutionSearch,
|
||||
OrientationSearch,
|
||||
@ -98,6 +99,12 @@ describe('SearchQueryParser', () => {
|
||||
check({type: SearchQueryTypes.min_rating, value: 10, negate: true} as MinRatingSearch);
|
||||
check({type: SearchQueryTypes.max_rating, value: 1, negate: true} as MaxRatingSearch);
|
||||
});
|
||||
it('Person count search', () => {
|
||||
check({type: SearchQueryTypes.min_person_count, value: 10} as MinPersonCountSearch);
|
||||
check({type: SearchQueryTypes.max_person_count, value: 1} as MaxPersonCountSearch);
|
||||
check({type: SearchQueryTypes.min_person_count, value: 10, negate: true} as MinPersonCountSearch);
|
||||
check({type: SearchQueryTypes.max_person_count, value: 1, negate: true} as MaxPersonCountSearch);
|
||||
});
|
||||
it('Resolution search', () => {
|
||||
check({type: SearchQueryTypes.min_resolution, value: 10} as MinResolutionSearch);
|
||||
check({type: SearchQueryTypes.max_resolution, value: 5} as MaxResolutionSearch);
|
||||
|
Loading…
x
Reference in New Issue
Block a user