Skip to content

Commit

Permalink
Merge branch 'main' into feat/client3
Browse files Browse the repository at this point in the history
  • Loading branch information
mamartinezmejia committed Oct 4, 2024
2 parents e235bb4 + c1af547 commit 9b989dc
Show file tree
Hide file tree
Showing 6 changed files with 190 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import ca.bc.gov.app.dto.AddressSearchDto;
import ca.bc.gov.app.dto.ContactSearchDto;
import ca.bc.gov.app.dto.ForestClientDto;
import ca.bc.gov.app.dto.PredictiveSearchResultDto;
import ca.bc.gov.app.service.ClientSearchService;
import io.micrometer.observation.annotation.Observed;
import java.time.LocalDate;
Expand Down Expand Up @@ -136,6 +137,14 @@ public Flux<ForestClientDto> findByClientName(
return service.findByClientName(clientName);
}

@GetMapping("/predictive")
public Flux<PredictiveSearchResultDto> findByPredictiveSearch(
@RequestParam String value
){
log.info("Receiving request to search by predictive search {}", value);
return service.predictiveSearch(value);
}



}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package ca.bc.gov.app.dto;

import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.apache.commons.lang3.StringUtils;

public record PredictiveSearchResultDto(
String clientNumber,
String clientAcronym,
String clientName,
String clientFirstName,
String doingBusinessAs,
String clientIdentification,
String clientMiddleName,
String city,
String clientType,
String statusCode,
long score
) {

@JsonProperty("name")
public String name() {
if (StringUtils.isNotBlank(this.clientFirstName)) {
return Stream.of(this.clientFirstName, this.clientMiddleName, this.clientName)
.filter(Objects::nonNull)
.map(String::trim)
.collect(Collectors.joining(" "));
} else {
return this.clientName;
}
}

}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package ca.bc.gov.app.repository;

