befly 3.15.4 → 3.15.6

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.
@@ -338,6 +338,12 @@ export class SyncTable {
338
338
  .replace(/\s*unsigned/gi, "")
339
339
  .replace(/\([^)]*\)/g, "")
340
340
  .trim();
341
+ // TEXT 家族:允许互相转换(包含收缩),交由数据库自身约束(可能截断/报错)。
342
+ // 目的:兼容历史库里已有的 TEXT / MEDIUMTEXT / LONGTEXT 等差异。
343
+ const textFamily = ["tinytext", "text", "mediumtext", "longtext"];
344
+ if (textFamily.includes(cBase) && textFamily.includes(nBase)) {
345
+ return true;
346
+ }
341
347
  const intTypes = ["tinyint", "smallint", "mediumint", "int", "integer", "bigint"];
342
348
  const cIntIdx = intTypes.indexOf(cBase);
343
349
  const nIntIdx = intTypes.indexOf(nBase);
@@ -512,7 +518,6 @@ export class SyncTable {
512
518
  const stmt = SyncTable.buildIndexSQL(tableName, act.indexName, act.fieldName, act.action);
513
519
  try {
514
520
  await db.unsafe(stmt);
515
- Logger.debug(`[索引变化] 删除索引 ${tableName}.${act.indexName} (${act.fieldName})`);
516
521
  }
517
522
  catch (error) {
518
523
  Logger.error({ err: error, table: tableName, index: act.indexName, field: act.fieldName, msg: "删除索引失败" });
@@ -534,7 +539,6 @@ export class SyncTable {
534
539
  const stmt = SyncTable.buildIndexSQL(tableName, act.indexName, act.fieldName, act.action);
535
540
  try {
536
541
  await db.unsafe(stmt);
537
- Logger.debug(`[索引变化] 新建索引 ${tableName}.${act.indexName} (${act.fieldName})`);
538
542
  }
539
543
  catch (error) {
540
544
  Logger.error({ err: error, table: tableName, index: act.indexName, field: act.fieldName, msg: "创建索引失败" });
@@ -552,6 +556,7 @@ export class SyncTable {
552
556
  const { ENGINE, CHARSET, COLLATE } = SyncTable.MYSQL_TABLE_CONFIG;
553
557
  const createSQL = `CREATE TABLE ${tableQuoted} (\n ${cols}\n ) ENGINE=${ENGINE} DEFAULT CHARSET=${CHARSET} COLLATE=${COLLATE}`;
554
558
  await db.unsafe(createSQL);
559
+ Logger.debug(`[表 ${tableName}] + 创建表(系统字段 + 业务字段)`);
555
560
  const indexTasks = [];
556
561
  const existingIndexes = {};
557
562
  for (const sysField of systemIndexFields) {
@@ -585,15 +590,18 @@ export class SyncTable {
585
590
  const modifyClauses = [];
586
591
  const defaultClauses = [];
587
592
  const indexActions = [];
593
+ // 汇总输出(默认仅打印汇总,避免逐条日志刷屏)
594
+ const addedBusinessFields = [];
595
+ const addedSystemFields = [];
596
+ const modifiedFields = [];
597
+ const defaultOnlyChangedFields = [];
598
+ const compatibleTypeChanges = [];
588
599
  for (const [fieldKey, fieldDef] of Object.entries(fields)) {
589
600
  const dbFieldName = snakeCase(fieldKey);
590
601
  if (existingColumns[dbFieldName]) {
591
602
  const comparison = SyncTable.compareFieldDefinition(existingColumns[dbFieldName], fieldDef);
592
603
  if (comparison.length > 0) {
593
- for (const c of comparison) {
594
- const changeLabel = SyncTable.CHANGE_TYPE_LABELS[c.type] || "未知";
595
- Logger.debug(` ~ 修改 ${dbFieldName} ${changeLabel}: ${c.current} -> ${c.expected}`);
596
- }
604
+ modifiedFields.push(dbFieldName);
597
605
  const hasTypeChange = comparison.some((c) => c.type === "datatype");
598
606
  const onlyDefaultChanged = comparison.every((c) => c.type === "default");
599
607
  const defaultChanged = comparison.some((c) => c.type === "default");
@@ -606,7 +614,7 @@ export class SyncTable {
606
614
  const errorMsg = [`禁止字段类型变更: ${tableName}.${dbFieldName}`, `当前类型: ${typeChange?.current}`, `目标类型: ${typeChange?.expected}`, "说明: 仅允许宽化型变更(如 INT->BIGINT, VARCHAR->TEXT),其他类型变更需要手动处理"].join("\n");
607
615
  throw new Error(errorMsg);
608
616
  }
609
- Logger.debug(`[兼容类型变更] ${tableName}.${dbFieldName} ${currentType} -> ${expectedType}`);
617
+ compatibleTypeChanges.push(`${dbFieldName}: ${currentType} -> ${expectedType}`);
610
618
  }
611
619
  if (defaultChanged) {
612
620
  const actualDefault = SyncTable.resolveDefaultValue(fieldDef.default ?? null, fieldDef.type);
@@ -619,6 +627,7 @@ export class SyncTable {
619
627
  if (fieldDef.type !== "text") {
620
628
  const colQuoted = SyncTable.quoteIdentifier(dbFieldName);
621
629
  defaultClauses.push(`ALTER COLUMN ${colQuoted} SET DEFAULT ${v}`);
630
+ defaultOnlyChangedFields.push(dbFieldName);
622
631
  }
623
632
  }
624
633
  }
@@ -629,6 +638,7 @@ export class SyncTable {
629
638
  }
630
639
  }
631
640
  else {
641
+ addedBusinessFields.push(dbFieldName);
632
642
  addClauses.push(SyncTable.generateDDLClause(fieldKey, fieldDef, true));
633
643
  changed = true;
634
644
  }
@@ -638,7 +648,7 @@ export class SyncTable {
638
648
  if (!existingColumns[sysFieldName]) {
639
649
  const colDef = SyncTable.getSystemColumnDef(sysFieldName);
640
650
  if (colDef) {
641
- Logger.debug(` + 新增系统字段 ${sysFieldName}`);
651
+ addedSystemFields.push(sysFieldName);
642
652
  addClauses.push(`ADD COLUMN ${colDef}`);
643
653
  changed = true;
644
654
  }
@@ -673,6 +683,51 @@ export class SyncTable {
673
683
  indexActions: indexActions
674
684
  };
675
685
  if (plan.changed) {
686
+ // 在执行 DDL 前输出“单条汇总日志”(每张表最多一条),避免刷屏且仍保证表名明确。
687
+ const summaryParts = [];
688
+ summaryParts.push(`[表 ${tableName}] 变更汇总`);
689
+ summaryParts.push(`新增字段=${addedBusinessFields.length}`);
690
+ summaryParts.push(`新增系统字段=${addedSystemFields.length}`);
691
+ summaryParts.push(`修改字段=${modifiedFields.length}`);
692
+ summaryParts.push(`默认值更新=${defaultOnlyChangedFields.length}`);
693
+ summaryParts.push(`索引变更=${indexActions.length}`);
694
+ const detailParts = [];
695
+ if (addedBusinessFields.length > 0) {
696
+ detailParts.push(`新增字段:${addedBusinessFields.join(",")}`);
697
+ }
698
+ if (addedSystemFields.length > 0) {
699
+ detailParts.push(`新增系统字段:${addedSystemFields.join(",")}`);
700
+ }
701
+ if (modifiedFields.length > 0) {
702
+ detailParts.push(`修改字段:${modifiedFields.join(",")}`);
703
+ }
704
+ if (defaultOnlyChangedFields.length > 0) {
705
+ detailParts.push(`默认值更新:${defaultOnlyChangedFields.join(",")}`);
706
+ }
707
+ if (compatibleTypeChanges.length > 0) {
708
+ detailParts.push(`兼容类型变更:${compatibleTypeChanges.join(";")}`);
709
+ }
710
+ if (indexActions.length > 0) {
711
+ const createIndexSummaries = [];
712
+ const dropIndexSummaries = [];
713
+ for (const a of indexActions) {
714
+ const item = `${a.indexName}(${a.fieldName})`;
715
+ if (a.action === "create") {
716
+ createIndexSummaries.push(`+${item}`);
717
+ }
718
+ else {
719
+ dropIndexSummaries.push(`-${item}`);
720
+ }
721
+ }
722
+ const indexPart = [];
723
+ if (dropIndexSummaries.length > 0)
724
+ indexPart.push(dropIndexSummaries.join(","));
725
+ if (createIndexSummaries.length > 0)
726
+ indexPart.push(createIndexSummaries.join(","));
727
+ detailParts.push(`索引:${indexPart.join(",")}`);
728
+ }
729
+ const msg = detailParts.length > 0 ? `${summaryParts.join(",")};${detailParts.join(",")}` : summaryParts.join(",");
730
+ Logger.debug(msg);
676
731
  await SyncTable.applyTablePlan(db, tableName, plan);
677
732
  }
678
733
  return plan;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "befly",
3
- "version": "3.15.4",
4
- "gitHead": "05c5c5653d75a72b91a4fb1a66ab3e975e94ccc3",
3
+ "version": "3.15.6",
4
+ "gitHead": "41c6d052c600ae43302d2a97e7a5b597976cdb90",
5
5
  "private": false,
6
6
  "description": "Befly - 为 Bun 专属打造的 TypeScript API 接口框架核心引擎",
7
7
  "keywords": [