@tachybase/module-backup 1.6.20 → 1.6.22
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/externalVersion.js +4 -4
- package/dist/node_modules/@hapi/topo/package.json +1 -1
- package/dist/node_modules/archiver/package.json +1 -1
- package/dist/node_modules/cron-parser/package.json +1 -1
- package/dist/node_modules/semver/package.json +1 -1
- package/dist/node_modules/yauzl/package.json +1 -1
- package/dist/server/dumper.d.ts +3 -2
- package/dist/server/dumper.js +26 -7
- package/dist/server/progress-tracker.d.ts +1 -1
- package/dist/server/progress-tracker.js +1 -0
- package/dist/server/resourcers/backup-files.js +20 -14
- package/dist/server/restorer.d.ts +3 -3
- package/dist/server/restorer.js +29 -11
- package/dist/server/server.js +6 -1
- package/package.json +10 -7
package/dist/externalVersion.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
module.exports = {
|
|
2
2
|
"react": "18.3.1",
|
|
3
|
-
"@tachybase/client": "1.6.
|
|
4
|
-
"@tego/client": "1.6.
|
|
3
|
+
"@tachybase/client": "1.6.22",
|
|
4
|
+
"@tego/client": "1.6.13",
|
|
5
5
|
"@ant-design/icons": "6.1.0",
|
|
6
6
|
"antd": "5.22.5",
|
|
7
|
-
"@tachybase/schema": "1.6.
|
|
8
|
-
"@tego/server": "1.6.
|
|
7
|
+
"@tachybase/schema": "1.6.13",
|
|
8
|
+
"@tego/server": "1.6.13",
|
|
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-
|
|
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-06-16T10:35:02.430Z"}
|
|
@@ -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-
|
|
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-06-16T10:35:02.332Z"}
|
|
@@ -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-
|
|
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-06-16T10:35:03.142Z"}
|
|
@@ -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-
|
|
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-06-16T10:35:02.687Z"}
|
|
@@ -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-
|
|
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-06-16T10:35:02.874Z"}
|
package/dist/server/dumper.d.ts
CHANGED
|
@@ -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
|
|
64
|
+
cleanLockFile(fileName: string, appName?: string): Promise<void>;
|
|
65
65
|
getLockFile(appName: string): Promise<string>;
|
|
66
|
-
|
|
66
|
+
startDumpTask(options: DumpOptions): string;
|
|
67
|
+
runDumpTask(options: DumpOptions): Promise<string>;
|
|
67
68
|
dumpableCollectionsGroupByGroup(): Promise<{
|
|
68
69
|
[x: string]: Pick<any, string>[];
|
|
69
70
|
}>;
|
package/dist/server/dumper.js
CHANGED
|
@@ -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
|
|
69
|
-
const
|
|
70
|
-
const
|
|
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(
|
|
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
|
-
|
|
224
|
-
|
|
225
|
+
startDumpTask(options) {
|
|
226
|
+
const taskId = options.fileName || _Dumper.generateFileName();
|
|
227
|
+
const taskPromise = this.dump({
|
|
225
228
|
groups: options.groups,
|
|
226
|
-
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();
|
|
@@ -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<
|
|
41
|
+
}): Promise<void | string>;
|
|
42
42
|
}
|
|
43
43
|
export {};
|
package/dist/server/restorer.js
CHANGED
|
@@ -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 (
|
|
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.
|
|
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({
|
|
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
|
-
|
|
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
|
-
|
|
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;
|
package/dist/server/server.js
CHANGED
|
@@ -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
|
-
|
|
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.
|
|
4
|
+
"version": "1.6.22",
|
|
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.
|
|
24
|
-
"@tachybase/test": "1.6.
|
|
25
|
-
"@tego/client": "1.6.
|
|
26
|
-
"@tego/server": "1.6.
|
|
23
|
+
"@tachybase/schema": "1.6.13",
|
|
24
|
+
"@tachybase/test": "1.6.13",
|
|
25
|
+
"@tego/client": "1.6.13",
|
|
26
|
+
"@tego/server": "1.6.13",
|
|
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.
|
|
47
|
-
"@tachybase/
|
|
46
|
+
"@tachybase/client": "1.6.22",
|
|
47
|
+
"@tachybase/plugin-audit-logs": "1.6.22",
|
|
48
|
+
"@tachybase/plugin-field-sequence": "1.6.22",
|
|
49
|
+
"@tachybase/plugin-block-map": "1.6.22",
|
|
50
|
+
"@tachybase/module-worker-thread": "1.6.22"
|
|
48
51
|
},
|
|
49
52
|
"description.zh-CN": "备份和还原应用,可用于应用的复制、迁移、升级等场景。",
|
|
50
53
|
"displayName.zh-CN": "应用的备份与还原",
|