@proteinjs/db 1.19.0 → 1.20.0

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 (104) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/generated/index.js +1 -1
  3. package/dist/generated/index.js.map +1 -1
  4. package/dist/generated/test/index.d.ts +1 -1
  5. package/dist/generated/test/index.d.ts.map +1 -1
  6. package/dist/generated/test/index.js +50 -32
  7. package/dist/generated/test/index.js.map +1 -1
  8. package/dist/index.d.ts +0 -6
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +0 -6
  11. package/dist/index.js.map +1 -1
  12. package/dist/src/Db.d.ts +2 -2
  13. package/dist/src/Db.d.ts.map +1 -1
  14. package/dist/src/Db.js +6 -3
  15. package/dist/src/Db.js.map +1 -1
  16. package/dist/src/TableWatcherRunner.d.ts.map +1 -1
  17. package/dist/src/TableWatcherRunner.js +4 -1
  18. package/dist/src/TableWatcherRunner.js.map +1 -1
  19. package/dist/src/schema/TableManager.d.ts.map +1 -1
  20. package/dist/src/schema/TableManager.js +4 -1
  21. package/dist/src/schema/TableManager.js.map +1 -1
  22. package/dist/test/index.d.ts +13 -0
  23. package/dist/test/index.d.ts.map +1 -0
  24. package/dist/test/index.js +29 -0
  25. package/dist/test/index.js.map +1 -0
  26. package/dist/test/reusable/CascadeDeleteTests.d.ts +1 -189
  27. package/dist/test/reusable/CascadeDeleteTests.d.ts.map +1 -1
  28. package/dist/test/reusable/CascadeDeleteTests.js +36 -393
  29. package/dist/test/reusable/CascadeDeleteTests.js.map +1 -1
  30. package/dist/test/reusable/ColumnTypesTests.d.ts +1 -52
  31. package/dist/test/reusable/ColumnTypesTests.d.ts.map +1 -1
  32. package/dist/test/reusable/ColumnTypesTests.js +20 -86
  33. package/dist/test/reusable/ColumnTypesTests.js.map +1 -1
  34. package/dist/test/reusable/CrudTests.d.ts +1 -50
  35. package/dist/test/reusable/CrudTests.d.ts.map +1 -1
  36. package/dist/test/reusable/CrudTests.js +37 -126
  37. package/dist/test/reusable/CrudTests.js.map +1 -1
  38. package/dist/test/reusable/DynamicReferenceColumnTests.d.ts +3 -0
  39. package/dist/test/reusable/DynamicReferenceColumnTests.d.ts.map +1 -0
  40. package/dist/test/reusable/DynamicReferenceColumnTests.js +429 -0
  41. package/dist/test/reusable/DynamicReferenceColumnTests.js.map +1 -0
  42. package/dist/test/reusable/TableManagerTests.d.ts +1 -2
  43. package/dist/test/reusable/TableManagerTests.d.ts.map +1 -1
  44. package/dist/test/reusable/TableManagerTests.js +57 -152
  45. package/dist/test/reusable/TableManagerTests.js.map +1 -1
  46. package/dist/test/reusable/TransactionTests.d.ts +1 -51
  47. package/dist/test/reusable/TransactionTests.d.ts.map +1 -1
  48. package/dist/test/reusable/TransactionTests.js +24 -111
  49. package/dist/test/reusable/TransactionTests.js.map +1 -1
  50. package/dist/test/util/DbTestEnvironment.d.ts +12 -0
  51. package/dist/test/util/DbTestEnvironment.d.ts.map +1 -0
  52. package/dist/test/util/DbTestEnvironment.js +125 -0
  53. package/dist/test/util/DbTestEnvironment.js.map +1 -0
  54. package/dist/test/util/tables/cascadeDeleteTestTables.d.ts +191 -0
  55. package/dist/test/util/tables/cascadeDeleteTestTables.d.ts.map +1 -0
  56. package/dist/test/util/tables/cascadeDeleteTestTables.js +234 -0
  57. package/dist/test/util/tables/cascadeDeleteTestTables.js.map +1 -0
  58. package/dist/test/util/tables/columnTypesTestTables.d.ts +47 -0
  59. package/dist/test/util/tables/columnTypesTestTables.d.ts.map +1 -0
  60. package/dist/test/util/tables/columnTypesTestTables.js +49 -0
  61. package/dist/test/util/tables/columnTypesTestTables.js.map +1 -0
  62. package/dist/test/util/tables/crudTestTables.d.ts +48 -0
  63. package/dist/test/util/tables/crudTestTables.d.ts.map +1 -0
  64. package/dist/test/util/tables/crudTestTables.js +58 -0
  65. package/dist/test/util/tables/crudTestTables.js.map +1 -0
  66. package/dist/test/util/tables/dynamicReferenceColumnTestTables.d.ts +76 -0
  67. package/dist/test/util/tables/dynamicReferenceColumnTestTables.d.ts.map +1 -0
  68. package/dist/test/util/tables/dynamicReferenceColumnTestTables.js +131 -0
  69. package/dist/test/util/tables/dynamicReferenceColumnTestTables.js.map +1 -0
  70. package/dist/test/util/tables/tableManagerTestTables.d.ts +86 -0
  71. package/dist/test/util/tables/tableManagerTestTables.d.ts.map +1 -0
  72. package/dist/test/util/tables/tableManagerTestTables.js +131 -0
  73. package/dist/test/util/tables/tableManagerTestTables.js.map +1 -0
  74. package/dist/test/util/tables/transactionTestTables.d.ts +48 -0
  75. package/dist/test/util/tables/transactionTestTables.d.ts.map +1 -0
  76. package/dist/test/util/tables/transactionTestTables.js +58 -0
  77. package/dist/test/util/tables/transactionTestTables.js.map +1 -0
  78. package/generated/index.ts +1 -1
  79. package/generated/test/index.ts +35 -17
  80. package/index.ts +0 -7
  81. package/package.json +23 -10
  82. package/src/Db.ts +8 -3
  83. package/src/TableWatcherRunner.ts +4 -1
  84. package/src/schema/TableManager.ts +4 -1
  85. package/test/index.ts +13 -0
  86. package/test/reusable/CascadeDeleteTests.ts +38 -320
  87. package/test/reusable/ColumnTypesTests.ts +9 -85
  88. package/test/reusable/CrudTests.ts +26 -97
  89. package/test/reusable/DynamicReferenceColumnTests.ts +342 -0
  90. package/test/reusable/TableManagerTests.ts +18 -97
  91. package/test/reusable/TransactionTests.ts +26 -93
  92. package/test/util/DbTestEnvironment.ts +46 -0
  93. package/test/util/tables/cascadeDeleteTestTables.ts +232 -0
  94. package/test/util/tables/columnTypesTestTables.ts +63 -0
  95. package/test/util/tables/crudTestTables.ts +44 -0
  96. package/test/util/tables/dynamicReferenceColumnTestTables.ts +87 -0
  97. package/test/util/tables/tableManagerTestTables.ts +98 -0
  98. package/test/util/tables/transactionTestTables.ts +44 -0
  99. package/tsconfig.json +7 -1
  100. package/dist/test/reusable/DynamicReferenceColumn.d.ts +0 -77
  101. package/dist/test/reusable/DynamicReferenceColumn.d.ts.map +0 -1
  102. package/dist/test/reusable/DynamicReferenceColumn.js +0 -656
  103. package/dist/test/reusable/DynamicReferenceColumn.js.map +0 -1
  104. 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
