befly 3.15.7 → 3.15.9

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/dist/befly.js CHANGED
@@ -8246,7 +8246,7 @@ function formatValuePreview(value) {
8246
8246
  }
8247
8247
  var RESERVED_FIELDS = ["id", "created_at", "updated_at", "deleted_at", "state"];
8248
8248
  var RESERVED_FIELD_SET = new Set(RESERVED_FIELDS);
8249
- var FIELD_TYPES = ["string", "number", "text", "array_string", "array_text", "array_number_string", "array_number_text"];
8249
+ var FIELD_TYPES = ["string", "number", "text", "datetime", "array_string", "array_text", "array_number_string", "array_number_text"];
8250
8250
  var FIELD_TYPE_SET = new Set(FIELD_TYPES);
8251
8251
  var ALLOWED_FIELD_PROPERTIES = ["name", "type", "min", "max", "default", "detail", "index", "unique", "nullable", "unsigned", "regexp"];
8252
8252
  var ALLOWED_FIELD_PROPERTY_SET = new Set(ALLOWED_FIELD_PROPERTIES);
@@ -8389,6 +8389,23 @@ async function checkTable(tables, config2) {
8389
8389
  Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u4E3A ${field.type} \u7C7B\u578B\uFF0C\u4E0D\u652F\u6301\u552F\u4E00\u7EA6\u675F\uFF08unique=true \u65E0\u6548\uFF09`);
8390
8390
  hasError = true;
8391
8391
  }
8392
+ } else if (field.type === "datetime") {
8393
+ if (field.min !== undefined && field.min !== null) {
8394
+ Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u4E3A datetime \u7C7B\u578B\uFF0Cmin \u5FC5\u987B\u4E3A null\uFF0C\u5F53\u524D\u4E3A "${field.min}"`);
8395
+ hasError = true;
8396
+ }
8397
+ if (field.max !== undefined && field.max !== null) {
8398
+ Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u4E3A datetime \u7C7B\u578B\uFF0Cmax \u5FC5\u987B\u4E3A null\uFF0C\u5F53\u524D\u4E3A "${field.max}"`);
8399
+ hasError = true;
8400
+ }
8401
+ if (field.default !== undefined && field.default !== null) {
8402
+ Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u4E3A datetime \u7C7B\u578B\uFF0C\u9ED8\u8BA4\u503C\u5FC5\u987B\u4E3A null\uFF08\u5982\u9700\u5F53\u524D\u65F6\u95F4\uFF0C\u8BF7\u5728\u4E1A\u52A1\u5199\u5165\u65F6\u8D4B\u503C\uFF09\u3002\u5F53\u524D\u4E3A ${formatValuePreview(field.default)}`);
8403
+ hasError = true;
8404
+ }
8405
+ if (field.unsigned !== undefined) {
8406
+ Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u4E3A datetime \u7C7B\u578B\uFF0C\u4E0D\u5141\u8BB8\u8BBE\u7F6E unsigned`);
8407
+ hasError = true;
8408
+ }
8392
8409
  } else if (field.type === "string" || field.type === "array_string" || field.type === "array_number_string") {
8393
8410
  if (field.max === undefined || field.max === null || typeof field.max !== "number") {
8394
8411
  Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u4E3A ${field.type} \u7C7B\u578B\uFF0C` + `\u5FC5\u987B\u8BBE\u7F6E max \u4E14\u7C7B\u578B\u4E3A\u6570\u5B57\uFF1B\u5176\u4E2D array_*_string \u7684 max \u8868\u793A\u5355\u4E2A\u5143\u7D20\u957F\u5EA6\uFF0C\u5F53\u524D\u4E3A "${field.max}"`);
