@proteinjs/db 1.21.7 → 1.21.9
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 +11 -0
- package/LICENSE +21 -0
- package/dist/generated/index.js +7 -7
- package/dist/generated/index.js.map +1 -1
- package/dist/generated/test/index.js +5 -5
- package/dist/generated/test/index.js.map +1 -1
- package/dist/src/source/SourceRecordLoader.d.ts +28 -7
- package/dist/src/source/SourceRecordLoader.d.ts.map +1 -1
- package/dist/src/source/SourceRecordLoader.js +79 -48
- package/dist/src/source/SourceRecordLoader.js.map +1 -1
- package/dist/test/SourceRecordLoader.test.d.ts +2 -0
- package/dist/test/SourceRecordLoader.test.d.ts.map +1 -0
- package/dist/test/SourceRecordLoader.test.js +121 -0
- package/dist/test/SourceRecordLoader.test.js.map +1 -0
- package/dist/test/reusable/CascadeDeleteTests.js +2 -2
- package/dist/test/reusable/ColumnTypesTests.js +2 -2
- package/dist/test/reusable/CrudTests.js +3 -3
- package/dist/test/reusable/DynamicReferenceColumnTests.js +2 -2
- package/dist/test/reusable/TableManagerTests.js +2 -2
- package/dist/test/reusable/TransactionTests.js +2 -2
- package/generated/index.ts +18 -21
- package/generated/test/index.ts +41 -44
- package/package.json +10 -9
- package/src/source/SourceRecordLoader.ts +73 -42
- package/test/SourceRecordLoader.test.ts +154 -0
- package/test/reusable/CascadeDeleteTests.ts +2 -2
- package/test/reusable/ColumnTypesTests.ts +2 -2
- package/test/reusable/CrudTests.ts +3 -3
- package/test/reusable/DynamicReferenceColumnTests.ts +2 -2
- package/test/reusable/TableManagerTests.ts +2 -2
- package/test/reusable/TransactionTests.ts +2 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@proteinjs/db",
|
|
3
|
-
"version": "1.21.
|
|
3
|
+
"version": "1.21.9",
|
|
4
4
|
"main": "./dist/generated/index.js",
|
|
5
5
|
"types": "./dist/generated/index.d.ts",
|
|
6
6
|
"exports": {
|
|
@@ -41,19 +41,19 @@
|
|
|
41
41
|
"test": "jest --passWithNoTests"
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"@proteinjs/db-query": "^1.4.
|
|
45
|
-
"@proteinjs/logger": "^1.0.
|
|
44
|
+
"@proteinjs/db-query": "^1.4.7",
|
|
45
|
+
"@proteinjs/logger": "^1.0.18",
|
|
46
46
|
"@proteinjs/reflection": "^1.1.11",
|
|
47
|
-
"@proteinjs/serializer": "^1.1.
|
|
48
|
-
"@proteinjs/server-api": "^3.0.
|
|
49
|
-
"@proteinjs/service": "^1.2.
|
|
50
|
-
"@proteinjs/user-auth": "^1.1.
|
|
47
|
+
"@proteinjs/serializer": "^1.1.7",
|
|
48
|
+
"@proteinjs/server-api": "^3.0.5",
|
|
49
|
+
"@proteinjs/service": "^1.2.14",
|
|
50
|
+
"@proteinjs/user-auth": "^1.1.12",
|
|
51
51
|
"@proteinjs/util": "^1.6.0",
|
|
52
52
|
"moment": "2.29.4",
|
|
53
53
|
"uuid": "8.3.0"
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
56
|
-
"@proteinjs/reflection-build": "^1.4.
|
|
56
|
+
"@proteinjs/reflection-build": "^1.4.6",
|
|
57
57
|
"@types/jest": "29.5.5",
|
|
58
58
|
"@types/node": "14.0.27",
|
|
59
59
|
"@types/uuid": "8.3.0",
|
|
@@ -65,5 +65,6 @@
|
|
|
65
65
|
"jest": "29.7.0",
|
|
66
66
|
"ts-jest": "29.1.1",
|
|
67
67
|
"typescript": "5.2.2"
|
|
68
|
-
}
|
|
68
|
+
},
|
|
69
|
+
"gitHead": "75411714e31c9033803f328cb43fa922d77d9782"
|
|
69
70
|
}
|
|
@@ -67,11 +67,12 @@ export class SourceRecordLoader {
|
|
|
67
67
|
/**
|
|
68
68
|
* Compare source record fields against the existing DB record to detect actual changes.
|
|
69
69
|
* Only fields present on the source record are compared (ignoring `created`, `updated`).
|
|
70
|
-
* Uses serialization to normalize values (e.g. Reference objects, Moment, JSON) before
|
|
70
|
+
* Uses serialization to normalize values (e.g. Reference objects, Moment, JSON) before
|
|
71
|
+
* comparison, then delegates to {@link findMismatchPath}.
|
|
71
72
|
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
73
|
+
* Object-valued fields (e.g. `JsonColumn` blobs) are treated as source-authoritative:
|
|
74
|
+
* any structural drift, including extra keys left behind by earlier source versions,
|
|
75
|
+
* triggers a rewrite. Primitive columns retain their existing semantics.
|
|
75
76
|
*/
|
|
76
77
|
private async hasChanges(table: Table<any>, sourceRecord: any, existingRecord: any): Promise<boolean> {
|
|
77
78
|
const serializer = new RecordSerializer(table);
|
|
@@ -92,11 +93,43 @@ export class SourceRecordLoader {
|
|
|
92
93
|
return false;
|
|
93
94
|
}
|
|
94
95
|
|
|
96
|
+
private async getSourceRecordsMap() {
|
|
97
|
+
const sourceRecordsMap: SourceRecordsMap = {};
|
|
98
|
+
const sourceRecordTables = getSourceRecordTables();
|
|
99
|
+
for (const sourceRecordTable of sourceRecordTables) {
|
|
100
|
+
if (!sourceRecordsMap[sourceRecordTable.name]) {
|
|
101
|
+
sourceRecordsMap[sourceRecordTable.name] = { table: sourceRecordTable, records: [], recordIds: [] };
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const sourceRecordLoaders = getSourceRecordLoaders();
|
|
106
|
+
for (const sourceRecordLoader of sourceRecordLoaders) {
|
|
107
|
+
if (!sourceRecordsMap[sourceRecordLoader.table.name]) {
|
|
108
|
+
sourceRecordsMap[sourceRecordLoader.table.name] = {
|
|
109
|
+
table: sourceRecordLoader.table,
|
|
110
|
+
records: [],
|
|
111
|
+
recordIds: [],
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
sourceRecordsMap[sourceRecordLoader.table.name].records.push(sourceRecordLoader.record);
|
|
116
|
+
sourceRecordsMap[sourceRecordLoader.table.name].recordIds.push(sourceRecordLoader.record.id);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return sourceRecordsMap;
|
|
120
|
+
}
|
|
121
|
+
|
|
95
122
|
/**
|
|
96
123
|
* Find the first point of divergence between source and existing values.
|
|
97
124
|
* Returns a description of the mismatch path, or null if they match.
|
|
98
|
-
*
|
|
99
|
-
*
|
|
125
|
+
*
|
|
126
|
+
* For object-valued fields (e.g. a `JsonColumn` blob), source is treated as
|
|
127
|
+
* fully authoritative: any structural drift — extra keys in existing, missing
|
|
128
|
+
* keys in existing, or value differences anywhere in the subtree — produces
|
|
129
|
+
* a mismatch. Comparison goes through {@link SourceRecordLoader.canonicalStringify}
|
|
130
|
+
* so that key ordering (which backing stores may canonicalize alphabetically)
|
|
131
|
+
* does not cause false positives.
|
|
132
|
+
*
|
|
100
133
|
* For arrays, order and length must match exactly.
|
|
101
134
|
*/
|
|
102
135
|
private findMismatchPath(source: any, existing: any, path: string): string | null {
|
|
@@ -139,47 +172,45 @@ export class SourceRecordLoader {
|
|
|
139
172
|
return null;
|
|
140
173
|
}
|
|
141
174
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
}
|
|
148
|
-
if (!(key in existing)) {
|
|
149
|
-
return `${path}.${key}: key missing in existing`;
|
|
150
|
-
}
|
|
151
|
-
const result = this.findMismatchPath(source[key], existing[key], `${path}.${key}`);
|
|
152
|
-
if (result) {
|
|
153
|
-
return result;
|
|
154
|
-
}
|
|
175
|
+
// Both values are non-null, non-array objects. Treat source as authoritative:
|
|
176
|
+
// any structural drift triggers a mismatch. Canonical stringify normalizes
|
|
177
|
+
// key order so storage-side canonicalization (e.g. Spanner alphabetizes JSON
|
|
178
|
+
// keys) doesn't register as drift.
|
|
179
|
+
if (this.canonicalStringify(source) !== this.canonicalStringify(existing)) {
|
|
180
|
+
return `${path}: object differs`;
|
|
155
181
|
}
|
|
156
|
-
|
|
157
182
|
return null;
|
|
158
183
|
}
|
|
159
184
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
185
|
+
/**
|
|
186
|
+
* Canonical JSON stringification with recursively sorted object keys.
|
|
187
|
+
*
|
|
188
|
+
* Why this exists: some stores (notably Spanner) canonicalize JSON object
|
|
189
|
+
* keys alphabetically on storage. Source records declared in TypeScript
|
|
190
|
+
* code don't guarantee alphabetical key order, so a plain `JSON.stringify`
|
|
191
|
+
* comparison between source and the existing DB value would produce false
|
|
192
|
+
* mismatches driven purely by key ordering. Sorting keys on both sides
|
|
193
|
+
* normalizes them so semantic equality maps to string equality.
|
|
194
|
+
*
|
|
195
|
+
* Arrays preserve order (order is semantic for arrays); only object keys
|
|
196
|
+
* are sorted.
|
|
197
|
+
*/
|
|
198
|
+
private canonicalStringify(value: unknown): string {
|
|
199
|
+
if (value === null || typeof value !== 'object') {
|
|
200
|
+
return JSON.stringify(value);
|
|
167
201
|
}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
if (!sourceRecordsMap[sourceRecordLoader.table.name]) {
|
|
172
|
-
sourceRecordsMap[sourceRecordLoader.table.name] = {
|
|
173
|
-
table: sourceRecordLoader.table,
|
|
174
|
-
records: [],
|
|
175
|
-
recordIds: [],
|
|
176
|
-
};
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
sourceRecordsMap[sourceRecordLoader.table.name].records.push(sourceRecordLoader.record);
|
|
180
|
-
sourceRecordsMap[sourceRecordLoader.table.name].recordIds.push(sourceRecordLoader.record.id);
|
|
202
|
+
if (Array.isArray(value)) {
|
|
203
|
+
// Mirror JSON.stringify: undefined array elements serialize as `null`.
|
|
204
|
+
return '[' + value.map((v) => (v === undefined ? 'null' : this.canonicalStringify(v))).join(',') + ']';
|
|
181
205
|
}
|
|
182
|
-
|
|
183
|
-
|
|
206
|
+
// Mirror JSON.stringify: skip object properties whose value is `undefined`.
|
|
207
|
+
// This keeps source records that declare optional fields (as `undefined`)
|
|
208
|
+
// from being treated as drift vs existing rows that simply don't have the
|
|
209
|
+
// field — `undefined` would never have been written to the DB.
|
|
210
|
+
const obj = value as Record<string, unknown>;
|
|
211
|
+
const keys = Object.keys(obj)
|
|
212
|
+
.filter((k) => obj[k] !== undefined)
|
|
213
|
+
.sort();
|
|
214
|
+
return '{' + keys.map((k) => JSON.stringify(k) + ':' + this.canonicalStringify(obj[k])).join(',') + '}';
|
|
184
215
|
}
|
|
185
216
|
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { SourceRecordLoader } from '../src/source/SourceRecordLoader';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Covers the two helpers that drive SourceRecordLoader's change-detection:
|
|
5
|
+
* - `canonicalStringify`: deterministic, key-order-independent JSON
|
|
6
|
+
* - `findMismatchPath`: per-field drift detection that uses canonical stringify
|
|
7
|
+
* so object-valued columns (e.g. `JsonColumn`) are compared strictly while
|
|
8
|
+
* remaining immune to storage-side key reordering (Spanner alphabetizes JSON
|
|
9
|
+
* object keys on write).
|
|
10
|
+
*
|
|
11
|
+
* Both are private methods on `SourceRecordLoader`. Tests access them through
|
|
12
|
+
* the instance with a cast — cheaper than wiring full `hasChanges` fixtures
|
|
13
|
+
* (Table, RecordSerializer, Db) and keeps the public API surface of the class
|
|
14
|
+
* unchanged.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
type LoaderInternals = {
|
|
18
|
+
canonicalStringify: (value: unknown) => string;
|
|
19
|
+
findMismatchPath: (source: any, existing: any, path: string) => string | null;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const internals = () => new SourceRecordLoader() as unknown as LoaderInternals;
|
|
23
|
+
|
|
24
|
+
describe('SourceRecordLoader.canonicalStringify', () => {
|
|
25
|
+
it('produces the same string for objects with different key orders', () => {
|
|
26
|
+
const loader = internals();
|
|
27
|
+
const a = { foo: 1, bar: 2, baz: 3 };
|
|
28
|
+
const b = { baz: 3, foo: 1, bar: 2 };
|
|
29
|
+
expect(loader.canonicalStringify(a)).toBe(loader.canonicalStringify(b));
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('sorts keys alphabetically in nested objects', () => {
|
|
33
|
+
const loader = internals();
|
|
34
|
+
const value = { z: { c: 1, a: 2, b: 3 }, a: 1 };
|
|
35
|
+
expect(loader.canonicalStringify(value)).toBe('{"a":1,"z":{"a":2,"b":3,"c":1}}');
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('preserves array order (arrays are semantically ordered)', () => {
|
|
39
|
+
const loader = internals();
|
|
40
|
+
expect(loader.canonicalStringify([3, 1, 2])).toBe('[3,1,2]');
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('handles primitives the same as JSON.stringify', () => {
|
|
44
|
+
const loader = internals();
|
|
45
|
+
expect(loader.canonicalStringify('hello')).toBe('"hello"');
|
|
46
|
+
expect(loader.canonicalStringify(42)).toBe('42');
|
|
47
|
+
expect(loader.canonicalStringify(true)).toBe('true');
|
|
48
|
+
expect(loader.canonicalStringify(null)).toBe('null');
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
describe('SourceRecordLoader.findMismatchPath', () => {
|
|
53
|
+
describe('object comparison', () => {
|
|
54
|
+
it('returns null for identical objects', () => {
|
|
55
|
+
const loader = internals();
|
|
56
|
+
const source = { content: '', type: 'body1', linkedThoughtId: '' };
|
|
57
|
+
const existing = { content: '', type: 'body1', linkedThoughtId: '' };
|
|
58
|
+
expect(loader.findMismatchPath(source, existing, 'newThoughtTemplate')).toBeNull();
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('returns null when existing has the same keys in a different order (Spanner alphabetizes)', () => {
|
|
62
|
+
// This is the critical case: Spanner canonicalizes JSON object keys
|
|
63
|
+
// alphabetically on storage. Source declared in TypeScript doesn't
|
|
64
|
+
// guarantee alphabetical key order. The two must still compare equal.
|
|
65
|
+
const loader = internals();
|
|
66
|
+
const source = { content: '', type: 'body1', linkedThoughtId: '' };
|
|
67
|
+
const existing = { content: '', linkedThoughtId: '', type: 'body1' };
|
|
68
|
+
expect(loader.findMismatchPath(source, existing, 'newThoughtTemplate')).toBeNull();
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('reports a mismatch when existing has extra keys (ThoughtLink drift case)', () => {
|
|
72
|
+
// Regression guard for the bug that prompted this change: source was
|
|
73
|
+
// simplified to drop TextType drift keys (fontSize, bold, italic, etc.),
|
|
74
|
+
// but the old "extras tolerated" behavior left the stale keys on the DB
|
|
75
|
+
// row, causing type-switch demotion to persist.
|
|
76
|
+
const loader = internals();
|
|
77
|
+
const source = {
|
|
78
|
+
thoughtType: { object: { content: '', type: 'body1', linkedThoughtId: '' } },
|
|
79
|
+
};
|
|
80
|
+
const existing = {
|
|
81
|
+
thoughtType: {
|
|
82
|
+
object: {
|
|
83
|
+
content: '',
|
|
84
|
+
type: 'body1',
|
|
85
|
+
linkedThoughtId: '',
|
|
86
|
+
fontSize: 14,
|
|
87
|
+
bold: false,
|
|
88
|
+
italic: false,
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
expect(loader.findMismatchPath(source, existing, 'newThoughtTemplate')).not.toBeNull();
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it('reports a mismatch when existing is missing a key present in source', () => {
|
|
96
|
+
const loader = internals();
|
|
97
|
+
const source = { content: '', type: 'body1', linkedThoughtId: '' };
|
|
98
|
+
const existing = { content: '', type: 'body1' };
|
|
99
|
+
expect(loader.findMismatchPath(source, existing, 'newThoughtTemplate')).not.toBeNull();
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it('reports a mismatch for a nested value difference', () => {
|
|
103
|
+
const loader = internals();
|
|
104
|
+
const source = { thoughtType: { object: { type: 'body1' } } };
|
|
105
|
+
const existing = { thoughtType: { object: { type: 'body2' } } };
|
|
106
|
+
expect(loader.findMismatchPath(source, existing, 'newThoughtTemplate')).not.toBeNull();
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it('treats source-side undefined values as equivalent to missing in existing', () => {
|
|
110
|
+
// `JSON.stringify` drops undefined values, so the DB cannot store them
|
|
111
|
+
// in the first place. Source declaring an undefined field must not be
|
|
112
|
+
// treated as drift vs an existing row that lacks the field.
|
|
113
|
+
const loader = internals();
|
|
114
|
+
const source = { content: 'hi', optional: undefined };
|
|
115
|
+
const existing = { content: 'hi' };
|
|
116
|
+
expect(loader.findMismatchPath(source, existing, 'newThoughtTemplate')).toBeNull();
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
describe('array comparison', () => {
|
|
121
|
+
it('reports a mismatch on array length', () => {
|
|
122
|
+
const loader = internals();
|
|
123
|
+
expect(loader.findMismatchPath([1, 2], [1, 2, 3], 'tags')).not.toBeNull();
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it('reports a mismatch on array element difference', () => {
|
|
127
|
+
const loader = internals();
|
|
128
|
+
expect(loader.findMismatchPath([1, 2], [1, 3], 'tags')).not.toBeNull();
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it('returns null for equal arrays', () => {
|
|
132
|
+
const loader = internals();
|
|
133
|
+
expect(loader.findMismatchPath([1, 2, 3], [1, 2, 3], 'tags')).toBeNull();
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
describe('primitive comparison', () => {
|
|
138
|
+
it('returns null for equal primitives', () => {
|
|
139
|
+
const loader = internals();
|
|
140
|
+
expect(loader.findMismatchPath('x', 'x', 'name')).toBeNull();
|
|
141
|
+
expect(loader.findMismatchPath(5, 5, 'count')).toBeNull();
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it('reports a mismatch for different primitives', () => {
|
|
145
|
+
const loader = internals();
|
|
146
|
+
expect(loader.findMismatchPath('x', 'y', 'name')).not.toBeNull();
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it('reports a mismatch for type differences', () => {
|
|
150
|
+
const loader = internals();
|
|
151
|
+
expect(loader.findMismatchPath('1', 1, 'value')).not.toBeNull();
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
});
|
|
@@ -40,8 +40,8 @@ export const cascadeDeleteTests = (
|
|
|
40
40
|
const db = new Db(driver, undefined, transactionContextFactory);
|
|
41
41
|
const testEnv = new DbTestEnvironment(driver, dropTable);
|
|
42
42
|
|
|
43
|
-
beforeAll(async () => await testEnv.beforeAll(),
|
|
44
|
-
afterAll(async () => await testEnv.afterAll(),
|
|
43
|
+
beforeAll(async () => await testEnv.beforeAll(), 30000);
|
|
44
|
+
afterAll(async () => await testEnv.afterAll(), 30000);
|
|
45
45
|
|
|
46
46
|
/**
|
|
47
47
|
* -------------------- Cascade Delete (holder → referenced) --------------------
|
|
@@ -11,8 +11,8 @@ export const columnTypeTests = (
|
|
|
11
11
|
const db = new Db(driver, undefined, transactionContextFactory);
|
|
12
12
|
const testEnv = new DbTestEnvironment(driver, dropTable);
|
|
13
13
|
|
|
14
|
-
beforeAll(async () => await testEnv.beforeAll(),
|
|
15
|
-
afterAll(async () => await testEnv.afterAll(),
|
|
14
|
+
beforeAll(async () => await testEnv.beforeAll(), 30000);
|
|
15
|
+
afterAll(async () => await testEnv.afterAll(), 30000);
|
|
16
16
|
|
|
17
17
|
test('Insert record with all null values', async () => {
|
|
18
18
|
const testRecord: Omit<TestRecord, keyof Record> = {
|
|
@@ -12,8 +12,8 @@ export const crudTests = (
|
|
|
12
12
|
const db = new Db(driver, undefined, transactionContextFactory);
|
|
13
13
|
const testEnv = new DbTestEnvironment(driver, dropTable);
|
|
14
14
|
|
|
15
|
-
beforeAll(async () => await testEnv.beforeAll(),
|
|
16
|
-
afterAll(async () => await testEnv.afterAll(),
|
|
15
|
+
beforeAll(async () => await testEnv.beforeAll(), 30000);
|
|
16
|
+
afterAll(async () => await testEnv.afterAll(), 30000);
|
|
17
17
|
|
|
18
18
|
test('Insert', async () => {
|
|
19
19
|
const testEmployee: Omit<Employee, keyof Record> = { name: 'Veronica' };
|
|
@@ -417,7 +417,7 @@ export const crudTests = (
|
|
|
417
417
|
// Clean up
|
|
418
418
|
await db.delete(table, { id: insertedRecord1.id });
|
|
419
419
|
await db.delete(table, { id: insertedRecord2.id });
|
|
420
|
-
},
|
|
420
|
+
}, 30000);
|
|
421
421
|
|
|
422
422
|
test('Case sensitivity', async () => {
|
|
423
423
|
const testEmployee: Omit<Employee, keyof Record> = {
|
|
@@ -14,8 +14,8 @@ export const dynamicReferenceColumnTests = (driver: DbDriver, dropTable: (table:
|
|
|
14
14
|
const db = new Db(driver);
|
|
15
15
|
const testEnv = new DbTestEnvironment(driver, dropTable);
|
|
16
16
|
|
|
17
|
-
beforeAll(async () => await testEnv.beforeAll(),
|
|
18
|
-
afterAll(async () => await testEnv.afterAll(),
|
|
17
|
+
beforeAll(async () => await testEnv.beforeAll(), 30000);
|
|
18
|
+
afterAll(async () => await testEnv.afterAll(), 30000);
|
|
19
19
|
|
|
20
20
|
test('should handle references to different types', async () => {
|
|
21
21
|
// Create an engineer
|
|
@@ -34,8 +34,8 @@ export const tableManagerTests = (
|
|
|
34
34
|
const tableManager = driver.getTableManager();
|
|
35
35
|
const testEnv = new DbTestEnvironment(driver, dropTable);
|
|
36
36
|
|
|
37
|
-
beforeAll(async () => await testEnv.beforeAll(),
|
|
38
|
-
afterAll(async () => await testEnv.afterAll(),
|
|
37
|
+
beforeAll(async () => await testEnv.beforeAll(), 30000);
|
|
38
|
+
afterAll(async () => await testEnv.afterAll(), 30000);
|
|
39
39
|
|
|
40
40
|
afterEach(async () => {
|
|
41
41
|
await dropTable(tableManagerTestTables.ColumnTypes);
|
|
@@ -16,8 +16,8 @@ export const transactionTests = (
|
|
|
16
16
|
const db = new Db(driver, undefined, transactionContextFactory);
|
|
17
17
|
const testEnv = new DbTestEnvironment(driver, dropTable);
|
|
18
18
|
|
|
19
|
-
beforeAll(async () => await testEnv.beforeAll(),
|
|
20
|
-
afterAll(async () => await testEnv.afterAll(),
|
|
19
|
+
beforeAll(async () => await testEnv.beforeAll(), 30000);
|
|
20
|
+
afterAll(async () => await testEnv.afterAll(), 30000);
|
|
21
21
|
|
|
22
22
|
test('Transaction with successful operations', async () => {
|
|
23
23
|
const testEmployee1: Omit<TransactionEmployee, keyof Record> = {
|