add address entity management

This commit is contained in:
cuqmbr 2025-05-01 11:48:43 +03:00
parent e70c807b7c
commit d500d1f84c
Signed by: cuqmbr
GPG Key ID: 0AA446880C766199
87 changed files with 1494 additions and 617 deletions

View File

@ -0,0 +1,58 @@
using cuqmbr.TravelGuide.Application.Common.Mappings;
using cuqmbr.TravelGuide.Domain.Entities;
namespace cuqmbr.TravelGuide.Application.Addresses;
public sealed class AddressDto : IMapFrom<Address>
{
public Guid Uuid { get; set; }
public string Name { get; set; }
public double Longitude { get; set; }
public double Latitude { get; set; }
public string VehicleType { get; set; }
public Guid CountryUuid { get; set; }
public string CountryName { get; set; }
public Guid RegionUuid { get; set; }
public string RegionName { get; set; }
public Guid CityUuid { get; set; }
public string CityName { get; set; }
public void Mapping(MappingProfile profile)
{
profile.CreateMap<Address, AddressDto>()
.ForMember(
d => d.Uuid,
opt => opt.MapFrom(s => s.Guid))
.ForMember(
d => d.VehicleType,
opt => opt.MapFrom(s => s.VehicleType.Name))
.ForMember(
d => d.CountryUuid,
opt => opt.MapFrom(s => s.City.Region.Country.Guid))
.ForMember(
d => d.CountryName,
opt => opt.MapFrom(s => s.City.Region.Country.Name))
.ForMember(
d => d.RegionUuid,
opt => opt.MapFrom(s => s.City.Region.Guid))
.ForMember(
d => d.RegionName,
opt => opt.MapFrom(s => s.City.Region.Name))
.ForMember(
d => d.CityUuid,
opt => opt.MapFrom(s => s.City.Guid))
.ForMember(
d => d.CityName,
opt => opt.MapFrom(s => s.City.Name));
}
}

View File

@ -0,0 +1,17 @@
using cuqmbr.TravelGuide.Domain.Enums;
using MediatR;
namespace cuqmbr.TravelGuide.Application.Addresses.Commands.AddAddress;
public record AddAddressCommand : IRequest<AddressDto>
{
public string Name { get; set; }
public double Longitude { get; set; }
public double Latitude { get; set; }
public VehicleType VehicleType { get; set; }
public Guid CityGuid { get; set; }
}

View File

@ -0,0 +1,31 @@
using cuqmbr.TravelGuide.Application.Common.Authorization;
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
using cuqmbr.TravelGuide.Application.Common.Models;
using MediatR.Behaviors.Authorization;
namespace cuqmbr.TravelGuide.Application.Addresses.Commands.AddAddress;
public class AddAddressCommandAuthorizer :
AbstractRequestAuthorizer<AddAddressCommand>
{
private readonly SessionUserService _sessionUserService;
public AddAddressCommandAuthorizer(SessionUserService sessionUserService)
{
_sessionUserService = sessionUserService;
}
public override void BuildPolicy(AddAddressCommand request)
{
UseRequirement(new MustBeAuthenticatedRequirement
{
IsAuthenticated= _sessionUserService.IsAuthenticated
});
UseRequirement(new MustBeInRolesRequirement
{
RequiredRoles = [IdentityRole.Administrator],
UserRoles = _sessionUserService.Roles
});
}
}

View File

@ -0,0 +1,64 @@
using MediatR;
using cuqmbr.TravelGuide.Application.Common.Interfaces.Persistence;
using cuqmbr.TravelGuide.Domain.Entities;
using AutoMapper;
using cuqmbr.TravelGuide.Application.Common.Exceptions;
namespace cuqmbr.TravelGuide.Application.Addresses.Commands.AddAddress;
public class AddAddressCommandHandler :
IRequestHandler<AddAddressCommand, AddressDto>
{
private readonly UnitOfWork _unitOfWork;
private readonly IMapper _mapper;
public AddAddressCommandHandler(
UnitOfWork unitOfWork,
IMapper mapper)
{
_unitOfWork = unitOfWork;
_mapper = mapper;
}
public async Task<AddressDto> Handle(
AddAddressCommand request,
CancellationToken cancellationToken)
{
var entity = await _unitOfWork.AddressRepository.GetOneAsync(
e => e.Name == request.Name && e.City.Guid == request.CityGuid,
cancellationToken);
if (entity != null)
{
throw new DuplicateEntityException(
"Address with given name already exists.");
}
var parentEntity = await _unitOfWork.CityRepository.GetOneAsync(
e => e.Guid == request.CityGuid, e => e.Region.Country,
cancellationToken);
if (parentEntity == null)
{
throw new NotFoundException(
$"Parent entity with Guid: {request.CityGuid} not found.");
}
entity = new Address()
{
Name = request.Name,
Longitude = request.Longitude,
Latitude = request.Latitude,
VehicleType = request.VehicleType,
CityId = parentEntity.Id
};
entity = await _unitOfWork.AddressRepository.AddOneAsync(
entity, cancellationToken);
await _unitOfWork.SaveAsync(cancellationToken);
_unitOfWork.Dispose();
return _mapper.Map<AddressDto>(entity);
}
}

View File

@ -0,0 +1,65 @@
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
using cuqmbr.TravelGuide.Domain.Enums;
using FluentValidation;
using Microsoft.Extensions.Localization;
namespace cuqmbr.TravelGuide.Application.Addresses.Commands.AddAddress;
public class AddAddressCommandValidator : AbstractValidator<AddAddressCommand>
{
public AddAddressCommandValidator(
IStringLocalizer localizer,
CultureService cultureService)
{
RuleFor(v => v.Name)
.NotEmpty()
.WithMessage(localizer["FluentValidation.NotEmpty"])
.MaximumLength(64)
.WithMessage(
String.Format(
cultureService.Culture,
localizer["FluentValidation.MaximumLength"],
64));
RuleFor(v => v.Latitude)
.GreaterThanOrEqualTo(-90)
.WithMessage(
String.Format(
cultureService.Culture,
localizer["FluentValidation.GreaterThanOrEqualTo"],
-90))
.LessThanOrEqualTo(90)
.WithMessage(
String.Format(
cultureService.Culture,
localizer["FluentValidation.LessThanOrEqualTo"],
90));
RuleFor(v => v.Longitude)
.GreaterThanOrEqualTo(-180)
.WithMessage(
String.Format(
cultureService.Culture,
localizer["FluentValidation.GreaterThanOrEqualTo"],
-180))
.LessThanOrEqualTo(180)
.WithMessage(
String.Format(
cultureService.Culture,
localizer["FluentValidation.LessThanOrEqualTo"],
180));
RuleFor(v => v.VehicleType)
.Must((v, vt) => VehicleType.Enumerations.ContainsValue(vt))
.WithMessage(
String.Format(
localizer["FluentValidation.MustBeInEnum"],
String.Join(
", ",
VehicleType.Enumerations.Values.Select(e => e.Name))));
RuleFor(v => v.CityGuid)
.NotEmpty()
.WithMessage(localizer["FluentValidation.NotEmpty"]);
}
}

View File

@ -0,0 +1,8 @@
using MediatR;
namespace cuqmbr.TravelGuide.Application.Addresses.Commands.DeleteAddress;
public record DeleteAddressCommand : IRequest
{
public Guid Guid { get; set; }
}

View File

@ -0,0 +1,31 @@
using cuqmbr.TravelGuide.Application.Common.Authorization;
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
using cuqmbr.TravelGuide.Application.Common.Models;
using MediatR.Behaviors.Authorization;
namespace cuqmbr.TravelGuide.Application.Addresses.Commands.DeleteAddress;
public class DeleteAddressCommandAuthorizer :
AbstractRequestAuthorizer<DeleteAddressCommand>
{
private readonly SessionUserService _sessionUserService;
public DeleteAddressCommandAuthorizer(SessionUserService sessionUserService)
{
_sessionUserService = sessionUserService;
}
public override void BuildPolicy(DeleteAddressCommand request)
{
UseRequirement(new MustBeAuthenticatedRequirement
{
IsAuthenticated= _sessionUserService.IsAuthenticated
});
UseRequirement(new MustBeInRolesRequirement
{
RequiredRoles = [IdentityRole.Administrator],
UserRoles = _sessionUserService.Roles
});
}
}

View File

@ -0,0 +1,34 @@
using MediatR;
using cuqmbr.TravelGuide.Application.Common.Interfaces.Persistence;
using cuqmbr.TravelGuide.Application.Common.Exceptions;
namespace cuqmbr.TravelGuide.Application.Addresses.Commands.DeleteAddress;
public class DeleteAddressCommandHandler : IRequestHandler<DeleteAddressCommand>
{
private readonly UnitOfWork _unitOfWork;
public DeleteAddressCommandHandler(UnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
}
public async Task Handle(
DeleteAddressCommand request,
CancellationToken cancellationToken)
{
var entity = await _unitOfWork.AddressRepository.GetOneAsync(
e => e.Guid == request.Guid, cancellationToken);
if (entity == null)
{
throw new NotFoundException();
}
await _unitOfWork.AddressRepository.DeleteOneAsync(
entity, cancellationToken);
await _unitOfWork.SaveAsync(cancellationToken);
_unitOfWork.Dispose();
}
}

View File

@ -0,0 +1,14 @@
using FluentValidation;
using Microsoft.Extensions.Localization;
namespace cuqmbr.TravelGuide.Application.Addresses.Commands.DeleteAddress;
public class DeleteAddressCommandValidator : AbstractValidator<DeleteAddressCommand>
{
public DeleteAddressCommandValidator(IStringLocalizer localizer)
{
RuleFor(v => v.Guid)
.NotEmpty()
.WithMessage(localizer["FluentValidation.NotEmpty"]);
}
}

View File

@ -0,0 +1,19 @@
using MediatR;
using cuqmbr.TravelGuide.Domain.Enums;
namespace cuqmbr.TravelGuide.Application.Addresses.Commands.UpdateAddress;
public record UpdateAddressCommand : IRequest<AddressDto>
{
public Guid Guid { get; set; }
public string Name { get; set; }
public double Longitude { get; set; }
public double Latitude { get; set; }
public VehicleType VehicleType { get; set; }
public Guid CityGuid { get; set; }
}

View File

@ -0,0 +1,31 @@
using cuqmbr.TravelGuide.Application.Common.Authorization;
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
using cuqmbr.TravelGuide.Application.Common.Models;
using MediatR.Behaviors.Authorization;
namespace cuqmbr.TravelGuide.Application.Addresses.Commands.UpdateAddress;
public class UpdateAddressCommandAuthorizer :
AbstractRequestAuthorizer<UpdateAddressCommand>
{
private readonly SessionUserService _sessionUserService;
public UpdateAddressCommandAuthorizer(SessionUserService sessionUserService)
{
_sessionUserService = sessionUserService;
}
public override void BuildPolicy(UpdateAddressCommand request)
{
UseRequirement(new MustBeAuthenticatedRequirement
{
IsAuthenticated= _sessionUserService.IsAuthenticated
});
UseRequirement(new MustBeInRolesRequirement
{
RequiredRoles = [IdentityRole.Administrator],
UserRoles = _sessionUserService.Roles
});
}
}

View File

@ -0,0 +1,58 @@
using MediatR;
using cuqmbr.TravelGuide.Application.Common.Interfaces.Persistence;
using AutoMapper;
using cuqmbr.TravelGuide.Application.Common.Exceptions;
namespace cuqmbr.TravelGuide.Application.Addresses.Commands.UpdateAddress;
public class UpdateAddressCommandHandler :
IRequestHandler<UpdateAddressCommand, AddressDto>
{
private readonly UnitOfWork _unitOfWork;
private readonly IMapper _mapper;
public UpdateAddressCommandHandler(
UnitOfWork unitOfWork,
IMapper mapper)
{
_unitOfWork = unitOfWork;
_mapper = mapper;
}
public async Task<AddressDto> Handle(
UpdateAddressCommand request,
CancellationToken cancellationToken)
{
var entity = await _unitOfWork.AddressRepository.GetOneAsync(
e => e.Guid == request.Guid, e => e.City.Region.Country,
cancellationToken);
if (entity == null)
{
throw new NotFoundException();
}
var parentEntity = await _unitOfWork.CityRepository.GetOneAsync(
e => e.Guid == request.CityGuid, cancellationToken);
if (parentEntity == null)
{
throw new NotFoundException(
$"Parent entity with Guid: {request.CityGuid} not found.");
}
entity.Name = request.Name;
entity.Longitude = request.Longitude;
entity.Latitude = request.Latitude;
entity.VehicleType = request.VehicleType;
entity.CityId = parentEntity.Id;
entity = await _unitOfWork.AddressRepository.UpdateOneAsync(
entity, cancellationToken);
await _unitOfWork.SaveAsync(cancellationToken);
_unitOfWork.Dispose();
return _mapper.Map<AddressDto>(entity);
}
}

View File

@ -0,0 +1,31 @@
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
using FluentValidation;
using Microsoft.Extensions.Localization;
namespace cuqmbr.TravelGuide.Application.Addresses.Commands.UpdateAddress;
public class UpdateAddressCommandValidator : AbstractValidator<UpdateAddressCommand>
{
public UpdateAddressCommandValidator(
IStringLocalizer localizer,
CultureService cultureService)
{
RuleFor(v => v.Guid)
.NotEmpty()
.WithMessage(localizer["FluentValidation.NotEmpty"]);
RuleFor(v => v.Name)
.NotEmpty()
.WithMessage(localizer["FluentValidation.NotEmpty"])
.MaximumLength(64)
.WithMessage(
String.Format(
cultureService.Culture,
localizer["FluentValidation.MaximumLength"],
64));
RuleFor(v => v.CityGuid)
.NotEmpty()
.WithMessage(localizer["FluentValidation.NotEmpty"]);
}
}

View File

@ -0,0 +1,8 @@
using MediatR;
namespace cuqmbr.TravelGuide.Application.Addresses.Queries.GetAddress;
public record GetAddressQuery : IRequest<AddressDto>
{
public Guid Guid { get; set; }
}

View File

@ -0,0 +1,31 @@
using cuqmbr.TravelGuide.Application.Common.Authorization;
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
using cuqmbr.TravelGuide.Application.Common.Models;
using MediatR.Behaviors.Authorization;
namespace cuqmbr.TravelGuide.Application.Addresses.Queries.GetAddress;
public class GetAddressQueryAuthorizer :
AbstractRequestAuthorizer<GetAddressQuery>
{
private readonly SessionUserService _sessionUserService;
public GetAddressQueryAuthorizer(SessionUserService sessionUserService)
{
_sessionUserService = sessionUserService;
}
public override void BuildPolicy(GetAddressQuery request)
{
UseRequirement(new MustBeAuthenticatedRequirement
{
IsAuthenticated= _sessionUserService.IsAuthenticated
});
UseRequirement(new MustBeInRolesRequirement
{
RequiredRoles = [IdentityRole.Administrator],
UserRoles = _sessionUserService.Roles
});
}
}

View File

@ -0,0 +1,39 @@
using MediatR;
using cuqmbr.TravelGuide.Application.Common.Interfaces.Persistence;
using cuqmbr.TravelGuide.Application.Common.Exceptions;
using AutoMapper;
namespace cuqmbr.TravelGuide.Application.Addresses.Queries.GetAddress;
public class GetAddressQueryHandler :
IRequestHandler<GetAddressQuery, AddressDto>
{
private readonly UnitOfWork _unitOfWork;
private readonly IMapper _mapper;
public GetAddressQueryHandler(
UnitOfWork unitOfWork,
IMapper mapper)
{
_unitOfWork = unitOfWork;
_mapper = mapper;
}
public async Task<AddressDto> Handle(
GetAddressQuery request,
CancellationToken cancellationToken)
{
var entity = await _unitOfWork.AddressRepository.GetOneAsync(
e => e.Guid == request.Guid, e => e.City.Region.Country,
cancellationToken);
_unitOfWork.Dispose();
if (entity == null)
{
throw new NotFoundException();
}
return _mapper.Map<AddressDto>(entity);
}
}

View File

@ -0,0 +1,14 @@
using FluentValidation;
using Microsoft.Extensions.Localization;
namespace cuqmbr.TravelGuide.Application.Addresses.Queries.GetAddress;
public class GetAddressQueryValidator : AbstractValidator<GetAddressQuery>
{
public GetAddressQueryValidator(IStringLocalizer localizer)
{
RuleFor(v => v.Guid)
.NotEmpty()
.WithMessage(localizer["FluentValidation.NotEmpty"]);
}
}

View File

@ -0,0 +1,21 @@
using cuqmbr.TravelGuide.Application.Common.Models;
using MediatR;
namespace cuqmbr.TravelGuide.Application.Addresses.Queries.GetAddressesPage;
public record GetAddressesPageQuery : IRequest<PaginatedList<AddressDto>>
{
public int PageNumber { get; set; } = 1;
public int PageSize { get; set; } = 10;
public string Search { get; set; } = String.Empty;
public string Sort { get; set; } = String.Empty;
public Guid? CountryGuid { get; set; }
public Guid? RegionGuid { get; set; }
public Guid? CityGuid { get; set; }
}

