Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
146 changes: 146 additions & 0 deletions src/search/AdvancedSearchManager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
// set up environment
import * as dotenv from 'dotenv';
dotenv.config();

import { CveResult } from '../result/CveResult.js';
import { SearchResultData } from "./SearchResultData.js";
import { BasicSearchManager, SearchOptions } from "./BasicSearchManager.js"

export class SearchAPIOptions extends SearchOptions {
searchFields: Array<string>;
filters: Array<object>;
resultsPerPage: number;
pageNumber: number;
rangeObjects: Array<rangeObject>
rangeStart: Date;
rangeEnd: Date;
rangeField: string;
}

//support for date ranges
export class rangeObject {
rangeField: string;
rangeStart: Date;
rangeEnd: Date;
}

export class AdvancedSearchManager extends BasicSearchManager {
/** search for text at search provider
* @param searchText the text string to search for
* @param options options to specify how to search, with well-defined defaults
* @param queryString query strings for each filter on the search request
*/
async apiSearch(searchText: string, options: Partial<SearchAPIOptions> = undefined, queryStrings?: Array<object>): Promise<CveResult> {
let response = undefined;

if (!options) {
options = {
useCache: true,
searchFields: null,
filters: null,
resultsPerPage: 20,
pageNumber: 0,
rangeObjects: null,
rangeStart: null,
rangeEnd: null,
rangeField: null,
track_total_hits: true,
default_operator: "AND",
metadataOnly: false,
fields: []
};
}

const validateResult = this.validateSearchText(searchText, options.filters)

//Build range object to add to the query
// let rangeObj = null;
const rangeArray = [...(options.rangeObjects ?? [])];

// if (options.rangeObjects) {
// options.rangeObjects.forEach(rangeObject => {
// rangeObj = {
// range: {
// [rangeObject.rangeField]: {
// "gte": rangeObject.rangeStart,
// "lte": rangeObject.rangeEnd,
// }
// }
// };
// rangeArray.push(rangeObj);
// })

// }
//Build query object
const queryObj = {
must: [],
filter: [
...options.filters
],
};

//Add rangeObj only if it exists
if (rangeArray) {
queryObj.filter.push(...rangeArray);
}

if (searchText != null) {
queryObj.must = [
{
query_string: {
query: searchText,
fields: ["containers.cna.descriptions.value"]
},
}
];
}

//Add query_string only if there is text to search
else if (queryStrings != null) {
queryObj.must = [
...queryStrings
];
} else {
delete queryObj.must
}

if (validateResult.isOk()) {

response = await this._searchReader._client.search({
index: this._searchReader._cveIndex,
body: {
query: {
bool: queryObj

},
track_total_hits: true,
size: options.resultsPerPage,
from: options.pageNumber
}
});

return CveResult.ok(response.body as SearchResultData);
}
else {
// return CveResult.error(new CveError(1, `Unknown error when searching for ${text}`));
return validateResult
}
}

/** validates search text string and marks up CveResult
* with errors and/or notes, if any
*/
// @todo
validateSearchText(text: string, filters: Array<object>): CveResult {

let result: CveResult
if (!text && !filters) {
result = CveResult.error(9002)
}
else {
result = CveResult.ok("", ["no validation was done"])
}

return result
}
}
138 changes: 1 addition & 137 deletions src/search/BasicSearchManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,10 @@
import * as dotenv from 'dotenv';
dotenv.config();

import { CveErrorCodes, CveResult } from '../result/CveResult.js';
import { CveResult } from '../result/CveResult.js';
import { SearchProviderSpec } from '../adapters/search/SearchAdapter.js';
import { SearchQueryBuilder } from './SearchQueryBuilder.js';
import { SearchReader } from '../adapters/search/SearchReader.js';
import { SearchResultData } from "./SearchResultData.js";


/** options when using search()
Expand All @@ -21,26 +20,8 @@ export class SearchOptions {
sort: {}[];
from: number;
size: number;

}

export class SearchAPIOptions extends SearchOptions {
searchFields: Array<string>;
filters: Array<object>;
resultsPerPage: number;
rangeObjects: Array<rangeObject>
rangeStart: Date;
rangeEnd: Date;
rangeField: string;
}

//support for date ranges
export class rangeObject {
rangeField: string;
rangeStart: Date;
rangeEnd: Date;

}

/** A manager class that provides basic search capabilities
* including a flexible search() that provides consistent
Expand Down Expand Up @@ -86,121 +67,4 @@ export class BasicSearchManager {
return result
}

/** search for text at search provider
* @param searchText the text string to search for
* @param options options to specify how to search, with well-defined defaults
*/
async apiSearch(searchText: string, options: Partial<SearchAPIOptions> = undefined, queryStrings?: Array<object>): Promise<CveResult> {
let response = undefined;

if (!options) {
options = {
useCache: true,
searchFields: null,
filters: null,
resultsPerPage: 20,
rangeObjects: null,
rangeStart: null,
rangeEnd: null,
rangeField: null,
track_total_hits: true,
default_operator: "AND",
metadataOnly: false,
fields: []
};
}

let validateResult = this.validateSearchText(searchText, options.filters)

//Build range object to add to the query
let rangeObj = null;
let rangeArray = [];

if (options.rangeObjects) {
options.rangeObjects.forEach(rangeObject => {
rangeObj = {
range: {
[rangeObject.rangeField]: {
"gte": rangeObject.rangeStart,
"lte": rangeObject.rangeEnd,
}
}
};
rangeArray.push(rangeObj);
})

}
//Build query object
const queryObj = {
must: [],
filter: [
...options.filters
],
};

//Add rangeObj only if it exists
if (rangeArray) {
queryObj.filter.push(...rangeArray);
}

if (searchText != null) {
queryObj.must = [
{
query_string: {
query: searchText,
fields: ["containers.cna.descriptions.value"]
},
}
];
}

//Add query_string only if there is text to search
else if (queryStrings != null) {
queryObj.must = [
...queryStrings
];
} else {
delete queryObj.must
}

if (validateResult.isOk()) {

response = await this._searchReader._client.search({
index: this._searchReader._cveIndex,
body: {
query: {
bool: queryObj

},
track_total_hits: true,
size: options.resultsPerPage
}
});

return CveResult.ok(response.body as SearchResultData);
}
else {
// return CveResult.error(new CveError(1, `Unknown error when searching for ${text}`));
return validateResult
}
}

/** validates search text string and marks up CveResult
* with errors and/or notes, if any
*/
// @todo
validateSearchText(text: string, filters: Array<object>): CveResult {

let result: CveResult
if (!text && !filters) {
result = CveResult.error(9002)
}
else {
result = CveResult.ok("", ["no validation was done"])
}

return result
}


}
Loading