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

Cl/reset wire in use case #22

Merged
merged 4 commits into from
Jul 23, 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
6 changes: 6 additions & 0 deletions Dfe.Data.SearchPrototype.sln
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dfe.Data.SearchPrototype.Web.Tests", "Dfe.Data.SearchPrototype\Web\Tests\Dfe.Data.SearchPrototype.Web.Tests.csproj", "{A6882653-52E1-472D-97F4-03C0FB8D0B2F}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "NuGet", "NuGet", "{0D4ACC06-9FA9-422A-8F92-92B565879E16}"
ProjectSection(SolutionItems) = preProject
NuGet\DfE.Data.ComponentLibrary.CleanArchitecture.2.0.37-beta-ci-20240610-104522.nupkg = NuGet\DfE.Data.ComponentLibrary.CleanArchitecture.2.0.37-beta-ci-20240610-104522.nupkg
NuGet\DfE.Data.ComponentLibrary.CrossCuttingConcerns.Mapping.2.0.37-beta-ci-20240610-104522.nupkg = NuGet\DfE.Data.ComponentLibrary.CrossCuttingConcerns.Mapping.2.0.37-beta-ci-20240610-104522.nupkg
NuGet\DfE.Data.ComponentLibrary.CrossCuttingConcerns.Json.2.0.37-beta-ci-20240610-104522.nupkg = NuGet\DfE.Data.ComponentLibrary.CrossCuttingConcerns.Json.2.0.37-beta-ci-20240610-104522.nupkg
NuGet\DfE.Data.ComponentLibrary.Infrastructure.CognitiveSearch.2.0.37-beta-ci-20240610-104522.nupkg = NuGet\DfE.Data.ComponentLibrary.Infrastructure.CognitiveSearch.2.0.37-beta-ci-20240610-104522.nupkg
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dfe.Data.SearchPrototype.Infrastructure", "Dfe.Data.SearchPrototype\Infrastructure\Dfe.Data.SearchPrototype.Infrastructure.csproj", "{95EDB119-5238-451B-944A-84A1F8891171}"
EndProject
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
using Dfe.Data.SearchPrototype.Search;
using DfE.Data.ComponentLibrary.CrossCuttingConcerns.Mapping;

namespace Dfe.Data.SearchPrototype.Infrastructure.Mapping;
namespace Dfe.Data.SearchPrototype.Infrastructure.Mappers;

/// <summary>
/// Facilitates mapping from the received T:Azure.Search.Documents.Models.SearchResults
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using DfE.Data.ComponentLibrary.CrossCuttingConcerns.Mapping;