View File

@ -0,0 +1,31 @@
using cuqmbr.TravelGuide.Application.Common.Authorization;
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
using cuqmbr.TravelGuide.Application.Common.Models;
using MediatR.Behaviors.Authorization;
namespace cuqmbr.TravelGuide.Application.Addresses.Queries.GetAddressesPage;
public class GetAddressesPageQueryAuthorizer :
AbstractRequestAuthorizer<GetAddressesPageQuery>
{
private readonly SessionUserService _sessionUserService;
public GetAddressesPageQueryAuthorizer(SessionUserService sessionUserService)
{
_sessionUserService = sessionUserService;
}
public override void BuildPolicy(GetAddressesPageQuery request)
{
UseRequirement(new MustBeAuthenticatedRequirement
{
IsAuthenticated= _sessionUserService.IsAuthenticated
});
UseRequirement(new MustBeInRolesRequirement
{
RequiredRoles = [IdentityRole.Administrator],
UserRoles = _sessionUserService.Roles
});
}
}

View File

@ -0,0 +1,59 @@
using MediatR;
using cuqmbr.TravelGuide.Application.Common.Interfaces.Persistence;
using AutoMapper;
using cuqmbr.TravelGuide.Application.Common.Models;
using cuqmbr.TravelGuide.Application.Common.Extensions;
namespace cuqmbr.TravelGuide.Application.Addresses.Queries.GetAddressesPage;
public class GetAddressesPageQueryHandler :
IRequestHandler<GetAddressesPageQuery, PaginatedList<AddressDto>>
{
private readonly UnitOfWork _unitOfWork;
private readonly IMapper _mapper;
public GetAddressesPageQueryHandler(
UnitOfWork unitOfWork,
IMapper mapper)
{
_unitOfWork = unitOfWork;
_mapper = mapper;
}
public async Task<PaginatedList<AddressDto>> Handle(
GetAddressesPageQuery request,
CancellationToken cancellationToken)
{
var paginatedList = await _unitOfWork.AddressRepository.GetPageAsync(
e =>
(e.Name.ToLower().Contains(request.Search.ToLower()) ||
e.City.Name.ToLower().Contains(request.Search.ToLower()) ||
e.City.Region.Name.ToLower().Contains(request.Search.ToLower()) ||
e.City.Region.Country.Name.ToLower().Contains(request.Search.ToLower())) &&
(request.CityGuid != null
? e.City.Guid == request.CityGuid
: true) &&
(request.RegionGuid != null
? e.City.Region.Guid == request.RegionGuid
: true) &&
(request.CountryGuid != null
? e.City.Region.Country.Guid == request.CountryGuid
: true),
e => e.City.Region.Country,
request.PageNumber, request.PageSize,
cancellationToken);
var mappedItems = _mapper
.ProjectTo<AddressDto>(paginatedList.Items.AsQueryable());
mappedItems = QueryableExtension<AddressDto>
.ApplySort(mappedItems, request.Sort);
_unitOfWork.Dispose();
return new PaginatedList<AddressDto>(
mappedItems.ToList(),
paginatedList.TotalCount, request.PageNumber,
request.PageSize);
}
}

View File

@ -0,0 +1,43 @@
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
using FluentValidation;
using Microsoft.Extensions.Localization;
namespace cuqmbr.TravelGuide.Application.Addresses.Queries.GetAddressesPage;
public class GetAddressesPageQueryValidator : AbstractValidator<GetAddressesPageQuery>
{
public GetAddressesPageQueryValidator(
IStringLocalizer localizer,
CultureService cultureService)
{
RuleFor(v => v.PageNumber)
.GreaterThanOrEqualTo(1)
.WithMessage(
String.Format(
cultureService.Culture,
localizer["FluentValidation.GreaterThanOrEqualTo"],
1));
RuleFor(v => v.PageSize)
.GreaterThanOrEqualTo(1)
.WithMessage(
String.Format(
cultureService.Culture,
localizer["FluentValidation.GreaterThanOrEqualTo"],
1))
.LessThanOrEqualTo(50)
.WithMessage(
String.Format(
cultureService.Culture,
localizer["FluentValidation.LessThanOrEqualTo"],
50));
RuleFor(v => v.Search)
.MaximumLength(64)
.WithMessage(
String.Format(
cultureService.Culture,
localizer["FluentValidation.MaximumLength"],
64));
}
}

View File

@ -0,0 +1,14 @@
namespace cuqmbr.TravelGuide.Application.Addresses.ViewModels;
public sealed class AddAddressViewModel
{
public string Name { get; set; }
public double Longitude { get; set; }
public double Latitude { get; set; }
public string VehicleType { get; set; }
public Guid CityUuid { get; set; }
}

View File

@ -0,0 +1,10 @@
namespace cuqmbr.TravelGuide.Application.Addresses.ViewModels;
public sealed class GetAddressesPageFilterViewModel
{
public Guid? CountryUuid { get; set; }
public Guid? RegionUuid { get; set; }
public Guid? CityUuid { get; set; }
}

View File

@ -0,0 +1,14 @@
namespace cuqmbr.TravelGuide.Application.Addresses.ViewModels;
public sealed class UpdateAddressViewModel
{
public string Name { get; set; }
public double Longitude { get; set; }
public double Latitude { get; set; }
public string VehicleType { get; set; }
public Guid CityUuid { get; set; }
}

View File

@ -6,5 +6,5 @@ public record AddCityCommand : IRequest<CityDto>
{ {
public string Name { get; set; } public string Name { get; set; }
public Guid RegionUuid { get; set; } public Guid RegionGuid { get; set; }
} }

View File

@ -25,7 +25,7 @@ public class AddCityCommandHandler :
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
var entity = await _unitOfWork.CityRepository.GetOneAsync( var entity = await _unitOfWork.CityRepository.GetOneAsync(
e => e.Name == request.Name && e.Region.Guid == request.RegionUuid, e => e.Name == request.Name && e.Region.Guid == request.RegionGuid,
cancellationToken); cancellationToken);
if (entity != null) if (entity != null)
@ -35,13 +35,13 @@ public class AddCityCommandHandler :
} }
var parentEntity = await _unitOfWork.RegionRepository.GetOneAsync( var parentEntity = await _unitOfWork.RegionRepository.GetOneAsync(
e => e.Guid == request.RegionUuid, e => e.Country, e => e.Guid == request.RegionGuid, e => e.Country,
cancellationToken); cancellationToken);
if (parentEntity == null) if (parentEntity == null)
{ {
throw new NotFoundException( throw new NotFoundException(
$"Parent entity with Guid: {request.RegionUuid} not found."); $"Parent entity with Guid: {request.RegionGuid} not found.");
} }
entity = new City() entity = new City()

View File

@ -20,7 +20,7 @@ public class AddCityCommandValidator : AbstractValidator<AddCityCommand>
localizer["FluentValidation.MaximumLength"], localizer["FluentValidation.MaximumLength"],
64)); 64));
RuleFor(v => v.RegionUuid) RuleFor(v => v.RegionGuid)
.NotEmpty() .NotEmpty()
.WithMessage(localizer["FluentValidation.NotEmpty"]); .WithMessage(localizer["FluentValidation.NotEmpty"]);
} }

View File

@ -4,5 +4,5 @@ namespace cuqmbr.TravelGuide.Application.Cities.Commands.DeleteCity;
public record DeleteCityCommand : IRequest public record DeleteCityCommand : IRequest
{ {
public Guid Uuid { get; set; } public Guid Guid { get; set; }
} }

View File

@ -18,7 +18,7 @@ public class DeleteCityCommandHandler : IRequestHandler<DeleteCityCommand>
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
var entity = await _unitOfWork.CityRepository.GetOneAsync( var entity = await _unitOfWork.CityRepository.GetOneAsync(
e => e.Guid == request.Uuid, cancellationToken); e => e.Guid == request.Guid, cancellationToken);
if (entity == null) if (entity == null)
{ {

View File

@ -7,7 +7,7 @@ public class DeleteCityCommandValidator : AbstractValidator<DeleteCityCommand>
{ {
public DeleteCityCommandValidator(IStringLocalizer localizer) public DeleteCityCommandValidator(IStringLocalizer localizer)
{ {
RuleFor(v => v.Uuid) RuleFor(v => v.Guid)
.NotEmpty() .NotEmpty()
.WithMessage(localizer["FluentValidation.NotEmpty"]); .WithMessage(localizer["FluentValidation.NotEmpty"]);
} }

View File

@ -4,9 +4,9 @@ namespace cuqmbr.TravelGuide.Application.Cities.Commands.UpdateCity;
public record UpdateCityCommand : IRequest<CityDto> public record UpdateCityCommand : IRequest<CityDto>
{ {
public Guid Uuid { get; set; } public Guid Guid { get; set; }
public string Name { get; set; } public string Name { get; set; }
public Guid RegionUuid { get; set; } public Guid RegionGuid { get; set; }
} }

View File

@ -24,7 +24,7 @@ public class UpdateCityCommandHandler :
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
var entity = await _unitOfWork.CityRepository.GetOneAsync( var entity = await _unitOfWork.CityRepository.GetOneAsync(
e => e.Guid == request.Uuid, e => e.Region.Country, e => e.Guid == request.Guid, e => e.Region.Country,
cancellationToken); cancellationToken);
if (entity == null) if (entity == null)
@ -33,12 +33,12 @@ public class UpdateCityCommandHandler :
} }
var parentEntity = await _unitOfWork.RegionRepository.GetOneAsync( var parentEntity = await _unitOfWork.RegionRepository.GetOneAsync(
e => e.Guid == request.RegionUuid, cancellationToken); e => e.Guid == request.RegionGuid, cancellationToken);
if (parentEntity == null) if (parentEntity == null)
{ {
throw new NotFoundException( throw new NotFoundException(
$"Parent entity with Guid: {request.RegionUuid} not found."); $"Parent entity with Guid: {request.RegionGuid} not found.");
} }
entity.Name = request.Name; entity.Name = request.Name;

View File

@ -10,7 +10,7 @@ public class UpdateCityCommandValidator : AbstractValidator<UpdateCityCommand>
IStringLocalizer localizer, IStringLocalizer localizer,
CultureService cultureService) CultureService cultureService)
{ {
RuleFor(v => v.Uuid) RuleFor(v => v.Guid)
.NotEmpty() .NotEmpty()
.WithMessage(localizer["FluentValidation.NotEmpty"]); .WithMessage(localizer["FluentValidation.NotEmpty"]);
@ -24,7 +24,7 @@ public class UpdateCityCommandValidator : AbstractValidator<UpdateCityCommand>
localizer["FluentValidation.MaximumLength"], localizer["FluentValidation.MaximumLength"],
64)); 64));
RuleFor(v => v.RegionUuid) RuleFor(v => v.RegionGuid)
.NotEmpty() .NotEmpty()
.WithMessage(localizer["FluentValidation.NotEmpty"]); .WithMessage(localizer["FluentValidation.NotEmpty"]);
} }

View File

@ -13,7 +13,7 @@ public record GetCitiesPageQuery : IRequest<PaginatedList<CityDto>>
public string Sort { get; set; } = String.Empty; public string Sort { get; set; } = String.Empty;
public Guid? CountryUuid { get; set; } public Guid? CountryGuid { get; set; }
public Guid? RegionUuid { get; set; } public Guid? RegionGuid { get; set; }
} }

View File

@ -29,11 +29,11 @@ public class GetCitiesPageQueryHandler :
(e.Name.ToLower().Contains(request.Search.ToLower()) || (e.Name.ToLower().Contains(request.Search.ToLower()) ||
e.Region.Name.ToLower().Contains(request.Search.ToLower()) || e.Region.Name.ToLower().Contains(request.Search.ToLower()) ||
e.Region.Country.Name.ToLower().Contains(request.Search.ToLower())) && e.Region.Country.Name.ToLower().Contains(request.Search.ToLower())) &&
(request.RegionUuid != null (request.RegionGuid != null
? e.Region.Guid == request.RegionUuid ? e.Region.Guid == request.RegionGuid
: true) && : true) &&
(request.CountryUuid != null (request.CountryGuid != null
? e.Region.Country.Guid == request.CountryUuid ? e.Region.Country.Guid == request.CountryGuid
: true), : true),
e => e.Region.Country, e => e.Region.Country,
request.PageNumber, request.PageSize, request.PageNumber, request.PageSize,

View File

@ -4,5 +4,5 @@ namespace cuqmbr.TravelGuide.Application.Cities.Queries.GetCity;
public record GetCityQuery : IRequest<CityDto> public record GetCityQuery : IRequest<CityDto>
{ {
public Guid Uuid { get; set; } public Guid Guid { get; set; }
} }

View File

@ -24,7 +24,7 @@ public class GetCityQueryHandler :
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
var entity = await _unitOfWork.CityRepository.GetOneAsync( var entity = await _unitOfWork.CityRepository.GetOneAsync(
e => e.Guid == request.Uuid, e => e.Region.Country, e => e.Guid == request.Guid, e => e.Region.Country,
cancellationToken); cancellationToken);
_unitOfWork.Dispose(); _unitOfWork.Dispose();

View File

@ -7,7 +7,7 @@ public class GetCityQueryValidator : AbstractValidator<GetCityQuery>
{ {
public GetCityQueryValidator(IStringLocalizer localizer) public GetCityQueryValidator(IStringLocalizer localizer)
{ {
RuleFor(v => v.Uuid) RuleFor(v => v.Guid)
.NotEmpty() .NotEmpty()
.WithMessage(localizer["FluentValidation.NotEmpty"]); .WithMessage(localizer["FluentValidation.NotEmpty"]);
} }

View File

@ -0,0 +1,8 @@
namespace cuqmbr.TravelGuide.Application.Cities.ViewModels;
public sealed class AddCityViewModel
{
public string Name { get; set; }
public Guid RegionGuid { get; set; }
}

View File

@ -0,0 +1,8 @@
namespace cuqmbr.TravelGuide.Application.Cities.ViewModels;
public sealed class UpdateCityViewModel
{
public string Name { get; set; }
public Guid RegionUuid { get; set; }
}

View File

@ -0,0 +1,6 @@
using cuqmbr.TravelGuide.Domain.Entities;
namespace cuqmbr.TravelGuide.Application.Common.Interfaces
.Persistence.Repositories;
public interface AddressRepository : BaseRepository<Address> { }

View File

@ -10,6 +10,8 @@ public interface UnitOfWork : IDisposable
CityRepository CityRepository { get; } CityRepository CityRepository { get; }
AddressRepository AddressRepository { get; }
int Save(); int Save();
Task<int> SaveAsync(CancellationToken cancellationToken); Task<int> SaveAsync(CancellationToken cancellationToken);

View File

@ -0,0 +1,6 @@
namespace cuqmbr.TravelGuide.Application.Countries.ViewModels;
public sealed class AddCountryViewModel
{
public string Name { get; set; }
}

View File

@ -0,0 +1,6 @@
namespace cuqmbr.TravelGuide.Application.Countries.ViewModels;
public sealed class UpdateCountryViewModel
{
public string Name { get; set; }
}

View File

@ -6,5 +6,5 @@ public record AddRegionCommand : IRequest<RegionDto>
{ {
public string Name { get; set; } public string Name { get; set; }
public Guid CountryUuid { get; set; } public Guid CountryGuid { get; set; }
} }

View File

@ -25,7 +25,7 @@ public class AddRegionCommandHandler :
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
var entity = await _unitOfWork.RegionRepository.GetOneAsync( var entity = await _unitOfWork.RegionRepository.GetOneAsync(
e => e.Name == request.Name && e.Country.Guid == request.CountryUuid, e => e.Name == request.Name && e.Country.Guid == request.CountryGuid,
cancellationToken); cancellationToken);
if (entity != null) if (entity != null)
@ -35,12 +35,12 @@ public class AddRegionCommandHandler :
} }
var parentEntity = await _unitOfWork.CountryRepository.GetOneAsync( var parentEntity = await _unitOfWork.CountryRepository.GetOneAsync(
e => e.Guid == request.CountryUuid, cancellationToken); e => e.Guid == request.CountryGuid, cancellationToken);
if (parentEntity == null) if (parentEntity == null)
{ {
throw new NotFoundException( throw new NotFoundException(
$"Parent entity with Guid: {request.CountryUuid} not found."); $"Parent entity with Guid: {request.CountryGuid} not found.");
} }
entity = new Region() entity = new Region()

View File

@ -20,7 +20,7 @@ public class AddRegionCommandValidator : AbstractValidator<AddRegionCommand>
localizer["FluentValidation.MaximumLength"], localizer["FluentValidation.MaximumLength"],
64)); 64));
RuleFor(v => v.CountryUuid) RuleFor(v => v.CountryGuid)
.NotEmpty() .NotEmpty()
.WithMessage(localizer["FluentValidation.NotEmpty"]); .WithMessage(localizer["FluentValidation.NotEmpty"]);
} }

