Pular para o conteúdo principal

Mapper

O IMapper e a interface que define a conversao bidirecional entre domain models e representacoes de persistencia. Cada mapper possui responsabilidade unica: converter um unico tipo de agregado.

Interface

import type { Aggregate } from "tyforge";
import type { IEntityProps } from "tyforge";
import type { Result, Exceptions, Paginated } from "tyforge";

interface IMapper<
TAggregate extends Aggregate<IEntityProps>,
TPersistence,
> {
toDomain(raw: TPersistence): Result<TAggregate, Exceptions>;
toDomainMany(raw: TPersistence[]): Result<TAggregate[], Exceptions>;
toPersistence(domain: TAggregate): Result<TPersistence, Exceptions>;
toPersistenceMany(domains: TAggregate[]): Result<TPersistence[], Exceptions>;
toDomainPaginated(raw: Paginated<TPersistence>): Result<Paginated<TAggregate>, Exceptions>;
}

Metodos

MetodoEntradaSaidaDescricao
toDomainTPersistenceResult<TAggregate>Converte um registro de persistencia para domain model
toDomainManyTPersistence[]Result<TAggregate[]>Converte multiplos registros para domain models
toPersistenceTAggregateResult<TPersistence>Converte um domain model para formato de persistencia
toPersistenceManyTAggregate[]Result<TPersistence[]>Converte multiplos domain models para persistencia
toDomainPaginatedPaginated<TPersistence>Result<Paginated<TAggregate>>Converte uma pagina inteira de registros para domain models

Todos os metodos retornam Result, garantindo que erros de conversao (dados corrompidos no banco, campos faltando) sao tratados explicitamente sem lancar excecoes.

Convencao de nomenclatura

Mappers seguem o prefixo Mapper seguido do nome do agregado:

MapperAgregado
MapperUserUser
MapperOrderOrder
MapperProductProduct

Exemplo completo

import {
isFailure, isSuccess, ok, all,
Paginated, Result, Exceptions,
} from "tyforge";
import type { IMapper } from "tyforge";
import { User } from "./user.aggregate";
import type { TUserJson } from "./user.aggregate";

class MapperUser implements IMapper<User, TUserJson> {
toDomain(raw: TUserJson): Result<User, Exceptions> {
return User.assign(raw);
}

toDomainMany(raw: TUserJson[]): Result<User[], Exceptions> {
return all(raw.map(r => this.toDomain(r)));
}

toPersistence(domain: User): Result<TUserJson, Exceptions> {
return ok(domain.toJSON());
}

toPersistenceMany(domains: User[]): Result<TUserJson[], Exceptions> {
return all(domains.map(d => this.toPersistence(d)));
}

toDomainPaginated(raw: Paginated<TUserJson>): Result<Paginated<User>, Exceptions> {
const result = this.toDomainMany(raw.items);
if (isFailure(result)) return result;
return ok(new Paginated(result.value, raw.total, raw.page, raw.pageSize));
}
}

toDomain vs toDomainMany

O toDomainMany usa o combinador all() do Result pattern. Se qualquer item falhar na conversao, o resultado inteiro e uma falha com o primeiro erro encontrado. Isso garante que uma lista de registros e completamente valida ou completamente rejeitada.

toDomainMany(raw: TUserJson[]): Result<User[], Exceptions> {
return all(raw.map(r => this.toDomain(r)));
}

toDomainPaginated

O toDomainPaginated recebe um Paginated<TPersistence> e preserva os metadados de paginacao (total, page, pageSize) enquanto converte apenas os itens:

toDomainPaginated(raw: Paginated<TUserJson>): Result<Paginated<User>, Exceptions> {
const result = this.toDomainMany(raw.items);
if (isFailure(result)) return result;
return ok(new Paginated(result.value, raw.total, raw.page, raw.pageSize));
}

DtoRes — quem monta a resposta

O mapper nao e responsavel por montar respostas de API. Essa responsabilidade e do DtoRes, montado pelo controller ou use case:

class DtoResUserProfile extends DtoRes<TProps, TJson> {
static fromDomain(domain: User): Result<DtoResUserProfile, Exceptions> {
const result = userProfileValidator.create({
id: domain.id?.getValue() ?? "",
fullName: domain.name.getValue(),
email: domain.email.getValue(),
isAdult: domain.age.getValue() >= 18,
});
if (isFailure(result)) return result;
return ok(new DtoResUserProfile(result.value));
}
}

Proximos passos

  • UseCase — orquestracao que usa o Mapper
  • Repository — interface de persistencia que retorna dados para o Mapper
  • Aggregate — domain model que o Mapper converte