Files
repo/repo.go

120 lines
2.4 KiB
Go
Raw Normal View History

2025-05-03 21:35:32 +03:00
package outbox
import (
"context"
"database/sql"
"encoding/json"
"errors"
"time"
)
var (
ErrSerialize = errors.New("error serialize/deserialize")
ErrInsert = errors.New("error create")
ErrNotFound = errors.New("not found")
ErrRead = errors.New("error read")
ErrUpdate = errors.New("error update")
ErrDelete = errors.New("error delete")
)
func OpenOrCreate[T any](ctx context.Context, db *sql.DB, tablename string) (*Repo[T], error) {
if err := initDB(ctx, db, tablename); err != nil {
return nil, err
}
return &Repo[T]{
db: db,
table: tablename,
}, nil
}
type Repo[T any] struct {
db *sql.DB
table string
}
func (r *Repo[T]) CreateOrUpdate(ctx context.Context, id string, v *T) error {
now := time.Now()
stmt := "INSERT INTO $1 (id, created_at, updated_at, payload) VALUES ($2, $3, $4)"
b, err := serialize(v)
if err != nil {
return err
}
if _, err := r.db.ExecContext(ctx, stmt, r.table, id, now, now, b); err != nil {
return errors.Join(ErrInsert, err)
}
return nil
}
func (r *Repo[T]) Read(ctx context.Context, id string) (*T, error) {
stmt := "SELECT payload FROM $1 WHERE id = $2 AND deleted_at is NULL"
row, err := r.db.QueryContext(ctx, stmt, r.table, id)
if err != nil {
// TODO err not found
return nil, errors.Join(ErrRead, err)
}
b := []byte{}
if err := row.Scan(&b); err != nil {
return nil, err
}
v, err := deserialize[T](b)
if err != nil {
return nil, err
}
return v, nil
}
func (r *Repo[T]) Update(ctx context.Context, id string, v *T) error {
now := time.Now()
stmt := "UPDATE $1 SET updated_at = $3, payload = $4 WHERE id = $2"
b, err := json.Marshal(v)
if err != nil {
return errors.Join(ErrSerialize, err)
}
if _, err := r.db.ExecContext(ctx, stmt, r.table, id, now, b); err != nil {
return errors.Join(ErrUpdate, err)
}
return nil
}
func (r *Repo[T]) Delete(ctx context.Context, id string) error {
now := time.Now()
stmt := "UPDATE $1 SET deleted_at = $3 WHERE id = $2"
if _, err := r.db.ExecContext(ctx, stmt, r.table, now, id); err != nil {
return errors.Join(ErrDelete, err)
}
return nil
}
func serialize(v any) ([]byte, error) {
b, err := json.Marshal(v)
if err != nil {
return nil, errors.Join(ErrSerialize, err)
}
return b, nil
}
func deserialize[T any](b []byte) (*T, error) {
v := new(T)
if err := json.Unmarshal(b, v); err != nil {
return nil, errors.Join(ErrSerialize, err)
}
return v, nil
}