View File

@ -4,5 +4,5 @@ namespace cuqmbr.TravelGuide.Application.Regions.Commands.DeleteRegion;
public record DeleteRegionCommand : IRequest public record DeleteRegionCommand : IRequest
{ {
public Guid Uuid { get; set; } public Guid Guid { get; set; }
} }

View File

@ -18,7 +18,7 @@ public class DeleteRegionCommandHandler : IRequestHandler<DeleteRegionCommand>
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
var entity = await _unitOfWork.RegionRepository.GetOneAsync( var entity = await _unitOfWork.RegionRepository.GetOneAsync(
e => e.Guid == request.Uuid, cancellationToken); e => e.Guid == request.Guid, cancellationToken);
if (entity == null) if (entity == null)
{ {

View File

@ -7,7 +7,7 @@ public class DeleteRegionCommandValidator : AbstractValidator<DeleteRegionComman
{ {
public DeleteRegionCommandValidator(IStringLocalizer localizer) public DeleteRegionCommandValidator(IStringLocalizer localizer)
{ {
RuleFor(v => v.Uuid) RuleFor(v => v.Guid)
.NotEmpty() .NotEmpty()
.WithMessage(localizer["FluentValidation.NotEmpty"]); .WithMessage(localizer["FluentValidation.NotEmpty"]);
} }

View File

@ -4,9 +4,9 @@ namespace cuqmbr.TravelGuide.Application.Regions.Commands.UpdateRegion;
public record UpdateRegionCommand : IRequest<RegionDto> public record UpdateRegionCommand : IRequest<RegionDto>
{ {
public Guid Uuid { get; set; } public Guid Guid { get; set; }
public string Name { get; set; } public string Name { get; set; }
public Guid CountryUuid { get; set; } public Guid CountryGuid { get; set; }
} }

View File

@ -24,7 +24,7 @@ public class UpdateRegionCommandHandler :
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
var entity = await _unitOfWork.RegionRepository.GetOneAsync( var entity = await _unitOfWork.RegionRepository.GetOneAsync(
e => e.Guid == request.Uuid, cancellationToken); e => e.Guid == request.Guid, cancellationToken);
if (entity == null) if (entity == null)
{ {
@ -32,12 +32,12 @@ public class UpdateRegionCommandHandler :
} }
var parentEntity = await _unitOfWork.CountryRepository.GetOneAsync( var parentEntity = await _unitOfWork.CountryRepository.GetOneAsync(
e => e.Guid == request.CountryUuid, cancellationToken); e => e.Guid == request.CountryGuid, cancellationToken);
if (parentEntity == null) if (parentEntity == null)
{ {
throw new NotFoundException( throw new NotFoundException(
$"Parent entity with Guid: {request.CountryUuid} not found."); $"Parent entity with Guid: {request.CountryGuid} not found.");
} }
entity.Name = request.Name; entity.Name = request.Name;

View File

@ -10,7 +10,7 @@ public class UpdateRegionCommandValidator : AbstractValidator<UpdateRegionComman
IStringLocalizer localizer, IStringLocalizer localizer,
CultureService cultureService) CultureService cultureService)
{ {
RuleFor(v => v.Uuid) RuleFor(v => v.Guid)
.NotEmpty() .NotEmpty()
.WithMessage(localizer["FluentValidation.NotEmpty"]); .WithMessage(localizer["FluentValidation.NotEmpty"]);
@ -24,7 +24,7 @@ public class UpdateRegionCommandValidator : AbstractValidator<UpdateRegionComman
localizer["FluentValidation.MaximumLength"], localizer["FluentValidation.MaximumLength"],
64)); 64));
RuleFor(v => v.CountryUuid) RuleFor(v => v.CountryGuid)
.NotEmpty() .NotEmpty()
.WithMessage(localizer["FluentValidation.NotEmpty"]); .WithMessage(localizer["FluentValidation.NotEmpty"]);
} }

View File

@ -4,5 +4,5 @@ namespace cuqmbr.TravelGuide.Application.Regions.Queries.GetRegion;
public record GetRegionQuery : IRequest<RegionDto> public record GetRegionQuery : IRequest<RegionDto>
{ {
public Guid Uuid { get; set; } public Guid Guid { get; set; }
} }

View File

@ -24,7 +24,7 @@ public class GetRegionQueryHandler :
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
var entity = await _unitOfWork.RegionRepository.GetOneAsync( var entity = await _unitOfWork.RegionRepository.GetOneAsync(
e => e.Guid == request.Uuid, e => e.Country, e => e.Guid == request.Guid, e => e.Country,
cancellationToken); cancellationToken);
_unitOfWork.Dispose(); _unitOfWork.Dispose();

View File

@ -7,7 +7,7 @@ public class GetRegionQueryValidator : AbstractValidator<GetRegionQuery>
{ {
public GetRegionQueryValidator(IStringLocalizer localizer) public GetRegionQueryValidator(IStringLocalizer localizer)
{ {
RuleFor(v => v.Uuid) RuleFor(v => v.Guid)
.NotEmpty() .NotEmpty()
.WithMessage(localizer["FluentValidation.NotEmpty"]); .WithMessage(localizer["FluentValidation.NotEmpty"]);
} }

View File

@ -13,5 +13,5 @@ public record GetRegionsPageQuery : IRequest<PaginatedList<RegionDto>>
public string Sort { get; set; } = String.Empty; public string Sort { get; set; } = String.Empty;
public Guid? CountryUuid { get; set; } public Guid? CountryGuid { get; set; }
} }

View File

@ -28,8 +28,8 @@ public class GetRegionsPageQueryHandler :
e => e =>
(e.Name.ToLower().Contains(request.Search.ToLower()) || (e.Name.ToLower().Contains(request.Search.ToLower()) ||
e.Country.Name.ToLower().Contains(request.Search.ToLower())) && e.Country.Name.ToLower().Contains(request.Search.ToLower())) &&
(request.CountryUuid != null (request.CountryGuid != null
? e.Country.Guid == request.CountryUuid ? e.Country.Guid == request.CountryGuid
: true), : true),
e => e.Country, e => e.Country,
request.PageNumber, request.PageSize, request.PageNumber, request.PageSize,

View File

@ -0,0 +1,8 @@
namespace cuqmbr.TravelGuide.Application.Regions.ViewModels;
public sealed class AddRegionViewModel
{
public string Name { get; set; }
public Guid CountryUuid { get; set; }
}

View File

@ -0,0 +1,8 @@
namespace cuqmbr.TravelGuide.Application.Regions.ViewModels;
public sealed class UpdateRegionViewModel
{
public string Name { get; set; }
public Guid CountryUuid { get; set; }
}

View File

