befly 3.15.8 → 3.15.10
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 +93 -4
- 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 +36 -3
- 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) {
|
|
@@ -10169,6 +10201,7 @@ class SyncTable {
|
|
|
10169
10201
|
static stripAlgorithmAndLock(stmt) {
|
|
10170
10202
|
let sql = String(stmt);
|
|
10171
10203
|
sql = sql.replace(/\bALGORITHM\s*=\s*(INPLACE|INSTANT|COPY)\b\s*,?\s*/gi, "").replace(/\bLOCK\s*=\s*(NONE|SHARED|EXCLUSIVE)\b\s*,?\s*/gi, "");
|
|
10204
|
+
sql = sql.replace(/^\s*(ALTER\s+TABLE\s+(?:`[^`]+`|[a-zA-Z_][a-zA-Z0-9_]*))\s*,\s*/i, "$1 ");
|
|
10172
10205
|
sql = sql.replace(/,\s*,/g, ", ").replace(/,\s*$/g, "").replace(/\s{2,}/g, " ").trim();
|
|
10173
10206
|
return sql;
|
|
10174
10207
|
}
|
|
@@ -10235,6 +10268,9 @@ class SyncTable {
|
|
|
10235
10268
|
if (cBase === "char" && nBase === "varchar" || cBase === "varchar" && nBase === "char") {
|
|
10236
10269
|
return true;
|
|
10237
10270
|
}
|
|
10271
|
+
if (cBase === "datetime" && nBase === "bigint" || cBase === "bigint" && nBase === "datetime") {
|
|
10272
|
+
return false;
|
|
10273
|
+
}
|
|
10238
10274
|
return false;
|
|
10239
10275
|
}
|
|
10240
10276
|
static compareFieldDefinition(existingColumn, fieldDef) {
|
|
@@ -10382,12 +10418,12 @@ class SyncTable {
|
|
|
10382
10418
|
const clauses = [...plan.addClauses, ...plan.modifyClauses];
|
|
10383
10419
|
if (clauses.length > 0) {
|
|
10384
10420
|
const tableQuoted = SyncTable.quoteIdentifier(tableName);
|
|
10385
|
-
const stmt = `ALTER TABLE ${tableQuoted} ALGORITHM=INSTANT,
|
|
10421
|
+
const stmt = `ALTER TABLE ${tableQuoted} ALGORITHM=INSTANT, ${clauses.join(", ")}`;
|
|
10386
10422
|
await SyncTable.executeDDLSafely(db, stmt);
|
|
10387
10423
|
}
|
|
10388
10424
|
if (plan.defaultClauses.length > 0) {
|
|
10389
10425
|
const tableQuoted = SyncTable.quoteIdentifier(tableName);
|
|
10390
|
-
const stmt = `ALTER TABLE ${tableQuoted} ALGORITHM=INSTANT,
|
|
10426
|
+
const stmt = `ALTER TABLE ${tableQuoted} ALGORITHM=INSTANT, ${plan.defaultClauses.join(", ")}`;
|
|
10391
10427
|
await SyncTable.executeDDLSafely(db, stmt);
|
|
10392
10428
|
}
|
|
10393
10429
|
if (createIndexActions.length > 0) {
|
|
@@ -10461,7 +10497,12 @@ class SyncTable {
|
|
|
10461
10497
|
const typeMapping = SyncTable.getTypeMapping();
|
|
10462
10498
|
const expectedType = typeMapping[fieldDef.type]?.toLowerCase() || "";
|
|
10463
10499
|
if (!SyncTable.isCompatibleTypeChange(currentType, expectedType)) {
|
|
10464
|
-
const errorMsg = [
|
|
10500
|
+
const errorMsg = [
|
|
10501
|
+
`\u7981\u6B62\u5B57\u6BB5\u7C7B\u578B\u53D8\u66F4: ${tableName}.${dbFieldName}`,
|
|
10502
|
+
`\u5F53\u524D\u7C7B\u578B: ${typeChange?.current}`,
|
|
10503
|
+
`\u76EE\u6807\u7C7B\u578B: ${typeChange?.expected}`,
|
|
10504
|
+
"\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"
|
|
10505
|
+
].join(`
|
|
10465
10506
|
`);
|
|
10466
10507
|
throw new Error(errorMsg);
|
|
10467
10508
|
}
|
|
@@ -12485,6 +12526,15 @@ class Validator {
|
|
|
12485
12526
|
case "string":
|
|
12486
12527
|
case "text":
|
|
12487
12528
|
return typeof value === "string" ? { value, error: null } : { value: null, error: "\u5FC5\u987B\u662F\u5B57\u7B26\u4E32" };
|
|
12529
|
+
case "datetime":
|
|
12530
|
+
if (typeof value !== "string") {
|
|
12531
|
+
return { value: null, error: "\u5FC5\u987B\u662F\u65F6\u95F4\u5B57\u7B26\u4E32" };
|
|
12532
|
+
}
|
|
12533
|
+
const trimmed = value.trim();
|
|
12534
|
+
if (/^\d{4}-\d{2}-\d{2}$/.test(trimmed)) {
|
|
12535
|
+
return { value: `${trimmed} 00:00:00`, error: null };
|
|
12536
|
+
}
|
|
12537
|
+
return { value: trimmed, error: null };
|
|
12488
12538
|
case "array_string":
|
|
12489
12539
|
case "array_text":
|
|
12490
12540
|
return Array.isArray(value) ? { value, error: null } : { value: null, error: "\u5FC5\u987B\u662F\u6570\u7EC4" };
|
|
@@ -12532,6 +12582,43 @@ class Validator {
|
|
|
12532
12582
|
if (regex && !this.testRegex(regex, value))
|
|
12533
12583
|
return "\u683C\u5F0F\u4E0D\u6B63\u786E";
|
|
12534
12584
|
break;
|
|
12585
|
+
case "datetime": {
|
|
12586
|
+
if (typeof value !== "string")
|
|
12587
|
+
return "\u5FC5\u987B\u662F\u65F6\u95F4\u5B57\u7B26\u4E32";
|
|
12588
|
+
if (!/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/.test(value))
|
|
12589
|
+
return "\u683C\u5F0F\u4E0D\u6B63\u786E";
|
|
12590
|
+
const [datePart, timePart] = value.split(" ");
|
|
12591
|
+
if (typeof datePart !== "string" || typeof timePart !== "string")
|
|
12592
|
+
return "\u683C\u5F0F\u4E0D\u6B63\u786E";
|
|
12593
|
+
const [yStr, mStr, dStr] = datePart.split("-");
|
|
12594
|
+
const [hhStr, mmStr, ssStr] = timePart.split(":");
|
|
12595
|
+
const year = Number(yStr);
|
|
12596
|
+
const month = Number(mStr);
|
|
12597
|
+
const day = Number(dStr);
|
|
12598
|
+
const hh = Number(hhStr);
|
|
12599
|
+
const mm = Number(mmStr);
|
|
12600
|
+
const ss = Number(ssStr);
|
|
12601
|
+
if (!Number.isInteger(year) || year < 1000 || year > 9999)
|
|
12602
|
+
return "\u683C\u5F0F\u4E0D\u6B63\u786E";
|
|
12603
|
+
if (!Number.isInteger(month) || month < 1 || month > 12)
|
|
12604
|
+
return "\u683C\u5F0F\u4E0D\u6B63\u786E";
|
|
12605
|
+
if (!Number.isInteger(day) || day < 1)
|
|
12606
|
+
return "\u683C\u5F0F\u4E0D\u6B63\u786E";
|
|
12607
|
+
if (!Number.isInteger(hh) || hh < 0 || hh > 23)
|
|
12608
|
+
return "\u683C\u5F0F\u4E0D\u6B63\u786E";
|
|
12609
|
+
if (!Number.isInteger(mm) || mm < 0 || mm > 59)
|
|
12610
|
+
return "\u683C\u5F0F\u4E0D\u6B63\u786E";
|
|
12611
|
+
if (!Number.isInteger(ss) || ss < 0 || ss > 59)
|
|
12612
|
+
return "\u683C\u5F0F\u4E0D\u6B63\u786E";
|
|
12613
|
+
const isLeap = year % 4 === 0 && year % 100 !== 0 || year % 400 === 0;
|
|
12614
|
+
const daysInMonth = [31, isLeap ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
|
12615
|
+
const maxDay = daysInMonth[month - 1] ?? 0;
|
|
12616
|
+
if (day > maxDay)
|
|
12617
|
+
return "\u683C\u5F0F\u4E0D\u6B63\u786E";
|
|
12618
|
+
if (regex && !this.testRegex(regex, value))
|
|
12619
|
+
return "\u683C\u5F0F\u4E0D\u6B63\u786E";
|
|
12620
|
+
break;
|
|
12621
|
+
}
|
|
12535
12622
|
case "array_string":
|
|
12536
12623
|
case "array_text":
|
|
12537
12624
|
case "array_number_string":
|
|
@@ -12589,6 +12676,8 @@ class Validator {
|
|
|
12589
12676
|
switch (type.toLowerCase()) {
|
|
12590
12677
|
case "number":
|
|
12591
12678
|
return 0;
|
|
12679
|
+
case "datetime":
|
|
12680
|
+
return null;
|
|
12592
12681
|
case "array_string":
|
|
12593
12682
|
case "array_text":
|
|
12594
12683
|
case "array_number_string":
|