befly 3.15.5 → 3.15.7
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 +123 -48
- package/dist/befly.min.js +12 -12
- package/dist/sync/syncTable.d.ts +6 -0
- package/dist/sync/syncTable.js +135 -51
- 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
|
}
|
|
@@ -10335,13 +10362,17 @@ class SyncTable {
|
|
|
10335
10362
|
return;
|
|
10336
10363
|
const dropIndexActions = plan.indexActions.filter((a) => a.action === "drop");
|
|
10337
10364
|
const createIndexActions = plan.indexActions.filter((a) => a.action === "create");
|
|
10338
|
-
|
|
10339
|
-
const
|
|
10365
|
+
if (dropIndexActions.length > 0) {
|
|
10366
|
+
const dropClauses = [];
|
|
10367
|
+
for (const act of dropIndexActions) {
|
|
10368
|
+
dropClauses.push(SyncTable.buildIndexClause(act.indexName, act.fieldName, "drop"));
|
|
10369
|
+
}
|
|
10370
|
+
const tableQuoted = SyncTable.quoteIdentifier(tableName);
|
|
10371
|
+
const stmt = `ALTER TABLE ${tableQuoted} ALGORITHM=INPLACE, LOCK=NONE, ${dropClauses.join(", ")}`;
|
|
10340
10372
|
try {
|
|
10341
|
-
await
|
|
10342
|
-
Logger.debug(`[\u7D22\u5F15\u53D8\u5316] \u5220\u9664\u7D22\u5F15 ${tableName}.${act.indexName} (${act.fieldName})`);
|
|
10373
|
+
await SyncTable.executeDDLSafely(db, stmt);
|
|
10343
10374
|
} catch (error) {
|
|
10344
|
-
Logger.error({ err: error, table: tableName,
|
|
10375
|
+
Logger.error({ err: error, table: tableName, msg: "\u6279\u91CF\u5220\u9664\u7D22\u5F15\u5931\u8D25" });
|
|
10345
10376
|
throw error;
|
|
10346
10377
|
}
|
|
10347
10378
|
}
|
|
@@ -10356,13 +10387,17 @@ class SyncTable {
|
|
|
10356
10387
|
const stmt = `ALTER TABLE ${tableQuoted} ALGORITHM=INSTANT, LOCK=NONE, ${plan.defaultClauses.join(", ")}`;
|
|
10357
10388
|
await SyncTable.executeDDLSafely(db, stmt);
|
|
10358
10389
|
}
|
|
10359
|
-
|
|
10360
|
-
const
|
|
10390
|
+
if (createIndexActions.length > 0) {
|
|
10391
|
+
const createClauses = [];
|
|
10392
|
+
for (const act of createIndexActions) {
|
|
10393
|
+
createClauses.push(SyncTable.buildIndexClause(act.indexName, act.fieldName, "create"));
|
|
10394
|
+
}
|
|
10395
|
+
const tableQuoted = SyncTable.quoteIdentifier(tableName);
|
|
10396
|
+
const stmt = `ALTER TABLE ${tableQuoted} ALGORITHM=INPLACE, LOCK=NONE, ${createClauses.join(", ")}`;
|
|
10361
10397
|
try {
|
|
10362
|
-
await
|
|
10363
|
-
Logger.debug(`[\u7D22\u5F15\u53D8\u5316] \u65B0\u5EFA\u7D22\u5F15 ${tableName}.${act.indexName} (${act.fieldName})`);
|
|
10398
|
+
await SyncTable.executeDDLSafely(db, stmt);
|
|
10364
10399
|
} catch (error) {
|
|
10365
|
-
Logger.error({ err: error, table: tableName,
|
|
10400
|
+
Logger.error({ err: error, table: tableName, msg: "\u6279\u91CF\u521B\u5EFA\u7D22\u5F15\u5931\u8D25" });
|
|
10366
10401
|
throw error;
|
|
10367
10402
|
}
|
|
10368
10403
|
}
|
|
@@ -10377,29 +10412,22 @@ class SyncTable {
|
|
|
10377
10412
|
${cols}
|
|
10378
10413
|
) ENGINE=${ENGINE} DEFAULT CHARSET=${CHARSET} COLLATE=${COLLATE}`;
|
|
10379
10414
|
await db.unsafe(createSQL);
|
|
10380
|
-
|
|
10381
|
-
const
|
|
10415
|
+
Logger.debug(`[\u8868 ${tableName}] + \u521B\u5EFA\u8868\uFF08\u7CFB\u7EDF\u5B57\u6BB5 + \u4E1A\u52A1\u5B57\u6BB5\uFF09`);
|
|
10416
|
+
const indexClauses = [];
|
|
10382
10417
|
for (const sysField of systemIndexFields) {
|
|
10383
10418
|
const indexName = `idx_${sysField}`;
|
|
10384
|
-
|
|
10385
|
-
continue;
|
|
10386
|
-
}
|
|
10387
|
-
const stmt = SyncTable.buildIndexSQL(tableName, indexName, sysField, "create");
|
|
10388
|
-
indexTasks.push(db.unsafe(stmt));
|
|
10419
|
+
indexClauses.push(SyncTable.buildIndexClause(indexName, sysField, "create"));
|
|
10389
10420
|
}
|
|
10390
10421
|
for (const [fieldKey, fieldDef] of Object.entries(fields)) {
|
|
10391
10422
|
const dbFieldName = snakeCase(fieldKey);
|
|
10392
10423
|
if (fieldDef.index === true && fieldDef.unique !== true) {
|
|
10393
10424
|
const indexName = `idx_${dbFieldName}`;
|
|
10394
|
-
|
|
10395
|
-
continue;
|
|
10396
|
-
}
|
|
10397
|
-
const stmt = SyncTable.buildIndexSQL(tableName, indexName, dbFieldName, "create");
|
|
10398
|
-
indexTasks.push(db.unsafe(stmt));
|
|
10425
|
+
indexClauses.push(SyncTable.buildIndexClause(indexName, dbFieldName, "create"));
|
|
10399
10426
|
}
|
|
10400
10427
|
}
|
|
10401
|
-
if (
|
|
10402
|
-
|
|
10428
|
+
if (indexClauses.length > 0) {
|
|
10429
|
+
const stmt = `ALTER TABLE ${tableQuoted} ALGORITHM=INPLACE, LOCK=NONE, ${indexClauses.join(", ")}`;
|
|
10430
|
+
await SyncTable.executeDDLSafely(db, stmt);
|
|
10403
10431
|
}
|
|
10404
10432
|
}
|
|
10405
10433
|
static async modifyTable(db, dbName, tableName, fields) {
|
|
@@ -10410,15 +10438,17 @@ class SyncTable {
|
|
|
10410
10438
|
const modifyClauses = [];
|
|
10411
10439
|
const defaultClauses = [];
|
|
10412
10440
|
const indexActions = [];
|
|
10441
|
+
const addedBusinessFields = [];
|
|
10442
|
+
const addedSystemFields = [];
|
|
10443
|
+
const modifiedFields = [];
|
|
10444
|
+
const defaultOnlyChangedFields = [];
|
|
10445
|
+
const compatibleTypeChanges = [];
|
|
10413
10446
|
for (const [fieldKey, fieldDef] of Object.entries(fields)) {
|
|
10414
10447
|
const dbFieldName = snakeCase(fieldKey);
|
|
10415
10448
|
if (existingColumns[dbFieldName]) {
|
|
10416
10449
|
const comparison = SyncTable.compareFieldDefinition(existingColumns[dbFieldName], fieldDef);
|
|
10417
10450
|
if (comparison.length > 0) {
|
|
10418
|
-
|
|
10419
|
-
const changeLabel = SyncTable.CHANGE_TYPE_LABELS[c.type] || "\u672A\u77E5";
|
|
10420
|
-
Logger.debug(` ~ \u4FEE\u6539 ${dbFieldName} ${changeLabel}: ${c.current} -> ${c.expected}`);
|
|
10421
|
-
}
|
|
10451
|
+
modifiedFields.push(dbFieldName);
|
|
10422
10452
|
const hasTypeChange = comparison.some((c) => c.type === "datatype");
|
|
10423
10453
|
const onlyDefaultChanged = comparison.every((c) => c.type === "default");
|
|
10424
10454
|
const defaultChanged = comparison.some((c) => c.type === "default");
|
|
@@ -10432,7 +10462,7 @@ class SyncTable {
|
|
|
10432
10462
|
`);
|
|
10433
10463
|
throw new Error(errorMsg);
|
|
10434
10464
|
}
|
|
10435
|
-
|
|
10465
|
+
compatibleTypeChanges.push(`${dbFieldName}: ${currentType} -> ${expectedType}`);
|
|
10436
10466
|
}
|
|
10437
10467
|
if (defaultChanged) {
|
|
10438
10468
|
const actualDefault = SyncTable.resolveDefaultValue(fieldDef.default ?? null, fieldDef.type);
|
|
@@ -10445,6 +10475,7 @@ class SyncTable {
|
|
|
10445
10475
|
if (fieldDef.type !== "text") {
|
|
10446
10476
|
const colQuoted = SyncTable.quoteIdentifier(dbFieldName);
|
|
10447
10477
|
defaultClauses.push(`ALTER COLUMN ${colQuoted} SET DEFAULT ${v}`);
|
|
10478
|
+
defaultOnlyChangedFields.push(dbFieldName);
|
|
10448
10479
|
}
|
|
10449
10480
|
}
|
|
10450
10481
|
}
|
|
@@ -10454,6 +10485,7 @@ class SyncTable {
|
|
|
10454
10485
|
changed = true;
|
|
10455
10486
|
}
|
|
10456
10487
|
} else {
|
|
10488
|
+
addedBusinessFields.push(dbFieldName);
|
|
10457
10489
|
addClauses.push(SyncTable.generateDDLClause(fieldKey, fieldDef, true));
|
|
10458
10490
|
changed = true;
|
|
10459
10491
|
}
|
|
@@ -10463,7 +10495,7 @@ class SyncTable {
|
|
|
10463
10495
|
if (!existingColumns[sysFieldName]) {
|
|
10464
10496
|
const colDef = SyncTable.getSystemColumnDef(sysFieldName);
|
|
10465
10497
|
if (colDef) {
|
|
10466
|
-
|
|
10498
|
+
addedSystemFields.push(sysFieldName);
|
|
10467
10499
|
addClauses.push(`ADD COLUMN ${colDef}`);
|
|
10468
10500
|
changed = true;
|
|
10469
10501
|
}
|
|
@@ -10497,6 +10529,49 @@ class SyncTable {
|
|
|
10497
10529
|
indexActions
|
|
10498
10530
|
};
|
|
10499
10531
|
if (plan.changed) {
|
|
10532
|
+
const summaryParts = [];
|
|
10533
|
+
summaryParts.push(`[\u8868 ${tableName}] \u53D8\u66F4\u6C47\u603B`);
|
|
10534
|
+
summaryParts.push(`\u65B0\u589E\u5B57\u6BB5=${addedBusinessFields.length}`);
|
|
10535
|
+
summaryParts.push(`\u65B0\u589E\u7CFB\u7EDF\u5B57\u6BB5=${addedSystemFields.length}`);
|
|
10536
|
+
summaryParts.push(`\u4FEE\u6539\u5B57\u6BB5=${modifiedFields.length}`);
|
|
10537
|
+
summaryParts.push(`\u9ED8\u8BA4\u503C\u66F4\u65B0=${defaultOnlyChangedFields.length}`);
|
|
10538
|
+
summaryParts.push(`\u7D22\u5F15\u53D8\u66F4=${indexActions.length}`);
|
|
10539
|
+
const detailParts = [];
|
|
10540
|
+
if (addedBusinessFields.length > 0) {
|
|
10541
|
+
detailParts.push(`\u65B0\u589E\u5B57\u6BB5:${addedBusinessFields.join(",")}`);
|
|
10542
|
+
}
|
|
10543
|
+
if (addedSystemFields.length > 0) {
|
|
10544
|
+
detailParts.push(`\u65B0\u589E\u7CFB\u7EDF\u5B57\u6BB5:${addedSystemFields.join(",")}`);
|
|
10545
|
+
}
|
|
10546
|
+
if (modifiedFields.length > 0) {
|
|
10547
|
+
detailParts.push(`\u4FEE\u6539\u5B57\u6BB5:${modifiedFields.join(",")}`);
|
|
10548
|
+
}
|
|
10549
|
+
if (defaultOnlyChangedFields.length > 0) {
|
|
10550
|
+
detailParts.push(`\u9ED8\u8BA4\u503C\u66F4\u65B0:${defaultOnlyChangedFields.join(",")}`);
|
|
10551
|
+
}
|
|
10552
|
+
if (compatibleTypeChanges.length > 0) {
|
|
10553
|
+
detailParts.push(`\u517C\u5BB9\u7C7B\u578B\u53D8\u66F4:${compatibleTypeChanges.join(";")}`);
|
|
10554
|
+
}
|
|
10555
|
+
if (indexActions.length > 0) {
|
|
10556
|
+
const createIndexSummaries = [];
|
|
10557
|
+
const dropIndexSummaries = [];
|
|
10558
|
+
for (const a of indexActions) {
|
|
10559
|
+
const item = `${a.indexName}(${a.fieldName})`;
|
|
10560
|
+
if (a.action === "create") {
|
|
10561
|
+
createIndexSummaries.push(`+${item}`);
|
|
10562
|
+
} else {
|
|
10563
|
+
dropIndexSummaries.push(`-${item}`);
|
|
10564
|
+
}
|
|
10565
|
+
}
|
|
10566
|
+
const indexPart = [];
|
|
10567
|
+
if (dropIndexSummaries.length > 0)
|
|
10568
|
+
indexPart.push(dropIndexSummaries.join(","));
|
|
10569
|
+
if (createIndexSummaries.length > 0)
|
|
10570
|
+
indexPart.push(createIndexSummaries.join(","));
|
|
10571
|
+
detailParts.push(`\u7D22\u5F15:${indexPart.join(",")}`);
|
|
10572
|
+
}
|
|
10573
|
+
const msg = detailParts.length > 0 ? `${summaryParts.join("\uFF0C")}\uFF1B${detailParts.join("\uFF0C")}` : summaryParts.join("\uFF0C");
|
|
10574
|
+
Logger.debug(msg);
|
|
10500
10575
|
await SyncTable.applyTablePlan(db, tableName, plan);
|
|
10501
10576
|
}
|
|
10502
10577
|
return plan;
|