@simplysm/orm-common 13.0.68 → 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,526 @@
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 "../setup/test-utils"; // toMatchSql matcher
7
+ import * as expected from "./date.expected";
8
+ import { DateTime } from "@simplysm/core-common";
9
+
10
+ describe("Expr - Date/Time functions", () => {
11
+ describe("year - extract year", () => {
12
+ const db = createTestDb();
13
+ const def = db
14
+ .user()
15
+ .select((item) => ({
16
+ yearPart: expr.year(item.createdAt),
17
+ }))
18
+ .getSelectQueryDef();
19
+
20
+ it("Verify QueryDef", () => {
21
+ expect(def.select).toMatchObject({
22
+ yearPart: {
23
+ type: "year",
24
+ arg: { type: "column", path: ["T1", "createdAt"] },
25
+ },
26
+ });
27
+ });
28
+
29
+ it.each(dialects)("[%s] Verify SQL", (dialect) => {
30
+ const builder = createQueryBuilder(dialect);
31
+ expect(builder.build(def)).toMatchSql(expected.year[dialect]);
32
+ });
33
+ });
34
+
35
+ describe("month - extract month", () => {
36
+ const db = createTestDb();
37
+ const def = db
38
+ .user()
39
+ .select((item) => ({
40
+ monthPart: expr.month(item.createdAt),
41
+ }))
42
+ .getSelectQueryDef();
43
+
44
+ it("Verify QueryDef", () => {
45
+ expect(def.select).toMatchObject({
46
+ monthPart: {
47
+ type: "month",
48
+ arg: { type: "column", path: ["T1", "createdAt"] },
49
+ },
50
+ });
51
+ });
52
+
53
+ it.each(dialects)("[%s] Verify SQL", (dialect) => {
54
+ const builder = createQueryBuilder(dialect);
55
+ expect(builder.build(def)).toMatchSql(expected.month[dialect]);
56
+ });
57
+ });
58
+
59
+ describe("day - extract day", () => {
60
+ const db = createTestDb();
61
+ const def = db
62
+ .user()
63
+ .select((item) => ({
64
+ dayPart: expr.day(item.createdAt),
65
+ }))
66
+ .getSelectQueryDef();
67
+
68
+ it("Verify QueryDef", () => {
69
+ expect(def.select).toMatchObject({
70
+ dayPart: {
71
+ type: "day",
72
+ arg: { type: "column", path: ["T1", "createdAt"] },
73
+ },
74
+ });
75
+ });
76
+
77
+ it.each(dialects)("[%s] Verify SQL", (dialect) => {
78
+ const builder = createQueryBuilder(dialect);
79
+ expect(builder.build(def)).toMatchSql(expected.day[dialect]);
80
+ });
81
+ });
82
+
83
+ describe("hour - extract hour", () => {
84
+ const db = createTestDb();
85
+ const def = db
86
+ .user()
87
+ .select((item) => ({
88
+ hourPart: expr.hour(item.createdAt),
89
+ }))
90
+ .getSelectQueryDef();
91
+
92
+ it("Verify QueryDef", () => {
93
+ expect(def.select).toMatchObject({
94
+ hourPart: {
95
+ type: "hour",
96
+ arg: { type: "column", path: ["T1", "createdAt"] },
97
+ },
98
+ });
99
+ });
100
+
101
+ it.each(dialects)("[%s] Verify SQL", (dialect) => {
102
+ const builder = createQueryBuilder(dialect);
103
+ expect(builder.build(def)).toMatchSql(expected.hour[dialect]);
104
+ });
105
+ });
106
+
107
+ describe("minute - extract minute", () => {
108
+ const db = createTestDb();
109
+ const def = db
110
+ .user()
111
+ .select((item) => ({
112
+ minutePart: expr.minute(item.createdAt),
113
+ }))
114
+ .getSelectQueryDef();
115
+
116
+ it("Verify QueryDef", () => {
117
+ expect(def.select).toMatchObject({
118
+ minutePart: {
119
+ type: "minute",
120
+ arg: { type: "column", path: ["T1", "createdAt"] },
121
+ },
122
+ });
123
+ });
124
+
125
+ it.each(dialects)("[%s] Verify SQL", (dialect) => {
126
+ const builder = createQueryBuilder(dialect);
127
+ expect(builder.build(def)).toMatchSql(expected.minute[dialect]);
128
+ });
129
+ });
130
+
131
+ describe("second - extract second", () => {
132
+ const db = createTestDb();
133
+ const def = db
134
+ .user()
135
+ .select((item) => ({
136
+ secondPart: expr.second(item.createdAt),
137
+ }))
138
+ .getSelectQueryDef();
139
+
140
+ it("Verify QueryDef", () => {
141
+ expect(def.select).toMatchObject({
142
+ secondPart: {
143
+ type: "second",
144
+ arg: { type: "column", path: ["T1", "createdAt"] },
145
+ },
146
+ });
147
+ });
148
+
149
+ it.each(dialects)("[%s] Verify SQL", (dialect) => {
150
+ const builder = createQueryBuilder(dialect);
151
+ expect(builder.build(def)).toMatchSql(expected.second[dialect]);
152
+ });
153
+ });
154
+
155
+ describe("dateDiff - date difference (days)", () => {
156
+ const db = createTestDb();
157
+ const targetDate = new DateTime(2024, 1, 1);
158
+ const def = db
159
+ .user()
160
+ .select((item) => ({
161
+ daysDiff: expr.dateDiff("day", item.createdAt, targetDate),
162
+ }))
163
+ .getSelectQueryDef();
164
+
165
+ it("Verify QueryDef", () => {
166
+ expect(def.select).toMatchObject({
167
+ daysDiff: {
168
+ type: "dateDiff",
169
+ separator: "day",
170
+ from: { type: "column", path: ["T1", "createdAt"] },
171
+ to: { type: "value", value: targetDate },
172
+ },
173
+ });
174
+ });
175
+
176
+ it.each(dialects)("[%s] Verify SQL", (dialect) => {
177
+ const builder = createQueryBuilder(dialect);
178
+ expect(builder.build(def)).toMatchSql(expected.dateDiffDay[dialect]);
179
+ });
180
+ });
181
+
182
+ describe("dateDiff - date difference (years)", () => {
183
+ const db = createTestDb();
184
+ const targetDate = new DateTime(2024, 1, 1);
185
+ const def = db
186
+ .user()
187
+ .select((item) => ({
188
+ yearsDiff: expr.dateDiff("year", item.createdAt, targetDate),
189
+ }))
190
+ .getSelectQueryDef();
191
+
192
+ it("Verify QueryDef", () => {
193
+ expect(def.select).toMatchObject({
194
+ yearsDiff: {
195
+ type: "dateDiff",
196
+ separator: "year",
197
+ from: { type: "column", path: ["T1", "createdAt"] },
198
+ to: { type: "value", value: targetDate },
199
+ },
200
+ });
201
+ });
202
+
203
+ it.each(dialects)("[%s] Verify SQL", (dialect) => {
204
+ const builder = createQueryBuilder(dialect);
205
+ expect(builder.build(def)).toMatchSql(expected.dateDiffYear[dialect]);
206
+ });
207
+ });
208
+
209
+ describe("dateDiff - date difference (months)", () => {
210
+ const db = createTestDb();
211
+ const targetDate = new DateTime(2024, 1, 1);
212
+ const def = db
213
+ .user()
214
+ .select((item) => ({
215
+ monthsDiff: expr.dateDiff("month", item.createdAt, targetDate),
216
+ }))
217
+ .getSelectQueryDef();
218
+
219
+ it("Verify QueryDef", () => {
220
+ expect(def.select).toMatchObject({
221
+ monthsDiff: {
222
+ type: "dateDiff",
223
+ separator: "month",
224
+ from: { type: "column", path: ["T1", "createdAt"] },
225
+ to: { type: "value", value: targetDate },
226
+ },
227
+ });
228
+ });
229
+
230
+ it.each(dialects)("[%s] Verify SQL", (dialect) => {
231
+ const builder = createQueryBuilder(dialect);
232
+ expect(builder.build(def)).toMatchSql(expected.dateDiffMonth[dialect]);
233
+ });
234
+ });
235
+
236
+ describe("dateDiff - date difference (hours)", () => {
237
+ const db = createTestDb();
238
+ const targetDate = new DateTime(2024, 1, 1);
239
+ const def = db
240
+ .user()
241
+ .select((item) => ({
242
+ hoursDiff: expr.dateDiff("hour", item.createdAt, targetDate),
243
+ }))
244
+ .getSelectQueryDef();
245
+
246
+ it("Verify QueryDef", () => {
247
+ expect(def.select).toMatchObject({
248
+ hoursDiff: {
249
+ type: "dateDiff",
250
+ separator: "hour",
251
+ from: { type: "column", path: ["T1", "createdAt"] },
252
+ to: { type: "value", value: targetDate },
253
+ },
254
+ });
255
+ });
256
+
257
+ it.each(dialects)("[%s] Verify SQL", (dialect) => {
258
+ const builder = createQueryBuilder(dialect);
259
+ expect(builder.build(def)).toMatchSql(expected.dateDiffHour[dialect]);
260
+ });
261
+ });
262
+
263
+ describe("dateDiff - date difference (minutes)", () => {
264
+ const db = createTestDb();
265
+ const targetDate = new DateTime(2024, 1, 1);
266
+ const def = db
267
+ .user()
268
+ .select((item) => ({
269
+ minutesDiff: expr.dateDiff("minute", item.createdAt, targetDate),
270
+ }))
271
+ .getSelectQueryDef();
272
+
273
+ it("Verify QueryDef", () => {
274
+ expect(def.select).toMatchObject({
275
+ minutesDiff: {
276
+ type: "dateDiff",
277
+ separator: "minute",
278
+ from: { type: "column", path: ["T1", "createdAt"] },
279
+ to: { type: "value", value: targetDate },
280
+ },
281
+ });
282
+ });
283
+
284
+ it.each(dialects)("[%s] Verify SQL", (dialect) => {
285
+ const builder = createQueryBuilder(dialect);
286
+ expect(builder.build(def)).toMatchSql(expected.dateDiffMinute[dialect]);
287
+ });
288
+ });
289
+
290
+ describe("dateDiff - date difference (seconds)", () => {
291
+ const db = createTestDb();
292
+ const targetDate = new DateTime(2024, 1, 1);
293
+ const def = db
294
+ .user()
295
+ .select((item) => ({
296
+ secondsDiff: expr.dateDiff("second", item.createdAt, targetDate),
297
+ }))
298
+ .getSelectQueryDef();
299
+
300
+ it("Verify QueryDef", () => {
301
+ expect(def.select).toMatchObject({
302
+ secondsDiff: {
303
+ type: "dateDiff",
304
+ separator: "second",
305
+ from: { type: "column", path: ["T1", "createdAt"] },
306
+ to: { type: "value", value: targetDate },
307
+ },
308
+ });
309
+ });
310
+
311
+ it.each(dialects)("[%s] Verify SQL", (dialect) => {
312
+ const builder = createQueryBuilder(dialect);
313
+ expect(builder.build(def)).toMatchSql(expected.dateDiffSecond[dialect]);
314
+ });
315
+ });
316
+
317
+ describe("dateAdd - add date (months)", () => {
318
+ const db = createTestDb();
319
+ const def = db
320
+ .user()
321
+ .select((item) => ({
322
+ nextMonth: expr.dateAdd("month", item.createdAt, 1),
323
+ }))
324
+ .getSelectQueryDef();
325
+
326
+ it("Verify QueryDef", () => {
327
+ expect(def.select).toMatchObject({
328
+ nextMonth: {
329
+ type: "dateAdd",
330
+ separator: "month",
331
+ source: { type: "column", path: ["T1", "createdAt"] },
332
+ value: { type: "value", value: 1 },
333
+ },
334
+ });
335
+ });
336
+
337
+ it.each(dialects)("[%s] Verify SQL", (dialect) => {
338
+ const builder = createQueryBuilder(dialect);
339
+ expect(builder.build(def)).toMatchSql(expected.dateAddMonth[dialect]);
340
+ });
341
+ });
342
+
343
+ describe("dateAdd - add date (years)", () => {
344
+ const db = createTestDb();
345
+ const def = db
346
+ .user()
347
+ .select((item) => ({
348
+ nextYear: expr.dateAdd("year", item.createdAt, 1),
349
+ }))
350
+ .getSelectQueryDef();
351
+
352
+ it.each(dialects)("[%s] Verify SQL", (dialect) => {
353
+ const builder = createQueryBuilder(dialect);
354
+ expect(builder.build(def)).toMatchSql(expected.dateAddYear[dialect]);
355
+ });
356
+ });
357
+
358
+ describe("dateAdd - add date (days)", () => {
359
+ const db = createTestDb();
360
+ const def = db
361
+ .user()
362
+ .select((item) => ({
363
+ nextWeek: expr.dateAdd("day", item.createdAt, 7),
364
+ }))
365
+ .getSelectQueryDef();
366
+
367
+ it.each(dialects)("[%s] Verify SQL", (dialect) => {
368
+ const builder = createQueryBuilder(dialect);
369
+ expect(builder.build(def)).toMatchSql(expected.dateAddDay[dialect]);
370
+ });
371
+ });
372
+
373
+ describe("dateAdd - add date (hours)", () => {
374
+ const db = createTestDb();
375
+ const def = db
376
+ .user()
377
+ .select((item) => ({
378
+ twoHoursLater: expr.dateAdd("hour", item.createdAt, 2),
379
+ }))
380
+ .getSelectQueryDef();
381
+
382
+ it.each(dialects)("[%s] Verify SQL", (dialect) => {
383
+ const builder = createQueryBuilder(dialect);
384
+ expect(builder.build(def)).toMatchSql(expected.dateAddHour[dialect]);
385
+ });
386
+ });
387
+
388
+ describe("dateAdd - add date (minutes)", () => {
389
+ const db = createTestDb();
390
+ const def = db
391
+ .user()
392
+ .select((item) => ({
393
+ thirtyMinLater: expr.dateAdd("minute", item.createdAt, 30),
394
+ }))
395
+ .getSelectQueryDef();
396
+
397
+ it.each(dialects)("[%s] Verify SQL", (dialect) => {
398
+ const builder = createQueryBuilder(dialect);
399
+ expect(builder.build(def)).toMatchSql(expected.dateAddMinute[dialect]);
400
+ });
401
+ });
402
+
403
+ describe("dateAdd - add date (seconds)", () => {
404
+ const db = createTestDb();
405
+ const def = db
406
+ .user()
407
+ .select((item) => ({
408
+ fortyFiveSecLater: expr.dateAdd("second", item.createdAt, 45),
409
+ }))
410
+ .getSelectQueryDef();
411
+
412
+ it.each(dialects)("[%s] Verify SQL", (dialect) => {
413
+ const builder = createQueryBuilder(dialect);
414
+ expect(builder.build(def)).toMatchSql(expected.dateAddSecond[dialect]);
415
+ });
416
+ });
417
+
418
+ describe("formatDate - date formatting", () => {
419
+ const db = createTestDb();
420
+ const def = db
421
+ .user()
422
+ .select((item) => ({
423
+ formatted: expr.formatDate(item.createdAt, "yyyy-MM-dd HH:mm:ss"),
424
+ }))
425
+ .getSelectQueryDef();
426
+
427
+ it("Verify QueryDef", () => {
428
+ expect(def.select).toMatchObject({
429
+ formatted: {
430
+ type: "formatDate",
431
+ source: { type: "column", path: ["T1", "createdAt"] },
432
+ format: "yyyy-MM-dd HH:mm:ss",
433
+ },
434
+ });
435
+ });
436
+
437
+ it.each(dialects)("[%s] Verify SQL", (dialect) => {
438
+ const builder = createQueryBuilder(dialect);
439
+ expect(builder.build(def)).toMatchSql(expected.formatDate[dialect]);
440
+ });
441
+ });
442
+
443
+ describe("isoWeek - ISO week", () => {
444
+ const db = createTestDb();
445
+ const def = db
446
+ .user()
447
+ .select((item) => ({
448
+ week: expr.isoWeek(expr.cast(item.createdAt, { type: "date" })),
449
+ }))
450
+ .getSelectQueryDef();
451
+
452
+ it("Verify QueryDef", () => {
453
+ expect(def.select).toMatchObject({
454
+ week: {
455
+ type: "isoWeek",
456
+ arg: {
457
+ type: "cast",
458
+ source: { type: "column", path: ["T1", "createdAt"] },
459
+ targetType: { type: "date" },
460
+ },
461
+ },
462
+ });
463
+ });
464
+
465
+ it.each(dialects)("[%s] Verify SQL", (dialect) => {
466
+ const builder = createQueryBuilder(dialect);
467
+ expect(builder.build(def)).toMatchSql(expected.isoWeek[dialect]);
468
+ });
469
+ });
470
+
471
+ describe("isoWeekStartDate - ISO week start date", () => {
472
+ const db = createTestDb();
473
+ const def = db
474
+ .user()
475
+ .select((item) => ({
476
+ weekStart: expr.isoWeekStartDate(expr.cast(item.createdAt, { type: "date" })),
477
+ }))
478
+ .getSelectQueryDef();
479
+
480
+ it("Verify QueryDef", () => {
481
+ expect(def.select).toMatchObject({
482
+ weekStart: {
483
+ type: "isoWeekStartDate",
484
+ arg: {
485
+ type: "cast",
486
+ source: { type: "column", path: ["T1", "createdAt"] },
487
+ targetType: { type: "date" },
488
+ },
489
+ },
490
+ });
491
+ });
492
+
493
+ it.each(dialects)("[%s] Verify SQL", (dialect) => {
494
+ const builder = createQueryBuilder(dialect);
495
+ expect(builder.build(def)).toMatchSql(expected.isoWeekStartDate[dialect]);
496
+ });
497
+ });
498
+
499
+ describe("isoYearMonth - ISO year-month (YYYY-MM)", () => {
500
+ const db = createTestDb();
501
+ const def = db
502
+ .user()
503
+ .select((item) => ({
504
+ yearMonth: expr.isoYearMonth(expr.cast(item.createdAt, { type: "date" })),
505
+ }))
506
+ .getSelectQueryDef();
507
+
508
+ it("Verify QueryDef", () => {
509
+ expect(def.select).toMatchObject({
510
+ yearMonth: {
511
+ type: "isoYearMonth",
512
+ arg: {
513
+ type: "cast",
514
+ source: { type: "column", path: ["T1", "createdAt"] },
515
+ targetType: { type: "date" },
516
+ },
517
+ },
518
+ });
519
+ });
520
+
521
+ it.each(dialects)("[%s] Verify SQL", (dialect) => {
522
+ const builder = createQueryBuilder(dialect);
523
+ expect(builder.build(def)).toMatchSql(expected.isoYearMonth[dialect]);
524
+ });
525
+ });
526
+ });
@@ -0,0 +1,62 @@
1
+ import { mysql, pgsql, tsql } from "@simplysm/core-common";
2
+ import type { ExpectedSql } from "../setup/test-utils";
3
+
4
+ export const abs: ExpectedSql = {
5
+ mysql: mysql`
6
+ SELECT ABS(\`T1\`.\`age\`) AS \`absAge\`
7
+ FROM \`TestDb\`.\`User\` AS \`T1\`
8
+ `,
9
+ mssql: tsql`
10
+ SELECT ABS([T1].[age]) AS [absAge]
11
+ FROM [TestDb].[TestSchema].[User] AS [T1]
12
+ `,
13
+ postgresql: pgsql`
14
+ SELECT ABS("T1"."age") AS "absAge"
15
+ FROM "TestSchema"."User" AS "T1"
16
+ `,
17
+ };
18
+
19
+ export const round: ExpectedSql = {
20
+ mysql: mysql`
21
+ SELECT ROUND(\`T1\`.\`age\`, 2) AS \`rounded\`
22
+ FROM \`TestDb\`.\`User\` AS \`T1\`
23
+ `,
24
+ mssql: tsql`
25
+ SELECT ROUND([T1].[age], 2) AS [rounded]
26
+ FROM [TestDb].[TestSchema].[User] AS [T1]
27
+ `,
28
+ postgresql: pgsql`
29
+ SELECT ROUND("T1"."age", 2) AS "rounded"
30
+ FROM "TestSchema"."User" AS "T1"
31
+ `,
32
+ };
33
+
34
+ export const ceil: ExpectedSql = {
35
+ mysql: mysql`
36
+ SELECT CEIL(\`T1\`.\`age\`) AS \`ceiled\`
37
+ FROM \`TestDb\`.\`User\` AS \`T1\`
38
+ `,
39
+ mssql: tsql`
40
+ SELECT CEILING([T1].[age]) AS [ceiled]
41
+ FROM [TestDb].[TestSchema].[User] AS [T1]
42
+ `,
43
+ postgresql: pgsql`
44
+ SELECT CEIL("T1"."age") AS "ceiled"
45
+ FROM "TestSchema"."User" AS "T1"
46
+ `,
47
+ };
48
+
49
+ export const floor: ExpectedSql = {
50
+ mysql: mysql`
51
+ SELECT FLOOR(\`T1\`.\`age\`) AS \`floored\`
52
+ FROM \`TestDb\`.\`User\` AS \`T1\`
53
+ `,
54
+ mssql: tsql`
55
+ SELECT FLOOR([T1].[age]) AS [floored]
56
+ FROM [TestDb].[TestSchema].[User] AS [T1]
57
+ `,
58
+ postgresql: pgsql`
59
+ SELECT FLOOR("T1"."age") AS "floored"
60
+ FROM "TestSchema"."User" AS "T1"
61
+ `,
62
+ };
@@ -0,0 +1,106 @@
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 "../setup/test-utils"; // toMatchSql matcher
7
+ import * as expected from "./math.expected";
8
+
9
+ describe("Expr - Math functions", () => {
10
+ describe("abs - absolute value", () => {
11
+ const db = createTestDb();
12
+ const def = db
13
+ .user()
14
+ .select((item) => ({
15
+ absAge: expr.abs(item.age),
16
+ }))
17
+ .getSelectQueryDef();
18
+
19
+ it("Verify QueryDef", () => {
20
+ expect(def.select).toMatchObject({
21
+ absAge: {
22
+ type: "abs",
23
+ arg: { type: "column", path: ["T1", "age"] },
24
+ },
25
+ });
26
+ });
27
+
28
+ it.each(dialects)("[%s] Verify SQL", (dialect) => {
29
+ const builder = createQueryBuilder(dialect);
30
+ expect(builder.build(def)).toMatchSql(expected.abs[dialect]);
31
+ });
32
+ });
33
+
34
+ describe("round - rounding", () => {
35
+ const db = createTestDb();
36
+ const def = db
37
+ .user()
38
+ .select((item) => ({
39
+ rounded: expr.round(item.age, 2),
40
+ }))
41
+ .getSelectQueryDef();
42
+
43
+ it("Verify QueryDef", () => {
44
+ expect(def.select).toMatchObject({
45
+ rounded: {
46
+ type: "round",
47
+ arg: { type: "column", path: ["T1", "age"] },
48
+ digits: 2,
49
+ },
50
+ });
51
+ });
52
+
53
+ it.each(dialects)("[%s] Verify SQL", (dialect) => {
54
+ const builder = createQueryBuilder(dialect);
55
+ expect(builder.build(def)).toMatchSql(expected.round[dialect]);
56
+ });
57
+ });
58
+
59
+ describe("ceil - ceiling", () => {
60
+ const db = createTestDb();
61
+ const def = db
62
+ .user()
63
+ .select((item) => ({
64
+ ceiled: expr.ceil(item.age),
65
+ }))
66
+ .getSelectQueryDef();
67
+
68
+ it("Verify QueryDef", () => {
69
+ expect(def.select).toMatchObject({
70
+ ceiled: {
71
+ type: "ceil",
72
+ arg: { type: "column", path: ["T1", "age"] },
73
+ },
74
+ });
75
+ });
76
+
77
+ it.each(dialects)("[%s] Verify SQL", (dialect) => {
78
+ const builder = createQueryBuilder(dialect);
79
+ expect(builder.build(def)).toMatchSql(expected.ceil[dialect]);
80
+ });
81
+ });
82
+
83
+ describe("floor - flooring", () => {
84
+ const db = createTestDb();
85
+ const def = db
86
+ .user()
87
+ .select((item) => ({
88
+ floored: expr.floor(item.age),
89
+ }))
90
+ .getSelectQueryDef();
91
+
92
+ it("Verify QueryDef", () => {
93
+ expect(def.select).toMatchObject({
94
+ floored: {
95
+ type: "floor",
96
+ arg: { type: "column", path: ["T1", "age"] },
97
+ },
98
+ });
99
+ });
100
+
101
+ it.each(dialects)("[%s] Verify SQL", (dialect) => {
102
+ const builder = createQueryBuilder(dialect);
103
+ expect(builder.build(def)).toMatchSql(expected.floor[dialect]);
104
+ });
105
+ });
106
+ });