Add new method for shop (#28)

This commit is contained in:
struga 2023-10-19 12:47:27 +03:00 committed by GitHub
parent d578032110
commit c44673a36a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 196 additions and 100 deletions

View File

@ -23,7 +23,6 @@
<management.port>8023</management.port>
<exposed.ports>${server.port} ${management.port}</exposed.ports>
<dockerfile.registry>${env.REGISTRY}</dockerfile.registry>
<deanonimus.proto.version>1.18-b9fab4f</deanonimus.proto.version>
</properties>
<dependencies>
@ -64,7 +63,7 @@
<dependency>
<groupId>dev.vality</groupId>
<artifactId>deanonimus-proto</artifactId>
<version>1.23-b4ce7de</version>
<version>1.36-94fb655</version>
</dependency>
<!--spring-->
<dependency>

View File

@ -3,16 +3,18 @@ package dev.vality.deanonimus.converter;
import dev.vality.damsel.deanonimus.Party;
import dev.vality.deanonimus.util.EnumUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;
@Component
@RequiredArgsConstructor
public class PartyConverter {
public class PartyConverter implements Converter<dev.vality.deanonimus.domain.Party, Party> {
private final ContractorConverter contractorConverter;
private final ContractConverter contractConverter;
private final ShopConverter shopConverter;
private final ShopListConverter shopConverter;
@Override
public Party convert(dev.vality.deanonimus.domain.Party domainParty) {
return new Party(
domainParty.getId(),

View File

@ -25,4 +25,5 @@ public class SearchHitConverter {
private SearchHit convertSearchHit(org.springframework.data.elasticsearch.core.SearchHit<Party> partySearchHit) {
return new SearchHit(partySearchHit.getScore(), partyConverter.convert(partySearchHit.getContent()));
}
}

View File

@ -0,0 +1,31 @@
package dev.vality.deanonimus.converter;
import dev.vality.damsel.deanonimus.SearchShopHit;
import dev.vality.deanonimus.domain.Party;
import lombok.RequiredArgsConstructor;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
import static java.util.stream.Collectors.toList;
@Component
@RequiredArgsConstructor
public class SearchHitShopConverter {
private final ShopListConverter converter;
public List<SearchShopHit> convert(SearchHits<Party> searchHits) {
List<SearchShopHit> hits = new ArrayList<>();
for (SearchHit<Party> searchHit : searchHits) {
hits.addAll(converter.convert(searchHit.getContent().getShops()).values()
.stream()
.map(shop -> new SearchShopHit(searchHit.getScore(), shop))
.collect(toList()));
}
return hits;
}
}

View File

@ -2,29 +2,16 @@ package dev.vality.deanonimus.converter;
import dev.vality.damsel.deanonimus.*;
import dev.vality.deanonimus.util.EnumUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
@Component
public class ShopConverter {
@RequiredArgsConstructor
public class ShopDomainToShopApiConverter implements Converter<dev.vality.deanonimus.domain.Shop, Shop> {
public Map<String, Shop> convert(List<dev.vality.deanonimus.domain.Shop> shops) {
return Optional.ofNullable(shops).orElse(Collections.emptyList())
.stream()
.map(this::convertToEntity)
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (a, b) -> a));
}
private Map.Entry<String, Shop> convertToEntity(dev.vality.deanonimus.domain.Shop shopDomain) {
return Map.entry(shopDomain.getId(), convertShop(shopDomain));
}
private Shop convertShop(dev.vality.deanonimus.domain.Shop shopDomain) {
@Override
public Shop convert(dev.vality.deanonimus.domain.Shop shopDomain) {
Shop shop = new Shop()
.setId(shopDomain.getId())
.setBlocking(EnumUtils.convertBlocking(shopDomain.getBlocking()))
@ -49,7 +36,7 @@ public class ShopConverter {
return shop;
}
private void setAccount(dev.vality.deanonimus.domain.Shop shopDomain, Shop shop) {
private void setAccount(dev.vality.deanonimus.domain.Shop shopDomain, dev.vality.damsel.deanonimus.Shop shop) {
if (shopDomain.getAccountCurrencyCode() != null) {
shop.setAccount(new ShopAccount(
new CurrencyRef(shopDomain.getAccountCurrencyCode()),
@ -59,5 +46,4 @@ public class ShopConverter {
));
}
}
}

View File

@ -0,0 +1,29 @@
package dev.vality.deanonimus.converter;
import dev.vality.damsel.deanonimus.Shop;
import lombok.RequiredArgsConstructor;
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.stream.Collectors;
@Component
@RequiredArgsConstructor
public class ShopListConverter {
private final Converter<dev.vality.deanonimus.domain.Shop, Shop> converter;
public Map<String, Shop> convert(List<dev.vality.deanonimus.domain.Shop> shops) {
return Optional.ofNullable(shops).orElse(Collections.emptyList())
.stream()
.map(this::convertToEntity)
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (a, b) -> a));
}
private Map.Entry<String, Shop> convertToEntity(dev.vality.deanonimus.domain.Shop shopDomain) {
return Map.entry(shopDomain.getId(), Objects.requireNonNull(converter.convert(shopDomain)));
}
}

View File

@ -1,81 +1,10 @@
package dev.vality.deanonimus.db;
import dev.vality.deanonimus.domain.Party;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.lucene.search.join.ScoreMode;
import org.elasticsearch.index.query.QueryBuilder;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.Query;
import org.springframework.stereotype.Component;
import static dev.vality.deanonimus.constant.ElasticsearchConstants.*;
import static org.elasticsearch.index.query.QueryBuilders.*;
public interface SearchDao {
@Slf4j
@Component
@RequiredArgsConstructor
public class SearchDao {
@Value("${data.response.limit}")
Integer responseLimit;
private final ElasticsearchRestTemplate elasticsearchRestTemplate;
public SearchHits<Party> searchParty(String text) {
QueryBuilder builder = boolQuery()
.should(searchPartyFields(text))
.should(searchShopFields(text))
.should(searchContractFields(text))
.should(searchContractorFields(text));
Query searchQuery = new NativeSearchQueryBuilder()
.withQuery(builder)
.withPageable(PageRequest.of(0, responseLimit))
.build();
return elasticsearchRestTemplate.search(searchQuery, Party.class);
}
private QueryBuilder searchContractorFields(String text) {
return nestedQuery(CONTRACTOR_INDEX,
multiMatchQuery(text,
"contractors.id",
"contractors.registeredUserEmail",
"contractors.russianLegalEntityRegisteredName",
"contractors.russianLegalEntityInn",
"contractors.russianLegalEntityRussianBankAccount",
"contractors.internationalLegalEntityLegalName",
"contractors.internationalLegalEntityTradingName"), ScoreMode.Total);
}
private QueryBuilder searchContractFields(String text) {
return nestedQuery(CONTRACT_INDEX,
multiMatchQuery(text,
"contracts.id",
"contracts.legalAgreementId",
"contracts.reportActSignerFullName"), ScoreMode.Total);
}
private QueryBuilder searchPartyFields(String text) {
return multiMatchQuery(text,
"id",
"email"
);
}
private QueryBuilder searchShopFields(String text) {
return nestedQuery(SHOP_INDEX,
multiMatchQuery(text,
"shops.id",
"shops.locationUrl"
), ScoreMode.Total);
}
SearchHits<Party> searchParty(String text);
}

View File

@ -0,0 +1,82 @@
package dev.vality.deanonimus.db;
import dev.vality.deanonimus.domain.Party;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.lucene.search.join.ScoreMode;
import org.elasticsearch.index.query.QueryBuilder;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.Query;
import org.springframework.stereotype.Component;
import static dev.vality.deanonimus.constant.ElasticsearchConstants.*;
import static org.elasticsearch.index.query.QueryBuilders.*;
@Slf4j
@Component
@RequiredArgsConstructor
public class SearchDaoImpl implements SearchDao {
@Value("${data.response.limit}")
Integer responseLimit;
private final ElasticsearchRestTemplate elasticsearchRestTemplate;
@Override
public SearchHits<Party> searchParty(String text) {
QueryBuilder builder = boolQuery()
.should(searchPartyFields(text))
.should(searchShopFields(text))
.should(searchContractFields(text))
.should(searchContractorFields(text));
Query searchQuery = new NativeSearchQueryBuilder()
.withQuery(builder)
.withPageable(PageRequest.of(0, responseLimit))
.build();
return elasticsearchRestTemplate.search(searchQuery, Party.class);
}
private QueryBuilder searchContractorFields(String text) {
return nestedQuery(CONTRACTOR_INDEX,
multiMatchQuery(text,
"contractors.id",
"contractors.registeredUserEmail",
"contractors.russianLegalEntityRegisteredName",
"contractors.russianLegalEntityInn",
"contractors.russianLegalEntityRussianBankAccount",
"contractors.internationalLegalEntityLegalName",
"contractors.internationalLegalEntityTradingName"), ScoreMode.Total);
}
private QueryBuilder searchContractFields(String text) {
return nestedQuery(CONTRACT_INDEX,
multiMatchQuery(text,
"contracts.id",
"contracts.legalAgreementId",
"contracts.reportActSignerFullName"), ScoreMode.Total);
}
private QueryBuilder searchPartyFields(String text) {
return multiMatchQuery(text,
"id",
"email"
);
}
private QueryBuilder searchShopFields(String text) {
return nestedQuery(SHOP_INDEX,
multiMatchQuery(text,
"shops.id",
"shops.locationUrl"
), ScoreMode.Total);
}
}

View File

@ -2,9 +2,12 @@ package dev.vality.deanonimus.handler;
import dev.vality.damsel.deanonimus.DeanonimusSrv;
import dev.vality.damsel.deanonimus.SearchHit;
import dev.vality.damsel.deanonimus.SearchShopHit;
import dev.vality.deanonimus.converter.SearchHitConverter;
import dev.vality.deanonimus.converter.SearchHitShopConverter;
import dev.vality.deanonimus.db.SearchDao;
import dev.vality.deanonimus.domain.Party;
import dev.vality.deanonimus.domain.Shop;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.thrift.TException;
@ -19,13 +22,22 @@ import java.util.List;
public class DeanonimusServiceHandler implements DeanonimusSrv.Iface {
private final SearchHitConverter searchHitConverter;
private final SearchHitShopConverter searchHitShopConverter;
private final SearchDao searchDao;
@Override
public List<SearchHit> searchParty(String text) throws TException {
log.info("Incoming request with text: {}", text);
log.info("Incoming request for party with text: {}", text);
SearchHits<Party> searchHits = searchDao.searchParty(text);
log.info("Found: {}", searchHits);
log.info("Found party: {}", searchHits);
return searchHitConverter.convert(searchHits);
}
@Override
public List<SearchShopHit> searchShopText(String text) throws TException {
log.info("Incoming request for shop with text: {}", text);
SearchHits<Party> searchHits = searchDao.searchParty(text);
log.info("Found shop: {}", searchHits);
return searchHitShopConverter.convert(searchHits);
}
}

View File

@ -1,6 +1,7 @@
package dev.vality.deanonimus;
import dev.vality.damsel.deanonimus.SearchHit;
import dev.vality.damsel.deanonimus.SearchShopHit;
import dev.vality.deanonimus.db.PartyRepository;
import dev.vality.deanonimus.domain.Party;
import dev.vality.deanonimus.handler.DeanonimusServiceHandler;
@ -100,6 +101,30 @@ public class ReadTest extends AbstractIntegrationTest {
.anyMatch(shop -> shop.getId().equals(SHOP))));
}
@Test
void searchShopByShopId() throws TException {
Party party = givenParty(PARTY, EMAIL);
givenShop(party, SHOP, URL);
List<SearchShopHit> searchShopHits = deanonimusServiceHandler.searchShopText(SHOP);
assertFalse(searchShopHits.isEmpty());
assertTrue(searchShopHits.stream()
.anyMatch(partySearchHit -> partySearchHit.getShop().getId().equals(SHOP)));
}
@Test
void searchShopByShopUrl() throws TException {
Party party = givenParty(PARTY, EMAIL);
givenShop(party, SHOP, URL);
List<SearchShopHit> searchHits = deanonimusServiceHandler.searchShopText(URL);
assertFalse(searchHits.isEmpty());
assertTrue(searchHits.stream()
.anyMatch(partySearchHit -> partySearchHit.getShop().getLocation().getUrl().contains(URL)));
}
@Test
void searchByContractorEmail() throws TException {
Party party = givenParty(PARTY, null);