- } from '../../src/Columns';
13
- import { DbDriver } from '../../src/Db';
14
- import { Record, withRecordColumns } from '../../src/Record';
15
- import { Column, Table } from '../../src/Table';
16
-
17
- interface User extends Record {
18
- name: string;
19
- email: string;
20
- active: boolean;
21
- }
22
-
23
- class UserTestTable extends Table<User> {
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
- if (driver.start) {
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(new ColumnTypesTable());
115
- await dropTable(new UserTestTable());
116
- await dropTable(new MappedIndexUserTable());
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 '../../src/Db';
3
- import { withRecordColumns, Record } from '../../src/Record';
4
- import { BooleanColumn, DateColumn, StringColumn } from '../../src/Columns';
5
- import { Table } from '../../src/Table';
6
- import { DefaultTransactionContextFactory } from '../../src/transaction/TransactionContextFactory';
7
-
8
- interface Employee extends Record {
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, getTransactionTestTable, transactionContextFactory);
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
- if (driver.stop) {
85
- await driver.stop();
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<Employee, keyof Record> = {
23
+ const testEmployee1: Omit<TransactionEmployee, keyof Record> = {
91
24
  name: 'Veronica',
92
25
  department: 'Engineering',
93
26
  };
94
- const testEmployee2: Omit<Employee, keyof Record> = {
27
+ const testEmployee2: Omit<TransactionEmployee, keyof Record> = {
95
28
  name: 'Brent',
96
29
  department: 'Engineering',
97
30
  };
98
- const emplyeeTable: Table<Employee> = new EmployeeTestTable();
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<Employee>(emplyeeTable.name).condition({
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<Employee, keyof Record> = {
62
+ const testEmployee1: Omit<TransactionEmployee, keyof Record> = {
130
63
  name: 'Veronica',
131
64
  department: 'Engineering',
132
65
  };
133
- const testEmployee2: Omit<Employee, keyof Record> = {
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<Employee> = new EmployeeTestTable();
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<Employee, keyof Record> = {
92
+ const testEmployee: Omit<TransactionEmployee, keyof Record> = {
160
93
  name: 'Veronica',
161
94
  department: 'Engineering',
162
95
  };
163
- const emplyeeTable: Table<Employee> = new EmployeeTestTable();
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<Employee, keyof Record> = {
112
+ const testEmployee: Omit<TransactionEmployee, keyof Record> = {
180
113
  name: 'Veronica',
181
114
  department: 'Engineering',
182
115
  };
183
- const emplyeeTable: Table<Employee> = new EmployeeTestTable();
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<Employee, keyof Record> = {
138
+ const testEmployee: Omit<TransactionEmployee, keyof Record> = {
206
139
  name: 'Veronica',
207
140
  department: 'Engineering',
208
141
  };
209
- const testReservedWord: Omit<ReservedWordTest, keyof Record> = {
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<Employee> = new EmployeeTestTable();
216
- const reservedWordTable: Table<ReservedWordTest> = new ReservedWordTestTable();
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 () => {