@naturalcycles/db-lib 10.21.0 → 10.23.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.
- package/dist/commondao/common.dao.d.ts +2 -2
- package/dist/commondao/common.dao.js +15 -5
- package/dist/commondb/common.db.d.ts +1 -0
- package/dist/commondb/common.db.js +1 -0
- package/dist/testing/commonDaoTest.js +51 -47
- package/package.json +1 -1
- package/src/commondao/common.dao.ts +17 -7
- package/src/commondb/common.db.ts +2 -0
- package/src/testing/commonDaoTest.ts +50 -46
|
@@ -175,9 +175,9 @@ export declare class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity
|
|
|
175
175
|
private static multiGetMapByTableById;
|
|
176
176
|
private static prepareMultiGetOutput;
|
|
177
177
|
/**
|
|
178
|
-
*
|
|
178
|
+
* @experimental.
|
|
179
179
|
*/
|
|
180
|
-
static
|
|
180
|
+
static multiDelete(inputs: (DaoWithId<AnyDao> | DaoWithIds<AnyDao>)[], opt?: CommonDaoOptions): Promise<NonNegativeInteger>;
|
|
181
181
|
static multiSave(inputs: (DaoWithRows<AnyDao> | DaoWithRow<AnyDao>)[], opt?: CommonDaoSaveBatchOptions<any>): Promise<void>;
|
|
182
182
|
createTransaction(opt?: CommonDBTransactionOptions): Promise<CommonDaoTransaction>;
|
|
183
183
|
runInTransaction<T = void>(fn: CommonDaoTransactionFn<T>, opt?: CommonDBTransactionOptions): Promise<T>;
|
|
@@ -854,17 +854,27 @@ export class CommonDao {
|
|
|
854
854
|
return bmsByProp;
|
|
855
855
|
}
|
|
856
856
|
/**
|
|
857
|
-
*
|
|
857
|
+
* @experimental.
|
|
858
858
|
*/
|
|
859
|
-
static async
|
|
859
|
+
static async multiDelete(inputs, opt = {}) {
|
|
860
860
|
if (!inputs.length)
|
|
861
861
|
return 0;
|
|
862
862
|
const { db } = inputs[0].dao.cfg;
|
|
863
863
|
const idsByTable = {};
|
|
864
|
-
for (const
|
|
865
|
-
|
|
864
|
+
for (const input of inputs) {
|
|
865
|
+
const { dao } = input;
|
|
866
|
+
const { table } = dao.cfg;
|
|
867
|
+
dao.requireWriteAccess();
|
|
868
|
+
dao.requireObjectMutability(opt);
|
|
869
|
+
idsByTable[table] ||= [];
|
|
870
|
+
if ('id' in input) {
|
|
871
|
+
idsByTable[table].push(input.id);
|
|
872
|
+
}
|
|
873
|
+
else {
|
|
874
|
+
idsByTable[table].push(...input.ids);
|
|
875
|
+
}
|
|
866
876
|
}
|
|
867
|
-
return await db.multiDelete(idsByTable);
|
|
877
|
+
return await db.multiDelete(idsByTable, opt);
|
|
868
878
|
}
|
|
869
879
|
static async multiSave(inputs, opt = {}) {
|
|
870
880
|
if (!inputs.length)
|
|
@@ -263,36 +263,38 @@ export async function runCommonDaoTest(db, quirks = {}) {
|
|
|
263
263
|
const expected = [items[0], { ...items[2], k1: 'k1_mod' }];
|
|
264
264
|
expectMatch(expected, rows, quirks);
|
|
265
265
|
});
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
266
|
+
if (support.createTransaction) {
|
|
267
|
+
test('createTransaction happy path', async () => {
|
|
268
|
+
// cleanup
|
|
269
|
+
await dao.query().deleteByQuery();
|
|
270
|
+
// Test that id, created, updated are created
|
|
271
|
+
const now = localTime.nowUnix();
|
|
272
|
+
const row = _omit(item1, ['id', 'created', 'updated']);
|
|
273
|
+
let tx = await dao.createTransaction();
|
|
274
|
+
await tx.save(dao, row);
|
|
275
|
+
await tx.commit();
|
|
276
|
+
const loaded = await dao.query().runQuery();
|
|
277
|
+
expect(loaded.length).toBe(1);
|
|
278
|
+
expect(loaded[0].id).toBeDefined();
|
|
279
|
+
expect(loaded[0].created).toBeGreaterThanOrEqual(now);
|
|
280
|
+
expect(loaded[0].updated).toBe(loaded[0].created);
|
|
281
|
+
tx = await dao.createTransaction();
|
|
282
|
+
await tx.deleteById(dao, loaded[0].id);
|
|
283
|
+
await tx.commit();
|
|
284
|
+
// saveBatch [item1, 2, 3]
|
|
285
|
+
// save item3 with k1: k1_mod
|
|
286
|
+
// delete item2
|
|
287
|
+
// remaining: item1, item3_with_k1_mod
|
|
288
|
+
tx = await dao.createTransaction();
|
|
289
|
+
await tx.saveBatch(dao, items);
|
|
290
|
+
await tx.save(dao, { ...items[2], k1: 'k1_mod' });
|
|
291
|
+
await tx.deleteById(dao, items[1].id);
|
|
292
|
+
await tx.commit();
|
|
293
|
+
const rows = await dao.query().runQuery();
|
|
294
|
+
const expected = [items[0], { ...items[2], k1: 'k1_mod' }];
|
|
295
|
+
expectMatch(expected, rows, quirks);
|
|
296
|
+
});
|
|
297
|
+
}
|
|
296
298
|
test('transaction rollback', async () => {
|
|
297
299
|
const expected = await prepare();
|
|
298
300
|
let err;
|
|
@@ -310,23 +312,25 @@ export async function runCommonDaoTest(db, quirks = {}) {
|
|
|
310
312
|
const rows = await dao.query().runQuery();
|
|
311
313
|
expectMatch(expected, rows, quirks);
|
|
312
314
|
});
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
315
|
+
if (support.createTransaction) {
|
|
316
|
+
test('createTransaction rollback', async () => {
|
|
317
|
+
const expected = await prepare();
|
|
318
|
+
let err;
|
|
319
|
+
try {
|
|
320
|
+
const tx = await dao.createTransaction();
|
|
321
|
+
await tx.deleteById(dao, items[2].id);
|
|
322
|
+
await tx.save(dao, { ...items[0], k1: 5 }); // it should fail here
|
|
323
|
+
await tx.commit();
|
|
324
|
+
}
|
|
325
|
+
catch (err_) {
|
|
326
|
+
err = err_;
|
|
327
|
+
}
|
|
328
|
+
expect(err).toBeDefined();
|
|
329
|
+
expect(err).toBeInstanceOf(Error);
|
|
330
|
+
const rows = await dao.query().runQuery();
|
|
331
|
+
expectMatch(expected, rows, quirks);
|
|
332
|
+
});
|
|
333
|
+
}
|
|
330
334
|
if (support.queries) {
|
|
331
335
|
test('transaction cleanup', async () => {
|
|
332
336
|
await dao.query().deleteByQuery();
|
package/package.json
CHANGED
|
@@ -1139,20 +1139,30 @@ export class CommonDao<
|
|
|
1139
1139
|
}
|
|
1140
1140
|
|
|
1141
1141
|
/**
|
|
1142
|
-
*
|
|
1142
|
+
* @experimental.
|
|
1143
1143
|
*/
|
|
1144
|
-
static async
|
|
1145
|
-
inputs: DaoWithIds<AnyDao>[],
|
|
1146
|
-
|
|
1144
|
+
static async multiDelete(
|
|
1145
|
+
inputs: (DaoWithId<AnyDao> | DaoWithIds<AnyDao>)[],
|
|
1146
|
+
opt: CommonDaoOptions = {},
|
|
1147
1147
|
): Promise<NonNegativeInteger> {
|
|
1148
1148
|
if (!inputs.length) return 0
|
|
1149
1149
|
const { db } = inputs[0]!.dao.cfg
|
|
1150
1150
|
const idsByTable: StringMap<string[]> = {}
|
|
1151
|
-
for (const
|
|
1152
|
-
|
|
1151
|
+
for (const input of inputs) {
|
|
1152
|
+
const { dao } = input
|
|
1153
|
+
const { table } = dao.cfg
|
|
1154
|
+
dao.requireWriteAccess()
|
|
1155
|
+
dao.requireObjectMutability(opt)
|
|
1156
|
+
idsByTable[table] ||= []
|
|
1157
|
+
|
|
1158
|
+
if ('id' in input) {
|
|
1159
|
+
idsByTable[table].push(input.id)
|
|
1160
|
+
} else {
|
|
1161
|
+
idsByTable[table].push(...input.ids)
|
|
1162
|
+
}
|
|
1153
1163
|
}
|
|
1154
1164
|
|
|
1155
|
-
return await db.multiDelete(idsByTable)
|
|
1165
|
+
return await db.multiDelete(idsByTable, opt)
|
|
1156
1166
|
}
|
|
1157
1167
|
|
|
1158
1168
|
static async multiSave(
|
|
@@ -273,6 +273,7 @@ export interface CommonDBSupport {
|
|
|
273
273
|
bufferValues?: boolean
|
|
274
274
|
nullValues?: boolean
|
|
275
275
|
transactions?: boolean
|
|
276
|
+
createTransaction?: boolean
|
|
276
277
|
timeMachine?: boolean
|
|
277
278
|
multiTableOperations?: boolean
|
|
278
279
|
}
|
|
@@ -294,6 +295,7 @@ export const commonDBFullSupport: Required<CommonDBSupport> = {
|
|
|
294
295
|
bufferValues: true,
|
|
295
296
|
nullValues: true,
|
|
296
297
|
transactions: true,
|
|
298
|
+
createTransaction: true,
|
|
297
299
|
timeMachine: true,
|
|
298
300
|
multiTableOperations: true,
|
|
299
301
|
}
|
|
@@ -358,42 +358,44 @@ export async function runCommonDaoTest(
|
|
|
358
358
|
expectMatch(expected, rows, quirks)
|
|
359
359
|
})
|
|
360
360
|
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
361
|
+
if (support.createTransaction) {
|
|
362
|
+
test('createTransaction happy path', async () => {
|
|
363
|
+
// cleanup
|
|
364
|
+
await dao.query().deleteByQuery()
|
|
364
365
|
|
|
365
|
-
|
|
366
|
-
|
|
366
|
+
// Test that id, created, updated are created
|
|
367
|
+
const now = localTime.nowUnix()
|
|
367
368
|
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
369
|
+
const row = _omit(item1, ['id', 'created', 'updated'])
|
|
370
|
+
let tx = await dao.createTransaction()
|
|
371
|
+
await tx.save(dao, row)
|
|
372
|
+
await tx.commit()
|
|
372
373
|
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
374
|
+
const loaded = await dao.query().runQuery()
|
|
375
|
+
expect(loaded.length).toBe(1)
|
|
376
|
+
expect(loaded[0]!.id).toBeDefined()
|
|
377
|
+
expect(loaded[0]!.created).toBeGreaterThanOrEqual(now)
|
|
378
|
+
expect(loaded[0]!.updated).toBe(loaded[0]!.created)
|
|
378
379
|
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
380
|
+
tx = await dao.createTransaction()
|
|
381
|
+
await tx.deleteById(dao, loaded[0]!.id)
|
|
382
|
+
await tx.commit()
|
|
382
383
|
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
384
|
+
// saveBatch [item1, 2, 3]
|
|
385
|
+
// save item3 with k1: k1_mod
|
|
386
|
+
// delete item2
|
|
387
|
+
// remaining: item1, item3_with_k1_mod
|
|
388
|
+
tx = await dao.createTransaction()
|
|
389
|
+
await tx.saveBatch(dao, items)
|
|
390
|
+
await tx.save(dao, { ...items[2]!, k1: 'k1_mod' })
|
|
391
|
+
await tx.deleteById(dao, items[1]!.id)
|
|
392
|
+
await tx.commit()
|
|
392
393
|
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
394
|
+
const rows = await dao.query().runQuery()
|
|
395
|
+
const expected = [items[0], { ...items[2]!, k1: 'k1_mod' }]
|
|
396
|
+
expectMatch(expected, rows, quirks)
|
|
397
|
+
})
|
|
398
|
+
}
|
|
397
399
|
|
|
398
400
|
test('transaction rollback', async () => {
|
|
399
401
|
const expected = await prepare()
|
|
@@ -416,25 +418,27 @@ export async function runCommonDaoTest(
|
|
|
416
418
|
expectMatch(expected, rows, quirks)
|
|
417
419
|
})
|
|
418
420
|
|
|
419
|
-
|
|
420
|
-
|
|
421
|
+
if (support.createTransaction) {
|
|
422
|
+
test('createTransaction rollback', async () => {
|
|
423
|
+
const expected = await prepare()
|
|
421
424
|
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
425
|
+
let err: any
|
|
426
|
+
try {
|
|
427
|
+
const tx = await dao.createTransaction()
|
|
428
|
+
await tx.deleteById(dao, items[2]!.id)
|
|
429
|
+
await tx.save(dao, { ...items[0]!, k1: 5 as any }) // it should fail here
|
|
430
|
+
await tx.commit()
|
|
431
|
+
} catch (err_) {
|
|
432
|
+
err = err_
|
|
433
|
+
}
|
|
431
434
|
|
|
432
|
-
|
|
433
|
-
|
|
435
|
+
expect(err).toBeDefined()
|
|
436
|
+
expect(err).toBeInstanceOf(Error)
|
|
434
437
|
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
+
const rows = await dao.query().runQuery()
|
|
439
|
+
expectMatch(expected, rows, quirks)
|
|
440
|
+
})
|
|
441
|
+
}
|
|
438
442
|
|
|
439
443
|
if (support.queries) {
|
|
440
444
|
test('transaction cleanup', async () => {
|