@tachybase/plugin-database-clean 1.6.2
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/README.md +134 -0
- package/README.zh-CN.md +136 -0
- package/client.d.ts +2 -0
- package/client.js +1 -0
- package/dist/client/index.d.ts +1 -0
- package/dist/client/index.js +1 -0
- package/dist/client/locale.d.ts +7 -0
- package/dist/client/pages/TableDetail.d.ts +1 -0
- package/dist/client/pages/TableList.d.ts +1 -0
- package/dist/client/plugin.d.ts +7 -0
- package/dist/externalVersion.js +11 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +39 -0
- package/dist/locale/en-US.json +65 -0
- package/dist/locale/zh-CN.json +65 -0
- package/dist/node_modules/archiver/LICENSE +22 -0
- package/dist/node_modules/archiver/index.js +73 -0
- package/dist/node_modules/archiver/lib/core.js +974 -0
- package/dist/node_modules/archiver/lib/error.js +40 -0
- package/dist/node_modules/archiver/lib/plugins/json.js +110 -0
- package/dist/node_modules/archiver/lib/plugins/tar.js +167 -0
- package/dist/node_modules/archiver/lib/plugins/zip.js +120 -0
- package/dist/node_modules/archiver/package.json +1 -0
- package/dist/server/adapters/base-adapter.d.ts +63 -0
- package/dist/server/adapters/base-adapter.js +31 -0
- package/dist/server/adapters/index.d.ts +36 -0
- package/dist/server/adapters/index.js +86 -0
- package/dist/server/adapters/mysql-adapter.d.ts +13 -0
- package/dist/server/adapters/mysql-adapter.js +118 -0
- package/dist/server/adapters/postgres-adapter.d.ts +13 -0
- package/dist/server/adapters/postgres-adapter.js +115 -0
- package/dist/server/adapters/sqlite-adapter.d.ts +13 -0
- package/dist/server/adapters/sqlite-adapter.js +115 -0
- package/dist/server/collections/.gitkeep +0 -0
- package/dist/server/constants.d.ts +4 -0
- package/dist/server/constants.js +38 -0
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.js +33 -0
- package/dist/server/plugin.d.ts +11 -0
- package/dist/server/plugin.js +61 -0
- package/dist/server/resourcers/database-clean.d.ts +31 -0
- package/dist/server/resourcers/database-clean.js +303 -0
- package/dist/server/services/database-service.d.ts +46 -0
- package/dist/server/services/database-service.js +138 -0
- package/dist/server/services/filtered-backup-service.d.ts +40 -0
- package/dist/server/services/filtered-backup-service.js +269 -0
- package/dist/server/utils/lock.d.ts +23 -0
- package/dist/server/utils/lock.js +62 -0
- package/dist/server/utils.d.ts +2 -0
- package/dist/server/utils.js +43 -0
- package/package.json +26 -0
- package/server.d.ts +2 -0
- package/server.js +1 -0
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
20
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
21
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
22
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
23
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
24
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
25
|
+
mod
|
|
26
|
+
));
|
|
27
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
28
|
+
var filtered_backup_service_exports = {};
|
|
29
|
+
__export(filtered_backup_service_exports, {
|
|
30
|
+
FilteredBackupService: () => FilteredBackupService
|
|
31
|
+
});
|
|
32
|
+
module.exports = __toCommonJS(filtered_backup_service_exports);
|
|
33
|
+
var import_node_fs = __toESM(require("node:fs"));
|
|
34
|
+
var import_promises = __toESM(require("node:fs/promises"));
|
|
35
|
+
var import_node_path = __toESM(require("node:path"));
|
|
36
|
+
var import_node_stream = __toESM(require("node:stream"));
|
|
37
|
+
var import_node_util = __toESM(require("node:util"));
|
|
38
|
+
var import_archiver = __toESM(require("archiver"));
|
|
39
|
+
var import_dayjs = __toESM(require("dayjs"));
|
|
40
|
+
var import_lodash = __toESM(require("lodash"));
|
|
41
|
+
var import_adapters = require("../adapters");
|
|
42
|
+
var import_utils = require("../utils");
|
|
43
|
+
const finished = import_node_util.default.promisify(import_node_stream.default.finished);
|
|
44
|
+
class FieldValueWriter {
|
|
45
|
+
static toDumpedValue(field, val) {
|
|
46
|
+
if (val === null) return val;
|
|
47
|
+
if (field.type === "point" || field.type === "lineString" || field.type === "circle" || field.type === "polygon") {
|
|
48
|
+
const mockObj = {
|
|
49
|
+
getDataValue: () => val
|
|
50
|
+
};
|
|
51
|
+
const newValue = field.options.get.call(mockObj);
|
|
52
|
+
return newValue;
|
|
53
|
+
}
|
|
54
|
+
return val;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
class FilteredBackupService {
|
|
58
|
+
constructor(app) {
|
|
59
|
+
this.app = app;
|
|
60
|
+
this.workDir = import_node_path.default.resolve(process.env.TEGO_RUNTIME_HOME || process.cwd(), "storage", "temp", "database-clean");
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* 生成备份文件名
|
|
64
|
+
*/
|
|
65
|
+
static generateFileName(collectionName, filter) {
|
|
66
|
+
var _a, _b, _c, _d, _e, _f;
|
|
67
|
+
const random = Math.floor(1e3 + Math.random() * 9e3);
|
|
68
|
+
const timestamp = (0, import_dayjs.default)().format("YYYYMMDD_HHmmss");
|
|
69
|
+
let rangeSuffix = "";
|
|
70
|
+
if (((_a = filter == null ? void 0 : filter.createdAt) == null ? void 0 : _a.$gte) || ((_b = filter == null ? void 0 : filter.createdAt) == null ? void 0 : _b.$lte)) {
|
|
71
|
+
const from = filter.createdAt.$gte ? (0, import_dayjs.default)(filter.createdAt.$gte).format("YYYYMMDD") : "start";
|
|
72
|
+
const to = filter.createdAt.$lte ? (0, import_dayjs.default)(filter.createdAt.$lte).format("YYYYMMDD") : "end";
|
|
73
|
+
rangeSuffix = `_createdAt_${from}_${to}`;
|
|
74
|
+
} else if (((_c = filter == null ? void 0 : filter.updatedAt) == null ? void 0 : _c.$gte) || ((_d = filter == null ? void 0 : filter.updatedAt) == null ? void 0 : _d.$lte)) {
|
|
75
|
+
const from = filter.updatedAt.$gte ? (0, import_dayjs.default)(filter.updatedAt.$gte).format("YYYYMMDD") : "start";
|
|
76
|
+
const to = filter.updatedAt.$lte ? (0, import_dayjs.default)(filter.updatedAt.$lte).format("YYYYMMDD") : "end";
|
|
77
|
+
rangeSuffix = `_updatedAt_${from}_${to}`;
|
|
78
|
+
} else if (((_e = filter == null ? void 0 : filter.id) == null ? void 0 : _e.$gte) !== void 0 || ((_f = filter == null ? void 0 : filter.id) == null ? void 0 : _f.$lte) !== void 0) {
|
|
79
|
+
const from = filter.id.$gte !== void 0 ? filter.id.$gte : "start";
|
|
80
|
+
const to = filter.id.$lte !== void 0 ? filter.id.$lte : "end";
|
|
81
|
+
rangeSuffix = `_id_${from}_${to}`;
|
|
82
|
+
}
|
|
83
|
+
return `db-clean_${collectionName}${rangeSuffix}_${timestamp}_${random}.tbdump`;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* 备份单个集合的筛选数据
|
|
87
|
+
*/
|
|
88
|
+
async backupCollection(options) {
|
|
89
|
+
import_adapters.DatabaseAdapterFactory.getAdapter(this.app);
|
|
90
|
+
const { collectionName, filter, fileName, appName } = options;
|
|
91
|
+
const collection = this.app.db.getCollection(collectionName);
|
|
92
|
+
if (!collection) {
|
|
93
|
+
throw new Error(`Collection ${collectionName} not found`);
|
|
94
|
+
}
|
|
95
|
+
await import_promises.default.mkdir(this.workDir, { recursive: true });
|
|
96
|
+
const collectionDataDir = import_node_path.default.resolve(this.workDir, "collections", collectionName);
|
|
97
|
+
await import_promises.default.mkdir(collectionDataDir, { recursive: true });
|
|
98
|
+
const attributes = collection.model.tableAttributes;
|
|
99
|
+
const columns = [...new Set(import_lodash.default.map(attributes, "field"))];
|
|
100
|
+
const whereConditions = [];
|
|
101
|
+
const replacements = {};
|
|
102
|
+
if (filter == null ? void 0 : filter.createdAt) {
|
|
103
|
+
if (filter.createdAt.$gte) {
|
|
104
|
+
whereConditions.push('"createdAt" >= :createdAtGte');
|
|
105
|
+
replacements.createdAtGte = filter.createdAt.$gte;
|
|
106
|
+
}
|
|
107
|
+
if (filter.createdAt.$lte) {
|
|
108
|
+
whereConditions.push('"createdAt" <= :createdAtLte');
|
|
109
|
+
replacements.createdAtLte = filter.createdAt.$lte;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
if (filter == null ? void 0 : filter.updatedAt) {
|
|
113
|
+
if (filter.updatedAt.$gte) {
|
|
114
|
+
whereConditions.push('"updatedAt" >= :updatedAtGte');
|
|
115
|
+
replacements.updatedAtGte = filter.updatedAt.$gte;
|
|
116
|
+
}
|
|
117
|
+
if (filter.updatedAt.$lte) {
|
|
118
|
+
whereConditions.push('"updatedAt" <= :updatedAtLte');
|
|
119
|
+
replacements.updatedAtLte = filter.updatedAt.$lte;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
if (filter == null ? void 0 : filter.id) {
|
|
123
|
+
const primaryKey = collection.model.primaryKeyAttribute || "id";
|
|
124
|
+
if (filter.id.$gte !== void 0) {
|
|
125
|
+
whereConditions.push(`"${primaryKey}" >= :idGte`);
|
|
126
|
+
replacements.idGte = filter.id.$gte;
|
|
127
|
+
}
|
|
128
|
+
if (filter.id.$lte !== void 0) {
|
|
129
|
+
whereConditions.push(`"${primaryKey}" <= :idLte`);
|
|
130
|
+
replacements.idLte = filter.id.$lte;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
const whereClause = whereConditions.length > 0 ? `WHERE ${whereConditions.join(" AND ")}` : "";
|
|
134
|
+
const dataFilePath = import_node_path.default.resolve(collectionDataDir, "data");
|
|
135
|
+
const dataStream = import_node_fs.default.createWriteStream(dataFilePath);
|
|
136
|
+
let count = 0;
|
|
137
|
+
const sql = `SELECT * FROM ${collection.isParent() ? "ONLY" : ""} ${collection.quotedTableName()} ${whereClause}`;
|
|
138
|
+
const rows = await this.app.db.sequelize.query((0, import_utils.sqlAdapter)(this.app.db, sql), {
|
|
139
|
+
type: "SELECT",
|
|
140
|
+
replacements
|
|
141
|
+
});
|
|
142
|
+
for (const row of rows) {
|
|
143
|
+
const rowData = JSON.stringify(
|
|
144
|
+
columns.map((col) => {
|
|
145
|
+
const val = row[col];
|
|
146
|
+
const field = collection.getField(col);
|
|
147
|
+
return field ? FieldValueWriter.toDumpedValue(field, val) : val;
|
|
148
|
+
})
|
|
149
|
+
);
|
|
150
|
+
if (!dataStream.write(rowData + "\r\n", "utf8")) {
|
|
151
|
+
await new Promise((resolve) => dataStream.once("drain", resolve));
|
|
152
|
+
}
|
|
153
|
+
count++;
|
|
154
|
+
}
|
|
155
|
+
dataStream.end();
|
|
156
|
+
await finished(dataStream);
|
|
157
|
+
const metaAttributes = import_lodash.default.mapValues(attributes, (attr, key) => {
|
|
158
|
+
var _a, _b, _c;
|
|
159
|
+
const collectionField = collection.getField(key);
|
|
160
|
+
const fieldOptionKeys = ["field", "primaryKey", "autoIncrement", "allowNull", "defaultValue", "unique"];
|
|
161
|
+
if (collectionField) {
|
|
162
|
+
const fieldAttributes = {
|
|
163
|
+
field: attr.field,
|
|
164
|
+
isCollectionField: true,
|
|
165
|
+
type: collectionField.type,
|
|
166
|
+
typeOptions: collectionField.options
|
|
167
|
+
};
|
|
168
|
+
if (((_c = (_b = (_a = fieldAttributes.typeOptions) == null ? void 0 : _a.defaultValue) == null ? void 0 : _b.constructor) == null ? void 0 : _c.name) === "UUIDV4") {
|
|
169
|
+
delete fieldAttributes.typeOptions.defaultValue;
|
|
170
|
+
}
|
|
171
|
+
return fieldAttributes;
|
|
172
|
+
}
|
|
173
|
+
return {
|
|
174
|
+
...import_lodash.default.pick(attr, fieldOptionKeys),
|
|
175
|
+
type: attr.type.constructor.toString(),
|
|
176
|
+
isCollectionField: false,
|
|
177
|
+
typeOptions: attr.type.options
|
|
178
|
+
};
|
|
179
|
+
});
|
|
180
|
+
const meta = {
|
|
181
|
+
name: collectionName,
|
|
182
|
+
tableName: collection.getTableNameWithSchema(),
|
|
183
|
+
count,
|
|
184
|
+
columns,
|
|
185
|
+
attributes: metaAttributes,
|
|
186
|
+
filter
|
|
187
|
+
// 保存筛选条件
|
|
188
|
+
};
|
|
189
|
+
if (collection.options.inherits) {
|
|
190
|
+
meta["inherits"] = import_lodash.default.uniq(collection.options.inherits);
|
|
191
|
+
}
|
|
192
|
+
await import_promises.default.writeFile(import_node_path.default.resolve(collectionDataDir, "meta"), JSON.stringify(meta), "utf8");
|
|
193
|
+
const rootMeta = {
|
|
194
|
+
version: this.app.getVersion(),
|
|
195
|
+
dialect: this.app.db.sequelize.getDialect(),
|
|
196
|
+
DB_UNDERSCORED: process.env.DB_UNDERSCORED || "false",
|
|
197
|
+
DB_SCHEMA: process.env.DB_SCHEMA || "",
|
|
198
|
+
COLLECTION_MANAGER_SCHEMA: process.env.COLLECTION_MANAGER_SCHEMA || "",
|
|
199
|
+
DB_TABLE_PREFIX: process.env.DB_TABLE_PREFIX || "",
|
|
200
|
+
// 标记为 database-clean 插件生成的部分备份
|
|
201
|
+
backupType: "database-clean",
|
|
202
|
+
dumpableCollectionsGroupByGroup: {
|
|
203
|
+
custom: [
|
|
204
|
+
{
|
|
205
|
+
name: collectionName,
|
|
206
|
+
group: "custom",
|
|
207
|
+
origin: "@tachybase/plugin-database-clean",
|
|
208
|
+
title: collectionName,
|
|
209
|
+
isView: false
|
|
210
|
+
}
|
|
211
|
+
]
|
|
212
|
+
},
|
|
213
|
+
dumpedGroups: ["custom"],
|
|
214
|
+
delayCollections: [],
|
|
215
|
+
filter
|
|
216
|
+
// 保存筛选条件供参考
|
|
217
|
+
};
|
|
218
|
+
await import_promises.default.writeFile(import_node_path.default.resolve(this.workDir, "meta"), JSON.stringify(rootMeta), "utf8");
|
|
219
|
+
const backupFileName = fileName || FilteredBackupService.generateFileName(collectionName, filter);
|
|
220
|
+
const filePath = await this.packDumpedDir(backupFileName, appName);
|
|
221
|
+
await this.clearWorkDir();
|
|
222
|
+
return {
|
|
223
|
+
fileName: backupFileName,
|
|
224
|
+
filePath: filePath.filePath
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
async packDumpedDir(fileName, appName) {
|
|
228
|
+
const storageDir = this.getStorageDir(appName);
|
|
229
|
+
await import_promises.default.mkdir(storageDir, { recursive: true });
|
|
230
|
+
const filePath = import_node_path.default.resolve(storageDir, fileName);
|
|
231
|
+
const output = import_node_fs.default.createWriteStream(filePath);
|
|
232
|
+
const archive = (0, import_archiver.default)("zip", {
|
|
233
|
+
zlib: { level: 9 }
|
|
234
|
+
});
|
|
235
|
+
const onClose = new Promise((resolve, reject) => {
|
|
236
|
+
output.on("close", function() {
|
|
237
|
+
resolve({
|
|
238
|
+
filePath,
|
|
239
|
+
dirname: storageDir
|
|
240
|
+
});
|
|
241
|
+
});
|
|
242
|
+
archive.on("error", function(err) {
|
|
243
|
+
reject(err);
|
|
244
|
+
});
|
|
245
|
+
});
|
|
246
|
+
archive.pipe(output);
|
|
247
|
+
archive.directory(this.workDir, false);
|
|
248
|
+
await archive.finalize();
|
|
249
|
+
await onClose;
|
|
250
|
+
return { filePath, dirname: storageDir };
|
|
251
|
+
}
|
|
252
|
+
getStorageDir(appName) {
|
|
253
|
+
if (appName && appName !== "main") {
|
|
254
|
+
return import_node_path.default.resolve(process.env.TEGO_RUNTIME_HOME || process.cwd(), "storage", "backups", appName);
|
|
255
|
+
}
|
|
256
|
+
return import_node_path.default.resolve(process.env.TEGO_RUNTIME_HOME || process.cwd(), "storage", "backups");
|
|
257
|
+
}
|
|
258
|
+
async clearWorkDir() {
|
|
259
|
+
try {
|
|
260
|
+
await import_promises.default.rm(this.workDir, { recursive: true, force: true });
|
|
261
|
+
} catch (error) {
|
|
262
|
+
this.app.logger.warn("Failed to clear work directory:", error);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
267
|
+
0 && (module.exports = {
|
|
268
|
+
FilteredBackupService
|
|
269
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Application } from '@tego/server';
|
|
2
|
+
/**
|
|
3
|
+
* 基于缓存的锁实现,用于防止并发操作
|
|
4
|
+
*/
|
|
5
|
+
export declare class DatabaseCleanLock {
|
|
6
|
+
private app;
|
|
7
|
+
private cache;
|
|
8
|
+
private readonly LOCK_PREFIX;
|
|
9
|
+
private readonly LOCK_TTL;
|
|
10
|
+
constructor(app: Application);
|
|
11
|
+
/**
|
|
12
|
+
* 获取锁
|
|
13
|
+
*/
|
|
14
|
+
acquire(collectionName: string): Promise<boolean>;
|
|
15
|
+
/**
|
|
16
|
+
* 释放锁
|
|
17
|
+
*/
|
|
18
|
+
release(collectionName: string): Promise<void>;
|
|
19
|
+
/**
|
|
20
|
+
* 检查锁是否存在
|
|
21
|
+
*/
|
|
22
|
+
isLocked(collectionName: string): Promise<boolean>;
|
|
23
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __export = (target, all) => {
|
|
6
|
+
for (var name in all)
|
|
7
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
8
|
+
};
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
|
+
var lock_exports = {};
|
|
19
|
+
__export(lock_exports, {
|
|
20
|
+
DatabaseCleanLock: () => DatabaseCleanLock
|
|
21
|
+
});
|
|
22
|
+
module.exports = __toCommonJS(lock_exports);
|
|
23
|
+
class DatabaseCleanLock {
|
|
24
|
+
// 2小时
|
|
25
|
+
constructor(app) {
|
|
26
|
+
this.app = app;
|
|
27
|
+
this.LOCK_PREFIX = "database-clean:lock:";
|
|
28
|
+
this.LOCK_TTL = 2 * 60 * 60 * 1e3;
|
|
29
|
+
this.cache = app.cache;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* 获取锁
|
|
33
|
+
*/
|
|
34
|
+
async acquire(collectionName) {
|
|
35
|
+
const lockKey = `${this.LOCK_PREFIX}${collectionName}`;
|
|
36
|
+
const existingLock = await this.cache.get(lockKey);
|
|
37
|
+
if (existingLock) {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
await this.cache.set(lockKey, Date.now(), this.LOCK_TTL);
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* 释放锁
|
|
45
|
+
*/
|
|
46
|
+
async release(collectionName) {
|
|
47
|
+
const lockKey = `${this.LOCK_PREFIX}${collectionName}`;
|
|
48
|
+
await this.cache.del(lockKey);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* 检查锁是否存在
|
|
52
|
+
*/
|
|
53
|
+
async isLocked(collectionName) {
|
|
54
|
+
const lockKey = `${this.LOCK_PREFIX}${collectionName}`;
|
|
55
|
+
const lock = await this.cache.get(lockKey);
|
|
56
|
+
return !!lock;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
60
|
+
0 && (module.exports = {
|
|
61
|
+
DatabaseCleanLock
|
|
62
|
+
});
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
20
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
21
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
22
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
23
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
24
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
25
|
+
mod
|
|
26
|
+
));
|
|
27
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
28
|
+
var utils_exports = {};
|
|
29
|
+
__export(utils_exports, {
|
|
30
|
+
sqlAdapter: () => sqlAdapter
|
|
31
|
+
});
|
|
32
|
+
module.exports = __toCommonJS(utils_exports);
|
|
33
|
+
var import_lodash = __toESM(require("lodash"));
|
|
34
|
+
function sqlAdapter(database, sql) {
|
|
35
|
+
if (database.isMySQLCompatibleDialect()) {
|
|
36
|
+
return import_lodash.default.replace(sql, /"/g, "`");
|
|
37
|
+
}
|
|
38
|
+
return sql;
|
|
39
|
+
}
|
|
40
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
41
|
+
0 && (module.exports = {
|
|
42
|
+
sqlAdapter
|
|
43
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@tachybase/plugin-database-clean",
|
|
3
|
+
"displayName": "Database Cleanup Tool",
|
|
4
|
+
"version": "1.6.2",
|
|
5
|
+
"description": "Clean up database.",
|
|
6
|
+
"main": "dist/server/index.js",
|
|
7
|
+
"devDependencies": {
|
|
8
|
+
"@ant-design/icons": "^5.6.1",
|
|
9
|
+
"@tachybase/client": "1.6.1",
|
|
10
|
+
"@tachybase/test": "1.6.1",
|
|
11
|
+
"@tego/client": "1.6.1",
|
|
12
|
+
"@tego/server": "1.6.1",
|
|
13
|
+
"@types/archiver": "^5.3.4",
|
|
14
|
+
"@types/file-saver": "^2.0.7",
|
|
15
|
+
"@types/lodash": "^4.17.20",
|
|
16
|
+
"antd": "5.22.5",
|
|
17
|
+
"archiver": "^7.0.1",
|
|
18
|
+
"dayjs": "1.11.13",
|
|
19
|
+
"file-saver": "^2.0.5",
|
|
20
|
+
"lodash": "4.17.21",
|
|
21
|
+
"react-router-dom": "6.28.1",
|
|
22
|
+
"sequelize": "^6.37.5"
|
|
23
|
+
},
|
|
24
|
+
"description.zh-CN": "数据库清理。",
|
|
25
|
+
"displayName.zh-CN": "数据库清理工具"
|
|
26
|
+
}
|
package/server.d.ts
ADDED
package/server.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = require('./dist/server/index.js');
|