Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add education phase to search results #27

Merged
merged 5 commits into from
Jul 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions Dfe.Data.SearchPrototype/Infrastructure/Establishment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,19 @@ public class Establishment
/// The type of the establishment of the retrieved establishment result
/// </summary>
public string? TYPEOFESTABLISHMENTNAME { get; set; }
/// <summary>
/// "1" if the establishment includes the Primary phase of education
/// "0" if the establishment does not include the Primary phase of education
/// </summary>
public string? ISPRIMARY { get; set; }
/// <summary>
/// "1" if the establishment includes the secondary phase of education
/// "0" if the establishment does not include the secondary phase of education
/// </summary>
public string? ISSECONDARY { get; set; }
/// <summary>
/// "1" if the establishment includes the post 16 phase of education
/// "0" if the establishment does not include the post 16 phase of education
/// </summary>
public string? ISPOST16 { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using Dfe.Data.SearchPrototype.Common.Mappers;
using Dfe.Data.SearchPrototype.SearchForEstablishments;

namespace Dfe.Data.SearchPrototype.Infrastructure.Mappers;

/// <summary>
/// Facilitates mapping from the received T:Dfe.Data.SearchPrototype.Infrastructure.Establishment
/// into the required T:Dfe.Data.SearchPrototype.SearchForEstablishments.EducationPhase object.
/// </summary>
public class AzureSearchResultToEducationPhaseMapper : IMapper<Infrastructure.Establishment, EducationPhase>
{
/// <summary>
/// The following mapping dependency provides the functionality to map from a raw Azure
/// search result, to a configured T:Dfe.Data.SearchPrototype.SearchForEstablishments.EducationPhase
/// instance, the complete implementation of which is defined in the IOC container.
/// </summary>
/// <param name="input">
/// The raw T:Dfe.Data.SearchPrototype.Infrastructure.Establishment used to map from.
/// </param>
/// <returns>
/// The configured T:Dfe.Data.SearchPrototype.SearchForEstablishments.EducationPhase instance expected.
/// </returns>
public EducationPhase MapFrom(Establishment input)
{
if (string.IsNullOrEmpty(input.ISPRIMARY))
{
throw new ArgumentException(nameof(input.ISPRIMARY));
}
if (string.IsNullOrEmpty(input.ISSECONDARY))
{
throw new ArgumentException(nameof(input.ISSECONDARY));
}
if (string.IsNullOrEmpty(input.ISPOST16))
{
throw new ArgumentException(nameof(input.ISPOST16));
}
return new(
isPrimary: input.ISPRIMARY,
isSecondary: input.ISSECONDARY,
isPost16: input.ISPOST16);

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,19 @@ namespace Dfe.Data.SearchPrototype.Infrastructure.Mappers;
public sealed class AzureSearchResultToEstablishmentMapper : IMapper<Establishment, SearchForEstablishments.Establishment>
{
private readonly IMapper<Establishment, Address> _addressMapper;
private readonly IMapper<Establishment, EducationPhase> _educationPhaseMapper;

/// <summary>
/// Constructor
/// </summary>
/// <param name="addressMapper">Address mapper instance</param>
public AzureSearchResultToEstablishmentMapper(IMapper<Establishment, Address> addressMapper)
/// <param name="educationPhaseMapper">EducationPhase mapper instance</param>
public AzureSearchResultToEstablishmentMapper(
IMapper<Establishment, Address> addressMapper,
IMapper<Establishment, EducationPhase> educationPhaseMapper)
{
_addressMapper = addressMapper;
_educationPhaseMapper = educationPhaseMapper;
}

/// <summary>
Expand All @@ -43,6 +48,7 @@ public SearchForEstablishments.Establishment MapFrom(Establishment input)
return new(urn: input.id,
name: input.ESTABLISHMENTNAME,
address: _addressMapper.MapFrom(input),
establishmentType: input.TYPEOFESTABLISHMENTNAME);
establishmentType: input.TYPEOFESTABLISHMENTNAME,
educationPhase: _educationPhaseMapper.MapFrom(input));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,15 @@ public sealed class AzureSearchResponseToEstablishmentResultMapperTests
IMapper<Establishment, SearchForEstablishments.Establishment> _searchResultToEstablishmentMapper;
IMapper<Response<SearchResults<Establishment>>, EstablishmentResults> _searchResponseMapper;
IMapper<Establishment, SearchForEstablishments.Address> _searchResultToAddressMapper;
IMapper<Establishment, SearchForEstablishments.EducationPhase> _searchResultToEducationPhaseMapper;

public AzureSearchResponseToEstablishmentResultMapperTests()
{
_searchResultToEducationPhaseMapper = new AzureSearchResultToEducationPhaseMapper();
_searchResultToAddressMapper = new AzureSearchResultToAddressMapper();
_searchResultToEstablishmentMapper =
new AzureSearchResultToEstablishmentMapper(_searchResultToAddressMapper);
_searchResponseMapper =
new AzureSearchResultToEstablishmentMapper(_searchResultToAddressMapper, _searchResultToEducationPhaseMapper);
_searchResponseMapper =
new AzureSearchResponseToEstablishmentResultMapper(_searchResultToEstablishmentMapper);
}

Expand All @@ -40,7 +42,7 @@ public void MapFrom_WithValidSearchResults_ReturnsConfiguredEstablishments()
// assert
mappedResult.Should().NotBeNull();
mappedResult.Establishments.Should().HaveCount(searchResultDocuments.Count());
foreach(var searchResult in searchResultDocuments)
foreach (var searchResult in searchResultDocuments)
{
searchResult.ShouldHaveMatchingMappedEstablishment(mappedResult);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@ public sealed class AzureSearchResultToEstablishmentMapperTests
{
IMapper<Establishment, SearchForEstablishments.Establishment> _establishmentMapper;
IMapper<Establishment, SearchForEstablishments.Address> _addressMapper;
IMapper<Establishment, SearchForEstablishments.EducationPhase> _educationPhaseMapper;

public AzureSearchResultToEstablishmentMapperTests()
{
_addressMapper = new AzureSearchResultToAddressMapper();
_establishmentMapper = new AzureSearchResultToEstablishmentMapper(_addressMapper);
_educationPhaseMapper = new AzureSearchResultToEducationPhaseMapper();
_establishmentMapper = new AzureSearchResultToEstablishmentMapper(_addressMapper, _educationPhaseMapper);
}

[Fact]
Expand All @@ -35,7 +37,9 @@ public void MapFrom_With_Valid_Search_Result_Returns_Configured_Establishment()
result.Address.Address3.Should().Be(establishmentFake.ADDRESS3);
result.Address.Town.Should().Be(establishmentFake.TOWN);
result.Address.Postcode.Should().Be(establishmentFake.POSTCODE);
result.EstablishmentType.Should().Be(establishmentFake.TYPEOFESTABLISHMENTNAME);
result.EducationPhase.IsPrimary.Should().Be(establishmentFake.ISPRIMARY == "1" ? true : false);
result.EducationPhase.IsSecondary.Should().Be(establishmentFake.ISSECONDARY == "1" ? true : false);
result.EducationPhase.IsPost16.Should().Be(establishmentFake.ISPOST16 == "1" ? true : false);
}

[Fact]
Expand Down Expand Up @@ -70,7 +74,7 @@ public void MapFrom_With_Null_id_Throws_Expected_Argument_Exception()
.Invoking(mapper =>
mapper.MapFrom(establishmentFake))
.Should()
.Throw<ArgumentException>().WithMessage("Value cannot be null. (Parameter 'id')");
.Throw<ArgumentException>();
}

[Fact]
Expand All @@ -93,4 +97,26 @@ public void MapFrom_With_Null_Name_Throws_Expected_Argument_Exception()
.Should()
.Throw<ArgumentException>();
}
}

[Fact]
public void MapFrom_With_NullIsPrimary_Throws_Expected_Argument_Exception()
{
// arrange.
const string EstablishmentId = "123456";

// act.
var establishmentFake = new Establishment()
{
id = EstablishmentId,
ESTABLISHMENTNAME = "Test Establishment",
ISPRIMARY = null!
};

// act.
_establishmentMapper
.Invoking(mapper =>
mapper.MapFrom(establishmentFake))
.Should()
.Throw<ArgumentException>();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,16 @@ public static Establishment Create()
_ => new Bogus.Faker().Address.ZipCode())
.RuleFor(
establishment => establishment.TYPEOFESTABLISHMENTNAME,
_ => new Bogus.Faker().Random.Word());
_ => new Bogus.Faker().Random.Word())
.RuleFor(
establishment => establishment.ISPRIMARY,
_ => new Bogus.Faker().Random.Number(0, 1).ToString())
.RuleFor(
establishment => establishment.ISSECONDARY,
_ => new Bogus.Faker().Random.Number(0, 1).ToString())
.RuleFor(
establishment => establishment.ISPOST16,
_ => new Bogus.Faker().Random.Number(0, 1).ToString());
return searchResultFaker.Generate();
}
}
47 changes: 47 additions & 0 deletions Dfe.Data.SearchPrototype/SearchForEstablishments/EducationPhase.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
namespace Dfe.Data.SearchPrototype.SearchForEstablishments;

