Skip to content

Commit

Permalink
MongodbConditionConverter convert GenericQueryBuilder to mongodb query
Browse files Browse the repository at this point in the history
  • Loading branch information
nhat-phan committed Mar 20, 2018
1 parent 0c5d2be commit bd8aaa0
Show file tree
Hide file tree
Showing 11 changed files with 1,060 additions and 10 deletions.
4 changes: 2 additions & 2 deletions dist/lib/query-builders/GenericQueryBuilder.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ export declare class GenericQueryBuilder implements IBasicQuery, IConditionQuery
protected isUsed: boolean;
protected name: string;
protected fields: {
select: string[];
distinct: string[];
select?: string[];
distinct?: string[];
};
protected selectedFields: string[];
protected distinctFields: string[];
Expand Down
2 changes: 1 addition & 1 deletion dist/lib/query-builders/GenericQueryBuilder.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const GenericQueryCondition_1 = require("./GenericQueryCondition");
const lodash_1 = require("lodash");
class GenericQueryBuilder {
constructor(softDelete) {
this.fields = { select: [], distinct: [] };
this.fields = {};
this.ordering = {};
this.conditions = [];
this.convention = this.getQueryConvention();
Expand Down
8 changes: 6 additions & 2 deletions dist/lib/query-builders/GenericQueryCondition.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,12 @@ export declare class GenericQueryCondition implements IConditionQuery {
toObject(): Object;
protected buildQuery(bool: 'and' | 'or', arg0: string | SubCondition, arg1: Operator | any, arg2: any): this;
protected buildSubQuery(queryCondition: GenericQueryCondition, arg0: Function): this;
where(arg0: string | SubCondition, arg1?: Operator | any, arg2?: any): this;
orWhere(arg0: string | SubCondition, arg1?: Operator | any, arg2?: any): this;
where(conditionBuilder: SubCondition): this;
where(field: string, value: any): this;
where(field: string, operator: Operator, value: any): this;
orWhere(conditionBuilder: SubCondition): this;
orWhere(field: string, value: any): this;
orWhere(field: string, operator: Operator, value: any): this;
whereIn(field: string, values: Array<any>): this;
whereNotIn(field: string, values: Array<any>): this;
orWhereIn(field: string, values: Array<any>): this;
Expand Down
25 changes: 25 additions & 0 deletions dist/lib/query-builders/mongodb/MongodbConditionConverter.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Operator } from '../interfaces/IConditionQuery';
export declare type SimpleCondition = {
bool: 'and' | 'or';
field: string;
operator: Operator;
value: any;
};
export declare type GroupOfCondition = {
bool: 'and' | 'or';
queries: Condition[];
};
export declare type Condition = SimpleCondition | GroupOfCondition;
export declare class MongodbConditionConverter {
queryConditions: Object[];
constructor(queryConditions: Object[]);
convert(): Object;
protected convertConditions(conditions: Condition[]): any;
protected hasAnyIntersectKey(a: Object, b: Object): boolean;
protected convertConditionsWithAnd(bucket: Object, conditions: Condition[]): void;
protected convertConditionsWithOr(bucket: Object, conditions: Condition[]): void;
protected convertCondition(condition: Condition): Object;
protected convertGroupOfCondition(condition: GroupOfCondition): Object;
private convertNotEmptyGroupOfCondition(condition);
protected convertSimpleCondition(condition: SimpleCondition): Object;
}
135 changes: 135 additions & 0 deletions dist/lib/query-builders/mongodb/MongodbConditionConverter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const lodash_1 = require("lodash");
class MongodbConditionConverter {
constructor(queryConditions) {
this.queryConditions = queryConditions;
}
convert() {
return this.convertConditions(this.queryConditions);
}
convertConditions(conditions) {
const result = {};
for (let i = 0, l = conditions.length; i < l; i++) {
// fix edge case: `query.orWhere().where()...`
if (i === 0 && conditions[i].bool === 'or') {
conditions[i].bool = 'and';
}
// always change previous statement of OR bool to OR
if (conditions[i].bool === 'or' && conditions[i - 1].bool === 'and') {
conditions[i - 1].bool = 'or';
}
}
this.convertConditionsWithAnd(result, conditions.filter(item => item['bool'] === 'and'));
this.convertConditionsWithOr(result, conditions.filter(item => item['bool'] === 'or'));
if (Object.keys(result).length === 1 && typeof result['$and'] !== 'undefined' && result['$and'].length === 1) {
return result['$and'][0];
}
return result;
}
hasAnyIntersectKey(a, b) {
const keyOfA = Object.keys(a);
const keyOfB = Object.keys(b);
for (const key of keyOfB) {
if (keyOfA.indexOf(key) !== -1) {
return true;
}
}
return false;
}
convertConditionsWithAnd(bucket, conditions) {
let result = {};
for (const condition of conditions) {
const query = this.convertCondition(condition);
if (this.hasAnyIntersectKey(result, query) && !Array.isArray(result)) {
result = [result];
}
if (Array.isArray(result)) {
result.push(query);
continue;
}
Object.assign(result, query);
}
if (Array.isArray(result)) {
Object.assign(bucket, { $and: result });
return;
}
const keysLength = Object.keys(result).length;
if (keysLength === 1) {
Object.assign(bucket, result);
}
if (keysLength > 1) {
Object.assign(bucket, { $and: [result] });
}
}
convertConditionsWithOr(bucket, conditions) {
const result = [];
for (const condition of conditions) {
const query = this.convertCondition(condition);
result.push(Object.assign({}, query));
}
if (result.length > 1) {
Object.assign(bucket, { $or: result });
}
}
convertCondition(condition) {
if (typeof condition['queries'] === 'undefined') {
return this.convertSimpleCondition(condition);
}
return this.convertGroupOfCondition(condition);
}
convertGroupOfCondition(condition) {
if (!condition.queries || condition.queries.length === 0) {
return {};
}
if (condition.queries.length === 1) {
return this.convertCondition(condition.queries[0]);
}
return this.convertNotEmptyGroupOfCondition(condition);
}
convertNotEmptyGroupOfCondition(condition) {
const result = this.convertConditions(condition.queries);
if (Object.keys(result).length === 0) {
return {};
}
if (condition.bool === 'and') {
if (Object.keys(result).length === 1) {
return result;
}
return { $and: [result] };
}
if (Object.keys(result).length === 1 && typeof result['$or'] !== 'undefined') {
return result;
}
return { $or: [result] };
}
convertSimpleCondition(condition) {
if (typeof condition.value === 'undefined') {
return {};
}
switch (condition.operator) {
case '!=':
case '<>':
return lodash_1.set({}, condition.field, { $ne: condition.value });
case '<':
return lodash_1.set({}, condition.field, { $lt: condition.value });
case '<=':
case '=<':
return lodash_1.set({}, condition.field, { $lte: condition.value });
case '>':
return lodash_1.set({}, condition.field, { $gt: condition.value });
case '>=':
case '=>':
return lodash_1.set({}, condition.field, { $gte: condition.value });
case 'in':
return lodash_1.set({}, condition.field, { $in: condition.value });
case 'not-in':
return lodash_1.set({}, condition.field, { $nin: condition.value });
case '=':
case '==':
default:
return lodash_1.set({}, condition.field, condition.value);
}
}
}
exports.MongodbConditionConverter = MongodbConditionConverter;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import 'jest';
Loading

0 comments on commit bd8aaa0

Please sign in to comment.