From 2518a1046fc4ca77a6f38bbcdf9c61a15a49c02b Mon Sep 17 00:00:00 2001 From: Julian Krauser Date: Sat, 14 Dec 2024 15:44:17 +0100 Subject: [PATCH] builder change --- src/helpers/dynamicQueryBuilder.ts | 141 +++++++++++------------------ src/type/dynamicQueries.ts | 6 +- 2 files changed, 54 insertions(+), 93 deletions(-) diff --git a/src/helpers/dynamicQueryBuilder.ts b/src/helpers/dynamicQueryBuilder.ts index 7bbdd25..e6f655d 100644 --- a/src/helpers/dynamicQueryBuilder.ts +++ b/src/helpers/dynamicQueryBuilder.ts @@ -1,4 +1,4 @@ -import { Brackets, DataSource, ObjectLiteral, SelectQueryBuilder } from "typeorm"; +import { Brackets, DataSource, NotBrackets, ObjectLiteral, SelectQueryBuilder, WhereExpressionBuilder } from "typeorm"; import { dataSource } from "../data-source"; import { ConditionStructure, DynamicQueryStructure } from "../type/dynamicQueries"; import { TableMeta } from "../type/tableMeta"; @@ -52,103 +52,93 @@ export default abstract class DynamicQueryBuilder { count: number = 25 ): SelectQueryBuilder { let query = dataSource.getRepository(queryObj.table).createQueryBuilder(queryObj.table + "_0"); - query = this.buildDynamicQuery(query, queryObj); - query = query.offset(offset); - query = query.limit(count); + + this.buildDynamicQuery(query, queryObj); + + query.offset(offset); + query.limit(count); return query; - - dataSource - .getRepository("member") - .createQueryBuilder("member_0") - .select("member_0.firstname") - .addSelect("member_0.lastname") - .where("member_0.mail LIKE '%@gmail.com'") - .andWhere( - new Brackets((qb) => { - qb.where("user.firstName LIKE '%J'").orWhere("user.lastName LIKE '%K'"); - }) - ) - .leftJoinAndSelect("member_0.sendNewsletter", "communication_0") - .addSelect("communication_0.*") - .orderBy("member_0.firstname", "ASC") - .addOrderBy("member_0.lastname", "ASC"); } - public static buildDynamicQuery( - queryBuilder: SelectQueryBuilder, + private static buildDynamicQuery( + query: SelectQueryBuilder, queryObject: DynamicQueryStructure, depth: number = 0 - ): SelectQueryBuilder { + ): void { const alias = queryObject.table + "_" + depth; - // Handle SELECT if (queryObject.select == "*") { - queryBuilder.select(`${alias}.*`); + query.addSelect(`${alias}.*`); } else { - queryBuilder.select(queryObject.select.map((col) => `${alias}.${col}`)); + for (const select of queryObject.select) { + query.addSelect(`${alias}.${select}`); + } } - // Handle WHERE if (queryObject.where) { - this.applyWhere(queryBuilder, queryObject.where, alias); + this.applyWhere(query, queryObject.where, alias); } - // Handle JOINS if (queryObject.join) { - queryObject.join.forEach((join) => { - const joinAlias = join.table; - const joinType = "leftJoin"; // Default join type - const joinCondition = `${alias}.${join.foreignColumn} = ${joinAlias}.${join.foreignColumn}`; + for (const join of queryObject.join) { + query.leftJoinAndSelect(`${alias}.${join.foreignColumn}`, join.table + "_" + (depth + 1)); - queryBuilder[joinType](`${join.table}`, joinAlias, joinCondition); - - // Recursively handle sub-joins and their conditions - this.buildDynamicQuery(queryBuilder, join, depth + 1); - }); + this.buildDynamicQuery(query, join, depth + 1); + } } - // Handle ORDER BY if (queryObject.orderBy) { queryObject.orderBy.forEach((order) => { - queryBuilder.addOrderBy(`${alias}.${order.column}`, order.order); + query.addOrderBy(`${alias}.${order.column}`, order.order); }); } - - return queryBuilder; } - // Helper: Apply WHERE conditions - public static applyWhere( - queryBuilder: SelectQueryBuilder, + public static applyWhere( + query: SelectQueryBuilder | WhereExpressionBuilder, conditions: Array, alias: string ): void { - conditions.forEach((condition, index) => { - if (condition.structureType === "condition") { + for (const condition of conditions) { + if (condition.structureType == "condition") { const whereClause = this.buildConditionClause(condition, alias); - const whereMethod = condition.concat === "_" ? "where" : "andWhere"; - if (condition.concat === "OR") { - queryBuilder.orWhere(whereClause.query, whereClause.parameters); + if (condition.concat == "_" || condition.concat == "AND") { + query.andWhere(whereClause.query, whereClause.parameters); } else { - queryBuilder[whereMethod](whereClause.query, whereClause.parameters); + query.orWhere(whereClause.query, whereClause.parameters); + } + } else { + if (condition.concat == "AND") { + query.andWhere( + condition.invert == undefined || condition.invert == true + ? new Brackets((qb) => { + this.applyWhere(qb, condition.conditions, alias); + }) + : new NotBrackets((qb) => { + this.applyWhere(qb, condition.conditions, alias); + }) + ); + } else { + query.orWhere( + condition.invert == undefined || condition.invert == true + ? new Brackets((qb) => { + this.applyWhere(qb, condition.conditions, alias); + }) + : new NotBrackets((qb) => { + this.applyWhere(qb, condition.conditions, alias); + }) + ); } - } else if (condition.structureType === "nested") { - const nestedQuery = this.conditionsToQuery(condition.condition, alias); - const whereMethod = condition.concat === "OR" ? "orWhere" : "andWhere"; - - queryBuilder[whereMethod](`(${nestedQuery.query})`, nestedQuery.parameters); } - }); + } } - // Helper: Build a single condition clause - public static buildConditionClause( - condition: ConditionStructure, + private static buildConditionClause( + condition: ConditionStructure & { structureType: "condition" }, alias: string ): { query: string; parameters: Record } { - if (condition.structureType == "nested") return; const parameterKey = `${alias}_${condition.column}_${Math.random().toString(36).substring(2)}`; let query = `${alias}.${condition.column}`; let parameters: Record = {}; @@ -213,37 +203,8 @@ export default abstract class DynamicQueryBuilder { query += ` LIKE :${parameterKey}`; parameters[parameterKey] = `%${condition.value}`; break; - default: - throw new Error(`Unsupported operation: ${condition.operation}`); } return { query, parameters }; } - - // Helper: Convert nested conditions to a query - public static conditionsToQuery( - conditions: Array, - alias: string - ): { query: string; parameters: Record } { - let queryParts: string[] = []; - let parameters: Record = {}; - - conditions.forEach((condition, index) => { - if (condition.structureType === "condition") { - const clause = this.buildConditionClause(condition, alias); - queryParts.push(clause.query); - parameters = { ...parameters, ...clause.parameters }; - } else if (condition.structureType === "nested") { - const nested = this.conditionsToQuery(condition.condition, alias); - queryParts.push(`(${nested.query})`); - parameters = { ...parameters, ...nested.parameters }; - } - }); - - return { query: queryParts.join(" AND "), parameters }; - } - - // use switch... for compare functions - // use NotBrackets/Brackets for nested conditions - // use joins by requesting table schema and setting correct column } diff --git a/src/type/dynamicQueries.ts b/src/type/dynamicQueries.ts index 92f953c..5e69094 100644 --- a/src/type/dynamicQueries.ts +++ b/src/type/dynamicQueries.ts @@ -16,7 +16,7 @@ export type ConditionStructure = ( | { structureType: "nested"; invert?: boolean; - condition: Array; + conditions: Array; } ) & { concat: WhereType; @@ -52,7 +52,7 @@ export type OrderByStructure = { export type OrderByType = "ASC" | "DESC"; -const exampleQuery: DynamicQueryStructure = { +export const exampleQuery: DynamicQueryStructure = { select: ["firstname", "lastname"], table: "member", where: [ @@ -66,7 +66,7 @@ const exampleQuery: DynamicQueryStructure = { { structureType: "nested", concat: "AND", - condition: [ + conditions: [ { structureType: "condition", concat: "_",