@naturalcycles/db-lib 8.57.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.
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
import { ZlibOptions } from 'node:zlib';
|
|
3
|
-
import { AsyncMapper, ErrorMode } from '@naturalcycles/js-lib';
|
|
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.
|
|
@@ -33,10 +34,19 @@ export interface DBPipelineBackupOptions extends TransformLogProgressOptions {
|
|
|
33
34
|
limit?: number;
|
|
34
35
|
/**
|
|
35
36
|
* If set - will do "incremental backup" (not full), only for entities that updated >= `sinceUpdated`
|
|
36
|
-
*
|
|
37
|
-
* @default undefined
|
|
38
37
|
*/
|
|
39
|
-
sinceUpdated?:
|
|
38
|
+
sinceUpdated?: UnixTimestampNumber;
|
|
39
|
+
/**
|
|
40
|
+
* Map for each table a `sinceUpdated` timestamp, or `undefined`.
|
|
41
|
+
* If set - will do "incremental backup" (not full), only for entities that updated >= `sinceUpdated` (on a per table basis)
|
|
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>;
|
|
40
50
|
/**
|
|
41
51
|
* Directory path to store dumped files. Will create `${tableName}.ndjson` (or .ndjson.gz if gzip=true) files.
|
|
42
52
|
* All parent directories will be created.
|
|
@@ -63,7 +73,12 @@ export interface DBPipelineBackupOptions extends TransformLogProgressOptions {
|
|
|
63
73
|
* @default `{}`
|
|
64
74
|
* Default mappers will be "passthroughMapper" (pass all data as-is).
|
|
65
75
|
*/
|
|
66
|
-
mapperPerTable?:
|
|
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>;
|
|
67
82
|
/**
|
|
68
83
|
* You can alter default `transformMapOptions` here.
|
|
69
84
|
*
|
|
@@ -18,21 +18,32 @@ 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,
|
|
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;
|
|
25
|
-
|
|
26
|
-
console.log(`>> ${(0, nodejs_lib_1.dimWhite)('dbPipelineBackup')} started in ${(0, nodejs_lib_1.grey)(outputDirPath)}...${sinceUpdatedStr}`);
|
|
25
|
+
console.log(`>> ${(0, nodejs_lib_1.dimWhite)('dbPipelineBackup')} started in ${(0, nodejs_lib_1.grey)(outputDirPath)}...`);
|
|
27
26
|
(0, nodejs_lib_1._ensureDirSync)(outputDirPath);
|
|
28
27
|
tables ||= await db.getTables();
|
|
29
28
|
console.log(`${(0, nodejs_lib_1.yellow)(tables.length)} ${(0, nodejs_lib_1.boldWhite)('table(s)')}:\n` + tables.join('\n'));
|
|
30
29
|
const statsPerTable = {};
|
|
31
30
|
await (0, js_lib_1.pMap)(tables, async (table) => {
|
|
32
31
|
let q = index_1.DBQuery.create(table).limit(limit);
|
|
32
|
+
const sinceUpdated = opt.sinceUpdatedPerTable?.[table] ?? opt.sinceUpdated;
|
|
33
33
|
if (sinceUpdated) {
|
|
34
34
|
q = q.filter('updated', '>=', sinceUpdated);
|
|
35
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
|
+
}
|
|
36
47
|
const filePath = `${outputDirPath}/${table}.ndjson` + (gzip ? '.gz' : '');
|
|
37
48
|
const schemaFilePath = `${outputDirPath}/${table}.schema.json`;
|
|
38
49
|
if (protectFromOverwrite && (0, nodejs_lib_1._pathExistsSync)(filePath)) {
|
|
@@ -41,7 +52,7 @@ async function dbPipelineBackup(opt) {
|
|
|
41
52
|
const started = Date.now();
|
|
42
53
|
let rows = 0;
|
|
43
54
|
(0, nodejs_lib_1._ensureFileSync)(filePath);
|
|
44
|
-
console.log(`>> ${
|
|
55
|
+
// console.log(`>> ${grey(filePath)} started...`)
|
|
45
56
|
if (emitSchemaFromDB) {
|
|
46
57
|
const schema = await db.getTableSchema(table);
|
|
47
58
|
await (0, nodejs_lib_1._writeJson)(schemaFilePath, schema, { spaces: 2 });
|
|
@@ -50,8 +61,8 @@ async function dbPipelineBackup(opt) {
|
|
|
50
61
|
await (0, nodejs_lib_1._pipeline)([
|
|
51
62
|
db.streamQuery(q),
|
|
52
63
|
(0, nodejs_lib_1.transformLogProgress)({
|
|
53
|
-
logEvery: 1000,
|
|
54
64
|
...opt,
|
|
65
|
+
logEvery: logEveryPerTable[table] ?? opt.logEvery ?? 1000,
|
|
55
66
|
metric: table,
|
|
56
67
|
}),
|
|
57
68
|
(0, nodejs_lib_1.transformMap)(mapperPerTable[table] || js_lib_1._passthroughMapper, {
|
package/package.json
CHANGED
|
@@ -8,6 +8,8 @@ import {
|
|
|
8
8
|
pMap,
|
|
9
9
|
_passthroughMapper,
|
|
10
10
|
localTime,
|
|
11
|
+
UnixTimestampNumber,
|
|
12
|
+
StringMap,
|
|
11
13
|
} from '@naturalcycles/js-lib'
|
|
12
14
|
import {
|
|
13
15
|
NDJsonStats,
|
|
@@ -65,10 +67,21 @@ export interface DBPipelineBackupOptions extends TransformLogProgressOptions {
|
|
|
65
67
|
|
|
66
68
|
/**
|
|
67
69
|
* If set - will do "incremental backup" (not full), only for entities that updated >= `sinceUpdated`
|
|
68
|
-
*
|
|
69
|
-
* @default undefined
|
|
70
70
|
*/
|
|
71
|
-
sinceUpdated?:
|
|
71
|
+
sinceUpdated?: UnixTimestampNumber
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Map for each table a `sinceUpdated` timestamp, or `undefined`.
|
|
75
|
+
* If set - will do "incremental backup" (not full), only for entities that updated >= `sinceUpdated` (on a per table basis)
|
|
76
|
+
*/
|
|
77
|
+
sinceUpdatedPerTable?: StringMap<UnixTimestampNumber>
|
|
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>
|
|
72
85
|
|
|
73
86
|
/**
|
|
74
87
|
* Directory path to store dumped files. Will create `${tableName}.ndjson` (or .ndjson.gz if gzip=true) files.
|
|
@@ -100,7 +113,13 @@ export interface DBPipelineBackupOptions extends TransformLogProgressOptions {
|
|
|
100
113
|
* @default `{}`
|
|
101
114
|
* Default mappers will be "passthroughMapper" (pass all data as-is).
|
|
102
115
|
*/
|
|
103
|
-
mapperPerTable?:
|
|
116
|
+
mapperPerTable?: StringMap<AsyncMapper>
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* If defined - it'll use that `logEvery` for that table.
|
|
120
|
+
* Default logEvery is 1000.
|
|
121
|
+
*/
|
|
122
|
+
logEveryPerTable?: StringMap<number>
|
|
104
123
|
|
|
105
124
|
/**
|
|
106
125
|
* You can alter default `transformMapOptions` here.
|
|
@@ -143,11 +162,12 @@ export async function dbPipelineBackup(opt: DBPipelineBackupOptions): Promise<ND
|
|
|
143
162
|
db,
|
|
144
163
|
concurrency = 16,
|
|
145
164
|
limit = 0,
|
|
146
|
-
sinceUpdated,
|
|
147
165
|
outputDirPath,
|
|
148
166
|
protectFromOverwrite = false,
|
|
149
167
|
zlibOptions,
|
|
150
168
|
mapperPerTable = {},
|
|
169
|
+
queryPerTable = {},
|
|
170
|
+
logEveryPerTable = {},
|
|
151
171
|
transformMapOptions,
|
|
152
172
|
errorMode = ErrorMode.SUPPRESS,
|
|
153
173
|
emitSchemaFromDB = false,
|
|
@@ -158,11 +178,7 @@ export async function dbPipelineBackup(opt: DBPipelineBackupOptions): Promise<ND
|
|
|
158
178
|
|
|
159
179
|
let { tables } = opt
|
|
160
180
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
console.log(
|
|
164
|
-
`>> ${dimWhite('dbPipelineBackup')} started in ${grey(outputDirPath)}...${sinceUpdatedStr}`,
|
|
165
|
-
)
|
|
181
|
+
console.log(`>> ${dimWhite('dbPipelineBackup')} started in ${grey(outputDirPath)}...`)
|
|
166
182
|
|
|
167
183
|
_ensureDirSync(outputDirPath)
|
|
168
184
|
|
|
@@ -175,12 +191,25 @@ export async function dbPipelineBackup(opt: DBPipelineBackupOptions): Promise<ND
|
|
|
175
191
|
await pMap(
|
|
176
192
|
tables,
|
|
177
193
|
async table => {
|
|
178
|
-
let q = DBQuery.create(table).limit(limit)
|
|
194
|
+
let q = DBQuery.create<any>(table).limit(limit)
|
|
179
195
|
|
|
196
|
+
const sinceUpdated = opt.sinceUpdatedPerTable?.[table] ?? opt.sinceUpdated
|
|
180
197
|
if (sinceUpdated) {
|
|
181
198
|
q = q.filter('updated', '>=', sinceUpdated)
|
|
182
199
|
}
|
|
183
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
|
+
|
|
184
213
|
const filePath = `${outputDirPath}/${table}.ndjson` + (gzip ? '.gz' : '')
|
|
185
214
|
const schemaFilePath = `${outputDirPath}/${table}.schema.json`
|
|
186
215
|
|
|
@@ -193,7 +222,7 @@ export async function dbPipelineBackup(opt: DBPipelineBackupOptions): Promise<ND
|
|
|
193
222
|
|
|
194
223
|
_ensureFileSync(filePath)
|
|
195
224
|
|
|
196
|
-
console.log(`>> ${grey(filePath)} started...`)
|
|
225
|
+
// console.log(`>> ${grey(filePath)} started...`)
|
|
197
226
|
|
|
198
227
|
if (emitSchemaFromDB) {
|
|
199
228
|
const schema = await db.getTableSchema(table)
|
|
@@ -204,8 +233,8 @@ export async function dbPipelineBackup(opt: DBPipelineBackupOptions): Promise<ND
|
|
|
204
233
|
await _pipeline([
|
|
205
234
|
db.streamQuery(q),
|
|
206
235
|
transformLogProgress({
|
|
207
|
-
logEvery: 1000,
|
|
208
236
|
...opt,
|
|
237
|
+
logEvery: logEveryPerTable[table] ?? opt.logEvery ?? 1000,
|
|
209
238
|
metric: table,
|
|
210
239
|
}),
|
|
211
240
|
transformMap(mapperPerTable[table] || _passthroughMapper, {
|