@simplysm/orm-common 13.0.75 → 13.0.77
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.
- package/README.md +575 -50
- package/dist/create-db-context.d.ts +1 -1
- package/dist/create-db-context.d.ts.map +1 -1
- package/dist/create-db-context.js +34 -27
- package/dist/create-db-context.js.map +1 -1
- package/dist/ddl/initialize.js +4 -4
- package/dist/ddl/initialize.js.map +1 -1
- package/dist/ddl/relation-ddl.d.ts +7 -7
- package/dist/ddl/relation-ddl.d.ts.map +1 -1
- package/dist/ddl/relation-ddl.js +18 -18
- package/dist/ddl/relation-ddl.js.map +1 -1
- package/dist/ddl/schema-ddl.d.ts +1 -1
- package/dist/ddl/schema-ddl.d.ts.map +1 -1
- package/dist/ddl/schema-ddl.js +2 -2
- package/dist/ddl/schema-ddl.js.map +1 -1
- package/dist/ddl/table-ddl.js +2 -2
- package/dist/ddl/table-ddl.js.map +1 -1
- package/dist/exec/queryable.d.ts +24 -24
- package/dist/exec/queryable.d.ts.map +1 -1
- package/dist/exec/queryable.js +37 -37
- package/dist/exec/queryable.js.map +1 -1
- package/dist/expr/expr-unit.js +1 -1
- package/dist/expr/expr-unit.js.map +1 -1
- package/dist/expr/expr.d.ts +9 -9
- package/dist/expr/expr.d.ts.map +1 -1
- package/dist/expr/expr.js +10 -10
- package/dist/expr/expr.js.map +1 -1
- package/dist/query-builder/base/expr-renderer-base.d.ts +2 -2
- package/dist/query-builder/base/expr-renderer-base.d.ts.map +1 -1
- package/dist/query-builder/base/query-builder-base.d.ts +7 -15
- package/dist/query-builder/base/query-builder-base.d.ts.map +1 -1
- package/dist/query-builder/base/query-builder-base.js +2 -2
- package/dist/query-builder/base/query-builder-base.js.map +1 -1
- package/dist/query-builder/mssql/mssql-expr-renderer.d.ts +4 -4
- package/dist/query-builder/mssql/mssql-expr-renderer.d.ts.map +1 -1
- package/dist/query-builder/mssql/mssql-expr-renderer.js +8 -8
- package/dist/query-builder/mssql/mssql-expr-renderer.js.map +1 -1
- package/dist/query-builder/mssql/mssql-query-builder.d.ts +7 -7
- package/dist/query-builder/mssql/mssql-query-builder.d.ts.map +1 -1
- package/dist/query-builder/mssql/mssql-query-builder.js +7 -7
- package/dist/query-builder/mssql/mssql-query-builder.js.map +1 -1
- package/dist/query-builder/mysql/mysql-expr-renderer.d.ts +4 -4
- package/dist/query-builder/mysql/mysql-expr-renderer.d.ts.map +1 -1
- package/dist/query-builder/mysql/mysql-expr-renderer.js +9 -9
- package/dist/query-builder/mysql/mysql-expr-renderer.js.map +1 -1
- package/dist/query-builder/mysql/mysql-query-builder.d.ts +7 -7
- package/dist/query-builder/mysql/mysql-query-builder.d.ts.map +1 -1
- package/dist/query-builder/mysql/mysql-query-builder.js +11 -11
- package/dist/query-builder/mysql/mysql-query-builder.js.map +1 -1
- package/dist/query-builder/postgresql/postgresql-expr-renderer.d.ts +4 -4
- package/dist/query-builder/postgresql/postgresql-expr-renderer.d.ts.map +1 -1
- package/dist/query-builder/postgresql/postgresql-expr-renderer.js +8 -8
- package/dist/query-builder/postgresql/postgresql-expr-renderer.js.map +1 -1
- package/dist/query-builder/postgresql/postgresql-query-builder.d.ts +7 -7
- package/dist/query-builder/postgresql/postgresql-query-builder.d.ts.map +1 -1
- package/dist/query-builder/postgresql/postgresql-query-builder.js +7 -7
- package/dist/query-builder/postgresql/postgresql-query-builder.js.map +1 -1
- package/dist/schema/procedure-builder.d.ts +1 -1
- package/dist/schema/table-builder.d.ts +1 -1
- package/dist/schema/table-builder.d.ts.map +1 -1
- package/dist/schema/table-builder.js +1 -1
- package/dist/schema/view-builder.d.ts +1 -1
- package/dist/schema/view-builder.d.ts.map +1 -1
- package/dist/schema/view-builder.js +1 -1
- package/dist/types/db-context-def.d.ts +18 -18
- package/dist/types/db-context-def.d.ts.map +1 -1
- package/dist/types/expr.d.ts +6 -6
- package/dist/types/expr.d.ts.map +1 -1
- package/dist/types/query-def.d.ts +15 -15
- package/dist/types/query-def.d.ts.map +1 -1
- package/dist/types/query-def.js +6 -6
- package/dist/utils/result-parser.d.ts.map +1 -1
- package/dist/utils/result-parser.js +44 -16
- package/dist/utils/result-parser.js.map +1 -1
- package/package.json +2 -2
- package/src/create-db-context.ts +36 -29
- package/src/ddl/initialize.ts +4 -4
- package/src/ddl/relation-ddl.ts +16 -16
- package/src/ddl/schema-ddl.ts +2 -2
- package/src/ddl/table-ddl.ts +2 -2
- package/src/exec/queryable.ts +58 -58
- package/src/expr/expr-unit.ts +1 -1
- package/src/expr/expr.ts +13 -13
- package/src/query-builder/base/expr-renderer-base.ts +2 -2
- package/src/query-builder/base/query-builder-base.ts +18 -14
- package/src/query-builder/mssql/mssql-expr-renderer.ts +11 -10
- package/src/query-builder/mssql/mssql-query-builder.ts +13 -13
- package/src/query-builder/mysql/mysql-expr-renderer.ts +12 -11
- package/src/query-builder/mysql/mysql-query-builder.ts +17 -17
- package/src/query-builder/postgresql/postgresql-expr-renderer.ts +11 -10
- package/src/query-builder/postgresql/postgresql-query-builder.ts +13 -13
- package/src/schema/procedure-builder.ts +1 -1
- package/src/schema/table-builder.ts +1 -1
- package/src/schema/view-builder.ts +1 -1
- package/src/types/db-context-def.ts +18 -18
- package/src/types/expr.ts +6 -6
- package/src/types/query-def.ts +31 -31
- package/src/utils/result-parser.ts +60 -16
- package/tests/db-context/create-db-context.spec.ts +6 -37
- package/tests/db-context/define-db-context.spec.ts +0 -51
- package/tests/ddl/basic.expected.ts +8 -8
- package/tests/ddl/basic.spec.ts +24 -181
- package/tests/ddl/column-builder.spec.ts +0 -112
- package/tests/ddl/index-builder.spec.ts +10 -64
- package/tests/ddl/procedure-builder.spec.ts +0 -106
- package/tests/ddl/relation-builder.spec.ts +4 -205
- package/tests/ddl/table-builder.spec.ts +0 -34
- package/tests/ddl/view-builder.spec.ts +0 -60
- package/tests/dml/delete.spec.ts +0 -33
- package/tests/dml/insert.spec.ts +0 -78
- package/tests/dml/update.spec.ts +2 -98
- package/tests/dml/upsert.spec.ts +0 -52
- package/tests/errors/queryable-errors.spec.ts +0 -51
- package/tests/escape.spec.ts +0 -41
- package/tests/examples/pivot.spec.ts +0 -333
- package/tests/examples/sampling.spec.ts +0 -63
- package/tests/examples/unpivot.spec.ts +0 -65
- package/tests/exec/search-parser.spec.ts +0 -16
- package/tests/expr/comparison.spec.ts +0 -66
- package/tests/expr/conditional.expected.ts +2 -2
- package/tests/expr/conditional.spec.ts +8 -35
- package/tests/expr/date.spec.ts +5 -72
- package/tests/expr/math.spec.ts +0 -47
- package/tests/expr/string.spec.ts +0 -56
- package/tests/expr/utility.spec.ts +0 -27
- package/tests/select/basic.spec.ts +5 -74
- package/tests/select/filter.spec.ts +0 -114
- package/tests/select/group.spec.ts +0 -85
- package/tests/select/join.spec.ts +0 -113
- package/tests/select/order.spec.ts +0 -49
- package/tests/select/subquery.spec.ts +0 -96
- package/tests/select/window.spec.ts +0 -185
- package/tests/types/nullable-queryable-record.spec.ts +0 -48
- package/tests/utils/result-parser-perf.spec.ts +0 -67
- package/tests/utils/result-parser.spec.ts +4 -38
package/tests/dml/update.spec.ts
CHANGED
|
@@ -41,42 +41,6 @@ describe("UPDATE - Basic", () => {
|
|
|
41
41
|
});
|
|
42
42
|
});
|
|
43
43
|
|
|
44
|
-
describe("UPDATE multiple columns", () => {
|
|
45
|
-
const db = createTestDb();
|
|
46
|
-
|
|
47
|
-
const def = db
|
|
48
|
-
.employee()
|
|
49
|
-
.where((e) => [expr.eq(e.id, 1)])
|
|
50
|
-
.getUpdateQueryDef(() => ({
|
|
51
|
-
name: expr.val("string", "New Name"),
|
|
52
|
-
departmentId: expr.val("number", 2),
|
|
53
|
-
}));
|
|
54
|
-
|
|
55
|
-
it("Verify QueryDef", () => {
|
|
56
|
-
expect(def).toEqual({
|
|
57
|
-
type: "update",
|
|
58
|
-
table: { database: "TestDb", schema: "TestSchema", name: "Employee" },
|
|
59
|
-
as: "T1",
|
|
60
|
-
record: {
|
|
61
|
-
name: { type: "value", value: "New Name" },
|
|
62
|
-
departmentId: { type: "value", value: 2 },
|
|
63
|
-
},
|
|
64
|
-
where: [
|
|
65
|
-
{
|
|
66
|
-
type: "eq",
|
|
67
|
-
source: { type: "column", path: ["T1", "id"] },
|
|
68
|
-
target: { type: "value", value: 1 },
|
|
69
|
-
},
|
|
70
|
-
],
|
|
71
|
-
});
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
it.each(dialects)("[%s] should validate SQL", (dialect) => {
|
|
75
|
-
const builder = createQueryBuilder(dialect);
|
|
76
|
-
expect(builder.build(def)).toMatchSql(expected.updateMultiCol[dialect]);
|
|
77
|
-
});
|
|
78
|
-
});
|
|
79
|
-
|
|
80
44
|
describe("UPDATE with literal values (without expr.val)", () => {
|
|
81
45
|
const db = createTestDb();
|
|
82
46
|
|
|
@@ -153,45 +117,6 @@ describe("UPDATE - Basic", () => {
|
|
|
153
117
|
});
|
|
154
118
|
});
|
|
155
119
|
|
|
156
|
-
describe("UPDATE referencing current values (e.g., count = count + 1)", () => {
|
|
157
|
-
const db = createTestDb();
|
|
158
|
-
|
|
159
|
-
const def = db
|
|
160
|
-
.employee()
|
|
161
|
-
.where((e) => [expr.eq(e.id, 1)])
|
|
162
|
-
.getUpdateQueryDef((e) => ({
|
|
163
|
-
// managerId = managerId + 1 (example)
|
|
164
|
-
managerId: expr.raw("number")`${e.managerId} + 1`,
|
|
165
|
-
}));
|
|
166
|
-
|
|
167
|
-
it("Verify QueryDef", () => {
|
|
168
|
-
expect(def).toEqual({
|
|
169
|
-
type: "update",
|
|
170
|
-
table: { database: "TestDb", schema: "TestSchema", name: "Employee" },
|
|
171
|
-
as: "T1",
|
|
172
|
-
record: {
|
|
173
|
-
managerId: {
|
|
174
|
-
type: "raw",
|
|
175
|
-
sql: "$1 + 1",
|
|
176
|
-
params: [{ type: "column", path: ["T1", "managerId"] }],
|
|
177
|
-
},
|
|
178
|
-
},
|
|
179
|
-
where: [
|
|
180
|
-
{
|
|
181
|
-
type: "eq",
|
|
182
|
-
source: { type: "column", path: ["T1", "id"] },
|
|
183
|
-
target: { type: "value", value: 1 },
|
|
184
|
-
},
|
|
185
|
-
],
|
|
186
|
-
});
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
it.each(dialects)("[%s] should validate SQL", (dialect) => {
|
|
190
|
-
const builder = createQueryBuilder(dialect);
|
|
191
|
-
expect(builder.build(def)).toMatchSql(expected.updateWithRef[dialect]);
|
|
192
|
-
});
|
|
193
|
-
});
|
|
194
|
-
|
|
195
120
|
describe("Specify output column", () => {
|
|
196
121
|
const db = createTestDb();
|
|
197
122
|
|
|
@@ -277,14 +202,14 @@ describe("FK switch", () => {
|
|
|
277
202
|
|
|
278
203
|
const def = db.getSwitchFkQueryDef(
|
|
279
204
|
{ database: "TestDb", schema: "TestSchema", name: "Employee" },
|
|
280
|
-
|
|
205
|
+
false,
|
|
281
206
|
);
|
|
282
207
|
|
|
283
208
|
it("Verify QueryDef", () => {
|
|
284
209
|
expect(def).toEqual({
|
|
285
210
|
type: "switchFk",
|
|
286
211
|
table: { database: "TestDb", schema: "TestSchema", name: "Employee" },
|
|
287
|
-
|
|
212
|
+
enabled: false,
|
|
288
213
|
});
|
|
289
214
|
});
|
|
290
215
|
|
|
@@ -294,25 +219,4 @@ describe("FK switch", () => {
|
|
|
294
219
|
});
|
|
295
220
|
});
|
|
296
221
|
|
|
297
|
-
describe("FK on", () => {
|
|
298
|
-
const db = createTestDb();
|
|
299
|
-
|
|
300
|
-
const def = db.getSwitchFkQueryDef(
|
|
301
|
-
{ database: "TestDb", schema: "TestSchema", name: "Employee" },
|
|
302
|
-
"on",
|
|
303
|
-
);
|
|
304
|
-
|
|
305
|
-
it("Verify QueryDef", () => {
|
|
306
|
-
expect(def).toEqual({
|
|
307
|
-
type: "switchFk",
|
|
308
|
-
table: { database: "TestDb", schema: "TestSchema", name: "Employee" },
|
|
309
|
-
switch: "on",
|
|
310
|
-
});
|
|
311
|
-
});
|
|
312
|
-
|
|
313
|
-
it.each(dialects)("[%s] should validate SQL", (dialect) => {
|
|
314
|
-
const builder = createQueryBuilder(dialect);
|
|
315
|
-
expect(builder.build(def)).toMatchSql(expected.fkOn[dialect]);
|
|
316
|
-
});
|
|
317
|
-
});
|
|
318
222
|
});
|
package/tests/dml/upsert.spec.ts
CHANGED
|
@@ -146,58 +146,6 @@ describe("UPSERT - Basic", () => {
|
|
|
146
146
|
});
|
|
147
147
|
});
|
|
148
148
|
|
|
149
|
-
describe("Complex WHERE condition", () => {
|
|
150
|
-
const db = createTestDb();
|
|
151
|
-
const def = db
|
|
152
|
-
.employee()
|
|
153
|
-
.where((e) => [expr.eq(e.name, "Gildong Hong"), expr.eq(e.departmentId, 1)])
|
|
154
|
-
.getUpsertQueryDef(
|
|
155
|
-
() => ({ managerId: expr.val("number", 10) }),
|
|
156
|
-
(upd) => ({
|
|
157
|
-
name: expr.val("string", "Gildong Hong"),
|
|
158
|
-
departmentId: expr.val("number", 1),
|
|
159
|
-
managerId: upd.managerId,
|
|
160
|
-
}),
|
|
161
|
-
);
|
|
162
|
-
|
|
163
|
-
it("Verify QueryDef", () => {
|
|
164
|
-
expect(def).toEqual({
|
|
165
|
-
type: "upsert",
|
|
166
|
-
table: { database: "TestDb", schema: "TestSchema", name: "Employee" },
|
|
167
|
-
existsSelectQuery: {
|
|
168
|
-
type: "select",
|
|
169
|
-
as: "T1",
|
|
170
|
-
from: { database: "TestDb", schema: "TestSchema", name: "Employee" },
|
|
171
|
-
where: [
|
|
172
|
-
{
|
|
173
|
-
type: "eq",
|
|
174
|
-
source: { type: "column", path: ["T1", "name"] },
|
|
175
|
-
target: { type: "value", value: "Gildong Hong" },
|
|
176
|
-
},
|
|
177
|
-
{
|
|
178
|
-
type: "eq",
|
|
179
|
-
source: { type: "column", path: ["T1", "departmentId"] },
|
|
180
|
-
target: { type: "value", value: 1 },
|
|
181
|
-
},
|
|
182
|
-
],
|
|
183
|
-
},
|
|
184
|
-
updateRecord: {
|
|
185
|
-
managerId: { type: "value", value: 10 },
|
|
186
|
-
},
|
|
187
|
-
insertRecord: {
|
|
188
|
-
name: { type: "value", value: "Gildong Hong" },
|
|
189
|
-
departmentId: { type: "value", value: 1 },
|
|
190
|
-
managerId: { type: "value", value: 10 },
|
|
191
|
-
},
|
|
192
|
-
});
|
|
193
|
-
});
|
|
194
|
-
|
|
195
|
-
it.each(dialects)("[%s] should validate SQL", (dialect) => {
|
|
196
|
-
const builder = createQueryBuilder(dialect);
|
|
197
|
-
expect(builder.build(def)).toMatchSql(expected.upsertMultiWhere[dialect]);
|
|
198
|
-
});
|
|
199
|
-
});
|
|
200
|
-
|
|
201
149
|
describe("UPSERT with literal values (without expr.val)", () => {
|
|
202
150
|
const db = createTestDb();
|
|
203
151
|
const def = db
|
|
@@ -10,9 +10,6 @@ describe("Queryable error cases", () => {
|
|
|
10
10
|
expect(() => expr.and([])).toThrow("empty arrays are not allowed");
|
|
11
11
|
});
|
|
12
12
|
|
|
13
|
-
it("ArgumentError when calling or() with empty array", () => {
|
|
14
|
-
expect(() => expr.or([])).toThrow("empty arrays are not allowed");
|
|
15
|
-
});
|
|
16
13
|
});
|
|
17
14
|
|
|
18
15
|
describe("executable errors", () => {
|
|
@@ -97,21 +94,6 @@ describe("Queryable error cases", () => {
|
|
|
97
94
|
}).toThrow("inQuery subquery must SELECT only a single column.");
|
|
98
95
|
});
|
|
99
96
|
|
|
100
|
-
it("Error when using subquery without column specification", () => {
|
|
101
|
-
const db = createTestDb();
|
|
102
|
-
|
|
103
|
-
expect(() => {
|
|
104
|
-
db.user()
|
|
105
|
-
.where((u) => [
|
|
106
|
-
expr.inQuery(
|
|
107
|
-
u.id,
|
|
108
|
-
// @ts-expect-error - subquery without SELECT
|
|
109
|
-
db.post(),
|
|
110
|
-
),
|
|
111
|
-
])
|
|
112
|
-
.getSelectQueryDef();
|
|
113
|
-
}).toThrow("inQuery subquery must SELECT only a single column.");
|
|
114
|
-
});
|
|
115
97
|
});
|
|
116
98
|
|
|
117
99
|
describe("countAsync() errors", () => {
|
|
@@ -141,37 +123,4 @@ describe("Queryable error cases", () => {
|
|
|
141
123
|
});
|
|
142
124
|
});
|
|
143
125
|
|
|
144
|
-
describe("RecursiveQueryable.union() errors", () => {
|
|
145
|
-
it("Error when calling union with a single queryable", () => {
|
|
146
|
-
const db = createTestDb();
|
|
147
|
-
|
|
148
|
-
expect(() => {
|
|
149
|
-
db.employee()
|
|
150
|
-
.where((e) => [expr.null(e.managerId)])
|
|
151
|
-
.recursive((cte) => cte.union(db.employee()));
|
|
152
|
-
}).toThrow("union requires at least 2 queryables.");
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
it("Error when calling union with zero queryables", () => {
|
|
156
|
-
const db = createTestDb();
|
|
157
|
-
|
|
158
|
-
expect(() => {
|
|
159
|
-
db.employee()
|
|
160
|
-
.where((e) => [expr.null(e.managerId)])
|
|
161
|
-
.recursive((cte) => cte.union());
|
|
162
|
-
}).toThrow("union requires at least 2 queryables.");
|
|
163
|
-
});
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
describe("JoinQueryable.union() errors", () => {
|
|
167
|
-
it("Error when calling union with a single queryable inside join", () => {
|
|
168
|
-
const db = createTestDb();
|
|
169
|
-
|
|
170
|
-
expect(() => {
|
|
171
|
-
db.user().join("posts", (j, u) =>
|
|
172
|
-
j.union(db.post().where((p) => [expr.eq(p.userId, u.id)])),
|
|
173
|
-
);
|
|
174
|
-
}).toThrow("union requires at least 2 queryables.");
|
|
175
|
-
});
|
|
176
|
-
});
|
|
177
126
|
});
|
package/tests/escape.spec.ts
CHANGED
|
@@ -23,45 +23,14 @@ describe("MysqlExprRenderer.escapeString", () => {
|
|
|
23
23
|
|
|
24
24
|
//#endregion
|
|
25
25
|
|
|
26
|
-
//#region ========== Control Character Escaping ==========
|
|
27
|
-
|
|
28
|
-
it("should escape newlines", () => {
|
|
29
|
-
const result = renderer.escapeString("line1\nline2");
|
|
30
|
-
expect(result).toBe("line1\\nline2");
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
it("should escape carriage returns", () => {
|
|
34
|
-
const result = renderer.escapeString("line1\rline2");
|
|
35
|
-
expect(result).toBe("line1\\rline2");
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
it("should escape tabs", () => {
|
|
39
|
-
const result = renderer.escapeString("col1\tcol2");
|
|
40
|
-
expect(result).toBe("col1\\tcol2");
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
//#endregion
|
|
44
|
-
|
|
45
26
|
//#region ========== Combined Attack Test ==========
|
|
46
27
|
|
|
47
|
-
it("should defend against SQL injection attempts", () => {
|
|
48
|
-
const malicious = "'; DROP TABLE users; --";
|
|
49
|
-
const result = renderer.escapeString(malicious);
|
|
50
|
-
expect(result).toBe("''; DROP TABLE users; --");
|
|
51
|
-
});
|
|
52
|
-
|
|
53
28
|
it("should defend against backslash + quote combination", () => {
|
|
54
29
|
const malicious = "\\'";
|
|
55
30
|
const result = renderer.escapeString(malicious);
|
|
56
31
|
expect(result).toBe("\\\\''");
|
|
57
32
|
});
|
|
58
33
|
|
|
59
|
-
it("should defend against NULL byte + SQL comment combination", () => {
|
|
60
|
-
const malicious = "admin\0-- ";
|
|
61
|
-
const result = renderer.escapeString(malicious);
|
|
62
|
-
expect(result).toBe("admin\\0-- ");
|
|
63
|
-
});
|
|
64
|
-
|
|
65
34
|
//#endregion
|
|
66
35
|
});
|
|
67
36
|
|
|
@@ -73,16 +42,6 @@ describe("MysqlExprRenderer.escapeValue", () => {
|
|
|
73
42
|
expect(result).toBe("'O''Reilly'");
|
|
74
43
|
});
|
|
75
44
|
|
|
76
|
-
it("correctly escapes string containing backslashes", () => {
|
|
77
|
-
const result = renderer.escapeValue("C:\\path");
|
|
78
|
-
expect(result).toBe("'C:\\\\path'");
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
it("defends against SQL injection attempts", () => {
|
|
82
|
-
const result = renderer.escapeValue("'; DROP TABLE users; --");
|
|
83
|
-
expect(result).toBe("'''; DROP TABLE users; --'");
|
|
84
|
-
});
|
|
85
|
-
|
|
86
45
|
it("returns 'NULL' string for null", () => {
|
|
87
46
|
const result = renderer.escapeValue(null);
|
|
88
47
|
expect(result).toBe("NULL");
|
|
@@ -68,339 +68,6 @@ describe("SELECT - PIVOT (groupBy + switch)", () => {
|
|
|
68
68
|
});
|
|
69
69
|
});
|
|
70
70
|
|
|
71
|
-
describe("COUNT", () => {
|
|
72
|
-
const db = createTestDb();
|
|
73
|
-
const def = db
|
|
74
|
-
.sales()
|
|
75
|
-
.groupBy((item) => [item.id, item.category])
|
|
76
|
-
.select((item) => ({
|
|
77
|
-
id: item.id,
|
|
78
|
-
category: item.category,
|
|
79
|
-
y2020: expr.count(expr.if(expr.eq(item.year, 2020), item.amount, undefined)),
|
|
80
|
-
y2021: expr.count(expr.if(expr.eq(item.year, 2021), item.amount, undefined)),
|
|
81
|
-
}))
|
|
82
|
-
.getSelectQueryDef();
|
|
83
|
-
|
|
84
|
-
it("Verify QueryDef", () => {
|
|
85
|
-
expect(def).toEqual({
|
|
86
|
-
type: "select",
|
|
87
|
-
as: "T1",
|
|
88
|
-
from: { database: "TestDb", schema: "TestSchema", name: "Sales" },
|
|
89
|
-
groupBy: [
|
|
90
|
-
{ type: "column", path: ["T1", "id"] },
|
|
91
|
-
{ type: "column", path: ["T1", "category"] },
|
|
92
|
-
],
|
|
93
|
-
select: {
|
|
94
|
-
id: { type: "column", path: ["T1", "id"] },
|
|
95
|
-
category: { type: "column", path: ["T1", "category"] },
|
|
96
|
-
y2020: {
|
|
97
|
-
type: "count",
|
|
98
|
-
arg: {
|
|
99
|
-
type: "if",
|
|
100
|
-
condition: {
|
|
101
|
-
type: "eq",
|
|
102
|
-
source: { type: "column", path: ["T1", "year"] },
|
|
103
|
-
target: { type: "value", value: 2020 },
|
|
104
|
-
},
|
|
105
|
-
then: { type: "column", path: ["T1", "amount"] },
|
|
106
|
-
else: { type: "value", value: undefined },
|
|
107
|
-
},
|
|
108
|
-
},
|
|
109
|
-
y2021: {
|
|
110
|
-
type: "count",
|
|
111
|
-
arg: {
|
|
112
|
-
type: "if",
|
|
113
|
-
condition: {
|
|
114
|
-
type: "eq",
|
|
115
|
-
source: { type: "column", path: ["T1", "year"] },
|
|
116
|
-
target: { type: "value", value: 2021 },
|
|
117
|
-
},
|
|
118
|
-
then: { type: "column", path: ["T1", "amount"] },
|
|
119
|
-
else: { type: "value", value: undefined },
|
|
120
|
-
},
|
|
121
|
-
},
|
|
122
|
-
},
|
|
123
|
-
});
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
it.each(dialects)("[%s] Verify SQL", (dialect) => {
|
|
127
|
-
const builder = createQueryBuilder(dialect);
|
|
128
|
-
expect(builder.build(def)).toMatchSql(expected.pivotCount[dialect]);
|
|
129
|
-
});
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
describe("AVG", () => {
|
|
133
|
-
const db = createTestDb();
|
|
134
|
-
const def = db
|
|
135
|
-
.sales()
|
|
136
|
-
.groupBy((item) => [item.id, item.category])
|
|
137
|
-
.select((item) => ({
|
|
138
|
-
id: item.id,
|
|
139
|
-
category: item.category,
|
|
140
|
-
y2020: expr.avg(expr.if(expr.eq(item.year, 2020), item.amount, undefined)),
|
|
141
|
-
y2021: expr.avg(expr.if(expr.eq(item.year, 2021), item.amount, undefined)),
|
|
142
|
-
}))
|
|
143
|
-
.getSelectQueryDef();
|
|
144
|
-
|
|
145
|
-
it("Verify QueryDef", () => {
|
|
146
|
-
expect(def).toEqual({
|
|
147
|
-
type: "select",
|
|
148
|
-
as: "T1",
|
|
149
|
-
from: { database: "TestDb", schema: "TestSchema", name: "Sales" },
|
|
150
|
-
groupBy: [
|
|
151
|
-
{ type: "column", path: ["T1", "id"] },
|
|
152
|
-
{ type: "column", path: ["T1", "category"] },
|
|
153
|
-
],
|
|
154
|
-
select: {
|
|
155
|
-
id: { type: "column", path: ["T1", "id"] },
|
|
156
|
-
category: { type: "column", path: ["T1", "category"] },
|
|
157
|
-
y2020: {
|
|
158
|
-
type: "avg",
|
|
159
|
-
arg: {
|
|
160
|
-
type: "if",
|
|
161
|
-
condition: {
|
|
162
|
-
type: "eq",
|
|
163
|
-
source: { type: "column", path: ["T1", "year"] },
|
|
164
|
-
target: { type: "value", value: 2020 },
|
|
165
|
-
},
|
|
166
|
-
then: { type: "column", path: ["T1", "amount"] },
|
|
167
|
-
else: { type: "value", value: undefined },
|
|
168
|
-
},
|
|
169
|
-
},
|
|
170
|
-
y2021: {
|
|
171
|
-
type: "avg",
|
|
172
|
-
arg: {
|
|
173
|
-
type: "if",
|
|
174
|
-
condition: {
|
|
175
|
-
type: "eq",
|
|
176
|
-
source: { type: "column", path: ["T1", "year"] },
|
|
177
|
-
target: { type: "value", value: 2021 },
|
|
178
|
-
},
|
|
179
|
-
then: { type: "column", path: ["T1", "amount"] },
|
|
180
|
-
else: { type: "value", value: undefined },
|
|
181
|
-
},
|
|
182
|
-
},
|
|
183
|
-
},
|
|
184
|
-
});
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
it.each(dialects)("[%s] Verify SQL", (dialect) => {
|
|
188
|
-
const builder = createQueryBuilder(dialect);
|
|
189
|
-
expect(builder.build(def)).toMatchSql(expected.pivotAvg[dialect]);
|
|
190
|
-
});
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
describe("MAX", () => {
|
|
194
|
-
const db = createTestDb();
|
|
195
|
-
const def = db
|
|
196
|
-
.sales()
|
|
197
|
-
.groupBy((item) => [item.id, item.category])
|
|
198
|
-
.select((item) => ({
|
|
199
|
-
id: item.id,
|
|
200
|
-
category: item.category,
|
|
201
|
-
y2020: expr.max(expr.if(expr.eq(item.year, 2020), item.amount, undefined)),
|
|
202
|
-
y2021: expr.max(expr.if(expr.eq(item.year, 2021), item.amount, undefined)),
|
|
203
|
-
}))
|
|
204
|
-
.getSelectQueryDef();
|
|
205
|
-
|
|
206
|
-
it("Verify QueryDef", () => {
|
|
207
|
-
expect(def).toEqual({
|
|
208
|
-
type: "select",
|
|
209
|
-
as: "T1",
|
|
210
|
-
from: { database: "TestDb", schema: "TestSchema", name: "Sales" },
|
|
211
|
-
groupBy: [
|
|
212
|
-
{ type: "column", path: ["T1", "id"] },
|
|
213
|
-
{ type: "column", path: ["T1", "category"] },
|
|
214
|
-
],
|
|
215
|
-
select: {
|
|
216
|
-
id: { type: "column", path: ["T1", "id"] },
|
|
217
|
-
category: { type: "column", path: ["T1", "category"] },
|
|
218
|
-
y2020: {
|
|
219
|
-
type: "max",
|
|
220
|
-
arg: {
|
|
221
|
-
type: "if",
|
|
222
|
-
condition: {
|
|
223
|
-
type: "eq",
|
|
224
|
-
source: { type: "column", path: ["T1", "year"] },
|
|
225
|
-
target: { type: "value", value: 2020 },
|
|
226
|
-
},
|
|
227
|
-
then: { type: "column", path: ["T1", "amount"] },
|
|
228
|
-
else: { type: "value", value: undefined },
|
|
229
|
-
},
|
|
230
|
-
},
|
|
231
|
-
y2021: {
|
|
232
|
-
type: "max",
|
|
233
|
-
arg: {
|
|
234
|
-
type: "if",
|
|
235
|
-
condition: {
|
|
236
|
-
type: "eq",
|
|
237
|
-
source: { type: "column", path: ["T1", "year"] },
|
|
238
|
-
target: { type: "value", value: 2021 },
|
|
239
|
-
},
|
|
240
|
-
then: { type: "column", path: ["T1", "amount"] },
|
|
241
|
-
else: { type: "value", value: undefined },
|
|
242
|
-
},
|
|
243
|
-
},
|
|
244
|
-
},
|
|
245
|
-
});
|
|
246
|
-
});
|
|
247
|
-
|
|
248
|
-
it.each(dialects)("[%s] Verify SQL", (dialect) => {
|
|
249
|
-
const builder = createQueryBuilder(dialect);
|
|
250
|
-
expect(builder.build(def)).toMatchSql(expected.pivotMax[dialect]);
|
|
251
|
-
});
|
|
252
|
-
});
|
|
253
|
-
|
|
254
|
-
describe("MIN", () => {
|
|
255
|
-
const db = createTestDb();
|
|
256
|
-
const def = db
|
|
257
|
-
.sales()
|
|
258
|
-
.groupBy((item) => [item.id, item.category])
|
|
259
|
-
.select((item) => ({
|
|
260
|
-
id: item.id,
|
|
261
|
-
category: item.category,
|
|
262
|
-
y2020: expr.min(expr.if(expr.eq(item.year, 2020), item.amount, undefined)),
|
|
263
|
-
y2021: expr.min(expr.if(expr.eq(item.year, 2021), item.amount, undefined)),
|
|
264
|
-
}))
|
|
265
|
-
.getSelectQueryDef();
|
|
266
|
-
|
|
267
|
-
it("Verify QueryDef", () => {
|
|
268
|
-
expect(def).toEqual({
|
|
269
|
-
type: "select",
|
|
270
|
-
as: "T1",
|
|
271
|
-
from: { database: "TestDb", schema: "TestSchema", name: "Sales" },
|
|
272
|
-
groupBy: [
|
|
273
|
-
{ type: "column", path: ["T1", "id"] },
|
|
274
|
-
{ type: "column", path: ["T1", "category"] },
|
|
275
|
-
],
|
|
276
|
-
select: {
|
|
277
|
-
id: { type: "column", path: ["T1", "id"] },
|
|
278
|
-
category: { type: "column", path: ["T1", "category"] },
|
|
279
|
-
y2020: {
|
|
280
|
-
type: "min",
|
|
281
|
-
arg: {
|
|
282
|
-
type: "if",
|
|
283
|
-
condition: {
|
|
284
|
-
type: "eq",
|
|
285
|
-
source: { type: "column", path: ["T1", "year"] },
|
|
286
|
-
target: { type: "value", value: 2020 },
|
|
287
|
-
},
|
|
288
|
-
then: { type: "column", path: ["T1", "amount"] },
|
|
289
|
-
else: { type: "value", value: undefined },
|
|
290
|
-
},
|
|
291
|
-
},
|
|
292
|
-
y2021: {
|
|
293
|
-
type: "min",
|
|
294
|
-
arg: {
|
|
295
|
-
type: "if",
|
|
296
|
-
condition: {
|
|
297
|
-
type: "eq",
|
|
298
|
-
source: { type: "column", path: ["T1", "year"] },
|
|
299
|
-
target: { type: "value", value: 2021 },
|
|
300
|
-
},
|
|
301
|
-
then: { type: "column", path: ["T1", "amount"] },
|
|
302
|
-
else: { type: "value", value: undefined },
|
|
303
|
-
},
|
|
304
|
-
},
|
|
305
|
-
},
|
|
306
|
-
});
|
|
307
|
-
});
|
|
308
|
-
|
|
309
|
-
it.each(dialects)("[%s] Verify SQL", (dialect) => {
|
|
310
|
-
const builder = createQueryBuilder(dialect);
|
|
311
|
-
expect(builder.build(def)).toMatchSql(expected.pivotMin[dialect]);
|
|
312
|
-
});
|
|
313
|
-
});
|
|
314
|
-
|
|
315
|
-
describe("3 or more pivot values", () => {
|
|
316
|
-
const db = createTestDb();
|
|
317
|
-
const def = db
|
|
318
|
-
.sales()
|
|
319
|
-
.groupBy((item) => [item.id, item.category])
|
|
320
|
-
.select((item) => ({
|
|
321
|
-
id: item.id,
|
|
322
|
-
category: item.category,
|
|
323
|
-
y2019: expr.sum(expr.if(expr.eq(item.year, 2019), item.amount, undefined)),
|
|
324
|
-
y2020: expr.sum(expr.if(expr.eq(item.year, 2020), item.amount, undefined)),
|
|
325
|
-
y2021: expr.sum(expr.if(expr.eq(item.year, 2021), item.amount, undefined)),
|
|
326
|
-
y2022: expr.sum(expr.if(expr.eq(item.year, 2022), item.amount, undefined)),
|
|
327
|
-
}))
|
|
328
|
-
.getSelectQueryDef();
|
|
329
|
-
|
|
330
|
-
it("Verify QueryDef", () => {
|
|
331
|
-
expect(def).toEqual({
|
|
332
|
-
type: "select",
|
|
333
|
-
as: "T1",
|
|
334
|
-
from: { database: "TestDb", schema: "TestSchema", name: "Sales" },
|
|
335
|
-
groupBy: [
|
|
336
|
-
{ type: "column", path: ["T1", "id"] },
|
|
337
|
-
{ type: "column", path: ["T1", "category"] },
|
|
338
|
-
],
|
|
339
|
-
select: {
|
|
340
|
-
id: { type: "column", path: ["T1", "id"] },
|
|
341
|
-
category: { type: "column", path: ["T1", "category"] },
|
|
342
|
-
y2019: {
|
|
343
|
-
type: "sum",
|
|
344
|
-
arg: {
|
|
345
|
-
type: "if",
|
|
346
|
-
condition: {
|
|
347
|
-
type: "eq",
|
|
348
|
-
source: { type: "column", path: ["T1", "year"] },
|
|
349
|
-
target: { type: "value", value: 2019 },
|
|
350
|
-
},
|
|
351
|
-
then: { type: "column", path: ["T1", "amount"] },
|
|
352
|
-
else: { type: "value", value: undefined },
|
|
353
|
-
},
|
|
354
|
-
},
|
|
355
|
-
y2020: {
|
|
356
|
-
type: "sum",
|
|
357
|
-
arg: {
|
|
358
|
-
type: "if",
|
|
359
|
-
condition: {
|
|
360
|
-
type: "eq",
|
|
361
|
-
source: { type: "column", path: ["T1", "year"] },
|
|
362
|
-
target: { type: "value", value: 2020 },
|
|
363
|
-
},
|
|
364
|
-
then: { type: "column", path: ["T1", "amount"] },
|
|
365
|
-
else: { type: "value", value: undefined },
|
|
366
|
-
},
|
|
367
|
-
},
|
|
368
|
-
y2021: {
|
|
369
|
-
type: "sum",
|
|
370
|
-
arg: {
|
|
371
|
-
type: "if",
|
|
372
|
-
condition: {
|
|
373
|
-
type: "eq",
|
|
374
|
-
source: { type: "column", path: ["T1", "year"] },
|
|
375
|
-
target: { type: "value", value: 2021 },
|
|
376
|
-
},
|
|
377
|
-
then: { type: "column", path: ["T1", "amount"] },
|
|
378
|
-
else: { type: "value", value: undefined },
|
|
379
|
-
},
|
|
380
|
-
},
|
|
381
|
-
y2022: {
|
|
382
|
-
type: "sum",
|
|
383
|
-
arg: {
|
|
384
|
-
type: "if",
|
|
385
|
-
condition: {
|
|
386
|
-
type: "eq",
|
|
387
|
-
source: { type: "column", path: ["T1", "year"] },
|
|
388
|
-
target: { type: "value", value: 2022 },
|
|
389
|
-
},
|
|
390
|
-
then: { type: "column", path: ["T1", "amount"] },
|
|
391
|
-
else: { type: "value", value: undefined },
|
|
392
|
-
},
|
|
393
|
-
},
|
|
394
|
-
},
|
|
395
|
-
});
|
|
396
|
-
});
|
|
397
|
-
|
|
398
|
-
it.each(dialects)("[%s] Verify SQL", (dialect) => {
|
|
399
|
-
const builder = createQueryBuilder(dialect);
|
|
400
|
-
expect(builder.build(def)).toMatchSql(expected.pivotMultipleYears[dialect]);
|
|
401
|
-
});
|
|
402
|
-
});
|
|
403
|
-
|
|
404
71
|
describe("String pivot column", () => {
|
|
405
72
|
const db = createTestDb();
|
|
406
73
|
const def = db
|