Merge pull request '#41-query-builder-sorting' (#87) from #41-query-builder-sorting into develop

Reviewed-on: #87
This commit is contained in:
Julian Krauser 2025-04-15 08:47:22 +00:00
commit 9fefd93f09
2 changed files with 41 additions and 18 deletions

View file

@ -2,6 +2,7 @@ import { Brackets, DataSource, NotBrackets, ObjectLiteral, SelectQueryBuilder, W
import { dataSource } from "../data-source"; import { dataSource } from "../data-source";
import { ConditionStructure, DynamicQueryStructure, FieldType, QueryResult } from "../type/dynamicQueries"; import { ConditionStructure, DynamicQueryStructure, FieldType, QueryResult } from "../type/dynamicQueries";
import { TableMeta } from "../type/tableMeta"; import { TableMeta } from "../type/tableMeta";
import { StringHelper } from "./stringHelper";
export default abstract class DynamicQueryBuilder { export default abstract class DynamicQueryBuilder {
public static allowedTables: Array<string> = [ public static allowedTables: Array<string> = [
@ -62,11 +63,18 @@ export default abstract class DynamicQueryBuilder {
count?: number; count?: number;
noLimit?: boolean; noLimit?: boolean;
}): SelectQueryBuilder<ObjectLiteral> { }): SelectQueryBuilder<ObjectLiteral> {
let affix = Math.random().toString(36).substring(2); let affix = queryObj.id ?? StringHelper.random(10);
let query = dataSource.getRepository(queryObj.table).createQueryBuilder(`${queryObj.table}_${affix}`); let query = dataSource.getRepository(queryObj.table).createQueryBuilder(`${affix}_${queryObj.table}`);
this.buildDynamicQuery(query, queryObj, affix); this.buildDynamicQuery(query, queryObj, affix);
if (queryObj.orderBy) {
queryObj.orderBy.forEach((order) => {
// compatability layer for none id (old) queries
if (order.id) query.addOrderBy(`${order.id}_${order.table}.${order.column}`, order.order);
});
}
if (!noLimit) { if (!noLimit) {
query.offset(offset); query.offset(offset);
query.limit(count); query.limit(count);
@ -78,10 +86,10 @@ export default abstract class DynamicQueryBuilder {
private static buildDynamicQuery( private static buildDynamicQuery(
query: SelectQueryBuilder<ObjectLiteral>, query: SelectQueryBuilder<ObjectLiteral>,
queryObject: DynamicQueryStructure, queryObject: DynamicQueryStructure,
affix: string = "", affix: string = "", // table id
depth: number = 0 depth: number = 0
): void { ): void {
const alias = queryObject.table + "_" + affix; const alias = `${affix}_${queryObject.table}`;
let firstSelect = true; let firstSelect = true;
let selects: Array<string> = []; let selects: Array<string> = [];
@ -108,18 +116,12 @@ export default abstract class DynamicQueryBuilder {
if (queryObject.join) { if (queryObject.join) {
for (const join of queryObject.join) { for (const join of queryObject.join) {
let subaffix = Math.random().toString(36).substring(2); let subaffix = join.id ?? StringHelper.random(10);
query.leftJoin(`${alias}.${join.foreignColumn}`, join.table + "_" + subaffix); query.leftJoin(`${alias}.${join.foreignColumn}`, `${subaffix}_${join.table}`);
this.buildDynamicQuery(query, join, subaffix, depth + 1); this.buildDynamicQuery(query, join, subaffix, depth + 1);
} }
} }
if (queryObject.orderBy) {
queryObject.orderBy.forEach((order) => {
query.addOrderBy(`${alias}.${order.column}`, order.order);
});
}
} }
public static applyWhere( public static applyWhere(
@ -127,6 +129,7 @@ export default abstract class DynamicQueryBuilder {
conditions: Array<ConditionStructure>, conditions: Array<ConditionStructure>,
alias: string alias: string
): void { ): void {
console.log(conditions, alias);
for (const condition of conditions) { for (const condition of conditions) {
if (condition.structureType == "condition") { if (condition.structureType == "condition") {
const whereClause = this.buildConditionClause(condition, alias); const whereClause = this.buildConditionClause(condition, alias);
@ -166,7 +169,7 @@ export default abstract class DynamicQueryBuilder {
condition: ConditionStructure & { structureType: "condition" }, condition: ConditionStructure & { structureType: "condition" },
alias: string alias: string
): { query: string; parameters: Record<string, unknown> } { ): { query: string; parameters: Record<string, unknown> } {
const parameterKey = `${alias}_${condition.column}_${Math.random().toString(36).substring(2)}`; const parameterKey = `${condition.column}_${Math.random().toString(36).substring(2)}`;
let query = `${alias}.${condition.column}`; let query = `${alias}.${condition.column}`;
let parameters: Record<string, unknown> = {}; let parameters: Record<string, unknown> = {};
@ -236,6 +239,8 @@ export default abstract class DynamicQueryBuilder {
parameters[`${parameterKey}_end`] = new Date(new Date().getFullYear() - (condition.value as number), 11, 31); parameters[`${parameterKey}_end`] = new Date(new Date().getFullYear() - (condition.value as number), 11, 31);
} }
console.log(query, parameters);
return { query, parameters }; return { query, parameters };
} }
@ -379,6 +384,7 @@ export default abstract class DynamicQueryBuilder {
count: noLimit ? total : count, count: noLimit ? total : count,
}; };
} catch (error) { } catch (error) {
console.log(error);
return { return {
stats: "error", stats: "error",
sql: error.sql, sql: error.sql,
@ -391,19 +397,22 @@ export default abstract class DynamicQueryBuilder {
} }
const memberQuery: DynamicQueryStructure = { const memberQuery: DynamicQueryStructure = {
id: "memberId",
select: "*", select: "*",
table: "member", table: "member",
orderBy: [ orderBy: [
{ column: "lastname", order: "ASC" }, { id: "memberId", depth: 0, table: "member", column: "lastname", order: "ASC" },
{ column: "firstname", order: "ASC" }, { id: "memberId", depth: 0, table: "member", column: "firstname", order: "ASC" },
], ],
}; };
const memberByRunningMembershipQuery: DynamicQueryStructure = { const memberByRunningMembershipQuery: DynamicQueryStructure = {
id: "memberId",
select: "*", select: "*",
table: "member", table: "member",
join: [ join: [
{ {
id: "membershipId",
select: "*", select: "*",
table: "membership", table: "membership",
where: [{ structureType: "condition", concat: "_", operation: "null", column: "end", value: "" }], where: [{ structureType: "condition", concat: "_", operation: "null", column: "end", value: "" }],
@ -411,7 +420,7 @@ const memberByRunningMembershipQuery: DynamicQueryStructure = {
}, },
], ],
orderBy: [ orderBy: [
{ column: "lastname", order: "ASC" }, { id: "memberId", depth: 0, table: "member", column: "lastname", order: "ASC" },
{ column: "firstname", order: "ASC" }, { id: "memberId", depth: 0, table: "member", column: "firstname", order: "ASC" },
], ],
}; };

View file

@ -1,9 +1,10 @@
export interface DynamicQueryStructure { export interface DynamicQueryStructure {
id: string;
select: string[] | "*"; select: string[] | "*";
table: string; table: string;
where?: Array<ConditionStructure>; where?: Array<ConditionStructure>;
join?: Array<DynamicQueryStructure & { foreignColumn: string }>; join?: Array<DynamicQueryStructure & { foreignColumn: string }>;
orderBy?: Array<OrderByStructure>; orderBy?: Array<OrderByStructure>; // only at top level
} }
export type ConditionStructure = ( export type ConditionStructure = (
@ -48,6 +49,9 @@ export type WhereOperation =
// TODO: age between | age equals | age greater | age smaller // TODO: age between | age equals | age greater | age smaller
export type OrderByStructure = { export type OrderByStructure = {
id: string;
depth: number;
table: string;
column: string; column: string;
order: OrderByType; order: OrderByType;
}; };
@ -59,6 +63,7 @@ export type QueryResult = {
}; };
export const exampleQuery: DynamicQueryStructure = { export const exampleQuery: DynamicQueryStructure = {
id: "1234",
select: ["firstname", "lastname"], select: ["firstname", "lastname"],
table: "member", table: "member",
where: [ where: [
@ -92,16 +97,19 @@ export const exampleQuery: DynamicQueryStructure = {
], ],
join: [ join: [
{ {
id: "5678",
select: "*", select: "*",
table: "communication", table: "communication",
foreignColumn: "sendNewsletter", foreignColumn: "sendNewsletter",
}, },
{ {
id: "91011",
select: "*", select: "*",
table: "membership", table: "membership",
foreignColumn: "memberships", foreignColumn: "memberships",
join: [ join: [
{ {
id: "121314",
select: "*", select: "*",
table: "membership_status", table: "membership_status",
foreignColumn: "status", foreignColumn: "status",
@ -120,10 +128,16 @@ export const exampleQuery: DynamicQueryStructure = {
], ],
orderBy: [ orderBy: [
{ {
id: "1234",
depth: 0,
table: "member",
column: "firstname", column: "firstname",
order: "ASC", order: "ASC",
}, },
{ {
id: "1234",
depth: 0,
table: "member",
column: "lastname", column: "lastname",
order: "ASC", order: "ASC",
}, },