@proteinjs/db 1.19.0 → 1.20.1
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/CHANGELOG.md +16 -0
- package/dist/generated/index.js +1 -1
- package/dist/generated/index.js.map +1 -1
- package/dist/generated/test/index.d.ts +1 -1
- package/dist/generated/test/index.d.ts.map +1 -1
- package/dist/generated/test/index.js +52 -34
- package/dist/generated/test/index.js.map +1 -1
- package/dist/index.d.ts +0 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -6
- package/dist/index.js.map +1 -1
- package/dist/src/Db.d.ts +2 -2
- package/dist/src/Db.d.ts.map +1 -1
- package/dist/src/Db.js +6 -3
- package/dist/src/Db.js.map +1 -1
- package/dist/src/TableWatcherRunner.d.ts.map +1 -1
- package/dist/src/TableWatcherRunner.js +4 -1
- package/dist/src/TableWatcherRunner.js.map +1 -1
- package/dist/src/schema/TableManager.d.ts.map +1 -1
- package/dist/src/schema/TableManager.js +4 -1
- package/dist/src/schema/TableManager.js.map +1 -1
- package/dist/test/index.d.ts +13 -0
- package/dist/test/index.d.ts.map +1 -0
- package/dist/test/index.js +29 -0
- package/dist/test/index.js.map +1 -0
- package/dist/test/reusable/CascadeDeleteTests.d.ts +1 -189
- package/dist/test/reusable/CascadeDeleteTests.d.ts.map +1 -1
- package/dist/test/reusable/CascadeDeleteTests.js +36 -393
- package/dist/test/reusable/CascadeDeleteTests.js.map +1 -1
- package/dist/test/reusable/ColumnTypesTests.d.ts +1 -52
- package/dist/test/reusable/ColumnTypesTests.d.ts.map +1 -1
- package/dist/test/reusable/ColumnTypesTests.js +20 -86
- package/dist/test/reusable/ColumnTypesTests.js.map +1 -1
- package/dist/test/reusable/CrudTests.d.ts +1 -50
- package/dist/test/reusable/CrudTests.d.ts.map +1 -1
- package/dist/test/reusable/CrudTests.js +37 -126
- package/dist/test/reusable/CrudTests.js.map +1 -1
- package/dist/test/reusable/DynamicReferenceColumnTests.d.ts +3 -0
- package/dist/test/reusable/DynamicReferenceColumnTests.d.ts.map +1 -0
- package/dist/test/reusable/DynamicReferenceColumnTests.js +429 -0
- package/dist/test/reusable/DynamicReferenceColumnTests.js.map +1 -0
- package/dist/test/reusable/TableManagerTests.d.ts +1 -2
- package/dist/test/reusable/TableManagerTests.d.ts.map +1 -1
- package/dist/test/reusable/TableManagerTests.js +57 -152
- package/dist/test/reusable/TableManagerTests.js.map +1 -1
- package/dist/test/reusable/TransactionTests.d.ts +1 -51
- package/dist/test/reusable/TransactionTests.d.ts.map +1 -1
- package/dist/test/reusable/TransactionTests.js +24 -111
- package/dist/test/reusable/TransactionTests.js.map +1 -1
- package/dist/test/util/DbTestEnvironment.d.ts +12 -0
- package/dist/test/util/DbTestEnvironment.d.ts.map +1 -0
- package/dist/test/util/DbTestEnvironment.js +125 -0
- package/dist/test/util/DbTestEnvironment.js.map +1 -0
- package/dist/test/util/tables/cascadeDeleteTestTables.d.ts +191 -0
- package/dist/test/util/tables/cascadeDeleteTestTables.d.ts.map +1 -0
- package/dist/test/util/tables/cascadeDeleteTestTables.js +234 -0
- package/dist/test/util/tables/cascadeDeleteTestTables.js.map +1 -0
- package/dist/test/util/tables/columnTypesTestTables.d.ts +47 -0
- package/dist/test/util/tables/columnTypesTestTables.d.ts.map +1 -0
- package/dist/test/util/tables/columnTypesTestTables.js +49 -0
- package/dist/test/util/tables/columnTypesTestTables.js.map +1 -0
- package/dist/test/util/tables/crudTestTables.d.ts +48 -0
- package/dist/test/util/tables/crudTestTables.d.ts.map +1 -0
- package/dist/test/util/tables/crudTestTables.js +58 -0
- package/dist/test/util/tables/crudTestTables.js.map +1 -0
- package/dist/test/util/tables/dynamicReferenceColumnTestTables.d.ts +76 -0
- package/dist/test/util/tables/dynamicReferenceColumnTestTables.d.ts.map +1 -0
- package/dist/test/util/tables/dynamicReferenceColumnTestTables.js +131 -0
- package/dist/test/util/tables/dynamicReferenceColumnTestTables.js.map +1 -0
- package/dist/test/util/tables/tableManagerTestTables.d.ts +86 -0
- package/dist/test/util/tables/tableManagerTestTables.d.ts.map +1 -0
- package/dist/test/util/tables/tableManagerTestTables.js +131 -0
- package/dist/test/util/tables/tableManagerTestTables.js.map +1 -0
- package/dist/test/util/tables/transactionTestTables.d.ts +48 -0
- package/dist/test/util/tables/transactionTestTables.d.ts.map +1 -0
- package/dist/test/util/tables/transactionTestTables.js +58 -0
- package/dist/test/util/tables/transactionTestTables.js.map +1 -0
- package/generated/index.ts +18 -15
- package/generated/test/index.ts +67 -46
- package/index.ts +0 -7
- package/package.json +29 -17
- package/src/Db.ts +8 -3
- package/src/TableWatcherRunner.ts +4 -1
- package/src/schema/TableManager.ts +4 -1
- package/test/index.ts +13 -0
- package/test/reusable/CascadeDeleteTests.ts +38 -320
- package/test/reusable/ColumnTypesTests.ts +9 -85
- package/test/reusable/CrudTests.ts +26 -97
- package/test/reusable/DynamicReferenceColumnTests.ts +342 -0
- package/test/reusable/TableManagerTests.ts +18 -97
- package/test/reusable/TransactionTests.ts +26 -93
- package/test/util/DbTestEnvironment.ts +46 -0
- package/test/util/tables/cascadeDeleteTestTables.ts +232 -0
- package/test/util/tables/columnTypesTestTables.ts +63 -0
- package/test/util/tables/crudTestTables.ts +44 -0
- package/test/util/tables/dynamicReferenceColumnTestTables.ts +87 -0
- package/test/util/tables/tableManagerTestTables.ts +98 -0
- package/test/util/tables/transactionTestTables.ts +44 -0
- package/tsconfig.json +7 -1
- package/LICENSE +0 -21
- package/dist/test/reusable/DynamicReferenceColumn.d.ts +0 -77
- package/dist/test/reusable/DynamicReferenceColumn.d.ts.map +0 -1
- package/dist/test/reusable/DynamicReferenceColumn.js +0 -656
- package/dist/test/reusable/DynamicReferenceColumn.js.map +0 -1
- package/test/reusable/DynamicReferenceColumn.ts +0 -487
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
import { Db, DbDriver, Reference, Table } from '@proteinjs/db';
|
|
2
|
+
import { QueryBuilder } from '@proteinjs/db-query';
|
|
3
|
+
import { DbTestEnvironment } from '../util/DbTestEnvironment';
|
|
4
|
+
import {
|
|
5
|
+
Designer,
|
|
6
|
+
dynamicReferenceTestTables,
|
|
7
|
+
Engineer,
|
|
8
|
+
ProjectAssignment,
|
|
9
|
+
ProjectManager,
|
|
10
|
+
} from '../util/tables/dynamicReferenceColumnTestTables';
|
|
11
|
+
|
|
12
|
+
export const dynamicReferenceColumnTests = (driver: DbDriver, dropTable: (table: Table<any>) => Promise<void>) => {
|
|
13
|
+
return () => {
|
|
14
|
+
const db = new Db(driver);
|
|
15
|
+
const testEnv = new DbTestEnvironment(driver, dropTable);
|
|
16
|
+
|
|
17
|
+
beforeAll(async () => await testEnv.beforeAll(), 10000);
|
|
18
|
+
afterAll(async () => await testEnv.afterAll(), 10000);
|
|
19
|
+
|
|
20
|
+
test('should handle references to different types', async () => {
|
|
21
|
+
// Create an engineer
|
|
22
|
+
const engineer = await db.insert(dynamicReferenceTestTables.Engineer, {
|
|
23
|
+
name: 'John Doe',
|
|
24
|
+
yearsOfExperience: 5,
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
// Create a designer
|
|
28
|
+
const designer = await db.insert(dynamicReferenceTestTables.Designer, {
|
|
29
|
+
name: 'Jane Smith',
|
|
30
|
+
specialization: 'UI/UX',
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// Assign both to different projects
|
|
34
|
+
const engineerAssignment = await db.insert(dynamicReferenceTestTables.ProjectAssignment, {
|
|
35
|
+
projectName: 'Backend API',
|
|
36
|
+
employeeRef: new Reference(dynamicReferenceTestTables.Engineer.name, engineer.id),
|
|
37
|
+
startDate: '2024-01-01',
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
const designerAssignment = await db.insert(dynamicReferenceTestTables.ProjectAssignment, {
|
|
41
|
+
projectName: 'Website Redesign',
|
|
42
|
+
employeeRef: new Reference(dynamicReferenceTestTables.Designer.name, designer.id),
|
|
43
|
+
startDate: '2024-01-15',
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
// Verify engineer assignment
|
|
47
|
+
const fetchedEngineerAssignment = await db.get(dynamicReferenceTestTables.ProjectAssignment, {
|
|
48
|
+
id: engineerAssignment.id,
|
|
49
|
+
});
|
|
50
|
+
expect(fetchedEngineerAssignment.employeeRef?._table).toBe(dynamicReferenceTestTables.Engineer.name);
|
|
51
|
+
expect(fetchedEngineerAssignment.employeeRef?._id).toBe(engineer.id);
|
|
52
|
+
expect(fetchedEngineerAssignment.employeeTableName).toBe(dynamicReferenceTestTables.Engineer.name);
|
|
53
|
+
|
|
54
|
+
// Verify designer assignment
|
|
55
|
+
const fetchedDesignerAssignment = await db.get(dynamicReferenceTestTables.ProjectAssignment, {
|
|
56
|
+
id: designerAssignment.id,
|
|
57
|
+
});
|
|
58
|
+
expect(fetchedDesignerAssignment.employeeRef?._table).toBe(dynamicReferenceTestTables.Designer.name);
|
|
59
|
+
expect(fetchedDesignerAssignment.employeeRef?._id).toBe(designer.id);
|
|
60
|
+
expect(fetchedDesignerAssignment.employeeTableName).toBe(dynamicReferenceTestTables.Designer.name);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
test('should cascade delete multiple types of records when references are deleted', async () => {
|
|
64
|
+
// Create employees
|
|
65
|
+
const engineer = await db.insert(dynamicReferenceTestTables.Engineer, {
|
|
66
|
+
name: 'John Doe',
|
|
67
|
+
yearsOfExperience: 5,
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
const projectManager = await db.insert(dynamicReferenceTestTables.ProjectManager, {
|
|
71
|
+
name: 'Alice Brown',
|
|
72
|
+
certificate: 'Scrum Master',
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
const designer = await db.insert(dynamicReferenceTestTables.Designer, {
|
|
76
|
+
name: 'Jane Smith',
|
|
77
|
+
specialization: 'UI/UX',
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
// Create assignments
|
|
81
|
+
const engineerAssignment = await db.insert(dynamicReferenceTestTables.ProjectAssignment, {
|
|
82
|
+
projectName: 'Backend API',
|
|
83
|
+
employeeRef: new Reference<Engineer>(dynamicReferenceTestTables.Engineer.name, engineer.id),
|
|
84
|
+
startDate: '2024-01-01',
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
const pmAssignment = await db.insert(dynamicReferenceTestTables.ProjectAssignment, {
|
|
88
|
+
projectName: 'Project Planning',
|
|
89
|
+
employeeRef: new Reference<ProjectManager>(dynamicReferenceTestTables.ProjectManager.name, projectManager.id),
|
|
90
|
+
startDate: '2024-01-10',
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
const designerAssignment = await db.insert(dynamicReferenceTestTables.ProjectAssignment, {
|
|
94
|
+
projectName: 'Website Redesign',
|
|
95
|
+
employeeRef: new Reference<Designer>(dynamicReferenceTestTables.Designer.name, designer.id),
|
|
96
|
+
startDate: '2024-01-15',
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
// Delete the engineer's and PM's assignments - should cascade delete both
|
|
100
|
+
const deleteQuery = new QueryBuilder<ProjectAssignment>(
|
|
101
|
+
dynamicReferenceTestTables.ProjectAssignment.name
|
|
102
|
+
).condition({
|
|
103
|
+
field: 'id',
|
|
104
|
+
operator: 'IN',
|
|
105
|
+
value: [engineerAssignment.id, pmAssignment.id],
|
|
106
|
+
});
|
|
107
|
+
const recordsDeleted = await db.delete(dynamicReferenceTestTables.ProjectAssignment, deleteQuery);
|
|
108
|
+
|
|
109
|
+
expect(recordsDeleted).toBe(2);
|
|
110
|
+
|
|
111
|
+
// Verify engineer and PM were deleted but designer remains
|
|
112
|
+
const remainingEngineers = await db.query(dynamicReferenceTestTables.Engineer, { id: engineer.id });
|
|
113
|
+
expect(remainingEngineers.length).toBe(0); // Engineer should be deleted
|
|
114
|
+
|
|
115
|
+
const remainingPMs = await db.query(dynamicReferenceTestTables.ProjectManager, { id: projectManager.id });
|
|
116
|
+
expect(remainingPMs.length).toBe(0); // PM should be deleted
|
|
117
|
+
|
|
118
|
+
const remainingDesigners = await db.query(dynamicReferenceTestTables.Designer, { id: designer.id });
|
|
119
|
+
expect(remainingDesigners.length).toBe(1); // Designer should still exist
|
|
120
|
+
expect(remainingDesigners[0].id).toBe(designer.id);
|
|
121
|
+
|
|
122
|
+
// Only designer assignment should still exist
|
|
123
|
+
const remainingAssignmentsQuery = new QueryBuilder<ProjectAssignment>(
|
|
124
|
+
dynamicReferenceTestTables.ProjectAssignment.name
|
|
125
|
+
).condition({
|
|
126
|
+
field: 'id',
|
|
127
|
+
operator: 'IN',
|
|
128
|
+
value: [engineerAssignment.id, pmAssignment.id, designerAssignment.id],
|
|
129
|
+
});
|
|
130
|
+
const remainingAssignments = await db.query(
|
|
131
|
+
dynamicReferenceTestTables.ProjectAssignment,
|
|
132
|
+
remainingAssignmentsQuery
|
|
133
|
+
);
|
|
134
|
+
expect(remainingAssignments.length).toBe(1);
|
|
135
|
+
expect(remainingAssignments[0].id).toBe(designerAssignment.id);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
test('should allow changing table name when updating reference to new type', async () => {
|
|
139
|
+
// Create employees
|
|
140
|
+
const engineer = await db.insert(dynamicReferenceTestTables.Engineer, {
|
|
141
|
+
name: 'John Doe',
|
|
142
|
+
yearsOfExperience: 5,
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
const designer = await db.insert(dynamicReferenceTestTables.Designer, {
|
|
146
|
+
name: 'Jane Smith',
|
|
147
|
+
specialization: 'UI/UX',
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
// Create initial assignment to engineer
|
|
151
|
+
const assignment = await db.insert(dynamicReferenceTestTables.ProjectAssignment, {
|
|
152
|
+
projectName: 'Full Stack App',
|
|
153
|
+
employeeRef: new Reference(dynamicReferenceTestTables.Engineer.name, engineer.id),
|
|
154
|
+
startDate: '2024-01-01',
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
// Reassign to designer
|
|
158
|
+
await db.update(
|
|
159
|
+
dynamicReferenceTestTables.ProjectAssignment,
|
|
160
|
+
{
|
|
161
|
+
employeeRef: new Reference(dynamicReferenceTestTables.Designer.name, designer.id),
|
|
162
|
+
},
|
|
163
|
+
{ id: assignment.id }
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
// Verify reassignment
|
|
167
|
+
const updatedAssignment = await db.get(dynamicReferenceTestTables.ProjectAssignment, { id: assignment.id });
|
|
168
|
+
expect(updatedAssignment.employeeRef).toBeDefined();
|
|
169
|
+
expect(updatedAssignment.employeeRef?._table).toBe(dynamicReferenceTestTables.Designer.name);
|
|
170
|
+
expect(updatedAssignment.employeeRef?._id).toBe(designer.id);
|
|
171
|
+
expect(updatedAssignment.employeeTableName).toBe(dynamicReferenceTestTables.Designer.name);
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
describe('DynamicReferenceTableNameColumn behavior', () => {
|
|
175
|
+
test('should handle defaultValue logic correctly', async () => {
|
|
176
|
+
// Test case 1: Reference column is populated
|
|
177
|
+
const engineer = await db.insert(dynamicReferenceTestTables.Engineer, {
|
|
178
|
+
name: 'John Doe',
|
|
179
|
+
yearsOfExperience: 5,
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
const assignment = await db.insert(dynamicReferenceTestTables.ProjectAssignment, {
|
|
183
|
+
projectName: 'Test Project',
|
|
184
|
+
employeeRef: new Reference(dynamicReferenceTestTables.Engineer.name, engineer.id),
|
|
185
|
+
startDate: '2024-01-01',
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
// Verify table name was set correctly from reference
|
|
189
|
+
expect(assignment.employeeTableName).toBe(dynamicReferenceTestTables.Engineer.name);
|
|
190
|
+
|
|
191
|
+
// Test case 2: Reference column is null
|
|
192
|
+
const assignmentNoRef = await db.insert(dynamicReferenceTestTables.ProjectAssignment, {
|
|
193
|
+
projectName: 'No Reference Project',
|
|
194
|
+
employeeRef: null,
|
|
195
|
+
startDate: '2024-01-01',
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
// Verify table name is null when reference is null
|
|
199
|
+
expect(assignmentNoRef.employeeTableName).toBeNull();
|
|
200
|
+
|
|
201
|
+
// Test case 3: Reference without table name should throw
|
|
202
|
+
await expect(
|
|
203
|
+
db.insert(dynamicReferenceTestTables.ProjectAssignment, {
|
|
204
|
+
projectName: 'Invalid Reference',
|
|
205
|
+
employeeRef: new Reference('', engineer.id), // Empty table name
|
|
206
|
+
startDate: '2024-01-01',
|
|
207
|
+
})
|
|
208
|
+
).rejects.toThrow(/table name must be set in Reference object/);
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
test('should handle updateValue logic correctly', async () => {
|
|
212
|
+
// Create initial records
|
|
213
|
+
const engineer = await db.insert(dynamicReferenceTestTables.Engineer, {
|
|
214
|
+
name: 'John Doe',
|
|
215
|
+
yearsOfExperience: 5,
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
const designer = await db.insert(dynamicReferenceTestTables.Designer, {
|
|
219
|
+
name: 'Jane Smith',
|
|
220
|
+
specialization: 'UI/UX',
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
const assignment = await db.insert(dynamicReferenceTestTables.ProjectAssignment, {
|
|
224
|
+
projectName: 'Initial Project',
|
|
225
|
+
employeeRef: new Reference(dynamicReferenceTestTables.Engineer.name, engineer.id),
|
|
226
|
+
startDate: '2024-01-01',
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
// Test case 1: Update reference to new table
|
|
230
|
+
await db.update(
|
|
231
|
+
dynamicReferenceTestTables.ProjectAssignment,
|
|
232
|
+
{
|
|
233
|
+
employeeRef: new Reference(dynamicReferenceTestTables.Designer.name, designer.id),
|
|
234
|
+
},
|
|
235
|
+
{ id: assignment.id }
|
|
236
|
+
);
|
|
237
|
+
|
|
238
|
+
const updatedAssignment = await db.get(dynamicReferenceTestTables.ProjectAssignment, { id: assignment.id });
|
|
239
|
+
expect(updatedAssignment.employeeTableName).toBe(dynamicReferenceTestTables.Designer.name);
|
|
240
|
+
|
|
241
|
+
// Test case 2: Update without changing reference
|
|
242
|
+
await db.update(
|
|
243
|
+
dynamicReferenceTestTables.ProjectAssignment,
|
|
244
|
+
{
|
|
245
|
+
projectName: 'Updated Project Name',
|
|
246
|
+
},
|
|
247
|
+
{ id: assignment.id }
|
|
248
|
+
);
|
|
249
|
+
|
|
250
|
+
const unchangedAssignment = await db.get(dynamicReferenceTestTables.ProjectAssignment, { id: assignment.id });
|
|
251
|
+
expect(unchangedAssignment.employeeTableName).toBe(dynamicReferenceTestTables.Designer.name); // Should retain previous value
|
|
252
|
+
|
|
253
|
+
// Test case 3: Update with invalid reference should throw
|
|
254
|
+
await expect(
|
|
255
|
+
db.update(
|
|
256
|
+
dynamicReferenceTestTables.ProjectAssignment,
|
|
257
|
+
{
|
|
258
|
+
employeeRef: new Reference('', designer.id), // Empty table name
|
|
259
|
+
},
|
|
260
|
+
{ id: assignment.id }
|
|
261
|
+
)
|
|
262
|
+
).rejects.toThrow(/table name must be set in Reference object/);
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
test('should handle null references correctly', async () => {
|
|
266
|
+
// Create initial assignment with reference
|
|
267
|
+
const engineer = await db.insert(dynamicReferenceTestTables.Engineer, {
|
|
268
|
+
name: 'John Doe',
|
|
269
|
+
yearsOfExperience: 5,
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
const assignment = await db.insert(dynamicReferenceTestTables.ProjectAssignment, {
|
|
273
|
+
projectName: 'Initial Project',
|
|
274
|
+
employeeRef: new Reference(dynamicReferenceTestTables.Engineer.name, engineer.id),
|
|
275
|
+
startDate: '2024-01-01',
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
// Update to null reference
|
|
279
|
+
await db.update(
|
|
280
|
+
dynamicReferenceTestTables.ProjectAssignment,
|
|
281
|
+
{
|
|
282
|
+
employeeRef: null,
|
|
283
|
+
},
|
|
284
|
+
{ id: assignment.id }
|
|
285
|
+
);
|
|
286
|
+
|
|
287
|
+
const nullRefAssignment = await db.get(dynamicReferenceTestTables.ProjectAssignment, { id: assignment.id });
|
|
288
|
+
expect(nullRefAssignment.employeeRef).toBeNull();
|
|
289
|
+
expect(nullRefAssignment.employeeTableName).toBe(dynamicReferenceTestTables.Engineer.name); // Should retain previous value
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
test('should handle custom defaultValue override for projectLead', async () => {
|
|
293
|
+
const engineer = await db.insert(dynamicReferenceTestTables.Engineer, {
|
|
294
|
+
name: 'John Doe',
|
|
295
|
+
yearsOfExperience: 5,
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
// Even with a reference provided, should use the custom default value
|
|
299
|
+
const assignment = await db.insert(dynamicReferenceTestTables.ProjectAssignment, {
|
|
300
|
+
projectName: 'Custom Default Test',
|
|
301
|
+
projectLeadRef: new Reference(dynamicReferenceTestTables.Engineer.name, engineer.id),
|
|
302
|
+
startDate: '2024-01-01',
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
// Should use our custom default value instead of the reference's table name
|
|
306
|
+
expect(assignment.projectLeadTableName).toBe('TEST_DEFAULT_VALUE');
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
test('should handle custom updateValue override for projectLead', async () => {
|
|
310
|
+
const engineer = await db.insert(dynamicReferenceTestTables.Engineer, {
|
|
311
|
+
name: 'John Doe',
|
|
312
|
+
yearsOfExperience: 5,
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
const designer = await db.insert(dynamicReferenceTestTables.Designer, {
|
|
316
|
+
name: 'Jane Smith',
|
|
317
|
+
specialization: 'UI/UX',
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
// Create initial assignment
|
|
321
|
+
const assignment = await db.insert(dynamicReferenceTestTables.ProjectAssignment, {
|
|
322
|
+
projectName: 'Initial Project',
|
|
323
|
+
projectLeadRef: new Reference(dynamicReferenceTestTables.Engineer.name, engineer.id),
|
|
324
|
+
startDate: '2024-01-01',
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
// Update the reference
|
|
328
|
+
await db.update(
|
|
329
|
+
dynamicReferenceTestTables.ProjectAssignment,
|
|
330
|
+
{
|
|
331
|
+
projectLeadRef: new Reference(dynamicReferenceTestTables.Designer.name, designer.id),
|
|
332
|
+
},
|
|
333
|
+
{ id: assignment.id }
|
|
334
|
+
);
|
|
335
|
+
|
|
336
|
+
const updatedAssignment = await db.get(dynamicReferenceTestTables.ProjectAssignment, { id: assignment.id });
|
|
337
|
+
// Should use our custom update value instead of the new reference's table name
|
|
338
|
+
expect(updatedAssignment.projectLeadTableName).toBe('TEST_UPDATE_VALUE');
|
|
339
|
+
});
|
|
340
|
+
});
|
|
341
|
+
};
|
|
342
|
+
};
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import {
|
|
2
|
-
BinaryColumn,
|
|
3
|
-
BooleanColumn,
|
|
4
2
|
DateColumn,
|
|
5
3
|
DateTimeColumn,
|
|
6
4
|
DecimalColumn,
|
|
@@ -9,87 +7,18 @@ import {
|
|
|
9
7
|
ObjectColumn,
|
|
10
8
|
StringColumn,
|
|
11
9
|
UuidColumn,
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
name = 'db_test_user';
|
|
25
|
-
columns = withRecordColumns<User>({
|
|
26
|
-
name: new StringColumn('name'),
|
|
27
|
-
email: new StringColumn('email'),
|
|
28
|
-
active: new BooleanColumn('active'),
|
|
29
|
-
});
|
|
30
|
-
indexes = [
|
|
31
|
-
{ name: 'db_test_user_email_index', columns: ['email'] as (keyof User)[] },
|
|
32
|
-
{ name: 'db_test_user_active_email_index', columns: ['active', 'email'] as (keyof User)[] },
|
|
33
|
-
];
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
interface MappedIndexUser extends Record {
|
|
37
|
-
emailAddress: string;
|
|
38
|
-
accountStatus: string;
|
|
39
|
-
createdOn: Date;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
class MappedIndexUserTable extends Table<MappedIndexUser> {
|
|
43
|
-
name = 'db_test_mapped_index_user';
|
|
44
|
-
columns = withRecordColumns<MappedIndexUser>({
|
|
45
|
-
emailAddress: new StringColumn('email_address'),
|
|
46
|
-
accountStatus: new StringColumn('account_status'),
|
|
47
|
-
createdOn: new DateColumn('created_on'),
|
|
48
|
-
});
|
|
49
|
-
indexes = [
|
|
50
|
-
{
|
|
51
|
-
name: 'db_test_mapped_index_user_email_index',
|
|
52
|
-
columns: ['emailAddress'] as (keyof MappedIndexUser)[],
|
|
53
|
-
},
|
|
54
|
-
{
|
|
55
|
-
name: 'db_test_mapped_index_user_status_email_index',
|
|
56
|
-
columns: ['accountStatus', 'emailAddress'] as (keyof MappedIndexUser)[],
|
|
57
|
-
},
|
|
58
|
-
];
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
interface ColumnTypes extends Record {
|
|
62
|
-
integer: number;
|
|
63
|
-
bigInteger: number;
|
|
64
|
-
text: string;
|
|
65
|
-
string: string;
|
|
66
|
-
float: number;
|
|
67
|
-
decimal: number;
|
|
68
|
-
boolean: boolean;
|
|
69
|
-
date: Date;
|
|
70
|
-
dateTime: moment.Moment;
|
|
71
|
-
binary: boolean;
|
|
72
|
-
object: any;
|
|
73
|
-
uuid: string;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
class ColumnTypesTable extends Table<ColumnTypes> {
|
|
77
|
-
name = 'db_test_column_types';
|
|
78
|
-
columns = withRecordColumns<ColumnTypes>({
|
|
79
|
-
integer: new IntegerColumn('integer', { nullable: true }),
|
|
80
|
-
bigInteger: new IntegerColumn('big_integer', { nullable: false }, true),
|
|
81
|
-
string: new StringColumn('string', { references: { table: 'db_test_user' } }),
|
|
82
|
-
text: new StringColumn('text', undefined, 'MAX'),
|
|
83
|
-
float: new FloatColumn('float', { defaultValue: async () => 0.5 }),
|
|
84
|
-
decimal: new DecimalColumn('decimal'),
|
|
85
|
-
boolean: new BooleanColumn('boolean'),
|
|
86
|
-
date: new DateColumn('date'),
|
|
87
|
-
dateTime: new DateTimeColumn('date_time'),
|
|
88
|
-
binary: new BinaryColumn('binary'),
|
|
89
|
-
object: new ObjectColumn('object'),
|
|
90
|
-
uuid: new UuidColumn('uuid', { unique: { unique: true } }),
|
|
91
|
-
});
|
|
92
|
-
}
|
|
10
|
+
DbDriver,
|
|
11
|
+
Column,
|
|
12
|
+
Table,
|
|
13
|
+
} from '@proteinjs/db';
|
|
14
|
+
import { DbTestEnvironment } from '../util/DbTestEnvironment';
|
|
15
|
+
import {
|
|
16
|
+
ColumnTypesTable,
|
|
17
|
+
MappedIndexUser,
|
|
18
|
+
MappedIndexUserTable,
|
|
19
|
+
tableManagerTestTables,
|
|
20
|
+
UserTestTable,
|
|
21
|
+
} from '../util/tables/tableManagerTestTables';
|
|
93
22
|
|
|
94
23
|
export const tableManagerTests = (
|
|
95
24
|
driver: DbDriver,
|
|
@@ -103,23 +32,15 @@ export const tableManagerTests = (
|
|
|
103
32
|
) => {
|
|
104
33
|
return () => {
|
|
105
34
|
const tableManager = driver.getTableManager();
|
|
35
|
+
const testEnv = new DbTestEnvironment(driver, dropTable);
|
|
106
36
|
|
|
107
|
-
beforeAll(async () =>
|
|
108
|
-
|
|
109
|
-
await driver.start();
|
|
110
|
-
}
|
|
111
|
-
});
|
|
37
|
+
beforeAll(async () => await testEnv.beforeAll(), 10000);
|
|
38
|
+
afterAll(async () => await testEnv.afterAll(), 10000);
|
|
112
39
|
|
|
113
40
|
afterEach(async () => {
|
|
114
|
-
await dropTable(
|
|
115
|
-
await dropTable(
|
|
116
|
-
await dropTable(
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
afterAll(async () => {
|
|
120
|
-
if (driver.stop) {
|
|
121
|
-
await driver.stop();
|
|
122
|
-
}
|
|
41
|
+
await dropTable(tableManagerTestTables.ColumnTypes);
|
|
42
|
+
await dropTable(tableManagerTestTables.User);
|
|
43
|
+
await dropTable(tableManagerTestTables.MappedIndexUser);
|
|
123
44
|
});
|
|
124
45
|
|
|
125
46
|
test('create primary key', async () => {
|
|
@@ -1,64 +1,11 @@
|
|
|
1
1
|
import { QueryBuilder } from '@proteinjs/db-query';
|
|
2
|
-
import { DbDriver, Db } from '
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
name: string;
|
|
10
|
-
department?: string;
|
|
11
|
-
jobTitle?: string | null;
|
|
12
|
-
isRemote?: boolean;
|
|
13
|
-
startDate?: Date;
|
|
14
|
-
object?: string;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
class EmployeeTestTable extends Table<Employee> {
|
|
18
|
-
name = 'db_transaction_test_employee';
|
|
19
|
-
columns = withRecordColumns<Employee>({
|
|
20
|
-
name: new StringColumn('name'),
|
|
21
|
-
department: new StringColumn('department'),
|
|
22
|
-
isRemote: new BooleanColumn('is_remote'),
|
|
23
|
-
jobTitle: new StringColumn('job_title'),
|
|
24
|
-
startDate: new DateColumn('start_date'),
|
|
25
|
-
object: new StringColumn('object'),
|
|
26
|
-
});
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
interface ReservedWordTest extends Record {
|
|
30
|
-
name: string;
|
|
31
|
-
order?: string;
|
|
32
|
-
select?: string;
|
|
33
|
-
join?: string;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
class ReservedWordTestTable extends Table<ReservedWordTest> {
|
|
37
|
-
name = 'db_transaction_test_reserved_word';
|
|
38
|
-
columns = withRecordColumns<ReservedWordTest>({
|
|
39
|
-
name: new StringColumn('name'),
|
|
40
|
-
order: new StringColumn('order'),
|
|
41
|
-
select: new StringColumn('select'),
|
|
42
|
-
join: new StringColumn('join'),
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Used for testing purposes only.
|
|
48
|
-
* */
|
|
49
|
-
export const getTransactionTestTable = (tableName: string) => {
|
|
50
|
-
const employeeTable = new EmployeeTestTable();
|
|
51
|
-
if (employeeTable.name == tableName) {
|
|
52
|
-
return new EmployeeTestTable();
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
const reservedWordTestTable = new ReservedWordTestTable();
|
|
56
|
-
if (reservedWordTestTable.name == tableName) {
|
|
57
|
-
return new ReservedWordTestTable();
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
throw new Error(`Cannot find test table: ${tableName}`);
|
|
61
|
-
};
|
|
2
|
+
import { DbDriver, Db, Record, Table, DefaultTransactionContextFactory } from '@proteinjs/db';
|
|
3
|
+
import { DbTestEnvironment } from '../util/DbTestEnvironment';
|
|
4
|
+
import {
|
|
5
|
+
TransactionEmployee,
|
|
6
|
+
TransactionReservedWordTest,
|
|
7
|
+
transactionTestTables,
|
|
8
|
+
} from '../util/tables/transactionTestTables';
|
|
62
9
|
|
|
63
10
|
export const transactionTests = (
|
|
64
11
|
driver: DbDriver,
|
|
@@ -66,36 +13,22 @@ export const transactionTests = (
|
|
|
66
13
|
dropTable: (table: Table<any>) => Promise<void>
|
|
67
14
|
) => {
|
|
68
15
|
return () => {
|
|
69
|
-
const db = new Db(driver,
|
|
70
|
-
|
|
71
|
-
beforeAll(async () => {
|
|
72
|
-
if (driver.start) {
|
|
73
|
-
await driver.start();
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
await driver.getTableManager().loadTable(new EmployeeTestTable());
|
|
77
|
-
await driver.getTableManager().loadTable(new ReservedWordTestTable());
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
afterAll(async () => {
|
|
81
|
-
await dropTable(new EmployeeTestTable());
|
|
82
|
-
await dropTable(new ReservedWordTestTable());
|
|
16
|
+
const db = new Db(driver, undefined, transactionContextFactory);
|
|
17
|
+
const testEnv = new DbTestEnvironment(driver, dropTable);
|
|
83
18
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
}
|
|
87
|
-
});
|
|
19
|
+
beforeAll(async () => await testEnv.beforeAll(), 10000);
|
|
20
|
+
afterAll(async () => await testEnv.afterAll(), 10000);
|
|
88
21
|
|
|
89
22
|
test('Transaction with successful operations', async () => {
|
|
90
|
-
const testEmployee1: Omit<
|
|
23
|
+
const testEmployee1: Omit<TransactionEmployee, keyof Record> = {
|
|
91
24
|
name: 'Veronica',
|
|
92
25
|
department: 'Engineering',
|
|
93
26
|
};
|
|
94
|
-
const testEmployee2: Omit<
|
|
27
|
+
const testEmployee2: Omit<TransactionEmployee, keyof Record> = {
|
|
95
28
|
name: 'Brent',
|
|
96
29
|
department: 'Engineering',
|
|
97
30
|
};
|
|
98
|
-
const emplyeeTable: Table<
|
|
31
|
+
const emplyeeTable: Table<TransactionEmployee> = transactionTestTables.TransactionEmployee;
|
|
99
32
|
|
|
100
33
|
// Execute multiple operations in a transaction
|
|
101
34
|
const results = await db.runTransaction(async () => {
|
|
@@ -117,7 +50,7 @@ export const transactionTests = (
|
|
|
117
50
|
expect(updatedEmp2.department).toBe('Engineering');
|
|
118
51
|
|
|
119
52
|
// Clean up
|
|
120
|
-
const qb = new QueryBuilder<
|
|
53
|
+
const qb = new QueryBuilder<TransactionEmployee>(emplyeeTable.name).condition({
|
|
121
54
|
field: 'id',
|
|
122
55
|
operator: 'IN',
|
|
123
56
|
value: [results.emp1.id, results.emp2.id],
|
|
@@ -126,15 +59,15 @@ export const transactionTests = (
|
|
|
126
59
|
});
|
|
127
60
|
|
|
128
61
|
test('Transaction rollback on error', async () => {
|
|
129
|
-
const testEmployee1: Omit<
|
|
62
|
+
const testEmployee1: Omit<TransactionEmployee, keyof Record> = {
|
|
130
63
|
name: 'Veronica',
|
|
131
64
|
department: 'Engineering',
|
|
132
65
|
};
|
|
133
|
-
const testEmployee2: Omit<
|
|
66
|
+
const testEmployee2: Omit<TransactionEmployee, keyof Record> = {
|
|
134
67
|
name: 'Brent',
|
|
135
68
|
department: undefined, // This will cause an error
|
|
136
69
|
};
|
|
137
|
-
const emplyeeTable: Table<
|
|
70
|
+
const emplyeeTable: Table<TransactionEmployee> = transactionTestTables.TransactionEmployee;
|
|
138
71
|
|
|
139
72
|
let insertedId: string | undefined;
|
|
140
73
|
|
|
@@ -156,11 +89,11 @@ export const transactionTests = (
|
|
|
156
89
|
});
|
|
157
90
|
|
|
158
91
|
test('Nested transactions are not allowed', async () => {
|
|
159
|
-
const testEmployee: Omit<
|
|
92
|
+
const testEmployee: Omit<TransactionEmployee, keyof Record> = {
|
|
160
93
|
name: 'Veronica',
|
|
161
94
|
department: 'Engineering',
|
|
162
95
|
};
|
|
163
|
-
const emplyeeTable: Table<
|
|
96
|
+
const emplyeeTable: Table<TransactionEmployee> = transactionTestTables.TransactionEmployee;
|
|
164
97
|
|
|
165
98
|
await expect(
|
|
166
99
|
db.runTransaction(async () => {
|
|
@@ -176,11 +109,11 @@ export const transactionTests = (
|
|
|
176
109
|
});
|
|
177
110
|
|
|
178
111
|
test('Transaction isolation', async () => {
|
|
179
|
-
const testEmployee: Omit<
|
|
112
|
+
const testEmployee: Omit<TransactionEmployee, keyof Record> = {
|
|
180
113
|
name: 'Veronica',
|
|
181
114
|
department: 'Engineering',
|
|
182
115
|
};
|
|
183
|
-
const emplyeeTable: Table<
|
|
116
|
+
const emplyeeTable: Table<TransactionEmployee> = transactionTestTables.TransactionEmployee;
|
|
184
117
|
|
|
185
118
|
// Start a transaction but don't commit immediately
|
|
186
119
|
const transactionPromise = db.runTransaction(async () => {
|
|
@@ -202,18 +135,18 @@ export const transactionTests = (
|
|
|
202
135
|
});
|
|
203
136
|
|
|
204
137
|
test('Transaction with multiple table operations', async () => {
|
|
205
|
-
const testEmployee: Omit<
|
|
138
|
+
const testEmployee: Omit<TransactionEmployee, keyof Record> = {
|
|
206
139
|
name: 'Veronica',
|
|
207
140
|
department: 'Engineering',
|
|
208
141
|
};
|
|
209
|
-
const testReservedWord: Omit<
|
|
142
|
+
const testReservedWord: Omit<TransactionReservedWordTest, keyof Record> = {
|
|
210
143
|
name: 'Test',
|
|
211
144
|
order: '1',
|
|
212
145
|
select: 'Option 1',
|
|
213
146
|
};
|
|
214
147
|
|
|
215
|
-
const emplyeeTable: Table<
|
|
216
|
-
const reservedWordTable: Table<
|
|
148
|
+
const emplyeeTable: Table<TransactionEmployee> = transactionTestTables.TransactionEmployee;
|
|
149
|
+
const reservedWordTable: Table<TransactionReservedWordTest> = transactionTestTables.TransactionReservedWord;
|
|
217
150
|
|
|
218
151
|
// Execute operations on multiple tables in a transaction
|
|
219
152
|
const results = await db.runTransaction(async () => {
|