polycule-connect/polyculeconnect/internal/db/backend/backend.go

138 lines
3.9 KiB
Go
Raw Normal View History

package backend
import (
"context"
"database/sql"
"encoding/json"
"errors"
"fmt"
"git.faercol.me/faercol/polyculeconnect/polyculeconnect/internal/model"
2024-10-06 09:28:26 +00:00
"git.faercol.me/faercol/polyculeconnect/polyculeconnect/logger"
"github.com/google/uuid"
)
var ErrNotFound = errors.New("backend not found")
const backendRows = `"id", "name", "oidc_issuer", "oidc_client_id", "oidc_client_secret", "oidc_redirect_uri", "oidc_scopes"`
type scannable interface {
Scan(dest ...any) error
}
type BackendDB interface {
GetAllBackends(ctx context.Context) ([]*model.Backend, error)
2024-09-22 08:26:27 +00:00
GetBackendByID(ctx context.Context, id uuid.UUID) (*model.Backend, error)
GetBackendByName(ctx context.Context, name string) (*model.Backend, error)
AddBackend(ctx context.Context, newBackend *model.Backend) error
DeleteBackend(ctx context.Context, id uuid.UUID) error
}
type sqlBackendDB struct {
db *sql.DB
}
func backendFromRow(row scannable) (*model.Backend, error) {
var res model.Backend
var scopesStr []byte
fmt.Println(string(scopesStr))
if err := row.Scan(&res.ID, &res.Name, &res.Config.Issuer, &res.Config.ClientID, &res.Config.ClientSecret, &res.Config.RedirectURI, &scopesStr); err != nil {
if errors.Is(err, sql.ErrNoRows) {
return nil, ErrNotFound
}
return nil, fmt.Errorf("invalid format for backend: %w", err)
}
if err := json.Unmarshal(scopesStr, &res.Config.Scopes); err != nil {
return nil, fmt.Errorf("invalid value for scopes: %w", err)
}
return &res, nil
}
func (db *sqlBackendDB) GetBackendByName(ctx context.Context, name string) (*model.Backend, error) {
2024-10-06 09:28:26 +00:00
logger.L.Debugf("Getting backend with name %s from DB", name)
query := fmt.Sprintf(`SELECT %s FROM "backend" WHERE "name" = ?`, backendRows)
row := db.db.QueryRowContext(ctx, query, name)
return backendFromRow(row)
}
2024-09-22 08:26:27 +00:00
func (db *sqlBackendDB) GetBackendByID(ctx context.Context, id uuid.UUID) (*model.Backend, error) {
2024-10-06 09:28:26 +00:00
logger.L.Debugf("Getting backend with ID %s from DB", id)
2024-09-22 08:26:27 +00:00
query := fmt.Sprintf(`SELECT %s FROM "backend" WHERE "id" = ?`, backendRows)
row := db.db.QueryRowContext(ctx, query, id)
return backendFromRow(row)
}
func (db *sqlBackendDB) GetAllBackends(ctx context.Context) ([]*model.Backend, error) {
2024-10-06 09:28:26 +00:00
logger.L.Debug("Getting all backends from DB")
rows, err := db.db.QueryContext(ctx, fmt.Sprintf(`SELECT %s FROM "backend"`, backendRows))
if err != nil {
return nil, err
}
var res []*model.Backend
for rows.Next() {
b, err := backendFromRow(rows)
if err != nil {
return nil, err
}
res = append(res, b)
}
2024-10-06 09:28:26 +00:00
return res, rows.Err()
}
func (db *sqlBackendDB) AddBackend(ctx context.Context, newBackend *model.Backend) error {
tx, err := db.db.BeginTx(ctx, nil)
if err != nil {
return fmt.Errorf("failed to start transaction: %w", err)
}
defer func() { _ = tx.Rollback() }()
scopesStr, err := json.Marshal(newBackend.Config.Scopes)
if err != nil {
return fmt.Errorf("failed to serialize scopes: %w", err)
}
query := fmt.Sprintf(`INSERT INTO "backend" (%s) VALUES ($1, $2, $3, $4, $5, $6, $7)`, backendRows)
_, err = tx.ExecContext(
ctx, query,
newBackend.ID, newBackend.Name,
newBackend.Config.Issuer, newBackend.Config.ClientID,
newBackend.Config.ClientSecret, newBackend.Config.RedirectURI,
scopesStr,
)
if err != nil {
return fmt.Errorf("failed to insert in DB: %w", err)
}
if err := tx.Commit(); err != nil {
return fmt.Errorf("failed to commit transaction: %w", err)
}
return nil
}
func (db *sqlBackendDB) DeleteBackend(ctx context.Context, id uuid.UUID) error {
tx, err := db.db.BeginTx(ctx, nil)
if err != nil {
return fmt.Errorf("failed to start transaction: %w", err)
}
defer func() { _ = tx.Rollback() }()
if _, err := tx.ExecContext(ctx, `DELETE FROM "backend" WHERE id = $1`, id.String()); err != nil {
return fmt.Errorf("failed to run query: %w", err)
}
if err := tx.Commit(); err != nil {
return fmt.Errorf("failed to commit transaction: %w", err)
}
return nil
}
func New(db *sql.DB) *sqlBackendDB {
return &sqlBackendDB{db: db}
}