132 lines
3.9 KiB
Go
132 lines
3.9 KiB
Go
package notificationstore
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
|
|
pgtable "galaxy/notification/internal/adapters/postgres/jet/notification/table"
|
|
"galaxy/notification/internal/service/malformedintent"
|
|
|
|
pg "github.com/go-jet/jet/v2/postgres"
|
|
)
|
|
|
|
// Record stores entry idempotently by stream entry id. The helper satisfies
|
|
// `worker.MalformedIntentRecorder`. Re-recording an entry with the same
|
|
// `stream_entry_id` is a silent no-op via `ON CONFLICT DO NOTHING`.
|
|
func (store *Store) Record(ctx context.Context, entry malformedintent.Entry) error {
|
|
if store == nil {
|
|
return errors.New("record malformed intent: nil store")
|
|
}
|
|
if ctx == nil {
|
|
return errors.New("record malformed intent: nil context")
|
|
}
|
|
if err := entry.Validate(); err != nil {
|
|
return fmt.Errorf("record malformed intent: %w", err)
|
|
}
|
|
|
|
rawFields, err := marshalRawFields(entry.RawFields)
|
|
if err != nil {
|
|
return fmt.Errorf("record malformed intent: %w", err)
|
|
}
|
|
|
|
operationCtx, cancel, err := store.operationContext(ctx, "record malformed intent")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer cancel()
|
|
|
|
stmt := pgtable.MalformedIntents.INSERT(
|
|
pgtable.MalformedIntents.StreamEntryID,
|
|
pgtable.MalformedIntents.NotificationType,
|
|
pgtable.MalformedIntents.Producer,
|
|
pgtable.MalformedIntents.IdempotencyKey,
|
|
pgtable.MalformedIntents.FailureCode,
|
|
pgtable.MalformedIntents.FailureMessage,
|
|
pgtable.MalformedIntents.RawFields,
|
|
pgtable.MalformedIntents.RecordedAt,
|
|
).VALUES(
|
|
entry.StreamEntryID,
|
|
entry.NotificationType,
|
|
entry.Producer,
|
|
entry.IdempotencyKey,
|
|
string(entry.FailureCode),
|
|
entry.FailureMessage,
|
|
rawFields,
|
|
entry.RecordedAt.UTC(),
|
|
).ON_CONFLICT(pgtable.MalformedIntents.StreamEntryID).DO_NOTHING()
|
|
|
|
query, args := stmt.Sql()
|
|
if _, err := store.db.ExecContext(operationCtx, query, args...); err != nil {
|
|
return fmt.Errorf("record malformed intent: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// GetMalformedIntent loads one malformed-intent entry by stream entry id.
|
|
// Returns found=false when no such row exists.
|
|
func (store *Store) GetMalformedIntent(ctx context.Context, streamEntryID string) (malformedintent.Entry, bool, error) {
|
|
if store == nil {
|
|
return malformedintent.Entry{}, false, errors.New("get malformed intent: nil store")
|
|
}
|
|
if ctx == nil {
|
|
return malformedintent.Entry{}, false, errors.New("get malformed intent: nil context")
|
|
}
|
|
|
|
operationCtx, cancel, err := store.operationContext(ctx, "get malformed intent")
|
|
if err != nil {
|
|
return malformedintent.Entry{}, false, err
|
|
}
|
|
defer cancel()
|
|
|
|
stmt := pg.SELECT(
|
|
pgtable.MalformedIntents.NotificationType,
|
|
pgtable.MalformedIntents.Producer,
|
|
pgtable.MalformedIntents.IdempotencyKey,
|
|
pgtable.MalformedIntents.FailureCode,
|
|
pgtable.MalformedIntents.FailureMessage,
|
|
pgtable.MalformedIntents.RawFields,
|
|
pgtable.MalformedIntents.RecordedAt,
|
|
).FROM(pgtable.MalformedIntents).
|
|
WHERE(pgtable.MalformedIntents.StreamEntryID.EQ(pg.String(streamEntryID)))
|
|
|
|
query, args := stmt.Sql()
|
|
row := store.db.QueryRowContext(operationCtx, query, args...)
|
|
|
|
var (
|
|
notificationType string
|
|
producer string
|
|
idempotencyKey string
|
|
failureCode string
|
|
failureMessage string
|
|
rawFields []byte
|
|
)
|
|
entry := malformedintent.Entry{StreamEntryID: streamEntryID}
|
|
if err := row.Scan(
|
|
¬ificationType,
|
|
&producer,
|
|
&idempotencyKey,
|
|
&failureCode,
|
|
&failureMessage,
|
|
&rawFields,
|
|
&entry.RecordedAt,
|
|
); err != nil {
|
|
if isNoRows(err) {
|
|
return malformedintent.Entry{}, false, nil
|
|
}
|
|
return malformedintent.Entry{}, false, fmt.Errorf("get malformed intent: %w", err)
|
|
}
|
|
entry.NotificationType = notificationType
|
|
entry.Producer = producer
|
|
entry.IdempotencyKey = idempotencyKey
|
|
entry.FailureCode = malformedintent.FailureCode(failureCode)
|
|
entry.FailureMessage = failureMessage
|
|
entry.RecordedAt = entry.RecordedAt.UTC()
|
|
fields, err := unmarshalRawFields(rawFields)
|
|
if err != nil {
|
|
return malformedintent.Entry{}, false, fmt.Errorf("get malformed intent: %w", err)
|
|
}
|
|
entry.RawFields = fields
|
|
return entry, true, nil
|
|
}
|