1
0
mirror of https://github.com/xuthus83/pigallery2.git synced 2024-11-03 21:04:03 +08:00

Fixing parsing errors.

This commit is contained in:
Patrik J. Braun 2021-03-14 10:56:59 +01:00
parent 47703b6b84
commit 41292ec4b4
4 changed files with 102 additions and 41 deletions

View File

@ -274,9 +274,7 @@ export class SearchManager implements ISearchManager {
if (typeof (<FromDateSearch>query).value === 'undefined') { if (typeof (<FromDateSearch>query).value === 'undefined') {
throw new Error('Invalid search query: Date Query should contain from value'); throw new Error('Invalid search query: Date Query should contain from value');
} }
const whereFN = (<TextSearch>query).negate ? 'orWhere' : 'andWhere';
const relation = (<TextSearch>query).negate ? '<' : '>='; const relation = (<TextSearch>query).negate ? '<' : '>=';
const relationRev = (<TextSearch>query).negate ? '>' : '<=';
const textParam: any = {}; const textParam: any = {};
textParam['from' + paramCounter.value] = (<FromDateSearch>query).value; textParam['from' + paramCounter.value] = (<FromDateSearch>query).value;

View File

@ -2,7 +2,7 @@ import {GPSMetadata} from './PhotoDTO';
import {Utils} from '../Utils'; import {Utils} from '../Utils';
export enum SearchQueryTypes { export enum SearchQueryTypes {
AND = 1, OR, SOME_OF, AND = 1, OR, SOME_OF, UNKNOWN_RELATION = 99999,
// non-text metadata // non-text metadata
// |- range types // |- range types
@ -120,17 +120,22 @@ export namespace SearchQueryDTO {
} }
}; };
export const parse = (str: string): SearchQueryDTO => { export const parse = (str: string, implicitOR = true): SearchQueryDTO => {
console.log(str); console.log('parsing: ' + str);
str = str.replace(/\s\s+/g, ' ') // remove double spaces str = str.replace(/\s\s+/g, ' ') // remove double spaces
.replace(/:\s+/g, ':').replace(/\)(?=\S)/g, ') ').trim(); .replace(/:\s+/g, ':').replace(/\)(?=\S)/g, ') ').trim();
if (str.charAt(0) === '(' && str.charAt(str.length - 1) === ')') { if (str.charAt(0) === '(' && str.charAt(str.length - 1) === ')') {
str = str.slice(1, str.length - 1); str = str.slice(1, str.length - 1);
} }
const fistNonBRSpace = () => { const fistSpace = (start = 0) => {
const bracketIn = []; const bracketIn = [];
for (let i = 0; i < str.length; ++i) { let quotationMark = false;
for (let i = start; i < str.length; ++i) {
if (str.charAt(i) === '"') {
quotationMark = !quotationMark;
continue;
}
if (str.charAt(i) === '(') { if (str.charAt(i) === '(') {
bracketIn.push(i); bracketIn.push(i);
continue; continue;
@ -140,7 +145,9 @@ export namespace SearchQueryDTO {
continue; continue;
} }
if (bracketIn.length === 0 && str.charAt(i) === ' ') { if (quotationMark === false &&
bracketIn.length === 0 &&
str.charAt(i) === ' ') {
return i; return i;
} }
} }
@ -148,34 +155,41 @@ export namespace SearchQueryDTO {
}; };
// tokenize // tokenize
const tokenEnd = fistNonBRSpace(); const tokenEnd = fistSpace();
if (tokenEnd !== str.length - 1) { if (tokenEnd !== str.length - 1) {
if (str.startsWith(' and', tokenEnd)) { if (str.startsWith(' and', tokenEnd)) {
return <ANDSearchQuery>{ return <ANDSearchQuery>{
type: SearchQueryTypes.AND, type: SearchQueryTypes.AND,
list: [SearchQueryDTO.parse(str.slice(0, tokenEnd)), // trim brackets list: [SearchQueryDTO.parse(str.slice(0, tokenEnd), implicitOR), // trim brackets
SearchQueryDTO.parse(str.slice(tokenEnd + 4))] SearchQueryDTO.parse(str.slice(tokenEnd + 4), implicitOR)]
}; };
} else { } else if (str.startsWith(' or', tokenEnd)) {
let padding = 0;
if (str.startsWith(' or', tokenEnd)) {
padding = 3;
}
return <ORSearchQuery>{ return <ORSearchQuery>{
type: SearchQueryTypes.OR, type: SearchQueryTypes.OR,
list: [SearchQueryDTO.parse(str.slice(0, tokenEnd)), // trim brackets list: [SearchQueryDTO.parse(str.slice(0, tokenEnd), implicitOR), // trim brackets
SearchQueryDTO.parse(str.slice(tokenEnd + padding))] SearchQueryDTO.parse(str.slice(tokenEnd + 3), implicitOR)]
};
} else { // Relation cannot be detected
return <SearchListQuery>{
type: implicitOR === true ? SearchQueryTypes.OR : SearchQueryTypes.UNKNOWN_RELATION,
list: [SearchQueryDTO.parse(str.slice(0, tokenEnd), implicitOR), // trim brackets
SearchQueryDTO.parse(str.slice(tokenEnd), implicitOR)]
}; };
} }
} }
if (str.startsWith('some-of:') || if (str.startsWith('some-of:') ||
new RegExp(/^\d*-of:/).test(str)) { new RegExp(/^\d*-of:/).test(str)) {
const prefix = str.startsWith('some-of:') ? 'some-of:' : new RegExp(/^\d*-of:/).exec(str)[0]; const prefix = str.startsWith('some-of:') ? 'some-of:' : new RegExp(/^\d*-of:/).exec(str)[0];
let tmpList: any = SearchQueryDTO.parse(str.slice(prefix.length + 1, -1)); // trim brackets let tmpList: any = SearchQueryDTO.parse(str.slice(prefix.length + 1, -1), false); // trim brackets
// console.log(JSON.stringify(tmpList, null, 4));
const unfoldList = (q: SearchListQuery): SearchQueryDTO[] => { const unfoldList = (q: SearchListQuery): SearchQueryDTO[] => {
if (q.list) { if (q.list) {
return [].concat.apply([], q.list.map(e => unfoldList(<any>e))); // flatten array if (q.type === SearchQueryTypes.UNKNOWN_RELATION) {
return [].concat.apply([], q.list.map(e => unfoldList(<any>e))); // flatten array
} else {
q.list.forEach(e => unfoldList(<any>e));
}
} }
return [q]; return [q];
}; };

View File

@ -792,7 +792,7 @@ describe('SearchManager', (sqlHelper: SQLTestHelper) => {
it('should search date', async () => { it('should search date', async () => {
const sm = new SearchManager(); const sm = new SearchManager();
let query: any = <FromDateSearch>{value: 0, type: SearchQueryTypes.from_date}; let query: any = <ToDateSearch>{value: 0, type: SearchQueryTypes.to_date};
expect(Utils.clone(await sm.search(query))) expect(Utils.clone(await sm.search(query)))
.to.deep.equalInAnyOrder(removeDir(<SearchResultDTO>{ .to.deep.equalInAnyOrder(removeDir(<SearchResultDTO>{
@ -803,15 +803,15 @@ describe('SearchManager', (sqlHelper: SQLTestHelper) => {
resultOverflow: false resultOverflow: false
})); }));
query = <ToDateSearch>{ query = <FromDateSearch>{
value: p.metadata.creationDate, type: SearchQueryTypes.to_date value: p.metadata.creationDate, type: SearchQueryTypes.from_date
}; };
expect(Utils.clone(await sm.search(query))) expect(Utils.clone(await sm.search(query)))
.to.deep.equalInAnyOrder(removeDir(<SearchResultDTO>{ .to.deep.equalInAnyOrder(removeDir(<SearchResultDTO>{
searchQuery: query, searchQuery: query,
directories: [], directories: [],
media: [p], media: [p, v],
metaFile: [], metaFile: [],
resultOverflow: false resultOverflow: false
})); }));
@ -826,7 +826,7 @@ describe('SearchManager', (sqlHelper: SQLTestHelper) => {
.to.deep.equalInAnyOrder(removeDir(<SearchResultDTO>{ .to.deep.equalInAnyOrder(removeDir(<SearchResultDTO>{
searchQuery: query, searchQuery: query,
directories: [], directories: [],
media: [p2, p_faceLess, p4, v], media: [p2, p_faceLess, p4],
metaFile: [], metaFile: [],
resultOverflow: false resultOverflow: false
})); }));
@ -851,7 +851,7 @@ describe('SearchManager', (sqlHelper: SQLTestHelper) => {
it('should search rating', async () => { it('should search rating', async () => {
const sm = new SearchManager(); const sm = new SearchManager();
let query: MinRatingSearch | MaxRatingSearch = <MinRatingSearch>{value: 0, type: SearchQueryTypes.min_rating}; let query: MinRatingSearch | MaxRatingSearch = <MaxRatingSearch>{value: 0, type: SearchQueryTypes.max_rating};
expect(Utils.clone(await sm.search(query))) expect(Utils.clone(await sm.search(query)))
@ -888,7 +888,7 @@ describe('SearchManager', (sqlHelper: SQLTestHelper) => {
.to.deep.equalInAnyOrder(removeDir(<SearchResultDTO>{ .to.deep.equalInAnyOrder(removeDir(<SearchResultDTO>{
searchQuery: query, searchQuery: query,
directories: [], directories: [],
media: [p2], media: [p2, p_faceLess],
metaFile: [], metaFile: [],
resultOverflow: false resultOverflow: false
})); }));
@ -898,7 +898,7 @@ describe('SearchManager', (sqlHelper: SQLTestHelper) => {
.to.deep.equalInAnyOrder(removeDir(<SearchResultDTO>{ .to.deep.equalInAnyOrder(removeDir(<SearchResultDTO>{
searchQuery: query, searchQuery: query,
directories: [], directories: [],
media: [p, p_faceLess], media: [p],
metaFile: [], metaFile: [],
resultOverflow: false resultOverflow: false
})); }));
@ -909,7 +909,7 @@ describe('SearchManager', (sqlHelper: SQLTestHelper) => {
const sm = new SearchManager(); const sm = new SearchManager();
let query: MinResolutionSearch | MaxResolutionSearch = let query: MinResolutionSearch | MaxResolutionSearch =
<MinResolutionSearch>{value: 0, type: SearchQueryTypes.min_resolution}; <MaxResolutionSearch>{value: 0, type: SearchQueryTypes.max_resolution};
expect(Utils.clone(await sm.search(query))) expect(Utils.clone(await sm.search(query)))
.to.deep.equalInAnyOrder(removeDir(<SearchResultDTO>{ .to.deep.equalInAnyOrder(removeDir(<SearchResultDTO>{
@ -930,27 +930,28 @@ describe('SearchManager', (sqlHelper: SQLTestHelper) => {
resultOverflow: false resultOverflow: false
})); }));
query = <MinResolutionSearch>{value: 2, type: SearchQueryTypes.min_resolution}; query = <MinResolutionSearch>{value: 3, type: SearchQueryTypes.min_resolution};
expect(Utils.clone(await sm.search(query))) expect(Utils.clone(await sm.search(query)))
.to.deep.equalInAnyOrder(removeDir(<SearchResultDTO>{ .to.deep.equalInAnyOrder(removeDir(<SearchResultDTO>{
searchQuery: query, searchQuery: query,
directories: [], directories: [],
media: [p2, p_faceLess], media: [p4],
metaFile: [],
resultOverflow: false
}));
query = <MinResolutionSearch>{value: 3, negate: true, type: SearchQueryTypes.min_resolution};
expect(Utils.clone(await sm.search(query)))
.to.deep.equalInAnyOrder(removeDir(<SearchResultDTO>{
searchQuery: query,
directories: [],
media: [p, p2, p_faceLess, v],
metaFile: [], metaFile: [],
resultOverflow: false resultOverflow: false
})); }));
query = <MaxResolutionSearch>{value: 3, negate: true, type: SearchQueryTypes.max_resolution}; query = <MaxResolutionSearch>{value: 3, negate: true, type: SearchQueryTypes.max_resolution};
expect(Utils.clone(await sm.search(query)))
.to.deep.equalInAnyOrder(removeDir(<SearchResultDTO>{
searchQuery: query,
directories: [],
media: [p, v, p4],
metaFile: [],
resultOverflow: false
}));
query = <MinResolutionSearch>{value: 3, negate: true, type: SearchQueryTypes.min_resolution};
expect(Utils.clone(await sm.search(query))) expect(Utils.clone(await sm.search(query)))
.to.deep.equalInAnyOrder(removeDir(<SearchResultDTO>{ .to.deep.equalInAnyOrder(removeDir(<SearchResultDTO>{
searchQuery: query, searchQuery: query,

View File

@ -13,6 +13,7 @@ import {
SearchQueryTypes, SearchQueryTypes,
SomeOfSearchQuery, SomeOfSearchQuery,
TextSearch, TextSearch,
TextSearchQueryMatchTypes,
ToDateSearch ToDateSearch
} from '../../../src/common/entities/SearchQueryDTO'; } from '../../../src/common/entities/SearchQueryDTO';
@ -33,6 +34,11 @@ describe('SearchQueryDTO', () => {
check(<TextSearch>{type: SearchQueryTypes.caption, text: 'caption'}); check(<TextSearch>{type: SearchQueryTypes.caption, text: 'caption'});
check(<TextSearch>{type: SearchQueryTypes.file_name, text: 'filename'}); check(<TextSearch>{type: SearchQueryTypes.file_name, text: 'filename'});
check(<TextSearch>{type: SearchQueryTypes.position, text: 'New York'}); check(<TextSearch>{type: SearchQueryTypes.position, text: 'New York'});
check(<TextSearch>{
type: SearchQueryTypes.position,
matchType: TextSearchQueryMatchTypes.exact_match,
text: 'New York'
});
}); });
it('Date search', () => { it('Date search', () => {
@ -62,6 +68,18 @@ describe('SearchQueryDTO', () => {
<TextSearch>{type: SearchQueryTypes.position, text: 'New York'} <TextSearch>{type: SearchQueryTypes.position, text: 'New York'}
] ]
}); });
check(<ANDSearchQuery>{
type: SearchQueryTypes.AND,
list: [
<TextSearch>{type: SearchQueryTypes.keyword, text: 'big boom'},
<TextSearch>{
type: SearchQueryTypes.position,
matchType: TextSearchQueryMatchTypes.exact_match,
text: 'New York'
}
]
});
check(<ANDSearchQuery>{ check(<ANDSearchQuery>{
type: SearchQueryTypes.AND, type: SearchQueryTypes.AND,
list: [ list: [
@ -75,6 +93,21 @@ describe('SearchQueryDTO', () => {
} }
] ]
}); });
check(<ANDSearchQuery>{
type: SearchQueryTypes.AND,
list: [
<SomeOfSearchQuery>{
type: SearchQueryTypes.SOME_OF,
min: 2,
list: [
<TextSearch>{type: SearchQueryTypes.keyword, text: 'big boom'},
<TextSearch>{type: SearchQueryTypes.position, text: 'New York'},
<TextSearch>{type: SearchQueryTypes.caption, text: 'caption test'}
]
},
<TextSearch>{type: SearchQueryTypes.position, text: 'New York'}
]
});
}); });
it('Or search', () => { it('Or search', () => {
check(<ORSearchQuery>{ check(<ORSearchQuery>{
@ -106,6 +139,21 @@ describe('SearchQueryDTO', () => {
<TextSearch>{type: SearchQueryTypes.position, text: 'New York'} <TextSearch>{type: SearchQueryTypes.position, text: 'New York'}
] ]
}); });
check(<SomeOfSearchQuery>{
type: SearchQueryTypes.SOME_OF,
list: [
<TextSearch>{
type: SearchQueryTypes.keyword,
matchType: TextSearchQueryMatchTypes.exact_match,
text: 'big boom'
},
<TextSearch>{
type: SearchQueryTypes.position,
matchType: TextSearchQueryMatchTypes.exact_match,
text: 'New York'
},
]
});
check(<SomeOfSearchQuery>{ check(<SomeOfSearchQuery>{
type: SearchQueryTypes.SOME_OF, type: SearchQueryTypes.SOME_OF,
min: 2, min: 2,