@ -3,7 +3,8 @@
"MaximumLength": "Must less than {0:G} characters.", "MaximumLength": "Must less than {0:G} characters.",
"NotEmpty": "Must not be empty.", "NotEmpty": "Must not be empty.",
"GreaterThanOrEqualTo": "Must be greater than or equal to {0:G}.", "GreaterThanOrEqualTo": "Must be greater than or equal to {0:G}.",
"LessThanOrEqualTo": "Must be less than or equal to {0:G}." "LessThanOrEqualTo": "Must be less than or equal to {0:G}.",
"MustBeInEnum": "Must be one of the following: {0}."
}, },
"ExceptionHandling": { "ExceptionHandling": {
"ValidationException": { "ValidationException": {

View File

@ -45,7 +45,7 @@ public static class Configuration
.AddEntityFrameworkStores<PostgreSqlIdentityDbContext>() .AddEntityFrameworkStores<PostgreSqlIdentityDbContext>()
.AddDefaultTokenProviders(); .AddDefaultTokenProviders();
if (configuration.Datastore.Initialize) if (configuration.Datastore.Migrate)
{ {
using var dbContextServiceProvider = services.BuildServiceProvider(); using var dbContextServiceProvider = services.BuildServiceProvider();
PostgreSqlInitializer.Initialize(dbContextServiceProvider); PostgreSqlInitializer.Initialize(dbContextServiceProvider);

View File

@ -7,11 +7,11 @@ public sealed class Address : EntityBase
public string Name { get; set; } public string Name { get; set; }
// TODO: Implement coordinates using NetTopologySuite // TODO: Implement coordinates using NetTopologySuite
// public double Longitude { get; set; } public double Longitude { get; set; }
//
// public double Latitude { get; set; }
// public VehicleType VehicleType { get; set; } public double Latitude { get; set; }
public VehicleType VehicleType { get; set; }
public long CityId { get; set; } public long CityId { get; set; }
@ -19,6 +19,5 @@ public sealed class Address : EntityBase
public City City { get; set; } public City City { get; set; }
public ICollection<RouteAddress> AddressRoutes { get; set; } // public ICollection<RouteAddress> AddressRoutes { get; set; }
} }

View File

@ -5,24 +5,24 @@ namespace cuqmbr.TravelGuide.Domain.Enums;
public abstract class VehicleType : Enumeration<VehicleType> public abstract class VehicleType : Enumeration<VehicleType>
{ {
public static readonly VehicleType Bus = new BusVehicleType(); public static readonly VehicleType Bus = new BusVehicleType();
public static readonly VehicleType Train = new TrainVehicleType(); public static readonly VehicleType Train = new TrainVehicleType();
public static readonly VehicleType Aircraft = new AircraftVehicleType(); public static readonly VehicleType Aircraft = new AircraftVehicleType();
protected VehicleType(int value, string name) : base(value, name) { } protected VehicleType(int value, string name) : base(value, name) { }
private sealed class BusVehicleType : VehicleType private sealed class BusVehicleType : VehicleType
{ {
public BusVehicleType() : base(0, "bus") { } public BusVehicleType() : base(0, "bus") { }
} }
private sealed class TrainVehicleType : VehicleType private sealed class TrainVehicleType : VehicleType
{ {
public TrainVehicleType() : base(1, "train") { } public TrainVehicleType() : base(1, "train") { }
} }
private sealed class AircraftVehicleType : VehicleType private sealed class AircraftVehicleType : VehicleType
{ {
public AircraftVehicleType() : base(2, "aircraft") { } public AircraftVehicleType() : base(2, "aircraft") { }
} }
} }

View File

@ -0,0 +1,196 @@
using Microsoft.AspNetCore.Mvc;
using Swashbuckle.AspNetCore.Annotations;
using cuqmbr.TravelGuide.Application.Common.Models;
using cuqmbr.TravelGuide.Application.Common.ViewModels;
using cuqmbr.TravelGuide.Domain.Enums;
using cuqmbr.TravelGuide.Application.Addresses;
using cuqmbr.TravelGuide.Application.Addresses.Commands.AddAddress;
using cuqmbr.TravelGuide.Application.Addresses.Queries.GetAddressesPage;
using cuqmbr.TravelGuide.Application.Addresses.Queries.GetAddress;
using cuqmbr.TravelGuide.Application.Addresses.Commands.UpdateAddress;
using cuqmbr.TravelGuide.Application.Addresses.Commands.DeleteAddress;
using cuqmbr.TravelGuide.Application.Addresses.ViewModels;
namespace cuqmbr.TravelGuide.HttpApi.Controllers;
[Route("addresses")]
public class AddressesController : ControllerBase
{
[HttpPost]
[SwaggerOperation("Add an address")]
[SwaggerResponse(
StatusCodes.Status201Created, "Object successfuly created",
typeof(AddressDto))]
[SwaggerResponse(
StatusCodes.Status400BadRequest, "Object already exists",
typeof(ProblemDetails))]
[SwaggerResponse(
StatusCodes.Status400BadRequest, "Input data validation error",
typeof(HttpValidationProblemDetails))]
[SwaggerResponse(
StatusCodes.Status401Unauthorized, "Unauthorized to perform an action",
typeof(ProblemDetails))]
[SwaggerResponse(
StatusCodes.Status403Forbidden,
"Not enough privileges to perform an action",
typeof(ProblemDetails))]
[SwaggerResponse(
StatusCodes.Status404NotFound, "Parent object not found",
typeof(ProblemDetails))]
[SwaggerResponse(
StatusCodes.Status500InternalServerError, "Internal server error",
typeof(ProblemDetails))]
public async Task<ActionResult<AddressDto>> Add(
[FromBody] AddAddressViewModel viewModel,
CancellationToken cancellationToken)
{
return StatusCode(
StatusCodes.Status201Created,
await Mediator.Send(
new AddAddressCommand()
{
Name = viewModel.Name,
Longitude = viewModel.Longitude,
Latitude = viewModel.Latitude,
VehicleType = VehicleType.FromName(viewModel.VehicleType),
CityGuid = viewModel.CityUuid
},
cancellationToken));
}
[HttpGet]
[SwaggerOperation("Get a list of all addresses")]
[SwaggerResponse(
StatusCodes.Status200OK, "Request successful",
typeof(PaginatedList<AddressDto>))]
[SwaggerResponse(
StatusCodes.Status400BadRequest, "Input data validation error",
typeof(HttpValidationProblemDetails))]
[SwaggerResponse(
StatusCodes.Status401Unauthorized, "Unauthorized to perform an action",
typeof(ProblemDetails))]
[SwaggerResponse(
StatusCodes.Status403Forbidden,
"Not enough privileges to perform an action",
typeof(ProblemDetails))]
[SwaggerResponse(
StatusCodes.Status500InternalServerError, "Internal server error",
typeof(ProblemDetails))]
public async Task<PaginatedList<AddressDto>> GetPage(
[FromQuery] PageQuery pageQuery, [FromQuery] SearchQuery searchQuery,
[FromQuery] SortQuery sortQuery,
[FromQuery] GetAddressesPageFilterViewModel filterQuery,
CancellationToken cancellationToken)
{
return await Mediator.Send(
new GetAddressesPageQuery()
{
PageNumber = pageQuery.PageNumber,
PageSize = pageQuery.PageSize,
Search = searchQuery.Search,
Sort = sortQuery.Sort,
CountryGuid = filterQuery.CountryUuid,
RegionGuid = filterQuery.RegionUuid,
CityGuid = filterQuery.CityUuid
},
cancellationToken);
}
[HttpGet("{uuid:guid}")]
[SwaggerOperation("Get an address by uuid")]
[SwaggerResponse(
StatusCodes.Status200OK, "Request successful", typeof(AddressDto))]
[SwaggerResponse(
StatusCodes.Status400BadRequest, "Input data validation error",
typeof(HttpValidationProblemDetails))]
[SwaggerResponse(
StatusCodes.Status401Unauthorized, "Unauthorized to perform an action",
typeof(ProblemDetails))]
[SwaggerResponse(
StatusCodes.Status403Forbidden,
"Not enough privileges to perform an action",
typeof(ProblemDetails))]
[SwaggerResponse(
StatusCodes.Status404NotFound, "Object not found", typeof(AddressDto))]
[SwaggerResponse(
StatusCodes.Status500InternalServerError, "Internal server error",
typeof(ProblemDetails))]
public async Task<AddressDto> Get(
[FromRoute] Guid uuid,
CancellationToken cancellationToken)
{
return await Mediator.Send(new GetAddressQuery() { Guid = uuid },
cancellationToken);
}
[HttpPut("{uuid:guid}")]
[SwaggerOperation("Update an address")]
[SwaggerResponse(
StatusCodes.Status200OK, "Request successful", typeof(AddressDto))]
[SwaggerResponse(
StatusCodes.Status400BadRequest, "Object already exists",
typeof(ProblemDetails))]
[SwaggerResponse(
StatusCodes.Status400BadRequest, "Input data validation error",
typeof(HttpValidationProblemDetails))]
[SwaggerResponse(
StatusCodes.Status401Unauthorized, "Unauthorized to perform an action",
typeof(ProblemDetails))]
[SwaggerResponse(
StatusCodes.Status403Forbidden,
"Not enough privileges to perform an action",
typeof(ProblemDetails))]
[SwaggerResponse(
StatusCodes.Status404NotFound, "Object not found", typeof(AddressDto))]
[SwaggerResponse(
StatusCodes.Status404NotFound, "Parent object not found",
typeof(ProblemDetails))]
[SwaggerResponse(
StatusCodes.Status500InternalServerError, "Internal server error",
typeof(ProblemDetails))]
public async Task<AddressDto> Update(
[FromRoute] Guid uuid,
[FromBody] UpdateAddressViewModel viewModel,
CancellationToken cancellationToken)
{
return await Mediator.Send(
new UpdateAddressCommand()
{
Guid = uuid,
Name = viewModel.Name,
Longitude = viewModel.Longitude,
Latitude = viewModel.Latitude,
VehicleType = VehicleType.FromName(viewModel.VehicleType),
CityGuid = viewModel.CityUuid
},
cancellationToken);
}
[HttpDelete("{uuid:guid}")]
[SwaggerOperation("Delete an address")]
[SwaggerResponse(StatusCodes.Status204NoContent, "Request successful")]
[SwaggerResponse(
StatusCodes.Status400BadRequest, "Input data validation error",
typeof(HttpValidationProblemDetails))]
[SwaggerResponse(
StatusCodes.Status401Unauthorized, "Unauthorized to perform an action",
typeof(ProblemDetails))]
[SwaggerResponse(
StatusCodes.Status403Forbidden,
"Not enough privileges to perform an action",
typeof(ProblemDetails))]
[SwaggerResponse(
StatusCodes.Status404NotFound, "Object not found", typeof(AddressDto))]
[SwaggerResponse(
StatusCodes.Status500InternalServerError, "Internal server error",
typeof(ProblemDetails))]
public async Task<IActionResult> Delete(
[FromRoute] Guid uuid,
CancellationToken cancellationToken)
{
await Mediator.Send(
new DeleteAddressCommand() { Guid = uuid },
cancellationToken);
return StatusCode(StatusCodes.Status204NoContent);
}
}

View File

@ -16,7 +16,7 @@ namespace cuqmbr.TravelGuide.HttpApi.Controllers;
public class CitiesController : ControllerBase public class CitiesController : ControllerBase
{ {
[HttpPost] [HttpPost]
[SwaggerOperation("Create a city")] [SwaggerOperation("Add a city")]
[SwaggerResponse( [SwaggerResponse(
StatusCodes.Status201Created, "Object successfuly created", StatusCodes.Status201Created, "Object successfuly created",
typeof(CityDto))] typeof(CityDto))]
@ -40,12 +40,18 @@ public class CitiesController : ControllerBase
StatusCodes.Status500InternalServerError, "Internal server error", StatusCodes.Status500InternalServerError, "Internal server error",
typeof(ProblemDetails))] typeof(ProblemDetails))]
public async Task<ActionResult<CityDto>> Add( public async Task<ActionResult<CityDto>> Add(
[FromBody] AddCityCommand command, [FromBody] AddCityViewModel viewModel,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
return StatusCode( return StatusCode(
StatusCodes.Status201Created, StatusCodes.Status201Created,
await Mediator.Send(command, cancellationToken)); await Mediator.Send(
new AddCityCommand()
{
Name = viewModel.Name,
RegionGuid = viewModel.RegionGuid
},
cancellationToken));
} }
[HttpGet] [HttpGet]
@ -79,14 +85,14 @@ public class CitiesController : ControllerBase
PageSize = pageQuery.PageSize, PageSize = pageQuery.PageSize,
Search = searchQuery.Search, Search = searchQuery.Search,
Sort = sortQuery.Sort, Sort = sortQuery.Sort,
CountryUuid = filterQuery.CountryUuid, CountryGuid = filterQuery.CountryUuid,
RegionUuid = filterQuery.RegionUuid RegionGuid = filterQuery.RegionUuid
}, },
cancellationToken); cancellationToken);
} }
[HttpGet("{uuid:guid}")] [HttpGet("{uuid:guid}")]
[SwaggerOperation("Get city by uuid")] [SwaggerOperation("Get a city by uuid")]
[SwaggerResponse( [SwaggerResponse(
StatusCodes.Status200OK, "Request successful", typeof(CityDto))] StatusCodes.Status200OK, "Request successful", typeof(CityDto))]
[SwaggerResponse( [SwaggerResponse(
@ -108,12 +114,12 @@ public class CitiesController : ControllerBase
[FromRoute] Guid uuid, [FromRoute] Guid uuid,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
return await Mediator.Send(new GetCityQuery() { Uuid = uuid }, return await Mediator.Send(new GetCityQuery() { Guid = uuid },
cancellationToken); cancellationToken);
} }
[HttpPut("{uuid:guid}")] [HttpPut("{uuid:guid}")]
[SwaggerOperation("Update city")] [SwaggerOperation("Update a city")]
[SwaggerResponse( [SwaggerResponse(
StatusCodes.Status200OK, "Request successful", typeof(CityDto))] StatusCodes.Status200OK, "Request successful", typeof(CityDto))]
[SwaggerResponse( [SwaggerResponse(
@ -139,15 +145,21 @@ public class CitiesController : ControllerBase
typeof(ProblemDetails))] typeof(ProblemDetails))]
public async Task<CityDto> Update( public async Task<CityDto> Update(
[FromRoute] Guid uuid, [FromRoute] Guid uuid,
[FromBody] UpdateCityCommand command, [FromBody] UpdateCityViewModel viewModel,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
command.Uuid = uuid; return await Mediator.Send(
return await Mediator.Send(command, cancellationToken); new UpdateCityCommand()
{
Guid = uuid,
Name= viewModel.Name,
RegionGuid = viewModel.RegionUuid
},
cancellationToken);
} }
[HttpDelete("{uuid:guid}")] [HttpDelete("{uuid:guid}")]
[SwaggerOperation("Delete city")] [SwaggerOperation("Delete a city")]
[SwaggerResponse(StatusCodes.Status204NoContent, "Request successful")] [SwaggerResponse(StatusCodes.Status204NoContent, "Request successful")]
[SwaggerResponse( [SwaggerResponse(
StatusCodes.Status400BadRequest, "Input data validation error", StatusCodes.Status400BadRequest, "Input data validation error",
@ -169,7 +181,7 @@ public class CitiesController : ControllerBase
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
await Mediator.Send( await Mediator.Send(
new DeleteCityCommand() { Uuid = uuid }, new DeleteCityCommand() { Guid = uuid },
cancellationToken); cancellationToken);
return StatusCode(StatusCodes.Status204NoContent); return StatusCode(StatusCodes.Status204NoContent);
} }

View File

@ -2,6 +2,7 @@ using Microsoft.AspNetCore.Mvc;
using Swashbuckle.AspNetCore.Annotations; using Swashbuckle.AspNetCore.Annotations;
using cuqmbr.TravelGuide.Application.Common.Models; using cuqmbr.TravelGuide.Application.Common.Models;
using cuqmbr.TravelGuide.Application.Common.ViewModels; using cuqmbr.TravelGuide.Application.Common.ViewModels;
using cuqmbr.TravelGuide.Application.Countries.ViewModels;
using cuqmbr.TravelGuide.Application.Countries; using cuqmbr.TravelGuide.Application.Countries;
using cuqmbr.TravelGuide.Application.Countries.Commands.AddCountry; using cuqmbr.TravelGuide.Application.Countries.Commands.AddCountry;
using cuqmbr.TravelGuide.Application.Countries.Queries.GetCountriesPage; using cuqmbr.TravelGuide.Application.Countries.Queries.GetCountriesPage;
@ -15,7 +16,7 @@ namespace cuqmbr.TravelGuide.HttpApi.Controllers;
public class CountriesController : ControllerBase public class CountriesController : ControllerBase
{ {
[HttpPost] [HttpPost]
[SwaggerOperation("Create a country")] [SwaggerOperation("Add a country")]
[SwaggerResponse( [SwaggerResponse(
StatusCodes.Status201Created, "Object successfuly created", StatusCodes.Status201Created, "Object successfuly created",
typeof(CountryDto))] typeof(CountryDto))]
@ -36,12 +37,17 @@ public class CountriesController : ControllerBase
StatusCodes.Status500InternalServerError, "Internal server error", StatusCodes.Status500InternalServerError, "Internal server error",
typeof(ProblemDetails))] typeof(ProblemDetails))]
public async Task<ActionResult<CountryDto>> Add( public async Task<ActionResult<CountryDto>> Add(
[FromBody] AddCountryCommand command, [FromBody] AddCountryViewModel viewModel,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
return StatusCode( return StatusCode(
StatusCodes.Status201Created, StatusCodes.Status201Created,
await Mediator.Send(command, cancellationToken)); await Mediator.Send(
new AddCountryCommand()
{
Name = viewModel.Name
},
cancellationToken));
} }
[HttpGet] [HttpGet]
@ -78,7 +84,7 @@ public class CountriesController : ControllerBase
} }
[HttpGet("{uuid:guid}")] [HttpGet("{uuid:guid}")]
[SwaggerOperation("Get country by uuid")] [SwaggerOperation("Get a country by uuid")]
[SwaggerResponse( [SwaggerResponse(
StatusCodes.Status200OK, "Request successful", typeof(CountryDto))] StatusCodes.Status200OK, "Request successful", typeof(CountryDto))]
[SwaggerResponse( [SwaggerResponse(
@ -105,7 +111,7 @@ public class CountriesController : ControllerBase
} }
[HttpPut("{uuid:guid}")] [HttpPut("{uuid:guid}")]
[SwaggerOperation("Update country")] [SwaggerOperation("Update a country")]
[SwaggerResponse( [SwaggerResponse(
StatusCodes.Status200OK, "Request successful", typeof(CountryDto))] StatusCodes.Status200OK, "Request successful", typeof(CountryDto))]
[SwaggerResponse( [SwaggerResponse(
@ -128,15 +134,20 @@ public class CountriesController : ControllerBase
typeof(ProblemDetails))] typeof(ProblemDetails))]
public async Task<CountryDto> Update( public async Task<CountryDto> Update(
[FromRoute] Guid uuid, [FromRoute] Guid uuid,
[FromBody] UpdateCountryCommand command, [FromBody] UpdateCountryViewModel viewModel,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
command.Guid = uuid; return await Mediator.Send(
return await Mediator.Send(command, cancellationToken); new UpdateCountryCommand()
{
Guid = uuid,
Name = viewModel.Name
},
cancellationToken);
} }
[HttpDelete("{uuid:guid}")] [HttpDelete("{uuid:guid}")]
[SwaggerOperation("Delete country")] [SwaggerOperation("Delete a country")]
[SwaggerResponse(StatusCodes.Status204NoContent, "Request successful")] [SwaggerResponse(StatusCodes.Status204NoContent, "Request successful")]
[SwaggerResponse( [SwaggerResponse(
StatusCodes.Status400BadRequest, "Input data validation error", StatusCodes.Status400BadRequest, "Input data validation error",

View File

@ -2,6 +2,7 @@ using Microsoft.AspNetCore.Mvc;
using Swashbuckle.AspNetCore.Annotations; using Swashbuckle.AspNetCore.Annotations;
using cuqmbr.TravelGuide.Application.Common.Models; using cuqmbr.TravelGuide.Application.Common.Models;
using cuqmbr.TravelGuide.Application.Common.ViewModels; using cuqmbr.TravelGuide.Application.Common.ViewModels;
using cuqmbr.TravelGuide.Application.Regions.ViewModels;
using cuqmbr.TravelGuide.Application.Regions; using cuqmbr.TravelGuide.Application.Regions;
using cuqmbr.TravelGuide.Application.Regions.Commands.AddRegion; using cuqmbr.TravelGuide.Application.Regions.Commands.AddRegion;
using cuqmbr.TravelGuide.Application.Regions.Queries.GetRegionsPage; using cuqmbr.TravelGuide.Application.Regions.Queries.GetRegionsPage;
@ -16,7 +17,7 @@ namespace cuqmbr.TravelGuide.HttpApi.Controllers;
public class RegionsController : ControllerBase public class RegionsController : ControllerBase
{ {
[HttpPost] [HttpPost]
[SwaggerOperation("Create a region")] [SwaggerOperation("Add a region")]
[SwaggerResponse( [SwaggerResponse(
StatusCodes.Status201Created, "Object successfuly created", StatusCodes.Status201Created, "Object successfuly created",
typeof(RegionDto))] typeof(RegionDto))]
@ -40,12 +41,17 @@ public class RegionsController : ControllerBase
StatusCodes.Status500InternalServerError, "Internal server error", StatusCodes.Status500InternalServerError, "Internal server error",
typeof(ProblemDetails))] typeof(ProblemDetails))]
public async Task<ActionResult<RegionDto>> Add( public async Task<ActionResult<RegionDto>> Add(
[FromBody] AddRegionCommand command, [FromBody] AddRegionViewModel viewModel,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
return StatusCode( return StatusCode(
StatusCodes.Status201Created, StatusCodes.Status201Created,
await Mediator.Send(command, cancellationToken)); await Mediator.Send(
new AddRegionCommand()
{
Name = viewModel.Name
},
cancellationToken));
} }
[HttpGet] [HttpGet]
@ -79,13 +85,13 @@ public class RegionsController : ControllerBase
PageSize = pageQuery.PageSize, PageSize = pageQuery.PageSize,
Search = searchQuery.Search, Search = searchQuery.Search,
Sort = sortQuery.Sort, Sort = sortQuery.Sort,
CountryUuid = filterQuery.CountryUuid CountryGuid = filterQuery.CountryUuid
}, },
cancellationToken); cancellationToken);
} }
[HttpGet("{uuid:guid}")] [HttpGet("{uuid:guid}")]
[SwaggerOperation("Get region by uuid")] [SwaggerOperation("Get a region by uuid")]
[SwaggerResponse( [SwaggerResponse(
StatusCodes.Status200OK, "Request successful", typeof(RegionDto))] StatusCodes.Status200OK, "Request successful", typeof(RegionDto))]
[SwaggerResponse( [SwaggerResponse(
@ -107,12 +113,12 @@ public class RegionsController : ControllerBase
[FromRoute] Guid uuid, [FromRoute] Guid uuid,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
return await Mediator.Send(new GetRegionQuery() { Uuid = uuid }, return await Mediator.Send(new GetRegionQuery() { Guid = uuid },
cancellationToken); cancellationToken);
} }
[HttpPut("{uuid:guid}")] [HttpPut("{uuid:guid}")]
[SwaggerOperation("Update region")] [SwaggerOperation("Update a region")]
[SwaggerResponse( [SwaggerResponse(
StatusCodes.Status200OK, "Request successful", typeof(RegionDto))] StatusCodes.Status200OK, "Request successful", typeof(RegionDto))]
[SwaggerResponse( [SwaggerResponse(
@ -138,15 +144,21 @@ public class RegionsController : ControllerBase
typeof(ProblemDetails))] typeof(ProblemDetails))]
public async Task<RegionDto> Update( public async Task<RegionDto> Update(
[FromRoute] Guid uuid, [FromRoute] Guid uuid,
[FromBody] UpdateRegionCommand command, [FromBody] UpdateRegionViewModel viewModel,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
command.Uuid = uuid; return await Mediator.Send(
return await Mediator.Send(command, cancellationToken); new UpdateRegionCommand()
{
Guid = uuid,
Name = viewModel.Name,
CountryGuid = viewModel.CountryUuid
},
cancellationToken);
} }
[HttpDelete("{uuid:guid}")] [HttpDelete("{uuid:guid}")]
[SwaggerOperation("Delete region")] [SwaggerOperation("Delete a region")]
[SwaggerResponse(StatusCodes.Status204NoContent, "Request successful")] [SwaggerResponse(StatusCodes.Status204NoContent, "Request successful")]
[SwaggerResponse( [SwaggerResponse(
StatusCodes.Status400BadRequest, "Input data validation error", StatusCodes.Status400BadRequest, "Input data validation error",
@ -168,7 +180,7 @@ public class RegionsController : ControllerBase
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
await Mediator.Send( await Mediator.Send(
new DeleteRegionCommand() { Uuid = uuid }, new DeleteRegionCommand() { Guid = uuid },
cancellationToken); cancellationToken);
return StatusCode(StatusCodes.Status204NoContent); return StatusCode(StatusCodes.Status204NoContent);
} }

View File

@ -8,7 +8,7 @@
}, },
"Datastore": { "Datastore": {
"Type": "postgresql", "Type": "postgresql",
"ConnectionString": "Host=127.0.0.1:5432;Database=travel_guide;Username=postgres;Password=0000" "ConnectionString": "Host=127.0.0.1:5432;Database=travel_guide;Username=postgres;Password=0000;Include Error Detail=true"
}, },
"Localization": { "Localization": {
"DefaultCultureName": "en-US", "DefaultCultureName": "en-US",

View File

@ -17,7 +17,7 @@ public sealed class Datastore
public string PartitionName { get; set; } = "identity"; public string PartitionName { get; set; } = "identity";
public bool Initialize { get; set; } = true; public bool Migrate { get; set; } = true;
} }
public sealed class JsonWebToken public sealed class JsonWebToken

View File

@ -1,55 +0,0 @@
using cuqmbr.TravelGuide.Domain.Entities;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace cuqmbr.TravelGuide.Persistence.InMemory.Configurations;
public class BaseConfiguration<TEntity> : IEntityTypeConfiguration<TEntity>
where TEntity : EntityBase
{
public virtual void Configure(EntityTypeBuilder<TEntity> builder)
{
builder
.HasKey(b => b.Id);
// .HasName($"pk_{builder.Metadata.GetTableName()}");
builder
.Property(b => b.Id)
.HasColumnName("id");
// .HasColumnType("bigint")
// .UseSequence(
// $"{builder.Metadata.GetTableName()}_" +
// $"{builder.Property(b => b.Id).Metadata.GetColumnName()}_" +
// "sequence");
//
// builder
// .HasIndex(b => b.Id)
// .HasDatabaseName(
// "ix_" +
// $"{builder.Metadata.GetTableName()}_" +
// $"{builder.Property(b => b.Id).Metadata.GetColumnName()}")
// .IsUnique();
//
//
// builder
// .HasAlternateKey(b => b.Guid)
// .HasName(
// "altk_" +
// $"{builder.Metadata.GetTableName()}_" +
// $"{builder.Property(b => b.Guid).Metadata.GetColumnName()}");
//
builder
.Property(b => b.Guid)
.HasColumnName("uuid")
// .HasColumnType("uuid")
.IsRequired(true);
//
// builder
// .HasIndex(b => b.Guid)
// .HasDatabaseName(
// "ix_" +
// $"{builder.Metadata.GetTableName()}_" +
// $"{builder.Property(b => b.Guid).Metadata.GetColumnName()}")
// .IsUnique();
}
}

View File

@ -1,31 +0,0 @@
using cuqmbr.TravelGuide.Domain.Entities;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace cuqmbr.TravelGuide.Persistence.InMemory.Configurations;
public class CountryConfiguration : BaseConfiguration<Country>
{
public override void Configure(EntityTypeBuilder<Country> builder)
{
builder
.ToTable("countries");
base.Configure(builder);
builder
.Property(c => c.Name)
.HasColumnName("name")
// .HasColumnType("varchar(64)")
.IsRequired(true);
// TODO: Remove comment
// builder
// .HasAlternateKey(c => c.Name)
// .HasName(
// "altk_" +
// $"{builder.Metadata.GetTableName()}_" +
// $"{builder.Property(c => c.Name).Metadata.GetColumnName()}");
}
}

View File

@ -1,40 +0,0 @@
using cuqmbr.TravelGuide.Domain.Entities;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace cuqmbr.TravelGuide.Persistence.InMemory.Configurations;
public class RegionConfiguration : BaseConfiguration<Region>
{
public override void Configure(EntityTypeBuilder<Region> builder)
{
builder
.ToTable("regions");
base.Configure(builder);
builder
.Property(r => r.Name)
.HasColumnName("name")
// .HasColumnType("varchar(64)")
.IsRequired(true);
builder
.Property(r => r.CountryId)
.HasColumnName("country_id")
// .HasColumnType("bigint")
.IsRequired(true);
builder
.HasOne(r => r.Country)
.WithMany(c => c.Regions)
.HasForeignKey(r => r.CountryId)
.HasConstraintName(
"fk_" +
$"{builder.Metadata.GetTableName()}_" +
$"{builder.Property(r => r.CountryId).Metadata.GetColumnName()}")
.OnDelete(DeleteBehavior.Cascade);
}
}

View File

@ -14,6 +14,7 @@ public class InMemoryDbContext : DbContext
public DbSet<Country> Countries { get => Set<Country>(); } public DbSet<Country> Countries { get => Set<Country>(); }
public DbSet<Region> Regions { get => Set<Region>(); } public DbSet<Region> Regions { get => Set<Region>(); }
public DbSet<City> Cities { get => Set<City>(); } public DbSet<City> Cities { get => Set<City>(); }
public DbSet<Address> Addresses { get => Set<Address>(); }
protected override void OnModelCreating(ModelBuilder builder) protected override void OnModelCreating(ModelBuilder builder)
{ {

View File

@ -24,6 +24,8 @@ public sealed class InMemoryUnitOfWork : UnitOfWork
public CityRepository CityRepository { get; init; } public CityRepository CityRepository { get; init; }
public AddressRepository AddressRepository { get; init; }
public int Save() public int Save()
{ {
return _dbContext.SaveChanges(); return _dbContext.SaveChanges();

View File

@ -0,0 +1,11 @@
using cuqmbr.TravelGuide.Application.Common.Interfaces.Persistence.Repositories;
using cuqmbr.TravelGuide.Domain.Entities;
namespace cuqmbr.TravelGuide.Persistence.InMemory.Repositories;
public sealed class InMemoryAddressRepository :
InMemoryBaseRepository<Address>, AddressRepository
{
public InMemoryAddressRepository(InMemoryDbContext dbContext)
: base(dbContext) { }
}

View File

@ -0,0 +1,64 @@
using cuqmbr.TravelGuide.Domain.Entities;
using cuqmbr.TravelGuide.Domain.Enums;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace cuqmbr.TravelGuide.Persistence.PostgreSql.Configurations;
public class AddressConfiguration : BaseConfiguration<Address>
{
public override void Configure(EntityTypeBuilder<Address> builder)
{
builder
.Property(a => a.VehicleType)
.HasColumnName("vehicle_type")
.HasColumnType("varchar(16)")
.IsRequired(true);
builder
.ToTable(
"addresses",
b => b.HasCheckConstraint(
"ck_" +
$"{builder.Metadata.GetTableName()}_" +
$"{builder.Property(a => a.VehicleType)
.Metadata.GetColumnName()}",
$"{builder.Property(a => a.VehicleType)
.Metadata.GetColumnName()} IN ('{String
.Join("', '", VehicleType.Enumerations
.Values.Select(v => v.Name))}')"));
base.Configure(builder);
builder
.Property(a => a.Name)
.HasColumnName("name")
.HasColumnType("varchar(128)")
.IsRequired(true);
builder
.Property(a => a.CityId)
.HasColumnName("city_id")
.HasColumnType("bigint")
.IsRequired(true);
builder
.HasOne(a => a.City)
.WithMany(c => c.Addresses)
.HasForeignKey(a => a.CityId)
.HasConstraintName(
"fk_" +
$"{builder.Metadata.GetTableName()}_" +
$"{builder.Property(a => a.CityId).Metadata.GetColumnName()}")
.OnDelete(DeleteBehavior.Cascade);
builder
.HasIndex(a => a.CityId)
.HasDatabaseName(
"ix_" +
$"{builder.Metadata.GetTableName()}_" +
$"{builder.Property(a => a.CityId).Metadata.GetColumnName()}");
}
}

View File

@ -36,5 +36,12 @@ public class CityConfiguration : BaseConfiguration<City>
$"{builder.Metadata.GetTableName()}_" + $"{builder.Metadata.GetTableName()}_" +
$"{builder.Property(c => c.RegionId).Metadata.GetColumnName()}") $"{builder.Property(c => c.RegionId).Metadata.GetColumnName()}")
.OnDelete(DeleteBehavior.Cascade); .OnDelete(DeleteBehavior.Cascade);
builder
.HasIndex(c => c.RegionId)
.HasDatabaseName(
"ix_" +
$"{builder.Metadata.GetTableName()}_" +
$"{builder.Property(c => c.RegionId).Metadata.GetColumnName()}");
} }
} }