namespace Dfe.Data.SearchPrototype.Infrastructure.Mapping
namespace Dfe.Data.SearchPrototype.Infrastructure.Mappers
{
/// <summary>
/// Facilitates mapping from the received T:Dfe.Data.SearchPrototype.Search.Establishment
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using Azure.Search.Documents;
using DfE.Data.ComponentLibrary.CrossCuttingConcerns.Mapping;

namespace Dfe.Data.SearchPrototype.Infrastructure.Options.Mapping;
namespace Dfe.Data.SearchPrototype.Infrastructure.Options.Mappers;

/// <summary>
/// Concrete mapper implementation which translates the results returned from the internal
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
using Azure;
using Azure.Search.Documents.Models;
using Dfe.Data.SearchPrototype.Infrastructure.Mapping;
using Dfe.Data.SearchPrototype.Infrastructure.Mappers;
using Dfe.Data.SearchPrototype.Infrastructure.Tests.TestDoubles;
using Dfe.Data.SearchPrototype.Search;
using DfE.Data.ComponentLibrary.CrossCuttingConcerns.Mapping;
using FluentAssertions;
using Xunit;

namespace Dfe.Data.SearchPrototype.Infrastructure.Tests.Mapping;
namespace Dfe.Data.SearchPrototype.Infrastructure.Tests.Mappers;

public sealed class AzureSearchResponseToEstablishmentResultMapperTests
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using Dfe.Data.SearchPrototype.Infrastructure.Mapping;
using Dfe.Data.SearchPrototype.Infrastructure.Mappers;
using DfE.Data.ComponentLibrary.CrossCuttingConcerns.Mapping;
using FluentAssertions;
using Xunit;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
using Dfe.Data.SearchPrototype.Infrastructure.Options;
using Dfe.Data.SearchPrototype.Infrastructure.Options.Mapping;
using Dfe.Data.SearchPrototype.Infrastructure.Options.Mappers;
using Dfe.Data.SearchPrototype.Infrastructure.Tests.Options.TestDoubles;
using FluentAssertions;
using Xunit;

namespace Dfe.Data.SearchPrototype.Infrastructure.Tests.Options.Mapping;
namespace Dfe.Data.SearchPrototype.Infrastructure.Tests.Options.Mappers;

public sealed class SearchOptionsToAzureOptionsMapperTests
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public class ResultsToResponseMapper : IMapper<EstablishmentResults, SearchByKey
/// </returns>
public SearchByKeywordResponse MapFrom(EstablishmentResults input)
{
SearchByKeywordResponse response = new(input.Establishments);
SearchByKeywordResponse response = new(input.Establishments);

return response;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,21 @@ namespace Dfe.Data.SearchPrototype.SearchForEstablishments;
/// </summary>
public sealed class SearchByKeywordRequest
{
/// <summary>
/// The following arguments are passed via the constructor and used to create
/// an immutable instance of the T:Dfe.Data.SearchPrototype.Search.SearchContext.
/// </summary>
/// <param name="searchKeyword">
/// The string keyword used to search the collection specified.
/// </param>
/// <param name="targetCollection">
/// The target collection on which to invoke a search.
/// </param>
public SearchByKeywordRequest(string searchKeyword, string targetCollection)
{
Context = SearchContext.Create(searchKeyword, targetCollection);
}

/// <summary>
/// This property exposes the T:Dfe.Data.SearchPrototype.Search.SearchContext object
/// which encapsulates the criteria necessary to perform a valid search.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public sealed class SearchByKeywordResponse
/// <summary>
/// The readonly collection of T:Dfe.Data.SearchPrototype.Search.Establishment search results.
/// </summary>
public IReadOnlyCollection<Establishment> EstablishmentResults { get;}
public IReadOnlyCollection<Establishment>? EstablishmentResults { get;}

/// <summary>
/// The following argument is passed via the constructor and is not changeable
Expand All @@ -21,7 +21,7 @@ public sealed class SearchByKeywordResponse
/// <param name="establishments">
/// The readonly collection of T:Dfe.Data.SearchPrototype.Search.Establishment search results.
/// </param>
public SearchByKeywordResponse(IReadOnlyCollection<Establishment> establishments)
public SearchByKeywordResponse(IReadOnlyCollection<Establishment>? establishments)
{
EstablishmentResults = establishments;
}
Expand Down
14 changes: 14 additions & 0 deletions Dfe.Data.SearchPrototype/SearchForEstablishments/SearchContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,19 @@ public SearchContext(string searchKeyword, string targetCollection)
(string.IsNullOrWhiteSpace(targetCollection)) ?
throw new ArgumentNullException(nameof(targetCollection)) : targetCollection;
}

/// <summary>
/// Factory method to allow implicit creation of a T:Dfe.Data.SearchPrototype.Search.SearchContext instance.
/// </summary>
/// <param name="searchKeyword">
/// The keyword string which defines the search.
/// </param>
/// <param name="targetCollection">
/// The underlying collection on which to undertake the search.
/// </param>
/// <returns>
/// A configured T:Dfe.Data.SearchPrototype.Search.SearchContext instance.
/// </returns>
public static SearchContext Create(string searchKeyword, string targetCollection) => new(searchKeyword, targetCollection);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public void MapFrom_ValidInput_ReturnsCorrectResponse()
//assert.
response.Should().NotBeNull();
response.EstablishmentResults.Should().HaveCountGreaterThanOrEqualTo(1);
response.EstablishmentResults.First().Urn.Should().Be(input.Establishments.First().Urn);
response.EstablishmentResults.First().Name.Should().Be(input.Establishments.First().Name);
response.EstablishmentResults!.First().Urn.Should().Be(input.Establishments.First().Urn);
response.EstablishmentResults!.First().Name.Should().Be(input.Establishments.First().Name);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,7 @@ public SearchByKeywordUseCaseTests()
public async Task UseCase_ValidRequest_ReturnsResponse()
{
// arrange
SearchByKeywordRequest request = new()
{
Context = new(searchKeyword: "anything", targetCollection: "collection")
};
SearchByKeywordRequest request = new("searchkeyword", "target collection");

// act
SearchByKeywordResponse response = await _useCase.HandleRequest(request);
Expand All @@ -49,19 +46,4 @@ public Task UseCase_NullSearchByKeywordRequest_ThrowsArgumentNullException()
.ThrowAsync<ArgumentNullException>()
.WithMessage("Value cannot be null. (Parameter 'SearchByKeywordRequest')");
}

[Fact]
public Task UseCase_NullSearchContext_ThrowsArgumentNullException()
{
// arrange
SearchByKeywordRequest request = new();

// act, assert
return _useCase.Invoking(
async usecase => await usecase
.HandleRequest(request))
.Should()
.ThrowAsync<ArgumentNullException>()
.WithMessage("Value cannot be null. (Parameter 'SearchContext')");
}
}
84 changes: 53 additions & 31 deletions Dfe.Data.SearchPrototype/Web/Controllers/HomeController.cs
Original file line number Diff line number Diff line change
@@ -1,44 +1,66 @@
using Dfe.Data.SearchPrototype.SearchForEstablishments;
using Dfe.Data.SearchPrototype.Web.Models;
using DfE.Data.ComponentLibrary.CleanArchitecture.CleanArchitecture.Application.UseCase;
using DfE.Data.ComponentLibrary.CrossCuttingConcerns.Mapping;
using Microsoft.AspNetCore.Mvc;
using System.Diagnostics;

namespace Dfe.Data.SearchPrototype.Web.Controllers
namespace Dfe.Data.SearchPrototype.Web.Controllers;

/// <summary>
/// Controller responsible for allowing searching by keyword.
/// </summary>
public class HomeController : Controller
{
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
private readonly ILogger<HomeController> _logger;
private readonly IUseCase<SearchByKeywordRequest, SearchByKeywordResponse> _searchByKeywordUseCase;
private readonly IMapper<SearchByKeywordResponse, SearchResultsViewModel> _mapper;

public HomeController(ILogger<HomeController> logger)
{
_logger = logger;
}
/// <summary>
/// The following dependencies include the use-case which orchestrates the search functionality,
/// and the mapper which transforms from the use-case response to the view model.
/// </summary>
/// <param name="logger">
/// The concrete implementation of the T:Microsoft.Extensions.Logging.ILogger
/// defined within, and injected by the IOC container (defined within program.cs)
/// </param>
/// <param name="searchByKeywordUseCase">
/// The concrete implementation of the T:DfE.Data.ComponentLibrary.CleanArchitecture.CleanArchitecture.Application.UseCase.IUseCase<SearchByKeywordRequest, SearchByKeywordResponse>
/// defined within, and injected by the IOC container (defined within program.cs)
/// </param>
/// <param name="mapper">
/// The concrete implementation of the T:DfE.Data.ComponentLibrary.CrossCuttingConcerns.Mapping.IMapper<EstablishmentResults, SearchByKeywordResponse>
/// defined within, and injected by the IOC container (defined within program.cs)
/// </param>
public HomeController(
ILogger<HomeController> logger,
IUseCase<SearchByKeywordRequest, SearchByKeywordResponse> searchByKeywordUseCase,
IMapper<SearchByKeywordResponse, SearchResultsViewModel> mapper)
{
_logger = logger;
_searchByKeywordUseCase = searchByKeywordUseCase;
_mapper = mapper;
}

public IActionResult Index()
/// <summary>
/// The action method that composes the view model based on the search keyword.
/// </summary>
/// <param name="searchKeyWord">search keyword</param>
/// <returns>
/// An IActionResult contract that represents the result of this action method.
/// </returns>
public async Task<IActionResult> Index(string searchKeyWord)
{
if (string.IsNullOrEmpty(searchKeyWord))
{
return View();
}
ViewBag.SearchQuery = searchKeyWord;

public IActionResult SearchResults(string searchKeyWord)
{
if (string.IsNullOrEmpty(searchKeyWord))
{
return View("Index");
}
ViewBag.SearchQuery = searchKeyWord;

var searchItems = new SearchResultsViewModel();
return View(searchItems);
}

public IActionResult Privacy()
{
return View();
}
SearchByKeywordResponse response =
await _searchByKeywordUseCase.HandleRequest(
new SearchByKeywordRequest(searchKeyWord, "establishments"));

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error()
{
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
SearchResultsViewModel viewModel = _mapper.MapFrom(response);
return View(viewModel);
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<RootNamespace>Dfe.Data.SearchPrototype.Web</RootNamespace>
<UserSecretsId>48e8e924-5ceb-41b1-9a4a-b16e14f1a95f</UserSecretsId>
</PropertyGroup>

<ItemGroup>
Expand All @@ -20,9 +21,13 @@

<ItemGroup>
<ProjectReference Include="..\Dfe.Data.SearchPrototype.csproj" />
<ProjectReference Include="..\Infrastructure\Dfe.Data.SearchPrototype.Infrastructure.csproj" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="DfE.Data.ComponentLibrary.CleanArchitecture" Version="2.0.37-beta-CI-20240610-104522" />
<PackageReference Include="DfE.Data.ComponentLibrary.Infrastructure.CognitiveSearch" Version="2.0.37-beta-CI-20240610-104522" />
<PackageReference Include="DfE.Data.ComponentLibrary.CrossCuttingConcerns.Mapping" Version="2.0.37-beta-CI-20240610-104522" />
<PackageReference Include="DfE.Data.ComponentLibrary.CrossCuttingConcerns.Json" Version="2.0.37-beta-CI-20240610-104522" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using Dfe.Data.SearchPrototype.Search;
using Dfe.Data.SearchPrototype.SearchForEstablishments;
using Dfe.Data.SearchPrototype.Web.Models;
using DfE.Data.ComponentLibrary.CrossCuttingConcerns.Mapping;

namespace Dfe.Data.SearchPrototype.Web.Mappers;

/// <summary>
/// Facilitates mapping from the received T:Dfe.Data.SearchPrototype.SearchForEstablishments.SearchByKeywordResponse
/// into the required T:Dfe.Data.SearchPrototype.Web.Models.SearchResultsViewModel object.
/// </summary>
public class SearchByKeywordResponseToViewModelMapper : IMapper<SearchByKeywordResponse, SearchResultsViewModel>
{
/// <summary>
/// The mapping input is the use-case search response T:Dfe.Data.SearchPrototype.SearchForEstablishments.SearchByKeywordResponse
/// and if any results are contained within the response a new P:Dfe.Data.SearchPrototype.Web.Models.SearchResultsViewModel.SearchItems
/// instance is created.
/// </summary>
/// <param name="input">
/// A configured T:Dfe.Data.SearchPrototype.SearchForEstablishments.SearchByKeywordResponse instance
/// </param>
/// <returns>
/// A configured T:Dfe.Data.SearchPrototype.Web.Models.SearchResultsViewModel instance
/// </returns>
public SearchResultsViewModel MapFrom(SearchByKeywordResponse input)
{
SearchResultsViewModel viewModel = new();

if (input.EstablishmentResults != null)
{
viewModel.SearchItems = new();
foreach (var establishment in input.EstablishmentResults)
{
viewModel.SearchItems.Add(new SearchItemViewModel
{
Urn = establishment.Urn,
Name = establishment.Name
});
}
}
return viewModel;
}
}

This file was deleted.

9 changes: 0 additions & 9 deletions Dfe.Data.SearchPrototype/Web/Models/ErrorViewModel.cs

This file was deleted.

Loading