@simplysm/orm-common 13.0.69 → 13.0.70

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (204) hide show
  1. package/README.md +54 -1447
  2. package/dist/create-db-context.d.ts +10 -10
  3. package/dist/create-db-context.js +9 -9
  4. package/dist/create-db-context.js.map +1 -1
  5. package/dist/ddl/column-ddl.d.ts +4 -4
  6. package/dist/ddl/initialize.d.ts +17 -17
  7. package/dist/ddl/initialize.js +2 -2
  8. package/dist/ddl/initialize.js.map +1 -1
  9. package/dist/ddl/relation-ddl.d.ts +6 -6
  10. package/dist/ddl/schema-ddl.d.ts +4 -4
  11. package/dist/ddl/table-ddl.d.ts +24 -24
  12. package/dist/ddl/table-ddl.js +4 -4
  13. package/dist/ddl/table-ddl.js.map +1 -1
  14. package/dist/errors/db-transaction-error.d.ts +15 -15
  15. package/dist/errors/db-transaction-error.d.ts.map +1 -1
  16. package/dist/exec/executable.d.ts +23 -23
  17. package/dist/exec/executable.js +3 -3
  18. package/dist/exec/executable.js.map +1 -1
  19. package/dist/exec/queryable.d.ts +160 -160
  20. package/dist/exec/queryable.js +119 -119
  21. package/dist/exec/queryable.js.map +1 -1
  22. package/dist/exec/search-parser.d.ts +37 -37
  23. package/dist/exec/search-parser.d.ts.map +1 -1
  24. package/dist/expr/expr-unit.d.ts +4 -4
  25. package/dist/expr/expr.d.ts +257 -257
  26. package/dist/expr/expr.js +265 -265
  27. package/dist/expr/expr.js.map +1 -1
  28. package/dist/query-builder/base/expr-renderer-base.d.ts +9 -9
  29. package/dist/query-builder/base/expr-renderer-base.js +2 -2
  30. package/dist/query-builder/base/expr-renderer-base.js.map +1 -1
  31. package/dist/query-builder/base/query-builder-base.d.ts +26 -26
  32. package/dist/query-builder/base/query-builder-base.d.ts.map +1 -1
  33. package/dist/query-builder/base/query-builder-base.js +22 -22
  34. package/dist/query-builder/base/query-builder-base.js.map +1 -1
  35. package/dist/query-builder/mssql/mssql-expr-renderer.d.ts +4 -4
  36. package/dist/query-builder/mssql/mssql-expr-renderer.d.ts.map +1 -1
  37. package/dist/query-builder/mssql/mssql-expr-renderer.js +18 -18
  38. package/dist/query-builder/mssql/mssql-expr-renderer.js.map +1 -1
  39. package/dist/query-builder/mssql/mssql-query-builder.d.ts +2 -2
  40. package/dist/query-builder/mssql/mssql-query-builder.d.ts.map +1 -1
  41. package/dist/query-builder/mssql/mssql-query-builder.js +11 -11
  42. package/dist/query-builder/mssql/mssql-query-builder.js.map +1 -1
  43. package/dist/query-builder/mysql/mysql-expr-renderer.d.ts +4 -4
  44. package/dist/query-builder/mysql/mysql-expr-renderer.d.ts.map +1 -1
  45. package/dist/query-builder/mysql/mysql-expr-renderer.js +17 -17
  46. package/dist/query-builder/mysql/mysql-expr-renderer.js.map +1 -1
  47. package/dist/query-builder/mysql/mysql-query-builder.d.ts +8 -8
  48. package/dist/query-builder/mysql/mysql-query-builder.d.ts.map +1 -1
  49. package/dist/query-builder/mysql/mysql-query-builder.js +5 -5
  50. package/dist/query-builder/mysql/mysql-query-builder.js.map +1 -1
  51. package/dist/query-builder/postgresql/postgresql-expr-renderer.d.ts +4 -4
  52. package/dist/query-builder/postgresql/postgresql-expr-renderer.d.ts.map +1 -1
  53. package/dist/query-builder/postgresql/postgresql-expr-renderer.js +17 -17
  54. package/dist/query-builder/postgresql/postgresql-expr-renderer.js.map +1 -1
  55. package/dist/query-builder/postgresql/postgresql-query-builder.d.ts +5 -5
  56. package/dist/query-builder/postgresql/postgresql-query-builder.d.ts.map +1 -1
  57. package/dist/query-builder/postgresql/postgresql-query-builder.js +8 -8
  58. package/dist/query-builder/postgresql/postgresql-query-builder.js.map +1 -1
  59. package/dist/query-builder/query-builder.d.ts +1 -1
  60. package/dist/schema/factory/column-builder.d.ts +79 -79
  61. package/dist/schema/factory/column-builder.js +42 -42
  62. package/dist/schema/factory/index-builder.d.ts +39 -39
  63. package/dist/schema/factory/index-builder.js +26 -26
  64. package/dist/schema/factory/relation-builder.d.ts +99 -99
  65. package/dist/schema/factory/relation-builder.d.ts.map +1 -1
  66. package/dist/schema/factory/relation-builder.js +38 -38
  67. package/dist/schema/procedure-builder.d.ts +49 -49
  68. package/dist/schema/procedure-builder.d.ts.map +1 -1
  69. package/dist/schema/procedure-builder.js +33 -33
  70. package/dist/schema/table-builder.d.ts +59 -59
  71. package/dist/schema/table-builder.d.ts.map +1 -1
  72. package/dist/schema/table-builder.js +43 -43
  73. package/dist/schema/view-builder.d.ts +49 -49
  74. package/dist/schema/view-builder.d.ts.map +1 -1
  75. package/dist/schema/view-builder.js +32 -32
  76. package/dist/types/column.d.ts +22 -22
  77. package/dist/types/column.js +1 -1
  78. package/dist/types/column.js.map +1 -1
  79. package/dist/types/db.d.ts +40 -40
  80. package/dist/types/expr.d.ts +59 -59
  81. package/dist/types/expr.d.ts.map +1 -1
  82. package/dist/types/query-def.d.ts +44 -44
  83. package/dist/types/query-def.d.ts.map +1 -1
  84. package/dist/utils/result-parser.d.ts +11 -11
  85. package/dist/utils/result-parser.js +3 -3
  86. package/dist/utils/result-parser.js.map +1 -1
  87. package/package.json +5 -5
  88. package/src/create-db-context.ts +20 -20
  89. package/src/ddl/column-ddl.ts +4 -4
  90. package/src/ddl/initialize.ts +259 -259
  91. package/src/ddl/relation-ddl.ts +89 -89
  92. package/src/ddl/schema-ddl.ts +4 -4
  93. package/src/ddl/table-ddl.ts +189 -189
  94. package/src/errors/db-transaction-error.ts +13 -13
  95. package/src/exec/executable.ts +25 -25
  96. package/src/exec/queryable.ts +2033 -2033
  97. package/src/exec/search-parser.ts +57 -57
  98. package/src/expr/expr-unit.ts +4 -4
  99. package/src/expr/expr.ts +2140 -2140
  100. package/src/query-builder/base/expr-renderer-base.ts +237 -237
  101. package/src/query-builder/base/query-builder-base.ts +213 -213
  102. package/src/query-builder/mssql/mssql-expr-renderer.ts +607 -607
  103. package/src/query-builder/mssql/mssql-query-builder.ts +650 -650
  104. package/src/query-builder/mysql/mysql-expr-renderer.ts +613 -613
  105. package/src/query-builder/mysql/mysql-query-builder.ts +759 -759
  106. package/src/query-builder/postgresql/postgresql-expr-renderer.ts +611 -611
  107. package/src/query-builder/postgresql/postgresql-query-builder.ts +686 -686
  108. package/src/query-builder/query-builder.ts +19 -19
  109. package/src/schema/factory/column-builder.ts +423 -423
  110. package/src/schema/factory/index-builder.ts +164 -164
  111. package/src/schema/factory/relation-builder.ts +453 -453
  112. package/src/schema/procedure-builder.ts +232 -232
  113. package/src/schema/table-builder.ts +319 -319
  114. package/src/schema/view-builder.ts +221 -221
  115. package/src/types/column.ts +188 -188
  116. package/src/types/db.ts +208 -208
  117. package/src/types/expr.ts +697 -697
  118. package/src/types/query-def.ts +513 -513
  119. package/src/utils/result-parser.ts +458 -458
  120. package/tests/db-context/create-db-context.spec.ts +224 -0
  121. package/tests/db-context/define-db-context.spec.ts +68 -0
  122. package/tests/ddl/basic.expected.ts +341 -0
  123. package/tests/ddl/basic.spec.ts +714 -0
  124. package/tests/ddl/column-builder.expected.ts +310 -0
  125. package/tests/ddl/column-builder.spec.ts +637 -0
  126. package/tests/ddl/index-builder.expected.ts +38 -0
  127. package/tests/ddl/index-builder.spec.ts +202 -0
  128. package/tests/ddl/procedure-builder.expected.ts +52 -0
  129. package/tests/ddl/procedure-builder.spec.ts +234 -0
  130. package/tests/ddl/relation-builder.expected.ts +36 -0
  131. package/tests/ddl/relation-builder.spec.ts +372 -0
  132. package/tests/ddl/table-builder.expected.ts +113 -0
  133. package/tests/ddl/table-builder.spec.ts +433 -0
  134. package/tests/ddl/view-builder.expected.ts +38 -0
  135. package/tests/ddl/view-builder.spec.ts +176 -0
  136. package/tests/dml/delete.expected.ts +96 -0
  137. package/tests/dml/delete.spec.ts +160 -0
  138. package/tests/dml/insert.expected.ts +192 -0
  139. package/tests/dml/insert.spec.ts +288 -0
  140. package/tests/dml/update.expected.ts +176 -0
  141. package/tests/dml/update.spec.ts +318 -0
  142. package/tests/dml/upsert.expected.ts +215 -0
  143. package/tests/dml/upsert.spec.ts +242 -0
  144. package/tests/errors/queryable-errors.spec.ts +177 -0
  145. package/tests/escape.spec.ts +100 -0
  146. package/tests/examples/pivot.expected.ts +211 -0
  147. package/tests/examples/pivot.spec.ts +533 -0
  148. package/tests/examples/sampling.expected.ts +69 -0
  149. package/tests/examples/sampling.spec.ts +104 -0
  150. package/tests/examples/unpivot.expected.ts +120 -0
  151. package/tests/examples/unpivot.spec.ts +226 -0
  152. package/tests/exec/search-parser.spec.ts +283 -0
  153. package/tests/executable/basic.expected.ts +18 -0
  154. package/tests/executable/basic.spec.ts +54 -0
  155. package/tests/expr/comparison.expected.ts +282 -0
  156. package/tests/expr/comparison.spec.ts +400 -0
  157. package/tests/expr/conditional.expected.ts +134 -0
  158. package/tests/expr/conditional.spec.ts +276 -0
  159. package/tests/expr/date.expected.ts +332 -0
  160. package/tests/expr/date.spec.ts +526 -0
  161. package/tests/expr/math.expected.ts +62 -0
  162. package/tests/expr/math.spec.ts +106 -0
  163. package/tests/expr/string.expected.ts +218 -0
  164. package/tests/expr/string.spec.ts +356 -0
  165. package/tests/expr/utility.expected.ts +147 -0
  166. package/tests/expr/utility.spec.ts +182 -0
  167. package/tests/select/basic.expected.ts +322 -0
  168. package/tests/select/basic.spec.ts +502 -0
  169. package/tests/select/filter.expected.ts +357 -0
  170. package/tests/select/filter.spec.ts +1068 -0
  171. package/tests/select/group.expected.ts +169 -0
  172. package/tests/select/group.spec.ts +244 -0
  173. package/tests/select/join.expected.ts +582 -0
  174. package/tests/select/join.spec.ts +805 -0
  175. package/tests/select/order.expected.ts +150 -0
  176. package/tests/select/order.spec.ts +189 -0
  177. package/tests/select/recursive-cte.expected.ts +244 -0
  178. package/tests/select/recursive-cte.spec.ts +514 -0
  179. package/tests/select/result-meta.spec.ts +270 -0
  180. package/tests/select/subquery.expected.ts +363 -0
  181. package/tests/select/subquery.spec.ts +537 -0
  182. package/tests/select/view.expected.ts +155 -0
  183. package/tests/select/view.spec.ts +235 -0
  184. package/tests/select/window.expected.ts +345 -0
  185. package/tests/select/window.spec.ts +618 -0
  186. package/tests/setup/MockExecutor.ts +18 -0
  187. package/tests/setup/TestDbContext.ts +59 -0
  188. package/tests/setup/models/Company.ts +13 -0
  189. package/tests/setup/models/Employee.ts +10 -0
  190. package/tests/setup/models/MonthlySales.ts +11 -0
  191. package/tests/setup/models/Post.ts +16 -0
  192. package/tests/setup/models/Sales.ts +10 -0
  193. package/tests/setup/models/User.ts +19 -0
  194. package/tests/setup/procedure/GetAllUsers.ts +9 -0
  195. package/tests/setup/procedure/GetUserById.ts +12 -0
  196. package/tests/setup/test-utils.ts +72 -0
  197. package/tests/setup/views/ActiveUsers.ts +8 -0
  198. package/tests/setup/views/UserSummary.ts +11 -0
  199. package/tests/types/nullable-queryable-record.spec.ts +145 -0
  200. package/tests/utils/result-parser-perf.spec.ts +210 -0
  201. package/tests/utils/result-parser.spec.ts +701 -0
  202. package/docs/expressions.md +0 -172
  203. package/docs/queries.md +0 -444
  204. package/docs/schema.md +0 -245
