@naturalcycles/db-lib 10.51.0 → 10.53.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.js +8 -3
- package/dist/commondao/common.dao.model.d.ts +16 -0
- package/dist/inmemory/queryInMemory.js +2 -9
- package/dist/query/dbQuery.js +4 -4
- package/dist/testing/commonDBTest.js +1 -1
- package/dist/testing/commonDaoTest.js +1 -1
- package/package.json +3 -3
- package/src/commondao/common.dao.model.ts +16 -0
- package/src/commondao/common.dao.ts +8 -3
- package/src/inmemory/queryInMemory.ts +4 -9
- package/src/query/dbQuery.ts +4 -4
- package/src/testing/commonDBTest.ts +1 -1
- package/src/testing/commonDaoTest.ts +1 -1
|
@@ -51,7 +51,7 @@ export class CommonDao {
|
|
|
51
51
|
// then we need to ensure that the '__compressed' property is part of the index exclusion list.
|
|
52
52
|
if (this.cfg.compress?.keys) {
|
|
53
53
|
const current = this.cfg.excludeFromIndexes;
|
|
54
|
-
this.cfg.excludeFromIndexes = current ?
|
|
54
|
+
this.cfg.excludeFromIndexes = current ? current.slice() : [];
|
|
55
55
|
if (!this.cfg.excludeFromIndexes.includes('__compressed')) {
|
|
56
56
|
this.cfg.excludeFromIndexes.push('__compressed');
|
|
57
57
|
}
|
|
@@ -653,12 +653,17 @@ export class CommonDao {
|
|
|
653
653
|
async compress(dbm) {
|
|
654
654
|
if (!this.cfg.compress?.keys.length)
|
|
655
655
|
return; // No compression requested
|
|
656
|
-
const { keys, level = 1 } = this.cfg.compress;
|
|
656
|
+
const { keys, level = 1, warnSizeBytes, onOversizeWarning } = this.cfg.compress;
|
|
657
657
|
const properties = _pick(dbm, keys);
|
|
658
658
|
const bufferString = JSON.stringify(properties);
|
|
659
659
|
// Unlike `decompress`, we're testing to use async zstd compression.
|
|
660
660
|
// Async Decompression leaks memory severely. But Compression seems fine.
|
|
661
661
|
const __compressed = await zip2.zstdCompress(bufferString, level);
|
|
662
|
+
if (warnSizeBytes && onOversizeWarning && __compressed.byteLength > warnSizeBytes) {
|
|
663
|
+
// Shallow-clone: `dbm` is mutated below (omit source keys + assign __compressed),
|
|
664
|
+
// so we hand the hook a snapshot of the pre-mutation state.
|
|
665
|
+
onOversizeWarning({ ...dbm }, __compressed.byteLength);
|
|
666
|
+
}
|
|
662
667
|
_omitWithUndefined(dbm, _objectKeys(properties), { mutate: true });
|
|
663
668
|
Object.assign(dbm, { __compressed });
|
|
664
669
|
}
|
|
@@ -792,7 +797,7 @@ export class CommonDao {
|
|
|
792
797
|
}
|
|
793
798
|
const idsByTable = {};
|
|
794
799
|
for (const [table, idSet] of _stringMapEntries(idSetByTable)) {
|
|
795
|
-
idsByTable[table] =
|
|
800
|
+
idsByTable[table] = Array.from(idSet);
|
|
796
801
|
}
|
|
797
802
|
return idsByTable;
|
|
798
803
|
}
|
|
@@ -185,6 +185,22 @@ export interface CommonDaoCfg<BM extends BaseDBEntity, DBM extends BaseDBEntity
|
|
|
185
185
|
* Undefined will default to level 1 (not the 3, which is the zstd default)
|
|
186
186
|
*/
|
|
187
187
|
level?: Integer;
|
|
188
|
+
/**
|
|
189
|
+
* If set, `onOversizeWarning` is invoked whenever the resulting `__compressed`
|
|
190
|
+
* Buffer exceeds this size in bytes. Useful for monitoring rows approaching
|
|
191
|
+
* DB row-size limits (e.g. Datastore's 1MB per entity).
|
|
192
|
+
*
|
|
193
|
+
* No-op unless `onOversizeWarning` is also provided.
|
|
194
|
+
*/
|
|
195
|
+
warnSizeBytes?: number;
|
|
196
|
+
/**
|
|
197
|
+
* Invoked when the `__compressed` Buffer exceeds `warnSizeBytes`.
|
|
198
|
+
*
|
|
199
|
+
* Called with a shallow clone of the DBM (since the original is mutated
|
|
200
|
+
* later in the compression step) and the resulting compressed size in bytes.
|
|
201
|
+
* The consumer decides how to surface the warning (Sentry, logger, metrics, etc.).
|
|
202
|
+
*/
|
|
203
|
+
onOversizeWarning?: (dbm: DBM, size: number) => void;
|
|
188
204
|
};
|
|
189
205
|
}
|
|
190
206
|
/**
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { comparators } from '@naturalcycles/js-lib/array';
|
|
1
2
|
import { _get, _pick } from '@naturalcycles/js-lib/object/object.util.js';
|
|
2
3
|
const FILTER_FNS = {
|
|
3
4
|
'==': (v, val) => v === val,
|
|
@@ -30,15 +31,7 @@ export function queryInMemory(q, rows = []) {
|
|
|
30
31
|
const [order] = q._orders;
|
|
31
32
|
if (order) {
|
|
32
33
|
const { name, descending } = order;
|
|
33
|
-
rows = rows.sort((
|
|
34
|
-
// oxlint-disable-next-line eqeqeq
|
|
35
|
-
if (a[name] == b[name])
|
|
36
|
-
return 0;
|
|
37
|
-
if (descending) {
|
|
38
|
-
return a[name] < b[name] ? 1 : -1;
|
|
39
|
-
}
|
|
40
|
-
return a[name] > b[name] ? 1 : -1;
|
|
41
|
-
});
|
|
34
|
+
rows = rows.sort(comparators.by(r => r[name], { dir: descending ? 'desc' : 'asc' }));
|
|
42
35
|
}
|
|
43
36
|
// .offset()
|
|
44
37
|
if (q._offsetValue) {
|
package/dist/query/dbQuery.js
CHANGED
|
@@ -101,12 +101,12 @@ export class DBQuery {
|
|
|
101
101
|
}
|
|
102
102
|
clone() {
|
|
103
103
|
return _objectAssign(new DBQuery(this.table), {
|
|
104
|
-
_filters:
|
|
104
|
+
_filters: this._filters.slice(),
|
|
105
105
|
_limitValue: this._limitValue,
|
|
106
106
|
_offsetValue: this._offsetValue,
|
|
107
|
-
_orders:
|
|
108
|
-
_selectedFieldNames: this._selectedFieldNames
|
|
109
|
-
_groupByFieldNames: this._groupByFieldNames
|
|
107
|
+
_orders: this._orders.slice(),
|
|
108
|
+
_selectedFieldNames: this._selectedFieldNames?.slice(),
|
|
109
|
+
_groupByFieldNames: this._groupByFieldNames?.slice(),
|
|
110
110
|
_distinct: this._distinct,
|
|
111
111
|
_startCursor: this._startCursor,
|
|
112
112
|
_endCursor: this._endCursor,
|
|
@@ -130,7 +130,7 @@ export async function runCommonDBTest(db, quirks = {}) {
|
|
|
130
130
|
test('query order by k1 desc', async () => {
|
|
131
131
|
const q = new DBQuery(TEST_TABLE).order('k1', true);
|
|
132
132
|
const { rows } = await db.runQuery(q);
|
|
133
|
-
expectMatch(
|
|
133
|
+
expectMatch(items.toReversed(), rows, quirks);
|
|
134
134
|
});
|
|
135
135
|
}
|
|
136
136
|
if (support.dbQuerySelectFields) {
|
|
@@ -160,7 +160,7 @@ export async function runCommonDaoTest(db, quirks = {}) {
|
|
|
160
160
|
if (support.dbQueryOrder) {
|
|
161
161
|
test('query order by k1 desc', async () => {
|
|
162
162
|
const rows = await dao.query().order('k1', true).runQuery();
|
|
163
|
-
expectMatch(
|
|
163
|
+
expectMatch(expectedItems.toReversed(), rows, quirks);
|
|
164
164
|
});
|
|
165
165
|
}
|
|
166
166
|
if (support.dbQuerySelectFields) {
|
package/package.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@naturalcycles/db-lib",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "10.
|
|
4
|
+
"version": "10.53.0",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@naturalcycles/js-lib": "^15",
|
|
7
7
|
"@naturalcycles/nodejs-lib": "^15"
|
|
8
8
|
},
|
|
9
9
|
"devDependencies": {
|
|
10
|
-
"@typescript/native-preview": "
|
|
11
|
-
"@naturalcycles/dev-lib": "
|
|
10
|
+
"@typescript/native-preview": "beta",
|
|
11
|
+
"@naturalcycles/dev-lib": "18.4.2"
|
|
12
12
|
},
|
|
13
13
|
"files": [
|
|
14
14
|
"dist",
|
|
@@ -224,6 +224,22 @@ export interface CommonDaoCfg<
|
|
|
224
224
|
* Undefined will default to level 1 (not the 3, which is the zstd default)
|
|
225
225
|
*/
|
|
226
226
|
level?: Integer
|
|
227
|
+
/**
|
|
228
|
+
* If set, `onOversizeWarning` is invoked whenever the resulting `__compressed`
|
|
229
|
+
* Buffer exceeds this size in bytes. Useful for monitoring rows approaching
|
|
230
|
+
* DB row-size limits (e.g. Datastore's 1MB per entity).
|
|
231
|
+
*
|
|
232
|
+
* No-op unless `onOversizeWarning` is also provided.
|
|
233
|
+
*/
|
|
234
|
+
warnSizeBytes?: number
|
|
235
|
+
/**
|
|
236
|
+
* Invoked when the `__compressed` Buffer exceeds `warnSizeBytes`.
|
|
237
|
+
*
|
|
238
|
+
* Called with a shallow clone of the DBM (since the original is mutated
|
|
239
|
+
* later in the compression step) and the resulting compressed size in bytes.
|
|
240
|
+
* The consumer decides how to surface the warning (Sentry, logger, metrics, etc.).
|
|
241
|
+
*/
|
|
242
|
+
onOversizeWarning?: (dbm: DBM, size: number) => void
|
|
227
243
|
}
|
|
228
244
|
}
|
|
229
245
|
|
|
@@ -95,7 +95,7 @@ export class CommonDao<
|
|
|
95
95
|
// then we need to ensure that the '__compressed' property is part of the index exclusion list.
|
|
96
96
|
if (this.cfg.compress?.keys) {
|
|
97
97
|
const current = this.cfg.excludeFromIndexes
|
|
98
|
-
this.cfg.excludeFromIndexes = current ?
|
|
98
|
+
this.cfg.excludeFromIndexes = current ? current.slice() : []
|
|
99
99
|
if (!this.cfg.excludeFromIndexes.includes('__compressed' as any)) {
|
|
100
100
|
this.cfg.excludeFromIndexes.push('__compressed' as any)
|
|
101
101
|
}
|
|
@@ -849,12 +849,17 @@ export class CommonDao<
|
|
|
849
849
|
private async compress(dbm: DBM): Promise<void> {
|
|
850
850
|
if (!this.cfg.compress?.keys.length) return // No compression requested
|
|
851
851
|
|
|
852
|
-
const { keys, level = 1 } = this.cfg.compress
|
|
852
|
+
const { keys, level = 1, warnSizeBytes, onOversizeWarning } = this.cfg.compress
|
|
853
853
|
const properties = _pick(dbm, keys)
|
|
854
854
|
const bufferString = JSON.stringify(properties)
|
|
855
855
|
// Unlike `decompress`, we're testing to use async zstd compression.
|
|
856
856
|
// Async Decompression leaks memory severely. But Compression seems fine.
|
|
857
857
|
const __compressed = await zip2.zstdCompress(bufferString, level)
|
|
858
|
+
if (warnSizeBytes && onOversizeWarning && __compressed.byteLength > warnSizeBytes) {
|
|
859
|
+
// Shallow-clone: `dbm` is mutated below (omit source keys + assign __compressed),
|
|
860
|
+
// so we hand the hook a snapshot of the pre-mutation state.
|
|
861
|
+
onOversizeWarning({ ...dbm }, __compressed.byteLength)
|
|
862
|
+
}
|
|
858
863
|
_omitWithUndefined(dbm as any, _objectKeys(properties), { mutate: true })
|
|
859
864
|
Object.assign(dbm, { __compressed })
|
|
860
865
|
}
|
|
@@ -1028,7 +1033,7 @@ export class CommonDao<
|
|
|
1028
1033
|
|
|
1029
1034
|
const idsByTable: StringMap<string[]> = {}
|
|
1030
1035
|
for (const [table, idSet] of _stringMapEntries(idSetByTable)) {
|
|
1031
|
-
idsByTable[table] =
|
|
1036
|
+
idsByTable[table] = Array.from(idSet)
|
|
1032
1037
|
}
|
|
1033
1038
|
return idsByTable
|
|
1034
1039
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { comparators } from '@naturalcycles/js-lib/array'
|
|
1
2
|
import { _get, _pick } from '@naturalcycles/js-lib/object/object.util.js'
|
|
2
3
|
import type { ObjectWithId } from '@naturalcycles/js-lib/types'
|
|
3
4
|
import type { DBQuery, DBQueryFilterOperator } from '../query/dbQuery.js'
|
|
@@ -38,15 +39,9 @@ export function queryInMemory<ROW extends ObjectWithId>(q: DBQuery<ROW>, rows: R
|
|
|
38
39
|
const [order] = q._orders
|
|
39
40
|
if (order) {
|
|
40
41
|
const { name, descending } = order
|
|
41
|
-
rows = rows.sort(
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
if (descending) {
|
|
46
|
-
return a[name] < b[name] ? 1 : -1
|
|
47
|
-
}
|
|
48
|
-
return a[name] > b[name] ? 1 : -1
|
|
49
|
-
})
|
|
42
|
+
rows = rows.sort(
|
|
43
|
+
comparators.by(r => r[name] as string | number, { dir: descending ? 'desc' : 'asc' }),
|
|
44
|
+
)
|
|
50
45
|
}
|
|
51
46
|
|
|
52
47
|
// .offset()
|
package/src/query/dbQuery.ts
CHANGED
|
@@ -171,12 +171,12 @@ export class DBQuery<ROW extends ObjectWithId> {
|
|
|
171
171
|
|
|
172
172
|
clone(): DBQuery<ROW> {
|
|
173
173
|
return _objectAssign(new DBQuery<ROW>(this.table), {
|
|
174
|
-
_filters:
|
|
174
|
+
_filters: this._filters.slice(),
|
|
175
175
|
_limitValue: this._limitValue,
|
|
176
176
|
_offsetValue: this._offsetValue,
|
|
177
|
-
_orders:
|
|
178
|
-
_selectedFieldNames: this._selectedFieldNames
|
|
179
|
-
_groupByFieldNames: this._groupByFieldNames
|
|
177
|
+
_orders: this._orders.slice(),
|
|
178
|
+
_selectedFieldNames: this._selectedFieldNames?.slice(),
|
|
179
|
+
_groupByFieldNames: this._groupByFieldNames?.slice(),
|
|
180
180
|
_distinct: this._distinct,
|
|
181
181
|
_startCursor: this._startCursor,
|
|
182
182
|
_endCursor: this._endCursor,
|
|
@@ -192,7 +192,7 @@ export async function runCommonDBTest(
|
|
|
192
192
|
test('query order by k1 desc', async () => {
|
|
193
193
|
const q = new DBQuery<TestItemDBM>(TEST_TABLE).order('k1', true)
|
|
194
194
|
const { rows } = await db.runQuery(q)
|
|
195
|
-
expectMatch(
|
|
195
|
+
expectMatch(items.toReversed(), rows, quirks)
|
|
196
196
|
})
|
|
197
197
|
}
|
|
198
198
|
|
|
@@ -213,7 +213,7 @@ export async function runCommonDaoTest(
|
|
|
213
213
|
if (support.dbQueryOrder) {
|
|
214
214
|
test('query order by k1 desc', async () => {
|
|
215
215
|
const rows = await dao.query().order('k1', true).runQuery()
|
|
216
|
-
expectMatch(
|
|
216
|
+
expectMatch(expectedItems.toReversed(), rows, quirks)
|
|
217
217
|
})
|
|
218
218
|
}
|
|
219
219
|
|