View File

@ -36,5 +36,12 @@ public class RegionConfiguration : BaseConfiguration<Region>
$"{builder.Metadata.GetTableName()}_" + $"{builder.Metadata.GetTableName()}_" +
$"{builder.Property(r => r.CountryId).Metadata.GetColumnName()}") $"{builder.Property(r => r.CountryId).Metadata.GetColumnName()}")
.OnDelete(DeleteBehavior.Cascade); .OnDelete(DeleteBehavior.Cascade);
builder
.HasIndex(r => r.CountryId)
.HasDatabaseName(
"ix_" +
$"{builder.Metadata.GetTableName()}_" +
$"{builder.Property(r => r.CountryId).Metadata.GetColumnName()}");
} }
} }

View File

@ -12,8 +12,8 @@ using cuqmbr.TravelGuide.Persistence.PostgreSql;
namespace Persistence.PostgreSql.Migrations namespace Persistence.PostgreSql.Migrations
{ {
[DbContext(typeof(PostgreSqlDbContext))] [DbContext(typeof(PostgreSqlDbContext))]
[Migration("20250430113338_Countries_Regions_Cities")] [Migration("20250430180231_Add_Countries_Regions_Cities_Addresses")]
partial class Countries_Regions_Cities partial class Add_Countries_Regions_Cities_Addresses
{ {
/// <inheritdoc /> /// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder) protected override void BuildTargetModel(ModelBuilder modelBuilder)
@ -24,9 +24,10 @@ namespace Persistence.PostgreSql.Migrations
.HasAnnotation("ProductVersion", "9.0.4") .HasAnnotation("ProductVersion", "9.0.4")
.HasAnnotation("Relational:MaxIdentifierLength", 63); .HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "vehicle_type", new[] { "bus", "train", "aircraft" });
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.HasSequence("addresses_id_sequence");
modelBuilder.HasSequence("cities_id_sequence"); modelBuilder.HasSequence("cities_id_sequence");
modelBuilder.HasSequence("countries_id_sequence"); modelBuilder.HasSequence("countries_id_sequence");
@ -37,25 +38,57 @@ namespace Persistence.PostgreSql.Migrations
{ {
b.Property<long>("Id") b.Property<long>("Id")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
.HasColumnType("bigint"); .HasColumnType("bigint")
.HasColumnName("id")
.HasDefaultValueSql("nextval('application.addresses_id_sequence')");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id")); NpgsqlPropertyBuilderExtensions.UseSequence(b.Property<long>("Id"), "addresses_id_sequence");
b.Property<long>("CityId") b.Property<long>("CityId")
.HasColumnType("bigint"); .HasColumnType("bigint")
.HasColumnName("city_id");
b.Property<Guid>("Guid") b.Property<Guid>("Guid")
.HasColumnType("uuid"); .HasColumnType("uuid")
.HasColumnName("uuid");
b.Property<double>("Latitude")
.HasColumnType("double precision");
b.Property<double>("Longitude")
.HasColumnType("double precision");
b.Property<string>("Name") b.Property<string>("Name")
.IsRequired() .IsRequired()
.HasColumnType("text"); .HasColumnType("varchar(128)")
.HasColumnName("name");
b.HasKey("Id"); b.Property<string>("VehicleType")
.IsRequired()
.HasColumnType("varchar(16)")
.HasColumnName("vehicle_type");
b.HasIndex("CityId"); b.HasKey("Id")
.HasName("pk_addresses");
b.ToTable("Address", "application"); b.HasAlternateKey("Guid")
.HasName("altk_addresses_Guid");
b.HasIndex("CityId")
.HasDatabaseName("ix_addresses_city_id");
b.HasIndex("Guid")
.IsUnique()
.HasDatabaseName("ix_addresses_uuid");
b.HasIndex("Id")
.IsUnique()
.HasDatabaseName("ix_addresses_id");
b.ToTable("addresses", "application", t =>
{
t.HasCheckConstraint("ck_addresses_vehicle_type", "vehicle_type IN ('bus', 'train', 'aircraft')");
});
}); });
modelBuilder.Entity("cuqmbr.TravelGuide.Domain.Entities.City", b => modelBuilder.Entity("cuqmbr.TravelGuide.Domain.Entities.City", b =>
@ -95,7 +128,8 @@ namespace Persistence.PostgreSql.Migrations
.IsUnique() .IsUnique()
.HasDatabaseName("ix_cities_id"); .HasDatabaseName("ix_cities_id");
b.HasIndex("RegionId"); b.HasIndex("RegionId")
.HasDatabaseName("ix_cities_region_id");
b.ToTable("cities", "application"); b.ToTable("cities", "application");
}); });
@ -165,7 +199,8 @@ namespace Persistence.PostgreSql.Migrations
b.HasAlternateKey("Guid") b.HasAlternateKey("Guid")
.HasName("altk_regions_Guid"); .HasName("altk_regions_Guid");
b.HasIndex("CountryId"); b.HasIndex("CountryId")
.HasDatabaseName("ix_regions_country_id");
b.HasIndex("Guid") b.HasIndex("Guid")
.IsUnique() .IsUnique()
@ -178,62 +213,14 @@ namespace Persistence.PostgreSql.Migrations
b.ToTable("regions", "application"); b.ToTable("regions", "application");
}); });
modelBuilder.Entity("cuqmbr.TravelGuide.Domain.Entities.Route", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
b.Property<Guid>("Guid")
.HasColumnType("uuid");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("Route", "application");
});
modelBuilder.Entity("cuqmbr.TravelGuide.Domain.Entities.RouteAddress", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
b.Property<long>("AddressId")
.HasColumnType("bigint");
b.Property<Guid>("Guid")
.HasColumnType("uuid");
b.Property<short>("Order")
.HasColumnType("smallint");
b.Property<long>("RouteId")
.HasColumnType("bigint");
b.HasKey("Id");
b.HasIndex("AddressId");
b.HasIndex("RouteId");
b.ToTable("RouteAddress", "application");
});
modelBuilder.Entity("cuqmbr.TravelGuide.Domain.Entities.Address", b => modelBuilder.Entity("cuqmbr.TravelGuide.Domain.Entities.Address", b =>
{ {
b.HasOne("cuqmbr.TravelGuide.Domain.Entities.City", "City") b.HasOne("cuqmbr.TravelGuide.Domain.Entities.City", "City")
.WithMany("Addresses") .WithMany("Addresses")
.HasForeignKey("CityId") .HasForeignKey("CityId")
.OnDelete(DeleteBehavior.Cascade) .OnDelete(DeleteBehavior.Cascade)
.IsRequired(); .IsRequired()
.HasConstraintName("fk_addresses_city_id");
b.Navigation("City"); b.Navigation("City");
}); });
@ -262,30 +249,6 @@ namespace Persistence.PostgreSql.Migrations
b.Navigation("Country"); b.Navigation("Country");
}); });
modelBuilder.Entity("cuqmbr.TravelGuide.Domain.Entities.RouteAddress", b =>
{
b.HasOne("cuqmbr.TravelGuide.Domain.Entities.Address", "Address")
.WithMany("AddressRoutes")
.HasForeignKey("AddressId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("cuqmbr.TravelGuide.Domain.Entities.Route", "Route")
.WithMany("RouteAddresses")
.HasForeignKey("RouteId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Address");
b.Navigation("Route");
});
modelBuilder.Entity("cuqmbr.TravelGuide.Domain.Entities.Address", b =>
{
b.Navigation("AddressRoutes");
});
modelBuilder.Entity("cuqmbr.TravelGuide.Domain.Entities.City", b => modelBuilder.Entity("cuqmbr.TravelGuide.Domain.Entities.City", b =>
{ {
b.Navigation("Addresses"); b.Navigation("Addresses");
@ -300,11 +263,6 @@ namespace Persistence.PostgreSql.Migrations
{ {
b.Navigation("Cities"); b.Navigation("Cities");
}); });
modelBuilder.Entity("cuqmbr.TravelGuide.Domain.Entities.Route", b =>
{
b.Navigation("RouteAddresses");
});
#pragma warning restore 612, 618 #pragma warning restore 612, 618
} }
} }

View File