@@ -0,0 +1,169 @@
1
+ /**
2
+ * SELECT - GROUP BY / HAVING test expected SQL
3
+ */
4
+ import { mysql, pgsql, tsql } from "@simplysm/core-common";
5
+ import type { ExpectedSql } from "../setup/test-utils";
6
+
7
+ //#region ========== GROUP BY ==========
8
+
9
+ export const groupSingle: ExpectedSql = {
10
+ mysql: mysql`
11
+ SELECT \`T1\`.\`name\` AS \`name\`, COUNT(\`T1\`.\`id\`) AS \`cnt\`
12
+ FROM \`TestDb\`.\`User\` AS \`T1\`
13
+ GROUP BY \`T1\`.\`name\`
14
+ `,
15
+ mssql: tsql`
16
+ SELECT [T1].[name] AS [name], COUNT([T1].[id]) AS [cnt]
17
+ FROM [TestDb].[TestSchema].[User] AS [T1]
18
+ GROUP BY [T1].[name]
19
+ `,
20
+ postgresql: pgsql`
21
+ SELECT "T1"."name" AS "name", COUNT("T1"."id") AS "cnt"
22
+ FROM "TestSchema"."User" AS "T1"
23
+ GROUP BY "T1"."name"
24
+ `,
25
+ };
26
+
27
+ export const groupMultiple: ExpectedSql = {
28
+ mysql: mysql`
29
+ SELECT
30
+ \`T1\`.\`name\` AS \`name\`,
31
+ \`T1\`.\`isActive\` AS \`isActive\`,
32
+ COUNT(\`T1\`.\`id\`) AS \`cnt\`
33
+ FROM \`TestDb\`.\`User\` AS \`T1\`
34
+ GROUP BY \`T1\`.\`name\`, \`T1\`.\`isActive\`
35
+ `,
36
+ mssql: tsql`
37
+ SELECT
38
+ [T1].[name] AS [name],
39
+ [T1].[isActive] AS [isActive],
40
+ COUNT([T1].[id]) AS [cnt]
41
+ FROM [TestDb].[TestSchema].[User] AS [T1]
42
+ GROUP BY [T1].[name], [T1].[isActive]
43
+ `,
44
+ postgresql: pgsql`
45
+ SELECT
46
+ "T1"."name" AS "name",
47
+ "T1"."isActive" AS "isActive",
48
+ COUNT("T1"."id") AS "cnt"
49
+ FROM "TestSchema"."User" AS "T1"
50
+ GROUP BY "T1"."name", "T1"."isActive"
51
+ `,
52
+ };
53
+
54
+ export const groupAggregate: ExpectedSql = {
55
+ mysql: mysql`
56
+ SELECT
57
+ \`T1\`.\`name\` AS \`name\`,
58
+ COUNT(\`T1\`.\`id\`) AS \`cnt\`,
59
+ SUM(\`T1\`.\`age\`) AS \`sumAge\`,
60
+ AVG(\`T1\`.\`age\`) AS \`avgAge\`,
61
+ MIN(\`T1\`.\`age\`) AS \`minAge\`,
62
+ MAX(\`T1\`.\`age\`) AS \`maxAge\`
63
+ FROM \`TestDb\`.\`User\` AS \`T1\`
64
+ GROUP BY \`T1\`.\`name\`
65
+ `,
66
+ mssql: tsql`
67
+ SELECT
68
+ [T1].[name] AS [name],
69
+ COUNT([T1].[id]) AS [cnt],
70
+ SUM([T1].[age]) AS [sumAge],
71
+ AVG([T1].[age]) AS [avgAge],
72
+ MIN([T1].[age]) AS [minAge],
73
+ MAX([T1].[age]) AS [maxAge]
74
+ FROM [TestDb].[TestSchema].[User] AS [T1]
75
+ GROUP BY [T1].[name]
76
+ `,
77
+ postgresql: pgsql`
78
+ SELECT
79
+ "T1"."name" AS "name",
80
+ COUNT("T1"."id") AS "cnt",
81
+ SUM("T1"."age") AS "sumAge",
82
+ AVG("T1"."age") AS "avgAge",
83
+ MIN("T1"."age") AS "minAge",
84
+ MAX("T1"."age") AS "maxAge"
85
+ FROM "TestSchema"."User" AS "T1"
86
+ GROUP BY "T1"."name"
87
+ `,
88
+ };
89
+
90
+ //#endregion
91
+
92
+ //#region ========== HAVING ==========
93
+
94
+ export const havingSingle: ExpectedSql = {
95
+ mysql: mysql`
96
+ SELECT \`T1\`.\`name\` AS \`name\`, COUNT(\`T1\`.\`id\`) AS \`cnt\`
97
+ FROM \`TestDb\`.\`User\` AS \`T1\`
98
+ GROUP BY \`T1\`.\`name\`
99
+ HAVING COUNT(\`T1\`.\`id\`) > 5
100
+ `,
101
+ mssql: tsql`
102
+ SELECT [T1].[name] AS [name], COUNT([T1].[id]) AS [cnt]
103
+ FROM [TestDb].[TestSchema].[User] AS [T1]
104
+ GROUP BY [T1].[name]
105
+ HAVING COUNT([T1].[id]) > 5
106
+ `,
107
+ postgresql: pgsql`
108
+ SELECT "T1"."name" AS "name", COUNT("T1"."id") AS "cnt"
109
+ FROM "TestSchema"."User" AS "T1"
110
+ GROUP BY "T1"."name"
111
+ HAVING COUNT("T1"."id") > 5
112
+ `,
113
+ };
114
+
115
+ export const havingMultiple: ExpectedSql = {
116
+ mysql: mysql`
117
+ SELECT
118
+ \`T1\`.\`name\` AS \`name\`,
119
+ COUNT(\`T1\`.\`id\`) AS \`cnt\`,
120
+ AVG(\`T1\`.\`age\`) AS \`avgAge\`
121
+ FROM \`TestDb\`.\`User\` AS \`T1\`
122
+ GROUP BY \`T1\`.\`name\`
123
+ HAVING COUNT(\`T1\`.\`id\`) > 5 AND AVG(\`T1\`.\`age\`) >= 25
124
+ `,
125
+ mssql: tsql`
126
+ SELECT
127
+ [T1].[name] AS [name],
128
+ COUNT([T1].[id]) AS [cnt],
129
+ AVG([T1].[age]) AS [avgAge]
130
+ FROM [TestDb].[TestSchema].[User] AS [T1]
131
+ GROUP BY [T1].[name]
132
+ HAVING COUNT([T1].[id]) > 5 AND AVG([T1].[age]) >= 25
133
+ `,
134
+ postgresql: pgsql`
135
+ SELECT
136
+ "T1"."name" AS "name",
137
+ COUNT("T1"."id") AS "cnt",
138
+ AVG("T1"."age") AS "avgAge"
139
+ FROM "TestSchema"."User" AS "T1"
140
+ GROUP BY "T1"."name"
141
+ HAVING COUNT("T1"."id") > 5 AND AVG("T1"."age") >= 25
142
+ `,
143
+ };
144
+
145
+ export const havingOrderCombo: ExpectedSql = {
146
+ mysql: mysql`
147
+ SELECT \`T1\`.\`name\` AS \`name\`, COUNT(\`T1\`.\`id\`) AS \`cnt\`
148
+ FROM \`TestDb\`.\`User\` AS \`T1\`
149
+ GROUP BY \`T1\`.\`name\`
150
+ HAVING COUNT(\`T1\`.\`id\`) > 1
151
+ ORDER BY COUNT(\`T1\`.\`id\`) DESC
152
+ `,
153
+ mssql: tsql`
154
+ SELECT [T1].[name] AS [name], COUNT([T1].[id]) AS [cnt]
155
+ FROM [TestDb].[TestSchema].[User] AS [T1]
156
+ GROUP BY [T1].[name]
157
+ HAVING COUNT([T1].[id]) > 1
158
+ ORDER BY COUNT([T1].[id]) DESC
159
+ `,
160
+ postgresql: pgsql`
161
+ SELECT "T1"."name" AS "name", COUNT("T1"."id") AS "cnt"
162
+ FROM "TestSchema"."User" AS "T1"
163
+ GROUP BY "T1"."name"
164
+ HAVING COUNT("T1"."id") > 1
165
+ ORDER BY COUNT("T1"."id") DESC
166
+ `,
167
+ };
168
+
169
+ //#endregion
@@ -0,0 +1,244 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { createTestDb } from "../setup/TestDbContext";
3
+ import { expr } from "../../src/expr/expr";
4
+ import { createQueryBuilder } from "../../src/query-builder/query-builder";
5
+ import { dialects } from "../setup/test-utils";
6
+ import * as expected from "./group.expected";
7
+
8
+ describe("SELECT - GROUP BY", () => {
9
+ //#region ========== Basic GROUP BY ==========
10
+
11
+ describe("single column", () => {
12
+ const db = createTestDb();
13
+ const def = db
14
+ .user()
15
+ .select((item) => ({
16
+ name: item.name,
17
+ cnt: expr.count(item.id),
18
+ }))
19
+ .groupBy((item) => [item.name])
20
+ .getSelectQueryDef();
21
+
22
+ it("Verify QueryDef", () => {
23
+ expect(def).toEqual({
24
+ type: "select",
25
+ as: "T1",
26
+ from: { database: "TestDb", schema: "TestSchema", name: "User" },
27
+ select: {
28
+ name: { type: "column", path: ["T1", "name"] },
29
+ cnt: { type: "count", arg: { type: "column", path: ["T1", "id"] } },
30
+ },
31
+ groupBy: [{ type: "column", path: ["T1", "name"] }],
32
+ });
33
+ });
34
+
35
+ it.each(dialects)("[%s] Verify SQL", (dialect) => {
36
+ const builder = createQueryBuilder(dialect);
37
+ expect(builder.build(def)).toMatchSql(expected.groupSingle[dialect]);
38
+ });
39
+ });
40
+
41
+ describe("multiple columns", () => {
42
+ const db = createTestDb();
43
+ const def = db
44
+ .user()
45
+ .select((item) => ({
46
+ name: item.name,
47
+ isActive: item.isActive,
48
+ cnt: expr.count(item.id),
49
+ }))
50
+ .groupBy((item) => [item.name, item.isActive])
51
+ .getSelectQueryDef();
52
+
53
+ it("Verify QueryDef", () => {
54
+ expect(def).toEqual({
55
+ type: "select",
56
+ as: "T1",
57
+ from: { database: "TestDb", schema: "TestSchema", name: "User" },
58
+ select: {
59
+ name: { type: "column", path: ["T1", "name"] },
60
+ isActive: { type: "column", path: ["T1", "isActive"] },
61
+ cnt: { type: "count", arg: { type: "column", path: ["T1", "id"] } },
62
+ },
63
+ groupBy: [
64
+ { type: "column", path: ["T1", "name"] },
65
+ { type: "column", path: ["T1", "isActive"] },
66
+ ],
67
+ });
68
+ });
69
+
70
+ it.each(dialects)("[%s] Verify SQL", (dialect) => {
71
+ const builder = createQueryBuilder(dialect);
72
+ expect(builder.build(def)).toMatchSql(expected.groupMultiple[dialect]);
73
+ });
74
+ });
75
+
76
+ describe("aggregate functions", () => {
77
+ const db = createTestDb();
78
+ const def = db
79
+ .user()
80
+ .select((item) => ({
81
+ name: item.name,
82
+ cnt: expr.count(item.id),
83
+ sumAge: expr.sum(item.age),
84
+ avgAge: expr.avg(item.age),
85
+ minAge: expr.min(item.age),
86
+ maxAge: expr.max(item.age),
87
+ }))
88
+ .groupBy((item) => [item.name])
89
+ .getSelectQueryDef();
90
+
91
+ it("Verify QueryDef", () => {
92
+ expect(def).toEqual({
93
+ type: "select",
94
+ as: "T1",
95
+ from: { database: "TestDb", schema: "TestSchema", name: "User" },
96
+ select: {
97
+ name: { type: "column", path: ["T1", "name"] },
98
+ cnt: { type: "count", arg: { type: "column", path: ["T1", "id"] } },
99
+ sumAge: { type: "sum", arg: { type: "column", path: ["T1", "age"] } },
100
+ avgAge: { type: "avg", arg: { type: "column", path: ["T1", "age"] } },
101
+ minAge: { type: "min", arg: { type: "column", path: ["T1", "age"] } },
102
+ maxAge: { type: "max", arg: { type: "column", path: ["T1", "age"] } },
103
+ },
104
+ groupBy: [{ type: "column", path: ["T1", "name"] }],
105
+ });
106
+ });
107
+
108
+ it.each(dialects)("[%s] Verify SQL", (dialect) => {
109
+ const builder = createQueryBuilder(dialect);
110
+ expect(builder.build(def)).toMatchSql(expected.groupAggregate[dialect]);
111
+ });
112
+ });
113
+
114
+ //#endregion
115
+ });
116
+
117
+ describe("SELECT - HAVING", () => {
118
+ //#region ========== HAVING ==========
119
+
120
+ describe("single condition", () => {
121
+ const db = createTestDb();
122
+ const def = db
123
+ .user()
124
+ .select((item) => ({
125
+ name: item.name,
126
+ cnt: expr.count(item.id),
127
+ }))
128
+ .groupBy((item) => [item.name])
129
+ .having((item) => [expr.gt(item.cnt, 5)])
130
+ .getSelectQueryDef();
131
+
132
+ it("Verify QueryDef", () => {
133
+ expect(def).toEqual({
134
+ type: "select",
135
+ as: "T1",
136
+ from: { database: "TestDb", schema: "TestSchema", name: "User" },
137
+ select: {
138
+ name: { type: "column", path: ["T1", "name"] },
139
+ cnt: { type: "count", arg: { type: "column", path: ["T1", "id"] } },
140
+ },
141
+ groupBy: [{ type: "column", path: ["T1", "name"] }],
142
+ having: [
143
+ {
144
+ type: "gt",
145
+ source: { type: "count", arg: { type: "column", path: ["T1", "id"] } },
146
+ target: { type: "value", value: 5 },
147
+ },
148
+ ],
149
+ });
150
+ });
151
+
152
+ it.each(dialects)("[%s] Verify SQL", (dialect) => {
153
+ const builder = createQueryBuilder(dialect);
154
+ expect(builder.build(def)).toMatchSql(expected.havingSingle[dialect]);
155
+ });
156
+ });
157
+
158
+ describe("multiple conditions", () => {
159
+ const db = createTestDb();
160
+ const def = db
161
+ .user()
162
+ .select((item) => ({
163
+ name: item.name,
164
+ cnt: expr.count(item.id),
165
+ avgAge: expr.avg(item.age),
166
+ }))
167
+ .groupBy((item) => [item.name])
168
+ .having((item) => [expr.gt(item.cnt, 5), expr.gte(item.avgAge, 25)])
169
+ .getSelectQueryDef();
170
+
171
+ it("Verify QueryDef", () => {
172
+ expect(def).toEqual({
173
+ type: "select",
174
+ as: "T1",
175
+ from: { database: "TestDb", schema: "TestSchema", name: "User" },
176
+ select: {
177
+ name: { type: "column", path: ["T1", "name"] },
178
+ cnt: { type: "count", arg: { type: "column", path: ["T1", "id"] } },
179
+ avgAge: { type: "avg", arg: { type: "column", path: ["T1", "age"] } },
180
+ },
181
+ groupBy: [{ type: "column", path: ["T1", "name"] }],
182
+ having: [
183
+ {
184
+ type: "gt",
185
+ source: { type: "count", arg: { type: "column", path: ["T1", "id"] } },
186
+ target: { type: "value", value: 5 },
187
+ },
188
+ {
189
+ type: "gte",
190
+ source: { type: "avg", arg: { type: "column", path: ["T1", "age"] } },
191
+ target: { type: "value", value: 25 },
192
+ },
193
+ ],
194
+ });
195
+ });
196
+
197
+ it.each(dialects)("[%s] Verify SQL", (dialect) => {
198
+ const builder = createQueryBuilder(dialect);
199
+ expect(builder.build(def)).toMatchSql(expected.havingMultiple[dialect]);
200
+ });
201
+ });
202
+
203
+ describe("GROUP BY + HAVING + ORDER BY combination", () => {
204
+ const db = createTestDb();
205
+ const def = db
206
+ .user()
207
+ .select((item) => ({
208
+ name: item.name,
209
+ cnt: expr.count(item.id),
210
+ }))
211
+ .groupBy((item) => [item.name])
212
+ .having((item) => [expr.gt(item.cnt, 1)])
213
+ .orderBy((item) => item.cnt, "DESC")
214
+ .getSelectQueryDef();
215
+
216
+ it("Verify QueryDef", () => {
217
+ expect(def).toEqual({
218
+ type: "select",
219
+ as: "T1",
220
+ from: { database: "TestDb", schema: "TestSchema", name: "User" },
221
+ select: {
222
+ name: { type: "column", path: ["T1", "name"] },
223
+ cnt: { type: "count", arg: { type: "column", path: ["T1", "id"] } },
224
+ },
225
+ groupBy: [{ type: "column", path: ["T1", "name"] }],
226
+ having: [
227
+ {
228
+ type: "gt",
229
+ source: { type: "count", arg: { type: "column", path: ["T1", "id"] } },
230
+ target: { type: "value", value: 1 },
231
+ },
232
+ ],
233
+ orderBy: [[{ type: "count", arg: { type: "column", path: ["T1", "id"] } }, "DESC"]],
234
+ });
235
+ });
236
+
237
+ it.each(dialects)("[%s] Verify SQL", (dialect) => {
238
+ const builder = createQueryBuilder(dialect);
239
+ expect(builder.build(def)).toMatchSql(expected.havingOrderCombo[dialect]);
240
+ });
241
+ });
242
+
243
+ //#endregion
244
+ });