Files
galaxy-game/mail/internal/adapters/postgres/mailstore/generic_acceptance.go
T
2026-04-26 20:34:39 +02:00

88 lines
3.3 KiB
Go

package mailstore
import (
"context"
"database/sql"
"errors"
"fmt"
pgtable "galaxy/mail/internal/adapters/postgres/jet/mail/table"
"galaxy/mail/internal/domain/common"
deliverydomain "galaxy/mail/internal/domain/delivery"
"galaxy/mail/internal/domain/idempotency"
"galaxy/mail/internal/service/acceptgenericdelivery"
)
// GenericAcceptance returns a handle that satisfies
// acceptgenericdelivery.Store. Generic and auth acceptance share the same
// idempotency / delivery read paths but the write input types differ — the
// adapter avoids a method-name conflict on Store.CreateAcceptance.
func (store *Store) GenericAcceptance() *GenericAcceptanceStore {
return &GenericAcceptanceStore{store: store}
}
// GenericAcceptanceStore is the acceptgenericdelivery.Store handle returned
// by Store.GenericAcceptance. It defers to the umbrella store for shared
// reads.
type GenericAcceptanceStore struct {
store *Store
}
var _ acceptgenericdelivery.Store = (*GenericAcceptanceStore)(nil)
// CreateAcceptance writes one generic-delivery acceptance write set inside
// one BEGIN … COMMIT transaction. Idempotency races surface as
// acceptgenericdelivery.ErrConflict.
func (handle *GenericAcceptanceStore) CreateAcceptance(ctx context.Context, input acceptgenericdelivery.CreateAcceptanceInput) error {
if handle == nil || handle.store == nil {
return errors.New("create generic acceptance: nil store")
}
if ctx == nil {
return errors.New("create generic acceptance: nil context")
}
if err := input.Validate(); err != nil {
return fmt.Errorf("create generic acceptance: %w", err)
}
return handle.store.withTx(ctx, "create generic acceptance", func(ctx context.Context, tx *sql.Tx) error {
first := input.FirstAttempt
if err := insertDelivery(ctx, tx, input.Delivery, input.Idempotency, input.Idempotency.ExpiresAt, &first); err != nil {
if isUniqueViolation(err) {
return acceptgenericdelivery.ErrConflict
}
return fmt.Errorf("create generic acceptance: insert delivery: %w", err)
}
if err := insertAttempt(ctx, tx, input.FirstAttempt); err != nil {
return fmt.Errorf("create generic acceptance: insert first attempt: %w", err)
}
if input.DeliveryPayload != nil {
payload, err := marshalDeliveryPayload(*input.DeliveryPayload)
if err != nil {
return fmt.Errorf("create generic acceptance: %w", err)
}
payloadStmt := pgtable.DeliveryPayloads.INSERT(
pgtable.DeliveryPayloads.DeliveryID,
pgtable.DeliveryPayloads.Payload,
).VALUES(
input.Delivery.DeliveryID.String(),
payload,
)
payloadQuery, payloadArgs := payloadStmt.Sql()
if _, err := tx.ExecContext(ctx, payloadQuery, payloadArgs...); err != nil {
return fmt.Errorf("create generic acceptance: insert delivery payload: %w", err)
}
}
return nil
})
}
// GetIdempotency forwards to the umbrella store.
func (handle *GenericAcceptanceStore) GetIdempotency(ctx context.Context, source deliverydomain.Source, key common.IdempotencyKey) (idempotency.Record, bool, error) {
return handle.store.GetIdempotency(ctx, source, key)
}
// GetDelivery forwards to the umbrella store.
func (handle *GenericAcceptanceStore) GetDelivery(ctx context.Context, deliveryID common.DeliveryID) (deliverydomain.Delivery, bool, error) {
return handle.store.GetDelivery(ctx, deliveryID)
}