Skip to content

Commit c34b05b

Browse files
author
fernandocode
committed
v.0.4.4
Corrigido formas não suportadas de fazer um order by (por alias, por index, com subquery, com count, etc)
1 parent f845f5c commit c34b05b

13 files changed

+207
-52
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "database-builder",
3-
"version": "0.4.3",
3+
"version": "0.4.4",
44
"description": "Library to assist in creating and maintaining SQL commands.",
55
"main": "./src/index.js",
66
"types": "./src/index.d.ts",
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
export enum ExpressionOrColumnEnum {
22
Expression,
3-
Column,
3+
Column
44
}

src/core/query-helper.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { QueryCompiled } from "./query-compiled";
2+
import { Replaceable } from "./replaceable";
3+
import { ParamType, Utils } from "./utils";
4+
5+
export class QueryHelper {
6+
7+
public static compileWithoutParams(queryCompiled: QueryCompiled): string {
8+
return Replaceable.replaceArrayPattern(queryCompiled.query, "?", this.formatParamsToInline(queryCompiled.params));
9+
}
10+
11+
private static formatParamsToInline(params: ParamType[]): any[] {
12+
return params.map(param => {
13+
return Utils.isString(param) || Utils.isBoolean(param)
14+
? `'${param}'`
15+
: param as any;
16+
});
17+
}
18+
}

src/core/replaceable.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
2+
export class Replaceable {
3+
4+
public static replaceAt(base: string, index: number, replace: string) {
5+
return index > -1
6+
? base.substring(0, index) + replace + base.substring(index + 1)
7+
: base;
8+
}
9+
10+
public static replaceArrayPattern(base: string, searchValue: string, replaceArray: string[]) {
11+
replaceArray.forEach(replace => {
12+
base = this.replaceAt(base, base.indexOf(searchValue), replace);
13+
});
14+
return base;
15+
}
16+
}

src/core/utils.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import { MetadataTable } from "../metadata-table";
2323
import { MetadataTableBase } from "../metadata-table-base";
2424
import { ProjectionCompile } from "../crud/projection-compile";
2525
import * as lodash from "lodash";
26+
import { QueryCompiled } from ".";
2627

2728
export type ParamType = ValueType | ReplacementParam;
2829

@@ -33,6 +34,8 @@ export type TypeOrString<T> = (new () => T) | string;
3334

3435
export type ExpressionOrColumn<TReturn, T> = ReturnExpression<TReturn, T> | string;
3536

37+
export type TypeOrderBy<TReturn, T> = ExpressionOrColumn<TReturn, T> | PlanRef | number | QueryCompiled | QueryCompiled[];
38+
3639
export type TypeWhere<T> = Expression<T> | ValueTypeToParse | ColumnRef | ProjectionsHelper<T> | PlanRef;
3740

3841
export type TypeProjection<T> = ProjectionsHelper<T> | ColumnRef | PlanRef;
@@ -111,7 +114,7 @@ export class Utils {
111114
}
112115

113116
public static isReservedBoolean(value: any): boolean {
114-
return value === "true" || value === "false" || value === 0 || value === 1 ;
117+
return value === "true" || value === "false" || value === 0 || value === 1;
115118
}
116119

