@naturalcycles/db-lib 10.40.1 → 10.41.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.
|
@@ -131,9 +131,17 @@ export declare class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity
|
|
|
131
131
|
bmToDBM(bm: undefined, opt?: CommonDaoOptions): Promise<null>;
|
|
132
132
|
bmToDBM(bm?: BM, opt?: CommonDaoOptions): Promise<DBM>;
|
|
133
133
|
bmsToDBM(bms: BM[], opt?: CommonDaoOptions): Promise<DBM[]>;
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
134
|
+
/**
|
|
135
|
+
* Mutates `dbm`.
|
|
136
|
+
*/
|
|
137
|
+
compress(dbm: DBM): Promise<void>;
|
|
138
|
+
/**
|
|
139
|
+
* Mutates `dbm`.
|
|
140
|
+
*/
|
|
141
|
+
decompress(dbm: DBM): Promise<void>;
|
|
142
|
+
anyToDBM(dbm: undefined, opt?: CommonDaoOptions): Promise<null>;
|
|
143
|
+
anyToDBM(dbm?: any, opt?: CommonDaoOptions): Promise<DBM>;
|
|
144
|
+
anyToDBMs(rows: DBM[], opt?: CommonDaoOptions): Promise<DBM[]>;
|
|
137
145
|
/**
|
|
138
146
|
* Returns *converted value* (NOT the same reference).
|
|
139
147
|
* Does NOT mutate the object.
|
|
@@ -3,10 +3,11 @@ import { _uniqBy } from '@naturalcycles/js-lib/array/array.util.js';
|
|
|
3
3
|
import { localTime } from '@naturalcycles/js-lib/datetime/localTime.js';
|
|
4
4
|
import { _assert, ErrorMode } from '@naturalcycles/js-lib/error';
|
|
5
5
|
import { _deepJsonEquals } from '@naturalcycles/js-lib/object/deepEquals.js';
|
|
6
|
-
import { _filterUndefinedValues, _objectAssignExact, } from '@naturalcycles/js-lib/object/object.util.js';
|
|
6
|
+
import { _filterUndefinedValues, _objectAssignExact, _omitWithUndefined, _pick, } from '@naturalcycles/js-lib/object/object.util.js';
|
|
7
7
|
import { pMap } from '@naturalcycles/js-lib/promise/pMap.js';
|
|
8
|
-
import { _passthroughPredicate, _stringMapEntries, _stringMapValues, _typeCast, } from '@naturalcycles/js-lib/types';
|
|
8
|
+
import { _objectKeys, _passthroughPredicate, _stringMapEntries, _stringMapValues, _typeCast, } from '@naturalcycles/js-lib/types';
|
|
9
9
|
import { stringId } from '@naturalcycles/nodejs-lib';
|
|
10
|
+
import { decompressZstdOrInflateToString, zstdCompress } from '@naturalcycles/nodejs-lib/zip';
|
|
10
11
|
import { DBLibError } from '../cnst.js';
|
|
11
12
|
import { RunnableDBQuery } from '../query/dbQuery.js';
|
|
12
13
|
import { CommonDaoTransaction } from './commonDaoTransaction.js';
|
|
@@ -76,7 +77,7 @@ export class CommonDao {
|
|
|
76
77
|
if (!id)
|
|
77
78
|
return null;
|
|
78
79
|
const [row] = await this.loadByIds([id], opt);
|
|
79
|
-
return this.anyToDBM(row, opt) || null;
|
|
80
|
+
return await (this.anyToDBM(row, opt) || null);
|
|
80
81
|
}
|
|
81
82
|
async getByIds(ids, opt = {}) {
|
|
82
83
|
const dbms = await this.loadByIds(ids, opt);
|
|
@@ -84,7 +85,7 @@ export class CommonDao {
|
|
|
84
85
|
}
|
|
85
86
|
async getByIdsAsDBM(ids, opt = {}) {
|
|
86
87
|
const rows = await this.loadByIds(ids, opt);
|
|
87
|
-
return this.anyToDBMs(rows);
|
|
88
|
+
return await this.anyToDBMs(rows);
|
|
88
89
|
}
|
|
89
90
|
// DRY private method
|
|
90
91
|
async loadByIds(ids, opt = {}) {
|
|
@@ -149,7 +150,7 @@ export class CommonDao {
|
|
|
149
150
|
q.table = opt.table || q.table;
|
|
150
151
|
const { rows, ...queryResult } = await this.cfg.db.runQuery(q, opt);
|
|
151
152
|
const isPartialQuery = !!q._selectedFieldNames;
|
|
152
|
-
const dbms = isPartialQuery ? rows : this.anyToDBMs(rows, opt);
|
|
153
|
+
const dbms = isPartialQuery ? rows : await this.anyToDBMs(rows, opt);
|
|
153
154
|
return { rows: dbms, ...queryResult };
|
|
154
155
|
}
|
|
155
156
|
async runQueryCount(q, opt = {}) {
|
|
@@ -164,7 +165,7 @@ export class CommonDao {
|
|
|
164
165
|
return pipeline;
|
|
165
166
|
opt.skipValidation ??= true;
|
|
166
167
|
opt.errorMode ||= ErrorMode.SUPPRESS;
|
|
167
|
-
return pipeline.
|
|
168
|
+
return pipeline.map(async (dbm) => await this.anyToDBM(dbm, opt), { errorMode: opt.errorMode });
|
|
168
169
|
}
|
|
169
170
|
streamQuery(q, opt = {}) {
|
|
170
171
|
const pipeline = this.streamQueryRaw(q, opt);
|
|
@@ -339,7 +340,7 @@ export class CommonDao {
|
|
|
339
340
|
async saveAsDBM(dbm, opt = {}) {
|
|
340
341
|
this.requireWriteAccess();
|
|
341
342
|
this.assignIdCreatedUpdated(dbm, opt); // mutates
|
|
342
|
-
const row = this.anyToDBM(dbm, opt);
|
|
343
|
+
const row = await this.anyToDBM(dbm, opt);
|
|
343
344
|
this.cfg.hooks.beforeSave?.(row);
|
|
344
345
|
const table = opt.table || this.cfg.table;
|
|
345
346
|
const saveOptions = this.prepareSaveOptions(opt);
|
|
@@ -371,7 +372,7 @@ export class CommonDao {
|
|
|
371
372
|
return [];
|
|
372
373
|
this.requireWriteAccess();
|
|
373
374
|
dbms.forEach(dbm => this.assignIdCreatedUpdated(dbm, opt));
|
|
374
|
-
const rows = this.anyToDBMs(dbms, opt);
|
|
375
|
+
const rows = await this.anyToDBMs(dbms, opt);
|
|
375
376
|
if (this.cfg.hooks.beforeSave) {
|
|
376
377
|
rows.forEach(row => this.cfg.hooks.beforeSave(row));
|
|
377
378
|
}
|
|
@@ -538,6 +539,8 @@ export class CommonDao {
|
|
|
538
539
|
// optimization: no need to run full joi DBM validation, cause BM validation will be run
|
|
539
540
|
// const dbm = this.anyToDBM(_dbm, opt)
|
|
540
541
|
const dbm = { ..._dbm, ...this.cfg.hooks.parseNaturalId(_dbm.id) };
|
|
542
|
+
// Decompress
|
|
543
|
+
await this.decompress(dbm);
|
|
541
544
|
// DBM > BM
|
|
542
545
|
const bm = ((await this.cfg.hooks.beforeDBMToBM?.(dbm)) || dbm);
|
|
543
546
|
// Validate/convert BM
|
|
@@ -552,24 +555,60 @@ export class CommonDao {
|
|
|
552
555
|
// bm gets assigned to the new reference
|
|
553
556
|
bm = this.validateAndConvert(bm, 'save', opt);
|
|
554
557
|
// BM > DBM
|
|
555
|
-
|
|
558
|
+
const dbm = ((await this.cfg.hooks.beforeBMToDBM?.(bm)) || bm);
|
|
559
|
+
// Compress
|
|
560
|
+
if (this.cfg.compress)
|
|
561
|
+
await this.compress(dbm);
|
|
562
|
+
return dbm;
|
|
556
563
|
}
|
|
557
564
|
async bmsToDBM(bms, opt = {}) {
|
|
558
565
|
// try/catch?
|
|
559
566
|
return await pMap(bms, async (bm) => await this.bmToDBM(bm, opt));
|
|
560
567
|
}
|
|
561
|
-
|
|
568
|
+
/**
|
|
569
|
+
* Mutates `dbm`.
|
|
570
|
+
*/
|
|
571
|
+
async compress(dbm) {
|
|
572
|
+
if (!this.cfg.compress)
|
|
573
|
+
return; // No compression requested
|
|
574
|
+
const { keys } = this.cfg.compress;
|
|
575
|
+
const properties = _pick(dbm, keys);
|
|
576
|
+
_assert(!('data' in dbm) || 'data' in properties, `Data (${dbm.id}) already has a "data" property. When using compression, this property must be included in the compression keys list.`);
|
|
577
|
+
const bufferString = JSON.stringify(properties);
|
|
578
|
+
const data = await zstdCompress(bufferString);
|
|
579
|
+
_omitWithUndefined(dbm, _objectKeys(properties), { mutate: true });
|
|
580
|
+
Object.assign(dbm, { data });
|
|
581
|
+
}
|
|
582
|
+
/**
|
|
583
|
+
* Mutates `dbm`.
|
|
584
|
+
*/
|
|
585
|
+
async decompress(dbm) {
|
|
586
|
+
_typeCast(dbm);
|
|
587
|
+
if (!Buffer.isBuffer(dbm.data))
|
|
588
|
+
return; // No compressed data
|
|
589
|
+
// try-catch to avoid a `data` with Buffer which is not compressed, but legit data
|
|
590
|
+
try {
|
|
591
|
+
const bufferString = await decompressZstdOrInflateToString(dbm.data);
|
|
592
|
+
const properties = JSON.parse(bufferString);
|
|
593
|
+
dbm.data = undefined;
|
|
594
|
+
Object.assign(dbm, properties);
|
|
595
|
+
}
|
|
596
|
+
catch { }
|
|
597
|
+
}
|
|
598
|
+
async anyToDBM(dbm, _opt = {}) {
|
|
562
599
|
if (!dbm)
|
|
563
600
|
return null;
|
|
564
601
|
// this shouldn't be happening on load! but should on save!
|
|
565
602
|
// this.assignIdCreatedUpdated(dbm, opt)
|
|
566
603
|
dbm = { ...dbm, ...this.cfg.hooks.parseNaturalId(dbm.id) };
|
|
604
|
+
// Decompress
|
|
605
|
+
await this.decompress(dbm);
|
|
567
606
|
// Validate/convert DBM
|
|
568
607
|
// return this.validateAndConvert(dbm, this.cfg.dbmSchema, DBModelType.DBM, opt)
|
|
569
608
|
return dbm;
|
|
570
609
|
}
|
|
571
|
-
anyToDBMs(rows, opt = {}) {
|
|
572
|
-
return rows
|
|
610
|
+
async anyToDBMs(rows, opt = {}) {
|
|
611
|
+
return await pMap(rows, async (entity) => await this.anyToDBM(entity, opt));
|
|
573
612
|
}
|
|
574
613
|
/**
|
|
575
614
|
* Returns *converted value* (NOT the same reference).
|
|
@@ -167,6 +167,16 @@ export interface CommonDaoCfg<BM extends BaseDBEntity, DBM extends BaseDBEntity
|
|
|
167
167
|
* @experimental
|
|
168
168
|
*/
|
|
169
169
|
patchInTransaction?: boolean;
|
|
170
|
+
/**
|
|
171
|
+
* When specified, the listed properties will be compressed under a `data` property in the DBM.
|
|
172
|
+
* If DBM already has a `data` property and you don't add it to the list, an error will be thrown.
|
|
173
|
+
*
|
|
174
|
+
* Compression happens after the `beforeBMToDBM` hook and before the DBM is saved to the database.
|
|
175
|
+
* Decompression happens after the DBM is loaded from the database and before the `beforeDBMToBM` hook.
|
|
176
|
+
*/
|
|
177
|
+
compress?: {
|
|
178
|
+
keys: [keyof DBM, ...(keyof DBM)[]];
|
|
179
|
+
};
|
|
170
180
|
}
|
|
171
181
|
/**
|
|
172
182
|
* Index can be defined in simple form, just as a property name: `abc`
|
package/package.json
CHANGED
|
@@ -205,6 +205,17 @@ export interface CommonDaoCfg<
|
|
|
205
205
|
* @experimental
|
|
206
206
|
*/
|
|
207
207
|
patchInTransaction?: boolean
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* When specified, the listed properties will be compressed under a `data` property in the DBM.
|
|
211
|
+
* If DBM already has a `data` property and you don't add it to the list, an error will be thrown.
|
|
212
|
+
*
|
|
213
|
+
* Compression happens after the `beforeBMToDBM` hook and before the DBM is saved to the database.
|
|
214
|
+
* Decompression happens after the DBM is loaded from the database and before the `beforeDBMToBM` hook.
|
|
215
|
+
*/
|
|
216
|
+
compress?: {
|
|
217
|
+
keys: [keyof DBM, ...(keyof DBM)[]]
|
|
218
|
+
}
|
|
208
219
|
}
|
|
209
220
|
|
|
210
221
|
/**
|
|
@@ -6,9 +6,12 @@ import { _deepJsonEquals } from '@naturalcycles/js-lib/object/deepEquals.js'
|
|
|
6
6
|
import {
|
|
7
7
|
_filterUndefinedValues,
|
|
8
8
|
_objectAssignExact,
|
|
9
|
+
_omitWithUndefined,
|
|
10
|
+
_pick,
|
|
9
11
|
} from '@naturalcycles/js-lib/object/object.util.js'
|
|
10
12
|
import { pMap } from '@naturalcycles/js-lib/promise/pMap.js'
|
|
11
13
|
import {
|
|
14
|
+
_objectKeys,
|
|
12
15
|
_passthroughPredicate,
|
|
13
16
|
_stringMapEntries,
|
|
14
17
|
_stringMapValues,
|
|
@@ -22,6 +25,7 @@ import {
|
|
|
22
25
|
import { stringId } from '@naturalcycles/nodejs-lib'
|
|
23
26
|
import type { JsonSchema } from '@naturalcycles/nodejs-lib/ajv'
|
|
24
27
|
import type { Pipeline } from '@naturalcycles/nodejs-lib/stream'
|
|
28
|
+
import { decompressZstdOrInflateToString, zstdCompress } from '@naturalcycles/nodejs-lib/zip'
|
|
25
29
|
import { DBLibError } from '../cnst.js'
|
|
26
30
|
import type {
|
|
27
31
|
CommonDBSaveOptions,
|
|
@@ -118,7 +122,7 @@ export class CommonDao<
|
|
|
118
122
|
async getByIdAsDBM(id?: ID | null, opt: CommonDaoReadOptions = {}): Promise<DBM | null> {
|
|
119
123
|
if (!id) return null
|
|
120
124
|
const [row] = await this.loadByIds([id], opt)
|
|
121
|
-
return this.anyToDBM(row, opt) || null
|
|
125
|
+
return await (this.anyToDBM(row, opt) || null)
|
|
122
126
|
}
|
|
123
127
|
|
|
124
128
|
async getByIds(ids: ID[], opt: CommonDaoReadOptions = {}): Promise<BM[]> {
|
|
@@ -128,7 +132,7 @@ export class CommonDao<
|
|
|
128
132
|
|
|
129
133
|
async getByIdsAsDBM(ids: ID[], opt: CommonDaoReadOptions = {}): Promise<DBM[]> {
|
|
130
134
|
const rows = await this.loadByIds(ids, opt)
|
|
131
|
-
return this.anyToDBMs(rows)
|
|
135
|
+
return await this.anyToDBMs(rows)
|
|
132
136
|
}
|
|
133
137
|
|
|
134
138
|
// DRY private method
|
|
@@ -216,7 +220,7 @@ export class CommonDao<
|
|
|
216
220
|
q.table = opt.table || q.table
|
|
217
221
|
const { rows, ...queryResult } = await this.cfg.db.runQuery<DBM>(q, opt)
|
|
218
222
|
const isPartialQuery = !!q._selectedFieldNames
|
|
219
|
-
const dbms = isPartialQuery ? rows : this.anyToDBMs(rows, opt)
|
|
223
|
+
const dbms = isPartialQuery ? rows : await this.anyToDBMs(rows, opt)
|
|
220
224
|
return { rows: dbms, ...queryResult }
|
|
221
225
|
}
|
|
222
226
|
|
|
@@ -235,7 +239,7 @@ export class CommonDao<
|
|
|
235
239
|
opt.skipValidation ??= true
|
|
236
240
|
opt.errorMode ||= ErrorMode.SUPPRESS
|
|
237
241
|
|
|
238
|
-
return pipeline.
|
|
242
|
+
return pipeline.map(async dbm => await this.anyToDBM(dbm, opt), { errorMode: opt.errorMode })
|
|
239
243
|
}
|
|
240
244
|
|
|
241
245
|
streamQuery(q: DBQuery<DBM>, opt: CommonDaoStreamOptions<BM> = {}): Pipeline<BM> {
|
|
@@ -455,7 +459,7 @@ export class CommonDao<
|
|
|
455
459
|
async saveAsDBM(dbm: Unsaved<DBM>, opt: CommonDaoSaveOptions<BM, DBM> = {}): Promise<DBM> {
|
|
456
460
|
this.requireWriteAccess()
|
|
457
461
|
this.assignIdCreatedUpdated(dbm, opt) // mutates
|
|
458
|
-
const row = this.anyToDBM(dbm, opt)
|
|
462
|
+
const row = await this.anyToDBM(dbm, opt)
|
|
459
463
|
this.cfg.hooks!.beforeSave?.(row)
|
|
460
464
|
const table = opt.table || this.cfg.table
|
|
461
465
|
const saveOptions = this.prepareSaveOptions(opt)
|
|
@@ -496,7 +500,7 @@ export class CommonDao<
|
|
|
496
500
|
if (!dbms.length) return []
|
|
497
501
|
this.requireWriteAccess()
|
|
498
502
|
dbms.forEach(dbm => this.assignIdCreatedUpdated(dbm, opt))
|
|
499
|
-
const rows = this.anyToDBMs(dbms as DBM[], opt)
|
|
503
|
+
const rows = await this.anyToDBMs(dbms as DBM[], opt)
|
|
500
504
|
if (this.cfg.hooks!.beforeSave) {
|
|
501
505
|
rows.forEach(row => this.cfg.hooks!.beforeSave!(row))
|
|
502
506
|
}
|
|
@@ -710,6 +714,9 @@ export class CommonDao<
|
|
|
710
714
|
// const dbm = this.anyToDBM(_dbm, opt)
|
|
711
715
|
const dbm: DBM = { ..._dbm, ...this.cfg.hooks!.parseNaturalId!(_dbm.id as ID) }
|
|
712
716
|
|
|
717
|
+
// Decompress
|
|
718
|
+
await this.decompress(dbm)
|
|
719
|
+
|
|
713
720
|
// DBM > BM
|
|
714
721
|
const bm = ((await this.cfg.hooks!.beforeDBMToBM?.(dbm)) || dbm) as Partial<BM>
|
|
715
722
|
|
|
@@ -734,7 +741,12 @@ export class CommonDao<
|
|
|
734
741
|
bm = this.validateAndConvert(bm, 'save', opt)
|
|
735
742
|
|
|
736
743
|
// BM > DBM
|
|
737
|
-
|
|
744
|
+
const dbm = ((await this.cfg.hooks!.beforeBMToDBM?.(bm)) || bm) as DBM
|
|
745
|
+
|
|
746
|
+
// Compress
|
|
747
|
+
if (this.cfg.compress) await this.compress(dbm)
|
|
748
|
+
|
|
749
|
+
return dbm
|
|
738
750
|
}
|
|
739
751
|
|
|
740
752
|
async bmsToDBM(bms: BM[], opt: CommonDaoOptions = {}): Promise<DBM[]> {
|
|
@@ -742,9 +754,43 @@ export class CommonDao<
|
|
|
742
754
|
return await pMap(bms, async bm => await this.bmToDBM(bm, opt))
|
|
743
755
|
}
|
|
744
756
|
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
757
|
+
/**
|
|
758
|
+
* Mutates `dbm`.
|
|
759
|
+
*/
|
|
760
|
+
async compress(dbm: DBM): Promise<void> {
|
|
761
|
+
if (!this.cfg.compress) return // No compression requested
|
|
762
|
+
|
|
763
|
+
const { keys } = this.cfg.compress
|
|
764
|
+
const properties = _pick(dbm, keys)
|
|
765
|
+
_assert(
|
|
766
|
+
!('data' in dbm) || 'data' in properties,
|
|
767
|
+
`Data (${dbm.id}) already has a "data" property. When using compression, this property must be included in the compression keys list.`,
|
|
768
|
+
)
|
|
769
|
+
const bufferString = JSON.stringify(properties)
|
|
770
|
+
const data = await zstdCompress(bufferString)
|
|
771
|
+
_omitWithUndefined(dbm as any, _objectKeys(properties), { mutate: true })
|
|
772
|
+
Object.assign(dbm, { data })
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
/**
|
|
776
|
+
* Mutates `dbm`.
|
|
777
|
+
*/
|
|
778
|
+
async decompress(dbm: DBM): Promise<void> {
|
|
779
|
+
_typeCast<Compressed<DBM>>(dbm)
|
|
780
|
+
if (!Buffer.isBuffer(dbm.data)) return // No compressed data
|
|
781
|
+
|
|
782
|
+
// try-catch to avoid a `data` with Buffer which is not compressed, but legit data
|
|
783
|
+
try {
|
|
784
|
+
const bufferString = await decompressZstdOrInflateToString(dbm.data)
|
|
785
|
+
const properties = JSON.parse(bufferString)
|
|
786
|
+
dbm.data = undefined
|
|
787
|
+
Object.assign(dbm, properties)
|
|
788
|
+
} catch {}
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
async anyToDBM(dbm: undefined, opt?: CommonDaoOptions): Promise<null>
|
|
792
|
+
async anyToDBM(dbm?: any, opt?: CommonDaoOptions): Promise<DBM>
|
|
793
|
+
async anyToDBM(dbm?: DBM, _opt: CommonDaoOptions = {}): Promise<DBM | null> {
|
|
748
794
|
if (!dbm) return null
|
|
749
795
|
|
|
750
796
|
// this shouldn't be happening on load! but should on save!
|
|
@@ -752,13 +798,16 @@ export class CommonDao<
|
|
|
752
798
|
|
|
753
799
|
dbm = { ...dbm, ...this.cfg.hooks!.parseNaturalId!(dbm.id as ID) }
|
|
754
800
|
|
|
801
|
+
// Decompress
|
|
802
|
+
await this.decompress(dbm)
|
|
803
|
+
|
|
755
804
|
// Validate/convert DBM
|
|
756
805
|
// return this.validateAndConvert(dbm, this.cfg.dbmSchema, DBModelType.DBM, opt)
|
|
757
806
|
return dbm
|
|
758
807
|
}
|
|
759
808
|
|
|
760
|
-
anyToDBMs(rows: DBM[], opt: CommonDaoOptions = {}): DBM[] {
|
|
761
|
-
return rows
|
|
809
|
+
async anyToDBMs(rows: DBM[], opt: CommonDaoOptions = {}): Promise<DBM[]> {
|
|
810
|
+
return await pMap(rows, async entity => await this.anyToDBM(entity, opt))
|
|
762
811
|
}
|
|
763
812
|
|
|
764
813
|
/**
|
|
@@ -1140,3 +1189,11 @@ export type InferDBM<DAO> = DAO extends CommonDao<any, infer DBM> ? DBM : never
|
|
|
1140
1189
|
export type InferID<DAO> = DAO extends CommonDao<any, any, infer ID> ? ID : never
|
|
1141
1190
|
|
|
1142
1191
|
export type AnyDao = CommonDao<any>
|
|
1192
|
+
|
|
1193
|
+
/**
|
|
1194
|
+
* Represents a DBM whose properties have been compressed into a `data` Buffer.
|
|
1195
|
+
*
|
|
1196
|
+
* Used internally during compression/decompression so that DBM instances can
|
|
1197
|
+
* carry their compressed payload alongside the original type shape.
|
|
1198
|
+
*/
|
|
1199
|
+
type Compressed<DBM> = DBM & { data?: Buffer }
|