@sch_cat/export-utils 0.0.1
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/LICENSE +16 -0
- package/README.md +7 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +322 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +72 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/tools.d.ts +2 -0
- package/dist/utils/tools.d.ts.map +1 -0
- package/dist/utils/tools.js +5 -0
- package/dist/utils/tools.js.map +1 -0
- package/package.json +59 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
Copyright (c) 2026 sch
|
|
2
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
3
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
4
|
+
in the Software without restriction, including without limitation the rights
|
|
5
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
6
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
7
|
+
furnished to do so, subject to the following conditions:
|
|
8
|
+
The above copyright notice and this permission notice shall be included in all
|
|
9
|
+
copies or substantial portions of the Software.
|
|
10
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
11
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
12
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
13
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
14
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
15
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
16
|
+
SOFTWARE.
|
package/README.md
ADDED
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type ExportMongoOptions, type ExportMysqlOptions, type ExportUtilsOptions, type TaskProcessInput, type TaskProcessResult } from './types.js';
|
|
2
|
+
export declare class ExportUtils {
|
|
3
|
+
private redisClient;
|
|
4
|
+
private mysqlClient;
|
|
5
|
+
private mongoClient;
|
|
6
|
+
private readonly options;
|
|
7
|
+
private readonly DEFAULT_EXPORT_DIR;
|
|
8
|
+
private readonly TASK_OUT_TIME;
|
|
9
|
+
constructor(options: ExportUtilsOptions);
|
|
10
|
+
private redisInit;
|
|
11
|
+
private mysqlInit;
|
|
12
|
+
private mongoInit;
|
|
13
|
+
private processUpdate;
|
|
14
|
+
createMysqlExportTask(params: ExportMysqlOptions): Promise<string>;
|
|
15
|
+
private exportMysqlToCsv;
|
|
16
|
+
createMongoExportTask(params: ExportMongoOptions): Promise<string>;
|
|
17
|
+
private exportMongoToCsv;
|
|
18
|
+
getTaskStatus(params: TaskProcessInput): Promise<(TaskProcessResult | {})[]>;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAUA,OAAO,EAEH,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EAEvB,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACzB,MAAM,YAAY,CAAC;AAGpB,qBAAa,WAAW;IACpB,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,WAAW,CAAe;IAClC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqB;IAC7C,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAa;IAChD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAQ;gBAE1B,OAAO,EAAE,kBAAkB;YAKzB,SAAS;YAMT,SAAS;YAST,SAAS;YAcT,aAAa;IAsBrB,qBAAqB,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,MAAM,CAAC;YA4B1D,gBAAgB;IAiHxB,qBAAqB,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,MAAM,CAAC;YA4B1D,gBAAgB;IA6GxB,aAAa,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,CAAC,iBAAiB,GAAG,EAAE,CAAC,EAAE,CAAC;CAYrF"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import { stringify } from 'csv-stringify';
|
|
3
|
+
import { createWriteStream, mkdirSync } from 'fs';
|
|
4
|
+
import { Redis } from 'ioredis';
|
|
5
|
+
import { MongoClient } from 'mongodb';
|
|
6
|
+
import mysql, {} from 'mysql2';
|
|
7
|
+
import { dirname, isAbsolute, join } from 'path';
|
|
8
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
9
|
+
import zlib from 'zlib';
|
|
10
|
+
import { ProcessStatus, } from './types.js';
|
|
11
|
+
import { isValidIdentifier } from './utils/tools.js';
|
|
12
|
+
export class ExportUtils {
|
|
13
|
+
redisClient;
|
|
14
|
+
mysqlClient;
|
|
15
|
+
mongoClient;
|
|
16
|
+
options;
|
|
17
|
+
DEFAULT_EXPORT_DIR = 'exports'; //默认导出目录
|
|
18
|
+
TASK_OUT_TIME = 3600; //任务超时时间
|
|
19
|
+
constructor(options) {
|
|
20
|
+
this.options = options;
|
|
21
|
+
}
|
|
22
|
+
//redis初始化
|
|
23
|
+
async redisInit() {
|
|
24
|
+
const { redisOptions } = this.options;
|
|
25
|
+
this.redisClient = new Redis(redisOptions);
|
|
26
|
+
}
|
|
27
|
+
//mysql初始化
|
|
28
|
+
async mysqlInit() {
|
|
29
|
+
const { mysqlOptions } = this.options;
|
|
30
|
+
if (!mysqlOptions) {
|
|
31
|
+
throw new Error('缺少mysql配置信息');
|
|
32
|
+
}
|
|
33
|
+
this.mysqlClient = mysql.createConnection(mysqlOptions);
|
|
34
|
+
}
|
|
35
|
+
//mongo初始化
|
|
36
|
+
async mongoInit() {
|
|
37
|
+
const { mongoOptions } = this.options;
|
|
38
|
+
if (!mongoOptions) {
|
|
39
|
+
throw new Error('缺少mongo配置信息');
|
|
40
|
+
}
|
|
41
|
+
const { url, options } = mongoOptions;
|
|
42
|
+
try {
|
|
43
|
+
this.mongoClient = await MongoClient.connect(url, options);
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
console.error(error);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
//更新进度
|
|
50
|
+
async processUpdate(params) {
|
|
51
|
+
let { taskId, current = -1, total = -1, errMsg } = params;
|
|
52
|
+
let progressPercent = total > 0 ? ((current / total) * 100).toFixed(2) + '%' : '0.00%';
|
|
53
|
+
let status = current >= total ? ProcessStatus.COMPLETED : ProcessStatus.RUNNING;
|
|
54
|
+
if (errMsg) {
|
|
55
|
+
status = ProcessStatus.FAILED;
|
|
56
|
+
progressPercent = '0.00%';
|
|
57
|
+
total = -1;
|
|
58
|
+
current = -1;
|
|
59
|
+
errMsg;
|
|
60
|
+
}
|
|
61
|
+
const updates = {
|
|
62
|
+
taskId,
|
|
63
|
+
total,
|
|
64
|
+
current,
|
|
65
|
+
progress: progressPercent,
|
|
66
|
+
status,
|
|
67
|
+
};
|
|
68
|
+
this.redisClient.set(`export:${taskId}`, JSON.stringify(updates), 'EX', this.TASK_OUT_TIME);
|
|
69
|
+
}
|
|
70
|
+
//创建导出mysql任务
|
|
71
|
+
async createMysqlExportTask(params) {
|
|
72
|
+
if (!this.redisClient) {
|
|
73
|
+
await this.redisInit();
|
|
74
|
+
}
|
|
75
|
+
if (!this.mysqlClient) {
|
|
76
|
+
await this.mysqlInit();
|
|
77
|
+
}
|
|
78
|
+
const { table, columns = [] } = params;
|
|
79
|
+
//参数校验
|
|
80
|
+
if (!isValidIdentifier(table)) {
|
|
81
|
+
throw new Error('Invalid table name');
|
|
82
|
+
}
|
|
83
|
+
if (columns.length) {
|
|
84
|
+
for (const col of columns) {
|
|
85
|
+
if (!isValidIdentifier(col.key)) {
|
|
86
|
+
throw new Error(`Invalid column key: "${col.key}"`);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
//任务ID
|
|
91
|
+
const taskId = `export-mysql-csv-${uuidv4()}`;
|
|
92
|
+
this.exportMysqlToCsv(taskId, params);
|
|
93
|
+
return taskId;
|
|
94
|
+
}
|
|
95
|
+
//mysql导出
|
|
96
|
+
async exportMysqlToCsv(taskId, params) {
|
|
97
|
+
const { table, outputPath, columns = [], where = '', batchSize = 1000, onCompleted, onErr } = params;
|
|
98
|
+
// 路径处理
|
|
99
|
+
const finalOutputPath = isAbsolute(outputPath)
|
|
100
|
+
? outputPath
|
|
101
|
+
: join(process.cwd(), this.DEFAULT_EXPORT_DIR, outputPath);
|
|
102
|
+
mkdirSync(dirname(finalOutputPath), { recursive: true });
|
|
103
|
+
// 初始化进度
|
|
104
|
+
const countQuery = `SELECT COUNT(*) AS total FROM \`${table}\`` + (where.trim() ? ` WHERE ${where.trim()}` : '');
|
|
105
|
+
const [countRows] = await this.mysqlClient.promise().query(countQuery);
|
|
106
|
+
const totalRows = countRows[0].total;
|
|
107
|
+
// 写入初始状态到 Redis
|
|
108
|
+
this.processUpdate({ taskId, current: 0, total: totalRows });
|
|
109
|
+
// 创建 CSV 写入流
|
|
110
|
+
const inputColumns = columns.map(col => {
|
|
111
|
+
return { key: col.key, header: col.header || col.key };
|
|
112
|
+
});
|
|
113
|
+
const csvStream = stringify({
|
|
114
|
+
header: true, // 写入表头
|
|
115
|
+
delimiter: ',', // 分隔符
|
|
116
|
+
quoted: false, // 默认不加引号
|
|
117
|
+
quoted_match: /[,\"\n\r]/, // 仅当字段包含这些字符时加引号
|
|
118
|
+
escape: '"', // 转义字符
|
|
119
|
+
bom: true, // 添加 BOM,确保 Excel 正确识别 UTF-8
|
|
120
|
+
...(inputColumns.length && { columns: inputColumns }), // 仅当指定列时设置 columns
|
|
121
|
+
});
|
|
122
|
+
// 创建文件写入流
|
|
123
|
+
const gzip = zlib.createGzip();
|
|
124
|
+
const fileStream = createWriteStream(`${finalOutputPath}.csv.gz`);
|
|
125
|
+
csvStream.pipe(gzip).pipe(fileStream);
|
|
126
|
+
// 构建 SQL 查询
|
|
127
|
+
const columnList = !columns.length ? '*' : columns.map(col => `\`${col.key}\``).join(', ');
|
|
128
|
+
const query = `SELECT ${columnList} FROM \`${table}\`` + (where.trim() ? ` WHERE ${where.trim()}` : '');
|
|
129
|
+
// 使用流式查询
|
|
130
|
+
const stream = this.mysqlClient.query(query).stream();
|
|
131
|
+
// 处理背压
|
|
132
|
+
let shouldPause = false;
|
|
133
|
+
let rowCount = 0;
|
|
134
|
+
// 错误处理(防止静默失败)
|
|
135
|
+
const handleError = (error, context) => {
|
|
136
|
+
console.error(`❌ ${context}:`, error.message);
|
|
137
|
+
this.processUpdate({ taskId, errMsg: error.message });
|
|
138
|
+
if (onErr) {
|
|
139
|
+
onErr({
|
|
140
|
+
taskId,
|
|
141
|
+
status: ProcessStatus.FAILED,
|
|
142
|
+
errMsg: error.message,
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
this.mysqlClient.end();
|
|
146
|
+
};
|
|
147
|
+
this.mysqlClient.on('error', err => handleError(err, 'MySQL connection error'));
|
|
148
|
+
stream.on('error', err => handleError(err, 'MySQL query error'));
|
|
149
|
+
csvStream.on('error', err => handleError(err, 'CSV stream error'));
|
|
150
|
+
fileStream.on('error', err => handleError(err, 'File write error'));
|
|
151
|
+
stream.on('data', (row) => {
|
|
152
|
+
rowCount++;
|
|
153
|
+
let outputRow = {};
|
|
154
|
+
for (const col of columns) {
|
|
155
|
+
const rawValue = row[col.key];
|
|
156
|
+
const formattedValue = col.formatter ? col.formatter(rawValue) : rawValue;
|
|
157
|
+
outputRow[col.key] = formattedValue;
|
|
158
|
+
}
|
|
159
|
+
const canContinue = csvStream.write(columns.length ? outputRow : row);
|
|
160
|
+
if (!canContinue) {
|
|
161
|
+
shouldPause = true;
|
|
162
|
+
stream.pause();
|
|
163
|
+
}
|
|
164
|
+
// 📈 每 batch 更新进度
|
|
165
|
+
if (rowCount % batchSize === 0 || rowCount === totalRows) {
|
|
166
|
+
console.log(`process:${rowCount}/${totalRows}`);
|
|
167
|
+
this.processUpdate({ taskId, current: rowCount, total: totalRows });
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
stream.on('end', () => {
|
|
171
|
+
csvStream.end(); // 触发 'finish'
|
|
172
|
+
});
|
|
173
|
+
csvStream.on('drain', () => {
|
|
174
|
+
if (shouldPause) {
|
|
175
|
+
shouldPause = false;
|
|
176
|
+
stream.resume();
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
csvStream.on('finish', () => {
|
|
180
|
+
if (onCompleted) {
|
|
181
|
+
onCompleted({
|
|
182
|
+
taskId,
|
|
183
|
+
rowCount,
|
|
184
|
+
outputPath: `${finalOutputPath}.csv.gz`,
|
|
185
|
+
status: ProcessStatus.COMPLETED,
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
// console.log(`🎉 Export completed! Total rows: ${rowCount}`);
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
//创建导出mongo任务
|
|
192
|
+
async createMongoExportTask(params) {
|
|
193
|
+
if (!this.redisClient) {
|
|
194
|
+
await this.redisInit();
|
|
195
|
+
}
|
|
196
|
+
if (!this.mongoClient) {
|
|
197
|
+
await this.mongoInit();
|
|
198
|
+
}
|
|
199
|
+
const { collection, columns = [] } = params;
|
|
200
|
+
//参数校验
|
|
201
|
+
if (!isValidIdentifier(collection)) {
|
|
202
|
+
throw new Error('Invalid table name');
|
|
203
|
+
}
|
|
204
|
+
if (columns.length) {
|
|
205
|
+
for (const col of columns) {
|
|
206
|
+
if (!isValidIdentifier(col.key)) {
|
|
207
|
+
throw new Error(`Invalid column key: "${col.key}"`);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
//任务ID
|
|
212
|
+
const taskId = `export-mongo-csv-${uuidv4()}`;
|
|
213
|
+
this.exportMongoToCsv(taskId, params);
|
|
214
|
+
return taskId;
|
|
215
|
+
}
|
|
216
|
+
//mongo导出
|
|
217
|
+
async exportMongoToCsv(taskId, params) {
|
|
218
|
+
const { collection, db, outputPath, columns = [], query = {}, batchSize = 1000, onCompleted, onErr } = params;
|
|
219
|
+
// 路径处理
|
|
220
|
+
const finalOutputPath = isAbsolute(outputPath)
|
|
221
|
+
? outputPath
|
|
222
|
+
: join(process.cwd(), this.DEFAULT_EXPORT_DIR, outputPath);
|
|
223
|
+
mkdirSync(dirname(finalOutputPath), { recursive: true });
|
|
224
|
+
// 获取集合
|
|
225
|
+
const collectionClient = this.mongoClient.db(db).collection(collection);
|
|
226
|
+
// 初始化进度
|
|
227
|
+
const totalRows = await collectionClient.countDocuments(query);
|
|
228
|
+
// 写入初始状态到 Redis
|
|
229
|
+
this.processUpdate({ taskId, current: 0, total: totalRows });
|
|
230
|
+
// 创建 CSV 写入流
|
|
231
|
+
const inputColumns = columns.map(col => {
|
|
232
|
+
return { key: col.key, header: col.header || col.key };
|
|
233
|
+
});
|
|
234
|
+
const csvStream = stringify({
|
|
235
|
+
header: true, // 写入表头
|
|
236
|
+
delimiter: ',', // 分隔符
|
|
237
|
+
quoted: false, // 默认不加引号
|
|
238
|
+
quoted_match: /[,\"\n\r]/, // 仅当字段包含这些字符时加引号
|
|
239
|
+
escape: '"', // 转义字符
|
|
240
|
+
bom: true, // 添加 BOM,确保 Excel 正确识别 UTF-8
|
|
241
|
+
...(inputColumns.length && { columns: inputColumns }), // 仅当指定列时设置 columns
|
|
242
|
+
});
|
|
243
|
+
// 创建文件写入流
|
|
244
|
+
const gzip = zlib.createGzip();
|
|
245
|
+
const fileStream = createWriteStream(`${finalOutputPath}.csv.gz`);
|
|
246
|
+
csvStream.pipe(gzip).pipe(fileStream);
|
|
247
|
+
// 处理背压
|
|
248
|
+
let shouldPause = false;
|
|
249
|
+
let rowCount = 0;
|
|
250
|
+
// 创建 MongoDB 游标(流式读取)
|
|
251
|
+
const cursor = collectionClient.find(query).batchSize(batchSize).stream();
|
|
252
|
+
// 错误处理(防止静默失败)
|
|
253
|
+
const handleError = (error, context) => {
|
|
254
|
+
console.error(`❌ ${context}:`, error.message);
|
|
255
|
+
this.processUpdate({ taskId, errMsg: error.message });
|
|
256
|
+
if (onErr) {
|
|
257
|
+
onErr({
|
|
258
|
+
taskId,
|
|
259
|
+
status: ProcessStatus.FAILED,
|
|
260
|
+
errMsg: error.message,
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
this.mysqlClient.end();
|
|
264
|
+
};
|
|
265
|
+
this.mongoClient.on('error', err => handleError(err, 'mongo connection error'));
|
|
266
|
+
cursor.on('error', err => handleError(err, 'mongo query error'));
|
|
267
|
+
csvStream.on('error', err => handleError(err, 'CSV stream error'));
|
|
268
|
+
fileStream.on('error', err => handleError(err, 'File write error'));
|
|
269
|
+
cursor.on('data', (row) => {
|
|
270
|
+
rowCount++;
|
|
271
|
+
let outputRow = {};
|
|
272
|
+
for (const col of columns) {
|
|
273
|
+
const rawValue = row[col.key];
|
|
274
|
+
const formattedValue = col.formatter ? col.formatter(rawValue) : rawValue;
|
|
275
|
+
outputRow[col.key] = formattedValue;
|
|
276
|
+
}
|
|
277
|
+
const canContinue = csvStream.write(columns.length ? outputRow : row);
|
|
278
|
+
if (!canContinue) {
|
|
279
|
+
shouldPause = true;
|
|
280
|
+
cursor.pause();
|
|
281
|
+
}
|
|
282
|
+
// 📈 每 batch 更新进度
|
|
283
|
+
if (rowCount % batchSize === 0 || rowCount === totalRows) {
|
|
284
|
+
console.log(`process:${rowCount}/${totalRows}`);
|
|
285
|
+
this.processUpdate({ taskId, current: rowCount, total: totalRows });
|
|
286
|
+
}
|
|
287
|
+
});
|
|
288
|
+
cursor.on('end', () => {
|
|
289
|
+
csvStream.end(); // 触发 'finish'
|
|
290
|
+
});
|
|
291
|
+
csvStream.on('drain', () => {
|
|
292
|
+
if (shouldPause) {
|
|
293
|
+
shouldPause = false;
|
|
294
|
+
cursor.resume();
|
|
295
|
+
}
|
|
296
|
+
});
|
|
297
|
+
csvStream.on('finish', () => {
|
|
298
|
+
if (onCompleted) {
|
|
299
|
+
onCompleted({
|
|
300
|
+
taskId,
|
|
301
|
+
rowCount,
|
|
302
|
+
outputPath: `${finalOutputPath}.csv.gz`,
|
|
303
|
+
status: ProcessStatus.COMPLETED,
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
// console.log(`🎉 Export completed! Total rows: ${rowCount}`);
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
//查询任务状态
|
|
310
|
+
async getTaskStatus(params) {
|
|
311
|
+
const { taskIdList } = params;
|
|
312
|
+
const keys = taskIdList.map(val => {
|
|
313
|
+
return `export:${val}`;
|
|
314
|
+
});
|
|
315
|
+
let result = await this.redisClient.mget(keys);
|
|
316
|
+
let processList = result.map(val => {
|
|
317
|
+
return val ? JSON.parse(val) : {};
|
|
318
|
+
});
|
|
319
|
+
return processList;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { RedisOptions } from 'ioredis';
|
|
2
|
+
import type { Document, Filter, MongoClientOptions } from 'mongodb';
|
|
3
|
+
import type { ConnectionOptions } from 'mysql2';
|
|
4
|
+
export interface ExportUtilsOptions {
|
|
5
|
+
type: 'mysql' | 'mongodb';
|
|
6
|
+
mysqlOptions?: ConnectionOptions;
|
|
7
|
+
mongoOptions?: {
|
|
8
|
+
url: string;
|
|
9
|
+
options?: MongoClientOptions;
|
|
10
|
+
};
|
|
11
|
+
redisOptions: RedisOptions;
|
|
12
|
+
}
|
|
13
|
+
export type ExportCompletedHook = (result: ExportResult) => void | Promise<void>;
|
|
14
|
+
export type ExportErrHook = (result: ExportErr) => void | Promise<void>;
|
|
15
|
+
export interface ExportResult {
|
|
16
|
+
outputPath: string;
|
|
17
|
+
rowCount: number;
|
|
18
|
+
status: ProcessStatus;
|
|
19
|
+
taskId: string;
|
|
20
|
+
}
|
|
21
|
+
export interface ExportErr {
|
|
22
|
+
taskId: string;
|
|
23
|
+
errMsg: string;
|
|
24
|
+
status: ProcessStatus;
|
|
25
|
+
}
|
|
26
|
+
export interface ExportOptions {
|
|
27
|
+
outputPath: string;
|
|
28
|
+
columns?: ExportColumn[];
|
|
29
|
+
batchSize?: number;
|
|
30
|
+
onCompleted?: ExportCompletedHook;
|
|
31
|
+
onErr?: ExportErrHook;
|
|
32
|
+
}
|
|
33
|
+
export interface ExportMysqlOptions extends ExportOptions {
|
|
34
|
+
table: string;
|
|
35
|
+
where?: string;
|
|
36
|
+
}
|
|
37
|
+
export interface ExportMongoOptions extends ExportOptions {
|
|
38
|
+
db: string;
|
|
39
|
+
collection: string;
|
|
40
|
+
query?: Filter<Document>;
|
|
41
|
+
}
|
|
42
|
+
export interface ProcessUpdateParams {
|
|
43
|
+
taskId: string;
|
|
44
|
+
current?: number;
|
|
45
|
+
total?: number;
|
|
46
|
+
errMsg?: string;
|
|
47
|
+
}
|
|
48
|
+
export declare enum ProcessStatus {
|
|
49
|
+
RUNNING = "running",
|
|
50
|
+
COMPLETED = "completed",
|
|
51
|
+
FAILED = "failed"
|
|
52
|
+
}
|
|
53
|
+
export interface TaskProcessInput {
|
|
54
|
+
taskIdList: string[];
|
|
55
|
+
}
|
|
56
|
+
export interface TaskProcessResult {
|
|
57
|
+
taskId: string;
|
|
58
|
+
status: ProcessStatus;
|
|
59
|
+
current: number;
|
|
60
|
+
total: number;
|
|
61
|
+
progress: string;
|
|
62
|
+
errMsg?: string;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* 列配置(通用)
|
|
66
|
+
*/
|
|
67
|
+
export interface ExportColumn {
|
|
68
|
+
key: string;
|
|
69
|
+
header?: string;
|
|
70
|
+
formatter?: (value: any) => string;
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AACpE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,QAAQ,CAAC;AAGhD,MAAM,WAAW,kBAAkB;IAC/B,IAAI,EAAE,OAAO,GAAG,SAAS,CAAC;IAC1B,YAAY,CAAC,EAAE,iBAAiB,CAAC;IACjC,YAAY,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,kBAAkB,CAAA;KAAE,CAAC;IAC7D,YAAY,EAAE,YAAY,CAAC;CAC9B;AAGD,MAAM,MAAM,mBAAmB,GAAG,CAAC,MAAM,EAAE,YAAY,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AACjF,MAAM,MAAM,aAAa,GAAG,CAAC,MAAM,EAAE,SAAS,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAGxE,MAAM,WAAW,YAAY;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,aAAa,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;CAClB;AAGD,MAAM,WAAW,SAAS;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,aAAa,CAAC;CACzB;AAGD,MAAM,WAAW,aAAa;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,YAAY,EAAE,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,mBAAmB,CAAC;IAClC,KAAK,CAAC,EAAE,aAAa,CAAC;CACzB;AAGD,MAAM,WAAW,kBAAmB,SAAQ,aAAa;IACrD,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAClB;AAGD,MAAM,WAAW,kBAAmB,SAAQ,aAAa;IACrD,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;CAC5B;AAGD,MAAM,WAAW,mBAAmB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB;AAGD,oBAAY,aAAa;IACrB,OAAO,YAAY;IACnB,SAAS,cAAc;IACvB,MAAM,WAAW;CACpB;AAGD,MAAM,WAAW,gBAAgB;IAC7B,UAAU,EAAE,MAAM,EAAE,CAAC;CACxB;AAGD,MAAM,WAAW,iBAAiB;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,aAAa,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,MAAM,CAAC;CACtC"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
//任务状态枚举
|
|
2
|
+
export var ProcessStatus;
|
|
3
|
+
(function (ProcessStatus) {
|
|
4
|
+
ProcessStatus["RUNNING"] = "running";
|
|
5
|
+
ProcessStatus["COMPLETED"] = "completed";
|
|
6
|
+
ProcessStatus["FAILED"] = "failed";
|
|
7
|
+
})(ProcessStatus || (ProcessStatus = {}));
|
|
8
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AA8DA,QAAQ;AACR,MAAM,CAAN,IAAY,aAIX;AAJD,WAAY,aAAa;IACrB,oCAAmB,CAAA;IACnB,wCAAuB,CAAA;IACvB,kCAAiB,CAAA;AACrB,CAAC,EAJW,aAAa,KAAb,aAAa,QAIxB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../src/utils/tools.ts"],"names":[],"mappings":"AACA,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAEtD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../../src/utils/tools.ts"],"names":[],"mappings":"AAAA,6BAA6B;AAC7B,MAAM,UAAU,iBAAiB,CAAC,GAAW;IACzC,OAAO,0BAA0B,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAChD,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@sch_cat/export-utils",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "A lightweight CSV/Excel export utility for TS with TypeORM support",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"import": "./dist/index.js",
|
|
9
|
+
"types": "./dist/index.d.ts"
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
"main": "./dist/index.js",
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsc",
|
|
16
|
+
"dev:mysql": "tsx examples/export-mysql.ts",
|
|
17
|
+
"dev:mongo": "tsx examples/export-mongo.ts",
|
|
18
|
+
"start": "node dist/examples/run.js",
|
|
19
|
+
"prepack": "npm run build",
|
|
20
|
+
"test": "echo \"No tests yet\"",
|
|
21
|
+
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
|
|
22
|
+
"format": "prettier --write \"src/**/*.ts\""
|
|
23
|
+
},
|
|
24
|
+
"keywords": [
|
|
25
|
+
"ts",
|
|
26
|
+
"export",
|
|
27
|
+
"csv",
|
|
28
|
+
"typeorm",
|
|
29
|
+
"microservice"
|
|
30
|
+
],
|
|
31
|
+
"author": "501241320@qq.com",
|
|
32
|
+
"license": "MIT",
|
|
33
|
+
"files": [
|
|
34
|
+
"dist",
|
|
35
|
+
"README.md",
|
|
36
|
+
"LICENSE"
|
|
37
|
+
],
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@types/node": "^25.0.10",
|
|
40
|
+
"@typescript-eslint/eslint-plugin": "^8.54.0",
|
|
41
|
+
"@typescript-eslint/parser": "^8.54.0",
|
|
42
|
+
"eslint": "^9.39.2",
|
|
43
|
+
"eslint-config-prettier": "^10.1.8",
|
|
44
|
+
"eslint-plugin-import": "^2.32.0",
|
|
45
|
+
"eslint-plugin-prettier": "^5.5.5",
|
|
46
|
+
"eslint-plugin-unused-imports": "^4.3.0",
|
|
47
|
+
"prettier": "^3.8.1",
|
|
48
|
+
"tsx": "^4.21.0",
|
|
49
|
+
"typescript": "^5.9.3"
|
|
50
|
+
},
|
|
51
|
+
"dependencies": {
|
|
52
|
+
"csv-stringify": "^6.6.0",
|
|
53
|
+
"ioredis": "^5.9.2",
|
|
54
|
+
"mongodb": "^7.0.0",
|
|
55
|
+
"mysql2": "^3.16.2",
|
|
56
|
+
"uuid": "^13.0.0",
|
|
57
|
+
"zlib": "^1.0.5"
|
|
58
|
+
}
|
|
59
|
+
}
|