@naturalcycles/db-lib 10.0.2 → 10.1.1
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/adapter/cachedb/cache.db.d.ts +5 -5
- package/dist/adapter/cachedb/cache.db.js +8 -12
- package/dist/adapter/cachedb/cache.db.model.d.ts +2 -2
- package/dist/adapter/cachedb/cache.db.model.js +1 -2
- package/dist/adapter/cachedb/index.d.ts +2 -2
- package/dist/adapter/cachedb/index.js +2 -5
- package/dist/adapter/file/file.db.d.ts +5 -6
- package/dist/adapter/file/file.db.js +25 -27
- package/dist/adapter/file/file.db.model.d.ts +2 -2
- package/dist/adapter/file/file.db.model.js +1 -2
- package/dist/adapter/file/inMemory.persistence.plugin.d.ts +2 -2
- package/dist/adapter/file/inMemory.persistence.plugin.js +3 -7
- package/dist/adapter/file/index.d.ts +3 -3
- package/dist/adapter/file/index.js +3 -7
- package/dist/adapter/file/localFile.persistence.plugin.d.ts +2 -2
- package/dist/adapter/file/localFile.persistence.plugin.js +11 -15
- package/dist/adapter/file/noop.persistence.plugin.d.ts +2 -2
- package/dist/adapter/file/noop.persistence.plugin.js +1 -5
- package/dist/adapter/inmemory/inMemory.db.d.ts +5 -4
- package/dist/adapter/inmemory/inMemory.db.js +43 -41
- package/dist/adapter/inmemory/inMemoryKeyValueDB.d.ts +2 -2
- package/dist/adapter/inmemory/inMemoryKeyValueDB.js +7 -11
- package/dist/adapter/inmemory/queryInMemory.d.ts +1 -1
- package/dist/adapter/inmemory/queryInMemory.js +4 -7
- package/dist/base.common.db.d.ts +5 -4
- package/dist/base.common.db.js +8 -9
- package/dist/cnst.js +2 -5
- package/dist/common.db.d.ts +8 -2
- package/dist/common.db.js +3 -6
- package/dist/commondao/common.dao.d.ts +11 -4
- package/dist/commondao/common.dao.js +120 -113
- package/dist/commondao/common.dao.model.d.ts +2 -2
- package/dist/commondao/common.dao.model.js +2 -5
- package/dist/db.model.d.ts +6 -1
- package/dist/db.model.js +4 -7
- package/dist/index.d.ts +17 -17
- package/dist/index.js +17 -20
- package/dist/kv/commonKeyValueDB.d.ts +1 -1
- package/dist/kv/commonKeyValueDB.js +1 -4
- package/dist/kv/commonKeyValueDao.d.ts +3 -3
- package/dist/kv/commonKeyValueDao.js +10 -14
- package/dist/kv/commonKeyValueDaoMemoCache.d.ts +1 -1
- package/dist/kv/commonKeyValueDaoMemoCache.js +4 -8
- package/dist/model.util.js +9 -15
- package/dist/pipeline/dbPipelineBackup.d.ts +2 -2
- package/dist/pipeline/dbPipelineBackup.js +27 -30
- package/dist/pipeline/dbPipelineCopy.d.ts +2 -2
- package/dist/pipeline/dbPipelineCopy.js +20 -23
- package/dist/pipeline/dbPipelineRestore.d.ts +2 -2
- package/dist/pipeline/dbPipelineRestore.js +27 -30
- package/dist/query/dbQuery.d.ts +3 -3
- package/dist/query/dbQuery.js +7 -12
- package/dist/testing/{dbTest.d.ts → commonDBTest.d.ts} +1 -1
- package/dist/testing/{dbTest.js → commonDBTest.js} +81 -62
- package/dist/testing/commonDaoTest.d.ts +3 -0
- package/dist/testing/{daoTest.js → commonDaoTest.js} +101 -38
- package/dist/testing/index.d.ts +7 -7
- package/dist/testing/index.js +6 -20
- package/dist/testing/keyValueDBTest.d.ts +1 -1
- package/dist/testing/keyValueDBTest.js +28 -31
- package/dist/testing/keyValueDaoTest.d.ts +1 -1
- package/dist/testing/keyValueDaoTest.js +8 -11
- package/dist/testing/test.model.js +30 -37
- package/dist/testing/timeSeriesTest.util.d.ts +1 -1
- package/dist/testing/timeSeriesTest.util.js +3 -6
- package/dist/timeseries/commonTimeSeriesDao.d.ts +1 -1
- package/dist/timeseries/commonTimeSeriesDao.js +5 -9
- package/dist/timeseries/timeSeries.model.d.ts +1 -1
- package/dist/timeseries/timeSeries.model.js +1 -2
- package/dist/transaction/dbTransaction.util.d.ts +3 -2
- package/dist/transaction/dbTransaction.util.js +2 -5
- package/dist/validation/index.d.ts +2 -2
- package/dist/validation/index.js +25 -28
- package/package.json +3 -3
- package/src/adapter/cachedb/cache.db.model.ts +2 -2
- package/src/adapter/cachedb/cache.db.ts +6 -6
- package/src/adapter/cachedb/index.ts +2 -2
- package/src/adapter/file/file.db.model.ts +2 -2
- package/src/adapter/file/file.db.ts +8 -6
- package/src/adapter/file/inMemory.persistence.plugin.ts +2 -2
- package/src/adapter/file/index.ts +3 -3
- package/src/adapter/file/localFile.persistence.plugin.ts +2 -2
- package/src/adapter/file/noop.persistence.plugin.ts +2 -2
- package/src/adapter/inmemory/inMemory.db.ts +15 -10
- package/src/adapter/inmemory/inMemoryKeyValueDB.ts +7 -3
- package/src/adapter/inmemory/queryInMemory.ts +1 -1
- package/src/base.common.db.ts +10 -5
- package/src/common.db.ts +10 -2
- package/src/commondao/common.dao.model.ts +2 -2
- package/src/commondao/common.dao.ts +20 -6
- package/src/db.model.ts +7 -1
- package/src/index.ts +17 -17
- package/src/kv/commonKeyValueDB.ts +1 -1
- package/src/kv/commonKeyValueDao.ts +3 -3
- package/src/kv/commonKeyValueDaoMemoCache.ts +1 -1
- package/src/pipeline/dbPipelineBackup.ts +2 -2
- package/src/pipeline/dbPipelineCopy.ts +3 -3
- package/src/pipeline/dbPipelineRestore.ts +2 -2
- package/src/query/dbQuery.ts +3 -3
- package/src/testing/{dbTest.ts → commonDBTest.ts} +34 -6
- package/src/testing/{daoTest.ts → commonDaoTest.ts} +89 -11
- package/src/testing/index.ts +7 -7
- package/src/testing/keyValueDBTest.ts +2 -2
- package/src/testing/keyValueDaoTest.ts +3 -3
- package/src/testing/timeSeriesTest.util.ts +1 -1
- package/src/timeseries/commonTimeSeriesDao.ts +2 -2
- package/src/timeseries/timeSeries.model.ts +1 -1
- package/src/transaction/dbTransaction.util.ts +3 -2
- package/src/validation/index.ts +8 -3
- package/dist/testing/daoTest.d.ts +0 -3
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
exports.dbPipelineRestore = dbPipelineRestore;
|
|
4
|
-
const js_lib_1 = require("@naturalcycles/js-lib");
|
|
5
|
-
const nodejs_lib_1 = require("@naturalcycles/nodejs-lib");
|
|
1
|
+
import { _hb, _mapValues, _passthroughMapper, ErrorMode, localTime, pMap, } from '@naturalcycles/js-lib';
|
|
2
|
+
import { _pipeline, boldWhite, dimWhite, fs2, grey, NDJsonStats, transformChunk, transformFilterSync, transformLogProgress, transformMap, transformTap, writableForEach, yellow, } from '@naturalcycles/nodejs-lib';
|
|
6
3
|
/**
|
|
7
4
|
* Pipeline from NDJSON files in a folder (optionally gzipped) to CommonDB.
|
|
8
5
|
* Allows to define a mapper and a predicate to map/filter objects between input and output.
|
|
@@ -10,17 +7,17 @@ const nodejs_lib_1 = require("@naturalcycles/nodejs-lib");
|
|
|
10
7
|
*
|
|
11
8
|
* Optionally you can provide mapperPerTable and @param transformMapOptions (one for all mappers) - it will run for each table.
|
|
12
9
|
*/
|
|
13
|
-
async function dbPipelineRestore(opt) {
|
|
14
|
-
const { db, concurrency = 16, chunkSize = 100, limit, sinceUpdated, inputDirPath, mapperPerTable = {}, saveOptionsPerTable = {}, transformMapOptions, errorMode =
|
|
10
|
+
export async function dbPipelineRestore(opt) {
|
|
11
|
+
const { db, concurrency = 16, chunkSize = 100, limit, sinceUpdated, inputDirPath, mapperPerTable = {}, saveOptionsPerTable = {}, transformMapOptions, errorMode = ErrorMode.SUPPRESS, recreateTables = false, } = opt;
|
|
15
12
|
const onlyTables = opt.tables && new Set(opt.tables);
|
|
16
|
-
const sinceUpdatedStr = sinceUpdated ? ' since ' +
|
|
17
|
-
console.log(`>> ${
|
|
18
|
-
|
|
13
|
+
const sinceUpdatedStr = sinceUpdated ? ' since ' + grey(localTime(sinceUpdated).toPretty()) : '';
|
|
14
|
+
console.log(`>> ${dimWhite('dbPipelineRestore')} started in ${grey(inputDirPath)}...${sinceUpdatedStr}`);
|
|
15
|
+
fs2.ensureDir(inputDirPath);
|
|
19
16
|
const tablesToGzip = new Set();
|
|
20
17
|
const sizeByTable = {};
|
|
21
18
|
const statsPerTable = {};
|
|
22
19
|
const tables = [];
|
|
23
|
-
|
|
20
|
+
fs2.readdir(inputDirPath).forEach(f => {
|
|
24
21
|
let table;
|
|
25
22
|
let gzip = false;
|
|
26
23
|
if (f.endsWith('.ndjson')) {
|
|
@@ -38,61 +35,61 @@ async function dbPipelineRestore(opt) {
|
|
|
38
35
|
tables.push(table);
|
|
39
36
|
if (gzip)
|
|
40
37
|
tablesToGzip.add(table);
|
|
41
|
-
sizeByTable[table] =
|
|
38
|
+
sizeByTable[table] = fs2.stat(`${inputDirPath}/${f}`).size;
|
|
42
39
|
});
|
|
43
|
-
const sizeStrByTable =
|
|
44
|
-
console.log(`${
|
|
40
|
+
const sizeStrByTable = _mapValues(sizeByTable, (_k, b) => _hb(b));
|
|
41
|
+
console.log(`${yellow(tables.length)} ${boldWhite('table(s)')}:\n`, sizeStrByTable);
|
|
45
42
|
// const schemaByTable: Record<string, CommonSchema> = {}
|
|
46
43
|
if (recreateTables) {
|
|
47
|
-
await
|
|
44
|
+
await pMap(tables, async (table) => {
|
|
48
45
|
const schemaFilePath = `${inputDirPath}/${table}.schema.json`;
|
|
49
|
-
if (!
|
|
46
|
+
if (!fs2.pathExists(schemaFilePath)) {
|
|
50
47
|
console.warn(`${schemaFilePath} does not exist!`);
|
|
51
48
|
return;
|
|
52
49
|
}
|
|
53
|
-
const schema = await
|
|
50
|
+
const schema = await fs2.readJsonAsync(schemaFilePath);
|
|
54
51
|
await db.createTable(table, schema, { dropIfExists: true });
|
|
55
52
|
});
|
|
56
53
|
}
|
|
57
|
-
await
|
|
54
|
+
await pMap(tables, async (table) => {
|
|
58
55
|
const gzip = tablesToGzip.has(table);
|
|
59
56
|
const filePath = `${inputDirPath}/${table}.ndjson` + (gzip ? '.gz' : '');
|
|
60
57
|
const saveOptions = saveOptionsPerTable[table] || {};
|
|
61
58
|
const started = Date.now();
|
|
62
59
|
let rows = 0;
|
|
63
60
|
const sizeBytes = sizeByTable[table];
|
|
64
|
-
console.log(`<< ${
|
|
65
|
-
await
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
61
|
+
console.log(`<< ${grey(filePath)} ${dimWhite(_hb(sizeBytes))} started...`);
|
|
62
|
+
await _pipeline([
|
|
63
|
+
fs2.createReadStreamAsNDJSON(filePath).take(limit || Number.POSITIVE_INFINITY),
|
|
64
|
+
transformTap(() => rows++),
|
|
65
|
+
transformLogProgress({
|
|
69
66
|
logEvery: 1000,
|
|
70
67
|
...opt,
|
|
71
68
|
metric: table,
|
|
72
69
|
}),
|
|
73
70
|
...(sinceUpdated
|
|
74
|
-
? [
|
|
71
|
+
? [transformFilterSync(r => r.updated >= sinceUpdated)]
|
|
75
72
|
: []),
|
|
76
|
-
|
|
73
|
+
transformMap(mapperPerTable[table] || _passthroughMapper, {
|
|
77
74
|
errorMode,
|
|
78
75
|
flattenArrayOutput: true,
|
|
79
76
|
...transformMapOptions,
|
|
80
77
|
metric: table,
|
|
81
78
|
}),
|
|
82
|
-
|
|
83
|
-
|
|
79
|
+
transformChunk({ chunkSize }),
|
|
80
|
+
writableForEach(async (dbms) => {
|
|
84
81
|
await db.saveBatch(table, dbms, saveOptions);
|
|
85
82
|
}),
|
|
86
83
|
]);
|
|
87
|
-
const stats =
|
|
84
|
+
const stats = NDJsonStats.create({
|
|
88
85
|
tookMillis: Date.now() - started,
|
|
89
86
|
rows,
|
|
90
87
|
sizeBytes,
|
|
91
88
|
});
|
|
92
|
-
console.log(`<< ${
|
|
89
|
+
console.log(`<< ${grey(filePath)}\n` + stats.toPretty());
|
|
93
90
|
statsPerTable[table] = stats;
|
|
94
91
|
}, { concurrency, errorMode });
|
|
95
|
-
const statsTotal =
|
|
92
|
+
const statsTotal = NDJsonStats.createCombined(Object.values(statsPerTable));
|
|
96
93
|
console.log(statsTotal.toPretty('total'));
|
|
97
94
|
return statsTotal;
|
|
98
95
|
}
|
package/dist/query/dbQuery.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { AsyncMapper, BaseDBEntity, ObjectWithId } from '@naturalcycles/js-lib';
|
|
2
2
|
import type { ReadableTyped } from '@naturalcycles/nodejs-lib';
|
|
3
|
-
import type {
|
|
4
|
-
import type {
|
|
5
|
-
import type { RunQueryResult } from '../db.model';
|
|
3
|
+
import type { CommonDao } from '../commondao/common.dao.js';
|
|
4
|
+
import type { CommonDaoOptions, CommonDaoReadOptions, CommonDaoStreamDeleteOptions, CommonDaoStreamForEachOptions, CommonDaoStreamOptions } from '../commondao/common.dao.model.js';
|
|
5
|
+
import type { RunQueryResult } from '../db.model.js';
|
|
6
6
|
/**
|
|
7
7
|
* Modeled after Firestore operators (WhereFilterOp type)
|
|
8
8
|
*
|
package/dist/query/dbQuery.js
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
exports.RunnableDBQuery = exports.DBQuery = exports.dbQueryFilterOperatorValues = void 0;
|
|
4
|
-
const js_lib_1 = require("@naturalcycles/js-lib");
|
|
5
|
-
exports.dbQueryFilterOperatorValues = [
|
|
1
|
+
import { _objectAssign, _truncate } from '@naturalcycles/js-lib';
|
|
2
|
+
export const dbQueryFilterOperatorValues = [
|
|
6
3
|
'<',
|
|
7
4
|
'<=',
|
|
8
5
|
'==',
|
|
@@ -24,7 +21,7 @@ exports.dbQueryFilterOperatorValues = [
|
|
|
24
21
|
*
|
|
25
22
|
* <DBM> is the type of **queried** object (so e.g `key of DBM` can be used), not **returned** object.
|
|
26
23
|
*/
|
|
27
|
-
class DBQuery {
|
|
24
|
+
export class DBQuery {
|
|
28
25
|
table;
|
|
29
26
|
constructor(table) {
|
|
30
27
|
this.table = table;
|
|
@@ -102,7 +99,7 @@ class DBQuery {
|
|
|
102
99
|
return this;
|
|
103
100
|
}
|
|
104
101
|
clone() {
|
|
105
|
-
return
|
|
102
|
+
return _objectAssign(new DBQuery(this.table), {
|
|
106
103
|
_filters: [...this._filters],
|
|
107
104
|
_limitValue: this._limitValue,
|
|
108
105
|
_offsetValue: this._offsetValue,
|
|
@@ -136,19 +133,18 @@ class DBQuery {
|
|
|
136
133
|
tokens.push(`limit ${this._limitValue}`);
|
|
137
134
|
}
|
|
138
135
|
if (this._startCursor) {
|
|
139
|
-
tokens.push(`startCursor ${
|
|
136
|
+
tokens.push(`startCursor ${_truncate(this._startCursor, 8)}`);
|
|
140
137
|
}
|
|
141
138
|
if (this._endCursor) {
|
|
142
|
-
tokens.push(`endCursor ${
|
|
139
|
+
tokens.push(`endCursor ${_truncate(this._endCursor, 8)}`);
|
|
143
140
|
}
|
|
144
141
|
return tokens;
|
|
145
142
|
}
|
|
146
143
|
}
|
|
147
|
-
exports.DBQuery = DBQuery;
|
|
148
144
|
/**
|
|
149
145
|
* DBQuery that has additional method to support Fluent API style.
|
|
150
146
|
*/
|
|
151
|
-
class RunnableDBQuery extends DBQuery {
|
|
147
|
+
export class RunnableDBQuery extends DBQuery {
|
|
152
148
|
dao;
|
|
153
149
|
/**
|
|
154
150
|
* Pass `table` to override table.
|
|
@@ -203,4 +199,3 @@ class RunnableDBQuery extends DBQuery {
|
|
|
203
199
|
return await this.dao.deleteByQuery(this, opt);
|
|
204
200
|
}
|
|
205
201
|
}
|
|
206
|
-
exports.RunnableDBQuery = RunnableDBQuery;
|
|
@@ -1,25 +1,22 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
const dbQuery_1 = require("../query/dbQuery");
|
|
7
|
-
const test_model_1 = require("./test.model");
|
|
8
|
-
async function runCommonDBTest(db, quirks = {}) {
|
|
1
|
+
import { _deepFreeze, _filterObject, _pick, _sortBy, localTime, pMap } from '@naturalcycles/js-lib';
|
|
2
|
+
import { CommonDBType } from '../common.db.js';
|
|
3
|
+
import { DBQuery } from '../query/dbQuery.js';
|
|
4
|
+
import { createTestItemDBM, createTestItemsDBM, TEST_TABLE, testItemBMJsonSchema, } from './test.model.js';
|
|
5
|
+
export async function runCommonDBTest(db, quirks = {}) {
|
|
9
6
|
// this is because vitest cannot be "required" from cjs
|
|
10
7
|
const { test, expect } = await import('vitest');
|
|
11
8
|
const { support } = db;
|
|
12
|
-
const items =
|
|
13
|
-
|
|
9
|
+
const items = createTestItemsDBM(3);
|
|
10
|
+
_deepFreeze(items);
|
|
14
11
|
const item1 = items[0];
|
|
15
|
-
const queryAll = () =>
|
|
12
|
+
const queryAll = () => DBQuery.create(TEST_TABLE);
|
|
16
13
|
test('ping', async () => {
|
|
17
14
|
await db.ping();
|
|
18
15
|
});
|
|
19
16
|
// CREATE TABLE, DROP
|
|
20
17
|
if (support.createTable) {
|
|
21
18
|
test('createTable, dropIfExists=true', async () => {
|
|
22
|
-
await db.createTable(
|
|
19
|
+
await db.createTable(TEST_TABLE, testItemBMJsonSchema, { dropIfExists: true });
|
|
23
20
|
});
|
|
24
21
|
}
|
|
25
22
|
if (support.queries) {
|
|
@@ -36,21 +33,21 @@ async function runCommonDBTest(db, quirks = {}) {
|
|
|
36
33
|
}
|
|
37
34
|
// GET empty
|
|
38
35
|
test('getByIds(item1.id) should return empty', async () => {
|
|
39
|
-
const [item1Loaded] = await db.getByIds(
|
|
36
|
+
const [item1Loaded] = await db.getByIds(TEST_TABLE, [item1.id]);
|
|
40
37
|
// console.log(a)
|
|
41
38
|
expect(item1Loaded).toBeUndefined();
|
|
42
39
|
});
|
|
43
40
|
test('getByIds([]) should return []', async () => {
|
|
44
|
-
expect(await db.getByIds(
|
|
41
|
+
expect(await db.getByIds(TEST_TABLE, [])).toEqual([]);
|
|
45
42
|
});
|
|
46
43
|
test('getByIds(...) should return empty', async () => {
|
|
47
|
-
expect(await db.getByIds(
|
|
44
|
+
expect(await db.getByIds(TEST_TABLE, ['abc', 'abcd'])).toEqual([]);
|
|
48
45
|
});
|
|
49
46
|
// TimeMachine
|
|
50
47
|
if (support.timeMachine) {
|
|
51
48
|
test('getByIds(...) 10 minutes ago should return []', async () => {
|
|
52
|
-
expect(await db.getByIds(
|
|
53
|
-
readAt:
|
|
49
|
+
expect(await db.getByIds(TEST_TABLE, [item1.id, 'abc'], {
|
|
50
|
+
readAt: localTime.now().minus(10, 'minute').unix,
|
|
54
51
|
})).toEqual([]);
|
|
55
52
|
});
|
|
56
53
|
}
|
|
@@ -58,27 +55,27 @@ async function runCommonDBTest(db, quirks = {}) {
|
|
|
58
55
|
if (support.nullValues) {
|
|
59
56
|
test('should allow to save and load null values', async () => {
|
|
60
57
|
const item3 = {
|
|
61
|
-
...
|
|
58
|
+
...createTestItemDBM(3),
|
|
62
59
|
k2: null,
|
|
63
60
|
};
|
|
64
|
-
|
|
65
|
-
await db.saveBatch(
|
|
66
|
-
const item3Loaded = (await db.getByIds(
|
|
61
|
+
_deepFreeze(item3);
|
|
62
|
+
await db.saveBatch(TEST_TABLE, [item3]);
|
|
63
|
+
const item3Loaded = (await db.getByIds(TEST_TABLE, [item3.id]))[0];
|
|
67
64
|
expectMatch([item3], [item3Loaded], quirks);
|
|
68
65
|
expect(item3Loaded.k2).toBeNull();
|
|
69
66
|
});
|
|
70
67
|
}
|
|
71
|
-
if (db.dbType ===
|
|
68
|
+
if (db.dbType === CommonDBType.document) {
|
|
72
69
|
test('undefined values should not be saved/loaded', async () => {
|
|
73
70
|
const item3 = {
|
|
74
|
-
...
|
|
71
|
+
...createTestItemDBM(3),
|
|
75
72
|
k2: undefined,
|
|
76
73
|
};
|
|
77
|
-
|
|
74
|
+
_deepFreeze(item3);
|
|
78
75
|
const expected = { ...item3 };
|
|
79
76
|
delete expected.k2;
|
|
80
|
-
await db.saveBatch(
|
|
81
|
-
const item3Loaded = (await db.getByIds(
|
|
77
|
+
await db.saveBatch(TEST_TABLE, [item3]);
|
|
78
|
+
const item3Loaded = (await db.getByIds(TEST_TABLE, [item3.id]))[0];
|
|
82
79
|
expectMatch([expected], [item3Loaded], quirks);
|
|
83
80
|
expect(item3Loaded.k2).toBeUndefined();
|
|
84
81
|
expect(Object.keys(item3Loaded)).not.toContain('k2');
|
|
@@ -86,81 +83,81 @@ async function runCommonDBTest(db, quirks = {}) {
|
|
|
86
83
|
}
|
|
87
84
|
if (support.updateSaveMethod) {
|
|
88
85
|
test('saveBatch UPDATE method should throw', async () => {
|
|
89
|
-
await expect(db.saveBatch(
|
|
86
|
+
await expect(db.saveBatch(TEST_TABLE, items, { saveMethod: 'update' })).rejects.toThrow();
|
|
90
87
|
});
|
|
91
88
|
}
|
|
92
89
|
test('saveBatch test items', async () => {
|
|
93
|
-
await db.saveBatch(
|
|
90
|
+
await db.saveBatch(TEST_TABLE, items);
|
|
94
91
|
});
|
|
95
92
|
test('saveBatch should throw on null id', async () => {
|
|
96
|
-
await expect(db.saveBatch(
|
|
93
|
+
await expect(db.saveBatch(TEST_TABLE, [{ ...item1, id: null }])).rejects.toThrow();
|
|
97
94
|
});
|
|
98
95
|
if (support.insertSaveMethod) {
|
|
99
96
|
test('saveBatch INSERT method should throw', async () => {
|
|
100
|
-
await expect(db.saveBatch(
|
|
97
|
+
await expect(db.saveBatch(TEST_TABLE, items, { saveMethod: 'insert' })).rejects.toThrow();
|
|
101
98
|
});
|
|
102
99
|
}
|
|
103
100
|
if (support.updateSaveMethod) {
|
|
104
101
|
test('saveBatch UPDATE method should pass', async () => {
|
|
105
|
-
await db.saveBatch(
|
|
102
|
+
await db.saveBatch(TEST_TABLE, items, { saveMethod: 'update' });
|
|
106
103
|
});
|
|
107
104
|
}
|
|
108
105
|
// GET not empty
|
|
109
106
|
test('getByIds all items', async () => {
|
|
110
|
-
const rows = await db.getByIds(
|
|
111
|
-
expectMatch(items,
|
|
107
|
+
const rows = await db.getByIds(TEST_TABLE, items.map(i => i.id).concat('abcd'));
|
|
108
|
+
expectMatch(items, _sortBy(rows, r => r.id), quirks);
|
|
112
109
|
});
|
|
113
110
|
// QUERY
|
|
114
111
|
if (support.queries) {
|
|
115
112
|
test('runQuery(all) should return all items', async () => {
|
|
116
113
|
let { rows } = await db.runQuery(queryAll());
|
|
117
|
-
rows =
|
|
114
|
+
rows = _sortBy(rows, r => r.id); // because query doesn't specify order here
|
|
118
115
|
expectMatch(items, rows, quirks);
|
|
119
116
|
});
|
|
120
117
|
if (support.dbQueryFilter) {
|
|
121
118
|
test('query even=true', async () => {
|
|
122
|
-
const q = new
|
|
119
|
+
const q = new DBQuery(TEST_TABLE).filter('even', '==', true);
|
|
123
120
|
let { rows } = await db.runQuery(q);
|
|
124
121
|
if (!support.dbQueryOrder)
|
|
125
|
-
rows =
|
|
122
|
+
rows = _sortBy(rows, r => r.id);
|
|
126
123
|
expectMatch(items.filter(i => i.even), rows, quirks);
|
|
127
124
|
});
|
|
128
125
|
}
|
|
129
126
|
if (support.dbQueryOrder) {
|
|
130
127
|
test('query order by k1 desc', async () => {
|
|
131
|
-
const q = new
|
|
128
|
+
const q = new DBQuery(TEST_TABLE).order('k1', true);
|
|
132
129
|
const { rows } = await db.runQuery(q);
|
|
133
130
|
expectMatch([...items].reverse(), rows, quirks);
|
|
134
131
|
});
|
|
135
132
|
}
|
|
136
133
|
if (support.dbQuerySelectFields) {
|
|
137
134
|
test('projection query with only ids', async () => {
|
|
138
|
-
const q = new
|
|
135
|
+
const q = new DBQuery(TEST_TABLE).select(['id']);
|
|
139
136
|
let { rows } = await db.runQuery(q);
|
|
140
|
-
rows =
|
|
141
|
-
expectMatch(items.map(item =>
|
|
137
|
+
rows = _sortBy(rows, r => r.id); // cause order is not specified
|
|
138
|
+
expectMatch(items.map(item => _pick(item, ['id'])), rows, quirks);
|
|
142
139
|
});
|
|
143
140
|
test('projection query without ids', async () => {
|
|
144
|
-
const q = new
|
|
141
|
+
const q = new DBQuery(TEST_TABLE).select(['k1']);
|
|
145
142
|
let { rows } = await db.runQuery(q);
|
|
146
|
-
rows =
|
|
147
|
-
expectMatch(items.map(item =>
|
|
143
|
+
rows = _sortBy(rows, r => r.k1); // cause order is not specified
|
|
144
|
+
expectMatch(items.map(item => _pick(item, ['k1'])), rows, quirks);
|
|
148
145
|
});
|
|
149
146
|
test('projection query empty fields (edge case)', async () => {
|
|
150
|
-
const q = new
|
|
147
|
+
const q = new DBQuery(TEST_TABLE).select([]);
|
|
151
148
|
const { rows } = await db.runQuery(q);
|
|
152
149
|
expectMatch(items.map(() => ({})), rows, quirks);
|
|
153
150
|
});
|
|
154
151
|
}
|
|
155
152
|
test('runQueryCount should return 3', async () => {
|
|
156
|
-
expect(await db.runQueryCount(new
|
|
153
|
+
expect(await db.runQueryCount(new DBQuery(TEST_TABLE))).toBe(3);
|
|
157
154
|
});
|
|
158
155
|
}
|
|
159
156
|
// STREAM
|
|
160
157
|
if (support.streaming) {
|
|
161
158
|
test('streamQuery all', async () => {
|
|
162
159
|
let rows = await db.streamQuery(queryAll()).toArray();
|
|
163
|
-
rows =
|
|
160
|
+
rows = _sortBy(rows, r => r.id); // cause order is not specified in DBQuery
|
|
164
161
|
expectMatch(items, rows, quirks);
|
|
165
162
|
});
|
|
166
163
|
}
|
|
@@ -169,7 +166,7 @@ async function runCommonDBTest(db, quirks = {}) {
|
|
|
169
166
|
const tables = await db.getTables();
|
|
170
167
|
// console.log({ tables })
|
|
171
168
|
if (support.tableSchemas) {
|
|
172
|
-
await
|
|
169
|
+
await pMap(tables, async (table) => {
|
|
173
170
|
const schema = await db.getTableSchema(table);
|
|
174
171
|
// console.log(schema)
|
|
175
172
|
expect(schema.$id).toBe(`${table}.schema.json`);
|
|
@@ -179,7 +176,7 @@ async function runCommonDBTest(db, quirks = {}) {
|
|
|
179
176
|
// DELETE BY
|
|
180
177
|
if (support.queries && support.dbQueryFilter) {
|
|
181
178
|
test('deleteByQuery even=false', async () => {
|
|
182
|
-
const q = new
|
|
179
|
+
const q = new DBQuery(TEST_TABLE).filter('even', '==', false);
|
|
183
180
|
const deleted = await db.deleteByQuery(q);
|
|
184
181
|
expect(deleted).toBe(items.filter(item => !item.even).length);
|
|
185
182
|
expect(await db.runQueryCount(queryAll())).toBe(1);
|
|
@@ -191,11 +188,11 @@ async function runCommonDBTest(db, quirks = {}) {
|
|
|
191
188
|
const s = 'helloWorld 1';
|
|
192
189
|
const b1 = Buffer.from(s);
|
|
193
190
|
const item = {
|
|
194
|
-
...
|
|
191
|
+
...createTestItemDBM(1),
|
|
195
192
|
b1,
|
|
196
193
|
};
|
|
197
|
-
await db.saveBatch(
|
|
198
|
-
const loaded = (await db.getByIds(
|
|
194
|
+
await db.saveBatch(TEST_TABLE, [item]);
|
|
195
|
+
const loaded = (await db.getByIds(TEST_TABLE, [item.id]))[0];
|
|
199
196
|
const b1Loaded = loaded.b1;
|
|
200
197
|
// console.log({
|
|
201
198
|
// b11: typeof b1,
|
|
@@ -210,6 +207,16 @@ async function runCommonDBTest(db, quirks = {}) {
|
|
|
210
207
|
});
|
|
211
208
|
}
|
|
212
209
|
if (support.transactions) {
|
|
210
|
+
/**
|
|
211
|
+
* Returns expected items in the DB after the preparation.
|
|
212
|
+
*/
|
|
213
|
+
async function prepare() {
|
|
214
|
+
// cleanup
|
|
215
|
+
await db.deleteByQuery(queryAll());
|
|
216
|
+
const itemsToSave = [items[0], { ...items[2], k1: 'k1_mod' }];
|
|
217
|
+
await db.saveBatch(TEST_TABLE, itemsToSave);
|
|
218
|
+
return itemsToSave;
|
|
219
|
+
}
|
|
213
220
|
test('transaction happy path', async () => {
|
|
214
221
|
// cleanup
|
|
215
222
|
await db.deleteByQuery(queryAll());
|
|
@@ -218,21 +225,34 @@ async function runCommonDBTest(db, quirks = {}) {
|
|
|
218
225
|
// delete item2
|
|
219
226
|
// remaining: item1, item3_with_k1_mod
|
|
220
227
|
await db.runInTransaction(async (tx) => {
|
|
221
|
-
await tx.saveBatch(
|
|
222
|
-
await tx.saveBatch(
|
|
223
|
-
await tx.deleteByIds(
|
|
228
|
+
await tx.saveBatch(TEST_TABLE, items);
|
|
229
|
+
await tx.saveBatch(TEST_TABLE, [{ ...items[2], k1: 'k1_mod' }]);
|
|
230
|
+
await tx.deleteByIds(TEST_TABLE, [items[1].id]);
|
|
224
231
|
});
|
|
225
232
|
const { rows } = await db.runQuery(queryAll());
|
|
226
233
|
const expected = [items[0], { ...items[2], k1: 'k1_mod' }];
|
|
227
234
|
expectMatch(expected, rows, quirks);
|
|
228
235
|
});
|
|
236
|
+
test('createTransaction happy path', async () => {
|
|
237
|
+
// cleanup
|
|
238
|
+
await db.deleteByQuery(queryAll());
|
|
239
|
+
const tx = await db.createTransaction();
|
|
240
|
+
await tx.saveBatch(TEST_TABLE, items);
|
|
241
|
+
await tx.saveBatch(TEST_TABLE, [{ ...items[2], k1: 'k1_mod' }]);
|
|
242
|
+
await tx.deleteByIds(TEST_TABLE, [items[1].id]);
|
|
243
|
+
await tx.commit();
|
|
244
|
+
const { rows } = await db.runQuery(queryAll());
|
|
245
|
+
const expected = [items[0], { ...items[2], k1: 'k1_mod' }];
|
|
246
|
+
expectMatch(expected, rows, quirks);
|
|
247
|
+
});
|
|
229
248
|
test('transaction rollback', async () => {
|
|
249
|
+
const expected = await prepare();
|
|
230
250
|
let err;
|
|
231
251
|
try {
|
|
232
252
|
await db.runInTransaction(async (tx) => {
|
|
233
|
-
await tx.deleteByIds(
|
|
253
|
+
await tx.deleteByIds(TEST_TABLE, [items[2].id]);
|
|
234
254
|
// It should fail on id == null
|
|
235
|
-
await tx.saveBatch(
|
|
255
|
+
await tx.saveBatch(TEST_TABLE, [{ ...items[0], k1: 5, id: null }]);
|
|
236
256
|
});
|
|
237
257
|
}
|
|
238
258
|
catch (err_) {
|
|
@@ -240,7 +260,6 @@ async function runCommonDBTest(db, quirks = {}) {
|
|
|
240
260
|
}
|
|
241
261
|
expect(err).toBeDefined();
|
|
242
262
|
const { rows } = await db.runQuery(queryAll());
|
|
243
|
-
const expected = [items[0], { ...items[2], k1: 'k1_mod' }];
|
|
244
263
|
expectMatch(expected, rows, quirks);
|
|
245
264
|
});
|
|
246
265
|
}
|
|
@@ -248,12 +267,12 @@ async function runCommonDBTest(db, quirks = {}) {
|
|
|
248
267
|
test('patchByQuery', async () => {
|
|
249
268
|
// cleanup, reset initial data
|
|
250
269
|
await db.deleteByQuery(queryAll());
|
|
251
|
-
await db.saveBatch(
|
|
270
|
+
await db.saveBatch(TEST_TABLE, items);
|
|
252
271
|
const patch = {
|
|
253
272
|
k3: 5,
|
|
254
273
|
k2: 'abc',
|
|
255
274
|
};
|
|
256
|
-
await db.patchByQuery(
|
|
275
|
+
await db.patchByQuery(DBQuery.create(TEST_TABLE).filterEq('even', true), patch);
|
|
257
276
|
const { rows } = await db.runQuery(queryAll());
|
|
258
277
|
const expected = items.map(r => {
|
|
259
278
|
if (r.even) {
|
|
@@ -268,8 +287,8 @@ async function runCommonDBTest(db, quirks = {}) {
|
|
|
268
287
|
test('incrementBatch', async () => {
|
|
269
288
|
// cleanup, reset initial data
|
|
270
289
|
await db.deleteByQuery(queryAll());
|
|
271
|
-
await db.saveBatch(
|
|
272
|
-
await db.incrementBatch(
|
|
290
|
+
await db.saveBatch(TEST_TABLE, items);
|
|
291
|
+
await db.incrementBatch(TEST_TABLE, 'k3', { id1: 1, id2: 2 });
|
|
273
292
|
const { rows } = await db.runQuery(queryAll());
|
|
274
293
|
const expected = items.map(r => {
|
|
275
294
|
if (r.id === 'id1') {
|
|
@@ -294,7 +313,7 @@ async function runCommonDBTest(db, quirks = {}) {
|
|
|
294
313
|
// const actualSorted = sortObjectDeep(actual)
|
|
295
314
|
if (quirks.allowBooleansAsUndefined) {
|
|
296
315
|
expected = expected.map(r => {
|
|
297
|
-
return typeof r !== 'object' ? r :
|
|
316
|
+
return typeof r !== 'object' ? r : _filterObject(r, (_k, v) => v !== false);
|
|
298
317
|
});
|
|
299
318
|
}
|
|
300
319
|
if (quirks.allowExtraPropertiesInResponse) {
|