@ -1,13 +1,12 @@
using System; using System;
using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable #nullable disable
namespace Persistence.PostgreSql.Migrations namespace Persistence.PostgreSql.Migrations
{ {
/// <inheritdoc /> /// <inheritdoc />
public partial class Countries_Regions_Cities : Migration public partial class Add_Countries_Regions_Cities_Addresses : Migration
{ {
/// <inheritdoc /> /// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder) protected override void Up(MigrationBuilder migrationBuilder)
@ -15,8 +14,9 @@ namespace Persistence.PostgreSql.Migrations
migrationBuilder.EnsureSchema( migrationBuilder.EnsureSchema(
name: "application"); name: "application");
migrationBuilder.AlterDatabase() migrationBuilder.CreateSequence(
.Annotation("Npgsql:Enum:vehicle_type", "bus,train,aircraft"); name: "addresses_id_sequence",
schema: "application");
migrationBuilder.CreateSequence( migrationBuilder.CreateSequence(
name: "cities_id_sequence", name: "cities_id_sequence",
@ -45,21 +45,6 @@ namespace Persistence.PostgreSql.Migrations
table.UniqueConstraint("altk_countries_Guid", x => x.uuid); table.UniqueConstraint("altk_countries_Guid", x => x.uuid);
}); });
migrationBuilder.CreateTable(
name: "Route",
schema: "application",
columns: table => new
{
Id = table.Column<long>(type: "bigint", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Name = table.Column<string>(type: "text", nullable: false),
Guid = table.Column<Guid>(type: "uuid", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Route", x => x.Id);
});
migrationBuilder.CreateTable( migrationBuilder.CreateTable(
name: "regions", name: "regions",
schema: "application", schema: "application",
@ -107,64 +92,51 @@ namespace Persistence.PostgreSql.Migrations
}); });
migrationBuilder.CreateTable( migrationBuilder.CreateTable(
name: "Address", name: "addresses",
schema: "application", schema: "application",
columns: table => new columns: table => new
{ {
Id = table.Column<long>(type: "bigint", nullable: false) id = table.Column<long>(type: "bigint", nullable: false, defaultValueSql: "nextval('application.addresses_id_sequence')"),
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), name = table.Column<string>(type: "varchar(128)", nullable: false),
Name = table.Column<string>(type: "text", nullable: false), Longitude = table.Column<double>(type: "double precision", nullable: false),
CityId = table.Column<long>(type: "bigint", nullable: false), Latitude = table.Column<double>(type: "double precision", nullable: false),
Guid = table.Column<Guid>(type: "uuid", nullable: false) vehicle_type = table.Column<string>(type: "varchar(16)", nullable: false),
city_id = table.Column<long>(type: "bigint", nullable: false),
uuid = table.Column<Guid>(type: "uuid", nullable: false)
}, },
constraints: table => constraints: table =>
{ {
table.PrimaryKey("PK_Address", x => x.Id); table.PrimaryKey("pk_addresses", x => x.id);
table.UniqueConstraint("altk_addresses_Guid", x => x.uuid);
table.CheckConstraint("ck_addresses_vehicle_type", "vehicle_type IN ('bus', 'train', 'aircraft')");
table.ForeignKey( table.ForeignKey(
name: "FK_Address_cities_CityId", name: "fk_addresses_city_id",
column: x => x.CityId, column: x => x.city_id,
principalSchema: "application", principalSchema: "application",
principalTable: "cities", principalTable: "cities",
principalColumn: "id", principalColumn: "id",
onDelete: ReferentialAction.Cascade); onDelete: ReferentialAction.Cascade);
}); });
migrationBuilder.CreateTable( migrationBuilder.CreateIndex(
name: "RouteAddress", name: "ix_addresses_city_id",
schema: "application", schema: "application",
columns: table => new table: "addresses",
{ column: "city_id");
Id = table.Column<long>(type: "bigint", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Order = table.Column<short>(type: "smallint", nullable: false),
AddressId = table.Column<long>(type: "bigint", nullable: false),
RouteId = table.Column<long>(type: "bigint", nullable: false),
Guid = table.Column<Guid>(type: "uuid", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_RouteAddress", x => x.Id);
table.ForeignKey(
name: "FK_RouteAddress_Address_AddressId",
column: x => x.AddressId,
principalSchema: "application",
principalTable: "Address",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_RouteAddress_Route_RouteId",
column: x => x.RouteId,
principalSchema: "application",
principalTable: "Route",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex( migrationBuilder.CreateIndex(
name: "IX_Address_CityId", name: "ix_addresses_id",
schema: "application", schema: "application",
table: "Address", table: "addresses",
column: "CityId"); column: "id",
unique: true);
migrationBuilder.CreateIndex(
name: "ix_addresses_uuid",
schema: "application",
table: "addresses",
column: "uuid",
unique: true);
migrationBuilder.CreateIndex( migrationBuilder.CreateIndex(
name: "ix_cities_id", name: "ix_cities_id",
@ -174,7 +146,7 @@ namespace Persistence.PostgreSql.Migrations
unique: true); unique: true);
migrationBuilder.CreateIndex( migrationBuilder.CreateIndex(
name: "IX_cities_region_id", name: "ix_cities_region_id",
schema: "application", schema: "application",
table: "cities", table: "cities",
column: "region_id"); column: "region_id");
@ -201,7 +173,7 @@ namespace Persistence.PostgreSql.Migrations
unique: true); unique: true);
migrationBuilder.CreateIndex( migrationBuilder.CreateIndex(
name: "IX_regions_country_id", name: "ix_regions_country_id",
schema: "application", schema: "application",
table: "regions", table: "regions",
column: "country_id"); column: "country_id");
@ -219,33 +191,13 @@ namespace Persistence.PostgreSql.Migrations
table: "regions", table: "regions",
column: "uuid", column: "uuid",
unique: true); unique: true);
migrationBuilder.CreateIndex(
name: "IX_RouteAddress_AddressId",
schema: "application",
table: "RouteAddress",
column: "AddressId");
migrationBuilder.CreateIndex(
name: "IX_RouteAddress_RouteId",
schema: "application",
table: "RouteAddress",
column: "RouteId");
} }
/// <inheritdoc /> /// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder) protected override void Down(MigrationBuilder migrationBuilder)
{ {
migrationBuilder.DropTable( migrationBuilder.DropTable(
name: "RouteAddress", name: "addresses",
schema: "application");
migrationBuilder.DropTable(
name: "Address",
schema: "application");
migrationBuilder.DropTable(
name: "Route",
schema: "application"); schema: "application");
migrationBuilder.DropTable( migrationBuilder.DropTable(
@ -260,6 +212,10 @@ namespace Persistence.PostgreSql.Migrations
name: "countries", name: "countries",
schema: "application"); schema: "application");
migrationBuilder.DropSequence(
name: "addresses_id_sequence",
schema: "application");
migrationBuilder.DropSequence( migrationBuilder.DropSequence(
name: "cities_id_sequence", name: "cities_id_sequence",
schema: "application"); schema: "application");

View File

@ -21,9 +21,10 @@ namespace Persistence.PostgreSql.Migrations
.HasAnnotation("ProductVersion", "9.0.4") .HasAnnotation("ProductVersion", "9.0.4")
.HasAnnotation("Relational:MaxIdentifierLength", 63); .HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "vehicle_type", new[] { "bus", "train", "aircraft" });
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.HasSequence("addresses_id_sequence");
modelBuilder.HasSequence("cities_id_sequence"); modelBuilder.HasSequence("cities_id_sequence");
modelBuilder.HasSequence("countries_id_sequence"); modelBuilder.HasSequence("countries_id_sequence");
@ -34,25 +35,57 @@ namespace Persistence.PostgreSql.Migrations
{ {
b.Property<long>("Id") b.Property<long>("Id")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
.HasColumnType("bigint"); .HasColumnType("bigint")
.HasColumnName("id")
.HasDefaultValueSql("nextval('application.addresses_id_sequence')");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id")); NpgsqlPropertyBuilderExtensions.UseSequence(b.Property<long>("Id"), "addresses_id_sequence");
b.Property<long>("CityId") b.Property<long>("CityId")
.HasColumnType("bigint"); .HasColumnType("bigint")
.HasColumnName("city_id");
b.Property<Guid>("Guid") b.Property<Guid>("Guid")
.HasColumnType("uuid"); .HasColumnType("uuid")
.HasColumnName("uuid");
b.Property<double>("Latitude")
.HasColumnType("double precision");
b.Property<double>("Longitude")
.HasColumnType("double precision");
b.Property<string>("Name") b.Property<string>("Name")
.IsRequired() .IsRequired()
.HasColumnType("text"); .HasColumnType("varchar(128)")
.HasColumnName("name");
b.HasKey("Id"); b.Property<string>("VehicleType")
.IsRequired()
.HasColumnType("varchar(16)")
.HasColumnName("vehicle_type");
b.HasIndex("CityId"); b.HasKey("Id")
.HasName("pk_addresses");
b.ToTable("Address", "application"); b.HasAlternateKey("Guid")
.HasName("altk_addresses_Guid");
b.HasIndex("CityId")
.HasDatabaseName("ix_addresses_city_id");
b.HasIndex("Guid")
.IsUnique()
.HasDatabaseName("ix_addresses_uuid");
b.HasIndex("Id")
.IsUnique()
.HasDatabaseName("ix_addresses_id");
b.ToTable("addresses", "application", t =>
{
t.HasCheckConstraint("ck_addresses_vehicle_type", "vehicle_type IN ('bus', 'train', 'aircraft')");
});
}); });
modelBuilder.Entity("cuqmbr.TravelGuide.Domain.Entities.City", b => modelBuilder.Entity("cuqmbr.TravelGuide.Domain.Entities.City", b =>
@ -92,7 +125,8 @@ namespace Persistence.PostgreSql.Migrations
.IsUnique() .IsUnique()
.HasDatabaseName("ix_cities_id"); .HasDatabaseName("ix_cities_id");
b.HasIndex("RegionId"); b.HasIndex("RegionId")
.HasDatabaseName("ix_cities_region_id");
b.ToTable("cities", "application"); b.ToTable("cities", "application");
}); });
@ -162,7 +196,8 @@ namespace Persistence.PostgreSql.Migrations
b.HasAlternateKey("Guid") b.HasAlternateKey("Guid")
.HasName("altk_regions_Guid"); .HasName("altk_regions_Guid");
b.HasIndex("CountryId"); b.HasIndex("CountryId")
.HasDatabaseName("ix_regions_country_id");
b.HasIndex("Guid") b.HasIndex("Guid")
.IsUnique() .IsUnique()
@ -175,62 +210,14 @@ namespace Persistence.PostgreSql.Migrations
b.ToTable("regions", "application"); b.ToTable("regions", "application");
}); });
modelBuilder.Entity("cuqmbr.TravelGuide.Domain.Entities.Route", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
b.Property<Guid>("Guid")
.HasColumnType("uuid");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("Route", "application");
});
modelBuilder.Entity("cuqmbr.TravelGuide.Domain.Entities.RouteAddress", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
b.Property<long>("AddressId")
.HasColumnType("bigint");
b.Property<Guid>("Guid")
.HasColumnType("uuid");
b.Property<short>("Order")
.HasColumnType("smallint");
b.Property<long>("RouteId")
.HasColumnType("bigint");
b.HasKey("Id");
b.HasIndex("AddressId");
b.HasIndex("RouteId");
b.ToTable("RouteAddress", "application");
});
modelBuilder.Entity("cuqmbr.TravelGuide.Domain.Entities.Address", b => modelBuilder.Entity("cuqmbr.TravelGuide.Domain.Entities.Address", b =>
{ {
b.HasOne("cuqmbr.TravelGuide.Domain.Entities.City", "City") b.HasOne("cuqmbr.TravelGuide.Domain.Entities.City", "City")
.WithMany("Addresses") .WithMany("Addresses")
.HasForeignKey("CityId") .HasForeignKey("CityId")
.OnDelete(DeleteBehavior.Cascade) .OnDelete(DeleteBehavior.Cascade)
.IsRequired(); .IsRequired()
.HasConstraintName("fk_addresses_city_id");
b.Navigation("City"); b.Navigation("City");
}); });
@ -259,30 +246,6 @@ namespace Persistence.PostgreSql.Migrations
b.Navigation("Country"); b.Navigation("Country");
}); });
modelBuilder.Entity("cuqmbr.TravelGuide.Domain.Entities.RouteAddress", b =>
{
b.HasOne("cuqmbr.TravelGuide.Domain.Entities.Address", "Address")
.WithMany("AddressRoutes")
.HasForeignKey("AddressId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("cuqmbr.TravelGuide.Domain.Entities.Route", "Route")
.WithMany("RouteAddresses")
.HasForeignKey("RouteId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Address");
b.Navigation("Route");
});
modelBuilder.Entity("cuqmbr.TravelGuide.Domain.Entities.Address", b =>
{
b.Navigation("AddressRoutes");
});
modelBuilder.Entity("cuqmbr.TravelGuide.Domain.Entities.City", b => modelBuilder.Entity("cuqmbr.TravelGuide.Domain.Entities.City", b =>
{ {
b.Navigation("Addresses"); b.Navigation("Addresses");
@ -297,11 +260,6 @@ namespace Persistence.PostgreSql.Migrations
{ {
b.Navigation("Cities"); b.Navigation("Cities");
}); });
modelBuilder.Entity("cuqmbr.TravelGuide.Domain.Entities.Route", b =>
{
b.Navigation("RouteAddresses");
});
#pragma warning restore 612, 618 #pragma warning restore 612, 618
} }
} }

View File