/// <summary>
/// Object used to encapsulate the education phase of the retrieved establishment.
/// </summary>
public class EducationPhase
{
/// <summary>
/// true if the establishment includes the Primary phase of education
/// false if the establishment does not include the Primary phase of education
/// </summary>
public bool IsPrimary { get; }

/// <summary>
/// true if the establishment includes the secondary phase of education
/// false if the establishment does not include the secondary phase of education
/// </summary>
public bool IsSecondary { get; }

/// <summary>
/// true if the establishment includes the post 16 phase of education
/// false if the establishment does not include the post 16 phase of education
/// </summary>
public bool IsPost16 { get; }

/// <summary>
/// Establishes an immutable education phase of establishment instance via the constructor arguments specified.
/// </summary>
///<param name="isPrimary">
/// "1" if the establishment includes the Primary phase of education
/// "0" if the establishment does not include the Primary phase of education
/// </param>
/// <param name="isSecondary">
/// "1" if the establishment includes the secondary phase of education
/// "0" if the establishment does not include the secondary phase of education
/// </param>
/// <param name="isPost16">
/// "1" if the establishment includes the post 16 phase of education
/// "0" if the establishment does not include the post 16 phase of education
/// </param>
public EducationPhase(string isPrimary, string isSecondary, string isPost16)
{
IsPrimary = isPrimary == "1" ? true : false;
IsSecondary = isSecondary == "1" ? true : false;
IsPost16 = isPost16 == "1" ? true : false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ public class Establishment
/// The read-only type of the establishment.
/// </summary>
public string EstablishmentType { get; }
public EducationPhase EducationPhase { get; }

/// <summary>
/// Establishes an immutable establishment instance via the constructor arguments specified.
Expand All @@ -37,11 +38,12 @@ public class Establishment
/// <param name="establishmentType">
/// The type of the given establishment.
/// </param>
public Establishment(string urn, string name, Address address, string establishmentType)
public Establishment(string urn, string name, Address address, string establishmentType, EducationPhase educationPhase)
{
Urn = urn;
Name = name;
Address = address;
EstablishmentType = establishmentType;
EducationPhase = educationPhase;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ private static string GetEstablishmentPostcodeFake() =>
private static string GetEstablishmentTypeFake() =>
new Faker().Random.Word();

private static string GetEstablishmentEducationPhaseFake() =>
new Faker().Random.Int(0, 1).ToString();

public static Establishment Create()
{
var address = new Address()
Expand All @@ -41,11 +44,17 @@ public static Establishment Create()
Postcode = GetEstablishmentPostcodeFake()
};

var educationPhase = new EducationPhase(
isPrimary: GetEstablishmentEducationPhaseFake(),
isSecondary: GetEstablishmentEducationPhaseFake(),
isPost16: GetEstablishmentEducationPhaseFake());

return new(
urn: GetEstablishmentIdentifierFake(),
name: GetEstablishmentNameFake(),
address: address,
establishmentType: GetEstablishmentTypeFake()
establishmentType: GetEstablishmentTypeFake(),
educationPhase: educationPhase
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ public SearchResultsViewModel MapFrom(SearchByKeywordResponse input)
Address3 = establishment.Address.Address3,
Postcode = establishment.Address.Postcode
},
EducationPhase = new EducationPhaseViewModel()
{
IsPrimary = establishment.EducationPhase.IsPrimary,
IsSecondary = establishment.EducationPhase.IsSecondary,
IsPost16 = establishment.EducationPhase.IsPost16
},
EstablishmentType = establishment.EstablishmentType
});
}
Expand Down
17 changes: 17 additions & 0 deletions Dfe.Data.SearchPrototype/Web/Models/AddressViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,21 @@ public class AddressViewModel
/// Postcode
/// </summary>
public string? Postcode { get; set; }

