auth/internal/ticket/repository/sqlite3/sqlite3_ticket.go

123 lines
2.7 KiB
Go

package sqlite3
import (
"context"
"database/sql"
"errors"
"fmt"
"net/url"
"time"
"github.com/jmoiron/sqlx"
"source.toby3d.me/toby3d/auth/internal/domain"
"source.toby3d.me/toby3d/auth/internal/ticket"
)
type (
Ticket struct {
Resource string `db:"resource"`
Subject string `db:"subject"`
Ticket string `db:"ticket"`
CreatedAt sql.NullTime `db:"created_at"`
}
sqlite3TicketRepository struct {
config *domain.Config
db *sqlx.DB
}
)
const (
QueryTable string = `CREATE TABLE IF NOT EXISTS tickets (
created_at DATETIME NOT NULL,
resource TEXT NOT NULL,
subject TEXT NOT NULL,
ticket TEXT UNIQUE PRIMARY KEY NOT NULL
);`
QueryGet string = `SELECT *
FROM tickets
WHERE ticket=$1;`
QueryCreate string = `INSERT INTO tickets (created_at, resource, subject, ticket)
VALUES (:created_at, :resource, :subject, :ticket);`
QueryDelete string = `DELETE FROM tickets
WHERE ticket=$1;`
)
func NewSQLite3TicketRepository(db *sqlx.DB, config *domain.Config) ticket.Repository {
db.MustExec(QueryTable)
return &sqlite3TicketRepository{
config: config,
db: db,
}
}
func (repo *sqlite3TicketRepository) Create(ctx context.Context, t domain.Ticket) error {
if _, err := repo.db.NamedExecContext(ctx, QueryCreate, NewTicket(&t)); err != nil {
return fmt.Errorf("cannot create token record in db: %w", err)
}
return nil
}
func (repo *sqlite3TicketRepository) GetAndDelete(ctx context.Context, rawTicket string) (*domain.Ticket, error) {
tx, err := repo.db.Beginx()
if err != nil {
_ = tx.Rollback()
return nil, fmt.Errorf("failed to begin transaction: %w", err)
}
tkt := new(Ticket)
if err = tx.GetContext(ctx, tkt, QueryGet, rawTicket); err != nil {
//nolint:errcheck // deffered method
defer tx.Rollback()
if errors.Is(err, sql.ErrNoRows) {
return nil, ticket.ErrNotExist
}
return nil, fmt.Errorf("cannot find ticket in db: %w", err)
}
if _, err = tx.ExecContext(ctx, QueryDelete, rawTicket); err != nil {
_ = tx.Rollback()
return nil, fmt.Errorf("cannot remove ticket from db: %w", err)
}
if err = tx.Commit(); err != nil {
return nil, fmt.Errorf("failed to commit transaction: %w", err)
}
result := new(domain.Ticket)
tkt.Populate(result)
return result, nil
}
func (repo *sqlite3TicketRepository) GC() {}
func NewTicket(src *domain.Ticket) *Ticket {
return &Ticket{
CreatedAt: sql.NullTime{
Time: time.Now().UTC(),
Valid: true,
},
Resource: src.Resource.String(),
Subject: src.Subject.String(),
Ticket: src.Ticket,
}
}
func (t *Ticket) Populate(dst *domain.Ticket) {
dst.Ticket = t.Ticket
dst.Subject, _ = domain.ParseMe(t.Subject)
dst.Resource, _ = url.Parse(t.Resource)
}