@naturalcycles/db-lib 8.19.0 → 8.21.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/CHANGELOG.md +28 -0
- package/dist/adapter/file/file.db.js +2 -1
- package/dist/base.common.db.d.ts +2 -2
- package/dist/base.common.db.js +1 -1
- package/dist/commondao/common.dao.d.ts +6 -0
- package/dist/commondao/common.dao.js +16 -1
- package/dist/testing/daoTest.js +24 -1
- package/dist/testing/dbTest.d.ts +1 -0
- package/dist/testing/dbTest.js +24 -1
- package/dist/testing/test.model.d.ts +1 -1
- package/dist/testing/test.model.js +3 -3
- package/package.json +1 -1
- package/src/adapter/file/file.db.ts +4 -1
- package/src/base.common.db.ts +6 -2
- package/src/commondao/common.dao.ts +20 -2
- package/src/testing/daoTest.ts +27 -0
- package/src/testing/dbTest.ts +27 -0
- package/src/testing/test.model.ts +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,31 @@
|
|
|
1
|
+
## [8.21.1](https://github.com/NaturalCycles/db-lib/compare/v8.21.0...v8.21.1) (2021-10-18)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* test for saving/loading undefined values ([e7a8dcf](https://github.com/NaturalCycles/db-lib/commit/e7a8dcff296ba7c8c23c4157510dd79fe7ef1727))
|
|
7
|
+
|
|
8
|
+
# [8.21.0](https://github.com/NaturalCycles/db-lib/compare/v8.20.1...v8.21.0) (2021-10-18)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
* preserve `null` values in CommonDao load and save ([6f9b0d6](https://github.com/NaturalCycles/db-lib/commit/6f9b0d6e8419d2d1a0c025b7375c2504c3b267d5))
|
|
14
|
+
|
|
15
|
+
## [8.20.1](https://github.com/NaturalCycles/db-lib/compare/v8.20.0...v8.20.1) (2021-10-17)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
### Bug Fixes
|
|
19
|
+
|
|
20
|
+
* types, test ([fb2f741](https://github.com/NaturalCycles/db-lib/commit/fb2f741d8c5c63a04fb70f48fcafbb529669caf2))
|
|
21
|
+
|
|
22
|
+
# [8.20.0](https://github.com/NaturalCycles/db-lib/compare/v8.19.0...v8.20.0) (2021-10-17)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
### Features
|
|
26
|
+
|
|
27
|
+
* CommonDao.runUnionQueries ([ed6c986](https://github.com/NaturalCycles/db-lib/commit/ed6c986e8ba25b660903e235c062237b5100e63c))
|
|
28
|
+
|
|
1
29
|
# [8.19.0](https://github.com/NaturalCycles/db-lib/compare/v8.18.0...v8.19.0) (2021-10-17)
|
|
2
30
|
|
|
3
31
|
|
|
@@ -41,7 +41,7 @@ class FileDB extends __1.BaseCommonDB {
|
|
|
41
41
|
async saveBatch(table, rows, _opt) {
|
|
42
42
|
if (!rows.length)
|
|
43
43
|
return; // save some api calls
|
|
44
|
-
// 1. Load the whole file
|
|
44
|
+
// 1. Load the whole file
|
|
45
45
|
const byId = (0, js_lib_1._by)(await this.loadFile(table), r => r.id);
|
|
46
46
|
// 2. Merge with new data (using ids)
|
|
47
47
|
let saved = 0;
|
|
@@ -173,6 +173,7 @@ class FileDB extends __1.BaseCommonDB {
|
|
|
173
173
|
* Mutates
|
|
174
174
|
*/
|
|
175
175
|
sortRows(rows) {
|
|
176
|
+
rows.forEach(r => (0, js_lib_1._filterUndefinedValues)(r, true));
|
|
176
177
|
if (this.cfg.sortOnSave) {
|
|
177
178
|
(0, js_lib_1._sortBy)(rows, r => r[this.cfg.sortOnSave.name], true);
|
|
178
179
|
if (this.cfg.sortOnSave.descending)
|
package/dist/base.common.db.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { JsonSchemaObject, JsonSchemaRootObject } from '@naturalcycles/js-lib';
|
|
2
2
|
import { ReadableTyped } from '@naturalcycles/nodejs-lib';
|
|
3
3
|
import { CommonDB } from './common.db';
|
|
4
|
-
import { CommonDBOptions, ObjectWithId, RunQueryResult } from './db.model';
|
|
4
|
+
import { CommonDBOptions, CommonDBSaveOptions, ObjectWithId, RunQueryResult } from './db.model';
|
|
5
5
|
import { DBQuery } from './query/dbQuery';
|
|
6
6
|
import { DBTransaction } from './transaction/dbTransaction';
|
|
7
7
|
/**
|
|
@@ -18,7 +18,7 @@ export declare class BaseCommonDB implements CommonDB {
|
|
|
18
18
|
getByIds<ROW extends ObjectWithId>(_table: string, _ids: string[]): Promise<ROW[]>;
|
|
19
19
|
runQuery<ROW extends ObjectWithId>(_q: DBQuery<ROW>): Promise<RunQueryResult<ROW>>;
|
|
20
20
|
runQueryCount<ROW extends ObjectWithId>(_q: DBQuery<ROW>): Promise<number>;
|
|
21
|
-
saveBatch<ROW extends ObjectWithId>(_table: string, _rows: ROW[]): Promise<void>;
|
|
21
|
+
saveBatch<ROW extends ObjectWithId>(_table: string, _rows: ROW[], _opt?: CommonDBSaveOptions<ROW>): Promise<void>;
|
|
22
22
|
streamQuery<ROW extends ObjectWithId>(_q: DBQuery<ROW>): ReadableTyped<ROW>;
|
|
23
23
|
/**
|
|
24
24
|
* Naive implementation.
|
package/dist/base.common.db.js
CHANGED
|
@@ -40,6 +40,12 @@ export declare class CommonDao<BM extends Partial<ObjectWithId>, DBM extends Obj
|
|
|
40
40
|
*/
|
|
41
41
|
query(table?: string): RunnableDBQuery<BM, DBM, TM>;
|
|
42
42
|
runQuery(q: DBQuery<DBM>, opt?: CommonDaoOptions): Promise<Saved<BM>[]>;
|
|
43
|
+
/**
|
|
44
|
+
* Convenience method that runs multiple queries in parallel and then merges their results together.
|
|
45
|
+
* Does deduplication by id.
|
|
46
|
+
* Order is not guaranteed, as queries run in parallel.
|
|
47
|
+
*/
|
|
48
|
+
runUnionQueries(queries: DBQuery<DBM>[], opt?: CommonDaoOptions): Promise<Saved<BM>[]>;
|
|
43
49
|
runQueryExtended(q: DBQuery<DBM>, opt?: CommonDaoOptions): Promise<RunQueryResult<Saved<BM>>>;
|
|
44
50
|
runQueryAsDBM(q: DBQuery<DBM>, opt?: CommonDaoOptions): Promise<DBM[]>;
|
|
45
51
|
runQueryExtendedAsDBM(q: DBQuery<DBM>, opt?: CommonDaoOptions): Promise<RunQueryResult<DBM>>;
|
|
@@ -175,6 +175,15 @@ class CommonDao {
|
|
|
175
175
|
const { rows } = await this.runQueryExtended(q, opt);
|
|
176
176
|
return rows;
|
|
177
177
|
}
|
|
178
|
+
/**
|
|
179
|
+
* Convenience method that runs multiple queries in parallel and then merges their results together.
|
|
180
|
+
* Does deduplication by id.
|
|
181
|
+
* Order is not guaranteed, as queries run in parallel.
|
|
182
|
+
*/
|
|
183
|
+
async runUnionQueries(queries, opt) {
|
|
184
|
+
const results = (await (0, js_lib_1.pMap)(queries, async (q) => (await this.runQueryExtended(q, opt)).rows)).flat();
|
|
185
|
+
return (0, js_lib_1._uniqBy)(results, r => r.id);
|
|
186
|
+
}
|
|
178
187
|
async runQueryExtended(q, opt = {}) {
|
|
179
188
|
q.table = opt.table || q.table;
|
|
180
189
|
const op = `runQuery(${q.pretty()})`;
|
|
@@ -630,8 +639,14 @@ class CommonDao {
|
|
|
630
639
|
// `raw` option completely bypasses any processing
|
|
631
640
|
if (opt.raw)
|
|
632
641
|
return obj;
|
|
642
|
+
// Kirill 2021-10-18: I realized that there's little reason to keep removing null values
|
|
643
|
+
// So, from now on we'll preserve them
|
|
644
|
+
// "undefined" values, I believe, are/were not saved to/from DB anyway (due to e.g JSON.stringify removing them)
|
|
645
|
+
// But let's keep watching it!
|
|
646
|
+
//
|
|
633
647
|
// Filter null and undefined values
|
|
634
|
-
obj =
|
|
648
|
+
// obj = _filterNullishValues(obj as any)
|
|
649
|
+
obj = { ...obj }; // prevent mutation
|
|
635
650
|
// Pre-validation hooks
|
|
636
651
|
if (modelType === db_model_1.DBModelType.DBM) {
|
|
637
652
|
obj = this.cfg.hooks.beforeDBMValidate(obj);
|
package/dist/testing/daoTest.js
CHANGED
|
@@ -22,7 +22,7 @@ function runCommonDaoTest(db, features = {}, quirks = {}) {
|
|
|
22
22
|
// tableSchemas = true,
|
|
23
23
|
createTable = true, dbQueryFilter = true,
|
|
24
24
|
// dbQueryFilterIn = true,
|
|
25
|
-
dbQueryOrder = true, dbQuerySelectFields = true, streaming = true, strongConsistency = true, } = features;
|
|
25
|
+
dbQueryOrder = true, dbQuerySelectFields = true, streaming = true, strongConsistency = true, nullValues = true, } = features;
|
|
26
26
|
// const {
|
|
27
27
|
// allowExtraPropertiesInResponse,
|
|
28
28
|
// allowBooleansAsUndefined,
|
|
@@ -72,6 +72,29 @@ function runCommonDaoTest(db, features = {}, quirks = {}) {
|
|
|
72
72
|
expect(await dao.getByIds(['abc', 'abcd'])).toEqual([]);
|
|
73
73
|
});
|
|
74
74
|
// SAVE
|
|
75
|
+
if (nullValues) {
|
|
76
|
+
test('should allow to save and load null values', async () => {
|
|
77
|
+
const item3 = {
|
|
78
|
+
...(0, test_model_1.createTestItemBM)(3),
|
|
79
|
+
k2: null,
|
|
80
|
+
};
|
|
81
|
+
await dao.save(item3);
|
|
82
|
+
const item3Loaded = await dao.requireById(item3.id);
|
|
83
|
+
(0, dbTest_1.expectMatch)([item3], [item3Loaded], quirks);
|
|
84
|
+
expect(item3Loaded.k2).toBe(null);
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
test('undefined values should not be saved/loaded', async () => {
|
|
88
|
+
const item3 = {
|
|
89
|
+
...(0, test_model_1.createTestItemBM)(3),
|
|
90
|
+
k2: undefined,
|
|
91
|
+
};
|
|
92
|
+
await dao.save(item3);
|
|
93
|
+
const item3Loaded = await dao.requireById(item3.id);
|
|
94
|
+
(0, dbTest_1.expectMatch)([item3], [item3Loaded], quirks);
|
|
95
|
+
expect(item3Loaded.k2).toBe(undefined);
|
|
96
|
+
expect(Object.keys(item3Loaded)).not.toContain('k2');
|
|
97
|
+
});
|
|
75
98
|
test('saveBatch test items', async () => {
|
|
76
99
|
const itemsSaved = await dao.saveBatch(items);
|
|
77
100
|
expect(itemsSaved[0]).toBe(items[0]); // expect "same object" returned
|
package/dist/testing/dbTest.d.ts
CHANGED
package/dist/testing/dbTest.js
CHANGED
|
@@ -12,7 +12,7 @@ const test_util_1 = require("./test.util");
|
|
|
12
12
|
function runCommonDBTest(db, features = {}, quirks = {}) {
|
|
13
13
|
const { querying = true, tableSchemas = true, createTable = true, dbQueryFilter = true,
|
|
14
14
|
// dbQueryFilterIn = true,
|
|
15
|
-
dbQueryOrder = true, dbQuerySelectFields = true, streaming = true, strongConsistency = true, bufferSupport = true, } = features;
|
|
15
|
+
dbQueryOrder = true, dbQuerySelectFields = true, streaming = true, strongConsistency = true, bufferSupport = true, nullValues = true, } = features;
|
|
16
16
|
// const {
|
|
17
17
|
// allowExtraPropertiesInResponse,
|
|
18
18
|
// allowBooleansAsUndefined,
|
|
@@ -58,6 +58,29 @@ function runCommonDBTest(db, features = {}, quirks = {}) {
|
|
|
58
58
|
expect(await db.getByIds(test_model_1.TEST_TABLE, ['abc', 'abcd'])).toEqual([]);
|
|
59
59
|
});
|
|
60
60
|
// SAVE
|
|
61
|
+
if (nullValues) {
|
|
62
|
+
test('should allow to save and load null values', async () => {
|
|
63
|
+
const item3 = {
|
|
64
|
+
...(0, test_model_1.createTestItemDBM)(3),
|
|
65
|
+
k2: null,
|
|
66
|
+
};
|
|
67
|
+
await db.saveBatch(test_model_1.TEST_TABLE, [item3]);
|
|
68
|
+
const item3Loaded = (await db.getByIds(test_model_1.TEST_TABLE, [item3.id]))[0];
|
|
69
|
+
expectMatch([item3], [item3Loaded], quirks);
|
|
70
|
+
expect(item3Loaded.k2).toBe(null);
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
test('undefined values should not be saved/loaded', async () => {
|
|
74
|
+
const item3 = {
|
|
75
|
+
...(0, test_model_1.createTestItemDBM)(3),
|
|
76
|
+
k2: undefined,
|
|
77
|
+
};
|
|
78
|
+
await db.saveBatch(test_model_1.TEST_TABLE, [item3]);
|
|
79
|
+
const item3Loaded = (await db.getByIds(test_model_1.TEST_TABLE, [item3.id]))[0];
|
|
80
|
+
expectMatch([item3], [item3Loaded], quirks);
|
|
81
|
+
expect(item3Loaded.k2).toBe(undefined);
|
|
82
|
+
expect(Object.keys(item3Loaded)).not.toContain('k2');
|
|
83
|
+
});
|
|
61
84
|
test('saveBatch test items', async () => {
|
|
62
85
|
await db.saveBatch(test_model_1.TEST_TABLE, items);
|
|
63
86
|
});
|
|
@@ -3,7 +3,7 @@ import { JsonSchemaObject, BaseDBEntity, Saved } from '@naturalcycles/js-lib';
|
|
|
3
3
|
export declare const TEST_TABLE = "TEST_TABLE";
|
|
4
4
|
export interface TestItemBM extends BaseDBEntity {
|
|
5
5
|
k1: string;
|
|
6
|
-
k2?: string;
|
|
6
|
+
k2?: string | null;
|
|
7
7
|
k3?: number;
|
|
8
8
|
even?: boolean;
|
|
9
9
|
b1?: Buffer;
|
|
@@ -7,14 +7,14 @@ const MOCK_TS_2018_06_21 = 1529539200;
|
|
|
7
7
|
exports.TEST_TABLE = 'TEST_TABLE';
|
|
8
8
|
exports.testItemBMSchema = (0, nodejs_lib_1.objectSchema)({
|
|
9
9
|
k1: nodejs_lib_1.stringSchema,
|
|
10
|
-
k2: nodejs_lib_1.stringSchema.optional(),
|
|
10
|
+
k2: nodejs_lib_1.stringSchema.allow(null).optional(),
|
|
11
11
|
k3: nodejs_lib_1.numberSchema.optional(),
|
|
12
12
|
even: nodejs_lib_1.booleanSchema.optional(),
|
|
13
13
|
b1: nodejs_lib_1.binarySchema.optional(),
|
|
14
14
|
}).concat(nodejs_lib_1.baseDBEntitySchema);
|
|
15
15
|
exports.testItemDBMSchema = (0, nodejs_lib_1.objectSchema)({
|
|
16
16
|
k1: nodejs_lib_1.stringSchema,
|
|
17
|
-
k2: nodejs_lib_1.stringSchema.optional(),
|
|
17
|
+
k2: nodejs_lib_1.stringSchema.allow(null).optional(),
|
|
18
18
|
k3: nodejs_lib_1.numberSchema.optional(),
|
|
19
19
|
even: nodejs_lib_1.booleanSchema.optional(),
|
|
20
20
|
b1: nodejs_lib_1.binarySchema.optional(),
|
|
@@ -26,7 +26,7 @@ exports.testItemTMSchema = (0, nodejs_lib_1.objectSchema)({
|
|
|
26
26
|
exports.testItemBMJsonSchema = js_lib_1.jsonSchema
|
|
27
27
|
.rootObject({
|
|
28
28
|
k1: js_lib_1.jsonSchema.string(),
|
|
29
|
-
k2: js_lib_1.jsonSchema.string().optional(),
|
|
29
|
+
k2: js_lib_1.jsonSchema.oneOf([js_lib_1.jsonSchema.string(), js_lib_1.jsonSchema.null()]).optional(),
|
|
30
30
|
k3: js_lib_1.jsonSchema.number().optional(),
|
|
31
31
|
even: js_lib_1.jsonSchema.boolean().optional(),
|
|
32
32
|
b1: js_lib_1.jsonSchema.buffer().optional(),
|
package/package.json
CHANGED
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
_stringMapValues,
|
|
11
11
|
_uniq,
|
|
12
12
|
JsonSchemaRootObject,
|
|
13
|
+
_filterUndefinedValues,
|
|
13
14
|
} from '@naturalcycles/js-lib'
|
|
14
15
|
import { Debug, readableCreate, ReadableTyped } from '@naturalcycles/nodejs-lib'
|
|
15
16
|
import { dimGrey } from '@naturalcycles/nodejs-lib/dist/colors'
|
|
@@ -82,7 +83,7 @@ export class FileDB extends BaseCommonDB implements CommonDB {
|
|
|
82
83
|
): Promise<void> {
|
|
83
84
|
if (!rows.length) return // save some api calls
|
|
84
85
|
|
|
85
|
-
// 1. Load the whole file
|
|
86
|
+
// 1. Load the whole file
|
|
86
87
|
const byId = _by(await this.loadFile<ROW>(table), r => r.id)
|
|
87
88
|
|
|
88
89
|
// 2. Merge with new data (using ids)
|
|
@@ -261,6 +262,8 @@ export class FileDB extends BaseCommonDB implements CommonDB {
|
|
|
261
262
|
* Mutates
|
|
262
263
|
*/
|
|
263
264
|
sortRows<ROW>(rows: ROW[]): ROW[] {
|
|
265
|
+
rows.forEach(r => _filterUndefinedValues(r, true))
|
|
266
|
+
|
|
264
267
|
if (this.cfg.sortOnSave) {
|
|
265
268
|
_sortBy(rows, r => r[this.cfg.sortOnSave!.name], true)
|
|
266
269
|
if (this.cfg.sortOnSave.descending) rows.reverse() // mutates
|
package/src/base.common.db.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { Readable } from 'stream'
|
|
|
2
2
|
import { JsonSchemaObject, JsonSchemaRootObject } from '@naturalcycles/js-lib'
|
|
3
3
|
import { ReadableTyped } from '@naturalcycles/nodejs-lib'
|
|
4
4
|
import { CommonDB } from './common.db'
|
|
5
|
-
import { CommonDBOptions, ObjectWithId, RunQueryResult } from './db.model'
|
|
5
|
+
import { CommonDBOptions, CommonDBSaveOptions, ObjectWithId, RunQueryResult } from './db.model'
|
|
6
6
|
import { DBQuery } from './query/dbQuery'
|
|
7
7
|
import { DBTransaction } from './transaction/dbTransaction'
|
|
8
8
|
import { commitDBTransactionSimple } from './transaction/dbTransaction.util'
|
|
@@ -55,7 +55,11 @@ export class BaseCommonDB implements CommonDB {
|
|
|
55
55
|
return 0
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
async saveBatch<ROW extends ObjectWithId>(
|
|
58
|
+
async saveBatch<ROW extends ObjectWithId>(
|
|
59
|
+
_table: string,
|
|
60
|
+
_rows: ROW[],
|
|
61
|
+
_opt?: CommonDBSaveOptions<ROW>,
|
|
62
|
+
): Promise<void> {}
|
|
59
63
|
|
|
60
64
|
streamQuery<ROW extends ObjectWithId>(_q: DBQuery<ROW>): ReadableTyped<ROW> {
|
|
61
65
|
return Readable.from([])
|
|
@@ -3,13 +3,13 @@ import {
|
|
|
3
3
|
AsyncMapper,
|
|
4
4
|
ErrorMode,
|
|
5
5
|
JsonSchemaObject,
|
|
6
|
-
_filterNullishValues,
|
|
7
6
|
_passthroughPredicate,
|
|
8
7
|
_since,
|
|
9
8
|
_truncate,
|
|
10
9
|
pMap,
|
|
11
10
|
JsonSchemaRootObject,
|
|
12
11
|
Saved,
|
|
12
|
+
_uniqBy,
|
|
13
13
|
} from '@naturalcycles/js-lib'
|
|
14
14
|
import {
|
|
15
15
|
AjvSchema,
|
|
@@ -242,6 +242,18 @@ export class CommonDao<
|
|
|
242
242
|
return rows
|
|
243
243
|
}
|
|
244
244
|
|
|
245
|
+
/**
|
|
246
|
+
* Convenience method that runs multiple queries in parallel and then merges their results together.
|
|
247
|
+
* Does deduplication by id.
|
|
248
|
+
* Order is not guaranteed, as queries run in parallel.
|
|
249
|
+
*/
|
|
250
|
+
async runUnionQueries(queries: DBQuery<DBM>[], opt?: CommonDaoOptions): Promise<Saved<BM>[]> {
|
|
251
|
+
const results = (
|
|
252
|
+
await pMap(queries, async q => (await this.runQueryExtended(q, opt)).rows)
|
|
253
|
+
).flat()
|
|
254
|
+
return _uniqBy(results, r => r.id)
|
|
255
|
+
}
|
|
256
|
+
|
|
245
257
|
async runQueryExtended(
|
|
246
258
|
q: DBQuery<DBM>,
|
|
247
259
|
opt: CommonDaoOptions = {},
|
|
@@ -852,8 +864,14 @@ export class CommonDao<
|
|
|
852
864
|
// `raw` option completely bypasses any processing
|
|
853
865
|
if (opt.raw) return obj as any as OUT
|
|
854
866
|
|
|
867
|
+
// Kirill 2021-10-18: I realized that there's little reason to keep removing null values
|
|
868
|
+
// So, from now on we'll preserve them
|
|
869
|
+
// "undefined" values, I believe, are/were not saved to/from DB anyway (due to e.g JSON.stringify removing them)
|
|
870
|
+
// But let's keep watching it!
|
|
871
|
+
//
|
|
855
872
|
// Filter null and undefined values
|
|
856
|
-
obj = _filterNullishValues(obj as any)
|
|
873
|
+
// obj = _filterNullishValues(obj as any)
|
|
874
|
+
obj = { ...obj } // prevent mutation
|
|
857
875
|
|
|
858
876
|
// Pre-validation hooks
|
|
859
877
|
if (modelType === DBModelType.DBM) {
|
package/src/testing/daoTest.ts
CHANGED
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
testItemDBMSchema,
|
|
11
11
|
testItemTMSchema,
|
|
12
12
|
TEST_TABLE,
|
|
13
|
+
createTestItemBM,
|
|
13
14
|
} from './test.model'
|
|
14
15
|
import { getTestItemSchema, TestItemBM } from '.'
|
|
15
16
|
|
|
@@ -38,6 +39,7 @@ export function runCommonDaoTest(
|
|
|
38
39
|
dbQuerySelectFields = true,
|
|
39
40
|
streaming = true,
|
|
40
41
|
strongConsistency = true,
|
|
42
|
+
nullValues = true,
|
|
41
43
|
} = features
|
|
42
44
|
|
|
43
45
|
// const {
|
|
@@ -101,6 +103,31 @@ export function runCommonDaoTest(
|
|
|
101
103
|
})
|
|
102
104
|
|
|
103
105
|
// SAVE
|
|
106
|
+
if (nullValues) {
|
|
107
|
+
test('should allow to save and load null values', async () => {
|
|
108
|
+
const item3 = {
|
|
109
|
+
...createTestItemBM(3),
|
|
110
|
+
k2: null,
|
|
111
|
+
}
|
|
112
|
+
await dao.save(item3)
|
|
113
|
+
const item3Loaded = await dao.requireById(item3.id)
|
|
114
|
+
expectMatch([item3], [item3Loaded], quirks)
|
|
115
|
+
expect(item3Loaded.k2).toBe(null)
|
|
116
|
+
})
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
test('undefined values should not be saved/loaded', async () => {
|
|
120
|
+
const item3 = {
|
|
121
|
+
...createTestItemBM(3),
|
|
122
|
+
k2: undefined,
|
|
123
|
+
}
|
|
124
|
+
await dao.save(item3)
|
|
125
|
+
const item3Loaded = await dao.requireById(item3.id)
|
|
126
|
+
expectMatch([item3], [item3Loaded], quirks)
|
|
127
|
+
expect(item3Loaded.k2).toBe(undefined)
|
|
128
|
+
expect(Object.keys(item3Loaded)).not.toContain('k2')
|
|
129
|
+
})
|
|
130
|
+
|
|
104
131
|
test('saveBatch test items', async () => {
|
|
105
132
|
const itemsSaved = await dao.saveBatch(items)
|
|
106
133
|
expect(itemsSaved[0]).toBe(items[0]) // expect "same object" returned
|
package/src/testing/dbTest.ts
CHANGED
|
@@ -34,6 +34,7 @@ export interface CommonDBImplementationFeatures {
|
|
|
34
34
|
streaming?: boolean
|
|
35
35
|
|
|
36
36
|
bufferSupport?: boolean
|
|
37
|
+
nullValues?: boolean
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
/**
|
|
@@ -76,6 +77,7 @@ export function runCommonDBTest(
|
|
|
76
77
|
streaming = true,
|
|
77
78
|
strongConsistency = true,
|
|
78
79
|
bufferSupport = true,
|
|
80
|
+
nullValues = true,
|
|
79
81
|
} = features
|
|
80
82
|
|
|
81
83
|
// const {
|
|
@@ -135,6 +137,31 @@ export function runCommonDBTest(
|
|
|
135
137
|
})
|
|
136
138
|
|
|
137
139
|
// SAVE
|
|
140
|
+
if (nullValues) {
|
|
141
|
+
test('should allow to save and load null values', async () => {
|
|
142
|
+
const item3 = {
|
|
143
|
+
...createTestItemDBM(3),
|
|
144
|
+
k2: null,
|
|
145
|
+
}
|
|
146
|
+
await db.saveBatch(TEST_TABLE, [item3])
|
|
147
|
+
const item3Loaded = (await db.getByIds<TestItemDBM>(TEST_TABLE, [item3.id]))[0]!
|
|
148
|
+
expectMatch([item3], [item3Loaded], quirks)
|
|
149
|
+
expect(item3Loaded.k2).toBe(null)
|
|
150
|
+
})
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
test('undefined values should not be saved/loaded', async () => {
|
|
154
|
+
const item3 = {
|
|
155
|
+
...createTestItemDBM(3),
|
|
156
|
+
k2: undefined,
|
|
157
|
+
}
|
|
158
|
+
await db.saveBatch(TEST_TABLE, [item3])
|
|
159
|
+
const item3Loaded = (await db.getByIds<TestItemDBM>(TEST_TABLE, [item3.id]))[0]!
|
|
160
|
+
expectMatch([item3], [item3Loaded], quirks)
|
|
161
|
+
expect(item3Loaded.k2).toBe(undefined)
|
|
162
|
+
expect(Object.keys(item3Loaded)).not.toContain('k2')
|
|
163
|
+
})
|
|
164
|
+
|
|
138
165
|
test('saveBatch test items', async () => {
|
|
139
166
|
await db.saveBatch(TEST_TABLE, items)
|
|
140
167
|
})
|
|
@@ -15,7 +15,7 @@ export const TEST_TABLE = 'TEST_TABLE'
|
|
|
15
15
|
|
|
16
16
|
export interface TestItemBM extends BaseDBEntity {
|
|
17
17
|
k1: string
|
|
18
|
-
k2?: string
|
|
18
|
+
k2?: string | null
|
|
19
19
|
k3?: number
|
|
20
20
|
even?: boolean
|
|
21
21
|
b1?: Buffer
|
|
@@ -30,7 +30,7 @@ export interface TestItemTM {
|
|
|
30
30
|
|
|
31
31
|
export const testItemBMSchema = objectSchema<TestItemBM>({
|
|
32
32
|
k1: stringSchema,
|
|
33
|
-
k2: stringSchema.optional(),
|
|
33
|
+
k2: stringSchema.allow(null).optional(),
|
|
34
34
|
k3: numberSchema.optional(),
|
|
35
35
|
even: booleanSchema.optional(),
|
|
36
36
|
b1: binarySchema.optional(),
|
|
@@ -38,7 +38,7 @@ export const testItemBMSchema = objectSchema<TestItemBM>({
|
|
|
38
38
|
|
|
39
39
|
export const testItemDBMSchema = objectSchema<TestItemDBM>({
|
|
40
40
|
k1: stringSchema,
|
|
41
|
-
k2: stringSchema.optional(),
|
|
41
|
+
k2: stringSchema.allow(null).optional(),
|
|
42
42
|
k3: numberSchema.optional(),
|
|
43
43
|
even: booleanSchema.optional(),
|
|
44
44
|
b1: binarySchema.optional(),
|
|
@@ -52,7 +52,7 @@ export const testItemTMSchema = objectSchema<TestItemTM>({
|
|
|
52
52
|
export const testItemBMJsonSchema = jsonSchema
|
|
53
53
|
.rootObject<TestItemBM>({
|
|
54
54
|
k1: jsonSchema.string(),
|
|
55
|
-
k2: jsonSchema.string().optional(),
|
|
55
|
+
k2: jsonSchema.oneOf<string | null>([jsonSchema.string(), jsonSchema.null()]).optional(),
|
|
56
56
|
k3: jsonSchema.number().optional(),
|
|
57
57
|
even: jsonSchema.boolean().optional(),
|
|
58
58
|
b1: jsonSchema.buffer().optional(),
|