@@ -10025,6 +10042,7 @@ class SyncTable {
10025
10042
  return {
10026
10043
  number: "BIGINT",
10027
10044
  string: "VARCHAR",
10045
+ datetime: "DATETIME",
10028
10046
  text: "MEDIUMTEXT",
10029
10047
  array_string: "VARCHAR",
10030
10048
  array_text: "MEDIUMTEXT",
@@ -10080,6 +10098,8 @@ class SyncTable {
10080
10098
  return 0;
10081
10099
  case "string":
10082
10100
  return "";
10101
+ case "datetime":
10102
+ return "null";
10083
10103
  case "array_string":
10084
10104
  case "array_number_string":
10085
10105
  return "[]";
@@ -10103,6 +10123,18 @@ class SyncTable {
10103
10123
  return ` DEFAULT '${escaped}'`;
10104
10124
  }
10105
10125
  }
10126
+ if (fieldType === "datetime") {
10127
+ if (typeof actualDefault === "string") {
10128
+ const trimmed = actualDefault.trim();
10129
+ if (/^current_timestamp(\(\s*\d+\s*\)|\(\s*\))?$/i.test(trimmed)) {
10130
+ const normalized = trimmed.toUpperCase().replace(/\(\s*\)/g, "");
10131
+ return ` DEFAULT ${normalized}`;
10132
+ }
10133
+ const escaped = trimmed.replace(/'/g, "''");
10134
+ return ` DEFAULT '${escaped}'`;
10135
+ }
10136
+ return "";
10137
+ }
10106
10138
  return "";
10107
10139
  }
10108
10140
  static buildIndexClause(indexName, fieldName, action) {
@@ -10232,6 +10264,12 @@ class SyncTable {
10232
10264
  }
10233
10265
  if (cBase === "varchar" && (nBase === "text" || nBase === "mediumtext" || nBase === "longtext"))
10234
10266
  return true;
10267
+ if (cBase === "char" && nBase === "varchar" || cBase === "varchar" && nBase === "char") {
10268
+ return true;
10269
+ }
10270
+ if (cBase === "datetime" && nBase === "bigint" || cBase === "bigint" && nBase === "datetime") {
10271
+ return false;
10272
+ }
10235
10273
  return false;
10236
10274
  }
10237
10275
  static compareFieldDefinition(existingColumn, fieldDef) {
@@ -10458,11 +10496,24 @@ class SyncTable {
10458
10496
  const typeMapping = SyncTable.getTypeMapping();
10459
10497
  const expectedType = typeMapping[fieldDef.type]?.toLowerCase() || "";
10460
10498
  if (!SyncTable.isCompatibleTypeChange(currentType, expectedType)) {
10461
- const errorMsg = [`\u7981\u6B62\u5B57\u6BB5\u7C7B\u578B\u53D8\u66F4: ${tableName}.${dbFieldName}`, `\u5F53\u524D\u7C7B\u578B: ${typeChange?.current}`, `\u76EE\u6807\u7C7B\u578B: ${typeChange?.expected}`, "\u8BF4\u660E: \u4EC5\u5141\u8BB8\u5BBD\u5316\u578B\u53D8\u66F4\uFF08\u5982 INT->BIGINT, VARCHAR->TEXT\uFF09\uFF0C\u5176\u4ED6\u7C7B\u578B\u53D8\u66F4\u9700\u8981\u624B\u52A8\u5904\u7406"].join(`
10499
+ const errorMsg = [
10500
+ `\u7981\u6B62\u5B57\u6BB5\u7C7B\u578B\u53D8\u66F4: ${tableName}.${dbFieldName}`,
10501
+ `\u5F53\u524D\u7C7B\u578B: ${typeChange?.current}`,
10502
+ `\u76EE\u6807\u7C7B\u578B: ${typeChange?.expected}`,
10503
+ "\u8BF4\u660E: \u4EC5\u5141\u8BB8\u5BBD\u5316\u578B\u53D8\u66F4\uFF08\u5982 INT->BIGINT, VARCHAR->TEXT\uFF09\uFF0C\u4EE5\u53CA CHAR/VARCHAR \u4E92\u8F6C\uFF1BDATETIME \u4E0E BIGINT \u4E0D\u5141\u8BB8\u4E92\u8F6C\uFF08\u9700\u8981\u624B\u52A8\u8FC1\u79FB\u6570\u636E\uFF09"
10504
+ ].join(`
10462
10505
  `);
10463
10506
  throw new Error(errorMsg);
10464
10507
  }
10465
- compatibleTypeChanges.push(`${dbFieldName}: ${currentType} -> ${expectedType}`);
10508
+ let compatLabel = "";
10509
+ if (currentType === "char" && expectedType === "varchar" || currentType === "varchar" && expectedType === "char") {
10510
+ compatLabel = "char/varchar\u4E92\u8F6C";
10511
+ }
10512
+ if (compatLabel) {
10513
+ compatibleTypeChanges.push(`${dbFieldName}: ${currentType} -> ${expectedType} (${compatLabel})`);
10514
+ } else {
10515
+ compatibleTypeChanges.push(`${dbFieldName}: ${currentType} -> ${expectedType}`);
10516
+ }
10466
10517
  }
10467
10518
  if (defaultChanged) {
10468
10519
  const actualDefault = SyncTable.resolveDefaultValue(fieldDef.default ?? null, fieldDef.type);
@@ -12474,6 +12525,15 @@ class Validator {
12474
12525
  case "string":
12475
12526
  case "text":
12476
12527
  return typeof value === "string" ? { value, error: null } : { value: null, error: "\u5FC5\u987B\u662F\u5B57\u7B26\u4E32" };
12528
+ case "datetime":
12529
+ if (typeof value !== "string") {
12530
+ return { value: null, error: "\u5FC5\u987B\u662F\u65F6\u95F4\u5B57\u7B26\u4E32" };
12531
+ }
12532
+ const trimmed = value.trim();
12533
+ if (/^\d{4}-\d{2}-\d{2}$/.test(trimmed)) {
12534
+ return { value: `${trimmed} 00:00:00`, error: null };
12535
+ }
12536
+ return { value: trimmed, error: null };
12477
12537
  case "array_string":
12478
12538
  case "array_text":
12479
12539
  return Array.isArray(value) ? { value, error: null } : { value: null, error: "\u5FC5\u987B\u662F\u6570\u7EC4" };
@@ -12521,6 +12581,43 @@ class Validator {
12521
12581
  if (regex && !this.testRegex(regex, value))
12522
12582
  return "\u683C\u5F0F\u4E0D\u6B63\u786E";
12523
12583
  break;
12584
+ case "datetime": {
12585
+ if (typeof value !== "string")
12586
+ return "\u5FC5\u987B\u662F\u65F6\u95F4\u5B57\u7B26\u4E32";
12587
+ if (!/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/.test(value))
12588
+ return "\u683C\u5F0F\u4E0D\u6B63\u786E";
12589
+ const [datePart, timePart] = value.split(" ");
12590
+ if (typeof datePart !== "string" || typeof timePart !== "string")
12591
+ return "\u683C\u5F0F\u4E0D\u6B63\u786E";
12592
+ const [yStr, mStr, dStr] = datePart.split("-");
12593
+ const [hhStr, mmStr, ssStr] = timePart.split(":");
12594
+ const year = Number(yStr);
12595
+ const month = Number(mStr);
12596
+ const day = Number(dStr);
12597
+ const hh = Number(hhStr);
12598
+ const mm = Number(mmStr);
12599
+ const ss = Number(ssStr);
12600
+ if (!Number.isInteger(year) || year < 1000 || year > 9999)
12601
+ return "\u683C\u5F0F\u4E0D\u6B63\u786E";
12602
+ if (!Number.isInteger(month) || month < 1 || month > 12)
12603
+ return "\u683C\u5F0F\u4E0D\u6B63\u786E";
12604
+ if (!Number.isInteger(day) || day < 1)
12605
+ return "\u683C\u5F0F\u4E0D\u6B63\u786E";
12606
+ if (!Number.isInteger(hh) || hh < 0 || hh > 23)
12607
+ return "\u683C\u5F0F\u4E0D\u6B63\u786E";
12608
+ if (!Number.isInteger(mm) || mm < 0 || mm > 59)
12609
+ return "\u683C\u5F0F\u4E0D\u6B63\u786E";
12610
+ if (!Number.isInteger(ss) || ss < 0 || ss > 59)
12611
+ return "\u683C\u5F0F\u4E0D\u6B63\u786E";
12612
+ const isLeap = year % 4 === 0 && year % 100 !== 0 || year % 400 === 0;
12613
+ const daysInMonth = [31, isLeap ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
12614
+ const maxDay = daysInMonth[month - 1] ?? 0;
12615
+ if (day > maxDay)
12616
+ return "\u683C\u5F0F\u4E0D\u6B63\u786E";
12617
+ if (regex && !this.testRegex(regex, value))
12618
+ return "\u683C\u5F0F\u4E0D\u6B63\u786E";
12619
+ break;
12620
+ }
12524
12621
  case "array_string":
12525
12622
  case "array_text":
12526
12623
  case "array_number_string":
@@ -12578,6 +12675,8 @@ class Validator {
12578
12675
  switch (type.toLowerCase()) {
12579
12676
  case "number":
12580
12677
  return 0;
12678
+ case "datetime":
12679
+ return null;
12581
12680
  case "array_string":
12582
12681
  case "array_text":
12583
12682
  case "array_number_string":