mirror of
https://gitee.com/ulthon/ulthon_admin.git
synced 2026-07-07 18:42:49 +08:00
feat: 发布智能体版
This commit is contained in:
@@ -46,6 +46,8 @@ class SchemeToDbService
|
||||
$fullTableName = $prefix . $tableName;
|
||||
}
|
||||
|
||||
$sql = $this->buildCreateTableSql($fullTableName, $tableAttr, $ref);
|
||||
|
||||
// 检查表是否存在
|
||||
$tableExists = $this->checkTableExists($connection, $fullTableName);
|
||||
$backupTableName = null;
|
||||
@@ -66,7 +68,6 @@ class SchemeToDbService
|
||||
}
|
||||
|
||||
// 2. 建表
|
||||
$sql = $this->buildCreateTableSql($fullTableName, $tableAttr, $ref);
|
||||
Db::connect($connection)->execute($sql);
|
||||
|
||||
// 3. 恢复数据
|
||||
@@ -121,88 +122,159 @@ class SchemeToDbService
|
||||
$schemeIndexes = $this->buildSchemeIndexSignature($ref);
|
||||
$dbIndexes = $this->buildDbIndexSignature($dbKeysRows);
|
||||
|
||||
$diffs = [];
|
||||
$missingFields = [];
|
||||
$extraFields = [];
|
||||
$changedFields = [];
|
||||
|
||||
foreach ($schemeColumns as $field => $sig) {
|
||||
if (!isset($dbColumns[$field])) {
|
||||
$diffs[] = "缺少字段:{$field}";
|
||||
$missingFields[] = $field;
|
||||
continue;
|
||||
}
|
||||
|
||||
$row = $dbColumns[$field];
|
||||
$fieldChanges = [];
|
||||
|
||||
$dbType = $this->normalizeDbType((string)$row['Type']);
|
||||
$schemeType = $this->normalizeDbType($sig['type']);
|
||||
if ($dbType !== $schemeType) {
|
||||
$diffs[] = "字段类型不一致:{$field} DB={$dbType} Scheme={$schemeType}";
|
||||
$fieldChanges['type'] = ['db' => $dbType, 'scheme' => $schemeType];
|
||||
}
|
||||
|
||||
$dbNull = (string)$row['Null'];
|
||||
$schemeNull = $sig['null'];
|
||||
if ($dbNull !== $schemeNull) {
|
||||
$diffs[] = "字段可空不一致:{$field} DB={$dbNull} Scheme={$schemeNull}";
|
||||
$fieldChanges['null'] = ['db' => $dbNull, 'scheme' => $schemeNull];
|
||||
}
|
||||
|
||||
$dbDefault = $row['Default'];
|
||||
$schemeDefault = $sig['default'];
|
||||
if (!$this->defaultEquals($dbDefault, $schemeDefault)) {
|
||||
$dbStr = is_null($dbDefault) ? 'NULL' : (string)$dbDefault;
|
||||
$schemeStr = is_null($schemeDefault) ? 'NULL' : (string)$schemeDefault;
|
||||
$diffs[] = "字段默认值不一致:{$field} DB={$dbStr} Scheme={$schemeStr}";
|
||||
$fieldChanges['default'] = [
|
||||
'db' => $this->stringifyDefault($dbDefault),
|
||||
'scheme' => $this->stringifyDefault($schemeDefault),
|
||||
];
|
||||
}
|
||||
|
||||
$dbExtra = (string)$row['Extra'];
|
||||
$schemeExtra = $sig['extra'];
|
||||
if ($dbExtra !== $schemeExtra) {
|
||||
$diffs[] = "字段 Extra 不一致:{$field} DB={$dbExtra} Scheme={$schemeExtra}";
|
||||
$fieldChanges['extra'] = ['db' => $dbExtra, 'scheme' => $schemeExtra];
|
||||
}
|
||||
|
||||
$dbPrimary = (string)$row['Key'] === 'PRI';
|
||||
if ($dbPrimary !== $sig['primary']) {
|
||||
$diffs[] = "字段主键不一致:{$field} DB=" . ($dbPrimary ? 'PRI' : '') . " Scheme=" . ($sig['primary'] ? 'PRI' : '');
|
||||
$fieldChanges['primary'] = [
|
||||
'db' => $dbPrimary ? 'PRI' : '',
|
||||
'scheme' => $sig['primary'] ? 'PRI' : '',
|
||||
];
|
||||
}
|
||||
|
||||
$dbComment = (string)$row['Comment'];
|
||||
$schemeComment = $sig['comment'];
|
||||
if ($this->parseComment($dbComment) !== $this->parseComment($schemeComment)) {
|
||||
$diffs[] = "字段注释不一致:{$field} DB={$dbComment} Scheme={$schemeComment}";
|
||||
$fieldChanges['comment'] = ['db' => $dbComment, 'scheme' => $schemeComment];
|
||||
}
|
||||
|
||||
if (!empty($fieldChanges)) {
|
||||
$changedFields[$field] = $fieldChanges;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($dbColumns as $field => $row) {
|
||||
if (!isset($schemeColumns[$field])) {
|
||||
$diffs[] = "多余字段:{$field}";
|
||||
$extraFields[] = $field;
|
||||
}
|
||||
}
|
||||
|
||||
$missingIndexes = [];
|
||||
$extraIndexes = [];
|
||||
$changedIndexes = [];
|
||||
|
||||
foreach ($schemeIndexes as $name => $idx) {
|
||||
if (!isset($dbIndexes[$name])) {
|
||||
$diffs[] = "缺少索引:{$name}";
|
||||
$missingIndexes[] = $name;
|
||||
continue;
|
||||
}
|
||||
|
||||
$dbIdx = $dbIndexes[$name];
|
||||
$idxChanges = [];
|
||||
|
||||
if ($dbIdx['type'] !== $idx['type']) {
|
||||
$diffs[] = "索引类型不一致:{$name} DB={$dbIdx['type']} Scheme={$idx['type']}";
|
||||
$idxChanges['type'] = ['db' => $dbIdx['type'], 'scheme' => $idx['type']];
|
||||
}
|
||||
|
||||
if ($dbIdx['columns'] !== $idx['columns']) {
|
||||
$diffs[] = "索引字段不一致:{$name} DB=" . implode(',', $dbIdx['columns']) . " Scheme=" . implode(',', $idx['columns']);
|
||||
$idxChanges['columns'] = [
|
||||
'db' => implode(',', $dbIdx['columns']),
|
||||
'scheme' => implode(',', $idx['columns']),
|
||||
];
|
||||
}
|
||||
|
||||
if (!empty($idxChanges)) {
|
||||
$changedIndexes[$name] = $idxChanges;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($dbIndexes as $name => $idx) {
|
||||
if (!isset($schemeIndexes[$name])) {
|
||||
$diffs[] = "多余索引:{$name}";
|
||||
$extraIndexes[] = $name;
|
||||
}
|
||||
}
|
||||
|
||||
$tableCommentDiff = $this->diffTableComment($connection, $fullTableName, $tableAttr->comment);
|
||||
if ($tableCommentDiff !== null) {
|
||||
$diffs[] = $tableCommentDiff;
|
||||
$hasDiff = !empty($missingFields) || !empty($extraFields) || !empty($changedFields) || !empty($missingIndexes) || !empty($extraIndexes) || !empty($changedIndexes) || $tableCommentDiff !== null;
|
||||
if (!$hasDiff) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return $diffs;
|
||||
$lines = [];
|
||||
$lines[] = '差异汇总:'
|
||||
. '字段缺失=' . count($missingFields)
|
||||
. ',字段多余=' . count($extraFields)
|
||||
. ',字段修改=' . count($changedFields)
|
||||
. ';索引缺失=' . count($missingIndexes)
|
||||
. ',索引多余=' . count($extraIndexes)
|
||||
. ',索引修改=' . count($changedIndexes)
|
||||
. ';表注释=' . ($tableCommentDiff !== null ? '不一致' : '一致');
|
||||
|
||||
if (!empty($missingFields)) {
|
||||
$lines[] = '字段缺失(' . count($missingFields) . '):' . implode(',', $missingFields);
|
||||
}
|
||||
if (!empty($extraFields)) {
|
||||
$lines[] = '字段多余(' . count($extraFields) . '):' . implode(',', $extraFields);
|
||||
}
|
||||
if (!empty($changedFields)) {
|
||||
$lines[] = '字段修改(' . count($changedFields) . '):' . implode(',', array_keys($changedFields));
|
||||
foreach ($changedFields as $field => $changes) {
|
||||
$lines[] = '字段 ' . $field . ':';
|
||||
foreach ($changes as $k => $v) {
|
||||
$lines[] = ' - ' . $k . ':DB=' . $v['db'] . ' Scheme=' . $v['scheme'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($missingIndexes)) {
|
||||
$lines[] = '索引缺失(' . count($missingIndexes) . '):' . implode(',', $missingIndexes);
|
||||
}
|
||||
if (!empty($extraIndexes)) {
|
||||
$lines[] = '索引多余(' . count($extraIndexes) . '):' . implode(',', $extraIndexes);
|
||||
}
|
||||
if (!empty($changedIndexes)) {
|
||||
$lines[] = '索引修改(' . count($changedIndexes) . '):' . implode(',', array_keys($changedIndexes));
|
||||
foreach ($changedIndexes as $name => $changes) {
|
||||
$lines[] = '索引 ' . $name . ':';
|
||||
foreach ($changes as $k => $v) {
|
||||
$lines[] = ' - ' . $k . ':DB=' . $v['db'] . ' Scheme=' . $v['scheme'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($tableCommentDiff !== null) {
|
||||
$lines[] = $tableCommentDiff;
|
||||
}
|
||||
|
||||
return $lines;
|
||||
}
|
||||
|
||||
public function getColumnsForCurd(string $className, array $onlyFields = []): array
|
||||
@@ -227,6 +299,7 @@ class SchemeToDbService
|
||||
|
||||
/** @var Field $field */
|
||||
$field = $fieldAttrs[0]->newInstance();
|
||||
$this->validateSchemeField($field, $ref->getName(), $fieldName);
|
||||
|
||||
$columns[$fieldName] = [
|
||||
'type' => $this->buildMysqlTypeFromSchemeField($field),
|
||||
@@ -283,6 +356,7 @@ class SchemeToDbService
|
||||
/** @var Field $field */
|
||||
$field = $fieldAttrs[0]->newInstance();
|
||||
$fieldName = $prop->getName();
|
||||
$this->validateSchemeField($field, $ref->getName(), $fieldName);
|
||||
|
||||
$line = "`$fieldName` {$field->type}";
|
||||
|
||||
@@ -364,6 +438,20 @@ class SchemeToDbService
|
||||
return "CREATE TABLE `$tableName` (\n $body\n) ENGINE={$tableAttr->engine} DEFAULT CHARSET={$tableAttr->charset}$comment";
|
||||
}
|
||||
|
||||
protected function validateSchemeField(Field $field, string $className, string $fieldName): void
|
||||
{
|
||||
$type = strtolower(trim($field->type));
|
||||
$length = $field->length;
|
||||
|
||||
if ($length !== null && $length < 1) {
|
||||
throw new \InvalidArgumentException("Scheme 字段定义非法:{$className}::\${$fieldName} length 必须 >= 1,当前={$length}");
|
||||
}
|
||||
|
||||
if ($type === 'char' && $length !== null && $length > 255) {
|
||||
throw new \InvalidArgumentException("Scheme 字段定义非法:{$className}::\${$fieldName} type=char 的 length 超出范围,允许 1-255,当前={$length}");
|
||||
}
|
||||
}
|
||||
|
||||
protected function restoreData(string $connection, $newTable, $oldTable, array $properties)
|
||||
{
|
||||
$fields = [];
|
||||
@@ -431,6 +519,7 @@ class SchemeToDbService
|
||||
$fieldName = $prop->getName();
|
||||
/** @var Field $field */
|
||||
$field = $fieldAttrs[0]->newInstance();
|
||||
$this->validateSchemeField($field, $ref->getName(), $fieldName);
|
||||
|
||||
$sig[$fieldName] = [
|
||||
'type' => $this->buildMysqlTypeFromSchemeField($field),
|
||||
@@ -614,6 +703,23 @@ class SchemeToDbService
|
||||
return (string)$dbDefault === (string)$schemeDefault;
|
||||
}
|
||||
|
||||
protected function stringifyDefault($value): string
|
||||
{
|
||||
if (is_null($value)) {
|
||||
return 'NULL';
|
||||
}
|
||||
|
||||
if (is_bool($value)) {
|
||||
return $value ? '1' : '0';
|
||||
}
|
||||
|
||||
if (is_int($value) || is_float($value)) {
|
||||
return (string)$value;
|
||||
}
|
||||
|
||||
return (string)$value;
|
||||
}
|
||||
|
||||
protected function diffTableComment(string $connection, string $tableName, string $schemeComment): ?string
|
||||
{
|
||||
$type = strtolower((string)Config::get('database.connections.' . $connection . '.type', ''));
|
||||
|
||||
Reference in New Issue
Block a user