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

feat(cn-browse): Implement Indexing and Re-indexing Mechanisms for Call-Numbers #707

Merged
merged 1 commit into from
Dec 5, 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
2 changes: 2 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
### Features
* Move Instance sub-entities population from database trigger to code ([MSEARCH-887](https://folio-org.atlassian.net/browse/MSEARCH-887))
* Call Numbers Browse: Implement Database Structure and Logic for Managing Call Numbers ([MSEARCH-862](https://folio-org.atlassian.net/browse/MSEARCH-862))
* Call Numbers Browse: Implement Call Number Browse Config ([MSEARCH-863](https://folio-org.atlassian.net/browse/MSEARCH-863))
* Call Numbers Browse: Implement Indexing and Re-indexing Mechanisms for Call-Numbers ([MSEARCH-864](https://folio-org.atlassian.net/browse/MSEARCH-864))

### Bug fixes
* Remove shelving order calculation for local call-number types
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.folio.search.model.entity;

import java.util.Set;
import org.folio.search.model.index.InstanceSubResource;

public record InstanceCallNumberEntityAgg(
String id,
String fullCallNumber,
String callNumber,
String callNumberPrefix,
String callNumberSuffix,
String callNumberTypeId,
String volume,
String enumeration,
String chronology,
String copyNumber,
Set<InstanceSubResource> instances) { }
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package org.folio.search.model.index;

import java.util.Set;

public record CallNumberResource(
String id,
String fullCallNumber,
String callNumber,
String callNumberPrefix,
String callNumberSuffix,
String callNumberTypeId,
String volume,
String enumeration,
String chronology,
String copyNumber,
Set<InstanceSubResource> instances) { }
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ public class InstanceSubResource {
private Boolean shared;
private int count;
private List<String> typeId;
private List<String> locationId;
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public enum ReindexEntityType {
SUBJECT("subject", false, true),
CONTRIBUTOR("contributor", false, true),
CLASSIFICATION("classification", false, true),
CALL_NUMBER("call-number", false, true),
CALL_NUMBER("call_number", false, true),
ITEM("item", true, false),
HOLDINGS("holdings", true, false);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public enum ResourceType {
INSTANCE("instance"),
INSTANCE_CONTRIBUTOR("contributor"),
INSTANCE_CLASSIFICATION("instance_classification"),
INSTANCE_CALL_NUMBER("instance_call_number"),
INSTANCE_SUBJECT("instance_subject"),
INSTITUTION("institution"),
ITEM("item"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,13 +115,13 @@ public FolioIndexOperationResponse indexInstancesById(List<ResourceEvent> resour

private Map<String, List<SearchDocumentBody>> processIndexInstanceEvents(List<ResourceEvent> resourceEvents) {
var indexEvents = extractEventsForDataMove(resourceEvents);
preProcessEvents(indexEvents);
var fetchedInstances = Optional.ofNullable(consortiumTenantExecutor.execute(
() -> resourceFetchService.fetchInstancesByIds(indexEvents)))
.orElse(Collections.emptyList()).stream()
.filter(Objects::nonNull)
.toList();

preProcessEvents(fetchedInstances);
return searchDocumentConverter.convert(fetchedInstances);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,33 @@
package org.folio.search.service.converter.preprocessor.extractor.impl;

import static java.util.Collections.emptyList;
import static java.util.Collections.emptySet;
import static org.apache.commons.collections4.MapUtils.getMap;
import static org.apache.commons.collections4.MapUtils.getString;
import static org.folio.search.utils.CollectionUtils.subtract;
import static org.folio.search.utils.SearchConverterUtils.getNewAsMap;
import static org.folio.search.utils.SearchConverterUtils.getOldAsMap;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import lombok.extern.log4j.Log4j2;
import org.folio.search.domain.dto.ResourceEvent;
import org.folio.search.domain.dto.ResourceEventType;
import org.folio.search.domain.dto.TenantConfiguredFeature;
import org.folio.search.model.entity.CallNumberEntity;
import org.folio.search.model.entity.InstanceCallNumberEntity;
import org.folio.search.model.entity.InstanceCallNumberEntityAgg;
import org.folio.search.model.index.CallNumberResource;
import org.folio.search.model.types.ResourceType;
import org.folio.search.service.FeatureConfigService;
import org.folio.search.service.converter.preprocessor.extractor.ChildResourceExtractor;
import org.folio.search.service.reindex.jdbc.CallNumberRepository;
import org.folio.search.utils.CollectionUtils;
import org.folio.search.utils.JsonConverter;
import org.springframework.stereotype.Component;

Expand All @@ -35,35 +45,62 @@ public class CallNumberResourceExtractor extends ChildResourceExtractor {
public static final String ENUMERATION_FIELD = "enumeration";
public static final String COPY_NUMBER_FIELD = "copyNumber";

private final CallNumberRepository repository;
private final JsonConverter jsonConverter;
private final FeatureConfigService featureConfigService;

public CallNumberResourceExtractor(CallNumberRepository repository, JsonConverter jsonConverter,
FeatureConfigService featureConfigService) {
super(repository);
this.repository = repository;
this.jsonConverter = jsonConverter;
this.featureConfigService = featureConfigService;
}

@Override
public List<ResourceEvent> prepareEvents(ResourceEvent resource) {
return List.of();
if (!featureConfigService.isEnabled(TenantConfiguredFeature.BROWSE_CALL_NUMBERS)) {
return Collections.emptyList();
}
var oldCallNumbers = getCallNumberResources(getOldAsMap(resource));
var newCallNumbers = getCallNumberResources(getNewAsMap(resource));

if (oldCallNumbers.equals(newCallNumbers)) {
return emptyList();
}

var tenant = resource.getTenant();
var callNumbersForCreate = subtract(newCallNumbers, oldCallNumbers);
var callNumbersForDelete = subtract(oldCallNumbers, newCallNumbers);

var idsForCreate = toIds(callNumbersForCreate);
var idsForDelete = toIds(callNumbersForDelete);

List<String> idsForFetch = new ArrayList<>();
idsForFetch.addAll(idsForCreate);
idsForFetch.addAll(idsForDelete);

var entityAggList = repository.fetchByIds(idsForFetch);
var list = getResourceEventsForDeletion(idsForDelete, entityAggList, tenant);

var list1 = entityAggList.stream()
.map(entities -> toResourceEvent(entities, tenant))
.toList();
return CollectionUtils.mergeSafelyToList(list, list1);
}

@Override
public List<ResourceEvent> prepareEventsOnSharing(ResourceEvent resource) {
return List.of();
return emptyList();
}

@Override
public boolean hasChildResourceChanges(ResourceEvent event) {
public boolean hasChildResourceChanges(ResourceEvent resource) {
if (!featureConfigService.isEnabled(TenantConfiguredFeature.BROWSE_CALL_NUMBERS)) {
return false;
}
var oldAsMap = getOldAsMap(event);
var newAsMap = getNewAsMap(event);
var oldCallNumber = constructEntity(oldAsMap);
var newCallNumber = constructEntity(newAsMap);
var oldCallNumber = toCallNumberEntity(getOldAsMap(resource));
var newCallNumber = toCallNumberEntity(getNewAsMap(resource));
return !oldCallNumber.equals(newCallNumber);
}

Expand Down Expand Up @@ -93,6 +130,74 @@ protected Map<String, Object> constructEntity(Map<String, Object> entityProperti
if (!featureConfigService.isEnabled(TenantConfiguredFeature.BROWSE_CALL_NUMBERS)) {
return Collections.emptyMap();
}
return toCallNumberEntity(entityProperties)
.map(jsonConverter::convertToMap)
.orElse(Collections.emptyMap());
}

@Override
protected String childrenFieldName() {
return "";
}

@Override
protected Set<Map<String, Object>> getChildResources(Map<String, Object> event) {
return Set.of(event);
}

private Set<CallNumberEntity> getCallNumberResources(Map<String, Object> event) {
return toCallNumberEntity(event)
.map(Set::of)
.orElse(emptySet());
}

private List<String> toIds(Set<CallNumberEntity> subtract) {
return subtract.stream()
.map(CallNumberEntity::getId)
.collect(Collectors.toCollection(ArrayList::new));
}

private List<ResourceEvent> getResourceEventsForDeletion(List<String> idsForDelete,
List<InstanceCallNumberEntityAgg> entityAggList,
String tenant) {
var notFoundEntitiesForDelete = new ArrayList<>(idsForDelete);
var iterator = notFoundEntitiesForDelete.iterator();
while (iterator.hasNext()) {
var callNumber = iterator.next();
for (var agg : entityAggList) {
if (agg.id().equals(callNumber)) {
iterator.remove();
}
}
}

return notFoundEntitiesForDelete.stream()
.map(callNumberId -> toResourceDeleteEvent(callNumberId, tenant))
.toList();
}

private ResourceEvent toResourceDeleteEvent(String id, String tenant) {
return new ResourceEvent()
.id(id)
.tenant(tenant)
.resourceName(ResourceType.INSTANCE_CALL_NUMBER.getName())
.type(ResourceEventType.DELETE);
}

private ResourceEvent toResourceEvent(InstanceCallNumberEntityAgg source, String tenant) {
var id = source.id();
var resource = new CallNumberResource(id, source.fullCallNumber(), source.callNumber(),
source.callNumberPrefix(), source.callNumberSuffix(), source.callNumberTypeId(), source.volume(),
source.enumeration(), source.chronology(), source.copyNumber(), source.instances());
return new ResourceEvent()
.id(id)
.tenant(tenant)
.resourceName(ResourceType.INSTANCE_CALL_NUMBER.getName())
.type(ResourceEventType.UPDATE)
._new(jsonConverter.convertToMap(resource));
}

private Optional<CallNumberEntity> toCallNumberEntity(Map<String, Object> entityProperties) {
var callNumberComponents = getCallNumberComponents(entityProperties);
var callNumber = getString(callNumberComponents, CALL_NUMBER_FIELD);
if (callNumber != null) {
Expand All @@ -106,9 +211,9 @@ protected Map<String, Object> constructEntity(Map<String, Object> entityProperti
.enumeration(getString(entityProperties, ENUMERATION_FIELD))
.copyNumber(getString(entityProperties, COPY_NUMBER_FIELD))
.build();
return jsonConverter.convertToMap(callNumberEntity);
return Optional.of(callNumberEntity);
}
return Collections.emptyMap();
return Optional.empty();
}

@SuppressWarnings("unchecked")
Expand All @@ -117,14 +222,4 @@ private Map<String, Object> getCallNumberComponents(Map<String, Object> entityPr
Collections.<String, Object>emptyMap());
}

@Override
protected String childrenFieldName() {
return "";
}

@Override
protected Set<Map<String, Object>> getChildResources(Map<String, Object> event) {
return Set.of(event);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ public final class ReindexConstants {
ReindexEntityType.HOLDINGS, ResourceType.HOLDINGS,
ReindexEntityType.SUBJECT, ResourceType.INSTANCE_SUBJECT,
ReindexEntityType.CLASSIFICATION, ResourceType.INSTANCE_CLASSIFICATION,
ReindexEntityType.CONTRIBUTOR, ResourceType.INSTANCE_CONTRIBUTOR
ReindexEntityType.CONTRIBUTOR, ResourceType.INSTANCE_CONTRIBUTOR,
ReindexEntityType.CALL_NUMBER, ResourceType.INSTANCE_CALL_NUMBER
);

public static final String CALL_NUMBER_TABLE = "call_number";
Expand Down
Loading
Loading