kra-new/internal/data/integration/migrations.go

154 lines
4.6 KiB
Go

package integration
import (
"encoding/json"
"errors"
"reflect"
"strings"
integrationbiz "kra/internal/biz/integration"
"kra/pkg/database/migration"
"gorm.io/gorm"
)
func Migrations() []migration.Step {
return []migration.Step{
{ID: "202608200001_data_infrastructure", Migrate: func(db *gorm.DB) error {
return migration.CreateMissingTables(db, &ConfigPO{})
}},
{ID: "202608210001_communication_integration_defaults", Migrate: ensureCommunicationIntegrationConfigs},
{ID: "202608200004_payment_defaults", Migrate: ensurePaymentIntegrationConfigs},
{ID: "202608290004_kafka_integration_default", Migrate: ensureKafkaIntegrationConfig},
{ID: "202608290005_communication_integration_default_upgrade", Migrate: upgradeCommunicationIntegrationDefaults},
}
}
func ensureCommunicationIntegrationConfigs(db *gorm.DB) error {
defaults := []struct{ kind, provider string }{
{integrationbiz.IntegrationKindMQ, "emqx"},
{integrationbiz.IntegrationKindMQ, "kafka"},
{integrationbiz.IntegrationKindMQ, "rabbitmq"},
{integrationbiz.IntegrationKindWebSocket, "melody"},
}
for _, item := range defaults {
if err := ensureIntegrationConfig(db, item.kind, item.provider); err != nil {
return err
}
}
return nil
}
func ensureKafkaIntegrationConfig(db *gorm.DB) error {
return ensureIntegrationConfig(db, integrationbiz.IntegrationKindMQ, "kafka")
}
func ensureIntegrationConfig(db *gorm.DB, kind, provider string) error {
var row ConfigPO
err := db.Where("kind = ? AND provider = ?", kind, provider).First(&row).Error
if errors.Is(err, gorm.ErrRecordNotFound) {
values, marshalErr := json.Marshal(integrationbiz.DefaultIntegrationConfig(kind, provider))
if marshalErr != nil {
return marshalErr
}
return db.Create(&ConfigPO{Kind: kind, Provider: provider, Enabled: false, Config: string(values)}).Error
}
return err
}
func upgradeCommunicationIntegrationDefaults(db *gorm.DB) error {
for _, kind := range []string{integrationbiz.IntegrationKindMQ, integrationbiz.IntegrationKindWebSocket} {
for _, definition := range integrationbiz.IntegrationDefinitions(kind) {
var row ConfigPO
err := db.Where("kind = ? AND provider = ?", kind, definition.Provider).First(&row).Error
if errors.Is(err, gorm.ErrRecordNotFound) {
continue
}
if err != nil {
return err
}
values := integrationObject(json.RawMessage(row.Config))
changed := false
for key, value := range definition.Defaults {
if _, exists := values[key]; !exists {
values[key] = value
changed = true
}
}
for _, field := range definition.Fields {
if !field.Required || !emptyIntegrationConfigValue(values[field.Key]) || emptyIntegrationConfigValue(definition.Defaults[field.Key]) {
continue
}
values[field.Key] = definition.Defaults[field.Key]
changed = true
}
if _, exists := values["enabled"]; exists {
delete(values, "enabled")
changed = true
}
if !changed {
continue
}
encoded, marshalErr := json.Marshal(values)
if marshalErr != nil {
return marshalErr
}
if err := db.Model(&row).Update("config", string(encoded)).Error; err != nil {
return err
}
}
}
return nil
}
func emptyIntegrationConfigValue(value any) bool {
switch typed := value.(type) {
case nil:
return true
case string:
return strings.TrimSpace(typed) == ""
case []any:
return len(typed) == 0
case []string:
return len(typed) == 0
default:
return false
}
}
func ensurePaymentIntegrationConfigs(db *gorm.DB) error {
for _, definition := range integrationbiz.IntegrationDefinitions(integrationbiz.IntegrationKindPayment) {
provider := definition.Provider
var row ConfigPO
err := db.Where("kind = ? AND provider = ?", integrationbiz.IntegrationKindPayment, provider).First(&row).Error
defaults := integrationbiz.DefaultIntegrationConfig(integrationbiz.IntegrationKindPayment, provider)
if errors.Is(err, gorm.ErrRecordNotFound) {
encoded, marshalErr := json.Marshal(defaults)
if marshalErr != nil {
return marshalErr
}
if err := db.Create(&ConfigPO{Kind: integrationbiz.IntegrationKindPayment, Provider: provider, Config: string(encoded)}).Error; err != nil {
return err
}
continue
}
if err != nil {
return err
}
values := integrationObject(json.RawMessage(row.Config))
merged := integrationbiz.MergeIntegrationDefaults(defaults, values)
changed := !reflect.DeepEqual(values, merged)
values = merged
if changed {
encoded, marshalErr := json.Marshal(values)
if marshalErr != nil {
return marshalErr
}
if err := db.Model(&row).Update("config", string(encoded)).Error; err != nil {
return err
}
}
}
return nil
}