/// <summary>
/// Establishment address.
/// </summary>
/// <returns>
/// Address formatted as a display-friendly string
/// </returns>
public string AddressAsString()
{
var addressComponents
= new[] { Street, Locality, Address3, Town, Postcode }
.Where(addressComponent => !string.IsNullOrEmpty(addressComponent))
.ToArray();
var readableAddress = string.Join(", ", addressComponents);

return readableAddress;
}
}
46 changes: 46 additions & 0 deletions Dfe.Data.SearchPrototype/Web/Models/EducationPhaseViewModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using Dfe.Data.SearchPrototype.SearchForEstablishments;

namespace Dfe.Data.SearchPrototype.Web.Models;

/// <summary>
/// A view model representation of an education phase from a single search result.
/// </summary>
public class EducationPhaseViewModel
{
/// <summary>
/// true if the establishment includes the Primary phase of education
/// false if the establishment does not include the Primary phase of education
/// </summary>
public bool IsPrimary { get; set; }
/// <summary>
/// true if the establishment includes the secondary phase of education
/// false if the establishment does not include the secondary phase of education
/// </summary>
public bool IsSecondary { get; set; }
/// <summary>
/// true if the establishment includes the post 16 phase of education
/// false if the establishment does not include the post 16 phase of education
/// </summary>
public bool IsPost16 { get; set; }

/// <summary>
/// Establishment education phase
/// </summary>
/// <returns>
/// Education phase formatted as a display-friendly string
/// </returns>
public string EducationPhaseAsString()
{
var mapEducationPhaseCodeToString = new Dictionary<string, bool>
{
{"Primary", IsPrimary },
{"Secondary", IsSecondary },
{"16 plus", IsPost16 }
};
var educationPhaseComponents = mapEducationPhaseCodeToString
.Where(educationPhaseCode => educationPhaseCode.Value == true)
.Select(educationPhaseCode => educationPhaseCode.Key);

return string.Join(", ", educationPhaseComponents);
}
}
Loading