124 lines
3.6 KiB
Go
124 lines
3.6 KiB
Go
package backend
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"errors"
|
|
"fmt"
|
|
|
|
"git.faercol.me/faercol/polyculeconnect/polyculeconnect/internal/model"
|
|
"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"`
|
|
|
|
type scannable interface {
|
|
Scan(dest ...any) error
|
|
}
|
|
|
|
type BackendDB interface {
|
|
GetAllBackends(ctx context.Context) ([]*model.Backend, error)
|
|
|
|
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
|
|
|
|
if err := row.Scan(&res.ID, &res.Name, &res.OIDCConfig.Issuer, &res.OIDCConfig.ClientID, &res.OIDCConfig.ClientSecret, &res.OIDCConfig.RedirectURI); err != nil {
|
|
if errors.Is(err, sql.ErrNoRows) {
|
|
return nil, ErrNotFound
|
|
}
|
|
return nil, fmt.Errorf("invalid format for backend: %w", err)
|
|
}
|
|
return &res, nil
|
|
}
|
|
|
|
func (db *sqlBackendDB) GetBackendByName(ctx context.Context, name string) (*model.Backend, error) {
|
|
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)
|
|
}
|
|
|
|
func (db *sqlBackendDB) GetBackendByID(ctx context.Context, id uuid.UUID) (*model.Backend, error) {
|
|
logger.L.Debugf("Getting backend with ID %s from DB", id)
|
|
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) {
|
|
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)
|
|
}
|
|
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() }()
|
|
|
|
query := fmt.Sprintf(`INSERT INTO "backend" (%s) VALUES ($1, $2, $3, $4, $5, $6)`, backendRows)
|
|
_, err = tx.ExecContext(
|
|
ctx, query,
|
|
newBackend.ID, newBackend.Name,
|
|
newBackend.OIDCConfig.Issuer, newBackend.OIDCConfig.ClientID,
|
|
newBackend.OIDCConfig.ClientSecret, newBackend.OIDCConfig.RedirectURI,
|
|
)
|
|
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}
|
|
}
|