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:
parent
47703b6b84
commit
41292ec4b4
@ -274,9 +274,7 @@ export class SearchManager implements ISearchManager {
|
||||
if (typeof (<FromDateSearch>query).value === 'undefined') {
|
||||
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 relationRev = (<TextSearch>query).negate ? '>' : '<=';
|
||||
|
||||
const textParam: any = {};
|
||||
textParam['from' + paramCounter.value] = (<FromDateSearch>query).value;
|
||||
|
@ -2,7 +2,7 @@ import {GPSMetadata} from './PhotoDTO';
|
||||
import {Utils} from '../Utils';
|
||||
|
||||
export enum SearchQueryTypes {
|
||||
AND = 1, OR, SOME_OF,
|
||||
AND = 1, OR, SOME_OF, UNKNOWN_RELATION = 99999,
|
||||
|
||||
// non-text metadata
|
||||
// |- range types
|
||||
@ -120,17 +120,22 @@ export namespace SearchQueryDTO {
|
||||
}
|
||||
};
|
||||
|
||||
export const parse = (str: string): SearchQueryDTO => {
|
||||
console.log(str);
|
||||
export const parse = (str: string, implicitOR = true): SearchQueryDTO => {
|
||||
console.log('parsing: ' + str);
|
||||
str = str.replace(/\s\s+/g, ' ') // remove double spaces
|
||||
.replace(/:\s+/g, ':').replace(/\)(?=\S)/g, ') ').trim();
|
||||
|
||||
if (str.charAt(0) === '(' && str.charAt(str.length - 1) === ')') {
|
||||
str = str.slice(1, str.length - 1);
|
||||
}
|
||||
const fistNonBRSpace = () => {
|
||||
const fistSpace = (start = 0) => {
|
||||
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) === '(') {
|
||||
bracketIn.push(i);
|
||||
continue;
|
||||
@ -140,7 +145,9 @@ export namespace SearchQueryDTO {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (bracketIn.length === 0 && str.charAt(i) === ' ') {
|
||||
if (quotationMark === false &&
|
||||
bracketIn.length === 0 &&
|
||||
str.charAt(i) === ' ') {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
@ -148,34 +155,41 @@ export namespace SearchQueryDTO {
|
||||
};
|
||||
|
||||
// tokenize
|
||||
const tokenEnd = fistNonBRSpace();
|
||||
const tokenEnd = fistSpace();
|
||||
|
||||
if (tokenEnd !== str.length - 1) {
|
||||
if (str.startsWith(' and', tokenEnd)) {
|
||||
return <ANDSearchQuery>{
|
||||
type: SearchQueryTypes.AND,
|
||||
list: [SearchQueryDTO.parse(str.slice(0, tokenEnd)), // trim brackets
|
||||
SearchQueryDTO.parse(str.slice(tokenEnd + 4))]
|
||||
list: [SearchQueryDTO.parse(str.slice(0, tokenEnd), implicitOR), // trim brackets
|
||||
SearchQueryDTO.parse(str.slice(tokenEnd + 4), implicitOR)]
|
||||
};
|
||||
} else {
|
||||
let padding = 0;
|
||||
if (str.startsWith(' or', tokenEnd)) {
|
||||
padding = 3;
|
||||
}
|
||||
} else if (str.startsWith(' or', tokenEnd)) {
|
||||
return <ORSearchQuery>{
|
||||
type: SearchQueryTypes.OR,
|
||||
list: [SearchQueryDTO.parse(str.slice(0, tokenEnd)), // trim brackets
|
||||
SearchQueryDTO.parse(str.slice(tokenEnd + padding))]
|
||||
list: [SearchQueryDTO.parse(str.slice(0, tokenEnd), implicitOR), // trim brackets
|
||||
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:') ||
|
||||
new RegExp(/^\d*-of:/).test(str)) {
|
||||
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[] => {
|
||||
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];
|
||||
};
|
||||
|
@ -792,7 +792,7 @@ describe('SearchManager', (sqlHelper: SQLTestHelper) => {
|
||||
it('should search date', async () => {
|
||||
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)))
|
||||
.to.deep.equalInAnyOrder(removeDir(<SearchResultDTO>{
|
||||
@ -803,15 +803,15 @@ describe('SearchManager', (sqlHelper: SQLTestHelper) => {
|
||||
resultOverflow: false
|
||||
}));
|
||||
|
||||
query = <ToDateSearch>{
|
||||
value: p.metadata.creationDate, type: SearchQueryTypes.to_date
|
||||
query = <FromDateSearch>{
|
||||
value: p.metadata.creationDate, type: SearchQueryTypes.from_date
|
||||
};
|
||||
|
||||
expect(Utils.clone(await sm.search(query)))
|
||||
.to.deep.equalInAnyOrder(removeDir(<SearchResultDTO>{
|
||||
searchQuery: query,
|
||||
directories: [],
|
||||
media: [p],
|
||||
media: [p, v],
|
||||
metaFile: [],
|
||||
resultOverflow: false
|
||||
}));
|
||||
@ -826,7 +826,7 @@ describe('SearchManager', (sqlHelper: SQLTestHelper) => {
|
||||
.to.deep.equalInAnyOrder(removeDir(<SearchResultDTO>{
|
||||
searchQuery: query,
|
||||
directories: [],
|
||||
media: [p2, p_faceLess, p4, v],
|
||||
media: [p2, p_faceLess, p4],
|
||||
metaFile: [],
|
||||
resultOverflow: false
|
||||
}));
|
||||
@ -851,7 +851,7 @@ describe('SearchManager', (sqlHelper: SQLTestHelper) => {
|
||||
it('should search rating', async () => {
|
||||
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)))
|
||||
@ -888,7 +888,7 @@ describe('SearchManager', (sqlHelper: SQLTestHelper) => {
|
||||
.to.deep.equalInAnyOrder(removeDir(<SearchResultDTO>{
|
||||
searchQuery: query,
|
||||
directories: [],
|
||||
media: [p2],
|
||||
media: [p2, p_faceLess],
|
||||
metaFile: [],
|
||||
resultOverflow: false
|
||||
}));
|
||||
@ -898,7 +898,7 @@ describe('SearchManager', (sqlHelper: SQLTestHelper) => {
|
||||
.to.deep.equalInAnyOrder(removeDir(<SearchResultDTO>{
|
||||
searchQuery: query,
|
||||
directories: [],
|
||||
media: [p, p_faceLess],
|
||||
media: [p],
|
||||
metaFile: [],
|
||||
resultOverflow: false
|
||||
}));
|
||||
@ -909,7 +909,7 @@ describe('SearchManager', (sqlHelper: SQLTestHelper) => {
|
||||
const sm = new SearchManager();
|
||||
|
||||
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)))
|
||||
.to.deep.equalInAnyOrder(removeDir(<SearchResultDTO>{
|
||||
@ -930,27 +930,28 @@ describe('SearchManager', (sqlHelper: SQLTestHelper) => {
|
||||
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)))
|
||||
.to.deep.equalInAnyOrder(removeDir(<SearchResultDTO>{
|
||||
searchQuery: query,
|
||||
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: [],
|
||||
resultOverflow: false
|
||||
}));
|
||||
|
||||
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)))
|
||||
.to.deep.equalInAnyOrder(removeDir(<SearchResultDTO>{
|
||||
searchQuery: query,
|
||||
|
@ -13,6 +13,7 @@ import {
|
||||
SearchQueryTypes,
|
||||
SomeOfSearchQuery,
|
||||
TextSearch,
|
||||
TextSearchQueryMatchTypes,
|
||||
ToDateSearch
|
||||
} from '../../../src/common/entities/SearchQueryDTO';
|
||||
|
||||
@ -33,6 +34,11 @@ describe('SearchQueryDTO', () => {
|
||||
check(<TextSearch>{type: SearchQueryTypes.caption, text: 'caption'});
|
||||
check(<TextSearch>{type: SearchQueryTypes.file_name, text: 'filename'});
|
||||
check(<TextSearch>{type: SearchQueryTypes.position, text: 'New York'});
|
||||
check(<TextSearch>{
|
||||
type: SearchQueryTypes.position,
|
||||
matchType: TextSearchQueryMatchTypes.exact_match,
|
||||
text: 'New York'
|
||||
});
|
||||
});
|
||||
|
||||
it('Date search', () => {
|
||||
@ -62,6 +68,18 @@ describe('SearchQueryDTO', () => {
|
||||
<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>{
|
||||
type: SearchQueryTypes.AND,
|
||||
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', () => {
|
||||
check(<ORSearchQuery>{
|
||||
@ -106,6 +139,21 @@ describe('SearchQueryDTO', () => {
|
||||
<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>{
|
||||
type: SearchQueryTypes.SOME_OF,
|
||||
min: 2,
|
||||
|
Loading…
Reference in New Issue
Block a user