ModelQuery: add groupWhere and test it

This commit is contained in:
Alice Gaudon 2020-09-04 22:15:55 +02:00
parent 823f5d0d26
commit e29b6369af
3 changed files with 76 additions and 5 deletions

View File

@ -1,6 +1,6 @@
{
"name": "wms-core",
"version": "0.21.10",
"version": "0.21.11",
"description": "Node web application framework and toolbelt.",
"repository": "https://gitlab.com/ArisuOngaku/wms-core",
"author": "Alice Gaudon <alice@gaudon.pro>",

View File

@ -5,7 +5,8 @@ import Pagination from "../Pagination";
import ModelRelation from "./ModelRelation";
import ModelFactory from "./ModelFactory";
export default class ModelQuery<M extends Model> {
export default class ModelQuery<M extends Model> implements WhereFieldConsumer<M> {
public static select<M extends Model>(factory: ModelFactory<M>, ...fields: string[]): ModelQuery<M> {
return new ModelQuery(QueryType.SELECT, factory, fields.length > 0 ? fields : ['*']);
}
@ -32,7 +33,7 @@ export default class ModelQuery<M extends Model> {
private fields: (string | SelectFieldValue | UpdateFieldValue)[];
private _leftJoin?: string;
private _leftJoinOn: WhereFieldValue[] = [];
private _where: WhereFieldValue[] = [];
private _where: (WhereFieldValue | WhereFieldValueGroup)[] = [];
private _limit?: number;
private _offset?: number;
private _sortBy?: string;
@ -62,6 +63,27 @@ export default class ModelQuery<M extends Model> {
return this;
}
public groupWhere(setter: (query: WhereFieldConsumer<M>) => void, operator: WhereOperator = WhereOperator.AND): this {
this._where.push(new WhereFieldValueGroup(this.collectWheres(setter), operator));
return this;
}
private collectWheres(setter: (query: WhereFieldConsumer<M>) => void): (WhereFieldValue | WhereFieldValueGroup)[] {
const query = this;
const wheres: (WhereFieldValue | WhereFieldValueGroup)[] = [];
setter({
where(field: string, value: string | Date | ModelQuery<any> | any, test: WhereTest = WhereTest.EQ, operator: WhereOperator = WhereOperator.AND) {
wheres.push(new WhereFieldValue(field, value, false, test, operator));
return this;
},
groupWhere(setter: (query: WhereFieldConsumer<M>) => void, operator: WhereOperator = WhereOperator.AND) {
wheres.push(new WhereFieldValueGroup(query.collectWheres(setter), operator))
return this;
}
});
return wheres;
}
public limit(limit: number, offset: number = 0): this {
this._limit = limit;
this._offset = offset;
@ -154,11 +176,17 @@ export default class ModelQuery<M extends Model> {
this.fields?.filter(v => v instanceof FieldValue)
.flatMap(v => (<FieldValue>v).variables)
.forEach(v => variables.push(v));
this._where.flatMap(v => v.variables)
this._where.flatMap(v => this.getVariables(v))
.forEach(v => variables.push(v));
return variables;
}
private getVariables(where: WhereFieldValue | WhereFieldValueGroup): any[] {
return where instanceof WhereFieldValueGroup ?
where.fields.flatMap(v => this.getVariables(v)) :
where.variables;
}
public async execute(connection?: Connection): Promise<QueryResult> {
return await query(this.build(), this.variables, connection);
}
@ -327,4 +355,31 @@ class WhereFieldValue extends FieldValue {
}
return this._test;
}
}
}
class WhereFieldValueGroup {
public readonly fields: (WhereFieldValue | WhereFieldValueGroup)[];
public readonly operator: WhereOperator;
public constructor(fields: (WhereFieldValue | WhereFieldValueGroup)[], operator: WhereOperator) {
this.fields = fields;
this.operator = operator;
}
public toString(first: boolean = true): string {
let str = `${first ? '' : ` ${this.operator} `}(`;
let firstField = true;
for (const field of this.fields) {
str += field.toString(firstField);
firstField = false;
}
str += ')';
return str;
}
}
interface WhereFieldConsumer<M extends Model> {
where(field: string, value: string | Date | ModelQuery<any> | any, test?: WhereTest, operator?: WhereOperator): this;
groupWhere(setter: (query: WhereFieldConsumer<M>) => void, operator?: WhereOperator): this;
}

16
test/ModelQuery.test.ts Normal file
View File

@ -0,0 +1,16 @@
import ModelQuery, {WhereOperator} from "../src/db/ModelQuery";
import ModelFactory from "../src/db/ModelFactory";
import Model from "../src/db/Model";
describe('Test ModelQuery', () => {
test('groupWhere generates proper query', () => {
const query = ModelQuery.select({table: 'model'} as unknown as ModelFactory<Model>, '*');
query.where('f1', 'v1');
query.groupWhere(q => q.where('f2', 'v2').where('f3', 'v3')
.groupWhere(q => q.where('f4', 'v4'), WhereOperator.OR))
.where('f5', 'v5');
expect(query.toString(true)).toBe('SELECT * FROM model WHERE `f1`=? AND (`f2`=? AND `f3`=? OR (`f4`=?)) AND `f5`=? ');
expect(query.variables.length).toBe(5);
});
});