flexmonster-mongo-connector
Version:
Custom data source API implementation for MongoDB
307 lines (264 loc) • 16.8 kB
text/typescript
import {ClientSideFieldType} from '../../utils/consts/ClientSideFieldType';
import {ClientSideFilterQueries} from '../../utils/consts/ClientSideFilterQueries';
import {MongoFilterQueries} from '../../utils/consts/MongoFilterQueries';
import {IRequestField} from '../../requests/apiRequests/IRequestArgument';
import { APISchema } from '../../schema/APISchema';
import { DateIntervals } from '../../utils/consts/DateParts';
export class FilterQueryBuilder {
constructor() {}
public buildFilterQuery(query: any, schema: APISchema) {
//console.log(">>>>>>", JSON.stringify(query, null, " "));
let filterQuery = {};
if (Array.isArray(query)) {
this._buildClassicFilter(query, schema, filterQuery);
} else {
filterQuery = this._buildAdvancedFilter(query, schema);
}
//console.log(">>>>>>Mongo", JSON.stringify(filterQuery, null, " "));
return filterQuery;
}
private _buildClassicFilter(queryList: any, schema: APISchema, filterQuery: any) {
for (let i = 0; i < queryList.length; i++) {
const field: IRequestField = queryList[i]["field"];
filterQuery[field.uniqueName] = this._filterField(queryList[i], schema)[field.uniqueName];
}
return;
}
private _buildAdvancedFilter(query: any, schema: APISchema) {
const operationsList: any[] = [];
const mongoFilterObject: object = {
[this._getMongoLogicOperator(query["type"])]: operationsList
};
this._buildAvancedFilterRecursively(query["value"], schema, operationsList);
return mongoFilterObject;
}
private _buildAvancedFilterRecursively(query: any[], schema: APISchema, operationsList: any[]) {
for (let i = 0; i < query.length; i++) {
operationsList.push(this._buildAdvancedFilterItem(query[i], schema));
}
return;
}
private _buildAdvancedFilterItem(query: any, schema: APISchema): any {
//console.log(">>>>>filter", JSON.stringify(query));
if (typeof query["type"] !== "undefined") {
const operationsList: any[] = [];
const mongoFilterObject: object = {
[this._getMongoLogicOperator(query["type"])]: operationsList
};
this._buildAvancedFilterRecursively(query["value"], schema, operationsList);
return mongoFilterObject;
} else {
let mongoFilterQuery = this._filterField(query, schema);
//console.log(">>>>>AdvancedFilterItem", JSON.stringify(query));
if (mongoFilterQuery[0] !== undefined && Array.isArray(mongoFilterQuery[0])) {
const lastQuery: any = mongoFilterQuery.length > 1 && !Array.isArray(mongoFilterQuery[mongoFilterQuery.length - 1]) ? mongoFilterQuery.pop() : undefined;
const listOfOrConditions: any[] = lastQuery === undefined ? [] : [lastQuery];
const clientMemberFilterQuery: string = query[ClientSideFilterQueries.INCLUDE] !== undefined ? ClientSideFilterQueries.INCLUDE : ClientSideFilterQueries.EXCLUDE;
const negation: boolean = clientMemberFilterQuery === ClientSideFilterQueries.EXCLUDE;
const resultORQuery = {
[this._getMongoLogicOperator(ClientSideFilterQueries.OR, negation)]: listOfOrConditions
}
for (let i: number = 0; i < mongoFilterQuery.length; i++) {
listOfOrConditions.push({
[this._getMongoLogicOperator(ClientSideFilterQueries.AND, negation)]: mongoFilterQuery[i]
})
}
mongoFilterQuery = resultORQuery;
} else if (query["query"] !== undefined) {
const resultQuery = {
[query["field"]["uniqueName"]]: mongoFilterQuery
}
mongoFilterQuery = resultQuery;
}
return mongoFilterQuery;
}
}
private _getMongoLogicOperator(clientLogicOperator: string, negation: boolean = false): string {
let mongoLogicOperator: string = "";
if (ClientSideFilterQueries.AND === clientLogicOperator) {
mongoLogicOperator = !negation ? MongoFilterQueries.AND : MongoFilterQueries.OR;
} else if (ClientSideFilterQueries.OR === clientLogicOperator) {
mongoLogicOperator = !negation ? MongoFilterQueries.OR : MongoFilterQueries.AND;
}
if (mongoLogicOperator.length === 0) {
throw new Error("Invalid client filter format");
}
return mongoLogicOperator;
}
private _filterField(query: any, schema: APISchema /*, filterQuery: any*/): any {
let field: IRequestField = query["field"];
if ((schema.fields.get(field.uniqueName).type == ClientSideFieldType.STRING
|| schema.fields.get(field.uniqueName).type == ClientSideFieldType.NUMBER)
&& query.value == null) {
return this._filterLabelField(query, schema, field /*, filterQuery*/);
} else if (schema.fields.get(field.uniqueName).type == ClientSideFieldType.DATE
&& query.value == null) {
return this._filterDateField(query, schema, field /*, filterQuery*/);
} else if (query.value != null) {}
return;
}
private _filterLabelField(query: any, schema: APISchema, fieldName: IRequestField /*, filterQueryResult: any*/): any {
const fieldFilterObject: any = {};
const FLAGS = "gi";
if (query["query"]) {
query = query["query"];
if (query[ClientSideFilterQueries.BEGIN]) {
fieldFilterObject[MongoFilterQueries.REGEXP] = new RegExp("^" + query[ClientSideFilterQueries.BEGIN], FLAGS);
} else if (query[ClientSideFilterQueries.NOT_BEGIN]) {
fieldFilterObject[MongoFilterQueries.REGEXP] = new RegExp("^(?!" + query[ClientSideFilterQueries.NOT_BEGIN] + ").*", FLAGS);
} else if (query[ClientSideFilterQueries.CONTAIN]) {
fieldFilterObject[MongoFilterQueries.REGEXP] = new RegExp(query[ClientSideFilterQueries.CONTAIN], FLAGS);
} else if (query[ClientSideFilterQueries.NOT_CONTAIN]) {
fieldFilterObject[MongoFilterQueries.REGEXP] = new RegExp("^((?!" + query[ClientSideFilterQueries.NOT_CONTAIN] + ").)*$", FLAGS);
} else if (query[ClientSideFilterQueries.END]) {
fieldFilterObject[MongoFilterQueries.REGEXP] = new RegExp(query[ClientSideFilterQueries.END] + "$", FLAGS);
} else if (query[ClientSideFilterQueries.NOT_END]) {
fieldFilterObject[MongoFilterQueries.REGEXP] = new RegExp("^(?!.*" + query[ClientSideFilterQueries.NOT_END] + "$).*$", FLAGS);
} else if (query[ClientSideFilterQueries.EQUAL]) {
fieldFilterObject[MongoFilterQueries.EQUAL] = query[ClientSideFilterQueries.EQUAL];
} else if (query[ClientSideFilterQueries.NOT_EQUAL]) {
fieldFilterObject[MongoFilterQueries.NOT] = {
[MongoFilterQueries.EQUAL]: query[ClientSideFilterQueries.NOT_EQUAL]
};
} else if (query[ClientSideFilterQueries.GREATER]) {
fieldFilterObject[MongoFilterQueries.GREATER] = query[ClientSideFilterQueries.GREATER];
} else if (query[ClientSideFilterQueries.GREATER_EQUAL]) {
fieldFilterObject[MongoFilterQueries.GREATER_EQUAL] = query[ClientSideFilterQueries.GREATER_EQUAL];
} else if (query[ClientSideFilterQueries.LESS]) {
fieldFilterObject[MongoFilterQueries.LESS] = query[ClientSideFilterQueries.LESS];
} else if (query[ClientSideFilterQueries.LESS_EQUAL]) {
fieldFilterObject[MongoFilterQueries.LESS_EQUAL] = query[ClientSideFilterQueries.LESS_EQUAL];
} else if (query[ClientSideFilterQueries.BETWEEN]) {
fieldFilterObject[MongoFilterQueries.GREATER_EQUAL] = query[ClientSideFilterQueries.BETWEEN][0];
fieldFilterObject[MongoFilterQueries.LESS_EQUAL] = query[ClientSideFilterQueries.BETWEEN][1];
} else if (query[ClientSideFilterQueries.NOT_BETWEEN]) {
fieldFilterObject[MongoFilterQueries.NOT] = {
[MongoFilterQueries.GREATER_EQUAL]: query[ClientSideFilterQueries.NOT_BETWEEN][0],
[MongoFilterQueries.LESS_EQUAL]: query[ClientSideFilterQueries.NOT_BETWEEN][1]
};
}
} else {
if (query[ClientSideFilterQueries.INCLUDE]) {
return this.parseIncludeExcludeMembers(query[ClientSideFilterQueries.INCLUDE], ClientSideFilterQueries.INCLUDE, fieldName, schema, false);
} else if (query[ClientSideFilterQueries.EXCLUDE]) {
return this.parseIncludeExcludeMembers(query[ClientSideFilterQueries.EXCLUDE], ClientSideFilterQueries.EXCLUDE, fieldName, schema, false);
}
}
//filterQueryResult[fieldName.uniqueName] =
return fieldFilterObject;
}
private parseIncludeExcludeMembers(members: IFilterMemberObject[], membersFilterQuery: string, fieldName: IRequestField, schema: APISchema, isDate: boolean): any {
if (members == null) return [];
const result: any = [];
const membersList: (string | number | Date)[] = [];
let member: string | number | Date = null;
for (let i = 0; i < members.length; i++) {
member = isDate ? new Date((<number>members[i].member)) : members[i].member;
if (members[i].filter === undefined) {
membersList.push(member);
} else {
const mongofilterQueryChunk = {
[fieldName.uniqueName]: {
[this.getMongoGroupMemberFilter(membersFilterQuery)]: [member]
}
}
result.push(this.resolveRecursiveFilter(schema, mongofilterQueryChunk, members[i].filter, membersFilterQuery === ClientSideFilterQueries.EXCLUDE));
}
}
const queryFromMembersList = {
[fieldName.uniqueName]: {
[this.getMongoGroupMemberFilter(membersFilterQuery)]: membersList
}
}
if (result.length === 0) {
return queryFromMembersList;
} else {
if (membersList.length > 0) result.push(queryFromMembersList);
return result;
}
}
private getMongoGroupMemberFilter(membersFilterQuery: string, negation: boolean = false): string {
if (ClientSideFilterQueries.INCLUDE === membersFilterQuery) {
return !negation ? MongoFilterQueries.INCLUDE : MongoFilterQueries.EXCLUDE;
} else {
return !negation ? MongoFilterQueries.EXCLUDE : MongoFilterQueries.INCLUDE;
}
}
private resolveRecursiveFilter(schema: APISchema, mongofilterQueryChunk: any, filterQuery: IRecursiveFilterMemberObject, negation: boolean): any[] {
//console.log(">>>>ResolveRecursive", JSON.stringify(filterQuery));
const listOfMongoFilterChunks: any[] = [mongofilterQueryChunk];
let reference = filterQuery;
while (reference !== undefined) {
const mongoFilterChunk = {};
reference = this.reduceFilterItemRecurcion(reference, schema, mongoFilterChunk, negation);
listOfMongoFilterChunks.push(mongoFilterChunk);
}
//console.log(">>>>ResolveRecursive_END", JSON.stringify(listOfMongoFilterChunks));
return listOfMongoFilterChunks;
}
private reduceFilterItemRecurcion(filterQuery: IRecursiveFilterMemberObject, schema: APISchema, mongoFilterChunk: any, negation: boolean): IRecursiveFilterMemberObject {
let clientMemberQuery: string = filterQuery.include !== undefined ? ClientSideFilterQueries.INCLUDE : ClientSideFilterQueries.EXCLUDE;
const members: IFilterMemberObject[] = filterQuery.include !== undefined ? filterQuery.include : filterQuery.exclude;
const isDate: boolean = schema.fields.get(filterQuery.field.uniqueName).type === ClientSideFieldType.DATE;
mongoFilterChunk[filterQuery.field.uniqueName] = {
[this.getMongoGroupMemberFilter(clientMemberQuery, negation)]: [isDate ? new Date(members[0].member) : members[0].member]
}
return members[0].filter;
}
private _msDay: number = 24 * 60 * 60 * 1000;
private _filterDateField(query: any, schema: APISchema, fieldName: IRequestField /*, dateFieldFilterQuery: any*/): any {
const mongoFilterQuery: any = {};
const isIntervalDefined: boolean = this.isDateIntervalDefined(fieldName.interval);
if (query["query"]) {
query = query["query"];
if (query[ClientSideFilterQueries.BEFORE]) {
mongoFilterQuery[MongoFilterQueries.LESS] = this.adjustDateFormat(query[ClientSideFilterQueries.BEFORE], isIntervalDefined);
} else if (query[ClientSideFilterQueries.BEFORE_EQUAL]) {
mongoFilterQuery[MongoFilterQueries.LESS] = this.adjustDateFormat(query[ClientSideFilterQueries.BEFORE_EQUAL] + this._msDay, isIntervalDefined);
} else if (query[ClientSideFilterQueries.EQUAL]) {
mongoFilterQuery[MongoFilterQueries.GREATER_EQUAL] = this.adjustDateFormat(query[ClientSideFilterQueries.EQUAL], isIntervalDefined);
mongoFilterQuery[MongoFilterQueries.LESS] = this.adjustDateFormat(query[ClientSideFilterQueries.EQUAL] + this._msDay, isIntervalDefined); // query[ClientSideFilterQueries.EQUAL] + this._msDay;
} else if (query[ClientSideFilterQueries.NOT_EQUAL]) {
mongoFilterQuery[MongoFilterQueries.NOT] = {
[MongoFilterQueries.GREATER_EQUAL]: this.adjustDateFormat(query[ClientSideFilterQueries.NOT_EQUAL], isIntervalDefined),
[MongoFilterQueries.LESS]: this.adjustDateFormat(query[ClientSideFilterQueries.NOT_EQUAL] + this._msDay, isIntervalDefined)
};
} else if (query[ClientSideFilterQueries.AFTER]) {
mongoFilterQuery[MongoFilterQueries.GREATER_EQUAL] = this.adjustDateFormat(query[ClientSideFilterQueries.AFTER], isIntervalDefined);
} else if (query[ClientSideFilterQueries.AFTER_EQUAL]) {
mongoFilterQuery[MongoFilterQueries.GREATER_EQUAL] = this.adjustDateFormat(query[ClientSideFilterQueries.AFTER_EQUAL], isIntervalDefined);
} else if (query[ClientSideFilterQueries.BETWEEN]) {
mongoFilterQuery[MongoFilterQueries.GREATER_EQUAL] = this.adjustDateFormat(query[ClientSideFilterQueries.BETWEEN][0], isIntervalDefined);
mongoFilterQuery[MongoFilterQueries.LESS_EQUAL] = this.adjustDateFormat(query[ClientSideFilterQueries.BETWEEN][1], isIntervalDefined);
} else if (query[ClientSideFilterQueries.NOT_BETWEEN]) {
mongoFilterQuery[MongoFilterQueries.NOT] = {
[MongoFilterQueries.GREATER_EQUAL]: this.adjustDateFormat(query[ClientSideFilterQueries.NOT_BETWEEN][0], isIntervalDefined),
[MongoFilterQueries.LESS_EQUAL]: this.adjustDateFormat(query[ClientSideFilterQueries.NOT_BETWEEN][1], isIntervalDefined)
};
}
} else {
if (query[ClientSideFilterQueries.INCLUDE]) {
return this.parseIncludeExcludeMembers(query[ClientSideFilterQueries.INCLUDE], ClientSideFilterQueries.INCLUDE, fieldName, schema, true);
} else if (query[ClientSideFilterQueries.EXCLUDE]) {
return this.parseIncludeExcludeMembers(query[ClientSideFilterQueries.EXCLUDE], ClientSideFilterQueries.EXCLUDE, fieldName, schema, true);
}
}
//dateFieldFilterQuery[dateFieldFilterUniquName.uniqueName] =
return mongoFilterQuery;
}
private adjustDateFormat(timestamp: number, isIntervalDefined: boolean): Date | number {
return isIntervalDefined ? new Date(timestamp) : timestamp;
}
private isDateIntervalDefined(interval: string): boolean {
return interval !== undefined && DateIntervals.isValid(interval)
}
}
export interface IFilterMemberObject {
member: string | number;
filter?: any;
}
export interface IRecursiveFilterMemberObject {
field: IRequestField,
include?: IFilterMemberObject[],
exclude?: IFilterMemberObject[]
}