befly 3.19.8 → 3.20.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as z from "zod";
2
2
 
3
3
  import { Logger } from "../lib/logger.js";
4
- import { DB_ID_MODE_VALUES, RUN_MODE_VALUES } from "../configs/constConfig.js";
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: z.union([z.literal(0), z.literal(1)]).optional()
46
+ beflyMode: beflyModeSchema.optional()
47
47
  })
48
48
  .strict(),
49
49
 
@@ -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": 1
29
+ "beflyMode": "auto"
31
30
  },
32
31
 
33
32
  "redis": {
@@ -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
  // ==========================
@@ -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 = 1) {
358
- if (beflyMode === 0) {
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.idMode === "timeId") {
491
+ if (options.beflyMode === "auto") {
492
492
  validateTimeIdValue(options.id);
493
493
  result["id"] = options.id;
494
494
  }
495
495
 
496
- if (options.beflyMode !== 0) {
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 !== 0) {
512
+ if (options.beflyMode !== "manual") {
513
513
  result["updated_at"] = options.now;
514
514
  }
515
515
  return result;
@@ -192,9 +192,8 @@ export const dataOpsMethods = {
192
192
  const now = Date.now();
193
193
 
194
194
  let processed;
195
- if (this.idMode === "autoId") {
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,
@@ -231,9 +229,9 @@ export const dataOpsMethods = {
231
229
  const processedIdNum = isNumber(processedId) ? processedId : 0;
232
230
  const lastInsertRowidNum = toNumberFromSql(executeRes.data?.lastInsertRowid);
233
231
 
234
- const insertedId = this.idMode === "autoId" ? lastInsertRowidNum || 0 : processedIdNum || lastInsertRowidNum || 0;
235
- if (this.idMode === "autoId" && insertedId <= 0) {
236
- throw new Error(`插入失败:autoId 模式下无法获取 lastInsertRowid (table: ${table})`, {
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.idMode === "autoId") {
262
+ if (this.beflyMode === "manual") {
265
263
  processedList = dataList.map((data) => {
266
- return buildInsertRow({ idMode: "autoId", data: data, now: now, beflyMode: this.beflyMode });
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({ idMode: "timeId", data: data, id: id, now: now, beflyMode: this.beflyMode });
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.idMode === "autoId") {
286
+ if (this.beflyMode === "manual") {
289
287
  const firstId = toNumberFromSql(executeRes.data?.lastInsertRowid);
290
288
  if (firstId <= 0) {
291
- throw new Error(`批量插入失败:autoId 模式下无法获取 lastInsertRowid (table: ${table})`, {
289
+ throw new Error(`批量插入失败:beflyMode=manual 时无法获取 lastInsertRowid (table: ${table})`, {
292
290
  cause: null,
293
291
  code: "runtime"
294
292
  });
@@ -393,10 +391,10 @@ export const dataOpsMethods = {
393
391
  rows: processedList,
394
392
  fields: fields,
395
393
  quoteIdent: quoteIdentMySql,
396
- updatedAtField: this.beflyMode === 1 ? "updated_at" : "",
397
- updatedAtValue: this.beflyMode === 1 ? now : null,
394
+ updatedAtField: this.beflyMode === "auto" ? "updated_at" : "",
395
+ updatedAtValue: this.beflyMode === "auto" ? now : null,
398
396
  stateField: "state",
399
- stateGtZero: this.beflyMode === 1
397
+ stateGtZero: this.beflyMode === "auto"
400
398
  });
401
399
 
402
400
  const executeRes = await this.execute(query.sql, query.params);
@@ -431,8 +429,8 @@ export const dataOpsMethods = {
431
429
  validateTableWhereOptions(options, "delData", true);
432
430
  const { table, where } = options;
433
431
 
434
- // beflyMode=0:关闭默认 state 软删语义,delData 直接走物理删除
435
- if (this.beflyMode === 0) {
432
+ // beflyMode=manual:关闭默认 state 软删语义,delData 直接走物理删除
433
+ if (this.beflyMode === "manual") {
436
434
  return await this.delForce({
437
435
  table: table,
438
436
  where: where
@@ -552,7 +550,6 @@ export const dataOpsMethods = {
552
550
  dbName: this.dbName,
553
551
  sql: tx,
554
552
  isTransaction: true,
555
- idMode: this.idMode,
556
553
  beflyMode: this.beflyMode
557
554
  });
558
555
  const result = await callback(trans);
@@ -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.idMode = options.idMode === "autoId" ? "autoId" : "timeId";
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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "befly",
3
- "version": "3.19.8",
4
- "gitHead": "c0876969a14b2d6e66fd5105269e326581c0dde3",
3
+ "version": "3.20.0",
4
+ "gitHead": "218c4ffe07983e46bbb85f9e0a626a6b3b38c179",
5
5
  "private": false,
6
6
  "description": "Befly - 为 Bun 专属打造的 JavaScript API 接口框架核心引擎",
7
7
  "keywords": [
package/plugins/mysql.js CHANGED
@@ -19,7 +19,6 @@ export default {
19
19
  redis: befly.redis,
20
20
  dbName: befly.config?.mysql?.database,
21
21
  sql: Connect.getMysql(),
22
- idMode: befly.config?.mysql?.idMode,
23
22
  beflyMode: befly.config?.mysql?.beflyMode
24
23
  });
25
24
 
@@ -9,6 +9,7 @@ import { isNonEmptyString, isPlainObject } from "../../utils/is.js";
9
9
  import { camelCase } from "../../utils/util.js";
10
10
  import { buildSyncDbDiff, groupSyncDbColumns } from "./diff.js";
11
11
  import { querySyncDbColumns } from "./query.js";
12
+ import { printSyncDbProcessLog } from "./report.js";
12
13
 
13
14
  async function loadSyncDbTableDefs(tablesDir) {
14
15
  const tableMap = new Map();
@@ -52,6 +53,7 @@ async function loadSyncDbTableDefs(tablesDir) {
52
53
  export async function prepareSyncDbBaseContext(mysqlConfig) {
53
54
  const tablesDir = resolve(join(process.cwd(), "tables"));
54
55
  await mkdir(tablesDir, { recursive: true });
56
+ printSyncDbProcessLog(`tables目录=${tablesDir}`);
55
57
 
56
58
  if (!isPlainObject(mysqlConfig)) {
57
59
  throw new Error("syncDb 缺少 mysql 配置", {
@@ -62,16 +64,19 @@ export async function prepareSyncDbBaseContext(mysqlConfig) {
62
64
  });
63
65
  }
64
66
 
67
+ printSyncDbProcessLog(`beflyMode=${mysqlConfig.beflyMode === "manual" ? "manual" : "auto"}`);
68
+ printSyncDbProcessLog(`连接 MySQL,database=${mysqlConfig.database}`);
65
69
  await Connect.connectMysql(mysqlConfig);
66
70
  const mysql = new DbHelper({
67
71
  redis: null,
68
72
  dbName: mysqlConfig.database,
69
73
  sql: Connect.getMysql(),
70
- idMode: mysqlConfig.idMode,
71
74
  beflyMode: mysqlConfig.beflyMode
72
75
  });
73
76
 
77
+ printSyncDbProcessLog("开始读取数据库字段信息");
74
78
  const dbColumns = await querySyncDbColumns(mysql);
79
+ printSyncDbProcessLog(`数据库字段读取完成,columnCount=${dbColumns.length}`);
75
80
  const skippedBeflyTables = new Set();
76
81
  for (const row of dbColumns) {
77
82
  const tableName = String(row?.tableName || "");
@@ -89,7 +94,9 @@ export async function prepareSyncDbBaseContext(mysqlConfig) {
89
94
 
90
95
  const groupedDbColumns = groupSyncDbColumns(dbColumns);
91
96
  const existingTableMap = await loadSyncDbTableDefs(tablesDir);
92
- const diff = buildSyncDbDiff(groupedDbColumns, existingTableMap);
97
+ const diff = buildSyncDbDiff(groupedDbColumns, existingTableMap, mysqlConfig.beflyMode);
98
+ printSyncDbProcessLog(`tables定义文件数量=${existingTableMap.size}`);
99
+ printSyncDbProcessLog(`差异扫描完成,missingTableCount=${diff.missingTables.length},missingFieldCount=${Object.values(diff.missingFieldsByTable).reduce((sum, item) => sum + item.fields.length, 0)}`);
93
100
 
94
101
  return {
95
102
  diff: diff,
@@ -2,8 +2,20 @@ import { join } from "node:path";
2
2
 
3
3
  import { isNonEmptyString, isPlainObject } from "../../utils/is.js";
4
4
  import { camelCase } from "../../utils/util.js";
5
+ import { printSyncDbProcessLog } from "./report.js";
5
6
  import { toSyncDbFieldDef } from "./transform.js";
6
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
+
7
19
  export function groupSyncDbColumns(rows) {
8
20
  const grouped = new Map();
9
21
 
@@ -36,26 +48,31 @@ export function groupSyncDbColumns(rows) {
36
48
  return grouped;
37
49
  }
38
50
 
39
- export function buildSyncDbDiff(groupedDbColumns, existingTableMap) {
51
+ export function buildSyncDbDiff(groupedDbColumns, existingTableMap, beflyMode = "auto") {
40
52
  const missingTables = [];
41
53
  const missingFieldsByTable = {};
42
54
 
43
55
  for (const [tableName, columns] of groupedDbColumns.entries()) {
44
56
  const tableFileName = camelCase(tableName);
45
57
  const existing = existingTableMap.get(String(tableFileName).toLowerCase());
58
+ const filteredColumns = columns.filter((columnMeta) => !shouldSkipSyncDbColumn(columnMeta, beflyMode));
46
59
 
47
60
  if (!existing) {
61
+ if (filteredColumns.length === 0) {
62
+ continue;
63
+ }
64
+
48
65
  missingTables.push({
49
66
  tableName: tableName,
50
67
  tableFileName: tableFileName,
51
- columns: columns
68
+ columns: filteredColumns
52
69
  });
53
70
  continue;
54
71
  }
55
72
 
56
73
  const existingFields = isPlainObject(existing.tableDef) ? existing.tableDef : {};
57
74
  const missingFields = [];
58
- for (const columnMeta of columns) {
75
+ for (const columnMeta of filteredColumns) {
59
76
  const fieldInfo = toSyncDbFieldDef(columnMeta);
60
77
  if (Object.hasOwn(existingFields, fieldInfo.fieldName)) {
61
78
  continue;
@@ -103,6 +120,7 @@ export async function applySyncDbDiff(diff, tablesDir, existingTableMap) {
103
120
  const filePath = join(tablesDir, `${missingTable.tableFileName}.json`);
104
121
  await Bun.write(filePath, `${JSON.stringify(tableDef, null, 4)}\n`);
105
122
  createdTableFileCount = createdTableFileCount + 1;
123
+ printSyncDbProcessLog(`已生成表映射 ${filePath}`);
106
124
  }
107
125
 
108
126
  for (const [tableFileName, tableInfo] of Object.entries(diff.missingFieldsByTable)) {
@@ -116,6 +134,7 @@ export async function applySyncDbDiff(diff, tablesDir, existingTableMap) {
116
134
  }
117
135
 
118
136
  await Bun.write(targetFilePath, `${JSON.stringify(currentTableDef, null, 4)}\n`);
137
+ printSyncDbProcessLog(`已补充字段映射 ${targetFilePath},fieldCount=${tableInfo.fields.length}`);
119
138
  }
120
139
 
121
140
  return {
@@ -5,10 +5,11 @@ import { Connect } from "../../lib/connect.js";
5
5
  import { Logger } from "../../lib/logger.js";
6
6
  import { applySyncDbDiff, countSyncDbMissingFields } from "./diff.js";
7
7
  import { prepareSyncDbBaseContext } from "./context.js";
8
- import { printSyncDbDiffSummary, writeSyncDbCheckReport } from "./report.js";
8
+ import { printSyncDbDiffSummary, printSyncDbProcessLog, writeSyncDbCheckReport } from "./report.js";
9
9
 
10
10
  export async function syncDbCheck(mysqlConfig) {
11
11
  try {
12
+ printSyncDbProcessLog("开始执行 check");
12
13
  const reportPath = resolve(join(process.cwd(), "db.check.md"));
13
14
  await mkdir(dirname(reportPath), { recursive: true });
14
15
  await Bun.write(reportPath, "");
@@ -17,6 +18,7 @@ export async function syncDbCheck(mysqlConfig) {
17
18
  const missingFieldCount = countSyncDbMissingFields(diff);
18
19
  const writtenReportPath = await writeSyncDbCheckReport(reportPath, diff, groupedDbColumns, existingTableMap);
19
20
  printSyncDbDiffSummary("check", diff);
21
+ printSyncDbProcessLog(`check完成,missingTableCount=${diff.missingTables.length},missingFieldCount=${missingFieldCount}`);
20
22
 
21
23
  return {
22
24
  mode: "check",
@@ -42,10 +44,12 @@ export async function syncDbCheck(mysqlConfig) {
42
44
 
43
45
  export async function syncDbApply(mysqlConfig) {
44
46
  try {
47
+ printSyncDbProcessLog("开始执行 apply");
45
48
  const { diff, tablesDir, existingTableMap } = await prepareSyncDbBaseContext(mysqlConfig);
46
49
  printSyncDbDiffSummary("check", diff);
47
50
  const applyResult = await applySyncDbDiff(diff, tablesDir, existingTableMap);
48
51
  printSyncDbDiffSummary("apply", diff);
52
+ printSyncDbProcessLog(`apply完成,createdTableFileCount=${applyResult.createdTableFileCount},appendedFieldCount=${applyResult.appendedFieldCount}`);
49
53
 
50
54
  return {
51
55
  mode: "apply",
@@ -7,6 +7,10 @@ import { camelCase } from "../../utils/util.js";
7
7
  import { countSyncDbMissingFields } from "./diff.js";
8
8
  import { toSyncDbFieldDef } from "./transform.js";
9
9
 
10
+ export function printSyncDbProcessLog(message) {
11
+ process.stdout.write(`[syncDb] ${message}\n`);
12
+ }
13
+
10
14
  export function printSyncDbDiffSummary(mode, diff) {
11
15
  const tableNames = diff.missingTables.map((item) => item.tableName);
12
16
  const missingFieldGroups = Object.values(diff.missingFieldsByTable);
@@ -182,6 +186,7 @@ export async function writeSyncDbCheckReport(reportPath, diff, groupedDbColumns,
182
186
  await mkdir(dirname(reportPath), { recursive: true });
183
187
  const markdown = buildSyncDbCheckMarkdown(diff, groupedDbColumns, existingTableMap);
184
188
  await Bun.write(reportPath, markdown);
189
+ printSyncDbProcessLog(`差异报告已写入 ${reportPath}`);
185
190
  Logger.info("差异报告写入完成", {
186
191
  reportPath: reportPath
187
192
  });