Skip to content

MapPersistenceErrors

MapPersistenceErrors<TArgs, TEntity, TConstraint, TThis>(options): <TResult>(_target, _key, descriptor) => void

Defined in: packages/ddd-core/persistence/decorators/map-persistence-errors.decorator.ts:70

Method decorator that intercepts persistence failures from the wrapped method and translates identifiable database unique constraint violations into domain exceptions.

  • Unique violations: the persistence dialect (IPersistenceDialect) names the violated constraint by the entity property it covers; unique[key] builds the domain error. The dialect comes from options.dialect, else from setPersistenceDialect. A method that declares unique with no dialect available throws a TypeError before it runs, so a violation never escapes as a raw driver error.
  • Residual translation: Any error not matching a configured constraint is passed to the optional otherwise translator, which is the declarative place to convert driver/network failures into the neutral TransientOperationError retry signal.
  • Passthrough: Without otherwise — or when otherwise returns the error unchanged — the error is rethrown with its original identity, class, and stack trace completely preserved.

Use otherwise for application-level translation of unmatched driver or network failures. Keep persistence translation in this decorator so the lifecycle order relative to @AcknowledgePersisted and @Cache remains explicit in the decorator stack.

Always stack decorators in this outermost-to-innermost order:

  1. @Cache(...) — Best-effort cache synchronization after acknowledgment.
  2. @AcknowledgePersisted(...) — Acknowledges version baseline on successful write.
  3. @MapPersistenceErrors(...) — Translates low-level DB driver errors to domain exceptions.

TArgs extends unknown[]

TEntity

TConstraint extends string = never

TThis = unknown

The entity extractor, the unique errors, an optional dialect overriding the registered one (for a repository on another store), and an optional otherwise translator.

IPersistenceDialect

(args) => TEntity

(this, error, entity) => unknown

Optional translator applied to any error that did not match a unique constraint mapping. Return the error unchanged to preserve its identity, or return a replacement to express it in application terms.

The canonical use is transient-failure classification with mapPersistenceError, so that retry policies consume TransientOperationError rather than driver codes:

otherwise: (error, user) => mapPersistenceError(error, `deleting User ${user.id}`),

Deliberate domain errors thrown inside the method (ConcurrencyConflictError, EntityNotFoundException) also pass through this hook. mapPersistenceError returns non-transient errors unchanged, so no explicit re-throw guard is needed.

Written as a method, it runs with this bound to the repository instance (typed by TThis), for a message that names instance state.

UniqueErrors<TEntity, TConstraint>

<TResult>(_target, _key, descriptor) => void

Mapping unique constraints in a create repository

@Injectable()
export class CreateUserCommandRepository extends CommandRepository<User, UserSnapshot> {
@Cache<User, UserSnapshot>((u) => `users:${u.id}`, null, (u) => [`users:email:${u.email}`])
@AcknowledgePersisted<[User]>({ entity: ([user]) => user })
@MapPersistenceErrors<[User], User>({
entity: ([user]) => user,
unique: { email: (user) => new UniqueEmailException(user) },
})
async save(user: User): Promise<UserSnapshot> {
const created = this.store.em.create(User, user);
this.store.em.persist(created);
await this.store.em.flush();
return created.toJSON();
}
}