feat: use postgres
This commit is contained in:
@@ -0,0 +1,148 @@
|
||||
package mailstore
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
pgtable "galaxy/mail/internal/adapters/postgres/jet/mail/table"
|
||||
"galaxy/mail/internal/domain/malformedcommand"
|
||||
|
||||
pg "github.com/go-jet/jet/v2/postgres"
|
||||
)
|
||||
|
||||
// Record stores entry idempotently by stream entry id. The helper satisfies
|
||||
// worker.MalformedCommandRecorder.
|
||||
func (store *Store) Record(ctx context.Context, entry malformedcommand.Entry) error {
|
||||
if store == nil {
|
||||
return errors.New("record malformed command: nil store")
|
||||
}
|
||||
if ctx == nil {
|
||||
return errors.New("record malformed command: nil context")
|
||||
}
|
||||
if err := entry.Validate(); err != nil {
|
||||
return fmt.Errorf("record malformed command: %w", err)
|
||||
}
|
||||
|
||||
rawFields, err := marshalRawFields(entry.RawFields)
|
||||
if err != nil {
|
||||
return fmt.Errorf("record malformed command: %w", err)
|
||||
}
|
||||
|
||||
operationCtx, cancel, err := store.operationContext(ctx, "record malformed command")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cancel()
|
||||
|
||||
stmt := pgtable.MalformedCommands.INSERT(
|
||||
pgtable.MalformedCommands.StreamEntryID,
|
||||
pgtable.MalformedCommands.DeliveryID,
|
||||
pgtable.MalformedCommands.Source,
|
||||
pgtable.MalformedCommands.IdempotencyKey,
|
||||
pgtable.MalformedCommands.FailureCode,
|
||||
pgtable.MalformedCommands.FailureMessage,
|
||||
pgtable.MalformedCommands.RawFields,
|
||||
pgtable.MalformedCommands.RecordedAt,
|
||||
).VALUES(
|
||||
entry.StreamEntryID,
|
||||
entry.DeliveryID,
|
||||
entry.Source,
|
||||
entry.IdempotencyKey,
|
||||
string(entry.FailureCode),
|
||||
entry.FailureMessage,
|
||||
rawFields,
|
||||
entry.RecordedAt.UTC(),
|
||||
).ON_CONFLICT(pgtable.MalformedCommands.StreamEntryID).DO_NOTHING()
|
||||
|
||||
query, args := stmt.Sql()
|
||||
if _, err := store.db.ExecContext(operationCtx, query, args...); err != nil {
|
||||
return fmt.Errorf("record malformed command: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetMalformedCommand loads one malformed-command entry by stream entry id.
|
||||
func (store *Store) GetMalformedCommand(ctx context.Context, streamEntryID string) (malformedcommand.Entry, bool, error) {
|
||||
if store == nil {
|
||||
return malformedcommand.Entry{}, false, errors.New("get malformed command: nil store")
|
||||
}
|
||||
if ctx == nil {
|
||||
return malformedcommand.Entry{}, false, errors.New("get malformed command: nil context")
|
||||
}
|
||||
operationCtx, cancel, err := store.operationContext(ctx, "get malformed command")
|
||||
if err != nil {
|
||||
return malformedcommand.Entry{}, false, err
|
||||
}
|
||||
defer cancel()
|
||||
|
||||
stmt := pg.SELECT(
|
||||
pgtable.MalformedCommands.DeliveryID,
|
||||
pgtable.MalformedCommands.Source,
|
||||
pgtable.MalformedCommands.IdempotencyKey,
|
||||
pgtable.MalformedCommands.FailureCode,
|
||||
pgtable.MalformedCommands.FailureMessage,
|
||||
pgtable.MalformedCommands.RawFields,
|
||||
pgtable.MalformedCommands.RecordedAt,
|
||||
).FROM(pgtable.MalformedCommands).
|
||||
WHERE(pgtable.MalformedCommands.StreamEntryID.EQ(pg.String(streamEntryID)))
|
||||
|
||||
query, args := stmt.Sql()
|
||||
row := store.db.QueryRowContext(operationCtx, query, args...)
|
||||
var (
|
||||
deliveryID string
|
||||
source string
|
||||
idempotencyKey string
|
||||
failureCode string
|
||||
failureMessage string
|
||||
rawFields []byte
|
||||
)
|
||||
entry := malformedcommand.Entry{StreamEntryID: streamEntryID}
|
||||
if err := row.Scan(&deliveryID, &source, &idempotencyKey, &failureCode, &failureMessage, &rawFields, &entry.RecordedAt); err != nil {
|
||||
if isNoRows(err) {
|
||||
return malformedcommand.Entry{}, false, nil
|
||||
}
|
||||
return malformedcommand.Entry{}, false, fmt.Errorf("get malformed command: %w", err)
|
||||
}
|
||||
entry.DeliveryID = deliveryID
|
||||
entry.Source = source
|
||||
entry.IdempotencyKey = idempotencyKey
|
||||
entry.FailureCode = malformedcommand.FailureCode(failureCode)
|
||||
entry.FailureMessage = failureMessage
|
||||
entry.RecordedAt = entry.RecordedAt.UTC()
|
||||
fields, err := unmarshalRawFields(rawFields)
|
||||
if err != nil {
|
||||
return malformedcommand.Entry{}, false, fmt.Errorf("get malformed command: %w", err)
|
||||
}
|
||||
entry.RawFields = fields
|
||||
return entry, true, nil
|
||||
}
|
||||
|
||||
// DeleteMalformedCommandsOlderThan removes malformed-command rows whose
|
||||
// recorded_at predates cutoff. The helper satisfies the SQLRetentionStore
|
||||
// contract used by the periodic retention worker.
|
||||
func (store *Store) DeleteMalformedCommandsOlderThan(ctx context.Context, cutoff time.Time) (int64, error) {
|
||||
if store == nil {
|
||||
return 0, errors.New("delete malformed commands: nil store")
|
||||
}
|
||||
operationCtx, cancel, err := store.operationContext(ctx, "delete malformed commands")
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer cancel()
|
||||
|
||||
stmt := pgtable.MalformedCommands.DELETE().
|
||||
WHERE(pgtable.MalformedCommands.RecordedAt.LT(pg.TimestampzT(cutoff.UTC())))
|
||||
|
||||
query, args := stmt.Sql()
|
||||
result, err := store.db.ExecContext(operationCtx, query, args...)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("delete malformed commands: %w", err)
|
||||
}
|
||||
rows, err := result.RowsAffected()
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("delete malformed commands: rows affected: %w", err)
|
||||
}
|
||||
return rows, nil
|
||||
}
|
||||
Reference in New Issue
Block a user