@tachybase/module-backup 1.6.21 → 1.6.23

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,11 +1,11 @@
1
1
  module.exports = {
2
2
  "react": "18.3.1",
3
- "@tachybase/client": "1.6.21",
4
- "@tego/client": "1.6.11",
3
+ "@tachybase/client": "1.6.23",
4
+ "@tego/client": "1.6.16",
5
5
  "@ant-design/icons": "6.1.0",
6
6
  "antd": "5.22.5",
7
- "@tachybase/schema": "1.6.11",
8
- "@tego/server": "1.6.11",
7
+ "@tachybase/schema": "1.6.16",
8
+ "@tego/server": "1.6.16",
9
9
  "dayjs": "1.11.13",
10
10
  "lodash": "4.17.21",
11
11
  "react-i18next": "16.2.1"
@@ -1 +1 @@
1
- {"name":"@hapi/topo","description":"Topological sorting with grouping support","version":"6.0.2","repository":"git://github.com/hapijs/topo","main":"lib/index.js","types":"lib/index.d.ts","files":["lib"],"keywords":["topological","sort","toposort","topsort"],"eslintConfig":{"extends":["plugin:@hapi/module"]},"dependencies":{"@hapi/hoek":"^11.0.2"},"devDependencies":{"@hapi/code":"^9.0.3","@hapi/eslint-plugin":"*","@hapi/lab":"^25.1.2","@types/node":"^17.0.31","typescript":"~4.6.4"},"scripts":{"test":"lab -a @hapi/code -t 100 -L -Y","test-cov-html":"lab -a @hapi/code -t 100 -L -r html -o coverage.html"},"license":"BSD-3-Clause","_lastModified":"2026-05-22T08:41:29.372Z"}
1
+ {"name":"@hapi/topo","description":"Topological sorting with grouping support","version":"6.0.2","repository":"git://github.com/hapijs/topo","main":"lib/index.js","types":"lib/index.d.ts","files":["lib"],"keywords":["topological","sort","toposort","topsort"],"eslintConfig":{"extends":["plugin:@hapi/module"]},"dependencies":{"@hapi/hoek":"^11.0.2"},"devDependencies":{"@hapi/code":"^9.0.3","@hapi/eslint-plugin":"*","@hapi/lab":"^25.1.2","@types/node":"^17.0.31","typescript":"~4.6.4"},"scripts":{"test":"lab -a @hapi/code -t 100 -L -Y","test-cov-html":"lab -a @hapi/code -t 100 -L -r html -o coverage.html"},"license":"BSD-3-Clause","_lastModified":"2026-07-07T10:16:03.554Z"}
@@ -1 +1 @@
1
- {"name":"archiver","version":"7.0.1","description":"a streaming interface for archive generation","homepage":"https://github.com/archiverjs/node-archiver","author":{"name":"Chris Talkington","url":"http://christalkington.com/"},"repository":{"type":"git","url":"https://github.com/archiverjs/node-archiver.git"},"bugs":{"url":"https://github.com/archiverjs/node-archiver/issues"},"license":"MIT","main":"index.js","files":["index.js","lib"],"engines":{"node":">= 14"},"scripts":{"test":"mocha --reporter dot","bench":"node benchmark/simple/pack-zip.js"},"dependencies":{"archiver-utils":"^5.0.2","async":"^3.2.4","buffer-crc32":"^1.0.0","readable-stream":"^4.0.0","readdir-glob":"^1.1.2","tar-stream":"^3.0.0","zip-stream":"^6.0.1"},"devDependencies":{"archiver-jsdoc-theme":"1.1.3","chai":"4.4.1","jsdoc":"4.0.2","mkdirp":"3.0.1","mocha":"10.3.0","rimraf":"5.0.5","stream-bench":"0.1.2","tar":"6.2.0","yauzl":"3.1.2"},"keywords":["archive","archiver","stream","zip","tar"],"publishConfig":{"registry":"https://registry.npmjs.org/"},"_lastModified":"2026-05-22T08:41:29.270Z"}
1
+ {"name":"archiver","version":"7.0.1","description":"a streaming interface for archive generation","homepage":"https://github.com/archiverjs/node-archiver","author":{"name":"Chris Talkington","url":"http://christalkington.com/"},"repository":{"type":"git","url":"https://github.com/archiverjs/node-archiver.git"},"bugs":{"url":"https://github.com/archiverjs/node-archiver/issues"},"license":"MIT","main":"index.js","files":["index.js","lib"],"engines":{"node":">= 14"},"scripts":{"test":"mocha --reporter dot","bench":"node benchmark/simple/pack-zip.js"},"dependencies":{"archiver-utils":"^5.0.2","async":"^3.2.4","buffer-crc32":"^1.0.0","readable-stream":"^4.0.0","readdir-glob":"^1.1.2","tar-stream":"^3.0.0","zip-stream":"^6.0.1"},"devDependencies":{"archiver-jsdoc-theme":"1.1.3","chai":"4.4.1","jsdoc":"4.0.2","mkdirp":"3.0.1","mocha":"10.3.0","rimraf":"5.0.5","stream-bench":"0.1.2","tar":"6.2.0","yauzl":"3.1.2"},"keywords":["archive","archiver","stream","zip","tar"],"publishConfig":{"registry":"https://registry.npmjs.org/"},"_lastModified":"2026-07-07T10:16:03.452Z"}
@@ -1 +1 @@
1
- {"name":"cron-parser","version":"4.9.0","description":"Node.js library for parsing crontab instructions","main":"lib/parser.js","types":"types/index.d.ts","typesVersions":{"<4.1":{"*":["types/ts3/*"]}},"directories":{"test":"test"},"scripts":{"test:tsd":"tsd","test:unit":"TZ=UTC tap ./test/*.js","test:cover":"TZ=UTC tap --coverage-report=html ./test/*.js","lint":"eslint .","lint:fix":"eslint --fix .","test":"npm run lint && npm run test:unit && npm run test:tsd"},"repository":{"type":"git","url":"https://github.com/harrisiirak/cron-parser.git"},"keywords":["cron","crontab","parser"],"author":"Harri Siirak","contributors":["Nicholas Clawson","Daniel Prentis <daniel@salsitasoft.com>","Renault John Lecoultre","Richard Astbury <richard.astbury@gmail.com>","Meaglin Wasabi <Meaglin.wasabi@gmail.com>","Mike Kusold <hello@mikekusold.com>","Alex Kit <alex.kit@atmajs.com>","Santiago Gimeno <santiago.gimeno@gmail.com>","Daniel <darc.tec@gmail.com>","Christian Steininger <christian.steininger.cs@gmail.com>","Mykola Piskovyi <m.piskovyi@gmail.com>","Brian Vaughn <brian.david.vaughn@gmail.com>","Nicholas Clawson <nickclaw@gmail.com>","Yasuhiroki <yasuhiroki.duck@gmail.com>","Nicholas Clawson <nickclaw@gmail.com>","Brendan Warkentin <faazshift@gmail.com>","Charlie Fish <fishcharlie.code@gmail.com>","Ian Graves <ian+diskimage@iangrav.es>","Andy Thompson <me@andytson.com>","Regev Brody <regevbr@gmail.com>"],"license":"MIT","dependencies":{"luxon":"^3.2.1"},"devDependencies":{"eslint":"^8.27.0","sinon":"^15.0.1","tap":"^16.3.3","tsd":"^0.26.0"},"engines":{"node":">=12.0.0"},"browser":{"fs":false},"tap":{"check-coverage":false},"tsd":{"directory":"test","compilerOptions":{"lib":["es2017","dom"]}},"files":["lib","types","LICENSE","README.md"],"_lastModified":"2026-05-22T08:41:30.503Z"}
1
+ {"name":"cron-parser","version":"4.9.0","description":"Node.js library for parsing crontab instructions","main":"lib/parser.js","types":"types/index.d.ts","typesVersions":{"<4.1":{"*":["types/ts3/*"]}},"directories":{"test":"test"},"scripts":{"test:tsd":"tsd","test:unit":"TZ=UTC tap ./test/*.js","test:cover":"TZ=UTC tap --coverage-report=html ./test/*.js","lint":"eslint .","lint:fix":"eslint --fix .","test":"npm run lint && npm run test:unit && npm run test:tsd"},"repository":{"type":"git","url":"https://github.com/harrisiirak/cron-parser.git"},"keywords":["cron","crontab","parser"],"author":"Harri Siirak","contributors":["Nicholas Clawson","Daniel Prentis <daniel@salsitasoft.com>","Renault John Lecoultre","Richard Astbury <richard.astbury@gmail.com>","Meaglin Wasabi <Meaglin.wasabi@gmail.com>","Mike Kusold <hello@mikekusold.com>","Alex Kit <alex.kit@atmajs.com>","Santiago Gimeno <santiago.gimeno@gmail.com>","Daniel <darc.tec@gmail.com>","Christian Steininger <christian.steininger.cs@gmail.com>","Mykola Piskovyi <m.piskovyi@gmail.com>","Brian Vaughn <brian.david.vaughn@gmail.com>","Nicholas Clawson <nickclaw@gmail.com>","Yasuhiroki <yasuhiroki.duck@gmail.com>","Nicholas Clawson <nickclaw@gmail.com>","Brendan Warkentin <faazshift@gmail.com>","Charlie Fish <fishcharlie.code@gmail.com>","Ian Graves <ian+diskimage@iangrav.es>","Andy Thompson <me@andytson.com>","Regev Brody <regevbr@gmail.com>"],"license":"MIT","dependencies":{"luxon":"^3.2.1"},"devDependencies":{"eslint":"^8.27.0","sinon":"^15.0.1","tap":"^16.3.3","tsd":"^0.26.0"},"engines":{"node":">=12.0.0"},"browser":{"fs":false},"tap":{"check-coverage":false},"tsd":{"directory":"test","compilerOptions":{"lib":["es2017","dom"]}},"files":["lib","types","LICENSE","README.md"],"_lastModified":"2026-07-07T10:16:04.242Z"}
@@ -1 +1 @@
1
- {"name":"semver","version":"7.7.2","description":"The semantic version parser used by npm.","main":"index.js","scripts":{"test":"tap","snap":"tap","lint":"npm run eslint","postlint":"template-oss-check","lintfix":"npm run eslint -- --fix","posttest":"npm run lint","template-oss-apply":"template-oss-apply --force","eslint":"eslint \"**/*.{js,cjs,ts,mjs,jsx,tsx}\""},"devDependencies":{"@npmcli/eslint-config":"^5.0.0","@npmcli/template-oss":"4.24.3","benchmark":"^2.1.4","tap":"^16.0.0"},"license":"ISC","repository":{"type":"git","url":"git+https://github.com/npm/node-semver.git"},"bin":{"semver":"bin/semver.js"},"files":["bin/","lib/","classes/","functions/","internal/","ranges/","index.js","preload.js","range.bnf"],"tap":{"timeout":30,"coverage-map":"map.js","nyc-arg":["--exclude","tap-snapshots/**"]},"engines":{"node":">=10"},"author":"GitHub Inc.","templateOSS":{"//@npmcli/template-oss":"This file is partially managed by @npmcli/template-oss. Edits may be overwritten.","version":"4.24.3","engines":">=10","distPaths":["classes/","functions/","internal/","ranges/","index.js","preload.js","range.bnf"],"allowPaths":["/classes/","/functions/","/internal/","/ranges/","/index.js","/preload.js","/range.bnf","/benchmarks"],"publish":"true"},"_lastModified":"2026-05-22T08:41:29.876Z"}
1
+ {"name":"semver","version":"7.7.2","description":"The semantic version parser used by npm.","main":"index.js","scripts":{"test":"tap","snap":"tap","lint":"npm run eslint","postlint":"template-oss-check","lintfix":"npm run eslint -- --fix","posttest":"npm run lint","template-oss-apply":"template-oss-apply --force","eslint":"eslint \"**/*.{js,cjs,ts,mjs,jsx,tsx}\""},"devDependencies":{"@npmcli/eslint-config":"^5.0.0","@npmcli/template-oss":"4.24.3","benchmark":"^2.1.4","tap":"^16.0.0"},"license":"ISC","repository":{"type":"git","url":"git+https://github.com/npm/node-semver.git"},"bin":{"semver":"bin/semver.js"},"files":["bin/","lib/","classes/","functions/","internal/","ranges/","index.js","preload.js","range.bnf"],"tap":{"timeout":30,"coverage-map":"map.js","nyc-arg":["--exclude","tap-snapshots/**"]},"engines":{"node":">=10"},"author":"GitHub Inc.","templateOSS":{"//@npmcli/template-oss":"This file is partially managed by @npmcli/template-oss. Edits may be overwritten.","version":"4.24.3","engines":">=10","distPaths":["classes/","functions/","internal/","ranges/","index.js","preload.js","range.bnf"],"allowPaths":["/classes/","/functions/","/internal/","/ranges/","/index.js","/preload.js","/range.bnf","/benchmarks"],"publish":"true"},"_lastModified":"2026-07-07T10:16:03.813Z"}
@@ -1 +1 @@
1
- {"name":"yauzl","version":"3.2.0","description":"yet another unzip library for node","engines":{"node":">=12"},"main":"index.js","scripts":{"test":"node test/test.js"},"repository":{"type":"git","url":"git+https://github.com/thejoshwolfe/yauzl.git"},"keywords":["unzip","zip","stream","archive","file"],"author":"Josh Wolfe <thejoshwolfe@gmail.com>","license":"MIT","bugs":{"url":"https://github.com/thejoshwolfe/yauzl/issues"},"homepage":"https://github.com/thejoshwolfe/yauzl","dependencies":{"buffer-crc32":"~0.2.3","pend":"~1.2.0"},"devDependencies":{"bl":"^6.0.11"},"files":["fd-slicer.js","index.js"],"_lastModified":"2026-05-22T08:41:30.058Z"}
1
+ {"name":"yauzl","version":"3.2.0","description":"yet another unzip library for node","engines":{"node":">=12"},"main":"index.js","scripts":{"test":"node test/test.js"},"repository":{"type":"git","url":"git+https://github.com/thejoshwolfe/yauzl.git"},"keywords":["unzip","zip","stream","archive","file"],"author":"Josh Wolfe <thejoshwolfe@gmail.com>","license":"MIT","bugs":{"url":"https://github.com/thejoshwolfe/yauzl/issues"},"homepage":"https://github.com/thejoshwolfe/yauzl","dependencies":{"buffer-crc32":"~0.2.3","pend":"~1.2.0"},"devDependencies":{"bl":"^6.0.11"},"files":["fd-slicer.js","index.js"],"_lastModified":"2026-07-07T10:16:03.983Z"}
@@ -61,9 +61,10 @@ export declare class Dumper extends AppMigrator {
61
61
  backUpFilePath(fileName: string, appName?: string): string;
62
62
  lockFilePath(fileName: string, appName?: string): string;
63
63
  writeLockFile(fileName: string, appName?: string): Promise<string>;
64
- cleanLockFile(fileName: string, appName: string): Promise<void>;
64
+ cleanLockFile(fileName: string, appName?: string): Promise<void>;
65
65
  getLockFile(appName: string): Promise<string>;
66
- runDumpTask(options: DumpOptions): Promise<void>;
66
+ startDumpTask(options: DumpOptions): string;
67
+ runDumpTask(options: DumpOptions): Promise<string>;
67
68
  dumpableCollectionsGroupByGroup(): Promise<{
68
69
  [x: string]: Pick<any, string>[];
69
70
  }>;
@@ -65,9 +65,11 @@ const _Dumper = class _Dumper extends import_app_migrator.AppMigrator {
65
65
  return this.dumpTasks.get(taskId);
66
66
  }
67
67
  static async getFileStatus(filePath, appName) {
68
- const lockFile = filePath + ".lock";
69
- const progressFile = filePath + ".progress";
70
- const fileName = import_node_path.default.basename(filePath);
68
+ const isLockFilePath = import_node_path.default.extname(filePath) === ".lock";
69
+ const backupFilePath = isLockFilePath ? filePath.slice(0, -".lock".length) : filePath;
70
+ const lockFile = isLockFilePath ? filePath : filePath + ".lock";
71
+ const progressFile = backupFilePath + ".progress";
72
+ const fileName = import_node_path.default.basename(backupFilePath);
71
73
  return import_node_fs.default.promises.stat(lockFile).then(async (lockFileStat) => {
72
74
  if (lockFileStat.isFile()) {
73
75
  if (lockFileStat.ctime.getTime() < Date.now() - 2 * 60 * 60 * 1e3) {
@@ -96,7 +98,7 @@ const _Dumper = class _Dumper extends import_app_migrator.AppMigrator {
96
98
  }
97
99
  }).catch((error) => {
98
100
  if (error.code === "ENOENT") {
99
- return import_node_fs.default.promises.stat(filePath).then((backupFileStat) => {
101
+ return import_node_fs.default.promises.stat(backupFilePath).then((backupFileStat) => {
100
102
  if (backupFileStat.isFile()) {
101
103
  return {
102
104
  name: fileName,
@@ -220,13 +222,30 @@ const _Dumper = class _Dumper extends import_app_migrator.AppMigrator {
220
222
  await this.writeLockFile(backupFileName, appName);
221
223
  return backupFileName;
222
224
  }
223
- async runDumpTask(options) {
224
- await this.dump({
225
+ startDumpTask(options) {
226
+ const taskId = options.fileName || _Dumper.generateFileName();
227
+ const taskPromise = this.dump({
225
228
  groups: options.groups,
226
- fileName: options.fileName,
229
+ fileName: taskId,
227
230
  appName: options.appName,
228
231
  userId: options.userId
229
232
  });
233
+ _Dumper.dumpTasks.set(taskId, taskPromise);
234
+ taskPromise.then(
235
+ () => {
236
+ _Dumper.dumpTasks.delete(taskId);
237
+ },
238
+ () => {
239
+ _Dumper.dumpTasks.delete(taskId);
240
+ }
241
+ );
242
+ return taskId;
243
+ }
244
+ async runDumpTask(options) {
245
+ const taskId = this.startDumpTask(options);
246
+ const taskPromise = _Dumper.getTaskPromise(taskId);
247
+ await taskPromise;
248
+ return taskId;
230
249
  }
231
250
  async dumpableCollectionsGroupByGroup() {
232
251
  return (0, import_lodash.default)(await this.dumpableCollections()).map((c) => import_lodash.default.pick(c, ["name", "group", "origin", "title", "isView", "inherits"])).groupBy("group").mapValues((items) => import_lodash.default.sortBy(items, (item) => item.name)).value();
@@ -60,7 +60,7 @@ export declare class ProgressManager {
60
60
  /**
61
61
  * 清理进度文件
62
62
  */
63
- cleanProgressFile(fileName: string, appName: string): Promise<void>;
63
+ cleanProgressFile(fileName: string, appName?: string): Promise<void>;
64
64
  /**
65
65
  * 创建进度跟踪器
66
66
  */
@@ -134,6 +134,7 @@ const _ProgressManager = class _ProgressManager {
134
134
  */
135
135
  async writeProgress(fileName, progress, appName, userId) {
136
136
  const filePath = this.progressFilePath(fileName, appName);
137
+ await import_promises.default.mkdir(import_node_path.default.dirname(filePath), { recursive: true });
137
138
  await import_promises.default.writeFile(filePath, JSON.stringify(progress), "utf8");
138
139
  this.pushProgressViaWebSocket(fileName, progress, userId, appName);
139
140
  }
@@ -182,8 +182,9 @@ var backup_files_default = {
182
182
  let useWorker = data.method === "worker" || data.method === "priority" && ((_c = app.worker) == null ? void 0 : _c.available);
183
183
  const dumper = new import_dumper.Dumper(ctx.tego);
184
184
  const taskId = await dumper.getLockFile(ctx.tego.name);
185
+ let taskPromise;
185
186
  if (useWorker) {
186
- app.worker.callPluginMethod({
187
+ taskPromise = app.worker.callPluginMethod({
187
188
  plugin: import_server2.default,
188
189
  method: "workerCreateBackUp",
189
190
  params: {
@@ -194,28 +195,33 @@ var backup_files_default = {
194
195
  },
195
196
  // 目前限制方法并发为1
196
197
  concurrency: 1
197
- }).then((res) => {
198
- app.noticeManager.notify("backup", { level: "info", msg: ctx.t("Done", { ns: "backup" }) });
199
- }).catch((error) => {
200
- app.noticeManager.notify("backup", { level: "error", msg: error.message });
201
- }).finally(() => {
202
- dumper.cleanLockFile(taskId, ctx.tego.name);
203
198
  });
204
199
  } else {
205
200
  const plugin = app.pm.get(import_server2.default);
206
- plugin.workerCreateBackUp({
201
+ taskPromise = plugin.workerCreateBackUp({
207
202
  dataTypes: data.dataTypes,
208
203
  appName: ctx.tego.name,
209
204
  filename: taskId,
210
205
  userId
211
- }).then((res) => {
212
- app.noticeManager.notify("backup", { level: "info", msg: ctx.t("Done", { ns: "backup" }) });
213
- }).catch((error) => {
214
- app.noticeManager.notify("backup", { level: "error", msg: error.message });
215
- }).finally(() => {
216
- dumper.cleanLockFile(taskId, ctx.tego.name);
217
206
  });
218
207
  }
208
+ import_dumper.Dumper.dumpTasks.set(taskId, taskPromise);
209
+ void (async () => {
210
+ try {
211
+ await taskPromise;
212
+ app.noticeManager.notify("backup", { level: "info", msg: ctx.t("Done", { ns: "backup" }) });
213
+ } catch (error) {
214
+ const msg = error instanceof Error ? error.message : error ? String(error) : ctx.t("Backup failed", { ns: "backup" });
215
+ app.noticeManager.notify("backup", { level: "error", msg });
216
+ } finally {
217
+ import_dumper.Dumper.dumpTasks.delete(taskId);
218
+ try {
219
+ await dumper.cleanLockFile(taskId, ctx.tego.name);
220
+ } catch (error) {
221
+ app.logger.error("clean backup lock file error", error);
222
+ }
223
+ }
224
+ })();
219
225
  ctx.body = {
220
226
  key: taskId
221
227
  };
@@ -28,9 +28,9 @@ export declare class Restorer extends AppMigrator {
28
28
  insert?: boolean;
29
29
  clear?: boolean;
30
30
  rowCondition?: (row: any) => boolean;
31
- }): Promise<void>;
31
+ }): Promise<void | string>;
32
32
  importDb(options: RestoreOptions): Promise<void>;
33
- insertMetaRows({ rows, collectionName, columns, fieldAttributes, rawAttributes, addSchemaTableName, options }: {
33
+ insertMetaRows({ rows, collectionName, columns, fieldAttributes, rawAttributes, addSchemaTableName, options, }: {
34
34
  rows: any;
35
35
  collectionName: any;
36
36
  columns: any;
@@ -38,6 +38,6 @@ export declare class Restorer extends AppMigrator {
38
38
  rawAttributes: any;
39
39
  addSchemaTableName: any;
40
40
  options: any;
41
- }): Promise<any>;
41
+ }): Promise<void | string>;
42
42
  }
43
43
  export {};
@@ -206,7 +206,7 @@ class Restorer extends import_app_migrator.AppMigrator {
206
206
  await import_promises.default.stat(collectionMetaPath);
207
207
  } catch (e) {
208
208
  app.logger.info(`${collectionName} has no meta`);
209
- return;
209
+ return options.insert === false ? "" : void 0;
210
210
  }
211
211
  const metaContent = await import_promises.default.readFile(collectionMetaPath, "utf8");
212
212
  const meta = JSON.parse(metaContent);
@@ -217,7 +217,7 @@ class Restorer extends import_app_migrator.AppMigrator {
217
217
  const columns = meta["columns"];
218
218
  if (columns.length === 0) {
219
219
  app.logger.info(`${collectionName} has no columns`);
220
- return;
220
+ return options.insert === false ? "" : void 0;
221
221
  }
222
222
  const fieldAttributes = import_lodash.default.mapValues(meta.attributes, (attr) => {
223
223
  if (attr.isCollectionField) {
@@ -264,11 +264,12 @@ class Restorer extends import_app_migrator.AppMigrator {
264
264
  }
265
265
  const batchSize = 1e3;
266
266
  let batch = [];
267
+ const sqlResults = [];
267
268
  let allLength = 0;
268
269
  await (0, import_utils.readEveryLines)(collectionDataPath, async (line) => {
269
270
  batch.push(line);
270
271
  if (batch.length >= batchSize) {
271
- await this.insertMetaRows({
272
+ const result = await this.insertMetaRows({
272
273
  rows: batch,
273
274
  collectionName,
274
275
  columns,
@@ -277,12 +278,15 @@ class Restorer extends import_app_migrator.AppMigrator {
277
278
  addSchemaTableName,
278
279
  options
279
280
  });
281
+ if (result) {
282
+ sqlResults.push(result);
283
+ }
280
284
  allLength += batchSize;
281
285
  batch = [];
282
286
  }
283
287
  });
284
- if (!this.importedCollections.includes(collectionName)) {
285
- await this.insertMetaRows({
288
+ if (batch.length > 0) {
289
+ const result = await this.insertMetaRows({
286
290
  rows: batch,
287
291
  collectionName,
288
292
  columns,
@@ -291,8 +295,14 @@ class Restorer extends import_app_migrator.AppMigrator {
291
295
  addSchemaTableName,
292
296
  options
293
297
  });
298
+ if (result) {
299
+ sqlResults.push(result);
300
+ }
294
301
  allLength += batch.length;
295
302
  }
303
+ if (options.insert === false) {
304
+ return sqlResults.join("\n");
305
+ }
296
306
  app.logger.info(`${collectionName} imported with ${allLength} rows`);
297
307
  if (meta.autoIncrement) {
298
308
  const queryInterface = app.db.queryInterface;
@@ -306,7 +316,9 @@ class Restorer extends import_app_migrator.AppMigrator {
306
316
  currentVal: meta.autoIncrement.currentVal
307
317
  });
308
318
  }
309
- this.importedCollections.push(collectionName);
319
+ if (!this.importedCollections.includes(collectionName)) {
320
+ this.importedCollections.push(collectionName);
321
+ }
310
322
  }
311
323
  async importDb(options) {
312
324
  const sqlContentPath = import_node_path.default.resolve(this.workDir, "sql-content.json");
@@ -336,13 +348,20 @@ class Restorer extends import_app_migrator.AppMigrator {
336
348
  }
337
349
  }
338
350
  }
339
- async insertMetaRows({ rows, collectionName, columns, fieldAttributes, rawAttributes, addSchemaTableName, options }) {
351
+ async insertMetaRows({
352
+ rows,
353
+ collectionName,
354
+ columns,
355
+ fieldAttributes,
356
+ rawAttributes,
357
+ addSchemaTableName,
358
+ options
359
+ }) {
340
360
  const app = this.app;
341
361
  const db = app.db;
342
362
  if (rows.length === 0) {
343
363
  app.logger.info(`${collectionName} has no data to import`);
344
- this.importedCollections.push(collectionName);
345
- return;
364
+ return options.insert === false ? "" : void 0;
346
365
  }
347
366
  const rowsWithMeta = rows.map(
348
367
  (row) => JSON.parse(row).map((val, index) => [columns[index], val]).reduce((carry, [column, val]) => {
@@ -358,8 +377,7 @@ class Restorer extends import_app_migrator.AppMigrator {
358
377
  });
359
378
  if (rowsWithMeta.length === 0) {
360
379
  app.logger.info(`${collectionName} has no data to import`);
361
- this.importedCollections.push(collectionName);
362
- return;
380
+ return options.insert === false ? "" : void 0;
363
381
  }
364
382
  const insertGeneratorAttributes = import_lodash.default.mapKeys(rawAttributes, (value, key) => {
365
383
  return value.field;
@@ -272,12 +272,17 @@ const _PluginBackupRestoreServer = class _PluginBackupRestoreServer extends impo
272
272
  this.schedule(cronJob, null, false);
273
273
  }
274
274
  async workerCreateBackUp(data) {
275
- await new import_dumper.Dumper(this.app).runDumpTask({
275
+ const taskId = new import_dumper.Dumper(this.app).startDumpTask({
276
276
  groups: new Set(data.dataTypes),
277
277
  appName: data.appName,
278
278
  fileName: data.filename,
279
279
  userId: data.userId
280
280
  });
281
+ const taskPromise = import_dumper.Dumper.getTaskPromise(taskId);
282
+ if (!taskPromise) {
283
+ throw new Error(`Backup task ${taskId} is not tracked for app ${data.appName}`);
284
+ }
285
+ await taskPromise;
281
286
  }
282
287
  };
283
288
  _PluginBackupRestoreServer.inspectFields = ["repeat", "enabled"];
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tachybase/module-backup",
3
3
  "displayName": "App backup & restore",
4
- "version": "1.6.21",
4
+ "version": "1.6.23",
5
5
  "description": "Backup and restore applications for scenarios such as application replication, migration, and upgrades.",
6
6
  "keywords": [
7
7
  "System management"
@@ -20,10 +20,10 @@
20
20
  "devDependencies": {
21
21
  "@ant-design/icons": "^6.1.0",
22
22
  "@hapi/topo": "^6.0.2",
23
- "@tachybase/schema": "1.6.11",
24
- "@tachybase/test": "1.6.11",
25
- "@tego/client": "1.6.11",
26
- "@tego/server": "1.6.11",
23
+ "@tachybase/schema": "1.6.16",
24
+ "@tachybase/test": "1.6.16",
25
+ "@tego/client": "1.6.16",
26
+ "@tego/server": "1.6.16",
27
27
  "@types/archiver": "^5.3.4",
28
28
  "@types/file-saver": "^2.0.7",
29
29
  "@types/lodash": "^4.17.20",
@@ -43,8 +43,11 @@
43
43
  "semver": "7.7.2",
44
44
  "tar": "^7.4.3",
45
45
  "yauzl": "^3.2.0",
46
- "@tachybase/client": "1.6.21",
47
- "@tachybase/module-worker-thread": "1.6.21"
46
+ "@tachybase/client": "1.6.23",
47
+ "@tachybase/module-worker-thread": "1.6.23",
48
+ "@tachybase/plugin-audit-logs": "1.6.23",
49
+ "@tachybase/plugin-block-map": "1.6.23",
50
+ "@tachybase/plugin-field-sequence": "1.6.23"
48
51
  },
49
52
  "description.zh-CN": "备份和还原应用,可用于应用的复制、迁移、升级等场景。",
50
53
  "displayName.zh-CN": "应用的备份与还原",