befly 3.15.6 → 3.15.8
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 +82 -42
- package/dist/befly.min.js +12 -12
- package/dist/sync/syncTable.d.ts +6 -0
- package/dist/sync/syncTable.js +96 -45
- package/package.json +2 -2
package/dist/befly.js
CHANGED
|
@@ -10105,17 +10105,18 @@ class SyncTable {
|
|
|
10105
10105
|
}
|
|
10106
10106
|
return "";
|
|
10107
10107
|
}
|
|
10108
|
-
static
|
|
10109
|
-
const tableQuoted = SyncTable.quoteIdentifier(tableName);
|
|
10108
|
+
static buildIndexClause(indexName, fieldName, action) {
|
|
10110
10109
|
const indexQuoted = SyncTable.quoteIdentifier(indexName);
|
|
10111
|
-
const fieldQuoted = SyncTable.quoteIdentifier(fieldName);
|
|
10112
|
-
const parts = [];
|
|
10113
10110
|
if (action === "create") {
|
|
10114
|
-
|
|
10115
|
-
|
|
10116
|
-
parts.push(`DROP INDEX ${indexQuoted}`);
|
|
10111
|
+
const fieldQuoted = SyncTable.quoteIdentifier(fieldName);
|
|
10112
|
+
return `ADD INDEX ${indexQuoted} (${fieldQuoted})`;
|
|
10117
10113
|
}
|
|
10118
|
-
return `
|
|
10114
|
+
return `DROP INDEX ${indexQuoted}`;
|
|
10115
|
+
}
|
|
10116
|
+
static buildIndexSQL(tableName, indexName, fieldName, action) {
|
|
10117
|
+
const tableQuoted = SyncTable.quoteIdentifier(tableName);
|
|
10118
|
+
const clause = SyncTable.buildIndexClause(indexName, fieldName, action);
|
|
10119
|
+
return `ALTER TABLE ${tableQuoted} ALGORITHM=INPLACE, LOCK=NONE, ${clause}`;
|
|
10119
10120
|
}
|
|
10120
10121
|
static getSystemColumnDef(fieldName) {
|
|
10121
10122
|
let meta = null;
|
|
@@ -10165,23 +10166,49 @@ class SyncTable {
|
|
|
10165
10166
|
const nullableSql = normalized.nullable ? " NULL" : " NOT NULL";
|
|
10166
10167
|
return `${isAdd ? "ADD COLUMN" : "MODIFY COLUMN"} ${colQuoted} ${sqlType}${uniqueSql}${nullableSql}${defaultSql} COMMENT "${escapeComment(normalized.name)}"`;
|
|
10167
10168
|
}
|
|
10169
|
+
static stripAlgorithmAndLock(stmt) {
|
|
10170
|
+
let sql = String(stmt);
|
|
10171
|
+
sql = sql.replace(/\bALGORITHM\s*=\s*(INPLACE|INSTANT|COPY)\b\s*,?\s*/gi, "").replace(/\bLOCK\s*=\s*(NONE|SHARED|EXCLUSIVE)\b\s*,?\s*/gi, "");
|
|
10172
|
+
sql = sql.replace(/,\s*,/g, ", ").replace(/,\s*$/g, "").replace(/\s{2,}/g, " ").trim();
|
|
10173
|
+
return sql;
|
|
10174
|
+
}
|
|
10175
|
+
static buildDdlFallbackCandidates(stmt) {
|
|
10176
|
+
const original = String(stmt);
|
|
10177
|
+
const attempted = [];
|
|
10178
|
+
if (/\bALGORITHM\s*=\s*INSTANT\b/i.test(original)) {
|
|
10179
|
+
attempted.push({
|
|
10180
|
+
stmt: original.replace(/\bALGORITHM\s*=\s*INSTANT\b/gi, "ALGORITHM=INPLACE"),
|
|
10181
|
+
reason: "ALGORITHM=INSTANT \u2192 INPLACE"
|
|
10182
|
+
});
|
|
10183
|
+
}
|
|
10184
|
+
const stripped = SyncTable.stripAlgorithmAndLock(original);
|
|
10185
|
+
if (stripped !== original) {
|
|
10186
|
+
attempted.push({ stmt: stripped, reason: "\u79FB\u9664 ALGORITHM/LOCK" });
|
|
10187
|
+
}
|
|
10188
|
+
const out = [];
|
|
10189
|
+
for (const item of attempted) {
|
|
10190
|
+
if (!item.stmt || item.stmt.trim() === "")
|
|
10191
|
+
continue;
|
|
10192
|
+
if (item.stmt === original)
|
|
10193
|
+
continue;
|
|
10194
|
+
if (out.some((x) => x.stmt === item.stmt))
|
|
10195
|
+
continue;
|
|
10196
|
+
out.push(item);
|
|
10197
|
+
}
|
|
10198
|
+
return out;
|
|
10199
|
+
}
|
|
10168
10200
|
static async executeDDLSafely(db, stmt) {
|
|
10169
10201
|
try {
|
|
10170
10202
|
await db.unsafe(stmt);
|
|
10171
10203
|
return true;
|
|
10172
10204
|
} catch (error) {
|
|
10173
|
-
|
|
10174
|
-
|
|
10205
|
+
const candidates = SyncTable.buildDdlFallbackCandidates(stmt);
|
|
10206
|
+
for (const candidate of candidates) {
|
|
10175
10207
|
try {
|
|
10176
|
-
await db.unsafe(
|
|
10208
|
+
await db.unsafe(candidate.stmt);
|
|
10209
|
+
Logger.debug(`[DDL\u964D\u7EA7] ${candidate.reason}\uFF08\u5DF2\u6210\u529F\uFF09`);
|
|
10177
10210
|
return true;
|
|
10178
|
-
} catch {
|
|
10179
|
-
let traditionSql = stmt;
|
|
10180
|
-
traditionSql = traditionSql.replace(/\bALGORITHM\s*=\s*(INPLACE|INSTANT)\b\s*,?\s*/g, "").replace(/\bLOCK\s*=\s*(NONE|SHARED|EXCLUSIVE)\b\s*,?\s*/g, "");
|
|
10181
|
-
traditionSql = traditionSql.replace(/,\s*,/g, ", ").replace(/,\s*$/g, "").replace(/\s{2,}/g, " ").trim();
|
|
10182
|
-
await db.unsafe(traditionSql);
|
|
10183
|
-
return true;
|
|
10184
|
-
}
|
|
10211
|
+
} catch {}
|
|
10185
10212
|
}
|
|
10186
10213
|
throw error;
|
|
10187
10214
|
}
|
|
@@ -10205,6 +10232,9 @@ class SyncTable {
|
|
|
10205
10232
|
}
|
|
10206
10233
|
if (cBase === "varchar" && (nBase === "text" || nBase === "mediumtext" || nBase === "longtext"))
|
|
10207
10234
|
return true;
|
|
10235
|
+
if (cBase === "char" && nBase === "varchar" || cBase === "varchar" && nBase === "char") {
|
|
10236
|
+
return true;
|
|
10237
|
+
}
|
|
10208
10238
|
return false;
|
|
10209
10239
|
}
|
|
10210
10240
|
static compareFieldDefinition(existingColumn, fieldDef) {
|
|
@@ -10335,12 +10365,17 @@ class SyncTable {
|
|
|
10335
10365
|
return;
|
|
10336
10366
|
const dropIndexActions = plan.indexActions.filter((a) => a.action === "drop");
|
|
10337
10367
|
const createIndexActions = plan.indexActions.filter((a) => a.action === "create");
|
|
10338
|
-
|
|
10339
|
-
const
|
|
10368
|
+
if (dropIndexActions.length > 0) {
|
|
10369
|
+
const dropClauses = [];
|
|
10370
|
+
for (const act of dropIndexActions) {
|
|
10371
|
+
dropClauses.push(SyncTable.buildIndexClause(act.indexName, act.fieldName, "drop"));
|
|
10372
|
+
}
|
|
10373
|
+
const tableQuoted = SyncTable.quoteIdentifier(tableName);
|
|
10374
|
+
const stmt = `ALTER TABLE ${tableQuoted} ALGORITHM=INPLACE, LOCK=NONE, ${dropClauses.join(", ")}`;
|
|
10340
10375
|
try {
|
|
10341
|
-
await
|
|
10376
|
+
await SyncTable.executeDDLSafely(db, stmt);
|
|
10342
10377
|
} catch (error) {
|
|
10343
|
-
Logger.error({ err: error, table: tableName,
|
|
10378
|
+
Logger.error({ err: error, table: tableName, msg: "\u6279\u91CF\u5220\u9664\u7D22\u5F15\u5931\u8D25" });
|
|
10344
10379
|
throw error;
|
|
10345
10380
|
}
|
|
10346
10381
|
}
|
|
@@ -10355,12 +10390,17 @@ class SyncTable {
|
|
|
10355
10390
|
const stmt = `ALTER TABLE ${tableQuoted} ALGORITHM=INSTANT, LOCK=NONE, ${plan.defaultClauses.join(", ")}`;
|
|
10356
10391
|
await SyncTable.executeDDLSafely(db, stmt);
|
|
10357
10392
|
}
|
|
10358
|
-
|
|
10359
|
-
const
|
|
10393
|
+
if (createIndexActions.length > 0) {
|
|
10394
|
+
const createClauses = [];
|
|
10395
|
+
for (const act of createIndexActions) {
|
|
10396
|
+
createClauses.push(SyncTable.buildIndexClause(act.indexName, act.fieldName, "create"));
|
|
10397
|
+
}
|
|
10398
|
+
const tableQuoted = SyncTable.quoteIdentifier(tableName);
|
|
10399
|
+
const stmt = `ALTER TABLE ${tableQuoted} ALGORITHM=INPLACE, LOCK=NONE, ${createClauses.join(", ")}`;
|
|
10360
10400
|
try {
|
|
10361
|
-
await
|
|
10401
|
+
await SyncTable.executeDDLSafely(db, stmt);
|
|
10362
10402
|
} catch (error) {
|
|
10363
|
-
Logger.error({ err: error, table: tableName,
|
|
10403
|
+
Logger.error({ err: error, table: tableName, msg: "\u6279\u91CF\u521B\u5EFA\u7D22\u5F15\u5931\u8D25" });
|
|
10364
10404
|
throw error;
|
|
10365
10405
|
}
|
|
10366
10406
|
}
|
|
@@ -10376,29 +10416,21 @@ class SyncTable {
|
|
|
10376
10416
|
) ENGINE=${ENGINE} DEFAULT CHARSET=${CHARSET} COLLATE=${COLLATE}`;
|
|
10377
10417
|
await db.unsafe(createSQL);
|
|
10378
10418
|
Logger.debug(`[\u8868 ${tableName}] + \u521B\u5EFA\u8868\uFF08\u7CFB\u7EDF\u5B57\u6BB5 + \u4E1A\u52A1\u5B57\u6BB5\uFF09`);
|
|
10379
|
-
const
|
|
10380
|
-
const existingIndexes = {};
|
|
10419
|
+
const indexClauses = [];
|
|
10381
10420
|
for (const sysField of systemIndexFields) {
|
|
10382
10421
|
const indexName = `idx_${sysField}`;
|
|
10383
|
-
|
|
10384
|
-
continue;
|
|
10385
|
-
}
|
|
10386
|
-
const stmt = SyncTable.buildIndexSQL(tableName, indexName, sysField, "create");
|
|
10387
|
-
indexTasks.push(db.unsafe(stmt));
|
|
10422
|
+
indexClauses.push(SyncTable.buildIndexClause(indexName, sysField, "create"));
|
|
10388
10423
|
}
|
|
10389
10424
|
for (const [fieldKey, fieldDef] of Object.entries(fields)) {
|
|
10390
10425
|
const dbFieldName = snakeCase(fieldKey);
|
|
10391
10426
|
if (fieldDef.index === true && fieldDef.unique !== true) {
|
|
10392
10427
|
const indexName = `idx_${dbFieldName}`;
|
|
10393
|
-
|
|
10394
|
-
continue;
|
|
10395
|
-
}
|
|
10396
|
-
const stmt = SyncTable.buildIndexSQL(tableName, indexName, dbFieldName, "create");
|
|
10397
|
-
indexTasks.push(db.unsafe(stmt));
|
|
10428
|
+
indexClauses.push(SyncTable.buildIndexClause(indexName, dbFieldName, "create"));
|
|
10398
10429
|
}
|
|
10399
10430
|
}
|
|
10400
|
-
if (
|
|
10401
|
-
|
|
10431
|
+
if (indexClauses.length > 0) {
|
|
10432
|
+
const stmt = `ALTER TABLE ${tableQuoted} ALGORITHM=INPLACE, LOCK=NONE, ${indexClauses.join(", ")}`;
|
|
10433
|
+
await SyncTable.executeDDLSafely(db, stmt);
|
|
10402
10434
|
}
|
|
10403
10435
|
}
|
|
10404
10436
|
static async modifyTable(db, dbName, tableName, fields) {
|
|
@@ -10429,11 +10461,19 @@ class SyncTable {
|
|
|
10429
10461
|
const typeMapping = SyncTable.getTypeMapping();
|
|
10430
10462
|
const expectedType = typeMapping[fieldDef.type]?.toLowerCase() || "";
|
|
10431
10463
|
if (!SyncTable.isCompatibleTypeChange(currentType, expectedType)) {
|
|
10432
|
-
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(`
|
|
10464
|
+
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\u4EE5\u53CA CHAR/VARCHAR \u4E92\u8F6C\uFF1B\u5176\u4ED6\u7C7B\u578B\u53D8\u66F4\u9700\u8981\u624B\u52A8\u5904\u7406"].join(`
|
|
10433
10465
|
`);
|
|
10434
10466
|
throw new Error(errorMsg);
|
|
10435
10467
|
}
|
|
10436
|
-
|
|
10468
|
+
let compatLabel = "";
|
|
10469
|
+
if (currentType === "char" && expectedType === "varchar" || currentType === "varchar" && expectedType === "char") {
|
|
10470
|
+
compatLabel = "char/varchar\u4E92\u8F6C";
|
|
10471
|
+
}
|
|
10472
|
+
if (compatLabel) {
|
|
10473
|
+
compatibleTypeChanges.push(`${dbFieldName}: ${currentType} -> ${expectedType} (${compatLabel})`);
|
|
10474
|
+
} else {
|
|
10475
|
+
compatibleTypeChanges.push(`${dbFieldName}: ${currentType} -> ${expectedType}`);
|
|
10476
|
+
}
|
|
10437
10477
|
}
|
|
10438
10478
|
if (defaultChanged) {
|
|
10439
10479
|
const actualDefault = SyncTable.resolveDefaultValue(fieldDef.default ?? null, fieldDef.type);
|