@naturalcycles/db-lib 8.54.0 → 8.54.2
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/file/localFile.persistence.plugin.js +6 -5
- package/dist/adapter/inmemory/inMemory.db.js +5 -4
- package/dist/cnst.js +1 -1
- package/dist/commondao/common.dao.d.ts +2 -2
- package/dist/commondao/common.dao.model.d.ts +4 -4
- package/dist/commondao/common.dao.model.js +1 -1
- package/dist/db.model.js +2 -2
- package/dist/pipeline/dbPipelineBackup.js +7 -6
- package/dist/pipeline/dbPipelineRestore.js +3 -3
- package/dist/testing/test.model.d.ts +3 -3
- package/dist/timeseries/commonTimeSeriesDao.js +2 -1
- package/dist/validation/index.d.ts +7 -7
- package/dist/validation/index.js +1 -1
- package/package.json +3 -4
- package/readme.md +1 -1
- package/src/adapter/file/file.db.ts +1 -1
- package/src/adapter/file/localFile.persistence.plugin.ts +9 -6
- package/src/adapter/inmemory/inMemory.db.ts +7 -4
- package/src/commondao/common.dao.model.ts +4 -4
- package/src/commondao/common.dao.ts +9 -9
- package/src/pipeline/dbPipelineBackup.ts +11 -6
- package/src/pipeline/dbPipelineRestore.ts +6 -3
- package/src/query/dbQuery.ts +4 -1
- package/src/testing/dbTest.ts +1 -1
- package/src/testing/test.model.ts +2 -2
- package/src/timeseries/commonTimeSeriesDao.ts +3 -3
- package/src/validation/index.ts +11 -2
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.LocalFilePersistencePlugin = void 0;
|
|
4
|
+
const fs = require("node:fs");
|
|
4
5
|
const node_stream_1 = require("node:stream");
|
|
6
|
+
const fsp = require("node:fs/promises");
|
|
5
7
|
const node_zlib_1 = require("node:zlib");
|
|
6
8
|
const js_lib_1 = require("@naturalcycles/js-lib");
|
|
7
9
|
const nodejs_lib_1 = require("@naturalcycles/nodejs-lib");
|
|
8
|
-
const fs = require("fs-extra");
|
|
9
10
|
/**
|
|
10
11
|
* Persists in local filesystem as ndjson.
|
|
11
12
|
*/
|
|
@@ -19,15 +20,15 @@ class LocalFilePersistencePlugin {
|
|
|
19
20
|
}
|
|
20
21
|
async ping() { }
|
|
21
22
|
async getTables() {
|
|
22
|
-
return (await
|
|
23
|
+
return (await fsp.readdir(this.cfg.storagePath))
|
|
23
24
|
.filter(f => f.includes('.ndjson'))
|
|
24
25
|
.map(f => f.split('.ndjson')[0]);
|
|
25
26
|
}
|
|
26
27
|
async loadFile(table) {
|
|
27
|
-
await
|
|
28
|
+
await (0, nodejs_lib_1._ensureDir)(this.cfg.storagePath);
|
|
28
29
|
const ext = `ndjson${this.cfg.gzip ? '.gz' : ''}`;
|
|
29
30
|
const filePath = `${this.cfg.storagePath}/${table}.${ext}`;
|
|
30
|
-
if (!(await
|
|
31
|
+
if (!(await (0, nodejs_lib_1._pathExists)(filePath)))
|
|
31
32
|
return [];
|
|
32
33
|
const transformUnzip = this.cfg.gzip ? [(0, node_zlib_1.createUnzip)()] : [];
|
|
33
34
|
const rows = [];
|
|
@@ -44,7 +45,7 @@ class LocalFilePersistencePlugin {
|
|
|
44
45
|
await (0, js_lib_1.pMap)(ops, async (op) => await this.saveFile(op.table, op.rows), { concurrency: 16 });
|
|
45
46
|
}
|
|
46
47
|
async saveFile(table, rows) {
|
|
47
|
-
await
|
|
48
|
+
await (0, nodejs_lib_1._ensureDir)(this.cfg.storagePath);
|
|
48
49
|
const ext = `ndjson${this.cfg.gzip ? '.gz' : ''}`;
|
|
49
50
|
const filePath = `${this.cfg.storagePath}/${table}.${ext}`;
|
|
50
51
|
const transformZip = this.cfg.gzip ? [(0, node_zlib_1.createGzip)()] : [];
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.InMemoryDB = void 0;
|
|
4
|
+
const fs = require("node:fs");
|
|
5
|
+
const fsp = require("node:fs/promises");
|
|
4
6
|
const node_stream_1 = require("node:stream");
|
|
5
7
|
const node_zlib_1 = require("node:zlib");
|
|
6
8
|
const js_lib_1 = require("@naturalcycles/js-lib");
|
|
7
9
|
const nodejs_lib_1 = require("@naturalcycles/nodejs-lib");
|
|
8
10
|
const colors_1 = require("@naturalcycles/nodejs-lib/dist/colors");
|
|
9
|
-
const fs = require("fs-extra");
|
|
10
11
|
const __1 = require("../..");
|
|
11
12
|
const dbQuery_1 = require("../../query/dbQuery");
|
|
12
13
|
class InMemoryDB {
|
|
@@ -166,7 +167,7 @@ class InMemoryDB {
|
|
|
166
167
|
(0, js_lib_1._assert)(this.cfg.persistenceEnabled, 'flushToDisk() called but persistenceEnabled=false');
|
|
167
168
|
const { persistentStoragePath, persistZip } = this.cfg;
|
|
168
169
|
const started = Date.now();
|
|
169
|
-
await
|
|
170
|
+
await (0, nodejs_lib_1._emptyDir)(persistentStoragePath);
|
|
170
171
|
const transformZip = persistZip ? [(0, node_zlib_1.createGzip)()] : [];
|
|
171
172
|
let tables = 0;
|
|
172
173
|
// infinite concurrency for now
|
|
@@ -192,9 +193,9 @@ class InMemoryDB {
|
|
|
192
193
|
(0, js_lib_1._assert)(this.cfg.persistenceEnabled, 'restoreFromDisk() called but persistenceEnabled=false');
|
|
193
194
|
const { persistentStoragePath } = this.cfg;
|
|
194
195
|
const started = Date.now();
|
|
195
|
-
await
|
|
196
|
+
await (0, nodejs_lib_1._ensureDir)(persistentStoragePath);
|
|
196
197
|
this.data = {}; // empty it in the beginning!
|
|
197
|
-
const files = (await
|
|
198
|
+
const files = (await fsp.readdir(persistentStoragePath)).filter(f => f.includes('.ndjson'));
|
|
198
199
|
// infinite concurrency for now
|
|
199
200
|
await (0, js_lib_1.pMap)(files, async (file) => {
|
|
200
201
|
const fname = `${persistentStoragePath}/${file}`;
|
package/dist/cnst.js
CHANGED
|
@@ -7,4 +7,4 @@ var DBLibError;
|
|
|
7
7
|
DBLibError["DAO_IS_READ_ONLY"] = "DAO_IS_READ_ONLY";
|
|
8
8
|
DBLibError["NON_UNIQUE_ID"] = "NON_UNIQUE_ID";
|
|
9
9
|
DBLibError["OBJECT_IS_IMMUTABLE"] = "OBJECT_IS_IMMUTABLE";
|
|
10
|
-
})(DBLibError
|
|
10
|
+
})(DBLibError || (exports.DBLibError = DBLibError = {}));
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AnyObject, AsyncMapper, JsonSchemaObject, JsonSchemaRootObject, ObjectWithId, Promisable, Saved, UnixTimestampMillisNumber, Unsaved, ZodSchema } from '@naturalcycles/js-lib';
|
|
2
|
-
import { AjvSchema,
|
|
2
|
+
import { AjvSchema, ObjectSchema, ReadableTyped } from '@naturalcycles/nodejs-lib';
|
|
3
3
|
import { DBDeleteByIdsOperation, DBModelType, DBOperation, DBPatch, DBSaveBatchOperation, RunQueryResult } from '../db.model';
|
|
4
4
|
import { DBQuery, RunnableDBQuery } from '../query/dbQuery';
|
|
5
5
|
import { CommonDaoCfg, CommonDaoCreateOptions, CommonDaoOptions, CommonDaoSaveOptions, CommonDaoStreamForEachOptions, CommonDaoStreamOptions } from './common.dao.model';
|
|
@@ -145,7 +145,7 @@ export declare class CommonDao<BM extends Partial<ObjectWithId<ID>>, DBM extends
|
|
|
145
145
|
*
|
|
146
146
|
* Does NOT mutate the object.
|
|
147
147
|
*/
|
|
148
|
-
validateAndConvert<IN, OUT = IN>(obj: Partial<IN>, schema:
|
|
148
|
+
validateAndConvert<IN, OUT = IN>(obj: Partial<IN>, schema: ObjectSchema<IN> | AjvSchema<IN> | ZodSchema<IN> | undefined, modelType: DBModelType, opt?: CommonDaoOptions): OUT;
|
|
149
149
|
getTableSchema(): Promise<JsonSchemaRootObject<DBM>>;
|
|
150
150
|
createTable(schema: JsonSchemaObject<DBM>, opt?: CommonDaoCreateOptions): Promise<void>;
|
|
151
151
|
/**
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { CommonLogger, ErrorMode, ObjectWithId, Promisable, Saved, ZodError, ZodSchema } from '@naturalcycles/js-lib';
|
|
2
|
-
import { AjvSchema, AjvValidationError, JoiValidationError,
|
|
2
|
+
import { AjvSchema, AjvValidationError, JoiValidationError, ObjectSchema, TransformLogProgressOptions, TransformMapOptions } from '@naturalcycles/nodejs-lib';
|
|
3
3
|
import { CommonDB } from '../common.db';
|
|
4
4
|
import { CommonDBCreateOptions, CommonDBOptions, CommonDBSaveOptions } from '../db.model';
|
|
5
5
|
export interface CommonDaoHooks<BM extends Partial<ObjectWithId<ID>>, DBM extends ObjectWithId<ID>, TM, ID extends string | number> {
|
|
@@ -110,9 +110,9 @@ export interface CommonDaoCfg<BM extends Partial<ObjectWithId<ID>>, DBM extends
|
|
|
110
110
|
/**
|
|
111
111
|
* Joi, AjvSchema or ZodSchema is supported.
|
|
112
112
|
*/
|
|
113
|
-
dbmSchema?:
|
|
114
|
-
bmSchema?:
|
|
115
|
-
tmSchema?:
|
|
113
|
+
dbmSchema?: ObjectSchema<DBM> | AjvSchema<DBM> | ZodSchema<DBM>;
|
|
114
|
+
bmSchema?: ObjectSchema<BM> | AjvSchema<BM> | ZodSchema<BM>;
|
|
115
|
+
tmSchema?: ObjectSchema<TM> | AjvSchema<TM> | ZodSchema<TM>;
|
|
116
116
|
excludeFromIndexes?: (keyof DBM)[];
|
|
117
117
|
/**
|
|
118
118
|
* Defaults to false.
|
|
@@ -19,4 +19,4 @@ var CommonDaoLogLevel;
|
|
|
19
19
|
* Log EVERYTHING - all data passing in and out (max 10 rows). Very verbose!
|
|
20
20
|
*/
|
|
21
21
|
CommonDaoLogLevel[CommonDaoLogLevel["DATA_FULL"] = 30] = "DATA_FULL";
|
|
22
|
-
})(CommonDaoLogLevel
|
|
22
|
+
})(CommonDaoLogLevel || (exports.CommonDaoLogLevel = CommonDaoLogLevel = {}));
|
package/dist/db.model.js
CHANGED
|
@@ -5,13 +5,13 @@ var DBRelation;
|
|
|
5
5
|
(function (DBRelation) {
|
|
6
6
|
DBRelation["ONE_TO_ONE"] = "ONE_TO_ONE";
|
|
7
7
|
DBRelation["ONE_TO_MANY"] = "ONE_TO_MANY";
|
|
8
|
-
})(DBRelation
|
|
8
|
+
})(DBRelation || (exports.DBRelation = DBRelation = {}));
|
|
9
9
|
var DBModelType;
|
|
10
10
|
(function (DBModelType) {
|
|
11
11
|
DBModelType["DBM"] = "DBM";
|
|
12
12
|
DBModelType["BM"] = "BM";
|
|
13
13
|
DBModelType["TM"] = "TM";
|
|
14
|
-
})(DBModelType
|
|
14
|
+
})(DBModelType || (exports.DBModelType = DBModelType = {}));
|
|
15
15
|
/**
|
|
16
16
|
* Allows to construct a query similar to:
|
|
17
17
|
*
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.dbPipelineBackup = void 0;
|
|
4
|
+
const fs = require("node:fs");
|
|
5
|
+
const fsp = require("node:fs/promises");
|
|
4
6
|
const node_zlib_1 = require("node:zlib");
|
|
5
7
|
const js_lib_1 = require("@naturalcycles/js-lib");
|
|
6
8
|
const nodejs_lib_1 = require("@naturalcycles/nodejs-lib");
|
|
7
9
|
const colors_1 = require("@naturalcycles/nodejs-lib/dist/colors");
|
|
8
|
-
const fs = require("fs-extra");
|
|
9
10
|
const index_1 = require("../index");
|
|
10
11
|
/**
|
|
11
12
|
* Pipeline from input stream(s) to a NDJSON file (optionally gzipped).
|
|
@@ -23,7 +24,7 @@ async function dbPipelineBackup(opt) {
|
|
|
23
24
|
let { tables } = opt;
|
|
24
25
|
const sinceUpdatedStr = sinceUpdated ? ' since ' + (0, colors_1.grey)((0, js_lib_1.localTime)(sinceUpdated).toPretty()) : '';
|
|
25
26
|
console.log(`>> ${(0, colors_1.dimWhite)('dbPipelineBackup')} started in ${(0, colors_1.grey)(outputDirPath)}...${sinceUpdatedStr}`);
|
|
26
|
-
|
|
27
|
+
(0, nodejs_lib_1._ensureDirSync)(outputDirPath);
|
|
27
28
|
tables ||= await db.getTables();
|
|
28
29
|
console.log(`${(0, colors_1.yellow)(tables.length)} ${(0, colors_1.boldWhite)('table(s)')}:\n` + tables.join('\n'));
|
|
29
30
|
const statsPerTable = {};
|
|
@@ -34,16 +35,16 @@ async function dbPipelineBackup(opt) {
|
|
|
34
35
|
}
|
|
35
36
|
const filePath = `${outputDirPath}/${table}.ndjson` + (gzip ? '.gz' : '');
|
|
36
37
|
const schemaFilePath = `${outputDirPath}/${table}.schema.json`;
|
|
37
|
-
if (protectFromOverwrite && (
|
|
38
|
+
if (protectFromOverwrite && (0, nodejs_lib_1._pathExistsSync)(filePath)) {
|
|
38
39
|
throw new js_lib_1.AppError(`dbPipelineBackup: output file exists: ${filePath}`);
|
|
39
40
|
}
|
|
40
41
|
const started = Date.now();
|
|
41
42
|
let rows = 0;
|
|
42
|
-
|
|
43
|
+
(0, nodejs_lib_1._ensureFileSync)(filePath);
|
|
43
44
|
console.log(`>> ${(0, colors_1.grey)(filePath)} started...`);
|
|
44
45
|
if (emitSchemaFromDB) {
|
|
45
46
|
const schema = await db.getTableSchema(table);
|
|
46
|
-
await
|
|
47
|
+
await (0, nodejs_lib_1._writeJsonFile)(schemaFilePath, schema, { spaces: 2 });
|
|
47
48
|
console.log(`>> ${(0, colors_1.grey)(schemaFilePath)} saved (generated from DB)`);
|
|
48
49
|
}
|
|
49
50
|
await (0, nodejs_lib_1._pipeline)([
|
|
@@ -66,7 +67,7 @@ async function dbPipelineBackup(opt) {
|
|
|
66
67
|
...(gzip ? [(0, node_zlib_1.createGzip)(zlibOptions)] : []),
|
|
67
68
|
fs.createWriteStream(filePath),
|
|
68
69
|
]);
|
|
69
|
-
const { size: sizeBytes } = await
|
|
70
|
+
const { size: sizeBytes } = await fsp.stat(filePath);
|
|
70
71
|
const stats = nodejs_lib_1.NDJsonStats.create({
|
|
71
72
|
tookMillis: Date.now() - started,
|
|
72
73
|
rows,
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.dbPipelineRestore = void 0;
|
|
4
|
+
const fs = require("node:fs");
|
|
4
5
|
const node_zlib_1 = require("node:zlib");
|
|
5
6
|
const js_lib_1 = require("@naturalcycles/js-lib");
|
|
6
7
|
const nodejs_lib_1 = require("@naturalcycles/nodejs-lib");
|
|
7
8
|
const colors_1 = require("@naturalcycles/nodejs-lib/dist/colors");
|
|
8
|
-
const fs = require("fs-extra");
|
|
9
9
|
/**
|
|
10
10
|
* Pipeline from NDJSON files in a folder (optionally gzipped) to CommonDB.
|
|
11
11
|
* Allows to define a mapper and a predicate to map/filter objects between input and output.
|
|
@@ -19,7 +19,7 @@ async function dbPipelineRestore(opt) {
|
|
|
19
19
|
const onlyTables = opt.tables && new Set(opt.tables);
|
|
20
20
|
const sinceUpdatedStr = sinceUpdated ? ' since ' + (0, colors_1.grey)((0, js_lib_1.localTime)(sinceUpdated).toPretty()) : '';
|
|
21
21
|
console.log(`>> ${(0, colors_1.dimWhite)('dbPipelineRestore')} started in ${(0, colors_1.grey)(inputDirPath)}...${sinceUpdatedStr}`);
|
|
22
|
-
|
|
22
|
+
(0, nodejs_lib_1._ensureDirSync)(inputDirPath);
|
|
23
23
|
const tablesToGzip = new Set();
|
|
24
24
|
const sizeByTable = {};
|
|
25
25
|
const statsPerTable = {};
|
|
@@ -54,7 +54,7 @@ async function dbPipelineRestore(opt) {
|
|
|
54
54
|
console.warn(`${schemaFilePath} does not exist!`);
|
|
55
55
|
return;
|
|
56
56
|
}
|
|
57
|
-
const schema = await
|
|
57
|
+
const schema = await (0, nodejs_lib_1._readJsonFile)(schemaFilePath);
|
|
58
58
|
await db.createTable(table, schema, { dropIfExists: true });
|
|
59
59
|
});
|
|
60
60
|
}
|
|
@@ -15,9 +15,9 @@ export interface TestItemTM {
|
|
|
15
15
|
k1: string;
|
|
16
16
|
even?: boolean;
|
|
17
17
|
}
|
|
18
|
-
export declare const testItemBMSchema: import("
|
|
19
|
-
export declare const testItemDBMSchema: import("
|
|
20
|
-
export declare const testItemTMSchema: import("
|
|
18
|
+
export declare const testItemBMSchema: import("joi").ObjectSchema<TestItemBM>;
|
|
19
|
+
export declare const testItemDBMSchema: import("joi").ObjectSchema<TestItemDBM>;
|
|
20
|
+
export declare const testItemTMSchema: import("joi").ObjectSchema<TestItemTM>;
|
|
21
21
|
export declare const testItemBMJsonSchema: JsonSchemaObject<TestItemBM>;
|
|
22
22
|
export declare const testItemDBMJsonSchema: JsonSchemaObject<TestItemDBM>;
|
|
23
23
|
export declare function createTestItemDBM(num?: number): TestItemDBM;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.CommonTimeSeriesDao = void 0;
|
|
4
|
+
const js_lib_1 = require("@naturalcycles/js-lib");
|
|
4
5
|
const __1 = require("..");
|
|
5
6
|
const dbQuery_1 = require("../query/dbQuery");
|
|
6
7
|
const _TIMESERIES_RAW = '_TIMESERIES_RAW';
|
|
@@ -20,7 +21,7 @@ class CommonTimeSeriesDao {
|
|
|
20
21
|
async getSeries() {
|
|
21
22
|
return (await this.cfg.db.getTables())
|
|
22
23
|
.map(t => /^(.*)_TIMESERIES_RAW$/.exec(t)?.[1])
|
|
23
|
-
.filter(
|
|
24
|
+
.filter(js_lib_1._isTruthy);
|
|
24
25
|
}
|
|
25
26
|
// convenience method
|
|
26
27
|
async save(series, tsMillis, value) {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { CommonDBOptions, CommonDBSaveOptions } from '../db.model';
|
|
2
|
-
import { DBQuery, DBQueryFilter, DBQueryOrder } from '../query/dbQuery';
|
|
3
|
-
export declare const commonDBOptionsSchema: import("
|
|
4
|
-
export declare const commonDBSaveOptionsSchema: import("
|
|
5
|
-
export declare const dbQueryFilterOperatorSchema: import("@naturalcycles/nodejs-lib/dist/validation/joi/string.extensions").
|
|
6
|
-
export declare const dbQueryFilterSchema: import("
|
|
7
|
-
export declare const dbQueryOrderSchema: import("
|
|
8
|
-
export declare const dbQuerySchema: import("
|
|
2
|
+
import { DBQuery, DBQueryFilter, DBQueryFilterOperator, DBQueryOrder } from '../query/dbQuery';
|
|
3
|
+
export declare const commonDBOptionsSchema: import("joi").ObjectSchema<CommonDBOptions>;
|
|
4
|
+
export declare const commonDBSaveOptionsSchema: import("joi").ObjectSchema<CommonDBSaveOptions<any>>;
|
|
5
|
+
export declare const dbQueryFilterOperatorSchema: import("@naturalcycles/nodejs-lib/dist/validation/joi/string.extensions").StringSchema<DBQueryFilterOperator>;
|
|
6
|
+
export declare const dbQueryFilterSchema: import("joi").ObjectSchema<DBQueryFilter<import("@naturalcycles/js-lib").AnyObjectWithId<string | number>>>;
|
|
7
|
+
export declare const dbQueryOrderSchema: import("joi").ObjectSchema<DBQueryOrder<import("@naturalcycles/js-lib").AnyObjectWithId<string | number>>>;
|
|
8
|
+
export declare const dbQuerySchema: import("joi").ObjectSchema<DBQuery<any>>;
|
package/dist/validation/index.js
CHANGED
|
@@ -10,7 +10,7 @@ exports.commonDBOptionsSchema = (0, nodejs_lib_1.objectSchema)({
|
|
|
10
10
|
exports.commonDBSaveOptionsSchema = (0, nodejs_lib_1.objectSchema)({
|
|
11
11
|
excludeFromIndexes: (0, nodejs_lib_1.arraySchema)(nodejs_lib_1.stringSchema).optional(),
|
|
12
12
|
}).concat(exports.commonDBOptionsSchema);
|
|
13
|
-
exports.dbQueryFilterOperatorSchema = nodejs_lib_1.
|
|
13
|
+
exports.dbQueryFilterOperatorSchema = nodejs_lib_1.Joi.string().valid(...dbQuery_1.dbQueryFilterOperatorValues);
|
|
14
14
|
exports.dbQueryFilterSchema = (0, nodejs_lib_1.objectSchema)({
|
|
15
15
|
name: nodejs_lib_1.stringSchema,
|
|
16
16
|
op: exports.dbQueryFilterOperatorSchema,
|
package/package.json
CHANGED
|
@@ -5,13 +5,12 @@
|
|
|
5
5
|
},
|
|
6
6
|
"dependencies": {
|
|
7
7
|
"@naturalcycles/js-lib": "^14.116.0",
|
|
8
|
-
"@naturalcycles/nodejs-lib": "^12.0.0"
|
|
9
|
-
"fs-extra": "^11.1.0"
|
|
8
|
+
"@naturalcycles/nodejs-lib": "^12.0.0"
|
|
10
9
|
},
|
|
11
10
|
"devDependencies": {
|
|
12
11
|
"@naturalcycles/bench-lib": "^1.0.0",
|
|
13
12
|
"@naturalcycles/dev-lib": "^13.0.0",
|
|
14
|
-
"@types/node": "^
|
|
13
|
+
"@types/node": "^20.2.1",
|
|
15
14
|
"jest": "^29.0.0"
|
|
16
15
|
},
|
|
17
16
|
"files": [
|
|
@@ -41,7 +40,7 @@
|
|
|
41
40
|
"engines": {
|
|
42
41
|
"node": ">=18.12"
|
|
43
42
|
},
|
|
44
|
-
"version": "8.54.
|
|
43
|
+
"version": "8.54.2",
|
|
45
44
|
"description": "Lowest Common Denominator API to supported Databases",
|
|
46
45
|
"keywords": [
|
|
47
46
|
"db",
|
package/readme.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
[](https://www.npmjs.com/package/@naturalcycles/db-lib)
|
|
6
6
|
[](https://github.com/prettier/prettier)
|
|
7
7
|
[](https://github.com/NaturalCycles/db-lib)
|
|
8
|
-
[](https://github.com/NaturalCycles/db-lib/actions)
|
|
9
9
|
|
|
10
10
|
Defines 3 things:
|
|
11
11
|
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import * as fs from 'node:fs'
|
|
1
2
|
import { Readable } from 'node:stream'
|
|
3
|
+
import * as fsp from 'node:fs/promises'
|
|
2
4
|
import { createGzip, createUnzip } from 'node:zlib'
|
|
3
5
|
import { pMap, ObjectWithId } from '@naturalcycles/js-lib'
|
|
4
6
|
import {
|
|
@@ -7,8 +9,9 @@ import {
|
|
|
7
9
|
transformToNDJson,
|
|
8
10
|
writablePushToArray,
|
|
9
11
|
_pipeline,
|
|
12
|
+
_ensureDir,
|
|
13
|
+
_pathExists,
|
|
10
14
|
} from '@naturalcycles/nodejs-lib'
|
|
11
|
-
import * as fs from 'fs-extra'
|
|
12
15
|
import { DBSaveBatchOperation } from '../../db.model'
|
|
13
16
|
import { FileDBPersistencePlugin } from './file.db.model'
|
|
14
17
|
|
|
@@ -36,22 +39,22 @@ export class LocalFilePersistencePlugin implements FileDBPersistencePlugin {
|
|
|
36
39
|
}
|
|
37
40
|
}
|
|
38
41
|
|
|
39
|
-
|
|
42
|
+
cfg!: LocalFilePersistencePluginCfg
|
|
40
43
|
|
|
41
44
|
async ping(): Promise<void> {}
|
|
42
45
|
|
|
43
46
|
async getTables(): Promise<string[]> {
|
|
44
|
-
return (await
|
|
47
|
+
return (await fsp.readdir(this.cfg.storagePath))
|
|
45
48
|
.filter(f => f.includes('.ndjson'))
|
|
46
49
|
.map(f => f.split('.ndjson')[0]!)
|
|
47
50
|
}
|
|
48
51
|
|
|
49
52
|
async loadFile<ROW extends ObjectWithId>(table: string): Promise<ROW[]> {
|
|
50
|
-
await
|
|
53
|
+
await _ensureDir(this.cfg.storagePath)
|
|
51
54
|
const ext = `ndjson${this.cfg.gzip ? '.gz' : ''}`
|
|
52
55
|
const filePath = `${this.cfg.storagePath}/${table}.${ext}`
|
|
53
56
|
|
|
54
|
-
if (!(await
|
|
57
|
+
if (!(await _pathExists(filePath))) return []
|
|
55
58
|
|
|
56
59
|
const transformUnzip = this.cfg.gzip ? [createUnzip()] : []
|
|
57
60
|
|
|
@@ -73,7 +76,7 @@ export class LocalFilePersistencePlugin implements FileDBPersistencePlugin {
|
|
|
73
76
|
}
|
|
74
77
|
|
|
75
78
|
async saveFile<ROW extends ObjectWithId>(table: string, rows: ROW[]): Promise<void> {
|
|
76
|
-
await
|
|
79
|
+
await _ensureDir(this.cfg.storagePath)
|
|
77
80
|
const ext = `ndjson${this.cfg.gzip ? '.gz' : ''}`
|
|
78
81
|
const filePath = `${this.cfg.storagePath}/${table}.${ext}`
|
|
79
82
|
const transformZip = this.cfg.gzip ? [createGzip()] : []
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import * as fs from 'node:fs'
|
|
2
|
+
import * as fsp from 'node:fs/promises'
|
|
1
3
|
import { Readable } from 'node:stream'
|
|
2
4
|
import { createGzip, createUnzip } from 'node:zlib'
|
|
3
5
|
import {
|
|
@@ -23,9 +25,10 @@ import {
|
|
|
23
25
|
transformToNDJson,
|
|
24
26
|
writablePushToArray,
|
|
25
27
|
_pipeline,
|
|
28
|
+
_emptyDir,
|
|
29
|
+
_ensureDir,
|
|
26
30
|
} from '@naturalcycles/nodejs-lib'
|
|
27
31
|
import { dimGrey, yellow } from '@naturalcycles/nodejs-lib/dist/colors'
|
|
28
|
-
import * as fs from 'fs-extra'
|
|
29
32
|
import { CommonDB, DBIncrement, DBPatch, DBTransaction, queryInMemory } from '../..'
|
|
30
33
|
import {
|
|
31
34
|
CommonDBCreateOptions,
|
|
@@ -279,7 +282,7 @@ export class InMemoryDB implements CommonDB {
|
|
|
279
282
|
|
|
280
283
|
const started = Date.now()
|
|
281
284
|
|
|
282
|
-
await
|
|
285
|
+
await _emptyDir(persistentStoragePath)
|
|
283
286
|
|
|
284
287
|
const transformZip = persistZip ? [createGzip()] : []
|
|
285
288
|
let tables = 0
|
|
@@ -314,11 +317,11 @@ export class InMemoryDB implements CommonDB {
|
|
|
314
317
|
|
|
315
318
|
const started = Date.now()
|
|
316
319
|
|
|
317
|
-
await
|
|
320
|
+
await _ensureDir(persistentStoragePath)
|
|
318
321
|
|
|
319
322
|
this.data = {} // empty it in the beginning!
|
|
320
323
|
|
|
321
|
-
const files = (await
|
|
324
|
+
const files = (await fsp.readdir(persistentStoragePath)).filter(f => f.includes('.ndjson'))
|
|
322
325
|
|
|
323
326
|
// infinite concurrency for now
|
|
324
327
|
await pMap(files, async file => {
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
AjvSchema,
|
|
12
12
|
AjvValidationError,
|
|
13
13
|
JoiValidationError,
|
|
14
|
-
|
|
14
|
+
ObjectSchema,
|
|
15
15
|
TransformLogProgressOptions,
|
|
16
16
|
TransformMapOptions,
|
|
17
17
|
} from '@naturalcycles/nodejs-lib'
|
|
@@ -148,9 +148,9 @@ export interface CommonDaoCfg<
|
|
|
148
148
|
/**
|
|
149
149
|
* Joi, AjvSchema or ZodSchema is supported.
|
|
150
150
|
*/
|
|
151
|
-
dbmSchema?:
|
|
152
|
-
bmSchema?:
|
|
153
|
-
tmSchema?:
|
|
151
|
+
dbmSchema?: ObjectSchema<DBM> | AjvSchema<DBM> | ZodSchema<DBM>
|
|
152
|
+
bmSchema?: ObjectSchema<BM> | AjvSchema<BM> | ZodSchema<BM>
|
|
153
|
+
tmSchema?: ObjectSchema<TM> | AjvSchema<TM> | ZodSchema<TM>
|
|
154
154
|
|
|
155
155
|
excludeFromIndexes?: (keyof DBM)[]
|
|
156
156
|
|
|
@@ -30,7 +30,7 @@ import {
|
|
|
30
30
|
AjvValidationError,
|
|
31
31
|
getValidationResult,
|
|
32
32
|
JoiValidationError,
|
|
33
|
-
|
|
33
|
+
ObjectSchema,
|
|
34
34
|
ReadableTyped,
|
|
35
35
|
stringId,
|
|
36
36
|
transformBuffer,
|
|
@@ -453,7 +453,7 @@ export class CommonDao<
|
|
|
453
453
|
if (partialQuery || opt.raw) return dbm as any
|
|
454
454
|
|
|
455
455
|
if (this.cfg.hooks!.afterLoad) {
|
|
456
|
-
dbm = (await this.cfg.hooks!.afterLoad(dbm))
|
|
456
|
+
dbm = (await this.cfg.hooks!.afterLoad(dbm))!
|
|
457
457
|
if (dbm === null) return SKIP
|
|
458
458
|
}
|
|
459
459
|
|
|
@@ -503,7 +503,7 @@ export class CommonDao<
|
|
|
503
503
|
if (partialQuery || opt.raw) return dbm
|
|
504
504
|
|
|
505
505
|
if (this.cfg.hooks!.afterLoad) {
|
|
506
|
-
dbm = (await this.cfg.hooks!.afterLoad(dbm))
|
|
506
|
+
dbm = (await this.cfg.hooks!.afterLoad(dbm))!
|
|
507
507
|
if (dbm === null) return SKIP
|
|
508
508
|
}
|
|
509
509
|
|
|
@@ -550,7 +550,7 @@ export class CommonDao<
|
|
|
550
550
|
transformMap<any, DBM>(
|
|
551
551
|
async dbm => {
|
|
552
552
|
if (this.cfg.hooks!.afterLoad) {
|
|
553
|
-
dbm = (await this.cfg.hooks!.afterLoad(dbm))
|
|
553
|
+
dbm = (await this.cfg.hooks!.afterLoad(dbm))!
|
|
554
554
|
if (dbm === null) return SKIP
|
|
555
555
|
}
|
|
556
556
|
|
|
@@ -592,7 +592,7 @@ export class CommonDao<
|
|
|
592
592
|
transformMap<DBM, Saved<BM>>(
|
|
593
593
|
async dbm => {
|
|
594
594
|
if (this.cfg.hooks!.afterLoad) {
|
|
595
|
-
dbm = (await this.cfg.hooks!.afterLoad(dbm))
|
|
595
|
+
dbm = (await this.cfg.hooks!.afterLoad(dbm))!
|
|
596
596
|
if (dbm === null) return SKIP
|
|
597
597
|
}
|
|
598
598
|
|
|
@@ -765,7 +765,7 @@ export class CommonDao<
|
|
|
765
765
|
let dbm = await this.bmToDBM(bm as BM, opt)
|
|
766
766
|
|
|
767
767
|
if (this.cfg.hooks!.beforeSave) {
|
|
768
|
-
dbm = (await this.cfg.hooks!.beforeSave(dbm))
|
|
768
|
+
dbm = (await this.cfg.hooks!.beforeSave(dbm))!
|
|
769
769
|
if (dbm === null && !opt.tx) return bm as any
|
|
770
770
|
}
|
|
771
771
|
|
|
@@ -852,7 +852,7 @@ export class CommonDao<
|
|
|
852
852
|
const assignGeneratedIds = opt.assignGeneratedIds || this.cfg.assignGeneratedIds
|
|
853
853
|
|
|
854
854
|
if (this.cfg.hooks!.beforeSave) {
|
|
855
|
-
row = (await this.cfg.hooks!.beforeSave(row))
|
|
855
|
+
row = (await this.cfg.hooks!.beforeSave(row))!
|
|
856
856
|
if (row === null) return dbm
|
|
857
857
|
}
|
|
858
858
|
|
|
@@ -1178,7 +1178,7 @@ export class CommonDao<
|
|
|
1178
1178
|
*/
|
|
1179
1179
|
validateAndConvert<IN, OUT = IN>(
|
|
1180
1180
|
obj: Partial<IN>,
|
|
1181
|
-
schema:
|
|
1181
|
+
schema: ObjectSchema<IN> | AjvSchema<IN> | ZodSchema<IN> | undefined,
|
|
1182
1182
|
modelType: DBModelType,
|
|
1183
1183
|
opt: CommonDaoOptions = {},
|
|
1184
1184
|
): OUT {
|
|
@@ -1231,7 +1231,7 @@ export class CommonDao<
|
|
|
1231
1231
|
})
|
|
1232
1232
|
} else {
|
|
1233
1233
|
// Joi
|
|
1234
|
-
const vr = getValidationResult
|
|
1234
|
+
const vr = getValidationResult(obj, schema, objectName)
|
|
1235
1235
|
error = vr.error
|
|
1236
1236
|
convertedValue = vr.value
|
|
1237
1237
|
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import * as fs from 'node:fs'
|
|
2
|
+
import * as fsp from 'node:fs/promises'
|
|
1
3
|
import { createGzip, ZlibOptions } from 'node:zlib'
|
|
2
4
|
import {
|
|
3
5
|
AppError,
|
|
@@ -16,9 +18,12 @@ import {
|
|
|
16
18
|
transformTap,
|
|
17
19
|
transformToNDJson,
|
|
18
20
|
_pipeline,
|
|
21
|
+
_ensureDirSync,
|
|
22
|
+
_pathExistsSync,
|
|
23
|
+
_ensureFileSync,
|
|
24
|
+
_writeJsonFile,
|
|
19
25
|
} from '@naturalcycles/nodejs-lib'
|
|
20
26
|
import { boldWhite, dimWhite, grey, yellow } from '@naturalcycles/nodejs-lib/dist/colors'
|
|
21
|
-
import * as fs from 'fs-extra'
|
|
22
27
|
import { CommonDB } from '../common.db'
|
|
23
28
|
import { DBQuery } from '../index'
|
|
24
29
|
|
|
@@ -156,7 +161,7 @@ export async function dbPipelineBackup(opt: DBPipelineBackupOptions): Promise<ND
|
|
|
156
161
|
`>> ${dimWhite('dbPipelineBackup')} started in ${grey(outputDirPath)}...${sinceUpdatedStr}`,
|
|
157
162
|
)
|
|
158
163
|
|
|
159
|
-
|
|
164
|
+
_ensureDirSync(outputDirPath)
|
|
160
165
|
|
|
161
166
|
tables ||= await db.getTables()
|
|
162
167
|
|
|
@@ -176,20 +181,20 @@ export async function dbPipelineBackup(opt: DBPipelineBackupOptions): Promise<ND
|
|
|
176
181
|
const filePath = `${outputDirPath}/${table}.ndjson` + (gzip ? '.gz' : '')
|
|
177
182
|
const schemaFilePath = `${outputDirPath}/${table}.schema.json`
|
|
178
183
|
|
|
179
|
-
if (protectFromOverwrite && (
|
|
184
|
+
if (protectFromOverwrite && _pathExistsSync(filePath)) {
|
|
180
185
|
throw new AppError(`dbPipelineBackup: output file exists: ${filePath}`)
|
|
181
186
|
}
|
|
182
187
|
|
|
183
188
|
const started = Date.now()
|
|
184
189
|
let rows = 0
|
|
185
190
|
|
|
186
|
-
|
|
191
|
+
_ensureFileSync(filePath)
|
|
187
192
|
|
|
188
193
|
console.log(`>> ${grey(filePath)} started...`)
|
|
189
194
|
|
|
190
195
|
if (emitSchemaFromDB) {
|
|
191
196
|
const schema = await db.getTableSchema(table)
|
|
192
|
-
await
|
|
197
|
+
await _writeJsonFile(schemaFilePath, schema, { spaces: 2 })
|
|
193
198
|
console.log(`>> ${grey(schemaFilePath)} saved (generated from DB)`)
|
|
194
199
|
}
|
|
195
200
|
|
|
@@ -214,7 +219,7 @@ export async function dbPipelineBackup(opt: DBPipelineBackupOptions): Promise<ND
|
|
|
214
219
|
fs.createWriteStream(filePath),
|
|
215
220
|
])
|
|
216
221
|
|
|
217
|
-
const { size: sizeBytes } = await
|
|
222
|
+
const { size: sizeBytes } = await fsp.stat(filePath)
|
|
218
223
|
|
|
219
224
|
const stats = NDJsonStats.create({
|
|
220
225
|
tookMillis: Date.now() - started,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import * as fs from 'node:fs'
|
|
1
2
|
import { createUnzip } from 'node:zlib'
|
|
2
3
|
import {
|
|
3
4
|
AsyncMapper,
|
|
@@ -8,6 +9,7 @@ import {
|
|
|
8
9
|
_passthroughMapper,
|
|
9
10
|
SavedDBEntity,
|
|
10
11
|
localTime,
|
|
12
|
+
JsonSchemaObject,
|
|
11
13
|
} from '@naturalcycles/js-lib'
|
|
12
14
|
import {
|
|
13
15
|
NDJsonStats,
|
|
@@ -23,9 +25,10 @@ import {
|
|
|
23
25
|
transformTap,
|
|
24
26
|
writableForEach,
|
|
25
27
|
_pipeline,
|
|
28
|
+
_ensureDirSync,
|
|
29
|
+
_readJsonFile,
|
|
26
30
|
} from '@naturalcycles/nodejs-lib'
|
|
27
31
|
import { boldWhite, dimWhite, grey, yellow } from '@naturalcycles/nodejs-lib/dist/colors'
|
|
28
|
-
import * as fs from 'fs-extra'
|
|
29
32
|
import { CommonDB } from '../common.db'
|
|
30
33
|
import { CommonDBSaveOptions } from '../index'
|
|
31
34
|
|
|
@@ -139,7 +142,7 @@ export async function dbPipelineRestore(opt: DBPipelineRestoreOptions): Promise<
|
|
|
139
142
|
`>> ${dimWhite('dbPipelineRestore')} started in ${grey(inputDirPath)}...${sinceUpdatedStr}`,
|
|
140
143
|
)
|
|
141
144
|
|
|
142
|
-
|
|
145
|
+
_ensureDirSync(inputDirPath)
|
|
143
146
|
|
|
144
147
|
const tablesToGzip = new Set<string>()
|
|
145
148
|
const sizeByTable: Record<string, number> = {}
|
|
@@ -179,7 +182,7 @@ export async function dbPipelineRestore(opt: DBPipelineRestoreOptions): Promise<
|
|
|
179
182
|
return
|
|
180
183
|
}
|
|
181
184
|
|
|
182
|
-
const schema = await
|
|
185
|
+
const schema = await _readJsonFile<JsonSchemaObject<any>>(schemaFilePath)
|
|
183
186
|
await db.createTable(table, schema, { dropIfExists: true })
|
|
184
187
|
})
|
|
185
188
|
}
|
package/src/query/dbQuery.ts
CHANGED
|
@@ -244,7 +244,10 @@ export class RunnableDBQuery<
|
|
|
244
244
|
/**
|
|
245
245
|
* Pass `table` to override table.
|
|
246
246
|
*/
|
|
247
|
-
constructor(
|
|
247
|
+
constructor(
|
|
248
|
+
public dao: CommonDao<BM, DBM, TM, ID>,
|
|
249
|
+
table?: string,
|
|
250
|
+
) {
|
|
248
251
|
super(table || dao.cfg.table)
|
|
249
252
|
}
|
|
250
253
|
|
package/src/testing/dbTest.ts
CHANGED
|
@@ -112,7 +112,7 @@ export function runCommonDBTest(
|
|
|
112
112
|
deepFreeze(items)
|
|
113
113
|
const item1 = items[0]!
|
|
114
114
|
|
|
115
|
-
const queryAll = () => DBQuery.create<TestItemDBM>(TEST_TABLE)
|
|
115
|
+
const queryAll = (): DBQuery<TestItemDBM> => DBQuery.create<TestItemDBM>(TEST_TABLE)
|
|
116
116
|
|
|
117
117
|
test('ping', async () => {
|
|
118
118
|
await db.ping()
|
|
@@ -35,7 +35,7 @@ export const testItemBMSchema = objectSchema<TestItemBM>({
|
|
|
35
35
|
k3: numberSchema.optional(),
|
|
36
36
|
even: booleanSchema.optional(),
|
|
37
37
|
b1: binarySchema.optional(),
|
|
38
|
-
}).concat(baseDBEntitySchema)
|
|
38
|
+
}).concat(baseDBEntitySchema as any)
|
|
39
39
|
|
|
40
40
|
export const testItemDBMSchema = objectSchema<TestItemDBM>({
|
|
41
41
|
k1: stringSchema,
|
|
@@ -43,7 +43,7 @@ export const testItemDBMSchema = objectSchema<TestItemDBM>({
|
|
|
43
43
|
k3: numberSchema.optional(),
|
|
44
44
|
even: booleanSchema.optional(),
|
|
45
45
|
b1: binarySchema.optional(),
|
|
46
|
-
}).concat(savedDBEntitySchema)
|
|
46
|
+
}).concat(savedDBEntitySchema as any)
|
|
47
47
|
|
|
48
48
|
export const testItemTMSchema = objectSchema<TestItemTM>({
|
|
49
49
|
k1: stringSchema,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ObjectWithId } from '@naturalcycles/js-lib'
|
|
1
|
+
import { _isTruthy, ObjectWithId } from '@naturalcycles/js-lib'
|
|
2
2
|
import { DBTransaction } from '..'
|
|
3
3
|
import { DBQuery } from '../query/dbQuery'
|
|
4
4
|
import {
|
|
@@ -26,8 +26,8 @@ export class CommonTimeSeriesDao {
|
|
|
26
26
|
|
|
27
27
|
async getSeries(): Promise<string[]> {
|
|
28
28
|
return (await this.cfg.db.getTables())
|
|
29
|
-
.map(t => /^(.*)_TIMESERIES_RAW$/.exec(t)?.[1]
|
|
30
|
-
.filter(
|
|
29
|
+
.map(t => /^(.*)_TIMESERIES_RAW$/.exec(t)?.[1])
|
|
30
|
+
.filter(_isTruthy)
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
// convenience method
|
package/src/validation/index.ts
CHANGED
|
@@ -3,11 +3,18 @@ import {
|
|
|
3
3
|
arraySchema,
|
|
4
4
|
booleanSchema,
|
|
5
5
|
integerSchema,
|
|
6
|
+
Joi,
|
|
6
7
|
objectSchema,
|
|
7
8
|
stringSchema,
|
|
8
9
|
} from '@naturalcycles/nodejs-lib'
|
|
9
10
|
import { CommonDBOptions, CommonDBSaveOptions } from '../db.model'
|
|
10
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
DBQuery,
|
|
13
|
+
DBQueryFilter,
|
|
14
|
+
DBQueryFilterOperator,
|
|
15
|
+
dbQueryFilterOperatorValues,
|
|
16
|
+
DBQueryOrder,
|
|
17
|
+
} from '../query/dbQuery'
|
|
11
18
|
|
|
12
19
|
export const commonDBOptionsSchema = objectSchema<CommonDBOptions>({
|
|
13
20
|
onlyCache: booleanSchema.optional(),
|
|
@@ -18,7 +25,9 @@ export const commonDBSaveOptionsSchema = objectSchema<CommonDBSaveOptions>({
|
|
|
18
25
|
excludeFromIndexes: arraySchema(stringSchema).optional(),
|
|
19
26
|
}).concat(commonDBOptionsSchema)
|
|
20
27
|
|
|
21
|
-
export const dbQueryFilterOperatorSchema =
|
|
28
|
+
export const dbQueryFilterOperatorSchema = Joi.string<DBQueryFilterOperator>().valid(
|
|
29
|
+
...dbQueryFilterOperatorValues,
|
|
30
|
+
)
|
|
22
31
|
|
|
23
32
|
export const dbQueryFilterSchema = objectSchema<DBQueryFilter>({
|
|
24
33
|
name: stringSchema,
|