feat: 发布智能体版

This commit is contained in:
augushong
2026-03-26 20:22:34 +08:00
parent 7ee9e102a5
commit 8cc08bcb8c
138 changed files with 7964 additions and 660 deletions

View File

@@ -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', ''));