@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,282 @@
1
+ import { mysql, pgsql, tsql, DateTime, DateOnly, Time, Uuid } from "@simplysm/core-common";
2
+ import type { ExpectedSql } from "../setup/test-utils";
3
+
4
+ // DateTime 값 테스트용
5
+ export const testDateTime = new DateTime(2024, 1, 15, 10, 30, 0);
6
+ export const testDateOnly = new DateOnly(2024, 1, 15);
7
+ export const testTime = new Time(10, 30, 0);
8
+ export const testUuid = new Uuid("12345678-1234-1234-1234-123456789012");
9
+
10
+ export const eqNull: ExpectedSql = {
11
+ mysql: mysql`
12
+ SELECT *
13
+ FROM \`TestDb\`.\`User\` AS \`T1\`
14
+ WHERE \`T1\`.\`email\` <=> NULL
15
+ `,
16
+ mssql: tsql`
17
+ SELECT *
18
+ FROM [TestDb].[TestSchema].[User] AS [T1]
19
+ WHERE (([T1].[email] IS NULL AND NULL IS NULL) OR [T1].[email] = NULL)
20
+ `,
21
+ postgresql: pgsql`
22
+ SELECT *
23
+ FROM "TestSchema"."User" AS "T1"
24
+ WHERE "T1"."email" IS NOT DISTINCT FROM NULL
25
+ `,
26
+ };
27
+
28
+ export const eqValue: ExpectedSql = {
29
+ mysql: mysql`
30
+ SELECT *
31
+ FROM \`TestDb\`.\`User\` AS \`T1\`
32
+ WHERE \`T1\`.\`id\` <=> 1
33
+ `,
34
+ mssql: tsql`
35
+ SELECT *
36
+ FROM [TestDb].[TestSchema].[User] AS [T1]
37
+ WHERE (([T1].[id] IS NULL AND 1 IS NULL) OR [T1].[id] = 1)
38
+ `,
39
+ postgresql: pgsql`
40
+ SELECT *
41
+ FROM "TestSchema"."User" AS "T1"
42
+ WHERE "T1"."id" IS NOT DISTINCT FROM 1
43
+ `,
44
+ };
45
+
46
+ export const gt: ExpectedSql = {
47
+ mysql: mysql`
48
+ SELECT *
49
+ FROM \`TestDb\`.\`User\` AS \`T1\`
50
+ WHERE \`T1\`.\`age\` > 20
51
+ `,
52
+ mssql: tsql`
53
+ SELECT *
54
+ FROM [TestDb].[TestSchema].[User] AS [T1]
55
+ WHERE [T1].[age] > 20
56
+ `,
57
+ postgresql: pgsql`
58
+ SELECT *
59
+ FROM "TestSchema"."User" AS "T1"
60
+ WHERE "T1"."age" > 20
61
+ `,
62
+ };
63
+
64
+ export const lt: ExpectedSql = {
65
+ mysql: mysql`
66
+ SELECT *
67
+ FROM \`TestDb\`.\`User\` AS \`T1\`
68
+ WHERE \`T1\`.\`age\` < 30
69
+ `,
70
+ mssql: tsql`
71
+ SELECT *
72
+ FROM [TestDb].[TestSchema].[User] AS [T1]
73
+ WHERE [T1].[age] < 30
74
+ `,
75
+ postgresql: pgsql`
76
+ SELECT *
77
+ FROM "TestSchema"."User" AS "T1"
78
+ WHERE "T1"."age" < 30
79
+ `,
80
+ };
81
+
82
+ export const gte: ExpectedSql = {
83
+ mysql: mysql`
84
+ SELECT *
85
+ FROM \`TestDb\`.\`User\` AS \`T1\`
86
+ WHERE \`T1\`.\`age\` >= 18
87
+ `,
88
+ mssql: tsql`
89
+ SELECT *
90
+ FROM [TestDb].[TestSchema].[User] AS [T1]
91
+ WHERE [T1].[age] >= 18
92
+ `,
93
+ postgresql: pgsql`
94
+ SELECT *
95
+ FROM "TestSchema"."User" AS "T1"
96
+ WHERE "T1"."age" >= 18
97
+ `,
98
+ };
99
+
100
+ export const lte: ExpectedSql = {
101
+ mysql: mysql`
102
+ SELECT *
103
+ FROM \`TestDb\`.\`User\` AS \`T1\`
104
+ WHERE \`T1\`.\`age\` <= 65
105
+ `,
106
+ mssql: tsql`
107
+ SELECT *
108
+ FROM [TestDb].[TestSchema].[User] AS [T1]
109
+ WHERE [T1].[age] <= 65
110
+ `,
111
+ postgresql: pgsql`
112
+ SELECT *
113
+ FROM "TestSchema"."User" AS "T1"
114
+ WHERE "T1"."age" <= 65
115
+ `,
116
+ };
117
+
118
+ export const between: ExpectedSql = {
119
+ mysql: mysql`
120
+ SELECT *
121
+ FROM \`TestDb\`.\`User\` AS \`T1\`
122
+ WHERE \`T1\`.\`age\` BETWEEN 20 AND 30
123
+ `,
124
+ mssql: tsql`
125
+ SELECT *
126
+ FROM [TestDb].[TestSchema].[User] AS [T1]
127
+ WHERE [T1].[age] BETWEEN 20 AND 30
128
+ `,
129
+ postgresql: pgsql`
130
+ SELECT *
131
+ FROM "TestSchema"."User" AS "T1"
132
+ WHERE "T1"."age" BETWEEN 20 AND 30
133
+ `,
134
+ };
135
+
136
+ export const betweenFromOnly: ExpectedSql = {
137
+ mysql: mysql`
138
+ SELECT *
139
+ FROM \`TestDb\`.\`User\` AS \`T1\`
140
+ WHERE \`T1\`.\`age\` >= 20
141
+ `,
142
+ mssql: tsql`
143
+ SELECT *
144
+ FROM [TestDb].[TestSchema].[User] AS [T1]
145
+ WHERE [T1].[age] >= 20
146
+ `,
147
+ postgresql: pgsql`
148
+ SELECT *
149
+ FROM "TestSchema"."User" AS "T1"
150
+ WHERE "T1"."age" >= 20
151
+ `,
152
+ };
153
+
154
+ export const betweenToOnly: ExpectedSql = {
155
+ mysql: mysql`
156
+ SELECT *
157
+ FROM \`TestDb\`.\`User\` AS \`T1\`
158
+ WHERE \`T1\`.\`age\` <= 30
159
+ `,
160
+ mssql: tsql`
161
+ SELECT *
162
+ FROM [TestDb].[TestSchema].[User] AS [T1]
163
+ WHERE [T1].[age] <= 30
164
+ `,
165
+ postgresql: pgsql`
166
+ SELECT *
167
+ FROM "TestSchema"."User" AS "T1"
168
+ WHERE "T1"."age" <= 30
169
+ `,
170
+ };
171
+
172
+ export const betweenNone: ExpectedSql = {
173
+ mysql: mysql`
174
+ SELECT *
175
+ FROM \`TestDb\`.\`User\` AS \`T1\`
176
+ WHERE 1=1
177
+ `,
178
+ mssql: tsql`
179
+ SELECT *
180
+ FROM [TestDb].[TestSchema].[User] AS [T1]
181
+ WHERE 1=1
182
+ `,
183
+ postgresql: pgsql`
184
+ SELECT *
185
+ FROM "TestSchema"."User" AS "T1"
186
+ WHERE TRUE
187
+ `,
188
+ };
189
+
190
+ export const betweenColumns: ExpectedSql = {
191
+ mysql: mysql`
192
+ SELECT *
193
+ FROM \`TestDb\`.\`MonthlySales\` AS \`T1\`
194
+ WHERE \`T1\`.\`feb\` BETWEEN \`T1\`.\`jan\` AND \`T1\`.\`mar\`
195
+ `,
196
+ mssql: tsql`
197
+ SELECT *
198
+ FROM [TestDb].[TestSchema].[MonthlySales] AS [T1]
199
+ WHERE [T1].[feb] BETWEEN [T1].[jan] AND [T1].[mar]
200
+ `,
201
+ postgresql: pgsql`
202
+ SELECT *
203
+ FROM "TestSchema"."MonthlySales" AS "T1"
204
+ WHERE "T1"."feb" BETWEEN "T1"."jan" AND "T1"."mar"
205
+ `,
206
+ };
207
+
208
+ export const regexpMysqlPostgresql: ExpectedSql = {
209
+ mysql: mysql`
210
+ SELECT *
211
+ FROM \`TestDb\`.\`User\` AS \`T1\`
212
+ WHERE \`T1\`.\`name\` REGEXP '^test.*'
213
+ `,
214
+ mssql: tsql``,
215
+ postgresql: pgsql`
216
+ SELECT *
217
+ FROM "TestSchema"."User" AS "T1"
218
+ WHERE "T1"."name" ~ '^test.*'
219
+ `,
220
+ };
221
+
222
+ export const inEmpty: ExpectedSql = {
223
+ mysql: mysql`
224
+ SELECT *
225
+ FROM \`TestDb\`.\`User\` AS \`T1\`
226
+ WHERE 1=0
227
+ `,
228
+ mssql: tsql`
229
+ SELECT *
230
+ FROM [TestDb].[TestSchema].[User] AS [T1]
231
+ WHERE 1=0
232
+ `,
233
+ postgresql: pgsql`
234
+ SELECT *
235
+ FROM "TestSchema"."User" AS "T1"
236
+ WHERE FALSE
237
+ `,
238
+ };
239
+
240
+ //#region ========== DateTime/DateOnly/Time 값 테스트 ==========
241
+
242
+ export const eqDateTime: ExpectedSql = {
243
+ mysql: mysql`
244
+ SELECT *
245
+ FROM \`TestDb\`.\`User\` AS \`T1\`
246
+ WHERE \`T1\`.\`createdAt\` <=> '2024-01-15 10:30:00'
247
+ `,
248
+ mssql: tsql`
249
+ SELECT *
250
+ FROM [TestDb].[TestSchema].[User] AS [T1]
251
+ WHERE (([T1].[createdAt] IS NULL AND '2024-01-15 10:30:00' IS NULL) OR [T1].[createdAt] = '2024-01-15 10:30:00')
252
+ `,
253
+ postgresql: pgsql`
254
+ SELECT *
255
+ FROM "TestSchema"."User" AS "T1"
256
+ WHERE "T1"."createdAt" IS NOT DISTINCT FROM '2024-01-15 10:30:00'::timestamp
257
+ `,
258
+ };
259
+
260
+ //#endregion
261
+
262
+ //#region ========== inQuery 테스트 ==========
263
+
264
+ export const inQuery: ExpectedSql = {
265
+ mysql: mysql`
266
+ SELECT *
267
+ FROM \`TestDb\`.\`User\` AS \`T1\`
268
+ WHERE \`T1\`.\`id\` IN (SELECT \`T2\`.\`userId\` AS \`userId\` FROM \`TestDb\`.\`Post\` AS \`T2\`)
269
+ `,
270
+ mssql: tsql`
271
+ SELECT *
272
+ FROM [TestDb].[TestSchema].[User] AS [T1]
273
+ WHERE [T1].[id] IN (SELECT [T2].[userId] AS [userId] FROM [TestDb].[TestSchema].[Post] AS [T2])
274
+ `,
275
+ postgresql: pgsql`
276
+ SELECT *
277
+ FROM "TestSchema"."User" AS "T1"
278
+ WHERE "T1"."id" IN (SELECT "T2"."userId" AS "userId" FROM "TestSchema"."Post" AS "T2")
279
+ `,
280
+ };
281
+
282
+ //#endregion
@@ -0,0 +1,400 @@
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 "./comparison.expected";
8
+ import { DateTime } from "@simplysm/core-common";
9
+
10
+ describe("Expr - Comparison operators (null-safe)", () => {
11
+ describe("eq - equality comparison (null == null → true)", () => {
12
+ const db = createTestDb();
13
+ const def = db
14
+ .user()
15
+ .where((item) => [expr.eq(item.email, undefined)])
16
+ .getSelectQueryDef();
17
+
18
+ it("Verify QueryDef", () => {
19
+ expect(def).toMatchObject({
20
+ type: "select",
21
+ as: "T1",
22
+ from: { database: "TestDb", schema: "TestSchema", name: "User" },
23
+ where: [
24
+ {
25
+ type: "eq",
26
+ source: { type: "column", path: ["T1", "email"] },
27
+ target: { type: "value", value: undefined },
28
+ },
29
+ ],
30
+ });
31
+ });
32
+
33
+ it.each(dialects)("[%s] Verify SQL", (dialect) => {
34
+ const builder = createQueryBuilder(dialect);
35
+ expect(builder.build(def)).toMatchSql(expected.eqNull[dialect]);
36
+ });
37
+ });
38
+
39
+ describe("eq - value comparison (1 == 1 → true)", () => {
40
+ const db = createTestDb();
41
+ const def = db
42
+ .user()
43
+ .where((item) => [expr.eq(item.id, 1)])
44
+ .getSelectQueryDef();
45
+
46
+ it("Verify QueryDef", () => {
47
+ expect(def).toMatchObject({
48
+ type: "select",
49
+ where: [
50
+ {
51
+ type: "eq",
52
+ source: { type: "column", path: ["T1", "id"] },
53
+ target: { type: "value", value: 1 },
54
+ },
55
+ ],
56
+ });
57
+ });
58
+
59
+ it.each(dialects)("[%s] Verify SQL", (dialect) => {
60
+ const builder = createQueryBuilder(dialect);
61
+ expect(builder.build(def)).toMatchSql(expected.eqValue[dialect]);
62
+ });
63
+ });
64
+
65
+ describe("gt - greater than comparison", () => {
66
+ const db = createTestDb();
67
+ const def = db
68
+ .user()
69
+ .where((item) => [expr.gt(item.age, 20)])
70
+ .getSelectQueryDef();
71
+
72
+ it("Verify QueryDef", () => {
73
+ expect(def).toMatchObject({
74
+ type: "select",
75
+ where: [
76
+ {
77
+ type: "gt",
78
+ source: { type: "column", path: ["T1", "age"] },
79
+ target: { type: "value", value: 20 },
80
+ },
81
+ ],
82
+ });
83
+ });
84
+
85
+ it.each(dialects)("[%s] Verify SQL", (dialect) => {
86
+ const builder = createQueryBuilder(dialect);
87
+ expect(builder.build(def)).toMatchSql(expected.gt[dialect]);
88
+ });
89
+ });
90
+
91
+ describe("lt - less than comparison", () => {
92
+ const db = createTestDb();
93
+ const def = db
94
+ .user()
95
+ .where((item) => [expr.lt(item.age, 30)])
96
+ .getSelectQueryDef();
97
+
98
+ it("Verify QueryDef", () => {
99
+ expect(def).toMatchObject({
100
+ type: "select",
101
+ where: [
102
+ {
103
+ type: "lt",
104
+ source: { type: "column", path: ["T1", "age"] },
105
+ target: { type: "value", value: 30 },
106
+ },
107
+ ],
108
+ });
109
+ });
110
+
111
+ it.each(dialects)("[%s] Verify SQL", (dialect) => {
112
+ const builder = createQueryBuilder(dialect);
113
+ expect(builder.build(def)).toMatchSql(expected.lt[dialect]);
114
+ });
115
+ });
116
+
117
+ describe("gte - greater than or equal comparison", () => {
118
+ const db = createTestDb();
119
+ const def = db
120
+ .user()
121
+ .where((item) => [expr.gte(item.age, 18)])
122
+ .getSelectQueryDef();
123
+
124
+ it("Verify QueryDef", () => {
125
+ expect(def).toMatchObject({
126
+ type: "select",
127
+ where: [
128
+ {
129
+ type: "gte",
130
+ source: { type: "column", path: ["T1", "age"] },
131
+ target: { type: "value", value: 18 },
132
+ },
133
+ ],
134
+ });
135
+ });
136
+
137
+ it.each(dialects)("[%s] Verify SQL", (dialect) => {
138
+ const builder = createQueryBuilder(dialect);
139
+ expect(builder.build(def)).toMatchSql(expected.gte[dialect]);
140
+ });
141
+ });
142
+
143
+ describe("lte - less than or equal comparison", () => {
144
+ const db = createTestDb();
145
+ const def = db
146
+ .user()
147
+ .where((item) => [expr.lte(item.age, 65)])
148
+ .getSelectQueryDef();
149
+
150
+ it("Verify QueryDef", () => {
151
+ expect(def).toMatchObject({
152
+ type: "select",
153
+ where: [
154
+ {
155
+ type: "lte",
156
+ source: { type: "column", path: ["T1", "age"] },
157
+ target: { type: "value", value: 65 },
158
+ },
159
+ ],
160
+ });
161
+ });
162
+
163
+ it.each(dialects)("[%s] Verify SQL", (dialect) => {
164
+ const builder = createQueryBuilder(dialect);
165
+ expect(builder.build(def)).toMatchSql(expected.lte[dialect]);
166
+ });
167
+ });
168
+
169
+ describe("between - range comparison", () => {
170
+ const db = createTestDb();
171
+ const def = db
172
+ .user()
173
+ .where((item) => [expr.between(item.age, 20, 30)])
174
+ .getSelectQueryDef();
175
+
176
+ it("Verify QueryDef", () => {
177
+ expect(def).toMatchObject({
178
+ type: "select",
179
+ where: [
180
+ {
181
+ type: "between",
182
+ source: { type: "column", path: ["T1", "age"] },
183
+ from: { type: "value", value: 20 },
184
+ to: { type: "value", value: 30 },
185
+ },
186
+ ],
187
+ });
188
+ });
189
+
190
+ it.each(dialects)("[%s] Verify SQL", (dialect) => {
191
+ const builder = createQueryBuilder(dialect);
192
+ expect(builder.build(def)).toMatchSql(expected.between[dialect]);
193
+ });
194
+ });
195
+
196
+ describe("between - only from present (>= handling)", () => {
197
+ const db = createTestDb();
198
+ const def = db
199
+ .user()
200
+ .where((item) => [expr.between(item.age, 20, undefined)])
201
+ .getSelectQueryDef();
202
+
203
+ it("Verify QueryDef", () => {
204
+ expect(def).toMatchObject({
205
+ type: "select",
206
+ where: [
207
+ {
208
+ type: "between",
209
+ source: { type: "column", path: ["T1", "age"] },
210
+ from: { type: "value", value: 20 },
211
+ to: undefined,
212
+ },
213
+ ],
214
+ });
215
+ });
216
+
217
+ it.each(dialects)("[%s] Verify SQL", (dialect) => {
218
+ const builder = createQueryBuilder(dialect);
219
+ expect(builder.build(def)).toMatchSql(expected.betweenFromOnly[dialect]);
220
+ });
221
+ });
222
+
223
+ describe("between - only to present (<= handling)", () => {
224
+ const db = createTestDb();
225
+ const def = db
226
+ .user()
227
+ .where((item) => [expr.between(item.age, undefined, 30)])
228
+ .getSelectQueryDef();
229
+
230
+ it("Verify QueryDef", () => {
231
+ expect(def).toMatchObject({
232
+ type: "select",
233
+ where: [
234
+ {
235
+ type: "between",
236
+ source: { type: "column", path: ["T1", "age"] },
237
+ from: undefined,
238
+ to: { type: "value", value: 30 },
239
+ },
240
+ ],
241
+ });
242
+ });
243
+
244
+ it.each(dialects)("[%s] Verify SQL", (dialect) => {
245
+ const builder = createQueryBuilder(dialect);
246
+ expect(builder.build(def)).toMatchSql(expected.betweenToOnly[dialect]);
247
+ });
248
+ });
249
+
250
+ describe("between - both absent (always true)", () => {
251
+ const db = createTestDb();
252
+ const def = db
253
+ .user()
254
+ .where((item) => [expr.between(item.age, undefined, undefined)])
255
+ .getSelectQueryDef();
256
+
257
+ it("Verify QueryDef", () => {
258
+ expect(def).toMatchObject({
259
+ type: "select",
260
+ where: [
261
+ {
262
+ type: "between",
263
+ source: { type: "column", path: ["T1", "age"] },
264
+ from: undefined,
265
+ to: undefined,
266
+ },
267
+ ],
268
+ });
269
+ });
270
+
271
+ it.each(dialects)("[%s] Verify SQL", (dialect) => {
272
+ const builder = createQueryBuilder(dialect);
273
+ expect(builder.build(def)).toMatchSql(expected.betweenNone[dialect]);
274
+ });
275
+ });
276
+
277
+ describe("between - using column references for from/to", () => {
278
+ const db = createTestDb();
279
+ const def = db
280
+ .monthlySales()
281
+ .where((item) => [expr.between(item.feb, item.jan, item.mar)])
282
+ .getSelectQueryDef();
283
+
284
+ it("Verify QueryDef", () => {
285
+ expect(def).toMatchObject({
286
+ type: "select",
287
+ where: [
288
+ {
289
+ type: "between",
290
+ source: { type: "column", path: ["T1", "feb"] },
291
+ from: { type: "column", path: ["T1", "jan"] },
292
+ to: { type: "column", path: ["T1", "mar"] },
293
+ },
294
+ ],
295
+ });
296
+ });
297
+
298
+ it.each(dialects)("[%s] Verify SQL", (dialect) => {
299
+ const builder = createQueryBuilder(dialect);
300
+ expect(builder.build(def)).toMatchSql(expected.betweenColumns[dialect]);
301
+ });
302
+ });
303
+
304
+ describe("regexp - regex comparison (MySQL/PostgreSQL)", () => {
305
+ const db = createTestDb();
306
+ const def = db
307
+ .user()
308
+ .where((item) => [expr.regexp(item.name, "^test.*")])
309
+ .getSelectQueryDef();
310
+
311
+ it.each(["mysql", "postgresql"] as const)("[%s] Verify SQL", (dialect) => {
312
+ const builder = createQueryBuilder(dialect);
313
+ expect(builder.build(def)).toMatchSql(expected.regexpMysqlPostgresql[dialect]);
314
+ });
315
+ });
316
+
317
+ describe("in - empty array (always false)", () => {
318
+ const db = createTestDb();
319
+ const def = db
320
+ .user()
321
+ .where((item) => [expr.in(item.id, [])])
322
+ .getSelectQueryDef();
323
+
324
+ it("Verify QueryDef", () => {
325
+ expect(def).toMatchObject({
326
+ type: "select",
327
+ where: [
328
+ {
329
+ type: "in",
330
+ source: { type: "column", path: ["T1", "id"] },
331
+ values: [],
332
+ },
333
+ ],
334
+ });
335
+ });
336
+
337
+ it.each(dialects)("[%s] Verify SQL", (dialect) => {
338
+ const builder = createQueryBuilder(dialect);
339
+ expect(builder.build(def)).toMatchSql(expected.inEmpty[dialect]);
340
+ });
341
+ });
342
+
343
+ //#region ========== DateTime 값 테스트 ==========
344
+
345
+ describe("eq - DateTime value comparison", () => {
346
+ const db = createTestDb();
347
+ const testDateTime = new DateTime(2024, 1, 15, 10, 30, 0);
348
+ const def = db
349
+ .user()
350
+ .where((item) => [expr.eq(item.createdAt, testDateTime)])
351
+ .getSelectQueryDef();
352
+
353
+ it.each(dialects)("[%s] Verify SQL", (dialect) => {
354
+ const builder = createQueryBuilder(dialect);
355
+ expect(builder.build(def)).toMatchSql(expected.eqDateTime[dialect]);
356
+ });
357
+ });
358
+
359
+ //#endregion
360
+
361
+ //#region ========== inQuery 테스트 ==========
362
+
363
+ describe("inQuery - subquery IN condition", () => {
364
+ const db = createTestDb();
365
+ const def = db
366
+ .user()
367
+ .where((u) => [
368
+ expr.inQuery(
369
+ u.id,
370
+ db.post().select((p) => ({ userId: p.userId })),
371
+ ),
372
+ ])
373
+ .getSelectQueryDef();
374
+
375
+ it("Verify QueryDef", () => {
376
+ expect(def).toMatchObject({
377
+ type: "select",
378
+ where: [
379
+ {
380
+ type: "inQuery",
381
+ source: { type: "column", path: ["T1", "id"] },
382
+ query: {
383
+ type: "select",
384
+ select: {
385
+ userId: { type: "column", path: ["T2", "userId"] },
386
+ },
387
+ },
388
+ },
389
+ ],
390
+ });
391
+ });
392
+
393
+ it.each(dialects)("[%s] Verify SQL", (dialect) => {
394
+ const builder = createQueryBuilder(dialect);
395
+ expect(builder.build(def)).toMatchSql(expected.inQuery[dialect]);
396
+ });
397
+ });
398
+
399
+ //#endregion
400
+ });