package postgres import ( "context" "database/sql" "fmt" "time" "github.com/google/uuid" "github.com/ocdp/cluster-service/internal/domain/entity" "github.com/ocdp/cluster-service/internal/domain/repository" "github.com/ocdp/cluster-service/internal/pkg/crypto" ) // RegistryRepository PostgreSQL Registry 仓储实现 type RegistryRepository struct { db *DB encryptor crypto.Encryptor } // NewRegistryRepository 创建 PostgreSQL Registry 仓储 func NewRegistryRepository(db *DB, encryptor crypto.Encryptor) repository.RegistryRepository { return &RegistryRepository{ db: db, encryptor: encryptor, } } // Create 创建 Registry func (r *RegistryRepository) Create(ctx context.Context, registry *entity.Registry) error { if registry.ID == "" { registry.ID = uuid.New().String() } // 加密密码 encryptedPassword, err := r.encryptor.Encrypt(registry.Password) if err != nil { return fmt.Errorf("failed to encrypt password: %w", err) } query := ` INSERT INTO registries (id, name, url, description, username, password, insecure, created_at, updated_at) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) ` _, err = r.db.conn.ExecContext(ctx, query, registry.ID, registry.Name, registry.URL, registry.Description, registry.Username, encryptedPassword, registry.Insecure, registry.CreatedAt, registry.UpdatedAt, ) if err != nil { return fmt.Errorf("failed to create registry: %w", err) } return nil } // GetByID 根据 ID 获取 Registry func (r *RegistryRepository) GetByID(ctx context.Context, id string) (*entity.Registry, error) { query := ` SELECT id, name, url, description, username, password, insecure, created_at, updated_at FROM registries WHERE id = $1 ` registry := &entity.Registry{} var encryptedPassword string err := r.db.conn.QueryRowContext(ctx, query, id).Scan( ®istry.ID, ®istry.Name, ®istry.URL, ®istry.Description, ®istry.Username, &encryptedPassword, ®istry.Insecure, ®istry.CreatedAt, ®istry.UpdatedAt, ) if err == sql.ErrNoRows { return nil, entity.ErrRegistryNotFound } if err != nil { return nil, fmt.Errorf("failed to get registry: %w", err) } // 解密密码 registry.Password, err = r.encryptor.Decrypt(encryptedPassword) if err != nil { return nil, fmt.Errorf("failed to decrypt password: %w", err) } return registry, nil } // GetByName 根据名称获取 Registry func (r *RegistryRepository) GetByName(ctx context.Context, name string) (*entity.Registry, error) { query := ` SELECT id, name, url, description, username, password, insecure, created_at, updated_at FROM registries WHERE name = $1 ` registry := &entity.Registry{} var encryptedPassword string err := r.db.conn.QueryRowContext(ctx, query, name).Scan( ®istry.ID, ®istry.Name, ®istry.URL, ®istry.Description, ®istry.Username, &encryptedPassword, ®istry.Insecure, ®istry.CreatedAt, ®istry.UpdatedAt, ) if err == sql.ErrNoRows { return nil, entity.ErrRegistryNotFound } if err != nil { return nil, fmt.Errorf("failed to get registry: %w", err) } // 解密密码 registry.Password, err = r.encryptor.Decrypt(encryptedPassword) if err != nil { return nil, fmt.Errorf("failed to decrypt password: %w", err) } return registry, nil } // Update 更新 Registry func (r *RegistryRepository) Update(ctx context.Context, registry *entity.Registry) error { registry.UpdatedAt = time.Now() // 加密密码 encryptedPassword, err := r.encryptor.Encrypt(registry.Password) if err != nil { return fmt.Errorf("failed to encrypt password: %w", err) } query := ` UPDATE registries SET name = $1, url = $2, description = $3, username = $4, password = $5, insecure = $6, updated_at = $7 WHERE id = $8 ` result, err := r.db.conn.ExecContext(ctx, query, registry.Name, registry.URL, registry.Description, registry.Username, encryptedPassword, registry.Insecure, registry.UpdatedAt, registry.ID, ) if err != nil { return fmt.Errorf("failed to update registry: %w", err) } rows, err := result.RowsAffected() if err != nil { return fmt.Errorf("failed to get affected rows: %w", err) } if rows == 0 { return entity.ErrRegistryNotFound } return nil } // Delete 删除 Registry func (r *RegistryRepository) Delete(ctx context.Context, id string) error { query := `DELETE FROM registries WHERE id = $1` result, err := r.db.conn.ExecContext(ctx, query, id) if err != nil { return fmt.Errorf("failed to delete registry: %w", err) } rows, err := result.RowsAffected() if err != nil { return fmt.Errorf("failed to get affected rows: %w", err) } if rows == 0 { return entity.ErrRegistryNotFound } return nil } // List 列出所有 Registries func (r *RegistryRepository) List(ctx context.Context) ([]*entity.Registry, error) { query := ` SELECT id, name, url, description, username, password, insecure, created_at, updated_at FROM registries ORDER BY created_at DESC ` rows, err := r.db.conn.QueryContext(ctx, query) if err != nil { return nil, fmt.Errorf("failed to list registries: %w", err) } defer rows.Close() registries := make([]*entity.Registry, 0) for rows.Next() { registry := &entity.Registry{} var encryptedPassword string err := rows.Scan( ®istry.ID, ®istry.Name, ®istry.URL, ®istry.Description, ®istry.Username, &encryptedPassword, ®istry.Insecure, ®istry.CreatedAt, ®istry.UpdatedAt, ) if err != nil { return nil, fmt.Errorf("failed to scan registry: %w", err) } // 解密密码 registry.Password, err = r.encryptor.Decrypt(encryptedPassword) if err != nil { return nil, fmt.Errorf("failed to decrypt password: %w", err) } registries = append(registries, registry) } if err := rows.Err(); err != nil { return nil, fmt.Errorf("rows iteration error: %w", err) } return registries, nil }