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 +102 -3
- package/dist/befly.min.js +10 -10
- package/dist/checks/checkTable.js +24 -2
- package/dist/lib/validator.js +53 -0
- package/dist/sync/syncTable.js +46 -2
- package/dist/types/validate.d.ts +1 -1
- package/package.json +2 -2
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 = [
|
|
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
|
-
|
|
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":
|