import ca.bc.gov.app.dto.PredictiveSearchResultDto;
import ca.bc.gov.app.entity.ForestClientEntity;
import java.time.LocalDateTime;
import org.springframework.data.domain.Pageable;
import org.springframework.data.r2dbc.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.data.repository.query.ReactiveQueryByExampleExecutor;
Expand All @@ -16,6 +18,8 @@ public interface ForestClientRepository extends ReactiveCrudRepository<ForestCli
ReactiveQueryByExampleExecutor<ForestClientEntity>,
ReactiveSortingRepository<ForestClientEntity, String> {

Flux<ForestClientEntity> findBy(Pageable page);

@Query("""
SELECT * FROM FOREST_CLIENT x
WHERE (UPPER(x.REGISTRY_COMPANY_TYPE_CODE) || x.CORP_REGN_NMBR) = UPPER(:registrationNumber)
Expand Down Expand Up @@ -56,4 +60,46 @@ Flux<ForestClientEntity> findClientByIncorporationOrName(

Mono<ForestClientEntity> findByClientNumber(String clientNumber);

@Query("""
SELECT
c.client_number,
c.CLIENT_ACRONYM as client_acronym,
c.client_name,
c.legal_first_name as client_first_name,
dba.doing_business_as_name as doing_business_as,
c.client_identification,
c.legal_middle_name as client_middle_name,
cl.city as city,
ctc.description as client_type,
c.client_status_code as status_code,
(
CASE WHEN c.client_number = :value THEN 112 ELSE 0 END +
CASE WHEN c.CLIENT_ACRONYM = :value THEN 111 ELSE 0 END +
(UTL_MATCH.JARO_WINKLER_SIMILARITY(c.client_name, :value)+10) +
(UTL_MATCH.JARO_WINKLER_SIMILARITY(c.legal_first_name, :value)+9) +
(UTL_MATCH.JARO_WINKLER_SIMILARITY(dba.doing_business_as_name, :value)+7) +
CASE WHEN c.client_identification = :value THEN 106 ELSE 0 END +
UTL_MATCH.JARO_WINKLER_SIMILARITY(c.legal_middle_name, :value)
) AS score
FROM the.forest_client c
LEFT JOIN the.CLIENT_DOING_BUSINESS_AS dba ON c.client_number = dba.client_number
LEFT JOIN the.CLIENT_TYPE_CODE ctc ON c.client_type_code = ctc.client_type_code
LEFT JOIN the.CLIENT_LOCATION cl ON c.client_number = cl.client_number
WHERE
(
c.client_number = :value
OR c.CLIENT_ACRONYM = :value
OR UTL_MATCH.JARO_WINKLER_SIMILARITY(c.client_name,:value) >= 90
OR c.client_name LIKE '%' || :value || '%'
OR UTL_MATCH.JARO_WINKLER_SIMILARITY(c.legal_first_name,:value) >= 90
OR UTL_MATCH.JARO_WINKLER_SIMILARITY(dba.doing_business_as_name,:value) >= 90
OR dba.doing_business_as_name LIKE '%' || :value || '%'
OR c.client_identification = :value
OR UTL_MATCH.JARO_WINKLER_SIMILARITY(c.legal_middle_name,:value) >= 90
) AND
cl.CLIENT_LOCN_CODE = '00'
ORDER BY score DESC
FETCH FIRST 5 ROWS ONLY""")
Flux<PredictiveSearchResultDto> findByPredictiveSearch(String value);

}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import ca.bc.gov.app.dto.AddressSearchDto;
import ca.bc.gov.app.dto.ContactSearchDto;
import ca.bc.gov.app.dto.ForestClientDto;
import ca.bc.gov.app.dto.PredictiveSearchResultDto;
import ca.bc.gov.app.entity.ClientDoingBusinessAsEntity;
import ca.bc.gov.app.entity.ForestClientContactEntity;
import ca.bc.gov.app.entity.ForestClientEntity;
Expand Down Expand Up @@ -531,6 +532,20 @@ public Flux<ForestClientDto> findByClientName(String clientName) {
);
}

public Flux<PredictiveSearchResultDto> predictiveSearch(String value){
log.info("Predictive search for value {}", value);
if (StringUtils.isBlank(value)) {
return Flux.error(new MissingRequiredParameterException("value"));
}
return forestClientRepository
.findByPredictiveSearch(value.toUpperCase())
.doOnNext(dto -> log.info("Found predictive search for value {} as {} {} with score {}",
value,
dto.clientNumber(), dto.name(), dto.score()
)
);
}

/**
* This method is used to search for clients based on a given query criteria, page number, and
* page size. It first creates a query based on the provided query criteria. Then, it counts the
Expand Down Expand Up @@ -563,5 +578,4 @@ private <T> Flux<T> searchClientByQuery(
.doOnNext(client -> log.info("Found client for query {}", queryCriteria));
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,44 @@ void shouldSearchClientName(

}

@ParameterizedTest
@MethodSource("byPredictive")
@DisplayName("Search using the predictive search")
void shouldSearchPredicatively(
String searchValue,
String expectedClientNumber,
String expectedClientName
) {

ResponseSpec response =
client
.get()
.uri(uriBuilder ->
uriBuilder
.path("/api/search/predictive")
.queryParam("value", Optional.ofNullable(searchValue))
.build(new HashMap<>())
)
.header("Content-Type", MediaType.APPLICATION_JSON_VALUE)
.exchange();

if (StringUtils.isNotBlank(expectedClientNumber)) {
response
.expectStatus().isOk()
.expectBody()
.jsonPath("$[0].clientNumber").isNotEmpty()
.jsonPath("$[0].clientNumber").isEqualTo(expectedClientNumber)
.jsonPath("$[0].clientName").isNotEmpty()
.jsonPath("$[0].name").isEqualTo(expectedClientName)
.consumeWith(System.out::println);
}else{
response.expectStatus().isOk()
.expectBody()
.consumeWith(System.out::println).json("[]");
}

}

private static Stream<Arguments> byEmail() {
return
Stream.concat(
Expand Down Expand Up @@ -485,4 +523,14 @@ private static Stream<Arguments> doingBusinessAs() {
);
}

private static Stream<Arguments> byPredictive() {
return Stream
.of(
Arguments.of("indian canada", "00000006", "INDIAN CANADA"),
Arguments.of("kilback", "00000123", "REICHERT, KILBACK AND EMARD"),
Arguments.of("darbie", "00000145", "DARBIE BLIND"),
Arguments.of("pietro", StringUtils.EMPTY, StringUtils.EMPTY)
);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import ca.bc.gov.app.dto.AddressSearchDto;
import ca.bc.gov.app.dto.ContactSearchDto;
import ca.bc.gov.app.dto.ForestClientDto;
import ca.bc.gov.app.dto.PredictiveSearchResultDto;
import ca.bc.gov.app.exception.MissingRequiredParameterException;
import ca.bc.gov.app.extensions.AbstractTestContainerIntegrationTest;
import java.util.List;
Expand Down Expand Up @@ -97,6 +98,31 @@ void shouldFindByContact(

}

@DisplayName("should do predictive search")
@ParameterizedTest
@MethodSource("byPredictive")
void shouldSearchWithPredictiveSearch(
String searchValue,
String expectedClientNumber,
String expectedClientName
) {

FirstStep<PredictiveSearchResultDto> test =
service
.predictiveSearch(searchValue)
.as(StepVerifier::create);

if(StringUtils.isNotBlank(expectedClientNumber)) {
test
.assertNext(dto -> {
assertNotNull(dto);
assertEquals(expectedClientNumber, dto.clientNumber());
assertEquals(expectedClientName, dto.name());
});
}
test.verifyComplete();
}

private void verifyTestData(
List<String> expectedList,
Class<RuntimeException> exception,
Expand Down Expand Up @@ -293,4 +319,15 @@ private static Stream<Arguments> emptyCases() {
);
}

private static Stream<Arguments> byPredictive() {
return Stream
.of(
Arguments.of("indian canada", "00000006", "INDIAN CANADA"),
Arguments.of("kilback", "00000123", "REICHERT, KILBACK AND EMARD"),
Arguments.of("darbie", "00000145", "DARBIE BLIND"),
Arguments.of("pietro", StringUtils.EMPTY, StringUtils.EMPTY)
);
}


}

0 comments on commit 9b989dc

Please sign in to comment.