Skip to content

Commit

Permalink
MODSOURCE-783 add qualifier
Browse files Browse the repository at this point in the history
  • Loading branch information
dmytrokrutii committed Jul 18, 2024
1 parent d8728fe commit b0b0c68
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 24 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.folio.dao.util;

import org.folio.processing.value.Value;
import org.folio.rest.jaxrs.model.Filter;
import org.marc4j.marc.impl.Verifier;

/**
Expand All @@ -15,6 +16,7 @@ public class MatchField {
private final String ind2;
private final String subfield;
private final Value value;
private final QualifierMatch qualifierMatch;
private final String fieldPath;

public MatchField(String tag, String ind1, String ind2, String subfield, Value value) {
Expand All @@ -24,6 +26,20 @@ public MatchField(String tag, String ind1, String ind2, String subfield, Value v
this.subfield = subfield;
this.value = value;
this.fieldPath = tag + ind1 + ind2 + subfield;
this.qualifierMatch = null;
}

public MatchField(String tag, String ind1, String ind2, String subfield, Value value, QualifierMatch qualifierMatch) {
this.tag = tag;
this.ind1 = ind1;
this.ind2 = ind2;
this.subfield = subfield;
this.value = value;
this.qualifierMatch = qualifierMatch;
this.fieldPath = tag + ind1 + ind2 + subfield;
}

public record QualifierMatch(Filter.Qualifier qualifier, String value) {
}

public String getTag() {
Expand All @@ -46,6 +62,10 @@ public Value getValue() {
return value;
}

public QualifierMatch getQualifierMatch() {
return qualifierMatch;
}

public boolean isControlField() {
return Verifier.isControlField(tag);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ public final class RecordDaoUtil {
public static final String RECORD_NOT_FOUND_TEMPLATE = "Record with id '%s' was not found";

private static final String COMMA = ",";
private static final String LIKE_OPERATOR = "%";
private static final List<String> DELETED_LEADER_RECORD_STATUS = Arrays.asList("d", "s", "x");

private RecordDaoUtil() {}
Expand All @@ -77,6 +78,17 @@ public static Condition getExternalIdsCondition(List<String> externalIds, IdType
return getIdCondition(idType, idField -> idField.in(toUUIDs(externalIds)));
}

/**
* Get {@link Condition} where in external list ids and {@link IdType} and match by qualifier value
*
* @param externalIds list of external id
* @param idType external id type
* @return condition
*/
public static Condition getExternalIdsConditionWithQualifier(List<String> externalIds, IdType idType, MatchField.QualifierMatch qualifier) {
return getIdConditionWithQualifier(idType, idField -> idField.in(toUUIDs(externalIds)), qualifier);
}

/**
* Count query by {@link Condition}
*
Expand Down Expand Up @@ -478,6 +490,18 @@ public static Condition filterRecordByExternalHridValues(List<String> externalHr
return RECORDS_LB.EXTERNAL_HRID.in(externalHridValues);
}

/**
* Get {@link Condition} to filter by external entity hrid using specified values and match by qualifier value
*
* @param externalHridValues external entity hrid values to equal
* @return condition
*/
public static Condition filterRecordByExternalHridValuesWithQualifier(List<String> externalHridValues, MatchField.QualifierMatch qualifier) {
var qualifierCondition = buildQualifierCondition(RECORDS_LB.EXTERNAL_HRID, qualifier);
var resultCondition = RECORDS_LB.EXTERNAL_HRID.in(externalHridValues);
return qualifierCondition != null ? resultCondition.and(qualifierCondition) : resultCondition;
}

