diff --git a/src/lib/build.ts b/src/lib/build.ts index a7da4e9..9feee8b 100644 --- a/src/lib/build.ts +++ b/src/lib/build.ts @@ -37,6 +37,7 @@ export function buildSelectQuery( select: "", where: query.where, groupBy: query.groupBy, + having: query.having, orderBy: query.orderBy, limit: query.limit, offset: query.offset, @@ -213,6 +214,9 @@ export function sql( if (params.groupBy && params.groupBy.length > 0) { sql += ` GROUP BY ${group(params.groupBy)}`; } + if (params.having && Object.keys(params.having).length > 0) { + sql += ` HAVING ${where(params.having, "AND", params.relations || {})}`; + } if (params.orderBy && Object.keys(params.orderBy).length > 0) { sql += ` ORDER BY ${order(params.orderBy)}`; } diff --git a/src/lib/types.ts b/src/lib/types.ts index f5d875b..f08d6be 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -71,6 +71,7 @@ export type IncludeQuery = { offset?: number; include?: Include; groupBy?: string[]; + having?: QueryHavingCondition; orderBy?: OrderBy; leftJoin?: Join; rightJoin?: Join; @@ -95,6 +96,7 @@ export type SelectQuery = { offset?: number; include?: Include; groupBy?: string[]; + having?: QueryHavingCondition; orderBy?: OrderBy; leftJoin?: Join; rightJoin?: Join; @@ -135,6 +137,10 @@ export type NestedWhereCondition = { export type QueryWhereCondition = WhereCondition | NestedWhereCondition; +export type QueryHavingCondition = + | WhereCondition + | Omit; + export type SelectType = "simple" | "aggregated" | "object"; export type SqlParams = { @@ -146,6 +152,7 @@ export type SqlParams = { limit?: number; offset?: number; groupBy?: GroupBy; + having?: QueryHavingCondition; orderBy?: OrderBy; relations?: Relations; returning?: Array; diff --git a/src/test/build.test.ts b/src/test/build.test.ts index a80a73e..ced53b4 100644 --- a/src/test/build.test.ts +++ b/src/test/build.test.ts @@ -81,6 +81,9 @@ describe("sql", () => { join: " JOIN other_table ON table.id = other_table.table_id", where: { id: 1 }, groupBy: ["name"], + having: { + 'COUNT("name")': 1, + }, orderBy: { name: "ASC" }, limit: 10, offset: 5, @@ -92,7 +95,7 @@ describe("sql", () => { }; const result = sql(params, append); expect(result).toBe( - 'SELECT * FROM table JOIN other_table ON table.id = other_table.table_id JOIN another_table ON table.id = another_table.table_id WHERE "id" = 1 AND other_table.name = "test" GROUP BY "name" ORDER BY "name" ASC LIMIT 10 OFFSET 5 RETURNING "id", "name"', + `SELECT * FROM table JOIN other_table ON table.id = other_table.table_id JOIN another_table ON table.id = another_table.table_id WHERE "id" = 1 AND other_table.name = "test" GROUP BY "name" HAVING COUNT("name") = 1 ORDER BY "name" ASC LIMIT 10 OFFSET 5 RETURNING "id", "name"`, ); }); });