befly 3.19.9 → 3.20.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/checks/config.js +3 -3
- package/configs/beflyConfig.json +1 -2
- package/configs/constConfig.js +0 -3
- package/lib/connect.js +2 -1
- package/lib/dbHelper/builders.js +13 -12
- package/lib/dbHelper/dataOps.js +42 -37
- package/lib/dbHelper/index.js +1 -2
- package/lib/dbHelper/util.js +13 -75
- package/package.json +2 -2
- package/plugins/mysql.js +0 -1
- package/scripts/syncDb/context.js +2 -2
- package/scripts/syncDb/diff.js +19 -3
package/checks/config.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as z from "zod";
|
|
2
2
|
|
|
3
3
|
import { Logger } from "../lib/logger.js";
|
|
4
|
-
import {
|
|
4
|
+
import { RUN_MODE_VALUES } from "../configs/constConfig.js";
|
|
5
5
|
import { formatZodIssues } from "../utils/formatZodIssues.js";
|
|
6
6
|
import { isNoTrimStringAllowEmpty, isValidTimeZone } from "../utils/is.js";
|
|
7
7
|
|
|
@@ -9,6 +9,7 @@ z.config(z.locales.zhCN());
|
|
|
9
9
|
|
|
10
10
|
const boolIntSchema = z.union([z.literal(0), z.literal(1), z.literal(true), z.literal(false)]);
|
|
11
11
|
const noTrimString = z.string().refine(isNoTrimStringAllowEmpty, "不允许首尾空格");
|
|
12
|
+
const beflyModeSchema = z.union([z.literal("manual"), z.literal("auto")]);
|
|
12
13
|
|
|
13
14
|
const configSchema = z
|
|
14
15
|
.object({
|
|
@@ -36,14 +37,13 @@ const configSchema = z
|
|
|
36
37
|
|
|
37
38
|
mysql: z
|
|
38
39
|
.object({
|
|
39
|
-
idMode: z.enum(DB_ID_MODE_VALUES),
|
|
40
40
|
hostname: noTrimString,
|
|
41
41
|
port: z.int().min(1).max(65535),
|
|
42
42
|
username: noTrimString,
|
|
43
43
|
password: noTrimString,
|
|
44
44
|
database: noTrimString,
|
|
45
45
|
max: z.number().min(1),
|
|
46
|
-
beflyMode:
|
|
46
|
+
beflyMode: beflyModeSchema.optional()
|
|
47
47
|
})
|
|
48
48
|
.strict(),
|
|
49
49
|
|
package/configs/beflyConfig.json
CHANGED
|
@@ -20,14 +20,13 @@
|
|
|
20
20
|
},
|
|
21
21
|
|
|
22
22
|
"mysql": {
|
|
23
|
-
"idMode": "timeId",
|
|
24
23
|
"hostname": "127.0.0.1",
|
|
25
24
|
"port": 3306,
|
|
26
25
|
"username": "root",
|
|
27
26
|
"password": "root",
|
|
28
27
|
"database": "befly_dev",
|
|
29
28
|
"max": 10,
|
|
30
|
-
"beflyMode":
|
|
29
|
+
"beflyMode": "auto"
|
|
31
30
|
},
|
|
32
31
|
|
|
33
32
|
"redis": {
|
package/configs/constConfig.js
CHANGED
|
@@ -30,9 +30,6 @@ export const ENUM_KIND_TYPES = ["enum"];
|
|
|
30
30
|
// 运行模式可选值
|
|
31
31
|
export const RUN_MODE_VALUES = ["development", "production"];
|
|
32
32
|
|
|
33
|
-
// 数据库 ID 生成模式可选值
|
|
34
|
-
export const DB_ID_MODE_VALUES = ["timeId", "autoId"];
|
|
35
|
-
|
|
36
33
|
// ==========================
|
|
37
34
|
// 字段验证规则配置
|
|
38
35
|
// ==========================
|
package/lib/connect.js
CHANGED
package/lib/dbHelper/builders.js
CHANGED
|
@@ -2,7 +2,7 @@ import { fieldClear } from "../../utils/fieldClear.js";
|
|
|
2
2
|
import { isFiniteNumber, isNonEmptyString, isNullable, isPlainObject, isString } from "../../utils/is.js";
|
|
3
3
|
import { arrayKeysToCamel, keysToCamel, keysToSnake, snakeCase } from "../../utils/util.js";
|
|
4
4
|
import { SqlBuilder } from "../sqlBuilder/index.js";
|
|
5
|
-
import {
|
|
5
|
+
import { getJoinMainQualifier, normalizeBigIntValues, normalizeTableRef, quoteIdentMySql } from "./util.js";
|
|
6
6
|
import { assertNoExprField, validateAndClassifyFields, validateExcludeFieldsResult, validateQueryOptions, validateTimeIdValue } from "./validate.js";
|
|
7
7
|
|
|
8
8
|
export function clearDeep(value, options) {
|
|
@@ -354,8 +354,8 @@ export function processJoinOn(on) {
|
|
|
354
354
|
return result;
|
|
355
355
|
}
|
|
356
356
|
|
|
357
|
-
export function addDefaultStateFilter(where = {}, table, hasJoins = false, beflyMode =
|
|
358
|
-
if (beflyMode ===
|
|
357
|
+
export function addDefaultStateFilter(where = {}, table, hasJoins = false, beflyMode = "auto") {
|
|
358
|
+
if (beflyMode === "manual") {
|
|
359
359
|
return where;
|
|
360
360
|
}
|
|
361
361
|
|
|
@@ -488,12 +488,12 @@ export function buildInsertRow(options) {
|
|
|
488
488
|
result[key] = value;
|
|
489
489
|
}
|
|
490
490
|
|
|
491
|
-
if (options.
|
|
491
|
+
if (options.beflyMode === "auto") {
|
|
492
492
|
validateTimeIdValue(options.id);
|
|
493
493
|
result["id"] = options.id;
|
|
494
494
|
}
|
|
495
495
|
|
|
496
|
-
if (options.beflyMode !==
|
|
496
|
+
if (options.beflyMode !== "manual") {
|
|
497
497
|
result["created_at"] = options.now;
|
|
498
498
|
result["updated_at"] = options.now;
|
|
499
499
|
result["state"] = 1;
|
|
@@ -509,7 +509,7 @@ export function buildUpdateRow(options) {
|
|
|
509
509
|
for (const [key, value] of Object.entries(userData)) {
|
|
510
510
|
result[key] = value;
|
|
511
511
|
}
|
|
512
|
-
if (options.beflyMode !==
|
|
512
|
+
if (options.beflyMode !== "manual") {
|
|
513
513
|
result["updated_at"] = options.now;
|
|
514
514
|
}
|
|
515
515
|
return result;
|
|
@@ -542,14 +542,16 @@ export const builderMethods = {
|
|
|
542
542
|
this.applyJoins(builder, prepared.joins);
|
|
543
543
|
const result = builder.toSelectSql();
|
|
544
544
|
const executeRes = await this.execute(result.sql, result.params);
|
|
545
|
-
const
|
|
545
|
+
const countRow = executeRes.data?.[0] || null;
|
|
546
|
+
const normalizedCountRow = countRow ? normalizeBigIntValues(countRow) : null;
|
|
547
|
+
const total = normalizedCountRow?.total ?? normalizedCountRow?.count ?? 0;
|
|
546
548
|
return {
|
|
547
549
|
total: total,
|
|
548
550
|
sql: executeRes.sql
|
|
549
551
|
};
|
|
550
552
|
},
|
|
551
553
|
|
|
552
|
-
normalizeRowData(row
|
|
554
|
+
normalizeRowData(row) {
|
|
553
555
|
if (!row) {
|
|
554
556
|
return {};
|
|
555
557
|
}
|
|
@@ -560,7 +562,7 @@ export const builderMethods = {
|
|
|
560
562
|
return {};
|
|
561
563
|
}
|
|
562
564
|
|
|
563
|
-
const convertedList =
|
|
565
|
+
const convertedList = normalizeBigIntValues([deserialized]);
|
|
564
566
|
if (convertedList && convertedList.length > 0) {
|
|
565
567
|
return convertedList[0];
|
|
566
568
|
}
|
|
@@ -568,10 +570,10 @@ export const builderMethods = {
|
|
|
568
570
|
return deserialized;
|
|
569
571
|
},
|
|
570
572
|
|
|
571
|
-
normalizeListData(list
|
|
573
|
+
normalizeListData(list) {
|
|
572
574
|
const camelList = arrayKeysToCamel(list);
|
|
573
575
|
const deserializedList = camelList.map((item) => deserializeArrayFields(item)).filter((item) => item !== null);
|
|
574
|
-
return
|
|
576
|
+
return normalizeBigIntValues(deserializedList);
|
|
575
577
|
},
|
|
576
578
|
|
|
577
579
|
normalizeJoinOptions(options, cleanWhere) {
|
|
@@ -615,7 +617,6 @@ export const builderMethods = {
|
|
|
615
617
|
};
|
|
616
618
|
|
|
617
619
|
if (options.fields !== undefined) output.fields = options.fields;
|
|
618
|
-
if (options.bigint !== undefined) output.bigint = options.bigint;
|
|
619
620
|
if (options.where !== undefined) output.where = options.where;
|
|
620
621
|
if (options.joins !== undefined) output.joins = options.joins;
|
|
621
622
|
if (options.orderBy !== undefined) output.orderBy = options.orderBy;
|
package/lib/dbHelper/dataOps.js
CHANGED
|
@@ -2,7 +2,7 @@ import { isNumber } from "../../utils/is.js";
|
|
|
2
2
|
import { snakeCase } from "../../utils/util.js";
|
|
3
3
|
import { Logger } from "../logger.js";
|
|
4
4
|
import { SqlBuilder } from "../sqlBuilder/index.js";
|
|
5
|
-
import {
|
|
5
|
+
import { normalizeSqlMetaNumber, quoteIdentMySql } from "./util.js";
|
|
6
6
|
import { addDefaultStateFilter, buildInsertRow, buildPartialUpdateData, buildUpdateRow, clearDeep, whereKeysToSnake } from "./builders.js";
|
|
7
7
|
import { assertBatchInsertRowsConsistent, assertNoUndefinedInRecord, validateGeneratedBatchId, validateIncrementOptions, validateInsertBatchSize, validateNoJoinReadOptions, validatePageLimitRange, validateSafeFieldName, validateTableBatchDataOptions, validateTableDataOptions, validateTableName, validateTableWhereOptions } from "./validate.js";
|
|
8
8
|
|
|
@@ -33,7 +33,7 @@ export const dataOpsMethods = {
|
|
|
33
33
|
const executeRes = await this.execute(sql, params);
|
|
34
34
|
const result = executeRes.data;
|
|
35
35
|
|
|
36
|
-
const data = this.normalizeRowData(result?.[0] || null
|
|
36
|
+
const data = this.normalizeRowData(result?.[0] || null);
|
|
37
37
|
return {
|
|
38
38
|
data: data,
|
|
39
39
|
sql: executeRes.sql
|
|
@@ -81,7 +81,7 @@ export const dataOpsMethods = {
|
|
|
81
81
|
|
|
82
82
|
return {
|
|
83
83
|
data: {
|
|
84
|
-
lists: this.normalizeListData(list
|
|
84
|
+
lists: this.normalizeListData(list),
|
|
85
85
|
total: total,
|
|
86
86
|
page: prepared.page,
|
|
87
87
|
limit: prepared.limit,
|
|
@@ -131,7 +131,7 @@ export const dataOpsMethods = {
|
|
|
131
131
|
Logger.warn(`getAll 达到最大限制 ${MAX_LIMIT},实际总数 ${total},只返回前 ${MAX_LIMIT} 条`, { table: options.table, limit: MAX_LIMIT, total: total });
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
-
const lists = this.normalizeListData(result
|
|
134
|
+
const lists = this.normalizeListData(result);
|
|
135
135
|
|
|
136
136
|
return {
|
|
137
137
|
data: {
|
|
@@ -192,9 +192,8 @@ export const dataOpsMethods = {
|
|
|
192
192
|
const now = Date.now();
|
|
193
193
|
|
|
194
194
|
let processed;
|
|
195
|
-
if (this.
|
|
195
|
+
if (this.beflyMode === "manual") {
|
|
196
196
|
processed = buildInsertRow({
|
|
197
|
-
idMode: "autoId",
|
|
198
197
|
data: data,
|
|
199
198
|
now: now,
|
|
200
199
|
beflyMode: this.beflyMode
|
|
@@ -213,7 +212,6 @@ export const dataOpsMethods = {
|
|
|
213
212
|
});
|
|
214
213
|
}
|
|
215
214
|
processed = buildInsertRow({
|
|
216
|
-
idMode: "timeId",
|
|
217
215
|
data: data,
|
|
218
216
|
id: id,
|
|
219
217
|
now: now,
|
|
@@ -229,11 +227,11 @@ export const dataOpsMethods = {
|
|
|
229
227
|
|
|
230
228
|
const processedId = processed["id"];
|
|
231
229
|
const processedIdNum = isNumber(processedId) ? processedId : 0;
|
|
232
|
-
const lastInsertRowidNum =
|
|
230
|
+
const lastInsertRowidNum = normalizeSqlMetaNumber(executeRes.data?.lastInsertRowid);
|
|
233
231
|
|
|
234
|
-
const insertedId = this.
|
|
235
|
-
if (this.
|
|
236
|
-
throw new Error(`插入失败:
|
|
232
|
+
const insertedId = this.beflyMode === "manual" ? lastInsertRowidNum || 0 : processedIdNum || lastInsertRowidNum || 0;
|
|
233
|
+
if (this.beflyMode === "manual" && insertedId <= 0) {
|
|
234
|
+
throw new Error(`插入失败:beflyMode=manual 时无法获取 lastInsertRowid (table: ${table})`, {
|
|
237
235
|
cause: null,
|
|
238
236
|
code: "runtime"
|
|
239
237
|
});
|
|
@@ -261,9 +259,9 @@ export const dataOpsMethods = {
|
|
|
261
259
|
let ids = [];
|
|
262
260
|
|
|
263
261
|
let processedList;
|
|
264
|
-
if (this.
|
|
262
|
+
if (this.beflyMode === "manual") {
|
|
265
263
|
processedList = dataList.map((data) => {
|
|
266
|
-
return buildInsertRow({
|
|
264
|
+
return buildInsertRow({ data: data, now: now, beflyMode: this.beflyMode });
|
|
267
265
|
});
|
|
268
266
|
} else {
|
|
269
267
|
const nextIds = [];
|
|
@@ -274,7 +272,7 @@ export const dataOpsMethods = {
|
|
|
274
272
|
processedList = dataList.map((data, index) => {
|
|
275
273
|
const id = nextIds[index];
|
|
276
274
|
validateGeneratedBatchId(id, snakeTable, index);
|
|
277
|
-
return buildInsertRow({
|
|
275
|
+
return buildInsertRow({ data: data, id: id, now: now, beflyMode: this.beflyMode });
|
|
278
276
|
});
|
|
279
277
|
}
|
|
280
278
|
|
|
@@ -285,10 +283,10 @@ export const dataOpsMethods = {
|
|
|
285
283
|
try {
|
|
286
284
|
const executeRes = await this.execute(sql, params);
|
|
287
285
|
|
|
288
|
-
if (this.
|
|
289
|
-
const firstId =
|
|
286
|
+
if (this.beflyMode === "manual") {
|
|
287
|
+
const firstId = normalizeSqlMetaNumber(executeRes.data?.lastInsertRowid);
|
|
290
288
|
if (firstId <= 0) {
|
|
291
|
-
throw new Error(`批量插入失败:
|
|
289
|
+
throw new Error(`批量插入失败:beflyMode=manual 时无法获取 lastInsertRowid (table: ${table})`, {
|
|
292
290
|
cause: null,
|
|
293
291
|
code: "runtime"
|
|
294
292
|
});
|
|
@@ -347,7 +345,7 @@ export const dataOpsMethods = {
|
|
|
347
345
|
quoteIdent: quoteIdentMySql
|
|
348
346
|
});
|
|
349
347
|
const executeRes = await this.execute(query.sql, query.params);
|
|
350
|
-
const changes =
|
|
348
|
+
const changes = normalizeSqlMetaNumber(executeRes.data?.affectedRows);
|
|
351
349
|
return {
|
|
352
350
|
data: changes,
|
|
353
351
|
sql: executeRes.sql
|
|
@@ -393,14 +391,14 @@ export const dataOpsMethods = {
|
|
|
393
391
|
rows: processedList,
|
|
394
392
|
fields: fields,
|
|
395
393
|
quoteIdent: quoteIdentMySql,
|
|
396
|
-
updatedAtField: this.beflyMode ===
|
|
397
|
-
updatedAtValue: this.beflyMode ===
|
|
394
|
+
updatedAtField: this.beflyMode === "auto" ? "updated_at" : "",
|
|
395
|
+
updatedAtValue: this.beflyMode === "auto" ? now : null,
|
|
398
396
|
stateField: "state",
|
|
399
|
-
stateGtZero: this.beflyMode ===
|
|
397
|
+
stateGtZero: this.beflyMode === "auto"
|
|
400
398
|
});
|
|
401
399
|
|
|
402
400
|
const executeRes = await this.execute(query.sql, query.params);
|
|
403
|
-
const changes =
|
|
401
|
+
const changes = normalizeSqlMetaNumber(executeRes.data?.affectedRows);
|
|
404
402
|
return {
|
|
405
403
|
data: changes,
|
|
406
404
|
sql: executeRes.sql
|
|
@@ -420,7 +418,7 @@ export const dataOpsMethods = {
|
|
|
420
418
|
const { sql, params } = builder.toUpdateSql(snakeTable, processed);
|
|
421
419
|
|
|
422
420
|
const executeRes = await this.execute(sql, params);
|
|
423
|
-
const changes =
|
|
421
|
+
const changes = normalizeSqlMetaNumber(executeRes.data?.affectedRows);
|
|
424
422
|
return {
|
|
425
423
|
data: changes,
|
|
426
424
|
sql: executeRes.sql
|
|
@@ -430,20 +428,28 @@ export const dataOpsMethods = {
|
|
|
430
428
|
async delData(options) {
|
|
431
429
|
validateTableWhereOptions(options, "delData", true);
|
|
432
430
|
const { table, where } = options;
|
|
431
|
+
const snakeTable = snakeCase(table);
|
|
432
|
+
const snakeWhere = whereKeysToSnake(clearDeep(where));
|
|
433
|
+
const now = Date.now();
|
|
434
|
+
const processed = {
|
|
435
|
+
state: 0,
|
|
436
|
+
deleted_at: now
|
|
437
|
+
};
|
|
433
438
|
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
return await this.delForce({
|
|
437
|
-
table: table,
|
|
438
|
-
where: where
|
|
439
|
-
});
|
|
439
|
+
if (this.beflyMode === "auto") {
|
|
440
|
+
processed.updated_at = now;
|
|
440
441
|
}
|
|
441
442
|
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
443
|
+
const whereFiltered = addDefaultStateFilter(snakeWhere, snakeTable, false, this.beflyMode);
|
|
444
|
+
const builder = this.createSqlBuilder().where(whereFiltered);
|
|
445
|
+
const { sql, params } = builder.toUpdateSql(snakeTable, processed);
|
|
446
|
+
const executeRes = await this.execute(sql, params);
|
|
447
|
+
const changes = normalizeSqlMetaNumber(executeRes.data?.affectedRows);
|
|
448
|
+
|
|
449
|
+
return {
|
|
450
|
+
data: changes,
|
|
451
|
+
sql: executeRes.sql
|
|
452
|
+
};
|
|
447
453
|
},
|
|
448
454
|
|
|
449
455
|
async delForce(options) {
|
|
@@ -457,7 +463,7 @@ export const dataOpsMethods = {
|
|
|
457
463
|
const { sql, params } = builder.toDeleteSql(snakeTable);
|
|
458
464
|
|
|
459
465
|
const executeRes = await this.execute(sql, params);
|
|
460
|
-
const changes =
|
|
466
|
+
const changes = normalizeSqlMetaNumber(executeRes.data?.affectedRows);
|
|
461
467
|
return {
|
|
462
468
|
data: changes,
|
|
463
469
|
sql: executeRes.sql
|
|
@@ -510,7 +516,7 @@ export const dataOpsMethods = {
|
|
|
510
516
|
}
|
|
511
517
|
|
|
512
518
|
const executeRes = await this.execute(sql, params);
|
|
513
|
-
const changes =
|
|
519
|
+
const changes = normalizeSqlMetaNumber(executeRes.data?.affectedRows);
|
|
514
520
|
return {
|
|
515
521
|
data: changes,
|
|
516
522
|
sql: executeRes.sql
|
|
@@ -552,7 +558,6 @@ export const dataOpsMethods = {
|
|
|
552
558
|
dbName: this.dbName,
|
|
553
559
|
sql: tx,
|
|
554
560
|
isTransaction: true,
|
|
555
|
-
idMode: this.idMode,
|
|
556
561
|
beflyMode: this.beflyMode
|
|
557
562
|
});
|
|
558
563
|
const result = await callback(trans);
|
package/lib/dbHelper/index.js
CHANGED
|
@@ -16,8 +16,7 @@ function DbHelper(options) {
|
|
|
16
16
|
|
|
17
17
|
this.sql = options.sql || null;
|
|
18
18
|
this.isTransaction = options.isTransaction === true;
|
|
19
|
-
this.
|
|
20
|
-
this.beflyMode = options.beflyMode === 0 ? 0 : 1;
|
|
19
|
+
this.beflyMode = options.beflyMode === "manual" ? "manual" : "auto";
|
|
21
20
|
}
|
|
22
21
|
|
|
23
22
|
Object.assign(DbHelper.prototype, builderMethods, executeMethods, dataOpsMethods);
|
package/lib/dbHelper/util.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { isNullable, isString } from "../../utils/is.js";
|
|
2
2
|
import { canConvertToNumber, snakeCase } from "../../utils/util.js";
|
|
3
3
|
import { parseTableRef } from "./validate.js";
|
|
4
4
|
|
|
@@ -41,101 +41,39 @@ export function getJoinMainQualifier(tableRef) {
|
|
|
41
41
|
return snakeCase(parsed.table);
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
export function
|
|
44
|
+
export function normalizeSqlMetaNumber(value) {
|
|
45
45
|
if (isNullable(value)) {
|
|
46
46
|
return 0;
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
if (typeof value
|
|
50
|
-
if (!Number.isFinite(value)) {
|
|
51
|
-
return 0;
|
|
52
|
-
}
|
|
53
|
-
return value;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
if (typeof value === "bigint") {
|
|
57
|
-
const maxSafe = BigInt(Number.MAX_SAFE_INTEGER);
|
|
58
|
-
const minSafe = BigInt(Number.MIN_SAFE_INTEGER);
|
|
59
|
-
if (value <= maxSafe && value >= minSafe) {
|
|
60
|
-
return Number(value);
|
|
61
|
-
}
|
|
49
|
+
if (typeof value !== "number") {
|
|
62
50
|
return 0;
|
|
63
51
|
}
|
|
64
52
|
|
|
65
|
-
if (
|
|
66
|
-
|
|
67
|
-
return 0;
|
|
68
|
-
}
|
|
69
|
-
const parsed = Number(value);
|
|
70
|
-
if (!Number.isFinite(parsed)) {
|
|
71
|
-
return 0;
|
|
72
|
-
}
|
|
73
|
-
return parsed;
|
|
53
|
+
if (!Number.isFinite(value)) {
|
|
54
|
+
return 0;
|
|
74
55
|
}
|
|
75
56
|
|
|
76
|
-
return
|
|
57
|
+
return value;
|
|
77
58
|
}
|
|
78
59
|
|
|
79
|
-
export function
|
|
60
|
+
export function normalizeBigIntValues(arr) {
|
|
80
61
|
if (isNullable(arr)) {
|
|
81
62
|
return arr;
|
|
82
63
|
}
|
|
83
64
|
|
|
84
|
-
const defaultFields = ["id", "pid", "sort"];
|
|
85
|
-
|
|
86
|
-
const buildFields = (userFields) => {
|
|
87
|
-
if (!userFields || userFields.length === 0) {
|
|
88
|
-
return defaultFields;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
const merged = ["id", "pid", "sort"];
|
|
92
|
-
for (const f of userFields) {
|
|
93
|
-
if (!isString(f)) {
|
|
94
|
-
continue;
|
|
95
|
-
}
|
|
96
|
-
if (!isNonEmptyString(f)) {
|
|
97
|
-
continue;
|
|
98
|
-
}
|
|
99
|
-
const trimmed = f.trim();
|
|
100
|
-
if (!merged.includes(trimmed)) {
|
|
101
|
-
merged.push(trimmed);
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
return merged;
|
|
105
|
-
};
|
|
106
|
-
|
|
107
|
-
const effectiveFields = buildFields(fields);
|
|
108
|
-
const fieldSet = new Set(effectiveFields);
|
|
109
|
-
|
|
110
65
|
const convertRecord = (source) => {
|
|
111
66
|
const converted = {};
|
|
112
67
|
|
|
113
68
|
for (const [key, value] of Object.entries(source)) {
|
|
114
69
|
let nextValue = value;
|
|
115
70
|
|
|
116
|
-
if (
|
|
117
|
-
const
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
bigintValue = value;
|
|
123
|
-
} else if (isString(value)) {
|
|
124
|
-
if (/^-?\d+$/.test(value)) {
|
|
125
|
-
try {
|
|
126
|
-
bigintValue = BigInt(value);
|
|
127
|
-
} catch {
|
|
128
|
-
bigintValue = null;
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
if (bigintValue !== null) {
|
|
134
|
-
const convertedNumber = canConvertToNumber(bigintValue);
|
|
135
|
-
if (convertedNumber !== null) {
|
|
136
|
-
nextValue = convertedNumber;
|
|
137
|
-
}
|
|
138
|
-
}
|
|
71
|
+
if (typeof value === "bigint") {
|
|
72
|
+
const convertedNumber = canConvertToNumber(value);
|
|
73
|
+
if (convertedNumber !== null) {
|
|
74
|
+
nextValue = convertedNumber;
|
|
75
|
+
} else {
|
|
76
|
+
nextValue = String(value);
|
|
139
77
|
}
|
|
140
78
|
}
|
|
141
79
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "befly",
|
|
3
|
-
"version": "3.
|
|
4
|
-
"gitHead": "
|
|
3
|
+
"version": "3.20.1",
|
|
4
|
+
"gitHead": "8563274caa09eace7480d14da3552aec0ca24296",
|
|
5
5
|
"private": false,
|
|
6
6
|
"description": "Befly - 为 Bun 专属打造的 JavaScript API 接口框架核心引擎",
|
|
7
7
|
"keywords": [
|
package/plugins/mysql.js
CHANGED
|
@@ -64,13 +64,13 @@ export async function prepareSyncDbBaseContext(mysqlConfig) {
|
|
|
64
64
|
});
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
+
printSyncDbProcessLog(`beflyMode=${mysqlConfig.beflyMode === "manual" ? "manual" : "auto"}`);
|
|
67
68
|
printSyncDbProcessLog(`连接 MySQL,database=${mysqlConfig.database}`);
|
|
68
69
|
await Connect.connectMysql(mysqlConfig);
|
|
69
70
|
const mysql = new DbHelper({
|
|
70
71
|
redis: null,
|
|
71
72
|
dbName: mysqlConfig.database,
|
|
72
73
|
sql: Connect.getMysql(),
|
|
73
|
-
idMode: mysqlConfig.idMode,
|
|
74
74
|
beflyMode: mysqlConfig.beflyMode
|
|
75
75
|
});
|
|
76
76
|
|
|
@@ -94,7 +94,7 @@ export async function prepareSyncDbBaseContext(mysqlConfig) {
|
|
|
94
94
|
|
|
95
95
|
const groupedDbColumns = groupSyncDbColumns(dbColumns);
|
|
96
96
|
const existingTableMap = await loadSyncDbTableDefs(tablesDir);
|
|
97
|
-
const diff = buildSyncDbDiff(groupedDbColumns, existingTableMap);
|
|
97
|
+
const diff = buildSyncDbDiff(groupedDbColumns, existingTableMap, mysqlConfig.beflyMode);
|
|
98
98
|
printSyncDbProcessLog(`tables定义文件数量=${existingTableMap.size}`);
|
|
99
99
|
printSyncDbProcessLog(`差异扫描完成,missingTableCount=${diff.missingTables.length},missingFieldCount=${Object.values(diff.missingFieldsByTable).reduce((sum, item) => sum + item.fields.length, 0)}`);
|
|
100
100
|
|
package/scripts/syncDb/diff.js
CHANGED
|
@@ -5,6 +5,17 @@ import { camelCase } from "../../utils/util.js";
|
|
|
5
5
|
import { printSyncDbProcessLog } from "./report.js";
|
|
6
6
|
import { toSyncDbFieldDef } from "./transform.js";
|
|
7
7
|
|
|
8
|
+
const SYNC_DB_MANAGED_FIELD_NAMES = new Set(["id", "created_at", "updated_at", "deleted_at", "state"]);
|
|
9
|
+
|
|
10
|
+
function shouldSkipSyncDbColumn(columnMeta, beflyMode) {
|
|
11
|
+
if (beflyMode !== "manual") {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const columnName = String(columnMeta?.columnName || "").toLowerCase();
|
|
16
|
+
return SYNC_DB_MANAGED_FIELD_NAMES.has(columnName);
|
|
17
|
+
}
|
|
18
|
+
|
|
8
19
|
export function groupSyncDbColumns(rows) {
|
|
9
20
|
const grouped = new Map();
|
|
10
21
|
|
|
@@ -37,26 +48,31 @@ export function groupSyncDbColumns(rows) {
|
|
|
37
48
|
return grouped;
|
|
38
49
|
}
|
|
39
50
|
|
|
40
|
-
export function buildSyncDbDiff(groupedDbColumns, existingTableMap) {
|
|
51
|
+
export function buildSyncDbDiff(groupedDbColumns, existingTableMap, beflyMode = "auto") {
|
|
41
52
|
const missingTables = [];
|
|
42
53
|
const missingFieldsByTable = {};
|
|
43
54
|
|
|
44
55
|
for (const [tableName, columns] of groupedDbColumns.entries()) {
|
|
45
56
|
const tableFileName = camelCase(tableName);
|
|
46
57
|
const existing = existingTableMap.get(String(tableFileName).toLowerCase());
|
|
58
|
+
const filteredColumns = columns.filter((columnMeta) => !shouldSkipSyncDbColumn(columnMeta, beflyMode));
|
|
47
59
|
|
|
48
60
|
if (!existing) {
|
|
61
|
+
if (filteredColumns.length === 0) {
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
|
|
49
65
|
missingTables.push({
|
|
50
66
|
tableName: tableName,
|
|
51
67
|
tableFileName: tableFileName,
|
|
52
|
-
columns:
|
|
68
|
+
columns: filteredColumns
|
|
53
69
|
});
|
|
54
70
|
continue;
|
|
55
71
|
}
|
|
56
72
|
|
|
57
73
|
const existingFields = isPlainObject(existing.tableDef) ? existing.tableDef : {};
|
|
58
74
|
const missingFields = [];
|
|
59
|
-
for (const columnMeta of
|
|
75
|
+
for (const columnMeta of filteredColumns) {
|
|
60
76
|
const fieldInfo = toSyncDbFieldDef(columnMeta);
|
|
61
77
|
if (Object.hasOwn(existingFields, fieldInfo.fieldName)) {
|
|
62
78
|
continue;
|