@simplysm/orm-common 13.0.69 → 13.0.71

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 +105 -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,218 @@
1
+ import { mysql, pgsql, tsql } from "@simplysm/core-common";
2
+ import type { ExpectedSql } from "../setup/test-utils";
3
+
4
+ export const concat: ExpectedSql = {
5
+ mysql: mysql`
6
+ SELECT CONCAT(IFNULL(\`T1\`.\`name\`, ''), IFNULL('@', ''), IFNULL(\`T1\`.\`email\`, '')) AS \`fullName\`
7
+ FROM \`TestDb\`.\`User\` AS \`T1\`
8
+ `,
9
+ mssql: tsql`
10
+ SELECT CONCAT([T1].[name], N'@', [T1].[email]) AS [fullName]
11
+ FROM [TestDb].[TestSchema].[User] AS [T1]
12
+ `,
13
+ postgresql: pgsql`
14
+ SELECT COALESCE("T1"."name", '') || COALESCE('@', '') || COALESCE("T1"."email", '') AS "fullName"
15
+ FROM "TestSchema"."User" AS "T1"
16
+ `,
17
+ };
18
+
19
+ export const length: ExpectedSql = {
20
+ mysql: mysql`
21
+ SELECT CHAR_LENGTH(IFNULL(\`T1\`.\`name\`, '')) AS \`nameLength\`
22
+ FROM \`TestDb\`.\`User\` AS \`T1\`
23
+ `,
24
+ mssql: tsql`
25
+ SELECT LEN(ISNULL([T1].[name], N'')) AS [nameLength]
26
+ FROM [TestDb].[TestSchema].[User] AS [T1]
27
+ `,
28
+ postgresql: pgsql`
29
+ SELECT LENGTH(COALESCE("T1"."name", '')) AS "nameLength"
30
+ FROM "TestSchema"."User" AS "T1"
31
+ `,
32
+ };
33
+
34
+ export const byteLength: ExpectedSql = {
35
+ mysql: mysql`
36
+ SELECT LENGTH(IFNULL(\`T1\`.\`name\`, '')) AS \`byteLen\`
37
+ FROM \`TestDb\`.\`User\` AS \`T1\`
38
+ `,
39
+ mssql: tsql`
40
+ SELECT DATALENGTH(ISNULL([T1].[name], N'')) AS [byteLen]
41
+ FROM [TestDb].[TestSchema].[User] AS [T1]
42
+ `,
43
+ postgresql: pgsql`
44
+ SELECT OCTET_LENGTH(COALESCE("T1"."name", '')) AS "byteLen"
45
+ FROM "TestSchema"."User" AS "T1"
46
+ `,
47
+ };
48
+
49
+ export const left: ExpectedSql = {
50
+ mysql: mysql`
51
+ SELECT LEFT(\`T1\`.\`name\`, 3) AS \`prefix\`
52
+ FROM \`TestDb\`.\`User\` AS \`T1\`
53
+ `,
54
+ mssql: tsql`
55
+ SELECT LEFT([T1].[name], 3) AS [prefix]
56
+ FROM [TestDb].[TestSchema].[User] AS [T1]
57
+ `,
58
+ postgresql: pgsql`
59
+ SELECT LEFT("T1"."name", 3) AS "prefix"
60
+ FROM "TestSchema"."User" AS "T1"
61
+ `,
62
+ };
63
+
64
+ export const right: ExpectedSql = {
65
+ mysql: mysql`
66
+ SELECT RIGHT(\`T1\`.\`name\`, 3) AS \`suffix\`
67
+ FROM \`TestDb\`.\`User\` AS \`T1\`
68
+ `,
69
+ mssql: tsql`
70
+ SELECT RIGHT([T1].[name], 3) AS [suffix]
71
+ FROM [TestDb].[TestSchema].[User] AS [T1]
72
+ `,
73
+ postgresql: pgsql`
74
+ SELECT RIGHT("T1"."name", 3) AS "suffix"
75
+ FROM "TestSchema"."User" AS "T1"
76
+ `,
77
+ };
78
+
79
+ export const trim: ExpectedSql = {
80
+ mysql: mysql`
81
+ SELECT TRIM(\`T1\`.\`name\`) AS \`trimmed\`
82
+ FROM \`TestDb\`.\`User\` AS \`T1\`
83
+ `,
84
+ mssql: tsql`
85
+ SELECT RTRIM(LTRIM([T1].[name])) AS [trimmed]
86
+ FROM [TestDb].[TestSchema].[User] AS [T1]
87
+ `,
88
+ postgresql: pgsql`
89
+ SELECT TRIM("T1"."name") AS "trimmed"
90
+ FROM "TestSchema"."User" AS "T1"
91
+ `,
92
+ };
93
+
94
+ export const padStart: ExpectedSql = {
95
+ mysql: mysql`
96
+ SELECT LPAD(\`T1\`.\`name\`, 10, '0') AS \`padded\`
97
+ FROM \`TestDb\`.\`User\` AS \`T1\`
98
+ `,
99
+ mssql: tsql`
100
+ SELECT RIGHT(REPLICATE(N'0', 10) + [T1].[name], 10) AS [padded]
101
+ FROM [TestDb].[TestSchema].[User] AS [T1]
102
+ `,
103
+ postgresql: pgsql`
104
+ SELECT LPAD("T1"."name", 10, '0') AS "padded"
105
+ FROM "TestSchema"."User" AS "T1"
106
+ `,
107
+ };
108
+
109
+ export const replace: ExpectedSql = {
110
+ mysql: mysql`
111
+ SELECT REPLACE(\`T1\`.\`name\`, 'a', 'A') AS \`replaced\`
112
+ FROM \`TestDb\`.\`User\` AS \`T1\`
113
+ `,
114
+ mssql: tsql`
115
+ SELECT REPLACE([T1].[name], N'a', N'A') AS [replaced]
116
+ FROM [TestDb].[TestSchema].[User] AS [T1]
117
+ `,
118
+ postgresql: pgsql`
119
+ SELECT REPLACE("T1"."name", 'a', 'A') AS "replaced"
120
+ FROM "TestSchema"."User" AS "T1"
121
+ `,
122
+ };
123
+
124
+ export const upper: ExpectedSql = {
125
+ mysql: mysql`
126
+ SELECT UPPER(\`T1\`.\`name\`) AS \`upper\`
127
+ FROM \`TestDb\`.\`User\` AS \`T1\`
128
+ `,
129
+ mssql: tsql`
130
+ SELECT UPPER([T1].[name]) AS [upper]
131
+ FROM [TestDb].[TestSchema].[User] AS [T1]
132
+ `,
133
+ postgresql: pgsql`
134
+ SELECT UPPER("T1"."name") AS "upper"
135
+ FROM "TestSchema"."User" AS "T1"
136
+ `,
137
+ };
138
+
139
+ export const lower: ExpectedSql = {
140
+ mysql: mysql`
141
+ SELECT LOWER(\`T1\`.\`name\`) AS \`lower\`
142
+ FROM \`TestDb\`.\`User\` AS \`T1\`
143
+ `,
144
+ mssql: tsql`
145
+ SELECT LOWER([T1].[name]) AS [lower]
146
+ FROM [TestDb].[TestSchema].[User] AS [T1]
147
+ `,
148
+ postgresql: pgsql`
149
+ SELECT LOWER("T1"."name") AS "lower"
150
+ FROM "TestSchema"."User" AS "T1"
151
+ `,
152
+ };
153
+
154
+ export const substring: ExpectedSql = {
155
+ mysql: mysql`
156
+ SELECT SUBSTRING(\`T1\`.\`name\`, 1, 5) AS \`sub\`
157
+ FROM \`TestDb\`.\`User\` AS \`T1\`
158
+ `,
159
+ mssql: tsql`
160
+ SELECT SUBSTRING([T1].[name], 1, 5) AS [sub]
161
+ FROM [TestDb].[TestSchema].[User] AS [T1]
162
+ `,
163
+ postgresql: pgsql`
164
+ SELECT SUBSTRING("T1"."name", 1, 5) AS "sub"
165
+ FROM "TestSchema"."User" AS "T1"
166
+ `,
167
+ };
168
+
169
+ export const indexOf: ExpectedSql = {
170
+ mysql: mysql`
171
+ SELECT LOCATE('test', \`T1\`.\`name\`) AS \`pos\`
172
+ FROM \`TestDb\`.\`User\` AS \`T1\`
173
+ `,
174
+ mssql: tsql`
175
+ SELECT CHARINDEX(N'test', [T1].[name]) AS [pos]
176
+ FROM [TestDb].[TestSchema].[User] AS [T1]
177
+ `,
178
+ postgresql: pgsql`
179
+ SELECT POSITION('test' IN "T1"."name") AS "pos"
180
+ FROM "TestSchema"."User" AS "T1"
181
+ `,
182
+ };
183
+
184
+ export const like: ExpectedSql = {
185
+ mysql: mysql`
186
+ SELECT *
187
+ FROM \`TestDb\`.\`User\` AS \`T1\`
188
+ WHERE \`T1\`.\`name\` LIKE '%test%' ESCAPE '\\\\'
189
+ `,
190
+ mssql: tsql`
191
+ SELECT *
192
+ FROM [TestDb].[TestSchema].[User] AS [T1]
193
+ WHERE [T1].[name] LIKE N'%test%' ESCAPE '\\'
194
+ `,
195
+ postgresql: pgsql`
196
+ SELECT *
197
+ FROM "TestSchema"."User" AS "T1"
198
+ WHERE "T1"."name" LIKE '%test%' ESCAPE '\\'
199
+ `,
200
+ };
201
+
202
+ export const likeEscape: ExpectedSql = {
203
+ mysql: mysql`
204
+ SELECT *
205
+ FROM \`TestDb\`.\`User\` AS \`T1\`
206
+ WHERE \`T1\`.\`name\` LIKE '%\\\\%%' ESCAPE '\\\\'
207
+ `,
208
+ mssql: tsql`
209
+ SELECT *
210
+ FROM [TestDb].[TestSchema].[User] AS [T1]
211
+ WHERE [T1].[name] LIKE N'%\\%%' ESCAPE '\\'
212
+ `,
213
+ postgresql: pgsql`
214
+ SELECT *
215
+ FROM "TestSchema"."User" AS "T1"
216
+ WHERE "T1"."name" LIKE '%\\%%' ESCAPE '\\'
217
+ `,
218
+ };
@@ -0,0 +1,356 @@
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 "./string.expected";
8
+
9
+ describe("Expr - String functions", () => {
10
+ describe("concat - string concatenation (null processing)", () => {
11
+ const db = createTestDb();
12
+ const def = db
13
+ .user()
14
+ .select((item) => ({
15
+ fullName: expr.concat(item.name, "@", item.email),
16
+ }))
17
+ .getSelectQueryDef();
18
+
19
+ it("Verify QueryDef", () => {
20
+ expect(def.select).toMatchObject({
21
+ fullName: {
22
+ type: "concat",
23
+ args: expect.arrayContaining([
24
+ { type: "column", path: ["T1", "name"] },
25
+ { type: "value", value: "@" },
26
+ { type: "column", path: ["T1", "email"] },
27
+ ]),
28
+ },
29
+ });
30
+ });
31
+
32
+ it.each(dialects)("[%s] Verify SQL", (dialect) => {
33
+ const builder = createQueryBuilder(dialect);
34
+ expect(builder.build(def)).toMatchSql(expected.concat[dialect]);
35
+ });
36
+ });
37
+
38
+ describe("length - character length", () => {
39
+ const db = createTestDb();
40
+ const def = db
41
+ .user()
42
+ .select((item) => ({
43
+ nameLength: expr.length(item.name),
44
+ }))
45
+ .getSelectQueryDef();
46
+
47
+ it("Verify QueryDef", () => {
48
+ expect(def.select).toMatchObject({
49
+ nameLength: {
50
+ type: "length",
51
+ arg: { type: "column", path: ["T1", "name"] },
52
+ },
53
+ });
54
+ });
55
+
56
+ it.each(dialects)("[%s] Verify SQL", (dialect) => {
57
+ const builder = createQueryBuilder(dialect);
58
+ expect(builder.build(def)).toMatchSql(expected.length[dialect]);
59
+ });
60
+ });
61
+
62
+ describe("byteLength - byte length", () => {
63
+ const db = createTestDb();
64
+ const def = db
65
+ .user()
66
+ .select((item) => ({
67
+ byteLen: expr.byteLength(item.name),
68
+ }))
69
+ .getSelectQueryDef();
70
+
71
+ it("Verify QueryDef", () => {
72
+ expect(def.select).toMatchObject({
73
+ byteLen: {
74
+ type: "byteLength",
75
+ arg: { type: "column", path: ["T1", "name"] },
76
+ },
77
+ });
78
+ });
79
+
80
+ it.each(dialects)("[%s] Verify SQL", (dialect) => {
81
+ const builder = createQueryBuilder(dialect);
82
+ expect(builder.build(def)).toMatchSql(expected.byteLength[dialect]);
83
+ });
84
+ });
85
+
86
+ describe("left - extract left string", () => {
87
+ const db = createTestDb();
88
+ const def = db
89
+ .user()
90
+ .select((item) => ({
91
+ prefix: expr.left(item.name, 3),
92
+ }))
93
+ .getSelectQueryDef();
94
+
95
+ it("Verify QueryDef", () => {
96
+ expect(def.select).toMatchObject({
97
+ prefix: {
98
+ type: "left",
99
+ source: { type: "column", path: ["T1", "name"] },
100
+ length: { type: "value", value: 3 },
101
+ },
102
+ });
103
+ });
104
+
105
+ it.each(dialects)("[%s] Verify SQL", (dialect) => {
106
+ const builder = createQueryBuilder(dialect);
107
+ expect(builder.build(def)).toMatchSql(expected.left[dialect]);
108
+ });
109
+ });
110
+
111
+ describe("right - extract right string", () => {
112
+ const db = createTestDb();
113
+ const def = db
114
+ .user()
115
+ .select((item) => ({
116
+ suffix: expr.right(item.name, 3),
117
+ }))
118
+ .getSelectQueryDef();
119
+
120
+ it("Verify QueryDef", () => {
121
+ expect(def.select).toMatchObject({
122
+ suffix: {
123
+ type: "right",
124
+ source: { type: "column", path: ["T1", "name"] },
125
+ length: { type: "value", value: 3 },
126
+ },
127
+ });
128
+ });
129
+
130
+ it.each(dialects)("[%s] Verify SQL", (dialect) => {
131
+ const builder = createQueryBuilder(dialect);
132
+ expect(builder.build(def)).toMatchSql(expected.right[dialect]);
133
+ });
134
+ });
135
+
136
+ describe("trim - remove whitespace", () => {
137
+ const db = createTestDb();
138
+ const def = db
139
+ .user()
140
+ .select((item) => ({
141
+ trimmed: expr.trim(item.name),
142
+ }))
143
+ .getSelectQueryDef();
144
+
145
+ it("Verify QueryDef", () => {
146
+ expect(def.select).toMatchObject({
147
+ trimmed: {
148
+ type: "trim",
149
+ arg: { type: "column", path: ["T1", "name"] },
150
+ },
151
+ });
152
+ });
153
+
154
+ it.each(dialects)("[%s] Verify SQL", (dialect) => {
155
+ const builder = createQueryBuilder(dialect);
156
+ expect(builder.build(def)).toMatchSql(expected.trim[dialect]);
157
+ });
158
+ });
159
+
160
+ describe("padStart - left padding", () => {
161
+ const db = createTestDb();
162
+ const def = db
163
+ .user()
164
+ .select((item) => ({
165
+ padded: expr.padStart(item.name, 10, "0"),
166
+ }))
167
+ .getSelectQueryDef();
168
+
169
+ it("Verify QueryDef", () => {
170
+ expect(def.select).toMatchObject({
171
+ padded: {
172
+ type: "padStart",
173
+ source: { type: "column", path: ["T1", "name"] },
174
+ length: { type: "value", value: 10 },
175
+ fillString: { type: "value", value: "0" },
176
+ },
177
+ });
178
+ });
179
+
180
+ it.each(dialects)("[%s] Verify SQL", (dialect) => {
181
+ const builder = createQueryBuilder(dialect);
182
+ expect(builder.build(def)).toMatchSql(expected.padStart[dialect]);
183
+ });
184
+ });
185
+
186
+ describe("replace - character replacement", () => {
187
+ const db = createTestDb();
188
+ const def = db
189
+ .user()
190
+ .select((item) => ({
191
+ replaced: expr.replace(item.name, "a", "A"),
192
+ }))
193
+ .getSelectQueryDef();
194
+
195
+ it("Verify QueryDef", () => {
196
+ expect(def.select).toMatchObject({
197
+ replaced: {
198
+ type: "replace",
199
+ source: { type: "column", path: ["T1", "name"] },
200
+ from: { type: "value", value: "a" },
201
+ to: { type: "value", value: "A" },
202
+ },
203
+ });
204
+ });
205
+
206
+ it.each(dialects)("[%s] Verify SQL", (dialect) => {
207
+ const builder = createQueryBuilder(dialect);
208
+ expect(builder.build(def)).toMatchSql(expected.replace[dialect]);
209
+ });
210
+ });
211
+
212
+ describe("upper - convert to uppercase", () => {
213
+ const db = createTestDb();
214
+ const def = db
215
+ .user()
216
+ .select((item) => ({
217
+ upper: expr.upper(item.name),
218
+ }))
219
+ .getSelectQueryDef();
220
+
221
+ it("Verify QueryDef", () => {
222
+ expect(def.select).toMatchObject({
223
+ upper: {
224
+ type: "upper",
225
+ arg: { type: "column", path: ["T1", "name"] },
226
+ },
227
+ });
228
+ });
229
+
230
+ it.each(dialects)("[%s] Verify SQL", (dialect) => {
231
+ const builder = createQueryBuilder(dialect);
232
+ expect(builder.build(def)).toMatchSql(expected.upper[dialect]);
233
+ });
234
+ });
235
+
236
+ describe("lower - convert to lowercase", () => {
237
+ const db = createTestDb();
238
+ const def = db
239
+ .user()
240
+ .select((item) => ({
241
+ lower: expr.lower(item.name),
242
+ }))
243
+ .getSelectQueryDef();
244
+
245
+ it("Verify QueryDef", () => {
246
+ expect(def.select).toMatchObject({
247
+ lower: {
248
+ type: "lower",
249
+ arg: { type: "column", path: ["T1", "name"] },
250
+ },
251
+ });
252
+ });
253
+
254
+ it.each(dialects)("[%s] Verify SQL", (dialect) => {
255
+ const builder = createQueryBuilder(dialect);
256
+ expect(builder.build(def)).toMatchSql(expected.lower[dialect]);
257
+ });
258
+ });
259
+
260
+ describe("substring - substring", () => {
261
+ const db = createTestDb();
262
+ const def = db
263
+ .user()
264
+ .select((item) => ({
265
+ sub: expr.substring(item.name, 1, 5),
266
+ }))
267
+ .getSelectQueryDef();
268
+
269
+ it("Verify QueryDef", () => {
270
+ expect(def.select).toMatchObject({
271
+ sub: {
272
+ type: "substring",
273
+ source: { type: "column", path: ["T1", "name"] },
274
+ start: { type: "value", value: 1 },
275
+ length: { type: "value", value: 5 },
276
+ },
277
+ });
278
+ });
279
+
280
+ it.each(dialects)("[%s] Verify SQL", (dialect) => {
281
+ const builder = createQueryBuilder(dialect);
282
+ expect(builder.build(def)).toMatchSql(expected.substring[dialect]);
283
+ });
284
+ });
285
+
286
+ describe("indexOf - character position (0-based)", () => {
287
+ const db = createTestDb();
288
+ const def = db
289
+ .user()
290
+ .select((item) => ({
291
+ pos: expr.indexOf(item.name, "test"),
292
+ }))
293
+ .getSelectQueryDef();
294
+
295
+ it("Verify QueryDef", () => {
296
+ expect(def.select).toMatchObject({
297
+ pos: {
298
+ type: "indexOf",
299
+ source: { type: "column", path: ["T1", "name"] },
300
+ search: { type: "value", value: "test" },
301
+ },
302
+ });
303
+ });
304
+
305
+ it.each(dialects)("[%s] Verify SQL", (dialect) => {
306
+ const builder = createQueryBuilder(dialect);
307
+ expect(builder.build(def)).toMatchSql(expected.indexOf[dialect]);
308
+ });
309
+ });
310
+
311
+ describe("like - LIKE pattern matching", () => {
312
+ const db = createTestDb();
313
+ const def = db
314
+ .user()
315
+ .where((item) => [expr.like(item.name, "%test%")])
316
+ .getSelectQueryDef();
317
+
318
+ it("Verify QueryDef", () => {
319
+ expect(def.where).toEqual([
320
+ {
321
+ type: "like",
322
+ source: { type: "column", path: ["T1", "name"] },
323
+ pattern: { type: "value", value: "%test%" },
324
+ },
325
+ ]);
326
+ });
327
+
328
+ it.each(dialects)("[%s] Verify SQL", (dialect) => {
329
+ const builder = createQueryBuilder(dialect);
330
+ expect(builder.build(def)).toMatchSql(expected.like[dialect]);
331
+ });
332
+ });
333
+
334
+ describe("like - escape processing (%)", () => {
335
+ const db = createTestDb();
336
+ const def = db
337
+ .user()
338
+ .where((item) => [expr.like(item.name, "%\\%%")])
339
+ .getSelectQueryDef();
340
+
341
+ it("Verify QueryDef", () => {
342
+ expect(def.where).toEqual([
343
+ {
344
+ type: "like",
345
+ source: { type: "column", path: ["T1", "name"] },
346
+ pattern: { type: "value", value: "%\\%%" },
347
+ },
348
+ ]);
349
+ });
350
+
351
+ it.each(dialects)("[%s] Verify SQL", (dialect) => {
352
+ const builder = createQueryBuilder(dialect);
353
+ expect(builder.build(def)).toMatchSql(expected.likeEscape[dialect]);
354
+ });
355
+ });
356
+ });
@@ -0,0 +1,147 @@
1
+ /**
2
+ * Expr - utility function test expected SQL
3
+ */
4
+ import { mysql, pgsql, tsql } from "@simplysm/core-common";
5
+ import type { ExpectedSql } from "../setup/test-utils";
6
+
7
+ //#region ========== ROW_NUM ==========
8
+
9
+ export const rowNum: ExpectedSql = {
10
+ mysql: mysql`
11
+ SELECT
12
+ \`T1\`.\`id\` AS \`id\`,
13
+ ROW_NUMBER() OVER () AS \`rowNum\`
14
+ FROM \`TestDb\`.\`User\` AS \`T1\`
15
+ `,
16
+ mssql: tsql`
17
+ SELECT
18
+ [T1].[id] AS [id],
19
+ ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS [rowNum]
20
+ FROM [TestDb].[TestSchema].[User] AS [T1]
21
+ `,
22
+ postgresql: pgsql`
23
+ SELECT
24
+ "T1"."id" AS "id",
25
+ ROW_NUMBER() OVER () AS "rowNum"
26
+ FROM "TestSchema"."User" AS "T1"
27
+ `,
28
+ };
29
+
30
+ //#endregion
31
+
32
+ //#region ========== RANDOM ==========
33
+
34
+ export const random: ExpectedSql = {
35
+ mysql: mysql`
36
+ SELECT
37
+ \`T1\`.\`id\` AS \`id\`,
38
+ RAND() AS \`randomVal\`
39
+ FROM \`TestDb\`.\`User\` AS \`T1\`
40
+ `,
41
+ mssql: tsql`
42
+ SELECT
43
+ [T1].[id] AS [id],
44
+ NEWID() AS [randomVal]
45
+ FROM [TestDb].[TestSchema].[User] AS [T1]
46
+ `,
47
+ postgresql: pgsql`
48
+ SELECT
49
+ "T1"."id" AS "id",
50
+ RANDOM() AS "randomVal"
51
+ FROM "TestSchema"."User" AS "T1"
52
+ `,
53
+ };
54
+
55
+ //#endregion
56
+
57
+ //#region ========== CAST ==========
58
+
59
+ export const castToInt: ExpectedSql = {
60
+ mysql: mysql`
61
+ SELECT
62
+ \`T1\`.\`id\` AS \`id\`,
63
+ CAST(\`T1\`.\`age\` AS INT) AS \`ageInt\`
64
+ FROM \`TestDb\`.\`User\` AS \`T1\`
65
+ `,
66
+ mssql: tsql`
67
+ SELECT
68
+ [T1].[id] AS [id],
69
+ CAST([T1].[age] AS INT) AS [ageInt]
70
+ FROM [TestDb].[TestSchema].[User] AS [T1]
71
+ `,
72
+ postgresql: pgsql`
73
+ SELECT
74
+ "T1"."id" AS "id",
75
+ CAST("T1"."age" AS INTEGER) AS "ageInt"
76
+ FROM "TestSchema"."User" AS "T1"
77
+ `,
78
+ };
79
+
80
+ export const castToVarchar: ExpectedSql = {
81
+ mysql: mysql`
82
+ SELECT
83
+ \`T1\`.\`id\` AS \`id\`,
84
+ CAST(\`T1\`.\`age\` AS VARCHAR(50)) AS \`ageStr\`
85
+ FROM \`TestDb\`.\`User\` AS \`T1\`
86
+ `,
87
+ mssql: tsql`
88
+ SELECT
89
+ [T1].[id] AS [id],
90
+ CAST([T1].[age] AS NVARCHAR(50)) AS [ageStr]
91
+ FROM [TestDb].[TestSchema].[User] AS [T1]
92
+ `,
93
+ postgresql: pgsql`
94
+ SELECT
95
+ "T1"."id" AS "id",
96
+ CAST("T1"."age" AS VARCHAR(50)) AS "ageStr"
97
+ FROM "TestSchema"."User" AS "T1"
98
+ `,
99
+ };
100
+
101
+ //#endregion
102
+
103
+ //#region ========== RAW ==========
104
+
105
+ export const rawBasic: ExpectedSql = {
106
+ mysql: mysql`
107
+ SELECT
108
+ \`T1\`.\`id\` AS \`id\`,
109
+ NOW() AS \`serverTime\`
110
+ FROM \`TestDb\`.\`User\` AS \`T1\`
111
+ `,
112
+ mssql: tsql`
113
+ SELECT
114
+ [T1].[id] AS [id],
115
+ NOW() AS [serverTime]
116
+ FROM [TestDb].[TestSchema].[User] AS [T1]
117
+ `,
118
+ postgresql: pgsql`
119
+ SELECT
120
+ "T1"."id" AS "id",
121
+ NOW() AS "serverTime"
122
+ FROM "TestSchema"."User" AS "T1"
123
+ `,
124
+ };
125
+
126
+ export const rawWithParam: ExpectedSql = {
127
+ mysql: mysql`
128
+ SELECT
129
+ \`T1\`.\`id\` AS \`id\`,
130
+ CONCAT(\`T1\`.\`name\`, ' - ', \`T1\`.\`email\`) AS \`combined\`
131
+ FROM \`TestDb\`.\`User\` AS \`T1\`
132
+ `,
133
+ mssql: tsql`
134
+ SELECT
135
+ [T1].[id] AS [id],
136
+ CONCAT([T1].[name], ' - ', [T1].[email]) AS [combined]
137
+ FROM [TestDb].[TestSchema].[User] AS [T1]
138
+ `,
139
+ postgresql: pgsql`
140
+ SELECT
141
+ "T1"."id" AS "id",
142
+ CONCAT("T1"."name", ' - ', "T1"."email") AS "combined"
143
+ FROM "TestSchema"."User" AS "T1"
144
+ `,
145
+ };
146
+
147
+ //#endregion