@ -24,15 +24,12 @@ public class PostgreSqlDbContext : DbContext
builder.HasDefaultSchema(DefaultSchema); builder.HasDefaultSchema(DefaultSchema);
builder.HasPostgresEnum(
"vehicle_type",
VehicleType.Enumerations.Select(e => e.Value.Name).ToArray());
builder builder
.ApplyConfigurationsFromAssembly( .ApplyConfigurationsFromAssembly(
Assembly.GetExecutingAssembly(), Assembly.GetExecutingAssembly(),
t => t.Namespace == t => t.Namespace ==
"cuqmbr.TravelGuide.Persistence.PostgreSql.Configurations"); "cuqmbr.TravelGuide.Persistence.PostgreSql.Configurations");
} }
protected override void ConfigureConventions( protected override void ConfigureConventions(

View File

@ -16,6 +16,7 @@ public sealed class PostgreSqlUnitOfWork : UnitOfWork
CountryRepository = new PostgreSqlCountryRepository(_dbContext); CountryRepository = new PostgreSqlCountryRepository(_dbContext);
RegionRepository = new PostgreSqlRegionRepository(_dbContext); RegionRepository = new PostgreSqlRegionRepository(_dbContext);
CityRepository = new PostgreSqlCityRepository(_dbContext); CityRepository = new PostgreSqlCityRepository(_dbContext);
AddressRepository = new PostgreSqlAddressRepository(_dbContext);
} }
public CountryRepository CountryRepository { get; init; } public CountryRepository CountryRepository { get; init; }
@ -24,6 +25,8 @@ public sealed class PostgreSqlUnitOfWork : UnitOfWork
public CityRepository CityRepository { get; init; } public CityRepository CityRepository { get; init; }
public AddressRepository AddressRepository { get; init; }
public int Save() public int Save()
{ {
return _dbContext.SaveChanges(); return _dbContext.SaveChanges();

View File

@ -0,0 +1,11 @@
using cuqmbr.TravelGuide.Application.Common.Interfaces.Persistence.Repositories;
using cuqmbr.TravelGuide.Domain.Entities;
namespace cuqmbr.TravelGuide.Persistence.PostgreSql.Repositories;
public sealed class PostgreSqlAddressRepository :
PostgreSqlBaseRepository<Address>, AddressRepository
{
public PostgreSqlAddressRepository(PostgreSqlDbContext dbContext)
: base(dbContext) { }
}

View File

@ -35,7 +35,7 @@ public class CitiesTests : TestBase
new AddRegionCommand() new AddRegionCommand()
{ {
Name = regionName, Name = regionName,
CountryUuid = addCountryResult.Uuid CountryGuid = addCountryResult.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
string cityName = "City Name"; string cityName = "City Name";
@ -44,13 +44,13 @@ public class CitiesTests : TestBase
new AddCityCommand() new AddCityCommand()
{ {
Name = cityName, Name = cityName,
RegionUuid = addRegionResult.Uuid RegionGuid = addRegionResult.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
var getCityResult = await mediator.Send( var getCityResult = await mediator.Send(
new GetCityQuery() new GetCityQuery()
{ {
Uuid = addCityResult.Uuid, Guid = addCityResult.Uuid,
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
Assert.NotNull(getCityResult); Assert.NotNull(getCityResult);
@ -89,7 +89,7 @@ public class CitiesTests : TestBase
new AddRegionCommand() new AddRegionCommand()
{ {
Name = regionName, Name = regionName,
CountryUuid = addCountryResult.Uuid CountryGuid = addCountryResult.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
string cityName = "City Name"; string cityName = "City Name";
@ -98,14 +98,14 @@ public class CitiesTests : TestBase
new AddCityCommand() new AddCityCommand()
{ {
Name = cityName, Name = cityName,
RegionUuid = addRegionResult.Uuid RegionGuid = addRegionResult.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
await Assert.ThrowsAsync<DuplicateEntityException>(() => await Assert.ThrowsAsync<DuplicateEntityException>(() =>
mediator.Send(new AddCityCommand() mediator.Send(new AddCityCommand()
{ {
Name = cityName, Name = cityName,
RegionUuid = addRegionResult.Uuid RegionGuid = addRegionResult.Uuid
}, TestContext.Current.CancellationToken)); }, TestContext.Current.CancellationToken));
} }
@ -132,14 +132,14 @@ public class CitiesTests : TestBase
new AddRegionCommand() new AddRegionCommand()
{ {
Name = regionName1, Name = regionName1,
CountryUuid = addCountryResult.Uuid CountryGuid = addCountryResult.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
var addRegionResult2 = await mediator.Send( var addRegionResult2 = await mediator.Send(
new AddRegionCommand() new AddRegionCommand()
{ {
Name = regionName2, Name = regionName2,
CountryUuid = addCountryResult.Uuid CountryGuid = addCountryResult.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
string cityName = "City Name"; string cityName = "City Name";
@ -148,20 +148,20 @@ public class CitiesTests : TestBase
new AddCityCommand() new AddCityCommand()
{ {
Name = cityName, Name = cityName,
RegionUuid = addRegionResult1.Uuid RegionGuid = addRegionResult1.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
var addCityResult2 = await mediator.Send( var addCityResult2 = await mediator.Send(
new AddCityCommand() new AddCityCommand()
{ {
Name = cityName, Name = cityName,
RegionUuid = addRegionResult2.Uuid RegionGuid = addRegionResult2.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
var getCityResult1 = await mediator.Send( var getCityResult1 = await mediator.Send(
new GetCityQuery() new GetCityQuery()
{ {
Uuid = addCityResult1.Uuid, Guid = addCityResult1.Uuid,
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
Assert.NotNull(getCityResult1); Assert.NotNull(getCityResult1);
@ -180,7 +180,7 @@ public class CitiesTests : TestBase
var getCityResult2 = await mediator.Send( var getCityResult2 = await mediator.Send(
new GetCityQuery() new GetCityQuery()
{ {
Uuid = addCityResult2.Uuid, Guid = addCityResult2.Uuid,
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
Assert.NotNull(getCityResult2); Assert.NotNull(getCityResult2);
@ -209,7 +209,7 @@ public class CitiesTests : TestBase
mediator.Send(new AddCityCommand() mediator.Send(new AddCityCommand()
{ {
Name = "Name", Name = "Name",
RegionUuid = Guid.NewGuid() RegionGuid = Guid.NewGuid()
}, TestContext.Current.CancellationToken)); }, TestContext.Current.CancellationToken));
} }
@ -246,7 +246,7 @@ public class CitiesTests : TestBase
mediator.Send(new AddCityCommand() mediator.Send(new AddCityCommand()
{ {
Name = "Name", Name = "Name",
RegionUuid = RegionGuid =
Guid.TryParse(uuid, out var guid) ? guid : Guid.Empty Guid.TryParse(uuid, out var guid) ? guid : Guid.Empty
}, TestContext.Current.CancellationToken)); }, TestContext.Current.CancellationToken));
} }
@ -303,7 +303,7 @@ public class CitiesTests : TestBase
new AddRegionCommand() new AddRegionCommand()
{ {
Name = regionName, Name = regionName,
CountryUuid = addCountryResult.Uuid CountryGuid = addCountryResult.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
string cityName = "City Name"; string cityName = "City Name";
@ -312,7 +312,7 @@ public class CitiesTests : TestBase
new AddCityCommand() new AddCityCommand()
{ {
Name = cityName, Name = cityName,
RegionUuid = addRegionResult.Uuid RegionGuid = addRegionResult.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
string newName = "Different Name"; string newName = "Different Name";
@ -320,9 +320,9 @@ public class CitiesTests : TestBase
var updateCityResult = await mediator.Send( var updateCityResult = await mediator.Send(
new UpdateCityCommand() new UpdateCityCommand()
{ {
Uuid = addCityResult.Uuid, Guid = addCityResult.Uuid,
Name = newName, Name = newName,
RegionUuid = addRegionResult.Uuid RegionGuid = addRegionResult.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
Assert.NotNull(updateCityResult); Assert.NotNull(updateCityResult);
@ -355,7 +355,7 @@ public class CitiesTests : TestBase
mediator.Send(new UpdateCityCommand() mediator.Send(new UpdateCityCommand()
{ {
Name = name, Name = name,
RegionUuid = Guid.NewGuid() RegionGuid = Guid.NewGuid()
}, TestContext.Current.CancellationToken)); }, TestContext.Current.CancellationToken));
} }
@ -373,9 +373,9 @@ public class CitiesTests : TestBase
await Assert.ThrowsAsync<ValidationException>(() => await Assert.ThrowsAsync<ValidationException>(() =>
mediator.Send(new UpdateCityCommand() mediator.Send(new UpdateCityCommand()
{ {
Uuid = Guid.NewGuid(), Guid = Guid.NewGuid(),
Name = "Name", Name = "Name",
RegionUuid = RegionGuid =
Guid.TryParse(uuid, out var guid) ? guid : Guid.Empty Guid.TryParse(uuid, out var guid) ? guid : Guid.Empty
}, TestContext.Current.CancellationToken)); }, TestContext.Current.CancellationToken));
} }
@ -394,9 +394,9 @@ public class CitiesTests : TestBase
await Assert.ThrowsAsync<ValidationException>(() => await Assert.ThrowsAsync<ValidationException>(() =>
mediator.Send(new UpdateCityCommand() mediator.Send(new UpdateCityCommand()
{ {
Uuid = Guid.TryParse(uuid, out var guid) ? guid : Guid.Empty, Guid = Guid.TryParse(uuid, out var guid) ? guid : Guid.Empty,
Name = "Name", Name = "Name",
RegionUuid = Guid.NewGuid() RegionGuid = Guid.NewGuid()
}, TestContext.Current.CancellationToken)); }, TestContext.Current.CancellationToken));
} }
@ -418,15 +418,15 @@ public class CitiesTests : TestBase
new AddRegionCommand() new AddRegionCommand()
{ {
Name = "Name", Name = "Name",
CountryUuid = addCountryResult.Uuid CountryGuid = addCountryResult.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
await Assert.ThrowsAsync<NotFoundException>(() => await Assert.ThrowsAsync<NotFoundException>(() =>
mediator.Send(new UpdateCityCommand() mediator.Send(new UpdateCityCommand()
{ {
Uuid = Guid.NewGuid(), Guid = Guid.NewGuid(),
Name = "Different Name", Name = "Different Name",
RegionUuid = addRegionResult.Uuid RegionGuid = addRegionResult.Uuid
}, TestContext.Current.CancellationToken)); }, TestContext.Current.CancellationToken));
} }
@ -448,22 +448,22 @@ public class CitiesTests : TestBase
new AddRegionCommand() new AddRegionCommand()
{ {
Name = "Name", Name = "Name",
CountryUuid = addCountryResult.Uuid CountryGuid = addCountryResult.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
var addCityResult = await mediator.Send( var addCityResult = await mediator.Send(
new AddCityCommand() new AddCityCommand()
{ {
Name = "Name", Name = "Name",
RegionUuid = addRegionResult.Uuid RegionGuid = addRegionResult.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
await Assert.ThrowsAsync<NotFoundException>(() => await Assert.ThrowsAsync<NotFoundException>(() =>
mediator.Send(new UpdateCityCommand() mediator.Send(new UpdateCityCommand()
{ {
Uuid = addCityResult.Uuid, Guid = addCityResult.Uuid,
Name = "Different Name", Name = "Different Name",
RegionUuid = Guid.NewGuid() RegionGuid = Guid.NewGuid()
}, TestContext.Current.CancellationToken)); }, TestContext.Current.CancellationToken));
} }
@ -515,26 +515,26 @@ public class CitiesTests : TestBase
new AddRegionCommand() new AddRegionCommand()
{ {
Name = "Name", Name = "Name",
CountryUuid = addCountryResult.Uuid CountryGuid = addCountryResult.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
var addCityResult = await mediator.Send( var addCityResult = await mediator.Send(
new AddCityCommand() new AddCityCommand()
{ {
Name = "Name", Name = "Name",
RegionUuid = addRegionResult.Uuid RegionGuid = addRegionResult.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
await mediator.Send( await mediator.Send(
new DeleteCityCommand() new DeleteCityCommand()
{ {
Uuid = addCityResult.Uuid, Guid = addCityResult.Uuid,
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
await Assert.ThrowsAsync<NotFoundException>(() => await Assert.ThrowsAsync<NotFoundException>(() =>
mediator.Send(new GetCityQuery() mediator.Send(new GetCityQuery()
{ {
Uuid = addCityResult.Uuid, Guid = addCityResult.Uuid,
}, TestContext.Current.CancellationToken)); }, TestContext.Current.CancellationToken));
} }
@ -552,7 +552,7 @@ public class CitiesTests : TestBase
await Assert.ThrowsAsync<ValidationException>(() => await Assert.ThrowsAsync<ValidationException>(() =>
mediator.Send(new DeleteCityCommand() mediator.Send(new DeleteCityCommand()
{ {
Uuid = Guid.TryParse(uuid, out var guid) ? guid : Guid.Empty Guid = Guid.TryParse(uuid, out var guid) ? guid : Guid.Empty
}, TestContext.Current.CancellationToken)); }, TestContext.Current.CancellationToken));
} }
@ -567,7 +567,7 @@ public class CitiesTests : TestBase
await Assert.ThrowsAsync<NotFoundException>(() => await Assert.ThrowsAsync<NotFoundException>(() =>
mediator.Send(new DeleteCityCommand() mediator.Send(new DeleteCityCommand()
{ {
Uuid = Guid.NewGuid() Guid = Guid.NewGuid()
}, TestContext.Current.CancellationToken)); }, TestContext.Current.CancellationToken));
} }
@ -623,7 +623,7 @@ public class CitiesTests : TestBase
new AddRegionCommand() new AddRegionCommand()
{ {
Name = regionName, Name = regionName,
CountryUuid = addCountryResult.Uuid CountryGuid = addCountryResult.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
string cityName = "Name"; string cityName = "Name";
@ -632,13 +632,13 @@ public class CitiesTests : TestBase
new AddCityCommand() new AddCityCommand()
{ {
Name = cityName, Name = cityName,
RegionUuid = addRegionResult.Uuid RegionGuid = addRegionResult.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
var getCityResult = await mediator.Send( var getCityResult = await mediator.Send(
new GetCityQuery() new GetCityQuery()
{ {
Uuid = addCityResult.Uuid, Guid = addCityResult.Uuid,
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
Assert.NotNull(getCityResult); Assert.NotNull(getCityResult);
@ -670,7 +670,7 @@ public class CitiesTests : TestBase
mediator.Send( mediator.Send(
new GetCityQuery() new GetCityQuery()
{ {
Uuid = Guid.TryParse(uuid, out var guid) ? guid : Guid.Empty Guid = Guid.TryParse(uuid, out var guid) ? guid : Guid.Empty
}, TestContext.Current.CancellationToken)); }, TestContext.Current.CancellationToken));
} }
@ -686,7 +686,7 @@ public class CitiesTests : TestBase
mediator.Send( mediator.Send(
new GetCityQuery() new GetCityQuery()
{ {
Uuid = Guid.NewGuid() Guid = Guid.NewGuid()
}, TestContext.Current.CancellationToken)); }, TestContext.Current.CancellationToken));
} }
@ -743,14 +743,14 @@ public class CitiesTests : TestBase
new AddRegionCommand() new AddRegionCommand()
{ {
Name = regionName1, Name = regionName1,
CountryUuid = addCountryResult.Uuid CountryGuid = addCountryResult.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
var addRegionResult2 = await mediator.Send( var addRegionResult2 = await mediator.Send(
new AddRegionCommand() new AddRegionCommand()
{ {
Name = regionName2, Name = regionName2,
CountryUuid = addCountryResult.Uuid CountryGuid = addCountryResult.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
string cityName1 = "City Name 1"; string cityName1 = "City Name 1";
@ -760,14 +760,14 @@ public class CitiesTests : TestBase
new AddCityCommand() new AddCityCommand()
{ {
Name = cityName1, Name = cityName1,
RegionUuid = addRegionResult1.Uuid RegionGuid = addRegionResult1.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
var addCityResult2 = await mediator.Send( var addCityResult2 = await mediator.Send(
new AddCityCommand() new AddCityCommand()
{ {
Name = cityName2, Name = cityName2,
RegionUuid = addRegionResult2.Uuid RegionGuid = addRegionResult2.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
var getCitiesResult = await mediator.Send( var getCitiesResult = await mediator.Send(
@ -928,14 +928,14 @@ public class CitiesTests : TestBase
new AddRegionCommand() new AddRegionCommand()
{ {
Name = regionName1, Name = regionName1,
CountryUuid = addCountryResult1.Uuid CountryGuid = addCountryResult1.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
var addRegionResult2 = await mediator.Send( var addRegionResult2 = await mediator.Send(
new AddRegionCommand() new AddRegionCommand()
{ {
Name = regionName2, Name = regionName2,
CountryUuid = addCountryResult2.Uuid CountryGuid = addCountryResult2.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
string cityName1 = "City Name 1"; string cityName1 = "City Name 1";
@ -945,14 +945,14 @@ public class CitiesTests : TestBase
new AddCityCommand() new AddCityCommand()
{ {
Name = cityName1, Name = cityName1,
RegionUuid = addRegionResult1.Uuid RegionGuid = addRegionResult1.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
var addCityResult2 = await mediator.Send( var addCityResult2 = await mediator.Send(
new AddCityCommand() new AddCityCommand()
{ {
Name = cityName2, Name = cityName2,
RegionUuid = addRegionResult2.Uuid RegionGuid = addRegionResult2.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
var getCitiesResult = await mediator.Send( var getCitiesResult = await mediator.Send(
@ -1022,14 +1022,14 @@ public class CitiesTests : TestBase
new AddRegionCommand() new AddRegionCommand()
{ {
Name = regionName1, Name = regionName1,
CountryUuid = addCountryResult1.Uuid CountryGuid = addCountryResult1.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
var addRegionResult2 = await mediator.Send( var addRegionResult2 = await mediator.Send(
new AddRegionCommand() new AddRegionCommand()
{ {
Name = regionName2, Name = regionName2,
CountryUuid = addCountryResult2.Uuid CountryGuid = addCountryResult2.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
string cityName1 = "City Name 1"; string cityName1 = "City Name 1";
@ -1039,14 +1039,14 @@ public class CitiesTests : TestBase
new AddCityCommand() new AddCityCommand()
{ {
Name = cityName1, Name = cityName1,
RegionUuid = addRegionResult1.Uuid RegionGuid = addRegionResult1.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
var addCityResult2 = await mediator.Send( var addCityResult2 = await mediator.Send(
new AddCityCommand() new AddCityCommand()
{ {
Name = cityName2, Name = cityName2,
RegionUuid = addRegionResult2.Uuid RegionGuid = addRegionResult2.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
var getCitiesResult = await mediator.Send( var getCitiesResult = await mediator.Send(
@ -1116,14 +1116,14 @@ public class CitiesTests : TestBase
new AddRegionCommand() new AddRegionCommand()
{ {
Name = regionName1, Name = regionName1,
CountryUuid = addCountryResult1.Uuid CountryGuid = addCountryResult1.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
var addRegionResult2 = await mediator.Send( var addRegionResult2 = await mediator.Send(
new AddRegionCommand() new AddRegionCommand()
{ {
Name = regionName2, Name = regionName2,
CountryUuid = addCountryResult2.Uuid CountryGuid = addCountryResult2.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
string cityName1 = "City Name 1"; string cityName1 = "City Name 1";
@ -1133,14 +1133,14 @@ public class CitiesTests : TestBase
new AddCityCommand() new AddCityCommand()
{ {
Name = cityName1, Name = cityName1,
RegionUuid = addRegionResult1.Uuid RegionGuid = addRegionResult1.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
var addCityResult2 = await mediator.Send( var addCityResult2 = await mediator.Send(
new AddCityCommand() new AddCityCommand()
{ {
Name = cityName2, Name = cityName2,
RegionUuid = addRegionResult2.Uuid RegionGuid = addRegionResult2.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
var getCitiesResult = await mediator.Send( var getCitiesResult = await mediator.Send(
@ -1210,14 +1210,14 @@ public class CitiesTests : TestBase
new AddRegionCommand() new AddRegionCommand()
{ {
Name = regionName1, Name = regionName1,
CountryUuid = addCountryResult1.Uuid CountryGuid = addCountryResult1.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
var addRegionResult2 = await mediator.Send( var addRegionResult2 = await mediator.Send(
new AddRegionCommand() new AddRegionCommand()
{ {
Name = regionName2, Name = regionName2,
CountryUuid = addCountryResult2.Uuid CountryGuid = addCountryResult2.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
string cityName1 = "City Name 1"; string cityName1 = "City Name 1";
@ -1227,14 +1227,14 @@ public class CitiesTests : TestBase
new AddCityCommand() new AddCityCommand()
{ {
Name = cityName1, Name = cityName1,
RegionUuid = addRegionResult1.Uuid RegionGuid = addRegionResult1.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
var addCityResult2 = await mediator.Send( var addCityResult2 = await mediator.Send(
new AddCityCommand() new AddCityCommand()
{ {
Name = cityName2, Name = cityName2,
RegionUuid = addRegionResult2.Uuid RegionGuid = addRegionResult2.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
var getCitiesResult = await mediator.Send( var getCitiesResult = await mediator.Send(
@ -1324,14 +1324,14 @@ public class CitiesTests : TestBase
new AddRegionCommand() new AddRegionCommand()
{ {
Name = regionName1, Name = regionName1,
CountryUuid = addCountryResult1.Uuid CountryGuid = addCountryResult1.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
var addRegionResult2 = await mediator.Send( var addRegionResult2 = await mediator.Send(
new AddRegionCommand() new AddRegionCommand()
{ {
Name = regionName2, Name = regionName2,
CountryUuid = addCountryResult2.Uuid CountryGuid = addCountryResult2.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
string cityName1 = "City Name 1"; string cityName1 = "City Name 1";
@ -1341,14 +1341,14 @@ public class CitiesTests : TestBase
new AddCityCommand() new AddCityCommand()
{ {
Name = cityName1, Name = cityName1,
RegionUuid = addRegionResult1.Uuid RegionGuid = addRegionResult1.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
var addCityResult2 = await mediator.Send( var addCityResult2 = await mediator.Send(
new AddCityCommand() new AddCityCommand()
{ {
Name = cityName2, Name = cityName2,
RegionUuid = addRegionResult2.Uuid RegionGuid = addRegionResult2.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
var getCitiesResult = await mediator.Send( var getCitiesResult = await mediator.Send(
@ -1356,7 +1356,7 @@ public class CitiesTests : TestBase
{ {
PageNumber = 1, PageNumber = 1,
PageSize = 10, PageSize = 10,
CountryUuid = addCountryResult1.Uuid CountryGuid = addCountryResult1.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
Assert.NotNull(getCitiesResult); Assert.NotNull(getCitiesResult);
@ -1419,14 +1419,14 @@ public class CitiesTests : TestBase
new AddRegionCommand() new AddRegionCommand()
{ {
Name = regionName1, Name = regionName1,
CountryUuid = addCountryResult1.Uuid CountryGuid = addCountryResult1.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
var addRegionResult2 = await mediator.Send( var addRegionResult2 = await mediator.Send(
new AddRegionCommand() new AddRegionCommand()
{ {
Name = regionName2, Name = regionName2,
CountryUuid = addCountryResult2.Uuid CountryGuid = addCountryResult2.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
string cityName1 = "City Name 1"; string cityName1 = "City Name 1";
@ -1436,14 +1436,14 @@ public class CitiesTests : TestBase
new AddCityCommand() new AddCityCommand()
{ {
Name = cityName1, Name = cityName1,
RegionUuid = addRegionResult1.Uuid RegionGuid = addRegionResult1.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
var addCityResult2 = await mediator.Send( var addCityResult2 = await mediator.Send(
new AddCityCommand() new AddCityCommand()
{ {
Name = cityName2, Name = cityName2,
RegionUuid = addRegionResult2.Uuid RegionGuid = addRegionResult2.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
var getCitiesResult = await mediator.Send( var getCitiesResult = await mediator.Send(
@ -1451,7 +1451,7 @@ public class CitiesTests : TestBase
{ {
PageNumber = 1, PageNumber = 1,
PageSize = 10, PageSize = 10,
RegionUuid = addRegionResult2.Uuid RegionGuid = addRegionResult2.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
Assert.NotNull(getCitiesResult); Assert.NotNull(getCitiesResult);

View File

@ -34,13 +34,13 @@ public class RegionsTests : TestBase
new AddRegionCommand() new AddRegionCommand()
{ {
Name = regionName, Name = regionName,
CountryUuid = addCountryResult.Uuid CountryGuid = addCountryResult.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
var getRegionResult = await mediator.Send( var getRegionResult = await mediator.Send(
new GetRegionQuery() new GetRegionQuery()
{ {
Uuid = addRegionResult.Uuid, Guid = addRegionResult.Uuid,
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
Assert.NotNull(getRegionResult); Assert.NotNull(getRegionResult);
@ -73,14 +73,14 @@ public class RegionsTests : TestBase
new AddRegionCommand() new AddRegionCommand()
{ {
Name = regionName, Name = regionName,
CountryUuid = addCountryResult.Uuid CountryGuid = addCountryResult.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
await Assert.ThrowsAsync<DuplicateEntityException>(() => await Assert.ThrowsAsync<DuplicateEntityException>(() =>
mediator.Send(new AddRegionCommand() mediator.Send(new AddRegionCommand()
{ {
Name = regionName, Name = regionName,
CountryUuid = addCountryResult.Uuid CountryGuid = addCountryResult.Uuid
}, TestContext.Current.CancellationToken)); }, TestContext.Current.CancellationToken));
} }
@ -114,20 +114,20 @@ public class RegionsTests : TestBase
new AddRegionCommand() new AddRegionCommand()
{ {
Name = regionName, Name = regionName,
CountryUuid = addCountryResult1.Uuid CountryGuid = addCountryResult1.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
var addRegionResult2 = await mediator.Send( var addRegionResult2 = await mediator.Send(
new AddRegionCommand() new AddRegionCommand()
{ {
Name = regionName, Name = regionName,
CountryUuid = addCountryResult2.Uuid CountryGuid = addCountryResult2.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
var getRegionResult1 = await mediator.Send( var getRegionResult1 = await mediator.Send(
new GetRegionQuery() new GetRegionQuery()
{ {
Uuid = addRegionResult1.Uuid, Guid = addRegionResult1.Uuid,
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
Assert.NotNull(getRegionResult1); Assert.NotNull(getRegionResult1);
@ -138,7 +138,7 @@ public class RegionsTests : TestBase
var getRegionResult2 = await mediator.Send( var getRegionResult2 = await mediator.Send(
new GetRegionQuery() new GetRegionQuery()
{ {
Uuid = addRegionResult2.Uuid, Guid = addRegionResult2.Uuid,
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
Assert.NotNull(getRegionResult2); Assert.NotNull(getRegionResult2);
@ -161,7 +161,7 @@ public class RegionsTests : TestBase
mediator.Send(new AddRegionCommand() mediator.Send(new AddRegionCommand()
{ {
Name = "Name", Name = "Name",
CountryUuid = Guid.NewGuid() CountryGuid = Guid.NewGuid()
}, TestContext.Current.CancellationToken)); }, TestContext.Current.CancellationToken));
} }
@ -198,7 +198,7 @@ public class RegionsTests : TestBase
mediator.Send(new AddRegionCommand() mediator.Send(new AddRegionCommand()
{ {
Name = "Name", Name = "Name",
CountryUuid = CountryGuid =
Guid.TryParse(uuid, out var guid) ? guid : Guid.Empty Guid.TryParse(uuid, out var guid) ? guid : Guid.Empty
}, TestContext.Current.CancellationToken)); }, TestContext.Current.CancellationToken));
} }
@ -255,7 +255,7 @@ public class RegionsTests : TestBase
new AddRegionCommand() new AddRegionCommand()
{ {
Name = regionName, Name = regionName,
CountryUuid = addCountryResult.Uuid CountryGuid = addCountryResult.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
string newName = "Different Name"; string newName = "Different Name";
@ -263,15 +263,15 @@ public class RegionsTests : TestBase
var updateRegionResult = await mediator.Send( var updateRegionResult = await mediator.Send(
new UpdateRegionCommand() new UpdateRegionCommand()
{ {
Uuid = addRegionResult.Uuid, Guid = addRegionResult.Uuid,
Name = newName, Name = newName,
CountryUuid = addCountryResult.Uuid CountryGuid = addCountryResult.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
var getRegionResult = await mediator.Send( var getRegionResult = await mediator.Send(
new GetRegionQuery() new GetRegionQuery()
{ {
Uuid = addRegionResult.Uuid, Guid = addRegionResult.Uuid,
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
Assert.NotNull(getRegionResult); Assert.NotNull(getRegionResult);
@ -297,7 +297,7 @@ public class RegionsTests : TestBase
mediator.Send(new UpdateRegionCommand() mediator.Send(new UpdateRegionCommand()
{ {
Name = name, Name = name,
CountryUuid = Guid.NewGuid() CountryGuid = Guid.NewGuid()
}, TestContext.Current.CancellationToken)); }, TestContext.Current.CancellationToken));
} }
@ -315,9 +315,9 @@ public class RegionsTests : TestBase
await Assert.ThrowsAsync<ValidationException>(() => await Assert.ThrowsAsync<ValidationException>(() =>
mediator.Send(new UpdateRegionCommand() mediator.Send(new UpdateRegionCommand()
{ {
Uuid = Guid.NewGuid(), Guid = Guid.NewGuid(),
Name = "Name", Name = "Name",
CountryUuid = CountryGuid =
Guid.TryParse(uuid, out var guid) ? guid : Guid.Empty Guid.TryParse(uuid, out var guid) ? guid : Guid.Empty
}, TestContext.Current.CancellationToken)); }, TestContext.Current.CancellationToken));
} }
@ -336,9 +336,9 @@ public class RegionsTests : TestBase
await Assert.ThrowsAsync<ValidationException>(() => await Assert.ThrowsAsync<ValidationException>(() =>
mediator.Send(new UpdateRegionCommand() mediator.Send(new UpdateRegionCommand()
{ {
Uuid = Guid.TryParse(uuid, out var guid) ? guid : Guid.Empty, Guid = Guid.TryParse(uuid, out var guid) ? guid : Guid.Empty,
Name = "Name", Name = "Name",
CountryUuid = Guid.NewGuid() CountryGuid = Guid.NewGuid()
}, TestContext.Current.CancellationToken)); }, TestContext.Current.CancellationToken));
} }
@ -359,9 +359,9 @@ public class RegionsTests : TestBase
await Assert.ThrowsAsync<NotFoundException>(() => await Assert.ThrowsAsync<NotFoundException>(() =>
mediator.Send(new UpdateRegionCommand() mediator.Send(new UpdateRegionCommand()
{ {
Uuid = Guid.NewGuid(), Guid = Guid.NewGuid(),
Name = "Different Name", Name = "Different Name",
CountryUuid = addCountryResult.Uuid CountryGuid = addCountryResult.Uuid
}, TestContext.Current.CancellationToken)); }, TestContext.Current.CancellationToken));
} }
@ -383,15 +383,15 @@ public class RegionsTests : TestBase
new AddRegionCommand() new AddRegionCommand()
{ {
Name = "Name", Name = "Name",
CountryUuid = addCountryResult.Uuid CountryGuid = addCountryResult.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
await Assert.ThrowsAsync<NotFoundException>(() => await Assert.ThrowsAsync<NotFoundException>(() =>
mediator.Send(new UpdateRegionCommand() mediator.Send(new UpdateRegionCommand()
{ {
Uuid = addCountryResult.Uuid, Guid = addCountryResult.Uuid,
Name = "Different Name", Name = "Different Name",
CountryUuid = Guid.NewGuid() CountryGuid = Guid.NewGuid()
}, TestContext.Current.CancellationToken)); }, TestContext.Current.CancellationToken));
} }
@ -443,19 +443,19 @@ public class RegionsTests : TestBase
new AddRegionCommand() new AddRegionCommand()
{ {
Name = "Name", Name = "Name",
CountryUuid = addCountryResult.Uuid CountryGuid = addCountryResult.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
await mediator.Send( await mediator.Send(
new DeleteRegionCommand() new DeleteRegionCommand()
{ {
Uuid = addRegionResult.Uuid, Guid = addRegionResult.Uuid,
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
await Assert.ThrowsAsync<NotFoundException>(() => await Assert.ThrowsAsync<NotFoundException>(() =>
mediator.Send(new GetRegionQuery() mediator.Send(new GetRegionQuery()
{ {
Uuid = addRegionResult.Uuid, Guid = addRegionResult.Uuid,
}, TestContext.Current.CancellationToken)); }, TestContext.Current.CancellationToken));
} }
@ -473,7 +473,7 @@ public class RegionsTests : TestBase
await Assert.ThrowsAsync<ValidationException>(() => await Assert.ThrowsAsync<ValidationException>(() =>
mediator.Send(new DeleteRegionCommand() mediator.Send(new DeleteRegionCommand()
{ {
Uuid = Guid.TryParse(uuid, out var guid) ? guid : Guid.Empty Guid = Guid.TryParse(uuid, out var guid) ? guid : Guid.Empty
}, TestContext.Current.CancellationToken)); }, TestContext.Current.CancellationToken));
} }
@ -488,7 +488,7 @@ public class RegionsTests : TestBase
await Assert.ThrowsAsync<NotFoundException>(() => await Assert.ThrowsAsync<NotFoundException>(() =>
mediator.Send(new DeleteRegionCommand() mediator.Send(new DeleteRegionCommand()
{ {
Uuid = Guid.NewGuid() Guid = Guid.NewGuid()
}, TestContext.Current.CancellationToken)); }, TestContext.Current.CancellationToken));
} }
@ -544,13 +544,13 @@ public class RegionsTests : TestBase
new AddRegionCommand() new AddRegionCommand()
{ {
Name = regionName, Name = regionName,
CountryUuid = addCountryResult.Uuid CountryGuid = addCountryResult.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
var getRegionResult = await mediator.Send( var getRegionResult = await mediator.Send(
new GetRegionQuery() new GetRegionQuery()
{ {
Uuid = addRegionResult.Uuid, Guid = addRegionResult.Uuid,
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
Assert.NotNull(getRegionResult); Assert.NotNull(getRegionResult);
@ -577,7 +577,7 @@ public class RegionsTests : TestBase
mediator.Send( mediator.Send(
new GetRegionQuery() new GetRegionQuery()
{ {
Uuid = Guid.TryParse(uuid, out var guid) ? guid : Guid.Empty Guid = Guid.TryParse(uuid, out var guid) ? guid : Guid.Empty
}, TestContext.Current.CancellationToken)); }, TestContext.Current.CancellationToken));
} }
@ -593,7 +593,7 @@ public class RegionsTests : TestBase
mediator.Send( mediator.Send(
new GetRegionQuery() new GetRegionQuery()
{ {
Uuid = Guid.NewGuid() Guid = Guid.NewGuid()
}, TestContext.Current.CancellationToken)); }, TestContext.Current.CancellationToken));
} }
@ -657,14 +657,14 @@ public class RegionsTests : TestBase
new AddRegionCommand() new AddRegionCommand()
{ {
Name = regionName1, Name = regionName1,
CountryUuid = addCountryResult1.Uuid CountryGuid = addCountryResult1.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
var addRegionResult2 = await mediator.Send( var addRegionResult2 = await mediator.Send(
new AddRegionCommand() new AddRegionCommand()
{ {
Name = regionName2, Name = regionName2,
CountryUuid = addCountryResult2.Uuid CountryGuid = addCountryResult2.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
var getRegionsResult = await mediator.Send( var getRegionsResult = await mediator.Send(
@ -782,14 +782,14 @@ public class RegionsTests : TestBase
new AddRegionCommand() new AddRegionCommand()
{ {
Name = regionName1, Name = regionName1,
CountryUuid = addCountryResult1.Uuid CountryGuid = addCountryResult1.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
var addRegionResult2 = await mediator.Send( var addRegionResult2 = await mediator.Send(
new AddRegionCommand() new AddRegionCommand()
{ {
Name = regionName2, Name = regionName2,
CountryUuid = addCountryResult2.Uuid CountryGuid = addCountryResult2.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
var getRegionsResult = await mediator.Send( var getRegionsResult = await mediator.Send(
@ -850,14 +850,14 @@ public class RegionsTests : TestBase
new AddRegionCommand() new AddRegionCommand()
{ {
Name = regionName1, Name = regionName1,
CountryUuid = addCountryResult1.Uuid CountryGuid = addCountryResult1.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
var addRegionResult2 = await mediator.Send( var addRegionResult2 = await mediator.Send(
new AddRegionCommand() new AddRegionCommand()
{ {
Name = regionName2, Name = regionName2,
CountryUuid = addCountryResult2.Uuid CountryGuid = addCountryResult2.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
var getRegionsResult = await mediator.Send( var getRegionsResult = await mediator.Send(
@ -918,14 +918,14 @@ public class RegionsTests : TestBase
new AddRegionCommand() new AddRegionCommand()
{ {
Name = regionName1, Name = regionName1,
CountryUuid = addCountryResult1.Uuid CountryGuid = addCountryResult1.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
var addRegionResult2 = await mediator.Send( var addRegionResult2 = await mediator.Send(
new AddRegionCommand() new AddRegionCommand()
{ {
Name = regionName2, Name = regionName2,
CountryUuid = addCountryResult2.Uuid CountryGuid = addCountryResult2.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
var getRegionsResult = await mediator.Send( var getRegionsResult = await mediator.Send(
@ -987,21 +987,21 @@ public class RegionsTests : TestBase
new AddRegionCommand() new AddRegionCommand()
{ {
Name = regionName1, Name = regionName1,
CountryUuid = addCountryResult1.Uuid CountryGuid = addCountryResult1.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
var addRegionResult2 = await mediator.Send( var addRegionResult2 = await mediator.Send(
new AddRegionCommand() new AddRegionCommand()
{ {
Name = regionName2, Name = regionName2,
CountryUuid = addCountryResult2.Uuid CountryGuid = addCountryResult2.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
var addRegionResult3 = await mediator.Send( var addRegionResult3 = await mediator.Send(
new AddRegionCommand() new AddRegionCommand()
{ {
Name = regionName3, Name = regionName3,
CountryUuid = addCountryResult2.Uuid CountryGuid = addCountryResult2.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
var getRegionsResult = await mediator.Send( var getRegionsResult = await mediator.Send(
@ -1009,7 +1009,7 @@ public class RegionsTests : TestBase
{ {
PageNumber = 1, PageNumber = 1,
PageSize = 10, PageSize = 10,
CountryUuid = addCountryResult1.Uuid CountryGuid = addCountryResult1.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
Assert.NotNull(getRegionsResult); Assert.NotNull(getRegionsResult);
@ -1036,7 +1036,7 @@ public class RegionsTests : TestBase
{ {
PageNumber = 1, PageNumber = 1,
PageSize = 10, PageSize = 10,
CountryUuid = addCountryResult2.Uuid CountryGuid = addCountryResult2.Uuid
}, TestContext.Current.CancellationToken); }, TestContext.Current.CancellationToken);
Assert.NotNull(getRegionsResult); Assert.NotNull(getRegionsResult);