/**
* Get {@link Condition} to filter by snapshotId id
*
Expand Down Expand Up @@ -734,20 +758,47 @@ private static Condition getRecordTypeCondition(RecordType recordType) {
}

private static Condition getIdCondition(IdType idType, Function<Field<UUID>, Condition> idFieldToConditionMapper) {
IdType idTypeToUse = idType;
RecordType recordType = null;
if (idType == IdType.HOLDINGS) {
idTypeToUse = IdType.EXTERNAL;
recordType = RecordType.MARC_HOLDING;
} else if (idType == IdType.INSTANCE) {
idTypeToUse = IdType.EXTERNAL;
recordType = RecordType.MARC_BIB;
} else if (idType == IdType.AUTHORITY) {
idTypeToUse = IdType.EXTERNAL;
recordType = RecordType.MARC_AUTHORITY;
}
IdType idTypeToUse = getIdType(idType);
RecordType recordType = getRecordType(idTypeToUse);
var idField = RECORDS_LB.field(LOWER_CAMEL.to(LOWER_UNDERSCORE, idTypeToUse.getIdField()), UUID.class);
return idFieldToConditionMapper.apply(idField).and(getRecordTypeCondition(recordType));
}

private static Condition getIdConditionWithQualifier(IdType idType, Function<Field<UUID>, Condition> idFieldToConditionMapper, MatchField.QualifierMatch qualifier) {
IdType idTypeToUse = getIdType(idType);
RecordType recordType = getRecordType(idTypeToUse);
var idField = RECORDS_LB.field(LOWER_CAMEL.to(LOWER_UNDERSCORE, idTypeToUse.getIdField()), UUID.class);
var qualifierCondition = buildQualifierCondition(idField, qualifier);
var resultCondition = idFieldToConditionMapper.apply(idField).and(getRecordTypeCondition(recordType));
return qualifierCondition != null ? resultCondition.and(qualifierCondition) : resultCondition;
}

private static Condition buildQualifierCondition(Field field, MatchField.QualifierMatch qualifier) {
if (qualifier == null) {
return null;
}
var value = qualifier.value();
return switch (qualifier.qualifier()) {
case BEGINS_WITH -> field.like(value + LIKE_OPERATOR);
case ENDS_WITH -> field.like(LIKE_OPERATOR + value);
case CONTAINS -> field.like(LIKE_OPERATOR + value + LIKE_OPERATOR);
};
}

private static RecordType getRecordType(IdType idType) {
return switch (idType) {
case HOLDINGS -> RecordType.MARC_HOLDING;
case INSTANCE -> RecordType.MARC_BIB;
case AUTHORITY -> RecordType.MARC_AUTHORITY;
default -> null;
};
}

private static IdType getIdType(IdType idType) {
return switch (idType) {
case HOLDINGS, INSTANCE, AUTHORITY -> IdType.EXTERNAL;
default -> idType;
};
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,7 @@
import static java.util.Objects.nonNull;
import static java.util.stream.Collectors.collectingAndThen;
import static java.util.stream.Collectors.toList;
import static org.folio.dao.util.RecordDaoUtil.RECORD_NOT_FOUND_TEMPLATE;
import static org.folio.dao.util.RecordDaoUtil.ensureRecordForeignKeys;
import static org.folio.dao.util.RecordDaoUtil.ensureRecordHasId;
import static org.folio.dao.util.RecordDaoUtil.ensureRecordHasSuppressDiscovery;
import static org.folio.dao.util.RecordDaoUtil.filterRecordByExternalHridValues;
import static org.folio.dao.util.RecordDaoUtil.filterRecordByState;
import static org.folio.dao.util.RecordDaoUtil.getExternalIdsCondition;
import static org.folio.dao.util.RecordDaoUtil.*;
import static org.folio.dao.util.SnapshotDaoUtil.SNAPSHOT_NOT_FOUND_TEMPLATE;
import static org.folio.dao.util.SnapshotDaoUtil.SNAPSHOT_NOT_STARTED_MESSAGE_TEMPLATE;
import static org.folio.rest.util.QueryParamUtil.toRecordType;
Expand Down Expand Up @@ -462,7 +456,11 @@ private MatchField prepareMatchField(RecordMatchingDto recordMatchingDto) {
String ind1 = filter.getIndicator1() != null ? filter.getIndicator1() : StringUtils.EMPTY;
String ind2 = filter.getIndicator2() != null ? filter.getIndicator2() : StringUtils.EMPTY;
String subfield = filter.getSubfield() != null ? filter.getSubfield() : StringUtils.EMPTY;
return new MatchField(filter.getField(), ind1, ind2, subfield, ListValue.of(filter.getValues()));
MatchField.QualifierMatch qualifier = null;
if (filter.getQualifier() != null && filter.getQualifierValue() != null) {
qualifier = new MatchField.QualifierMatch(filter.getQualifier(), filter.getQualifierValue());
}
return new MatchField(filter.getField(), ind1, ind2, subfield, ListValue.of(filter.getValues()), qualifier);
}

private TypeConnection getTypeConnection(RecordMatchingDto.RecordType recordType) {
Expand All @@ -477,13 +475,14 @@ private Future<RecordsIdentifiersCollection> processDefaultMatchField(MatchField
RecordMatchingDto recordMatchingDto, String tenantId) {
Condition condition = filterRecordByState(Record.State.ACTUAL.value());
List<String> values = ((ListValue) matchField.getValue()).getValue();
var qualifier = matchField.getQualifierMatch();

if (matchField.isMatchedId()) {
condition = condition.and(getExternalIdsCondition(values, IdType.RECORD));
condition = condition.and(getExternalIdsConditionWithQualifier(values, IdType.RECORD, qualifier));
} else if (matchField.isExternalId()) {
condition = condition.and(getExternalIdsCondition(values, IdType.EXTERNAL));
condition = condition.and(getExternalIdsConditionWithQualifier(values, IdType.EXTERNAL, qualifier));
} else if (matchField.isExternalHrid()) {
condition = condition.and(filterRecordByExternalHridValues(values));
condition = condition.and(filterRecordByExternalHridValuesWithQualifier(values, qualifier));
}

return recordDao.getRecords(condition, typeConnection.getDbType(), Collections.emptyList(), recordMatchingDto.getOffset(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,9 @@ public void shouldReturnEmptyCollectionIfRecordsDoNotMatch() {
.withField("999")
.withIndicator1("f")
.withIndicator2("f")
.withSubfield("s"))))
.withSubfield("s")
.withQualifier(Filter.Qualifier.BEGINS_WITH)
.withQualifierValue("TEST"))))
.post(RECORDS_MATCHING_PATH)
.then()
.statusCode(HttpStatus.SC_OK)
Expand Down

0 comments on commit b0b0c68

Please sign in to comment.