Skip to content

Commit

Permalink
MSEARCH-762 Local Instances are not exported with the cql file in Mem…
Browse files Browse the repository at this point in the history
…ber tenant (#600)

* fix(mod-search): fix export of cql files

- Add query filter for active affiliation
- Add converter to consortia for member tenant

Closes: MSEARCH-762
  • Loading branch information
viacheslavpoliakov authored Jun 26, 2024
1 parent ce9630b commit 705e6e8
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 9 deletions.
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
* Browse: Duplicate results in exact match with diacritics ([MSEARCH-751](https://folio-org.atlassian.net/browse/MSEARCH-751))
* Classification browse: Fix instances count for Shared Facet ([MSEARCH-761](https://folio-org.atlassian.net/browse/MSEARCH-761))
* Subjects/Contributors browse: Fix instances count for Shared Facet ([MSEARCH-782](https://folio-org.atlassian.net/browse/MSEARCH-782))
* Search Resources IDs: Local instances are not searchable with requests from member tenants ([MSEARCH-762](https://folio-org.atlassian.net/browse/MSEARCH-762))

### Tech Dept
* Re-Index: delete all records from consortium_instance on full re-index ([MSEARCH-744](https://folio-org.atlassian.net/browse/MSEARCH-744))
Expand Down
16 changes: 16 additions & 0 deletions src/main/java/org/folio/search/cql/CqlSearchQueryConverter.java
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,22 @@ public SearchSourceBuilder convertForConsortia(String query, String resource) {
return convertForConsortia(query, resource, false);
}

/**
* Converts given CQL search query value to the elasticsearch {@link SearchSourceBuilder} object.
* Wraps base 'convert' and adds active affiliation tenantId filter in case of consortia mode
*
* @param query cql query to parse
* @param resource resource name
* @param tenantId active affiliation member tenant name
* @return search source as {@link SearchSourceBuilder} object with query and sorting conditions
*/
public SearchSourceBuilder convertForConsortia(String query, String resource, String tenantId) {
var sourceBuilder = convert(query, resource);
var queryBuilder = consortiumSearchHelper
.filterQueryForActiveAffiliation(sourceBuilder.query(), resource, tenantId);
return sourceBuilder.query(queryBuilder);
}

public SearchSourceBuilder convertForConsortia(String query, String resource, boolean consortiumConsolidated) {
var sourceBuilder = convert(query, resource);
if (consortiumConsolidated) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,8 @@ protected OutputStreamWriter createOutputStreamWriter(OutputStream outputStream)
private void streamResourceIds(CqlResourceIdsRequest request, Consumer<List<String>> idsConsumer) {
log.info("streamResourceIds:: by [query: {}, resource: {}]", request.getQuery(), request.getResource());

var searchSource = queryConverter.convertForConsortia(request.getQuery(), request.getResource())
var searchSource = queryConverter
.convertForConsortia(request.getQuery(), request.getResource(), request.getTenantId())
.size(streamIdsProperties.getScrollQuerySize())
.fetchSource(new String[] {request.getSourceFieldPath()}, null)
.sort(fieldSort("_doc"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,15 @@ public class ConsortiumSearchHelper {

public QueryBuilder filterQueryForActiveAffiliation(QueryBuilder query, String resource) {
var contextTenantId = folioExecutionContext.getTenantId();
return filterQueryForActiveAffiliation(query, resource, contextTenantId);
}

/**
* Modifies query to support both 'shared' filter and Active Affiliation.
* Active Affiliation have precedence over 'shared' filter so in case of member tenant
* modified query will have member 'tenantId' filter with shared=true).
*/
public QueryBuilder filterQueryForActiveAffiliation(QueryBuilder query, String resource, String contextTenantId) {
var centralTenantId = consortiumTenantService.getCentralTenant(contextTenantId);
if (centralTenantId.isEmpty()) {
return query;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ class ResourceIdServiceTest {

@Test
void streamResourceIds() throws IOException {
when(queryConverter.convertForConsortia(TEST_QUERY, RESOURCE_NAME)).thenReturn(searchSource());
when(queryConverter.convertForConsortia(TEST_QUERY, RESOURCE_NAME, TENANT_ID)).thenReturn(searchSource());
when(properties.getScrollQuerySize()).thenReturn(QUERY_SIZE);
mockSearchRepositoryCall(List.of(RANDOM_ID));

Expand All @@ -80,7 +80,7 @@ void streamResourceIds() throws IOException {

@Test
void streamResourceIdsAsText() {
when(queryConverter.convertForConsortia(TEST_QUERY, RESOURCE_NAME)).thenReturn(searchSource());
when(queryConverter.convertForConsortia(TEST_QUERY, RESOURCE_NAME, TENANT_ID)).thenReturn(searchSource());
when(properties.getScrollQuerySize()).thenReturn(QUERY_SIZE);
mockSearchRepositoryCall(List.of(RANDOM_ID));

Expand Down Expand Up @@ -125,7 +125,7 @@ void streamResourceIds_negative_throwExceptionOnWritingIdField() throws IOExcept
mockSearchRepositoryCall(List.of(RANDOM_ID));
when(properties.getScrollQuerySize()).thenReturn(QUERY_SIZE);
when(objectMapper.createGenerator(outputStream)).thenReturn(generator);
when(queryConverter.convertForConsortia(TEST_QUERY, RESOURCE_NAME)).thenReturn(searchSource());
when(queryConverter.convertForConsortia(TEST_QUERY, RESOURCE_NAME, TENANT_ID)).thenReturn(searchSource());
doThrow(new IOException("Failed to write string field")).when(generator).writeStringField("id", RANDOM_ID);

var request = request();
Expand All @@ -142,7 +142,7 @@ void streamResourceIdsAsText_negative_throwExceptionOnWritingIdField() throws IO
mockSearchRepositoryCall(List.of(RANDOM_ID));
when(properties.getScrollQuerySize()).thenReturn(QUERY_SIZE);
when(resourceIdService.createOutputStreamWriter(outputStream)).thenReturn(writer);
when(queryConverter.convertForConsortia(TEST_QUERY, RESOURCE_NAME)).thenReturn(searchSource());
when(queryConverter.convertForConsortia(TEST_QUERY, RESOURCE_NAME, TENANT_ID)).thenReturn(searchSource());
doThrow(new IOException("Failed to write string field")).when(writer).write(RANDOM_ID + '\n');

var request = request();
Expand All @@ -154,7 +154,7 @@ void streamResourceIdsAsText_negative_throwExceptionOnWritingIdField() throws IO
@Test
void streamResourceIds_positive_emptyCollectionProvided() throws IOException {
mockSearchRepositoryCall(emptyList());
when(queryConverter.convertForConsortia(TEST_QUERY, RESOURCE_NAME)).thenReturn(searchSource());
when(queryConverter.convertForConsortia(TEST_QUERY, RESOURCE_NAME, TENANT_ID)).thenReturn(searchSource());
when(properties.getScrollQuerySize()).thenReturn(QUERY_SIZE);

var outputStream = new ByteArrayOutputStream();
Expand All @@ -167,7 +167,7 @@ void streamResourceIds_positive_emptyCollectionProvided() throws IOException {
@Test
void streamResourceIdsInTextTextType_positive_emptyCollectionProvided() {
mockSearchRepositoryCall(emptyList());
when(queryConverter.convertForConsortia(TEST_QUERY, RESOURCE_NAME)).thenReturn(searchSource());
when(queryConverter.convertForConsortia(TEST_QUERY, RESOURCE_NAME, TENANT_ID)).thenReturn(searchSource());
when(properties.getScrollQuerySize()).thenReturn(QUERY_SIZE);

var outputStream = new ByteArrayOutputStream();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import static com.google.common.collect.Sets.newHashSet;
import static org.assertj.core.api.Assertions.assertThat;
import static org.folio.search.utils.SearchUtils.CONTRIBUTOR_RESOURCE;
import static org.folio.search.utils.SearchUtils.INSTANCE_RESOURCE;
import static org.folio.search.utils.SearchUtils.INSTANCE_SUBJECT_RESOURCE;
import static org.folio.search.utils.TestConstants.CENTRAL_TENANT_ID;
import static org.folio.search.utils.TestConstants.TENANT_ID;
Expand Down Expand Up @@ -37,8 +38,10 @@
class ConsortiumSearchHelperTest {

private static final String SUBRESOURCE_PREFIX = "instances.";
private static final String TENANT_ID_FIELD = SUBRESOURCE_PREFIX + "tenantId";
private static final String SHARED_FIELD = SUBRESOURCE_PREFIX + "shared";
private static final String TENANT_ID_FIELD_NAME = "tenantId";
private static final String TENANT_ID_FIELD = SUBRESOURCE_PREFIX + TENANT_ID_FIELD_NAME;
private static final String SHARED_FIELD_NAME = "shared";
private static final String SHARED_FIELD = SUBRESOURCE_PREFIX + SHARED_FIELD_NAME;

@Mock
private FolioExecutionContext context;
Expand Down Expand Up @@ -72,6 +75,43 @@ void filterQueryForActiveAffiliation_positive_basicNotConsortiumTenant() {
verify(consortiumSearchHelper, times(0)).filterQueryForActiveAffiliation(any(), any(), any(), any());
}

@Test
void filterQueryActiveAffiliation_filteredByMemberTenant() {
var query = boolQuery()
.filter(termQuery("staffSuppress", false))
.filter(termQuery(SHARED_FIELD_NAME, false));
var expected = boolQuery()
.filter(termQuery("staffSuppress", false))
.filter(termQuery(SHARED_FIELD_NAME, false))
.minimumShouldMatch(1)
.should(termQuery(TENANT_ID_FIELD_NAME, TENANT_ID))
.should(termQuery(SHARED_FIELD_NAME, true));

when(tenantService.getCentralTenant(TENANT_ID)).thenReturn(Optional.of(CENTRAL_TENANT_ID));

var actual = consortiumSearchHelper.filterQueryForActiveAffiliation(query, INSTANCE_RESOURCE, TENANT_ID);

assertThat(actual).isEqualTo(expected);
}

@Test
void filterQueryActiveAffiliation_notFilteredByMemberTenant() {
var query = boolQuery()
.filter(termQuery("staffSuppress", false))
.filter(termQuery(SHARED_FIELD_NAME, false));
var expected = boolQuery()
.filter(termQuery("staffSuppress", false))
.filter(termQuery(SHARED_FIELD_NAME, false))
.minimumShouldMatch(1)
.should(termQuery(SHARED_FIELD_NAME, true));

when(tenantService.getCentralTenant(CENTRAL_TENANT_ID)).thenReturn(Optional.of(CENTRAL_TENANT_ID));

var actual = consortiumSearchHelper.filterQueryForActiveAffiliation(query, INSTANCE_RESOURCE, CENTRAL_TENANT_ID);

assertThat(actual).isEqualTo(expected);
}

@Test
void filterQueryForActiveAffiliation_positive_basicConsortiumCentralTenant() {
var query = matchAllQuery();
Expand Down

0 comments on commit 705e6e8

Please sign in to comment.