refactor(db): use version string as primary key for ConfigVersion

-transition `of_config_versions` primary key from `id` to `version` string.
-add database migration files `202606270001_make_version_primary_key.sql` for PostgreSQL and SQLite.
-introduce AfterFind/AfterCreate GORM hooks to preserve JSON backward compatibility.
-refactor API controllers, logics, and front-end typescript definitions to receive `string` parameter.
This commit is contained in:
ryan
2026-06-27 13:23:30 +08:00
parent b48414e1fe
commit 13d6966cb5
11 changed files with 132 additions and 39 deletions
@@ -79,9 +79,9 @@ func ListConfigVersions(ctx context.Context) ([]*model.ConfigVersionSummary, err
return model.ListConfigVersionSummaries(ctx)
}
// GetConfigVersionDetail returns a config version by id.
func GetConfigVersionDetail(ctx context.Context, id uint) (*model.ConfigVersion, error) {
return model.GetConfigVersionByID(ctx, id)
// GetConfigVersionDetail returns a config version by version.
func GetConfigVersionDetail(ctx context.Context, version string) (*model.ConfigVersion, error) {
return model.GetConfigVersionByVersion(ctx, version)
}
// GetActiveConfigVersion returns the active config version.
@@ -243,12 +243,12 @@ func PublishConfigVersion(ctx context.Context, createdBy string, force bool) (*m
}
// ActivateConfigVersion activates an existing config version.
func ActivateConfigVersion(ctx context.Context, id uint) (*model.ConfigVersion, error) {
version, err := model.GetConfigVersionByID(ctx, id)
func ActivateConfigVersion(ctx context.Context, versionStr string) (*model.ConfigVersion, error) {
version, err := model.GetConfigVersionByVersion(ctx, versionStr)
if err != nil {
return nil, err
}
if err = model.ActivateConfigVersionTx(ctx, id); err != nil {
if err = model.ActivateConfigVersionTx(ctx, versionStr); err != nil {
return nil, err
}
version.IsActive = true
@@ -271,7 +271,7 @@ func CleanupConfigVersions(ctx context.Context, keepCount int) (*CleanupResult,
if len(versions) <= keepCount {
return &CleanupResult{DeletedCount: 0, Message: cleanupSuccessMessage}, nil
}
var deleteIDs []uint
var deleteVersions []string
for index, version := range versions {
if index < keepCount {
continue
@@ -279,12 +279,12 @@ func CleanupConfigVersions(ctx context.Context, keepCount int) (*CleanupResult,
if version.IsActive {
continue
}
deleteIDs = append(deleteIDs, version.ID)
deleteVersions = append(deleteVersions, version.Version)
}
if len(deleteIDs) == 0 {
if len(deleteVersions) == 0 {
return &CleanupResult{DeletedCount: 0, Message: cleanupSuccessMessage}, nil
}
deletedCount, err := model.DeleteConfigVersionsByIDs(ctx, deleteIDs)
deletedCount, err := model.DeleteConfigVersionsByVersions(ctx, deleteVersions)
if err != nil {
return nil, err
}
@@ -31,6 +31,7 @@ func setupConfigVersionTestDB(t *testing.T) func() {
&model.OpenFlareWAFRuleGroup{},
&model.OpenFlareWAFRuleGroupBinding{},
&model.OpenFlareWAFIPGroup{},
&model.SystemConfig{},
))
db.SetDB(sqliteDB)
@@ -64,7 +65,6 @@ func TestListConfigVersionsOrdersByCreatedAtDesc(t *testing.T) {
}
require.NoError(t, conn.Create(newer).Error)
require.NoError(t, conn.Create(older).Error)
require.Greater(t, older.ID, newer.ID)
versions, err := ListConfigVersions(ctx)
require.NoError(t, err)
@@ -91,7 +91,7 @@ func TestPublishConfigVersionCreatesVersion(t *testing.T) {
version, err := PublishConfigVersion(ctx, "tester", false)
require.NoError(t, err)
require.NotNil(t, version)
assert.NotZero(t, version.ID)
assert.NotEmpty(t, version.ID)
assert.True(t, version.IsActive)
assert.Equal(t, "tester", version.CreatedBy)
assert.NotEmpty(t, version.Version)
@@ -18,6 +18,15 @@ func handleLogicError(c *gin.Context, err error) bool {
return apiutil.AbortNotFoundIfMissing(c, err, "记录不存在")
}
func versionParam(c *gin.Context) (string, bool) {
version := c.Param("id")
if version == "" {
response.AbortBadRequest(c, "无效的版本号")
return "", false
}
return version, true
}
// ListConfigVersionsHandler lists config versions.
// @Summary 获取配置版本列表
// @Description 返回所有已发布的 OpenResty 配置版本摘要,按创建时间倒序排列,需要管理员权限
@@ -50,11 +59,11 @@ func ListConfigVersionsHandler(c *gin.Context) {
// @Failure 404 {object} response.Any "无权限或版本不存在"
// @Router /api/v1/d/config-versions/{id} [get]
func GetConfigVersionHandler(c *gin.Context) {
id, ok := apiutil.IDParam(c)
versionStr, ok := versionParam(c)
if !ok {
return
}
version, err := GetConfigVersionDetail(c.Request.Context(), id)
version, err := GetConfigVersionDetail(c.Request.Context(), versionStr)
if handleLogicError(c, err) {
return
}
@@ -152,11 +161,11 @@ func PublishConfigVersionHandler(c *gin.Context) {
// @Failure 404 {object} response.Any "无权限或版本不存在"
// @Router /api/v1/d/config-versions/{id}/activate [post]
func ActivateConfigVersionHandler(c *gin.Context) {
id, ok := apiutil.IDParam(c)
versionStr, ok := versionParam(c)
if !ok {
return
}
version, err := ActivateConfigVersion(c.Request.Context(), id)
version, err := ActivateConfigVersion(c.Request.Context(), versionStr)
if handleLogicError(c, err) {
return
}