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 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
  // ==========================
package/lib/connect.js CHANGED
@@ -42,7 +42,8 @@ export class Connect {
42
42
  database: config.database,
43
43
  username: config.username,
44
44
  password: config.password,
45
- max: config.max
45
+ max: config.max,
46
+ bigint: true
46
47
  };
47
48
 
48
49
  this.mysqlClient = new SQL(sqlConfig);
@@ -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 { convertBigIntFields, getJoinMainQualifier, normalizeTableRef, quoteIdentMySql } from "./util.js";
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 = 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;
@@ -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 total = executeRes.data?.[0]?.total || executeRes.data?.[0]?.count || 0;
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, bigintFields) {
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 = convertBigIntFields([deserialized], bigintFields);
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, bigintFields) {
573
+ normalizeListData(list) {
572
574
  const camelList = arrayKeysToCamel(list);
573
575
  const deserializedList = camelList.map((item) => deserializeArrayFields(item)).filter((item) => item !== null);
574
- return convertBigIntFields(deserializedList, bigintFields);
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;
@@ -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 { quoteIdentMySql, toNumberFromSql } from "./util.js";
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, options.bigint);
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, options.bigint),
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, options.bigint);
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.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,
@@ -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 = toNumberFromSql(executeRes.data?.lastInsertRowid);
230
+ const lastInsertRowidNum = normalizeSqlMetaNumber(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") {
289
- const firstId = toNumberFromSql(executeRes.data?.lastInsertRowid);
286
+ if (this.beflyMode === "manual") {
287
+ const firstId = normalizeSqlMetaNumber(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
  });
@@ -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 = toNumberFromSql(executeRes.data?.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 === 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);
403
- const changes = toNumberFromSql(executeRes.data?.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 = toNumberFromSql(executeRes.data?.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
- // beflyMode=0:关闭默认 state 软删语义,delData 直接走物理删除
435
- if (this.beflyMode === 0) {
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
- return await this.updData({
443
- table: table,
444
- data: { state: 0, deleted_at: Date.now() },
445
- where: where
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 = toNumberFromSql(executeRes.data?.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 = toNumberFromSql(executeRes.data?.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);
@@ -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);
@@ -1,4 +1,4 @@
1
- import { isNonEmptyString, isNullable, isString } from "../../utils/is.js";
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 toNumberFromSql(value) {
44
+ export function normalizeSqlMetaNumber(value) {
45
45
  if (isNullable(value)) {
46
46
  return 0;
47
47
  }
48
48
 
49
- if (typeof value === "number") {
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 (typeof value === "string") {
66
- if (!value.trim()) {
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 0;
57
+ return value;
77
58
  }
78
59
 
79
- export function convertBigIntFields(arr, fields) {
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 (!isNullable(value)) {
117
- const shouldConvert = fieldSet.has(key) || key.endsWith("Id") || key.endsWith("_id") || key.endsWith("At") || key.endsWith("_at");
118
-
119
- if (shouldConvert) {
120
- let bigintValue = null;
121
- if (typeof value === "bigint") {
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.19.9",
4
- "gitHead": "558ea1598bb0547b5b068a1c014ea1f4d48939d5",
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
@@ -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
 
@@ -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
 
@@ -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: 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 columns) {
75
+ for (const columnMeta of filteredColumns) {
60
76
  const fieldInfo = toSyncDbFieldDef(columnMeta);
61
77
  if (Object.hasOwn(existingFields, fieldInfo.fieldName)) {
62
78
  continue;