@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?: number;
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?: Record<string, AsyncMapper>;
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, sinceUpdated, 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;
25
- const sinceUpdatedStr = sinceUpdated ? ' since ' + (0, nodejs_lib_1.grey)((0, js_lib_1.localTime)(sinceUpdated).toPretty()) : '';
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(`>> ${(0, nodejs_lib_1.grey)(filePath)} started...`);
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
@@ -40,7 +40,7 @@
40
40
  "engines": {
41
41
  "node": ">=18.12"
42
42
  },
43
- "version": "8.57.0",
43
+ "version": "8.59.0",
44
44
  "description": "Lowest Common Denominator API to supported Databases",
45
45
  "keywords": [
46
46
  "db",
@@ -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?: number
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?: Record<string, AsyncMapper>
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
- const sinceUpdatedStr = sinceUpdated ? ' since ' + grey(localTime(sinceUpdated).toPretty()) : ''
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, {