befly 3.15.2 → 3.15.4
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.config.js +14 -0
- package/dist/befly.js +161 -61
- package/dist/befly.min.js +12 -12
- package/dist/checks/checkConfig.js +47 -0
- package/dist/checks/checkTable.d.ts +2 -1
- package/dist/checks/checkTable.js +41 -40
- package/dist/index.js +1 -1
- package/dist/lib/dbHelper.d.ts +4 -1
- package/dist/lib/dbHelper.js +59 -20
- package/dist/lib/dbUtils.d.ts +13 -6
- package/dist/lib/dbUtils.js +7 -1
- package/dist/plugins/db.js +3 -1
- package/dist/types/befly.d.ts +16 -0
- package/dist/types/database.d.ts +2 -2
- package/package.json +2 -2
package/dist/befly.config.js
CHANGED
|
@@ -12,6 +12,7 @@ const defaultOptions = {
|
|
|
12
12
|
devPassword: "beflydev123456",
|
|
13
13
|
bodyLimit: 1048576, // 1MB
|
|
14
14
|
tz: "Asia/Shanghai",
|
|
15
|
+
strict: true,
|
|
15
16
|
// ========== 日志配置 ==========
|
|
16
17
|
logger: {
|
|
17
18
|
debug: 1,
|
|
@@ -24,6 +25,7 @@ const defaultOptions = {
|
|
|
24
25
|
},
|
|
25
26
|
// ========== 数据库配置 ==========
|
|
26
27
|
db: {
|
|
28
|
+
idMode: "timeId",
|
|
27
29
|
host: "127.0.0.1",
|
|
28
30
|
port: 3306,
|
|
29
31
|
username: "root",
|
|
@@ -93,5 +95,17 @@ export async function loadBeflyConfig(nodeEnv) {
|
|
|
93
95
|
throw new Error(`配置错误:redis.prefix 不允许包含 ':'(RedisHelper 会自动拼接分隔符 ':'),请改为不带冒号的前缀,例如 'befly_demo',当前值=${redisPrefix}`);
|
|
94
96
|
}
|
|
95
97
|
}
|
|
98
|
+
const idMode = config.db?.idMode;
|
|
99
|
+
if (idMode !== undefined && idMode !== "timeId" && idMode !== "autoId") {
|
|
100
|
+
throw new Error(`配置错误:db.idMode 只能是 'timeId' 或 'autoId',当前值=${String(idMode)}`);
|
|
101
|
+
}
|
|
102
|
+
const strict = config.strict;
|
|
103
|
+
if (strict !== undefined && typeof strict !== "boolean") {
|
|
104
|
+
throw new Error(`配置错误:strict 必须为 boolean,当前值=${String(strict)}`);
|
|
105
|
+
}
|
|
106
|
+
const legacyCheckTable = config.checkTable;
|
|
107
|
+
if (legacyCheckTable !== undefined) {
|
|
108
|
+
throw new Error(`配置错误:checkTable 配置已废弃,请使用根属性 strict(例如 { "strict": false }),当前值=${String(legacyCheckTable)}`);
|
|
109
|
+
}
|
|
96
110
|
return config;
|
|
97
111
|
}
|
package/dist/befly.js
CHANGED
|
@@ -7537,6 +7537,7 @@ var defaultOptions = {
|
|
|
7537
7537
|
devPassword: "beflydev123456",
|
|
7538
7538
|
bodyLimit: 1048576,
|
|
7539
7539
|
tz: "Asia/Shanghai",
|
|
7540
|
+
strict: true,
|
|
7540
7541
|
logger: {
|
|
7541
7542
|
debug: 1,
|
|
7542
7543
|
excludeFields: ["password", "token", "secret"],
|
|
@@ -7547,6 +7548,7 @@ var defaultOptions = {
|
|
|
7547
7548
|
maxArrayItems: 100
|
|
7548
7549
|
},
|
|
7549
7550
|
db: {
|
|
7551
|
+
idMode: "timeId",
|
|
7550
7552
|
host: "127.0.0.1",
|
|
7551
7553
|
port: 3306,
|
|
7552
7554
|
username: "root",
|
|
@@ -7602,6 +7604,18 @@ async function loadBeflyConfig(nodeEnv) {
|
|
|
7602
7604
|
throw new Error(`\u914D\u7F6E\u9519\u8BEF\uFF1Aredis.prefix \u4E0D\u5141\u8BB8\u5305\u542B ':'\uFF08RedisHelper \u4F1A\u81EA\u52A8\u62FC\u63A5\u5206\u9694\u7B26 ':'\uFF09\uFF0C\u8BF7\u6539\u4E3A\u4E0D\u5E26\u5192\u53F7\u7684\u524D\u7F00\uFF0C\u4F8B\u5982 'befly_demo'\uFF0C\u5F53\u524D\u503C=${redisPrefix}`);
|
|
7603
7605
|
}
|
|
7604
7606
|
}
|
|
7607
|
+
const idMode = config2.db?.idMode;
|
|
7608
|
+
if (idMode !== undefined && idMode !== "timeId" && idMode !== "autoId") {
|
|
7609
|
+
throw new Error(`\u914D\u7F6E\u9519\u8BEF\uFF1Adb.idMode \u53EA\u80FD\u662F 'timeId' \u6216 'autoId'\uFF0C\u5F53\u524D\u503C=${String(idMode)}`);
|
|
7610
|
+
}
|
|
7611
|
+
const strict = config2.strict;
|
|
7612
|
+
if (strict !== undefined && typeof strict !== "boolean") {
|
|
7613
|
+
throw new Error(`\u914D\u7F6E\u9519\u8BEF\uFF1Astrict \u5FC5\u987B\u4E3A boolean\uFF0C\u5F53\u524D\u503C=${String(strict)}`);
|
|
7614
|
+
}
|
|
7615
|
+
const legacyCheckTable = config2.checkTable;
|
|
7616
|
+
if (legacyCheckTable !== undefined) {
|
|
7617
|
+
throw new Error(`\u914D\u7F6E\u9519\u8BEF\uFF1AcheckTable \u914D\u7F6E\u5DF2\u5E9F\u5F03\uFF0C\u8BF7\u4F7F\u7528\u6839\u5C5E\u6027 strict\uFF08\u4F8B\u5982 { "strict": false }\uFF09\uFF0C\u5F53\u524D\u503C=${String(legacyCheckTable)}`);
|
|
7618
|
+
}
|
|
7605
7619
|
return config2;
|
|
7606
7620
|
}
|
|
7607
7621
|
|
|
@@ -7725,6 +7739,19 @@ function isValidPort(value) {
|
|
|
7725
7739
|
function isValidNonNegativeInt(value) {
|
|
7726
7740
|
return typeof value === "number" && Number.isFinite(value) && value >= 0 && Math.floor(value) === value;
|
|
7727
7741
|
}
|
|
7742
|
+
function isValidPositiveInt(value) {
|
|
7743
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 1 && Math.floor(value) === value;
|
|
7744
|
+
}
|
|
7745
|
+
function isValidTimeZone(value) {
|
|
7746
|
+
if (!isNonEmptyString(value))
|
|
7747
|
+
return false;
|
|
7748
|
+
try {
|
|
7749
|
+
new Intl.DateTimeFormat("en-US", { timeZone: value }).format(0);
|
|
7750
|
+
return true;
|
|
7751
|
+
} catch {
|
|
7752
|
+
return false;
|
|
7753
|
+
}
|
|
7754
|
+
}
|
|
7728
7755
|
function validateDbConfig(db) {
|
|
7729
7756
|
if (!db) {
|
|
7730
7757
|
throw new Error("\u914D\u7F6E\u9519\u8BEF\uFF1A\u7F3A\u5C11 db \u914D\u7F6E\uFF08config.db\uFF09");
|
|
@@ -7780,6 +7807,11 @@ async function checkConfig(config2) {
|
|
|
7780
7807
|
if (config2.nodeEnv !== "development" && config2.nodeEnv !== "production") {
|
|
7781
7808
|
throw new Error(`\u914D\u7F6E\u9519\u8BEF\uFF1AnodeEnv \u53EA\u80FD\u662F development/production\uFF0C\u5F53\u524D\u503C=${String(config2.nodeEnv)}`);
|
|
7782
7809
|
}
|
|
7810
|
+
if (config2.appName !== undefined) {
|
|
7811
|
+
if (!isNonEmptyString(config2.appName)) {
|
|
7812
|
+
throw new Error(`\u914D\u7F6E\u9519\u8BEF\uFF1AappName \u5FC5\u987B\u4E3A\u975E\u7A7A\u5B57\u7B26\u4E32\uFF0C\u5F53\u524D\u503C=${String(config2.appName)}`);
|
|
7813
|
+
}
|
|
7814
|
+
}
|
|
7783
7815
|
if (config2.appPort !== undefined) {
|
|
7784
7816
|
if (!isValidPort(config2.appPort)) {
|
|
7785
7817
|
throw new Error(`\u914D\u7F6E\u9519\u8BEF\uFF1AappPort \u5FC5\u987B\u4E3A 1..65535 \u7684\u6570\u5B57\uFF0C\u5F53\u524D\u503C=${String(config2.appPort)}`);
|
|
@@ -7790,6 +7822,33 @@ async function checkConfig(config2) {
|
|
|
7790
7822
|
throw new Error(`\u914D\u7F6E\u9519\u8BEF\uFF1AappHost \u5FC5\u987B\u4E3A\u975E\u7A7A\u5B57\u7B26\u4E32\uFF0C\u5F53\u524D\u503C=${String(config2.appHost)}`);
|
|
7791
7823
|
}
|
|
7792
7824
|
}
|
|
7825
|
+
if (config2.devEmail !== undefined) {
|
|
7826
|
+
if (typeof config2.devEmail !== "string") {
|
|
7827
|
+
throw new Error(`\u914D\u7F6E\u9519\u8BEF\uFF1AdevEmail \u5FC5\u987B\u4E3A\u5B57\u7B26\u4E32\uFF08\u5141\u8BB8\u4E3A\u7A7A\u5B57\u7B26\u4E32\uFF09\uFF0C\u5F53\u524D\u503C=${String(config2.devEmail)}`);
|
|
7828
|
+
}
|
|
7829
|
+
const trimmedDevEmail = config2.devEmail.trim();
|
|
7830
|
+
if (trimmedDevEmail.length > 0 && !trimmedDevEmail.includes("@")) {
|
|
7831
|
+
throw new Error(`\u914D\u7F6E\u9519\u8BEF\uFF1AdevEmail \u683C\u5F0F\u9519\u8BEF\uFF08\u5FC5\u987B\u5305\u542B '@'\uFF0C\u6216\u7F6E\u4E3A\u7A7A\u5B57\u7B26\u4E32\u4EE5\u7981\u7528 syncDev\uFF09\uFF0C\u5F53\u524D\u503C=${String(config2.devEmail)}`);
|
|
7832
|
+
}
|
|
7833
|
+
}
|
|
7834
|
+
if (config2.devPassword !== undefined) {
|
|
7835
|
+
if (typeof config2.devPassword !== "string") {
|
|
7836
|
+
throw new Error(`\u914D\u7F6E\u9519\u8BEF\uFF1AdevPassword \u5FC5\u987B\u4E3A\u5B57\u7B26\u4E32\uFF08\u5141\u8BB8\u4E3A\u7A7A\u5B57\u7B26\u4E32\uFF09\uFF0C\u5F53\u524D\u503C=${String(config2.devPassword)}`);
|
|
7837
|
+
}
|
|
7838
|
+
}
|
|
7839
|
+
if (config2.bodyLimit !== undefined) {
|
|
7840
|
+
if (!isValidPositiveInt(config2.bodyLimit)) {
|
|
7841
|
+
throw new Error(`\u914D\u7F6E\u9519\u8BEF\uFF1AbodyLimit \u5FC5\u987B\u4E3A\u6B63\u6574\u6570\uFF08\u5B57\u8282\uFF09\uFF0C\u5F53\u524D\u503C=${String(config2.bodyLimit)}`);
|
|
7842
|
+
}
|
|
7843
|
+
}
|
|
7844
|
+
if (config2.tz !== undefined) {
|
|
7845
|
+
if (!isValidTimeZone(config2.tz)) {
|
|
7846
|
+
throw new Error(`\u914D\u7F6E\u9519\u8BEF\uFF1Atz \u5FC5\u987B\u4E3A\u6709\u6548\u7684 IANA \u65F6\u533A\u5B57\u7B26\u4E32\uFF08\u4F8B\u5982 'Asia/Shanghai'\uFF09\uFF0C\u5F53\u524D\u503C=${String(config2.tz)}`);
|
|
7847
|
+
}
|
|
7848
|
+
}
|
|
7849
|
+
if (typeof config2.strict !== "boolean") {
|
|
7850
|
+
throw new Error(`\u914D\u7F6E\u9519\u8BEF\uFF1Astrict \u5FC5\u987B\u4E3A true \u6216 false\uFF0C\u5F53\u524D\u503C=${String(config2.strict)}`);
|
|
7851
|
+
}
|
|
7793
7852
|
validateDbConfig(config2.db);
|
|
7794
7853
|
validateRedisConfig(config2.redis);
|
|
7795
7854
|
}
|
|
@@ -8196,7 +8255,7 @@ var FIELD_NAME_REGEX = /^[\u4e00-\u9fa5a-zA-Z0-9 _-]+$/;
|
|
|
8196
8255
|
var MAX_VARCHAR_LENGTH = 16383;
|
|
8197
8256
|
var MAX_INDEX_STRING_LENGTH_FOR_INDEX = 500;
|
|
8198
8257
|
var MAX_INDEX_STRING_LENGTH_FOR_UNIQUE = 180;
|
|
8199
|
-
async function checkTable(tables) {
|
|
8258
|
+
async function checkTable(tables, config2) {
|
|
8200
8259
|
let hasError = false;
|
|
8201
8260
|
for (const item of tables) {
|
|
8202
8261
|
if (item.type !== "table") {
|
|
@@ -8285,87 +8344,88 @@ async function checkTable(tables) {
|
|
|
8285
8344
|
Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u5B57\u6BB5 default \u7C7B\u578B\u9519\u8BEF\uFF0C\u5FC5\u987B\u4E3A\u53EF JSON \u5E8F\u5217\u5316\u7684\u503C\u6216 null` + `\uFF08typeof=${typeof field.default}\uFF0Cvalue=${formatValuePreview(field.default)}\uFF09`);
|
|
8286
8345
|
hasError = true;
|
|
8287
8346
|
}
|
|
8288
|
-
|
|
8289
|
-
|
|
8290
|
-
|
|
8291
|
-
|
|
8347
|
+
if (config2.strict) {
|
|
8348
|
+
if (!FIELD_NAME_REGEX.test(field.name)) {
|
|
8349
|
+
Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u5B57\u6BB5\u540D\u79F0 "${field.name}" \u683C\u5F0F\u9519\u8BEF\uFF0C` + `\u5FC5\u987B\u4E3A\u4E2D\u6587\u3001\u6570\u5B57\u3001\u5B57\u6BCD\u3001\u4E0B\u5212\u7EBF\u3001\u77ED\u6A2A\u7EBF\u3001\u7A7A\u683C`);
|
|
8350
|
+
hasError = true;
|
|
8351
|
+
}
|
|
8292
8352
|
}
|
|
8293
|
-
if (!FIELD_TYPE_SET.has(
|
|
8294
|
-
Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u5B57\u6BB5\u7C7B\u578B "${
|
|
8353
|
+
if (!FIELD_TYPE_SET.has(field.type)) {
|
|
8354
|
+
Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u5B57\u6BB5\u7C7B\u578B "${field.type}" \u683C\u5F0F\u9519\u8BEF\uFF0C` + `\u5FC5\u987B\u4E3A${FIELD_TYPES.join("\u3001")}\u4E4B\u4E00`);
|
|
8295
8355
|
hasError = true;
|
|
8296
8356
|
}
|
|
8297
|
-
if (
|
|
8298
|
-
Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u5B57\u6BB5\u7C7B\u578B\u4E3A ${
|
|
8357
|
+
if (field.type !== "number" && field.unsigned !== undefined) {
|
|
8358
|
+
Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u5B57\u6BB5\u7C7B\u578B\u4E3A ${field.type}\uFF0C\u4E0D\u5141\u8BB8\u8BBE\u7F6E unsigned\uFF08\u4EC5 number \u7C7B\u578B\u6709\u6548\uFF09`);
|
|
8299
8359
|
hasError = true;
|
|
8300
8360
|
}
|
|
8301
8361
|
if (field.unique === true && field.index === true) {
|
|
8302
8362
|
Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u540C\u65F6\u8BBE\u7F6E\u4E86 unique=true \u548C index=true\uFF0C` + `unique \u548C index \u4E0D\u80FD\u540C\u65F6\u8BBE\u7F6E\uFF0C\u8BF7\u5220\u9664\u5176\u4E00\uFF08\u5426\u5219\u4F1A\u521B\u5EFA\u91CD\u590D\u7D22\u5F15\uFF09`);
|
|
8303
8363
|
hasError = true;
|
|
8304
8364
|
}
|
|
8305
|
-
if (
|
|
8306
|
-
if (
|
|
8307
|
-
Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u6700\u5C0F\u503C "${
|
|
8365
|
+
if (field.min !== undefined && field.max !== undefined && field.min !== null && field.max !== null) {
|
|
8366
|
+
if (field.min > field.max) {
|
|
8367
|
+
Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u6700\u5C0F\u503C "${field.min}" \u4E0D\u80FD\u5927\u4E8E\u6700\u5927\u503C "${field.max}"`);
|
|
8308
8368
|
hasError = true;
|
|
8309
8369
|
}
|
|
8310
8370
|
}
|
|
8311
|
-
if (
|
|
8312
|
-
if (
|
|
8313
|
-
Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u7684 ${
|
|
8371
|
+
if (field.type === "text" || field.type === "array_text" || field.type === "array_number_text") {
|
|
8372
|
+
if (field.min !== undefined && field.min !== null) {
|
|
8373
|
+
Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u7684 ${field.type} \u7C7B\u578B\u6700\u5C0F\u503C\u5E94\u4E3A null\uFF0C\u5F53\u524D\u4E3A "${field.min}"`);
|
|
8314
8374
|
hasError = true;
|
|
8315
8375
|
}
|
|
8316
|
-
if (
|
|
8317
|
-
Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u7684 ${
|
|
8376
|
+
if (field.max !== undefined && field.max !== null) {
|
|
8377
|
+
Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u7684 ${field.type} \u7C7B\u578B\u6700\u5927\u957F\u5EA6\u5E94\u4E3A null\uFF0C\u5F53\u524D\u4E3A "${field.max}"`);
|
|
8318
8378
|
hasError = true;
|
|
8319
8379
|
}
|
|
8320
|
-
if (
|
|
8321
|
-
Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u4E3A ${
|
|
8380
|
+
if (field.default !== undefined && field.default !== null) {
|
|
8381
|
+
Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u4E3A ${field.type} \u7C7B\u578B\uFF0C\u9ED8\u8BA4\u503C\u5FC5\u987B\u4E3A null\uFF0C\u5F53\u524D\u4E3A "${field.default}"`);
|
|
8322
8382
|
hasError = true;
|
|
8323
8383
|
}
|
|
8324
8384
|
if (field.index === true) {
|
|
8325
|
-
Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u4E3A ${
|
|
8385
|
+
Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u4E3A ${field.type} \u7C7B\u578B\uFF0C\u4E0D\u652F\u6301\u521B\u5EFA\u7D22\u5F15\uFF08index=true \u65E0\u6548\uFF09`);
|
|
8326
8386
|
hasError = true;
|
|
8327
8387
|
}
|
|
8328
8388
|
if (field.unique === true) {
|
|
8329
|
-
Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u4E3A ${
|
|
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`);
|
|
8330
8390
|
hasError = true;
|
|
8331
8391
|
}
|
|
8332
|
-
} else if (
|
|
8333
|
-
if (
|
|
8334
|
-
Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u4E3A ${
|
|
8392
|
+
} else if (field.type === "string" || field.type === "array_string" || field.type === "array_number_string") {
|
|
8393
|
+
if (field.max === undefined || field.max === null || typeof field.max !== "number") {
|
|
8394
|
+
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}"`);
|
|
8335
8395
|
hasError = true;
|
|
8336
|
-
} else if (
|
|
8337
|
-
Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u6700\u5927\u957F\u5EA6 ${
|
|
8396
|
+
} else if (field.max > MAX_VARCHAR_LENGTH) {
|
|
8397
|
+
Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u6700\u5927\u957F\u5EA6 ${field.max} \u8D8A\u754C\uFF0C` + `${field.type} \u7C7B\u578B\u957F\u5EA6\u5FC5\u987B\u5728 1..${MAX_VARCHAR_LENGTH} \u8303\u56F4\u5185`);
|
|
8338
8398
|
hasError = true;
|
|
8339
8399
|
} else {
|
|
8340
|
-
if (field.index === true &&
|
|
8341
|
-
Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u8BBE\u7F6E\u4E86 index=true\uFF0C` + `\u4F46 max=${
|
|
8400
|
+
if (field.index === true && field.max > MAX_INDEX_STRING_LENGTH_FOR_INDEX) {
|
|
8401
|
+
Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u8BBE\u7F6E\u4E86 index=true\uFF0C` + `\u4F46 max=${field.max} \u8D85\u51FA\u5141\u8BB8\u8303\u56F4\uFF08\u8981\u6C42 <= ${MAX_INDEX_STRING_LENGTH_FOR_INDEX}\uFF09`);
|
|
8342
8402
|
hasError = true;
|
|
8343
8403
|
}
|
|
8344
|
-
if (field.unique === true &&
|
|
8345
|
-
Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u8BBE\u7F6E\u4E86 unique=true\uFF0C` + `\u4F46 max=${
|
|
8404
|
+
if (field.unique === true && field.max > MAX_INDEX_STRING_LENGTH_FOR_UNIQUE) {
|
|
8405
|
+
Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u8BBE\u7F6E\u4E86 unique=true\uFF0C` + `\u4F46 max=${field.max} \u8D85\u51FA\u5141\u8BB8\u8303\u56F4\uFF08\u8981\u6C42 <= ${MAX_INDEX_STRING_LENGTH_FOR_UNIQUE}\uFF09`);
|
|
8346
8406
|
hasError = true;
|
|
8347
8407
|
}
|
|
8348
8408
|
}
|
|
8349
|
-
if (
|
|
8350
|
-
if (typeof
|
|
8351
|
-
Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u4E3A ${
|
|
8409
|
+
if (field.default !== undefined && field.default !== null) {
|
|
8410
|
+
if (typeof field.default !== "string") {
|
|
8411
|
+
Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u4E3A ${field.type} \u7C7B\u578B\uFF0C\u9ED8\u8BA4\u503C\u5FC5\u987B\u4E3A\u5B57\u7B26\u4E32\u6216 null` + `\uFF08typeof=${typeof field.default}\uFF0Cvalue=${formatValuePreview(field.default)}\uFF09`);
|
|
8352
8412
|
hasError = true;
|
|
8353
|
-
} else if (
|
|
8413
|
+
} else if (field.type !== "string") {
|
|
8354
8414
|
try {
|
|
8355
|
-
const parsed = JSON.parse(
|
|
8415
|
+
const parsed = JSON.parse(field.default);
|
|
8356
8416
|
if (!Array.isArray(parsed)) {
|
|
8357
|
-
Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u4E3A ${
|
|
8417
|
+
Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u4E3A ${field.type} \u7C7B\u578B\uFF0C\u9ED8\u8BA4\u503C\u5E94\u4E3A JSON \u6570\u7EC4\u5B57\u7B26\u4E32\uFF08\u4F8B\u5982 "[]"\uFF09` + `\uFF08value=${formatValuePreview(field.default)}\uFF09`);
|
|
8358
8418
|
hasError = true;
|
|
8359
8419
|
}
|
|
8360
8420
|
} catch {
|
|
8361
|
-
Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u4E3A ${
|
|
8421
|
+
Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u4E3A ${field.type} \u7C7B\u578B\uFF0C\u9ED8\u8BA4\u503C\u5E94\u4E3A JSON \u6570\u7EC4\u5B57\u7B26\u4E32\uFF08\u4F8B\u5982 "[]"\uFF09` + `\uFF08value=${formatValuePreview(field.default)}\uFF09`);
|
|
8362
8422
|
hasError = true;
|
|
8363
8423
|
}
|
|
8364
8424
|
}
|
|
8365
8425
|
}
|
|
8366
|
-
} else if (
|
|
8367
|
-
if (
|
|
8368
|
-
Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u4E3A number \u7C7B\u578B\uFF0C\u9ED8\u8BA4\u503C\u5FC5\u987B\u4E3A\u6570\u5B57\u6216 null` + `\uFF08typeof=${typeof
|
|
8426
|
+
} else if (field.type === "number") {
|
|
8427
|
+
if (field.default !== undefined && field.default !== null && typeof field.default !== "number") {
|
|
8428
|
+
Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u4E3A number \u7C7B\u578B\uFF0C\u9ED8\u8BA4\u503C\u5FC5\u987B\u4E3A\u6570\u5B57\u6216 null` + `\uFF08typeof=${typeof field.default}\uFF0Cvalue=${formatValuePreview(field.default)}\uFF09`);
|
|
8369
8429
|
hasError = true;
|
|
8370
8430
|
}
|
|
8371
8431
|
}
|
|
@@ -13324,7 +13384,12 @@ class DbUtils {
|
|
|
13324
13384
|
for (const [key, value] of Object.entries(userData)) {
|
|
13325
13385
|
result[key] = value;
|
|
13326
13386
|
}
|
|
13327
|
-
|
|
13387
|
+
if (options.idMode === "timeId") {
|
|
13388
|
+
if (!Number.isFinite(options.id) || options.id <= 0) {
|
|
13389
|
+
throw new Error(`buildInsertRow(timeId) \u5931\u8D25\uFF1Aid \u5FC5\u987B\u4E3A > 0 \u7684\u6709\u9650 number (id: ${String(options.id)})`);
|
|
13390
|
+
}
|
|
13391
|
+
result["id"] = options.id;
|
|
13392
|
+
}
|
|
13328
13393
|
result["created_at"] = options.now;
|
|
13329
13394
|
result["updated_at"] = options.now;
|
|
13330
13395
|
result["state"] = 1;
|
|
@@ -14095,6 +14160,7 @@ class DbHelper {
|
|
|
14095
14160
|
dbName;
|
|
14096
14161
|
sql = null;
|
|
14097
14162
|
isTransaction = false;
|
|
14163
|
+
idMode;
|
|
14098
14164
|
constructor(options) {
|
|
14099
14165
|
this.redis = options.redis;
|
|
14100
14166
|
if (typeof options.dbName !== "string" || options.dbName.trim() === "") {
|
|
@@ -14103,6 +14169,7 @@ class DbHelper {
|
|
|
14103
14169
|
this.dbName = options.dbName;
|
|
14104
14170
|
this.sql = options.sql || null;
|
|
14105
14171
|
this.isTransaction = Boolean(options.sql);
|
|
14172
|
+
this.idMode = options.idMode === "autoId" ? "autoId" : "timeId";
|
|
14106
14173
|
}
|
|
14107
14174
|
createSqlBuilder() {
|
|
14108
14175
|
return new SqlBuilder({ quoteIdent: quoteIdentMySql });
|
|
@@ -14397,13 +14464,18 @@ class DbHelper {
|
|
|
14397
14464
|
const { table, data } = options;
|
|
14398
14465
|
const snakeTable = snakeCase(table);
|
|
14399
14466
|
const now = Date.now();
|
|
14400
|
-
let
|
|
14401
|
-
|
|
14402
|
-
|
|
14403
|
-
}
|
|
14404
|
-
|
|
14467
|
+
let processed;
|
|
14468
|
+
if (this.idMode === "autoId") {
|
|
14469
|
+
processed = DbUtils.buildInsertRow({ idMode: "autoId", data, now });
|
|
14470
|
+
} else {
|
|
14471
|
+
let id;
|
|
14472
|
+
try {
|
|
14473
|
+
id = await this.redis.genTimeID();
|
|
14474
|
+
} catch (error) {
|
|
14475
|
+
throw new Error(`\u751F\u6210 ID \u5931\u8D25\uFF0CRedis \u53EF\u80FD\u4E0D\u53EF\u7528 (table: ${table})`, { cause: error });
|
|
14476
|
+
}
|
|
14477
|
+
processed = DbUtils.buildInsertRow({ idMode: "timeId", data, id, now });
|
|
14405
14478
|
}
|
|
14406
|
-
const processed = DbUtils.buildInsertRow({ data, id, now });
|
|
14407
14479
|
SqlCheck.assertNoUndefinedInRecord(processed, `insData \u63D2\u5165\u6570\u636E (table: ${snakeTable})`);
|
|
14408
14480
|
const builder = this.createSqlBuilder();
|
|
14409
14481
|
const { sql, params } = builder.toInsertSql(snakeTable, processed);
|
|
@@ -14411,7 +14483,10 @@ class DbHelper {
|
|
|
14411
14483
|
const processedId = processed["id"];
|
|
14412
14484
|
const processedIdNum = typeof processedId === "number" ? processedId : 0;
|
|
14413
14485
|
const lastInsertRowidNum = toNumberFromSql(execRes.data?.lastInsertRowid);
|
|
14414
|
-
const insertedId = processedIdNum || lastInsertRowidNum || 0;
|
|
14486
|
+
const insertedId = this.idMode === "autoId" ? lastInsertRowidNum || 0 : processedIdNum || lastInsertRowidNum || 0;
|
|
14487
|
+
if (this.idMode === "autoId" && insertedId <= 0) {
|
|
14488
|
+
throw new Error(`\u63D2\u5165\u5931\u8D25\uFF1AautoId \u6A21\u5F0F\u4E0B\u65E0\u6CD5\u83B7\u53D6 lastInsertRowid (table: ${table})`);
|
|
14489
|
+
}
|
|
14415
14490
|
return {
|
|
14416
14491
|
data: insertedId,
|
|
14417
14492
|
sql: execRes.sql
|
|
@@ -14430,23 +14505,46 @@ class DbHelper {
|
|
|
14430
14505
|
throw new Error(`\u6279\u91CF\u63D2\u5165\u6570\u91CF ${dataList.length} \u8D85\u8FC7\u6700\u5927\u9650\u5236 ${MAX_BATCH_SIZE}`);
|
|
14431
14506
|
}
|
|
14432
14507
|
const snakeTable = snakeCase(table);
|
|
14433
|
-
const ids = [];
|
|
14434
|
-
for (let i = 0;i < dataList.length; i++) {
|
|
14435
|
-
ids.push(await this.redis.genTimeID());
|
|
14436
|
-
}
|
|
14437
14508
|
const now = Date.now();
|
|
14438
|
-
|
|
14439
|
-
|
|
14440
|
-
|
|
14441
|
-
|
|
14509
|
+
let ids = [];
|
|
14510
|
+
let processedList;
|
|
14511
|
+
if (this.idMode === "autoId") {
|
|
14512
|
+
processedList = dataList.map((data) => {
|
|
14513
|
+
return DbUtils.buildInsertRow({ idMode: "autoId", data, now });
|
|
14514
|
+
});
|
|
14515
|
+
} else {
|
|
14516
|
+
const nextIds = [];
|
|
14517
|
+
for (let i = 0;i < dataList.length; i++) {
|
|
14518
|
+
nextIds.push(await this.redis.genTimeID());
|
|
14442
14519
|
}
|
|
14443
|
-
|
|
14444
|
-
|
|
14520
|
+
ids = nextIds;
|
|
14521
|
+
processedList = dataList.map((data, index) => {
|
|
14522
|
+
const id = nextIds[index];
|
|
14523
|
+
if (typeof id !== "number") {
|
|
14524
|
+
throw new Error(`\u6279\u91CF\u63D2\u5165\u751F\u6210 ID \u5931\u8D25\uFF1Aids[${index}] \u4E0D\u662F number (table: ${snakeTable})`);
|
|
14525
|
+
}
|
|
14526
|
+
return DbUtils.buildInsertRow({ idMode: "timeId", data, id, now });
|
|
14527
|
+
});
|
|
14528
|
+
}
|
|
14445
14529
|
const insertFields = SqlCheck.assertBatchInsertRowsConsistent(processedList, { table: snakeTable });
|
|
14446
14530
|
const builder = this.createSqlBuilder();
|
|
14447
14531
|
const { sql, params } = builder.toInsertSql(snakeTable, processedList);
|
|
14448
14532
|
try {
|
|
14449
14533
|
const execRes = await this.executeRun(sql, params);
|
|
14534
|
+
if (this.idMode === "autoId") {
|
|
14535
|
+
const firstId = toNumberFromSql(execRes.data?.lastInsertRowid);
|
|
14536
|
+
if (firstId <= 0) {
|
|
14537
|
+
throw new Error(`\u6279\u91CF\u63D2\u5165\u5931\u8D25\uFF1AautoId \u6A21\u5F0F\u4E0B\u65E0\u6CD5\u83B7\u53D6 lastInsertRowid (table: ${table})`);
|
|
14538
|
+
}
|
|
14539
|
+
const outIds = [];
|
|
14540
|
+
for (let i = 0;i < dataList.length; i++) {
|
|
14541
|
+
outIds.push(firstId + i);
|
|
14542
|
+
}
|
|
14543
|
+
return {
|
|
14544
|
+
data: outIds,
|
|
14545
|
+
sql: execRes.sql
|
|
14546
|
+
};
|
|
14547
|
+
}
|
|
14450
14548
|
return {
|
|
14451
14549
|
data: ids,
|
|
14452
14550
|
sql: execRes.sql
|
|
@@ -14600,7 +14698,7 @@ class DbHelper {
|
|
|
14600
14698
|
throw new Error("\u5F53\u524D SQL \u5BA2\u6237\u7AEF\u4E0D\u652F\u6301\u4E8B\u52A1 begin() \u65B9\u6CD5");
|
|
14601
14699
|
}
|
|
14602
14700
|
return await sql.begin(async (tx) => {
|
|
14603
|
-
const trans = new DbHelper({ redis: this.redis, dbName: this.dbName, sql: tx });
|
|
14701
|
+
const trans = new DbHelper({ redis: this.redis, dbName: this.dbName, sql: tx, idMode: this.idMode });
|
|
14604
14702
|
return await callback(trans);
|
|
14605
14703
|
});
|
|
14606
14704
|
}
|
|
@@ -14745,7 +14843,9 @@ var dbPlugin = {
|
|
|
14745
14843
|
}
|
|
14746
14844
|
try {
|
|
14747
14845
|
const sql = Connect.getSql();
|
|
14748
|
-
const
|
|
14846
|
+
const idMode = befly.config?.db?.idMode;
|
|
14847
|
+
const normalizedIdMode = idMode === "autoId" ? "autoId" : "timeId";
|
|
14848
|
+
const dbManager = new DbHelper({ redis: befly.redis, dbName, sql, idMode: normalizedIdMode });
|
|
14749
14849
|
return dbManager;
|
|
14750
14850
|
} catch (error) {
|
|
14751
14851
|
Logger.error({ env, err: error, msg: "\u6570\u636E\u5E93\u521D\u59CB\u5316\u5931\u8D25" });
|
|
@@ -15533,7 +15633,7 @@ class Befly {
|
|
|
15533
15633
|
const { apis, tables, plugins, hooks, addons } = await scanSources();
|
|
15534
15634
|
this.context["addons"] = addons;
|
|
15535
15635
|
await checkApi(apis);
|
|
15536
|
-
await checkTable(tables);
|
|
15636
|
+
await checkTable(tables, this.config);
|
|
15537
15637
|
await checkPlugin(plugins);
|
|
15538
15638
|
await checkHook(hooks);
|
|
15539
15639
|
const checkedMenus = await checkMenu(addons);
|