117120
public static isFunction(value: any): boolean {
@@ -166,13 +169,22 @@ export class Utils {
166169
return instance instanceof PlanRef;
167170
}
168171

169-
public static isEmpty(value: any) {
172+
public static isEmpty(value: any): boolean {
170173
if (this.isBoolean(value) || this.isDate(value)) {
171174
return this.isNull(value);
172175
}
173176
return lodash.isEmpty(value);
174177
}
175178

179+
public static isQueryCompiled(value: any): boolean {
180+
return value && this.isString(value.query) && this.isArray(value.params);
181+
}
182+
183+
public static isQueryCompiledArray(value: any): boolean {
184+
return (this.isArray(value)
185+
&& (value as any[]).filter(v => this.isQueryCompiled(v) === false).length === 0);
186+
}
187+
176188
public static databaseName<T>(tablename: TypeOrString<T>): string {
177189
return this.getValueByTypeOrString(tablename);
178190
}

src/crud/projection-builder.ts

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -108,11 +108,14 @@ export class ProjectionBuilder<T> {
108108
}
109109

110110
public add<TReturn>(
111-
expression: ExpressionOrColumn<TReturn, T>,
111+
expression: ExpressionOrColumn<TReturn, T> | QueryCompiled[] | SqlCompilable,
112112
alias?: string,
113113
): ProjectionBuilder<T> {
114+
if ((expression as SqlCompilable).compile || Utils.isQueryCompiledArray(expression)) {
115+
return this.subQuery((expression as (QueryCompiled[] | SqlCompilable)), alias);
116+
}
114117
this.buildProjectionWithExpression(void 0,
115-
expression,
118+
expression as ExpressionOrColumn<TReturn, T>,
116119
alias,
117120
);
118121
return this;
@@ -284,7 +287,8 @@ export class ProjectionBuilder<T> {
284287
): ProjectionBuilder<T> {
285288
const instanceProjection: ProjectionBuilder<T> = new ProjectionBuilder(this._typeT, this._aliasTable, void 0, false, this._getMapper);
286289
projectionCallback(instanceProjection);
287-
const projectionInner = instanceProjection.compile();
290+
const projectionInner = ProjectionCompile.compile(instanceProjection.result());
291+
// const projectionInner = instanceProjection.compile();
288292
this.buildProjectionWithExpression(Projection.Coalesce,
289293
`${projectionInner.projection}, ${defaultValue}`,
290294
alias,
@@ -337,9 +341,12 @@ export class ProjectionBuilder<T> {
337341
return this;
338342
}
339343

340-
public compile(): ProjectionCompiled {
341-
return ProjectionCompile.compile(this._projections);
344+
public result(): ProjectionModel[] {
345+
return this._projections;
342346
}
347+
// public compile(): ProjectionCompiled {
348+
// return ProjectionCompile.compile(this._projections);
349+
// }
343350

344351
private selectAllColumns(mapper: MapperTable): void {
345352
const columns = mapper.columns.filter(x => Utils.isNull(x.tableReference));

src/crud/projection-case-when.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ export class ProjectionCaseWhen<T> {
4545
this._whenBuilder.builder += ` ${type} ${projectionCompiled.projection}`;
4646
this._whenBuilder.params = this._whenBuilder.params.concat(projectionCompiled.params);
4747
} else if (Utils.isProjectionBuilder(projection)) {
48-
const projectionCompiled = (projection as ProjectionBuilder<T>).compile();
48+
const projectionCompiled = ProjectionCompile.compile((projection as ProjectionBuilder<T>).result());
49+
// const projectionCompiled = (projection as ProjectionBuilder<T>).compile();
4950
this._whenBuilder.builder += ` ${type} ${projectionCompiled.projection}`;
5051
this._whenBuilder.params = this._whenBuilder.params.concat(projectionCompiled.params);
5152
} else {

src/crud/query/join-query-builder-contract.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
1-
import { ProjectionCompiled } from "../projection-compiled";
21
import { QueryBuilderBaseContract } from "./query-builder-base-contract";
32
import { WhereCompiled } from "../where-compiled";
43
import { ParamType } from "../../core/utils";
4+
import { ProjectionModel } from "../projection-model";
55

66
export interface JoinQueryBuilderContract<T, TQuery extends JoinQueryBuilderContract<T, TQuery>>
77
extends QueryBuilderBaseContract<T, TQuery> {
88

99
_getOn(): WhereCompiled;
1010
_getTypeJoin(): string;
1111
_getWhere(): WhereCompiled;
12-
_getSelect(): ProjectionCompiled;
12+
_getProjections(): ProjectionModel[];
13+
// _getSelect(): ProjectionCompiled;
1314
_getGroupBy(): string;
1415
_getHaving(): WhereCompiled;
1516
_getOrderBy(): string;

src/crud/query/join-query-builder.ts

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { ParamType, ValueType } from "../../core/utils";
99
import { MapperTable } from "../../mapper-table";
1010
import { MetadataTable } from "../../metadata-table";
1111
import { QueryBuilder } from "./query-builder";
12+
import { ProjectionModel } from "../projection-model";
1213

1314
export class JoinQueryBuilder<T>
1415
extends QueryBuilderBase<T, JoinQueryBuilder<T>>
@@ -37,10 +38,7 @@ export class JoinQueryBuilder<T>
3738
}
3839

3940
public _getOn(): WhereCompiled {
40-
const t = this.whereCompile(this._on.compile());
41-
// console.log(this.tablename, t);
42-
return t;
43-
// return this._on.compile();
41+
return this.whereCompile(this._on.compile());
4442
}
4543

4644
public _getTypeJoin(): string {
@@ -52,9 +50,12 @@ export class JoinQueryBuilder<T>
5250
return this.whereCompiled;
5351
}
5452

55-
public _getSelect(): ProjectionCompiled {
56-
return this._projectionCompiled;
53+
public _getProjections(): ProjectionModel[] {
54+
return this._projections;
5755
}
56+
// public _getSelect(): ProjectionCompiled {
57+
// return this._projectionCompiled;
58+
// }
5859

5960
public _getGroupBy(): string {
6061
return this._groupBy;
@@ -70,12 +71,6 @@ export class JoinQueryBuilder<T>
7071

7172
public _getParams(): ParamType[] {
7273
return this._joinParams;
73-
// const compiled: QueryCompiled = this.buildBase();
74-
// return compiled.params
75-
// .concat(this._joinParams)
76-
// .concat(this.whereCompiled.params)
77-
// .concat(this._having.params)
78-
// .concat(this._limit.params);
7974
}
8075

8176
public addParamsOn(params: ValueType[]): JoinQueryBuilder<T> {
@@ -85,7 +80,6 @@ export class JoinQueryBuilder<T>
8580

8681
// Para adicionar alias da tabela no apelido da projeção padrão
8782
protected createProjectionBuilder(): ProjectionBuilder<T> {
88-
// return new ProjectionBuilder(this._typeT, this.alias, true);
8983
return super.createProjectionBuilder(true, void 0);
9084
}
9185

src/crud/query/query-builder-base.ts

Lines changed: 63 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { ProjectionCompiled } from "../projection-compiled";
22
import { UnionType } from "../../core/union-type";
33
import { ProjectionBuilder } from "../projection-builder";
4-
import { ExpressionOrColumn, ParamType, Utils } from "../../core/utils";
4+
import { ExpressionOrColumn, ParamType, Utils, TypeOrderBy } from "../../core/utils";
55
import { WhereBuilder } from "../where-builder";
66
import { OrderBy } from "../../core/enums/order-by";
77
import { WhereCompiled } from "../where-compiled";
@@ -22,6 +22,11 @@ import { DatabaseBuilderError } from "../../core";
2222
import { QueryBuilder } from "./query-builder";
2323
import { ModelUtils } from "../../core/model-utils";
2424
import { ParamFilter } from "../../core/param-filter";
25+
import { PlanRef } from "../../core/plan-ref";
26+
import { ProjectionModel } from "../projection-model";
27+
import { ProjectionCompile } from "../projection-compile";
28+
import { Replaceable } from "../../core/replaceable";
29+
import { QueryHelper } from "../../core/query-helper";
2530

2631
export abstract class QueryBuilderBase<T,
2732
TQuery extends QueryBuilderBase<T, TQuery>>
@@ -44,10 +49,11 @@ export abstract class QueryBuilderBase<T,
4449
params: []
4550
} as WhereCompiled;
4651

47-
protected _projectionCompiled: ProjectionCompiled = {
48-
projection: "",
49-
params: []
50-
} as ProjectionCompiled;
52+
protected _projections: ProjectionModel[] = [];
53+
// protected _projectionCompiled: ProjectionCompiled = {
54+
// projection: "",
55+
// params: []
56+
// } as ProjectionCompiled;
5157
// TODO: remove "_joinParams" e utilizar SqlAndParams como é realizado nos projections
5258
protected _joinParams: ParamType[] = [];
5359
protected _ignoreQueryFilter: boolean = false;
@@ -193,7 +199,8 @@ export abstract class QueryBuilderBase<T,
193199
): TQuery {
194200
const instanceProjection: ProjectionBuilder<T> = this.createProjectionBuilder();
195201
projectionCallback(instanceProjection);
196-
this.compileProjection(instanceProjection.compile());
202+
this.buildProjections(instanceProjection.result());
203+
// this.compileProjection(instanceProjection.compile());
197204
return this._getInstance();
198205
}
199206

@@ -204,21 +211,33 @@ export abstract class QueryBuilderBase<T,
204211
}
205212

206213
public orderBy<TReturn>(
207-
expression: ExpressionOrColumn<TReturn, T>,
214+
expression: TypeOrderBy<TReturn, T>,
208215
order: OrderBy = OrderBy.ASC
209216
): TQuery {
210-
this.compileOrderBy(`${Utils.addAlias(Utils.getColumn(expression), this._alias)} ${order}`);
217+
let columnName;
218+
if (Utils.isQueryCompiled(expression)) {
219+
return this.orderBy(`(${QueryHelper.compileWithoutParams(expression as QueryCompiled)})`, order);
220+
} else if (Utils.isQueryCompiledArray(expression)) {
221+
return this.orderBy((expression as QueryCompiled[])[0], order);
222+
} else if (Utils.isPlanRef(expression)) {
223+
columnName = (expression as PlanRef).result();
224+
} else if (Utils.isNumber(expression)) {
225+
columnName = `${(expression as number)}`;
226+
} else {
227+
columnName = Utils.addAlias(Utils.getColumn(expression as ExpressionOrColumn<TReturn, T>), this._alias);
228+
}
229+
this.compileOrderBy(`${columnName} ${order}`);
211230
return this._getInstance();
212231
}
213232

214233
public asc<TReturn>(
215-
expression: ExpressionOrColumn<TReturn, T>
234+
expression: TypeOrderBy<TReturn, T>
216235
): TQuery {
217236
return this.orderBy(expression, OrderBy.ASC);
218237
}
219238

220239
public desc<TReturn>(
221-
expression: ExpressionOrColumn<TReturn, T>
240+
expression: TypeOrderBy<TReturn, T>
222241
): TQuery {
223242
return this.orderBy(expression, OrderBy.DESC);
224243
}
@@ -246,6 +265,20 @@ export abstract class QueryBuilderBase<T,
246265
return this._getInstance();
247266
}
248267

268+
/**
269+
* Find projection by alias and result index (base 1...N+1)
270+
* @param projectionAlias alias to find the projection
271+
* @returns index (base 1...N+1)
272+
*/
273+
public getIndexProjection<TReturn>(projectionAlias: ExpressionOrColumn<TReturn, T>): number {
274+
const projectionColumnAlias = Utils.getColumn(projectionAlias);
275+
const index = this._projections.findIndex(x => x.projection.endsWith(` AS ${projectionColumnAlias}`));
276+
if (index > -1) {
277+
return index + 1;
278+
}
279+
throw new DatabaseBuilderError(`Not found projection alias ("${projectionColumnAlias}" in projections (current value: "${ProjectionCompile.compile(this._projections).projection}"))`);
280+
}
281+
249282
public ignoreQueryFilters(): TQuery {
250283
if (this._joinsQuery.length) {
251284
throw new DatabaseBuilderError(`Can't apply 'ignoreQueryFilters' after joining 'join()'`);
@@ -336,7 +369,8 @@ export abstract class QueryBuilderBase<T,
336369
this._joinsQuery.push(joinQuery);
337370
this._joinParams = this._joinParams.concat(joinQuery._getParams());
338371
this.compileWhere(this.whereCompiled, joinQuery._getWhere());
339-
this.compileProjection(joinQuery._getSelect());
372+
this.buildProjections(joinQuery._getProjections());
373+
// this.compileProjection(joinQuery._getSelect());
340374
this.compileGroupBy(joinQuery._getGroupBy());
341375
this.compileHaving(joinQuery._getHaving());
342376
this.compileOrderBy(joinQuery._getOrderBy());
@@ -347,10 +381,14 @@ export abstract class QueryBuilderBase<T,
347381
}
348382

349383
protected getColumnsCompiled(): ProjectionCompiled {
350-
if (!this._projectionCompiled.projection.length) {
384+
if (this._projections.length === 0) {
351385
this.setDefaultColumns();
352386
}
353-
return this._projectionCompiled;
387+
return ProjectionCompile.compile(this._projections);
388+
// if (!this._projectionCompiled.projection.length) {
389+
// this.setDefaultColumns();
390+
// }
391+
// return this._projectionCompiled;
354392
}
355393

356394
protected buildBase(): QueryCompiled {
@@ -404,15 +442,20 @@ export abstract class QueryBuilderBase<T,
404442
return queryBase;
405443
}
406444

407-
private compileProjection(compiled: ProjectionCompiled) {
408-
if (compiled.projection.length) {
409-
this._projectionCompiled.projection +=
410-
`${(this._projectionCompiled.projection.length ? ", " : "")}${compiled.projection}`;
411-
compiled.params.forEach((value: any) => {
412-
this._projectionCompiled.params.push(value);
413-
});
445+
private buildProjections(projections: ProjectionModel[]) {
446+
if (projections.length > 0) {
447+
this._projections = [...this._projections, ...projections];
414448
}
415449
}
450+
// private compileProjection(compiled: ProjectionCompiled) {
451+
// if (compiled.projection.length) {
452+
// this._projectionCompiled.projection +=
453+
// `${(this._projectionCompiled.projection.length ? ", " : "")}${compiled.projection}`;
454+
// compiled.params.forEach((value: any) => {
455+
// this._projectionCompiled.params.push(value);
456+
// });
457+
// }
458+
// }
416459

417460
private compileTableJoins<TJoin, TQueryJoin extends JoinQueryBuilderContract<TJoin, TQueryJoin>>(
418461
tablesBase: QueryCompiled,

0 commit comments

Comments
 (0)