UNPKG

flexmonster-mongo-connector

Version:

Custom data source API implementation for MongoDB

307 lines (264 loc) 16.8 kB
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[] }