[ACA-2219] support more precise searching (#976)

* support more precise searching

* exact term matching

* remove fdescribe

* update docs
This commit is contained in:
Denys Vuika
2019-02-27 04:25:50 +00:00
committed by Cilibiu Bogdan
parent f25eef599d
commit f58b6e5a9f
4 changed files with 151 additions and 10 deletions

View File

@@ -35,11 +35,16 @@ describe('SearchComponent', () => {
expect(component.formatSearchQuery('')).toBeNull();
});
it('should use original user input if content contains colons', () => {
it('should use original user input if text contains colons', () => {
const query = 'TEXT:test OR TYPE:folder';
expect(component.formatSearchQuery(query)).toBe(query);
});
it('should use original user input if text contains quotes', () => {
const query = `"Hello World"`;
expect(component.formatSearchQuery(query)).toBe(query);
});
it('should format user input according to the configuration fields', () => {
config.config = {
search: {
@@ -48,7 +53,7 @@ describe('SearchComponent', () => {
};
const query = component.formatSearchQuery('hello');
expect(query).toBe(`cm:name:"hello*" OR cm:title:"hello*"`);
expect(query).toBe(`(cm:name:"hello*" OR cm:title:"hello*")`);
});
it('should format user input as cm:name if configuration not provided', () => {
@@ -59,7 +64,75 @@ describe('SearchComponent', () => {
};
const query = component.formatSearchQuery('hello');
expect(query).toBe(`cm:name:"hello*"`);
expect(query).toBe(`(cm:name:"hello*")`);
});
it('should use AND operator when conjunction has no operators', () => {
config.config = {
search: {
'aca:fields': ['cm:name']
}
};
const query = component.formatSearchQuery('big yellow banana');
expect(query).toBe(
`(cm:name:"big*") AND (cm:name:"yellow*") AND (cm:name:"banana*")`
);
});
it('should support conjunctions with AND operator', () => {
config.config = {
search: {
'aca:fields': ['cm:name', 'cm:title']
}
};
const query = component.formatSearchQuery('big AND yellow AND banana');
expect(query).toBe(
`(cm:name:"big*" OR cm:title:"big*") AND (cm:name:"yellow*" OR cm:title:"yellow*") AND (cm:name:"banana*" OR cm:title:"banana*")`
);
});
it('should support conjunctions with OR operator', () => {
config.config = {
search: {
'aca:fields': ['cm:name', 'cm:title']
}
};
const query = component.formatSearchQuery('big OR yellow OR banana');
expect(query).toBe(
`(cm:name:"big*" OR cm:title:"big*") OR (cm:name:"yellow*" OR cm:title:"yellow*") OR (cm:name:"banana*" OR cm:title:"banana*")`
);
});
it('should support exact term matching with default fields', () => {
config.config = {
search: {
'aca:fields': ['cm:name', 'cm:title']
}
};
const query = component.formatSearchQuery('=orange');
expect(query).toBe(`(=cm:name:"orange" OR =cm:title:"orange")`);
});
it('should support exact term matching with operators', () => {
config.config = {
search: {
'aca:fields': ['cm:name', 'cm:title']
}
};
const query = component.formatSearchQuery('=test1.pdf or =test2.pdf');
expect(query).toBe(
`(=cm:name:"test1.pdf" OR =cm:title:"test1.pdf") or (=cm:name:"test2.pdf" OR =cm:title:"test2.pdf")`
);
});
it('should navigate to folder on double click', () => {

View File

@@ -114,6 +114,33 @@ export class SearchResultsComponent extends PageComponent implements OnInit {
}
}
private isOperator(input: string): boolean {
if (input) {
input = input.trim().toUpperCase();
const operators = ['AND', 'OR'];
return operators.includes(input);
}
return false;
}
private formatFields(fields: string[], term: string): string {
let prefix = '';
let suffix = '*';
if (term.startsWith('=')) {
prefix = '=';
suffix = '';
term = term.substring(1);
}
return (
'(' +
fields.map(field => `${prefix}${field}:"${term}${suffix}"`).join(' OR ') +
')'
);
}
formatSearchQuery(userInput: string) {
if (!userInput) {
return null;
@@ -121,14 +148,28 @@ export class SearchResultsComponent extends PageComponent implements OnInit {
userInput = userInput.trim();
if (userInput.includes(':')) {
if (userInput.includes(':') || userInput.includes('"')) {
return userInput;
}
const fields = this.config.get<string[]>('search.aca:fields', ['cm:name']);
const query = fields.map(field => `${field}:"${userInput}*"`).join(' OR ');
const words = userInput.split(' ');
return query;
if (words.length > 1) {
const separator = words.some(this.isOperator) ? ' ' : ' AND ';
return words
.map(term => {
if (this.isOperator(term)) {
return term;
}
return this.formatFields(fields, term);
})
.join(separator);
}
return this.formatFields(fields, userInput);
}
onSearchResultLoaded(nodePaging: NodePaging) {