@naturalcycles/db-lib 8.58.0 → 8.59.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.
|
@@ -3,6 +3,7 @@ import { ZlibOptions } from 'node:zlib';
|
|
|
3
3
|
import { AsyncMapper, ErrorMode, UnixTimestampNumber, StringMap } from '@naturalcycles/js-lib';
|
|
4
4
|
import { NDJsonStats, TransformLogProgressOptions, TransformMapOptions } from '@naturalcycles/nodejs-lib';
|
|
5
5
|
import { CommonDB } from '../common.db';
|
|
6
|
+
import { DBQuery } from '../index';
|
|
6
7
|
export interface DBPipelineBackupOptions extends TransformLogProgressOptions {
|
|
7
8
|
/**
|
|
8
9
|
* DB to dump data from.
|
|
@@ -40,6 +41,12 @@ export interface DBPipelineBackupOptions extends TransformLogProgressOptions {
|
|
|
40
41
|
* If set - will do "incremental backup" (not full), only for entities that updated >= `sinceUpdated` (on a per table basis)
|
|
41
42
|
*/
|
|
42
43
|
sinceUpdatedPerTable?: StringMap<UnixTimestampNumber>;
|
|
44
|
+
/**
|
|
45
|
+
* By default, dbPipelineBackup creates a Query based on sinceUpdated.
|
|
46
|
+
* But if queryPerTable is set for a table - it will override the Query that is ran for that table
|
|
47
|
+
* (and ignore sinceUpdated, sinceUpdatedPerTable, limit, and any other properties that modify the query).
|
|
48
|
+
*/
|
|
49
|
+
queryPerTable?: StringMap<DBQuery>;
|
|
43
50
|
/**
|
|
44
51
|
* Directory path to store dumped files. Will create `${tableName}.ndjson` (or .ndjson.gz if gzip=true) files.
|
|
45
52
|
* All parent directories will be created.
|
|
@@ -67,6 +74,11 @@ export interface DBPipelineBackupOptions extends TransformLogProgressOptions {
|
|
|
67
74
|
* Default mappers will be "passthroughMapper" (pass all data as-is).
|
|
68
75
|
*/
|
|
69
76
|
mapperPerTable?: StringMap<AsyncMapper>;
|
|
77
|
+
/**
|
|
78
|
+
* If defined - it'll use that `logEvery` for that table.
|
|
79
|
+
* Default logEvery is 1000.
|
|
80
|
+
*/
|
|
81
|
+
logEveryPerTable?: StringMap<number>;
|
|
70
82
|
/**
|
|
71
83
|
* You can alter default `transformMapOptions` here.
|
|
72
84
|
*
|
|
@@ -18,7 +18,7 @@ const index_1 = require("../index");
|
|
|
18
18
|
* Optionally you can provide mapperPerTable and @param transformMapOptions (one for all mappers) - it will run for each table.
|
|
19
19
|
*/
|
|
20
20
|
async function dbPipelineBackup(opt) {
|
|
21
|
-
const { db, concurrency = 16, limit = 0, outputDirPath, protectFromOverwrite = false, zlibOptions, mapperPerTable = {}, transformMapOptions, errorMode = js_lib_1.ErrorMode.SUPPRESS, emitSchemaFromDB = false, sortObjects = false, } = opt;
|
|
21
|
+
const { db, concurrency = 16, limit = 0, outputDirPath, protectFromOverwrite = false, zlibOptions, mapperPerTable = {}, queryPerTable = {}, logEveryPerTable = {}, transformMapOptions, errorMode = js_lib_1.ErrorMode.SUPPRESS, emitSchemaFromDB = false, sortObjects = false, } = opt;
|
|
22
22
|
const strict = errorMode !== js_lib_1.ErrorMode.SUPPRESS;
|
|
23
23
|
const gzip = opt.gzip !== false; // default to true
|
|
24
24
|
let { tables } = opt;
|
|
@@ -28,15 +28,22 @@ async function dbPipelineBackup(opt) {
|
|
|
28
28
|
console.log(`${(0, nodejs_lib_1.yellow)(tables.length)} ${(0, nodejs_lib_1.boldWhite)('table(s)')}:\n` + tables.join('\n'));
|
|
29
29
|
const statsPerTable = {};
|
|
30
30
|
await (0, js_lib_1.pMap)(tables, async (table) => {
|
|
31
|
-
const sinceUpdated = opt.sinceUpdatedPerTable?.[table] || opt.sinceUpdated;
|
|
32
|
-
const sinceUpdatedStr = sinceUpdated
|
|
33
|
-
? ' since ' + (0, nodejs_lib_1.grey)((0, js_lib_1.localTime)(sinceUpdated).toPretty())
|
|
34
|
-
: '';
|
|
35
|
-
console.log(`>> ${(0, nodejs_lib_1.grey)(table)}${sinceUpdatedStr}`);
|
|
36
31
|
let q = index_1.DBQuery.create(table).limit(limit);
|
|
32
|
+
const sinceUpdated = opt.sinceUpdatedPerTable?.[table] ?? opt.sinceUpdated;
|
|
37
33
|
if (sinceUpdated) {
|
|
38
34
|
q = q.filter('updated', '>=', sinceUpdated);
|
|
39
35
|
}
|
|
36
|
+
if (queryPerTable[table]) {
|
|
37
|
+
// Override the Query with this Query, completely ingoring any of the other query-related options
|
|
38
|
+
q = queryPerTable[table];
|
|
39
|
+
console.log(`>> ${(0, nodejs_lib_1.grey)(table)} ${q.pretty()}`);
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
const sinceUpdatedStr = sinceUpdated
|
|
43
|
+
? ' since ' + (0, nodejs_lib_1.grey)((0, js_lib_1.localTime)(sinceUpdated).toPretty())
|
|
44
|
+
: '';
|
|
45
|
+
console.log(`>> ${(0, nodejs_lib_1.grey)(table)}${sinceUpdatedStr}`);
|
|
46
|
+
}
|
|
40
47
|
const filePath = `${outputDirPath}/${table}.ndjson` + (gzip ? '.gz' : '');
|
|
41
48
|
const schemaFilePath = `${outputDirPath}/${table}.schema.json`;
|
|
42
49
|
if (protectFromOverwrite && (0, nodejs_lib_1._pathExistsSync)(filePath)) {
|
|
@@ -45,7 +52,7 @@ async function dbPipelineBackup(opt) {
|
|
|
45
52
|
const started = Date.now();
|
|
46
53
|
let rows = 0;
|
|
47
54
|
(0, nodejs_lib_1._ensureFileSync)(filePath);
|
|
48
|
-
console.log(`>> ${
|
|
55
|
+
// console.log(`>> ${grey(filePath)} started...`)
|
|
49
56
|
if (emitSchemaFromDB) {
|
|
50
57
|
const schema = await db.getTableSchema(table);
|
|
51
58
|
await (0, nodejs_lib_1._writeJson)(schemaFilePath, schema, { spaces: 2 });
|
|
@@ -54,8 +61,8 @@ async function dbPipelineBackup(opt) {
|
|
|
54
61
|
await (0, nodejs_lib_1._pipeline)([
|
|
55
62
|
db.streamQuery(q),
|
|
56
63
|
(0, nodejs_lib_1.transformLogProgress)({
|
|
57
|
-
logEvery: 1000,
|
|
58
64
|
...opt,
|
|
65
|
+
logEvery: logEveryPerTable[table] ?? opt.logEvery ?? 1000,
|
|
59
66
|
metric: table,
|
|
60
67
|
}),
|
|
61
68
|
(0, nodejs_lib_1.transformMap)(mapperPerTable[table] || js_lib_1._passthroughMapper, {
|
package/package.json
CHANGED
|
@@ -76,6 +76,13 @@ export interface DBPipelineBackupOptions extends TransformLogProgressOptions {
|
|
|
76
76
|
*/
|
|
77
77
|
sinceUpdatedPerTable?: StringMap<UnixTimestampNumber>
|
|
78
78
|
|
|
79
|
+
/**
|
|
80
|
+
* By default, dbPipelineBackup creates a Query based on sinceUpdated.
|
|
81
|
+
* But if queryPerTable is set for a table - it will override the Query that is ran for that table
|
|
82
|
+
* (and ignore sinceUpdated, sinceUpdatedPerTable, limit, and any other properties that modify the query).
|
|
83
|
+
*/
|
|
84
|
+
queryPerTable?: StringMap<DBQuery>
|
|
85
|
+
|
|
79
86
|
/**
|
|
80
87
|
* Directory path to store dumped files. Will create `${tableName}.ndjson` (or .ndjson.gz if gzip=true) files.
|
|
81
88
|
* All parent directories will be created.
|
|
@@ -108,6 +115,12 @@ export interface DBPipelineBackupOptions extends TransformLogProgressOptions {
|
|
|
108
115
|
*/
|
|
109
116
|
mapperPerTable?: StringMap<AsyncMapper>
|
|
110
117
|
|
|
118
|
+
/**
|
|
119
|
+
* If defined - it'll use that `logEvery` for that table.
|
|
120
|
+
* Default logEvery is 1000.
|
|
121
|
+
*/
|
|
122
|
+
logEveryPerTable?: StringMap<number>
|
|
123
|
+
|
|
111
124
|
/**
|
|
112
125
|
* You can alter default `transformMapOptions` here.
|
|
113
126
|
*
|
|
@@ -153,6 +166,8 @@ export async function dbPipelineBackup(opt: DBPipelineBackupOptions): Promise<ND
|
|
|
153
166
|
protectFromOverwrite = false,
|
|
154
167
|
zlibOptions,
|
|
155
168
|
mapperPerTable = {},
|
|
169
|
+
queryPerTable = {},
|
|
170
|
+
logEveryPerTable = {},
|
|
156
171
|
transformMapOptions,
|
|
157
172
|
errorMode = ErrorMode.SUPPRESS,
|
|
158
173
|
emitSchemaFromDB = false,
|
|
@@ -176,20 +191,25 @@ export async function dbPipelineBackup(opt: DBPipelineBackupOptions): Promise<ND
|
|
|
176
191
|
await pMap(
|
|
177
192
|
tables,
|
|
178
193
|
async table => {
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
const sinceUpdatedStr = sinceUpdated
|
|
182
|
-
? ' since ' + grey(localTime(sinceUpdated).toPretty())
|
|
183
|
-
: ''
|
|
184
|
-
|
|
185
|
-
console.log(`>> ${grey(table)}${sinceUpdatedStr}`)
|
|
186
|
-
|
|
187
|
-
let q = DBQuery.create(table).limit(limit)
|
|
194
|
+
let q = DBQuery.create<any>(table).limit(limit)
|
|
188
195
|
|
|
196
|
+
const sinceUpdated = opt.sinceUpdatedPerTable?.[table] ?? opt.sinceUpdated
|
|
189
197
|
if (sinceUpdated) {
|
|
190
198
|
q = q.filter('updated', '>=', sinceUpdated)
|
|
191
199
|
}
|
|
192
200
|
|
|
201
|
+
if (queryPerTable[table]) {
|
|
202
|
+
// Override the Query with this Query, completely ingoring any of the other query-related options
|
|
203
|
+
q = queryPerTable[table]!
|
|
204
|
+
|
|
205
|
+
console.log(`>> ${grey(table)} ${q.pretty()}`)
|
|
206
|
+
} else {
|
|
207
|
+
const sinceUpdatedStr = sinceUpdated
|
|
208
|
+
? ' since ' + grey(localTime(sinceUpdated).toPretty())
|
|
209
|
+
: ''
|
|
210
|
+
console.log(`>> ${grey(table)}${sinceUpdatedStr}`)
|
|
211
|
+
}
|
|
212
|
+
|
|
193
213
|
const filePath = `${outputDirPath}/${table}.ndjson` + (gzip ? '.gz' : '')
|
|
194
214
|
const schemaFilePath = `${outputDirPath}/${table}.schema.json`
|
|
195
215
|
|
|
@@ -202,7 +222,7 @@ export async function dbPipelineBackup(opt: DBPipelineBackupOptions): Promise<ND
|
|
|
202
222
|
|
|
203
223
|
_ensureFileSync(filePath)
|
|
204
224
|
|
|
205
|
-
console.log(`>> ${grey(filePath)} started...`)
|
|
225
|
+
// console.log(`>> ${grey(filePath)} started...`)
|
|
206
226
|
|
|
207
227
|
if (emitSchemaFromDB) {
|
|
208
228
|
const schema = await db.getTableSchema(table)
|
|
@@ -213,8 +233,8 @@ export async function dbPipelineBackup(opt: DBPipelineBackupOptions): Promise<ND
|
|
|
213
233
|
await _pipeline([
|
|
214
234
|
db.streamQuery(q),
|
|
215
235
|
transformLogProgress({
|
|
216
|
-
logEvery: 1000,
|
|
217
236
|
...opt,
|
|
237
|
+
logEvery: logEveryPerTable[table] ?? opt.logEvery ?? 1000,
|
|
218
238
|
metric: table,
|
|
219
239
|
}),
|
|
220
240
|
transformMap(mapperPerTable[table] || _passthroughMapper, {
|